import { type QuestionDetectionKind, type QuestionMode } from "../interpretation/question.js"; import type { HarnessDescriptor } from "../knowledge/descriptor.js"; import type { Clock, SignalName } from "./deps.js"; import type { HarnessEvent } from "./events.js"; import { type FailureSummary } from "./failure.js"; /** SIGTERM -> SIGKILL escalation budget for a child that ignores the first * signal. */ export declare const KILL_GRACE_MS = 5000; /** Shared process termination policy for turn runners and control probes. */ export declare function superviseTermination(clock: Clock, signal: (sig: SignalName) => void): { readonly escalate: () => void; readonly settle: () => void; }; /** Bounded unmatched stderr: a rolling tail plus the first Error headline * (at most 512 characters), so long stacks cannot erase the crash reason. */ export declare class StderrTail { private readonly lines; private bytes; private firstError; push(line: string): void; snapshot(): readonly string[]; } export interface SupervisorIo { readonly clock: Clock; /** Inactivity budget; undefined means no stall clock at all. */ readonly stallMs: number | undefined; /** Signal the supervised process. The supervisor never signals after * `settle()`. */ readonly signal: (sig: SignalName) => void; /** Deliver an event to the turn's consumer. */ readonly emit: (event: HarnessEvent) => Promise; /** Record a failure for the turn's done AND deliver it as an event. */ readonly fail: (summary: FailureSummary) => Promise; /** Where unclassified stderr goes. */ readonly tail: StderrTail; /** The stall clock fired: the runner records its own cause and ends the * turn; the supervisor has already begun escalation. */ readonly onStall: () => void; /** A question was detected at close, with its option count (for the * runner's boundary log). */ readonly onQuestion: (optionCount: number) => void; } export interface TurnClose { readonly detection: QuestionDetectionKind; /** True when the turn ended by asking: a successful turn, cause * awaiting-input. */ readonly asked: boolean; } export interface TurnSupervisor { /** Start a turn: reset per-turn state and arm the stall clock. */ beginTurn(): void; /** Any output chunk arrived: restart the inactivity budget, if a turn is * open and a budget exists. */ rearm(): void; /** Pause only inactivity while a native request awaits its caller. */ pauseInactivity(): void; /** Resume inactivity without resetting the turn or its last message. */ resumeInactivity(): void; /** The turn ended, or the process did: stop the stall clock. */ disarm(): void; /** SIGTERM now, SIGKILL after KILL_GRACE_MS unless the process exits. * Idempotent while an escalation is pending. */ escalate(): void; /** The process is gone: no further signals, no pending escalation, no * stall clock. */ settle(): void; /** Classify one stderr line: a limit wall becomes a limit event plus a * failure, an auth wall a failure plus an error event, anything else * goes to the tail. Returns the limit code when the line was a limit. */ stderrLine(line: string): Promise; /** A decoded event passed by: the last assistant message is where the * protocol says the hcn-question block lives (tracked in ask mode). */ noteEvent(event: HarnessEvent): void; /** At turn end: detect the block in the last assistant message, emit the * question (or the malformation as an error plus a task failure), and * report what was found. Synchronous: the events are enqueued, not * awaited, so a runner can close a turn from a timer callback. */ close(): TurnClose; } export declare const superviseTurn: (h: HarnessDescriptor, questionMode: QuestionMode, io: SupervisorIo) => TurnSupervisor; //# sourceMappingURL=supervisor.d.ts.map