@rynfar/meridian 1.71.1 → 1.73.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 +115 -162
- package/assets/desktop-dashboard.jpg +0 -0
- package/assets/trayTemplate.png +0 -0
- package/assets/trayTemplate@2x.png +0 -0
- package/assets/trayTemplate@3x.png +0 -0
- package/dist/cli-1jstkdj9.js +30 -0
- package/dist/{cli-9e5cxp89.js → cli-2h3w5n6g.js} +163 -65
- package/dist/cli-3zwfvexc.js +56 -0
- package/dist/{cli-hxxy0m1z.js → cli-82e2m44k.js} +2 -1
- package/dist/cli-8sw5wr9j.js +136 -0
- package/dist/{cli-khhjyk04.js → cli-chsp880k.js} +214 -21
- package/dist/cli-dh0a1bw4.js +619 -0
- package/dist/cli-eehk3052.js +57 -0
- package/dist/cli-grfp0s1j.js +330 -0
- package/dist/{cli-ryt69ryf.js → cli-p5zbk952.js} +2185 -358
- package/dist/{cli-8yp89fan.js → cli-p9ca4p13.js} +17 -2
- package/dist/cli-qpfky8wy.js +133 -0
- package/dist/cli.js +47 -12
- package/dist/cliDashboard-c0dvkj4y.js +325 -0
- package/dist/configDir.d.ts +30 -0
- package/dist/configDir.d.ts.map +1 -0
- package/dist/organizationName-90f0atkn.js +29 -0
- package/dist/{pluginPage-n3gdtbmj.js → pluginPage-3kxsrdpj.js} +1 -1
- package/dist/{profileCli-1eecbmgk.js → profileCli-1bfgc05h.js} +13 -3
- package/dist/{profilePage-vfj2dbhn.js → profilePage-etxqg3vn.js} +252 -60
- package/dist/profileRename-4a4km6g8.js +22 -0
- package/dist/{profiles-wch9h234.js → profiles-0mp32ek9.js} +16 -3
- package/dist/proxy/adapterInstances.d.ts +1 -1
- package/dist/proxy/adapterInstances.d.ts.map +1 -1
- package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
- package/dist/proxy/adapters/droid.d.ts.map +1 -1
- package/dist/proxy/authDiscovery.d.ts +52 -0
- package/dist/proxy/authDiscovery.d.ts.map +1 -0
- package/dist/proxy/credentialsMode.d.ts +77 -0
- package/dist/proxy/credentialsMode.d.ts.map +1 -0
- package/dist/proxy/design.d.ts.map +1 -1
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/followActive.d.ts +262 -0
- package/dist/proxy/followActive.d.ts.map +1 -0
- package/dist/proxy/limitDetection.d.ts +110 -0
- package/dist/proxy/limitDetection.d.ts.map +1 -0
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/oauthPlan.d.ts +63 -0
- package/dist/proxy/oauthPlan.d.ts.map +1 -0
- package/dist/proxy/oauthUsage.d.ts +65 -2
- package/dist/proxy/oauthUsage.d.ts.map +1 -1
- package/dist/proxy/openai.d.ts +4 -2
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/organizationName.d.ts +71 -0
- package/dist/proxy/organizationName.d.ts.map +1 -0
- package/dist/proxy/passthroughEarlyStop.d.ts +10 -0
- package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
- package/dist/proxy/planAllowance.d.ts +75 -0
- package/dist/proxy/planAllowance.d.ts.map +1 -0
- package/dist/proxy/probes.d.ts +85 -0
- package/dist/proxy/probes.d.ts.map +1 -0
- package/dist/proxy/profileCli.d.ts +53 -1
- package/dist/proxy/profileCli.d.ts.map +1 -1
- package/dist/proxy/profileHealth.d.ts +127 -0
- package/dist/proxy/profileHealth.d.ts.map +1 -0
- package/dist/proxy/profileRename.d.ts +83 -0
- package/dist/proxy/profileRename.d.ts.map +1 -0
- package/dist/proxy/profiles.d.ts +72 -6
- package/dist/proxy/profiles.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +7 -0
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/routing.d.ts +59 -1
- package/dist/proxy/routing.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts +1 -1
- package/dist/proxy/sdkFeatures.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/fingerprint.d.ts +5 -0
- package/dist/proxy/session/fingerprint.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/session/processIncarnation.d.ts +7 -0
- package/dist/proxy/session/processIncarnation.d.ts.map +1 -1
- package/dist/proxy/sessionLifecycle.d.ts +8 -1
- package/dist/proxy/sessionLifecycle.d.ts.map +1 -1
- package/dist/proxy/sessionStore.d.ts.map +1 -1
- package/dist/proxy/setup.d.ts.map +1 -1
- package/dist/proxy/supervision.d.ts +41 -0
- package/dist/proxy/supervision.d.ts.map +1 -0
- package/dist/proxy/tokenRefresh.d.ts +38 -4
- package/dist/proxy/tokenRefresh.d.ts.map +1 -1
- package/dist/server.js +11 -7
- package/dist/settings.d.ts +83 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/{setup-ndmjpy23.js → setup-7fr49z92.js} +1 -1
- package/dist/statusProbe-9x9q261e.js +151 -0
- package/dist/telemetry/dashboard.d.ts.map +1 -1
- package/dist/telemetry/index.d.ts +20 -2
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/landing.d.ts +1 -1
- package/dist/telemetry/landing.d.ts.map +1 -1
- package/dist/telemetry/logStore.d.ts +11 -0
- package/dist/telemetry/logStore.d.ts.map +1 -1
- package/dist/telemetry/pricingStore.d.ts +2 -2
- package/dist/telemetry/pricingStore.d.ts.map +1 -1
- package/dist/telemetry/profileBar.d.ts +10 -2
- package/dist/telemetry/profileBar.d.ts.map +1 -1
- package/dist/telemetry/profileFacts.d.ts +17 -0
- package/dist/telemetry/profileFacts.d.ts.map +1 -0
- package/dist/telemetry/profileOrder.d.ts +68 -0
- package/dist/telemetry/profileOrder.d.ts.map +1 -0
- package/dist/telemetry/profilePage.d.ts.map +1 -1
- package/dist/telemetry/profileSort.d.ts +35 -0
- package/dist/telemetry/profileSort.d.ts.map +1 -0
- package/dist/telemetry/profileSpent.d.ts +68 -0
- package/dist/telemetry/profileSpent.d.ts.map +1 -0
- package/dist/telemetry/routeChain.d.ts +32 -0
- package/dist/telemetry/routeChain.d.ts.map +1 -0
- package/dist/telemetry/routes.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +1 -1
- package/dist/telemetry/settingsPage.d.ts.map +1 -1
- package/dist/telemetry/sqlite.d.ts.map +1 -1
- package/dist/telemetry/store.d.ts +6 -1
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +132 -2
- package/dist/telemetry/types.d.ts.map +1 -1
- package/dist/{tokenRefresh-kzz08kea.js → tokenRefresh-eg9h83wd.js} +6 -1
- package/package.json +2 -1
- package/dist/cli-5jxyma6z.js +0 -277
- package/dist/cli-vj9cv18n.js +0 -38
- package/dist/proxy/settings.d.ts +0 -30
- package/dist/proxy/settings.d.ts.map +0 -1
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* Append-only, fixed capacity, oldest entries overwritten.
|
|
5
5
|
* No disk I/O in the hot path. Data resets on proxy restart.
|
|
6
6
|
*/
|
|
7
|
-
import type { RequestMetric, TelemetrySummary, ITelemetryStore } from "./types";
|
|
7
|
+
import type { RequestMetric, TelemetrySummary, ITelemetryStore, TelemetryRetention } from "./types";
|
|
8
|
+
/** Env beats the saved setting, which beats the default — the chain `routing`
|
|
9
|
+
* uses. A value that is not a positive integer is discarded at each step
|
|
10
|
+
* rather than falling through, so a typo cannot produce a zero-length ring. */
|
|
11
|
+
export declare function resolveTelemetryCapacity(): number;
|
|
8
12
|
export declare class MemoryTelemetryStore implements ITelemetryStore {
|
|
9
13
|
private buffer;
|
|
10
14
|
private head;
|
|
@@ -15,6 +19,7 @@ export declare class MemoryTelemetryStore implements ITelemetryStore {
|
|
|
15
19
|
record(metric: RequestMetric): void;
|
|
16
20
|
/** Get the total number of stored metrics. */
|
|
17
21
|
get size(): number;
|
|
22
|
+
describe(): TelemetryRetention;
|
|
18
23
|
/**
|
|
19
24
|
* Retrieve recent metrics, newest first.
|
|
20
25
|
* @param options.limit - Max entries to return (default: 50)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/telemetry/store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/telemetry/store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAOnG;;gFAEgF;AAChF,wBAAgB,wBAAwB,IAAI,MAAM,CAUjD;AAED,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,IAAI,CAAI;IAChB,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,QAAQ,CAAC,EAAE,MAAM;IAK7B,yCAAyC;IACzC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAMnC,8CAA8C;IAC9C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,QAAQ,IAAI,kBAAkB;IAc9B;;;;;OAKG;IACH,SAAS,CAAC,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,aAAa,EAAE;IAiB5F;kEAC8D;IAC9D,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAWlE;;;OAGG;IACH,SAAS,CAAC,QAAQ,GAAE,MAAuB,GAAG,gBAAgB;IAM9D,gCAAgC;IAChC,KAAK,IAAI,IAAI;CAKd;AAED,kDAAkD;AAClD,eAAO,MAAM,cAAc,sBAA6B,CAAA"}
|
|
@@ -9,6 +9,33 @@
|
|
|
9
9
|
* │ ├── upstream duration ──────┤
|
|
10
10
|
* ├──────────────────── total duration ────────────────────────────────────┤
|
|
11
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* How a request's account was chosen, as rendered in /telemetry's Route column.
|
|
14
|
+
*
|
|
15
|
+
* Lives here rather than in proxy/routing.ts because it is part of the
|
|
16
|
+
* RequestMetric wire shape, and telemetry may never import from proxy —
|
|
17
|
+
* dependencies flow proxy → telemetry only. `classifyRouteKind` produces it.
|
|
18
|
+
*
|
|
19
|
+
* The `-hop` kinds are one INTERNAL attempt of a pool dispatch. They are
|
|
20
|
+
* separate kinds rather than a flag because the collapsed row has to name the
|
|
21
|
+
* MODE that produced it: `priority` drains the pool in configured order,
|
|
22
|
+
* `active+priority` puts the selected account at its head, and those are
|
|
23
|
+
* different answers to "why this account" even when the chain looks alike.
|
|
24
|
+
*/
|
|
25
|
+
export type RouteKind = "pinned" | "active" | "sticky" | "priority" | "active+priority" | "priority-hop" | "active+priority-hop";
|
|
26
|
+
/** One account attempt within a client request's route. */
|
|
27
|
+
export interface RouteHop {
|
|
28
|
+
profileId: string;
|
|
29
|
+
/** Whether this attempt succeeded. The LAST hop answered the client
|
|
30
|
+
* whether or not it did — a chain ending `ok: false` means the pool ran out. */
|
|
31
|
+
ok: boolean;
|
|
32
|
+
status: number;
|
|
33
|
+
error: string | null;
|
|
34
|
+
/** Which allowance the account refused on ("five_hour", "seven_day_opus", …)
|
|
35
|
+
* when the refusal named one. Absent on hops that did not refuse, and on
|
|
36
|
+
* refusals Anthropic never attributed to a window. */
|
|
37
|
+
refusedBucket?: string;
|
|
38
|
+
}
|
|
12
39
|
export interface RequestMetric {
|
|
13
40
|
/** Unique request identifier */
|
|
14
41
|
requestId: string;
|
|
@@ -24,9 +51,30 @@ export interface RequestMetric {
|
|
|
24
51
|
model: string;
|
|
25
52
|
/** Original model string from the client request (e.g. "claude-sonnet-4-6-20250312") */
|
|
26
53
|
requestModel?: string;
|
|
27
|
-
/** Profile that served the request (multi-account)
|
|
28
|
-
*
|
|
54
|
+
/** Profile that served the request (multi-account). On records written
|
|
55
|
+
* before profile resolution ran this falls back to the pinned profile
|
|
56
|
+
* header, and is absent only when there was no pin either. */
|
|
29
57
|
profileId?: string;
|
|
58
|
+
/** How that profile was chosen — see proxy/routing.ts classifyRouteKind.
|
|
59
|
+
* Absent when the record was written before routing resolved. */
|
|
60
|
+
routeKind?: RouteKind;
|
|
61
|
+
/** Which allowance the serving account refused on, when this request was
|
|
62
|
+
* refused and Anthropic's wording or the SDK named a window. Recorded from
|
|
63
|
+
* the diagnosis the refusal bookkeeping already produced — nothing extra is
|
|
64
|
+
* computed for it. */
|
|
65
|
+
routeRefusedBucket?: string;
|
|
66
|
+
/** Correlates the internal hops of ONE client request. Priority routing
|
|
67
|
+
* re-enters the proxy once per candidate account, so a failover writes
|
|
68
|
+
* several rows; they share this id (the outer request's id). Absent on
|
|
69
|
+
* requests that were never dispatched through the pool. */
|
|
70
|
+
routeGroupId?: string;
|
|
71
|
+
/** 1-based position of this hop within its routeGroupId. */
|
|
72
|
+
routeAttempt?: number;
|
|
73
|
+
/** The full account chain for this client request, oldest attempt first,
|
|
74
|
+
* ending with the account that answered. DERIVED at read time by folding
|
|
75
|
+
* a routeGroupId's hops together — never stored, never computed on the
|
|
76
|
+
* request path. Absent on rows that were not part of a dispatch group. */
|
|
77
|
+
routeChain?: RouteHop[];
|
|
30
78
|
/** Streaming or non-streaming */
|
|
31
79
|
mode: "stream" | "non-stream";
|
|
32
80
|
/** Envelope-integrity violations detected on this response (dangling_block,
|
|
@@ -128,6 +176,35 @@ export interface CostEstimate {
|
|
|
128
176
|
estimatedUsd: number;
|
|
129
177
|
}>;
|
|
130
178
|
}
|
|
179
|
+
/** What one account did in a window. */
|
|
180
|
+
export interface RouteProfileTally {
|
|
181
|
+
/** Requests this account answered. */
|
|
182
|
+
served: number;
|
|
183
|
+
/** Attempts this account refused, including the ones a failover hid from
|
|
184
|
+
* the client — those never reach it as an error, so nothing else counts them. */
|
|
185
|
+
refused: number;
|
|
186
|
+
/** Refusals by allowance ("five_hour", "seven_day_opus", …), for the ones
|
|
187
|
+
* Anthropic attributed to a window. Sums to at most `refused`. */
|
|
188
|
+
refusedBuckets: Record<string, number>;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Where a window's requests went and which accounts refused them.
|
|
192
|
+
*
|
|
193
|
+
* DERIVED at read time from collapsed rows (telemetry/routeChain.ts) — nothing
|
|
194
|
+
* here is stored, and nothing is computed for it on the request path.
|
|
195
|
+
*/
|
|
196
|
+
export interface RouteSummary {
|
|
197
|
+
/** Client requests in the window. A failover counts ONCE, not once per hop. */
|
|
198
|
+
requests: number;
|
|
199
|
+
/** Requests that touched more than one account before being answered. */
|
|
200
|
+
failedOver: number;
|
|
201
|
+
/** Requests no account answered — the client received the refusal. */
|
|
202
|
+
unserved: number;
|
|
203
|
+
/** How the account was chosen, keyed by RouteKind. */
|
|
204
|
+
byKind: Record<string, number>;
|
|
205
|
+
/** Per-account tally, keyed by profileId ("default" when a row carried none). */
|
|
206
|
+
byProfile: Record<string, RouteProfileTally>;
|
|
207
|
+
}
|
|
131
208
|
export interface TelemetrySummary {
|
|
132
209
|
/** Time window these stats cover */
|
|
133
210
|
windowMs: number;
|
|
@@ -187,12 +264,65 @@ export interface SessionTreeSummary {
|
|
|
187
264
|
propagations: number;
|
|
188
265
|
cancelledDescendants: number;
|
|
189
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* The telemetry configuration that WOULD be used if the proxy started now.
|
|
269
|
+
*
|
|
270
|
+
* Distinct from TelemetryRetention, which describes the store that is actually
|
|
271
|
+
* running, and the pair only agrees until somebody edits a setting: the stores
|
|
272
|
+
* are built once at startup, so this is the intent and that is the fact.
|
|
273
|
+
* Comparing the two is how a settings page knows to say "restart to apply"
|
|
274
|
+
* instead of implying a change already took effect.
|
|
275
|
+
*/
|
|
276
|
+
export interface ResolvedTelemetryConfig {
|
|
277
|
+
persist: boolean;
|
|
278
|
+
/** Where SQLite would write. Meaningful only when `persist`. */
|
|
279
|
+
dbPath: string;
|
|
280
|
+
/** Days before a persisted row is deleted. Meaningful only when `persist`. */
|
|
281
|
+
retentionDays: number;
|
|
282
|
+
/** Rows the metric ring would hold. Meaningful only when NOT `persist`. */
|
|
283
|
+
telemetrySize: number;
|
|
284
|
+
/** Entries the diagnostic ring would hold. Meaningful only when NOT `persist`. */
|
|
285
|
+
diagnosticLogSize: number;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* What the store actually holds, so a page can say so instead of implying it
|
|
289
|
+
* holds everything.
|
|
290
|
+
*
|
|
291
|
+
* The dashboard offers a 24-hour window against a ring buffer that is under an
|
|
292
|
+
* hour of traffic at a working pace, and shows the difference nowhere: the page
|
|
293
|
+
* looks the same whether a window is empty because nothing happened or because
|
|
294
|
+
* the rows were overwritten. Reading the source is not an acceptable way to
|
|
295
|
+
* learn which.
|
|
296
|
+
*/
|
|
297
|
+
export interface TelemetryRetention {
|
|
298
|
+
/** "memory" is lost on restart; "sqlite" survives it. */
|
|
299
|
+
kind: "memory" | "sqlite";
|
|
300
|
+
/** Rows held right now. */
|
|
301
|
+
held: number;
|
|
302
|
+
/** Ring capacity — the oldest row is dropped past this (memory only). */
|
|
303
|
+
capacity?: number;
|
|
304
|
+
/** Days before cleanup deletes a row (sqlite only). */
|
|
305
|
+
retentionDays?: number;
|
|
306
|
+
/** Database file and its size on disk, WAL included (sqlite only). */
|
|
307
|
+
dbPath?: string;
|
|
308
|
+
dbBytes?: number;
|
|
309
|
+
/**
|
|
310
|
+
* Timestamp of the oldest row held, null when empty.
|
|
311
|
+
*
|
|
312
|
+
* This is the honest bound on every window the page offers: a window
|
|
313
|
+
* reaching further back than this shows less than it names, whether because
|
|
314
|
+
* rows were evicted or because the proxy has not been up that long.
|
|
315
|
+
*/
|
|
316
|
+
oldestTimestamp: number | null;
|
|
317
|
+
}
|
|
190
318
|
/** Storage backend for request metrics. */
|
|
191
319
|
export interface ITelemetryStore {
|
|
192
320
|
/** Record a completed request metric. */
|
|
193
321
|
record(metric: RequestMetric): void;
|
|
194
322
|
/** Number of stored metrics. */
|
|
195
323
|
readonly size: number;
|
|
324
|
+
/** What this store holds and for how long — see TelemetryRetention. */
|
|
325
|
+
describe(): TelemetryRetention;
|
|
196
326
|
/** Retrieve recent metrics, newest first. */
|
|
197
327
|
getRecent(options?: {
|
|
198
328
|
limit?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/telemetry/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAA;IAEjB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAA;IAEjB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;0EAEsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAA;IAEb,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/telemetry/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
credentialsFilePathForProfile,
|
|
7
7
|
ensureFreshToken,
|
|
8
8
|
getAuthRenewalStatus,
|
|
9
|
+
getStoredPlanFields,
|
|
9
10
|
isBackgroundRefreshActive,
|
|
11
|
+
readStoredCredentialPresence,
|
|
10
12
|
refreshOAuthToken,
|
|
11
13
|
resetAuthRenewalCache,
|
|
12
14
|
resetInflightRefresh,
|
|
@@ -14,7 +16,8 @@ import {
|
|
|
14
16
|
serializeCredentials,
|
|
15
17
|
startBackgroundRefresh,
|
|
16
18
|
stopBackgroundRefresh
|
|
17
|
-
} from "./cli-
|
|
19
|
+
} from "./cli-chsp880k.js";
|
|
20
|
+
import"./cli-1jstkdj9.js";
|
|
18
21
|
import"./cli-p9swy5t3.js";
|
|
19
22
|
export {
|
|
20
23
|
stopBackgroundRefresh,
|
|
@@ -24,7 +27,9 @@ export {
|
|
|
24
27
|
resetInflightRefresh,
|
|
25
28
|
resetAuthRenewalCache,
|
|
26
29
|
refreshOAuthToken,
|
|
30
|
+
readStoredCredentialPresence,
|
|
27
31
|
isBackgroundRefreshActive,
|
|
32
|
+
getStoredPlanFields,
|
|
28
33
|
getAuthRenewalStatus,
|
|
29
34
|
ensureFreshToken,
|
|
30
35
|
credentialsFilePathForProfile,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynfar/meridian",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.73.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,6 +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 --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
|
+
"pretest": "tsc --noEmit",
|
|
28
29
|
"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
30
|
"nix:lock": "bun2nix -o bun.nix",
|
|
30
31
|
"typecheck": "tsc --noEmit",
|
package/dist/cli-5jxyma6z.js
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getSetting,
|
|
3
|
-
setSetting
|
|
4
|
-
} from "./cli-vj9cv18n.js";
|
|
5
|
-
|
|
6
|
-
// src/proxy/profiles.ts
|
|
7
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
import { homedir } from "node:os";
|
|
10
|
-
|
|
11
|
-
// src/proxy/routing.ts
|
|
12
|
-
import { createHash } from "node:crypto";
|
|
13
|
-
function getRoutingMode(raw) {
|
|
14
|
-
const lower = raw?.toLowerCase();
|
|
15
|
-
if (lower === "sticky")
|
|
16
|
-
return "sticky";
|
|
17
|
-
if (lower === "priority")
|
|
18
|
-
return "priority";
|
|
19
|
-
return "active";
|
|
20
|
-
}
|
|
21
|
-
function getPriorityFailbackPolicy(raw) {
|
|
22
|
-
return raw?.toLowerCase() === "next-user-turn" ? "next-user-turn" : "new-conversation";
|
|
23
|
-
}
|
|
24
|
-
function shouldPromotePriorityAssignment(input) {
|
|
25
|
-
return input.policy === "next-user-turn" && input.requestKind === "human" && input.requestId !== undefined && input.requestId !== input.assignment.requestId;
|
|
26
|
-
}
|
|
27
|
-
function rendezvousScore(sessionKey, profileId) {
|
|
28
|
-
const digest = createHash("sha256").update(`${sessionKey}\x00${profileId}`).digest();
|
|
29
|
-
return digest.readBigUInt64BE(0);
|
|
30
|
-
}
|
|
31
|
-
function pickStickyProfile(sessionKey, profileIds) {
|
|
32
|
-
if (!sessionKey || profileIds.length === 0)
|
|
33
|
-
return;
|
|
34
|
-
let best;
|
|
35
|
-
let bestScore = -1n;
|
|
36
|
-
for (const id of profileIds) {
|
|
37
|
-
const score = rendezvousScore(sessionKey, id);
|
|
38
|
-
if (score > bestScore) {
|
|
39
|
-
bestScore = score;
|
|
40
|
-
best = id;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return best;
|
|
44
|
-
}
|
|
45
|
-
function resolvePriorityOrder(configuredIds, orderSetting) {
|
|
46
|
-
const existing = new Set(configuredIds);
|
|
47
|
-
const order = [];
|
|
48
|
-
const unknown = [];
|
|
49
|
-
for (const id of orderSetting ?? []) {
|
|
50
|
-
if (!existing.has(id)) {
|
|
51
|
-
unknown.push(id);
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (!order.includes(id))
|
|
55
|
-
order.push(id);
|
|
56
|
-
}
|
|
57
|
-
for (const id of configuredIds)
|
|
58
|
-
if (!order.includes(id))
|
|
59
|
-
order.push(id);
|
|
60
|
-
return { order, unknown };
|
|
61
|
-
}
|
|
62
|
-
function choosePriorityProfile(order, isExhausted) {
|
|
63
|
-
const preferred = order[0];
|
|
64
|
-
if (preferred === undefined)
|
|
65
|
-
return;
|
|
66
|
-
for (const id of order) {
|
|
67
|
-
if (!isExhausted(id))
|
|
68
|
-
return { id, allExhausted: false };
|
|
69
|
-
}
|
|
70
|
-
return { id: preferred, allExhausted: true };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
class ProfileExhaustion {
|
|
74
|
-
now;
|
|
75
|
-
marks = new Map;
|
|
76
|
-
constructor(now = Date.now) {
|
|
77
|
-
this.now = now;
|
|
78
|
-
}
|
|
79
|
-
mark(id, until, reason) {
|
|
80
|
-
const existing = this.marks.get(id);
|
|
81
|
-
if (existing && existing.until >= until)
|
|
82
|
-
return;
|
|
83
|
-
this.marks.set(id, { until, reason });
|
|
84
|
-
}
|
|
85
|
-
isExhausted(id) {
|
|
86
|
-
const entry = this.marks.get(id);
|
|
87
|
-
if (!entry)
|
|
88
|
-
return false;
|
|
89
|
-
if (entry.until <= this.now()) {
|
|
90
|
-
this.marks.delete(id);
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
snapshot() {
|
|
96
|
-
const out = [];
|
|
97
|
-
for (const [id, entry] of this.marks) {
|
|
98
|
-
if (entry.until <= this.now()) {
|
|
99
|
-
this.marks.delete(id);
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
out.push({ id, until: entry.until, reason: entry.reason });
|
|
103
|
-
}
|
|
104
|
-
return out;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
class AssignmentStore {
|
|
109
|
-
max;
|
|
110
|
-
entries = new Map;
|
|
111
|
-
constructor(max) {
|
|
112
|
-
this.max = max;
|
|
113
|
-
}
|
|
114
|
-
get(key) {
|
|
115
|
-
const value = this.entries.get(key);
|
|
116
|
-
if (value === undefined)
|
|
117
|
-
return;
|
|
118
|
-
this.entries.delete(key);
|
|
119
|
-
this.entries.set(key, value);
|
|
120
|
-
return value;
|
|
121
|
-
}
|
|
122
|
-
set(key, value) {
|
|
123
|
-
this.entries.delete(key);
|
|
124
|
-
this.entries.set(key, value);
|
|
125
|
-
if (this.entries.size > this.max) {
|
|
126
|
-
const oldest = this.entries.keys().next().value;
|
|
127
|
-
if (oldest !== undefined)
|
|
128
|
-
this.entries.delete(oldest);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
compareAndSet(key, expected, value) {
|
|
132
|
-
if (this.entries.get(key) !== expected)
|
|
133
|
-
return false;
|
|
134
|
-
this.set(key, value);
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
get size() {
|
|
138
|
-
return this.entries.size;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
var COOLDOWN_WINDOWS = ["seven_day", "five_hour"];
|
|
142
|
-
var COOLDOWN_CAP_MS = {
|
|
143
|
-
five_hour: 6 * 60 * 60000,
|
|
144
|
-
seven_day: 8 * 24 * 60 * 60000
|
|
145
|
-
};
|
|
146
|
-
function cooldownCapMs(type) {
|
|
147
|
-
return COOLDOWN_CAP_MS[type];
|
|
148
|
-
}
|
|
149
|
-
function resolveCooldownUntil(windows, now, defaultMs) {
|
|
150
|
-
return findCooldownReset(windows, now) ?? now + defaultMs;
|
|
151
|
-
}
|
|
152
|
-
function findCooldownReset(windows, now) {
|
|
153
|
-
for (const type of COOLDOWN_WINDOWS) {
|
|
154
|
-
const match = windows.find((w) => w.type === type && w.exhausted && (w.resetsAt ?? 0) > now);
|
|
155
|
-
if (match?.resetsAt) {
|
|
156
|
-
return Math.min(match.resetsAt, now + cooldownCapMs(type));
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// src/proxy/profiles.ts
|
|
163
|
-
var CONFIG_FILE = join(homedir(), ".config", "meridian", "profiles.json");
|
|
164
|
-
var DISK_CACHE_TTL_MS = 5000;
|
|
165
|
-
var diskProfilesCache = [];
|
|
166
|
-
var diskProfilesCacheAt = 0;
|
|
167
|
-
function loadProfilesFromDisk() {
|
|
168
|
-
if (diskProfilesCacheAt > 0 && Date.now() - diskProfilesCacheAt < DISK_CACHE_TTL_MS) {
|
|
169
|
-
return diskProfilesCache;
|
|
170
|
-
}
|
|
171
|
-
try {
|
|
172
|
-
if (!existsSync(CONFIG_FILE)) {
|
|
173
|
-
diskProfilesCache = [];
|
|
174
|
-
} else {
|
|
175
|
-
diskProfilesCache = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
176
|
-
}
|
|
177
|
-
diskProfilesCacheAt = Date.now();
|
|
178
|
-
return diskProfilesCache;
|
|
179
|
-
} catch (err) {
|
|
180
|
-
console.warn(`[meridian] Failed to read ${CONFIG_FILE}: ${err instanceof Error ? err.message : err}`);
|
|
181
|
-
diskProfilesCacheAt = Date.now();
|
|
182
|
-
diskProfilesCache = [];
|
|
183
|
-
return [];
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
var DEFAULT_PROFILE_ID = "default";
|
|
187
|
-
var activeProfileId;
|
|
188
|
-
function setActiveProfile(profileId) {
|
|
189
|
-
activeProfileId = profileId;
|
|
190
|
-
setSetting("activeProfile", profileId);
|
|
191
|
-
}
|
|
192
|
-
function getActiveProfileId() {
|
|
193
|
-
return activeProfileId;
|
|
194
|
-
}
|
|
195
|
-
function resetActiveProfile() {
|
|
196
|
-
activeProfileId = undefined;
|
|
197
|
-
}
|
|
198
|
-
function restoreActiveProfile(configProfiles) {
|
|
199
|
-
if (activeProfileId)
|
|
200
|
-
return;
|
|
201
|
-
if (!diskDiscoveryEnabled)
|
|
202
|
-
return;
|
|
203
|
-
const saved = getSetting("activeProfile");
|
|
204
|
-
if (!saved)
|
|
205
|
-
return;
|
|
206
|
-
const effective = getEffectiveProfiles(configProfiles);
|
|
207
|
-
if (effective.length === 0 || effective.some((p) => p.id === saved)) {
|
|
208
|
-
activeProfileId = saved;
|
|
209
|
-
} else {
|
|
210
|
-
console.warn(`[meridian] Saved active profile "${saved}" not found. Using default.`);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
var diskDiscoveryEnabled = false;
|
|
214
|
-
function enableDiskProfileDiscovery() {
|
|
215
|
-
diskDiscoveryEnabled = true;
|
|
216
|
-
}
|
|
217
|
-
function getEffectiveProfiles(configProfiles) {
|
|
218
|
-
const fromConfig = configProfiles ?? [];
|
|
219
|
-
if (!diskDiscoveryEnabled)
|
|
220
|
-
return fromConfig;
|
|
221
|
-
const fromDisk = loadProfilesFromDisk();
|
|
222
|
-
const configIds = new Set(fromConfig.map((p) => p.id));
|
|
223
|
-
return [...fromConfig, ...fromDisk.filter((p) => !configIds.has(p.id))];
|
|
224
|
-
}
|
|
225
|
-
function hasProfiles(configProfiles) {
|
|
226
|
-
return getEffectiveProfiles(configProfiles).length > 0;
|
|
227
|
-
}
|
|
228
|
-
function resolveProfile(profiles, defaultProfile, requestedId, options) {
|
|
229
|
-
const effective = getEffectiveProfiles(profiles);
|
|
230
|
-
if (effective.length === 0) {
|
|
231
|
-
return { id: DEFAULT_PROFILE_ID, type: "claude-max", env: {} };
|
|
232
|
-
}
|
|
233
|
-
const stickyId = options?.routingMode === "sticky" && options.stickySessionKey ? pickStickyProfile(options.stickySessionKey, effective.map((p) => p.id)) : undefined;
|
|
234
|
-
const resolvedId = requestedId || stickyId || activeProfileId || defaultProfile || effective[0].id;
|
|
235
|
-
const profile = effective.find((p) => p.id === resolvedId);
|
|
236
|
-
if (!profile) {
|
|
237
|
-
console.warn(`[meridian] Unknown profile "${resolvedId}". Using first configured profile.`);
|
|
238
|
-
return buildResolvedProfile(effective[0]);
|
|
239
|
-
}
|
|
240
|
-
return buildResolvedProfile(profile);
|
|
241
|
-
}
|
|
242
|
-
function buildResolvedProfile(profile) {
|
|
243
|
-
if (profile.oauthToken || profile.type === "oauth-token") {
|
|
244
|
-
const env2 = {};
|
|
245
|
-
if (profile.oauthToken) {
|
|
246
|
-
env2.CLAUDE_CODE_OAUTH_TOKEN = profile.oauthToken;
|
|
247
|
-
env2.CLAUDE_CONFIG_DIR = join(homedir(), ".config", "meridian", "profiles", profile.id);
|
|
248
|
-
}
|
|
249
|
-
return { id: profile.id, type: "oauth-token", env: env2 };
|
|
250
|
-
}
|
|
251
|
-
const type = profile.type ?? "claude-max";
|
|
252
|
-
if (type === "api") {
|
|
253
|
-
const env2 = {};
|
|
254
|
-
if (profile.apiKey)
|
|
255
|
-
env2.ANTHROPIC_API_KEY = profile.apiKey;
|
|
256
|
-
if (profile.baseUrl)
|
|
257
|
-
env2.ANTHROPIC_BASE_URL = profile.baseUrl;
|
|
258
|
-
return { id: profile.id, type, env: env2 };
|
|
259
|
-
}
|
|
260
|
-
const env = {};
|
|
261
|
-
if (profile.claudeConfigDir)
|
|
262
|
-
env.CLAUDE_CONFIG_DIR = profile.claudeConfigDir;
|
|
263
|
-
return { id: profile.id, type, env };
|
|
264
|
-
}
|
|
265
|
-
function listProfiles(profiles, defaultProfile) {
|
|
266
|
-
const effective = getEffectiveProfiles(profiles);
|
|
267
|
-
if (effective.length === 0)
|
|
268
|
-
return [];
|
|
269
|
-
const currentActive = activeProfileId || defaultProfile || effective[0].id;
|
|
270
|
-
return effective.map((p) => ({
|
|
271
|
-
id: p.id,
|
|
272
|
-
type: p.type ?? "claude-max",
|
|
273
|
-
isActive: p.id === currentActive
|
|
274
|
-
}));
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export { getRoutingMode, getPriorityFailbackPolicy, shouldPromotePriorityAssignment, resolvePriorityOrder, choosePriorityProfile, ProfileExhaustion, AssignmentStore, resolveCooldownUntil, findCooldownReset, loadProfilesFromDisk, setActiveProfile, getActiveProfileId, resetActiveProfile, restoreActiveProfile, enableDiskProfileDiscovery, getEffectiveProfiles, hasProfiles, resolveProfile, listProfiles };
|
package/dist/cli-vj9cv18n.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// src/proxy/settings.ts
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
3
|
-
import { join, dirname } from "node:path";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
function settingsFile() {
|
|
6
|
-
const override = process.env.MERIDIAN_CONFIG_DIR;
|
|
7
|
-
return override ? join(override, "settings.json") : join(homedir(), ".config", "meridian", "settings.json");
|
|
8
|
-
}
|
|
9
|
-
function loadSettings() {
|
|
10
|
-
const file = settingsFile();
|
|
11
|
-
try {
|
|
12
|
-
if (!existsSync(file))
|
|
13
|
-
return {};
|
|
14
|
-
return JSON.parse(readFileSync(file, "utf-8"));
|
|
15
|
-
} catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function saveSettings(updates) {
|
|
20
|
-
const file = settingsFile();
|
|
21
|
-
const current = loadSettings();
|
|
22
|
-
const merged = { ...current, ...updates };
|
|
23
|
-
try {
|
|
24
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
25
|
-
writeFileSync(file, JSON.stringify(merged, null, 2) + `
|
|
26
|
-
`, { mode: 384 });
|
|
27
|
-
} catch (err) {
|
|
28
|
-
console.warn(`[meridian] Failed to write ${file}: ${err instanceof Error ? err.message : err}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function getSetting(key) {
|
|
32
|
-
return loadSettings()[key];
|
|
33
|
-
}
|
|
34
|
-
function setSetting(key, value) {
|
|
35
|
-
saveSettings({ [key]: value });
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export { getSetting, setSetting };
|
package/dist/proxy/settings.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistent server settings.
|
|
3
|
-
*
|
|
4
|
-
* Stored in ~/.config/meridian/settings.json. Survives proxy restarts.
|
|
5
|
-
* Shared between CLI, UI, and API — browser localStorage is only used
|
|
6
|
-
* for client-only preferences (theme, collapsed sections, etc.).
|
|
7
|
-
*
|
|
8
|
-
* This is a leaf module — no imports from server.ts or session/.
|
|
9
|
-
*/
|
|
10
|
-
import type { PriorityFailbackPolicy } from "./routing";
|
|
11
|
-
export interface MeridianSettings {
|
|
12
|
-
/** Last active profile ID — restored on proxy startup */
|
|
13
|
-
activeProfile?: string;
|
|
14
|
-
/** Profile routing mode (#383, priority spec): "active" (default),
|
|
15
|
-
* "sticky", or "priority". MERIDIAN_ROUTING env var takes precedence. */
|
|
16
|
-
routing?: string;
|
|
17
|
-
/** Priority-mode pool order (highest priority first). Falls back to
|
|
18
|
-
* profiles.json order. MERIDIAN_PROFILE_ORDER env var takes precedence. */
|
|
19
|
-
profileOrder?: string[];
|
|
20
|
-
priorityFailback?: PriorityFailbackPolicy;
|
|
21
|
-
}
|
|
22
|
-
/** Read settings from disk. Returns empty object if file doesn't exist or is invalid. */
|
|
23
|
-
export declare function loadSettings(): MeridianSettings;
|
|
24
|
-
/** Write settings to disk. Merges with existing settings (doesn't clobber unknown keys). */
|
|
25
|
-
export declare function saveSettings(updates: Partial<MeridianSettings>): void;
|
|
26
|
-
/** Get a single setting value */
|
|
27
|
-
export declare function getSetting<K extends keyof MeridianSettings>(key: K): MeridianSettings[K];
|
|
28
|
-
/** Set a single setting value and persist */
|
|
29
|
-
export declare function setSetting<K extends keyof MeridianSettings>(key: K, value: MeridianSettings[K]): void;
|
|
30
|
-
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|