/** * Holder identity for the per-task worktree lock (T12506 · epic T12498). * * `@cleocode/worktree` takes an atomic per-task lock before `git worktree add` * and records who holds it. It cannot import core, so the spawn pipeline * resolves the identity here — the spawned agent's own session + agent id, the * stable device id, and the long-lived OWNER process (the agent harness above * the short-lived `cleo` + shell) with its `ps` start time — and passes it in * `CreateWorktreeOptions.holder`. * * The owner pid is usually the agent harness (codex, claude), which hosts many * sessions in turn, so the lock's liveness also consults the holder SESSION: * session end releases the session's locks, and an ended holder session is * reclaimable by a successor's spawn or `--resume`, audited (T13425). * * @module spawn/worktree-lock-holder * @task T12506 * @task T13425 */ import type { WorktreeLockAcquisition, WorktreeLockHolder, WorktreeLockSessionProbe, WorktreeLockSessionState } from '@cleocode/contracts'; import { type ProcessAncestor } from '../sessions/terminal-identity.js'; /** Inputs for {@link resolveSpawnLockHolder}. */ export interface SpawnLockHolderInput { /** The spawned agent's per-agent session id. */ sessionId?: string | null; /** The spawned agent's agent id. */ agentId?: string | null; /** Owner-process resolver (tests inject fakes). */ resolveOwner?: () => ProcessAncestor | null; /** Device-id reader (tests inject fakes). */ deviceId?: () => string; } /** * Build the {@link WorktreeLockHolder} for a spawn. * * Falls back to the current process (pid + start probed by the worktree * package) when the owner chain cannot be read, e.g. on Windows. * * @param input - Session/agent identity and test seams. * @returns The holder identity to record in the lock. */ export declare function resolveSpawnLockHolder(input?: SpawnLockHolderInput): WorktreeLockHolder; /** Session store lookup; tests inject fakes. */ export type SessionStatusLookup = (sessionId: string, projectRoot: string) => Promise<{ status: string; } | null>; /** * Map a session row to a lock-liveness state: an active or suspended session * keeps its locks (a suspended one may resume). Any other status releases them: * `ended`, or `orphaned`, which the idle sweep sets on a session idle past its * max age with no live claim. A missing session releases them too, including * a live session absent from an older snapshot after `cleo restore backup`. * * @param session - The session row, or `null` when none exists. * @returns The lock-liveness state. */ export declare function lockSessionState(session: { status: string; } | null): WorktreeLockSessionState; /** * Build the session probe for acquiring `taskId`'s worktree lock (T13425). * * The lock module is synchronous and cannot read the session store, so the * current holder's session is looked up here first. The probe answers for that * session only; any other id (the lock changed hands in between) is `unknown`, * which leaves the verdict to the pid and heartbeat checks. * * @param projectRoot - Project root (the session store). * @param taskId - Task whose lock is about to be acquired. * @param lookup - Session lookup (tests inject fakes). * @returns The probe to pass as `sessionProbe`. */ export declare function resolveLockSessionProbe(projectRoot: string, taskId: string, lookup?: SessionStatusLookup): Promise; /** * Audit a reclaimed worktree lock (T13425): which holder lost it and why. A * fresh or re-entered acquisition writes nothing. * * @param projectRoot - Project root (the audit log). * @param taskId - Task the lock guards. * @param worktreePath - The worktree the lock guards. * @param acquisition - The acquisition result. */ export declare function auditWorktreeLockReclaim(projectRoot: string, taskId: string, worktreePath: string, acquisition: WorktreeLockAcquisition | undefined): void; /** * Release every worktree lock held by `sessionId` in this project and audit * each (T13425). Called when the session ends. Never throws: a failure here * must not fail session end, and an unreleased lock is still reclaimable once * the session reads as ended. * * @param projectRoot - Project root. * @param sessionId - The ending session. * @returns The task ids whose locks were released. */ export declare function releaseSessionWorktreeLocks(projectRoot: string, sessionId: string): string[]; //# sourceMappingURL=worktree-lock-holder.d.ts.map