/** * The sink (progress §1, §2.3): the one impure thing in the whole feature. It tees the engine's event * stream into a projection and pushes the result at whichever surface this invocation actually has. * * Three decisions carry it, and none of them is about how the panel looks: * * - **It tees `emit`; it never replaces it** (§2.3). `createHostPort` persists FIRST and renders * second, so a rendering failure can never lose an event. * - **It is best-effort and self-disabling** (§2.3). Everything is caught, and on the first throw it * disables itself for the rest of the run after one warning. Progress is a convenience; a run must * not die because a terminal could not draw a box. This is not defensive programming for its own * sake — the sink runs inside `emit`, which the engine awaits, so an exception here would propagate * into the step that emitted the event and fail work that had already succeeded. * - **Rendering is state-free between events** (§2.4). The accumulated `RunEvent[]` is re-projected * each time rather than mutated, which makes the live widget, a resumed run, and the terminal card * literally the same function of the same input — the property that stops the three from drifting. * Re-projection is O(events) over a list a real run keeps in the thousands at worst. * * The surface is chosen by `ctx.mode`, not by `hasUI` (§7.2) — see progress-widget.ts for why those * two disagree exactly where it matters. */ import type { ExtensionCommandContext, ExtensionUIContext } from "@earendil-works/pi-coding-agent"; import type { RunEvent } from "../engine/types.ts"; import type { WorkflowDefinition } from "../flow/types.ts"; import type { Outline } from "../progress/types.ts"; import { type LineWriter } from "./progress-plain.ts"; /** Progress §11.2: the escape hatch for scripted environments that want the old silence. */ export declare const PROGRESS_OFF_ENV = "PI_WORKFLOWS_PROGRESS"; /** `"tui" | "rpc" | "json" | "print"` — the matrix progress §7.2 dispatches on. Not exported by name from PI. */ export type ProgressMode = ExtensionCommandContext["mode"]; /** The slice of the command context the sink reads. Narrow enough that a test's fake is a literal. */ export interface ProgressCtx { readonly mode: ProgressMode; readonly ui: Pick; /** `getSessionDir()` is `""` under `--no-session` — which is why the card is best-effort (§7.7). */ readonly sessionManager: { getSessionDir(): string; }; } export interface ProgressSinkOptions { readonly ctx: ProgressCtx; readonly outline: Outline; /** The run's short form for the panel header (`runIdHash`, naming.ts) — this layer owns that shape. */ readonly runLabel: string; /** `run-meta`'s path (spec §8.9), for the card's provenance line. */ readonly workflowFilePath?: string; /** Injected so a test can freeze it; the pure layer takes `now` as a parameter for the same reason. */ readonly now?: () => Date; /** Where headless lines go. Default stderr — NEVER stdout (§8.2). */ readonly write?: LineWriter; readonly env?: Record; } export interface ProgressSink { /** Tee one event. Never throws: a broken surface disables itself instead (§2.3). */ accept(event: RunEvent): void; /** Seed from a log loaded off disk, so a resumed run opens showing its history (§9.1). */ seed(events: readonly RunEvent[]): void; /** Whether the run's outcome has already been reported by a card, so `notify` should not repeat it (§7.8). */ reportedOutcome(): boolean; /** Clear the live surface. Safe to call more than once. */ dispose(): void; } /** * Build the sink for one command invocation. Returns a no-op sink when progress is switched off * (§11.2) — a disabled feature should cost nothing, not merely render nothing. */ export declare function createProgressSink(options: ProgressSinkOptions): ProgressSink; /** * How a command handler asks for a sink without knowing what a sink needs. * * The alternative — threading the surface choice through `handleRun`/`handleResume`/ * `handleAttendedQuestionnaire` — would push rendering into three signatures that currently take the * narrowest context they can (see commands/context.ts's `CommandCtx`). A bound factory keeps that where * it belongs, and makes a test's substitute one line. */ export type ProgressFor = (workflow: WorkflowDefinition, runId: string, workflowFilePath?: string) => ProgressSink; /** Bind a factory to one invocation's context. Called once per `/workflow` command, in extension.ts. */ export declare function bindProgress(ctx: ProgressCtx, overrides?: Pick): ProgressFor; /** The factory a caller uses when it wants no progress at all — the default in every handler signature. */ export declare const noProgressFor: ProgressFor; /** A sink that does nothing, for handlers called without one. */ export declare const inertProgress: ProgressSink; //# sourceMappingURL=progress-sink.d.ts.map