agent-gear 1.1.5 → 1.1.7

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.
@@ -9,7 +9,9 @@ function buildMockConn() {
9
9
  cancel: vi.fn<[unknown], Promise<void>>().mockResolvedValue(undefined),
10
10
  closeSession: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
11
11
  setSessionMode: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
12
- unstable_setSessionModel: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
12
+ setSessionConfigOption: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
13
+ authenticate: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
14
+ logout: vi.fn<[unknown], Promise<object>>().mockResolvedValue({}),
13
15
  };
14
16
  }
15
17
 
@@ -18,9 +20,13 @@ let mockConnInstance = buildMockConn();
18
20
  vi.mock('@agentclientprotocol/sdk', () => ({
19
21
  ndJsonStream: vi.fn(() => ({})),
20
22
  ClientSideConnection: vi.fn(function () { return mockConnInstance; }),
23
+ CreateElicitationRequest: {
24
+ isForm: (v: { mode?: string }) => v.mode === 'form',
25
+ isUrl: (v: { mode?: string }) => v.mode === 'url',
26
+ },
21
27
  }));
22
28
 
23
- import { AcpSessionBridge } from '../../src/acp/bridge.js';
29
+ import { AcpSessionBridge, extractConfigOptions } from '../../src/acp/bridge.js';
24
30
 
