{"version":3,"file":"working-context.test.d.ts","sourceRoot":"","sources":["../../src/core/working-context.test.ts"],"names":[],"mappings":"","sourcesContent":["import { afterAll, beforeAll, describe, expect, it, vi } from \"vitest\";\nimport type { DelegatedTask, DelegatedWorkSummary } from \"./delegated-work.js\";\nimport type { MemoryItem } from \"./memory.js\";\nimport {\n\tbuildWorkingContext,\n\tbuildWorkingContextDelegatedWorkSummary,\n\tbuildWorkingContextMemorySummary,\n\tbuildWorkingContextTodoSummary,\n\ttype WorkingContext,\n} from \"./working-context.js\";\n\n// Fixed time within 7 days of test fixture timestamps (2026-04-02) so\n// reviewMemoryItems produces staleCount: 0 deterministically.\nconst FIXED_NOW = new Date(\"2026-04-03T00:00:00.000Z\").getTime();\n\ntype TodoItem = { content: string; activeForm: string; status: \"pending\" | \"in_progress\" | \"completed\" };\n\nbeforeAll(() => {\n\tvi.useFakeTimers();\n\tvi.setSystemTime(FIXED_NOW);\n});\n\nafterAll(() => {\n\tvi.useRealTimers();\n});\n\nfunction makeMemoryItem(key: string, timestamp = \"2026-04-01T12:00:00.000Z\"): MemoryItem {\n\treturn { key, value: `${key} value`, timestamp };\n}\n\nfunction makeTodoItem(id: string, status: \"pending\" | \"in_progress\" | \"completed\", activeForm?: string): TodoItem {\n\treturn {\n\t\tcontent: id,\n\t\tstatus,\n\t\tactiveForm: activeForm ?? id,\n\t};\n}\n\nfunction makeDelegatedTask(agent: string, status: \"active\" | \"completed\" | \"error\" | \"blocked\"): DelegatedTask {\n\treturn {\n\t\ttoolCallId: `call_${agent}`,\n\t\tagent,\n\t\tagentSource: \"user\",\n\t\ttask: `Task for ${agent}`,\n\t\tmode: \"single\",\n\t\tstatus,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction makeDelegatedWorkSummary(tasks: DelegatedTask[]): DelegatedWorkSummary {\n\tconst active = tasks.filter((t) => t.status === \"active\");\n\tconst completed = tasks.filter((t) => t.status === \"completed\");\n\tconst failed = tasks.filter((t) => t.status === \"error\" || t.status === \"blocked\");\n\n\treturn {\n\t\tactive,\n\t\tcompleted,\n\t\tfailed,\n\t\ttotal: tasks.length,\n\t\tisSessionState: true,\n\t\tnote: \"ephemeral current-session state; not persisted across sessions or branches\",\n\t};\n}\n\ndescribe(\"buildWorkingContextMemorySummary\", () => {\n\tit(\"returns zero-count summary for empty memory items\", () => {\n\t\tconst result = buildWorkingContextMemorySummary([]);\n\t\texpect(result).toEqual({\n\t\t\titemCount: 0,\n\t\t\tstaleCount: 0,\n\t\t\tkeyPreview: [],\n\t\t\tisPersisted: true,\n\t\t\tscope: \"current_branch_session_state\",\n\t\t});\n\t});\n\n\tit(\"returns summary with correct counts\", () => {\n\t\tconst items: MemoryItem[] = [makeMemoryItem(\"alpha\"), makeMemoryItem(\"beta\"), makeMemoryItem(\"gamma\")];\n\n\t\tconst result = buildWorkingContextMemorySummary(items);\n\t\texpect(result).toEqual({\n\t\t\titemCount: 3,\n\t\t\tstaleCount: 0,\n\t\t\tkeyPreview: [\"alpha\", \"beta\", \"gamma\"],\n\t\t\tisPersisted: true,\n\t\t\tscope: \"current_branch_session_state\",\n\t\t});\n\t});\n\n\tit(\"limits key preview to 4 items\", () => {\n\t\tconst items: MemoryItem[] = [\n\t\t\tmakeMemoryItem(\"a\"),\n\t\t\tmakeMemoryItem(\"b\"),\n\t\t\tmakeMemoryItem(\"c\"),\n\t\t\tmakeMemoryItem(\"d\"),\n\t\t\tmakeMemoryItem(\"e\"),\n\t\t\tmakeMemoryItem(\"f\"),\n\t\t];\n\n\t\tconst result = buildWorkingContextMemorySummary(items);\n\t\texpect(result?.keyPreview).toEqual([\"a\", \"b\", \"c\", \"d\"]);\n\t\texpect(result?.itemCount).toBe(6);\n\t});\n\n\tit(\"marks memory as persisted\", () => {\n\t\tconst result = buildWorkingContextMemorySummary([makeMemoryItem(\"test\")]);\n\t\texpect(result?.isPersisted).toBe(true);\n\t});\n});\n\ndescribe(\"buildWorkingContextTodoSummary\", () => {\n\tit(\"returns zero-count summary for empty todos\", () => {\n\t\tconst result = buildWorkingContextTodoSummary([]);\n\t\texpect(result).toEqual({\n\t\t\ttotal: 0,\n\t\t\tcompleted: 0,\n\t\t\tisPersisted: true,\n\t\t\tscope: \"current_branch_session_state\",\n\t\t});\n\t});\n\n\tit(\"returns summary with correct counts\", () => {\n\t\tconst todos: TodoItem[] = [\n\t\t\tmakeTodoItem(\"task1\", \"completed\", \"Completed task\"),\n\t\t\tmakeTodoItem(\"task2\", \"in_progress\", \"In-progress task\"),\n\t\t\tmakeTodoItem(\"task3\", \"pending\"),\n\t\t\tmakeTodoItem(\"task4\", \"pending\"),\n\t\t];\n\n\t\tconst result = buildWorkingContextTodoSummary(todos);\n\t\texpect(result).toEqual({\n\t\t\ttotal: 4,\n\t\t\tcompleted: 1,\n\t\t\tinProgress: \"In-progress task\",\n\t\t\tisPersisted: true,\n\t\t\tscope: \"current_branch_session_state\",\n\t\t});\n\t});\n\n\tit(\"marks todos as persisted\", () => {\n\t\tconst result = buildWorkingContextTodoSummary([makeTodoItem(\"task1\", \"pending\")]);\n\t\texpect(result?.isPersisted).toBe(true);\n\t});\n});\n\ndescribe(\"buildWorkingContextDelegatedWorkSummary\", () => {\n\tit(\"returns zero-count delegated summary for empty delegated work\", () => {\n\t\tconst summary = makeDelegatedWorkSummary([]);\n\t\tconst result = buildWorkingContextDelegatedWorkSummary(summary);\n\t\texpect(result).toEqual({\n\t\t\tactiveCount: 0,\n\t\t\tcompletedCount: 0,\n\t\t\tfailedCount: 0,\n\t\t\tactiveAgents: [],\n\t\t\tfailurePreview: [],\n\t\t\tisPersisted: false,\n\t\t\tscope: \"current_process_runtime_state\",\n\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t});\n\t});\n\n\tit(\"returns summary with correct counts for active tasks only\", () => {\n\t\tconst tasks = [makeDelegatedTask(\"worker1\", \"active\")];\n\t\tconst summary = makeDelegatedWorkSummary(tasks);\n\n\t\tconst result = buildWorkingContextDelegatedWorkSummary(summary);\n\t\texpect(result).toEqual({\n\t\t\tactiveCount: 1,\n\t\t\tcompletedCount: 0,\n\t\t\tfailedCount: 0,\n\t\t\tactiveAgents: [\"worker1\"],\n\t\t\tfailurePreview: [],\n\t\t\tisPersisted: false,\n\t\t\tscope: \"current_process_runtime_state\",\n\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t});\n\t});\n\n\tit(\"returns summary with correct counts for mixed tasks\", () => {\n\t\tconst tasks = [\n\t\t\tmakeDelegatedTask(\"worker1\", \"active\"),\n\t\t\tmakeDelegatedTask(\"worker2\", \"active\"),\n\t\t\tmakeDelegatedTask(\"reviewer1\", \"completed\"),\n\t\t\tmakeDelegatedTask(\"scout1\", \"completed\"),\n\t\t\tmakeDelegatedTask(\"failed1\", \"error\"),\n\t\t];\n\t\tconst summary = makeDelegatedWorkSummary(tasks);\n\n\t\tconst result = buildWorkingContextDelegatedWorkSummary(summary);\n\t\texpect(result?.activeCount).toBe(2);\n\t\texpect(result?.completedCount).toBe(2);\n\t\texpect(result?.failedCount).toBe(1);\n\t\texpect(result?.activeAgents).toEqual([\"worker1\", \"worker2\"]);\n\t\texpect(result?.failurePreview).toEqual([\n\t\t\t{\n\t\t\t\tagent: \"failed1\",\n\t\t\t\ttask: \"Task for failed1\",\n\t\t\t\tmode: \"single\",\n\t\t\t\tstatus: \"error\",\n\t\t\t\tchildIndex: undefined,\n\t\t\t\tstep: undefined,\n\t\t\t\texitCode: undefined,\n\t\t\t\terrorMessage: undefined,\n\t\t\t},\n\t\t]);\n\t});\n\n\tit(\"includes granular child failure previews without changing persistence semantics\", () => {\n\t\tconst tasks: DelegatedTask[] = [\n\t\t\t{\n\t\t\t\ttoolCallId: \"parallel_1\",\n\t\t\t\tchildIndex: 2,\n\t\t\t\tagent: \"reviewer\",\n\t\t\t\tagentSource: \"user\",\n\t\t\t\ttask: \"Review the panel\",\n\t\t\t\tmode: \"parallel\",\n\t\t\t\tstatus: \"error\",\n\t\t\t\texitCode: 1,\n\t\t\t\terrorMessage: \"Review failed due to missing edge-case coverage.\",\n\t\t\t\ttimestamp: 2,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttoolCallId: \"chain_1\",\n\t\t\t\tagent: \"worker\",\n\t\t\t\tagentSource: \"user\",\n\t\t\t\ttask: \"Implement Plan complete\",\n\t\t\t\tmode: \"chain\",\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\tstep: 2,\n\t\t\t\texitCode: 0,\n\t\t\t\terrorMessage: \"Approval required before writing production config.\",\n\t\t\t\ttimestamp: 3,\n\t\t\t},\n\t\t];\n\t\tconst result = buildWorkingContextDelegatedWorkSummary(makeDelegatedWorkSummary(tasks));\n\n\t\texpect(result.isPersisted).toBe(false);\n\t\texpect(result.failurePreview).toEqual([\n\t\t\t{\n\t\t\t\tagent: \"worker\",\n\t\t\t\ttask: \"Implement Plan complete\",\n\t\t\t\tmode: \"chain\",\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\tstep: 2,\n\t\t\t\texitCode: 0,\n\t\t\t\terrorMessage: \"Approval required before writing production config.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tagent: \"reviewer\",\n\t\t\t\ttask: \"Review the panel\",\n\t\t\t\tmode: \"parallel\",\n\t\t\t\tstatus: \"error\",\n\t\t\t\tchildIndex: 2,\n\t\t\t\texitCode: 1,\n\t\t\t\terrorMessage: \"Review failed due to missing edge-case coverage.\",\n\t\t\t},\n\t\t]);\n\t});\n\n\tit(\"explicitly marks delegated work as NOT persisted\", () => {\n\t\tconst tasks = [makeDelegatedTask(\"worker1\", \"completed\")];\n\t\tconst summary = makeDelegatedWorkSummary(tasks);\n\n\t\tconst result = buildWorkingContextDelegatedWorkSummary(summary);\n\t\texpect(result?.isPersisted).toBe(false);\n\t\texpect(result?.scope).toBe(\"current_process_runtime_state\");\n\t\texpect(result?.note).toBe(\"live current-process state only; not persisted and resets on session switch/resume\");\n\t});\n});\n\ndescribe(\"buildWorkingContext (full integration)\", () => {\n\tit(\"returns explicit zero-state context when all sources are empty\", () => {\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems: [],\n\t\t\ttodos: [],\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: makeDelegatedWorkSummary([]),\n\t\t});\n\n\t\texpect(context).toEqual({\n\t\t\tmemory: {\n\t\t\t\titemCount: 0,\n\t\t\t\tstaleCount: 0,\n\t\t\t\tkeyPreview: [],\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttodo: {\n\t\t\t\ttotal: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgress: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttasks: {\n\t\t\t\ttotal: 0,\n\t\t\t\tpending: 0,\n\t\t\t\tinProgress: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgressTask: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\tdelegatedWork: {\n\t\t\t\tactiveCount: 0,\n\t\t\t\tcompletedCount: 0,\n\t\t\t\tfailedCount: 0,\n\t\t\t\tactiveAgents: [],\n\t\t\t\tfailurePreview: [],\n\t\t\t\tisPersisted: false,\n\t\t\t\tscope: \"current_process_runtime_state\",\n\t\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"returns explicit context when only memory exists\", () => {\n\t\tconst memoryItems: MemoryItem[] = [makeMemoryItem(\"alpha\")];\n\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems,\n\t\t\ttodos: [],\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: makeDelegatedWorkSummary([]),\n\t\t});\n\n\t\texpect(context).toEqual({\n\t\t\tmemory: {\n\t\t\t\titemCount: 1,\n\t\t\t\tstaleCount: 0,\n\t\t\t\tkeyPreview: [\"alpha\"],\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttodo: {\n\t\t\t\ttotal: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgress: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttasks: {\n\t\t\t\ttotal: 0,\n\t\t\t\tpending: 0,\n\t\t\t\tinProgress: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgressTask: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\tdelegatedWork: {\n\t\t\t\tactiveCount: 0,\n\t\t\t\tcompletedCount: 0,\n\t\t\t\tfailedCount: 0,\n\t\t\t\tactiveAgents: [],\n\t\t\t\tfailurePreview: [],\n\t\t\t\tisPersisted: false,\n\t\t\t\tscope: \"current_process_runtime_state\",\n\t\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"returns explicit context when only todos exist\", () => {\n\t\tconst todos: TodoItem[] = [makeTodoItem(\"task1\", \"completed\")];\n\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems: [],\n\t\t\ttodos,\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: makeDelegatedWorkSummary([]),\n\t\t});\n\n\t\texpect(context).toEqual({\n\t\t\tmemory: {\n\t\t\t\titemCount: 0,\n\t\t\t\tstaleCount: 0,\n\t\t\t\tkeyPreview: [],\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttodo: {\n\t\t\t\ttotal: 1,\n\t\t\t\tcompleted: 1,\n\t\t\t\tinProgress: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttasks: {\n\t\t\t\ttotal: 0,\n\t\t\t\tpending: 0,\n\t\t\t\tinProgress: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgressTask: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\tdelegatedWork: {\n\t\t\t\tactiveCount: 0,\n\t\t\t\tcompletedCount: 0,\n\t\t\t\tfailedCount: 0,\n\t\t\t\tactiveAgents: [],\n\t\t\t\tfailurePreview: [],\n\t\t\t\tisPersisted: false,\n\t\t\t\tscope: \"current_process_runtime_state\",\n\t\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"returns explicit context when only delegated work exists\", () => {\n\t\tconst tasks = [makeDelegatedTask(\"worker1\", \"active\")];\n\t\tconst summary = makeDelegatedWorkSummary(tasks);\n\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems: [],\n\t\t\ttodos: [],\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: summary,\n\t\t});\n\n\t\texpect(context).toEqual({\n\t\t\tmemory: {\n\t\t\t\titemCount: 0,\n\t\t\t\tstaleCount: 0,\n\t\t\t\tkeyPreview: [],\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttodo: {\n\t\t\t\ttotal: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgress: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\ttasks: {\n\t\t\t\ttotal: 0,\n\t\t\t\tpending: 0,\n\t\t\t\tinProgress: 0,\n\t\t\t\tcompleted: 0,\n\t\t\t\tinProgressTask: undefined,\n\t\t\t\tisPersisted: true,\n\t\t\t\tscope: \"current_branch_session_state\",\n\t\t\t},\n\t\t\tdelegatedWork: {\n\t\t\t\tactiveCount: 1,\n\t\t\t\tcompletedCount: 0,\n\t\t\t\tfailedCount: 0,\n\t\t\t\tactiveAgents: [\"worker1\"],\n\t\t\t\tfailurePreview: [],\n\t\t\t\tisPersisted: false,\n\t\t\t\tscope: \"current_process_runtime_state\",\n\t\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"returns full context when all sources have data\", () => {\n\t\tconst memoryItems: MemoryItem[] = [makeMemoryItem(\"alpha\"), makeMemoryItem(\"beta\")];\n\t\tconst todos: TodoItem[] = [makeTodoItem(\"task1\", \"completed\"), makeTodoItem(\"task2\", \"in_progress\", \"Working\")];\n\t\tconst tasks = [makeDelegatedTask(\"worker1\", \"active\"), makeDelegatedTask(\"scout1\", \"completed\")];\n\t\tconst summary = makeDelegatedWorkSummary(tasks);\n\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems,\n\t\t\ttodos,\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: summary,\n\t\t});\n\n\t\texpect(context.memory).toBeDefined();\n\t\texpect(context.memory?.itemCount).toBe(2);\n\t\texpect(context.memory?.isPersisted).toBe(true);\n\n\t\texpect(context.todo).toBeDefined();\n\t\texpect(context.todo?.total).toBe(2);\n\t\texpect(context.todo?.completed).toBe(1);\n\t\texpect(context.todo?.isPersisted).toBe(true);\n\n\t\texpect(context.delegatedWork).toBeDefined();\n\t\texpect(context.delegatedWork?.activeCount).toBe(1);\n\t\texpect(context.delegatedWork?.completedCount).toBe(1);\n\t\texpect(context.delegatedWork?.isPersisted).toBe(false);\n\t});\n\n\tit(\"produces JSON-serializable output\", () => {\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems: [makeMemoryItem(\"alpha\")],\n\t\t\ttodos: [makeTodoItem(\"task1\", \"in_progress\", \"Current\")],\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: makeDelegatedWorkSummary([makeDelegatedTask(\"worker1\", \"active\")]),\n\t\t});\n\n\t\tconst serialized = JSON.stringify(context);\n\t\tconst parsed = JSON.parse(serialized) as WorkingContext;\n\n\t\texpect(parsed.memory?.isPersisted).toBe(true);\n\t\texpect(parsed.todo?.isPersisted).toBe(true);\n\t\texpect(parsed.delegatedWork?.isPersisted).toBe(false);\n\t});\n\n\tit(\"empty delegated work case is represented explicitly with zero counts\", () => {\n\t\tconst context = buildWorkingContext({\n\t\t\tmemoryItems: [makeMemoryItem(\"alpha\")],\n\t\t\ttodos: [makeTodoItem(\"task1\", \"pending\")],\n\t\t\ttasks: [],\n\t\t\tdelegatedWorkSummary: makeDelegatedWorkSummary([]),\n\t\t});\n\n\t\texpect(context.memory).toBeDefined();\n\t\texpect(context.todo).toBeDefined();\n\t\texpect(context.delegatedWork).toEqual({\n\t\t\tactiveCount: 0,\n\t\t\tcompletedCount: 0,\n\t\t\tfailedCount: 0,\n\t\t\tactiveAgents: [],\n\t\t\tfailurePreview: [],\n\t\t\tisPersisted: false,\n\t\t\tscope: \"current_process_runtime_state\",\n\t\t\tnote: \"live current-process state only; not persisted and resets on session switch/resume\",\n\t\t});\n\t});\n});\n"]}