@yanlinglabs/winter-conformance 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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +128 -0
  3. package/dist/bun-required.d.ts +54 -0
  4. package/dist/goldens.d.ts +11 -0
  5. package/dist/index-v0zvhx0z.js +1576 -0
  6. package/dist/index-z5gwvsfh.js +49 -0
  7. package/dist/index.d.ts +5 -0
  8. package/dist/index.js +49 -0
  9. package/dist/official/capture.d.ts +1 -0
  10. package/dist/official/fetch.d.ts +40 -0
  11. package/dist/official/index.d.ts +3 -0
  12. package/dist/official/index.js +27 -0
  13. package/dist/trace.d.ts +9 -0
  14. package/dist/trace.js +8 -0
  15. package/goldens/advertised-set-round.trace.json +81 -0
  16. package/goldens/background-task-round.trace.json +210 -0
  17. package/goldens/bash-background-round.trace.json +148 -0
  18. package/goldens/canusetool-approved-round.trace.json +119 -0
  19. package/goldens/compaction-auto-round.trace.json +219 -0
  20. package/goldens/compaction-manual-round.trace.json +232 -0
  21. package/goldens/denied-tool-round.trace.json +141 -0
  22. package/goldens/hook-denied-round.trace.json +169 -0
  23. package/goldens/hooked-tool-round.trace.json +147 -0
  24. package/goldens/interrupt.trace.json +129 -0
  25. package/goldens/mcp-tool-round.trace.json +131 -0
  26. package/goldens/messaging-facet-round.trace.json +278 -0
  27. package/goldens/mode-switch-mid-session.trace.json +200 -0
  28. package/goldens/multi-turn.trace.json +110 -0
  29. package/goldens/p6-anthropic-fake.trace.json +147 -0
  30. package/goldens/p6-gemini-fake.trace.json +132 -0
  31. package/goldens/p6-openai-chat-fake.trace.json +133 -0
  32. package/goldens/p6-openai-responses-fake.trace.json +145 -0
  33. package/goldens/p6-resolution-failure.trace.json +68 -0
  34. package/goldens/plain-query.trace.json +82 -0
  35. package/goldens/resume.trace.json +162 -0
  36. package/goldens/sendmessage-child-round.trace.json +158 -0
  37. package/goldens/skill-invocation-round.trace.json +123 -0
  38. package/goldens/structured-exhaustion-round.trace.json +182 -0
  39. package/goldens/structured-output-round.trace.json +106 -0
  40. package/goldens/subagent-permission-round.trace.json +174 -0
  41. package/goldens/subagent-spawn-round.trace.json +120 -0
  42. package/goldens/tool-round.trace.json +119 -0
  43. package/goldens/toolsearch-select-round.trace.json +185 -0
  44. package/package.json +50 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 yanlingLabs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # `@yanlinglabs/winter-conformance`
