Merge remote-tracking branch 'origin/main'
This commit is contained in:
29
src-tauri/Cargo.lock
generated
29
src-tauri/Cargo.lock
generated
@@ -409,7 +409,7 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 2.0.114",
|
||||
"which",
|
||||
"which 4.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -792,7 +792,7 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
|
||||
[[package]]
|
||||
name = "codeg"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"agent-client-protocol-schema",
|
||||
"base64 0.22.1",
|
||||
@@ -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"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "codeg"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
description = "Agent Code Generation App"
|
||||
authors = ["feitao"]
|
||||
edition = "2021"
|
||||
@@ -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"
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -93,14 +93,24 @@ async fn check_npm_environment(node_required: Option<&str>) -> Vec<CheckItem> {
|
||||
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
|
||||
|
||||
@@ -113,8 +113,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
|
||||
name: "Claude Code",
|
||||
description: "ACP wrapper for Anthropic's Claude",
|
||||
distribution: AgentDistribution::Npx {
|
||||
version: "0.22.1",
|
||||
package: "@zed-industries/claude-agent-acp@0.22.1",
|
||||
version: "0.22.2",
|
||||
package: "@zed-industries/claude-agent-acp@0.22.2",
|
||||
cmd: "claude-agent-acp",
|
||||
args: &[],
|
||||
env: &[],
|
||||
|
||||
@@ -81,31 +81,49 @@ 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";
|
||||
fn is_cmd_available(cmd: &str) -> bool {
|
||||
which::which(cmd).is_ok()
|
||||
}
|
||||
|
||||
crate::process::tokio_command(check_cmd)
|
||||
.arg(cmd)
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.status()
|
||||
/// Detect the actual installed version of an npm global package by running
|
||||
/// `npm list -g <package_name> --json` and parsing the JSON output.
|
||||
async fn detect_npm_global_version(package_name: &str) -> Option<String> {
|
||||
let npm_path = which::which("npm").ok()?;
|
||||
let output = crate::process::tokio_command(npm_path)
|
||||
.arg("list")
|
||||
.arg("-g")
|
||||
.arg(package_name)
|
||||
.arg("--json")
|
||||
.arg("--depth=0")
|
||||
.output()
|
||||
.await
|
||||
.map(|s| s.success())
|
||||
.unwrap_or(false)
|
||||
.ok()?;
|
||||
// npm list --json may exit non-zero when package is missing, but still
|
||||
// outputs valid JSON with an empty dependencies object.
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let json: serde_json::Value = serde_json::from_str(&stdout).ok()?;
|
||||
let version = json
|
||||
.get("dependencies")?
|
||||
.get(package_name)?
|
||||
.get("version")?
|
||||
.as_str()?;
|
||||
normalize_version_candidate(version)
|
||||
}
|
||||
|
||||
async fn detect_local_version(agent_type: AgentType) -> Option<String> {
|
||||
let meta = registry::get_agent_meta(agent_type);
|
||||
match meta.distribution {
|
||||
registry::AgentDistribution::Npx { cmd, package, .. } => {
|
||||
if is_cmd_available(cmd).await {
|
||||
version_from_package_spec(package)
|
||||
} else {
|
||||
None
|
||||
if !is_cmd_available(cmd) {
|
||||
return None;
|
||||
}
|
||||
// Try `npm list -g <package_name> --json` to get the real installed version.
|
||||
let pkg_name = package_name_from_spec(package);
|
||||
if let Some(v) = detect_npm_global_version(&pkg_name).await {
|
||||
return Some(v);
|
||||
}
|
||||
// Fallback: parse version from registry package spec
|
||||
version_from_package_spec(package)
|
||||
}
|
||||
registry::AgentDistribution::Binary { cmd, .. } => {
|
||||
binary_cache::detect_installed_version(agent_type, cmd)
|
||||
@@ -1047,7 +1065,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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "codeg",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.3",
|
||||
"identifier": "app.codeg",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
||||
Reference in New Issue
Block a user