/**
 * SessionMonitor — Proactive session health monitoring.
 *
 * Unlike StallTriageNurse (reactive — triggers on unanswered messages) or
 * SessionWatchdog (reactive — triggers on stuck bash commands), the
 * SessionMonitor is PROACTIVE: it periodically checks all active sessions
 * and ensures users experience the responsiveness they'd expect.
 *
 * Responsibilities:
 * 1. Detect idle sessions (no tmux output changes for extended periods)
 * 2. Track session responsiveness (time between user message and agent reply)
 * 3. Send proactive health updates to users (not overbearing)
 * 4. Coordinate with StallTriageNurse for recovery when issues are found
 *
 * Design principle: Responsive and informative but not overbearing.
 * One update per issue per session — not a stream of "still checking" messages.
 */
import { EventEmitter } from 'events';
import type { SessionRecovery, RecoveryResult } from './SessionRecovery.js';
export interface SessionMonitorConfig {
    /** Enable the session monitor (default: true) */
    enabled?: boolean;
    /** How often to check sessions, in seconds (default: 60) */
    pollIntervalSec?: number;
    /** Minutes of inactivity before a session is flagged as idle (default: 15) */
    idleThresholdMinutes?: number;
    /** Minimum minutes between user notifications per topic (default: 30) */
    notificationCooldownMinutes?: number;
}
export interface SessionMonitorEvents {
    'monitor:idle-detected': {
        topicId: number;
        sessionName: string;
        idleMinutes: number;
    };
    'monitor:unresponsive': {
        topicId: number;
        sessionName: string;
        waitMinutes: number;
    };
    'monitor:recovery-triggered': {
        topicId: number;
        sessionName: string;
        reason: string;
    };
    'monitor:mechanical-recovery': {
        topicId: number;
        sessionName: string;
        result: RecoveryResult;
    };
    'monitor:user-notified': {
        topicId: number;
        message: string;
    };
    'monitor:recovery-deferred': {
        topicId: number;
        sessionName: string;
    };
}
export interface SessionMonitorDeps {
    /** Get all active topic-to-session mappings */
    getActiveTopicSessions: () => Map<number, string>;
    /** Capture tmux output for a session */
    captureSessionOutput: (sessionName: string, lines: number) => string | null;
    /** Check if a session is alive */
    isSessionAlive: (sessionName: string) => boolean;
    /** Get recent messages for a topic */
    getTopicHistory: (topicId: number, limit: number) => Array<{
        text: string;
        fromUser: boolean;
        timestamp: string;
    }>;
    /** Send a message to a topic */
    sendToTopic: (topicId: number, text: string) => Promise<any>;
    /** Trigger triage recovery for a session */
    triggerTriage?: (topicId: number, sessionName: string, reason: string) => Promise<{
        resolved: boolean;
    }>;
    /** Optional mechanical recovery layer — runs before LLM triage */
    sessionRecovery?: SessionRecovery;
    /** Optional path to the persisted context-exhaustion notify ledger. When set,
     *  the once-per-death-EPISODE dedup map survives server restarts — without it
     *  every boot (update-train churn) forgot which dead sessions were already
     *  announced and re-posted "conversation too long" once per restart (the
     *  bounded residual confirmed twice on 2026-06-06: topics 16566 + 19437). */
    statePath?: string;
}
export declare class SessionMonitor extends EventEmitter {
    private config;
    private deps;
    private snapshots;
    private interval;
    private running;
    /** Topic-level cooldown for context exhaustion — survives snapshot cleanup */
    private contextExhaustionCooldowns;
    /** Topic-level notification cooldown — survives snapshot cleanup.
     *  When snapshots are deleted (session dies between polls) and recreated,
     *  snap.notifiedAt resets to null. Without this, the dead-session notification
     *  fires every poll (60s) creating spam. */
    private notificationCooldowns;
    /** topicId -> {sessionName, at} already notified for context exhaustion.
     *  Makes the user notification once-per-failure-EPISODE (per session
     *  instance), not once-per-cooldown-window — the prior behavior re-posted
     *  the same death every cycle while the condition persisted (the 2026-06-06
     *  flood). A successful recovery clears the flag so a future genuine death
     *  notifies. Persisted via deps.statePath so a server restart does not
     *  forget the episode and re-announce the same death once per boot. */
    private ctxNotifiedSessions;
    private ctxPersistWarned;
    /** Entries older than this are pruned at load — a week-old dead-session
     *  episode is over by any reasonable measure, and pruning bounds the file. */
    private static readonly CTX_NOTIFIED_MAX_AGE_MS;
    constructor(deps: SessionMonitorDeps, config?: Partial<SessionMonitorConfig>);
    /** Load the persisted notify ledger (tolerant: missing/corrupt → empty). */
    private loadCtxNotified;
    /** Persist the notify ledger (atomic tmp+rename; failure-tolerant). */
    private persistCtxNotified;
    emit<K extends keyof SessionMonitorEvents>(event: K, data: SessionMonitorEvents[K]): boolean;
    on<K extends keyof SessionMonitorEvents>(event: K, listener: (data: SessionMonitorEvents[K]) => void): this;
    start(): void;
    stop(): void;
    getStatus(): {
        enabled: boolean;
        trackedSessions: number;
        sessionHealth: Array<{
            topicId: number;
            sessionName: string;
            status: string;
            idleMinutes: number;
        }>;
    };
    poll(): Promise<void>;
    private checkSession;
}
//# sourceMappingURL=SessionMonitor.d.ts.map