agent-gear 1.1.6 → 1.1.8

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.
Files changed (42) hide show
  1. package/dist/acp/bridge.d.ts +13 -0
  2. package/dist/acp/bridge.d.ts.map +1 -1
  3. package/dist/acp/bridge.js +125 -3
  4. package/dist/acp/bridge.js.map +1 -1
  5. package/dist/acp/bridge.test.js +130 -7
  6. package/dist/acp/bridge.test.js.map +1 -1
  7. package/dist/acp/prober.d.ts +24 -0
  8. package/dist/acp/prober.d.ts.map +1 -0
  9. package/dist/acp/prober.js +53 -0
  10. package/dist/acp/prober.js.map +1 -0
  11. package/dist/acp/prober.test.d.ts +2 -0
  12. package/dist/acp/prober.test.d.ts.map +1 -0
  13. package/dist/acp/prober.test.js +94 -0
  14. package/dist/acp/prober.test.js.map +1 -0
  15. package/dist/acp/spawner.js +4 -4
  16. package/dist/acp/spawner.js.map +1 -1
  17. package/dist/acp/sync-bridge.d.ts +2 -0
  18. package/dist/acp/sync-bridge.d.ts.map +1 -1
  19. package/dist/acp/sync-bridge.js +6 -0
  20. package/dist/acp/sync-bridge.js.map +1 -1
  21. package/dist/commands/mcp-proxy.d.ts +10 -0
  22. package/dist/commands/mcp-proxy.d.ts.map +1 -1
  23. package/dist/commands/mcp-proxy.js +78 -24
  24. package/dist/commands/mcp-proxy.js.map +1 -1
  25. package/dist/socketio-client.d.ts.map +1 -1
  26. package/dist/socketio-client.js +57 -3
  27. package/dist/socketio-client.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/acp/bridge.test.ts +159 -7
  30. package/src/acp/bridge.ts +152 -3
  31. package/src/acp/prober.test.ts +107 -0
  32. package/src/acp/prober.ts +73 -0
  33. package/src/acp/spawner.ts +4 -4
  34. package/src/acp/sync-bridge.ts +8 -0
  35. package/src/commands/mcp-proxy.ts +91 -28
  36. package/src/socketio-client.ts +72 -3
  37. package/tests/acp-bridge.test.ts +119 -0
  38. package/tests/acp-spawner.test.ts +28 -1
  39. package/tests/acp-wire-elicitation.test.ts +158 -0
  40. package/tests/acp-wire-mcp.test.ts +114 -0
  41. package/tests/commands/mcp-proxy-dispatcher.test.ts +117 -0
  42. package/tests/fixtures/fake-acp-agent.mjs +122 -0
@@ -0,0 +1,122 @@
1
+ // Fake ACP agent used by acp-wire-mcp.test.ts and acp-wire-elicitation.test.ts.
2
+ // Speaks ndjson JSON-RPC over stdio: answers initialize/session/new/session/resume
3
+ // and records every session/new & session/resume params payload to CAPTURE_FILE
4
+ // (one JSON per line) so tests can assert the exact wire format.
5
+ //
6
+ // When FAKE_AGENT_ELICITATION=form|url is set, a session/prompt makes the agent
7
+ // behave like an eliciting agent (e.g. opencode asking a question):
8
+ // 1. capture the initialize params (clientCapabilities advertisement)
9
+ // 2. send an outgoing `elicitation/create` request and await the client response
10
+ // 3. capture the elicitation response payload exactly as received on the wire
11
+ // 4. reply to session/prompt with stopReason "end_turn"
12
+ // 5. (url mode only) send an `elicitation/complete` notification afterwards
13
+ import { appendFileSync } from 'node:fs';
14
+ import { createInterface } from 'node:readline';
15
+
16
+ const captureFile = process.env.CAPTURE_FILE;
17
+ const elicitationMode = process.env.FAKE_AGENT_ELICITATION; // 'form' | 'url' | undefined
18
+
19
+ const rl = createInterface({ input: process.stdin });
20
+
21
+ let nextOutgoingId = 1000;
22
+ // outgoing request id -> continuation invoked with the client's response result
23
+ const pendingOutgoing = new Map();
24
+
25
+ function reply(id, result) {
26
+ process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id, result }) + '\n');
27
+ }
28
+
29
+ function request(method, params, onResult) {
30
+ const id = nextOutgoingId++;
31
+ pendingOutgoing.set(id, onResult);
32
+ process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
33
+ }
34
+
35
+ function notify(method, params) {
36
+ process.stdout.write(JSON.stringify({ jsonrpc: '2.0', method, params }) + '\n');
37
+ }
38
+
39
+ function capture(entry) {
40
+ if (captureFile) {
41
+ appendFileSync(captureFile, JSON.stringify(entry) + '\n');
42
+ }
43
+ }
44
+
45
+ function handlePrompt(msg) {
46
+ if (!elicitationMode) {
47
+ reply(msg.id, { stopReason: 'end_turn' });
48
+ return;
49
+ }
50
+
51
+ const sessionId = msg.params?.sessionId ?? 'fake-acp-session-1';
52
+ const params =
53
+ elicitationMode === 'form'
54
+ ? {
55
+ sessionId,
56
+ mode: 'form',
57
+ message: 'How should I approach this refactoring?',
58
+ requestedSchema: {
59
+ type: 'object',
60
+ properties: {
61
+ strategy: { type: 'string', enum: ['conservative', 'balanced', 'aggressive'] },
62
+ },
63
+ required: ['strategy'],
64
+ },
65
+ }
66
+ : {
67
+ sessionId,
68
+ mode: 'url',
69
+ elicitationId: 'fake-oauth-001',
70
+ url: 'https://agent.example.com/connect?elicitationId=fake-oauth-001',
71
+ message: 'Please authorize access to your repositories.',
72
+ };
73
+
74
+ request('elicitation/create', params, (result) => {
75
+ capture({ method: 'elicitation/create', response: result ?? null });
76
+ reply(msg.id, { stopReason: 'end_turn' });
77
+ if (elicitationMode === 'url') {
78
+ notify('elicitation/complete', { elicitationId: 'fake-oauth-001' });
79
+ }
80
+ });
81
+ }
82
+
83
+ rl.on('line', (line) => {
84
+ let msg;
85
+ try { msg = JSON.parse(line); } catch { return; }
86
+
87
+ // Response to an outgoing request (has id, no method)
88
+ if (msg.id !== undefined && !msg.method) {
89
+ const continuation = pendingOutgoing.get(msg.id);
90
+ if (continuation) {
91
+ pendingOutgoing.delete(msg.id);
92
+ continuation(msg.result);
93
+ }
94
+ return;
95
+ }
96
+
97
+ if (msg.id === undefined || !msg.method) return; // ignore notifications
98
+
99
+ switch (msg.method) {
100
+ case 'initialize':
101
+ if (elicitationMode) {
102
+ capture({ method: 'initialize', params: msg.params });
103
+ }
104
+ reply(msg.id, {
105
+ protocolVersion: 1,
106
+ agentCapabilities: { mcpCapabilities: { http: true, sse: true } },
107
+ agentInfo: { name: 'fake-acp-agent', version: '0.0.1' },
108
+ authMethods: [],
109
+ });
110
+ break;
111
+ case 'session/new':
112
+ case 'session/resume':
113
+ capture({ method: msg.method, params: msg.params });
114
+ reply(msg.id, { sessionId: 'fake-acp-session-1' });
115
+ break;
116
+ case 'session/prompt':
117
+ handlePrompt(msg);
118
+ break;
119
+ default:
120
+ reply(msg.id, {});
121
+ }
122
+ });