import type { BrandProfile, McpSdkServerConfigWithInstance, Options, Query } from "@yanlinglabs/winter-agent-sdk"; import type { ContinuityEndpoint, MessageOrigin } from "@yanlinglabs/winter-provider-runtime"; import type { SeamContextWithDirectory } from "./seams/context.js"; import type { GlobalMessagingHandle } from "./messaging/router.js"; import type { KeychainSeam } from "./seams/keychain.js"; import type { RuntimeDirectory } from "./seams/directory.js"; import type { RuntimeDirectoryStore } from "./seams/directory-store.js"; import type { GlobalMessagingOptions, RuntimeDirectoryOptions } from "./messaging/index.js"; import { type SwitchReviewerHandle } from "./store/review-switch.js"; import type { RuntimeSelection, SelectionInput } from "./selection/runtime-selection.js"; import { type VersionMatrixReport } from "./version-matrix.js"; import { type RecoveryReport } from "./run-home/exit.js"; import { type RunHome, type RunHomeFor, type RunHomeOutcome } from "./run-home/types.js"; /** * The injected peer. * * AN INSTANCE, not a name: a host that vendors the packages (WS-02's own model) can be certain no SDK * is instantiated twice. WS-23: the optional `claude` peer (the official runtime's module) is gone * with the official leg. */ export interface RuntimeSdkPeers { winter: typeof import("@yanlinglabs/winter-agent-sdk"); } export interface RuntimeSdkOptions { peers: RuntimeSdkPeers; /** * Host-declared peer package versions (D19a/R2, WS-02 §7.1) — THE ONLY DOOR inside a compiled * binary. The version matrix's probe 2 (`resolved-manifest`) resolves a peer's `package.json` via * `createRequire(...).resolve()`, which cannot see outside a compiled binary's own bundle * (`file:///$bunfs/...`); a host that self-spawns its own compiled artifact and whose injected peer * exports no version identity of its own (probe 1) has NOTHING for the matrix to read unless it * declares one here, from its own vendored `VERSIONS.json`. Declaring a version wins over both * probes when it parses — it does not bypass the matrix's range/exact-pin checks, only replaces how * the identity was DISCOVERED; an unparseable declared value falls through to probe 1 rather than * refusing on its own. Absent, behaviour is unchanged: probes 1 and 2, in that order. */ peerVersions?: { winterAgentSdk?: string; }; /** R-7b-2's seam; default = in-memory (which is also what every hermetic test uses). */ directoryStore?: RuntimeDirectoryStore; /** * Host-provided credential reads (WS-14 §12). WS-23: the official leg — which fetched a family's * credential at spawn — was this seam's only reader, and the Winter runtime resolves its own * `Options.provider.authRef` locator. Accepted and unused, so a host that still passes one keeps * compiling. */ keychain?: KeychainSeam; /** * Flows through to the Winter leg unchanged (D19 clause a). * * RESOLVED ONCE, at construction, through the INJECTED peer's own `resolveBrand` — so an invalid * profile is a typed construction refusal (`InvalidBrandError`, the Winter SDK's own class) beside * the version matrix's, rather than a surprise at the first query. `RuntimeSdk.brand` is the * result, and it is what the router's own name derivations use. * * PRECEDENCE, in one sentence: a per-query `Options.brand` wins on the Winter leg and is never * rewritten; this constructor profile fills in when a query supplies none; Winter's own defaults * fill in when neither does. */ brand?: Partial; /** * The switch reviewer's collaborators — the key keeps its name from when it configured the handoff * barrier (WS-23 retired the barrier; `reviewSwitch` is what survives of it). * * `winterHome` here is what fills `SeamContext.winterHome`, so the reviewer, the recovery door and * any later seam that reads the context all resolve under the same home. `resolveEndpoint` is the * host's catalog-registry resolver (WS-18 W18-20); absent, `defaultEndpointResolver()`. The shared * store is not offered: the router builds the one store every reader goes through. */ handoff?: { winterHome?: string; resolveEndpoint?: (origin: MessageOrigin) => ContinuityEndpoint; }; /** * WS-09 §1.3's capability servers, as the Winter SDK's own in-process shape — FORWARDED, never * rewritten into anything else (R-8, and the user's tool-ownership ruling R-8-1). * * THE ROUTER OWNS NO TOOL. The daemon owns the capability tools — computer, browser, office — and * hands them over as MCP SERVERS; this is the door they come through. The Winter leg receives each * entry BY REFERENCE under its own `name`, merged into `Options.mcpServers`. * * THE BRAND'S OWN SERVER NAME IS RESERVED: `brand.mcpServerName` is the standing server's key, the * one the messaging tools resolve through (`mcp____`), so a capability server * that claimed it would shadow them. That is a typed refusal at construction, not a silent * overwrite. A caller key that collides with a capability name is refused at the door too. */ capabilities?: readonly McpSdkServerConfigWithInstance[]; /** * The directory's and the router's own options (whole-branch review, F-3) — `messaging.winter` * carries the Winter adapter's options (its `permissionClass`, without which a receiver's class is * unknown and, since D2, fails closed). */ messaging?: { directory?: RuntimeDirectoryOptions; messaging?: GlobalMessagingOptions; }; /** * WS-21 §3.1: EVERY GENERATION CARRIES A RUN HOME, or the router refuses it (`run_home_required`). * * OPT-IN, AND THAT IS THE FEATURE DETECTION (the plan's Global Constraints). A host that has not * adopted WS-21 keeps its old defaults and this router serves it unchanged; the daemon sets this the * moment it links a router that exports `buildRunHome`, and from then on no child can run on the * user's real home by accident — a missing run home is a typed refusal, raised synchronously, * before the peer is touched. */ requireRunHome?: boolean; /** * WS-21 §3.1: the host's run-home builder, for the router's OWN cold-resume path * (`messaging/winter-adapter.ts`), which opens a Winter query no host call site is awaiting. The * router awaits it before it opens that query and applies the result exactly as `query()` does. * Absent with `requireRunHome` set, the cold resume answers a typed non-retryable `unavailable`. */ runHomeFor?: RunHomeFor; } /** Options members this package OWNS. Never forwarded to the peer — see `query()`. */ export declare const ROUTER_ONLY_OPTION_KEYS: readonly ["runtime"]; export type RouterOnlyOptionKey = (typeof ROUTER_ONLY_OPTION_KEYS)[number]; /** * The runtime-selection inputs the door accepts ALONGSIDE the pinned `Options` — "additive and * typed" (the plan's Global Constraints), and stripped before the peer sees them. */ export interface RouterRuntimeInput { /** * A selection already persisted for this session. WS-23: it must name `winter-agent` — the only * runtime this router serves; one naming the retired `claude-agent` runtime is a typed refusal * (`RuntimeLaunchInputError`, field `runtime.selection`) rather than a query on some other runtime. */ selection?: RuntimeSelection; /** Everything needed to decide one when there is no persisted selection yet (same rule). */ select?: SelectionInput; /** * This session's own id. WS-23: it keyed the in-process ledger that refused a mid-session change of * RUNTIME; with one runtime there is no such change, so it is accepted and unused. */ sessionId?: string; /** * WS-21 §3.1: the per-run folder this generation runs on, built by `buildRunHome` and awaited by the * host before it calls `query()`. Applied synchronously; required when the router was created with * `requireRunHome: true`. */ runHome?: RunHome; } /** `Options` plus the router's own additive input. Nothing is removed and nothing is renamed. */ export interface RouterOptions extends Options { runtime?: RouterRuntimeInput; } export interface RuntimeSdk { /** The resolved brand profile every Winter-owned name in this session derives from (I2). */ readonly brand: BrandProfile; /** * The one door (D19b). See this module's header for the deviations from the plan's pinned line. * WS-23: it returns the Winter peer's own `Query`, always — there is no second runtime whose handle * it could be. */ query(args: { prompt: string | AsyncIterable; options?: RouterOptions; }): Query; /** D13/D28, pure. Throws `SelectionRefusedError` on a typed refusal (see that class's own note). */ selectRuntime(input: SelectionInput): RuntimeSelection; /** WS-15 §6.1. */ directory: RuntimeDirectory; /** * WS-15 §6.2–6.4 — the HANDLE, which is the seam plus the two doors a host cannot work without. * * WIDENED, NEVER NARROWED (F-3). The plan pins `GlobalMessaging`, and `GlobalMessagingHandle` * extends it: every pinned member is present with its pinned signature, and what is added is * `attachWinterSession` — without which a host can configure a receiver's permission class and * still have nothing live to deliver to. */ messaging: GlobalMessagingHandle; readonly versions: VersionMatrixReport; /** * WS-21 §3.8: what became of a run home's working copy. `safe` — nothing is left to reconcile, the * host may `dispose()` it; `quarantined` — it diverged from the canonical store and its `projects/` * was copied to `/cache/quarantine/`; `pending` — the incarnation is still running, or the run * id is one this handle never applied. */ runHomeOutcome(runId: string): RunHomeOutcome; /** * WS-21 §3.8's recovery door: reconciles a recorded local-write root left behind by a crash (or a * pre-WS-21 spool root, Migration C), through THIS handle's own store, after recomputing the * claude-ready copy the root was staged from — PER TRANSCRIPT (I6). Each transcript is `clean` * (level), `appended` (the canonical file was behind and is now level), `canonical-ahead` (the * working copy is a prefix of a canonical history that moved on: nothing to append, nothing lost) or * `quarantined` (unprovable: its file is copied to `/cache/quarantine/`, nothing of it is * appended, its session keeps its repair flag). The root `outcome` is `quarantined` if any transcript * was, else `appended` if any was, else `clean`. A session's repair flag is cleared when every one of * its transcripts came back level — `canonical-ahead` included, without checking for a live writer (the * store facade keeps no live-session registry to check against), so a host MUST let this finish * before any session whose key it recovers opens. The daemon runs it at boot, before sessions open. */ reconcileRootForRecovery(root: string): Promise; dispose(): Promise; } /** * The `runtime` a host passes when it has only a run home to say (WS-21). WS-23: kept as a name — it * was the Winter overload's input when the door had two; `RouterRuntimeInput` accepts it as it is. */ export interface WinterLegRuntimeInput { runHome: RunHome; selection?: never; select?: never; } /** * The collaborators a lane swaps its real implementation into. * * Not part of `RuntimeSdk` (the plan pins that surface) and not a constructor option (the plan pins * those too) — it is this package's own internal wiring, exported for `test/spine/*` and for the * lanes' own tests to reach a single seam without standing up the whole handle. */ export interface RuntimeSdkInternals { /** * The switch reviewer (`reviewSwitch`) and the one shared store. The name is the handoff barrier's, * which this was part of until WS-23 — hosts reach the review as `runtimeSdkInternals(sdk).barrier`. */ barrier: SwitchReviewerHandle; /** The exact object every seam factory was handed — what a lane's real factory will receive. */ context: SeamContextWithDirectory; } /** Reaches the internals of a handle this package built. Returns undefined for anything else. */ export declare function runtimeSdkInternals(sdk: RuntimeSdk): RuntimeSdkInternals | undefined; /** * Builds the object forwarded to a peer's `query()`. * * THE INVARIANT, IN ONE SENTENCE: **the forwarded options are the caller's options minus * `ROUTER_ONLY_OPTION_KEYS`, plus the brand's capability-server entries under `mcpServers`, and * nothing else is rewritten.** * * THE COMMON CASE FORWARDS THE CALLER'S OWN OBJECT, by reference. "Passes through verbatim" is a * property a test can only really check by identity, and a router that copied unconditionally would * be quietly deciding which of `Options`' members it knows about — the exact drift D19b's "never a * translation layer" rules out. A copy is made ONLY when there is something to remove or something to * add, because that is the only time the caller's own object would be the wrong thing to hand over; * every other member keeps its own value identity through the copy. * * SO R-8 DID NOT WEAKEN THE PROPERTY, IT RESTATED IT. A host that configures no capabilities is * unaffected — the identity return below still fires, and the test that pins it is unchanged. A host * that configures them gets a copy whose every member except `mcpServers` is `Object.is`-identical to * its own, and whose `mcpServers` is its own entries plus the capability entries, by reference. * * A CAPABILITY KEY THE CALLER ALSO USES IS A TYPED REFUSAL, never a silent overwrite in either * direction: one of the two servers would simply not be there, and the party who would find out is * the model, at the one moment the tool matters. */ export declare function forwardableOptions(options: RouterOptions, brand?: Partial, capabilityServers?: Readonly>): Options; /** * Constructs the router. Throws `RuntimeSdkVersionError` on a version-matrix miss (D19a). * * THE MATRIX IS ASSERTED FIRST, before a single seam is built, so a refusal costs nothing and says * only what it is about. */ export declare function createRuntimeSdk(opts: RuntimeSdkOptions): RuntimeSdk;