/**
 * SocketDisconnectSentinel — detects Claude Code's "socket connection closed
 * unexpectedly" message in tracked sessions and runs a bounded recovery loop.
 *
 * Closes the gap surfaced by the joint diagnosis on 2026-05-22: the instar
 * repo had detectors for rate limits, quota, hundreds of patterns, but zero
 * detectors for Claude Code's own connection-drop string. When it fires, the
 * session freezes; nothing classifies it; no recovery runs; no user-visible
 * alert reaches the user.
 *
 * Pattern mirrors `RateLimitSentinel.report` → backoff → `resumeFn` →
 * verification → escalate, but the failure shape is simpler (no Claude
 * Code internal retries to wait out — disconnect is immediate) so the
 * lifecycle is shorter.
 *
 * Spec: docs/specs/silently-stopped-trio.md
 *
 * Signal-vs-authority: the regex + state machine are detectors. The
 * notifyFn path is the existing MessagingToneGate authority (called through
 * /attention). No new blocking authority introduced.
 */
import { EventEmitter } from 'node:events';
export type SocketDisconnectStatus = 'detected' | 'recovering' | 'recovered' | 'escalated';
export interface SocketDisconnectState {
    sessionName: string;
    detectedAt: number;
    attempts: number;
    lastInjectAt: number;
    status: SocketDisconnectStatus;
}
export interface SocketDisconnectSentinelDeps {
    /**
     * Inject a recovery nudge into the session: typically Ctrl+C then Enter.
     * Returns whether the injection was accepted.
     */
    resumeFn: (sessionName: string) => Promise<boolean>;
    /** Route a user-facing message; server.ts owns topic routing. */
    notifyFn: (sessionName: string, text: string) => Promise<void>;
    /** Peek at the session's most recent tmux output. Returns a string that
     * may be empty if the session has no recent output. */
    getRecentOutput: (sessionName: string) => string;
    /**
     * Optional: list the session names to scan on each tick. Required for the
     * self-driving `start()` loop; without it the sentinel is event-driven only
     * (caller invokes `scanSession`/`report`). The server wiring supplies this.
     */
    listSessionNames?: () => string[];
    /** Override Date.now (tests). */
    now?: () => number;
    /** Override timer setters (tests). */
    setTimer?: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;
    clearTimer?: (handle: ReturnType<typeof setTimeout>) => void;
}
export interface SocketDisconnectSentinelConfig {
    enabled?: boolean;
    /** Backoff staircase in ms between recovery attempts. Last value repeats. */
    backoffScheduleMs?: number[];
    /** Max recovery attempts before escalating. Default 4. */
    maxAttempts?: number;
    /** How long to wait after a nudge before declaring recovery (ms). Default 60s. */
    verifyWindowMs?: number;
    /** How often the self-driving loop scans every session (ms). Default 15s. */
    tickIntervalMs?: number;
}
/**
 * Patterns Claude Code uses when its connection to Anthropic drops. Broad
 * intentionally — false-positive cost is one harmless nudge; false-negative
 * cost is the silently-stopped failure class this sentinel exists to close.
 */
export declare const SOCKET_DISCONNECT_PATTERNS: readonly RegExp[];
/**
 * Detector — true if `text` contains any known disconnect pattern.
 */
export declare function detectSocketDisconnect(text: string): boolean;
export declare class SocketDisconnectSentinel extends EventEmitter {
    private readonly deps;
    private readonly cfg;
    private readonly states;
    private readonly timers;
    private tickHandle;
    /** Liveness of the tick loop (GUARD-POSTURE-ENDPOINT-SPEC §2.2): 0 = never ticked. */
    private lastTickAt;
    constructor(deps: SocketDisconnectSentinelDeps, cfg?: SocketDisconnectSentinelConfig);
    /**
     * Begin the self-driving scan loop. No-op unless `listSessionNames` was
     * provided (otherwise the sentinel is purely event-driven). The interval is
     * unref'd so it never holds the process open at shutdown.
     */
    start(): void;
    /** Stop the scan loop and cancel all in-flight recovery. */
    stop(): void;
    /** One scan pass over every session the registry currently knows about. */
    tick(): void;
    /** Called by the tick loop (or by an event trigger) for each tracked session. */
    scanSession(sessionName: string): void;
    /**
     * Public entry: report a detected disconnect. Idempotent — second call
     * for the same session within an active recovery is a no-op.
     */
    report(sessionName: string): void;
    isRecoveryActive(sessionName: string): boolean;
    listActive(): SocketDisconnectState[];
    /** Cancel any in-flight recovery for this session (test + shutdown helper). */
    clear(sessionName: string): void;
    /** Cancel all in-flight recovery (server shutdown). */
    shutdown(): void;
    private scheduleNextAttempt;
    private runAttempt;
    private verifyAttempt;
    private escalate;
    private notify;
    private setTimer;
    private clearTimer;
    /** Sync in-memory runtime read for the GuardRegistry (GET /guards).
     *  MUST stay a cheap property read — no I/O, no session listing. */
    guardStatus(): {
        enabled: boolean;
        lastTickAt: number;
    };
}
//# sourceMappingURL=SocketDisconnectSentinel.d.ts.map