import { connectWsLspTransport } from "./ws-transport.js"; import { E2bLspManager, type LspCapableEnv, type LspUnavailableReason } from "./manager.js"; import type { LspTransport } from "./types.js"; export interface E2bLspOptions { /** Injectable for tests (no E2B/ws). */ connect?: typeof connectWsLspTransport; retry?: { attempts: number; delayMs: number; }; /** Bridge auth token override. The manager pins ONE token per env+PORT — the bridge RESOURCE, not the * language (`portForLanguage` maps several languages, e.g. typescript/javascript, onto the SAME port/process * — see `createE2bLspManager`). On a RE-open (transport heal after the E2B proxy idle-killed the WS) the * original bridge process is still listening with the FIRST token — a fresh random token would be rejected * and the reconnect would always fail. */ token?: string; /** WS scheme for the bridge URL. E2B's `getHost` returns a public TLS proxy host → `wss` (default); * the k8s adapter returns a cluster-internal `podIP:port` → plain `ws` (no TLS on the pod network; * the per-session bridge token still gates access). */ scheme?: "ws" | "wss"; /** Observability hook (open/heal/degrade events) — prod wires the service logger. */ log?: (event: string, fields: Record) => void; /** §DESIGN-V2 F11: metrics registry (structural — matches the narrow surface remote-env-e2b.ts's `cfg.metrics` * already uses). `provider`/`generation`/`reason` labels are filled in by this module, never left freeform. */ metrics?: { inc(name: string, labels?: Record): void; }; /** §DESIGN-V2 F11: the deployment lane feeding this manager (boot/execution-env.ts passes it explicitly — * "e2b" or "k8s" — rather than this module guessing it back out of `scheme`, which is a WS-protocol detail * that happens to correlate with the lane but isn't the same axis). Defaults to inferring from `scheme` only * so existing callers that don't pass it (tests) keep working. */ provider?: string; /** §DESIGN-V2 F2/C6: health-probe override for tests (no real sandbox network). Defaults to a real * `GET /healthz` fetch (1s timeout) — `scheme` maps to the probe's URL scheme, F11 (`wss→https`, `ws→http`). */ probe?: (env: LspCapableEnv, port: number, token: string, scheme: "ws" | "wss") => Promise; } /** Start (+ install on a non-baked template) the language server + bridge inside THIS env's sandbox, then connect. * Every call starts (or re-starts) the bridge unconditionally — the one production caller is * `createE2bLspManager`, which de-dupes per env+port before ever reaching here (see its doc). */ export declare function openE2bLspTransport(language: string, env: LspCapableEnv, opts?: E2bLspOptions): Promise; /** §DESIGN-V2 A: `starting` while the write+install+startBackground sequence is in flight; `ready` once at * least one WS connect through this generation has succeeded; `dead` once this generation is confirmed (or * presumed, per its own failure) unusable — the ONLY way out of `dead` is minting a new generation. */ export type BridgeState = "starting" | "ready" | "dead"; /** * §DESIGN-V2 A/F3/F6: one bridge RESOURCE per env+port (not per language — `portForLanguage` maps * typescript/javascript onto the SAME port/process off the same `SERVER_CMD`, HRD-LSP-4). A crashed/never- * booted bridge can be replaced by minting a new `generation` (bounded by `MAX_BRIDGE_GENERATIONS` — a * crash-loop must degrade the language, not burn the sandbox indefinitely); the NEW generation is only ever * minted after `terminateBridgeCommand` confirms the OLD one actually stopped (F3) — an unconfirmed kill risks * EADDRINUSE permanently rejecting the new generation's fresh token (the old process is still the one * listening, and its token check has no way to know a replacement was intended). */ export interface E2bBridgeHandle { readonly port: number; /** Pinned once per generation — the shared bridge resource's auth secret. A per-LANGUAGE token would be * rejected by the one bridge process actually listening whenever two languages share a port (see the * module doc's HRD-LSP-4 reference): the second language mints a different token, the bridge only * recognizes whichever token started it, auth fails, retries exhaust, and that language is permanently * degraded to grep/read_file for the task. */ readonly token: string; /** The `LSP_CMD` this generation's bridge process was launched with — identity documentation (ts/js sharing * one value/port/process is legitimate, §DESIGN-V2 "不做"); not read back by this module. */ readonly serverCmd: string; /** 1 at first mint; +1 every restart. Bounds the restart budget (`MAX_BRIDGE_GENERATIONS`). */ readonly generation: number; state: BridgeState; /** The most recent human-readable diagnostic (write/install/start/connect failure, or a probe verdict) — * feeds `lastError`-style debugging; the MODEL-facing word is `deathReason` (via `unavailableReason`), not * this free-text string. */ lastError?: string; /** The SPECIFIC reason THIS generation died (unset while starting/ready). `unavailableReason`-facing * reporting overrides this to `bridge-restart-budget-exhausted` once `generation >= MAX_BRIDGE_GENERATIONS` * — "further restarts won't help" is a different (and, once true, more useful) word than "what killed the * last one." */ deathReason?: LspUnavailableReason; /** True once this generation has completed at least one real WS connect. Gates the fast healthz-probe heal * path (§DESIGN-V2 F2/F6): a generation that has never connected yet is still cold-starting, not dead — * treating an unreachable healthz as "dead" during that window would misjudge ordinary boot lag as a crash * and burn a restart generation for nothing. A generation that HAS connected before, though, really should * be reachable again quickly, so it skips the blind 6×1500ms retry loop and asks the bridge directly. */ everConnected: boolean; /** Resolves once the write+install+startBackground sequence has been ATTEMPTED for this generation — `false` * (with `state` already flipped to `dead` + `deathReason`/`lastError` set) means it failed before ever * reaching a connect attempt. */ ready: Promise; } /** A crash-loop must degrade the language, not retry the sandbox forever. 3 covers "an occasional OOM kill"; * a bridge that dies again immediately after 3 fresh starts is a standing failure, not a blip. */ export declare const MAX_BRIDGE_GENERATIONS = 3; /** The single shared `LspServerManager` for the deployment (`RunnerDeps.lspManager`). */ export declare function createE2bLspManager(opts?: E2bLspOptions): E2bLspManager; //# sourceMappingURL=e2b-manager.d.ts.map