/** * Result of committing the working tree. `hash` is the commit sha, or null when * there was nothing to commit (empty ledger, all paths ignored/missing, or no * dirty changes). `skippedIgnored` lists scoped paths that were dropped because * git ignores them, deliberately excluded from staging so an ignored bookkeeping * path in a self-reported ledger cannot fail the whole commit. Callers surface * this as an honest note rather than a failure. */ export interface CommitWorkingTreeResult { readonly hash: string | null; readonly skippedIgnored: readonly string[]; } /** * AgentWorktree, Manages git worktree lifecycle for spawned agents. * * Each agent works in an isolated git worktree so its file changes are * sandboxed from the main working tree. * * Lifecycle: * create() , create worktree + branch, return path * merge() , merge agent branch back to current branch, remove worktree * cleanup(), remove worktree without merging (cancel/error path) */ export declare class AgentWorktree { private readonly git; constructor(cwd: string); /** * Create a new worktree for the given agent. * Returns the absolute path to the worktree directory. */ create(agentId: string): Promise; /** * Merge the agent's branch back into the current branch and remove the worktree. * Returns true if a merge was performed, false if no changes were found. */ merge(agentId: string): Promise; /** * @param paths When provided (non-empty), stage only these paths instead of sweeping the * whole working tree. Paths are self-reported LLM claims, not ground truth, so they are * filtered before staging: * - a path that exists on disk (created/modified) is kept outright; * - a path that does not exist is kept only if `git ls-files` shows it as tracked (a real * deletion), otherwise it is a hallucinated path and dropped, `git add -A -- ` * throws "pathspec did not match any files" for a path neither on disk nor known to git; * - a path that git IGNORES (e.g. the product's own `.goodvibes/` bookkeeping written by a * memory/preference tool) is dropped and reported in `skippedIgnored`. This is load-bearing: * `git add -A -- ` exits non-zero ("paths are ignored") AFTER staging its valid * siblings, so a single ignored path in the ledger would both fail the whole batch and * leave the real deliverables staged in the user's index. * On any commit failure the staged paths are reset so the caller's index is never left mutated * by a commit that could not complete. Omit (or pass an empty array) to keep the legacy * `git add --all` sweep for back-compat. */ commitWorkingTree(message: string, paths?: string[]): Promise; /** * Unstage the given pathspecs after a failed commit so the caller's index is returned to its * pre-commit state. `git reset -- ` is safe on a repo with no HEAD yet (a brand-new * repo whose first commit was the one that just failed). Best-effort: a reset failure is logged, * not thrown, so it never masks the original commit error the caller needs to see. */ private _restoreIndex; currentHead(): Promise; /** * Remove the worktree without merging (cancel/error path). */ cleanup(agentId: string): Promise; private _worktreePath; private _branchName; /** * Check whether the agent branch has any commits that differ from * the current branch (the main working tree HEAD). */ private _hasChanges; private _branchExists; /** * Force-remove a worktree directory. */ private _removeWorktree; /** * Delete a branch (no-op if it doesn't exist). */ private _deleteBranch; } /** Outcome of integrating an item branch back into the base branch (see IsolatedWorktree.integrate). */ export type IntegrationOutcome = /** Clean merge, `hash` is the merge commit on the base branch. */ { readonly status: 'merged'; readonly hash: string; } /** The base merge conflicted; `files` names the conflicting paths. The base tree is restored (merge --abort) so the lane can continue. */ | { readonly status: 'conflict'; readonly files: readonly string[]; } /** The item branch carried no commits beyond base, nothing to merge (an honest no-op, not a failure). */ | { readonly status: 'empty'; }; /** * IsolatedWorktree, one work item's dedicated git worktree for the * orchestration engine's `worktree` isolation mode (see WorkstreamIsolation). * * Unlike {@link AgentWorktree} (whose merge() folds an agent branch into the * SAME working tree's current branch and is used today only for its * commitWorkingTree surface), an IsolatedWorktree models the full per-item * lifecycle the engine drives: * * create() , add a git worktree at `path` on a fresh branch `branch`, * branched from the base branch (the root tree's current HEAD). * commit() , scoped-commit the item's touched paths onto `branch`, INSIDE * the worktree (delegates to AgentWorktree.commitWorkingTree * bound to `path`, so the ignored/hallucinated/deletion * filtering is reused verbatim). * isClean() , whether the worktree's working tree has uncommitted changes * (drives the fail/kill cleanup rule: remove only if clean). * integrate(), merge `branch` into the base branch IN THE ROOT TREE. The * root tree stays checked out on base; a different branch being * merged never needs the worktree removed first. On conflict it * runs `merge --abort` to restore the root index so the single * sequential integration lane can proceed to the next item. * remove() , remove the worktree dir and delete `branch` (post-merge, or * a clean tree after fail/kill). * keepInPlace()/branchHasCommits(), inspection helpers for KEPT worktrees. * * Location: worktrees live under `/.goodvibes/.worktrees/`, the same * gitignored bookkeeping area AgentWorktree and WorktreeRegistry already use, * chosen over the system temp dir deliberately: (1) crash cleanup, a worktree * under the repo is discoverable by `git worktree list` and the existing * WorktreeRegistry path scan, so an orphan left by a crashed process can be * reconciled; a temp-dir worktree is invisible to repo-relative reconciliation * and can be swept out from under a KEPT (dirty) tree by an OS temp cleaner, * losing data. (2) gitignore interplay, `.goodvibes/` is already ignored and * the commit path already excludes it, so a nested worktree checkout there * never pollutes the parent's tracked status nor gets accidentally committed. */ export declare class IsolatedWorktree { readonly path: string; readonly branch: string; private readonly rootGit; private readonly baseBranch; /** * @param rootDir the repository root (base tree), merges land here. * @param path absolute path for this item's worktree directory. * @param branch the item branch name to create/check out in the worktree. * @param baseBranch the branch merges integrate into (the root tree's branch). */ constructor(rootDir: string, path: string, branch: string, baseBranch: string); /** Add the worktree on a fresh `branch` branched from base (the root tree's current HEAD). */ create(): Promise; /** * Scoped-commit the item's touched paths onto the item branch, inside the * worktree. Reuses AgentWorktree.commitWorkingTree (bound to the worktree * path) so the ignored/hallucinated/confirmed-deletion filtering is identical * to shared mode. A fresh worktree starts clean, so in worktree mode the * launch-dirty snapshot is per-worktree and trivially empty (see the engine). */ commit(message: string, paths?: string[]): Promise; /** HEAD of the item branch (inside the worktree), or null if it can't be read. */ currentHead(): Promise; /** True when the worktree has NO uncommitted changes (clean tree). Missing dir ⇒ treated as clean. */ isClean(): Promise; /** True when the item branch carries at least one commit beyond the base branch. */ branchHasCommits(): Promise; /** * Merge the item branch into the base branch in the ROOT tree. Returns an * honest {@link IntegrationOutcome}: `merged` (with the merge commit hash), * `conflict` (with the conflicting files, the merge is aborted so the root * is restored and the lane can continue), or `empty` (no commits to merge). * Never auto-resolves a conflict. */ integrate(): Promise; /** * The diff this item branch introduced over the base branch (base...branch, * changes on the branch since it diverged). The existing diff plumbing behind * a best-of-N candidate: returns the changed files, the unified diff text, and * the diffstat. A read error degrades to an empty diff, never throws. */ diff(): Promise<{ files: string[]; unifiedDiff: string; stat: string; }>; /** Remove the worktree directory and delete the item branch (post-merge, or a clean tree after fail/kill). */ remove(): Promise; /** * Evict this worktree under the kept-worktree cap. Eviction bounds DISK * usage, never work: any uncommitted state (modified AND untracked files, * unfiltered, preservation must be exact) is first committed onto the item * branch, then ONLY the directory is removed. The branch is deliberately * KEPT, so a conflicted/dirty tree evicted past the cap stays recoverable * with `git worktree add ` / `git show :`. * * When the preservation commit cannot be created, the directory is NOT * removed (the error propagates), leaving an over-cap directory on disk is * always preferred over destroying uncommitted work. * * @returns the preservation commit hash, or null when the tree was already * clean (nothing needed preserving). */ evict(): Promise<{ preservedCommit: string | null; }>; /** Remove the worktree directory (plain remove, then a --force retry). */ private removeDirectory; } //# sourceMappingURL=worktree.d.ts.map