import * as fs from 'node:fs'; /** * Content hashing and oversize policy for the read ledger (FR-5, Story 3.1). * * **This runs on the cold path only.** The PostToolUse hook appends a spool * line in pure bash and spawns nothing (N-4); the digest is computed when that * batch is flushed. Nothing in this module may be reached from a hook script. * * Consequence stated rather than hidden: a digest describes the file as of * *flush* time, not as of the read. Within one batch that is safe because an * edit replayed from the same spool wins the verdict (Story 3.3's * `edited-by-you-since`). A file changed by something outside Cortex between * the read and the flush records the changed bytes and will later read as * unchanged — a real, bounded imprecision, not a guarantee. */ /** 2 MiB. Past this the bytes are never read, so nothing is hashed. */ export declare const DEFAULT_DIGEST_MAX_BYTES: number; /** * The `(scope_key, path)` key's path half is normalized by * `normalizeFilePathKey` in `scope/keys.ts`, and `CortexStore` applies it on * both write and read so a caller cannot derive the key differently. Nothing * in this module needs to normalize. */ export interface FileDigest { /** Lowercase hex sha256, or null when the file was not hashed (oversize). */ sha256: string | null; byteSize: number; /** ISO-8601 UTC. Recorded for reporting only — never for change detection. */ mtime: string; oversize: boolean; } /** * Parse with `Number`, never `parseInt`. * * `parseInt` succeeds on a *prefix*: `parseInt('2e6')` is 2, which would turn a * 2 MB ceiling into a 2-byte one and mark every file oversize. Story 2.6's * review found exactly this in `resolveWalMaxBytes`. `gc.ts`'s neighbouring * `envNumber` still uses `parseInt` — deliberately not copied. */ export declare function resolveDigestMaxBytes(raw?: string | undefined): number; /** * Hash a file's bytes, or record its size alone when it exceeds the ceiling. * * Returns `null` when the file cannot be measured at all (missing, unreadable, * a directory). Capture edges never throw into a hook (AD-12), and a read of * something unhashable is simply not ledgered. */ export declare function computeFileDigest(filePath: string, maxBytes?: number, /** * Injected solely so the post-read ceiling re-check below is testable: the * bug it guards needs the file to change *between* the stat and the read, * which cannot be staged deterministically otherwise, and an untestable * correctness guarantee is one that regresses silently. Production always * takes the default. */ deps?: { statSync: typeof fs.statSync; }): FileDigest | null; /** * Per-flush memo. * * A 256 KiB batch can hold hundreds of reads of the same file, and every digest * in one flush describes the same on-disk state — so hashing a path more than * once per batch is not merely wasteful, it is the same value by construction. * The cache is created per batch and discarded with it; it must never be * module-level, or a long-lived MCP process would serve a stale hash forever. */ export type DigestCache = (filePath: string) => FileDigest | null; /** See `computeFileDigest`'s `deps`: a test seam, never used in production. */ export interface DigestDeps { statSync: typeof fs.statSync; } export declare function createDigestCache(maxBytes?: number, deps?: DigestDeps): DigestCache; //# sourceMappingURL=digest.d.ts.map