/** * Branch-lock engine — runtime enforcement for agent git isolation (T1118). * * Implements all four protection layers: * * - L1: Git worktree creation, merge-completion (ADR-062), and cleanup. * - L2: Shim symlink materialisation + spawn env construction. * - L3: Filesystem hardening via chmod (+ optional chattr on Linux). * - L4: Not here — L4 lives in validate-engine and session domain handlers. * * Worktree integration uses `git merge --no-ff` exclusively per ADR-062. * The legacy cherry-pick integration path was removed in T1624. * * All git operations use execFileSync with explicit arg arrays (no shell * interpolation) to prevent command injection. * * @task T1118 * @adr ADR-055 * @adr ADR-062 */ import type { AgentWorktreeState, FsHardenCapabilities, FsHardenState, WorktreeCleanupResult, WorktreeMergeResult, WorktreeSpawnResult } from '@cleocode/contracts'; import { getGitRoot } from '@cleocode/worktree'; export { getGitRoot }; /** * Resolve the worktree root directory for a project. * * Delegates to the canonical paths-SSoT helpers in `@cleocode/paths`. The * resolved directory follows the XDG canonical layout per D029: * * Linux: ~/.local/share/cleo/worktrees// * macOS: ~/Library/Application Support/cleo/worktrees// * Windows: %LOCALAPPDATA%\cleo\Data\worktrees\\ * * T9984: previously hand-rolled `createHash('sha256').update(projectRoot)` + * `process.env['XDG_DATA_HOME']` — both violations of the paths-SSoT lint * (`packages/paths/` is the only legitimate source of these computations). * Now routes through `computeProjectHash` and `resolveWorktreeRootForHash`. * * @param projectRoot - Absolute path to the project root. * @returns Absolute path to the worktree root directory. * * @task T1118 * @task T1120 * @task T9984 */ export declare function resolveAgentWorktreeRoot(projectRoot: string): string; /** * Create a git worktree for a spawned agent task. * * Creates branch `task/` off the current HEAD of the orchestrator's * branch and locks the worktree to prevent accidental pruning. * * @param taskId - The task ID driving the spawn. * @param projectRoot - Absolute path to the project root. * @returns The created worktree state. * * @task T1118 * @task T1120 * @task T11122 * @task T11123 */ export declare function createAgentWorktree(taskId: string, projectRoot: string): AgentWorktreeState; /** * Construct the spawn env-var injection + preamble for the agent. * * Called by orchestrateSpawn after createAgentWorktree to produce the * env block and prompt preamble that bind the agent to its worktree. * * @param worktree - The created worktree state. * @param shimDir - Directory containing the git shim symlink. * @param identity - Per-agent session + agent identity to inject (T11343). * `sessionId` → `CLEO_SESSION_ID`, `agentId` → `CLEO_AGENT_ID`. Only set * when non-empty so an unallocated identity never clobbers an inherited env. * @returns Spawn result with env vars, CWD, and prompt preamble. * * @task T1118 * @task T1120 * @task T1121 * @task T11343 */ export declare function buildWorktreeSpawnResult(worktree: AgentWorktreeState, shimDir: string, identity?: { sessionId?: string | null; agentId?: string | null; }): WorktreeSpawnResult; /** * Prune orphaned agent worktrees for a project. * * T11123: Delegates to `pruneWorktrees` from `@cleocode/worktree` which uses * the NAPI `pruneWorktrees` / `destroyWorktree` bindings (Rust worktrunk-core) * instead of raw `git worktree prune/unlock/remove` shell-outs. * * @param projectRoot - Absolute path to the project root. * @param taskIds - Optional set of known-active task IDs to preserve. * @returns Cleanup result. * * @task T1118 * @task T1120 * @task T11123 */ export declare function pruneOrphanedWorktrees(projectRoot: string, taskIds?: Set): WorktreeCleanupResult; /** * Result of a single-task worktree prune operation. * * @task T1462 */ export interface PruneWorktreeResult { /** Task ID whose worktree was targeted. */ taskId: string; /** Outcome: 'pruned' — cleaned up, 'skipped' — no worktree found, 'error' — failed. */ status: 'pruned' | 'skipped' | 'error'; /** Whether the worktree directory was removed. */ worktreeRemoved: boolean; /** Whether the task branch was deleted. */ branchDeleted: boolean; /** Whether the worktree was dirty (had uncommitted changes) when pruned. */ wasDirty: boolean; /** Error message if any step failed. */ error?: string; } /** * Prune the worktree for a single completed or cancelled task. * * This function does NOT integrate commits — it is called after * {@link completeAgentWorktreeViaMerge} (or `cleo complete`) has already * recorded the task as done. It simply removes the worktree filesystem entry * and the `task/` branch if the branch has no commits ahead of the * base ref. * * Behaviour: * - Returns `{ status: 'skipped' }` when no worktree exists for the task. * - Unlocks the worktree before removing (handles locked worktrees created by spawn). * - Falls back to `rmSync` if `git worktree remove` fails. * - Deletes `task/` branch only when it has 0 commits ahead of the * current HEAD (i.e. the branch has already been merged or is empty). * When commits are still present the branch is left in place and reported in * the result — callers should use `completeAgentWorktreeViaMerge` first. * - Always writes a `--force` remove with an audit log entry (`.cleo/audit/worktree-prune.jsonl`) * when the worktree is detected as dirty. * - Never throws — failures are returned in `{ status: 'error', error }`. * * @param taskId - The CLEO task ID (e.g. "T1462"). * @param projectRoot - Absolute path to the project root. * @param opts.auditLogPath - Override path for the audit JSONL (testing). * @returns Prune outcome. * * @task T1462 * @adr ADR-055 */ export declare function pruneWorktree(taskId: string, projectRoot: string, opts?: { auditLogPath?: string; }): PruneWorktreeResult; /** * Resolve the project's default integration branch in a project-agnostic way. * * Resolution order (per ADR-062): * * 1. `.cleo/config.json::git.defaultBranch` (explicit override). * 2. `git symbolic-ref refs/remotes/origin/HEAD` (what the remote calls * default — works for `master`, `main`, `trunk`, etc.). * 3. Probe local branches in order: `main`, `master`, `develop`, `trunk`. * 4. Fallback to `'main'`. * * @param projectRoot - Absolute path to the project root. * @returns The resolved default branch name (never throws). * * @task T1587 * @adr ADR-062 */ export declare function getDefaultBranch(projectRoot: string): string; /** * Complete a worker task's worktree via `git merge --no-ff` (ADR-062). * * Canonical worktree integration per ADR-062. Preserves the full agent * commit graph instead of rewriting SHAs, so `git log --grep "T"` * returns the originating commits with their original authorship. * * Steps performed inside the worktree at * `~/.local/share/cleo/worktrees///`: * * 1. Resolve target branch via {@link getDefaultBranch} (or `opts.targetBranch` * override). NEVER hardcodes "main". * 2. `git fetch origin` then `git rebase origin/` inside the * worktree. Conflicts cause an early non-fatal return — the agent must * re-resolve before completion. * 3. From the project's git root on ``, run * `git merge --no-ff task/ -m "Merge T: "` so the * merge commit subject is `git log --grep`-friendly. * 4. Capture the merge commit SHA and report it. * 5. Delegate worktree+branch removal to {@link pruneWorktree} (T1462). * * Project-agnostic: no string in this function hardcodes "main", "master", * or any other branch name. Test fixtures pass arbitrary `targetBranch`. * * @param taskId - The CLEO task ID (e.g. `"T1587"`). * @param projectRoot - Absolute path to the project root. * @param opts.targetBranch - Override the resolved default branch. * @param opts.taskTitle - Task title used in the merge commit message subject. * @param opts.skipFetch - Skip the `git fetch origin` step (test fixtures). * @returns Merge integration result. * * @task T1587 * @adr ADR-062 */ export declare function completeAgentWorktreeViaMerge(taskId: string, projectRoot: string, opts?: { targetBranch?: string; taskTitle?: string; skipFetch?: boolean; }): WorktreeMergeResult; /** * Result of a complete post-merge worktree integration. * * Extends `WorktreeMergeResult` with an additional audit log path field. * * @task T9043 * @adr ADR-062 */ export interface WorktreeIntegrationResult extends WorktreeMergeResult { /** Path to the audit log entry that was written (if any). */ auditLogEntry: string | null; } /** * Complete a worker task's worktree integration via merge, cleanup, and audit log. * * This is the orchestrator-facing convenience wrapper around * `completeAgentWorktreeViaMerge`. In addition to the merge+prune steps it: * * 1. Delegates all merge and cleanup to `completeAgentWorktreeViaMerge`. * 2. Appends a structured entry to `.cleo/audit/worktree-integration.jsonl` * recording the merge commit, task ID, and cleanup outcome. * * Orchestrators MUST call this (not `completeAgentWorktreeViaMerge` directly) * so every integration is auditable. * * @param taskId - The CLEO task ID (e.g. `"T1587"`). * @param projectRoot - Absolute path to the project root. * @param opts.targetBranch - Override the resolved default branch. * @param opts.taskTitle - Task title used in the merge commit message subject. * @param opts.skipFetch - Skip the `git fetch origin` step (test fixtures). * @param opts.auditLogPath - Override the audit JSONL path (testing). * @returns Integration result including audit log path. * * @task T9043 * @adr ADR-062 */ export declare function completeAgentWorktreeIntegration(taskId: string, projectRoot: string, opts?: { targetBranch?: string; taskTitle?: string; skipFetch?: boolean; auditLogPath?: string; }): WorktreeIntegrationResult; /** * Ensure the git shim symlink exists in the project's `.cleo/bin/git-shim/` dir. * * The shim directory is prepended to PATH in agent spawn env. Idempotent. * * @param projectRoot - Absolute path to the project root. * @returns Absolute path to the shim directory (to prepend to PATH). * * @task T1118 * @task T1121 */ export declare function ensureGitShimDir(projectRoot: string): string; /** * Detect platform capabilities for filesystem hardening. * * @returns Capability report. * * @task T1118 * @task T1122 */ export declare function detectFsHardenCapabilities(): FsHardenCapabilities; /** * Apply filesystem hardening to the orchestrator's .git/HEAD file. * * On Linux/macOS: chmod 400 the HEAD file. * When CLEO_HARD_LOCK=1: additionally attempt chattr +i (Linux) or chflags uchg (macOS). * * @param gitRoot - Absolute path to the git root directory. * @param opts.hardLock - Whether to apply immutable-file hardening. * @returns The applied harden state. * * @task T1118 * @task T1122 */ export declare function applyFsHarden(gitRoot: string, opts?: { hardLock?: boolean; }): FsHardenState; /** * Restore filesystem hardening (unlock HEAD) on session end or cleanup. * * @param hardenState - The state returned by applyFsHarden. * * @task T1118 * @task T1122 */ export declare function removeFsHarden(hardenState: FsHardenState): void; /** * Build the complete env block for a worker spawn with L1+L2 applied. * * @param worktreeResult - Result from buildWorktreeSpawnResult. * @param baseEnv - Base environment (defaults to process.env). * @returns Merged environment record. * * @task T1118 * @task T1120 * @task T1121 */ export declare function buildAgentEnv(worktreeResult: WorktreeSpawnResult, baseEnv?: Record<string, string>): Record<string, string>; //# sourceMappingURL=branch-lock.d.ts.map