aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-29 16:24:23 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-29 16:24:23 +0300
commit44b3adb125524ea9a55739eee3776f922f2115ad (patch)
tree8cb034f5d2ece211f374ef0eacea525a7028cce7 /src
parent8ed742da268376d33ee6045674c7b975ee3181f8 (diff)
fix(windows): preserve parent agent ownership
refs #1514
Diffstat (limited to 'src')
-rw-r--r--src/platform/windows.rs67
1 files changed, 34 insertions, 33 deletions
diff --git a/src/platform/windows.rs b/src/platform/windows.rs
index a206b0d1..705a1d1f 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -308,33 +308,16 @@ fn select_pane_foreground_job(
entries: &[WindowsProcessEntry],
) -> Option<ForegroundJob> {
let shell = entries.iter().find(|entry| entry.pid == shell_pid)?;
- let shell_job = || ForegroundJob {
- process_group_id: shell_pid,
- processes: vec![foreground_process_from_entry(shell)],
- };
-
let descendants = descendant_entries(shell_pid, entries);
let mut candidates = Vec::new();
- for entry in &descendants {
- let process = foreground_process_from_entry(entry);
- let job = ForegroundJob {
- process_group_id: entry.pid,
- processes: vec![process],
- };
- if let Some((agent, _)) = crate::detect::identify_agent_in_job(&job) {
- candidates.push((*entry, agent));
+ for entry in std::iter::once(shell).chain(descendants) {
+ if crate::detect::identify_agent_in_job(&foreground_job_from_entry(entry)).is_some() {
+ candidates.push(entry);
}
}
- match candidates.len() {
- 1 => candidates
- .pop()
- .map(|(entry, _)| foreground_job_from_entry(entry)),
- _ => select_single_agent_chain_candidate(&candidates, entries).map_or_else(
- || Some(shell_job()),
- |entry| Some(foreground_job_from_entry(entry)),
- ),
- }
+ let selected = select_topmost_agent_chain_candidate(&candidates, entries).unwrap_or(shell);
+ Some(foreground_job_from_entry(selected))
}
fn foreground_job_from_entry(entry: &WindowsProcessEntry) -> ForegroundJob {
@@ -344,22 +327,17 @@ fn foreground_job_from_entry(entry: &WindowsProcessEntry) -> ForegroundJob {
}
}
-fn select_single_agent_chain_candidate<'a>(
- candidates: &[(&'a WindowsProcessEntry, crate::detect::Agent)],
+fn select_topmost_agent_chain_candidate<'a>(
+ candidates: &[&'a WindowsProcessEntry],
entries: &[WindowsProcessEntry],
) -> Option<&'a WindowsProcessEntry> {
- let (_, first_agent) = candidates.first()?;
- if !candidates.iter().all(|(_, agent)| agent == first_agent) {
- return None;
- }
-
let parent_by_pid: HashMap<u32, u32> = entries
.iter()
.map(|entry| (entry.pid, entry.parent_pid))
.collect();
- candidates.iter().map(|(entry, _)| *entry).find(|entry| {
- candidates.iter().all(|(other, _)| {
+ candidates.iter().copied().find(|entry| {
+ candidates.iter().all(|other| {
entry.pid == other.pid || process_is_ancestor(entry.pid, other.pid, &parent_by_pid)
})
})
@@ -1645,11 +1623,16 @@ mod tests {
}
#[test]
- fn windows_process_tree_selects_topmost_claude_process_in_single_agent_chain() {
+ fn windows_process_tree_keeps_topmost_agent_over_different_agent_descendant() {
let entries = vec![
test_entry(10, 1, "powershell.exe", &["powershell.exe"]),
test_entry(20, 10, "claude.exe", &["claude.exe"]),
- test_entry(30, 20, "claude.exe", &["claude.exe", "mcp-server"]),
+ test_entry(
+ 30,
+ 20,
+ "cmd.exe",
+ &["cmd.exe", "/D", "/S", "/C", "codex mcp-server"],
+ ),
];
let job = super::select_pane_foreground_job(10, &entries).unwrap();
@@ -1659,6 +1642,24 @@ mod tests {
}
#[test]
+ fn windows_process_tree_keeps_root_agent_over_agent_descendant() {
+ let entries = vec![
+ test_entry(10, 1, "claude.exe", &["claude.exe"]),
+ test_entry(
+ 20,
+ 10,
+ "cmd.exe",
+ &["cmd.exe", "/D", "/S", "/C", "codex mcp-server"],
+ ),
+ ];
+
+ let job = super::select_pane_foreground_job(10, &entries).unwrap();
+
+ assert_eq!(job.process_group_id, 10);
+ assert_eq!(job.processes[0].name, "claude.exe");
+ }
+
+ #[test]
fn windows_process_tree_returns_shell_for_same_agent_siblings() {
let entries = vec![
test_entry(10, 1, "powershell.exe", &["powershell.exe"]),