import type { JudgeSay } from "../judge/stream.js"; import type { ResolvedConfig } from "../types.js"; /** One thing said, as the page receives it. */ export interface NarrationLine { at: string; runId: string; /** Which judge said it: a panel name, `refuter`, or whatever the caller calls itself. */ panel: string; /** * Which call of that judge said it. * * The name alone does not identify a speaker: two workers judge two view * groups at once and reach the same panel at the same time. This is what * keeps their prose apart, in the file and on the page. */ call: string; /** `open` and `close` bracket one call; `text` and `tool` are what happened inside it. */ kind: "open" | "text" | "tool" | "close"; text: string; } export declare function narrationPath(resolved: ResolvedConfig): string; /** * The narration of one run. * * Best-effort in the same way the event log is: a workspace that cannot be * written to must not take a run down, so a failed write disables the writer * and the run carries on judging in silence. */ export declare class Narration { private readonly runId; private readonly path; private enabled; /** One gathering buffer per call in flight, because several are. */ private readonly open; private written; constructor(resolved: ResolvedConfig, runId: string); /** Begin a run's narration, discarding whatever the last one left. */ start(): void; /** Everything one judge call says, tagged with which call is saying it. */ say(call: string, panel: string, s: JudgeSay): void; /** * Bracket one call, which is what the page counts progress in. * * A close also forgets the call's buffer, so a run that judges hundreds of * groups does not accumulate one entry per call for its whole life. */ mark(call: string, panel: string, kind: "open" | "close", text: string): void; /** * Write out prose being gathered: one call's, or every call's. * * The whole-file form is for the end of a run, where a call that never closed * still has something worth saying. */ flush(call?: string): void; /** The buffer for one call, made on first use. */ private gathering; private write; } export declare function setCurrentNarration(n: Narration | null): void; /** * Whether anything is listening. * * Asked before a call is made rather than after it has spoken, because the * streaming the page wants costs the CLI an order of magnitude more lines, and * a run nobody is watching should not pay for them. */ export declare function narrating(): boolean; /** Narrate, if a run is in flight. A no-op otherwise, so callers need no guard. */ export declare function say(call: string, panel: string, s: JudgeSay): void; export declare function openCall(panel: string, text: string): string; /** End one judge call, releasing its buffer. */ export declare function closeCall(call: string, panel: string): void; /** * The tail of a run's narration. * * Read whole, because the file is capped at a size that makes reading it whole * the simplest correct thing, and a partial read of a file being appended to * would have to handle a torn last line for no gain. */ export declare function readNarration(resolved: ResolvedConfig, limit?: number): NarrationLine[];