agent-gear 1.1.4 → 1.1.6
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.
- package/dist/acp/bridge.d.ts +70 -3
- package/dist/acp/bridge.d.ts.map +1 -1
- package/dist/acp/bridge.js +261 -59
- package/dist/acp/bridge.js.map +1 -1
- package/dist/acp/bridge.test.js +1 -1
- package/dist/acp/bridge.test.js.map +1 -1
- package/dist/acp/detector.d.ts +2 -0
- package/dist/acp/detector.d.ts.map +1 -1
- package/dist/acp/detector.js +28 -2
- package/dist/acp/detector.js.map +1 -1
- package/dist/acp/sync-bridge.d.ts +4 -1
- package/dist/acp/sync-bridge.d.ts.map +1 -1
- package/dist/acp/sync-bridge.js +17 -3
- package/dist/acp/sync-bridge.js.map +1 -1
- package/dist/socketio-client.d.ts.map +1 -1
- package/dist/socketio-client.js +131 -1
- package/dist/socketio-client.js.map +1 -1
- package/package.json +2 -2
- package/src/acp/bridge.test.ts +1 -1
- package/src/acp/bridge.ts +327 -60
- package/src/acp/detector.ts +28 -2
- package/src/acp/sync-bridge.ts +19 -3
- package/src/socketio-client.ts +154 -2
- package/tests/acp-bridge.test.ts +250 -31
- package/tests/acp-detector.test.ts +66 -6
- package/tests/acp-sync-bridge.test.ts +39 -1
- package/tests/socketio-client.test.ts +211 -0
|
@@ -32,21 +32,25 @@ describe('AcpDetector', () => {
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
describe('detect', () => {
|
|
35
|
-
it('should detect all
|
|
35
|
+
it('should detect all 7 servers when all available', async () => {
|
|
36
36
|
mockExecSuccessOnce('opencode v1.2.3\n');
|
|
37
37
|
mockExecSuccessOnce('copilot 1.0.0\n');
|
|
38
38
|
mockExecSuccessOnce('claude-agent-acp 0.1.0\n');
|
|
39
39
|
mockExecSuccessOnce('gemini 2.0.0\n');
|
|
40
40
|
mockExecSuccessOnce('codex-acp 0.5.0\n');
|
|
41
|
+
mockExecSuccessOnce('mimo 0.1.0\n');
|
|
42
|
+
mockExecSuccessOnce('kimi 1.0.0\n');
|
|
41
43
|
|
|
42
44
|
const result = await detector.detect();
|
|
43
45
|
|
|
44
|
-
expect(result).toHaveLength(
|
|
46
|
+
expect(result).toHaveLength(7);
|
|
45
47
|
expect(result[0]).toEqual({ type: 'opencode', available: true, version: '1.2.3' });
|
|
46
48
|
expect(result[1]).toEqual({ type: 'github_copilot', available: true, version: '1.0.0' });
|
|
47
49
|
expect(result[2]).toEqual({ type: 'claude_code', available: true, version: '0.1.0' });
|
|
48
50
|
expect(result[3]).toEqual({ type: 'gemini_cli', available: true, version: '2.0.0' });
|
|
49
51
|
expect(result[4]).toEqual({ type: 'codex', available: true, version: '0.5.0' });
|
|
52
|
+
expect(result[5]).toEqual({ type: 'mimo_code', available: true, version: '0.1.0' });
|
|
53
|
+
expect(result[6]).toEqual({ type: 'kimi_code', available: true, version: '1.0.0' });
|
|
50
54
|
});
|
|
51
55
|
|
|
52
56
|
it('should detect as unavailable when command fails', async () => {
|
|
@@ -55,15 +59,19 @@ describe('AcpDetector', () => {
|
|
|
55
59
|
mockExecFailureOnce();
|
|
56
60
|
mockExecFailureOnce();
|
|
57
61
|
mockExecFailureOnce();
|
|
62
|
+
mockExecFailureOnce();
|
|
63
|
+
mockExecFailureOnce();
|
|
58
64
|
|
|
59
65
|
const result = await detector.detect();
|
|
60
66
|
|
|
61
|
-
expect(result).toHaveLength(
|
|
67
|
+
expect(result).toHaveLength(7);
|
|
62
68
|
expect(result[0]).toEqual({ type: 'opencode', available: false });
|
|
63
69
|
expect(result[1]).toEqual({ type: 'github_copilot', available: false });
|
|
64
70
|
expect(result[2]).toEqual({ type: 'claude_code', available: false });
|
|
65
71
|
expect(result[3]).toEqual({ type: 'gemini_cli', available: false });
|
|
66
72
|
expect(result[4]).toEqual({ type: 'codex', available: false });
|
|
73
|
+
expect(result[5]).toEqual({ type: 'mimo_code', available: false });
|
|
74
|
+
expect(result[6]).toEqual({ type: 'kimi_code', available: false });
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
it('should detect claude_code only when other servers fail', async () => {
|
|
@@ -72,15 +80,19 @@ describe('AcpDetector', () => {
|
|
|
72
80
|
mockExecSuccessOnce('claude-agent-acp 0.1.0\n');
|
|
73
81
|
mockExecFailureOnce();
|
|
74
82
|
mockExecFailureOnce();
|
|
83
|
+
mockExecFailureOnce();
|
|
84
|
+
mockExecFailureOnce();
|
|
75
85
|
|
|
76
86
|
const result = await detector.detect();
|
|
77
87
|
|
|
78
|
-
expect(result).toHaveLength(
|
|
88
|
+
expect(result).toHaveLength(7);
|
|
79
89
|
expect(result[0]).toEqual({ type: 'opencode', available: false });
|
|
80
90
|
expect(result[1]).toEqual({ type: 'github_copilot', available: false });
|
|
81
91
|
expect(result[2]).toEqual({ type: 'claude_code', available: true, version: '0.1.0' });
|
|
82
92
|
expect(result[3]).toEqual({ type: 'gemini_cli', available: false });
|
|
83
93
|
expect(result[4]).toEqual({ type: 'codex', available: false });
|
|
94
|
+
expect(result[5]).toEqual({ type: 'mimo_code', available: false });
|
|
95
|
+
expect(result[6]).toEqual({ type: 'kimi_code', available: false });
|
|
84
96
|
});
|
|
85
97
|
|
|
86
98
|
it('should detect gemini_cli only when other servers fail', async () => {
|
|
@@ -89,10 +101,12 @@ describe('AcpDetector', () => {
|
|
|
89
101
|
mockExecFailureOnce();
|
|
90
102
|
mockExecSuccessOnce('gemini 2.0.0\n');
|
|
91
103
|
mockExecFailureOnce();
|
|
104
|
+
mockExecFailureOnce();
|
|
105
|
+
mockExecFailureOnce();
|
|
92
106
|
|
|
93
107
|
const result = await detector.detect();
|
|
94
108
|
|
|
95
|
-
expect(result).toHaveLength(
|
|
109
|
+
expect(result).toHaveLength(7);
|
|
96
110
|
expect(result[3]).toEqual({ type: 'gemini_cli', available: true, version: '2.0.0' });
|
|
97
111
|
});
|
|
98
112
|
|
|
@@ -102,19 +116,53 @@ describe('AcpDetector', () => {
|
|
|
102
116
|
mockExecFailureOnce();
|
|
103
117
|
mockExecFailureOnce();
|
|
104
118
|
mockExecSuccessOnce('codex-acp 0.5.0\n');
|
|
119
|
+
mockExecFailureOnce();
|
|
120
|
+
mockExecFailureOnce();
|
|
105
121
|
|
|
106
122
|
const result = await detector.detect();
|
|
107
123
|
|
|
108
|
-
expect(result).toHaveLength(
|
|
124
|
+
expect(result).toHaveLength(7);
|
|
109
125
|
expect(result[4]).toEqual({ type: 'codex', available: true, version: '0.5.0' });
|
|
110
126
|
});
|
|
111
127
|
|
|
128
|
+
it('should detect mimo_code only when other servers fail', async () => {
|
|
129
|
+
mockExecFailureOnce();
|
|
130
|
+
mockExecFailureOnce();
|
|
131
|
+
mockExecFailureOnce();
|
|
132
|
+
mockExecFailureOnce();
|
|
133
|
+
mockExecFailureOnce();
|
|
134
|
+
mockExecSuccessOnce('mimo 0.1.0\n');
|
|
135
|
+
mockExecFailureOnce();
|
|
136
|
+
|
|
137
|
+
const result = await detector.detect();
|
|
138
|
+
|
|
139
|
+
expect(result).toHaveLength(7);
|
|
140
|
+
expect(result[5]).toEqual({ type: 'mimo_code', available: true, version: '0.1.0' });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should detect kimi_code only when other servers fail', async () => {
|
|
144
|
+
mockExecFailureOnce();
|
|
145
|
+
mockExecFailureOnce();
|
|
146
|
+
mockExecFailureOnce();
|
|
147
|
+
mockExecFailureOnce();
|
|
148
|
+
mockExecFailureOnce();
|
|
149
|
+
mockExecFailureOnce();
|
|
150
|
+
mockExecSuccessOnce('kimi 2.0.0\n');
|
|
151
|
+
|
|
152
|
+
const result = await detector.detect();
|
|
153
|
+
|
|
154
|
+
expect(result).toHaveLength(7);
|
|
155
|
+
expect(result[6]).toEqual({ type: 'kimi_code', available: true, version: '2.0.0' });
|
|
156
|
+
});
|
|
157
|
+
|
|
112
158
|
it('should parse version with different formats', async () => {
|
|
113
159
|
mockExecSuccessOnce('OpenCode version 2.0.1\n');
|
|
114
160
|
mockExecSuccessOnce('copilot 3.0.0\n');
|
|
115
161
|
mockExecSuccessOnce('v0.1.0\n');
|
|
116
162
|
mockExecSuccessOnce('Gemini 2.0.0\n');
|
|
117
163
|
mockExecSuccessOnce('codex-acp version 0.5.0\n');
|
|
164
|
+
mockExecSuccessOnce('MiMo CLI v1.0.0\n');
|
|
165
|
+
mockExecSuccessOnce('kimi 2.0.0\n');
|
|
118
166
|
|
|
119
167
|
const result = await detector.detect();
|
|
120
168
|
|
|
@@ -123,6 +171,8 @@ describe('AcpDetector', () => {
|
|
|
123
171
|
expect(result[2].version).toBe('0.1.0');
|
|
124
172
|
expect(result[3].version).toBe('2.0.0');
|
|
125
173
|
expect(result[4].version).toBe('0.5.0');
|
|
174
|
+
expect(result[5].version).toBe('1.0.0');
|
|
175
|
+
expect(result[6].version).toBe('2.0.0');
|
|
126
176
|
});
|
|
127
177
|
});
|
|
128
178
|
|
|
@@ -152,6 +202,16 @@ describe('AcpDetector', () => {
|
|
|
152
202
|
expect(config).toEqual({ command: 'codex-acp', args: [] });
|
|
153
203
|
});
|
|
154
204
|
|
|
205
|
+
it('should return mimo_code spawner config', () => {
|
|
206
|
+
const config = detector.getSpawnerConfig('mimo_code');
|
|
207
|
+
expect(config).toEqual({ command: 'mimo', args: ['acp'] });
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should return kimi_code spawner config', () => {
|
|
211
|
+
const config = detector.getSpawnerConfig('kimi_code');
|
|
212
|
+
expect(config).toEqual({ command: 'kimi', args: ['acp'] });
|
|
213
|
+
});
|
|
214
|
+
|
|
155
215
|
it('should return opencode as default for unknown serverType', () => {
|
|
156
216
|
const config = detector.getSpawnerConfig('unknown_server');
|
|
157
217
|
expect(config).toEqual({ command: 'opencode', args: ['acp'] });
|
|
@@ -4,8 +4,9 @@ function buildMockConn() {
|
|
|
4
4
|
return {
|
|
5
5
|
initialize: vi.fn<[unknown], Promise<{ protocolVersion: number }>>().mockResolvedValue({ protocolVersion: 1 }),
|
|
6
6
|
newSession: vi.fn<[unknown], Promise<{ sessionId: string }>>().mockResolvedValue({ sessionId: 'sync-sess-1' }),
|
|
7
|
-
listSessions: vi.fn<[unknown], Promise<{ sessions: Array<{ sessionId: string; title: string | null; cwd: string; updatedAt: string | null }
|
|
7
|
+
listSessions: vi.fn<[unknown], Promise<{ sessions: Array<{ sessionId: string; title: string | null; cwd: string; updatedAt: string | null }>; nextCursor?: string | null }>>()
|
|
8
8
|
.mockResolvedValue({ sessions: [{ sessionId: 'hist-1', title: 'Session 1', cwd: '/home/user', updatedAt: '2026-01-01T00:00:00Z' }] }),
|
|
9
|
+
deleteSession: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
|
|
9
10
|
loadSession: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
|
|
10
11
|
cancel: vi.fn<[unknown], Promise<void>>().mockResolvedValue(undefined),
|
|
11
12
|
closeSession: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
|
|
@@ -128,6 +129,43 @@ describe('AcpSyncBridge', () => {
|
|
|
128
129
|
|
|
129
130
|
expect(result.sessions).toEqual([]);
|
|
130
131
|
});
|
|
132
|
+
|
|
133
|
+
it('should throw when not connected', async () => {
|
|
134
|
+
const bridge = createBridge(new MockAcpSpawner());
|
|
135
|
+
await expect(bridge.listSessions('/home/user')).rejects.toThrow('ACP connection not established');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should pass cursor to ACP and return nextCursor', async () => {
|
|
139
|
+
mc().listSessions.mockResolvedValue({
|
|
140
|
+
sessions: [{ sessionId: 'hist-2', title: 'Session 2', cwd: '/home/user', updatedAt: null }],
|
|
141
|
+
nextCursor: 'cursor-2',
|
|
142
|
+
});
|
|
143
|
+
const mockSpawner = new MockAcpSpawner();
|
|
144
|
+
const bridge = createBridge(mockSpawner);
|
|
145
|
+
await bridge.connect();
|
|
146
|
+
|
|
147
|
+
const result = await bridge.listSessions('/home/user', 'cursor-1');
|
|
148
|
+
|
|
149
|
+
expect(mc().listSessions).toHaveBeenCalledWith({ cwd: '/home/user', cursor: 'cursor-1' });
|
|
150
|
+
expect(result.nextCursor).toBe('cursor-2');
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('deleteSession', () => {
|
|
155
|
+
it('should call ACP deleteSession with the given session ID', async () => {
|
|
156
|
+
const mockSpawner = new MockAcpSpawner();
|
|
157
|
+
const bridge = createBridge(mockSpawner);
|
|
158
|
+
await bridge.connect();
|
|
159
|
+
|
|
160
|
+
await bridge.deleteSession('hist-1');
|
|
161
|
+
|
|
162
|
+
expect(mc().deleteSession).toHaveBeenCalledWith({ sessionId: 'hist-1' });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should throw when not connected', async () => {
|
|
166
|
+
const bridge = createBridge(new MockAcpSpawner());
|
|
167
|
+
await expect(bridge.deleteSession('hist-1')).rejects.toThrow();
|
|
168
|
+
});
|
|
131
169
|
});
|
|
132
170
|
|
|
133
171
|
describe('loadSession', () => {
|
|
@@ -9,6 +9,25 @@ const { mockStart, mockStop, MockHeartbeat } = vi.hoisted(() => {
|
|
|
9
9
|
return { mockStart: start, mockStop: stop, MockHeartbeat: HB };
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
+
const { MockAcpSyncBridge, mockBridge } = vi.hoisted(() => {
|
|
13
|
+
const bridge = {
|
|
14
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
15
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
16
|
+
listSessions: vi.fn(),
|
|
17
|
+
deleteSession: vi.fn(),
|
|
18
|
+
supportsDelete: vi.fn(),
|
|
19
|
+
start: vi.fn(),
|
|
20
|
+
stop: vi.fn(),
|
|
21
|
+
resume: vi.fn(),
|
|
22
|
+
};
|
|
23
|
+
const Cls = vi.fn(function () { return bridge; });
|
|
24
|
+
return { MockAcpSyncBridge: Cls, mockBridge: bridge };
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
vi.mock('../src/acp/sync-bridge.js', () => ({
|
|
28
|
+
AcpSyncBridge: MockAcpSyncBridge,
|
|
29
|
+
}));
|
|
30
|
+
|
|
12
31
|
vi.mock('socket.io-client', () => ({
|
|
13
32
|
io: vi.fn(),
|
|
14
33
|
}));
|
|
@@ -316,4 +335,196 @@ describe('SocketIO Client', () => {
|
|
|
316
335
|
});
|
|
317
336
|
});
|
|
318
337
|
});
|
|
338
|
+
|
|
339
|
+
describe('acp:list-sessions', () => {
|
|
340
|
+
function setup() {
|
|
341
|
+
mockBridge.connect.mockClear();
|
|
342
|
+
mockBridge.disconnect.mockClear();
|
|
343
|
+
mockBridge.listSessions.mockClear();
|
|
344
|
+
const mockSocket = createMockSocket();
|
|
345
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
346
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123');
|
|
347
|
+
mockSocket._trigger('connect');
|
|
348
|
+
mockSocket._trigger('registered', { controllerId: 'ctrl-1' });
|
|
349
|
+
return mockSocket;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
it('should pass cursor and emit nextCursor in result', async () => {
|
|
353
|
+
mockBridge.listSessions.mockResolvedValue({
|
|
354
|
+
sessions: [{ sessionId: 'hist-2', title: 'Session 2', cwd: '/home/user', updatedAt: null }],
|
|
355
|
+
nextCursor: 'cursor-2',
|
|
356
|
+
});
|
|
357
|
+
const mockSocket = setup();
|
|
358
|
+
|
|
359
|
+
mockSocket._trigger('acp:list-sessions', {
|
|
360
|
+
requestId: 'req-1',
|
|
361
|
+
serverType: 'opencode',
|
|
362
|
+
cwd: '/home/user',
|
|
363
|
+
cursor: 'cursor-1',
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
await vi.waitFor(() => {
|
|
367
|
+
expect(mockBridge.listSessions).toHaveBeenCalledWith('/home/user', 'cursor-1');
|
|
368
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:list-sessions:result', {
|
|
369
|
+
requestId: 'req-1',
|
|
370
|
+
success: true,
|
|
371
|
+
sessions: [{ sessionId: 'hist-2', title: 'Session 2', cwd: '/home/user', updatedAt: null }],
|
|
372
|
+
nextCursor: 'cursor-2',
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('should omit nextCursor when absent', async () => {
|
|
378
|
+
mockBridge.listSessions.mockResolvedValue({
|
|
379
|
+
sessions: [{ sessionId: 'hist-1', title: 'Session 1', cwd: '/home/user', updatedAt: null }],
|
|
380
|
+
});
|
|
381
|
+
const mockSocket = setup();
|
|
382
|
+
|
|
383
|
+
mockSocket._trigger('acp:list-sessions', {
|
|
384
|
+
requestId: 'req-2',
|
|
385
|
+
serverType: 'opencode',
|
|
386
|
+
cwd: '/home/user',
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
await vi.waitFor(() => {
|
|
390
|
+
expect(mockBridge.listSessions).toHaveBeenCalledWith('/home/user', undefined);
|
|
391
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:list-sessions:result', {
|
|
392
|
+
requestId: 'req-2',
|
|
393
|
+
success: true,
|
|
394
|
+
sessions: [{ sessionId: 'hist-1', title: 'Session 1', cwd: '/home/user', updatedAt: null }],
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('should emit failure result on error', async () => {
|
|
400
|
+
mockBridge.listSessions.mockRejectedValue(new Error('boom'));
|
|
401
|
+
const mockSocket = setup();
|
|
402
|
+
|
|
403
|
+
mockSocket._trigger('acp:list-sessions', {
|
|
404
|
+
requestId: 'req-3',
|
|
405
|
+
serverType: 'opencode',
|
|
406
|
+
cwd: '/home/user',
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
await vi.waitFor(() => {
|
|
410
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:list-sessions:result', {
|
|
411
|
+
requestId: 'req-3',
|
|
412
|
+
success: false,
|
|
413
|
+
error: 'boom',
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
describe('acp:set-config-option', () => {
|
|
420
|
+
it('should emit failure result when bridge not found', async () => {
|
|
421
|
+
const mockSocket = createMockSocket();
|
|
422
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
423
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123');
|
|
424
|
+
mockSocket._trigger('connect');
|
|
425
|
+
mockSocket._trigger('registered', { controllerId: 'ctrl-1' });
|
|
426
|
+
|
|
427
|
+
mockSocket._trigger('acp:set-config-option', {
|
|
428
|
+
sessionId: 'unknown-sess',
|
|
429
|
+
configId: 'opt-1',
|
|
430
|
+
value: 'val-1',
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
await vi.waitFor(() => {
|
|
434
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:set-config-option:result', {
|
|
435
|
+
sessionId: 'unknown-sess',
|
|
436
|
+
success: false,
|
|
437
|
+
configId: 'opt-1',
|
|
438
|
+
error: 'ACP bridge not found for session',
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
describe('acp:delete-history-session', () => {
|
|
445
|
+
function setup() {
|
|
446
|
+
mockBridge.connect.mockClear();
|
|
447
|
+
mockBridge.disconnect.mockClear();
|
|
448
|
+
mockBridge.deleteSession.mockClear();
|
|
449
|
+
mockBridge.supportsDelete.mockClear();
|
|
450
|
+
const mockSocket = createMockSocket();
|
|
451
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
452
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123');
|
|
453
|
+
mockSocket._trigger('connect');
|
|
454
|
+
mockSocket._trigger('registered', { controllerId: 'ctrl-1' });
|
|
455
|
+
return mockSocket;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
it('should delete session via sync bridge when supported', async () => {
|
|
459
|
+
mockBridge.supportsDelete.mockReturnValue(true);
|
|
460
|
+
mockBridge.deleteSession.mockResolvedValue(undefined);
|
|
461
|
+
const mockSocket = setup();
|
|
462
|
+
|
|
463
|
+
mockSocket._trigger('acp:delete-history-session', {
|
|
464
|
+
requestId: 'req-1',
|
|
465
|
+
sessionId: 'db-id-1',
|
|
466
|
+
externalSessionId: 'ext-1',
|
|
467
|
+
cwd: '/home/user',
|
|
468
|
+
serverType: 'opencode',
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
await vi.waitFor(() => {
|
|
472
|
+
expect(mockBridge.connect).toHaveBeenCalled();
|
|
473
|
+
expect(mockBridge.supportsDelete).toHaveBeenCalled();
|
|
474
|
+
expect(mockBridge.deleteSession).toHaveBeenCalledWith('ext-1');
|
|
475
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:delete-history-session:result', {
|
|
476
|
+
requestId: 'req-1',
|
|
477
|
+
sessionId: 'db-id-1',
|
|
478
|
+
success: true,
|
|
479
|
+
supported: true,
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it('should report unsupported without deleting when agent lacks capability', async () => {
|
|
485
|
+
mockBridge.supportsDelete.mockReturnValue(false);
|
|
486
|
+
const mockSocket = setup();
|
|
487
|
+
|
|
488
|
+
mockSocket._trigger('acp:delete-history-session', {
|
|
489
|
+
requestId: 'req-2',
|
|
490
|
+
sessionId: 'db-id-2',
|
|
491
|
+
externalSessionId: 'ext-2',
|
|
492
|
+
cwd: '/home/user',
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
await vi.waitFor(() => {
|
|
496
|
+
expect(mockBridge.deleteSession).not.toHaveBeenCalled();
|
|
497
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:delete-history-session:result', {
|
|
498
|
+
requestId: 'req-2',
|
|
499
|
+
sessionId: 'db-id-2',
|
|
500
|
+
success: false,
|
|
501
|
+
supported: false,
|
|
502
|
+
error: 'Session delete not supported by agent',
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
it('should emit failure result on error', async () => {
|
|
508
|
+
mockBridge.supportsDelete.mockReturnValue(true);
|
|
509
|
+
mockBridge.deleteSession.mockRejectedValue(new Error('boom'));
|
|
510
|
+
const mockSocket = setup();
|
|
511
|
+
|
|
512
|
+
mockSocket._trigger('acp:delete-history-session', {
|
|
513
|
+
requestId: 'req-3',
|
|
514
|
+
sessionId: 'db-id-3',
|
|
515
|
+
externalSessionId: 'ext-3',
|
|
516
|
+
cwd: '/home/user',
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
await vi.waitFor(() => {
|
|
520
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('acp:delete-history-session:result', {
|
|
521
|
+
requestId: 'req-3',
|
|
522
|
+
sessionId: 'db-id-3',
|
|
523
|
+
success: false,
|
|
524
|
+
supported: true,
|
|
525
|
+
error: 'boom',
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
});
|
|
319
530
|
});
|