import { describe, expect, it } from 'bun:test' import { ProjectionStore } from '../../src/projection/ProjectionStore.js' import type { RuntimeEvent } from '@aircoding/contracts' function event(type: string, payload: Record): RuntimeEvent> { return { id: `evt_${type}_${Math.random().toString(36).slice(2)}`, type, version: 1, timestamp: new Date().toISOString(), session_id: 'session_projection_apply' as any, project_id: 'project_projection_apply' as any, source: { kind: 'system' }, route: ['test', type], payload, } } describe('ProjectionStore.apply', () => { it('applies task and agent lifecycle events into a live snapshot', () => { const store = new ProjectionStore() const updates: string[] = [] store.subscribe((projection) => { updates.push(`${projection.tasks[0]?.status || 'none'}:${projection.agents[0]?.status || 'none'}`) }) store.apply(event('task.created', { task_id: 'task_1', type: 'execute', title: 'Create file', task_spec_json: {}, dependencies: [], metadata: {}, })) store.apply(event('task.started', { task_id: 'task_1', agent_id: 'agent_task_1', attempt_id: 'task_1_1', attempt_index: 0, workspace_id: 'ws_task_1', })) store.apply(event('agent.started', { agent_id: 'agent_task_1', agent_type: 'executor', task_id: 'task_1', metadata: {}, })) store.apply(event('agent.completed', { agent_id: 'agent_task_1', task_id: 'task_1', summary: 'done', metadata: {}, })) store.apply(event('task.completed', { task_id: 'task_1', agent_id: 'agent_task_1', attempt_id: 'task_1_1', worker_result_json: { status: 'completed' }, summary: 'done', changed_files: ['hello.txt'], evidence_refs: [], })) const snapshot = store.get_snapshot('session_projection_apply') expect(snapshot).toBeDefined() expect(snapshot!.tasks).toHaveLength(1) expect(snapshot!.tasks[0].status).toBe('completed') expect(snapshot!.tasks[0].agent_id).toBe('agent_task_1') expect(snapshot!.tasks[0].attempts).toBe(1) expect(snapshot!.agents).toHaveLength(1) expect(snapshot!.agents[0].status).toBe('completed') expect(updates.some((u) => u.startsWith('completed:completed'))).toBe(true) }) it('applies tool, permission, and blocker events', () => { const store = new ProjectionStore() store.apply(event('tool.started', { tool_run_id: 'tool_1', tool_name: 'fs.write', input_json: {}, metadata: {}, })) store.apply(event('tool.completed', { tool_run_id: 'tool_1', output_json: { ok: true }, duration_ms: 12, artifact_ids: [], evidence_refs: [], metadata: {}, })) store.apply(event('permission.prompt.requested', { prompt_id: 'perm_1', subject: 'shell.run', risk_level: 'medium', reason: 'risk score 70 requires user confirmation', options: ['allow_once', 'deny'], default_option: 'deny', request_ref: {}, })) store.apply(event('task.created', { task_id: 'task_blocked', type: 'execute', title: 'Blocked task', task_spec_json: {}, dependencies: [], metadata: {}, })) store.apply(event('task.blocked', { task_id: 'task_blocked', agent_id: 'agent_task_blocked', reason: 'worker blocked', blocker_kind: 'worker_blocked', evidence_refs: [], suggested_next_step: 'review blocker', })) store.apply(event('permission.prompt.resolved', { prompt_id: 'perm_1', selected_option: 'deny', decision_id: 'decision_1', resolved_by: 'test', })) const snapshot = store.get_snapshot('session_projection_apply') expect(snapshot).toBeDefined() expect(snapshot!.tool_runs).toEqual([{ tool_run_id: 'tool_1', tool_name: 'fs.write', status: 'ok', duration_ms: 12 }]) expect(snapshot!.permission_prompts).toHaveLength(0) expect(snapshot!.tasks.find((task) => task.id === 'task_blocked')?.status).toBe('blocked') expect(snapshot!.blockers).toEqual([{ task_id: 'task_blocked', reason: 'worker blocked', blocker_kind: 'worker_blocked' }]) }) })