/** Input row: a single indexed file with its content hash. */ export interface FileHashRow { /** Repo-relative POSIX path (forward slashes). */ path: string; /** Opaque content digest (e.g. SHA-256 hex). Any stable string works. */ hash: string; } /** Directory rollup result. */ export interface DirRollup { /** `Map`. The root directory is keyed as `''`. */ hashes: Map; /** `Map` — only direct files, no subdirs. */ filesByDir: Map; /** `Map` — direct subdirs. */ subDirsByDir: Map; } /** Diff between two rollups. */ export interface DirRollupDiff { /** Dirs present in `after` but not in `before`. */ addedDirs: string[]; /** Dirs present in `before` but not in `after`. */ removedDirs: string[]; /** Dirs whose aggregate hash changed between the two rollups. */ changedDirs: string[]; /** Dirs whose aggregate hash is identical in both rollups. */ unchangedDirs: string[]; } /** * Builds a dir-level Merkle rollup from a list of `{ path, hash }` rows. * * Algorithm: * 1. Group files by their immediate parent dir. * 2. Bottom-up, per directory, hash a canonical string built from * child entries: `"file::\n"` for files, * `"dir::\n"` for subdirs, sorted lexicographically. * 3. Parent dirs consume their children's aggregate hash when rolling up. * * The result is deterministic for a fixed input. */ export declare function computeDirRollup(files: FileHashRow[]): DirRollup; /** * Diffs two rollups by directory hash. This is the primary consumer * surface: given before/after rollups, the indexer only needs to * re-stat files inside `changedDirs` (plus their `addedDirs` counterparts). */ export declare function diffDirRollups(before: DirRollup, after: DirRollup): DirRollupDiff; /** * Given a set of unchanged directory paths, returns a predicate that * answers "can I skip this file?". A file is skippable iff any ancestor * directory (including its immediate parent) is in the unchanged set * **AND** the file itself appeared under that subtree in the baseline. * * The second condition prevents false-skips for *new* files dropped * into an otherwise-unchanged directory: those will still show up as * new rows in the `after` list, and the caller is expected to feed * `computeDirRollup(after)` to detect them — but `isSkippable` alone * is a cheap pre-filter when stat-ing a known-old file. */ export declare function makeSkippablePredicate(unchangedDirs: Set): (path: string) => boolean; /** Serialises a rollup to a small JSON object for persistence. */ export declare function serialiseRollup(r: DirRollup): { version: 1; hashes: Record; }; /** Inverse of `serialiseRollup`. Only the hash map survives a roundtrip. */ export declare function deserialiseRollup(blob: { version: 1; hashes: Record; }): DirRollup; //# sourceMappingURL=dir-merkle.d.ts.map