From 4e49e2f16a488a3956f950d2bac3761432a38273 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Thu, 12 Mar 2026 09:50:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dagent=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E5=8F=AF=E8=83=BD=E4=BC=9A=E6=AE=8B=E7=95=99?= =?UTF-8?q?=E5=AD=90=E8=BF=9B=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 2 +- src-tauri/src/acp/manager.rs | 16 ++++++++++++++++ src-tauri/src/acp/terminal_runtime.rs | 18 +++--------------- src-tauri/src/lib.rs | 10 +++++++++- src-tauri/src/terminal/manager.rs | 13 +++++++++++++ src-tauri/vendor/sacp-tokio/Cargo.toml | 3 +++ src-tauri/vendor/sacp-tokio/src/acp_agent.rs | 6 +++++- 8 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 61741e6..dd2dbfc 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4730,6 +4730,7 @@ name = "sacp-tokio" version = "11.0.0-alpha.1" dependencies = [ "futures", + "kill_tree", "sacp", "serde", "serde_json", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index adc886e..0c194f3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -47,6 +47,7 @@ toml = "0.8" notify = "6" base64 = "0.22" agent-client-protocol-schema = { version = "0.10", features = ["unstable_session_usage"] } +kill_tree = { version = "0.2", features = ["tokio"] } [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-window-state = "2" @@ -56,7 +57,6 @@ tauri-plugin-process = "2" [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Storage_FileSystem"] } -kill_tree = { version = "0.2", features = ["tokio"] } [patch.crates-io] sacp-tokio = { path = "vendor/sacp-tokio" } diff --git a/src-tauri/src/acp/manager.rs b/src-tauri/src/acp/manager.rs index f43d1fc..5125476 100644 --- a/src-tauri/src/acp/manager.rs +++ b/src-tauri/src/acp/manager.rs @@ -190,6 +190,22 @@ impl ConnectionManager { disconnected } + pub async fn disconnect_all(&self) -> usize { + let cmd_txs: Vec<_> = { + let mut connections = self.connections.lock().await; + connections + .drain() + .map(|(_, conn)| conn.cmd_tx) + .collect() + }; + let disconnected = cmd_txs.len(); + for cmd_tx in cmd_txs { + let _ = cmd_tx.send(ConnectionCommand::Disconnect).await; + } + eprintln!("[ACP] disconnect_all count={}", disconnected); + disconnected + } + pub async fn list_connections(&self) -> Vec { let connections = self.connections.lock().await; connections.values().map(|c| c.info()).collect() diff --git a/src-tauri/src/acp/terminal_runtime.rs b/src-tauri/src/acp/terminal_runtime.rs index e517e4b..30fe4c9 100644 --- a/src-tauri/src/acp/terminal_runtime.rs +++ b/src-tauri/src/acp/terminal_runtime.rs @@ -149,21 +149,9 @@ impl TerminalInstance { return Ok(()); }; - #[cfg(target_os = "windows")] - { - if let Some(pid) = child.id() { - let _ = kill_tree::tokio::kill_tree(pid); - } - } - - #[cfg(not(target_os = "windows"))] - { - if let Err(err) = child.kill().await { - if err.kind() != std::io::ErrorKind::InvalidInput { - return Err(TerminalRuntimeError::Internal(format!( - "failed to kill terminal process: {err}" - ))); - } + if let Some(pid) = child.id() { + if let Err(err) = kill_tree::tokio::kill_tree(pid).await { + eprintln!("[ACP] kill_tree failed for pid {pid}: {err}"); } } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index eca0a8b..891e85c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -268,9 +268,17 @@ pub fn run() { ]) .build(tauri::generate_context!()) .expect("error while building tauri application") - .run(|_app, event| { + .run(|app, event| { if let tauri::RunEvent::ExitRequested { .. } = event { APP_QUITTING.store(true, Ordering::Relaxed); + // Kill all terminal sessions to prevent orphaned processes. + if let Some(tm) = app.try_state::() { + tm.kill_all(); + } + // Disconnect all ACP agent connections (kills agent process trees). + if let Some(cm) = app.try_state::() { + tauri::async_runtime::block_on(cm.disconnect_all()); + } } }); } diff --git a/src-tauri/src/terminal/manager.rs b/src-tauri/src/terminal/manager.rs index 232d055..0f2073a 100644 --- a/src-tauri/src/terminal/manager.rs +++ b/src-tauri/src/terminal/manager.rs @@ -328,6 +328,19 @@ impl TerminalManager { } killed } + + pub fn kill_all(&self) -> usize { + let mut instances: Vec = { + let mut terminals = self.terminals.lock().unwrap(); + terminals.drain().map(|(_, inst)| inst).collect() + }; + let killed = instances.len(); + for instance in &mut instances { + terminate_terminal(instance); + } + eprintln!("[TERM] kill_all killed_terminals={}", killed); + killed + } } fn terminate_terminal(instance: &mut TerminalInstance) { diff --git a/src-tauri/vendor/sacp-tokio/Cargo.toml b/src-tauri/vendor/sacp-tokio/Cargo.toml index 0a4cd30..dfa6a7c 100644 --- a/src-tauri/vendor/sacp-tokio/Cargo.toml +++ b/src-tauri/vendor/sacp-tokio/Cargo.toml @@ -61,6 +61,9 @@ version = "1.1" version = "1.48" features = ["full"] +[dependencies.kill_tree] +version = "0.2" + [dependencies.tokio-util] version = "0.7" features = ["compat"] diff --git a/src-tauri/vendor/sacp-tokio/src/acp_agent.rs b/src-tauri/vendor/sacp-tokio/src/acp_agent.rs index 9598c9b..5ea376e 100644 --- a/src-tauri/vendor/sacp-tokio/src/acp_agent.rs +++ b/src-tauri/vendor/sacp-tokio/src/acp_agent.rs @@ -230,7 +230,11 @@ impl ChildGuard { impl Drop for ChildGuard { fn drop(&mut self) { - let _ = self.0.start_kill(); + if let Some(pid) = self.0.id() { + let _ = kill_tree::blocking::kill_tree(pid); + } else { + let _ = self.0.start_kill(); + } } }