@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.
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/bun-required.d.ts +54 -0
- package/dist/goldens.d.ts +11 -0
- package/dist/index-v0zvhx0z.js +1576 -0
- package/dist/index-z5gwvsfh.js +49 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +49 -0
- package/dist/official/capture.d.ts +1 -0
- package/dist/official/fetch.d.ts +40 -0
- package/dist/official/index.d.ts +3 -0
- package/dist/official/index.js +27 -0
- package/dist/trace.d.ts +9 -0
- package/dist/trace.js +8 -0
- package/goldens/advertised-set-round.trace.json +81 -0
- package/goldens/background-task-round.trace.json +210 -0
- package/goldens/bash-background-round.trace.json +148 -0
- package/goldens/canusetool-approved-round.trace.json +119 -0
- package/goldens/compaction-auto-round.trace.json +219 -0
- package/goldens/compaction-manual-round.trace.json +232 -0
- package/goldens/denied-tool-round.trace.json +141 -0
- package/goldens/hook-denied-round.trace.json +169 -0
- package/goldens/hooked-tool-round.trace.json +147 -0
- package/goldens/interrupt.trace.json +129 -0
- package/goldens/mcp-tool-round.trace.json +131 -0
- package/goldens/messaging-facet-round.trace.json +278 -0
- package/goldens/mode-switch-mid-session.trace.json +200 -0
- package/goldens/multi-turn.trace.json +110 -0
- package/goldens/p6-anthropic-fake.trace.json +147 -0
- package/goldens/p6-gemini-fake.trace.json +132 -0
- package/goldens/p6-openai-chat-fake.trace.json +133 -0
- package/goldens/p6-openai-responses-fake.trace.json +145 -0
- package/goldens/p6-resolution-failure.trace.json +68 -0
- package/goldens/plain-query.trace.json +82 -0
- package/goldens/resume.trace.json +162 -0
- package/goldens/sendmessage-child-round.trace.json +158 -0
- package/goldens/skill-invocation-round.trace.json +123 -0
- package/goldens/structured-exhaustion-round.trace.json +182 -0
- package/goldens/structured-output-round.trace.json +106 -0
- package/goldens/subagent-permission-round.trace.json +174 -0
- package/goldens/subagent-spawn-round.trace.json +120 -0
- package/goldens/tool-round.trace.json +119 -0
- package/goldens/toolsearch-select-round.trace.json +185 -0
- 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[];
|