diff --git a/src-tauri/src/commands/acp.rs b/src-tauri/src/commands/acp.rs index 1e1549d..4756e5c 100644 --- a/src-tauri/src/commands/acp.rs +++ b/src-tauri/src/commands/acp.rs @@ -91,6 +91,25 @@ async fn detect_global_cmd_version(cmd: &str) -> Option { normalize_version_candidate(&raw) } +/// 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) +} + async fn detect_local_version(agent_type: AgentType) -> Option { let meta = registry::get_agent_meta(agent_type); match meta.distribution { @@ -1036,9 +1055,12 @@ pub async fn acp_connect( runtime_env.insert("OPENCLAW_RESET_SESSION".into(), "1".into()); } - if let registry::AgentDistribution::Npx { cmd, package, .. } = meta.distribution { - if detect_global_cmd_version(cmd).await.is_none() { - install_npm_global_package(package).await?; + if let registry::AgentDistribution::Npx { cmd, .. } = meta.distribution { + if !is_cmd_available(cmd).await { + return Err(AcpError::protocol(format!( + "{} SDK is not installed. Please install it in Agent Settings.", + meta.name + ))); } }