2
+
3
+ Winter's SDK compatibility corpus: a trace normalizer, a set of committed golden traces, and the
4
+ pinned-upstream ("official SDK") mechanics that back Winter's compatibility claim against
5
+ `@anthropic-ai/claude-agent-sdk@0.3.250` (see [WS-02](../../../docs/superpowers/specs/winter/WS-02-repo-and-packaging.md)
6
+ in the `winter-agent-sdk` repository for the full spec, if you have it checked out).
7
+
8
+ This package is published to GitHub Packages under restricted access (`@yanlinglabs` scope). The
9
+ registry is chosen by the release workflow, not by a committed pin — see
10
+ [RELEASING.md](https://github.com/yanlingLabs/winter-agent-sdk/blob/main/RELEASING.md).
11
+
12
+ ## Install
13
+
14
+ Published to **both** registries. This is one of the org's own test harnesses rather than something a
15
+ consumer of the wrapper installs — and it is on public npm deliberately: the router package
16
+ `@yanlinglabs/winter-runtime-sdk` lives in its own repository and needs these golden traces and this trace normalizer as a dev dependency, and
17
+ reaching GitHub Packages from that repository's CI would mean a cross-repo `read:packages` token
18
+ whose only purpose is fetching test fixtures.
19
+
20
+ ### From public npm (anyone)
21
+
22
+ ```sh
23
+ npm install @yanlinglabs/winter-conformance
24
+ ```
25
+
26
+ Nothing else is needed: the `@yanlinglabs` scope is public on npm.
27
+
28
+ ### From GitHub Packages (the `yanlingLabs` org)
29
+
30
+ GitHub Packages needs the scope pointed at it and an authenticated read, even for a public package.
31
+ In your project's `.npmrc`:
32
+
33
+ ```
34
+ @yanlinglabs:registry=https://npm.pkg.github.com
35
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
36
+ ```
37
+
38
+ …with `GITHUB_TOKEN` in the environment — a personal access token carrying `read:packages`, never a
39
+ literal in the file. Then `npm install @yanlinglabs/winter-conformance` as usual.
40
+
41
+ **The published packages contain COMPILED OUTPUT ONLY.** Each tarball ships `dist/` — the bundled
42
+ JavaScript a consumer imports and the `.d.ts` declarations their type-checker reads — plus its data
43
+ files, `README.md` and `LICENSE`. It does **not** ship `src/`: the TypeScript sources live at
44
+ <https://github.com/yanlingLabs/winter-agent-sdk>, which is where to read them, file an issue, or send
45
+ a patch.
46
+
47
+ ## What it ships
48
+
49
+ | Import | What it is |
50
+ | --- | --- |
51
+ | `@yanlinglabs/winter-conformance` | The full barrel: everything below, in one import. |
52
+ | `@yanlinglabs/winter-conformance/trace` | `normalizeTrace`, `compareTraces`, and the `ConformanceTraceEntry` type — strips volatile fields (session ids, timestamps, durations, costs) from a captured SDK message trace and diffs two normalized traces. |
53
+ | `@yanlinglabs/winter-conformance/official` | The pinned-upstream mechanics: `fetchAndVerifyUpstream` (checksum-verified ephemeral fetch of the pinned official wrapper tarball) and `runCapture` (the `RUN_OFFICIAL_CAPTURE=1`-gated differential-signal harness). |
54
+
55
+ ## Bun-only surface
56
+
57
+ This package declares `engines.node` and every entry point **imports** cleanly under Node 18+ (the
58
+ compiled emit under `dist/` is what a non-Bun runtime resolves, via each export's `default`
59
+ condition; Bun resolves the `bun` condition and gets the TypeScript source unchanged). Importable is
60
+ not the same as runnable on every path — one exported function needs the Bun runtime:
61
+
62
+ | Function | Import | Needs | Why |
63
+ | --- | --- | --- | --- |
64
+ | `runCapture()` | `@yanlinglabs/winter-conformance`, `@yanlinglabs/winter-conformance/official` | `Bun.spawn`, `Bun.serve` | It installs the pinned official SDK into a throwaway npm prefix and drives it against loopback HTTP fakes. |
65
+
66
+ Called anywhere else it throws `BunRequiredError` (exported from both of those barrels) as its FIRST
67
+ action — before the pinned tarball is fetched and before any listener is bound — naming the function,
68
+ the Bun API and what to do instead. Catch it by identity:
69
+
70
+ ```ts
71
+ import { runCapture, BunRequiredError } from "@yanlinglabs/winter-conformance";
72
+
73
+ try {
74
+ await runCapture();
75
+ } catch (err) {
76
+ if (err instanceof BunRequiredError) { /* run the capture under Bun instead */ }
77
+ throw err;
78
+ }
79
+ ```
80
+
81
+ ### `BunRequiredError` is THIS package's own class
82
+
83
+ `@yanlinglabs/winter-provider-runtime` exports a class with the same name and shape, and the two are
84
+ deliberately **not** the same type — the packages share no dependency, so there is no module either
85
+ could import it from. **Catch the one you imported.** Within this package it is one type across every
86
+ subpath: an error thrown by `./official`'s `runCapture` satisfies `instanceof BunRequiredError`
87
+ imported from the main barrel, and vice versa, under Node as well as Bun. The same holds for
88
+ `ChecksumMismatchError` and `OfficialCompatUnavailableError`, which are also exported from both
89
+ entries (the compiled emit gives each export entry its own bundle, so each class carries a
90
+ package-scoped `Symbol.for` brand to make that hold).
91
+
92
+ Everything else here — the trace normalizer, the goldens and their loaders, `fetchAndVerifyUpstream`
93
+ and the checksum helpers — is plain Node-compatible code. The goldens `runCapture` produces are
94
+ ordinary JSON and are readable from Node whoever produced them.
95
+
96
+ Goldens (`goldens/*.trace.json`) ship as data alongside the compiled `dist/` — load them with `loadGolden`,
97
+ `listGoldens`, and `goldenPath` from the main barrel rather than reaching into the installed
98
+ package's directory layout by hand.
99
+
100
+ ```ts
101
+ import { normalizeTrace, compareTraces, loadGolden } from "@yanlinglabs/winter-conformance";
102
+
103
+ const golden = loadGolden("plain-query.trace.json");
104
+ const fresh = normalizeTrace(await traceMySession());
105
+ const diffs = compareTraces(fresh, golden);
106
+ ```
107
+
108
+ ## What it does NOT ship
109
+
110
+ Per WS-02 §6 and §9: no Anthropic-derived artifact of any kind (no upstream `.d.ts`, no `sdk.mjs`,
111
+ no native binary, no extracted prompt text). `compat/anthropic/0.3.250/` — the derived declaration
112
+ digests and independently-authored consumer fixtures this repository uses to prove compatibility —
113
+ is excluded from every published tarball; only `dist/` and `goldens/` ship (see this package's
114
+ `package.json` `files` field). The `runCapture()` harness under `./official` never writes a golden
115
+ file or persists anything from a live capture run; it prints a report for a human to read.
116
+
117
+ ## Runtime notes
118
+
119
+ `./trace` is plain, dependency-free TypeScript and is the one subpath this repository's own CI
120
+ proves importable under both Node 18 and Bun (the `pack-smoke` job, WS-02 §9 Step 3). The top-level
121
+ barrel and `./official` additionally pull in `./official/capture.ts`, which calls `Bun.spawn` (to
122
+ install the pinned official SDK into a throwaway npm prefix) — only inside `runCapture()`'s own
123
+ function body, never at module load, so importing the barrel itself never requires Bun; actually
124
+ *calling* `runCapture()` does.
125
+
126
+ ## License
127
+
128
+ MIT — see [`LICENSE`](./LICENSE), which ships in the published tarball.
@@ -0,0 +1,54 @@
1
+ /**
2
+ * A function that needs the Bun runtime was called somewhere else.
3
+ *
4
+ * `name` is the exported function the caller actually invoked (never the internal helper that
5
+ * reaches for Bun), because that is the name in their code.
6
+ */
7
+ /**
8
+ * P7a fix wave round 3 (F2): CROSS-BUNDLE `instanceof`.
9
+ *
10
+ * THE PROBLEM, measured on the compiled emit under Node. `build-packages.ts` runs `bun build` ONCE
11
+ * PER EXPORT ENTRY, so every entry bundle carries its own copy of every internal module: the class
12
+ * declared in one source file exists as TWO DISTINCT CLASSES at runtime, one in `dist/index.js` and
13
+ * one in `dist/<subpath>/index.js`. A consumer who imports the function from one subpath and the
14
+ * class from the other -- the pattern both new READMEs teach -- gets a silent `false` from
15
+ * `instanceof` and rethrows the very error the guard exists to make catchable. Under Bun the `bun`
16
+ * condition resolves both entries to the same `src/*.ts`, so the classes ARE identical, which is why
17
+ * no Bun-side test could see it.
18
+ *
19
+ * THE FIX, applied to the CLASS of the problem rather than to one error: every error class exported
20
+ * from more than one subpath of a package carries a PACKAGE-SCOPED `Symbol.for(...)` brand and a
21
+ * `static [Symbol.hasInstance]` that tests for it. `Symbol.for` is cross-realm and cross-copy, so
22
+ * every duplicated bundle of ONE package agrees -- while a DIFFERENT package's class, whose key
23
+ * names a different package, still does not match. The two packages stay deliberately distinct
24
+ * (they share no dependency and cannot share a module), and the existing distinctness test passes
25
+ * unchanged.
26
+ *
27
+ * Considered and recorded as a carry rather than done here: `bun build --splitting`, so shared
28
+ * internals emit once per package. It is the more fundamental answer and it changes the emit shape
29
+ * for every package and every `.d.ts` -- not a round-3-sized change.
30
+ */
31
+ export declare function brandedInstanceOf(brand: symbol): (candidate: unknown) => boolean;
32
+ /** The cross-bundle identity of THIS package's `BunRequiredError`. Package-scoped on purpose. */
33
+ declare const BUN_REQUIRED_BRAND: unique symbol;
34
+ export declare class BunRequiredError extends Error {
35
+ readonly name = "BunRequiredError";
36
+ /** F2: the brand `Symbol.hasInstance` below tests for. Present on every instance, in every bundle. */
37
+ readonly [BUN_REQUIRED_BRAND] = true;
38
+ /** F2: `instanceof` holds across this package's duplicated entry bundles, and only this package's. */
39
+ static [Symbol.hasInstance]: (candidate: unknown) => boolean;
40
+ /** The exported function the caller invoked. */
41
+ readonly functionName: string;
42
+ /** The Bun API that has no Node equivalent this package implements, e.g. `Bun.serve`. */
43
+ readonly bunApi: string;
44
+ constructor(functionName: string, bunApi: string, detail: string);
45
+ }
46
+ /** True when this process is Bun. Separated so a test can assert the guard without a subprocess. */
47
+ export declare function hasBunRuntime(): boolean;
48
+ /**
49
+ * Throws `BunRequiredError` unless this process is Bun. Called FIRST in each guarded function, before
50
+ * any network call, any file write and any credential read — a guard that fired after a side effect
51
+ * would be a worse failure than the `ReferenceError` it replaces.
52
+ */
53
+ export declare function requireBunRuntime(functionName: string, bunApi: string, detail: string): void;
54
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { ConformanceTraceEntry } from "./trace.js";
2
+ /** Every committed golden's file name (e.g. "plain-query.trace.json"), sorted for a stable order. */
3
+ export declare function listGoldens(): string[];
4
+ /** Absolute path to a named golden file. Does not check existence -- loadGolden's own read does that. */
5
+ export declare function goldenPath(name: string): string;
6
+ /**
7
+ * Reads and parses a committed golden trace by file name (e.g. "plain-query.trace.json", one of
8
+ * `listGoldens()`'s entries). The returned array is already `normalizeTrace()`-shaped -- every
9
+ * committed golden is, by `differential.ts`'s own convention (trace.ts's header comment).
10
+ */
11
+ export declare function loadGolden(name: string): ConformanceTraceEntry[];