1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone)]
6pub struct AgentEntry {
7 pub command: String,
8 pub args: Vec<String>,
9 pub description: String,
10}
11
12#[derive(Debug, Clone, Deserialize, Serialize)]
14pub struct AgentOverride {
15 pub command: String,
16 #[serde(default)]
17 pub args: Vec<String>,
18}
19
20pub fn default_registry() -> HashMap<String, AgentEntry> {
22 let mut m = HashMap::new();
23
24 m.insert(
26 "claude".into(),
27 AgentEntry {
28 command: "npx".into(),
29 args: vec!["-y".into(), "@zed-industries/claude-agent-acp".into()],
30 description: "Claude Code via ACP bridge".into(),
31 },
32 );
33 m.insert(
34 "codex".into(),
35 AgentEntry {
36 command: "npx".into(),
37 args: vec!["-y".into(), "@zed-industries/codex-acp".into()],
38 description: "OpenAI Codex CLI".into(),
39 },
40 );
41 m.insert(
42 "pi".into(),
43 AgentEntry {
44 command: "npx".into(),
45 args: vec!["-y".into(), "pi-acp".into()],
46 description: "Pi Coding Agent".into(),
47 },
48 );
49 m.insert(
50 "kilocode".into(),
51 AgentEntry {
52 command: "npx".into(),
53 args: vec!["-y".into(), "@kilocode/cli".into(), "acp".into()],
54 description: "Kilocode".into(),
55 },
56 );
57 m.insert(
58 "opencode".into(),
59 AgentEntry {
60 command: "npx".into(),
61 args: vec!["-y".into(), "opencode-ai".into(), "acp".into()],
62 description: "OpenCode".into(),
63 },
64 );
65
66 m.insert(
68 "gemini".into(),
69 AgentEntry {
70 command: "gemini".into(),
71 args: vec!["--acp".into()],
72 description: "Google Gemini CLI".into(),
73 },
74 );
75 m.insert(
76 "openclaw".into(),
77 AgentEntry {
78 command: "openclaw".into(),
79 args: vec!["acp".into()],
80 description: "OpenClaw".into(),
81 },
82 );
83 m.insert(
84 "cursor".into(),
85 AgentEntry {
86 command: "cursor-agent".into(),
87 args: vec!["acp".into()],
88 description: "Cursor".into(),
89 },
90 );
91 m.insert(
92 "copilot".into(),
93 AgentEntry {
94 command: "copilot".into(),
95 args: vec!["--acp".into(), "--stdio".into()],
96 description: "GitHub Copilot".into(),
97 },
98 );
99 m.insert(
100 "kiro".into(),
101 AgentEntry {
102 command: "kiro-cli".into(),
103 args: vec!["acp".into()],
104 description: "Kiro CLI (AWS)".into(),
105 },
106 );
107 m.insert(
108 "kimi".into(),
109 AgentEntry {
110 command: "kimi".into(),
111 args: vec!["acp".into()],
112 description: "Kimi CLI".into(),
113 },
114 );
115 m.insert(
116 "qwen".into(),
117 AgentEntry {
118 command: "qwen".into(),
119 args: vec!["--acp".into()],
120 description: "Qwen Code".into(),
121 },
122 );
123 m.insert(
124 "droid".into(),
125 AgentEntry {
126 command: "droid".into(),
127 args: vec!["exec".into(), "--output-format".into(), "acp".into()],
128 description: "Factory Droid".into(),
129 },
130 );
131 m.insert(
132 "goose".into(),
133 AgentEntry {
134 command: "goose".into(),
135 args: vec!["acp".into()],
136 description: "Goose (Block)".into(),
137 },
138 );
139
140 m
141}
142
143pub fn resolve_agent(
150 name: &str,
151 registry: &HashMap<String, AgentEntry>,
152 overrides: &HashMap<String, AgentOverride>,
153) -> (String, Vec<String>) {
154 if let Some(ov) = overrides.get(name) {
155 return (ov.command.clone(), ov.args.clone());
156 }
157
158 if let Some(entry) = registry.get(name) {
159 return (entry.command.clone(), entry.args.clone());
160 }
161
162 (name.to_string(), Vec::new())
164}