@rynfar/meridian 1.64.0 → 1.65.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.
@@ -51,9 +51,37 @@ export interface StoredSession {
51
51
  previousTranscript?: TranscriptLocator;
52
52
  }
53
53
  export type StoredSessionGeneration = string;
54
+ export interface DurablePriorityAssignment {
55
+ profileId: string;
56
+ lastHumanTurnDigest: string;
57
+ /** Monotonic signed issue-time high-water mark for replay suppression. */
58
+ lastHumanTurnIssuedAt: number;
59
+ mappingKey: string;
60
+ /** Exact mapping generation published atomically with this route. */
61
+ mappingGeneration: StoredSessionGeneration;
62
+ /** Unique route publication token. Replaced on every route mutation. */
63
+ generationId: string;
64
+ updatedAt: number;
65
+ }
66
+ export type PriorityAssignmentGeneration = string;
67
+ export interface DurablePriorityAttempt {
68
+ /** A prior exposed or crashed attempt blocks untrusted/same-turn replay. */
69
+ blocked: boolean;
70
+ blockedTurnDigest: string | null;
71
+ blockedTurnIssuedAt: number | null;
72
+ /** One exact in-flight request owns publication/release for this route. */
73
+ pendingTurnDigest: string | null;
74
+ pendingTurnIssuedAt: number | null;
75
+ ownerToken: string | null;
76
+ generationId: string;
77
+ updatedAt: number;
78
+ }
54
79
  /** Exact, key-bound durable generation used for compare-and-swap fencing. */
55
80
  export declare function getStoredSessionGeneration(session: StoredSession, key: string): StoredSessionGeneration;
81
+ export declare function getPriorityAssignmentGeneration(assignment: DurablePriorityAssignment, routeKey: string): PriorityAssignmentGeneration;
56
82
  export declare function getMaxStoredSessionsLimit(): number;
83
+ export declare function getMaxPriorityAssignmentsLimit(): number;
84
+ export declare function getMaxPriorityAttemptsLimit(): number;
57
85
  /** Set an explicit session store directory. Takes priority over env var.
58
86
  * Pass null to clear. For testing only. The legacy options parameter remains
59
87
  * accepted for compatibility, but transactions are always locked. */
