import type { Plan, PlanContext } from "./plan.js"; /** Normalize a repo-relative path for comparison: forward slashes, no leading `./`. */ export declare function normalizeRel(p: string): string; /** * The set of repo-relative paths with uncommitted changes (`git status --porcelain`): * modified, staged, or untracked. A rename maps to its destination (what's on disk). * Routed through the read-only {@link gitRead} seam, so it stays hermetic in tests and * cross-platform. Empty when git is absent / not a repo (`gitRead` → undefined): with * no git history there is no uncommitted work to clobber. * * `-uall` matters for the REMOVAL gate: default porcelain collapses an entirely * untracked directory to one `?? dir/` entry, so a FILE inside it would never appear * in this set and a `remove`/`--delete` of it would sail past the gate. `-uall` lists * every untracked file individually (ignored files stay excluded, so it stays cheap). * * `-z` (NUL-delimited) matters just as much: without it git C-QUOTES any path with an * "unusual" byte (an embedded newline, a `"`, or a non-ASCII byte becomes `"a\nb"`, * `"a\"b"`, `\NNN`). The old human-format parser kept those escapes (and `normalizeRel` * then rewrote the backslashes), so the dirty entry would NOT equal the real on-disk * path the remove plan targets — a dirty/untracked removal target with a quoted name * would slip past the gate, letting `--delete` move an uncommitted file without * `--force`. In `-z` git emits RAW, unquoted bytes and drops the ` -> ` rename arrow, * reversing the fields to `\0\0`, so paths match exactly with no unquoting. */ export declare function dirtyPaths(ctx: PlanContext): Promise>; /** * True when the worktree has ANY uncommitted change. (Kept as the simple predicate; * the `--apply` gate uses the precise {@link dirtyWriteTargets} instead.) */ export declare function isWorktreeDirty(ctx: PlanContext): Promise; /** * The repo-relative paths a plan would write that ALSO have uncommitted changes — the * precise "this apply would clobber your work" set that gates `--apply`. * * Only repo-local `write`/`doc`/`envblock` targets count; an `external` write (a * home/system file like `~/.codex/config.toml`) is never part of the repo worktree. * Crucially, a path aih writes that is NOT itself dirty — a brand-new file, or a clean * tracked one — is SAFE to write even when other, unrelated files in the repo are * dirty. So `aih mcp --apply --cli opencode` creating a new `opencode.json` is allowed * on a repo that merely has an untracked `codex/` dir elsewhere, while regenerating a * `CLAUDE.md` you have uncommitted edits to still gates. Empty under a clean/absent git * worktree. */ export declare function dirtyWriteTargets(plan: Plan, ctx: PlanContext): Promise; /** * The repo-relative paths a plan would REMOVE that ALSO have uncommitted changes — * the "this apply would delete your uncommitted work" set. Unlike writes, a removal * has no content-equality escape: deleting a dirty or untracked file always destroys * it, so this gates on dirty-set membership. Empty under a clean/absent git worktree, * so `--force` is never needed on a committed tree. * * A removal target may be a DIRECTORY (e.g. `aih skill remove` moves a whole skill * dir in one action). A dirty file lives in the set under its own path, never under * the parent dir's, so an exact-match test alone would let a dir removal clobber an * uncommitted file INSIDE it without `--force`. So a target also gates when any dirty * path is a descendant of it (`/…`) — the dir carries its dirty children. */ export declare function dirtyRemoveTargets(plan: Plan, ctx: PlanContext): Promise;