import type { LspSession, LspOperation, LspRequestParams, LspResult, LspTransport, LspReadText, LspReadGate } from "./lsp.js";
import type { LspDiagnosticsRegistry } from "./lsp-diagnostics.js";
export interface SessionWarmup {
    /** Empty results within this window after session creation are retried (a freshly-spawned server answers
     *  non-blocking ops with EMPTY results while its project is still loading — the model may call
     *  hover/documentSymbol FIRST and get non-null-but-empty answers; goToDefinition happens to block on load,
     *  which is why op-order made it look random). 0 disables. */
    windowMs: number;
    retryMs: number;
}
export declare class TransportLspSession implements LspSession {
    private readonly transport;
    private readonly languageId;
    private readonly readText;
    /** Observability hook for swallowed degrades (graceful "none" hides real transport faults otherwise). */
    private readonly log;
    private readonly warmup;
    /** filePath → the last text SENT to the server (didOpen/didChange) + its document version. */
    private readonly opened;
    /** HRD-LSP-19: the URI we actually SENT for each opened file → that file's `opened` key. The diagnostics
     *  staleness guard used to re-derive the key with `uriToPath(publishedUri)`, which normalizes a drive path
     *  to backslash form regardless of how the caller spelled it — so with any other spelling the lookup missed
     *  and a stale (older-version) publish sailed through the guard onto the model's screen. Keying on the URI
     *  we ourselves sent removes the round-trip entirely (`uriToPath` stays the fallback for a server that
     *  re-spells the URI). */
    private readonly openedUris;
    /** Files carried over from a session that died ({@link warmOpen}): not read yet — the next gated sync opens each one
     *  its caller's gate admits, before that caller's query, and drops the rest. */
    private readonly carried;
    /** Per file, the generation of the newest sync started for it — the only one that may still publish. */
    private readonly syncGen;
    /** Per file, the newest sync in flight (dropped when it settles); concurrent by-name syncs share ONE read/didOpen.
     *  Each entry owns a {@link SharedAbortScope} so ONE caller's abort no longer cancels the read the others are waiting on
     *  (HRD-LSP-12). `byName` = a read with no gate (the only kind another caller may share). */
    private readonly syncing;
    private readonly createdAt;
    /** HRD-LSP-11: the warm-up barrier as a shared JOB, not a boolean flag set before the await (which let the
     *  second concurrent first-op skip the barrier entirely, and permanently disabled it whenever the barrier
     *  request failed or was cancelled). */
    private warmupBarrier?;
    private warmupDone;
    private warmupAttempts;
    constructor(transport: LspTransport, languageId: string, readText: LspReadText, 
    /** Observability hook for swallowed degrades (graceful "none" hides real transport faults otherwise). */
    log?: (event: string, fields: Record<string, unknown>) => void, warmup?: SessionWarmup, 
    /** design/121: when set (and the transport dispatches notifications), the session feeds this
     *  registry from `textDocument/publishDiagnostics` — with version-staleness protection: a
     *  notification versioned OLDER than the text this session last SENT for that file is dropped
     *  (the server is still churning on stale content). Absent ⇒ pre-121 behavior byte-for-byte. */
    diagnostics?: LspDiagnosticsRegistry);
    /** HRD-LSP-16: ops in flight on this session. The manager consults it before LRU/idle-evicting a server —
     *  closing one mid-op turns a healthy answer into `server_terminated` for a caller that did nothing wrong. */
    get inFlight(): number;
    private activeRequests;
    request(op: LspOperation, params: LspRequestParams, signal?: AbortSignal, gate?: LspReadGate): Promise<LspResult>;
    private requestOnce;
    /**
     * HRD-LSP-11: run (or join) this session's ONE warm-up barrier.
     *
     * The old form set a boolean BEFORE awaiting the barrier request, so a second concurrent first-op read
     * `true` and fired its real request into a still-loading project (an empty answer retries, but a PARTIAL
     * non-empty symbol/reference list is accepted as complete — the silent half). And because the flag was
     * never cleared, any failure/abort of that one request disabled the barrier for the session's whole life.
     * Now: joiners await the same job, a failed barrier is re-armed (bounded by {@link WARMUP_MAX_ATTEMPTS}),
     * and one caller's abort neither cancels the shared barrier nor makes the others wait for it.
     */
    private warmupBarrierOnce;
    /** Re-sync every opened and carried file (+ the queried one) with its CURRENT on-disk text, in parallel, each through
     *  the caller's gate. Returns the QUERIED file's outcome — the one the op's honesty depends on (HRD-LSP-7). */
    private syncOpenedFiles;
    /**
     * The session's one read port. Every sync of a document takes the next generation of that document and publishes only if
     * it is still the newest one started when its read settles — so a sync that publishes after another started after that
     * publication and opened its object after it: an older object's text never lands after a newer one's. No sync ever waits
     * for another's read (a read that never settles, abandoned or not, holds up nobody else). A superseded sync publishes nothing: its waiters take the newest sync's outcome, or sync
     * again when that one is gone or abandoned. With a gate, the file is read only from the object the gate admitted and
     * holds, never by its name again; a file the newest gate does not admit is closed (not read, not re-sent, its text
     * dropped from the server's open documents). With none (a caller with no read face), by name through `readText` — and
     * such a sync shares a by-name read already in flight for the document, each joiner keeping its OWN cancellation
     * (HRD-LSP-12); a gated read is its caller's admission and is never shared.
     */
    private syncGated;
    private syncInTurn;
    /** didClose a document the caller's gate refused and forget it (a later caller whose gate admits it opens it afresh). */
    private closeRefused;
    /** didOpen a new file / didChange (full-text replace) an opened one whose disk content moved, from the text `read`
     *  returns — only while `isNewest()` holds when the read settles (else {@link SUPERSEDED}, nothing sent). Never throws: it
     *  REPORTS failure instead (`{ok:false}`) — an unreadable file no longer looks like a clean sync to the caller. */
    private publishRead;
    /** Structural fallback classification for errors carrying no {@link lspFailureOf} brand (a
     *  third-party transport, e.g. the TOB WS lane) — abort signal and transport liveness are the only
     *  transport-neutral facts available; everything else is a server fault. Cannot produce
     *  "unsupported_operation" until that transport brands its JSON-RPC error codes (cross-repo slip). */
    private static classifyUnbranded;
    /** Underlying connection gone (e.g. the server crashed / the WS was idle-killed) → the manager evicts + reopens. */
    get closed(): boolean;
    /** Files didOpen'd on this server — the manager carries them to a HEALED session: a fresh server with no
     *  project config only "sees" its open files (e.g. tsserver inferred project), so without the carry-over,
     *  cross-file ops (references/calls) silently degrade to single-file after a heal. */
    openedFiles(): string[];
    /** Carry files over to a fresh session (heal): nothing is read here — no caller's read face is in hand — and the next
     *  gated sync (an op, a change notice) opens each file its caller's gate admits before that caller's query, so no op
     *  is answered from a document set missing an admitted carried file (HRD-LSP-1). `deferred` counts the files carried;
     *  a carried file that later cannot be read is logged by that sync (`lsp_sync_skipped`). */
    warmOpen(filePaths: string[], _signal?: AbortSignal): Promise<{
        opened: number;
        failed: number;
        deferred: number;
    }>;
    /**
     * design/121: push the file's CURRENT text to the server WITHOUT an op (didOpen/didChange as
     * appropriate). The agent's edit/write tools call this fire-and-forget so the server re-analyzes
     * and pushes publishDiagnostics — the session's normal lazy sync only runs on the next LSP op,
     * which may never come. Through the caller's `gate`, as every read. Never throws (same best-effort contract as publishRead).
     */
    notifyFileChanged(filePath: string, signal?: AbortSignal, gate?: LspReadGate): Promise<void>;
    close(): Promise<void>;
}
