/** * Self-heal poisoned `.template-hashes.json` manifests. * * Versions before this fix walked `.codex/`, `.claude/`, etc. with a blind * recursive scan when computing the manifest, so they hashed user-owned * runtime data (`.codex/sessions/*`, `.claude/projects/*.jsonl`, pre-existing * `AGENTS.md`, user-added `.codex/skills//`, …). On uninstall, every * manifest entry is unlinked, which silently deletes user data. * * `pruneOrphanManifestKeys` removes any manifest entry that no current * platform configurator owns. The two entry points that consume it are * `trellis update` (before migration classification) and `trellis uninstall` * (before plan building). Together they ensure existing poisoned manifests * self-correct on the next routine command. * * Rules: * - `.trellis/*` entries are ALWAYS kept. `trellis uninstall` removes * `.trellis/` wholesale via `fs.rmSync(..., { recursive: true })`, so * manifest accuracy there doesn't affect uninstall data-loss. `update` * also relies on these entries to detect user-modified workflow files. * - Root-level `AGENTS.md` is kept only when it still looks Trellis-managed * (contains the managed block markers) or is missing on disk. This * self-heals old poisoned manifests for user-owned AGENTS.md files that * predated init and were skipped. * - Paths referenced by `from`/`to` of any migration manifest entry * (rename, rename-dir, delete, safe-file-delete) are preserved. Pruning * them would prevent legitimate pending migrations from finding their * source/target. * - Everything else: if the path is not in the union of * `collectPlatformTemplates()` for currently-configured platforms, it is * pruned. This matches "files trellis actually wrote during init/update". */ import type { AITool } from "../types/ai-tools.js"; import type { TemplateHashes } from "../types/migration.js"; export interface PruneResult { /** Manifest keys removed (POSIX-style relative paths). */ pruned: string[]; /** The post-prune manifest (saved to disk only when `pruned.length > 0`). */ hashes: TemplateHashes; } export interface PruneOptions { /** * Save the pruned manifest to `.template-hashes.json`. Defaults to true. * Callers can pass `false` to compute the prune without mutating disk * (dry-run, change-analysis passes). */ persist?: boolean; } /** * Walk the manifest and split it into kept vs pruned entries. * * @param cwd Project root — used to save the rewritten manifest. * @param configuredPlatforms Output of `getConfiguredPlatforms(cwd)` — caller * resolves this so we don't have to re-walk the filesystem. * @param hashes Already-loaded manifest contents. Passing it in (vs reading * from disk) lets the caller chain `loadHashes` → prune → use the result. * @param options.persist When true (default), saves the pruned manifest to * disk. Pass `false` for dry-run flows. */ export declare function pruneOrphanManifestKeys(cwd: string, configuredPlatforms: readonly AITool[], hashes: TemplateHashes, options?: PruneOptions): PruneResult; //# sourceMappingURL=manifest-prune.d.ts.map