/** * The crew-side actor audit trail (task #88). * * The engine's `LaunchOptions` carries no actor field, so WHO launched a run, * WHO approved a gate, and WHO rewrote a policy is knowledge only the daemon's * HTTP layer ever holds — this module is where it stops being ephemeral. One * JSON line per privileged action, appended to `~/.wicked-crew/audit.log` * (override: `WICKED_CREW_AUDIT_LOG`), read back by `GET /audit`. * * Posture: LOUD-NON-FATAL, matching the daemon's bus seams — an unwritable * audit file must not turn a valid gate approval into a 500, but it must be * SAID (once per failure) rather than swallowed. Appends are serialized on a * promise chain so concurrent handlers never interleave partial lines. */ import type { Actor, AuditEntry } from '../core/types.js'; /** * Where the audit trail lives unless overridden: the explicit `WICKED_CREW_AUDIT_LOG` env * override, then the daemon's state home — the `--db` parent when the bootstrap configured one, * the historical `~/.wicked-crew` default otherwise (crew#353's principle, same seam as the * project graphs and the project settings store). A `--db`-isolated daemon must neither APPEND * its trail to the operator's real `~/.wicked-crew/audit.log` (every `run.launched` / * `settings.updated` / `project.created` did exactly that) nor HYDRATE its retry/guidance/ * delivery indexes from the operator's real trail at boot. */ export declare function defaultAuditPath(env?: NodeJS.ProcessEnv): string; export interface AuditReadFilter { runId?: string; action?: string; /** Inclusive lower bound on the entry clock (`ts`, unix millis): keep entries with `ts >= since`. * Applied BEFORE `limit`, so `limit` trims the newest N of the in-window entries. */ since?: number; /** Max entries returned (newest first). Default 200, capped at 1000. */ limit?: number; } /** `readAll`'s filter: no limit — the whole point is that nothing gets trimmed. */ export type AuditScanFilter = Omit; export declare class AuditLog { readonly path: string; private readonly warn; private chain; private dirReady; private disabled; constructor(path?: string, warn?: (msg: string) => void); /** * A trail that records nothing and reads back empty — the DEFAULT for * directly-driven route sets (unit tests call `registerRoutes` without a * server), so they never write the operator's real `~/.wicked-crew/audit.log` * or leave appends pending after close (Copilot, #250). `createServer` * always builds a real one; this never rides a production path. */ static noop(): AuditLog; /** * Record one action. Fire-and-forget by design (the route's answer must not * wait on fsync of a sidecar), serialized so lines never interleave, loud on * failure. `flush()` awaits the chain — tests and shutdown use it. */ /** Returns the unix-millis `ts` stamped on the entry (0 when disabled) so a caller can reuse the * EXACT durable timestamp — e.g. the run-timing index, which must match what a restart rehydrates * from the trail rather than drift by a second off a second `Date.now()`. */ record(action: string, actor: Actor, fields?: { runId?: string; detail?: Record; }): number; /** Await every append issued so far. */ flush(): Promise; /** * Read the trail, newest first. A line that does not parse is skipped (a * torn final line after a crash is expected once) — the rest of the trail * still answers. */ read(filter?: AuditReadFilter): Promise; /** * Read the trail EXHAUSTIVELY, newest first — no read cap. The hydrate path * for the boot-time indexes (`RetryIndex`, `GuidanceIndex`): durable facts * like retry lineage must not vanish because 1000+ newer launches landed on * top of them (BRIEF-UX-002 C5). Same cost class as `read` — that already * parses the whole file and only trims the returned slice — so this is a * one-time full-file scan at boot, measured at ~19ms on a 19k-line live trail. */ readAll(filter?: AuditScanFilter): Promise; /** The shared full-file parse: every matching entry, newest first, uncapped. */ private scan; } //# sourceMappingURL=audit.d.ts.map