export type WsMode = 'shared' | 'exclusive'; export type WsScope = { kind: 'dir'; path: string; } | { kind: 'global'; name: string; }; export interface WsHolderInfo { /** Agent id when known ("manual" for bare CLI use). */ agentId?: string; kind?: string; taskId?: string; projectId?: string; /** Free-text reason shown in pings ("npm install", "git finalize"). */ label?: string; } export interface WsHandle { scope: WsScope; mode: WsMode; file: string; pid: number; startedAt: string; } export interface WsHolder { pid: number; mode: WsMode; startedAt: string; holder: WsHolderInfo; /** Absolute path of the holder file (purge/release needs it). */ file: string; stale: boolean; } /** Comfortably above any real build/install; crashed holders die by pid check anyway. */ export declare const WS_MAX_HOLD_MS: number; export declare const ARBITRATION_LOG: string; /** Canonical, case-folded identity of a working directory (win32-safe). */ export declare function canonicalDir(path: string): string; export declare function scopeKey(scope: WsScope): string; /** True when `file` lives inside the managed lock tree (release guard). */ export declare function isInsideLockRoot(file: string): boolean; /** Live + stale holders for a scope (stale ones still listed for pings). */ export declare function readWsHolders(scope: WsScope): WsHolder[]; /** Holders by precomputed scope key (status endpoints scan the tree). */ export declare function readWsHoldersByKey(key: string): WsHolder[]; export type AcquireResult = { ok: true; handle: WsHandle; } | { ok: false; reason: 'busy'; holders: WsHolder[]; } | { ok: false; reason: 'reentrant-conflict'; holders: WsHolder[]; }; /** * One-shot acquire. Exclusive requires an EMPTY live-holder set; shared * requires no live EXCLUSIVE holder. Same-pid same-mode is re-entrant * (returns the registered handle); same-pid cross-mode refuses rather than * corrupting state. */ export declare function tryAcquireWsLock(scope: WsScope, mode: WsMode, info?: WsHolderInfo): AcquireResult; /** * Wait until the scope admits `mode`, then hold it. Returns null on * deadline. `onWaiting` fires once per poll cycle while blocked (used to * emit bus pings + console notes exactly like ../lock.ts). */ export declare function acquireWsLock(scope: WsScope, mode: WsMode, info?: WsHolderInfo, opts?: { waitMs?: number; pollMs?: number; onWaiting?: (holders: WsHolder[]) => void; }): Promise; /** Release a handle this process owns (no-op otherwise). */ export declare function releaseWsLock(handle: WsHandle | null | undefined): void; /** Release every handle this process still holds (crash/exit safety net). */ export declare function releaseAllWsLocks(): void; /** Run `fn` under the lock; always releases, even on throw. */ export declare function withWsLock(scope: WsScope, mode: WsMode, info: WsHolderInfo, fn: () => Promise, opts?: { waitMs?: number; pollMs?: number; onWaiting?: (h: WsHolder[]) => void; }): Promise; /** Append-only human-readable trail (best-effort, size-capped). */ export declare function logArbitration(line: string): void; /** Temp helper used by tests/E2E to fabricate a stale holder. */ export declare function __writeForeignHolder(scope: WsScope, mode: WsMode, pid: number, ageMs?: number): string; /** Isolated root override for tests (never called in production paths). */ export declare function __setLockRootForTests(dir?: string): void;