From e3784fb3f339bba91650275dc59cb951720d0c0d Mon Sep 17 00:00:00 2001 From: xintaofei Date: Wed, 18 Mar 2026 22:59:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8rust=20which=E5=8C=85?= =?UTF-8?q?=E6=9D=A5=E6=9F=A5=E6=89=BE=E5=91=BD=E4=BB=A4=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E5=86=B3=E9=83=A8=E5=88=86=E7=94=B5=E8=84=91?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E8=AF=86=E5=88=AB=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/Cargo.lock | 27 ++++++++++++++++++++++++++- src-tauri/Cargo.toml | 1 + src-tauri/src/acp/connection.rs | 10 +++++++--- src-tauri/src/acp/preflight.rs | 24 +++++++++++++++++------- src-tauri/src/commands/acp.rs | 20 ++++---------------- 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index fcb1c4b..8673cff 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -409,7 +409,7 @@ dependencies = [ "rustc-hash", "shlex", "syn 2.0.114", - "which", + "which 4.4.2", ] [[package]] @@ -827,6 +827,7 @@ dependencies = [ "urlencoding", "uuid", "walkdir", + "which 7.0.3", "windows-sys 0.59.0", "zip 2.4.2", ] @@ -1422,6 +1423,12 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equivalent" version = "1.0.2" @@ -7185,6 +7192,18 @@ dependencies = [ "rustix 0.38.44", ] +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix 1.1.3", + "winsafe", +] + [[package]] name = "whoami" version = "1.6.1" @@ -7762,6 +7781,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5eda92d..ecd00bf 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -48,6 +48,7 @@ notify = "6" base64 = "0.22" agent-client-protocol-schema = { version = "0.10", features = ["unstable_session_usage", "unstable_session_fork"] } kill_tree = { version = "0.2", features = ["tokio"] } +which = "7" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-window-state = "2" diff --git a/src-tauri/src/acp/connection.rs b/src-tauri/src/acp/connection.rs index b8c779c..9c91447 100644 --- a/src-tauri/src/acp/connection.rs +++ b/src-tauri/src/acp/connection.rs @@ -131,9 +131,13 @@ async fn build_agent( parts.push(format!("{k}={v}")); } parts.push( - crate::process::normalized_program(cmd) - .to_string_lossy() - .to_string(), + which::which(cmd) + .map(|p| p.to_string_lossy().to_string()) + .unwrap_or_else(|_| { + crate::process::normalized_program(cmd) + .to_string_lossy() + .to_string() + }), ); for a in args { parts.push((*a).into()); diff --git a/src-tauri/src/acp/preflight.rs b/src-tauri/src/acp/preflight.rs index 45ee429..4890978 100644 --- a/src-tauri/src/acp/preflight.rs +++ b/src-tauri/src/acp/preflight.rs @@ -93,14 +93,24 @@ async fn check_npm_environment(node_required: Option<&str>) -> Vec { return checks; } - // Run node and npm checks in parallel + // Resolve absolute paths via `which` crate to avoid GUI PATH issues, + // then run version checks in parallel. + let node_path = which::which("node").ok(); + let npm_path = which::which("npm").ok(); + let (node_result, npm_result) = tokio::join!( - crate::process::tokio_command("node") - .arg("--version") - .output(), - crate::process::tokio_command("npm") - .arg("--version") - .output(), + async { + match &node_path { + Some(p) => crate::process::tokio_command(p).arg("--version").output().await, + None => Err(std::io::Error::new(std::io::ErrorKind::NotFound, "node not found in PATH")), + } + }, + async { + match &npm_path { + Some(p) => crate::process::tokio_command(p).arg("--version").output().await, + None => Err(std::io::Error::new(std::io::ErrorKind::NotFound, "npm not found in PATH")), + } + }, ); // Track the raw node version string for reuse in the version check diff --git a/src-tauri/src/commands/acp.rs b/src-tauri/src/commands/acp.rs index e7afba2..ae6231e 100644 --- a/src-tauri/src/commands/acp.rs +++ b/src-tauri/src/commands/acp.rs @@ -81,27 +81,15 @@ fn package_name_from_spec(package: &str) -> String { /// Check whether a command is available on the system PATH. /// Uses `which` on unix and `where` on windows — lightweight and does not /// invoke the target binary itself, avoiding side-effects or slow startups. -async fn is_cmd_available(cmd: &str) -> bool { - #[cfg(unix)] - let check_cmd = "which"; - #[cfg(windows)] - let check_cmd = "where"; - - crate::process::tokio_command(check_cmd) - .arg(cmd) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .status() - .await - .map(|s| s.success()) - .unwrap_or(false) +fn is_cmd_available(cmd: &str) -> bool { + which::which(cmd).is_ok() } async fn detect_local_version(agent_type: AgentType) -> Option { let meta = registry::get_agent_meta(agent_type); match meta.distribution { registry::AgentDistribution::Npx { cmd, package, .. } => { - if is_cmd_available(cmd).await { + if is_cmd_available(cmd) { version_from_package_spec(package) } else { None @@ -1047,7 +1035,7 @@ pub async fn acp_connect( } if let registry::AgentDistribution::Npx { cmd, .. } = meta.distribution { - if !is_cmd_available(cmd).await { + if !is_cmd_available(cmd) { return Err(AcpError::protocol(format!( "{} SDK is not installed. Please install it in Agent Settings.", meta.name