/**
 * Query the terminal and await responses without timeouts.
 *
 * Terminal queries (DECRQM, DA1, OSC 11, etc.) share the stdin stream
 * with keyboard input. Response sequences are syntactically
 * distinguishable from key events, so the input parser recognizes them
 * and dispatches them here.
 *
 * To avoid timeouts, each query batch is terminated by a DA1 sentinel
 * (CSI c) — every terminal since VT100 responds to DA1, and terminals
 * answer queries in order. So: if your query's response arrives before
 * DA1's, the terminal supports it; if DA1 arrives first, it doesn't.
 *
 * Usage:
 *   const [sync, grapheme] = await Promise.all([
 *     querier.send(decrqm(2026)),
 *     querier.send(decrqm(2027)),
 *     querier.flush(),
 *   ])
 *   // sync and grapheme are DECRPM responses or undefined if unsupported
 */
import type { TerminalResponse } from './parse-keypress.js';
/** A terminal query: an outbound request sequence paired with a matcher
 *  that recognizes the expected inbound response. Built by `decrqm()`,
 *  `oscColor()`, `kittyKeyboard()`, etc. */
export type TerminalQuery<T extends TerminalResponse = TerminalResponse> = {
    /** Escape sequence to write to stdout */
    request: string;
    /** Recognizes the expected response in the inbound stream */
    match: (r: TerminalResponse) => r is T;
};
type DecrpmResponse = Extract<TerminalResponse, {
    type: 'decrpm';
}>;
type Da1Response = Extract<TerminalResponse, {
    type: 'da1';
}>;
type Da2Response = Extract<TerminalResponse, {
    type: 'da2';
}>;
type KittyResponse = Extract<TerminalResponse, {
    type: 'kittyKeyboard';
}>;
type CursorPosResponse = Extract<TerminalResponse, {
    type: 'cursorPosition';
}>;
type OscResponse = Extract<TerminalResponse, {
    type: 'osc';
}>;
type XtversionResponse = Extract<TerminalResponse, {
    type: 'xtversion';
}>;
/** DECRQM: request DEC private mode status (CSI ? mode $ p).
 *  Terminal replies with DECRPM (CSI ? mode ; status $ y) or ignores. */
export declare function decrqm(mode: number): TerminalQuery<DecrpmResponse>;
/** Primary Device Attributes query (CSI c). Every terminal answers this —
 *  used internally by flush() as a universal sentinel. Call directly if
 *  you want the DA1 params. */
export declare function da1(): TerminalQuery<Da1Response>;
/** Secondary Device Attributes query (CSI > c). Returns terminal version. */
export declare function da2(): TerminalQuery<Da2Response>;
/** Query current Kitty keyboard protocol flags (CSI ? u).
 *  Terminal replies with CSI ? flags u or ignores. */
export declare function kittyKeyboard(): TerminalQuery<KittyResponse>;
/** DECXCPR: request cursor position with DEC-private marker (CSI ? 6 n).
 *  Terminal replies with CSI ? row ; col R. The `?` marker is critical —
 *  the plain DSR form (CSI 6 n → CSI row;col R) is ambiguous with
 *  modified F3 keys (Shift+F3 = CSI 1;2 R, etc.). */
export declare function cursorPosition(): TerminalQuery<CursorPosResponse>;
/** OSC dynamic color query (e.g. OSC 11 for bg color, OSC 10 for fg).
 *  The `?` data slot asks the terminal to reply with the current value. */
export declare function oscColor(code: number): TerminalQuery<OscResponse>;
/** XTVERSION: request terminal name/version (CSI > 0 q).
 *  Terminal replies with DCS > | name ST (e.g. "xterm.js(5.5.0)") or ignores.
 *  This survives SSH — the query goes through the pty, not the environment,
 *  so it identifies the *client* terminal even when TERM_PROGRAM isn't
 *  forwarded. Used to detect xterm.js for wheel-scroll compensation. */
export declare function xtversion(): TerminalQuery<XtversionResponse>;
export declare class TerminalQuerier {
    private stdout;
    /**
     * Interleaved queue of queries and sentinels in send order. Terminals
     * respond in order, so each flush() barrier only drains queries queued
     * before it — concurrent batches from independent callers stay isolated.
     */
    private queue;
    constructor(stdout: NodeJS.WriteStream);
    /**
     * Send a query and wait for its response.
     *
     * Resolves with the response when `query.match` matches an incoming
     * TerminalResponse, or with `undefined` when a flush() sentinel arrives
     * before any matching response (meaning the terminal ignored the query).
     *
     * Never rejects; never times out on its own. If you never call flush()
     * and the terminal doesn't respond, the promise remains pending.
     */
    send<T extends TerminalResponse>(query: TerminalQuery<T>): Promise<T | undefined>;
    /**
     * Send the DA1 sentinel. Resolves when DA1's response arrives.
     *
     * As a side effect, all queries still pending when DA1 arrives are
     * resolved with `undefined` (terminal didn't respond → doesn't support
     * the query). This is the barrier that makes send() timeout-free.
     *
     * Safe to call with no pending queries — still waits for a round-trip.
     */
    flush(): Promise<void>;
    /**
     * Dispatch a response parsed from stdin. Called by App.tsx's
     * processKeysInBatch for every `kind: 'response'` item.
     *
     * Matching strategy:
     * - First, try to match a pending query (FIFO, first match wins).
     *   This lets callers send(da1()) explicitly if they want the DA1
     *   params — a separate DA1 write means the terminal sends TWO DA1
     *   responses. The first matches the explicit query; the second
     *   (unmatched) fires the sentinel.
     * - Otherwise, if this is a DA1, fire the FIRST pending sentinel:
     *   resolve any queries queued before that sentinel with undefined
     *   (the terminal answered DA1 without answering them → unsupported)
     *   and signal its flush() completion. Only draining up to the first
     *   sentinel keeps later batches intact when multiple callers have
     *   concurrent queries in flight.
     * - Unsolicited responses (no match, no sentinel) are silently dropped.
     */
    onResponse(r: TerminalResponse): void;
}
export {};
