@omnicross/daemon 0.1.6 → 0.1.8

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/dist/cli.cjs CHANGED
@@ -1508,10 +1508,20 @@ function assertLoopbackGatewayUrl(value) {
1508
1508
  // src/ports/JsonOutboundKeyDb.ts
1509
1509
  var import_node_fs6 = require("fs");
1510
1510
  var JsonOutboundKeyDb = class {
1511
- constructor(keysPath) {
1511
+ /**
1512
+ * @param secretBox OPTIONAL reversible-secret codec. When present, a created
1513
+ * key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
1514
+ * operator "view key" affordance via `outboundApiKeysReveal`). When absent the
1515
+ * store stays hash-only (byte-identical to the legacy behavior) and reveal
1516
+ * always returns `null`. Existing 1-arg call sites (tests, lightweight
1517
+ * embedders) keep working.
1518
+ */
1519
+ constructor(keysPath, secretBox3) {
1512
1520
  this.keysPath = keysPath;
1521
+ this.secretBox = secretBox3;
1513
1522
  }
1514
1523
  keysPath;
1524
+ secretBox;
1515
1525
  async outboundApiKeysList() {
1516
1526
  return this.readRows();
1517
1527
  }
@@ -1537,10 +1547,27 @@ var JsonOutboundKeyDb = class {
1537
1547
  allowedEndpoints: input.allowedEndpoints,
1538
1548
  loopbackOnly: input.loopbackOnly
1539
1549
  };
1550
+ if (input.plaintext && this.secretBox) {
1551
+ row.keySecret = this.secretBox.encrypt(input.plaintext);
1552
+ }
1540
1553
  rows.push(row);
1541
1554
  this.writeRows(rows);
1542
1555
  return row;
1543
1556
  }
1557
+ async outboundApiKeysReveal(id) {
1558
+ const rows = this.readRows();
1559
+ const row = rows.find((r) => r.id === id);
1560
+ if (!row || !row.keySecret || !this.secretBox) return null;
1561
+ return this.secretBox.decrypt(row.keySecret);
1562
+ }
1563
+ async outboundApiKeysDelete(id) {
1564
+ const rows = this.readRows();
1565
+ const idx = rows.findIndex((r) => r.id === id);
1566
+ if (idx < 0) return false;
1567
+ rows.splice(idx, 1);
1568
+ this.writeRows(rows);
1569
+ return true;
1570
+ }
1544
1571
  async outboundApiKeysRevoke(id) {
1545
1572
  return this.mutateRow(id, (row) => {
1546
1573
  if (row.revokedAt !== null) return false;
@@ -1738,26 +1765,29 @@ async function keysRevoke(db, id) {
1738
1765
 
1739
1766
  // src/commands/launch.ts
1740
1767
  var import_node_child_process2 = require("child_process");
1741
- var import_node_fs24 = require("fs");
1768
+ var import_node_crypto15 = require("crypto");
1769
+ var import_node_fs25 = require("fs");
1742
1770
  var import_node_path17 = require("path");
1743
1771
  var import_node_util4 = require("util");
1744
- var import_cli_launcher2 = require("@omnicross/cli-launcher");
1772
+ var import_cli_launcher3 = require("@omnicross/cli-launcher");
1773
+ var import_provider_proxy5 = require("@omnicross/core/provider-proxy");
1745
1774
 
1746
1775
  // src/bootstrap.ts
1747
- var import_node_fs23 = require("fs");
1776
+ var import_node_fs24 = require("fs");
1748
1777
  var import_audit_types = require("@omnicross/contracts/audit-types");
1749
1778
  var import_billing_types = require("@omnicross/contracts/billing-types");
1750
1779
  var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1751
1780
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
1752
1781
  var import_outbound_api5 = require("@omnicross/core/outbound-api");
1753
1782
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
1754
- var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1783
+ var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1755
1784
  var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1756
- var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1785
+ var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1757
1786
  var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
1758
1787
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
1759
1788
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
1760
- var import_provider_proxy = require("@omnicross/core/provider-proxy");
1789
+ var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
1790
+ var import_cli_launcher2 = require("@omnicross/cli-launcher");
1761
1791
  var import_outbound_api6 = require("@omnicross/core/outbound-api");
1762
1792
  var import_usage = require("@omnicross/core/usage");
1763
1793
  var import_subscriptions4 = require("@omnicross/subscriptions");
@@ -1838,7 +1868,7 @@ async function runCodexLoopback(sessionId, codeVerifier, state, signal, deps) {
1838
1868
  const code = await deps.codexAwaitLoopback(state, void 0, signal);
1839
1869
  const result = await import_subscriptions.codexOAuth.exchangeCodeForTokens(
1840
1870
  { authorizationCode: code, codeVerifier, state },
1841
- deps.oauthExchangeFetch
1871
+ deps.oauthExchangeFetch("codex")
1842
1872
  );
1843
1873
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
1844
1874
  const block = {
@@ -2340,6 +2370,17 @@ function handleAuditQuery(req, res, reader) {
2340
2370
  res.writeHead(200, { "Content-Type": "application/json" });
2341
2371
  res.end(JSON.stringify({ records }));
2342
2372
  }
2373
+ async function handleAuditStatsQuery(req, res, reader) {
2374
+ const url = new URL(req.url ?? "/", "http://localhost");
2375
+ const query2 = {};
2376
+ const from = intParam(url.searchParams.get("from"));
2377
+ if (from !== void 0) query2.from = from;
2378
+ const to = intParam(url.searchParams.get("to"));
2379
+ if (to !== void 0) query2.to = to;
2380
+ const stats = reader ? await reader(query2) : { requestCount: 0, errorCount: 0, complete: true };
2381
+ res.writeHead(200, { "Content-Type": "application/json" });
2382
+ res.end(JSON.stringify(stats));
2383
+ }
2343
2384
 
2344
2385
  // src/admin/billingStatusApi.ts
2345
2386
  function handleBillingStatus(res, reader) {
@@ -2429,6 +2470,88 @@ async function handleWebhookTest(req, res) {
2429
2470
  res.end(JSON.stringify({ result }));
2430
2471
  }
2431
2472
 
2473
+ // src/admin/routeLeaseApi.ts
2474
+ var import_provider_proxy = require("@omnicross/core/provider-proxy");
2475
+ var MAX_BODY_BYTES = 64 * 1024;
2476
+ var SAFE_LEASE_ID = /^[A-Za-z0-9-]{1,128}$/u;
2477
+ async function readJson(req) {
2478
+ const chunks = [];
2479
+ let bytes = 0;
2480
+ for await (const chunk of req) {
2481
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2482
+ bytes += buffer.length;
2483
+ if (bytes > MAX_BODY_BYTES) throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is too large");
2484
+ chunks.push(buffer);
2485
+ }
2486
+ if (chunks.length === 0) return {};
2487
+ try {
2488
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
2489
+ } catch {
2490
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is not valid JSON");
2491
+ }
2492
+ }
2493
+ function json(res, status, body, noStore = false) {
2494
+ res.statusCode = status;
2495
+ res.setHeader("Content-Type", "application/json");
2496
+ if (noStore) res.setHeader("Cache-Control", "no-store");
2497
+ res.end(JSON.stringify(body));
2498
+ }
2499
+ function leaseId(value) {
2500
+ if (!value || !SAFE_LEASE_ID.test(value)) throw new import_provider_proxy.RouteLeaseError("invalid_request", "lease id is invalid");
2501
+ return value;
2502
+ }
2503
+ function header(req, name) {
2504
+ const value = req.headers[name.toLowerCase()];
2505
+ return Array.isArray(value) ? value[0] : value;
2506
+ }
2507
+ function writeError(res, error, noStore) {
2508
+ const safe = error instanceof import_provider_proxy.RouteLeaseError ? error : new import_provider_proxy.RouteLeaseError("upstream_unavailable", "route lease operation failed safely");
2509
+ if (safe.retryAfterSeconds !== void 0) res.setHeader("Retry-After", String(safe.retryAfterSeconds));
2510
+ json(res, safe.status, safe.toResponse(), noStore);
2511
+ }
2512
+ async function handleRouteLeaseApi(req, res, path2, deps) {
2513
+ const method = (req.method ?? "GET").toUpperCase();
2514
+ const noStore = method === "POST" && (path2 === "/admin/api/route-leases" || path2.endsWith("/renew"));
2515
+ try {
2516
+ if (!(0, import_provider_proxy.isLoopbackAddress)(req.socket.remoteAddress)) {
2517
+ throw new import_provider_proxy.RouteLeaseError("control_unauthorized", "route lease control plane is loopback only");
2518
+ }
2519
+ const manager = deps.routeLeaseManager;
2520
+ if (!manager) throw new import_provider_proxy.RouteLeaseError("daemon_not_ready", "route lease manager is unavailable");
2521
+ const base = "/admin/api/route-leases";
2522
+ const suffix = path2.slice(base.length).replace(/^\/+|\/+$/gu, "");
2523
+ const segments = suffix ? suffix.split("/") : [];
2524
+ if (segments.length === 1 && segments[0] === "capabilities") {
2525
+ if (method !== "GET" && method !== "HEAD") throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
2526
+ return json(res, 200, import_provider_proxy.ROUTE_LEASE_CAPABILITIES);
2527
+ }
2528
+ if (segments.length === 0) {
2529
+ if (method === "GET") return json(res, 200, { leases: manager.list() });
2530
+ if (method === "POST") {
2531
+ const outcome = await manager.createFromRequest(await readJson(req), header(req, "idempotency-key"));
2532
+ return json(res, outcome.created ? 201 : 200, outcome.result, true);
2533
+ }
2534
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
2535
+ }
2536
+ const id = leaseId(segments[0]);
2537
+ if (segments.length === 1) {
2538
+ if (method === "GET") return json(res, 200, manager.get(id));
2539
+ if (method === "DELETE") return json(res, 200, manager.release(id));
2540
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
2541
+ }
2542
+ if (segments.length === 2 && segments[1] === "renew" && method === "POST") {
2543
+ const body = await readJson(req);
2544
+ const ttl = (0, import_provider_proxy.normalizeRouteLeaseTtl)(
2545
+ body && typeof body === "object" && !Array.isArray(body) ? body.ttlSeconds : void 0
2546
+ );
2547
+ return json(res, 200, manager.renew(id, ttl), true);
2548
+ }
2549
+ throw new import_provider_proxy.RouteLeaseError("lease_not_found", "route lease endpoint was not found");
2550
+ } catch (error) {
2551
+ writeError(res, error, noStore);
2552
+ }
2553
+ }
2554
+
2432
2555
  // src/admin/adminApi.ts
2433
2556
  var import_node_http = __toESM(require("http"), 1);
2434
2557
  var import_outbound_api3 = require("@omnicross/core/outbound-api");
@@ -2522,7 +2645,13 @@ function listMappablePresets() {
2522
2645
  name: preset.name,
2523
2646
  apiFormat: resolved.format,
2524
2647
  baseUrl: preset.api_base_url,
2525
- models: Array.isArray(preset.models) ? preset.models : []
2648
+ models: Array.isArray(preset.models) ? preset.models : [],
2649
+ nameKey: preset.nameKey,
2650
+ icon: preset.icon,
2651
+ description: preset.description,
2652
+ features: preset.features,
2653
+ website: preset.website,
2654
+ modelsEndpoint: preset.modelsEndpoint
2526
2655
  });
2527
2656
  }
2528
2657
  return { mappable, excluded };
@@ -2911,7 +3040,7 @@ async function handleOAuthComplete(providerId, body, deps) {
2911
3040
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
2912
3041
  if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
2913
3042
  if (!rawCode) return err2(400, "oauth complete requires { code }");
2914
- const session = deps.oauthSessions.take(sessionId);
3043
+ const session = deps.oauthSessions.peek(sessionId);
2915
3044
  if (!session) return err2(410, "oauth session is unknown, expired, or already used");
2916
3045
  if (session.providerId !== providerId) {
2917
3046
  return err2(400, `oauth session does not match provider '${providerId}'`);
@@ -2925,13 +3054,15 @@ async function handleOAuthComplete(providerId, body, deps) {
2925
3054
  }
2926
3055
  code = splitCode;
2927
3056
  }
3057
+ const exchangeFetch = deps.oauthExchangeFetch(providerId);
2928
3058
  let block;
2929
3059
  try {
2930
- block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, deps.oauthExchangeFetch) : await exchangeGemini(code, session.codeVerifier, deps.oauthExchangeFetch);
3060
+ block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
2931
3061
  } catch (exchangeError) {
2932
3062
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
2933
3063
  return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
2934
3064
  }
3065
+ deps.oauthSessions.consume(sessionId);
2935
3066
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
2936
3067
  await deps.subscriptionAccountAppender.appendProviderAccount(providerId, block, label);
2937
3068
  const status = await statusEntryFor(deps.subscriptionAccounts, providerId);
@@ -2970,8 +3101,34 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
2970
3101
  var import_node_child_process = require("child_process");
2971
3102
  var import_node_crypto6 = require("crypto");
2972
3103
  var import_node_fs8 = require("fs");
3104
+ var import_node_net = require("net");
3105
+ var import_node_os3 = require("os");
2973
3106
  var import_node_path7 = require("path");
2974
3107
  var import_cli_launcher = require("@omnicross/cli-launcher");
3108
+ var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
3109
+
3110
+ // src/routeLeaseRenewal.ts
3111
+ var TERMINAL_LEASE_TTL_SECONDS = 600;
3112
+ var TERMINAL_LEASE_RENEW_INTERVAL_MS = 5 * 60 * 1e3;
3113
+ var TERMINAL_LEASE_MAX_LIFETIME_MS = 24 * 60 * 60 * 1e3;
3114
+ function startTerminalLeaseRenewal(manager, leaseId2) {
3115
+ const stopAt = Date.now() + TERMINAL_LEASE_MAX_LIFETIME_MS;
3116
+ const timer = setInterval(() => {
3117
+ if (Date.now() >= stopAt) {
3118
+ clearInterval(timer);
3119
+ return;
3120
+ }
3121
+ try {
3122
+ manager.renew(leaseId2, TERMINAL_LEASE_TTL_SECONDS);
3123
+ } catch {
3124
+ clearInterval(timer);
3125
+ }
3126
+ }, TERMINAL_LEASE_RENEW_INTERVAL_MS);
3127
+ timer.unref?.();
3128
+ return () => clearInterval(timer);
3129
+ }
3130
+
3131
+ // src/admin/cliLaunch.ts
2975
3132
  var LAUNCHABLE_CLIS = [
2976
3133
  { id: "claude", displayName: "Claude Code", command: "claude" },
2977
3134
  { id: "codex", displayName: "Codex CLI", command: "codex" },
@@ -3052,34 +3209,183 @@ async function buildLaunchEnv(cli, llmConfig, target) {
3052
3209
  function shq(s) {
3053
3210
  return `'${s.replace(/'/g, `'\\''`)}'`;
3054
3211
  }
3055
- var defaultTerminalOpener = ({ cli, command, extraArgs, env, cwd, platform }) => {
3212
+ var MAC_TERMINAL_BOOTSTRAP_SOURCE = `
3213
+ 'use strict';
3214
+ const fs = require('node:fs');
3215
+ const net = require('node:net');
3216
+ const { spawn } = require('node:child_process');
3217
+ const [socketPath, launchDir, cwd, command, ...args] = process.argv.slice(2);
3218
+ let payload = '';
3219
+ const socket = net.createConnection(socketPath);
3220
+ socket.setEncoding('utf8');
3221
+ socket.on('data', (chunk) => { payload += chunk; });
3222
+ socket.on('end', () => {
3223
+ const descriptor = JSON.parse(payload);
3224
+ if (!descriptor || Array.isArray(descriptor) || Object.values(descriptor).some((value) => typeof value !== 'string')) {
3225
+ throw new Error('invalid terminal launch descriptor');
3226
+ }
3227
+ try { fs.rmSync(launchDir, { recursive: true, force: true }); } catch {}
3228
+ const child = spawn(command, args, {
3229
+ cwd: cwd || undefined,
3230
+ env: { ...process.env, ...descriptor },
3231
+ stdio: 'inherit',
3232
+ });
3233
+ child.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
3234
+ child.on('exit', (code, signal) => {
3235
+ if (signal) process.kill(process.pid, signal);
3236
+ else process.exitCode = code == null ? 1 : code;
3237
+ });
3238
+ });
3239
+ socket.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
3240
+ `;
3241
+ var MAC_TERMINAL_IPC_TIMEOUT_MS = 12e4;
3242
+ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }, spawnProcess = import_node_child_process.spawn, macIpc = {}) {
3056
3243
  const childEnv = { ...process.env, ...env };
3057
3244
  if (platform === "win32") {
3058
3245
  const args = ["/c", "start", `"omnicross ${cli}"`];
3059
3246
  if (cwd) args.push("/D", `"${cwd}"`);
3060
3247
  args.push("cmd", "/k", command, ...extraArgs);
3061
- (0, import_node_child_process.spawn)(process.env["ComSpec"] || "cmd.exe", args, {
3248
+ spawnProcess(process.env["ComSpec"] || "cmd.exe", args, {
3062
3249
  env: childEnv,
3063
3250
  windowsVerbatimArguments: true,
3064
3251
  detached: true,
3065
3252
  stdio: "ignore"
3066
3253
  }).unref();
3067
- return;
3254
+ return () => {
3255
+ };
3068
3256
  }
3069
- const exportLine = Object.entries(env).map(([k, v]) => `export ${k}=${shq(v)}`).join("; ");
3070
3257
  const runLine = [command, ...extraArgs].map(shq).join(" ");
3071
- const script = `${exportLine}; ${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
3258
+ const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
3072
3259
  if (platform === "darwin") {
3073
- const osa = `tell application "Terminal" to do script ${JSON.stringify(script)}`;
3074
- (0, import_node_child_process.spawn)("osascript", ["-e", osa], { detached: true, stdio: "ignore" }).unref();
3075
- return;
3260
+ const launchDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path7.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
3261
+ const commandFile = (0, import_node_path7.join)(launchDir, "launch.command");
3262
+ const bootstrapFile = (0, import_node_path7.join)(launchDir, "bootstrap.cjs");
3263
+ const socketPath = macIpc.socketPath ?? (0, import_node_path7.join)(launchDir, "descriptor.sock");
3264
+ const openerEnv = { ...process.env };
3265
+ for (const key of Object.keys(env)) delete openerEnv[key];
3266
+ let claimed = false;
3267
+ let cleaned = false;
3268
+ let failureNotified = false;
3269
+ let timer;
3270
+ const notifyFailure = () => {
3271
+ cleanup();
3272
+ if (failureNotified) return;
3273
+ failureNotified = true;
3274
+ try {
3275
+ onFailure?.();
3276
+ } catch {
3277
+ }
3278
+ };
3279
+ const handleLaunchFailure = () => {
3280
+ if (claimed) cleanup();
3281
+ else notifyFailure();
3282
+ };
3283
+ const sockets = /* @__PURE__ */ new Set();
3284
+ const server = (0, import_node_net.createServer)((socket) => {
3285
+ socket.unref();
3286
+ sockets.add(socket);
3287
+ socket.once("close", () => sockets.delete(socket));
3288
+ try {
3289
+ macIpc.onAccepted?.(socket);
3290
+ } catch {
3291
+ cleanup();
3292
+ return;
3293
+ }
3294
+ if (claimed || cleaned) {
3295
+ socket.destroy();
3296
+ return;
3297
+ }
3298
+ claimed = true;
3299
+ try {
3300
+ macIpc.onClaimed?.();
3301
+ if (cleaned) return;
3302
+ socket.end(JSON.stringify(env), cleanup);
3303
+ } catch {
3304
+ cleanup();
3305
+ }
3306
+ });
3307
+ const cleanup = () => {
3308
+ if (!cleaned) {
3309
+ cleaned = true;
3310
+ if (timer) clearTimeout(timer);
3311
+ for (const socket of sockets) socket.destroy();
3312
+ sockets.clear();
3313
+ try {
3314
+ server.close();
3315
+ } catch {
3316
+ }
3317
+ }
3318
+ try {
3319
+ if (macIpc.removeArtifacts) {
3320
+ macIpc.removeArtifacts(launchDir);
3321
+ } else {
3322
+ (0, import_node_fs8.rmSync)(launchDir, {
3323
+ recursive: true,
3324
+ force: true,
3325
+ maxRetries: 3,
3326
+ retryDelay: 20
3327
+ });
3328
+ }
3329
+ } catch {
3330
+ }
3331
+ };
3332
+ try {
3333
+ (0, import_node_fs8.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
3334
+ (0, import_node_fs8.writeFileSync)(commandFile, `#!/bin/bash
3335
+ rm -f -- "$0"
3336
+ exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
3337
+ `, {
3338
+ encoding: "utf8",
3339
+ mode: 448
3340
+ });
3341
+ (0, import_node_fs8.chmodSync)(commandFile, 448);
3342
+ (0, import_node_fs8.chmodSync)(bootstrapFile, 448);
3343
+ server.once("error", handleLaunchFailure);
3344
+ server.listen(socketPath, () => {
3345
+ if (cleaned) return;
3346
+ try {
3347
+ macIpc.onListening?.();
3348
+ if (cleaned) return;
3349
+ if (process.platform !== "win32") (0, import_node_fs8.chmodSync)(socketPath, 384);
3350
+ const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
3351
+ env: openerEnv,
3352
+ detached: true,
3353
+ stdio: "ignore"
3354
+ });
3355
+ opener.once("error", handleLaunchFailure);
3356
+ opener.unref();
3357
+ server.unref();
3358
+ } catch {
3359
+ handleLaunchFailure();
3360
+ }
3361
+ });
3362
+ timer = setTimeout(handleLaunchFailure, macIpc.timeoutMs ?? MAC_TERMINAL_IPC_TIMEOUT_MS);
3363
+ timer.unref?.();
3364
+ return cleanup;
3365
+ } catch (error) {
3366
+ cleanup();
3367
+ throw error;
3368
+ }
3076
3369
  }
3077
- (0, import_node_child_process.spawn)("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
3370
+ spawnProcess("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
3371
+ env: childEnv,
3078
3372
  detached: true,
3079
3373
  stdio: "ignore"
3080
3374
  }).unref();
3081
- };
3375
+ return () => {
3376
+ };
3377
+ }
3378
+ var defaultTerminalOpener = (input) => openTerminal(input);
3082
3379
  var sessions = /* @__PURE__ */ new Map();
3380
+ function resetCliSessions() {
3381
+ for (const s of sessions.values()) {
3382
+ try {
3383
+ s.onSessionEnd();
3384
+ } catch {
3385
+ }
3386
+ }
3387
+ sessions.clear();
3388
+ }
3083
3389
  function errBody(message) {
3084
3390
  return { error: { type: "admin_api_error", message } };
3085
3391
  }
@@ -3134,29 +3440,81 @@ async function handleCliLaunch(cli, body, ctx) {
3134
3440
  } catch (err5) {
3135
3441
  return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
3136
3442
  }
3443
+ const id = (0, import_node_crypto6.randomUUID)();
3444
+ let leaseId2;
3137
3445
  let launch;
3138
3446
  try {
3139
- launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3447
+ if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
3448
+ const outcome = await ctx.routeLeaseManager.createFromRequest({
3449
+ schemaVersion: import_provider_proxy2.ROUTE_LEASE_REQUEST_SCHEMA,
3450
+ consumer: "omnicross-terminal",
3451
+ runtime: cli,
3452
+ upstream: { kind: "provider", providerId: target.providerId },
3453
+ model: target.model,
3454
+ execution: { sessionId: id }
3455
+ }, `omnicross-terminal:${id}`);
3456
+ leaseId2 = outcome.result.leaseId;
3457
+ const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
3458
+ launch = {
3459
+ env: outcome.result.launch.env,
3460
+ extraArgs: outcome.result.launch.extraArgs,
3461
+ onSessionEnd: () => {
3462
+ stopRenewal();
3463
+ ctx.routeLeaseManager?.release(outcome.result.leaseId);
3464
+ }
3465
+ };
3466
+ } else {
3467
+ launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3468
+ }
3140
3469
  } catch (err5) {
3141
- return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
3470
+ const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
3471
+ return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
3142
3472
  }
3143
3473
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
3144
3474
  const opener = ctx.opener ?? defaultTerminalOpener;
3475
+ let openerCleanup;
3476
+ let ended = false;
3477
+ let published = false;
3478
+ const onSessionEnd = () => {
3479
+ if (ended) return;
3480
+ ended = true;
3481
+ if (published) sessions.delete(id);
3482
+ try {
3483
+ openerCleanup?.();
3484
+ } finally {
3485
+ launch.onSessionEnd();
3486
+ }
3487
+ };
3145
3488
  try {
3146
- opener({ cli, command: meta.command, extraArgs: launch.extraArgs ?? [], env: launch.env, cwd, platform });
3489
+ const cleanup = opener({
3490
+ cli,
3491
+ command: meta.command,
3492
+ extraArgs: launch.extraArgs ?? [],
3493
+ env: launch.env,
3494
+ cwd,
3495
+ platform,
3496
+ onFailure: onSessionEnd
3497
+ });
3498
+ if (cleanup) openerCleanup = cleanup;
3147
3499
  } catch (err5) {
3148
- launch.onSessionEnd();
3500
+ onSessionEnd();
3149
3501
  return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
3150
3502
  }
3151
- const id = (0, import_node_crypto6.randomUUID)();
3503
+ if (ended) {
3504
+ openerCleanup?.();
3505
+ return { status: 500, body: errBody("failed to open terminal") };
3506
+ }
3152
3507
  sessions.set(id, {
3153
3508
  id,
3154
3509
  cli,
3155
3510
  providerId: target.providerId,
3156
3511
  model: target.model,
3512
+ ...leaseId2 ? { leaseId: leaseId2 } : {},
3157
3513
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3158
- onSessionEnd: launch.onSessionEnd
3514
+ onSessionEnd
3159
3515
  });
3516
+ published = true;
3517
+ if (ended) sessions.delete(id);
3160
3518
  return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
3161
3519
  }
3162
3520
 
@@ -3176,8 +3534,8 @@ function validateAuditSegment(patch) {
3176
3534
  }
3177
3535
  }
3178
3536
  const maxBodyBytes = audit["maxBodyBytes"];
3179
- if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < 0)) {
3180
- errors.push("audit.maxBodyBytes must be a non-negative number");
3537
+ if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < -1)) {
3538
+ errors.push("audit.maxBodyBytes must be -1 or a non-negative number");
3181
3539
  }
3182
3540
  const retentionDays = audit["retentionDays"];
3183
3541
  if (retentionDays !== void 0 && (typeof retentionDays !== "number" || !Number.isFinite(retentionDays) || retentionDays < 0)) {
@@ -3612,18 +3970,16 @@ function preserveWebhookSecrets(incoming, current) {
3612
3970
  }
3613
3971
 
3614
3972
  // src/audit/auditRuntime.ts
3615
- var import_node_path8 = require("path");
3616
3973
  var import_auditSink = require("@omnicross/core/pipeline/auditSink");
3617
3974
  var import_upstreamTrace = require("@omnicross/core/pipeline/upstreamTrace");
3618
3975
  var writer = null;
3619
3976
  var sweeper = null;
3620
- var auditDir = "";
3621
- function setAuditRuntime(w, s, dir) {
3977
+ function setAuditRuntime(w, s) {
3622
3978
  writer = w;
3623
3979
  sweeper = s;
3624
- auditDir = dir;
3625
3980
  }
3626
3981
  function applyAuditConfig(config) {
3982
+ (0, import_upstreamTrace.setUpstreamTracePath)(null);
3627
3983
  const enabled = config?.enabled === true && writer !== null;
3628
3984
  if (enabled && config) {
3629
3985
  (0, import_auditSink.setAuditCaptureConfig)(config);
@@ -3633,11 +3989,9 @@ function applyAuditConfig(config) {
3633
3989
  sweeper.configure(config);
3634
3990
  sweeper.start();
3635
3991
  }
3636
- (0, import_upstreamTrace.setUpstreamTracePath)(config.captureBodies ? (0, import_node_path8.join)(auditDir, "upstream-trace.jsonl") : null);
3637
3992
  } else {
3638
3993
  (0, import_auditSink.setAuditCaptureConfig)(null);
3639
3994
  (0, import_auditSink.setAuditSink)(null);
3640
- (0, import_upstreamTrace.setUpstreamTracePath)(null);
3641
3995
  if (sweeper) {
3642
3996
  if (config) sweeper.configure(config);
3643
3997
  sweeper.dispose();
@@ -4037,7 +4391,7 @@ function sealPack(bundleJson, passphrase) {
4037
4391
  cipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
4038
4392
  const ciphertext = Buffer.concat([cipher.update(bundleJson, "utf8"), cipher.final()]);
4039
4393
  const tag = cipher.getAuthTag();
4040
- const header = {
4394
+ const header2 = {
4041
4395
  magic: PACK_MAGIC,
4042
4396
  v: PACK_VERSION,
4043
4397
  kdf: KDF_ALGORITHM,
@@ -4048,7 +4402,7 @@ function sealPack(bundleJson, passphrase) {
4048
4402
  iv: iv.toString("base64"),
4049
4403
  tag: tag.toString("base64")
4050
4404
  };
4051
- return `${PACK_PREFIX}${toB64Url(JSON.stringify(header))}.${ciphertext.toString("base64")}`;
4405
+ return `${PACK_PREFIX}${toB64Url(JSON.stringify(header2))}.${ciphertext.toString("base64")}`;
4052
4406
  }
4053
4407
  function parsePack(packString) {
4054
4408
  if (typeof packString !== "string" || !packString.startsWith(PACK_PREFIX)) {
@@ -4059,28 +4413,28 @@ function parsePack(packString) {
4059
4413
  if (dot < 0) throw new PackAuthError("migration pack is malformed (missing body)");
4060
4414
  const headerB64Url = rest.slice(0, dot);
4061
4415
  const ctB64 = rest.slice(dot + 1);
4062
- let header;
4416
+ let header2;
4063
4417
  try {
4064
- header = JSON.parse(fromB64Url(headerB64Url));
4418
+ header2 = JSON.parse(fromB64Url(headerB64Url));
4065
4419
  } catch {
4066
4420
  throw new PackAuthError("migration pack is malformed (unreadable header)");
4067
4421
  }
4068
- if (!header || header.magic !== PACK_MAGIC || header.v !== PACK_VERSION || header.kdf !== KDF_ALGORITHM || typeof header.salt !== "string" || typeof header.iv !== "string" || typeof header.tag !== "string" || typeof header.N !== "number" || typeof header.r !== "number" || typeof header.p !== "number") {
4422
+ if (!header2 || header2.magic !== PACK_MAGIC || header2.v !== PACK_VERSION || header2.kdf !== KDF_ALGORITHM || typeof header2.salt !== "string" || typeof header2.iv !== "string" || typeof header2.tag !== "string" || typeof header2.N !== "number" || typeof header2.r !== "number" || typeof header2.p !== "number") {
4069
4423
  throw new PackAuthError("migration pack is malformed (unsupported header)");
4070
4424
  }
4071
4425
  const ciphertext = Buffer.from(ctB64, "base64");
4072
- return { header, ciphertext };
4426
+ return { header: header2, ciphertext };
4073
4427
  }
4074
4428
  function openPack(packString, passphrase) {
4075
4429
  assertPassphraseStrength(passphrase);
4076
- const { header, ciphertext } = parsePack(packString);
4077
- const salt = Buffer.from(header.salt, "base64");
4078
- const iv = Buffer.from(header.iv, "base64");
4079
- const tag = Buffer.from(header.tag, "base64");
4430
+ const { header: header2, ciphertext } = parsePack(packString);
4431
+ const salt = Buffer.from(header2.salt, "base64");
4432
+ const iv = Buffer.from(header2.iv, "base64");
4433
+ const tag = Buffer.from(header2.tag, "base64");
4080
4434
  if (iv.length !== IV_BYTES2 || tag.length !== TAG_BYTES2) {
4081
4435
  throw new PackAuthError("migration pack is malformed (invalid iv/tag length)");
4082
4436
  }
4083
- const key = deriveKey(passphrase, salt, header.N, header.r, header.p);
4437
+ const key = deriveKey(passphrase, salt, header2.N, header2.r, header2.p);
4084
4438
  const decipher = (0, import_node_crypto8.createDecipheriv)("aes-256-gcm", key, iv);
4085
4439
  decipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
4086
4440
  decipher.setAuthTag(tag);
@@ -4416,10 +4770,10 @@ function writeJson2(res, status, body) {
4416
4770
  res.writeHead(status, { "Content-Type": "application/json" });
4417
4771
  res.end(JSON.stringify(body));
4418
4772
  }
4419
- function writeError(res, status, message) {
4773
+ function writeError2(res, status, message) {
4420
4774
  writeJson2(res, status, { error: { type: "account_allowance_error", message } });
4421
4775
  }
4422
- function readJson(req) {
4776
+ function readJson2(req) {
4423
4777
  return new Promise((resolve3, reject) => {
4424
4778
  const chunks = [];
4425
4779
  req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
@@ -4445,10 +4799,10 @@ function allowanceProvider(value) {
4445
4799
  return value === "claude" || value === "codex" ? value : null;
4446
4800
  }
4447
4801
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
4448
- if (!service) return writeError(res, 501, "account allowance service is not available");
4802
+ if (!service) return writeError2(res, 501, "account allowance service is not available");
4449
4803
  if (method === "GET" && rest.length === 1 && rest[0] === "scheduling") {
4450
4804
  if (!service.getSchedulingStatus) {
4451
- return writeError(res, 501, "allowance scheduling diagnostics are not available");
4805
+ return writeError2(res, 501, "allowance scheduling diagnostics are not available");
4452
4806
  }
4453
4807
  return writeJson2(res, 200, { scheduling: service.getSchedulingStatus() });
4454
4808
  }
@@ -4456,30 +4810,32 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
4456
4810
  const params = query(req);
4457
4811
  const pathProvider = rest.length >= 2 ? rest[0] : null;
4458
4812
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
4459
- if (providerId === null) return writeError(res, 400, "providerId must be claude or codex");
4813
+ if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
4460
4814
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
4461
4815
  const allowances = await service.list({ providerId, accountId });
4462
4816
  return writeJson2(res, 200, { allowances });
4463
4817
  }
4464
4818
  if (method === "POST" && rest[0] === "refresh") {
4465
- const body = await readJson(req);
4819
+ const body = await readJson2(req);
4466
4820
  const requestedProvider = allowanceProvider(
4467
4821
  typeof body["providerId"] === "string" ? body["providerId"] : "claude"
4468
4822
  );
4469
4823
  if (requestedProvider !== "claude") {
4470
- return writeError(res, 400, "only Claude allowances support explicit refresh");
4824
+ return writeError2(res, 400, "only Claude allowances support explicit refresh");
4471
4825
  }
4472
4826
  const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
4473
4827
  const allowances = await service.refreshClaude(accountId);
4474
4828
  if (accountId && allowances.length === 0) {
4475
- return writeError(res, 404, `Claude account '${accountId}' not found`);
4829
+ return writeError2(res, 404, `Claude account '${accountId}' not found`);
4476
4830
  }
4477
4831
  return writeJson2(res, 200, { allowances });
4478
4832
  }
4479
- return writeError(res, 405, `method ${method} not allowed on account allowances`);
4833
+ return writeError2(res, 405, `method ${method} not allowed on account allowances`);
4480
4834
  }
4481
4835
 
4482
4836
  // src/admin/adminApi.ts
4837
+ var import_AccountRouteActivity = require("@omnicross/core/pipeline/AccountRouteActivity");
4838
+ var import_ServerOverloadCounter = require("@omnicross/core/pipeline/ServerOverloadCounter");
4483
4839
  function readBody(req) {
4484
4840
  return new Promise((resolve3, reject) => {
4485
4841
  const chunks = [];
@@ -4516,6 +4872,9 @@ function toKeyInfo(row) {
4516
4872
  id: row.id,
4517
4873
  name: row.name,
4518
4874
  keyPrefix: row.keyPrefix,
4875
+ // True only when a reversible `keySecret` envelope was persisted at creation
4876
+ // — gates the UI "view key" eye. Legacy hash-only rows read as absent.
4877
+ revealable: Boolean(row.keySecret),
4519
4878
  enabled: row.enabled,
4520
4879
  createdAt: row.createdAt,
4521
4880
  lastUsedAt: row.lastUsedAt,
@@ -5171,7 +5530,13 @@ function handlePresets(res, method) {
5171
5530
  name: p.name,
5172
5531
  apiFormat: p.apiFormat,
5173
5532
  baseUrl: p.baseUrl,
5174
- models: p.models
5533
+ models: p.models,
5534
+ nameKey: p.nameKey,
5535
+ icon: p.icon,
5536
+ description: p.description,
5537
+ features: p.features,
5538
+ website: p.website,
5539
+ modelsEndpoint: p.modelsEndpoint
5175
5540
  }));
5176
5541
  return writeJson3(res, 200, { presets, excluded });
5177
5542
  }
@@ -5205,12 +5570,27 @@ async function handleKeys(req, res, method, rest, deps) {
5205
5570
  plaintextOnce: created.plaintextOnce
5206
5571
  });
5207
5572
  }
5573
+ if (method === "GET" && rest.length === 2 && rest[1] === "reveal") {
5574
+ const revealed = await deps.keyDb.outboundApiKeysReveal(rest[0]);
5575
+ if (revealed !== null) return writeJson3(res, 200, { key: revealed });
5576
+ const exists = (await deps.keyDb.outboundApiKeysList()).some((r) => r.id === rest[0]);
5577
+ if (!exists) return writeJsonError(res, 404, `key '${rest[0]}' not found`);
5578
+ return writeJsonError(
5579
+ res,
5580
+ 409,
5581
+ `key '${rest[0]}' is not revealable (created before revealable key storage)`
5582
+ );
5583
+ }
5208
5584
  const id = rest[0];
5209
5585
  const action = rest[1];
5210
5586
  if (method === "POST" && id && action === "revoke") {
5211
5587
  const ok = await deps.keyDb.outboundApiKeysRevoke(id);
5212
5588
  return writeJson3(res, ok ? 200 : 404, { ok });
5213
5589
  }
5590
+ if (method === "DELETE" && id && !action) {
5591
+ const ok = await deps.keyDb.outboundApiKeysDelete(id);
5592
+ return writeJson3(res, ok ? 200 : 404, { ok });
5593
+ }
5214
5594
  if (method === "POST" && id && action === "enabled") {
5215
5595
  const body = await readJsonBody3(req);
5216
5596
  const enabled = body["enabled"] === true;
@@ -5387,6 +5767,40 @@ async function handleServer(req, res, method, deps) {
5387
5767
  return writeJsonError(res, 405, `method ${method} not allowed on server`);
5388
5768
  }
5389
5769
  async function handleAccounts(req, res, method, rest, deps) {
5770
+ if (rest[0] === "route-activity" && rest.length === 1) {
5771
+ if (method !== "GET") {
5772
+ return writeJsonError(res, 405, `method ${method} not allowed on account route activity`);
5773
+ }
5774
+ const query2 = requestQuery(req);
5775
+ const parsedLimit = Number(query2.get("limit") ?? "100");
5776
+ const records = (0, import_AccountRouteActivity.getSharedAccountRouteActivity)().list({
5777
+ providerId: query2.get("providerId") ?? void 0,
5778
+ accountId: query2.get("accountId") ?? void 0,
5779
+ sessionKey: query2.get("sessionKey") ?? void 0,
5780
+ limit: Number.isFinite(parsedLimit) ? parsedLimit : 100
5781
+ });
5782
+ return writeJson3(res, 200, {
5783
+ available: true,
5784
+ records,
5785
+ capacity: import_AccountRouteActivity.ACCOUNT_ROUTE_ACTIVITY_LIMIT,
5786
+ collectedAt: Date.now()
5787
+ });
5788
+ }
5789
+ if (rest[0] === "overload-counters" && rest.length === 1) {
5790
+ if (method !== "GET") {
5791
+ return writeJsonError(res, 405, `method ${method} not allowed on overload counters`);
5792
+ }
5793
+ const query2 = requestQuery(req);
5794
+ const entries = (0, import_ServerOverloadCounter.getSharedOverloadCounter)().list({
5795
+ providerId: query2.get("providerId") ?? void 0,
5796
+ accountId: query2.get("accountId") ?? void 0
5797
+ });
5798
+ return writeJson3(res, 200, {
5799
+ available: true,
5800
+ entries,
5801
+ collectedAt: Date.now()
5802
+ });
5803
+ }
5390
5804
  if (rest[0] === "allowances") {
5391
5805
  return handleAccountAllowanceApi(
5392
5806
  req,
@@ -5533,8 +5947,13 @@ async function handleAccounts(req, res, method, rest, deps) {
5533
5947
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
5534
5948
  return writeJsonError(res, 404, `account '${accountId}' not found`);
5535
5949
  }
5536
- const result = await deps.accountProbeService.probeAccount(providerId, accountId);
5537
- return writeJson3(res, 200, { ok: result.ok, marked: result.marked });
5950
+ const result = await deps.accountProbeService.testAccountConnection(providerId, accountId);
5951
+ return writeJson3(res, 200, {
5952
+ ok: result.ok,
5953
+ marked: result.marked,
5954
+ tier: result.tier,
5955
+ model: result.model
5956
+ });
5538
5957
  }
5539
5958
  if (method === "POST" && rest[2] === "label") {
5540
5959
  const accountId = rest[1];
@@ -5643,6 +6062,7 @@ async function handleCli(req, res, method, rest, deps) {
5643
6062
  const result = await handleCliLaunch(cli, body, {
5644
6063
  llmConfig: deps.llmConfig,
5645
6064
  providers,
6065
+ routeLeaseManager: deps.routeLeaseManager,
5646
6066
  opener: deps.cliTerminalOpener,
5647
6067
  probe: deps.cliPathProbe
5648
6068
  });
@@ -5813,7 +6233,7 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
5813
6233
  var import_node_fs9 = require("fs");
5814
6234
  var import_promises = require("fs/promises");
5815
6235
  var import_node_module = require("module");
5816
- var import_node_path9 = __toESM(require("path"), 1);
6236
+ var import_node_path8 = __toESM(require("path"), 1);
5817
6237
  var import_meta = {};
5818
6238
  var CONTENT_TYPES = {
5819
6239
  ".html": "text/html; charset=utf-8",
@@ -5834,13 +6254,13 @@ var CONTENT_TYPES = {
5834
6254
  function resolveUiDist() {
5835
6255
  const fromEnv = process.env["OMNICROSS_UI_DIST"];
5836
6256
  if (fromEnv) {
5837
- return (0, import_node_fs9.existsSync)(import_node_path9.default.join(fromEnv, "index.html")) ? import_node_path9.default.resolve(fromEnv) : null;
6257
+ return (0, import_node_fs9.existsSync)(import_node_path8.default.join(fromEnv, "index.html")) ? import_node_path8.default.resolve(fromEnv) : null;
5838
6258
  }
5839
6259
  try {
5840
6260
  const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
5841
6261
  const pkgJson = req.resolve("@omnicross/ui/package.json");
5842
- const dist = import_node_path9.default.join(import_node_path9.default.dirname(pkgJson), "dist");
5843
- return (0, import_node_fs9.existsSync)(import_node_path9.default.join(dist, "index.html")) ? dist : null;
6262
+ const dist = import_node_path8.default.join(import_node_path8.default.dirname(pkgJson), "dist");
6263
+ return (0, import_node_fs9.existsSync)(import_node_path8.default.join(dist, "index.html")) ? dist : null;
5844
6264
  } catch {
5845
6265
  return null;
5846
6266
  }
@@ -5882,16 +6302,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5882
6302
  res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
5883
6303
  return true;
5884
6304
  }
5885
- const filePath = import_node_path9.default.resolve(uiDist, rel === "" ? "index.html" : rel);
5886
- if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path9.default.sep)) {
6305
+ const filePath = import_node_path8.default.resolve(uiDist, rel === "" ? "index.html" : rel);
6306
+ if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path8.default.sep)) {
5887
6307
  res.writeHead(403, { "Content-Type": "application/json" });
5888
6308
  res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
5889
6309
  return true;
5890
6310
  }
5891
6311
  let target = filePath;
5892
6312
  if (!(0, import_node_fs9.existsSync)(target) || (0, import_node_fs9.statSync)(target).isDirectory()) {
5893
- if (import_node_path9.default.extname(rel) === "") {
5894
- target = import_node_path9.default.join(uiDist, "index.html");
6313
+ if (import_node_path8.default.extname(rel) === "") {
6314
+ target = import_node_path8.default.join(uiDist, "index.html");
5895
6315
  } else {
5896
6316
  res.writeHead(404, { "Content-Type": "application/json" });
5897
6317
  res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
@@ -5899,14 +6319,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5899
6319
  }
5900
6320
  }
5901
6321
  const body = await (0, import_promises.readFile)(target);
5902
- const type = CONTENT_TYPES[import_node_path9.default.extname(target).toLowerCase()] ?? "application/octet-stream";
6322
+ const type = CONTENT_TYPES[import_node_path8.default.extname(target).toLowerCase()] ?? "application/octet-stream";
5903
6323
  res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
5904
6324
  res.end(req.method === "HEAD" ? void 0 : body);
5905
6325
  return true;
5906
6326
  }
5907
6327
 
5908
6328
  // src/admin/version.ts
5909
- var DAEMON_VERSION = true ? "0.1.6" : "0.0.0-dev";
6329
+ var DAEMON_VERSION = true ? "0.1.8" : "0.0.0-dev";
5910
6330
 
5911
6331
  // src/admin/AdminServer.ts
5912
6332
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -6014,6 +6434,10 @@ var AdminServer = class {
6014
6434
  handleAuditQuery(req, res, this.deps.auditReader);
6015
6435
  return;
6016
6436
  }
6437
+ if (path2 === "/admin/api/audit/stats" && (req.method === "GET" || req.method === "HEAD")) {
6438
+ await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
6439
+ return;
6440
+ }
6017
6441
  if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
6018
6442
  handleBillingStatus(res, this.deps.billingStatusReader);
6019
6443
  return;
@@ -6022,6 +6446,10 @@ var AdminServer = class {
6022
6446
  await handleWebhookTest(req, res);
6023
6447
  return;
6024
6448
  }
6449
+ if (path2 === "/admin/api/route-leases" || path2.startsWith("/admin/api/route-leases/")) {
6450
+ await handleRouteLeaseApi(req, res, path2, this.deps);
6451
+ return;
6452
+ }
6025
6453
  if (path2.startsWith("/admin/api/")) {
6026
6454
  await handleAdminApi(req, res, path2, this.deps);
6027
6455
  return;
@@ -6033,8 +6461,8 @@ var AdminServer = class {
6033
6461
  }
6034
6462
  /** Constant-time bearer/header check against the configured token. */
6035
6463
  isAuthorized(req, token) {
6036
- const header = req.headers["authorization"];
6037
- const bearer = typeof header === "string" && header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : void 0;
6464
+ const header2 = req.headers["authorization"];
6465
+ const bearer = typeof header2 === "string" && header2.startsWith("Bearer ") ? header2.slice("Bearer ".length).trim() : void 0;
6038
6466
  const xToken = req.headers["x-admin-token"];
6039
6467
  const presented = bearer ?? (typeof xToken === "string" ? xToken.trim() : void 0);
6040
6468
  return constantTimeEquals(presented, token);
@@ -6130,20 +6558,36 @@ var OAuthSessionStore = class {
6130
6558
  return sessionId;
6131
6559
  }
6132
6560
  /**
6133
- * SINGLE-USE consume: return + delete the session for `sessionId`, or `null`
6134
- * when it is unknown, already used, or past its TTL (in which case it is
6135
- * dropped). A `null` return means the completer must reject (no exchange, no
6136
- * write).
6561
+ * NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
6562
+ * it is unknown, already consumed, or past its TTL (an expired entry is
6563
+ * dropped here). A `null` return means the completer must reject (no
6564
+ * exchange, no write).
6565
+ *
6566
+ * Deliberately NOT a consume: the completer peeks, runs the token exchange,
6567
+ * and only {@link consume}s once a token has actually been minted. Consuming
6568
+ * up-front burned the session on EVERY failed exchange (a mistyped/expired
6569
+ * pasted code, a proxy hiccup), so the user's natural retry hit
6570
+ * "session is unknown, expired, or already used" and the login became
6571
+ * unrecoverable without restarting the whole flow.
6137
6572
  */
6138
- take(sessionId) {
6573
+ peek(sessionId) {
6139
6574
  this.sweep();
6140
6575
  const session = this.sessions.get(sessionId);
6141
6576
  if (!session) return null;
6142
- this.sessions.delete(sessionId);
6143
- if (Date.now() - session.createdAt > this.ttlMs) return null;
6577
+ if (Date.now() - session.createdAt > this.ttlMs) {
6578
+ this.sessions.delete(sessionId);
6579
+ return null;
6580
+ }
6144
6581
  return session;
6145
6582
  }
6146
- /** Drop every session past its TTL. Called on each put/take. */
6583
+ /**
6584
+ * SINGLE-USE burn: drop the session so the same `sessionId` can never be
6585
+ * completed twice. Called ONLY after a successful token exchange.
6586
+ */
6587
+ consume(sessionId) {
6588
+ this.sessions.delete(sessionId);
6589
+ }
6590
+ /** Drop every session past its TTL. Called on each put/peek. */
6147
6591
  sweep() {
6148
6592
  const now = Date.now();
6149
6593
  for (const [id, session] of this.sessions) {
@@ -6158,6 +6602,10 @@ var LOOPBACK_HOST = "127.0.0.1";
6158
6602
  var LOOPBACK_PORT = 1455;
6159
6603
  var CALLBACK_PATH = "/auth/callback";
6160
6604
  var DEFAULT_TIMEOUT_MS = 5 * 6e4;
6605
+ var HTML_HEADERS = {
6606
+ "Content-Type": "text/html",
6607
+ Connection: "close"
6608
+ };
6161
6609
  function pageHtml(message) {
6162
6610
  return `<!doctype html><meta charset="utf-8"><title>omnicross login</title><body style="font-family:sans-serif;padding:2rem"><h2>${message}</h2><p>You can close this window and return to the terminal.</p></body>`;
6163
6611
  }
@@ -6168,30 +6616,31 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
6168
6616
  if (settled) return;
6169
6617
  settled = true;
6170
6618
  clearTimeout(timer);
6171
- server2.close(() => fn());
6619
+ fn();
6620
+ server2.close();
6172
6621
  };
6173
6622
  const server = (0, import_node_http3.createServer)((req, res) => {
6174
6623
  const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
6175
6624
  if (url.pathname !== CALLBACK_PATH) {
6176
- res.writeHead(404, { "Content-Type": "text/html" });
6625
+ res.writeHead(404, HTML_HEADERS);
6177
6626
  res.end(pageHtml("Not found"));
6178
6627
  return;
6179
6628
  }
6180
6629
  const code = url.searchParams.get("code");
6181
6630
  const state = url.searchParams.get("state");
6182
6631
  if (!code) {
6183
- res.writeHead(400, { "Content-Type": "text/html" });
6632
+ res.writeHead(400, HTML_HEADERS);
6184
6633
  res.end(pageHtml("Login failed: missing authorization code."));
6185
6634
  finish(server, () => reject(new Error("login: callback did not include an authorization code")));
6186
6635
  return;
6187
6636
  }
6188
6637
  if (state !== expectedState) {
6189
- res.writeHead(400, { "Content-Type": "text/html" });
6638
+ res.writeHead(400, HTML_HEADERS);
6190
6639
  res.end(pageHtml("Login failed: state mismatch."));
6191
6640
  finish(server, () => reject(new Error("login: callback state did not match (possible CSRF) \u2014 aborting")));
6192
6641
  return;
6193
6642
  }
6194
- res.writeHead(200, { "Content-Type": "text/html" });
6643
+ res.writeHead(200, HTML_HEADERS);
6195
6644
  res.end(pageHtml("Login complete."));
6196
6645
  finish(server, () => resolve3(code));
6197
6646
  });
@@ -6677,8 +7126,12 @@ var JsonlUsageEventStore = class {
6677
7126
  reasoningTokens: 0,
6678
7127
  costUsd: 0,
6679
7128
  costSavedByCacheUsd: 0,
6680
- eventCount: 0
7129
+ eventCount: 0,
7130
+ cacheEligibleEventCount: 0,
7131
+ coldCacheEventCount: 0,
7132
+ medianCacheHitRate: null
6681
7133
  };
7134
+ const perEventHitRates = [];
6682
7135
  for (const row of this.readRows(range)) {
6683
7136
  totals.inputTokens += row.inputTokens;
6684
7137
  totals.outputTokens += row.outputTokens;
@@ -6688,7 +7141,14 @@ var JsonlUsageEventStore = class {
6688
7141
  totals.costUsd += row.costUsd;
6689
7142
  totals.costSavedByCacheUsd += row.costSavedByCacheUsd;
6690
7143
  totals.eventCount += 1;
7144
+ const promptSideTokens = row.inputTokens + row.cacheReadTokens + row.cacheCreationTokens;
7145
+ if (promptSideTokens > 0) {
7146
+ totals.cacheEligibleEventCount += 1;
7147
+ if (row.cacheReadTokens === 0) totals.coldCacheEventCount += 1;
7148
+ perEventHitRates.push(row.cacheReadTokens / promptSideTokens);
7149
+ }
6691
7150
  }
7151
+ totals.medianCacheHitRate = median(perEventHitRates);
6692
7152
  return totals;
6693
7153
  }
6694
7154
  async getByModel(range) {
@@ -6922,6 +7382,15 @@ var NUMERIC_FIELDS = [
6922
7382
  ];
6923
7383
  var NULLABLE_STRING_FIELDS = ["messageId", "parentMessageId", "sessionId", "apiKeyId"];
6924
7384
  var isStringOrNull = (v) => v === null || typeof v === "string";
7385
+ var CACHE_KEY_SOURCES = /* @__PURE__ */ new Set([
7386
+ "client",
7387
+ "session-header",
7388
+ "thread-header",
7389
+ "body-session-id",
7390
+ "body-thread-id",
7391
+ "content-fingerprint",
7392
+ "none"
7393
+ ]);
6925
7394
  function isUsageEventRecord(parsed) {
6926
7395
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
6927
7396
  const r = parsed;
@@ -6929,6 +7398,10 @@ function isUsageEventRecord(parsed) {
6929
7398
  if (typeof r["providerId"] !== "string") return false;
6930
7399
  if (typeof r["model"] !== "string") return false;
6931
7400
  if (typeof r["engineOrigin"] !== "string") return false;
7401
+ if (r["cacheKeySource"] !== void 0 && (typeof r["cacheKeySource"] !== "string" || !CACHE_KEY_SOURCES.has(r["cacheKeySource"]))) return false;
7402
+ if (r["cacheKeyInjected"] !== void 0 && typeof r["cacheKeyInjected"] !== "boolean") {
7403
+ return false;
7404
+ }
6932
7405
  for (const f of NULLABLE_STRING_FIELDS) {
6933
7406
  if (!isStringOrNull(r[f])) return false;
6934
7407
  }
@@ -6938,6 +7411,12 @@ function isUsageEventRecord(parsed) {
6938
7411
  }
6939
7412
  return true;
6940
7413
  }
7414
+ function median(values) {
7415
+ if (values.length === 0) return null;
7416
+ values.sort((a, b) => a - b);
7417
+ const middle = Math.floor(values.length / 2);
7418
+ return values.length % 2 === 1 ? values[middle] : (values[middle - 1] + values[middle]) / 2;
7419
+ }
6941
7420
 
6942
7421
  // src/ports/JsonPricingStore.ts
6943
7422
  var import_node_fs13 = require("fs");
@@ -7298,7 +7777,7 @@ var JsonVoucherDb = class {
7298
7777
 
7299
7778
  // src/ports/JsonSubscriptionCredentialStore.ts
7300
7779
  var import_node_fs17 = require("fs");
7301
- var import_node_path11 = require("path");
7780
+ var import_node_path10 = require("path");
7302
7781
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
7303
7782
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
7304
7783
  var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -7348,10 +7827,10 @@ function findDuplicateCredentialIds(accounts) {
7348
7827
 
7349
7828
  // src/ports/external-cli-credentials.ts
7350
7829
  var import_node_fs16 = require("fs");
7351
- var import_node_os3 = require("os");
7352
- var import_node_path10 = require("path");
7353
- function externalStorePath(provider, home = (0, import_node_os3.homedir)()) {
7354
- return provider === "claude" ? (0, import_node_path10.join)(home, ".claude", ".credentials.json") : (0, import_node_path10.join)(home, ".codex", "auth.json");
7830
+ var import_node_os4 = require("os");
7831
+ var import_node_path9 = require("path");
7832
+ function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
7833
+ return provider === "claude" ? (0, import_node_path9.join)(home, ".claude", ".credentials.json") : (0, import_node_path9.join)(home, ".codex", "auth.json");
7355
7834
  }
7356
7835
  function decodeJwtExpiryMs(token) {
7357
7836
  try {
@@ -7398,7 +7877,7 @@ function parseCodexTokensEnvelope(raw) {
7398
7877
  }
7399
7878
  return parsed;
7400
7879
  }
7401
- function readExternalCliCredentials(provider, home = (0, import_node_os3.homedir)()) {
7880
+ function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
7402
7881
  const path2 = externalStorePath(provider, home);
7403
7882
  if (!(0, import_node_fs16.existsSync)(path2)) return null;
7404
7883
  let raw;
@@ -7441,9 +7920,15 @@ var JsonSubscriptionCredentialStore = class {
7441
7920
  * TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
7442
7921
  * through {@link fetchUpstream} with the account's `{ providerId, accountId }`
7443
7922
  * ctx so the per-account/provider proxy applies. `@internal` also a test seam.
7923
+ *
7924
+ * `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
7925
+ * receives a fresh access/refresh token pair. Carrying a `providerId` opts the
7926
+ * call into the upstream trace (so a failing refresh is diagnosable), and the
7927
+ * trace captures bodies verbatim — without this flag every refresh would write
7928
+ * a plaintext token pair into `upstream-trace.jsonl`.
7444
7929
  */
7445
7930
  buildRefreshFetch(providerId, accountId) {
7446
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId }));
7931
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
7447
7932
  }
7448
7933
  /**
7449
7934
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -7968,7 +8453,7 @@ var JsonSubscriptionCredentialStore = class {
7968
8453
  * `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
7969
8454
  * write incl. child 4's future refresh writes lands encrypted. */
7970
8455
  persist(config) {
7971
- (0, import_node_fs17.mkdirSync)((0, import_node_path11.dirname)(this.tokensPath), { recursive: true });
8456
+ (0, import_node_fs17.mkdirSync)((0, import_node_path10.dirname)(this.tokensPath), { recursive: true });
7972
8457
  const encrypted = encryptTokens(config, this.box);
7973
8458
  (0, import_node_fs17.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
7974
8459
  }
@@ -8003,6 +8488,124 @@ var JsonSubscriptionCredentialStore = class {
8003
8488
  // src/AccountHealthProbeScheduler.ts
8004
8489
  var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
8005
8490
 
8491
+ // src/probe/CodexGenerationProbe.ts
8492
+ var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
8493
+ var CODEX_GENERATION_PROBE_MODEL = "gpt-5.6-luna";
8494
+ var CODEX_GENERATION_PROBE_URL = "https://chatgpt.com/backend-api/codex/responses";
8495
+ var MAX_STREAM_BYTES = 256 * 1024;
8496
+ var PROBE_INSTRUCTION = "Return exactly PONG and no other text.";
8497
+ function buildCodexGenerationProbeInit(token, signal) {
8498
+ return {
8499
+ method: "POST",
8500
+ signal,
8501
+ headers: {
8502
+ ...import_codexCliHeaders.DEFAULT_CODEX_CLI_HEADERS,
8503
+ Authorization: `Bearer ${token}`,
8504
+ Accept: (0, import_codexCliHeaders.codexAcceptHeader)(true),
8505
+ "Content-Type": "application/json"
8506
+ },
8507
+ body: JSON.stringify({
8508
+ model: CODEX_GENERATION_PROBE_MODEL,
8509
+ input: [
8510
+ {
8511
+ role: "developer",
8512
+ content: [{ type: "input_text", text: PROBE_INSTRUCTION }]
8513
+ },
8514
+ {
8515
+ role: "user",
8516
+ content: [{ type: "input_text", text: "Connection probe." }]
8517
+ }
8518
+ ],
8519
+ // GPT-5.6 otherwise defaults to medium reasoning. A connectivity probe
8520
+ // needs the lowest-cost path and no tool reasoning.
8521
+ reasoning: { effort: "none" },
8522
+ stream: true,
8523
+ store: false
8524
+ })
8525
+ };
8526
+ }
8527
+ async function readCodexGenerationProbeStream(response) {
8528
+ if (!response.body) return { completed: false, outputChars: 0 };
8529
+ const reader = response.body.getReader();
8530
+ const decoder = new TextDecoder();
8531
+ let buffer = "";
8532
+ let bytes = 0;
8533
+ let outputChars = 0;
8534
+ try {
8535
+ while (true) {
8536
+ const { done, value } = await reader.read();
8537
+ if (done) break;
8538
+ bytes += value.byteLength;
8539
+ if (bytes > MAX_STREAM_BYTES) {
8540
+ await reader.cancel();
8541
+ return { completed: false, outputChars };
8542
+ }
8543
+ buffer += decoder.decode(value, { stream: true });
8544
+ buffer = buffer.replace(/\r\n/g, "\n");
8545
+ let boundary = buffer.indexOf("\n\n");
8546
+ while (boundary >= 0) {
8547
+ const block = buffer.slice(0, boundary);
8548
+ buffer = buffer.slice(boundary + 2);
8549
+ const event = parseSseBlock(block);
8550
+ if (event) {
8551
+ const type = event["type"];
8552
+ if (type === "response.output_text.delta" && typeof event["delta"] === "string") {
8553
+ outputChars += event["delta"].length;
8554
+ } else if (type === "response.output_text.done" && typeof event["text"] === "string") {
8555
+ outputChars = Math.max(outputChars, event["text"].length);
8556
+ } else if (type === "response.failed" || type === "error") {
8557
+ await reader.cancel();
8558
+ return { completed: false, outputChars };
8559
+ } else if (type === "response.completed") {
8560
+ const completedResponse = asRecord(event["response"]);
8561
+ const status = completedResponse?.["status"];
8562
+ outputChars = Math.max(outputChars, countCompletedOutputChars(completedResponse));
8563
+ await reader.cancel();
8564
+ return {
8565
+ completed: (status === void 0 || status === "completed") && outputChars > 0,
8566
+ outputChars
8567
+ };
8568
+ }
8569
+ }
8570
+ boundary = buffer.indexOf("\n\n");
8571
+ }
8572
+ }
8573
+ } catch {
8574
+ return { completed: false, outputChars };
8575
+ } finally {
8576
+ reader.releaseLock();
8577
+ }
8578
+ return { completed: false, outputChars };
8579
+ }
8580
+ function parseSseBlock(block) {
8581
+ const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
8582
+ if (!data || data === "[DONE]") return null;
8583
+ try {
8584
+ return JSON.parse(data);
8585
+ } catch {
8586
+ return null;
8587
+ }
8588
+ }
8589
+ function asRecord(value) {
8590
+ return value !== null && typeof value === "object" ? value : void 0;
8591
+ }
8592
+ function countCompletedOutputChars(response) {
8593
+ const output = response?.["output"];
8594
+ if (!Array.isArray(output)) return 0;
8595
+ let chars = 0;
8596
+ for (const item of output) {
8597
+ const content = asRecord(item)?.["content"];
8598
+ if (!Array.isArray(content)) continue;
8599
+ for (const part of content) {
8600
+ const record = asRecord(part);
8601
+ if (record?.["type"] === "output_text" && typeof record["text"] === "string") {
8602
+ chars += record["text"].length;
8603
+ }
8604
+ }
8605
+ }
8606
+ return chars;
8607
+ }
8608
+
8006
8609
  // src/probe/ProbeStrategy.ts
8007
8610
  var PROVIDER_PROBE_PLANS = {
8008
8611
  claude: {
@@ -8130,17 +8733,17 @@ var AccountHealthProbeScheduler = class {
8130
8733
  }
8131
8734
  if (readThrew) {
8132
8735
  this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
8133
- return { ok: false, marked: false };
8736
+ return { ok: false, marked: false, tier: "local" };
8134
8737
  }
8135
8738
  if (!token) {
8136
8739
  this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
8137
8740
  this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
8138
- return { ok: false, marked: true };
8741
+ return { ok: false, marked: true, tier: "local" };
8139
8742
  }
8140
8743
  const plan = this.planFor(providerId);
8141
8744
  if (plan.kind === "local") {
8142
8745
  this.record(providerId, accountId, { ts: now, ok: true, tier: "local" });
8143
- return { ok: true, marked: false };
8746
+ return { ok: true, marked: false, tier: "local" };
8144
8747
  }
8145
8748
  const start = this.now();
8146
8749
  let status = null;
@@ -8165,7 +8768,60 @@ var AccountHealthProbeScheduler = class {
8165
8768
  latencyMs,
8166
8769
  tier: "upstream"
8167
8770
  });
8168
- return { ok: status !== null && status < 400, marked };
8771
+ return { ok: status !== null && status < 400, marked, tier: "upstream" };
8772
+ }
8773
+ /**
8774
+ * Manual connection test. Codex performs a real, quota-consuming generation;
8775
+ * every other provider keeps its existing cheap probe. Scheduled sweeps never
8776
+ * call this method, so they remain non-billable.
8777
+ */
8778
+ async testAccountConnection(providerId, accountId) {
8779
+ if (providerId !== "codex") return this.probeAccount(providerId, accountId);
8780
+ const now = this.now();
8781
+ let token;
8782
+ try {
8783
+ token = await this.store.getAccessTokenForAccount(providerId, accountId);
8784
+ } catch {
8785
+ this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
8786
+ return { ok: false, marked: false, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8787
+ }
8788
+ if (!token) {
8789
+ this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
8790
+ this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
8791
+ return { ok: false, marked: true, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8792
+ }
8793
+ const startedAt = this.now();
8794
+ let attempt = await this.runCodexGenerationAttempt(accountId, token);
8795
+ if (attempt.status === 401 && this.store.refreshAccountToken) {
8796
+ try {
8797
+ if (await this.store.refreshAccountToken(providerId, accountId)) {
8798
+ const refreshed = await this.store.getAccessTokenForAccount(providerId, accountId);
8799
+ if (refreshed) attempt = await this.runCodexGenerationAttempt(accountId, refreshed);
8800
+ }
8801
+ } catch {
8802
+ }
8803
+ }
8804
+ const latencyMs = this.now() - startedAt;
8805
+ const ok = attempt.status !== null && attempt.status >= 200 && attempt.status < 300 && attempt.completed;
8806
+ let marked = false;
8807
+ if (ok) {
8808
+ this.health.clearTransientMark(providerId, accountId);
8809
+ } else if (attempt.status === 401 || attempt.status === 403) {
8810
+ marked = this.applyOutcome(providerId, accountId, attempt.status, attempt.bodyText, now);
8811
+ }
8812
+ this.record(providerId, accountId, {
8813
+ ts: now,
8814
+ ok,
8815
+ status: attempt.status,
8816
+ latencyMs,
8817
+ tier: "generation"
8818
+ });
8819
+ return {
8820
+ ok,
8821
+ marked,
8822
+ tier: "generation",
8823
+ model: CODEX_GENERATION_PROBE_MODEL
8824
+ };
8169
8825
  }
8170
8826
  /** Per-account rolling history for the authed admin surface (design D5). */
8171
8827
  getAllHistory() {
@@ -8222,6 +8878,24 @@ var AccountHealthProbeScheduler = class {
8222
8878
  return "";
8223
8879
  }
8224
8880
  }
8881
+ async runCodexGenerationAttempt(accountId, token) {
8882
+ try {
8883
+ const timeoutMs = Math.max(this.config.timeoutMs, 15e3);
8884
+ const response = await this.fetchImpl(
8885
+ CODEX_GENERATION_PROBE_URL,
8886
+ buildCodexGenerationProbeInit(token, AbortSignal.timeout(timeoutMs)),
8887
+ { providerId: "codex", accountId, redactBodies: true }
8888
+ );
8889
+ if (response.status < 200 || response.status >= 300) {
8890
+ const bodyText = response.status === 403 ? await this.readBounded(response) : void 0;
8891
+ return { status: response.status, completed: false, bodyText };
8892
+ }
8893
+ const stream = await readCodexGenerationProbeStream(response);
8894
+ return { status: response.status, completed: stream.completed };
8895
+ } catch {
8896
+ return { status: null, completed: false };
8897
+ }
8898
+ }
8225
8899
  key(providerId, accountId) {
8226
8900
  return `${providerId}${KEY_SEP}${accountId}`;
8227
8901
  }
@@ -8317,7 +8991,7 @@ var AccountHealthSweeper = class {
8317
8991
  };
8318
8992
 
8319
8993
  // src/audit/AuditPruneSweeper.ts
8320
- var import_node_fs18 = require("fs");
8994
+ var import_node_fs19 = require("fs");
8321
8995
  var import_node_path12 = require("path");
8322
8996
 
8323
8997
  // src/audit/auditFiles.ts
@@ -8340,12 +9014,206 @@ function auditFileDateMs(fileName) {
8340
9014
  return d.getTime();
8341
9015
  }
8342
9016
 
9017
+ // src/audit/auditStats.ts
9018
+ var import_node_fs18 = require("fs");
9019
+ var import_node_path11 = require("path");
9020
+ var SIDECAR_VERSION = 1;
9021
+ var META_PREFIX_BYTES = 64 * 1024;
9022
+ var READ_CHUNK_BYTES = 4 * 1024 * 1024;
9023
+ function auditStatsFileName(auditFile) {
9024
+ return auditFile.replace(/\.jsonl$/, ".stats.json");
9025
+ }
9026
+ function readPersisted(path2) {
9027
+ if (!(0, import_node_fs18.existsSync)(path2)) return null;
9028
+ try {
9029
+ const value = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
9030
+ if (value.version !== SIDECAR_VERSION || !Number.isSafeInteger(value.auditBytes) || (value.auditBytes ?? -1) < 0 || !Number.isSafeInteger(value.requestCount) || (value.requestCount ?? -1) < 0 || !Number.isSafeInteger(value.errorCount) || (value.errorCount ?? -1) < 0 || (value.errorCount ?? 0) > (value.requestCount ?? -1) || typeof value.complete !== "boolean" || value.minTs !== null && !Number.isFinite(value.minTs) || value.maxTs !== null && !Number.isFinite(value.maxTs)) {
9031
+ return null;
9032
+ }
9033
+ return value;
9034
+ } catch {
9035
+ return null;
9036
+ }
9037
+ }
9038
+ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
9039
+ const statsPath = (0, import_node_path11.join)((0, import_node_path11.dirname)(auditPath), auditStatsFileName((0, import_node_path11.basename)(auditPath)));
9040
+ const previous = auditBytesBefore === 0 ? {
9041
+ version: SIDECAR_VERSION,
9042
+ auditBytes: 0,
9043
+ requestCount: 0,
9044
+ errorCount: 0,
9045
+ complete: true,
9046
+ minTs: null,
9047
+ maxTs: null
9048
+ } : readPersisted(statsPath);
9049
+ if (!previous || !previous.complete || previous.auditBytes !== auditBytesBefore) return;
9050
+ const next = {
9051
+ version: SIDECAR_VERSION,
9052
+ auditBytes: auditBytesAfter,
9053
+ requestCount: previous.requestCount + 1,
9054
+ errorCount: previous.errorCount + (record.status >= 400 || Boolean(record.error) ? 1 : 0),
9055
+ complete: true,
9056
+ minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
9057
+ maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
9058
+ };
9059
+ (0, import_node_fs18.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
9060
+ }
9061
+ function queryCovers(stats, from, to) {
9062
+ return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
9063
+ }
9064
+ function fileOverlaps(file, from, to) {
9065
+ const start = auditFileDateMs(file);
9066
+ if (start === null) return false;
9067
+ const date = new Date(start);
9068
+ const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
9069
+ return end > from && start <= to;
9070
+ }
9071
+ function parseMetadataPrefix(prefix, prefixTruncated) {
9072
+ const text = prefix.toString("utf8");
9073
+ const tsMatch = /(?:^|,)"ts":(-?\d+)/.exec(text);
9074
+ const statusMatch = /(?:^|,)"status":(-?\d+)/.exec(text);
9075
+ const errorMatch = /(?:^|,)"error":"((?:\\.|[^"\\])*)"/.exec(text);
9076
+ const bodyStarted = /,(?:"requestBody"|"responseBody"):/.test(text);
9077
+ return {
9078
+ ts: tsMatch ? Number(tsMatch[1]) : void 0,
9079
+ status: statusMatch ? Number(statusMatch[1]) : void 0,
9080
+ hasError: Boolean(errorMatch?.[1]),
9081
+ complete: Boolean(tsMatch && statusMatch && (!prefixTruncated || bodyStarted))
9082
+ };
9083
+ }
9084
+ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
9085
+ let requestCount = 0;
9086
+ let errorCount = 0;
9087
+ let filteredRequestCount = 0;
9088
+ let filteredErrorCount = 0;
9089
+ let minTs = null;
9090
+ let maxTs = null;
9091
+ let complete = true;
9092
+ let prefixParts = [];
9093
+ let prefixBytes = 0;
9094
+ let prefixTruncated = false;
9095
+ const consumeLine = () => {
9096
+ if (prefixBytes === 0 && !prefixTruncated) return;
9097
+ const prefix = Buffer.concat(prefixParts, prefixBytes);
9098
+ const metadata = parseMetadataPrefix(prefix, prefixTruncated);
9099
+ if (!metadata.complete || metadata.ts === void 0 || metadata.status === void 0) {
9100
+ complete = false;
9101
+ } else {
9102
+ requestCount += 1;
9103
+ const isError = metadata.status >= 400 || metadata.hasError;
9104
+ if (isError) errorCount += 1;
9105
+ minTs = minTs === null ? metadata.ts : Math.min(minTs, metadata.ts);
9106
+ maxTs = maxTs === null ? metadata.ts : Math.max(maxTs, metadata.ts);
9107
+ if (metadata.ts >= from && metadata.ts <= to) {
9108
+ filteredRequestCount += 1;
9109
+ if (isError) filteredErrorCount += 1;
9110
+ }
9111
+ }
9112
+ prefixParts = [];
9113
+ prefixBytes = 0;
9114
+ prefixTruncated = false;
9115
+ };
9116
+ if (auditBytes > startByte) {
9117
+ const stream = (0, import_node_fs18.createReadStream)(auditPath, {
9118
+ start: startByte,
9119
+ end: auditBytes - 1,
9120
+ highWaterMark: READ_CHUNK_BYTES
9121
+ });
9122
+ for await (const value of stream) {
9123
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
9124
+ let offset = 0;
9125
+ while (offset < chunk.length) {
9126
+ const newline = chunk.indexOf(10, offset);
9127
+ const end = newline === -1 ? chunk.length : newline;
9128
+ if (prefixBytes < META_PREFIX_BYTES) {
9129
+ const retained = Math.min(META_PREFIX_BYTES - prefixBytes, end - offset);
9130
+ if (retained > 0) {
9131
+ prefixParts.push(Buffer.from(chunk.subarray(offset, offset + retained)));
9132
+ prefixBytes += retained;
9133
+ }
9134
+ if (retained < end - offset) prefixTruncated = true;
9135
+ } else if (end > offset) {
9136
+ prefixTruncated = true;
9137
+ }
9138
+ if (newline === -1) break;
9139
+ consumeLine();
9140
+ offset = newline + 1;
9141
+ }
9142
+ }
9143
+ }
9144
+ if (prefixBytes > 0 || prefixTruncated) complete = false;
9145
+ return {
9146
+ all: {
9147
+ version: SIDECAR_VERSION,
9148
+ auditBytes,
9149
+ requestCount,
9150
+ errorCount,
9151
+ complete,
9152
+ minTs,
9153
+ maxTs
9154
+ },
9155
+ filtered: { requestCount: filteredRequestCount, errorCount: filteredErrorCount, complete }
9156
+ };
9157
+ }
9158
+ function mergePersistedStats(previous, appended) {
9159
+ return {
9160
+ version: SIDECAR_VERSION,
9161
+ auditBytes: appended.auditBytes,
9162
+ requestCount: previous.requestCount + appended.requestCount,
9163
+ errorCount: previous.errorCount + appended.errorCount,
9164
+ complete: previous.complete && appended.complete,
9165
+ minTs: previous.minTs === null ? appended.minTs : appended.minTs === null ? previous.minTs : Math.min(previous.minTs, appended.minTs),
9166
+ maxTs: previous.maxTs === null ? appended.maxTs : appended.maxTs === null ? previous.maxTs : Math.max(previous.maxTs, appended.maxTs)
9167
+ };
9168
+ }
9169
+ async function readAuditStats(auditDir, query2 = {}) {
9170
+ if (!(0, import_node_fs18.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
9171
+ const from = typeof query2.from === "number" ? query2.from : -Infinity;
9172
+ const to = typeof query2.to === "number" ? query2.to : Infinity;
9173
+ let files;
9174
+ try {
9175
+ files = (0, import_node_fs18.readdirSync)(auditDir).filter((file) => AUDIT_FILE_RE.test(file) && fileOverlaps(file, from, to)).sort();
9176
+ } catch {
9177
+ return { requestCount: 0, errorCount: 0, complete: false };
9178
+ }
9179
+ const total = { requestCount: 0, errorCount: 0, complete: true };
9180
+ for (const file of files) {
9181
+ const auditPath = (0, import_node_path11.join)(auditDir, file);
9182
+ try {
9183
+ const auditBytes = (0, import_node_fs18.statSync)(auditPath).size;
9184
+ const statsPath = (0, import_node_path11.join)(auditDir, auditStatsFileName(file));
9185
+ const persisted = readPersisted(statsPath);
9186
+ if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
9187
+ total.requestCount += persisted.requestCount;
9188
+ total.errorCount += persisted.errorCount;
9189
+ continue;
9190
+ }
9191
+ const resumable = persisted && persisted.complete && persisted.auditBytes < auditBytes && queryCovers(persisted, from, to) ? persisted : null;
9192
+ const scanned = await scanAuditFile(
9193
+ auditPath,
9194
+ resumable?.auditBytes ?? 0,
9195
+ auditBytes,
9196
+ from,
9197
+ to
9198
+ );
9199
+ total.requestCount += scanned.filtered.requestCount + (resumable?.requestCount ?? 0);
9200
+ total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
9201
+ total.complete = total.complete && scanned.filtered.complete;
9202
+ const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
9203
+ if (current.complete) (0, import_node_fs18.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
9204
+ } catch {
9205
+ total.complete = false;
9206
+ }
9207
+ }
9208
+ return total;
9209
+ }
9210
+
8343
9211
  // src/audit/AuditPruneSweeper.ts
8344
9212
  var DAY_MS = 24 * 60 * 6e4;
8345
9213
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
8346
9214
  var AuditPruneSweeper = class {
8347
- constructor(auditDir2, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
8348
- this.auditDir = auditDir2;
9215
+ constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
9216
+ this.auditDir = auditDir;
8349
9217
  this.logger = logger;
8350
9218
  this.config = config;
8351
9219
  this.intervalMs = intervalMs;
@@ -8392,17 +9260,19 @@ var AuditPruneSweeper = class {
8392
9260
  if (!this.config.enabled || this.sweeping) return 0;
8393
9261
  this.sweeping = true;
8394
9262
  try {
8395
- if (!(0, import_node_fs18.existsSync)(this.auditDir)) return 0;
9263
+ if (!(0, import_node_fs19.existsSync)(this.auditDir)) return 0;
8396
9264
  const today = new Date(this.now());
8397
9265
  const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
8398
9266
  const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
8399
9267
  let removed = 0;
8400
- for (const file of (0, import_node_fs18.readdirSync)(this.auditDir)) {
9268
+ for (const file of (0, import_node_fs19.readdirSync)(this.auditDir)) {
8401
9269
  const dateMs = auditFileDateMs(file);
8402
9270
  if (dateMs === null || dateMs >= cutoff) continue;
8403
9271
  try {
8404
- (0, import_node_fs18.unlinkSync)((0, import_node_path12.join)(this.auditDir, file));
9272
+ (0, import_node_fs19.unlinkSync)((0, import_node_path12.join)(this.auditDir, file));
8405
9273
  removed += 1;
9274
+ const statsPath = (0, import_node_path12.join)(this.auditDir, auditStatsFileName(file));
9275
+ if ((0, import_node_fs19.existsSync)(statsPath)) (0, import_node_fs19.unlinkSync)(statsPath);
8406
9276
  } catch (error) {
8407
9277
  this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
8408
9278
  file,
@@ -8424,15 +9294,15 @@ var AuditPruneSweeper = class {
8424
9294
  };
8425
9295
 
8426
9296
  // src/audit/auditReader.ts
8427
- var import_node_fs19 = require("fs");
9297
+ var import_node_fs20 = require("fs");
8428
9298
  var import_node_path13 = require("path");
8429
9299
  var DEFAULT_LIMIT = 200;
8430
9300
  var MAX_LIMIT = 2e3;
8431
- function readAuditRecords(auditDir2, query2 = {}) {
8432
- if (!(0, import_node_fs19.existsSync)(auditDir2)) return [];
9301
+ function readAuditRecords(auditDir, query2 = {}) {
9302
+ if (!(0, import_node_fs20.existsSync)(auditDir)) return [];
8433
9303
  let files;
8434
9304
  try {
8435
- files = (0, import_node_fs19.readdirSync)(auditDir2).filter((f) => AUDIT_FILE_RE.test(f));
9305
+ files = (0, import_node_fs20.readdirSync)(auditDir).filter((f) => AUDIT_FILE_RE.test(f));
8436
9306
  } catch {
8437
9307
  return [];
8438
9308
  }
@@ -8443,7 +9313,7 @@ function readAuditRecords(auditDir2, query2 = {}) {
8443
9313
  for (const file of files.sort().reverse()) {
8444
9314
  let raw;
8445
9315
  try {
8446
- raw = (0, import_node_fs19.readFileSync)((0, import_node_path13.join)(auditDir2, file), "utf8");
9316
+ raw = (0, import_node_fs20.readFileSync)((0, import_node_path13.join)(auditDir, file), "utf8");
8447
9317
  } catch {
8448
9318
  continue;
8449
9319
  }
@@ -8472,11 +9342,11 @@ function isAuditRecord(value) {
8472
9342
  }
8473
9343
 
8474
9344
  // src/audit/AuditWriter.ts
8475
- var import_node_fs20 = require("fs");
9345
+ var import_node_fs21 = require("fs");
8476
9346
  var import_node_path14 = require("path");
8477
9347
  var AuditWriter = class {
8478
- constructor(auditDir2, logger, defer = (fn) => setTimeout(fn, 0)) {
8479
- this.auditDir = auditDir2;
9348
+ constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
9349
+ this.auditDir = auditDir;
8480
9350
  this.logger = logger;
8481
9351
  this.defer = defer;
8482
9352
  }
@@ -8506,16 +9376,30 @@ var AuditWriter = class {
8506
9376
  */
8507
9377
  appendNow(record) {
8508
9378
  if (!this.dirEnsured) {
8509
- (0, import_node_fs20.mkdirSync)(this.auditDir, { recursive: true });
9379
+ (0, import_node_fs21.mkdirSync)(this.auditDir, { recursive: true });
8510
9380
  this.dirEnsured = true;
8511
9381
  }
8512
9382
  const file = (0, import_node_path14.join)(this.auditDir, auditFileName(record.ts));
8513
- (0, import_node_fs20.appendFileSync)(file, JSON.stringify(record) + "\n", "utf8");
9383
+ const line = JSON.stringify(record) + "\n";
9384
+ const auditBytesBefore = (0, import_node_fs21.existsSync)(file) ? (0, import_node_fs21.statSync)(file).size : 0;
9385
+ (0, import_node_fs21.appendFileSync)(file, line, "utf8");
9386
+ try {
9387
+ updateAuditStatsAfterAppend(
9388
+ file,
9389
+ auditBytesBefore,
9390
+ auditBytesBefore + Buffer.byteLength(line, "utf8"),
9391
+ record
9392
+ );
9393
+ } catch (error) {
9394
+ this.logger.warn("[AuditWriter] failed to update audit stats", {
9395
+ error: error instanceof Error ? error.message : String(error)
9396
+ });
9397
+ }
8514
9398
  }
8515
9399
  };
8516
9400
 
8517
9401
  // src/billing/BillingPublisher.ts
8518
- var import_node_fs21 = require("fs");
9402
+ var import_node_fs22 = require("fs");
8519
9403
  var import_node_crypto13 = require("crypto");
8520
9404
  var import_node_path15 = require("path");
8521
9405
  var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -8589,7 +9473,7 @@ var BillingPublisher = class {
8589
9473
  appendNow(event) {
8590
9474
  this.ensureDir();
8591
9475
  const file = (0, import_node_path15.join)(this.billingDir, billingFileName(event.ts));
8592
- (0, import_node_fs21.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
9476
+ (0, import_node_fs22.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
8593
9477
  }
8594
9478
  /**
8595
9479
  * One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
@@ -8639,7 +9523,7 @@ var BillingPublisher = class {
8639
9523
  try {
8640
9524
  this.ensureDir();
8641
9525
  const file = (0, import_node_path15.join)(this.billingDir, deliveredFileName(event.ts));
8642
- (0, import_node_fs21.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
9526
+ (0, import_node_fs22.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
8643
9527
  } catch (error) {
8644
9528
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
8645
9529
  error: error instanceof Error ? error.message : String(error)
@@ -8648,20 +9532,20 @@ var BillingPublisher = class {
8648
9532
  }
8649
9533
  ensureDir() {
8650
9534
  if (this.dirEnsured) return;
8651
- (0, import_node_fs21.mkdirSync)(this.billingDir, { recursive: true });
9535
+ (0, import_node_fs22.mkdirSync)(this.billingDir, { recursive: true });
8652
9536
  this.dirEnsured = true;
8653
9537
  }
8654
9538
  };
8655
9539
 
8656
9540
  // src/billing/billingReader.ts
8657
- var import_node_fs22 = require("fs");
9541
+ var import_node_fs23 = require("fs");
8658
9542
  var import_node_path16 = require("path");
8659
9543
  function readBillingLedger(billingDir) {
8660
9544
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
8661
- if (!(0, import_node_fs22.existsSync)(billingDir)) return view;
9545
+ if (!(0, import_node_fs23.existsSync)(billingDir)) return view;
8662
9546
  let files;
8663
9547
  try {
8664
- files = (0, import_node_fs22.readdirSync)(billingDir);
9548
+ files = (0, import_node_fs23.readdirSync)(billingDir);
8665
9549
  } catch {
8666
9550
  return view;
8667
9551
  }
@@ -8692,7 +9576,7 @@ function readBillingStatus(billingDir) {
8692
9576
  function parseLines(dir, file) {
8693
9577
  let raw;
8694
9578
  try {
8695
- raw = (0, import_node_fs22.readFileSync)((0, import_node_path16.join)(dir, file), "utf8");
9579
+ raw = (0, import_node_fs23.readFileSync)((0, import_node_path16.join)(dir, file), "utf8");
8696
9580
  } catch {
8697
9581
  return [];
8698
9582
  }
@@ -8878,6 +9762,76 @@ var TokenRefreshScheduler = class {
8878
9762
  }
8879
9763
  };
8880
9764
 
9765
+ // src/routeLeaseSubscriptionPreflight.ts
9766
+ var import_provider_proxy3 = require("@omnicross/core/provider-proxy");
9767
+ var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
9768
+ var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
9769
+ var import_accountModelMap = require("@omnicross/subscriptions/scheduler/accountModelMap");
9770
+ var PROVIDERS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "opencodego"]);
9771
+ function accountArray(config, providerId) {
9772
+ const record = config;
9773
+ const key = `${providerId}Accounts`;
9774
+ const accounts = record[key];
9775
+ if (Array.isArray(accounts)) return accounts;
9776
+ const legacy = record[providerId];
9777
+ if (!legacy || typeof legacy !== "object") return [];
9778
+ const activeKey = `active${providerId[0].toUpperCase()}${providerId.slice(1)}AccountId`;
9779
+ return [{ id: String(record[activeKey] ?? "active"), enabled: true, tokens: legacy }];
9780
+ }
9781
+ function hasCredential(providerId, account) {
9782
+ const tokens = account.tokens;
9783
+ if (providerId === "opencodego") return typeof tokens.apiKey === "string" && tokens.apiKey.length > 0;
9784
+ return typeof tokens.accessToken === "string" && tokens.accessToken.length > 0;
9785
+ }
9786
+ function safeProviderId(value) {
9787
+ if (!PROVIDERS.has(value)) {
9788
+ throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "subscription provider was not found");
9789
+ }
9790
+ return value;
9791
+ }
9792
+ function createRouteLeaseSubscriptionPreflight(credentials) {
9793
+ return {
9794
+ async assertAvailable(upstream, model) {
9795
+ const providerId = safeProviderId(upstream.providerId);
9796
+ const config = await credentials.getFullConfig();
9797
+ const all = accountArray(config, providerId);
9798
+ if (all.length === 0) {
9799
+ throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "subscription provider has no configured account");
9800
+ }
9801
+ let bounded = all;
9802
+ if (upstream.kind === "account") {
9803
+ bounded = all.filter((account) => account.id === upstream.accountId);
9804
+ } else if (upstream.kind === "account-group") {
9805
+ bounded = all.filter((account) => account.group?.trim() === upstream.group);
9806
+ }
9807
+ if (bounded.length === 0) {
9808
+ throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "the selected subscription resource was not found");
9809
+ }
9810
+ const modelEligible = bounded.filter(
9811
+ (account) => (0, import_accountModelMap.accountSupportsModel)(account.supportedModels, model)
9812
+ );
9813
+ if (modelEligible.length === 0) {
9814
+ throw new import_provider_proxy3.RouteLeaseError("model_not_configured", "model is not supported by the selected subscription resource");
9815
+ }
9816
+ const credentialEligible = modelEligible.filter(
9817
+ (account) => account.enabled !== false && hasCredential(providerId, account)
9818
+ );
9819
+ const health2 = (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)();
9820
+ const allowance = (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)();
9821
+ const candidates = credentialEligible.filter(
9822
+ (account) => health2.isSchedulable(providerId, account.id) && allowance.preview(providerId, account.id, account.priority ?? 50).schedulable
9823
+ );
9824
+ if (candidates.length > 0) return;
9825
+ if (upstream.kind === "account") {
9826
+ throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "the selected subscription account is unavailable");
9827
+ }
9828
+ throw new import_provider_proxy3.RouteLeaseError("upstream_exhausted", "the selected subscription pool has no eligible account", {
9829
+ retryAfterSeconds: 30
9830
+ });
9831
+ }
9832
+ };
9833
+ }
9834
+
8881
9835
  // src/webhook/WebhookDispatcher.ts
8882
9836
  var import_node_crypto14 = require("crypto");
8883
9837
  var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -9060,11 +10014,11 @@ function buildDaemon(config, paths) {
9060
10014
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
9061
10015
  );
9062
10016
  (0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
9063
- (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)().configure(
10017
+ (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
9064
10018
  (0, import_outbound_api5.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
9065
10019
  );
9066
10020
  const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
9067
- const keyDb = new JsonOutboundKeyDb(paths.keysPath);
10021
+ const keyDb = new JsonOutboundKeyDb(paths.keysPath, secretBox3);
9068
10022
  const voucherDb = new JsonVoucherDb(defaultVouchersPath(paths.configPath));
9069
10023
  const settingsStore = new JsonApiServerSettingsStore(paths.configPath, secretBox3);
9070
10024
  const integrationStateStore = new IntegrationStateStore(
@@ -9127,11 +10081,22 @@ function buildDaemon(config, paths) {
9127
10081
  const usageRecorder = new import_usage.UsageRecorder(usageEventStore, pricingEngine, logger, {
9128
10082
  onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
9129
10083
  });
9130
- const providerProxy = (0, import_provider_proxy.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
10084
+ const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
10085
+ const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
10086
+ providerProxy,
10087
+ new import_provider_proxy4.RouteLeaseTargetResolver(llmConfig, {
10088
+ providerKeys: apiKeyPool,
10089
+ subscriptions: createRouteLeaseSubscriptionPreflight(credentialStore)
10090
+ }),
10091
+ import_cli_launcher2.routeLeaseDescriptorPort,
10092
+ { logger }
10093
+ );
10094
+ providerProxy.registerBeforeStop(() => routeLeaseManager.shutdown());
10095
+ providerProxy.registerBeforeStop(() => resetCliSessions());
9131
10096
  llmConfig.setReloadHook(() => apiKeyPool.invalidateCache());
9132
10097
  const accountHealthProbeScheduler = new AccountHealthProbeScheduler(
9133
10098
  credentialStore,
9134
- (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)(),
10099
+ (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
9135
10100
  logger,
9136
10101
  import_outbound_api5.DEFAULT_ACCOUNT_PROBE
9137
10102
  );
@@ -9165,7 +10130,7 @@ function buildDaemon(config, paths) {
9165
10130
  // lines through the injected logger (honors level/format/file sink).
9166
10131
  logger
9167
10132
  });
9168
- const auditDir2 = defaultAuditDir(paths.configPath);
10133
+ const auditDir = defaultAuditDir(paths.configPath);
9169
10134
  const billingDir = defaultBillingDir(paths.configPath);
9170
10135
  const adminServer = new AdminServer({
9171
10136
  configPath: paths.configPath,
@@ -9178,6 +10143,7 @@ function buildDaemon(config, paths) {
9178
10143
  keySpendReader: keySpendTracker,
9179
10144
  settingsStore,
9180
10145
  outboundApiServer,
10146
+ routeLeaseManager,
9181
10147
  subscriptionAccounts,
9182
10148
  accountAllowanceService,
9183
10149
  allowanceRefreshScheduler: claudeAllowanceRefreshScheduler,
@@ -9199,10 +10165,16 @@ function buildDaemon(config, paths) {
9199
10165
  // (NOT widening the least-authority writer — no token-returning read reachable).
9200
10166
  oauthSessions: new OAuthSessionStore(),
9201
10167
  // Real global fetch by default; a test seam (`paths.oauthExchangeFetch`) can
9202
- // inject a mock so no real token endpoint is hit.
9203
- // upstream-proxy: default the OAuth token-exchange fetch to the proxy-aware
9204
- // helper so interactive login honors a configured proxy (global/env layers).
9205
- oauthExchangeFetch: paths.oauthExchangeFetch ?? ((url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)),
10168
+ // inject a mock so no real token endpoint is hit (one FetchLike for every
10169
+ // provider the ctx below only matters on the real egress path).
10170
+ //
10171
+ // upstream-proxy: a PER-PROVIDER factory, so the exchange carries the same
10172
+ // `{ providerId }` ctx the CLI login and the token refresh already pass.
10173
+ // Without it the interactive login resolved only the global/env proxy layers
10174
+ // — `server.proxy.byProvider[...]` was silently skipped — and the call was
10175
+ // excluded from the upstream trace, so a failing login left no evidence.
10176
+ // `redactBodies` keeps the code/verifier + minted token out of that trace.
10177
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId, redactBodies: true }),
9206
10178
  subscriptionAccountAppender: credentialStore,
9207
10179
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
9208
10180
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -9254,7 +10226,8 @@ function buildDaemon(config, paths) {
9254
10226
  // date-rotated audit store. Bound to the store dir here so the AdminServer
9255
10227
  // carries no path/store coupling. Records hold IP/UA/bodies → admin-only,
9256
10228
  // NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
9257
- auditReader: (query2) => readAuditRecords(auditDir2, query2),
10229
+ auditReader: (query2) => readAuditRecords(auditDir, query2),
10230
+ auditStatsReader: (query2) => readAuditStats(auditDir, query2),
9258
10231
  // billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
9259
10232
  // secret-free total/delivered/pending counts of the durable ledger.
9260
10233
  billingStatusReader: () => readBillingStatus(billingDir)
@@ -9263,10 +10236,10 @@ function buildDaemon(config, paths) {
9263
10236
  logger,
9264
10237
  fetchImpl: (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)
9265
10238
  });
9266
- setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)());
9267
- const auditWriter = new AuditWriter(auditDir2, logger);
9268
- const auditPruneSweeper = new AuditPruneSweeper(auditDir2, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
9269
- setAuditRuntime(auditWriter, auditPruneSweeper, auditDir2);
10239
+ setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
10240
+ const auditWriter = new AuditWriter(auditDir, logger);
10241
+ const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
10242
+ setAuditRuntime(auditWriter, auditPruneSweeper);
9270
10243
  const billingPublisher = new BillingPublisher(billingDir, logger);
9271
10244
  const billingRetrySweeper = new BillingRetrySweeper(
9272
10245
  billingDir,
@@ -9278,7 +10251,7 @@ function buildDaemon(config, paths) {
9278
10251
  const tokenRefreshScheduler = new TokenRefreshScheduler(credentialStore, logger);
9279
10252
  const accountHealthSweeper = new AccountHealthSweeper(
9280
10253
  credentialStore,
9281
- (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)(),
10254
+ (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
9282
10255
  logger
9283
10256
  );
9284
10257
  return {
@@ -9287,6 +10260,7 @@ function buildDaemon(config, paths) {
9287
10260
  keyDb,
9288
10261
  settingsStore,
9289
10262
  providerProxy,
10263
+ routeLeaseManager,
9290
10264
  outboundApiServer,
9291
10265
  apiKeyPool,
9292
10266
  autoDisableStore,
@@ -9312,8 +10286,8 @@ function buildDaemon(config, paths) {
9312
10286
  }
9313
10287
  function isTokensStoreReadable(tokensPath) {
9314
10288
  try {
9315
- if (!(0, import_node_fs23.existsSync)(tokensPath)) return true;
9316
- (0, import_node_fs23.accessSync)(tokensPath, import_node_fs23.constants.R_OK);
10289
+ if (!(0, import_node_fs24.existsSync)(tokensPath)) return true;
10290
+ (0, import_node_fs24.accessSync)(tokensPath, import_node_fs24.constants.R_OK);
9317
10291
  return true;
9318
10292
  } catch {
9319
10293
  return false;
@@ -9361,7 +10335,7 @@ function resolveInPathDefault(candidate) {
9361
10335
  const segments = (process.env["PATH"] ?? "").split(import_node_path17.delimiter).filter(Boolean);
9362
10336
  for (const seg of segments) {
9363
10337
  const full = (0, import_node_path17.join)(seg, candidate);
9364
- if ((0, import_node_fs24.existsSync)(full)) return full;
10338
+ if ((0, import_node_fs25.existsSync)(full)) return full;
9365
10339
  }
9366
10340
  return null;
9367
10341
  }
@@ -9402,32 +10376,17 @@ async function runLaunch(argv, deps) {
9402
10376
  await daemon.llmConfig.ready();
9403
10377
  await daemon.providerProxy.start();
9404
10378
  } catch (err5) {
9405
- daemon.apiKeyPool.dispose();
9406
- daemon.tokenRefreshScheduler.dispose();
9407
- daemon.claudeAllowanceRefreshScheduler.dispose();
9408
- daemon.accountHealthSweeper.dispose();
9409
- daemon.accountHealthProbeScheduler.dispose();
9410
- daemon.auditPruneSweeper.dispose();
9411
- daemon.billingRetrySweeper.dispose();
9412
- daemon.pricingRefreshScheduler.dispose();
10379
+ await shutdownLaunchDaemon(daemon);
9413
10380
  throw err5;
9414
10381
  }
9415
10382
  let launch;
9416
10383
  try {
9417
- launch = await buildLaunchConfig(cli, daemon.llmConfig, {
10384
+ launch = await buildLaunchConfig(cli, daemon, {
9418
10385
  providerId: values.provider,
9419
10386
  model: values.model
9420
10387
  });
9421
10388
  } catch (err5) {
9422
- await daemon.providerProxy.stop();
9423
- daemon.apiKeyPool.dispose();
9424
- daemon.tokenRefreshScheduler.dispose();
9425
- daemon.claudeAllowanceRefreshScheduler.dispose();
9426
- daemon.accountHealthSweeper.dispose();
9427
- daemon.accountHealthProbeScheduler.dispose();
9428
- daemon.auditPruneSweeper.dispose();
9429
- daemon.billingRetrySweeper.dispose();
9430
- daemon.pricingRefreshScheduler.dispose();
10389
+ await shutdownLaunchDaemon(daemon);
9431
10390
  throw err5;
9432
10391
  }
9433
10392
  try {
@@ -9446,21 +10405,40 @@ async function runLaunch(argv, deps) {
9446
10405
  cwd: values.cwd
9447
10406
  });
9448
10407
  } finally {
9449
- launch.onSessionEnd();
9450
- await daemon.providerProxy.stop();
9451
- daemon.apiKeyPool.dispose();
9452
- daemon.tokenRefreshScheduler.dispose();
9453
- daemon.claudeAllowanceRefreshScheduler.dispose();
9454
- daemon.accountHealthSweeper.dispose();
9455
- daemon.accountHealthProbeScheduler.dispose();
9456
- daemon.auditPruneSweeper.dispose();
9457
- daemon.billingRetrySweeper.dispose();
9458
- daemon.pricingRefreshScheduler.dispose();
9459
- }
9460
- }
9461
- async function buildLaunchConfig(cli, llmConfig, opts) {
10408
+ try {
10409
+ launch.onSessionEnd();
10410
+ } finally {
10411
+ await shutdownLaunchDaemon(daemon);
10412
+ }
10413
+ }
10414
+ }
10415
+ async function buildLaunchConfig(cli, daemon, opts) {
10416
+ if (cli === "claude" || cli === "codex") {
10417
+ const internalId = (0, import_node_crypto15.randomUUID)();
10418
+ const outcome = await daemon.routeLeaseManager.createFromRequest({
10419
+ schemaVersion: import_provider_proxy5.ROUTE_LEASE_REQUEST_SCHEMA,
10420
+ consumer: "omnicross-terminal",
10421
+ runtime: cli,
10422
+ upstream: { kind: "provider", providerId: opts.providerId },
10423
+ model: opts.model,
10424
+ execution: { sessionId: `launch:${cli}:${internalId}` }
10425
+ }, `omnicross-launch:${internalId}`);
10426
+ const stopRenewal = startTerminalLeaseRenewal(
10427
+ daemon.routeLeaseManager,
10428
+ outcome.result.leaseId
10429
+ );
10430
+ return {
10431
+ baseUrl: daemon.providerProxy.getBaseUrl(),
10432
+ env: outcome.result.launch.env,
10433
+ extraArgs: outcome.result.launch.extraArgs,
10434
+ onSessionEnd: () => {
10435
+ stopRenewal();
10436
+ daemon.routeLeaseManager.release(outcome.result.leaseId);
10437
+ }
10438
+ };
10439
+ }
9462
10440
  const common = {
9463
- llmConfig,
10441
+ llmConfig: daemon.llmConfig,
9464
10442
  providerId: opts.providerId,
9465
10443
  model: opts.model,
9466
10444
  // Stable, bounded session id — pool failover (poolseam) fires on launch
@@ -9468,22 +10446,30 @@ async function buildLaunchConfig(cli, llmConfig, opts) {
9468
10446
  sessionId: `launch:${cli}`
9469
10447
  };
9470
10448
  switch (cli) {
9471
- case "claude":
9472
- return (0, import_cli_launcher2.buildClaudeCliLaunchConfig)(common);
9473
- case "codex":
9474
- return (0, import_cli_launcher2.buildCodexLaunchConfig)(common);
9475
10449
  case "gemini":
9476
- return (0, import_cli_launcher2.buildGeminiCliLaunchConfig)(common);
10450
+ return (0, import_cli_launcher3.buildGeminiCliLaunchConfig)(common);
9477
10451
  case "qwen":
9478
10452
  case "copilot":
9479
10453
  case "opencode":
9480
- return (0, import_cli_launcher2.buildChatCliLaunchConfig)({ backendId: cli, ...common });
10454
+ return (0, import_cli_launcher3.buildChatCliLaunchConfig)({ backendId: cli, ...common });
9481
10455
  default: {
9482
10456
  const _exhaustive = cli;
9483
10457
  throw new Error(`Unsupported launch CLI: ${String(_exhaustive)}`);
9484
10458
  }
9485
10459
  }
9486
10460
  }
10461
+ async function shutdownLaunchDaemon(daemon) {
10462
+ daemon.routeLeaseManager.shutdown();
10463
+ await daemon.providerProxy.stop();
10464
+ daemon.apiKeyPool.dispose();
10465
+ daemon.tokenRefreshScheduler.dispose();
10466
+ daemon.claudeAllowanceRefreshScheduler.dispose();
10467
+ daemon.accountHealthSweeper.dispose();
10468
+ daemon.accountHealthProbeScheduler.dispose();
10469
+ daemon.auditPruneSweeper.dispose();
10470
+ daemon.billingRetrySweeper.dispose();
10471
+ daemon.pricingRefreshScheduler.dispose();
10472
+ }
9487
10473
  function spawnCliInherit(plan) {
9488
10474
  return new Promise((resolve3, reject) => {
9489
10475
  const child = (0, import_node_child_process2.spawn)(plan.command, plan.args, {
@@ -9530,7 +10516,7 @@ var import_node_readline = require("readline");
9530
10516
  var import_node_util5 = require("util");
9531
10517
  var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
9532
10518
  var import_subscriptions5 = require("@omnicross/subscriptions");
9533
- var PROVIDERS = ["claude", "codex", "gemini"];
10519
+ var PROVIDERS2 = ["claude", "codex", "gemini"];
9534
10520
  async function runLogin(argv, deps) {
9535
10521
  const { values, positionals } = (0, import_node_util5.parseArgs)({
9536
10522
  args: argv,
@@ -9544,10 +10530,10 @@ async function runLogin(argv, deps) {
9544
10530
  });
9545
10531
  const provider = positionals[0];
9546
10532
  if (!provider) {
9547
- throw new Error(`login: a <provider> is required (one of ${PROVIDERS.join("|")})`);
10533
+ throw new Error(`login: a <provider> is required (one of ${PROVIDERS2.join("|")})`);
9548
10534
  }
9549
10535
  if (!isLoginProvider(provider)) {
9550
- throw new Error(`login: unknown provider '${provider}' (expected ${PROVIDERS.join("|")})`);
10536
+ throw new Error(`login: unknown provider '${provider}' (expected ${PROVIDERS2.join("|")})`);
9551
10537
  }
9552
10538
  if (!values.config) {
9553
10539
  throw new Error("login: --config <path> is required");
@@ -9563,7 +10549,7 @@ async function runLogin(argv, deps) {
9563
10549
  (0, import_upstreamFetch9.setUpstreamProxyResolver)(createUpstreamProxyResolver());
9564
10550
  try {
9565
10551
  const tokensPath = defaultTokensPath(values.config);
9566
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId: provider }));
10552
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
9567
10553
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
9568
10554
  const expiresAt = await runProviderLogin(
9569
10555
  provider,
@@ -9653,7 +10639,7 @@ async function loginGemini(store, deps, exchangeFetch, label) {
9653
10639
  return expiresAt;
9654
10640
  }
9655
10641
  function isLoginProvider(value) {
9656
- return PROVIDERS.includes(value);
10642
+ return PROVIDERS2.includes(value);
9657
10643
  }
9658
10644
  async function presentUrl(authUrl, deps) {
9659
10645
  console.info("Open this URL in your browser to authorize:");
@@ -9699,7 +10685,7 @@ function promptPaste(prompt) {
9699
10685
  }
9700
10686
 
9701
10687
  // src/commands/providers.ts
9702
- var import_node_crypto15 = require("crypto");
10688
+ var import_node_crypto16 = require("crypto");
9703
10689
  var import_node_util6 = require("util");
9704
10690
  async function runProviders(argv) {
9705
10691
  const { values, positionals } = (0, import_node_util6.parseArgs)({
@@ -9821,7 +10807,7 @@ function providersAddKey(configPath, providerId, opts) {
9821
10807
  const cfg = loadConfig(configPath);
9822
10808
  const row = cfg.providers.find((p) => p.id === providerId);
9823
10809
  if (!row) throw new Error(`providers add-key: unknown provider '${providerId}'`);
9824
- const entry = { id: (0, import_node_crypto15.randomUUID)(), apiKey: opts.key };
10810
+ const entry = { id: (0, import_node_crypto16.randomUUID)(), apiKey: opts.key };
9825
10811
  if (opts.label) entry.label = opts.label;
9826
10812
  if (opts.weight !== void 0) {
9827
10813
  const w = Number(opts.weight);
@@ -9849,7 +10835,7 @@ function providersRmKey(configPath, providerId, keyId) {
9849
10835
  }
9850
10836
 
9851
10837
  // src/commands/secrets.ts
9852
- var import_node_fs25 = require("fs");
10838
+ var import_node_fs26 = require("fs");
9853
10839
  var import_node_util7 = require("util");
9854
10840
  async function runSecrets(argv) {
9855
10841
  const { values, positionals } = (0, import_node_util7.parseArgs)({
@@ -9922,12 +10908,12 @@ function secretsStatus(args) {
9922
10908
  reportField("admin.token", cfg.admin.token);
9923
10909
  }
9924
10910
  const tokensPath = defaultTokensPath(args.config);
9925
- if ((0, import_node_fs25.existsSync)(tokensPath)) {
10911
+ if ((0, import_node_fs26.existsSync)(tokensPath)) {
9926
10912
  console.info(`Secret status for ${tokensPath}:`);
9927
10913
  reportTokenFields(tokensPath);
9928
10914
  }
9929
10915
  const integrationsPath = defaultIntegrationsPath(args.config);
9930
- if ((0, import_node_fs25.existsSync)(integrationsPath)) {
10916
+ if ((0, import_node_fs26.existsSync)(integrationsPath)) {
9931
10917
  const state = readRawJson(integrationsPath);
9932
10918
  const key = state.gatewayKey;
9933
10919
  if (key && typeof key === "object" && !Array.isArray(key)) {
@@ -9981,8 +10967,8 @@ async function secretsRotate(args) {
9981
10967
  const integrationsPath = defaultIntegrationsPath(args.config);
9982
10968
  try {
9983
10969
  cfg = loadConfig(args.config);
9984
- if ((0, import_node_fs25.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
9985
- if ((0, import_node_fs25.existsSync)(integrationsPath)) {
10970
+ if ((0, import_node_fs26.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
10971
+ if ((0, import_node_fs26.existsSync)(integrationsPath)) {
9986
10972
  integrationsPlain = new IntegrationStateStore(integrationsPath, oldBox).load();
9987
10973
  }
9988
10974
  } finally {
@@ -10017,20 +11003,20 @@ function secretsDecrypt(args) {
10017
11003
  let tokensPlain = null;
10018
11004
  try {
10019
11005
  cfg = loadConfig(args.config);
10020
- if ((0, import_node_fs25.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
11006
+ if ((0, import_node_fs26.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
10021
11007
  } finally {
10022
11008
  setSecretBox(null);
10023
11009
  }
10024
11010
  saveConfig(args.config, cfg);
10025
11011
  if (tokensPlain) {
10026
- (0, import_node_fs25.writeFileSync)(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
11012
+ (0, import_node_fs26.writeFileSync)(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
10027
11013
  }
10028
11014
  console.info(`Decrypted secrets to plaintext in ${args.config}` + tokensSuffix(args.config));
10029
11015
  }
10030
11016
  function readRawConfig(path2) {
10031
11017
  let parsed;
10032
11018
  try {
10033
- parsed = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8"));
11019
+ parsed = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
10034
11020
  } catch {
10035
11021
  throw new Error(`secrets: cannot read or parse '${path2}'`);
10036
11022
  }
@@ -10038,7 +11024,7 @@ function readRawConfig(path2) {
10038
11024
  }
10039
11025
  function readRawJson(path2) {
10040
11026
  try {
10041
- const parsed = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8"));
11027
+ const parsed = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
10042
11028
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
10043
11029
  return parsed;
10044
11030
  }
@@ -10048,13 +11034,13 @@ function readRawJson(path2) {
10048
11034
  }
10049
11035
  function encryptTokensFileInPlace(configPath, box) {
10050
11036
  const tokensPath = defaultTokensPath(configPath);
10051
- if (!(0, import_node_fs25.existsSync)(tokensPath)) return;
11037
+ if (!(0, import_node_fs26.existsSync)(tokensPath)) return;
10052
11038
  const plain = decryptTokensFile(tokensPath, box);
10053
11039
  writeTokensEncrypted(tokensPath, plain, box);
10054
11040
  }
10055
11041
  function rewriteIntegrationState(configPath, readBox, writeBox) {
10056
11042
  const path2 = defaultIntegrationsPath(configPath);
10057
- if (!(0, import_node_fs25.existsSync)(path2)) return;
11043
+ if (!(0, import_node_fs26.existsSync)(path2)) return;
10058
11044
  const state = new IntegrationStateStore(path2, readBox).load();
10059
11045
  new IntegrationStateStore(path2, writeBox).save(state);
10060
11046
  }
@@ -10067,7 +11053,7 @@ function writeTokensEncrypted(tokensPath, plain, box) {
10067
11053
  { updatedAt: "", ...plain },
10068
11054
  box
10069
11055
  );
10070
- (0, import_node_fs25.writeFileSync)(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
11056
+ (0, import_node_fs26.writeFileSync)(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
10071
11057
  }
10072
11058
  var TOKEN_FIELDS2 = {
10073
11059
  claude: ["accessToken", "refreshToken"],
@@ -10090,14 +11076,14 @@ function walkTokens(raw, fn) {
10090
11076
  return next;
10091
11077
  }
10092
11078
  function tokensSuffix(configPath) {
10093
- return (0, import_node_fs25.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
11079
+ return (0, import_node_fs26.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
10094
11080
  }
10095
11081
 
10096
11082
  // src/commands/start.ts
10097
11083
  var import_node_util8 = require("util");
10098
11084
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
10099
- var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
10100
- var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
11085
+ var import_SubscriptionAccountHealth5 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
11086
+ var import_AccountAllowanceScheduling6 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
10101
11087
 
10102
11088
  // src/identity/identityRuntime.ts
10103
11089
  var import_SubscriptionIdentityStore4 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
@@ -10157,11 +11143,11 @@ async function runStart(argv) {
10157
11143
  await daemon.llmConfig.ready();
10158
11144
  await daemon.providerProxy.start();
10159
11145
  const serverConfig = await (0, import_outbound_api7.loadServerConfig)(daemon.settingsStore);
10160
- (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)().configure({
11146
+ (0, import_SubscriptionAccountHealth5.getSharedAccountHealth)().configure({
10161
11147
  overloadEnabled: serverConfig.accountHealth?.overloadCooldownEnabled,
10162
11148
  overloadTtlMs: serverConfig.accountHealth?.overloadCooldownMs
10163
11149
  });
10164
- (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(serverConfig.allowanceScheduling);
11150
+ (0, import_AccountAllowanceScheduling6.getSharedAccountAllowanceScheduling)().configure(serverConfig.allowanceScheduling);
10165
11151
  daemon.claudeAllowanceRefreshScheduler.configure(serverConfig.allowanceScheduling);
10166
11152
  await daemon.outboundApiServer.applyConfig({
10167
11153
  enabled: true,