/**
 * DistributedLock — file-based cross-process lock with TTL + heartbeat.
 *
 * Story 6.4 — OpenLife v1.2 Royal Stack.
 *
 * Use case: prevent two OpenLife instances (e.g. dev + autonomous
 * daemon) from running the same WorkflowEngine run or mission
 * concurrently. The lock is a file under `<stateDir>/locks/<key>.lock`
 * containing `{pid, host, lockId, ts, ttlMs}`. Crash safety: if the
 * holder dies, the next contender takes over either (a) after `ttlMs`
 * elapses, or (b) immediately if the holder ran on THIS host and its
 * pid is provably gone (liveness reclaim) — a SIGKILL'd daemon does not
 * lock its own restart out for a full TTL. Reclaim is fail-safe: a live
 * pid, an unprobeable (cross-host) pid, or a reused pid all fall back to
 * TTL-only, so we never steal from a living holder.
 *
 * Atomicity: lock creation uses `O_EXCL | O_CREAT` so two processes
 * racing for the same key see exactly one winner. AtomicWriter is used
 * for renewals.
 */
export interface LockRecord {
    pid: number;
    host: string;
    lockId: string;
    key: string;
    acquiredAt: number;
    ts: number;
    ttlMs: number;
}
export interface AcquireSuccess {
    ok: true;
    lockId: string;
    filePath: string;
}
export interface AcquireFailure {
    ok: false;
    heldBy?: LockRecord;
    error?: 'collision' | 'io_error';
    message?: string;
}
export type AcquireResult = AcquireSuccess | AcquireFailure;
export interface DistributedLockOptions {
    /** Override base lock directory. Default: <OPENLIFE_STATE_DIR or .openlife>/locks */
    baseDir?: string;
}
export declare class DistributedLock {
    private readonly baseDir;
    /** In-process registry of held locks, keyed by lockId. */
    private readonly heldByLockId;
    constructor(opts?: DistributedLockOptions);
    /**
     * Attempt to acquire the lock for `key`. Succeeds if (a) no lock file
     * exists, or (b) the existing lock has expired (ts + ttlMs <= now).
     *
     * If `startHeartbeat: true` (default true), the caller's lock TTL is
     * auto-renewed at ttlMs/3 intervals via setInterval. Call release()
     * to stop the heartbeat.
     */
    acquire(key: string, ttlMs: number, opts?: {
        startHeartbeat?: boolean;
    }): AcquireResult;
    /**
     * Decide whether an existing lock can be taken over. Two independent
     * reclaim conditions, both fail-safe:
     *
     *   1. TTL expiry — `now - ts > ttlMs`. The original heartbeat-based
     *      rule: a holder that stopped renewing eventually goes stale.
     *   2. Liveness reclaim — the holder ran on THIS host and its pid is
     *      provably gone. The heartbeat can never renew a dead pid's `ts`,
     *      so the lock is dead weight; stealing it avoids waiting out the
     *      full TTL on a daemon that was SIGKILL'd mid-mission.
     *
     * Condition 2 is gated on same-host because `process.kill(pid, 0)` can
     * only probe local pids. A live pid (signal succeeds or EPERM), a
     * cross-host pid (unprobeable), or a reused pid (signal succeeds) all
     * fail this check and fall back to TTL-only — we never steal from a
     * living holder.
     */
    private isReclaimable;
    /**
     * Update the heartbeat (ts field) on a lock we hold. Returns true if
     * the renewal succeeded (file still exists and our lockId is intact),
     * false if the lock was stolen or removed.
     */
    renew(lockId: string): boolean;
    /**
     * Release the lock we hold. Removes the lock file (if we still own it)
     * and stops the heartbeat. Idempotent.
     */
    release(lockId: string): void;
    /**
     * Inspect the current holder for `key` (or null if unlocked).
     */
    peek(key: string): LockRecord | null;
    /**
     * Release all locks currently held by this process. Useful for clean
     * shutdown of a daemon.
     */
    releaseAll(): void;
    private trackHeld;
    private stopHeartbeat;
    private readLock;
    private ensureBaseDir;
    private lockPath;
    private sanitize;
    private newLockId;
    /** Exposed for tests so they can assert resolved storage location. */
    _baseDir(): string;
}
