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![
30 "-y".into(),
31 "@agentclientprotocol/claude-agent-acp@^0.24.2".into(),
32 ],
33 description: "Claude Code via ACP bridge".into(),
34 },
35 );
36 m.insert(
37 "codex".into(),
38 AgentEntry {
39 command: "npx".into(),
40 args: vec!["-y".into(), "@zed-industries/codex-acp@^0.10.0".into()],
41 description: "OpenAI Codex CLI".into(),
42 },
43 );
44 m.insert(
45 "pi".into(),
46 AgentEntry {
47 command: "npx".into(),
48 args: vec!["-y".into(), "pi-acp@^0.0.22".into()],
49 description: "Pi Coding Agent".into(),
50 },
51 );
52 m.insert(
53 "kilocode".into(),
54 AgentEntry {
55 command: "npx".into(),
56 args: vec!["-y".into(), "@kilocode/cli".into(), "acp".into()],
57 description: "Kilocode".into(),
58 },
59 );
60 m.insert(
61 "opencode".into(),
62 AgentEntry {
63 command: "npx".into(),
64 args: vec!["-y".into(), "opencode-ai".into(), "acp".into()],
65 description: "OpenCode".into(),
66 },
67 );
68
69 m.insert(
71 "gemini".into(),
72 AgentEntry {
73 command: "gemini".into(),
74 args: vec!["--acp".into()],
75 description: "Google Gemini CLI".into(),
76 },
77 );
78 m.insert(
79 "openclaw".into(),
80 AgentEntry {
81 command: "openclaw".into(),
82 args: vec!["acp".into()],
83 description: "OpenClaw".into(),
84 },
85 );
86 m.insert(
87 "cursor".into(),
88 AgentEntry {
89 command: "cursor-agent".into(),
90 args: vec!["acp".into()],
91 description: "Cursor".into(),
92 },
93 );
94 m.insert(
95 "copilot".into(),
96 AgentEntry {
97 command: "copilot".into(),
98 args: vec!["--acp".into(), "--stdio".into()],
99 description: "GitHub Copilot".into(),
100 },
101 );
102 m.insert(
103 "kiro".into(),
104 AgentEntry {
105 command: "kiro-cli-chat".into(),
106 args: vec!["acp".into()],
107 description: "Kiro CLI (AWS)".into(),
108 },
109 );
110 m.insert(
111 "iflow".into(),
112 AgentEntry {
113 command: "iflow".into(),
114 args: vec!["--experimental-acp".into()],
115 description: "iFlow ACP agent".into(),
116 },
117 );
118 m.insert(
119 "qoder".into(),
120 AgentEntry {
121 command: "qodercli".into(),
122 args: vec!["--acp".into()],
123 description: "Qoder CLI".into(),
124 },
125 );
126 m.insert(
127 "trae".into(),
128 AgentEntry {
129 command: "traecli".into(),
130 args: vec!["acp".into(), "serve".into()],
131 description: "Trae CLI".into(),
132 },
133 );
134 m.insert(
135 "kimi".into(),
136 AgentEntry {
137 command: "kimi".into(),
138 args: vec!["acp".into()],
139 description: "Kimi CLI".into(),
140 },
141 );
142 m.insert(
143 "qwen".into(),
144 AgentEntry {
145 command: "qwen".into(),
146 args: vec!["--acp".into()],
147 description: "Qwen Code".into(),
148 },
149 );
150 m.insert(
151 "droid".into(),
152 AgentEntry {
153 command: "droid".into(),
154 args: vec!["exec".into(), "--output-format".into(), "acp".into()],
155 description: "Factory Droid".into(),
156 },
157 );
158 m.insert(
159 "goose".into(),
160 AgentEntry {
161 command: "goose".into(),
162 args: vec!["acp".into()],
163 description: "Goose (Block)".into(),
164 },
165 );
166
167 m
168}
169
170pub fn resolve_agent(
177 name: &str,
178 registry: &HashMap<String, AgentEntry>,
179 overrides: &HashMap<String, AgentOverride>,
180) -> (String, Vec<String>) {
181 if let Some(ov) = overrides.get(name) {
182 return (ov.command.clone(), ov.args.clone());
183 }
184
185 if let Some(entry) = registry.get(name) {
186 return (entry.command.clone(), entry.args.clone());
187 }
188
189 (name.to_string(), Vec::new())
191}