25
31
  class MockAcpSpawner {
26
32
  start = vi.fn();
@@ -74,8 +80,13 @@ describe('AcpSessionBridge', () => {
74
80
  expect(mockSpawner.start).toHaveBeenCalledOnce();
75
81
  expect(mc().initialize).toHaveBeenCalledWith({
76
82
  protocolVersion: 1,
77
- clientCapabilities: {},
78
- clientInfo: { name: 'agent-gear', version: '1.0.0' },
83
+ clientCapabilities: {
84
+ session: {
85
+ configOptions: { boolean: {} },
86
+ },
87
+ elicitation: { form: {}, url: {} },
88
+ },
89
+ clientInfo: { name: 'agent-gear', version: '1.1.5' },
79
90
  });
80
91
  expect(mc().newSession).toHaveBeenCalledWith({
81
92
  cwd: '/home/user',
@@ -121,10 +132,16 @@ describe('AcpSessionBridge', () => {
121
132
  it('should include currentModel in acp:initialized when available', async () => {
122
133
  mockConnInstance.newSession = vi.fn().mockResolvedValue({
123
134
  sessionId: 'acp-sess-abc',
124
- models: {
125
- availableModels: [{ modelId: 'gpt-4', name: 'GPT-4' }],
126
- currentModelId: 'gpt-4',
127
- },
135
+ configOptions: [
136
+ {
137
+ id: 'model',
138
+ name: 'Model',
139
+ category: 'model',
140
+ type: 'select',
141
+ currentValue: 'gpt-4',
142
+ options: [{ value: 'gpt-4', name: 'GPT-4' }],
143
+ },
144
+ ],
128
145
  });
129
146
  const bridge = createBridge();
130
147
  const emitSpy = vi.fn();
@@ -141,13 +158,19 @@ describe('AcpSessionBridge', () => {
141
158
  it('should include availableModels and currentModelId in acp:initialized', async () => {
142
159
  mockConnInstance.newSession = vi.fn().mockResolvedValue({
143
160
  sessionId: 'acp-sess-abc',
144
- models: {
145
- availableModels: [
146
- { modelId: 'gpt-4', name: 'GPT-4' },
147
- { modelId: 'claude-3', name: 'Claude 3' },
148
- ],
149
- currentModelId: 'claude-3',
150
- },
161
+ configOptions: [
162
+ {
163
+ id: 'model',
164
+ name: 'Model',
165
+ category: 'model',
166
+ type: 'select',
167
+ currentValue: 'claude-3',
168
+ options: [
169
+ { value: 'gpt-4', name: 'GPT-4' },
170
+ { value: 'claude-3', name: 'Claude 3' },
171
+ ],
172
+ },
173
+ ],
151
174
  });
152
175
  const bridge = createBridge();
153
176
  const emitSpy = vi.fn();
@@ -165,6 +188,22 @@ describe('AcpSessionBridge', () => {
165
188
  }));
166
189
  });
167
190
 
191
+ it('should map auth method without type field to kind agent', async () => {
192
+ mc().initialize.mockResolvedValue({
193
+ protocolVersion: 1,
194
+ authMethods: [{ id: 'oauth', description: 'Login with agent' }],
195
+ });
196
+ const bridge = createBridge();
197
+
198
+ bridge.start();
199
+ await vi.advanceTimersByTimeAsync(0);
200
+
201
+ expect(mockSocket.emit).toHaveBeenCalledWith('acp:auth:required', {
202
+ sessionId: 'sess-1',
203
+ authMethods: [{ id: 'oauth', kind: 'agent', description: null, url: null }],
204
+ });
205
+ });
206
+
168
207
  it('should emit acp:stopped on initialize failure', async () => {
169
208
  mc().initialize.mockRejectedValue(new Error('init failed'));
170
209
  const bridge = createBridge();
@@ -201,6 +240,7 @@ describe('AcpSessionBridge', () => {
201
240
  expect(mc().resumeSession).toHaveBeenCalledWith({
202
241
  sessionId: 'existing-sess-id',
203
242
  cwd: '/home/user',
243
+ mcpServers: [],
204
244
  });
205
245
  expect(emitSpy).toHaveBeenCalledWith(expect.objectContaining({
206
246
  sessionId: 'sess-1',
@@ -491,6 +531,119 @@ describe('AcpSessionBridge', () => {
491
531
  });
492
532
  });
493
533
 
534
+ describe('unstable_createElicitation', () => {
535
+ it('form 模式:emit acp:elicitation 并在响应后 resolve accept + content', async () => {
536
+ const bridge = createBridge();
537
+ const requestedSchema = {
538
+ type: 'object',
539
+ properties: { name: { type: 'string' } },
540
+ required: ['name'],
541
+ };
542
+
543
+ const promise = bridge.unstable_createElicitation({
544
+ mode: 'form',
545
+ message: 'Need your name',
546
+ sessionId: 'acp-sess-abc',
547
+ toolCallId: 'tc-1',
548
+ requestedSchema,
549
+ } as never);
550
+
551
+ expect(mockSocket.emit).toHaveBeenCalledWith('acp:elicitation', expect.objectContaining({
552
+ sessionId: 'sess-1',
553
+ mode: 'form',
554
+ message: 'Need your name',
555
+ toolCallId: 'tc-1',
556
+ requestedSchema,
557
+ }));
558
+
559
+ const emitCall = mockSocket.emit.mock.calls.find((c: unknown[]) => c[0] === 'acp:elicitation');
560
+ const requestId = (emitCall![1] as { requestId: string }).requestId;
561
+ expect(requestId).toMatch(/^elic_/);
562
+
563
+ bridge.handleElicitationResponse(requestId, 'accept', { name: 'ash' });
564
+
565
+ const result = await promise;
566
+ expect(result).toEqual({ action: 'accept', content: { name: 'ash' } });
567
+ });
568
+
569
+ it('url 模式:透传 elicitationId 与 url', async () => {
570
+ const bridge = createBridge();
571
+
572
+ const promise = bridge.unstable_createElicitation({
573
+ mode: 'url',
574
+ message: 'Authorize access',
575
+ sessionId: 'acp-sess-abc',
576
+ elicitationId: 'elic-agent-1',
577
+ url: 'https://example.com/auth',
578
+ } as never);
579
+
580
+ expect(mockSocket.emit).toHaveBeenCalledWith('acp:elicitation', expect.objectContaining({
581
+ sessionId: 'sess-1',
582
+ mode: 'url',
583
+ message: 'Authorize access',
584
+ elicitationId: 'elic-agent-1',
585
+ url: 'https://example.com/auth',
586
+ }));
587
+
588
+ const emitCall = mockSocket.emit.mock.calls.find((c: unknown[]) => c[0] === 'acp:elicitation');
589
+ const requestId = (emitCall![1] as { requestId: string }).requestId;
590
+ bridge.handleElicitationResponse(requestId, 'decline');
591
+
592
+ const result = await promise;
593
+ expect(result).toEqual({ action: 'decline' });
594
+ });
595
+
596
+ it('custom/未知模式:立即返回 cancel 且不 emit socket 事件', async () => {
597
+ const bridge = createBridge();
598
+
599
+ const result = await bridge.unstable_createElicitation({
600
+ mode: '_vendor_custom',
601
+ message: 'custom request',
602
+ sessionId: 'acp-sess-abc',
603
+ } as never);
604
+
605
+ expect(result).toEqual({ action: 'cancel' });
606
+ expect(mockSocket.emit).not.toHaveBeenCalledWith('acp:elicitation', expect.anything());
607
+ });
608
+
609
+ it('65s 超时自动 resolve cancel', async () => {
610
+ const bridge = createBridge();
611
+
612
+ const promise = bridge.unstable_createElicitation({
613
+ mode: 'form',
614
+ message: 'm',
615
+ sessionId: 'acp-sess-abc',
616
+ requestedSchema: { type: 'object' },
617
+ } as never);
618
+
619
+ await vi.advanceTimersByTimeAsync(65_000);
620
+
621
+ const result = await promise;
622
+ expect(result).toEqual({ action: 'cancel' });
623
+ });
624
+
625
+ it('handleElicitationResponse 未知 requestId 打 warn 不抛错', () => {
626
+ const bridge = createBridge();
627
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
628
+
629
+ expect(() => bridge.handleElicitationResponse('elic_unknown', 'cancel')).not.toThrow();
630
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('elic_unknown'));
631
+ });
632
+ });
633
+
634
+ describe('unstable_completeElicitation', () => {
635
+ it('emit acp:elicitation:complete', async () => {
636
+ const bridge = createBridge();
637
+
638
+ await bridge.unstable_completeElicitation({ elicitationId: 'elic-agent-1' } as never);
639
+
640
+ expect(mockSocket.emit).toHaveBeenCalledWith('acp:elicitation:complete', {
641
+ sessionId: 'sess-1',
642
+ elicitationId: 'elic-agent-1',
643
+ });
644
+ });
645
+ });
646
+
494
647
  describe('setMode', () => {
495
648
  it('should call connection.setSessionMode', async () => {
496
649
  const bridge = createBridge();
@@ -511,51 +664,236 @@ describe('AcpSessionBridge', () => {
511
664
  await expect(bridge.setMode('mode-1')).resolves.toBeUndefined();
512
665
  expect(mc().setSessionMode).not.toHaveBeenCalled();
513
666
  });
667
+
668
+ it('should use setSessionConfigOption when mode config option exists', async () => {
669
+ mockConnInstance.newSession = vi.fn().mockResolvedValue({
670
+ sessionId: 'acp-sess-abc',
671
+ configOptions: [
672
+ {
673
+ id: 'mode',
674
+ name: 'Mode',
675
+ category: 'mode',
676
+ type: 'select',
677
+ currentValue: 'code',
678
+ options: [{ value: 'code', name: 'Code' }, { value: 'plan', name: 'Plan' }],
679
+ },
680
+ ],
681
+ });
682
+ const bridge = createBridge();
683
+ bridge.start();
684
+ await vi.advanceTimersByTimeAsync(0);
685
+
686
+ await bridge.setMode('plan');
687
+
688
+ expect(mc().setSessionConfigOption).toHaveBeenCalledWith({
689
+ sessionId: 'acp-sess-abc',
690
+ configId: 'mode',
691
+ value: 'plan',
692
+ });
693
+ });
514
694
  });
515
695
 
516
696
  describe('setModel', () => {
517
- it('should call connection.unstable_setSessionModel with correct params', async () => {
697
+ it('should call setSessionConfigOption when model config option exists', async () => {
698
+ mockConnInstance.newSession = vi.fn().mockResolvedValue({
699
+ sessionId: 'acp-sess-abc',
700
+ configOptions: [
701
+ {
702
+ id: 'model',
703
+ name: 'Model',
704
+ category: 'model',
705
+ type: 'select',
706
+ currentValue: 'gpt-4',
707
+ options: [{ value: 'gpt-4', name: 'GPT-4' }, { value: 'claude-3', name: 'Claude 3' }],
708
+ },
709
+ ],
710
+ });
518
711
  const bridge = createBridge();
519
712
  bridge.start();
520
713
  await vi.advanceTimersByTimeAsync(0);
521
714
 
522
- await bridge.setModel('model-2');
715
+ await bridge.setModel('claude-3');
523
716
 
524
- expect(mc().unstable_setSessionModel).toHaveBeenCalledWith({
717
+ expect(mc().setSessionConfigOption).toHaveBeenCalledWith({
525
718
  sessionId: 'acp-sess-abc',
526
- modelId: 'model-2',
719
+ configId: 'model',
720
+ value: 'claude-3',
527
721
  });
528
722
  });
529
723
 
724
+ it('should throw when initialized but no model config option', async () => {
725
+ const bridge = createBridge();
726
+ bridge.start();
727
+ await vi.advanceTimersByTimeAsync(0);
728
+
729
+ await expect(bridge.setModel('model-1')).rejects.toThrow(
730
+ 'Model switching is not supported',
731
+ );
732
+ expect(mc().setSessionConfigOption).not.toHaveBeenCalled();
733
+ });
734
+
530
735
  it('should not throw when not initialized', async () => {
531
736
  const bridge = createBridge();
532
737
 
533
738
  await expect(bridge.setModel('model-1')).resolves.toBeUndefined();
534
- expect(mc().unstable_setSessionModel).not.toHaveBeenCalled();
535
739
  });
536
740
  });
537
741
 
538
- describe('extractAvailableModels', () => {
539
- it('should return empty array when models is null', () => {
742
+ describe('setConfigOption', () => {
743
+ it('should call connection.setSessionConfigOption with boolean value', async () => {
540
744
  const bridge = createBridge();
745
+ bridge.start();
746
+ await vi.advanceTimersByTimeAsync(0);
747
+
748
+ await bridge.setConfigOption('opt-1', true);
541
749
 
542
- // Access private method via bracket notation
543
- const result = (bridge as unknown as Record<string, unknown>).extractAvailableModels(null);
544
- expect(result).toEqual([]);
750
+ expect(mc().setSessionConfigOption).toHaveBeenCalledWith({
751
+ sessionId: 'acp-sess-abc',
752
+ configId: 'opt-1',
753
+ value: true,
754
+ type: 'boolean',
755
+ });
545
756
  });
546
757
 
547
- it('should return empty array when models is undefined', () => {
758
+ it('should call connection.setSessionConfigOption with select value', async () => {
548
759
  const bridge = createBridge();
760
+ bridge.start();
761
+ await vi.advanceTimersByTimeAsync(0);
549
762
 
550
- const result = (bridge as unknown as Record<string, unknown>).extractAvailableModels(undefined);
551
- expect(result).toEqual([]);
763
+ await bridge.setConfigOption('opt-2', 'val-1');
764
+
765
+ expect(mc().setSessionConfigOption).toHaveBeenCalledWith({
766
+ sessionId: 'acp-sess-abc',
767
+ configId: 'opt-2',
768
+ value: 'val-1',
769
+ });
552
770
  });
553
771
 
554
- it('should return empty array when availableModels is missing', () => {
772
+ it('should update snapshot and emit acp:config-options from set_config_option response', async () => {
773
+ mockConnInstance.setSessionConfigOption = vi.fn().mockResolvedValue({
774
+ configOptions: [
775
+ {
776
+ id: 'flags',
777
+ name: 'Flags',
778
+ category: null,
779
+ type: 'boolean',
780
+ currentValue: true,
781
+ },
782
+ ],
783
+ });
555
784
  const bridge = createBridge();
785
+ bridge.start();
786
+ await vi.advanceTimersByTimeAsync(0);
556
787
 
557
- const result = (bridge as unknown as Record<string, unknown>).extractAvailableModels({});
558
- expect(result).toEqual([]);
788
+ await bridge.setConfigOption('flags', 'true');
789
+
790
+ expect(bridge.getConfigOptions()).toEqual([
791
+ {
792
+ id: 'flags',
793
+ name: 'Flags',
794
+ description: null,
795
+ category: null,
796
+ type: 'boolean',
797
+ currentValue: 'true',
798
+ options: [],
799
+ },
800
+ ]);
801
+ expect(mockSocket.emit).toHaveBeenCalledWith('acp:config-options', {
802
+ sessionId: 'sess-1',
803
+ configOptions: bridge.getConfigOptions(),
804
+ });
805
+ });
806
+
807
+ it('should not emit acp:config-options when response has no configOptions', async () => {
808
+ mockConnInstance.setSessionConfigOption = vi.fn().mockResolvedValue({});
809
+ const bridge = createBridge();
810
+ bridge.start();
811
+ await vi.advanceTimersByTimeAsync(0);
812
+
813
+ await bridge.setConfigOption('opt-2', 'val-1');
814
+
815
+ expect(mockSocket.emit).not.toHaveBeenCalledWith('acp:config-options', expect.anything());
816
+ });
817
+ });
818
+
819
+ describe('extractConfigOptions', () => {
820
+ it('should return empty array when configOptions is null or undefined', () => {
821
+ expect(extractConfigOptions(null)).toEqual([]);
822
+ expect(extractConfigOptions(undefined)).toEqual([]);
823
+ });
824
+
825
+ it('should flatten grouped select options with group name prefix', () => {
826
+ const result = extractConfigOptions([
827
+ {
828
+ id: 'model',
829
+ name: 'Model',
830
+ category: 'model',
831
+ type: 'select',
832
+ currentValue: 'gpt-4',
833
+ options: [
834
+ {
835
+ group: 'openai',
836
+ name: 'OpenAI',
837
+ options: [
838
+ { value: 'gpt-4', name: 'GPT-4' },
839
+ { value: 'gpt-4o', name: 'GPT-4o' },
840
+ ],
841
+ },
842
+ {
843
+ group: 'anthropic',
844
+ name: 'Anthropic',
845
+ options: [{ value: 'claude-3', name: 'Claude 3' }],
846
+ },
847
+ ],
848
+ },
849
+ ]);
850
+
851
+ expect(result[0].options).toEqual([
852
+ { value: 'gpt-4', name: 'OpenAI/GPT-4' },
853
+ { value: 'gpt-4o', name: 'OpenAI/GPT-4o' },
854
+ { value: 'claude-3', name: 'Anthropic/Claude 3' },
855
+ ]);
856
+ });
857
+
858
+ it('should map select and boolean config options', () => {
859
+ const result = extractConfigOptions([
860
+ {
861
+ id: 'model',
862
+ name: 'Model',
863
+ category: 'model',
864
+ type: 'select',
865
+ currentValue: 'gpt-4',
866
+ options: [{ value: 'gpt-4', name: 'GPT-4' }],
867
+ },
868
+ {
869
+ id: 'flags',
870
+ name: 'Flags',
871
+ category: null,
872
+ type: 'boolean',
873
+ currentValue: true,
874
+ },
875
+ ]);
876
+
877
+ expect(result).toEqual([
878
+ {
879
+ id: 'model',
880
+ name: 'Model',
881
+ description: null,
882
+ category: 'model',
883
+ type: 'select',
884
+ currentValue: 'gpt-4',
885
+ options: [{ value: 'gpt-4', name: 'GPT-4' }],
886
+ },
887
+ {
888
+ id: 'flags',
889
+ name: 'Flags',
890
+ description: null,
891
+ category: null,
892
+ type: 'boolean',
893
+ currentValue: 'true',
894
+ options: [],
895
+ },
896
+ ]);
559
897
  });
560
898
  });
561
899
  });
@@ -68,7 +68,34 @@ describe('AcpSpawner', () => {
68
68
  spawner.start();
69
69
  const stderr = mockProcess.stderr as Readable;
70
70
  stderr.emit('data', Buffer.from('some warning\n'));
71
- expect(consoleErrorSpy).toHaveBeenCalledWith('ACP stderr: some warning\n');
71
+ expect(consoleErrorSpy).toHaveBeenCalledWith('ACP stderr (session=sess-1): some warning\n');
72
+ });
73
+
74
+ it('should log resolved command, args and cwd on start', () => {
75
+ const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
76
+ spawner.start();
77
+ expect(consoleLogSpy).toHaveBeenCalledWith(
78
+ 'Starting ACP server: session=sess-1 cmd=/usr/bin/opencode args=["acp"] cwd=/tmp/project',
79
+ );
80
+ });
81
+
82
+ it('should log exit code, signal and spawn params on process exit', () => {
83
+ const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
84
+ spawner.start();
85
+ mockProcess.emit('exit', 1, null);
86
+ expect(consoleLogSpy).toHaveBeenCalledWith(
87
+ 'ACP process exited: session=sess-1 code=1 signal=null cmd=/usr/bin/opencode args=["acp"]',
88
+ );
89
+ });
90
+
91
+ it('should log process error with session and command', () => {
92
+ spawner.start();
93
+ const error = new Error('spawn opencode ENOENT');
94
+ mockProcess.emit('error', error);
95
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
96
+ 'ACP process error (session=sess-1, cmd=/usr/bin/opencode):',
97
+ error,
98
+ );
72
99
  });
73
100
 
74
101
  it('should resolve closed on process exit', async () => {
@@ -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', () => {