agentgui 1.0.1126 → 1.0.1127

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of agentgui might be problematic. Click here for more details.

Files changed (170) hide show
  1. package/.gm/browser-config.json +1 -0
  2. package/.gm/disciplines/agentgui/mem-1779277005143-0-1352.json +1 -0
  3. package/.gm/disciplines/agentgui/memories/.flat-export-done +0 -0
  4. package/.gm/disciplines/agentgui/memories/mem-c07fa3b0836edbe2-1352.md +8 -0
  5. package/.gm/gm.db +0 -0
  6. package/.gm/memories/.flat-export-done +1 -0
  7. package/.gm/memories/mem-0131ff4869d86085-370.md +10 -0
  8. package/.gm/memories/mem-04049d11cb8c1661-2135.md +8 -0
  9. package/.gm/memories/mem-069ff10372ed1770-1375.md +8 -0
  10. package/.gm/memories/mem-08a4a9e050a4deff-3048.md +8 -0
  11. package/.gm/memories/mem-09597ee0df9c9224-965.md +8 -0
  12. package/.gm/memories/mem-0993d156f571b619-1059.md +8 -0
  13. package/.gm/memories/mem-0b681bf2340c8df1-3170.md +8 -0
  14. package/.gm/memories/mem-0c444abde86202f6-1681.md +8 -0
  15. package/.gm/memories/mem-0d1408fa048b9923-1159.md +8 -0
  16. package/.gm/memories/mem-0dad5d82fec829ba-887.md +8 -0
  17. package/.gm/memories/mem-10a776effb7ce3a6-935.md +8 -0
  18. package/.gm/memories/mem-10d264b4f8e66fb4-1492.md +8 -0
  19. package/.gm/memories/mem-118c35ac67541d98-2909.md +8 -0
  20. package/.gm/memories/mem-119cf70dd19aa0a5-2225.md +8 -0
  21. package/.gm/memories/mem-15a07cd761b337c4-4320.md +8 -0
  22. package/.gm/memories/mem-15c73aca528535cb-2183.md +8 -0
  23. package/.gm/memories/mem-166f52796185e0e7-1487.md +8 -0
  24. package/.gm/memories/mem-1a148cf9c3126df5-3963.md +8 -0
  25. package/.gm/memories/mem-1a459001058f618e-567.md +8 -0
  26. package/.gm/memories/mem-1af3e13f7618e668-2146.md +8 -0
  27. package/.gm/memories/mem-1fd31d6873e9c164-794.md +8 -0
  28. package/.gm/memories/mem-21f551be092fd77d-2340.md +8 -0
  29. package/.gm/memories/mem-231ff5de003f20f0-586.md +8 -0
  30. package/.gm/memories/mem-2567393d3adb03ab-347.md +8 -0
  31. package/.gm/memories/mem-27faf41cdd050c80-1261.md +8 -0
  32. package/.gm/memories/mem-28889e43e8ce64cc-3663.md +8 -0
  33. package/.gm/memories/mem-2f4fd06515abf439-2562.md +8 -0
  34. package/.gm/memories/mem-34a749430303c5f7-544.md +8 -0
  35. package/.gm/memories/mem-3602d11d7bce9446-1057.md +8 -0
  36. package/.gm/memories/mem-38b7e24dbcba2f3e-639.md +8 -0
  37. package/.gm/memories/mem-39a7cc2f887a90b1-1079.md +8 -0
  38. package/.gm/memories/mem-40d6169c8759061d-806.md +8 -0
  39. package/.gm/memories/mem-4420e6d00e5c8632-2318.md +8 -0
  40. package/.gm/memories/mem-447e5a54ddc9357a-654.md +8 -0
  41. package/.gm/memories/mem-455b3beb4afabe14-591.md +8 -0
  42. package/.gm/memories/mem-4845ee594759151c-560.md +8 -0
  43. package/.gm/memories/mem-4a1254c60b868b88-374.md +8 -0
  44. package/.gm/memories/mem-4bafafa47a0e4b6c-3237.md +8 -0
  45. package/.gm/memories/mem-4c06c45b4d31bc60-1202.md +8 -0
  46. package/.gm/memories/mem-4dfac801d0378448-3676.md +8 -0
  47. package/.gm/memories/mem-4ecd3b713e384170-122.md +10 -0
  48. package/.gm/memories/mem-51d8992a3c6f6c9c-1073.md +8 -0
  49. package/.gm/memories/mem-539eee7e8c6c10ee-2557.md +8 -0
  50. package/.gm/memories/mem-559b8b2abc4b1091-1665.md +8 -0
  51. package/.gm/memories/mem-59dd73a463e54948-871.md +8 -0
  52. package/.gm/memories/mem-5b99b882ffe1a3c2-2262.md +8 -0
  53. package/.gm/memories/mem-5feb252a5244149c-1791.md +8 -0
  54. package/.gm/memories/mem-6224f8d185797f2b-1047.md +8 -0
  55. package/.gm/memories/mem-6434ee8261a6a6a2-3126.md +8 -0
  56. package/.gm/memories/mem-66b0947b946f3437-1155.md +8 -0
  57. package/.gm/memories/mem-6bdf783a1f6be7c2-1062.md +8 -0
  58. package/.gm/memories/mem-6d49f08bebac54c9-744.md +8 -0
  59. package/.gm/memories/mem-70d96acb736af2d7-685.md +8 -0
  60. package/.gm/memories/mem-70de7d5e71fcd439-2680.md +8 -0
  61. package/.gm/memories/mem-713614f12d7029da-1577.md +8 -0
  62. package/.gm/memories/mem-720d76c88e64f6ee-1967.md +8 -0
  63. package/.gm/memories/mem-7535f34f430fc196-1340.md +8 -0
  64. package/.gm/memories/mem-861a588d2773681a-1311.md +8 -0
  65. package/.gm/memories/mem-8af7980a92e09959-891.md +8 -0
  66. package/.gm/memories/mem-8b438ef4c609b7af-401.md +8 -0
  67. package/.gm/memories/mem-8f59884039787ef3-743.md +8 -0
  68. package/.gm/memories/mem-92b199c2024ee1aa-2513.md +8 -0
  69. package/.gm/memories/mem-9329105b05b9c0f6-324.md +10 -0
  70. package/.gm/memories/mem-94f30cec3c283f97-782.md +10 -0
  71. package/.gm/memories/mem-956d4813319f65a3-1710.md +8 -0
  72. package/.gm/memories/mem-96fffbb6615e031b-1263.md +8 -0
  73. package/.gm/memories/mem-993ab31f7a10aefa-718.md +8 -0
  74. package/.gm/memories/mem-a3e440db285f655a-995.md +8 -0
  75. package/.gm/memories/mem-a52933cd6495e6f5-2624.md +8 -0
  76. package/.gm/memories/mem-a86426ac44138c96-1606.md +8 -0
  77. package/.gm/memories/mem-a95b1d49d71133ce-1007.md +8 -0
  78. package/.gm/memories/mem-a9968a186368b022-1150.md +8 -0
  79. package/.gm/memories/mem-aaeae38d8eb01809-1076.md +8 -0
  80. package/.gm/memories/mem-ade01d9c02677c55-1557.md +8 -0
  81. package/.gm/memories/mem-b06b8c85b81663e6-1250.md +8 -0
  82. package/.gm/memories/mem-b451e5e17e555202-1490.md +8 -0
  83. package/.gm/memories/mem-b64ad00dcb6f909e-937.md +8 -0
  84. package/.gm/memories/mem-b7d6018ceca55b6f-2220.md +8 -0
  85. package/.gm/memories/mem-bdf466854032cac9-1509.md +8 -0
  86. package/.gm/memories/mem-c0482039e6ab4c50-2047.md +8 -0
  87. package/.gm/memories/mem-c4aaec5c4e6f80c2-920.md +8 -0
  88. package/.gm/memories/mem-c66976ddacb4fbe8-1454.md +8 -0
  89. package/.gm/memories/mem-c7c5bc263850c332-1844.md +8 -0
  90. package/.gm/memories/mem-cda639547932c796-713.md +8 -0
  91. package/.gm/memories/mem-cdf04ff6a6a0aa6f-671.md +8 -0
  92. package/.gm/memories/mem-cf8472c84d9e04c4-1883.md +8 -0
  93. package/.gm/memories/mem-cfd4d894370c63c3-1288.md +8 -0
  94. package/.gm/memories/mem-d060480435f92eec-1146.md +8 -0
  95. package/.gm/memories/mem-d347c921b79e6d44-1099.md +8 -0
  96. package/.gm/memories/mem-d3c8ea6c861bfbb8-1457.md +8 -0
  97. package/.gm/memories/mem-d5e928c552cd87f9-214.md +10 -0
  98. package/.gm/memories/mem-d63bc3b8a0269844-406.md +10 -0
  99. package/.gm/memories/mem-d9c19257abc2fa5e-1061.md +8 -0
  100. package/.gm/memories/mem-d9f26358a7cd3bb8-866.md +8 -0
  101. package/.gm/memories/mem-da1c91acf63d81d3-863.md +8 -0
  102. package/.gm/memories/mem-dc1ac3b04d22317e-664.md +8 -0
  103. package/.gm/memories/mem-dceeae20bc56d407-711.md +8 -0
  104. package/.gm/memories/mem-dd98b21c0896dc04-1557.md +8 -0
  105. package/.gm/memories/mem-df74674eec7745ac-178.md +10 -0
  106. package/.gm/memories/mem-dfe3b466fd5d1199-802.md +8 -0
  107. package/.gm/memories/mem-e0f9286aed2d5a06-1116.md +8 -0
  108. package/.gm/memories/mem-e1950b064099b7be-1895.md +8 -0
  109. package/.gm/memories/mem-e1d5431ae2542872-961.md +8 -0
  110. package/.gm/memories/mem-e490a181de6469fc-487.md +8 -0
  111. package/.gm/memories/mem-e72c6efbb27326fb-392.md +8 -0
  112. package/.gm/memories/mem-e943b58115a02b4c-593.md +8 -0
  113. package/.gm/memories/mem-e9bc5f9ed6edbcf7-1580.md +8 -0
  114. package/.gm/memories/mem-eae1e383927854fb-2649.md +8 -0
  115. package/.gm/memories/mem-ebbe6c0694c526f0-1392.md +8 -0
  116. package/.gm/memories/mem-ebf85becc23410b0-1633.md +8 -0
  117. package/.gm/memories/mem-ee0596fa17c7102e-362.md +10 -0
  118. package/.gm/memories/mem-ee4450fbc311b583-1361.md +8 -0
  119. package/.gm/memories/mem-ee8858162518f144-1252.md +8 -0
  120. package/.gm/memories/mem-f3297e82df622649-1166.md +8 -0
  121. package/.gm/memories/mem-f3f317c083d979ee-1210.md +8 -0
  122. package/.gm/memories/mem-f714a86465fba158-2041.md +8 -0
  123. package/.gm/memories/mem-f786bc1626d92845-204.md +10 -0
  124. package/.gm/memories/mem-f9f0dc8895b21e18-1217.md +8 -0
  125. package/.gm/memories/mem-fb3b2a7395800041-525.md +8 -0
  126. package/.gm/memories/mem-fc5753f92ee7d654-966.md +8 -0
  127. package/.gm/memories/mem-fe3faa1652f07239-480.md +8 -0
  128. package/.gm/memories/mem-ff8669e527e5c427-2788.md +8 -0
  129. package/.gm/mutables.yml +53 -0
  130. package/.gm/prd.yml +3342 -1
  131. package/AGENTS.md +122 -122
  132. package/UX_OPTIMIZATION_SUMMARY.md +238 -0
  133. package/agentgui-after.png +0 -0
  134. package/agentgui-current.png +0 -0
  135. package/agentgui-final.png +0 -0
  136. package/agentgui-nobrand.png +0 -0
  137. package/agentgui-now.png +0 -0
  138. package/agentgui-v2.png +0 -0
  139. package/agentgui-v4.png +0 -0
  140. package/bash.exe.stackdump +28 -0
  141. package/database.js +110 -109
  142. package/design-reference.png +0 -0
  143. package/lib/acp-sdk-manager.js +9 -42
  144. package/lib/claude-runner-acp.js +155 -213
  145. package/lib/claude-runner-agents.js +157 -170
  146. package/lib/http-handler.js +931 -400
  147. package/lib/ws-handlers-util.js +466 -11
  148. package/package.json +1 -1
  149. package/site/app/js/app.js +4741 -4221
  150. package/site/app/js/backend.js +602 -621
  151. package/site/app/vendor/anentrypoint-design/247420.css +13673 -14799
  152. package/site/app/vendor/anentrypoint-design/247420.js +449 -735
  153. package/.gm/.embed-generation.code_chunks +0 -1
  154. package/.gm/.embed-generation.git_commit_vectors +0 -1
  155. package/.gm/.embed-generation.memories +0 -1
  156. package/.gm/.embed-generation.rssearch_vectors +0 -1
  157. package/lib/acp-http-protocol.js +0 -95
  158. package/lib/http-routes/mutations.js +0 -199
  159. package/lib/http-routes/reads.js +0 -212
  160. package/lib/http-routes/shared.js +0 -225
  161. package/lib/ws-handlers/agents.js +0 -137
  162. package/lib/ws-handlers/chat.js +0 -157
  163. package/lib/ws-handlers/git.js +0 -159
  164. package/lib/ws-handlers/misc.js +0 -36
  165. package/lib/ws-handlers/shared.js +0 -47
  166. package/lib/ws-handlers/terminal-state.js +0 -16
  167. package/site/app/js/chat-persistence.js +0 -123
  168. package/site/app/js/hash-routing.js +0 -62
  169. package/site/app/js/history.js +0 -435
  170. package/site/app/js/shortcuts.js +0 -128
