import { type RunLabProvenance, type RunLiveness } from "./run-status.js"; export declare const RUN_INDEX_SCHEMA = "humanish.run-index.v1"; export interface RunIndexEntry { runId: string; /** Where the entry's facts came from: the status record, the bundle, or the directory alone. */ derivedFrom: "status" | "bundle" | "directory"; liveness: RunLiveness; mode?: "dry-run" | "live"; /** * The pid that owns a run, when it recorded one. This is how a surface identifies the run IT just * started without minting an id or guessing at a new directory: it spawned a process, and exactly * one run's record carries that pid. */ pid?: number; lab?: RunLabProvenance; startedAt?: string; updatedAt?: string; completedAt?: string; verdict?: string; participants?: { total: number; reachedGoal: number; reportedFriction?: number; }; estimatedCostUsd?: number | null; /** Wall-clock span when both ends are known; used for per-lab medians. */ durationMs?: number; } export interface RunIndexResult { schema: typeof RUN_INDEX_SCHEMA; cwd: string; /** Newest first, by the best timestamp each entry has. */ runs: RunIndexEntry[]; /** Directories that could not be read at all, by name — surfaced, never silently dropped. */ unreadable: string[]; } /** What a cached entry was derived from, so a changed file invalidates exactly that entry. */ interface CacheKey { file: string; mtimeMs: number; size: number; ino: number; } /** * A process-lifetime cache. Deliberately explicit rather than module-global state: a caller that * refreshes on a cadence keeps one and passes it back, and a caller that wants a cold read passes * nothing. Nothing here is authoritative, so a stale slot can only ever cost a re-read. */ export declare class RunIndexCache { private readonly slots; get(runId: string, key: CacheKey): RunIndexEntry | undefined; set(runId: string, key: CacheKey, entry: RunIndexEntry): void; /** Drop entries for runs that no longer exist, so a long-lived surface cannot leak. */ retain(runIds: Iterable): void; get size(): number; } export interface ReadRunIndexOptions { /** Reused across refreshes so unchanged runs are not re-read. */ cache?: RunIndexCache; /** Injectable clock, so liveness classification is reproducible in tests. */ nowMs?: number; /** Cap the number of runs returned (newest first). The full directory is still enumerated — * a cap on reads, not on truth — and the count reflects what was read. */ limit?: number; } /** * Read every run in `.humanish/runs`, cheapest source first. Never throws for a bad run directory; * an unreadable one is named in `unreadable`. */ export declare function readRunIndex(cwdInput: string, options?: ReadRunIndexOptions): Promise; export {};