@rynfar/meridian 1.34.1 → 1.35.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.
@@ -20,9 +20,1133 @@ import {
20
20
  setActiveProfile
21
21
  } from "./cli-vdp9s10c.js";
22
22
  import {
23
+ __commonJS,
24
+ __esm,
23
25
  __export,
24
- __require
25
- } from "./cli-a05ws7rb.js";
26
+ __require,
27
+ __toCommonJS,
28
+ __toESM
29
+ } from "./cli-p9swy5t3.js";
30
+
31
+ // src/telemetry/percentiles.ts
32
+ function computePercentiles(values) {
33
+ if (values.length === 0)
34
+ return { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
35
+ const sorted = [...values].sort((a, b) => a - b);
36
+ const sum = sorted.reduce((a, b) => a + b, 0);
37
+ return {
38
+ p50: sorted[Math.floor(sorted.length * 0.5)],
39
+ p95: sorted[Math.floor(sorted.length * 0.95)],
40
+ p99: sorted[Math.floor(sorted.length * 0.99)],
41
+ min: sorted[0],
42
+ max: sorted[sorted.length - 1],
43
+ avg: Math.round(sum / sorted.length)
44
+ };
45
+ }
46
+ function computeSummary(metrics, windowMs) {
47
+ if (metrics.length === 0) {
48
+ const emptyPhase = { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
49
+ return {
50
+ windowMs,
51
+ totalRequests: 0,
52
+ errorCount: 0,
53
+ requestsPerMinute: 0,
54
+ queueWait: emptyPhase,
55
+ proxyOverhead: emptyPhase,
56
+ ttfb: emptyPhase,
57
+ upstreamDuration: emptyPhase,
58
+ totalDuration: emptyPhase,
59
+ byModel: {},
60
+ byMode: {},
61
+ tokenUsage: {
62
+ totalInputTokens: 0,
63
+ totalOutputTokens: 0,
64
+ totalCacheReadTokens: 0,
65
+ totalCacheCreationTokens: 0,
66
+ avgCacheHitRate: 0,
67
+ cacheMissOnResumeCount: 0
68
+ }
69
+ };
70
+ }
71
+ const errorCount = metrics.filter((m) => m.error !== null).length;
72
+ const oldest = metrics[metrics.length - 1].timestamp;
73
+ const newest = metrics[0].timestamp;
74
+ const spanMs = Math.max(newest - oldest, 1);
75
+ const requestsPerMinute = metrics.length / spanMs * 60000;
76
+ const queueWaits = metrics.map((m) => m.queueWaitMs);
77
+ const overheads = metrics.map((m) => m.proxyOverheadMs);
78
+ const ttfbs = metrics.filter((m) => m.ttfbMs !== null).map((m) => m.ttfbMs);
79
+ const upstreams = metrics.map((m) => m.upstreamDurationMs);
80
+ const totals = metrics.map((m) => m.totalDurationMs);
81
+ const byModel = {};
82
+ for (const m of metrics) {
83
+ const modelKey = m.requestModel || m.model;
84
+ const entry = byModel[modelKey] ??= { count: 0, totalMs: 0 };
85
+ entry.count++;
86
+ entry.totalMs += m.totalDurationMs;
87
+ }
88
+ const byMode = {};
89
+ for (const m of metrics) {
90
+ const entry = byMode[m.mode] ??= { count: 0, totalMs: 0 };
91
+ entry.count++;
92
+ entry.totalMs += m.totalDurationMs;
93
+ }
94
+ let totalInputTokens = 0;
95
+ let totalOutputTokens = 0;
96
+ let totalCacheReadTokens = 0;
97
+ let totalCacheCreationTokens = 0;
98
+ let cacheHitRateSum = 0;
99
+ let cacheHitRateCount = 0;
100
+ let cacheMissOnResumeCount = 0;
101
+ for (const m of metrics) {
102
+ totalInputTokens += m.inputTokens ?? 0;
103
+ totalOutputTokens += m.outputTokens ?? 0;
104
+ totalCacheReadTokens += m.cacheReadInputTokens ?? 0;
105
+ totalCacheCreationTokens += m.cacheCreationInputTokens ?? 0;
106
+ if (m.cacheHitRate !== undefined) {
107
+ cacheHitRateSum += m.cacheHitRate;
108
+ cacheHitRateCount++;
109
+ }
110
+ if (m.isResume && m.cacheHitRate !== undefined && m.cacheHitRate === 0) {
111
+ cacheMissOnResumeCount++;
112
+ }
113
+ }
114
+ return {
115
+ windowMs,
116
+ totalRequests: metrics.length,
117
+ errorCount,
118
+ requestsPerMinute: Math.round(requestsPerMinute * 100) / 100,
119
+ queueWait: computePercentiles(queueWaits),
120
+ proxyOverhead: computePercentiles(overheads),
121
+ ttfb: ttfbs.length > 0 ? computePercentiles(ttfbs) : { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 },
122
+ upstreamDuration: computePercentiles(upstreams),
123
+ totalDuration: computePercentiles(totals),
124
+ byModel: Object.fromEntries(Object.entries(byModel).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
125
+ byMode: Object.fromEntries(Object.entries(byMode).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
126
+ tokenUsage: {
127
+ totalInputTokens,
128
+ totalOutputTokens,
129
+ totalCacheReadTokens,
130
+ totalCacheCreationTokens,
131
+ avgCacheHitRate: cacheHitRateCount > 0 ? Math.round(cacheHitRateSum / cacheHitRateCount * 100) / 100 : 0,
132
+ cacheMissOnResumeCount
133
+ }
134
+ };
135
+ }
136
+ var init_percentiles = () => {};
137
+
138
+ // node_modules/@neon-rs/load/dist/index.js
139
+ var require_dist = __commonJS((exports) => {
140
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
141
+ if (k2 === undefined)
142
+ k2 = k;
143
+ var desc = Object.getOwnPropertyDescriptor(m, k);
144
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
145
+ desc = { enumerable: true, get: function() {
146
+ return m[k];
147
+ } };
148
+ }
149
+ Object.defineProperty(o, k2, desc);
150
+ } : function(o, m, k, k2) {
151
+ if (k2 === undefined)
152
+ k2 = k;
153
+ o[k2] = m[k];
154
+ });
155
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
156
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
157
+ } : function(o, v) {
158
+ o["default"] = v;
159
+ });
160
+ var __importStar = exports && exports.__importStar || function(mod) {
161
+ if (mod && mod.__esModule)
162
+ return mod;
163
+ var result = {};
164
+ if (mod != null) {
165
+ for (var k in mod)
166
+ if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
167
+ __createBinding(result, mod, k);
168
+ }
169
+ __setModuleDefault(result, mod);
170
+ return result;
171
+ };
172
+ Object.defineProperty(exports, "__esModule", { value: true });
173
+ exports.load = exports.currentTarget = undefined;
174
+ var path = __importStar(__require("path"));
175
+ var fs = __importStar(__require("fs"));
176
+ function currentTarget() {
177
+ let os = null;
178
+ switch (process.platform) {
179
+ case "android":
180
+ switch (process.arch) {
181
+ case "arm":
182
+ return "android-arm-eabi";
183
+ case "arm64":
184
+ return "android-arm64";
185
+ }
186
+ os = "Android";
187
+ break;
188
+ case "win32":
189
+ switch (process.arch) {
190
+ case "x64":
191
+ return "win32-x64-msvc";
192
+ case "arm64":
193
+ return "win32-arm64-msvc";
194
+ case "ia32":
195
+ return "win32-ia32-msvc";
196
+ }
197
+ os = "Windows";
198
+ break;
199
+ case "darwin":
200
+ switch (process.arch) {
201
+ case "x64":
202
+ return "darwin-x64";
203
+ case "arm64":
204
+ return "darwin-arm64";
205
+ }
206
+ os = "macOS";
207
+ break;
208
+ case "linux":
209
+ switch (process.arch) {
210
+ case "x64":
211
+ case "arm64":
212
+ return isGlibc() ? `linux-${process.arch}-gnu` : `linux-${process.arch}-musl`;
213
+ case "arm":
214
+ return "linux-arm-gnueabihf";
215
+ }
216
+ os = "Linux";
217
+ break;
218
+ case "freebsd":
219
+ if (process.arch === "x64") {
220
+ return "freebsd-x64";
221
+ }
222
+ os = "FreeBSD";
223
+ break;
224
+ }
225
+ if (os) {
226
+ throw new Error(`Neon: unsupported ${os} architecture: ${process.arch}`);
227
+ }
228
+ throw new Error(`Neon: unsupported system: ${process.platform}`);
229
+ }
230
+ exports.currentTarget = currentTarget;
231
+ function isGlibc() {
232
+ const report = process.report?.getReport();
233
+ if (typeof report !== "object" || !report || !("header" in report)) {
234
+ return false;
235
+ }
236
+ const header = report.header;
237
+ return typeof header === "object" && !!header && "glibcVersionRuntime" in header;
238
+ }
239
+ function load(dirname2) {
240
+ const m = path.join(dirname2, "index.node");
241
+ return fs.existsSync(m) ? __require(m) : null;
242
+ }
243
+ exports.load = load;
244
+ });
245
+
246
+ // node_modules/detect-libc/lib/process.js
247
+ var require_process = __commonJS((exports, module) => {
248
+ var isLinux = () => process.platform === "linux";
249
+ var report = null;
250
+ var getReport = () => {
251
+ if (!report) {
252
+ report = isLinux() && process.report ? process.report.getReport() : {};
253
+ }
254
+ return report;
255
+ };
256
+ module.exports = { isLinux, getReport };
257
+ });
258
+
259
+ // node_modules/detect-libc/lib/filesystem.js
260
+ var require_filesystem = __commonJS((exports, module) => {
261
+ var fs = __require("fs");
262
+ var LDD_PATH = "/usr/bin/ldd";
263
+ var readFileSync2 = (path) => fs.readFileSync(path, "utf-8");
264
+ var readFile = (path) => new Promise((resolve2, reject) => {
265
+ fs.readFile(path, "utf-8", (err, data) => {
266
+ if (err) {
267
+ reject(err);
268
+ } else {
269
+ resolve2(data);
270
+ }
271
+ });
272
+ });
273
+ module.exports = {
274
+ LDD_PATH,
275
+ readFileSync: readFileSync2,
276
+ readFile
277
+ };
278
+ });
279
+
280
+ // node_modules/detect-libc/lib/detect-libc.js
281
+ var require_detect_libc = __commonJS((exports, module) => {
282
+ var childProcess = __require("child_process");
283
+ var { isLinux, getReport } = require_process();
284
+ var { LDD_PATH, readFile, readFileSync: readFileSync2 } = require_filesystem();
285
+ var cachedFamilyFilesystem;
286
+ var cachedVersionFilesystem;
287
+ var command = "getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true";
288
+ var commandOut = "";
289
+ var safeCommand = () => {
290
+ if (!commandOut) {
291
+ return new Promise((resolve2) => {
292
+ childProcess.exec(command, (err, out) => {
293
+ commandOut = err ? " " : out;
294
+ resolve2(commandOut);
295
+ });
296
+ });
297
+ }
298
+ return commandOut;
299
+ };
300
+ var safeCommandSync = () => {
301
+ if (!commandOut) {
302
+ try {
303
+ commandOut = childProcess.execSync(command, { encoding: "utf8" });
304
+ } catch (_err) {
305
+ commandOut = " ";
306
+ }
307
+ }
308
+ return commandOut;
309
+ };
310
+ var GLIBC = "glibc";
311
+ var RE_GLIBC_VERSION = /GLIBC\s(\d+\.\d+)/;
312
+ var MUSL = "musl";
313
+ var GLIBC_ON_LDD = GLIBC.toUpperCase();
314
+ var MUSL_ON_LDD = MUSL.toLowerCase();
315
+ var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-");
316
+ var familyFromReport = () => {
317
+ const report = getReport();
318
+ if (report.header && report.header.glibcVersionRuntime) {
319
+ return GLIBC;
320
+ }
321
+ if (Array.isArray(report.sharedObjects)) {
322
+ if (report.sharedObjects.some(isFileMusl)) {
323
+ return MUSL;
324
+ }
325
+ }
326
+ return null;
327
+ };
328
+ var familyFromCommand = (out) => {
329
+ const [getconf, ldd1] = out.split(/[\r\n]+/);
330
+ if (getconf && getconf.includes(GLIBC)) {
331
+ return GLIBC;
332
+ }
333
+ if (ldd1 && ldd1.includes(MUSL)) {
334
+ return MUSL;
335
+ }
336
+ return null;
337
+ };
338
+ var getFamilyFromLddContent = (content) => {
339
+ if (content.includes(MUSL_ON_LDD)) {
340
+ return MUSL;
341
+ }
342
+ if (content.includes(GLIBC_ON_LDD)) {
343
+ return GLIBC;
344
+ }
345
+ return null;
346
+ };
347
+ var familyFromFilesystem = async () => {
348
+ if (cachedFamilyFilesystem !== undefined) {
349
+ return cachedFamilyFilesystem;
350
+ }
351
+ cachedFamilyFilesystem = null;
352
+ try {
353
+ const lddContent = await readFile(LDD_PATH);
354
+ cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
355
+ } catch (e) {}
356
+ return cachedFamilyFilesystem;
357
+ };
358
+ var familyFromFilesystemSync = () => {
359
+ if (cachedFamilyFilesystem !== undefined) {
360
+ return cachedFamilyFilesystem;
361
+ }
362
+ cachedFamilyFilesystem = null;
363
+ try {
364
+ const lddContent = readFileSync2(LDD_PATH);
365
+ cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
366
+ } catch (e) {}
367
+ return cachedFamilyFilesystem;
368
+ };
369
+ var family = async () => {
370
+ let family2 = null;
371
+ if (isLinux()) {
372
+ family2 = await familyFromFilesystem();
373
+ if (!family2) {
374
+ family2 = familyFromReport();
375
+ }
376
+ if (!family2) {
377
+ const out = await safeCommand();
378
+ family2 = familyFromCommand(out);
379
+ }
380
+ }
381
+ return family2;
382
+ };
383
+ var familySync = () => {
384
+ let family2 = null;
385
+ if (isLinux()) {
386
+ family2 = familyFromFilesystemSync();
387
+ if (!family2) {
388
+ family2 = familyFromReport();
389
+ }
390
+ if (!family2) {
391
+ const out = safeCommandSync();
392
+ family2 = familyFromCommand(out);
393
+ }
394
+ }
395
+ return family2;
396
+ };
397
+ var isNonGlibcLinux = async () => isLinux() && await family() !== GLIBC;
398
+ var isNonGlibcLinuxSync = () => isLinux() && familySync() !== GLIBC;
399
+ var versionFromFilesystem = async () => {
400
+ if (cachedVersionFilesystem !== undefined) {
401
+ return cachedVersionFilesystem;
402
+ }
403
+ cachedVersionFilesystem = null;
404
+ try {
405
+ const lddContent = await readFile(LDD_PATH);
406
+ const versionMatch = lddContent.match(RE_GLIBC_VERSION);
407
+ if (versionMatch) {
408
+ cachedVersionFilesystem = versionMatch[1];
409
+ }
410
+ } catch (e) {}
411
+ return cachedVersionFilesystem;
412
+ };
413
+ var versionFromFilesystemSync = () => {
414
+ if (cachedVersionFilesystem !== undefined) {
415
+ return cachedVersionFilesystem;
416
+ }
417
+ cachedVersionFilesystem = null;
418
+ try {
419
+ const lddContent = readFileSync2(LDD_PATH);
420
+ const versionMatch = lddContent.match(RE_GLIBC_VERSION);
421
+ if (versionMatch) {
422
+ cachedVersionFilesystem = versionMatch[1];
423
+ }
424
+ } catch (e) {}
425
+ return cachedVersionFilesystem;
426
+ };
427
+ var versionFromReport = () => {
428
+ const report = getReport();
429
+ if (report.header && report.header.glibcVersionRuntime) {
430
+ return report.header.glibcVersionRuntime;
431
+ }
432
+ return null;
433
+ };
434
+ var versionSuffix = (s) => s.trim().split(/\s+/)[1];
435
+ var versionFromCommand = (out) => {
436
+ const [getconf, ldd1, ldd2] = out.split(/[\r\n]+/);
437
+ if (getconf && getconf.includes(GLIBC)) {
438
+ return versionSuffix(getconf);
439
+ }
440
+ if (ldd1 && ldd2 && ldd1.includes(MUSL)) {
441
+ return versionSuffix(ldd2);
442
+ }
443
+ return null;
444
+ };
445
+ var version = async () => {
446
+ let version2 = null;
447
+ if (isLinux()) {
448
+ version2 = await versionFromFilesystem();
449
+ if (!version2) {
450
+ version2 = versionFromReport();
451
+ }
452
+ if (!version2) {
453
+ const out = await safeCommand();
454
+ version2 = versionFromCommand(out);
455
+ }
456
+ }
457
+ return version2;
458
+ };
459
+ var versionSync = () => {
460
+ let version2 = null;
461
+ if (isLinux()) {
462
+ version2 = versionFromFilesystemSync();
463
+ if (!version2) {
464
+ version2 = versionFromReport();
465
+ }
466
+ if (!version2) {
467
+ const out = safeCommandSync();
468
+ version2 = versionFromCommand(out);
469
+ }
470
+ }
471
+ return version2;
472
+ };
473
+ module.exports = {
474
+ GLIBC,
475
+ MUSL,
476
+ family,
477
+ familySync,
478
+ isNonGlibcLinux,
479
+ isNonGlibcLinuxSync,
480
+ version,
481
+ versionSync
482
+ };
483
+ });
484
+
485
+ // node_modules/libsql/auth.js
486
+ var require_auth = __commonJS((exports, module) => {
487
+ var Authorization = {
488
+ ALLOW: 0,
489
+ DENY: 1
490
+ };
491
+ module.exports = Authorization;
492
+ });
493
+
494
+ // node_modules/libsql/sqlite-error.js
495
+ var require_sqlite_error = __commonJS((exports, module) => {
496
+ var descriptor = { value: "SqliteError", writable: true, enumerable: false, configurable: true };
497
+ function SqliteError(message, code, rawCode) {
498
+ if (new.target !== SqliteError) {
499
+ return new SqliteError(message, code);
500
+ }
501
+ if (typeof code !== "string") {
502
+ throw new TypeError("Expected second argument to be a string");
503
+ }
504
+ Error.call(this, message);
505
+ descriptor.value = "" + message;
506
+ Object.defineProperty(this, "message", descriptor);
507
+ Error.captureStackTrace(this, SqliteError);
508
+ this.code = code;
509
+ this.rawCode = rawCode;
510
+ }
511
+ Object.setPrototypeOf(SqliteError, Error);
512
+ Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
513
+ Object.defineProperty(SqliteError.prototype, "name", descriptor);
514
+ module.exports = SqliteError;
515
+ });
516
+
517
+ // node_modules/libsql/index.js
518
+ var require_libsql = __commonJS((exports, module) => {
519
+ var __dirname = "/home/runner/work/meridian/meridian/node_modules/libsql";
520
+ var { load, currentTarget } = require_dist();
521
+ var { familySync, GLIBC, MUSL } = require_detect_libc();
522
+ function requireNative() {
523
+ if (process.env.LIBSQL_JS_DEV) {
524
+ return load(__dirname);
525
+ }
526
+ let target = currentTarget();
527
+ if (familySync() == GLIBC) {
528
+ switch (target) {
529
+ case "linux-x64-musl":
530
+ target = "linux-x64-gnu";
531
+ break;
532
+ case "linux-arm64-musl":
533
+ target = "linux-arm64-gnu";
534
+ break;
535
+ }
536
+ }
537
+ if (target === "linux-arm-gnueabihf" && familySync() == MUSL) {
538
+ target = "linux-arm-musleabihf";
539
+ }
540
+ return __require(`@libsql/${target}`);
541
+ }
542
+ var {
543
+ databaseOpen,
544
+ databaseOpenWithSync,
545
+ databaseInTransaction,
546
+ databaseInterrupt,
547
+ databaseClose,
548
+ databaseSyncSync,
549
+ databaseSyncUntilSync,
550
+ databaseExecSync,
551
+ databasePrepareSync,
552
+ databaseDefaultSafeIntegers,
553
+ databaseAuthorizer,
554
+ databaseLoadExtension,
555
+ databaseMaxWriteReplicationIndex,
556
+ statementRaw,
557
+ statementIsReader,
558
+ statementGet,
559
+ statementRun,
560
+ statementInterrupt,
561
+ statementRowsSync,
562
+ statementColumns,
563
+ statementSafeIntegers,
564
+ rowsNext
565
+ } = requireNative();
566
+ var Authorization = require_auth();
567
+ var SqliteError = require_sqlite_error();
568
+ function convertError(err) {
569
+ if (err.libsqlError) {
570
+ return new SqliteError(err.message, err.code, err.rawCode);
571
+ }
572
+ return err;
573
+ }
574
+
575
+ class Database {
576
+ constructor(path, opts) {
577
+ const encryptionCipher = opts?.encryptionCipher ?? "aes256cbc";
578
+ if (opts && opts.syncUrl) {
579
+ var authToken = "";
580
+ if (opts.syncAuth) {
581
+ console.warn("Warning: The `syncAuth` option is deprecated, please use `authToken` option instead.");
582
+ authToken = opts.syncAuth;
583
+ } else if (opts.authToken) {
584
+ authToken = opts.authToken;
585
+ }
586
+ const encryptionKey = opts?.encryptionKey ?? "";
587
+ const syncPeriod = opts?.syncPeriod ?? 0;
588
+ const readYourWrites = opts?.readYourWrites ?? true;
589
+ const offline = opts?.offline ?? false;
590
+ const remoteEncryptionKey = opts?.remoteEncryptionKey ?? "";
591
+ this.db = databaseOpenWithSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, readYourWrites, offline, remoteEncryptionKey);
592
+ } else {
593
+ const authToken2 = opts?.authToken ?? "";
594
+ const encryptionKey = opts?.encryptionKey ?? "";
595
+ const timeout = opts?.timeout ?? 0;
596
+ const remoteEncryptionKey = opts?.remoteEncryptionKey ?? "";
597
+ this.db = databaseOpen(path, authToken2, encryptionCipher, encryptionKey, timeout, remoteEncryptionKey);
598
+ }
599
+ this.memory = path === ":memory:";
600
+ this.readonly = false;
601
+ this.name = "";
602
+ this.open = true;
603
+ const db = this.db;
604
+ Object.defineProperties(this, {
605
+ inTransaction: {
606
+ get() {
607
+ return databaseInTransaction(db);
608
+ }
609
+ }
610
+ });
611
+ }
612
+ sync() {
613
+ return databaseSyncSync.call(this.db);
614
+ }
615
+ syncUntil(replicationIndex) {
616
+ return databaseSyncUntilSync.call(this.db, replicationIndex);
617
+ }
618
+ prepare(sql) {
619
+ try {
620
+ const stmt = databasePrepareSync.call(this.db, sql);
621
+ return new Statement(stmt);
622
+ } catch (err) {
623
+ throw convertError(err);
624
+ }
625
+ }
626
+ transaction(fn) {
627
+ if (typeof fn !== "function")
628
+ throw new TypeError("Expected first argument to be a function");
629
+ const db = this;
630
+ const wrapTxn = (mode) => {
631
+ return (...bindParameters) => {
632
+ db.exec("BEGIN " + mode);
633
+ try {
634
+ const result = fn(...bindParameters);
635
+ db.exec("COMMIT");
636
+ return result;
637
+ } catch (err) {
638
+ db.exec("ROLLBACK");
639
+ throw err;
640
+ }
641
+ };
642
+ };
643
+ const properties = {
644
+ default: { value: wrapTxn("") },
645
+ deferred: { value: wrapTxn("DEFERRED") },
646
+ immediate: { value: wrapTxn("IMMEDIATE") },
647
+ exclusive: { value: wrapTxn("EXCLUSIVE") },
648
+ database: { value: this, enumerable: true }
649
+ };
650
+ Object.defineProperties(properties.default.value, properties);
651
+ Object.defineProperties(properties.deferred.value, properties);
652
+ Object.defineProperties(properties.immediate.value, properties);
653
+ Object.defineProperties(properties.exclusive.value, properties);
654
+ return properties.default.value;
655
+ }
656
+ pragma(source, options) {
657
+ if (options == null)
658
+ options = {};
659
+ if (typeof source !== "string")
660
+ throw new TypeError("Expected first argument to be a string");
661
+ if (typeof options !== "object")
662
+ throw new TypeError("Expected second argument to be an options object");
663
+ const simple = options["simple"];
664
+ const stmt = this.prepare(`PRAGMA ${source}`, this, true);
665
+ return simple ? stmt.pluck().get() : stmt.all();
666
+ }
667
+ backup(filename, options) {
668
+ throw new Error("not implemented");
669
+ }
670
+ serialize(options) {
671
+ throw new Error("not implemented");
672
+ }
673
+ function(name, options, fn) {
674
+ if (options == null)
675
+ options = {};
676
+ if (typeof options === "function") {
677
+ fn = options;
678
+ options = {};
679
+ }
680
+ if (typeof name !== "string")
681
+ throw new TypeError("Expected first argument to be a string");
682
+ if (typeof fn !== "function")
683
+ throw new TypeError("Expected last argument to be a function");
684
+ if (typeof options !== "object")
685
+ throw new TypeError("Expected second argument to be an options object");
686
+ if (!name)
687
+ throw new TypeError("User-defined function name cannot be an empty string");
688
+ throw new Error("not implemented");
689
+ }
690
+ aggregate(name, options) {
691
+ if (typeof name !== "string")
692
+ throw new TypeError("Expected first argument to be a string");
693
+ if (typeof options !== "object" || options === null)
694
+ throw new TypeError("Expected second argument to be an options object");
695
+ if (!name)
696
+ throw new TypeError("User-defined function name cannot be an empty string");
697
+ throw new Error("not implemented");
698
+ }
699
+ table(name, factory) {
700
+ if (typeof name !== "string")
701
+ throw new TypeError("Expected first argument to be a string");
702
+ if (!name)
703
+ throw new TypeError("Virtual table module name cannot be an empty string");
704
+ throw new Error("not implemented");
705
+ }
706
+ authorizer(rules) {
707
+ databaseAuthorizer.call(this.db, rules);
708
+ }
709
+ loadExtension(...args) {
710
+ databaseLoadExtension.call(this.db, ...args);
711
+ }
712
+ maxWriteReplicationIndex() {
713
+ return databaseMaxWriteReplicationIndex.call(this.db);
714
+ }
715
+ exec(sql) {
716
+ try {
717
+ databaseExecSync.call(this.db, sql);
718
+ } catch (err) {
719
+ throw convertError(err);
720
+ }
721
+ }
722
+ interrupt() {
723
+ databaseInterrupt.call(this.db);
724
+ }
725
+ close() {
726
+ databaseClose.call(this.db);
727
+ this.open = false;
728
+ }
729
+ defaultSafeIntegers(toggle) {
730
+ databaseDefaultSafeIntegers.call(this.db, toggle ?? true);
731
+ return this;
732
+ }
733
+ unsafeMode(...args) {
734
+ throw new Error("not implemented");
735
+ }
736
+ }
737
+
738
+ class Statement {
739
+ constructor(stmt) {
740
+ this.stmt = stmt;
741
+ this.pluckMode = false;
742
+ }
743
+ raw(raw2) {
744
+ statementRaw.call(this.stmt, raw2 ?? true);
745
+ return this;
746
+ }
747
+ pluck(pluckMode) {
748
+ this.pluckMode = pluckMode ?? true;
749
+ return this;
750
+ }
751
+ get reader() {
752
+ return statementIsReader.call(this.stmt);
753
+ }
754
+ run(...bindParameters) {
755
+ try {
756
+ if (bindParameters.length == 1 && typeof bindParameters[0] === "object") {
757
+ return statementRun.call(this.stmt, bindParameters[0]);
758
+ } else {
759
+ return statementRun.call(this.stmt, bindParameters.flat());
760
+ }
761
+ } catch (err) {
762
+ throw convertError(err);
763
+ }
764
+ }
765
+ get(...bindParameters) {
766
+ try {
767
+ if (bindParameters.length == 1 && typeof bindParameters[0] === "object") {
768
+ return statementGet.call(this.stmt, bindParameters[0]);
769
+ } else {
770
+ return statementGet.call(this.stmt, bindParameters.flat());
771
+ }
772
+ } catch (err) {
773
+ throw convertError(err);
774
+ }
775
+ }
776
+ iterate(...bindParameters) {
777
+ var rows = undefined;
778
+ if (bindParameters.length == 1 && typeof bindParameters[0] === "object") {
779
+ rows = statementRowsSync.call(this.stmt, bindParameters[0]);
780
+ } else {
781
+ rows = statementRowsSync.call(this.stmt, bindParameters.flat());
782
+ }
783
+ const iter = {
784
+ nextRows: Array(100),
785
+ nextRowIndex: 100,
786
+ next() {
787
+ try {
788
+ if (this.nextRowIndex === 100) {
789
+ rowsNext.call(rows, this.nextRows);
790
+ this.nextRowIndex = 0;
791
+ }
792
+ const row = this.nextRows[this.nextRowIndex];
793
+ this.nextRows[this.nextRowIndex] = undefined;
794
+ if (!row) {
795
+ return { done: true };
796
+ }
797
+ this.nextRowIndex++;
798
+ return { value: row, done: false };
799
+ } catch (err) {
800
+ throw convertError(err);
801
+ }
802
+ },
803
+ [Symbol.iterator]() {
804
+ return this;
805
+ }
806
+ };
807
+ return iter;
808
+ }
809
+ all(...bindParameters) {
810
+ try {
811
+ const result = [];
812
+ for (const row of this.iterate(...bindParameters)) {
813
+ if (this.pluckMode) {
814
+ result.push(row[Object.keys(row)[0]]);
815
+ } else {
816
+ result.push(row);
817
+ }
818
+ }
819
+ return result;
820
+ } catch (err) {
821
+ throw convertError(err);
822
+ }
823
+ }
824
+ interrupt() {
825
+ statementInterrupt.call(this.stmt);
826
+ }
827
+ columns() {
828
+ return statementColumns.call(this.stmt);
829
+ }
830
+ safeIntegers(toggle) {
831
+ statementSafeIntegers.call(this.stmt, toggle ?? true);
832
+ return this;
833
+ }
834
+ }
835
+ module.exports = Database;
836
+ module.exports.Authorization = Authorization;
837
+ module.exports.SqliteError = SqliteError;
838
+ });
839
+
840
+ // src/telemetry/sqlite.ts
841
+ var exports_sqlite = {};
842
+ __export(exports_sqlite, {
843
+ createSqliteStores: () => createSqliteStores
844
+ });
845
+ function openDatabase(dbPath) {
846
+ const db = new import_libsql.default(dbPath);
847
+ db.pragma("journal_mode = WAL");
848
+ db.pragma("synchronous = NORMAL");
849
+ db.exec(METRICS_SCHEMA);
850
+ db.exec(LOGS_SCHEMA);
851
+ return db;
852
+ }
853
+
854
+ class SqliteTelemetryStore {
855
+ db;
856
+ retentionMs;
857
+ insertCount = 0;
858
+ insertStmt;
859
+ countStmt;
860
+ constructor(db, retentionDays) {
861
+ this.db = db;
862
+ this.retentionMs = retentionDays * 24 * 60 * 60 * 1000;
863
+ this.insertStmt = db.prepare(`
864
+ INSERT INTO metrics (
865
+ request_id, timestamp, adapter, model, request_model, mode,
866
+ is_resume, is_passthrough, lineage_type,
867
+ has_deferred_tools, deferred_tool_count, tool_count, discovered_tools, session_discovered_count,
868
+ message_count, sdk_session_id,
869
+ status, queue_wait_ms, proxy_overhead_ms, ttfb_ms,
870
+ upstream_duration_ms, total_duration_ms, content_blocks, text_events, error,
871
+ input_tokens, output_tokens, cache_read_input_tokens,
872
+ cache_creation_input_tokens, cache_hit_rate
873
+ ) VALUES (
874
+ @requestId, @timestamp, @adapter, @model, @requestModel, @mode,
875
+ @isResume, @isPassthrough, @lineageType,
876
+ @hasDeferredTools, @deferredToolCount, @toolCount, @discoveredTools, @sessionDiscoveredCount,
877
+ @messageCount, @sdkSessionId,
878
+ @status, @queueWaitMs, @proxyOverheadMs, @ttfbMs,
879
+ @upstreamDurationMs, @totalDurationMs, @contentBlocks, @textEvents, @error,
880
+ @inputTokens, @outputTokens, @cacheReadInputTokens,
881
+ @cacheCreationInputTokens, @cacheHitRate
882
+ )
883
+ `);
884
+ this.countStmt = db.prepare("SELECT COUNT(*) as cnt FROM metrics");
885
+ }
886
+ record(metric) {
887
+ try {
888
+ this.insertStmt.run({
889
+ requestId: metric.requestId,
890
+ timestamp: metric.timestamp,
891
+ adapter: metric.adapter ?? null,
892
+ model: metric.model,
893
+ requestModel: metric.requestModel ?? null,
894
+ mode: metric.mode,
895
+ isResume: metric.isResume ? 1 : 0,
896
+ isPassthrough: metric.isPassthrough ? 1 : 0,
897
+ lineageType: metric.lineageType ?? null,
898
+ hasDeferredTools: metric.hasDeferredTools ? 1 : metric.hasDeferredTools === false ? 0 : null,
899
+ deferredToolCount: metric.deferredToolCount ?? null,
900
+ toolCount: metric.toolCount ?? null,
901
+ discoveredTools: metric.discoveredTools ? JSON.stringify(metric.discoveredTools) : null,
902
+ sessionDiscoveredCount: metric.sessionDiscoveredCount ?? null,
903
+ messageCount: metric.messageCount ?? null,
904
+ sdkSessionId: metric.sdkSessionId ?? null,
905
+ status: metric.status,
906
+ queueWaitMs: metric.queueWaitMs,
907
+ proxyOverheadMs: metric.proxyOverheadMs,
908
+ ttfbMs: metric.ttfbMs ?? null,
909
+ upstreamDurationMs: metric.upstreamDurationMs,
910
+ totalDurationMs: metric.totalDurationMs,
911
+ contentBlocks: metric.contentBlocks,
912
+ textEvents: metric.textEvents,
913
+ error: metric.error ?? null,
914
+ inputTokens: metric.inputTokens ?? null,
915
+ outputTokens: metric.outputTokens ?? null,
916
+ cacheReadInputTokens: metric.cacheReadInputTokens ?? null,
917
+ cacheCreationInputTokens: metric.cacheCreationInputTokens ?? null,
918
+ cacheHitRate: metric.cacheHitRate ?? null
919
+ });
920
+ } catch (err) {
921
+ console.error("[telemetry] SQLite write failed, skipping:", err);
922
+ return;
923
+ }
924
+ if (++this.insertCount % CLEANUP_INTERVAL === 0) {
925
+ this.cleanup();
926
+ }
927
+ }
928
+ get size() {
929
+ try {
930
+ return this.countStmt.get().cnt;
931
+ } catch {
932
+ return 0;
933
+ }
934
+ }
935
+ getRecent(options = {}) {
936
+ const { limit = 50, since, model } = options;
937
+ const conditions = [];
938
+ const params = { limit };
939
+ if (since !== undefined) {
940
+ conditions.push("timestamp >= @since");
941
+ params.since = since;
942
+ }
943
+ if (model !== undefined) {
944
+ conditions.push("model = @model");
945
+ params.model = model;
946
+ }
947
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
948
+ const sql = `SELECT * FROM metrics ${where} ORDER BY timestamp DESC, id DESC LIMIT @limit`;
949
+ try {
950
+ const rows = this.db.prepare(sql).all(params);
951
+ return rows.map(rowToMetric);
952
+ } catch {
953
+ return [];
954
+ }
955
+ }
956
+ getLastForSession(sdkSessionId) {
957
+ try {
958
+ const row = this.db.prepare(`SELECT * FROM metrics WHERE sdk_session_id = ? AND error IS NULL ORDER BY timestamp DESC, id DESC LIMIT 1`).get(sdkSessionId);
959
+ return row ? rowToMetric(row) : undefined;
960
+ } catch {
961
+ return;
962
+ }
963
+ }
964
+ summarize(windowMs = 60 * 60 * 1000) {
965
+ const since = Date.now() - windowMs;
966
+ const metrics = this.getRecent({ limit: 1e5, since });
967
+ return computeSummary(metrics, windowMs);
968
+ }
969
+ clear() {
970
+ try {
971
+ this.db.exec("DELETE FROM metrics");
972
+ } catch {}
973
+ }
974
+ cleanup() {
975
+ try {
976
+ const cutoff = Date.now() - this.retentionMs;
977
+ this.db.prepare("DELETE FROM metrics WHERE timestamp < ?").run(cutoff);
978
+ this.db.prepare("DELETE FROM diagnostic_logs WHERE timestamp < ?").run(cutoff);
979
+ this.db.pragma("wal_checkpoint(TRUNCATE)");
980
+ } catch (err) {
981
+ console.error("[telemetry] SQLite cleanup failed:", err);
982
+ }
983
+ }
984
+ }
985
+
986
+ class SqliteDiagnosticLogStore {
987
+ db;
988
+ insertStmt;
989
+ constructor(db) {
990
+ this.db = db;
991
+ this.insertStmt = db.prepare(`
992
+ INSERT INTO diagnostic_logs (timestamp, level, category, request_id, message)
993
+ VALUES (@timestamp, @level, @category, @requestId, @message)
994
+ `);
995
+ }
996
+ log(entry) {
997
+ try {
998
+ this.insertStmt.run({
999
+ timestamp: Date.now(),
1000
+ level: entry.level,
1001
+ category: entry.category,
1002
+ requestId: entry.requestId ?? null,
1003
+ message: entry.message
1004
+ });
1005
+ } catch (err) {
1006
+ console.error("[telemetry] SQLite log write failed:", err);
1007
+ }
1008
+ }
1009
+ session(message, requestId) {
1010
+ this.log({ level: "info", category: "session", message, requestId });
1011
+ }
1012
+ lineage(message, requestId) {
1013
+ this.log({ level: "warn", category: "lineage", message, requestId });
1014
+ }
1015
+ error(message, requestId) {
1016
+ this.log({ level: "error", category: "error", message, requestId });
1017
+ }
1018
+ getRecent(options = {}) {
1019
+ const { limit = 100, since, category } = options;
1020
+ const conditions = [];
1021
+ const params = { limit };
1022
+ if (since !== undefined) {
1023
+ conditions.push("timestamp >= @since");
1024
+ params.since = since;
1025
+ }
1026
+ if (category !== undefined) {
1027
+ conditions.push("category = @category");
1028
+ params.category = category;
1029
+ }
1030
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1031
+ const sql = `SELECT * FROM diagnostic_logs ${where} ORDER BY timestamp DESC, id DESC LIMIT @limit`;
1032
+ try {
1033
+ const rows = this.db.prepare(sql).all(params);
1034
+ return rows.map((r) => ({
1035
+ timestamp: r.timestamp,
1036
+ level: r.level,
1037
+ category: r.category,
1038
+ requestId: r.request_id ?? undefined,
1039
+ message: r.message
1040
+ }));
1041
+ } catch {
1042
+ return [];
1043
+ }
1044
+ }
1045
+ clear() {
1046
+ try {
1047
+ this.db.exec("DELETE FROM diagnostic_logs");
1048
+ } catch {}
1049
+ }
1050
+ }
1051
+ function rowToMetric(r) {
1052
+ return {
1053
+ requestId: r.request_id,
1054
+ timestamp: r.timestamp,
1055
+ adapter: r.adapter ?? undefined,
1056
+ model: r.model,
1057
+ requestModel: r.request_model ?? undefined,
1058
+ mode: r.mode,
1059
+ isResume: r.is_resume === 1,
1060
+ isPassthrough: r.is_passthrough === 1,
1061
+ lineageType: r.lineage_type ?? undefined,
1062
+ hasDeferredTools: r.has_deferred_tools === 1 ? true : r.has_deferred_tools === 0 ? false : undefined,
1063
+ deferredToolCount: r.deferred_tool_count ?? undefined,
1064
+ toolCount: r.tool_count ?? undefined,
1065
+ discoveredTools: r.discovered_tools ? JSON.parse(r.discovered_tools) : undefined,
1066
+ sessionDiscoveredCount: r.session_discovered_count ?? undefined,
1067
+ messageCount: r.message_count ?? undefined,
1068
+ sdkSessionId: r.sdk_session_id ?? undefined,
1069
+ status: r.status,
1070
+ queueWaitMs: r.queue_wait_ms,
1071
+ proxyOverheadMs: r.proxy_overhead_ms,
1072
+ ttfbMs: r.ttfb_ms ?? null,
1073
+ upstreamDurationMs: r.upstream_duration_ms,
1074
+ totalDurationMs: r.total_duration_ms,
1075
+ contentBlocks: r.content_blocks,
1076
+ textEvents: r.text_events,
1077
+ error: r.error ?? null,
1078
+ inputTokens: r.input_tokens ?? undefined,
1079
+ outputTokens: r.output_tokens ?? undefined,
1080
+ cacheReadInputTokens: r.cache_read_input_tokens ?? undefined,
1081
+ cacheCreationInputTokens: r.cache_creation_input_tokens ?? undefined,
1082
+ cacheHitRate: r.cache_hit_rate ?? undefined
1083
+ };
1084
+ }
1085
+ function createSqliteStores(dbPath, retentionDays) {
1086
+ const db = openDatabase(dbPath);
1087
+ return {
1088
+ telemetry: new SqliteTelemetryStore(db, retentionDays),
1089
+ diagnostics: new SqliteDiagnosticLogStore(db),
1090
+ close: () => {
1091
+ try {
1092
+ db.close();
1093
+ } catch {}
1094
+ }
1095
+ };
1096
+ }
1097
+ var import_libsql, METRICS_SCHEMA = `
1098
+ CREATE TABLE IF NOT EXISTS metrics (
1099
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1100
+ request_id TEXT NOT NULL,
1101
+ timestamp INTEGER NOT NULL,
1102
+ adapter TEXT,
1103
+ model TEXT NOT NULL,
1104
+ request_model TEXT,
1105
+ mode TEXT NOT NULL,
1106
+ is_resume INTEGER NOT NULL,
1107
+ is_passthrough INTEGER NOT NULL,
1108
+ lineage_type TEXT,
1109
+ has_deferred_tools INTEGER,
1110
+ deferred_tool_count INTEGER,
1111
+ tool_count INTEGER,
1112
+ discovered_tools TEXT,
1113
+ session_discovered_count INTEGER,
1114
+ message_count INTEGER,
1115
+ sdk_session_id TEXT,
1116
+ status INTEGER NOT NULL,
1117
+ queue_wait_ms REAL NOT NULL,
1118
+ proxy_overhead_ms REAL NOT NULL,
1119
+ ttfb_ms REAL,
1120
+ upstream_duration_ms REAL NOT NULL,
1121
+ total_duration_ms REAL NOT NULL,
1122
+ content_blocks INTEGER NOT NULL,
1123
+ text_events INTEGER NOT NULL,
1124
+ error TEXT,
1125
+ input_tokens INTEGER,
1126
+ output_tokens INTEGER,
1127
+ cache_read_input_tokens INTEGER,
1128
+ cache_creation_input_tokens INTEGER,
1129
+ cache_hit_rate REAL
1130
+ );
1131
+ CREATE INDEX IF NOT EXISTS idx_metrics_ts ON metrics(timestamp);
1132
+ CREATE INDEX IF NOT EXISTS idx_metrics_model ON metrics(model);
1133
+ CREATE INDEX IF NOT EXISTS idx_metrics_session_success ON metrics(sdk_session_id, timestamp DESC, id DESC);
1134
+ `, LOGS_SCHEMA = `
1135
+ CREATE TABLE IF NOT EXISTS diagnostic_logs (
1136
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1137
+ timestamp INTEGER NOT NULL,
1138
+ level TEXT NOT NULL,
1139
+ category TEXT NOT NULL,
1140
+ request_id TEXT,
1141
+ message TEXT NOT NULL
1142
+ );
1143
+ CREATE INDEX IF NOT EXISTS idx_logs_ts ON diagnostic_logs(timestamp);
1144
+ CREATE INDEX IF NOT EXISTS idx_logs_cat ON diagnostic_logs(category);
1145
+ `, CLEANUP_INTERVAL = 1000;
1146
+ var init_sqlite = __esm(() => {
1147
+ init_percentiles();
1148
+ import_libsql = __toESM(require_libsql(), 1);
1149
+ });
26
1150
 