@@ -1,170 +1,157 @@
1
- import { spawnSync } from 'child_process';
2
- import { AgentRunner } from './claude-runner.js';
3
- import { acpProtocolHandler } from './acp-protocol.js';
4
- import './claude-runner-direct.js';
5
- import './claude-runner-acp.js';
6
-
7
- const isWindows = process.platform === 'win32';
8
-
9
- export class AgentRegistry {
10
- constructor() { this.agents = new Map(); }
11
-
12
- register(config) {
13
- const runner = new AgentRunner(config);
14
- this.agents.set(config.id, runner);
15
- return runner;
16
- }
17
-
18
- get(agentId) { return this.agents.get(agentId); }
19
- has(agentId) { return this.agents.has(agentId); }
20
-
21
- list() {
22
- return Array.from(this.agents.values()).map(a => ({
23
- id: a.id, name: a.name, command: a.command, protocol: a.protocol,
24
- requiresAdapter: a.requiresAdapter, supportedFeatures: a.supportedFeatures, npxPackage: a.npxPackage
25
- }));
26
- }
27
-
28
- isAvailable(agentId) {
29
- if (!this._availCache) this._availCache = new Map();
30
- if (this._availCache.has(agentId)) return this._availCache.get(agentId);
31
- const a = this.agents.get(agentId);
32
- if (!a) return false;
33
- let ok = false;
34
- try {
35
- const whichCmd = isWindows ? 'where' : 'which';
36
- const which = spawnSync(whichCmd, [a.command], { encoding: 'utf-8', timeout: 3000 });
37
- if (which.status === 0 && (which.stdout || '').trim()) ok = true;
38
- if (!ok && a.npxPackage) {
39
- ok = ['bun', 'npx'].some(r => {
40
- const c = spawnSync(whichCmd, [r], { encoding: 'utf-8', timeout: 3000 });
41
- return c.status === 0 && (c.stdout || '').trim();
42
- });
43
- }
44
- } catch { ok = false; }
45
- this._availCache.set(agentId, ok);
46
- return ok;
47
- }
48
-
49
- listWithAvailability() {
50
- return this.list().map(a => ({ ...a, available: this.isAvailable(a.id), npxInstallable: !!a.npxPackage }));
51
- }
52
-
53
- listACPAvailable() {
54
- return this.list().filter(agent => {
55
- try {
56
- const whichCmd = isWindows ? 'where' : 'which';
57
- const which = spawnSync(whichCmd, [agent.command], { encoding: 'utf-8', timeout: 3000 });
58
- if (which.status === 0) {
59
- const binPath = (which.stdout || '').trim().split('\n')[0].trim();
60
- if (binPath) {
61
- const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000, shell: isWindows });
62
- if (check.status === 0 && (check.stdout || '').trim().length > 0) return true;
63
- }
64
- }
65
- const a = this.agents.get(agent.id);
66
- if (a && a.npxPackage) {
67
- const npxCheck = spawnSync(whichCmd, ['npx'], { encoding: 'utf-8', timeout: 3000 });
68
- if (npxCheck.status === 0) return true;
69
- const bunCheck = spawnSync(whichCmd, ['bun'], { encoding: 'utf-8', timeout: 3000 });
70
- if (bunCheck.status === 0) return true;
71
- }
72
- return false;
73
- } catch { return false; }
74
- });
75
- }
76
- }
77
-
78
- export const registry = new AgentRegistry();
79
-
80
- function parseClaudeOutput(line) {
81
- try {
82
- const entry = JSON.parse(line);
83
- if (!entry || typeof entry !== 'object') return null;
84
- if (entry.type === 'user' && entry.isMeta === true) return null;
85
- if (entry.isApiErrorMessage === true && entry.error === 'rate_limit') entry._rateLimitDetected = true;
86
- if (entry.type === 'assistant' && entry.message) entry._isFragment = entry.message.stop_reason === null || entry.message.stop_reason === undefined;
87
- if (entry.type === 'system' && entry.subtype === 'turn_duration' && entry.durationMs) entry._turnDurationMs = entry.durationMs;
88
- if (entry.type === 'system' && entry.subtype === 'compact_boundary' && entry.compactMetadata) entry._preTokens = entry.compactMetadata.preTokens;
89
- if (entry.message?.usage) {
90
- const u = entry.message.usage;
91
- entry._cacheUsage = { cache_creation: u.cache_creation_input_tokens || u['cache_creation.ephemeral_1h_input_tokens'] || u['cache_creation.ephemeral_5m_input_tokens'] || 0, cache_read: u.cache_read_input_tokens || 0 };
92
- }
93
- return entry;
94
- } catch { return null; }
95
- }
96
-
97
- registry.register({
98
- id: 'claude-code', name: 'Claude Code', command: 'claude', protocol: 'direct', supportsStdin: false, closeStdin: true,
99
- useJsonRpcStdin: false, supportedFeatures: ['streaming', 'resume', 'system-prompt', 'permissions-skip', 'steering'],
100
- // claude has an npx fallback (matches agent-discovery), so when `where claude`
101
- // misses a non-PATH install the agent still reports as runnable rather than
102
- // "(not installed)".
103
- npxPackage: '@anthropic-ai/claude-code',
104
- spawnEnv: { MAX_THINKING_TOKENS: '0', AGENTGUI_SUBPROCESS: '1' },
105
- buildArgs(prompt, config) {
106
- const { verbose = true, outputFormat = 'stream-json', print = true, resumeSessionId = null, systemPrompt = null, model = null } = config;
107
- const flags = [];
108
- if (print) flags.push('--print');
109
- if (verbose) flags.push('--verbose');
110
- flags.push(`--output-format=${outputFormat}`);
111
- if (model) flags.push('--model', model);
112
- if (resumeSessionId) flags.push('--resume', resumeSessionId);
113
- if (systemPrompt) flags.push('--append-system-prompt', systemPrompt);
114
- flags.push('--dangerously-skip-permissions');
115
- flags.push(typeof prompt === 'string' ? prompt : String(prompt));
116
- return flags;
117
- },
118
- parseOutput: parseClaudeOutput
119
- });
120
-
121
- // Antigravity (`agy`): a direct-protocol CLI like claude-code, but emits PLAIN
122
- // TEXT (no stream-json, no model flag, no printed session_id). Each stdout line
123
- // is wrapped into the assistant-text event the non-JSONL stream handler expects.
124
- // Resume uses --continue (most-recent conversation) since agy prints no session id.
125
- registry.register({
126
- id: 'agy', name: 'Antigravity', command: 'agy', protocol: 'direct',
127
- supportsStdin: false, closeStdin: true,
128
- supportedFeatures: ['streaming', 'resume'],
129
- spawnEnv: { AGENTGUI_SUBPROCESS: '1' },
130
- buildArgs(prompt, config) {
131
- const { resumeSessionId = null } = config;
132
- // agy's --print is a VALUE flag (the prompt is its argument), not a boolean
133
- // followed by a positional. A positional prompt exits with code 2.
134
- const flags = ['--print', typeof prompt === 'string' ? prompt : String(prompt), '--dangerously-skip-permissions'];
135
- if (resumeSessionId) flags.push('--continue');
136
- return flags;
137
- },
138
- parseOutput(line) {
139
- const text = line.replace(/\r$/, '');
140
- if (!text.trim()) return null;
141
- return { type: 'assistant', message: { content: [{ type: 'text', text }] } };
142
- },
143
- });
144
- // transport:'http' routes runACP through AgentRunner._runACPHttp (reuses the
145
- // long-lived server acp-sdk-manager.js already spawns for health/model
146
- // discovery) instead of spawning a fresh stdio subprocess per turn -
147
- // live-verified equivalent to the stdio path (same prompt, byte-identical
148
- // final assistant text, side-by-side witnessed). kilo is NOT flagged here:
149
- // its HTTP event shape was never independently live-verified this session.
150
- registry.register({ id: 'opencode', name: 'OpenCode', command: 'opencode', protocol: 'acp', transport: 'http', supportsStdin: false, npxPackage: 'opencode-ai', supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
151
- registry.register({ id: 'gemini', name: 'Gemini CLI', command: 'gemini', protocol: 'acp', supportsStdin: false, npxPackage: '@google/gemini-cli', supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs(prompt, config) { const args = ['--experimental-acp', '--yolo']; if (config?.model) args.push('--model', config.model); return args; }, protocolHandler: acpProtocolHandler });
152
- registry.register({ id: 'goose', name: 'Goose', command: 'goose', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
153
- registry.register({ id: 'openhands', name: 'OpenHands', command: 'openhands', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
154
- registry.register({ id: 'augment', name: 'Augment Code', command: 'augment', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
155
- registry.register({ id: 'cline', name: 'Cline', command: 'cline', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
156
- registry.register({ id: 'kimi', name: 'Kimi CLI', command: 'kimi', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
157
- registry.register({ id: 'qwen', name: 'Qwen Code', command: 'qwen-code', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
158
- // codex (@openai/codex >=0.147.0) has no `acp` subcommand - live-confirmed
159
- // via `codex --help`/`codex app-server --help`: `codex acp` is parsed as the
160
- // interactive TUI with prompt text "acp" and errors "stdin is not a
161
- // terminal" non-interactively. Its ACP-equivalent is `app-server` over a
162
- // WebSocket, a different transport this stdio-JSON-RPC runner cannot drive.
163
- // Registering it with buildArgs:()=>['acp'] would spawn a command that can
164
- // never succeed. Disabled until a WebSocket app-server client exists (see
165
- // PRD row aaa-codex-app-server-client).
166
- registry.register({ id: 'mistral', name: 'Mistral Vibe', command: 'mistral-vibe', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
167
- registry.register({ id: 'kiro', name: 'Kiro CLI', command: 'kiro', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
168
- registry.register({ id: 'fast-agent', name: 'fast-agent', command: 'fast-agent', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
169
- registry.register({ id: 'kilo', name: 'Kilo CLI', command: 'kilo', protocol: 'acp', supportsStdin: false, npxPackage: '@kilocode/cli', supportedFeatures: ['streaming', 'resume', 'acp-protocol', 'models'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
170
- registry.register({ id: 'hermes', name: 'Hermes Agent', command: 'hermes', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
1
+ import { spawnSync } from 'child_process';
2
+ import { AgentRunner } from './claude-runner.js';
3
+ import { acpProtocolHandler } from './acp-protocol.js';
4
+ import './claude-runner-direct.js';
5
+ import './claude-runner-acp.js';
6
+
7
+ const isWindows = process.platform === 'win32';
8
+
9
+ export class AgentRegistry {
10
+ constructor() { this.agents = new Map(); }
11
+
12
+ register(config) {
13
+ const runner = new AgentRunner(config);
14
+ this.agents.set(config.id, runner);
15
+ return runner;
16
+ }
17
+
18
+ get(agentId) { return this.agents.get(agentId); }
19
+ has(agentId) { return this.agents.has(agentId); }
20
+
21
+ list() {
22
+ return Array.from(this.agents.values()).map(a => ({
23
+ id: a.id, name: a.name, command: a.command, protocol: a.protocol,
24
+ requiresAdapter: a.requiresAdapter, supportedFeatures: a.supportedFeatures, npxPackage: a.npxPackage
25
+ }));
26
+ }
27
+
28
+ isAvailable(agentId) {
29
+ if (!this._availCache) this._availCache = new Map();
30
+ if (this._availCache.has(agentId)) return this._availCache.get(agentId);
31
+ const a = this.agents.get(agentId);
32
+ if (!a) return false;
33
+ let ok = false;
34
+ try {
35
+ const whichCmd = isWindows ? 'where' : 'which';
36
+ const which = spawnSync(whichCmd, [a.command], { encoding: 'utf-8', timeout: 3000 });
37
+ if (which.status === 0 && (which.stdout || '').trim()) ok = true;
38
+ if (!ok && a.npxPackage) {
39
+ ok = ['bun', 'npx'].some(r => {
40
+ const c = spawnSync(whichCmd, [r], { encoding: 'utf-8', timeout: 3000 });
41
+ return c.status === 0 && (c.stdout || '').trim();
42
+ });
43
+ }
44
+ } catch { ok = false; }
45
+ this._availCache.set(agentId, ok);
46
+ return ok;
47
+ }
48
+
49
+ listWithAvailability() {
50
+ return this.list().map(a => ({ ...a, available: this.isAvailable(a.id), npxInstallable: !!a.npxPackage }));
51
+ }
52
+
53
+ listACPAvailable() {
54
+ return this.list().filter(agent => {
55
+ try {
56
+ const whichCmd = isWindows ? 'where' : 'which';
57
+ const which = spawnSync(whichCmd, [agent.command], { encoding: 'utf-8', timeout: 3000 });
58
+ if (which.status === 0) {
59
+ const binPath = (which.stdout || '').trim().split('\n')[0].trim();
60
+ if (binPath) {
61
+ const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000, shell: isWindows });
62
+ if (check.status === 0 && (check.stdout || '').trim().length > 0) return true;
63
+ }
64
+ }
65
+ const a = this.agents.get(agent.id);
66
+ if (a && a.npxPackage) {
67
+ const npxCheck = spawnSync(whichCmd, ['npx'], { encoding: 'utf-8', timeout: 3000 });
68
+ if (npxCheck.status === 0) return true;
69
+ const bunCheck = spawnSync(whichCmd, ['bun'], { encoding: 'utf-8', timeout: 3000 });
70
+ if (bunCheck.status === 0) return true;
71
+ }
72
+ return false;
73
+ } catch { return false; }
74
+ });
75
+ }
76
+ }
77
+
78
+ export const registry = new AgentRegistry();
79
+
80
+ function parseClaudeOutput(line) {
81
+ try {
82
+ const entry = JSON.parse(line);
83
+ if (!entry || typeof entry !== 'object') return null;
84
+ if (entry.type === 'user' && entry.isMeta === true) return null;
85
+ if (entry.isApiErrorMessage === true && entry.error === 'rate_limit') entry._rateLimitDetected = true;
86
+ if (entry.type === 'assistant' && entry.message) entry._isFragment = entry.message.stop_reason === null || entry.message.stop_reason === undefined;
87
+ if (entry.type === 'system' && entry.subtype === 'turn_duration' && entry.durationMs) entry._turnDurationMs = entry.durationMs;
88
+ if (entry.type === 'system' && entry.subtype === 'compact_boundary' && entry.compactMetadata) entry._preTokens = entry.compactMetadata.preTokens;
89
+ if (entry.message?.usage) {
90
+ const u = entry.message.usage;
91
+ entry._cacheUsage = { cache_creation: u.cache_creation_input_tokens || u['cache_creation.ephemeral_1h_input_tokens'] || u['cache_creation.ephemeral_5m_input_tokens'] || 0, cache_read: u.cache_read_input_tokens || 0 };
92
+ }
93
+ return entry;
94
+ } catch { return null; }
95
+ }
96
+
97
+ registry.register({
98
+ id: 'claude-code', name: 'Claude Code', command: 'claude', protocol: 'direct', supportsStdin: false, closeStdin: true,
99
+ useJsonRpcStdin: false, supportedFeatures: ['streaming', 'resume', 'system-prompt', 'permissions-skip', 'steering'],
100
+ // claude has an npx fallback (matches agent-discovery), so when `where claude`
101
+ // misses a non-PATH install the agent still reports as runnable rather than
102
+ // "(not installed)".
103
+ npxPackage: '@anthropic-ai/claude-code',
104
+ spawnEnv: { MAX_THINKING_TOKENS: '0', AGENTGUI_SUBPROCESS: '1' },
105
+ buildArgs(prompt, config) {
106
+ const { verbose = true, outputFormat = 'stream-json', print = true, resumeSessionId = null, systemPrompt = null, model = null } = config;
107
+ const flags = [];
108
+ if (print) flags.push('--print');
109
+ if (verbose) flags.push('--verbose');
110
+ flags.push(`--output-format=${outputFormat}`);
111
+ if (model) flags.push('--model', model);
112
+ if (resumeSessionId) flags.push('--resume', resumeSessionId);
113
+ if (systemPrompt) flags.push('--append-system-prompt', systemPrompt);
114
+ flags.push('--dangerously-skip-permissions');
115
+ flags.push(typeof prompt === 'string' ? prompt : String(prompt));
116
+ return flags;
117
+ },
118
+ parseOutput: parseClaudeOutput
119
+ });
120
+
121
+ // Antigravity (`agy`): a direct-protocol CLI like claude-code, but emits PLAIN
122
+ // TEXT (no stream-json, no model flag, no printed session_id). Each stdout line
123
+ // is wrapped into the assistant-text event the non-JSONL stream handler expects.
124
+ // Resume uses --continue (most-recent conversation) since agy prints no session id.
125
+ registry.register({
126
+ id: 'agy', name: 'Antigravity', command: 'agy', protocol: 'direct',
127
+ supportsStdin: false, closeStdin: true,
128
+ supportedFeatures: ['streaming', 'resume'],
129
+ spawnEnv: { AGENTGUI_SUBPROCESS: '1' },
130
+ buildArgs(prompt, config) {
131
+ const { resumeSessionId = null } = config;
132
+ // agy's --print is a VALUE flag (the prompt is its argument), not a boolean
133
+ // followed by a positional. A positional prompt exits with code 2.
134
+ const flags = ['--print', typeof prompt === 'string' ? prompt : String(prompt), '--dangerously-skip-permissions'];
135
+ if (resumeSessionId) flags.push('--continue');
136
+ return flags;
137
+ },
138
+ parseOutput(line) {
139
+ const text = line.replace(/\r$/, '');
140
+ if (!text.trim()) return null;
141
+ return { type: 'assistant', message: { content: [{ type: 'text', text }] } };
142
+ },
143
+ });
144
+ registry.register({ id: 'opencode', name: 'OpenCode', command: 'opencode', protocol: 'acp', supportsStdin: false, npxPackage: 'opencode-ai', supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
145
+ registry.register({ id: 'gemini', name: 'Gemini CLI', command: 'gemini', protocol: 'acp', supportsStdin: false, npxPackage: '@google/gemini-cli', supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs(prompt, config) { const args = ['--experimental-acp', '--yolo']; if (config?.model) args.push('--model', config.model); return args; }, protocolHandler: acpProtocolHandler });
146
+ registry.register({ id: 'goose', name: 'Goose', command: 'goose', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
147
+ registry.register({ id: 'openhands', name: 'OpenHands', command: 'openhands', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
148
+ registry.register({ id: 'augment', name: 'Augment Code', command: 'augment', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
149
+ registry.register({ id: 'cline', name: 'Cline', command: 'cline', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
150
+ registry.register({ id: 'kimi', name: 'Kimi CLI', command: 'kimi', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
151
+ registry.register({ id: 'qwen', name: 'Qwen Code', command: 'qwen-code', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
152
+ registry.register({ id: 'codex', name: 'Codex CLI', command: 'codex', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
153
+ registry.register({ id: 'mistral', name: 'Mistral Vibe', command: 'mistral-vibe', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
154
+ registry.register({ id: 'kiro', name: 'Kiro CLI', command: 'kiro', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
155
+ registry.register({ id: 'fast-agent', name: 'fast-agent', command: 'fast-agent', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
156
+ registry.register({ id: 'kilo', name: 'Kilo CLI', command: 'kilo', protocol: 'acp', supportsStdin: false, npxPackage: '@kilocode/cli', supportedFeatures: ['streaming', 'resume', 'acp-protocol', 'models'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });
157
+ registry.register({ id: 'hermes', name: 'Hermes Agent', command: 'hermes', protocol: 'acp', supportsStdin: false, supportedFeatures: ['streaming', 'resume', 'acp-protocol'], buildArgs: () => ['acp'], protocolHandler: acpProtocolHandler });