/**
 * WarmSessionPool — Layer 2 core (THREADLINE-A2A-COHERENCE-SPEC).
 *
 * Keeps an agent-to-agent session "warm" for a TTL so rapid follow-ups inject into the running
 * session (via the existing live-injection path) instead of respawning each message. The
 * operator-confirmed model is **per-peer** with a **global + per-peer cap** and **TTL + LRU
 * eviction**, so an inbound flood (many threads / one chatty peer) can't pin unbounded live
 * Claude processes. This is the pure registry + eviction policy; the server wires it to the real
 * session lifecycle (keep-alive, inject, kill-on-evict) and the SessionReaper (warm sessions are
 * evict-eligible under resource pressure — eviction is lossless because the next message falls
 * back to Layer 1 resume).
 *
 * Pure + clock-injected → fully testable. Eviction is reported (the caller kills the tmux/Claude
 * session); the pool itself holds no I/O.
 */
export interface WarmSessionRecord {
    threadId: string;
    /** Peer identity the warm session belongs to (the per-peer cap key). */
    peerId: string;
    /** The tmux/session name to inject into / kill on eviction. */
    sessionName: string;
    createdAt: number;
    lastUsedAt: number;
}
export interface WarmSessionPoolConfig {
    /** Max warm sessions across all peers. */
    globalCap: number;
    /** Max warm sessions for any one peer (the inbound-flood bound). */
    perPeerCap: number;
    /** Idle TTL — a warm session unused for this long is reapable. */
    ttlMs: number;
}
/**
 * Thrown by `admit` when an existing thread record is owned by a DIFFERENT peer
 * than the caller presents (defense-in-depth, spec §3.5). The upstream
 * ThreadlineRouter ownership guard (identity-match) already blocks a peer
 * injecting into another's thread, but the pool MUST additionally refuse to
 * cross-bind a thread to a new peer — it must never silently overwrite the
 * owner. The caller treats this as a reject and falls back to a fresh
 * cold-spawn (no warm session).
 */
export declare class WarmSessionPeerConflictError extends Error {
    readonly threadId: string;
    readonly existingPeerId: string;
    readonly attemptedPeerId: string;
    constructor(threadId: string, existingPeerId: string, attemptedPeerId: string);
}
export declare class WarmSessionPool {
    private readonly config;
    private readonly now;
    private readonly byThread;
    constructor(config: WarmSessionPoolConfig, now?: () => number);
    size(): number;
    private peerCount;
    /** LRU among a predicate set (oldest lastUsedAt first). */
    private lru;
    /**
     * Admit (or refresh) a warm session for a thread. Returns the records that must be EVICTED
     * (killed by the caller) to honor the caps — LRU first, per-peer cap before global cap. An
     * existing thread is refreshed in place (no eviction).
     */
    admit(input: {
        threadId: string;
        peerId: string;
        sessionName: string;
    }): WarmSessionRecord[];
    /** Mark a thread's warm session used (LRU refresh). */
    touch(threadId: string): void;
    /**
     * The raw record for a thread, IGNORING the idle TTL (unlike `get`). Used for
     * a pre-spawn peer-conflict check so the router can refuse a cross-peer warm
     * spawn BEFORE spending a spawn (admit would throw, but only after the worker
     * is already launched). Returns undefined when no record exists.
     */
    peek(threadId: string): WarmSessionRecord | undefined;
    /** The warm session for a thread, if present and not past its idle TTL; else undefined. */
    get(threadId: string): WarmSessionRecord | undefined;
    remove(threadId: string): WarmSessionRecord | undefined;
    /** Reap warm sessions idle past the TTL. Returns the evicted records (caller kills them). */
    reapExpired(): WarmSessionRecord[];
    /** Reap up to n warm sessions under resource pressure (LRU first). Returns evicted records. */
    reapUnderPressure(n: number): WarmSessionRecord[];
}
//# sourceMappingURL=WarmSessionPool.d.ts.map