/** * Progress emitter for the orchestrator. * * The CLI prints live status as the orchestrator walks each module * through its state machine; tests use a capturing emitter to assert * on exactly which events fired in which order. Same shape as the * `[progress:start] / [progress:done]` pattern in * `packages/e2e/src/runner.ts`. */ import type { ModuleUpdateState, UpdateStep } from './types'; export type ProgressEvent = | { kind: 'plan'; modules: number } | { kind: 'self-update-start' } | { kind: 'self-update-done'; from: string; to: string } | { kind: 'self-update-skipped'; reason: string } | { kind: 'backup-start'; moduleId: string } | { kind: 'backup-done'; moduleId: string } | { kind: 'module-start'; moduleId: string; fromVersion: string; toVersion: string } | { kind: 'module-step'; moduleId: string; step: UpdateStep } | { kind: 'module-done'; state: ModuleUpdateState } | { kind: 'module-failed'; state: ModuleUpdateState } | { kind: 'module-skipped'; state: ModuleUpdateState } | { kind: 'run-done'; ok: boolean }; export interface ProgressEmitter { emit(event: ProgressEvent): void; } /** Default emitter — silent. Override for live console output. */ export const silentProgress: ProgressEmitter = { emit() {}, }; export interface CapturingEmitter extends ProgressEmitter { events: ProgressEvent[]; } /** Test helper: collect every event in `events` for later assertion. */ export function capturingProgress(): CapturingEmitter { const events: ProgressEvent[] = []; return { events, emit(event) { events.push(event); }, }; }