/** * Verified residue deletion — the finish `git worktree remove` does not do * (mmnto-ai/totem#2580 slice-2). * * Git exits 0 on a removal that leaves the directory standing (the husk class * the estate sensor keeps finding), so the `wt remove` verb never trusts the * exit code: it deletes, then RE-VERIFIES, and this module is the deletion * half of that contract. * * Three passes, in order, and the order is load-bearing: * 1. **Strip** every reparse point / symlink / junction, WITHOUT following * it. The link itself is unlinked; its target is not touched, not * descended into, and not deleted. This is the same code on POSIX * (symlinks) and win32 (symlinks + junctions) — `lstat` answers * `isSymbolicLink()` for a directory junction, and libuv's `unlink` * removes a directory reparse point by dropping the link. A worktree * commonly carries a `node_modules` full of pnpm links, and one followed * junction would delete a store OUTSIDE the tree. * 2. **Delete** recursively with retries — Windows hands back EBUSY/EPERM * while an indexer or a just-exited git still holds a handle, and a * single attempt reads that as a permanent failure. * 3. **Re-verify** with a no-follow existence probe. The result is reported, * never asserted: the caller decides, and `wt remove` only exits 0 when * this says the directory is gone. * * Nothing here throws for an ordinary filesystem outcome. A failed strip, a * failed delete, and a surviving directory are all RETURNED, so the caller can * name the survivors in its error rather than surfacing a raw ENOTEMPTY. */ export interface ResidueRemovalResult { /** True only when a no-follow probe confirms the directory is gone. */ removed: boolean; /** Links unlinked by the strip pass — reported so the finish is not silent. */ strippedLinks: string[]; /** Up to {@link SURVIVOR_SAMPLE_LIMIT} paths still present, for the error. */ survivors: string[]; /** The last delete failure, when one happened. */ lastError?: string; /** How many strip+delete attempts ran. */ attempts: number; } export interface ResidueRemovalOptions { dir: string; /** Test seam — production callers take the default. */ attempts?: number; /** Test seam — production callers take the default. */ retryDelayMs?: number; } /** * No-follow existence probe: a dangling link still counts as PRESENT, and the * probe FAILS CLOSED — only ENOENT/ENOTDIR mean "absent"; any other errno * reports the path as present, so an unknowable path reads as a survivor and * the caller fails loud instead of claiming a verified removal (#2580 bot * round, CR findings 8 + 9 — retires the errno-tri-state deferral). */ export declare function residuePathExists(p: string): boolean; /** * Depth-first strip of every reparse point under `dir`. Recursion enters REAL * directories only — a junction answers `isSymbolicLink()` first and is * unlinked, so the walk can never leave the tree (and cannot cycle). */ export declare function stripReparsePoints(dir: string): string[]; /** * Strip links, delete recursively with retries, then verify absence. Never * throws on a filesystem outcome — `removed: false` plus `survivors` is the * failure report, and the caller turns that into its own loud error. */ export declare function removeWorktreeResidue(options: ResidueRemovalOptions): Promise; //# sourceMappingURL=worktree-residue.d.ts.map