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,213 +1,155 @@
1
- import { spawn } from 'child_process';
2
- import { AgentRunner, getSpawnOptions, resolveCommand } from './claude-runner.js';
3
- import { ensureRunning as ensureAcpHttpRunning } from './acp-sdk-manager.js';
4
- import { createACPHttpProtocolHandler, parseSSEChunk } from './acp-http-protocol.js';
5
-
6
- function buildEnhancedHandler({ proc, outputs, sessionRef, promptIdRef, completedRef, drainingRef, requestIdRef, originalHandler, resolve, reject, clearTimeoutHandle, promptText }) {
7
- return function(message) {
8
- if (message.id && message.result && message.result.sessionId) {
9
- sessionRef.value = message.result.sessionId;
10
- promptIdRef.value = ++requestIdRef.value;
11
- proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: promptIdRef.value, method: 'session/prompt', params: { sessionId: sessionRef.value, prompt: [{ type: 'text', text: promptText }] } }) + '\n');
12
- return;
13
- }
14
- if (promptIdRef.value !== null && message.id === promptIdRef.value && message.result && message.result.stopReason) {
15
- completedRef.value = true; drainingRef.value = true;
16
- clearTimeoutHandle();
17
- setTimeout(() => { drainingRef.value = false; try { proc.kill(); } catch (e) {} resolve({ outputs, sessionId: sessionRef.value }); }, 1000);
18
- return;
19
- }
20
- if (promptIdRef.value !== null && message.id === promptIdRef.value && message.error) {
21
- completedRef.value = true; drainingRef.value = true;
22
- clearTimeoutHandle();
23
- originalHandler(message);
24
- setTimeout(() => { drainingRef.value = false; try { proc.kill(); } catch (e) {} reject(new Error(message.error.message || 'ACP prompt error')); }, 1000);
25
- return;
26
- }
27
- originalHandler(message);
28
- };
29
- }
30
-
31
- // opencode/kilo (registry entries with transport:'http') are live-verified
32
- // (lib/acp-http-protocol.js) to serve their normal REST+SSE API under `acp
33
- // --port`, already spawned as a long-lived server by acp-sdk-manager.js for
34
- // health/model discovery. This path reuses that same running server for the
35
- // actual prompt instead of spawning a fresh stdio subprocess per turn -
36
- // consolidating the two ACP process managers for these two agents only. The
37
- // other stdio-based ACP agents (gemini, goose, openhands, etc) are untouched.
38
- AgentRunner.prototype._runACPHttp = async function(prompt, cwd, config = {}) {
39
- const { timeout = 300000, onEvent = null } = config;
40
- const port = await ensureAcpHttpRunning(this.id);
41
- if (!port) { const e = new Error(`${this.name} ACP HTTP server not reachable`); e.isPrematureEnd = true; throw e; }
42
- const base = `http://127.0.0.1:${port}`;
43
- const sessionRes = await fetch(`${base}/session`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), signal: AbortSignal.timeout(10000) });
44
- if (!sessionRes.ok) throw new Error(`${this.name} ACP HTTP session create failed: ${sessionRes.status}`);
45
- const session = await sessionRes.json();
46
- const sessionId = session.id || session.sessionID;
47
- if (!sessionId) throw new Error(`${this.name} ACP HTTP session response missing id`);
48
-
49
- const handler = createACPHttpProtocolHandler();
50
- const outputs = [];
51
- const evController = new AbortController();
52
- const timeoutHandle = setTimeout(() => evController.abort(), timeout);
53
-
54
- const evPromise = fetch(`${base}/global/event`, { signal: evController.signal }).then(async (res) => {
55
- const reader = res.body.getReader();
56
- const decoder = new TextDecoder();
57
- let buffer = '';
58
- while (true) {
59
- const { value, done } = await reader.read();
60
- if (done) break;
61
- buffer += decoder.decode(value, { stream: true });
62
- const frames = parseSSEChunk(buffer);
63
- buffer = '';
64
- for (const frame of frames) {
65
- const normalized = handler(frame, { sessionId });
66
- if (!normalized) continue;
67
- outputs.push(normalized);
68
- if (onEvent) { try { onEvent(normalized); } catch (e) { console.error(`[${this.id}] onEvent error: ${e.message}`); } }
69
- if (normalized.type === 'result') { clearTimeout(timeoutHandle); return; }
70
- }
71
- }
72
- }).catch(() => {});
73
-
74
- const messageRes = await fetch(`${base}/session/${sessionId}/message`, {
75
- method: 'POST', headers: { 'Content-Type': 'application/json' },
76
- body: JSON.stringify({ parts: [{ type: 'text', text: prompt }] }),
77
- signal: AbortSignal.timeout(timeout),
78
- });
79
- if (!messageRes.ok) { evController.abort(); throw new Error(`${this.name} ACP HTTP message failed: ${messageRes.status}`); }
80
-
81
- await evPromise;
82
- evController.abort();
83
- return { outputs, sessionId };
84
- };
85
-
86
- AgentRunner.prototype.runACP = async function(prompt, cwd, config = {}, _retryCount = 0) {
87
- const maxRetries = config.maxRetries ?? 1;
88
- if (this.transport === 'http') return this._runACPHttp(prompt, cwd, config);
89
- try {
90
- return await this._runACPOnce(prompt, cwd, config);
91
- } catch (err) {
92
- const isEmptyExit = err.isPrematureEnd || (err.message && err.message.includes('ACP exited with code'));
93
- const isBinaryError = err.code === 'ENOENT' || (err.message && err.message.includes('ENOENT'));
94
- if ((isEmptyExit || isBinaryError) && _retryCount < maxRetries) {
95
- const delay = Math.min(1000 * Math.pow(2, _retryCount), 5000);
96
- console.error(`[${this.id}] ACP attempt ${_retryCount + 1} failed: ${err.message}. Retrying in ${delay}ms...`);
97
- await new Promise(r => setTimeout(r, delay));
98
- return this.runACP(prompt, cwd, config, _retryCount + 1);
99
- }
100
- if (err.isPrematureEnd) {
101
- const premErr = new Error(err.message);
102
- premErr.isPrematureEnd = true;
103
- premErr.exitCode = err.exitCode;
104
- premErr.stderrText = err.stderrText;
105
- throw premErr;
106
- }
107
- throw err;
108
- }
109
- };
110
-
111
- AgentRunner.prototype._runACPOnce = function(prompt, cwd, config = {}) {
112
- return new Promise((resolve, reject) => {
113
- const { timeout = 300000, onEvent = null, onError = null } = config;
114
- let cmd, args;
115
- if (this.requiresAdapter && this.adapterCommand) {
116
- cmd = this.adapterCommand; args = [...this.adapterArgs];
117
- } else {
118
- const resolved = resolveCommand(this.command, this.npxPackage);
119
- cmd = resolved.cmd; args = [...resolved.prefixArgs, ...this.buildArgs(prompt, config)];
120
- }
121
- const spawnOpts = getSpawnOptions(cwd);
122
- if (Object.keys(this.spawnEnv).length > 0) spawnOpts.env = { ...spawnOpts.env, ...this.spawnEnv };
123
- const proc = spawn(cmd, args, spawnOpts);
124
-
125
- if (config.onPid) { try { config.onPid(proc.pid); } catch (e) { console.error(`[${this.id}] onPid callback failed:`, e.message); } }
126
- if (config.onProcess) { try { config.onProcess(proc); } catch (e) { console.error(`[${this.id}] onProcess callback failed:`, e.message); } }
127
-
128
- const outputs = [];
129
- let timedOut = false;
130
- let stderrText = '';
131
- const sessionRef = { value: null };
132
- const promptIdRef = { value: null };
133
- const completedRef = { value: false };
134
- const drainingRef = { value: false };
135
- const requestIdRef = { value: 0 };
136
- let initialized = false;
137
-
138
- const timeoutHandle = setTimeout(() => { timedOut = true; proc.kill(); reject(new Error(`${this.name} ACP timeout after ${timeout}ms`)); }, timeout);
139
- const clearTimeoutHandle = () => clearTimeout(timeoutHandle);
140
-
141
- const originalHandler = (message) => {
142
- const normalized = this.protocolHandler(message, { sessionId: sessionRef.value, initialized });
143
- if (!normalized) { if (message.id === 1 && message.result) initialized = true; return; }
144
- outputs.push(normalized);
145
- if (normalized.session_id) sessionRef.value = normalized.session_id;
146
- if (onEvent) { try { onEvent(normalized); } catch (e) { console.error(`[${this.id}] onEvent error: ${e.message}`); } }
147
- };
148
-
149
- const enhancedHandler = buildEnhancedHandler({ proc, outputs, sessionRef, promptIdRef, completedRef, drainingRef, requestIdRef, originalHandler, resolve, reject, clearTimeoutHandle, promptText: prompt });
150
-
151
- proc.stdout.on('error', () => {});
152
- proc.stderr.on('error', () => {});
153
- proc.stderr.on('data', (chunk) => {
154
- const errorText = chunk.toString();
155
- stderrText += errorText;
156
- console.error(`[${this.id}] stderr:`, errorText);
157
- if (onError) { try { onError(errorText); } catch (e) {} }
158
- });
159
-
160
- proc.stdin.on('error', () => {});
161
- proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: ++requestIdRef.value, method: 'initialize', params: { protocolVersion: 1, clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true }, clientInfo: { name: 'agentgui', title: 'AgentGUI', version: '1.0.0' } } }) + '\n');
162
-
163
- let buffer = '';
164
- proc.stdout.on('data', (chunk) => {
165
- if (timedOut || (completedRef.value && !drainingRef.value)) return;
166
- buffer += chunk.toString();
167
- const lines = buffer.split('\n'); buffer = lines.pop();
168
- for (const line of lines) {
169
- if (line.trim()) {
170
- try {
171
- const message = JSON.parse(line);
172
- if (message.id === 1 && message.result) initialized = true;
173
- enhancedHandler(message);
174
- } catch (e) { console.error(`[${this.id}] JSON parse error:`, line.substring(0, 100)); }
175
- }
176
- }
177
- });
178
-
179
- const checkInitAndSend = () => {
180
- if (initialized) {
181
- const sessionParams = { cwd, mcpServers: [] };
182
- if (config.model) sessionParams.model = config.model;
183
- if (config.subAgent) sessionParams.agent = config.subAgent;
184
- if (config.systemPrompt) sessionParams.systemPrompt = config.systemPrompt;
185
- proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: ++requestIdRef.value, method: 'session/new', params: sessionParams }) + '\n');
186
- } else {
187
- setTimeout(checkInitAndSend, 100);
188
- }
189
- };
190
- setTimeout(checkInitAndSend, 200);
191
-
192
- proc.on('close', (code) => {
193
- clearTimeout(timeoutHandle);
194
- if (timedOut || completedRef.value) return;
195
- if (buffer.trim()) {
196
- try {
197
- const message = JSON.parse(buffer.trim());
198
- if (message.id === 1 && message.result) initialized = true;
199
- enhancedHandler(message);
200
- } catch (e) {}
201
- }
202
- if (code === 0 || outputs.length > 0) resolve({ outputs, sessionId: sessionRef.value });
203
- else {
204
- const detail = stderrText ? `: ${stderrText.substring(0, 200)}` : '';
205
- const err = new Error(`${this.name} ACP exited with code ${code}${detail}`);
206
- err.isPrematureEnd = true; err.exitCode = code; err.stderrText = stderrText;
207
- reject(err);
208
- }
209
- });
210
-
211
- proc.on('error', (err) => { clearTimeout(timeoutHandle); reject(err); });
212
- });
213
- };
1
+ import { spawn } from 'child_process';
2
+ import { AgentRunner, getSpawnOptions, resolveCommand } from './claude-runner.js';
3
+
4
+ function buildEnhancedHandler({ proc, outputs, sessionRef, promptIdRef, completedRef, drainingRef, requestIdRef, originalHandler, resolve, reject, clearTimeoutHandle, promptText }) {
5
+ return function(message) {
6
+ if (message.id && message.result && message.result.sessionId) {
7
+ sessionRef.value = message.result.sessionId;
8
+ promptIdRef.value = ++requestIdRef.value;
9
+ proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: promptIdRef.value, method: 'session/prompt', params: { sessionId: sessionRef.value, prompt: [{ type: 'text', text: promptText }] } }) + '\n');
10
+ return;
11
+ }
12
+ if (promptIdRef.value !== null && message.id === promptIdRef.value && message.result && message.result.stopReason) {
13
+ completedRef.value = true; drainingRef.value = true;
14
+ clearTimeoutHandle();
15
+ setTimeout(() => { drainingRef.value = false; try { proc.kill(); } catch (e) {} resolve({ outputs, sessionId: sessionRef.value }); }, 1000);
16
+ return;
17
+ }
18
+ if (promptIdRef.value !== null && message.id === promptIdRef.value && message.error) {
19
+ completedRef.value = true; drainingRef.value = true;
20
+ clearTimeoutHandle();
21
+ originalHandler(message);
22
+ setTimeout(() => { drainingRef.value = false; try { proc.kill(); } catch (e) {} reject(new Error(message.error.message || 'ACP prompt error')); }, 1000);
23
+ return;
24
+ }
25
+ originalHandler(message);
26
+ };
27
+ }
28
+
29
+ AgentRunner.prototype.runACP = async function(prompt, cwd, config = {}, _retryCount = 0) {
30
+ const maxRetries = config.maxRetries ?? 1;
31
+ try {
32
+ return await this._runACPOnce(prompt, cwd, config);
33
+ } catch (err) {
34
+ const isEmptyExit = err.isPrematureEnd || (err.message && err.message.includes('ACP exited with code'));
35
+ const isBinaryError = err.code === 'ENOENT' || (err.message && err.message.includes('ENOENT'));
36
+ if ((isEmptyExit || isBinaryError) && _retryCount < maxRetries) {
37
+ const delay = Math.min(1000 * Math.pow(2, _retryCount), 5000);
38
+ console.error(`[${this.id}] ACP attempt ${_retryCount + 1} failed: ${err.message}. Retrying in ${delay}ms...`);
39
+ await new Promise(r => setTimeout(r, delay));
40
+ return this.runACP(prompt, cwd, config, _retryCount + 1);
41
+ }
42
+ if (err.isPrematureEnd) {
43
+ const premErr = new Error(err.message);
44
+ premErr.isPrematureEnd = true;
45
+ premErr.exitCode = err.exitCode;
46
+ premErr.stderrText = err.stderrText;
47
+ throw premErr;
48
+ }
49
+ throw err;
50
+ }
51
+ };
52
+
53
+ AgentRunner.prototype._runACPOnce = function(prompt, cwd, config = {}) {
54
+ return new Promise((resolve, reject) => {
55
+ const { timeout = 300000, onEvent = null, onError = null } = config;
56
+ let cmd, args;
57
+ if (this.requiresAdapter && this.adapterCommand) {
58
+ cmd = this.adapterCommand; args = [...this.adapterArgs];
59
+ } else {
60
+ const resolved = resolveCommand(this.command, this.npxPackage);
61
+ cmd = resolved.cmd; args = [...resolved.prefixArgs, ...this.buildArgs(prompt, config)];
62
+ }
63
+ const spawnOpts = getSpawnOptions(cwd);
64
+ if (Object.keys(this.spawnEnv).length > 0) spawnOpts.env = { ...spawnOpts.env, ...this.spawnEnv };
65
+ const proc = spawn(cmd, args, spawnOpts);
66
+
67
+ if (config.onPid) { try { config.onPid(proc.pid); } catch (e) { console.error(`[${this.id}] onPid callback failed:`, e.message); } }
68
+ if (config.onProcess) { try { config.onProcess(proc); } catch (e) { console.error(`[${this.id}] onProcess callback failed:`, e.message); } }
69
+
70
+ const outputs = [];
71
+ let timedOut = false;
72
+ let stderrText = '';
73
+ const sessionRef = { value: null };
74
+ const promptIdRef = { value: null };
75
+ const completedRef = { value: false };
76
+ const drainingRef = { value: false };
77
+ const requestIdRef = { value: 0 };
78
+ let initialized = false;
79
+
80
+ const timeoutHandle = setTimeout(() => { timedOut = true; proc.kill(); reject(new Error(`${this.name} ACP timeout after ${timeout}ms`)); }, timeout);
81
+ const clearTimeoutHandle = () => clearTimeout(timeoutHandle);
82
+
83
+ const originalHandler = (message) => {
84
+ const normalized = this.protocolHandler(message, { sessionId: sessionRef.value, initialized });
85
+ if (!normalized) { if (message.id === 1 && message.result) initialized = true; return; }
86
+ outputs.push(normalized);
87
+ if (normalized.session_id) sessionRef.value = normalized.session_id;
88
+ if (onEvent) { try { onEvent(normalized); } catch (e) { console.error(`[${this.id}] onEvent error: ${e.message}`); } }
89
+ };
90
+
91
+ const enhancedHandler = buildEnhancedHandler({ proc, outputs, sessionRef, promptIdRef, completedRef, drainingRef, requestIdRef, originalHandler, resolve, reject, clearTimeoutHandle, promptText: prompt });
92
+
93
+ proc.stdout.on('error', () => {});
94
+ proc.stderr.on('error', () => {});
95
+ proc.stderr.on('data', (chunk) => {
96
+ const errorText = chunk.toString();
97
+ stderrText += errorText;
98
+ console.error(`[${this.id}] stderr:`, errorText);
99
+ if (onError) { try { onError(errorText); } catch (e) {} }
100
+ });
101
+
102
+ proc.stdin.on('error', () => {});
103
+ proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: ++requestIdRef.value, method: 'initialize', params: { protocolVersion: 1, clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true }, clientInfo: { name: 'agentgui', title: 'AgentGUI', version: '1.0.0' } } }) + '\n');
104
+
105
+ let buffer = '';
106
+ proc.stdout.on('data', (chunk) => {
107
+ if (timedOut || (completedRef.value && !drainingRef.value)) return;
108
+ buffer += chunk.toString();
109
+ const lines = buffer.split('\n'); buffer = lines.pop();
110
+ for (const line of lines) {
111
+ if (line.trim()) {
112
+ try {
113
+ const message = JSON.parse(line);
114
+ if (message.id === 1 && message.result) initialized = true;
115
+ enhancedHandler(message);
116
+ } catch (e) { console.error(`[${this.id}] JSON parse error:`, line.substring(0, 100)); }
117
+ }
118
+ }
119
+ });
120
+
121
+ const checkInitAndSend = () => {
122
+ if (initialized) {
123
+ const sessionParams = { cwd, mcpServers: [] };
124
+ if (config.model) sessionParams.model = config.model;
125
+ if (config.subAgent) sessionParams.agent = config.subAgent;
126
+ if (config.systemPrompt) sessionParams.systemPrompt = config.systemPrompt;
127
+ proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: ++requestIdRef.value, method: 'session/new', params: sessionParams }) + '\n');
128
+ } else {
129
+ setTimeout(checkInitAndSend, 100);
130
+ }
131
+ };
132
+ setTimeout(checkInitAndSend, 200);
133
+
134
+ proc.on('close', (code) => {
135
+ clearTimeout(timeoutHandle);
136
+ if (timedOut || completedRef.value) return;
137
+ if (buffer.trim()) {
138
+ try {
139
+ const message = JSON.parse(buffer.trim());
140
+ if (message.id === 1 && message.result) initialized = true;
141
+ enhancedHandler(message);
142
+ } catch (e) {}
143
+ }
144
+ if (code === 0 || outputs.length > 0) resolve({ outputs, sessionId: sessionRef.value });
145
+ else {
146
+ const detail = stderrText ? `: ${stderrText.substring(0, 200)}` : '';
147
+ const err = new Error(`${this.name} ACP exited with code ${code}${detail}`);
148
+ err.isPrematureEnd = true; err.exitCode = code; err.stderrText = stderrText;
149
+ reject(err);
150
+ }
151
+ });
152
+
153
+ proc.on('error', (err) => { clearTimeout(timeoutHandle); reject(err); });
154
+ });
155
+ };