import { describe, it, expect } from 'vitest'; import { mergeToolSnapshot, mapToolLifecycleStatus, snapshotToWireToolCall, synthesizeCanceledSnapshots, } from '../acp-tool-snapshot.js'; describe('mergeToolSnapshot', () => { it('preserves stable toolCallId across updates', () => { const first = mergeToolSnapshot('tc-1', { toolCallId: 'tc-1', title: 'Read file', kind: 'read', status: 'in_progress', rawInput: { path: 'foo.ts' }, }); const merged = mergeToolSnapshot( 'tc-1', { toolCallId: 'tc-1', title: 'Read file', status: 'completed', rawOutput: { content: 'hello' }, }, first, ); expect(merged.toolCallId).toBe('tc-1'); expect(merged.rawInput).toEqual({ path: 'foo.ts' }); expect(merged.status).toBe('completed'); expect(merged.rawOutput).toEqual({ content: 'hello' }); }); }); describe('snapshotToWireToolCall', () => { it('embeds ACP lifecycle meta for UI merge', () => { const wire = snapshotToWireToolCall({ toolCallId: 'tc-42', title: 'Edit', kind: 'edit', status: 'completed', rawInput: { path: 'a.ts' }, rawOutput: 'ok', }); expect(wire.id).toBe('tc-42'); expect(wire.name).toBe('edit'); expect(wire.args._acp).toMatchObject({ status: 'completed', title: 'Edit', output: 'ok' }); }); it('maps synthesized cancel to canceled lifecycle', () => { const [canceled] = synthesizeCanceledSnapshots([ { toolCallId: 'tc-1', title: 'Run', status: 'in_progress' }, ]); const wire = snapshotToWireToolCall(canceled!); expect(wire.args._acp).toMatchObject({ status: 'canceled' }); }); }); describe('mapToolLifecycleStatus', () => { it('maps ACP statuses to UI lifecycle', () => { expect(mapToolLifecycleStatus('completed')).toBe('completed'); expect(mapToolLifecycleStatus('failed')).toBe('failed'); expect(mapToolLifecycleStatus('in_progress')).toBe('running'); expect(mapToolLifecycleStatus(undefined, 'canceled')).toBe('canceled'); }); });