import { type OutputStyle } from '@williamthorsen/nmr-core'; import { type CheckCacheEntry } from './check-cache.js'; /** * What this invocation would be recorded under, insofar as an entry records the same facts. A mismatch is read * against these, so a refusal names the ingredient that moved rather than blaming the tree for all of them. */ export interface RunIdentity { commandString: string; nmrVersion: string; nodeVersion: string; /** Absent where no snapshot was taken, which leaves the tree unattributable rather than assumed equal. */ treeHash: string | undefined; } /** A recorded pass and what it left a reader: its command's own transcript, or the assembly a composite holds. */ export interface Recording { entry: CheckCacheEntry; /** What the command wrote, absent on a composite, which retains nothing of its own. */ transcript?: string; } /** * Which of the pass key's ingredients a recorded pass and this invocation disagree on, insofar as an entry * records enough to tell: the residual covers what it does not, which is the install, the platform, and the * environment variables the key folds in. */ export type KeyDifference = { ingredient: 'tree'; } | { ingredient: 'command-string'; } | { ingredient: 'nmr-version'; current: string; recorded: string; } | { ingredient: 'node-version'; current: string; recorded: string; } | { ingredient: 'other'; }; /** What `--log` found for one command at one scope. */ export type RecordingLookup = { ok: true; recording: Recording; } | { ok: false; refusal: RecordingRefusal; }; /** * Why there is nothing to print. Each is a separate answer to a reader asking for the last run's output, and * each names a different next move: run the command, run it on this tree, run it through a pipe, or stop * asking for a command no run records. */ export type RecordingRefusal = { kind: 'uncacheable'; } | { kind: 'gate-aside'; } | { kind: 'unrecorded'; } | { kind: 'mismatched'; ageMs: number; difference: KeyDifference; } | { kind: 'no-output'; ageMs: number; }; /** * Renders a recording as the reader sees it: a header dating what follows, the command string that produced * it, and then the run's own bytes. * * The header is what presents the body as a recording rather than as this invocation's output, which is what * lets a reader at a terminal be shown what a piped run wrote. The command string is the whole chain, hooks * included, so the header names what earned the pass and not merely what was typed. */ export declare function renderRecording(options: { command: string; recording: Recording; scope: string; style: OutputStyle; }): string; /** * Renders a refusal on the one line a fan-out can attribute, in the grammar a verdict uses: the scope, the * command, and what is missing. */ export declare function renderRefusal(options: { command: string; refusal: RecordingRefusal; scope: string; style: OutputStyle; }): string; /** * Resolves what one scope has to show for one command. * * Admitted on the pass key alone, so `--log` prints exactly what a skip would have recalled and never a * recording of some other tree. The retention key is deliberately not consulted: it certifies that a recording * describes this presentation environment, which is what a replayed excerpt needs and what a dated recording * does not. */ export declare function resolveRecording(options: { anchorDir: string; command: string; current: RunIdentity; isCacheable: boolean; key: string | undefined; monorepoRoot: string; }): Promise;