@rynfar/meridian 1.68.0 → 1.70.0
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 +1 -0
- package/dist/{cli-0zhb8ss4.js → cli-198xnjcn.js} +1033 -525
- package/dist/{cli-sh8bzdwe.js → cli-zdbv40d5.js} +26 -7
- package/dist/cli.js +4 -4
- package/dist/meridian/index.js +252 -0
- package/dist/meridian/package.json +6 -0
- package/dist/meridian-v2/index.js +20384 -41
- package/dist/meridian-v2.js +20382 -45
- package/dist/proxy/adapter.d.ts +16 -0
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/claudecode.d.ts +23 -0
- package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
- package/dist/proxy/adapters/detect.d.ts.map +1 -1
- package/dist/proxy/adapters/passthrough.d.ts.map +1 -1
- package/dist/proxy/adapters/polytoken.d.ts +36 -0
- package/dist/proxy/adapters/polytoken.d.ts.map +1 -0
- package/dist/proxy/errors.d.ts +2 -0
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/openaiResponses.d.ts +106 -3
- package/dist/proxy/openaiResponses.d.ts.map +1 -1
- package/dist/proxy/passthroughEarlyStop.d.ts +3 -3
- package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
- package/dist/proxy/passthroughTools.d.ts +63 -2
- package/dist/proxy/passthroughTools.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +3 -0
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/cache.d.ts +20 -3
- package/dist/proxy/session/cache.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts +56 -0
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/session/processIncarnation.d.ts +55 -0
- package/dist/proxy/session/processIncarnation.d.ts.map +1 -1
- package/dist/proxy/setup.d.ts +12 -2
- package/dist/proxy/setup.d.ts.map +1 -1
- package/dist/proxy/transforms/codex.d.ts +12 -0
- package/dist/proxy/transforms/codex.d.ts.map +1 -1
- package/dist/proxy/transforms/polytoken.d.ts +18 -0
- package/dist/proxy/transforms/polytoken.d.ts.map +1 -0
- package/dist/proxy/transforms/registry.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{setup-knvctar4.js → setup-b3ymd9z8.js} +3 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/plugin/meridian/index.js +1 -0
- package/plugin/meridian/package.json +6 -0
- package/plugin/meridian-v2.ts +223 -0
- package/plugin/meridian.ts +1 -1
|
@@ -157,6 +157,17 @@ export interface LineageMismatch {
|
|
|
157
157
|
previousDigest?: string;
|
|
158
158
|
storedCount: number;
|
|
159
159
|
incomingCount: number;
|
|
160
|
+
/** How many blocks the STORED message had at this index. Undefined for a
|
|
161
|
+
* session cached before block hashes were recorded (pre-1.61.0). */
|
|
162
|
+
storedBlockCount?: number;
|
|
163
|
+
/** Blocks the incoming message has at this index, counted over the same
|
|
164
|
+
* hashable domain as the stored side so the two are comparable. */
|
|
165
|
+
incomingBlockCount?: number;
|
|
166
|
+
/** What the client did to this message, when the stored block hashes make it
|
|
167
|
+
* decidable. Appended/dropped/rewritten are three different client bugs and
|
|
168
|
+
* the log could not tell them apart (#886) — which is precisely the question
|
|
169
|
+
* #767 turns on. */
|
|
170
|
+
blockChange?: "appended" | "dropped" | "rewritten" | "reordered" | "unknown";
|
|
160
171
|
}
|
|
161
172
|
/**
|
|
162
173
|
* Locate the first message whose hash differs between a stored session and an
|
|
@@ -186,6 +197,51 @@ precomputedIncomingHashes?: string[]): LineageMismatch;
|
|
|
186
197
|
* into a public issue.
|
|
187
198
|
*/
|
|
188
199
|
export declare function formatLineageMismatch(mismatch: LineageMismatch): string | undefined;
|
|
200
|
+
/**
|
|
201
|
+
* Why a request skipped session lookup entirely.
|
|
202
|
+
*
|
|
203
|
+
* `independent-request` is assigned in server.ts before `classifyLineage` runs,
|
|
204
|
+
* so it is the one divergence that emits no diagnostic at all — and four
|
|
205
|
+
* unrelated causes collapse into that single silent outcome. #820 was a log
|
|
206
|
+
* full of `lineage=new` with zero explanatory lines; the reporter could only
|
|
207
|
+
* identify the bypass by reading server.ts.
|
|
208
|
+
*
|
|
209
|
+
* Naming the cause is log-only. The `LineageDivergenceReason` handed to the
|
|
210
|
+
* `onSession` transform hook is unchanged, so plugins switching on it are
|
|
211
|
+
* unaffected.
|
|
212
|
+
*/
|
|
213
|
+
export type IndependentRequestCause = "fork-source" | "subagent" | "headerless-tool-result" | "no-cache-identity";
|
|
214
|
+
/**
|
|
215
|
+
* Decide whether a request bypasses session lookup, and say which rule did it.
|
|
216
|
+
*
|
|
217
|
+
* The caller derives `isIndependentSession` from this result rather than
|
|
218
|
+
* computing it separately, so the reported cause cannot drift away from the
|
|
219
|
+
* decision it explains. Evaluation order mirrors the guards' own precedence.
|
|
220
|
+
*/
|
|
221
|
+
export declare function independentRequestCause(input: {
|
|
222
|
+
/** An explicit session key. Distinct flows carry distinct keys, so a keyed
|
|
223
|
+
* request cannot collide and never needs the independence guard. */
|
|
224
|
+
hasSessionKey: boolean;
|
|
225
|
+
/** `x-meridian-source: fork-*` — a declared independent sub-request flow. */
|
|
226
|
+
forkSource: boolean;
|
|
227
|
+
isSubagent: boolean;
|
|
228
|
+
/** The last message carries a tool_result and the request has no session
|
|
229
|
+
* key, so it is a self-contained round of the client's own tool loop. */
|
|
230
|
+
clientDrivenLoop: boolean;
|
|
231
|
+
/** Whether a session key or a conversation fingerprint could be derived.
|
|
232
|
+
* Image-only and otherwise text-free headerless requests have neither. */
|
|
233
|
+
hasDurableKey: boolean;
|
|
234
|
+
}): IndependentRequestCause | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* The `diverged=` field for the request log line.
|
|
237
|
+
*
|
|
238
|
+
* The line renders `lineage=new` for every divergence without a cached
|
|
239
|
+
* session, so a key that never resolved, a history that did not match and a
|
|
240
|
+
* request that never looked are indistinguishable (#820). The reason is
|
|
241
|
+
* already in memory on every request; it was only reachable by writing a
|
|
242
|
+
* plugin. Reasons are fixed identifiers, never message content.
|
|
243
|
+
*/
|
|
244
|
+
export declare function formatDivergence(result: LineageResult, cause?: IndependentRequestCause): string | undefined;
|
|
189
245
|
/**
|
|
190
246
|
* Compute per-message hashes for an entire message array.
|
|
191
247
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lineage.d.ts","sourceRoot":"","sources":["../../../src/proxy/session/lineage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lineage.d.ts","sourceRoot":"","sources":["../../../src/proxy/session/lineage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,2BAA2B,CAAC,EAAE,MAAM,CAAA;IACpC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAW,SAAQ,mBAAmB;IACrD,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAA;CACnC;AAED;;6DAE6D;AAC7D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,GAAG,mBAAmB,CAG5E;AAED;0EAC0E;AAC1E,eAAO,MAAM,yBAAyB,IAAI,CAAA;AAE1C,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB;;qDAEiD;IACjD,WAAW,EAAE,MAAM,CAAA;IACnB;;kCAE8B;IAC9B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;iDAE6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAA;IAC/B;;oDAEgD;IAChD,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACtC;6FACyF;IACzF,gCAAgC,CAAC,EAAE,MAAM,CAAA;IACzC,0EAA0E;IAC1E,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAA;IACjC,iGAAiG;IACjG,YAAY,CAAC,EAAE,UAAU,CAAA;IACzB,wEAAwE;IACxE,iBAAiB,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjF,kBAAkB,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACnF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC9B,kBAAkB,EAAE,MAAM,EAC1B,IAAI,EAAE,OAAO,GACZ,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAOtB;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC9B,kBAAkB,EAAE,MAAM,EAC1B,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,iBAAiB,EAAE,MAAM,GAAG,SAAS,GACpC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAKtB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/F;IAAE,IAAI,EAAE,YAAY,CAAC;IAAG,OAAO,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAC1F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAS,OAAO,EAAE,YAAY,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACxG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAK,MAAM,EAAE,uBAAuB,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAC9E;sCACkC;IAClC,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAE,CAAA;AAElC,MAAM,MAAM,uBAAuB,GAC/B,cAAc,GACd,kBAAkB,GAClB,kBAAkB,GAClB,UAAU,GACV,mBAAmB,GACnB,WAAW,GACX,qBAAqB,GACrB,mBAAmB,GACnB,wBAAwB,GACxB,iBAAiB,CAAA;AA4CrB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAAG,MAAM,CAG1F;AAED,gFAAgF;AAChF,wBAAgB,0BAA0B,CACxC,MAAM,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EACvD,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GAClD,OAAO,CAKT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAE3E;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAA;IACd,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;+EAC2E;IAC3E,aAAa,CAAC,EAAE,YAAY,CAAA;IAC5B,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB;yEACqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;wEACoE;IACpE,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;yBAGqB;IACrB,WAAW,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,CAAA;CAC7E;AAaD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC;AAC/C;;gFAEgF;AAChF,yBAAyB,CAAC,EAAE,MAAM,EAAE,GACnC,eAAe,CAsCjB;AAwBD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAoBnF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,uBAAuB,GAC/B,aAAa,GACb,UAAU,GACV,wBAAwB,GACxB,mBAAmB,CAAA;AAEvB;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C;yEACqE;IACrE,aAAa,EAAE,OAAO,CAAA;IACtB,6EAA6E;IAC7E,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;IACnB;8EAC0E;IAC1E,gBAAgB,EAAE,OAAO,CAAA;IACzB;+EAC2E;IAC3E,aAAa,EAAE,OAAO,CAAA;CACvB,GAAG,uBAAuB,GAAG,SAAS,CAMtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,KAAK,CAAC,EAAE,uBAAuB,GAC9B,MAAM,GAAG,SAAS,CAKpB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,CAG9F;AAOD,uEAAuE;AACvE,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAIrG;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ7F;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,CA6B7F;AAyBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAC9C,aAAa,CAqLf"}
|
|
@@ -36,6 +36,61 @@ export declare function parseProcessIncarnationJson(raw: string): ProcessIncarna
|
|
|
36
36
|
* Unknown hosts and every unavailable or malformed observation fail closed.
|
|
37
37
|
*/
|
|
38
38
|
export declare function evaluateProcessIncarnation(owner: ProcessIncarnation, localBoot: LocalBootIdentity | undefined, observedStart: ProcessStartObservation | undefined): ProcessIncarnationProbe;
|
|
39
|
+
/**
|
|
40
|
+
* Operator-pinned host identity (#905).
|
|
41
|
+
*
|
|
42
|
+
* The derived `hostId` is wrong in both directions inside a container:
|
|
43
|
+
*
|
|
44
|
+
* - NOT STABLE. It mixes in the pid-namespace inode, which changes on every
|
|
45
|
+
* `docker restart`. The session store lives in the writable layer and
|
|
46
|
+
* survives that restart, so a proxy SIGKILLed while holding a store lock
|
|
47
|
+
* comes back with a different `hostId`; `probeProcessIncarnation` then
|
|
48
|
+
* returns `indeterminate` rather than `dead`, `retireStaleLock` refuses to
|
|
49
|
+
* retire it, and every request fails with `timed out waiting for lock`
|
|
50
|
+
* until the container is recreated. It fails toward a permanent hang.
|
|
51
|
+
* - NOT UNIQUE. Every container from a given image tag has a byte-identical
|
|
52
|
+
* `/etc/machine-id`, so `hostId` reduces to that pid-namespace inode, which
|
|
53
|
+
* is allocated from a fixed base at boot. Two freshly-booted hosts sharing
|
|
54
|
+
* a session directory can each read the other's LIVE lock as `dead` and
|
|
55
|
+
* retire it, deleting session resources under a running owner.
|
|
56
|
+
*
|
|
57
|
+
* Pinning it — the container ID works — fixes both. Unset outside containers,
|
|
58
|
+
* where the derived value is genuinely stable and unique, so nothing changes.
|
|
59
|
+
*
|
|
60
|
+
* Hashed like the derived value rather than used raw: `hostId` is compared for
|
|
61
|
+
* equality only, and hashing keeps a pinned value from leaking an operator's
|
|
62
|
+
* hostname into a lock file that is read cross-host.
|
|
63
|
+
*/
|
|
64
|
+
export declare function pinnedHostIdFor(pin: string | undefined): string | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Whether this host can produce a boot identity, and what to do if it cannot.
|
|
67
|
+
*
|
|
68
|
+
* Every session-store write takes a lock stamped with a process incarnation,
|
|
69
|
+
* and `captureProcessIncarnation` returns undefined without a boot identity —
|
|
70
|
+
* so `acquireLock` throws and EVERY request that touches a session fails with a
|
|
71
|
+
* 500. `/health` never probed this, so a container missing `/etc/machine-id`
|
|
72
|
+
* reported healthy to Docker and to any orchestrator while serving nothing,
|
|
73
|
+
* which is why the original occurrence took three days to find (#906, split
|
|
74
|
+
* from #903).
|
|
75
|
+
*
|
|
76
|
+
* Exported so both the startup check and `/health` read the same source rather
|
|
77
|
+
* than each inferring it.
|
|
78
|
+
*/
|
|
79
|
+
export interface BootIdentityStatus {
|
|
80
|
+
available: boolean;
|
|
81
|
+
platform: string;
|
|
82
|
+
/** Actionable next step, present only when unavailable. */
|
|
83
|
+
hint?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* What to tell an operator when this platform produced no boot identity.
|
|
87
|
+
*
|
|
88
|
+
* Pure and exported separately so every branch is testable without breaking the
|
|
89
|
+
* host it runs on. "cannot capture lock owner process incarnation" is what the
|
|
90
|
+
* original failure said, and it names nothing an operator can act on.
|
|
91
|
+
*/
|
|
92
|
+
export declare function bootIdentityHint(platform: string): string;
|
|
93
|
+
export declare function describeLocalBootIdentity(): BootIdentityStatus;
|
|
39
94
|
/** Parse field 22 (`starttime`) without assuming that comm contains no `)`. */
|
|
40
95
|
export declare function parseLinuxProcStatStartId(raw: string, expectedPid: number): string | undefined;
|
|
41
96
|
/** Capture metadata for a lock created by `pid` (normally the current process). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processIncarnation.d.ts","sourceRoot":"","sources":["../../../src/proxy/session/processIncarnation.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,2BAA2B,IAAI,CAAA;AAE5C,MAAM,MAAM,kBAAkB,GAC1B,wBAAwB,GACxB,kBAAkB,GAClB,qBAAqB,CAAA;AAEzB;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,2BAA2B,CAAA;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,kBAAkB,CAAA;CAChC;AAED,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,GAAG,eAAe,CAAA;AAExE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAA;CAAE,GACrE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,CAAA;AAkC/B,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CAqBtF;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAMvF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,iBAAiB,GAAG,SAAS,EACxC,aAAa,EAAE,uBAAuB,GAAG,SAAS,GACjD,uBAAuB,CAsBzB;
|
|
1
|
+
{"version":3,"file":"processIncarnation.d.ts","sourceRoot":"","sources":["../../../src/proxy/session/processIncarnation.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,2BAA2B,IAAI,CAAA;AAE5C,MAAM,MAAM,kBAAkB,GAC1B,wBAAwB,GACxB,kBAAkB,GAClB,qBAAqB,CAAA;AAEzB;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,2BAA2B,CAAA;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,kBAAkB,CAAA;CAChC;AAED,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,GAAG,eAAe,CAAA;AAExE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAA;CAAE,GACrE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,CAAA;AAkC/B,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CAqBtF;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAMvF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,iBAAiB,GAAG,SAAS,EACxC,aAAa,EAAE,uBAAuB,GAAG,SAAS,GACjD,uBAAuB,CAsBzB;AAkGD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG3E;AA2BD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAazD;AAED,wBAAgB,yBAAyB,IAAI,kBAAkB,CAI9D;AAYD,+EAA+E;AAC/E,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ9F;AAsDD,mFAAmF;AACnF,wBAAgB,yBAAyB,CAAC,GAAG,SAAc,GAAG,kBAAkB,GAAG,SAAS,CAkB3F;AAED,wEAAwE;AACxE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,uBAAuB,CAS1F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAE3E"}
|
package/dist/proxy/setup.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export declare class UnparseableConfigError extends Error {
|
|
|
18
18
|
readonly configPath: string;
|
|
19
19
|
constructor(configPath: string);
|
|
20
20
|
}
|
|
21
|
+
export declare class MissingV1PluginError extends Error {
|
|
22
|
+
readonly expectedPath: string;
|
|
23
|
+
constructor(expectedPath: string);
|
|
24
|
+
}
|
|
21
25
|
export declare class MissingV2PluginError extends Error {
|
|
22
26
|
readonly expectedPath: string;
|
|
23
27
|
constructor(expectedPath: string);
|
|
@@ -29,8 +33,14 @@ export declare class DuplicateMeridianConfigError extends Error {
|
|
|
29
33
|
}
|
|
30
34
|
export declare function findOpencodeConfigPath(): string;
|
|
31
35
|
/**
|
|
32
|
-
* Resolve the
|
|
33
|
-
*
|
|
36
|
+
* Resolve the V1 plugin package from any entry point. Works whether called from
|
|
37
|
+
* bin/cli.ts (dev) or dist/cli.js (installed).
|
|
38
|
+
*
|
|
39
|
+
* NOTE: an installed CLI must select the compiled package, not TypeScript.
|
|
40
|
+
* OpenCode Desktop runs its server inside Electron's Node rather than Bun, and
|
|
41
|
+
* Node refuses to strip types for files under node_modules
|
|
42
|
+
* (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING), so a published install that
|
|
43
|
+
* points at plugin/meridian.ts cannot load the plugin at all.
|
|
34
44
|
*/
|
|
35
45
|
export declare function findPluginPath(fromUrl: string): string;
|
|
36
46
|
export type OpenCodeGeneration = "v1" | "v2";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aACnB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aACjB,YAAY,EAAE,MAAM;gBAApB,YAAY,EAAE,MAAM;CAIjD;AAED,qBAAa,4BAA6B,SAAQ,KAAK;aAEnC,UAAU,EAAE,MAAM;aAClB,WAAW,EAAE,MAAM;gBADnB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM;CAKtC;AA+BD,wBAAgB,sBAAsB,IAAI,MAAM,CAK/C;AASD
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aACnB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aACjB,YAAY,EAAE,MAAM;gBAApB,YAAY,EAAE,MAAM;CAIjD;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aACjB,YAAY,EAAE,MAAM;gBAApB,YAAY,EAAE,MAAM;CAIjD;AAED,qBAAa,4BAA6B,SAAQ,KAAK;aAEnC,UAAU,EAAE,MAAM;aAClB,WAAW,EAAE,MAAM;gBADnB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM;CAKtC;AA+BD,wBAAgB,sBAAsB,IAAI,MAAM,CAK/C;AASD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAA;AAE5C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,kBAAkB,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,8BAA8B,aAGzC,CAAA;AAeF,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED,wEAAwE;AACxE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAYrF;AAED,KAAK,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;AAE3D;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,GAAE,SAAS,MAAM,EAEI,EAC7B,KAAK,GAAE,YASN,GACA,iBAAiB,CAQnB;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAE/F;AAgCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAgB/F;AAaD,sDAAsD;AACtD,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,mEAAmE;IACnE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,GAAG,MAAM,GAAG,SAAS,CAkBrB;AAMD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,GAAE,kBAAyB,GACpC,WAAW,CAiFb"}
|
|
@@ -8,5 +8,17 @@ import type { Transform } from "../transform";
|
|
|
8
8
|
* global MERIDIAN_PASSTHROUGH setting. Internal mode (SDK executes tools) would
|
|
9
9
|
* leave Codex waiting for tool calls that never come back.
|
|
10
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* Codex sends every MCP server as a `namespace` entry with the tool
|
|
13
|
+
* definitions inline, so a desktop session easily carries 250+ tools and
|
|
14
|
+
* crosses the auto-defer threshold. Deferring them is a net loss here: the
|
|
15
|
+
* deferred budget lifts the single-turn cap (see computePassthroughMaxTurns),
|
|
16
|
+
* so every tool-calling turn also generates the SDK's discarded digest turn —
|
|
17
|
+
* one or two extra reads of the full context, measured 2-3x cache reads per
|
|
18
|
+
* turn on a 680k-token session — while the alternative, loading the schemas,
|
|
19
|
+
* costs ~125k cached tokens once. Codex never sets `defer_loading` itself, so
|
|
20
|
+
* with no core set auto-defer stays off, the cap stays at 1, and a tool turn
|
|
21
|
+
* is one model call again.
|
|
22
|
+
*/
|
|
11
23
|
export declare const codexTransforms: Transform[];
|
|
12
24
|
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../src/proxy/transforms/codex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,cAAc,CAAA;AAE7D;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,EAQtC,CAAA"}
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../src/proxy/transforms/codex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,cAAc,CAAA;AAE7D;;;;;;;;GAQG;AACH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,EAQtC,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Transform } from "../transform";
|
|
2
|
+
/**
|
|
3
|
+
* Polytoken native transforms.
|
|
4
|
+
*
|
|
5
|
+
* Scoped to adapter base `polytoken` ONLY — deliberately not spread onto
|
|
6
|
+
* openai/jcode/codex, whose tool configs differ. The client owns the tool
|
|
7
|
+
* loop, so this is pure passthrough plumbing:
|
|
8
|
+
* - passthrough forced true (mandatory client-owned tool execution);
|
|
9
|
+
* - signed/redacted thinking preserved (supportsThinking true);
|
|
10
|
+
* - body/system/tools and the client's stream preference preserved;
|
|
11
|
+
* - empty SDK agents/hooks — no Task/task parsing, no fuzzy aliases;
|
|
12
|
+
* - no file-change tracking or core-tool rewriting;
|
|
13
|
+
* - empty blocked/incompatible/allowed MCP lists and coreToolNames: the
|
|
14
|
+
* generated client-passthrough MCP names are the only allowed tools, and
|
|
15
|
+
* an OpenCode-style allowlist would collide with client tool names.
|
|
16
|
+
*/
|
|
17
|
+
export declare const polytokenTransforms: Transform[];
|
|
18
|
+
//# sourceMappingURL=polytoken.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polytoken.d.ts","sourceRoot":"","sources":["../../../src/proxy/transforms/polytoken.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,cAAc,CAAA;AAE7D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,EAqB1C,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/proxy/transforms/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/proxy/transforms/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AA8C7C,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE,CAE9E"}
|
package/dist/server.js
CHANGED
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
runObserveHook,
|
|
12
12
|
runTransformHook,
|
|
13
13
|
startProxyServer
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-198xnjcn.js";
|
|
15
15
|
import"./cli-5jxyma6z.js";
|
|
16
16
|
import"./cli-sry5aqdj.js";
|
|
17
17
|
import"./cli-8yp89fan.js";
|
|
18
18
|
import"./cli-9e5cxp89.js";
|
|
19
19
|
import"./cli-khhjyk04.js";
|
|
20
20
|
import"./cli-vj9cv18n.js";
|
|
21
|
-
import"./cli-
|
|
21
|
+
import"./cli-zdbv40d5.js";
|
|
22
22
|
import"./cli-p9swy5t3.js";
|
|
23
23
|
export {
|
|
24
24
|
startProxyServer,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DuplicateMeridianConfigError,
|
|
3
|
+
MissingV1PluginError,
|
|
3
4
|
MissingV2PluginError,
|
|
4
5
|
SUPPORTED_OPENCODE_V2_VERSIONS,
|
|
5
6
|
UnparseableConfigError,
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
notePluginlessOpenCodeRequest,
|
|
14
15
|
pluginPathForGeneration,
|
|
15
16
|
runSetup
|
|
16
|
-
} from "./cli-
|
|
17
|
+
} from "./cli-zdbv40d5.js";
|
|
17
18
|
import"./cli-p9swy5t3.js";
|
|
18
19
|
export {
|
|
19
20
|
runSetup,
|
|
@@ -29,5 +30,6 @@ export {
|
|
|
29
30
|
UnparseableConfigError,
|
|
30
31
|
SUPPORTED_OPENCODE_V2_VERSIONS,
|
|
31
32
|
MissingV2PluginError,
|
|
33
|
+
MissingV1PluginError,
|
|
32
34
|
DuplicateMeridianConfigError
|
|
33
35
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AA2CnE,eAAO,MAAM,cAAc,EAAE,eAAkC,CAAA;AAC/D,eAAO,MAAM,aAAa,EAAE,mBAAwC,CAAA;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAC7C,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,aAAa,GACd,MAAM,SAAS,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynfar/meridian",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.70.0",
|
|
4
4
|
"description": "Local Anthropic API powered by your Claude Max subscription. One subscription, every agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/server.js",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"start": "./bin/claude-proxy-supervisor.sh",
|
|
23
23
|
"proxy": "./bin/claude-proxy-supervisor.sh",
|
|
24
|
-
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && bun build bin/cli.ts src/proxy/server.ts plugin/meridian-v2.ts --outdir dist --target node --splitting --external @anthropic-ai/claude-agent-sdk --external jsonc-parser --entry-naming \"[name].js\" && bun build plugin/meridian-v2/index.js --outdir dist/meridian-v2 --target node --splitting --external @anthropic-ai/claude-agent-sdk --external jsonc-parser --entry-naming \"[name].js\" && node scripts/package-
|
|
25
|
-
"postbuild": "node scripts/fix-bun-exports.mjs && node --check dist/cli.js && node --check dist/server.js && node --check dist/meridian-v2.js && node --check dist/meridian-v2/index.js && node -e \"if(!require('fs').existsSync('dist/proxy/server.d.ts'))process.exit(1)\"",
|
|
24
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && bun build bin/cli.ts src/proxy/server.ts plugin/meridian-v2.ts --outdir dist --target node --splitting --external @anthropic-ai/claude-agent-sdk --external jsonc-parser --entry-naming \"[name].js\" && bun build plugin/meridian/index.js --outdir dist/meridian --target node --splitting --external @anthropic-ai/claude-agent-sdk --external jsonc-parser --entry-naming \"[name].js\" && bun build plugin/meridian-v2/index.js --outdir dist/meridian-v2 --target node --splitting --external @anthropic-ai/claude-agent-sdk --external jsonc-parser --entry-naming \"[name].js\" && node scripts/package-opencode-plugins.mjs && tsc -p tsconfig.build.json",
|
|
25
|
+
"postbuild": "node scripts/fix-bun-exports.mjs && node --check dist/cli.js && node --check dist/server.js && node --check dist/meridian-v2.js && node --check dist/meridian/index.js && node --check dist/meridian-v2/index.js && node -e \"if(!require('fs').existsSync('dist/proxy/server.d.ts'))process.exit(1)\"",
|
|
26
26
|
"postinstall": "node -e \"try{require('child_process').spawnSync(process.execPath,[require.resolve('@anthropic-ai/claude-code/install.cjs')],{stdio:'inherit'})}catch(e){console.error('[meridian] claude-code postinstall skipped:',e.message)}\"",
|
|
27
27
|
"prepublishOnly": "bun run build",
|
|
28
|
-
"test": "bun test --path-ignore-patterns '**/*session-store*' --path-ignore-patterns '**/*session-fingerprint-context*' --path-ignore-patterns '**/*priority-routing-integration*' --path-ignore-patterns '**/*proxy-async-ops*' --path-ignore-patterns '**/*models-auth-status*' --path-ignore-patterns '**/*proxy-context-usage-store*' --path-ignore-patterns '**/*proxy-passthrough-thinking*' --path-ignore-patterns '**/*proxy-thinking-setting*' --path-ignore-patterns '**/*session-recovery*' --path-ignore-patterns '**/*models.test*' --path-ignore-patterns '**/*proxy-health-build*' && bun test src/__tests__/proxy-async-ops.test.ts && bun test src/__tests__/proxy-session-store.test.ts && bun test src/__tests__/session-store-pruning.test.ts && bun test src/__tests__/proxy-session-store-locking.test.ts && bun test src/__tests__/session-fingerprint-context.test.ts && bun test src/__tests__/proxy-context-usage-store.test.ts && bun test src/__tests__/models-auth-status.test.ts && bun test src/__tests__/proxy-passthrough-thinking.test.ts && bun test src/__tests__/proxy-session-recovery.test.ts && bun test src/__tests__/proxy-thinking-setting.test.ts && bun test src/__tests__/models.test.ts && bun test src/__tests__/proxy-health-build.test.ts && bun test src/__tests__/priority-routing-integration.test.ts",
|
|
28
|
+
"test": "bun test --timeout 30000 --path-ignore-patterns '**/*session-store*' --path-ignore-patterns '**/*session-fingerprint-context*' --path-ignore-patterns '**/*priority-routing-integration*' --path-ignore-patterns '**/*proxy-async-ops*' --path-ignore-patterns '**/*models-auth-status*' --path-ignore-patterns '**/*proxy-context-usage-store*' --path-ignore-patterns '**/*proxy-passthrough-thinking*' --path-ignore-patterns '**/*proxy-thinking-setting*' --path-ignore-patterns '**/*session-recovery*' --path-ignore-patterns '**/*models.test*' --path-ignore-patterns '**/*proxy-health-build*' && bun test --timeout 30000 src/__tests__/proxy-async-ops.test.ts && bun test --timeout 30000 src/__tests__/proxy-session-store.test.ts && bun test --timeout 30000 src/__tests__/session-store-pruning.test.ts && bun test --timeout 30000 src/__tests__/proxy-session-store-locking.test.ts && bun test --timeout 30000 src/__tests__/session-fingerprint-context.test.ts && bun test --timeout 30000 src/__tests__/proxy-context-usage-store.test.ts && bun test --timeout 30000 src/__tests__/models-auth-status.test.ts && bun test --timeout 30000 src/__tests__/proxy-passthrough-thinking.test.ts && bun test --timeout 30000 src/__tests__/proxy-session-recovery.test.ts && bun test --timeout 30000 src/__tests__/proxy-thinking-setting.test.ts && bun test --timeout 30000 src/__tests__/models.test.ts && bun test --timeout 30000 src/__tests__/proxy-health-build.test.ts && bun test --timeout 30000 src/__tests__/priority-routing-integration.test.ts",
|
|
29
29
|
"nix:lock": "bun2nix -o bun.nix",
|
|
30
30
|
"typecheck": "tsc --noEmit",
|
|
31
31
|
"proxy:direct": "bun run ./bin/cli.ts"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../meridian.ts"
|
package/plugin/meridian-v2.ts
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import * as Plugin from "@opencode-ai/plugin/promise/plugin"
|
|
19
|
+
import { Model } from "@opencode-ai/schema/model"
|
|
20
|
+
import type { CatalogDraft } from "@opencode-ai/plugin/promise/catalog"
|
|
19
21
|
import {
|
|
20
22
|
PRIORITY_ATTESTATION_HEADER,
|
|
21
23
|
createPriorityAttestation,
|
|
@@ -29,8 +31,18 @@ import {
|
|
|
29
31
|
export const SUPPORTED_OPENCODE_V2_VERSION = "0.0.0-beta-18314"
|
|
30
32
|
|
|
31
33
|
const MERIDIAN_PROVIDERS = new Set(["anthropic", "meridian"])
|
|
34
|
+
const MERIDIAN_CATALOG_PROVIDER = "meridian"
|
|
32
35
|
const PARENT_SESSION_ONE_SHOTS = new Set(["title", "summary"])
|
|
33
36
|
const ATTACHED_COMPACTION_AGENT = "compaction"
|
|
37
|
+
const MODEL_DISCOVERY_TIMEOUT_MS = 3_000
|
|
38
|
+
const PROVIDER_READY_POLL_MS = 25
|
|
39
|
+
// The plugin tree does not import from src/, so this mirrors VALID_EFFORTS in
|
|
40
|
+
// src/proxy/effort.ts. A test asserts the two stay identical. Filtering in this
|
|
41
|
+
// order also gives every model its variants low -> max regardless of the order
|
|
42
|
+
// the proxy happens to serialise its capability object in.
|
|
43
|
+
const MERIDIAN_EFFORTS = ["low", "medium", "high", "xhigh", "max"] as const
|
|
44
|
+
|
|
45
|
+
export const MERIDIAN_V2_EFFORTS: readonly string[] = MERIDIAN_EFFORTS
|
|
34
46
|
|
|
35
47
|
const SESSION_AFFINITY_HEADERS = [
|
|
36
48
|
"x-opencode-session",
|
|
@@ -131,6 +143,186 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
131
143
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
132
144
|
}
|
|
133
145
|
|
|
146
|
+
export interface MeridianModel {
|
|
147
|
+
id: string
|
|
148
|
+
name: string
|
|
149
|
+
contextWindow: number
|
|
150
|
+
efforts: string[]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface MeridianProviderModels {
|
|
154
|
+
providerID: string
|
|
155
|
+
models: MeridianModel[]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
type MeridianCatalogClient = {
|
|
159
|
+
provider: {
|
|
160
|
+
get(input: { providerID: string }): Promise<unknown>
|
|
161
|
+
}
|
|
162
|
+
reload(): Promise<void>
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
type ModelFetcher = (input: string | URL | Request, init?: RequestInit) => Promise<Response>
|
|
166
|
+
|
|
167
|
+
export function meridianModelsURL(baseURL: unknown): string | undefined {
|
|
168
|
+
if (typeof baseURL !== "string" || baseURL.length === 0) return undefined
|
|
169
|
+
try {
|
|
170
|
+
const url = new URL(baseURL)
|
|
171
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return undefined
|
|
172
|
+
url.search = ""
|
|
173
|
+
url.hash = ""
|
|
174
|
+
if (!url.pathname.endsWith("/")) url.pathname += "/"
|
|
175
|
+
// OpenCode's Anthropic provider carries the API version in the base URL
|
|
176
|
+
// (`http://127.0.0.1:3456/v1`), which is also the shape the V2 package gate
|
|
177
|
+
// configures. Appending `v1/models` there requests `/v1/v1/models`, a 404
|
|
178
|
+
// that silently disables discovery, so resolve `models` against an existing
|
|
179
|
+
// version segment instead.
|
|
180
|
+
const endpoint = /(?:^|\/)v1\/$/.test(url.pathname) ? "models" : "v1/models"
|
|
181
|
+
return new URL(endpoint, url).toString()
|
|
182
|
+
} catch {
|
|
183
|
+
return undefined
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function parseMeridianModels(value: unknown): MeridianModel[] | undefined {
|
|
188
|
+
if (!isRecord(value) || !Array.isArray(value.data)) return undefined
|
|
189
|
+
|
|
190
|
+
const models: MeridianModel[] = []
|
|
191
|
+
const ids = new Set<string>()
|
|
192
|
+
for (const item of value.data) {
|
|
193
|
+
if (!isRecord(item)) return undefined
|
|
194
|
+
const id = item.id
|
|
195
|
+
const name = item.display_name
|
|
196
|
+
const contextWindow = item.context_window
|
|
197
|
+
if (
|
|
198
|
+
typeof id !== "string"
|
|
199
|
+
|| id.length === 0
|
|
200
|
+
|| id.length > 256
|
|
201
|
+
|| /[^\x21-\x7E]/.test(id)
|
|
202
|
+
|| ids.has(id)
|
|
203
|
+
|| typeof name !== "string"
|
|
204
|
+
|| name.trim().length === 0
|
|
205
|
+
|| name.length > 256
|
|
206
|
+
|| typeof contextWindow !== "number"
|
|
207
|
+
|| !Number.isSafeInteger(contextWindow)
|
|
208
|
+
|| contextWindow <= 0
|
|
209
|
+
) {
|
|
210
|
+
return undefined
|
|
211
|
+
}
|
|
212
|
+
const capabilities = isRecord(item.capabilities) ? item.capabilities : undefined
|
|
213
|
+
const effort = capabilities && isRecord(capabilities.effort) ? capabilities.effort : undefined
|
|
214
|
+
const efforts = MERIDIAN_EFFORTS.filter((level) => isRecord(effort?.[level]) && effort[level].supported === true)
|
|
215
|
+
ids.add(id)
|
|
216
|
+
models.push({ id, name, contextWindow, efforts })
|
|
217
|
+
}
|
|
218
|
+
return models
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function fetchMeridianModels(
|
|
222
|
+
baseURL: unknown,
|
|
223
|
+
signal: AbortSignal,
|
|
224
|
+
fetcher: ModelFetcher = globalThis.fetch,
|
|
225
|
+
): Promise<MeridianModel[] | undefined> {
|
|
226
|
+
const url = meridianModelsURL(baseURL)
|
|
227
|
+
if (!url || signal.aborted) return undefined
|
|
228
|
+
|
|
229
|
+
const controller = new AbortController()
|
|
230
|
+
const abort = () => controller.abort()
|
|
231
|
+
const timeout = setTimeout(abort, MODEL_DISCOVERY_TIMEOUT_MS)
|
|
232
|
+
timeout.unref?.()
|
|
233
|
+
signal.addEventListener("abort", abort, { once: true })
|
|
234
|
+
try {
|
|
235
|
+
const response = await fetcher(url, { signal: controller.signal })
|
|
236
|
+
if (!response.ok) return undefined
|
|
237
|
+
return parseMeridianModels(await response.json())
|
|
238
|
+
} catch {
|
|
239
|
+
return undefined
|
|
240
|
+
} finally {
|
|
241
|
+
clearTimeout(timeout)
|
|
242
|
+
signal.removeEventListener("abort", abort)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function meridianProviderBaseURL(value: unknown): unknown {
|
|
247
|
+
if (!isRecord(value)) return undefined
|
|
248
|
+
const provider = isRecord(value.data) ? value.data : value
|
|
249
|
+
if (!isRecord(provider.settings)) return undefined
|
|
250
|
+
return provider.settings.baseURL
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function isLegacyMeridianBaseURL(baseURL: unknown): boolean {
|
|
254
|
+
if (typeof baseURL !== "string") return false
|
|
255
|
+
try {
|
|
256
|
+
const { hostname } = new URL(baseURL)
|
|
257
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]"
|
|
258
|
+
} catch {
|
|
259
|
+
return false
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export async function loadMeridianModels(
|
|
264
|
+
catalog: MeridianCatalogClient,
|
|
265
|
+
signal: AbortSignal,
|
|
266
|
+
fetcher: ModelFetcher = globalThis.fetch,
|
|
267
|
+
): Promise<MeridianProviderModels[]> {
|
|
268
|
+
const deadline = Date.now() + MODEL_DISCOVERY_TIMEOUT_MS
|
|
269
|
+
while (!signal.aborted) {
|
|
270
|
+
const providers = await Promise.all([...MERIDIAN_PROVIDERS].map(async (providerID) => {
|
|
271
|
+
try {
|
|
272
|
+
const baseURL = meridianProviderBaseURL(await catalog.provider.get({ providerID }))
|
|
273
|
+
if (providerID === MERIDIAN_CATALOG_PROVIDER && meridianModelsURL(baseURL) === undefined) return undefined
|
|
274
|
+
if (providerID !== MERIDIAN_CATALOG_PROVIDER && !isLegacyMeridianBaseURL(baseURL)) return undefined
|
|
275
|
+
return { providerID, baseURL }
|
|
276
|
+
} catch {
|
|
277
|
+
return undefined
|
|
278
|
+
}
|
|
279
|
+
}))
|
|
280
|
+
const configured = providers.flatMap(provider => provider ? [provider] : [])
|
|
281
|
+
if (configured.length > 0) {
|
|
282
|
+
const discovered = await Promise.all(configured.map(async ({ providerID, baseURL }) => {
|
|
283
|
+
const models = await fetchMeridianModels(baseURL, signal, fetcher)
|
|
284
|
+
return models ? { providerID, models } : undefined
|
|
285
|
+
}))
|
|
286
|
+
return discovered.flatMap(result => result ? [result] : [])
|
|
287
|
+
}
|
|
288
|
+
if (Date.now() >= deadline) return []
|
|
289
|
+
await new Promise<void>((resolve) => setTimeout(resolve, PROVIDER_READY_POLL_MS))
|
|
290
|
+
}
|
|
291
|
+
return []
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Write Meridian's advertised models over the assembled V2 catalog.
|
|
296
|
+
*
|
|
297
|
+
* Meridian is authoritative for what it will actually serve: the context window
|
|
298
|
+
* follows the signed-in subscription (Sonnet stays 200k so a 1M turn is not
|
|
299
|
+
* billed as Extra Usage), and the effort levels are the ones the proxy accepts.
|
|
300
|
+
* OpenCode's built-in models.dev entries disagree — beta-18866 advertises a 1M
|
|
301
|
+
* Sonnet — so an entry that already exists must be corrected, not skipped.
|
|
302
|
+
*
|
|
303
|
+
* This does not overwrite user configuration. V2 layers `providers.<id>.models`
|
|
304
|
+
* on top of plugin transforms, verified live on beta-18866: a configured
|
|
305
|
+
* `claude-opus-5` override survived a transform that wrote a different name and
|
|
306
|
+
* context to the same model.
|
|
307
|
+
*/
|
|
308
|
+
export function applyMeridianModels(
|
|
309
|
+
catalog: CatalogDraft,
|
|
310
|
+
providerID: string,
|
|
311
|
+
models: readonly MeridianModel[],
|
|
312
|
+
): void {
|
|
313
|
+
for (const model of models) {
|
|
314
|
+
catalog.model.update(providerID, model.id, (entry) => {
|
|
315
|
+
entry.name = model.name
|
|
316
|
+
entry.limit.context = model.contextWindow
|
|
317
|
+
entry.variants = model.efforts.map((effort) => ({
|
|
318
|
+
id: Model.VariantID.make(effort),
|
|
319
|
+
headers: {},
|
|
320
|
+
body: { effort },
|
|
321
|
+
}))
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
134
326
|
async function withTimeout<T>(pending: Promise<T>, timeoutMs: number): Promise<T | undefined> {
|
|
135
327
|
let timer: ReturnType<typeof setTimeout> | undefined
|
|
136
328
|
const timedOut = new Promise<undefined>((resolve) => {
|
|
@@ -196,6 +388,33 @@ const MeridianV2Plugin = Plugin.define({
|
|
|
196
388
|
pending: Promise<ResolvedAgentMetadata>
|
|
197
389
|
}>()
|
|
198
390
|
const registered: Array<{ dispose: () => Promise<void> }> = []
|
|
391
|
+
const modelDiscoveryController = new AbortController()
|
|
392
|
+
let discoveredModels: MeridianProviderModels[] = []
|
|
393
|
+
let discoveryStarted = false
|
|
394
|
+
|
|
395
|
+
registered.push(await context.catalog.transform((catalog) => {
|
|
396
|
+
for (const discovered of discoveredModels) {
|
|
397
|
+
applyMeridianModels(catalog, discovered.providerID, discovered.models)
|
|
398
|
+
}
|
|
399
|
+
}))
|
|
400
|
+
|
|
401
|
+
const discoverModels = async () => {
|
|
402
|
+
if (discoveryStarted || modelDiscoveryController.signal.aborted) return false
|
|
403
|
+
const models = await loadMeridianModels(context.catalog, modelDiscoveryController.signal).catch(() => [])
|
|
404
|
+
if (models.length === 0 || modelDiscoveryController.signal.aborted) return false
|
|
405
|
+
discoveryStarted = true
|
|
406
|
+
discoveredModels = models
|
|
407
|
+
await context.catalog.reload()
|
|
408
|
+
return true
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const catalogEvents = context.event.subscribe({ signal: modelDiscoveryController.signal })
|
|
412
|
+
void (async () => {
|
|
413
|
+
for await (const event of catalogEvents) {
|
|
414
|
+
if (event.type !== "catalog.updated") continue
|
|
415
|
+
if (await discoverModels()) return
|
|
416
|
+
}
|
|
417
|
+
})().catch(() => {})
|
|
199
418
|
|
|
200
419
|
const resolveAgentTraits = (agent: string, refresh = false): Promise<ResolvedAgentMetadata> => {
|
|
201
420
|
const cached = traitsByAgent.get(agent)
|
|
@@ -320,11 +539,15 @@ const MeridianV2Plugin = Plugin.define({
|
|
|
320
539
|
}, { providerID }))
|
|
321
540
|
}
|
|
322
541
|
} catch (error) {
|
|
542
|
+
// Setup never returns its cleanup on this path, so the discovery
|
|
543
|
+
// subscription and its poll loop would otherwise outlive the failure.
|
|
544
|
+
modelDiscoveryController.abort()
|
|
323
545
|
await Promise.allSettled(registered.map(({ dispose }) => dispose()))
|
|
324
546
|
throw error
|
|
325
547
|
}
|
|
326
548
|
|
|
327
549
|
return async () => {
|
|
550
|
+
modelDiscoveryController.abort()
|
|
328
551
|
const results = await Promise.allSettled(registered.map(({ dispose }) => dispose()))
|
|
329
552
|
const failures = results.flatMap(result => result.status === "rejected" ? [result.reason] : [])
|
|
330
553
|
if (failures.length > 0) throw new AggregateError(failures, "Failed to dispose Meridian V2 hooks")
|