27
1151
  // node_modules/hono/dist/compose.js
28
1152
  var compose = (middleware, onError, onNotFound) => {
@@ -2187,7 +3311,8 @@ var DEFAULT_PROXY_CONFIG = {
2187
3311
  idleTimeoutSeconds: 120,
2188
3312
  silent: false,
2189
3313
  profiles: undefined,
2190
- defaultProfile: undefined
3314
+ defaultProfile: undefined,
3315
+ version: undefined
2191
3316
  };
2192
3317
 
2193
3318
  // src/env.ts
@@ -2198,6 +3323,13 @@ function envBool(suffix) {
2198
3323
  const val = env(suffix);
2199
3324
  return val === "1" || val === "true" || val === "yes";
2200
3325
  }
3326
+ function envInt(suffix, defaultValue) {
3327
+ const val = env(suffix);
3328
+ if (!val)
3329
+ return defaultValue;
3330
+ const parsed = parseInt(val, 10);
3331
+ return Number.isFinite(parsed) ? parsed : defaultValue;
3332
+ }
2201
3333
 
2202
3334
  // src/proxy/server.ts
2203
3335
  import { exec as execCallback2 } from "child_process";
@@ -6270,7 +7402,12 @@ function stripMcpPrefix(toolName) {
6270
7402
  return toolName;
6271
7403
  }
6272
7404
 
7405
+ // src/telemetry/index.ts
7406
+ import { join } from "node:path";
7407
+ import { homedir } from "node:os";
7408
+
6273
7409
  // src/telemetry/store.ts
7410
+ init_percentiles();
6274
7411
  var DEFAULT_CAPACITY = 1000;
6275
7412
  function getCapacity() {
6276
7413
  const raw2 = process.env.MERIDIAN_TELEMETRY_SIZE ?? process.env.CLAUDE_PROXY_TELEMETRY_SIZE;
@@ -6282,7 +7419,7 @@ function getCapacity() {
6282
7419
  return parsed;
6283
7420
  }
6284
7421
 
6285
- class TelemetryStore {
7422
+ class MemoryTelemetryStore {
6286
7423
  buffer;
6287
7424
  head = 0;
6288
7425
  count = 0;
@@ -6329,94 +7466,7 @@ class TelemetryStore {
6329
7466
  summarize(windowMs = 60 * 60 * 1000) {
6330
7467
  const since = Date.now() - windowMs;
6331
7468
  const metrics = this.getRecent({ limit: this.capacity, since });
6332
- if (metrics.length === 0) {
6333
- const emptyPhase = { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
6334
- return {
6335
- windowMs,
6336
- totalRequests: 0,
6337
- errorCount: 0,
6338
- requestsPerMinute: 0,
6339
- queueWait: emptyPhase,
6340
- proxyOverhead: emptyPhase,
6341
- ttfb: emptyPhase,
6342
- upstreamDuration: emptyPhase,
6343
- totalDuration: emptyPhase,
6344
- byModel: {},
6345
- byMode: {},
6346
- tokenUsage: {
6347
- totalInputTokens: 0,
6348
- totalOutputTokens: 0,
6349
- totalCacheReadTokens: 0,
6350
- totalCacheCreationTokens: 0,
6351
- avgCacheHitRate: 0,
6352
- cacheMissOnResumeCount: 0
6353
- }
6354
- };
6355
- }
6356
- const errorCount = metrics.filter((m) => m.error !== null).length;
6357
- const oldest = metrics[metrics.length - 1].timestamp;
6358
- const newest = metrics[0].timestamp;
6359
- const spanMs = Math.max(newest - oldest, 1);
6360
- const requestsPerMinute = metrics.length / spanMs * 60000;
6361
- const queueWaits = metrics.map((m) => m.queueWaitMs);
6362
- const overheads = metrics.map((m) => m.proxyOverheadMs);
6363
- const ttfbs = metrics.filter((m) => m.ttfbMs !== null).map((m) => m.ttfbMs);
6364
- const upstreams = metrics.map((m) => m.upstreamDurationMs);
6365
- const totals = metrics.map((m) => m.totalDurationMs);
6366
- const byModel = {};
6367
- for (const m of metrics) {
6368
- const modelKey = m.requestModel || m.model;
6369
- const entry = byModel[modelKey] ??= { count: 0, totalMs: 0 };
6370
- entry.count++;
6371
- entry.totalMs += m.totalDurationMs;
6372
- }
6373
- const byMode = {};
6374
- for (const m of metrics) {
6375
- const entry = byMode[m.mode] ??= { count: 0, totalMs: 0 };
6376
- entry.count++;
6377
- entry.totalMs += m.totalDurationMs;
6378
- }
6379
- let totalInputTokens = 0;
6380
- let totalOutputTokens = 0;
6381
- let totalCacheReadTokens = 0;
6382
- let totalCacheCreationTokens = 0;
6383
- let cacheHitRateSum = 0;
6384
- let cacheHitRateCount = 0;
6385
- let cacheMissOnResumeCount = 0;
6386
- for (const m of metrics) {
6387
- totalInputTokens += m.inputTokens ?? 0;
6388
- totalOutputTokens += m.outputTokens ?? 0;
6389
- totalCacheReadTokens += m.cacheReadInputTokens ?? 0;
6390
- totalCacheCreationTokens += m.cacheCreationInputTokens ?? 0;
6391
- if (m.cacheHitRate !== undefined) {
6392
- cacheHitRateSum += m.cacheHitRate;
6393
- cacheHitRateCount++;
6394
- }
6395
- if (m.isResume && m.cacheHitRate !== undefined && m.cacheHitRate === 0) {
6396
- cacheMissOnResumeCount++;
6397
- }
6398
- }
6399
- return {
6400
- windowMs,
6401
- totalRequests: metrics.length,
6402
- errorCount,
6403
- requestsPerMinute: Math.round(requestsPerMinute * 100) / 100,
6404
- queueWait: computePercentiles(queueWaits),
6405
- proxyOverhead: computePercentiles(overheads),
6406
- ttfb: ttfbs.length > 0 ? computePercentiles(ttfbs) : { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 },
6407
- upstreamDuration: computePercentiles(upstreams),
6408
- totalDuration: computePercentiles(totals),
6409
- byModel: Object.fromEntries(Object.entries(byModel).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
6410
- byMode: Object.fromEntries(Object.entries(byMode).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
6411
- tokenUsage: {
6412
- totalInputTokens,
6413
- totalOutputTokens,
6414
- totalCacheReadTokens,
6415
- totalCacheCreationTokens,
6416
- avgCacheHitRate: cacheHitRateCount > 0 ? Math.round(cacheHitRateSum / cacheHitRateCount * 100) / 100 : 0,
6417
- cacheMissOnResumeCount
6418
- }
6419
- };
7469
+ return computeSummary(metrics, windowMs);
6420
7470
  }
6421
7471
  clear() {
6422
7472
  this.buffer = new Array(this.capacity).fill(null);
@@ -6424,25 +7474,12 @@ class TelemetryStore {
6424
7474
  this.count = 0;
6425
7475
  }
6426
7476
  }
6427
- function computePercentiles(values) {
6428
- if (values.length === 0)
6429
- return { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
6430
- const sorted = [...values].sort((a, b) => a - b);
6431
- const sum = sorted.reduce((a, b) => a + b, 0);
6432
- return {
6433
- p50: sorted[Math.floor(sorted.length * 0.5)],
6434
- p95: sorted[Math.floor(sorted.length * 0.95)],
6435
- p99: sorted[Math.floor(sorted.length * 0.99)],
6436
- min: sorted[0],
6437
- max: sorted[sorted.length - 1],
6438
- avg: Math.round(sum / sorted.length)
6439
- };
6440
- }
6441
- var telemetryStore = new TelemetryStore;
7477
+ var telemetryStore = new MemoryTelemetryStore;
7478
+
6442
7479
  // src/telemetry/logStore.ts
6443
7480
  var DEFAULT_CAPACITY2 = 500;
6444
7481
 
6445
- class DiagnosticLogStore {
7482
+ class MemoryDiagnosticLogStore {
6446
7483
  buffer;
6447
7484
  head = 0;
6448
7485
  count = 0;
@@ -6488,7 +7525,7 @@ class DiagnosticLogStore {
6488
7525
  this.count = 0;
6489
7526
  }
6490
7527
  }
6491
- var diagnosticLog = new DiagnosticLogStore;
7528
+ var diagnosticLog = new MemoryDiagnosticLogStore;
6492
7529
  // src/telemetry/routes.ts
6493
7530
  import { existsSync, readFileSync } from "node:fs";
6494
7531
  import { resolve, dirname } from "node:path";
@@ -6866,7 +7903,7 @@ function createTelemetryRoutes() {
6866
7903
  const limit = Number.parseInt(c.req.query("limit") || "50", 10);
6867
7904
  const since = c.req.query("since") ? Number.parseInt(c.req.query("since"), 10) : undefined;
6868
7905
  const model = c.req.query("model") || undefined;
6869
- const requests = telemetryStore.getRecent({
7906
+ const requests = telemetryStore2.getRecent({
6870
7907
  limit: Math.min(limit, 500),
6871
7908
  since,
6872
7909
  model
@@ -6875,14 +7912,14 @@ function createTelemetryRoutes() {
6875
7912
  });
6876
7913
  routes.get("/summary", (c) => {
6877
7914
  const windowMs = Number.parseInt(c.req.query("window") || "3600000", 10);
6878
- const summary = telemetryStore.summarize(windowMs);
7915
+ const summary = telemetryStore2.summarize(windowMs);
6879
7916
  return c.json(summary);
6880
7917
  });
6881
7918
  routes.get("/logs", (c) => {
6882
7919
  const limit = Number.parseInt(c.req.query("limit") || "100", 10);
6883
7920
  const since = c.req.query("since") ? Number.parseInt(c.req.query("since"), 10) : undefined;
6884
7921
  const category = c.req.query("category") || undefined;
6885
- const logs = diagnosticLog.getRecent({
7922
+ const logs = diagnosticLog2.getRecent({
6886
7923
  limit: Math.min(limit, 500),
6887
7924
  since,
6888
7925
  category
@@ -7014,6 +8051,95 @@ refresh();setInterval(refresh,10000);
7014
8051
  </script>
7015
8052
  </body>
7016
8053
  </html>`;
8054
+
8055
+ // src/telemetry/index.ts
8056
+ init_percentiles();
8057
+
8058
+ // src/telemetry/prometheus.ts
8059
+ var DURATION_BUCKETS = [10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 1e4, 30000];
8060
+ var PHASES = [
8061
+ { key: "queue_wait", extract: (m) => m.queueWaitMs },
8062
+ { key: "proxy_overhead", extract: (m) => m.proxyOverheadMs },
8063
+ { key: "ttfb", extract: (m) => m.ttfbMs },
8064
+ { key: "upstream", extract: (m) => m.upstreamDurationMs },
8065
+ { key: "total", extract: (m) => m.totalDurationMs }
8066
+ ];
8067
+ function escapeLabelValue(v) {
8068
+ return v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
8069
+ }
8070
+ function formatLabels(labels) {
8071
+ return Object.entries(labels).map(([k, v]) => `${k}="${escapeLabelValue(v)}"`).join(",");
8072
+ }
8073
+ function renderPrometheusMetrics(store) {
8074
+ const metrics = store.getRecent({ limit: 1e4 });
8075
+ const lines = [];
8076
+ lines.push("# HELP meridian_requests_total Total proxy requests");
8077
+ lines.push("# TYPE meridian_requests_total counter");
8078
+ const counters = new Map;
8079
+ for (const m of metrics) {
8080
+ const key = `${m.model}\x00${m.mode}\x00${m.status}`;
8081
+ counters.set(key, (counters.get(key) ?? 0) + 1);
8082
+ }
8083
+ for (const [key, count] of counters) {
8084
+ const [model, mode, status] = key.split("\x00");
8085
+ lines.push(`meridian_requests_total{${formatLabels({ model, mode, status })}} ${count}`);
8086
+ }
8087
+ lines.push("");
8088
+ lines.push("# HELP meridian_request_duration_ms Request duration by phase in milliseconds");
8089
+ lines.push("# TYPE meridian_request_duration_ms histogram");
8090
+ for (const phase of PHASES) {
8091
+ const values = [];
8092
+ for (const m of metrics) {
8093
+ const v = phase.extract(m);
8094
+ if (v !== null)
8095
+ values.push(v);
8096
+ }
8097
+ const phaseLabel = `phase="${escapeLabelValue(phase.key)}"`;
8098
+ for (const le of DURATION_BUCKETS) {
8099
+ const count = values.filter((v) => v <= le).length;
8100
+ lines.push(`meridian_request_duration_ms_bucket{${phaseLabel},le="${le}"} ${count}`);
8101
+ }
8102
+ lines.push(`meridian_request_duration_ms_bucket{${phaseLabel},le="+Inf"} ${values.length}`);
8103
+ const sum = values.reduce((a, b) => a + b, 0);
8104
+ lines.push(`meridian_request_duration_ms_sum{${phaseLabel}} ${sum}`);
8105
+ lines.push(`meridian_request_duration_ms_count{${phaseLabel}} ${values.length}`);
8106
+ }
8107
+ lines.push("");
8108
+ return lines.join(`
8109
+ `);
8110
+ }
8111
+
8112
+ // src/telemetry/index.ts
8113
+ init_sqlite();
8114
+ function getDefaultDbPath() {
8115
+ return join(homedir(), ".config", "meridian", "telemetry.db");
8116
+ }
8117
+ function createStores() {
8118
+ if (!envBool("TELEMETRY_PERSIST")) {
8119
+ return {
8120
+ telemetry: new MemoryTelemetryStore,
8121
+ diagnostics: new MemoryDiagnosticLogStore
8122
+ };
8123
+ }
8124
+ try {
8125
+ const { createSqliteStores: createSqliteStores2 } = (init_sqlite(), __toCommonJS(exports_sqlite));
8126
+ const dbPath = env("TELEMETRY_DB") ?? getDefaultDbPath();
8127
+ const retention = envInt("TELEMETRY_RETENTION_DAYS", 7);
8128
+ const stores = createSqliteStores2(dbPath, retention);
8129
+ console.error(`[telemetry] SQLite persistence enabled: ${dbPath} (${retention}d retention)`);
8130
+ return { telemetry: stores.telemetry, diagnostics: stores.diagnostics };
8131
+ } catch {
8132
+ console.warn("[telemetry] MERIDIAN_TELEMETRY_PERSIST is set but libsql is not installed. Run: npm install libsql");
8133
+ return {
8134
+ telemetry: new MemoryTelemetryStore,
8135
+ diagnostics: new MemoryDiagnosticLogStore
8136
+ };
8137
+ }
8138
+ }
8139
+ var stores = createStores();
8140
+ var telemetryStore2 = stores.telemetry;
8141
+ var diagnosticLog2 = stores.diagnostics;
8142
+
7017
8143
  // src/proxy/errors.ts
7018
8144
  function classifyError(errMsg) {
7019
8145
  const lower = errMsg.toLowerCase();
@@ -7121,7 +8247,7 @@ function isExtraUsageRequiredError(errMsg) {
7121
8247
  import { exec as execCallback } from "child_process";
7122
8248
  import { existsSync as existsSync2 } from "fs";
7123
8249
  import { fileURLToPath as fileURLToPath2 } from "url";
7124
- import { join, dirname as dirname2 } from "path";
8250
+ import { join as join2, dirname as dirname2 } from "path";
7125
8251
  import { promisify } from "util";
7126
8252
  var exec = promisify(execCallback);
7127
8253
  var AUTH_STATUS_CACHE_TTL_MS = 60000;
@@ -7263,7 +8389,7 @@ async function resolveClaudeExecutableAsync() {
7263
8389
  if (runningUnderBun) {
7264
8390
  try {
7265
8391
  const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
7266
- const sdkCliJs = join(dirname2(sdkPath), "cli.js");
8392
+ const sdkCliJs = join2(dirname2(sdkPath), "cli.js");
7267
8393
  if (existsSync2(sdkCliJs)) {
7268
8394
  cachedClaudePath = sdkCliJs;
7269
8395
  return sdkCliJs;
@@ -7281,7 +8407,7 @@ async function resolveClaudeExecutableAsync() {
7281
8407
  if (!runningUnderBun) {
7282
8408
  try {
7283
8409
  const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
7284
- const sdkCliJs = join(dirname2(sdkPath), "cli.js");
8410
+ const sdkCliJs = join2(dirname2(sdkPath), "cli.js");
7285
8411
  if (existsSync2(sdkCliJs)) {
7286
8412
  cachedClaudePath = sdkCliJs;
7287
8413
  return sdkCliJs;
@@ -14268,7 +15394,7 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
14268
15394
  if (suffixOverlap >= MIN_SUFFIX_FOR_COMPACTION && cached.messageHashes.length >= MIN_STORED_FOR_COMPACTION && suffixStartInIncoming > 0) {
14269
15395
  const compactionMsg = `Compaction detected (key=${cacheKey2.slice(0, 8)}…): suffix overlap ${suffixOverlap}/${cached.messageHashes.length}. Allowing resume.`;
14270
15396
  console.error(`[PROXY] ${compactionMsg}`);
14271
- diagnosticLog.lineage(compactionMsg);
15397
+ diagnosticLog2.lineage(compactionMsg);
14272
15398
  cached.lineageHash = computeLineageHash(messages);
14273
15399
  cached.messageHashes = incomingHashes;
14274
15400
  cached.messageCount = messages.length;
@@ -14286,13 +15412,13 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
14286
15412
  }
14287
15413
  const undoMsg = `Undo detected (key=${cacheKey2.slice(0, 8)}…): prefix overlap ${prefixOverlap}/${cached.messageHashes.length}, rollback UUID: ${rollbackUuid || "none (legacy session)"}.`;
14288
15414
  console.error(`[PROXY] ${undoMsg}`);
14289
- diagnosticLog.lineage(undoMsg);
15415
+ diagnosticLog2.lineage(undoMsg);
14290
15416
  return { type: "undo", session: cached, prefixOverlap, rollbackUuid };
14291
15417
  }
14292
15418
  if (prefixOverlap > 0 && messages.length > cached.messageCount) {
14293
15419
  const modifiedMsg = `Modified continuation (key=${cacheKey2.slice(0, 8)}…): prefix overlap ${prefixOverlap}/${cached.messageHashes.length}, incoming ${messages.length} msgs. Allowing resume.`;
14294
15420
  console.error(`[PROXY] ${modifiedMsg}`);
14295
- diagnosticLog.lineage(modifiedMsg);
15421
+ diagnosticLog2.lineage(modifiedMsg);
14296
15422
  cached.lineageHash = computeLineageHash(messages.slice(0, messages.length));
14297
15423
  cached.messageHashes = incomingHashes;
14298
15424
  cached.messageCount = messages.length;
@@ -14379,8 +15505,8 @@ import {
14379
15505
  unlinkSync,
14380
15506
  writeFileSync
14381
15507
  } from "node:fs";
14382
- import { homedir } from "node:os";
14383
- import { join as join2 } from "node:path";
15508
+ import { homedir as homedir2 } from "node:os";
15509
+ import { join as join3 } from "node:path";
14384
15510
  var DEFAULT_MAX_STORED_SESSIONS = 1e4;
14385
15511
  var STALE_LOCK_THRESHOLD_MS = 30000;
14386
15512
  function getMaxStoredSessions() {
@@ -14431,11 +15557,11 @@ function getStorePath() {
14431
15557
  if (!existsSync3(dir)) {
14432
15558
  mkdirSync(dir, { recursive: true });
14433
15559
  }
14434
- return join2(dir, "sessions.json");
15560
+ return join3(dir, "sessions.json");
14435
15561
  }
14436
15562
  function getDefaultCacheDir() {
14437
- const newDir = join2(homedir(), ".cache", "meridian");
14438
- const oldDir = join2(homedir(), ".cache", "opencode-claude-max-proxy");
15563
+ const newDir = join3(homedir2(), ".cache", "meridian");
15564
+ const oldDir = join3(homedir2(), ".cache", "opencode-claude-max-proxy");
14439
15565
  if (existsSync3(newDir))
14440
15566
  return newDir;
14441
15567
  if (existsSync3(oldDir)) {
@@ -14867,7 +15993,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
14867
15993
  isResume,
14868
15994
  isPassthrough
14869
15995
  };
14870
- const prevMetric = telemetryStore.getLastForSession(sdkSessionId);
15996
+ const prevMetric = telemetryStore2.getLastForSession(sdkSessionId);
14871
15997
  const previous = prevMetric ? {
14872
15998
  requestId: prevMetric.requestId,
14873
15999
  turnNumber: turnNumber - 1,
@@ -14886,7 +16012,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
14886
16012
  console.error(line);
14887
16013
  }
14888
16014
  for (const a of anomalies) {
14889
- diagnosticLog.log({
16015
+ diagnosticLog2.log({
14890
16016
  level: a.severity === "critical" ? "error" : "warn",
14891
16017
  category: "token",
14892
16018
  message: `${requestId} ${a.type}: ${a.detail}`,
@@ -14897,6 +16023,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
14897
16023
  }
14898
16024
  function createProxyServer(config = {}) {
14899
16025
  const finalConfig = { ...DEFAULT_PROXY_CONFIG, ...config };
16026
+ const serverVersion = finalConfig.version ?? "unknown";
14900
16027
  restoreActiveProfile(finalConfig.profiles);
14901
16028
  const sessionDiscoveredTools = new Map;
14902
16029
  const app = new Hono2;
@@ -14908,7 +16035,7 @@ function createProxyServer(config = {}) {
14908
16035
  status: "ok",
14909
16036
  service: "meridian",
14910
16037
  format: "anthropic",
14911
- endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/models", "/telemetry", "/health"]
16038
+ endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/models", "/telemetry", "/metrics", "/health"]
14912
16039
  });
14913
16040
  }
14914
16041
  return c.html(landingHtml);
@@ -15031,14 +16158,14 @@ function createProxyServer(config = {}) {
15031
16158
  const toolCount = body.tools?.length ?? 0;
15032
16159
  const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name} model=${model} stream=${stream2} tools=${toolCount} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
15033
16160
  console.error(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
15034
- diagnosticLog.session(`${requestLogLine}`, requestMeta.requestId);
16161
+ diagnosticLog2.session(`${requestLogLine}`, requestMeta.requestId);
15035
16162
  if (lineageResult.type === "diverged" && profileSessionId) {
15036
16163
  const recovery = lookupSessionRecovery(profileSessionId);
15037
16164
  if (recovery) {
15038
16165
  const prevId = recovery.previousClaudeSessionId || recovery.claudeSessionId;
15039
16166
  const recoveryMsg = `${requestMeta.requestId} SESSION RECOVERY: previous conversation available. Run: claude --resume ${prevId}`;
15040
16167
  console.error(`[PROXY] ${recoveryMsg}`);
15041
- diagnosticLog.session(recoveryMsg, requestMeta.requestId);
16168
+ diagnosticLog2.session(recoveryMsg, requestMeta.requestId);
15042
16169
  }
15043
16170
  }
15044
16171
  claudeLog("request.received", {
@@ -15471,7 +16598,7 @@ Subprocess stderr: ${stderrOutput}`;
15471
16598
  });
15472
16599
  const nonStreamQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
15473
16600
  checkTokenHealth(requestMeta.requestId, currentSessionId || resumeSessionId, lastUsage, allMessages.length, isResume, passthrough);
15474
- telemetryStore.record({
16601
+ telemetryStore2.record({
15475
16602
  requestId: requestMeta.requestId,
15476
16603
  timestamp: Date.now(),
15477
16604
  adapter: adapter.name,
@@ -15969,7 +17096,7 @@ data: {"type":"message_stop"}
15969
17096
  });
15970
17097
  const streamQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
15971
17098
  checkTokenHealth(requestMeta.requestId, currentSessionId || resumeSessionId, lastUsage, allMessages.length, isResume, passthrough);
15972
- telemetryStore.record({
17099
+ telemetryStore2.record({
15973
17100
  requestId: requestMeta.requestId,
15974
17101
  timestamp: Date.now(),
15975
17102
  adapter: adapter.name,
@@ -16088,7 +17215,7 @@ data: ${JSON.stringify({
16088
17215
  const classified = classifyError(errMsg);
16089
17216
  claudeLog("proxy.error", { error: errMsg, classified: classified.type });
16090
17217
  const errorQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
16091
- telemetryStore.record({
17218
+ telemetryStore2.record({
16092
17219
  requestId: requestMeta.requestId,
16093
17220
  timestamp: Date.now(),
16094
17221
  adapter: adapter.name,
@@ -16132,6 +17259,12 @@ data: ${JSON.stringify({
16132
17259
  app.post("/v1/messages", (c) => handleWithQueue(c, "/v1/messages"));
16133
17260
  app.post("/messages", (c) => handleWithQueue(c, "/messages"));
16134
17261
  app.route("/telemetry", createTelemetryRoutes());
17262
+ app.get("/metrics", (c) => {
17263
+ const body = renderPrometheusMetrics(telemetryStore2);
17264
+ return c.body(body, 200, {
17265
+ "Content-Type": "text/plain; version=0.0.4; charset=utf-8"
17266
+ });
17267
+ });
16135
17268
  app.get("/health", async (c) => {
16136
17269
  try {
16137
17270
  const healthProfile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile);
@@ -16140,6 +17273,7 @@ data: ${JSON.stringify({
16140
17273
  if (!auth) {
16141
17274
  return c.json({
16142
17275
  status: "degraded",
17276
+ version: serverVersion,
16143
17277
  error: "Could not verify auth status",
16144
17278
  mode: envBool("PASSTHROUGH") ? "passthrough" : "internal"
16145
17279
  });
@@ -16147,12 +17281,14 @@ data: ${JSON.stringify({
16147
17281
  if (!auth.loggedIn) {
16148
17282
  return c.json({
16149
17283
  status: "unhealthy",
17284
+ version: serverVersion,
16150
17285
  error: "Not logged in. Run: claude login",
16151
17286
  auth: { loggedIn: false }
16152
17287
  }, 503);
16153
17288
  }
16154
17289
  return c.json({
16155
17290
  status: "healthy",
17291
+ version: serverVersion,
16156
17292
  auth: {
16157
17293
  loggedIn: true,
16158
17294
  email: auth.email,
@@ -16164,6 +17300,7 @@ data: ${JSON.stringify({
16164
17300
  } catch {
16165
17301
  return c.json({
16166
17302
  status: "degraded",
17303
+ version: serverVersion,
16167
17304
  error: "Could not verify auth status",
16168
17305
  mode: envBool("PASSTHROUGH") ? "passthrough" : "internal"
16169
17306
  });
@@ -16191,7 +17328,7 @@ data: ${JSON.stringify({
16191
17328
  });
16192
17329
  });
16193
17330
  app.get("/profiles", async (c) => {
16194
- const { profilePageHtml } = await import("./profilePage-9nkbct3w.js");
17331
+ const { profilePageHtml } = await import("./profilePage-e90fq8ye.js");
16195
17332
  return c.html(profilePageHtml);
16196
17333
  });
16197
17334
  app.post("/profiles/active", async (c) => {