export type IncidentKind = "crash" | "operator-error" | "judge-unparseable" | "judge-rejected" | "skill-rollback" | "self-heal-rollback" | "healer-unparseable"; export interface Incident { at: string; kind: IncidentKind; /** The verb that was running, when it is known. */ verb?: string; message: string; /** Stack, reply head, or whatever else names the cause. */ detail?: string; /** * Which project it happened in, by directory. Absolute, and a directory * rather than a display name: it is what decides which log the entry is * appended to, and what `self-heal` reads to find a project that can grade * a replay. */ project?: string; /** Which judge panel was answering, when one was. */ judge?: string; version?: string; } export declare function incidentsPath(projectDir: string): string; /** * Which log an incident belongs in, or null when it belongs in none. * * A configured project first: `locateConfig` climbs to the root that holds a * `lookout.config.*`, so a failure in a subdirectory lands in the project's * own log rather than beside whatever the operator happened to `cd` into. * Failing that, lookout's own checkout, which is where a failure of `doctor` * or a mistyped verb actually belongs. Failing that, nowhere: writing into an * arbitrary directory would leave an un-ignored `.lookout/` in it. */ export declare function incidentLogDir(where: string | undefined): string | null; /** * Record one incident, in the log of the project it happened in. * * Synchronous and swallowing: this runs inside the top-level error handler, * and a logger that can throw there would replace the real failure with its * own. */ export declare function recordIncident(incident: Incident): void; /** * Every log a run should read, deduped, in the order given. * * `self-heal` and `doctor` are the two readers that legitimately span more * than one project: what they report on is lookout, and lookout's failures * are spread across the projects it was pointed at plus its own checkout. * Nulls are accepted so a caller can pass `ownCheckout()` without guarding. */ export declare function incidentSources(...dirs: (string | null | undefined)[]): string[]; /** Those logs read as one, oldest first, so clustering sees every occurrence. */ export declare function readIncidentsFrom(dirs: string[], limit?: number): Incident[]; /** The shape of a failure: numbers and paths stripped, so occurrences group. */ export declare function shapeOf(message: string): string; /** * The most recent incidents, newest last, capped so one read stays bounded. * The cap used to be 200, which quietly interacted with count-sorted * clustering: an old high-frequency bug aged out of the read window while * still dominating a person's mental model of what keeps breaking. */ export declare function readIncidents(projectDir: string, limit?: number): Incident[]; /** * Incidents that look like the same failure, grouped, most frequent first. * Pass `sinceDays` to make the counts mean PRESSURE (occurrences inside the * window), which is what heal selection uses: an all-time count made a bug * fixed months ago outrank the one that broke yesterday. Without it, the * grouping is the all-time record, which is what a page listing history * wants. */ export declare function clusterIncidents(incidents: Incident[], opts?: { sinceDays?: number; now?: string; }): { kind: IncidentKind; message: string; count: number; latest: Incident; }[];