agentgui 1.0.121 → 1.0.123

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.
@@ -1,51 +1,86 @@
1
1
  import { spawn } from 'child_process';
2
2
 
3
- export async function runClaudeWithStreaming(prompt, cwd, agentId = 'claude-code', config = {}) {
4
- return new Promise((resolve, reject) => {
5
- const {
6
- verbose = true,
7
- outputFormat = 'stream-json',
8
- timeout = 300000,
9
- print = true,
10
- resumeSessionId = null,
11
- systemPrompt = null,
12
- onEvent = null
13
- } = config;
3
+ /**
4
+ * Agent Framework
5
+ * Extensible registry for AI agent CLI integrations
6
+ * Supports multiple protocols: direct JSON streaming, ACP (JSON-RPC), etc.
7
+ */
14
8
 
15
- const flags = [];
16
- if (print) flags.push('--print');
17
- if (verbose) flags.push('--verbose');
18
- flags.push(`--output-format=${outputFormat}`);
19
- flags.push('--dangerously-skip-permissions');
20
- if (resumeSessionId) flags.push('--resume', resumeSessionId);
21
- if (systemPrompt) flags.push('--append-system-prompt', systemPrompt);
9
+ class AgentRunner {
10
+ constructor(config) {
11
+ this.id = config.id;
12
+ this.name = config.name;
13
+ this.command = config.command;
14
+ this.protocol = config.protocol || 'direct'; // 'direct' | 'acp' | etc
15
+ this.buildArgs = config.buildArgs || this.defaultBuildArgs;
16
+ this.parseOutput = config.parseOutput || this.defaultParseOutput;
17
+ this.supportsStdin = config.supportsStdin ?? true;
18
+ this.supportedFeatures = config.supportedFeatures || [];
19
+ this.protocolHandler = config.protocolHandler || null;
20
+ this.requiresAdapter = config.requiresAdapter || false;
21
+ this.adapterCommand = config.adapterCommand || null;
22
+ this.adapterArgs = config.adapterArgs || [];
23
+ }
24
+
25
+ defaultBuildArgs(prompt, config) {
26
+ return [];
27
+ }
22
28
 
23
- const proc = spawn('claude', flags, { cwd });
24
- let jsonBuffer = '';
25
- const outputs = [];
26
- let timedOut = false;
27
- let sessionId = null;
29
+ defaultParseOutput(line) {
30
+ try {
31
+ return JSON.parse(line);
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
28
36
 
29
- const timeoutHandle = setTimeout(() => {
30
- timedOut = true;
31
- proc.kill();
32
- reject(new Error(`Claude CLI timeout after ${timeout}ms for agent ${agentId}`));
33
- }, timeout);
37
+ async run(prompt, cwd, config = {}) {
38
+ if (this.protocol === 'acp' && this.protocolHandler) {
39
+ return this.runACP(prompt, cwd, config);
40
+ }
41
+ return this.runDirect(prompt, cwd, config);
42
+ }
34
43
 
35
- proc.stdin.write(prompt);
36
- proc.stdin.end();
44
+ async runDirect(prompt, cwd, config = {}) {
45
+ return new Promise((resolve, reject) => {
46
+ const {
47
+ timeout = 300000,
48
+ onEvent = null,
49
+ onError = null
50
+ } = config;
37
51
 
38
- proc.stdout.on('data', (chunk) => {
39
- if (timedOut) return;
52
+ const args = this.buildArgs(prompt, config);
53
+ const proc = spawn(this.command, args, { cwd });
54
+
55
+ let jsonBuffer = '';
56
+ const outputs = [];
57
+ let timedOut = false;
58
+ let sessionId = null;
59
+
60
+ const timeoutHandle = setTimeout(() => {
61
+ timedOut = true;
62
+ proc.kill();
63
+ reject(new Error(`${this.name} timeout after ${timeout}ms`));
64
+ }, timeout);
65
+
66
+ // Write to stdin if supported
67
+ if (this.supportsStdin) {
68
+ proc.stdin.write(prompt);
69
+ proc.stdin.end();
70
+ }
40
71
 
41
- jsonBuffer += chunk.toString();
42
- const lines = jsonBuffer.split('\n');
43
- jsonBuffer = lines.pop();
72
+ proc.stdout.on('data', (chunk) => {
73
+ if (timedOut) return;
74
+
75
+ jsonBuffer += chunk.toString();
76
+ const lines = jsonBuffer.split('\n');
77
+ jsonBuffer = lines.pop();
78
+
79
+ for (const line of lines) {
80
+ if (line.trim()) {
81
+ const parsed = this.parseOutput(line);
82
+ if (!parsed) continue;
44
83
 
45
- for (const line of lines) {
46
- if (line.trim()) {
47
- try {
48
- const parsed = JSON.parse(line);
49
84
  outputs.push(parsed);
50
85
 
51
86
  if (parsed.session_id) {
@@ -54,48 +89,760 @@ export async function runClaudeWithStreaming(prompt, cwd, agentId = 'claude-code
54
89
 
55
90
  if (onEvent) {
56
91
  try { onEvent(parsed); } catch (e) {
57
- console.error(`[claude-runner] onEvent error: ${e.message}`);
92
+ console.error(`[${this.id}] onEvent error: ${e.message}`);
58
93
  }
59
94
  }
60
- } catch (e) {
61
- console.error(`[claude-runner] JSON parse error on line: ${line.substring(0, 100)}`);
62
95
  }
63
96
  }
64
- }
65
- });
97
+ });
98
+
99
+ proc.stderr.on('data', (chunk) => {
100
+ const errorText = chunk.toString();
101
+ console.error(`[${this.id}] stderr:`, errorText);
102
+ if (onError) {
103
+ try { onError(errorText); } catch (e) {}
104
+ }
105
+ });
106
+
107
+ proc.on('close', (code) => {
108
+ clearTimeout(timeoutHandle);
109
+ if (timedOut) return;
110
+
111
+ // Some agents return non-zero but still produce valid output
112
+ const success = code === 0 || (outputs.length > 0 && this.allowNonZeroExit);
113
+
114
+ if (success) {
115
+ if (jsonBuffer.trim()) {
116
+ const parsed = this.parseOutput(jsonBuffer);
117
+ if (parsed) {
118
+ outputs.push(parsed);
119
+ if (parsed.session_id) sessionId = parsed.session_id;
120
+ if (onEvent) {
121
+ try { onEvent(parsed); } catch (e) {}
122
+ }
123
+ }
124
+ }
125
+ resolve({ outputs, sessionId });
126
+ } else {
127
+ reject(new Error(`${this.name} exited with code ${code}`));
128
+ }
129
+ });
66
130
 
67
- proc.stderr.on('data', (chunk) => {
68
- console.error(`[claude-runner] stderr: ${chunk.toString()}`);
131
+ proc.on('error', (err) => {
132
+ clearTimeout(timeoutHandle);
133
+ reject(err);
134
+ });
69
135
  });
136
+ }
70
137
 
71
- proc.on('close', (code) => {
72
- clearTimeout(timeoutHandle);
73
- if (timedOut) return;
138
+ async runACP(prompt, cwd, config = {}) {
139
+ return new Promise((resolve, reject) => {
140
+ const {
141
+ timeout = 300000,
142
+ onEvent = null,
143
+ onError = null
144
+ } = config;
74
145
 
75
- if (code === 0) {
76
- if (jsonBuffer.trim()) {
77
- try {
78
- const parsed = JSON.parse(jsonBuffer);
79
- outputs.push(parsed);
80
- if (parsed.session_id) sessionId = parsed.session_id;
81
- if (onEvent) {
82
- try { onEvent(parsed); } catch (e) {}
146
+ // Use adapter if required (e.g., for Claude Code via Zed adapter)
147
+ const cmd = this.requiresAdapter && this.adapterCommand ? this.adapterCommand : this.command;
148
+ const baseArgs = this.requiresAdapter && this.adapterCommand ? this.adapterArgs : ['acp'];
149
+ const args = [...baseArgs];
150
+
151
+ const proc = spawn(cmd, args, { cwd });
152
+
153
+ const outputs = [];
154
+ let timedOut = false;
155
+ let sessionId = null;
156
+ let requestId = 0;
157
+ let initialized = false;
158
+
159
+ const timeoutHandle = setTimeout(() => {
160
+ timedOut = true;
161
+ proc.kill();
162
+ reject(new Error(`${this.name} ACP timeout after ${timeout}ms`));
163
+ }, timeout);
164
+
165
+ // ACP protocol handler
166
+ const handleMessage = (message) => {
167
+ // Normalize ACP message to common format
168
+ const normalized = this.protocolHandler(message, { sessionId, initialized });
169
+ if (!normalized) {
170
+ // Check for initialization response
171
+ if (message.id === 1 && message.result) {
172
+ initialized = true;
173
+ }
174
+ return;
175
+ }
176
+
177
+ outputs.push(normalized);
178
+
179
+ if (normalized.session_id) {
180
+ sessionId = normalized.session_id;
181
+ }
182
+
183
+ if (onEvent) {
184
+ try { onEvent(normalized); } catch (e) {
185
+ console.error(`[${this.id}] onEvent error: ${e.message}`);
186
+ }
187
+ }
188
+ };
189
+
190
+ let buffer = '';
191
+ proc.stdout.on('data', (chunk) => {
192
+ if (timedOut) return;
193
+
194
+ buffer += chunk.toString();
195
+ const lines = buffer.split('\n');
196
+ buffer = lines.pop();
197
+
198
+ for (const line of lines) {
199
+ if (line.trim()) {
200
+ try {
201
+ const message = JSON.parse(line);
202
+ handleMessage(message);
203
+ } catch (e) {
204
+ console.error(`[${this.id}] JSON parse error:`, line.substring(0, 100));
83
205
  }
84
- } catch (e) {
85
- console.error(`[claude-runner] Final JSON parse error: ${jsonBuffer.substring(0, 100)}`);
86
206
  }
87
207
  }
88
- resolve({ outputs, sessionId });
89
- } else {
90
- reject(new Error(`Claude CLI exited with code ${code} for agent ${agentId}`));
91
- }
208
+ });
209
+
210
+ proc.stderr.on('data', (chunk) => {
211
+ const errorText = chunk.toString();
212
+ console.error(`[${this.id}] stderr:`, errorText);
213
+ if (onError) {
214
+ try { onError(errorText); } catch (e) {}
215
+ }
216
+ });
217
+
218
+ // Send ACP initialize request (protocolVersion must be an integer per ACP spec)
219
+ const initRequest = {
220
+ jsonrpc: '2.0',
221
+ id: ++requestId,
222
+ method: 'initialize',
223
+ params: {
224
+ protocolVersion: 1,
225
+ clientCapabilities: {
226
+ fs: { readTextFile: true, writeTextFile: true },
227
+ terminal: true
228
+ },
229
+ clientInfo: {
230
+ name: 'agentgui',
231
+ title: 'AgentGUI',
232
+ version: '1.0.0'
233
+ }
234
+ }
235
+ };
236
+ proc.stdin.write(JSON.stringify(initRequest) + '\n');
237
+
238
+ let sessionCreated = false;
239
+
240
+ // Wait for initialization then create session and send prompt
241
+ const checkInitAndSend = () => {
242
+ if (initialized && !sessionCreated) {
243
+ sessionCreated = true;
244
+
245
+ // Step 1: Create a new session
246
+ const sessionRequest = {
247
+ jsonrpc: '2.0',
248
+ id: ++requestId,
249
+ method: 'session/new',
250
+ params: {
251
+ cwd: cwd,
252
+ mcpServers: []
253
+ }
254
+ };
255
+ proc.stdin.write(JSON.stringify(sessionRequest) + '\n');
256
+ } else if (!initialized) {
257
+ setTimeout(checkInitAndSend, 100);
258
+ }
259
+ };
260
+
261
+ let promptId = null;
262
+ let completed = false;
263
+
264
+ // Handle session creation response and send prompt
265
+ const originalHandler = handleMessage;
266
+ const enhancedHandler = (message) => {
267
+ // Check for session/new response
268
+ if (message.id && message.result && message.result.sessionId) {
269
+ sessionId = message.result.sessionId;
270
+
271
+ // Step 2: Send the prompt
272
+ promptId = ++requestId;
273
+ const promptRequest = {
274
+ jsonrpc: '2.0',
275
+ id: promptId,
276
+ method: 'session/prompt',
277
+ params: {
278
+ sessionId: sessionId,
279
+ prompt: [{ type: 'text', text: prompt }]
280
+ }
281
+ };
282
+ proc.stdin.write(JSON.stringify(promptRequest) + '\n');
283
+ return;
284
+ }
285
+
286
+ // Check for prompt response (end of turn)
287
+ if (message.id === promptId && message.result && message.result.stopReason) {
288
+ completed = true;
289
+ clearTimeout(timeoutHandle);
290
+ proc.kill();
291
+ resolve({ outputs, sessionId });
292
+ return;
293
+ }
294
+
295
+ originalHandler(message);
296
+ };
297
+
298
+ // Override the message handler
299
+ buffer = '';
300
+ proc.stdout.removeAllListeners('data');
301
+ proc.stdout.on('data', (chunk) => {
302
+ if (timedOut || completed) return;
303
+
304
+ buffer += chunk.toString();
305
+ const lines = buffer.split('\n');
306
+ buffer = lines.pop();
307
+
308
+ for (const line of lines) {
309
+ if (line.trim()) {
310
+ try {
311
+ const message = JSON.parse(line);
312
+
313
+ // Check for initialization response
314
+ if (message.id === 1 && message.result) {
315
+ initialized = true;
316
+ }
317
+
318
+ enhancedHandler(message);
319
+ } catch (e) {
320
+ console.error(`[${this.id}] JSON parse error:`, line.substring(0, 100));
321
+ }
322
+ }
323
+ }
324
+ });
325
+
326
+ setTimeout(checkInitAndSend, 200);
327
+
328
+ proc.on('close', (code) => {
329
+ clearTimeout(timeoutHandle);
330
+ if (timedOut || completed) return;
331
+
332
+ if (code === 0 || outputs.length > 0) {
333
+ resolve({ outputs, sessionId });
334
+ } else {
335
+ reject(new Error(`${this.name} ACP exited with code ${code}`));
336
+ }
337
+ });
338
+
339
+ proc.on('error', (err) => {
340
+ clearTimeout(timeoutHandle);
341
+ reject(err);
342
+ });
92
343
  });
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Agent Registry
349
+ */
350
+ class AgentRegistry {
351
+ constructor() {
352
+ this.agents = new Map();
353
+ }
354
+
355
+ register(config) {
356
+ const runner = new AgentRunner(config);
357
+ this.agents.set(config.id, runner);
358
+ return runner;
359
+ }
93
360
 
94
- proc.on('error', (err) => {
95
- clearTimeout(timeoutHandle);
96
- reject(err);
361
+ get(agentId) {
362
+ return this.agents.get(agentId);
363
+ }
364
+
365
+ has(agentId) {
366
+ return this.agents.has(agentId);
367
+ }
368
+
369
+ list() {
370
+ return Array.from(this.agents.values()).map(a => ({
371
+ id: a.id,
372
+ name: a.name,
373
+ command: a.command,
374
+ protocol: a.protocol,
375
+ requiresAdapter: a.requiresAdapter,
376
+ supportedFeatures: a.supportedFeatures
377
+ }));
378
+ }
379
+
380
+ listACPAvailable() {
381
+ // Check which agents are actually installed
382
+ const { execSync } = require('child_process');
383
+ return this.list().filter(agent => {
384
+ try {
385
+ execSync(`which ${agent.command} 2>/dev/null`, { encoding: 'utf-8' });
386
+ return true;
387
+ } catch {
388
+ return false;
389
+ }
97
390
  });
98
- });
391
+ }
392
+ }
393
+
394
+ // Create global registry
395
+ const registry = new AgentRegistry();
396
+
397
+ /**
398
+ * Claude Code Agent
399
+ * Uses direct JSON streaming protocol
400
+ */
401
+ registry.register({
402
+ id: 'claude-code',
403
+ name: 'Claude Code',
404
+ command: 'claude',
405
+ protocol: 'direct',
406
+ supportsStdin: true,
407
+ supportedFeatures: ['streaming', 'resume', 'system-prompt', 'permissions-skip'],
408
+
409
+ buildArgs(prompt, config) {
410
+ const {
411
+ verbose = true,
412
+ outputFormat = 'stream-json',
413
+ print = true,
414
+ resumeSessionId = null,
415
+ systemPrompt = null
416
+ } = config;
417
+
418
+ const flags = [];
419
+ if (print) flags.push('--print');
420
+ if (verbose) flags.push('--verbose');
421
+ flags.push(`--output-format=${outputFormat}`);
422
+ flags.push('--dangerously-skip-permissions');
423
+ if (resumeSessionId) flags.push('--resume', resumeSessionId);
424
+ if (systemPrompt) flags.push('--append-system-prompt', systemPrompt);
425
+
426
+ return flags;
427
+ },
428
+
429
+ parseOutput(line) {
430
+ try {
431
+ return JSON.parse(line);
432
+ } catch {
433
+ return null;
434
+ }
435
+ }
436
+ });
437
+
438
+ /**
439
+ * OpenCode Agent
440
+ * Native ACP support
441
+ */
442
+ registry.register({
443
+ id: 'opencode',
444
+ name: 'OpenCode',
445
+ command: 'opencode',
446
+ protocol: 'acp',
447
+ supportsStdin: false,
448
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
449
+
450
+ buildArgs(prompt, config) {
451
+ return ['acp'];
452
+ },
453
+
454
+ protocolHandler(message, context) {
455
+ if (!message || typeof message !== 'object') return null;
456
+
457
+ // Handle ACP session/update notifications
458
+ if (message.method === 'session/update') {
459
+ const params = message.params || {};
460
+ const update = params.update || {};
461
+
462
+ // Agent message chunk (text response)
463
+ if (update.sessionUpdate === 'agent_message_chunk' && update.content) {
464
+ return {
465
+ type: 'assistant',
466
+ message: {
467
+ role: 'assistant',
468
+ content: [update.content]
469
+ },
470
+ session_id: params.sessionId
471
+ };
472
+ }
473
+
474
+ // Tool call
475
+ if (update.sessionUpdate === 'tool_call') {
476
+ return {
477
+ type: 'assistant',
478
+ message: {
479
+ role: 'assistant',
480
+ content: [{
481
+ type: 'tool_use',
482
+ id: update.toolCallId,
483
+ name: update.title || 'tool',
484
+ input: update.input || {}
485
+ }]
486
+ },
487
+ session_id: params.sessionId
488
+ };
489
+ }
490
+
491
+ // Tool call update (result)
492
+ if (update.sessionUpdate === 'tool_call_update' && update.status === 'completed') {
493
+ const content = update.content && update.content[0] ? update.content[0].content : null;
494
+ return {
495
+ type: 'assistant',
496
+ message: {
497
+ role: 'assistant',
498
+ content: [{
499
+ type: 'tool_result',
500
+ tool_use_id: update.toolCallId,
501
+ content: content ? (content.text || JSON.stringify(content)) : '',
502
+ is_error: false
503
+ }]
504
+ },
505
+ session_id: params.sessionId
506
+ };
507
+ }
508
+
509
+ // Usage update
510
+ if (update.sessionUpdate === 'usage_update') {
511
+ return {
512
+ type: 'usage',
513
+ usage: {
514
+ used: update.used,
515
+ size: update.size,
516
+ cost: update.cost
517
+ },
518
+ session_id: params.sessionId
519
+ };
520
+ }
521
+
522
+ // Plan update
523
+ if (update.sessionUpdate === 'plan') {
524
+ return {
525
+ type: 'plan',
526
+ entries: update.entries || [],
527
+ session_id: params.sessionId
528
+ };
529
+ }
530
+
531
+ // Skip other updates like available_commands_update
532
+ return null;
533
+ }
534
+
535
+ // Handle prompt response (end of turn)
536
+ if (message.id && message.result && message.result.stopReason) {
537
+ return {
538
+ type: 'result',
539
+ result: '',
540
+ stopReason: message.result.stopReason,
541
+ usage: message.result.usage,
542
+ session_id: context.sessionId
543
+ };
544
+ }
545
+
546
+ if (message.method === 'error' || message.error) {
547
+ return {
548
+ type: 'error',
549
+ error: message.error || message.params || { message: 'Unknown error' }
550
+ };
551
+ }
552
+
553
+ return null;
554
+ }
555
+ });
556
+
557
+ /**
558
+ * Common ACP protocol handler for all ACP agents
559
+ */
560
+ function createACPProtocolHandler() {
561
+ return function(message, context) {
562
+ if (!message || typeof message !== 'object') return null;
563
+
564
+ // Handle ACP session/update notifications
565
+ if (message.method === 'session/update') {
566
+ const params = message.params || {};
567
+ const update = params.update || {};
568
+
569
+ // Agent message chunk (text response)
570
+ if (update.sessionUpdate === 'agent_message_chunk' && update.content) {
571
+ return {
572
+ type: 'assistant',
573
+ message: {
574
+ role: 'assistant',
575
+ content: [update.content]
576
+ },
577
+ session_id: params.sessionId
578
+ };
579
+ }
580
+
581
+ // Tool call
582
+ if (update.sessionUpdate === 'tool_call') {
583
+ return {
584
+ type: 'assistant',
585
+ message: {
586
+ role: 'assistant',
587
+ content: [{
588
+ type: 'tool_use',
589
+ id: update.toolCallId,
590
+ name: update.title || 'tool',
591
+ input: update.input || {}
592
+ }]
593
+ },
594
+ session_id: params.sessionId
595
+ };
596
+ }
597
+
598
+ // Tool call update (result)
599
+ if (update.sessionUpdate === 'tool_call_update' && update.status === 'completed') {
600
+ const content = update.content && update.content[0] ? update.content[0].content : null;
601
+ return {
602
+ type: 'assistant',
603
+ message: {
604
+ role: 'assistant',
605
+ content: [{
606
+ type: 'tool_result',
607
+ tool_use_id: update.toolCallId,
608
+ content: content ? (content.text || JSON.stringify(content)) : '',
609
+ is_error: false
610
+ }]
611
+ },
612
+ session_id: params.sessionId
613
+ };
614
+ }
615
+
616
+ // Usage update
617
+ if (update.sessionUpdate === 'usage_update') {
618
+ return {
619
+ type: 'usage',
620
+ usage: {
621
+ used: update.used,
622
+ size: update.size,
623
+ cost: update.cost
624
+ },
625
+ session_id: params.sessionId
626
+ };
627
+ }
628
+
629
+ return null;
630
+ }
631
+
632
+ // Handle prompt response (end of turn)
633
+ if (message.id && message.result && message.result.stopReason) {
634
+ return {
635
+ type: 'result',
636
+ result: '',
637
+ stopReason: message.result.stopReason,
638
+ usage: message.result.usage,
639
+ session_id: context.sessionId
640
+ };
641
+ }
642
+
643
+ if (message.method === 'error' || message.error) {
644
+ return {
645
+ type: 'error',
646
+ error: message.error || message.params || { message: 'Unknown error' }
647
+ };
648
+ }
649
+
650
+ return null;
651
+ };
652
+ }
653
+
654
+ // Shared ACP handler
655
+ const acpProtocolHandler = createACPProtocolHandler();
656
+
657
+ /**
658
+ * Gemini CLI Agent
659
+ * Native ACP support
660
+ */
661
+ registry.register({
662
+ id: 'gemini',
663
+ name: 'Gemini CLI',
664
+ command: 'gemini',
665
+ protocol: 'acp',
666
+ supportsStdin: false,
667
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
668
+ buildArgs: () => ['acp'],
669
+ protocolHandler: acpProtocolHandler
670
+ });
671
+
672
+ /**
673
+ * Goose Agent
674
+ * Native ACP support
675
+ */
676
+ registry.register({
677
+ id: 'goose',
678
+ name: 'Goose',
679
+ command: 'goose',
680
+ protocol: 'acp',
681
+ supportsStdin: false,
682
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
683
+ buildArgs: () => ['acp'],
684
+ protocolHandler: acpProtocolHandler
685
+ });
686
+
687
+ /**
688
+ * OpenHands Agent
689
+ * Native ACP support
690
+ */
691
+ registry.register({
692
+ id: 'openhands',
693
+ name: 'OpenHands',
694
+ command: 'openhands',
695
+ protocol: 'acp',
696
+ supportsStdin: false,
697
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
698
+ buildArgs: () => ['acp'],
699
+ protocolHandler: acpProtocolHandler
700
+ });
701
+
702
+ /**
703
+ * Augment Code Agent - Native ACP support
704
+ */
705
+ registry.register({
706
+ id: 'augment',
707
+ name: 'Augment Code',
708
+ command: 'augment',
709
+ protocol: 'acp',
710
+ supportsStdin: false,
711
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
712
+ buildArgs: () => ['acp'],
713
+ protocolHandler: acpProtocolHandler
714
+ });
715
+
716
+ /**
717
+ * Cline Agent - Native ACP support
718
+ */
719
+ registry.register({
720
+ id: 'cline',
721
+ name: 'Cline',
722
+ command: 'cline',
723
+ protocol: 'acp',
724
+ supportsStdin: false,
725
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
726
+ buildArgs: () => ['acp'],
727
+ protocolHandler: acpProtocolHandler
728
+ });
729
+
730
+ /**
731
+ * Kimi CLI Agent (Moonshot AI) - Native ACP support
732
+ */
733
+ registry.register({
734
+ id: 'kimi',
735
+ name: 'Kimi CLI',
736
+ command: 'kimi',
737
+ protocol: 'acp',
738
+ supportsStdin: false,
739
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
740
+ buildArgs: () => ['acp'],
741
+ protocolHandler: acpProtocolHandler
742
+ });
743
+
744
+ /**
745
+ * Qwen Code Agent (Alibaba) - Native ACP support
746
+ */
747
+ registry.register({
748
+ id: 'qwen',
749
+ name: 'Qwen Code',
750
+ command: 'qwen-code',
751
+ protocol: 'acp',
752
+ supportsStdin: false,
753
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
754
+ buildArgs: () => ['acp'],
755
+ protocolHandler: acpProtocolHandler
756
+ });
757
+
758
+ /**
759
+ * Codex CLI Agent (OpenAI) - ACP support
760
+ */
761
+ registry.register({
762
+ id: 'codex',
763
+ name: 'Codex CLI',
764
+ command: 'codex',
765
+ protocol: 'acp',
766
+ supportsStdin: false,
767
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
768
+ buildArgs: () => ['acp'],
769
+ protocolHandler: acpProtocolHandler
770
+ });
771
+
772
+ /**
773
+ * Mistral Vibe Agent - Native ACP support
774
+ */
775
+ registry.register({
776
+ id: 'mistral',
777
+ name: 'Mistral Vibe',
778
+ command: 'mistral-vibe',
779
+ protocol: 'acp',
780
+ supportsStdin: false,
781
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
782
+ buildArgs: () => ['acp'],
783
+ protocolHandler: acpProtocolHandler
784
+ });
785
+
786
+ /**
787
+ * Kiro CLI Agent - Native ACP support
788
+ */
789
+ registry.register({
790
+ id: 'kiro',
791
+ name: 'Kiro CLI',
792
+ command: 'kiro',
793
+ protocol: 'acp',
794
+ supportsStdin: false,
795
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
796
+ buildArgs: () => ['acp'],
797
+ protocolHandler: acpProtocolHandler
798
+ });
799
+
800
+ /**
801
+ * fast-agent - Native ACP support
802
+ */
803
+ registry.register({
804
+ id: 'fast-agent',
805
+ name: 'fast-agent',
806
+ command: 'fast-agent',
807
+ protocol: 'acp',
808
+ supportsStdin: false,
809
+ supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
810
+ buildArgs: () => ['acp'],
811
+ protocolHandler: acpProtocolHandler
812
+ });
813
+
814
+ /**
815
+ * Main export function - runs any registered agent
816
+ */
817
+ export async function runClaudeWithStreaming(prompt, cwd, agentId = 'claude-code', config = {}) {
818
+ const agent = registry.get(agentId);
819
+
820
+ if (!agent) {
821
+ throw new Error(`Unknown agent: ${agentId}. Registered agents: ${registry.list().map(a => a.id).join(', ')}`);
822
+ }
823
+
824
+ return agent.run(prompt, cwd, config);
825
+ }
826
+
827
+ /**
828
+ * Get list of registered agents
829
+ */
830
+ export function getRegisteredAgents() {
831
+ return registry.list();
832
+ }
833
+
834
+ /**
835
+ * Get list of installed/available agents
836
+ */
837
+ export function getAvailableAgents() {
838
+ return registry.listACPAvailable();
839
+ }
840
+
841
+ /**
842
+ * Check if an agent is registered
843
+ */
844
+ export function isAgentRegistered(agentId) {
845
+ return registry.has(agentId);
99
846
  }
100
847
 
101
848
  export default runClaudeWithStreaming;