@@ -82,9 +110,114 @@ export type SharedSessionLookupResult = {
82
110
  /** Distinguish an authoritative absence from a transient/corrupt read. */
83
111
  export declare function lookupSharedSessionResult(key: string): SharedSessionLookupResult;
84
112
  export declare function lookupSharedSession(key: string): StoredSession | undefined;
113
+ export type PriorityAssignmentLookupResult = {
114
+ status: "found";
115
+ assignment: DurablePriorityAssignment;
116
+ generation: PriorityAssignmentGeneration;
117
+ attempt?: DurablePriorityAttempt;
118
+ } | {
119
+ status: "missing";
120
+ generation: PriorityAssignmentGeneration;
121
+ attempt?: DurablePriorityAttempt;
122
+ } | {
123
+ status: "error";
124
+ error: Error;
125
+ };
126
+ /** Read one exact durable route. V1 documents authoritatively contain none. */
127
+ export declare function lookupPriorityAssignmentResult(routeKey: string): PriorityAssignmentLookupResult;
85
128
  export declare function lookupSharedSessionByClaudeIdResult(claudeSessionId: string): SharedSessionLookupResult;
86
129
  export declare function lookupSharedSessionByClaudeId(claudeSessionId: string): StoredSession | undefined;
87
130
  export declare function storeSharedSession(key: string, claudeSessionId: string, messageCount?: number, lineageHash?: string, messageHashes?: string[], sdkMessageUuids?: Array<string | null>, contextUsage?: TokenUsage, messageBlockHashes?: string[][], passthroughToolCallAssistantUuid?: string | null, passthroughToolCallIds?: string[] | null, currentTranscript?: TranscriptLocator, sourceTranscript?: TranscriptLocator, expectedGeneration?: StoredSessionGeneration | null): StoredSessionGeneration | false;
131
+ export interface PriorityAttemptTurn {
132
+ turnId: string;
133
+ issuedAt: number;
134
+ }
135
+ export interface PriorityAttemptClaim {
136
+ ownerToken: string;
137
+ }
138
+ /**
139
+ * Reserve one durable route attempt before any SDK work can become exposed.
140
+ * A blocked/crashed attempt can be superseded only by a strictly newer trusted
141
+ * human turn. The prior blocker remains until the newer turn publishes.
142
+ */
143
+ export declare function claimPriorityAttempt(options: {
144
+ routeKey: string;
145
+ expectedAssignmentGeneration: PriorityAssignmentGeneration;
146
+ turn?: PriorityAttemptTurn;
147
+ }): PriorityAttemptClaim | false;
148
+ /** Release an unexposed attempt; an older blocker remains intact. */
149
+ export declare function releasePriorityAttempt(routeKey: string, ownerToken: string): boolean;
150
+ /** Persist exposure before returning an account-shaped error or cancellation. */
151
+ export declare function blockPriorityAttempt(routeKey: string, ownerToken: string): boolean;
152
+ export interface SharedSessionPriorityPublication {
153
+ routeKey: string;
154
+ profileId: string;
155
+ lastHumanTurnDigest: string;
156
+ lastHumanTurnIssuedAt: number;
157
+ expectedAssignmentGeneration: PriorityAssignmentGeneration;
158
+ }
159
+ export interface SharedSessionAndPriorityAssignmentOptions {
160
+ key: string;
161
+ claudeSessionId: string;
162
+ messageCount: number;
163
+ lineageHash: string;
164
+ messageHashes: string[];
165
+ sdkMessageUuids?: Array<string | null>;
166
+ contextUsage?: TokenUsage;
167
+ messageBlockHashes: string[][];
168
+ passthroughToolCallAssistantUuid?: string | null;
169
+ passthroughToolCallIds?: string[] | null;
170
+ currentTranscript?: TranscriptLocator;
171
+ sourceTranscript?: TranscriptLocator;
172
+ expectedMappingGeneration: StoredSessionGeneration;
173
+ /** Original routed mapping retained across chained publications for rollback. */
174
+ rollbackMappingKey?: string;
175
+ /** Exact pre-SDK durable claim cleared only by this winning publication. */
176
+ attemptOwnerToken?: string;
177
+ priority: SharedSessionPriorityPublication;
178
+ }
179
+ export interface SharedSessionAndPriorityAssignmentResult {
180
+ mappingGeneration: StoredSessionGeneration;
181
+ assignmentGeneration: PriorityAssignmentGeneration;
182
+ previousMapping: StoredSession | null;
183
+ previousAssignment: DurablePriorityAssignment | null;
184
+ }
185
+ /**
186
+ * Publish one session mapping and its selected priority route as one locked,
187
+ * durable compare-and-swap. A v1 document upgrades only when this transaction
188
+ * wins; all ordinary mapping writes preserve either input version.
189
+ */
190
+ export declare function storeSharedSessionAndPriorityAssignment(options: SharedSessionAndPriorityAssignmentOptions): SharedSessionAndPriorityAssignmentResult | false;
191
+ export interface FinalizeSharedSessionAndPriorityAssignmentOptions {
192
+ key: string;
193
+ routeKey: string;
194
+ expectedMappingGeneration: StoredSessionGeneration;
195
+ expectedAssignmentGeneration: PriorityAssignmentGeneration;
196
+ rollbackMappingKey?: string;
197
+ attemptOwnerToken?: string;
198
+ }
199
+ /**
200
+ * Make a successful publication irrevocable and prune its rollback backlog.
201
+ * Exact route+mapping CAS prevents a late finalizer from touching newer work.
202
+ */
203
+ export declare function finalizeSharedSessionAndPriorityAssignment(options: FinalizeSharedSessionAndPriorityAssignmentOptions): boolean;
204
+ export interface RollbackSharedSessionAndPriorityAssignmentOptions {
205
+ key: string;
206
+ routeKey: string;
207
+ expectedMappingGeneration: StoredSessionGeneration;
208
+ expectedAssignmentGeneration: PriorityAssignmentGeneration;
209
+ previousMapping: StoredSession | null;
210
+ previousAssignment: DurablePriorityAssignment | null;
211
+ attemptOwnerToken?: string;
212
+ }
213
+ export interface RollbackSharedSessionAndPriorityAssignmentResult {
214
+ mappingGeneration: StoredSessionGeneration;
215
+ assignmentGeneration: PriorityAssignmentGeneration;
216
+ restoredMapping: StoredSession | null;
217
+ restoredAssignment: DurablePriorityAssignment | null;
218
+ }
219
+ /** Restore the exact pre-request authorities after a canceled late publication. */
220
+ export declare function rollbackSharedSessionAndPriorityAssignment(options: RollbackSharedSessionAndPriorityAssignmentOptions): RollbackSharedSessionAndPriorityAssignmentResult | false;
88
221
  /** Attach an exact transcript locator without changing lineage or SDK identity.
89
222
  * The durable revision advances so concurrent readers cannot miss the mutation. */
90
223
  export declare function attachSharedTranscriptLocator(key: string, expectedClaudeSessionId: string, locator: TranscriptLocator, expectedGeneration?: StoredSessionGeneration): StoredSessionGeneration | false;
@@ -1 +1 @@
1
- {"version":3,"file":"sessionStore.d.ts","sourceRoot":"","sources":["../../src/proxy/sessionStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionStore.d.ts","sourceRoot":"","sources":["../../src/proxy/sessionStore.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@
7
7
  *
8
8
  * This is a leaf module — no imports from server.ts or session/.
9
9
  */
10
+ import type { PriorityFailbackPolicy } from "./routing";
10
11
  export interface MeridianSettings {
11
12
  /** Last active profile ID — restored on proxy startup */
12
13
  activeProfile?: string;
@@ -16,6 +17,7 @@ export interface MeridianSettings {
16
17
  /** Priority-mode pool order (highest priority first). Falls back to
17
18
  * profiles.json order. MERIDIAN_PROFILE_ORDER env var takes precedence. */
18
19
  profileOrder?: string[];
20
+ priorityFailback?: PriorityFailbackPolicy;
19
21
  }
20
22
  /** Read settings from disk. Returns empty object if file doesn't exist or is invalid. */
21
23
  export declare function loadSettings(): MeridianSettings;
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/proxy/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;8EAC0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;gFAC4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACxB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,IAAI,gBAAgB,CAQ/C;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAUrE;AAED,iCAAiC;AACjC,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,GAAG,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAExF;AAED,6CAA6C;AAC7C,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI,CAErG"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/proxy/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAqBvD,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;8EAC0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;gFAC4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;CAC1C;AAED,yFAAyF;AACzF,wBAAgB,YAAY,IAAI,gBAAgB,CAQ/C;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAUrE;AAED,iCAAiC;AACjC,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,GAAG,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAExF;AAED,6CAA6C;AAC7C,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI,CAErG"}
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH;;;;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;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;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,6BAA6B,qBAAqB,CAAA;AAE/D,6EAA6E;AAC7E,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;AA4BD;;;;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,CA2Eb"}
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;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;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,6BAA6B,qBAAqB,CAAA;AAE/D,6EAA6E;AAC7E,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;AA4BD;;;;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"}
package/dist/server.js CHANGED
@@ -11,14 +11,14 @@ import {
11
11
  runObserveHook,
12
12
  runTransformHook,
13
13
  startProxyServer
14
- } from "./cli-4ghkaajs.js";
15
- import"./cli-m0p2bc8v.js";
14
+ } from "./cli-7cts44b5.js";
15
+ import"./cli-pdpry6q0.js";
16
16
  import"./cli-sry5aqdj.js";
17
17
  import"./cli-8yp89fan.js";
18
18
  import"./cli-0ed6j0vk.js";
19
19
  import"./cli-khhjyk04.js";
20
20
  import"./cli-vj9cv18n.js";
21
- import"./cli-pbvm9kc2.js";
21
+ import"./cli-n8t34zmq.js";
22
22
  import"./cli-p9swy5t3.js";
23
23
  export {
24
24
  startProxyServer,
@@ -13,7 +13,7 @@ import {
13
13
  notePluginlessOpenCodeRequest,
14
14
  pluginPathForGeneration,
15
15
  runSetup
16
- } from "./cli-pbvm9kc2.js";
16
+ } from "./cli-n8t34zmq.js";
17
17
  import"./cli-p9swy5t3.js";
18
18
  export {
19
19
  runSetup,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynfar/meridian",
3
- "version": "1.64.0",
3
+ "version": "1.65.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",
@@ -25,7 +25,7 @@
25
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 -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 '**/*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__/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",
28
+ "test": "bun test --path-ignore-patterns '**/*session-store*' --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__/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",
29
29
  "nix:lock": "bun2nix -o bun.nix",
30
30
  "typecheck": "tsc --noEmit",
31
31
  "proxy:direct": "bun run ./bin/cli.ts"
@@ -16,6 +16,14 @@
16
16
  */
17
17
 
18
18
  import * as Plugin from "@opencode-ai/plugin/promise/plugin"
19
+ import {
20
+ PRIORITY_ATTESTATION_HEADER,
21
+ createPriorityAttestation,
22
+ deleteHeader,
23
+ getHeader,
24
+ setHeader,
25
+ type MutableHeaders,
26
+ } from "./priority-attestation"
19
27
 
20
28
  /** Exact V2 host used to compile and validate this beta-only integration. */
21
29
  export const SUPPORTED_OPENCODE_V2_VERSION = "0.0.0-beta-18314"
@@ -35,6 +43,7 @@ const MERIDIAN_CONTROL_HEADERS = [
35
43
  "x-meridian-source",
36
44
  "x-opencode-agent-name",
37
45
  "x-opencode-agent-mode",
46
+ PRIORITY_ATTESTATION_HEADER,
38
47
  ] as const
39
48
 
40
49
  export interface AgentTraits {
@@ -57,25 +66,6 @@ export function fallbackAgentTraits(agent: string): AgentTraits {
57
66
  return BUILTIN_AGENT_TRAITS[agent] ?? { mode: "primary", hidden: false }
58
67
  }
59
68
 
60
- type MutableHeaders = Record<string, string> | Headers
61
-
62
- function deleteHeader(headers: MutableHeaders, name: string): void {
63
- if (headers instanceof Headers) {
64
- headers.delete(name)
65
- return
66
- }
67
- const lower = name.toLowerCase()
68
- for (const key of Object.keys(headers)) {
69
- if (key.toLowerCase() === lower) delete headers[key]
70
- }
71
- }
72
-
73
- function setHeader(headers: MutableHeaders, name: string, value: string): void {
74
- deleteHeader(headers, name)
75
- if (headers instanceof Headers) headers.set(name, value)
76
- else headers[name] = value
77
- }
78
-
79
69
  function safeAgentName(agent: string): string {
80
70
  return agent.replace(/[^\x20-\x7E]/g, "").trim() || "unknown"
81
71
  }
@@ -123,55 +113,210 @@ export function applyMeridianV2Headers(
123
113
  setHeader(headers, "x-opencode-agent-mode", internalMode)
124
114
  }
125
115
 
116
+ const INTERNAL_ROUTING_AGENT_IDS = new Set(["title", "summary", "compaction"])
117
+ const AGENT_CACHE_MAX = 256
118
+ const AGENT_CACHE_TTL_MS = 5_000
119
+ const LOOKUP_TIMEOUT_MS = 250
120
+ const MAX_CONTEXT_ENTRIES = 2_048
121
+ const SAFE_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/
122
+
123
+ type ExactAgentMode = "primary" | "subagent" | "all"
124
+ type ResolvedAgentMetadata = {
125
+ readonly traits: AgentTraits
126
+ readonly exactMode: ExactAgentMode | undefined
127
+ readonly authoritative: boolean
128
+ }
129
+
130
+ function isRecord(value: unknown): value is Record<string, unknown> {
131
+ return typeof value === "object" && value !== null && !Array.isArray(value)
132
+ }
133
+
134
+ async function withTimeout<T>(pending: Promise<T>, timeoutMs: number): Promise<T | undefined> {
135
+ let timer: ReturnType<typeof setTimeout> | undefined
136
+ const timedOut = new Promise<undefined>((resolve) => {
137
+ timer = setTimeout(() => resolve(undefined), timeoutMs)
138
+ timer.unref?.()
139
+ })
140
+ try {
141
+ return await Promise.race([pending, timedOut])
142
+ } finally {
143
+ if (timer) clearTimeout(timer)
144
+ }
145
+ }
146
+
147
+ export function isRootV2Session(value: unknown, sessionID: string): boolean {
148
+ return isRecord(value)
149
+ && value.id === sessionID
150
+ && value.parentID === undefined
151
+ && value.fork === undefined
152
+ }
153
+
154
+ /**
155
+ * Find the exact host message ID that initiated the active model loop.
156
+ * Assistant/tool steps and selection records belong to the current loop and
157
+ * are skipped. A synthetic/compaction/shell/skill/system or unknown initiator
158
+ * fails closed instead of reusing an older human ID.
159
+ */
160
+ type V2HumanTurn = { readonly id: string; readonly issuedAt: number }
161
+
162
+ export function findLatestV2HumanTurn(value: unknown): V2HumanTurn | undefined {
163
+ if (!Array.isArray(value) || value.length === 0 || value.length > MAX_CONTEXT_ENTRIES) return undefined
164
+ for (let index = value.length - 1; index >= 0; index -= 1) {
165
+ const message = value[index]
166
+ if (!isRecord(message) || typeof message.type !== "string") return undefined
167
+ if (
168
+ message.type === "assistant"
169
+ || message.type === "agent-switched"
170
+ || message.type === "model-switched"
171
+ || message.type === "location-switched"
172
+ ) {
173
+ continue
174
+ }
175
+ if (message.type !== "user" || typeof message.id !== "string" || !SAFE_ID_PATTERN.test(message.id)) {
176
+ return undefined
177
+ }
178
+ const time = isRecord(message.time) ? message.time : undefined
179
+ const createdAt = time?.created
180
+ if (typeof createdAt !== "number" || !Number.isSafeInteger(createdAt) || createdAt < 0) return undefined
181
+ return { id: message.id, issuedAt: Math.floor(createdAt / 1000) }
182
+ }
183
+ return undefined
184
+ }
185
+
186
+ export function findLatestV2HumanMessageId(value: unknown): string | undefined {
187
+ return findLatestV2HumanTurn(value)?.id
188
+ }
189
+
126
190
  const MeridianV2Plugin = Plugin.define({
127
191
  id: "meridian",
128
192
  setup: async (context) => {
129
193
  const traitsByAgent = new Map<string, {
130
194
  expiresAt: number
131
- pending: Promise<AgentTraits>
195
+ request: symbol
196
+ pending: Promise<ResolvedAgentMetadata>
132
197
  }>()
133
198
  const registered: Array<{ dispose: () => Promise<void> }> = []
134
199
 
135
- const resolveAgentTraits = (agent: string): Promise<AgentTraits> => {
200
+ const resolveAgentTraits = (agent: string, refresh = false): Promise<ResolvedAgentMetadata> => {
136
201
  const cached = traitsByAgent.get(agent)
137
- if (cached && cached.expiresAt > Date.now()) return cached.pending
138
-
139
- const pending = Promise.resolve()
140
- .then(() => context.agent.get({ agentID: agent }))
141
- .then(({ data }) => ({
142
- mode: data.mode === "subagent" ? "subagent" as const : "primary" as const,
143
- hidden: data.hidden,
144
- }))
145
- .catch(() => {
146
- // A transient lookup failure must not permanently promote a custom
147
- // child to primary. Retry at the final HTTP boundary or next turn.
148
- if (traitsByAgent.get(agent)?.pending === pending) traitsByAgent.delete(agent)
149
- return fallbackAgentTraits(agent)
150
- })
151
- traitsByAgent.set(agent, { expiresAt: Date.now() + 5_000, pending })
202
+ if (!refresh && cached && cached.expiresAt > Date.now()) return cached.pending
203
+ if (refresh) traitsByAgent.delete(agent)
204
+
205
+ const request = Symbol(agent)
206
+ const pending = (async (): Promise<ResolvedAgentMetadata> => {
207
+ const controller = new AbortController()
208
+ try {
209
+ const result = await withTimeout(
210
+ context.agent.get({ agentID: agent }, { signal: controller.signal }),
211
+ LOOKUP_TIMEOUT_MS,
212
+ )
213
+ const data = result?.data
214
+ if (
215
+ !data
216
+ || (data.mode !== "primary" && data.mode !== "subagent" && data.mode !== "all")
217
+ || typeof data.hidden !== "boolean"
218
+ ) {
219
+ if (traitsByAgent.get(agent)?.request === request) traitsByAgent.delete(agent)
220
+ return { traits: fallbackAgentTraits(agent), exactMode: undefined, authoritative: false }
221
+ }
222
+ return {
223
+ traits: {
224
+ mode: data.mode === "subagent" ? "subagent" : "primary",
225
+ hidden: data.hidden,
226
+ },
227
+ exactMode: data.mode,
228
+ authoritative: true,
229
+ }
230
+ } catch {
231
+ // Retry a transient failure at the final HTTP boundary or next turn.
232
+ if (traitsByAgent.get(agent)?.request === request) traitsByAgent.delete(agent)
233
+ return { traits: fallbackAgentTraits(agent), exactMode: undefined, authoritative: false }
234
+ } finally {
235
+ controller.abort()
236
+ }
237
+ })()
238
+ traitsByAgent.delete(agent)
239
+ traitsByAgent.set(agent, { request, expiresAt: Date.now() + AGENT_CACHE_TTL_MS, pending })
240
+ while (traitsByAgent.size > AGENT_CACHE_MAX) {
241
+ const oldest = traitsByAgent.keys().next().value
242
+ if (oldest === undefined) break
243
+ traitsByAgent.delete(oldest)
244
+ }
152
245
  return pending
153
246
  }
154
247
 
155
248
  const apply = async (
156
249
  input: { sessionID: string; agent: string; model: { providerID: string } },
157
250
  headers: MutableHeaders,
158
- ): Promise<void> => {
159
- if (!MERIDIAN_PROVIDERS.has(String(input.model.providerID))) return
251
+ refreshTraits = false,
252
+ ): Promise<ResolvedAgentMetadata | undefined> => {
253
+ if (!MERIDIAN_PROVIDERS.has(String(input.model.providerID))) return undefined
160
254
  const agent = String(input.agent)
255
+ const metadata = await resolveAgentTraits(agent, refreshTraits)
161
256
  applyMeridianV2Headers(headers, {
162
257
  sessionID: String(input.sessionID),
163
258
  agent,
164
- traits: await resolveAgentTraits(agent),
259
+ traits: metadata.traits,
165
260
  })
261
+ return metadata
262
+ }
263
+
264
+ const resolveHumanTurn = async (
265
+ input: { sessionID: string; agent: string },
266
+ headers: MutableHeaders,
267
+ metadata: ResolvedAgentMetadata,
268
+ ): Promise<V2HumanTurn | undefined> => {
269
+ const sessionID = String(input.sessionID)
270
+ const agent = String(input.agent)
271
+ if (
272
+ !metadata.authoritative
273
+ || metadata.exactMode !== "primary"
274
+ || metadata.traits.hidden
275
+ || INTERNAL_ROUTING_AGENT_IDS.has(agent)
276
+ || safeAgentName(agent) !== agent
277
+ || getHeader(headers, "x-meridian-profile") !== undefined
278
+ ) {
279
+ return undefined
280
+ }
281
+
282
+ const controller = new AbortController()
283
+ try {
284
+ const result = await withTimeout(Promise.all([
285
+ context.session.get({ sessionID }, { signal: controller.signal }),
286
+ context.session.context({ sessionID }, { signal: controller.signal }),
287
+ ]), LOOKUP_TIMEOUT_MS)
288
+ if (!result || !isRootV2Session(result[0], sessionID)) return undefined
289
+ return findLatestV2HumanTurn(result[1])
290
+ } catch {
291
+ return undefined
292
+ } finally {
293
+ controller.abort()
294
+ }
166
295
  }
167
296
 
168
297
  try {
169
298
  for (const providerID of MERIDIAN_PROVIDERS) {
170
299
  registered.push(await context.session.hook("model.request", async (input) => {
300
+ // Apply lineage/tier identity early, but never emit the routing
301
+ // attestation before the final HTTP boundary.
171
302
  await apply(input, input.headers)
172
303
  }, { providerID }))
173
304
  registered.push(await context.session.hook("http.request", async (input) => {
174
- await apply(input, input.request.headers)
305
+ // Re-read exact visibility/mode at the final boundary. The model-hook
306
+ // cache is capability-only and must never authorize a stale visible
307
+ // primary after a config reload.
308
+ const metadata = await apply(input, input.request.headers, true)
309
+ if (!metadata) return
310
+ const humanTurn = await resolveHumanTurn(input, input.request.headers, metadata)
311
+ if (!humanTurn) return
312
+ const token = createPriorityAttestation({
313
+ generation: "oc2b18314",
314
+ sessionId: String(input.sessionID),
315
+ agentId: String(input.agent),
316
+ humanMessageId: humanTurn.id,
317
+ issuedAt: humanTurn.issuedAt,
318
+ })
319
+ if (token) setHeader(input.request.headers, PRIORITY_ATTESTATION_HEADER, token)
175
320
  }, { providerID }))
176
321
  }
177
322
  } catch (error) {