import type { WorkspaceContext } from '../engines/workspace-resolver.js';
/** Write a heartbeat to the lockfile every this many ms. */
export declare const HEARTBEAT_INTERVAL_MS = 10000;
/** A lock whose heartbeat is older than this is considered stale and acquirable. */
export declare const STALE_HEARTBEAT_MS = 30000;
export interface DaemonLockRecord {
    version: 1;
    pid: number;
    port?: number;
    token?: string;
    startedAt: number;
    updatedAt: number;
    /** Updated by the running daemon every HEARTBEAT_INTERVAL_MS. */
    heartbeatAt?: number;
    stateKey: string;
    stateRoot: string;
    workspaceRoot: string;
    repoRoot: string;
    /** Package version of the daemon process that wrote this lock. */
    pkgVersion?: string;
}
export interface AcquireDaemonLockResult {
    status: 'acquired' | 'running';
    lockPath: string;
    record: DaemonLockRecord;
    staleRemoved: boolean;
}
export interface ScannedDaemonLock {
    lockPath: string;
    stateRoot: string;
    lock: DaemonLockRecord;
}
export declare function getDaemonLockPath(workspace: Pick<WorkspaceContext, 'stateRoot'>): string;
export declare function isProcessAlive(pid: number): boolean;
/**
 * A lock is considered stale when its heartbeat has not been updated within
 * STALE_HEARTBEAT_MS (30 s).  A SIGKILL'd daemon cannot release its lock but
 * will stop writing heartbeats, so the next starter can safely acquire after
 * the TTL expires.
 */
export declare function isLockStale(lock: DaemonLockRecord): boolean;
export declare function readDaemonLock(lockPath: string): DaemonLockRecord | null;
export declare function writeDaemonLock(lockPath: string, record: DaemonLockRecord): DaemonLockRecord;
export declare function acquireDaemonLock(workspace: WorkspaceContext, overrides?: Partial<DaemonLockRecord>): AcquireDaemonLockResult;
export declare function removeDaemonLock(lockPath: string, options?: {
    pid?: number;
}): boolean;
export declare function scanAllLockfiles(rootDir?: string): ScannedDaemonLock[];
