Wave 3: 补齐九个适配器(Qwen/CodeBuddy/Cline/Copilot/Crush/Goose/Aider/Cursor/Warp)

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
leefer
2026-08-25 19:13:37 +08:00
co-authored by multica-agent
parent 4a2be5899d
commit b0d7124170
13 changed files with 1345 additions and 193 deletions
+25
View File
@@ -1534,6 +1534,31 @@ configuration:
}
}
/// 真机检测记录:对 Wave 3 九个新工具逐项 detect 并打印结果(自测记录用)。
/// 运行:cargo test -p agentdock-core real_machine_detect_wave3 -- --ignored --nocapture
#[test]
#[ignore]
fn real_machine_detect_wave3() {
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../adapters");
let adapters = load_adapters(&dir).expect("适配器目录应可加载");
let nine = ["qwen", "codebuddy", "cline", "copilot", "crush", "goose", "aider", "cursor", "warp"];
for id in nine {
let Some(adapter) = adapters.iter().find(|a| a.id == id) else {
panic!("缺少 {id}");
};
let r = detect_one(adapter);
println!(
"{} ({}): status={} version={:?} exe={:?}",
id, adapter.name_zh, r.status, r.version, r.executable
);
assert!([
"installed", "not_installed", "not_in_path", "permission_denied",
"exec_failed", "version_unparseable",
]
.contains(&r.status.as_str()));
}
}
/// 真机安装/卸载往返:gemini(npm 渠道,用户目录、可逆)。
/// 运行:cargo test -p agentdock-core real_machine_install_uninstall_gemini -- --ignored --nocapture
#[test]
+27 -2
View File
@@ -22,6 +22,21 @@ pub fn runtime_for_prog(prog: &str) -> Option<&'static str> {
}
}
/// 运行时 id → 中文显示名(与前端 RuntimeInstallModal 的 RUNTIME_LABELS 对齐)。
/// 「node」统一显示为「Node.js」,避免人话提示里出现 id 与按钮文案不一致。
pub fn runtime_label_zh(id: &str) -> &'static str {
match id {
"node" => "Node.js",
"python" => "Python",
"git" => "Git",
"winget" => "winget",
"uv" => "uv",
"choco" => "choco",
"scoop" => "scoop",
_ => "运行时",
}
}
/// 主入口:结合 spawn 错误与 stderr 尾部文本,产出结构化错误提示。
/// `spawn_err` 为 `Command::spawn` 的 io::ErrorNone 表示进程已启动但退出非 0)。
pub fn map_exec_error(prog: &str, spawn_err: Option<&std::io::Error>, stderr_tail: &str) -> ErrorHint {
@@ -33,7 +48,7 @@ pub fn map_exec_error(prog: &str, spawn_err: Option<&std::io::Error>, stderr_tai
ErrorKind::NotFound => {
let missing = runtime_for_prog(prog);
let friendly = match missing {
Some(r) => format!("未找到 {prog} 命令:需要先安装 {r}(可在下方「本机环境」区一键安装)"),
Some(r) => format!("未找到 {prog} 命令:需要先安装 {}(可在下方「本机环境」区一键安装)", runtime_label_zh(r)),
None => format!("未找到 {prog} 命令:请确认 {prog} 已安装并加入 PATH"),
};
return ErrorHint {
@@ -102,7 +117,17 @@ mod tests {
let h = map_exec_error("npm", Some(&not_found()), "");
assert_eq!(h.code, "program_not_found");
assert_eq!(h.missing_runtime.as_deref(), Some("node"));
assert!(h.friendly_zh.contains("Node") || h.friendly_zh.contains("node"));
// 文案统一为「Node.js」(与按钮/运行时中文名一致,而非裸 id「node」)
assert!(h.friendly_zh.contains("Node.js"), "人话提示应显示 Node.js{}", h.friendly_zh);
assert!(!h.friendly_zh.contains("安装 node"), "不应出现裸 id「node」:{}", h.friendly_zh);
}
#[test]
fn runtime_label_zh_maps_node() {
assert_eq!(runtime_label_zh("node"), "Node.js");
assert_eq!(runtime_label_zh("python"), "Python");
assert_eq!(runtime_label_zh("git"), "Git");
assert_eq!(runtime_label_zh("winget"), "winget");
}
#[test]