export interface SpawnOptions {
    workId: string;
    /** Stable session id within the work (ADR-008) — e.g. "s_1". The pty is
     *  keyed by (workId, sessionId) so it survives ws reconnect and a reload
     *  re-attaches to the SAME shell instead of spawning a fresh one. */
    sessionId: string;
    cwd: string;
    shell: string;
    cols: number;
    rows: number;
    env?: Record<string, string>;
}
export interface PtySession {
    id: string;
    workId: string;
    sessionId: string;
    write(data: string): void;
    resize(cols: number, rows: number): void;
    onData(cb: (data: string) => void): () => void;
    onExit(cb: (code: number) => void): () => void;
}
/**
 * Pool of ptys keyed by `(workId, sessionId)` (ADR-008 §6). A pty PERSISTS
 * across ws reconnect — `getOrSpawn` returns the existing shell for a key
 * instead of spawning a new one, so a reload / second tab on the same session
 * multiplexes onto one pty (output is fanned to every attached listener; resize
 * is last-writer-wins). The pty is disposed only on explicit `dispose()`
 * (session delete) or when the shell process exits.
 *
 * Each pty keeps a bounded RING BUFFER of its recent output so a freshly
 * attached ws (page reload) can replay prior scrollback before live output
 * resumes — see `replayBuffer` (ADR-008 §6).
 */
export declare class PtyPool {
    private readonly sessions;
    /** Compose the pool key. Distinct (workId, sessionId) → distinct pty.
     *  JSON-encode the pair so the key is unambiguous for ANY id contents — a
     *  bare delimiter (even "::") collides when an id itself contains it, e.g.
     *  ("a","b::c") vs ("a::b","c"). The encoded form can never collide. */
    private key;
    /**
     * Return the live pty for (workId, sessionId), or spawn one if none exists
     * (or the previous one exited). This is the resume primitive: a reconnecting
     * ws gets the SAME shell, scrollback intact in the running process.
     */
    getOrSpawn(opts: SpawnOptions): PtySession;
    spawn(opts: SpawnOptions): PtySession;
    /** Look up the live pty for a key (or undefined). */
    get(workId: string, sessionId: string): PtySession | undefined;
    /**
     * Recent output buffered for (workId, sessionId), concatenated oldest-first —
     * empty string if there is no live pty or it has produced nothing yet. A
     * freshly attached ws replays this to restore scrollback before wiring its
     * live onData listener (ADR-008 §6).
     */
    replayBuffer(workId: string, sessionId: string): string;
    /** Number of browser tabs currently attached to a session's pty. */
    attachCount(workId: string, sessionId: string): number;
    /**
     * Kill + drop the pty for (workId, sessionId). Called on explicit session
     * delete — NOT on ws.close (the pty must survive reconnect, ADR-008 §6).
     */
    dispose(workId: string, sessionId: string): void;
    disposeAll(): void;
}
//# sourceMappingURL=pty-pool.d.ts.map