agentgui 1.0.149 → 1.0.150

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.
@@ -139,7 +139,24 @@ class AgentRunner {
139
139
  });
140
140
  }
141
141
 
142
- async runACP(prompt, cwd, config = {}) {
142
+ async runACP(prompt, cwd, config = {}, _retryCount = 0) {
143
+ const maxRetries = config.maxRetries ?? 1;
144
+ try {
145
+ return await this._runACPOnce(prompt, cwd, config);
146
+ } catch (err) {
147
+ const isEmptyExit = err.message && err.message.includes('ACP exited with code');
148
+ const isBinaryError = err.code === 'ENOENT' || (err.message && err.message.includes('ENOENT'));
149
+ if ((isEmptyExit || isBinaryError) && _retryCount < maxRetries) {
150
+ const delay = Math.min(1000 * Math.pow(2, _retryCount), 5000);
151
+ console.error(`[${this.id}] ACP attempt ${_retryCount + 1} failed: ${err.message}. Retrying in ${delay}ms...`);
152
+ await new Promise(r => setTimeout(r, delay));
153
+ return this.runACP(prompt, cwd, config, _retryCount + 1);
154
+ }
155
+ throw err;
156
+ }
157
+ }
158
+
159
+ async _runACPOnce(prompt, cwd, config = {}) {
143
160
  return new Promise((resolve, reject) => {
144
161
  const {
145
162
  timeout = 300000,
@@ -147,11 +164,10 @@ class AgentRunner {
147
164
  onError = null
148
165
  } = config;
149
166
 
150
- // Use adapter if required (e.g., for Claude Code via Zed adapter)
151
167
  const cmd = this.requiresAdapter && this.adapterCommand ? this.adapterCommand : this.command;
152
168
  const baseArgs = this.requiresAdapter && this.adapterCommand ? this.adapterArgs : ['acp'];
153
169
  const args = [...baseArgs];
154
-
170
+
155
171
  const proc = spawn(cmd, args, { cwd });
156
172
 
157
173
  if (config.onPid) {
@@ -163,6 +179,7 @@ class AgentRunner {
163
179
  let sessionId = null;
164
180
  let requestId = 0;
165
181
  let initialized = false;
182
+ let stderrText = '';
166
183
 
167
184
  const timeoutHandle = setTimeout(() => {
168
185
  timedOut = true;
@@ -170,12 +187,9 @@ class AgentRunner {
170
187
  reject(new Error(`${this.name} ACP timeout after ${timeout}ms`));
171
188
  }, timeout);
172
189
 
173
- // ACP protocol handler
174
190
  const handleMessage = (message) => {
175
- // Normalize ACP message to common format
176
191
  const normalized = this.protocolHandler(message, { sessionId, initialized });
177
192
  if (!normalized) {
178
- // Check for initialization response
179
193
  if (message.id === 1 && message.result) {
180
194
  initialized = true;
181
195
  }
@@ -217,13 +231,13 @@ class AgentRunner {
217
231
 
218
232
  proc.stderr.on('data', (chunk) => {
219
233
  const errorText = chunk.toString();
234
+ stderrText += errorText;
220
235
  console.error(`[${this.id}] stderr:`, errorText);
221
236
  if (onError) {
222
237
  try { onError(errorText); } catch (e) {}
223
238
  }
224
239
  });
225
240
 
226
- // Send ACP initialize request (protocolVersion must be an integer per ACP spec)
227
241
  const initRequest = {
228
242
  jsonrpc: '2.0',
229
243
  id: ++requestId,
@@ -245,12 +259,10 @@ class AgentRunner {
245
259
 
246
260
  let sessionCreated = false;
247
261
 
248
- // Wait for initialization then create session and send prompt
249
262
  const checkInitAndSend = () => {
250
263
  if (initialized && !sessionCreated) {
251
264
  sessionCreated = true;
252
-
253
- // Step 1: Create a new session
265
+
254
266
  const sessionRequest = {
255
267
  jsonrpc: '2.0',
256
268
  id: ++requestId,
@@ -269,14 +281,11 @@ class AgentRunner {
269
281
  let promptId = null;
270
282
  let completed = false;
271
283
 
272
- // Handle session creation response and send prompt
273
284
  const originalHandler = handleMessage;
274
285
  const enhancedHandler = (message) => {
275
- // Check for session/new response
276
286
  if (message.id && message.result && message.result.sessionId) {
277
287
  sessionId = message.result.sessionId;
278
-
279
- // Step 2: Send the prompt
288
+
280
289
  promptId = ++requestId;
281
290
  const promptRequest = {
282
291
  jsonrpc: '2.0',
@@ -290,8 +299,7 @@ class AgentRunner {
290
299
  proc.stdin.write(JSON.stringify(promptRequest) + '\n');
291
300
  return;
292
301
  }
293
-
294
- // Check for prompt response (end of turn)
302
+
295
303
  if (message.id === promptId && message.result && message.result.stopReason) {
296
304
  completed = true;
297
305
  clearTimeout(timeoutHandle);
@@ -299,11 +307,10 @@ class AgentRunner {
299
307
  resolve({ outputs, sessionId });
300
308
  return;
301
309
  }
302
-
310
+
303
311
  originalHandler(message);
304
312
  };
305
313
 
306
- // Override the message handler
307
314
  buffer = '';
308
315
  proc.stdout.removeAllListeners('data');
309
316
  proc.stdout.on('data', (chunk) => {
@@ -317,12 +324,11 @@ class AgentRunner {
317
324
  if (line.trim()) {
318
325
  try {
319
326
  const message = JSON.parse(line);
320
-
321
- // Check for initialization response
327
+
322
328
  if (message.id === 1 && message.result) {
323
329
  initialized = true;
324
330
  }
325
-
331
+
326
332
  enhancedHandler(message);
327
333
  } catch (e) {
328
334
  console.error(`[${this.id}] JSON parse error:`, line.substring(0, 100));
@@ -340,7 +346,8 @@ class AgentRunner {
340
346
  if (code === 0 || outputs.length > 0) {
341
347
  resolve({ outputs, sessionId });
342
348
  } else {
343
- reject(new Error(`${this.name} ACP exited with code ${code}`));
349
+ const detail = stderrText ? `: ${stderrText.substring(0, 200)}` : '';
350
+ reject(new Error(`${this.name} ACP exited with code ${code}${detail}`));
344
351
  }
345
352
  });
346
353
 
@@ -386,12 +393,15 @@ class AgentRegistry {
386
393
  }
387
394
 
388
395
  listACPAvailable() {
389
- // Check which agents are actually installed
390
- const { execSync } = require('child_process');
396
+ const { spawnSync } = require('child_process');
391
397
  return this.list().filter(agent => {
392
398
  try {
393
- execSync(`which ${agent.command} 2>/dev/null`, { encoding: 'utf-8' });
394
- return true;
399
+ const which = spawnSync('which', [agent.command], { encoding: 'utf-8', timeout: 3000 });
400
+ if (which.status !== 0) return false;
401
+ const binPath = (which.stdout || '').trim();
402
+ if (!binPath) return false;
403
+ const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000 });
404
+ return check.status === 0 && (check.stdout || '').trim().length > 0;
395
405
  } catch {
396
406
  return false;
397
407
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.149",
3
+ "version": "1.0.150",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",