@yanlinglabs/winter-runtime-sdk 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,19 +14,33 @@ Decision record: WS-00 D19 (2026-09-05). Boundaries that do not move:
14
14
  builtin-path containment, Winter MCP plugin registration), shared session-store wiring, the
15
15
  cross-runtime handoff barrier with the materialized-resume decoration doors, and the runtime
16
16
  directory plus cross-runtime messaging router.
17
+ - **It owns NO TOOL** (the user's tool-ownership ruling, R-8-1). The default tools — `SendMessage`,
18
+ `ListAgents`, `ReadNotifications`, `advisor` — are DECLARED once in
19
+ `@yanlinglabs/winter-agent-sdk/tools` and BOUND here, under the official runtime's own built-in
20
+ names; the capability tools (computer, browser, office) are the HOST's, handed over as MCP servers
21
+ and forwarded to both legs unchanged. This package re-exports no tool surface of its own.
17
22
  - The host vendors all three packages directly (`winter-runtime-sdk`, `winter-agent-sdk`,
18
23
  `claude-agent-sdk`); this package declares the two SDKs as peer dependencies and receives their
19
24
  module instances by injection, so a host that never creates a Claude session never loads the
20
25
  official runtime and no SDK is ever instantiated twice.
21
26
  - A `brand` profile flows through unchanged (Winter defaults); Claude Code's own literals stay fixed.
22
27
 
23
- Status: Phase 7b, all four lanes landed and the door routed. The spine (the package scaffold, the
24
- contract re-export, the `createRuntimeSdk` constructor with its version matrix, the seams, the test
25
- harness and CI) and the four lanes behind those seams — the official-SDK adapter, the runtime
26
- directory and messaging router, the store wiring and handoff barrier, and runtime selection — are on
27
- `main`, with WS-17's eighteen router-owned rows proven and cited in `docs/conformance-rows.md`. See
28
- `docs/architecture.md` for the ownership map, the pinned interfaces and how this package consumes the
29
- Winter SDK before its first publish.
28
+ Status: Phase 7b landed all four lanes and routed the door; `0.0.2` is the Phase-8b prerequisite
29
+ release. The spine (the package scaffold, the contract re-export, the `createRuntimeSdk` constructor
30
+ with its version matrix, the seams, the test harness and CI) and the four lanes behind those seams —
31
+ the official-SDK adapter, the runtime directory and messaging router, the store wiring and handoff
32
+ barrier, and runtime selection — are on `main`, with WS-17's eighteen router-owned rows proven and
33
+ cited in `docs/conformance-rows.md`. See `docs/architecture.md` for the ownership map, the pinned
34
+ interfaces and how this package consumes the Winter SDK.
35
+
36
+ **What `0.0.2` changes** (peer floor: `@yanlinglabs/winter-agent-sdk >=0.0.3 <0.1.0`):
37
+
38
+ | | |
39
+ |---|---|
40
+ | `peerVersions` | A host DECLARES its peers' versions — the only door inside a compiled binary, where `require.resolve` cannot see out of the bundle to read a manifest. |
41
+ | `capabilities` + `toInputShape` | The host's own MCP servers, forwarded to BOTH legs: by reference into the Winter leg's `Options.mcpServers`, and registered into the official runtime from the same declaration. One declaration, two registrations, identical canonical names. |
42
+ | `advisor` | The standing server carries Winter's four default tools, `advisor` among them, bound under the official runtime's built-in names (measured: the pin honours an alias key that is not one of its own built-ins — `docs/probes/advisor-alias.md`). `advisor` supplies the REVIEWER; the tool is always registered. |
43
+ | no tool ownership | `src/native-args.ts` and the router's messaging handlers are gone: the definitions, schemas, acceptors, handler factories and the advisor all come from `@yanlinglabs/winter-agent-sdk/tools`, and this package re-exports none of them. |
30
44
 
31
45
  ---
32
46
 
@@ -36,8 +50,22 @@ Winter SDK before its first publish.
36
50
  runtime's handle untouched.
37
51
 
38
52
  ```ts
53
+ // The host owns the capability tools and hands them over as MCP SERVERS; the router forwards the same
54
+ // servers to BOTH legs and rewrites nothing else (R-8-1). `toInputShape` is the one line of glue the
55
+ // official branch needs — its in-process server constructor takes schemas in its own validator's shape,
56
+ // and this package deliberately depends on no validator.
57
+ const sdk = createRuntimeSdk({
58
+ peers,
59
+ keychain,
60
+ vendoredOfficialRuntime,
61
+ capabilities: [computerServer, browserServer, officeServer], // your own `{ type: "sdk", name, tools, instance }`
62
+ toInputShape: (schema) => jsonSchemaToZodRawShape(schema), // one line, over the validator you already have
63
+ });
64
+
39
65
  // The Winter leg: exactly what it always was. No runtime input, so nothing is decided and nothing
40
- // is stripped — the caller's own `options` object is forwarded by reference.
66
+ // is stripped — the caller's own `options` object is forwarded by reference (with no `capabilities`
67
+ // configured, by IDENTITY; with them, a copy whose every other member is still your own object, plus
68
+ // your servers under `mcpServers`).
41
69
  for await (const message of sdk.query({ prompt: "hello" })) { /* SdkMessage */ }
42
70
 
43
71
  // The official leg: a `claude-agent` selection, plus what only a host can answer.
@@ -51,7 +79,13 @@ const query = sdk.query({
51
79
  official: {
52
80
  sessionId: "s-42", // its directory row is `session:s-42`
53
81
  base: minimalOsEnvironmentFrom(process.env),
54
- mcpServers: officialMcpServers({ /* */ }),
82
+ // OPTIONAL SINCE 0.0.2: the router materializes the standing server and your capability
83
+ // servers itself. This stays as the escape hatch, and its reach is exactly one key: an entry
84
+ // under the BRAND's own standing-server name replaces the router's (that key reaches no other
85
+ // leg, so overriding it diverges from nothing); an entry naming a forwarded CAPABILITY is a
86
+ // typed refusal on BOTH legs, because that name is on both and a silent override would leave
87
+ // the two branches running different tools under one canonical name.
88
+ // mcpServers: officialMcpServers({ /* … */ }),
55
89
  },
56
90
  },
57
91
  },
@@ -134,12 +168,19 @@ at all.
134
168
  **The official branch disables the runtime's remote feature configuration by default** (R-7b-11).
135
169
  Every official child gets `TRAFFIC_OPT_OUT_VARIABLES` — the four names are exported, so read them
136
170
  rather than trusting this sentence. Measured on the pin, same binary and same options: 25 advertised
137
- tools with the fetch, 21 without; `DesignSync`, `Monitor`, `PushNotification` and
138
- `advisor_20260301:advisor` appear only when a CDN answers. A tool surface that moves with no version
139
- moving is not a pinned artifact, so this is on unless you say otherwise: `remoteConfig: "allow"` (per
140
- query on `runtime.official`, or deployment-wide on `createRuntimeSdk({ official: { env: { } } })`)
141
- opts back in, and the choice is recorded on the session's directory row as
142
- `RuntimeDirectoryEntry.remoteConfig`.
171
+ tools with the fetch, 21 without; `DesignSync`, `Monitor`, `PushNotification` and Anthropic's own
172
+ API-side `advisor_20260301:advisor` appear only when a CDN answers that one is the vendor's server
173
+ tool, orthogonal to what follows. A tool surface that moves with no version moving is not a pinned
174
+ artifact, so this is on unless you say otherwise: `remoteConfig: "allow"` (per query on
175
+ `runtime.official`, or deployment-wide on `createRuntimeSdk({ official: { env: { } } })`) opts back
176
+ in, and the choice is recorded on the session's directory row as `RuntimeDirectoryEntry.remoteConfig`.
177
+
178
+ **Winter's own `advisor` is registered on the official branch too (R-8-1), backing Anthropic's rather
179
+ than being refused.** WS-14 §11's standing MCP server used to throw if a capability list named
180
+ `advisor` — each branch was meant to have its own, unrelated advisor. The user's tool-ownership ruling
181
+ reverses that: `mcp__<brand>__advisor` is reachable on the official branch exactly like
182
+ `send_message`/`list_agents`, independent of whether the CDN-gated API-side one above is present that
183
+ session. `docs/probes/d29-advisor.md` §6 has the full reversal and what it does and does not change.
143
184
 
144
185
  **The materialized-resume PREFERRED door is open for the pinned runtime, by measurement** (R-7b-12).
145
186
  WS-17 §8's four probes pass against 0.3.250 on darwin-arm64 and linux-x64, so a handle over that peer
@@ -242,6 +283,18 @@ was handed, the `claude-resume-<uuid>` staging root SURVIVES — the destination
242
283
  deleting a live child's `CLAUDE_CONFIG_DIR` is worse than leaving a directory behind. It is locatable
243
284
  at `outcome.target.stagingRoot` and belongs to your retention pass.
244
285
 
286
+ **Compiled hosts must declare their peers' versions.** The version matrix's second probe
287
+ (`resolved-manifest`) resolves a peer's `package.json` by walking up from `createRequire(...).resolve()`
288
+ — which cannot see outside a compiled binary's own bundle (`file:///$bunfs/...`). A host that
289
+ self-spawns its own compiled artifact and whose injected peer exports no version identity of its own
290
+ has nothing left for the matrix to read, and construction refuses. `createRuntimeSdk({ peerVersions:
291
+ { winterAgentSdk, claudeAgentSdk } })` is the door: supply both from your own vendored
292
+ `VERSIONS.json`, stamped at your own build time (WS-02 §7.1). A declared version is checked FIRST —
293
+ it wins even over a peer that exports its own identity — and still has to satisfy the same
294
+ range/exact-pin checks as either probe; it changes how the identity was discovered, not what counts
295
+ as supported. A host that runs uncompiled (plain `bun`/`node`, source or an ordinary install) never
296
+ needs this field.
297
+
245
298
  **"Exactly one runtime owns a session" is a convention here, not a mechanism.** The barrier moves
246
299
  ownership only after the destination confirms, and the transcript's producer record is authoritative —
247
300
  but the store's writer lease is re-entrant per pid and this router hosts both branches in one process,
package/dist/door.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { BrandProfile, CredentialRef, Options, ProviderSelection, Query } from "@yanlinglabs/winter-agent-sdk";
2
2
  import type { GlobalMessagingHandle } from "./messaging/router.js";
3
+ import { type ReviewerResolver } from "@yanlinglabs/winter-agent-sdk/tools";
3
4
  import type { ContainmentPolicy } from "./official/containment.js";
4
5
  import { type OfficialPermissionMode } from "./official/callbacks.js";
5
6
  import { type OfficialEnvPolicy } from "./official/env-allowlist.js";
6
7
  import { type AuthCredentialPlan } from "./official/auth.js";
7
8
  import { type OptionsTemplatePolicy } from "./official/options-template.js";
9
+ import { type InputShapeFactory, type OfficialMcpModule, type WinterMcpServerDescriptor } from "./official/mcp-descriptors.js";
8
10
  import type { RuntimeDirectory } from "./seams/directory.js";
9
11
  import type { OfficialAdapter, RemoteConfigPolicy } from "./seams/official-adapter.js";
10
12
  import type { OfficialQuery, OfficialUserMessage } from "./seams/official-sdk-shapes.js";
@@ -81,7 +83,24 @@ export interface RouterOfficialInput {
81
83
  projectKey?: string;
82
84
  /** §3's `CLAUDE_CODE_TMPDIR` — the shared per-user temp root the host derives from the brand. */
83
85
  sharedTempRoot?: string;
84
- /** §11's servers, already materialized by the host (`officialMcpServers`). */
86
+ /**
87
+ * §11's servers, already materialized by the host (`officialMcpServers`) — THE ESCAPE HATCH, AND
88
+ * EXACTLY HOW FAR IT REACHES (review r1).
89
+ *
90
+ * Since R-8 the router materializes the standing server and the constructor's capability servers
91
+ * itself (`RuntimeSdkOptions.capabilities` + `toInputShape`), so most hosts never fill this in.
92
+ *
93
+ * * THE STANDING-SERVER KEY (`brand.mcpServerName`): THE HOST WINS. A host that built its own
94
+ * standing server means that server, and the router replacing it would be the translation layer
95
+ * this package is not — the same precedence `remoteConfig` (`:148-149`) and `options` (`:153`)
96
+ * have. It is also a key the OTHER leg never receives from the router, so one branch overriding
97
+ * it diverges from nothing.
98
+ * * A FORWARDED CAPABILITY'S NAME: REFUSED, with the same `RuntimeLaunchInputError` the Winter leg
99
+ * raises for the identical collision, before any runtime is launched. `capabilities` are
100
+ * forwarded to BOTH legs, so a per-key override here would leave this branch running the host's
101
+ * server and the Winter branch running the daemon's under one name — two different tools, one
102
+ * canonical name, no error anywhere.
103
+ */
85
104
  mcpServers?: Readonly<Record<string, unknown>>;
86
105
  /** §1 profile 2's staging root. Defaults to the vendor's own `<tmpdir>/claude-resume-<resume id>`. */
87
106
  stagingRoot?: string;
@@ -160,6 +179,48 @@ export interface OfficialLegDeps {
160
179
  transcriptProjectKey: (cwd: string) => string;
161
180
  /** WS-14 §5.1's vendored runtime, from the constructor. A per-query `Options` value wins over it. */
162
181
  vendoredOfficialRuntime?: string;
182
+ /**
183
+ * The daemon's capability servers, as DESCRIPTORS (R-8 / R-8-1).
184
+ *
185
+ * DESCRIPTORS RATHER THAN THE WINTER INSTANCES, because this branch does not consume a server — it
186
+ * REGISTERS one, through its own runtime's in-process constructor. `createRuntimeSdk` reads the
187
+ * host's declaration once (`capabilityServerDescriptors`) and the leg materializes it per session,
188
+ * beside the standing server it builds from `messaging`.
189
+ *
190
+ * PER SERVER, UNDER ITS OWN NAME, so `mcp__<server>__<tool>` is the same canonical name on both legs
191
+ * — which is the whole of WS-14 §11's "registered identically into BOTH branches".
192
+ */
193
+ capabilities?: readonly WinterMcpServerDescriptor[];
194
+ /**
195
+ * The host's JSON-Schema → validator-shape bridge (`RuntimeSdkOptions.toInputShape`).
196
+ *
197
+ * IT IS WHAT SWITCHES THE ROUTER-BUILT SERVERS ON. With it, this leg registers the standing server
198
+ * (the messaging tools) and every capability server itself, and a host stops hand-materializing.
199
+ * Without it and WITH capabilities configured, the leg REFUSES: a session whose capability tools
200
+ * exist on the Winter branch and silently not on this one is the divergence §11 exists to prevent.
201
+ */
202
+ toInputShape?: InputShapeFactory;
203
+ /**
204
+ * The injected official peer, duck-typed to §11's surface (`createSdkMcpServer`/`tool`).
205
+ *
206
+ * THE SAME OBJECT `peers.claude` ALREADY IS — the seam declares only `query`, because that is all
207
+ * the launch path needs, and this is the one other member of it this package uses. A module without
208
+ * the constructor is `OfficialMcpError`, thrown where the server would have been built.
209
+ */
210
+ mcpModule?: OfficialMcpModule;
211
+ /**
212
+ * What the host supplies for the STANDING ADVISOR — the reviewer, never the tool (interim review I-5).
213
+ *
214
+ * The advisor is registered on this branch whether or not a host fills this in, because the Winter
215
+ * runtime always advertises `advisor` and two legs whose advertised sets differ by a host option is
216
+ * exactly the divergence WS-14 §11 forbids. What this supplies is the REVIEWER: absent, the default
217
+ * resolver answers `undefined`, which is WS-06 §4's ordinary tool error ("no reviewer configured"),
218
+ * not a throw and not a missing tool.
219
+ */
220
+ advisor?: {
221
+ resolveReviewer?: ReviewerResolver;
222
+ maxChars?: number;
223
+ };
163
224
  /** The adapter's own policy, so a host's `env`/`containment` choices reach the door's own builders. */
164
225
  policy?: RouterOfficialPolicy;
165
226
  /**
package/dist/errors.d.ts CHANGED
@@ -38,12 +38,20 @@ export declare class RuntimeHandoffRequiredError extends RuntimeSdkError {
38
38
  * cannot run. This one is about the DOOR's own inputs: the session id its directory row is addressed
39
39
  * by, the credential its auth family needs, the vendored runtime path §5.1 will not guess. A host
40
40
  * catching it knows to fix a call site, not a configuration.
41
+ *
42
+ * THE PREFIX IS LEG-NEUTRAL, AND IT HAD TO BECOME SO (interim review I-7). It read "the official leg
43
+ * needs `<field>`" for as long as the official leg was the only caller — and then R-8 gave the class
44
+ * three refusals that are not: `capabilities` at CONSTRUCTION (before any leg exists, and fatal to a
45
+ * Winter-only host), and `mcpServers` on the WINTER leg. A host with no official peer at all reading
46
+ * "the official leg needs `mcpServers`" is told to look at the one branch it does not use. `leg` names
47
+ * the branch when there IS one, so nothing is lost where the old sentence was right.
41
48
  */
42
49
  export declare class RuntimeLaunchInputError extends RuntimeSdkError {
43
50
  readonly field: string;
44
51
  constructor(args: {
45
52
  field: string;
46
53
  reason: string;
54
+ leg?: "official" | "winter";
47
55
  });
48
56
  }
49
57
  /**
package/dist/index.d.ts CHANGED
@@ -14,12 +14,10 @@ export { RESUME_STAGING_PREFIX, isResumeStagingRoot, resumeStagingRoot } from ".
14
14
  export { MATERIALIZED_RESUME_PROBE_REPORTS, materializedResumeReportForPin } from "./store/pinned-probes.js";
15
15
  export { EXECUTION_INDIRECTION_ENV_NAMES, EXECUTION_INDIRECTION_ENV_PREFIXES, isExecutionIndirectionVariable } from "./official/env-allowlist.js";
16
16
  export { TRAFFIC_OPT_OUT_VARIABLES, TRAFFIC_OPT_OUT_VARIABLE_NAMES } from "./official/env-allowlist.js";
17
- export { LIST_AGENTS_FIELD_MAX, NATIVE_LIST_AGENTS_OUTPUT_SCHEMA, NATIVE_LIST_AGENTS_SCHEMA, NATIVE_SEND_MESSAGE_SCHEMA, SEND_MESSAGE_SUMMARY_MAX, SEND_MESSAGE_TO_MAX, acceptNativeListAgentsArgs, acceptNativeSendMessageArgs, } from "./native-args.js";
18
- export type { NativeArgsResult, NativeListAgentsArgs, NativeSendMessageArgs } from "./native-args.js";
19
17
  export * from "./seams/index.js";
20
18
  export { NotImplementedYet, RuntimeHandoffRequiredError, RuntimeLaunchInputError, RuntimeSdkDisposedError, RuntimeSdkError, RuntimeSdkVersionError, UnaddressableEntryError } from "./errors.js";
21
19
  export { createOfficialInputStream, isOfficialQuery, officialCredentialPlan, officialConnectionEnv, officialUserTurn } from "./door.js";
22
20
  export type { OfficialInputStream, RouterOfficialInput, RouterOfficialPolicy, RouterQuery } from "./door.js";
23
21
  export type { LaneId } from "./errors.js";
24
- export { createRuntimeMessaging, createMessagingToolHandlers, createAttachedSessionRegistry } from "./messaging/index.js";
25
- export type { AttachedOfficialSession, AttachedSession, AttachedSessionRegistry, AttachedWinterSession, DirectorySnapshot, GlobalMessagingHandle, GlobalMessagingOptions, MessagingToolCaller, MessagingToolHandlers, MessagingToolResult, ReplyRequest, RouterMessagingAdapter, RuntimeDirectoryHandle, RuntimeDirectoryOptions, RuntimeDirectoryRecoveryHooks, } from "./messaging/index.js";
22
+ export { createRuntimeMessaging, createAttachedSessionRegistry } from "./messaging/index.js";
23
+ export type { AttachedOfficialSession, AttachedSession, AttachedSessionRegistry, AttachedWinterSession, DirectorySnapshot, GlobalMessagingHandle, GlobalMessagingOptions, ReplyRequest, RouterMessagingAdapter, RuntimeDirectoryHandle, RuntimeDirectoryOptions, RuntimeDirectoryRecoveryHooks, } from "./messaging/index.js";