import { describe, expect, it } from 'vitest' import { handoffAttachmentName, parseHandoffManifest } from './handoffManifest' const UUID = '11111111-1111-4111-8111-111111111111' const good = { version: 1, issue: 42, from: 'chw', createdAt: '2026-08-26T00:00:00Z', branch: 'feature/x', sessions: { implementSessionId: 'a' }, profiles: {}, claude: [{ id: UUID, kind: 'implement' }], codex: [], } describe('handoffAttachmentName', () => { it('固定命名', () => { expect(handoffAttachmentName(42)).toBe('spx-handoff-issue-42.tgz') }) }) describe('parseHandoffManifest', () => { it('合法清单原样返回', () => { expect(parseHandoffManifest(JSON.stringify(good), 42)).toEqual(good) }) it('issue 不匹配 → 抛错', () => { expect(() => parseHandoffManifest(JSON.stringify(good), 43)).toThrow(/42/) }) it('version 不是 1 → 抛错', () => { expect(() => parseHandoffManifest(JSON.stringify({ ...good, version: 2 }), 42)).toThrow(/version/) }) it('claude 条目 kind 非法 → 抛错', () => { expect(() => parseHandoffManifest(JSON.stringify({ ...good, claude: [{ id: UUID, kind: 'x' }] }), 42)).toThrow(/claude/) }) it('claude 条目 id 非 UUID(路径穿越)→ 抛错', () => { expect(() => parseHandoffManifest(JSON.stringify({ ...good, claude: [{ id: '../x', kind: 'implement' }] }), 42)).toThrow(/claude/) }) it('codex 条目 id 非 UUID → 抛错', () => { expect(() => parseHandoffManifest(JSON.stringify({ ...good, codex: [{ id: 'not-a-uuid', relPath: '2026/08/26/rollout-x.jsonl' }] }), 42)).toThrow(/codex/) }) it('不是 JSON → 抛错', () => { expect(() => parseHandoffManifest('nope', 42)).toThrow() }) it('带 worktreePath → 原样带出', () => { const withPath = { ...good, worktreePath: '/Users/chw/wt/x' } expect(parseHandoffManifest(JSON.stringify(withPath), 42)).toEqual(withPath) }) it('不带 worktreePath → 结果里没有这个 key', () => { expect(parseHandoffManifest(JSON.stringify(good), 42)).not.toHaveProperty('worktreePath') }) })