/**
 * Reaper for orphaned / wedged keychain-helper processes.
 *
 * coreauthd / LocalAuthentication hangs can leave helper (and parent `agents`)
 * processes pile up. The pure planner ({@link planKeychainReap}) is unit-testable
 * without a real `ps`; the driver ({@link reapOrphanedKeychainProcesses}) shells
 * `ps` once per tick and kills through {@link killTree}.
 */
/** Grace before a helper whose parent exited is considered an orphan. */
export declare const ORPHAN_GRACE_SEC = 30;
/** Grace before a helper with a live parent is considered stuck. */
export declare const STUCK_GRACE_SEC = 90;
/** Snapshot of one process row from `ps`, fed into the pure planner. */
export interface KeychainProcessSnapshot {
    pid: number;
    ppid: number;
    /** Elapsed seconds since the process started. */
    elapsedSec: number;
    /** Stable start-time fingerprint from {@link captureProcessStartTime}; null fails closed. */
    startTime: string | null;
    /** True for a reap-eligible helper invocation (short-lived keychain verb). */
    isHelper: boolean;
    /**
     * True for the deliberately long-lived `watch-lock` watcher
     * (auto-lock-on-sleep). Mutually exclusive with {@link isHelper}; killing it
     * silently disables auto-lock-on-sleep, so it is reaped only once the owning
     * daemon is provably dead (RUSH-2419).
     */
    isWatchLock?: boolean;
}
/** Tracked state for a stuck parent across two-sweep debounce. */
export interface StuckParentCandidate {
    pid: number;
    startTime: string | null;
    helperPid: number;
    helperStartTime: string | null;
    firstSeenAt: number;
    stage: 'watch' | 'escalate';
}
/** Result of one planning pass. */
export interface ReapPlan {
    /** PIDs to kill this tick. */
    kill: number[];
    /** Candidates to carry forward to the next sweep. */
    nextCandidates: Map<number, StuckParentCandidate>;
}
/**
 * Pure predicate: decide which processes to kill given a `ps`-like snapshot.
 *
 * Three conservative classes:
 *   1. Orphaned helper: PPID == 1, helper path, alive longer than grace.
 *   2. Stuck `agents` parent: helper child alive longer than stuck grace,
 *      recorded on first sight, child killed on second sweep, parent on third.
 *   3. Orphaned `watch-lock`: long-lived watcher whose owning daemon is gone.
 *
 * Fails closed when start time can't be captured.
 */
export declare function planKeychainReap(snapshots: KeychainProcessSnapshot[], now: number, prevCandidates: ReadonlyMap<number, StuckParentCandidate>): ReapPlan;
/**
 * Parse macOS `ps -o etime=` elapsed time into whole seconds.
 *
 * BSD `etime` renders as `[[dd-]hh:]mm:ss`. `etimes` (raw seconds) is a GNU
 * extension that macOS `ps` rejects, so darwin uses `etime`.
 */
export declare function parseEtimeToSeconds(raw: string): number | null;
/**
 * Whether a `ps` command line is a reap-eligible helper invocation: the installed
 * helper binary running a short-lived keychain verb. Returns false for the
 * long-lived `watch-lock` watcher, which must never be mistaken for a stuck read.
 */
export declare function isReapableHelperCommand(command: string, helperPath: string): boolean;
/**
 * Whether a `ps` command line is the deliberately long-lived `watch-lock`
 * watcher. Inverse of {@link isReapableHelperCommand} for the watch-lock verb.
 */
export declare function isWatchLockHelperCommand(command: string, helperPath: string): boolean;
/** Test seam: reset the persisted candidate state. */
export declare function resetKeychainReaperCandidatesForTest(): void;
/**
 * Impure driver: snapshot all processes once with `ps`, plan the reap, then
 * execute kills through {@link killTree}.
 *
 * Path-matches the full helper path so an unrelated binary named "Agents CLI" is
 * never targeted. Returns on non-darwin without shelling anything.
 */
export declare function reapOrphanedKeychainProcesses(): Promise<{
    reaped: number;
    details: string[];
    plan: ReapPlan;
}>;
