/** * Worktree-sync git engine: every git-touching operation of the subsystem, built on one injected * `exec` seam (the `improvement-loop.ts` pattern) so each function is unit-testable with a * scripted exec fake and integration-testable against real git. * * Doctrine (see docs/worktree-sync.md): * - Git is the single source of truth. Freshness ("is current main an ancestor of the lane * tip?"), dirtiness, ahead/behind, and rebase-in-progress are RE-DERIVED per call -- the JSON * store (`store.ts`) contributes identity/binding only and is rebuildable via {@link reconcile}. * - Policy refusals are RETURNED as tagged codes (`codes.ts`), never thrown; git's own stderr * rides along as evidence, never as a branch condition. * - Nothing here deletes user work silently: releasing a lane with unlanded commits or dirty * files requires the explicit discard confirmation, and reconcile only marks orphans. */ import { type ExecResult } from "../exec.ts"; import { type AbortSyncResult, type BindLaneWorkerResult, type ContinueSyncResult, type CreateLaneResult, type LandResult, type LaneFacts, type LaneRegistration, type ReconcileResult, type ReleaseLaneResult, type SyncLaneResult, type SyncStatusResult, type WorktreeSyncPolicy, type WorktreeSyncRefusal } from "./codes.ts"; import { type SyncStorePaths } from "./store.ts"; export type WorktreeSyncExec = (command: string, args: string[], options: { cwd: string; timeout?: number; signal?: AbortSignal; maxBuffer?: number; env?: NodeJS.ProcessEnv; }) => Promise; export interface WorktreeSyncEngineOptions { /** Overrides default-branch resolution; unset resolves local `main`, then `master` (D13). */ mainBranchOverride?: string; /** Active-lane ceiling; `create_lane` refuses beyond it. */ maxLanes: number; } export interface WorktreeSyncEngineDeps { exec: WorktreeSyncExec; /** Session cwd -- any directory inside the repo (hub checkout or a lane worktree). */ cwd: string; /** Base for lane checkouts (`agent-paths.worktreesDir(agentDir)`); engine appends `/`. */ worktreesBaseDir: string; options: WorktreeSyncEngineOptions; signal?: AbortSignal; now?: () => string; pid?: number; sessionId?: string; /** Injectable fs probe for deterministic tests. Default: `existsSync`. */ fileExists?: (path: string) => boolean; /** Injectable file reader (conflict-marker scan, rebase progress). Default: `readFileSync`, * returning undefined on any read error. */ readFile?: (path: string) => string | undefined; /** Injectable same-host pid liveness for deterministic tests. */ isPidAlive?: (pid: number) => boolean; } export interface RepoContext { topLevel: string; gitCommonDir: string; mainBranch: string; mainSha: string; paths: SyncStorePaths; slug: string; /** Checkout where the main branch is checked out (the hub); undefined when main is not checked out. */ hubPath?: string; } /** Production exec: `exec.ts`'s bounded `execCommand` (rolling-tail output, timeout, abort). */ export declare function createDefaultWorktreeSyncExec(): WorktreeSyncExec; export declare function laneBranch(laneKey: string): string; export interface WorktreeListEntry { path: string; headSha?: string; /** Full ref (`refs/heads/x`) when a branch is checked out; undefined for detached/bare. */ branchRef?: string; } /** Parse `git worktree list --porcelain` blocks. */ export declare function parseWorktreeList(output: string): WorktreeListEntry[]; export declare function resolveRepoContext(deps: WorktreeSyncEngineDeps): Promise>; /** * Live git facts for one lane. `fresh` is THE freshness definition of the whole subsystem * (G3/G9): current main is an ancestor of the lane tip. Everything is re-derived; nothing is * read back from a cache that could disagree with git. */ export declare function deriveLaneFacts(deps: WorktreeSyncEngineDeps, ctx: RepoContext, lane: LaneRegistration): Promise; /** One-time repo git config (D7): shared rerere + zdiff3 conflict hunks -- the deterministic * conflict-resolution substrate for every lane (the rr-cache lives in the common dir, so one * resolution replays identically in all worktrees). Idempotent; only actual changes are audited. */ export declare function ensureRepoGitConfig(deps: WorktreeSyncEngineDeps, ctx: RepoContext): Promise; export interface CreateLaneArgs { laneKey?: string; goalId?: string; requirementId?: string; } export declare function createLane(deps: WorktreeSyncEngineDeps, args?: CreateLaneArgs): Promise; export interface BindLaneWorkerArgs { laneKey: string; laneId: string; } export declare function bindLaneWorker(deps: WorktreeSyncEngineDeps, args: BindLaneWorkerArgs): Promise; export interface ReleaseLaneArgs { laneKey: string; /** Required as exactly "yes-discard-lane" to release a lane with unlanded commits or dirty files (G11). */ confirm?: string; } export declare function releaseLane(deps: WorktreeSyncEngineDeps, args: ReleaseLaneArgs): Promise; /** * Startup/repair pass (mirrors the tmux session reconcile): diff the registry against git * reality, mark orphans (never delete -- G11), re-register lane worktrees git still knows that * the registry lost (a deleted store is fully rebuildable), self-heal orphan registrations whose * worktree+branch actually exist, clear dead owners, and release a provably-stale lock. */ export declare function reconcile(deps: WorktreeSyncEngineDeps): Promise; export interface SyncLaneArgs { laneKey: string; } /** * Rebase current main into the lane branch, locally (the awareness half of "perfect sync"; the * land gate is the enforcement half). Pins the main sha it derived so a concurrent land cannot * change this sync's meaning mid-flight (D-pinned-sha). Conflicts leave the rebase in progress * and return a structured worklist; `continueSync` verifies and drives on. */ export declare function syncLane(deps: WorktreeSyncEngineDeps, args: SyncLaneArgs): Promise; export interface ContinueSyncArgs { laneKey: string; } /** * G9: verify the agent's conflict resolution mechanically (zero conflict markers by byte-scan -- * the agent never self-certifies), stage it, and drive the rebase on. More conflicts return the * next worklist; completion returns sync_clean. */ export declare function continueSync(deps: WorktreeSyncEngineDeps, args: ContinueSyncArgs): Promise; export interface AbortSyncArgs { laneKey: string; } /** Abort an in-progress sync rebase: the lane returns to its pre-sync tip -- still stale, and * honestly reported as such by status. */ export declare function abortSync(deps: WorktreeSyncEngineDeps, args: AbortSyncArgs): Promise; export interface LandLaneArgs { laneKey: string; /** "on" runs gateCommand (G4); "off" is the owner-level opt-out, recorded per land event. */ gate: "on" | "off"; gateCommand?: string; gateTimeoutMs?: number; } /** * The land gate -- the ONLY door to main (G1-G7). Serialized under the integration lock; every * precondition is re-derived INSIDE the lock (the compare-and-swap that makes the whole system * race-free: even if every notification failed, a stale lane cannot land). Main only ever moves * by ff-only merge of an already-rebased lane branch; a successful land bumps the epoch and * broadcasts in the same critical section. */ export declare function landLane(deps: WorktreeSyncEngineDeps, args: LandLaneArgs): Promise; export interface SyncStatusArgs { policy: WorktreeSyncPolicy; } /** * The deterministic full picture (the tool's `status` action): epoch, hub, lock, and per-lane * live facts with the policy derivation (stale / syncRequired / overlap). The `advice` line is * assembled from codes -- never model-generated -- so every agent reads the same situation the * same way. */ export declare function buildSyncStatus(deps: WorktreeSyncEngineDeps, args: SyncStatusArgs): Promise; //# sourceMappingURL=git-engine.d.ts.map