@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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/bootstrap.ts
2
- import { accessSync, constants as fsConstants, existsSync as existsSync17 } from "fs";
2
+ import { accessSync, constants as fsConstants, existsSync as existsSync19 } from "fs";
3
3
  import { DEFAULT_AUDIT_CONFIG } from "@omnicross/contracts/audit-types";
4
4
  import { DEFAULT_BILLING_CONFIG } from "@omnicross/contracts/billing-types";
5
5
  import { getGeminiCodeAssistProjectResolver } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
@@ -12,7 +12,7 @@ import {
12
12
  normalizeServerConfig
13
13
  } from "@omnicross/core/outbound-api";
14
14
  import { setSubscriptionRegistryForOutbound } from "@omnicross/core/outbound-api/subscriptionRegistryPort";
15
- import { getSharedAccountHealth as getSharedAccountHealth3 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
15
+ import { getSharedAccountHealth as getSharedAccountHealth4 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
16
16
  import {
17
17
  __resetSharedAccountAllowanceStoreForTests,
18
18
  AccountAllowanceStore as AccountAllowanceStore3,
@@ -20,15 +20,18 @@ import {
20
20
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
21
21
  import {
22
22
  __resetSharedAccountAllowanceSchedulingForTests,
23
- getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling4
23
+ getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling5
24
24
  } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
25
25
  import { fetchUpstream as fetchUpstream7, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
26
26
  import { __resetSharedIdentityStoreForTests } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
27
27
  import { setGeminiCodeAssistResolver } from "@omnicross/core/ports/gemini-code-assist-resolver";
28
28
  import {
29
29
  __resetProviderProxyForTests,
30
- getProviderProxy
30
+ getProviderProxy,
31
+ RouteLeaseManager,
32
+ RouteLeaseTargetResolver
31
33
  } from "@omnicross/core/provider-proxy";
34
+ import { routeLeaseDescriptorPort } from "@omnicross/cli-launcher";
32
35
  import { KeySpendTracker } from "@omnicross/core/outbound-api";
33
36
  import { PricingEngine, UsageRecorder } from "@omnicross/core/usage";
34
37
  import {
@@ -114,7 +117,7 @@ async function runCodexLoopback(sessionId, codeVerifier, state, signal, deps) {
114
117
  const code = await deps.codexAwaitLoopback(state, void 0, signal);
115
118
  const result = await codexOAuth.exchangeCodeForTokens(
116
119
  { authorizationCode: code, codeVerifier, state },
117
- deps.oauthExchangeFetch
120
+ deps.oauthExchangeFetch("codex")
118
121
  );
119
122
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
120
123
  const block = {
@@ -634,6 +637,17 @@ function handleAuditQuery(req, res, reader) {
634
637
  res.writeHead(200, { "Content-Type": "application/json" });
635
638
  res.end(JSON.stringify({ records }));
636
639
  }
640
+ async function handleAuditStatsQuery(req, res, reader) {
641
+ const url = new URL(req.url ?? "/", "http://localhost");
642
+ const query2 = {};
643
+ const from = intParam(url.searchParams.get("from"));
644
+ if (from !== void 0) query2.from = from;
645
+ const to = intParam(url.searchParams.get("to"));
646
+ if (to !== void 0) query2.to = to;
647
+ const stats = reader ? await reader(query2) : { requestCount: 0, errorCount: 0, complete: true };
648
+ res.writeHead(200, { "Content-Type": "application/json" });
649
+ res.end(JSON.stringify(stats));
650
+ }
637
651
 
638
652
  // src/admin/billingStatusApi.ts
639
653
  function handleBillingStatus(res, reader) {
@@ -730,6 +744,93 @@ async function handleWebhookTest(req, res) {
730
744
  res.end(JSON.stringify({ result }));
731
745
  }
732
746
 
747
+ // src/admin/routeLeaseApi.ts
748
+ import {
749
+ isLoopbackAddress,
750
+ normalizeRouteLeaseTtl,
751
+ ROUTE_LEASE_CAPABILITIES,
752
+ RouteLeaseError
753
+ } from "@omnicross/core/provider-proxy";
754
+ var MAX_BODY_BYTES = 64 * 1024;
755
+ var SAFE_LEASE_ID = /^[A-Za-z0-9-]{1,128}$/u;
756
+ async function readJson(req) {
757
+ const chunks = [];
758
+ let bytes = 0;
759
+ for await (const chunk of req) {
760
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
761
+ bytes += buffer.length;
762
+ if (bytes > MAX_BODY_BYTES) throw new RouteLeaseError("invalid_request", "request body is too large");
763
+ chunks.push(buffer);
764
+ }
765
+ if (chunks.length === 0) return {};
766
+ try {
767
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
768
+ } catch {
769
+ throw new RouteLeaseError("invalid_request", "request body is not valid JSON");
770
+ }
771
+ }
772
+ function json(res, status, body, noStore = false) {
773
+ res.statusCode = status;
774
+ res.setHeader("Content-Type", "application/json");
775
+ if (noStore) res.setHeader("Cache-Control", "no-store");
776
+ res.end(JSON.stringify(body));
777
+ }
778
+ function leaseId(value) {
779
+ if (!value || !SAFE_LEASE_ID.test(value)) throw new RouteLeaseError("invalid_request", "lease id is invalid");
780
+ return value;
781
+ }
782
+ function header(req, name) {
783
+ const value = req.headers[name.toLowerCase()];
784
+ return Array.isArray(value) ? value[0] : value;
785
+ }
786
+ function writeError(res, error, noStore) {
787
+ const safe = error instanceof RouteLeaseError ? error : new RouteLeaseError("upstream_unavailable", "route lease operation failed safely");
788
+ if (safe.retryAfterSeconds !== void 0) res.setHeader("Retry-After", String(safe.retryAfterSeconds));
789
+ json(res, safe.status, safe.toResponse(), noStore);
790
+ }
791
+ async function handleRouteLeaseApi(req, res, path2, deps) {
792
+ const method = (req.method ?? "GET").toUpperCase();
793
+ const noStore = method === "POST" && (path2 === "/admin/api/route-leases" || path2.endsWith("/renew"));
794
+ try {
795
+ if (!isLoopbackAddress(req.socket.remoteAddress)) {
796
+ throw new RouteLeaseError("control_unauthorized", "route lease control plane is loopback only");
797
+ }
798
+ const manager = deps.routeLeaseManager;
799
+ if (!manager) throw new RouteLeaseError("daemon_not_ready", "route lease manager is unavailable");
800
+ const base = "/admin/api/route-leases";
801
+ const suffix = path2.slice(base.length).replace(/^\/+|\/+$/gu, "");
802
+ const segments = suffix ? suffix.split("/") : [];
803
+ if (segments.length === 1 && segments[0] === "capabilities") {
804
+ if (method !== "GET" && method !== "HEAD") throw new RouteLeaseError("invalid_request", "method is not allowed");
805
+ return json(res, 200, ROUTE_LEASE_CAPABILITIES);
806
+ }
807
+ if (segments.length === 0) {
808
+ if (method === "GET") return json(res, 200, { leases: manager.list() });
809
+ if (method === "POST") {
810
+ const outcome = await manager.createFromRequest(await readJson(req), header(req, "idempotency-key"));
811
+ return json(res, outcome.created ? 201 : 200, outcome.result, true);
812
+ }
813
+ throw new RouteLeaseError("invalid_request", "method is not allowed");
814
+ }
815
+ const id = leaseId(segments[0]);
816
+ if (segments.length === 1) {
817
+ if (method === "GET") return json(res, 200, manager.get(id));
818
+ if (method === "DELETE") return json(res, 200, manager.release(id));
819
+ throw new RouteLeaseError("invalid_request", "method is not allowed");
820
+ }
821
+ if (segments.length === 2 && segments[1] === "renew" && method === "POST") {
822
+ const body = await readJson(req);
823
+ const ttl = normalizeRouteLeaseTtl(
824
+ body && typeof body === "object" && !Array.isArray(body) ? body.ttlSeconds : void 0
825
+ );
826
+ return json(res, 200, manager.renew(id, ttl), true);
827
+ }
828
+ throw new RouteLeaseError("lease_not_found", "route lease endpoint was not found");
829
+ } catch (error) {
830
+ writeError(res, error, noStore);
831
+ }
832
+ }
833
+
733
834
  // src/admin/adminApi.ts
734
835
  import http from "http";
735
836
  import {
@@ -2145,7 +2246,13 @@ function listMappablePresets() {
2145
2246
  name: preset.name,
2146
2247
  apiFormat: resolved.format,
2147
2248
  baseUrl: preset.api_base_url,
2148
- models: Array.isArray(preset.models) ? preset.models : []
2249
+ models: Array.isArray(preset.models) ? preset.models : [],
2250
+ nameKey: preset.nameKey,
2251
+ icon: preset.icon,
2252
+ description: preset.description,
2253
+ features: preset.features,
2254
+ website: preset.website,
2255
+ modelsEndpoint: preset.modelsEndpoint
2149
2256
  });
2150
2257
  }
2151
2258
  return { mappable, excluded };
@@ -2536,7 +2643,7 @@ async function handleOAuthComplete(providerId, body, deps) {
2536
2643
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
2537
2644
  if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
2538
2645
  if (!rawCode) return err2(400, "oauth complete requires { code }");
2539
- const session = deps.oauthSessions.take(sessionId);
2646
+ const session = deps.oauthSessions.peek(sessionId);
2540
2647
  if (!session) return err2(410, "oauth session is unknown, expired, or already used");
2541
2648
  if (session.providerId !== providerId) {
2542
2649
  return err2(400, `oauth session does not match provider '${providerId}'`);
@@ -2550,13 +2657,15 @@ async function handleOAuthComplete(providerId, body, deps) {
2550
2657
  }
2551
2658
  code = splitCode;
2552
2659
  }
2660
+ const exchangeFetch = deps.oauthExchangeFetch(providerId);
2553
2661
  let block;
2554
2662
  try {
2555
- block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, deps.oauthExchangeFetch) : await exchangeGemini(code, session.codeVerifier, deps.oauthExchangeFetch);
2663
+ block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
2556
2664
  } catch (exchangeError) {
2557
2665
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
2558
2666
  return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
2559
2667
  }
2668
+ deps.oauthSessions.consume(sessionId);
2560
2669
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
2561
2670
  await deps.subscriptionAccountAppender.appendProviderAccount(providerId, block, label);
2562
2671
  const status = await statusEntryFor(deps.subscriptionAccounts, providerId);
@@ -2594,7 +2703,9 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
2594
2703
  // src/admin/cliLaunch.ts
2595
2704
  import { exec, spawn } from "child_process";
2596
2705
  import { randomUUID as randomUUID2 } from "crypto";
2597
- import { existsSync as existsSync5 } from "fs";
2706
+ import { chmodSync as chmodSync3, existsSync as existsSync5, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
2707
+ import { createServer } from "net";
2708
+ import { tmpdir } from "os";
2598
2709
  import { delimiter, join as join3 } from "path";
2599
2710
  import {
2600
2711
  buildChatCliLaunchConfig,
@@ -2602,6 +2713,33 @@ import {
2602
2713
  buildCodexLaunchConfig,
2603
2714
  buildGeminiCliLaunchConfig
2604
2715
  } from "@omnicross/cli-launcher";
2716
+ import {
2717
+ ROUTE_LEASE_REQUEST_SCHEMA,
2718
+ RouteLeaseError as RouteLeaseError2
2719
+ } from "@omnicross/core/provider-proxy";
2720
+
2721
+ // src/routeLeaseRenewal.ts
2722
+ var TERMINAL_LEASE_TTL_SECONDS = 600;
2723
+ var TERMINAL_LEASE_RENEW_INTERVAL_MS = 5 * 60 * 1e3;
2724
+ var TERMINAL_LEASE_MAX_LIFETIME_MS = 24 * 60 * 60 * 1e3;
2725
+ function startTerminalLeaseRenewal(manager, leaseId2) {
2726
+ const stopAt = Date.now() + TERMINAL_LEASE_MAX_LIFETIME_MS;
2727
+ const timer = setInterval(() => {
2728
+ if (Date.now() >= stopAt) {
2729
+ clearInterval(timer);
2730
+ return;
2731
+ }
2732
+ try {
2733
+ manager.renew(leaseId2, TERMINAL_LEASE_TTL_SECONDS);
2734
+ } catch {
2735
+ clearInterval(timer);
2736
+ }
2737
+ }, TERMINAL_LEASE_RENEW_INTERVAL_MS);
2738
+ timer.unref?.();
2739
+ return () => clearInterval(timer);
2740
+ }
2741
+
2742
+ // src/admin/cliLaunch.ts
2605
2743
  var LAUNCHABLE_CLIS = [
2606
2744
  { id: "claude", displayName: "Claude Code", command: "claude" },
2607
2745
  { id: "codex", displayName: "Codex CLI", command: "codex" },
@@ -2682,34 +2820,183 @@ async function buildLaunchEnv(cli, llmConfig, target) {
2682
2820
  function shq(s) {
2683
2821
  return `'${s.replace(/'/g, `'\\''`)}'`;
2684
2822
  }
2685
- var defaultTerminalOpener = ({ cli, command, extraArgs, env, cwd, platform }) => {
2823
+ var MAC_TERMINAL_BOOTSTRAP_SOURCE = `
2824
+ 'use strict';
2825
+ const fs = require('node:fs');
2826
+ const net = require('node:net');
2827
+ const { spawn } = require('node:child_process');
2828
+ const [socketPath, launchDir, cwd, command, ...args] = process.argv.slice(2);
2829
+ let payload = '';
2830
+ const socket = net.createConnection(socketPath);
2831
+ socket.setEncoding('utf8');
2832
+ socket.on('data', (chunk) => { payload += chunk; });
2833
+ socket.on('end', () => {
2834
+ const descriptor = JSON.parse(payload);
2835
+ if (!descriptor || Array.isArray(descriptor) || Object.values(descriptor).some((value) => typeof value !== 'string')) {
2836
+ throw new Error('invalid terminal launch descriptor');
2837
+ }
2838
+ try { fs.rmSync(launchDir, { recursive: true, force: true }); } catch {}
2839
+ const child = spawn(command, args, {
2840
+ cwd: cwd || undefined,
2841
+ env: { ...process.env, ...descriptor },
2842
+ stdio: 'inherit',
2843
+ });
2844
+ child.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
2845
+ child.on('exit', (code, signal) => {
2846
+ if (signal) process.kill(process.pid, signal);
2847
+ else process.exitCode = code == null ? 1 : code;
2848
+ });
2849
+ });
2850
+ socket.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
2851
+ `;
2852
+ var MAC_TERMINAL_IPC_TIMEOUT_MS = 12e4;
2853
+ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }, spawnProcess = spawn, macIpc = {}) {
2686
2854
  const childEnv = { ...process.env, ...env };
2687
2855
  if (platform === "win32") {
2688
2856
  const args = ["/c", "start", `"omnicross ${cli}"`];
2689
2857
  if (cwd) args.push("/D", `"${cwd}"`);
2690
2858
  args.push("cmd", "/k", command, ...extraArgs);
2691
- spawn(process.env["ComSpec"] || "cmd.exe", args, {
2859
+ spawnProcess(process.env["ComSpec"] || "cmd.exe", args, {
2692
2860
  env: childEnv,
2693
2861
  windowsVerbatimArguments: true,
2694
2862
  detached: true,
2695
2863
  stdio: "ignore"
2696
2864
  }).unref();
2697
- return;
2865
+ return () => {
2866
+ };
2698
2867
  }
2699
- const exportLine = Object.entries(env).map(([k, v]) => `export ${k}=${shq(v)}`).join("; ");
2700
2868
  const runLine = [command, ...extraArgs].map(shq).join(" ");
2701
- const script = `${exportLine}; ${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
2869
+ const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
2702
2870
  if (platform === "darwin") {
2703
- const osa = `tell application "Terminal" to do script ${JSON.stringify(script)}`;
2704
- spawn("osascript", ["-e", osa], { detached: true, stdio: "ignore" }).unref();
2705
- return;
2871
+ const launchDir = mkdtempSync(join3(tmpdir(), "omnicross-terminal-"));
2872
+ const commandFile = join3(launchDir, "launch.command");
2873
+ const bootstrapFile = join3(launchDir, "bootstrap.cjs");
2874
+ const socketPath = macIpc.socketPath ?? join3(launchDir, "descriptor.sock");
2875
+ const openerEnv = { ...process.env };
2876
+ for (const key of Object.keys(env)) delete openerEnv[key];
2877
+ let claimed = false;
2878
+ let cleaned = false;
2879
+ let failureNotified = false;
2880
+ let timer;
2881
+ const notifyFailure = () => {
2882
+ cleanup();
2883
+ if (failureNotified) return;
2884
+ failureNotified = true;
2885
+ try {
2886
+ onFailure?.();
2887
+ } catch {
2888
+ }
2889
+ };
2890
+ const handleLaunchFailure = () => {
2891
+ if (claimed) cleanup();
2892
+ else notifyFailure();
2893
+ };
2894
+ const sockets = /* @__PURE__ */ new Set();
2895
+ const server = createServer((socket) => {
2896
+ socket.unref();
2897
+ sockets.add(socket);
2898
+ socket.once("close", () => sockets.delete(socket));
2899
+ try {
2900
+ macIpc.onAccepted?.(socket);
2901
+ } catch {
2902
+ cleanup();
2903
+ return;
2904
+ }
2905
+ if (claimed || cleaned) {
2906
+ socket.destroy();
2907
+ return;
2908
+ }
2909
+ claimed = true;
2910
+ try {
2911
+ macIpc.onClaimed?.();
2912
+ if (cleaned) return;
2913
+ socket.end(JSON.stringify(env), cleanup);
2914
+ } catch {
2915
+ cleanup();
2916
+ }
2917
+ });
2918
+ const cleanup = () => {
2919
+ if (!cleaned) {
2920
+ cleaned = true;
2921
+ if (timer) clearTimeout(timer);
2922
+ for (const socket of sockets) socket.destroy();
2923
+ sockets.clear();
2924
+ try {
2925
+ server.close();
2926
+ } catch {
2927
+ }
2928
+ }
2929
+ try {
2930
+ if (macIpc.removeArtifacts) {
2931
+ macIpc.removeArtifacts(launchDir);
2932
+ } else {
2933
+ rmSync2(launchDir, {
2934
+ recursive: true,
2935
+ force: true,
2936
+ maxRetries: 3,
2937
+ retryDelay: 20
2938
+ });
2939
+ }
2940
+ } catch {
2941
+ }
2942
+ };
2943
+ try {
2944
+ writeFileSync5(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
2945
+ writeFileSync5(commandFile, `#!/bin/bash
2946
+ rm -f -- "$0"
2947
+ exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
2948
+ `, {
2949
+ encoding: "utf8",
2950
+ mode: 448
2951
+ });
2952
+ chmodSync3(commandFile, 448);
2953
+ chmodSync3(bootstrapFile, 448);
2954
+ server.once("error", handleLaunchFailure);
2955
+ server.listen(socketPath, () => {
2956
+ if (cleaned) return;
2957
+ try {
2958
+ macIpc.onListening?.();
2959
+ if (cleaned) return;
2960
+ if (process.platform !== "win32") chmodSync3(socketPath, 384);
2961
+ const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
2962
+ env: openerEnv,
2963
+ detached: true,
2964
+ stdio: "ignore"
2965
+ });
2966
+ opener.once("error", handleLaunchFailure);
2967
+ opener.unref();
2968
+ server.unref();
2969
+ } catch {
2970
+ handleLaunchFailure();
2971
+ }
2972
+ });
2973
+ timer = setTimeout(handleLaunchFailure, macIpc.timeoutMs ?? MAC_TERMINAL_IPC_TIMEOUT_MS);
2974
+ timer.unref?.();
2975
+ return cleanup;
2976
+ } catch (error) {
2977
+ cleanup();
2978
+ throw error;
2979
+ }
2706
2980
  }
2707
- spawn("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
2981
+ spawnProcess("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
2982
+ env: childEnv,
2708
2983
  detached: true,
2709
2984
  stdio: "ignore"
2710
2985
  }).unref();
2711
- };
2986
+ return () => {
2987
+ };
2988
+ }
2989
+ var defaultTerminalOpener = (input) => openTerminal(input);
2712
2990
  var sessions = /* @__PURE__ */ new Map();
2991
+ function resetCliSessions() {
2992
+ for (const s of sessions.values()) {
2993
+ try {
2994
+ s.onSessionEnd();
2995
+ } catch {
2996
+ }
2997
+ }
2998
+ sessions.clear();
2999
+ }
2713
3000
  function errBody(message) {
2714
3001
  return { error: { type: "admin_api_error", message } };
2715
3002
  }
@@ -2764,29 +3051,81 @@ async function handleCliLaunch(cli, body, ctx) {
2764
3051
  } catch (err5) {
2765
3052
  return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
2766
3053
  }
3054
+ const id = randomUUID2();
3055
+ let leaseId2;
2767
3056
  let launch;
2768
3057
  try {
2769
- launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3058
+ if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
3059
+ const outcome = await ctx.routeLeaseManager.createFromRequest({
3060
+ schemaVersion: ROUTE_LEASE_REQUEST_SCHEMA,
3061
+ consumer: "omnicross-terminal",
3062
+ runtime: cli,
3063
+ upstream: { kind: "provider", providerId: target.providerId },
3064
+ model: target.model,
3065
+ execution: { sessionId: id }
3066
+ }, `omnicross-terminal:${id}`);
3067
+ leaseId2 = outcome.result.leaseId;
3068
+ const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
3069
+ launch = {
3070
+ env: outcome.result.launch.env,
3071
+ extraArgs: outcome.result.launch.extraArgs,
3072
+ onSessionEnd: () => {
3073
+ stopRenewal();
3074
+ ctx.routeLeaseManager?.release(outcome.result.leaseId);
3075
+ }
3076
+ };
3077
+ } else {
3078
+ launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3079
+ }
2770
3080
  } catch (err5) {
2771
- return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
3081
+ const status = err5 instanceof RouteLeaseError2 ? err5.status : 400;
3082
+ return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
2772
3083
  }
2773
3084
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
2774
3085
  const opener = ctx.opener ?? defaultTerminalOpener;
3086
+ let openerCleanup;
3087
+ let ended = false;
3088
+ let published = false;
3089
+ const onSessionEnd = () => {
3090
+ if (ended) return;
3091
+ ended = true;
3092
+ if (published) sessions.delete(id);
3093
+ try {
3094
+ openerCleanup?.();
3095
+ } finally {
3096
+ launch.onSessionEnd();
3097
+ }
3098
+ };
2775
3099
  try {
2776
- opener({ cli, command: meta.command, extraArgs: launch.extraArgs ?? [], env: launch.env, cwd, platform });
3100
+ const cleanup = opener({
3101
+ cli,
3102
+ command: meta.command,
3103
+ extraArgs: launch.extraArgs ?? [],
3104
+ env: launch.env,
3105
+ cwd,
3106
+ platform,
3107
+ onFailure: onSessionEnd
3108
+ });
3109
+ if (cleanup) openerCleanup = cleanup;
2777
3110
  } catch (err5) {
2778
- launch.onSessionEnd();
3111
+ onSessionEnd();
2779
3112
  return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
2780
3113
  }
2781
- const id = randomUUID2();
3114
+ if (ended) {
3115
+ openerCleanup?.();
3116
+ return { status: 500, body: errBody("failed to open terminal") };
3117
+ }
2782
3118
  sessions.set(id, {
2783
3119
  id,
2784
3120
  cli,
2785
3121
  providerId: target.providerId,
2786
3122
  model: target.model,
3123
+ ...leaseId2 ? { leaseId: leaseId2 } : {},
2787
3124
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2788
- onSessionEnd: launch.onSessionEnd
3125
+ onSessionEnd
2789
3126
  });
3127
+ published = true;
3128
+ if (ended) sessions.delete(id);
2790
3129
  return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
2791
3130
  }
2792
3131
 
@@ -2806,8 +3145,8 @@ function validateAuditSegment(patch) {
2806
3145
  }
2807
3146
  }
2808
3147
  const maxBodyBytes = audit["maxBodyBytes"];
2809
- if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < 0)) {
2810
- errors.push("audit.maxBodyBytes must be a non-negative number");
3148
+ if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < -1)) {
3149
+ errors.push("audit.maxBodyBytes must be -1 or a non-negative number");
2811
3150
  }
2812
3151
  const retentionDays = audit["retentionDays"];
2813
3152
  if (retentionDays !== void 0 && (typeof retentionDays !== "number" || !Number.isFinite(retentionDays) || retentionDays < 0)) {
@@ -3252,18 +3591,16 @@ function preserveWebhookSecrets(incoming, current) {
3252
3591
  }
3253
3592
 
3254
3593
  // src/audit/auditRuntime.ts
3255
- import { join as join4 } from "path";
3256
3594
  import { setAuditCaptureConfig, setAuditSink } from "@omnicross/core/pipeline/auditSink";
3257
3595
  import { setUpstreamTracePath } from "@omnicross/core/pipeline/upstreamTrace";
3258
3596
  var writer = null;
3259
3597
  var sweeper = null;
3260
- var auditDir = "";
3261
- function setAuditRuntime(w, s, dir) {
3598
+ function setAuditRuntime(w, s) {
3262
3599
  writer = w;
3263
3600
  sweeper = s;
3264
- auditDir = dir;
3265
3601
  }
3266
3602
  function applyAuditConfig(config) {
3603
+ setUpstreamTracePath(null);
3267
3604
  const enabled = config?.enabled === true && writer !== null;
3268
3605
  if (enabled && config) {
3269
3606
  setAuditCaptureConfig(config);
@@ -3273,11 +3610,9 @@ function applyAuditConfig(config) {
3273
3610
  sweeper.configure(config);
3274
3611
  sweeper.start();
3275
3612
  }
3276
- setUpstreamTracePath(config.captureBodies ? join4(auditDir, "upstream-trace.jsonl") : null);
3277
3613
  } else {
3278
3614
  setAuditCaptureConfig(null);
3279
3615
  setAuditSink(null);
3280
- setUpstreamTracePath(null);
3281
3616
  if (sweeper) {
3282
3617
  if (config) sweeper.configure(config);
3283
3618
  sweeper.dispose();
@@ -3291,7 +3626,6 @@ function resetAuditRuntimeForTests() {
3291
3626
  if (sweeper) sweeper.dispose();
3292
3627
  writer = null;
3293
3628
  sweeper = null;
3294
- auditDir = "";
3295
3629
  }
3296
3630
 
3297
3631
  // src/billing/billingRuntime.ts
@@ -3693,7 +4027,7 @@ function sealPack(bundleJson, passphrase) {
3693
4027
  cipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
3694
4028
  const ciphertext = Buffer.concat([cipher.update(bundleJson, "utf8"), cipher.final()]);
3695
4029
  const tag = cipher.getAuthTag();
3696
- const header = {
4030
+ const header2 = {
3697
4031
  magic: PACK_MAGIC,
3698
4032
  v: PACK_VERSION,
3699
4033
  kdf: KDF_ALGORITHM,
@@ -3704,7 +4038,7 @@ function sealPack(bundleJson, passphrase) {
3704
4038
  iv: iv.toString("base64"),
3705
4039
  tag: tag.toString("base64")
3706
4040
  };
3707
- return `${PACK_PREFIX}${toB64Url(JSON.stringify(header))}.${ciphertext.toString("base64")}`;
4041
+ return `${PACK_PREFIX}${toB64Url(JSON.stringify(header2))}.${ciphertext.toString("base64")}`;
3708
4042
  }
3709
4043
  function parsePack(packString) {
3710
4044
  if (typeof packString !== "string" || !packString.startsWith(PACK_PREFIX)) {
@@ -3715,28 +4049,28 @@ function parsePack(packString) {
3715
4049
  if (dot < 0) throw new PackAuthError("migration pack is malformed (missing body)");
3716
4050
  const headerB64Url = rest.slice(0, dot);
3717
4051
  const ctB64 = rest.slice(dot + 1);
3718
- let header;
4052
+ let header2;
3719
4053
  try {
3720
- header = JSON.parse(fromB64Url(headerB64Url));
4054
+ header2 = JSON.parse(fromB64Url(headerB64Url));
3721
4055
  } catch {
3722
4056
  throw new PackAuthError("migration pack is malformed (unreadable header)");
3723
4057
  }
3724
- 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") {
4058
+ 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") {
3725
4059
  throw new PackAuthError("migration pack is malformed (unsupported header)");
3726
4060
  }
3727
4061
  const ciphertext = Buffer.from(ctB64, "base64");
3728
- return { header, ciphertext };
4062
+ return { header: header2, ciphertext };
3729
4063
  }
3730
4064
  function openPack(packString, passphrase) {
3731
4065
  assertPassphraseStrength(passphrase);
3732
- const { header, ciphertext } = parsePack(packString);
3733
- const salt = Buffer.from(header.salt, "base64");
3734
- const iv = Buffer.from(header.iv, "base64");
3735
- const tag = Buffer.from(header.tag, "base64");
4066
+ const { header: header2, ciphertext } = parsePack(packString);
4067
+ const salt = Buffer.from(header2.salt, "base64");
4068
+ const iv = Buffer.from(header2.iv, "base64");
4069
+ const tag = Buffer.from(header2.tag, "base64");
3736
4070
  if (iv.length !== IV_BYTES2 || tag.length !== TAG_BYTES2) {
3737
4071
  throw new PackAuthError("migration pack is malformed (invalid iv/tag length)");
3738
4072
  }
3739
- const key = deriveKey(passphrase, salt, header.N, header.r, header.p);
4073
+ const key = deriveKey(passphrase, salt, header2.N, header2.r, header2.p);
3740
4074
  const decipher = createDecipheriv2("aes-256-gcm", key, iv);
3741
4075
  decipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
3742
4076
  decipher.setAuthTag(tag);
@@ -4072,10 +4406,10 @@ function writeJson2(res, status, body) {
4072
4406
  res.writeHead(status, { "Content-Type": "application/json" });
4073
4407
  res.end(JSON.stringify(body));
4074
4408
  }
4075
- function writeError(res, status, message) {
4409
+ function writeError2(res, status, message) {
4076
4410
  writeJson2(res, status, { error: { type: "account_allowance_error", message } });
4077
4411
  }
4078
- function readJson(req) {
4412
+ function readJson2(req) {
4079
4413
  return new Promise((resolve2, reject) => {
4080
4414
  const chunks = [];
4081
4415
  req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
@@ -4101,10 +4435,10 @@ function allowanceProvider(value) {
4101
4435
  return value === "claude" || value === "codex" ? value : null;
4102
4436
  }
4103
4437
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
4104
- if (!service) return writeError(res, 501, "account allowance service is not available");
4438
+ if (!service) return writeError2(res, 501, "account allowance service is not available");
4105
4439
  if (method === "GET" && rest.length === 1 && rest[0] === "scheduling") {
4106
4440
  if (!service.getSchedulingStatus) {
4107
- return writeError(res, 501, "allowance scheduling diagnostics are not available");
4441
+ return writeError2(res, 501, "allowance scheduling diagnostics are not available");
4108
4442
  }
4109
4443
  return writeJson2(res, 200, { scheduling: service.getSchedulingStatus() });
4110
4444
  }
@@ -4112,30 +4446,35 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
4112
4446
  const params = query(req);
4113
4447
  const pathProvider = rest.length >= 2 ? rest[0] : null;
4114
4448
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
4115
- if (providerId === null) return writeError(res, 400, "providerId must be claude or codex");
4449
+ if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
4116
4450
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
4117
4451
  const allowances = await service.list({ providerId, accountId });
4118
4452
  return writeJson2(res, 200, { allowances });
4119
4453
  }
4120
4454
  if (method === "POST" && rest[0] === "refresh") {
4121
- const body = await readJson(req);
4455
+ const body = await readJson2(req);
4122
4456
  const requestedProvider = allowanceProvider(
4123
4457
  typeof body["providerId"] === "string" ? body["providerId"] : "claude"
4124
4458
  );
4125
4459
  if (requestedProvider !== "claude") {
4126
- return writeError(res, 400, "only Claude allowances support explicit refresh");
4460
+ return writeError2(res, 400, "only Claude allowances support explicit refresh");
4127
4461
  }
4128
4462
  const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
4129
4463
  const allowances = await service.refreshClaude(accountId);
4130
4464
  if (accountId && allowances.length === 0) {
4131
- return writeError(res, 404, `Claude account '${accountId}' not found`);
4465
+ return writeError2(res, 404, `Claude account '${accountId}' not found`);
4132
4466
  }
4133
4467
  return writeJson2(res, 200, { allowances });
4134
4468
  }
4135
- return writeError(res, 405, `method ${method} not allowed on account allowances`);
4469
+ return writeError2(res, 405, `method ${method} not allowed on account allowances`);
4136
4470
  }
4137
4471
 
4138
4472
  // src/admin/adminApi.ts
4473
+ import {
4474
+ ACCOUNT_ROUTE_ACTIVITY_LIMIT,
4475
+ getSharedAccountRouteActivity
4476
+ } from "@omnicross/core/pipeline/AccountRouteActivity";
4477
+ import { getSharedOverloadCounter } from "@omnicross/core/pipeline/ServerOverloadCounter";
4139
4478
  function readBody(req) {
4140
4479
  return new Promise((resolve2, reject) => {
4141
4480
  const chunks = [];
@@ -4172,6 +4511,9 @@ function toKeyInfo(row) {
4172
4511
  id: row.id,
4173
4512
  name: row.name,
4174
4513
  keyPrefix: row.keyPrefix,
4514
+ // True only when a reversible `keySecret` envelope was persisted at creation
4515
+ // — gates the UI "view key" eye. Legacy hash-only rows read as absent.
4516
+ revealable: Boolean(row.keySecret),
4175
4517
  enabled: row.enabled,
4176
4518
  createdAt: row.createdAt,
4177
4519
  lastUsedAt: row.lastUsedAt,
@@ -4827,7 +5169,13 @@ function handlePresets(res, method) {
4827
5169
  name: p.name,
4828
5170
  apiFormat: p.apiFormat,
4829
5171
  baseUrl: p.baseUrl,
4830
- models: p.models
5172
+ models: p.models,
5173
+ nameKey: p.nameKey,
5174
+ icon: p.icon,
5175
+ description: p.description,
5176
+ features: p.features,
5177
+ website: p.website,
5178
+ modelsEndpoint: p.modelsEndpoint
4831
5179
  }));
4832
5180
  return writeJson3(res, 200, { presets, excluded });
4833
5181
  }
@@ -4861,12 +5209,27 @@ async function handleKeys(req, res, method, rest, deps) {
4861
5209
  plaintextOnce: created.plaintextOnce
4862
5210
  });
4863
5211
  }
5212
+ if (method === "GET" && rest.length === 2 && rest[1] === "reveal") {
5213
+ const revealed = await deps.keyDb.outboundApiKeysReveal(rest[0]);
5214
+ if (revealed !== null) return writeJson3(res, 200, { key: revealed });
5215
+ const exists = (await deps.keyDb.outboundApiKeysList()).some((r) => r.id === rest[0]);
5216
+ if (!exists) return writeJsonError(res, 404, `key '${rest[0]}' not found`);
5217
+ return writeJsonError(
5218
+ res,
5219
+ 409,
5220
+ `key '${rest[0]}' is not revealable (created before revealable key storage)`
5221
+ );
5222
+ }
4864
5223
  const id = rest[0];
4865
5224
  const action = rest[1];
4866
5225
  if (method === "POST" && id && action === "revoke") {
4867
5226
  const ok = await deps.keyDb.outboundApiKeysRevoke(id);
4868
5227
  return writeJson3(res, ok ? 200 : 404, { ok });
4869
5228
  }
5229
+ if (method === "DELETE" && id && !action) {
5230
+ const ok = await deps.keyDb.outboundApiKeysDelete(id);
5231
+ return writeJson3(res, ok ? 200 : 404, { ok });
5232
+ }
4870
5233
  if (method === "POST" && id && action === "enabled") {
4871
5234
  const body = await readJsonBody3(req);
4872
5235
  const enabled = body["enabled"] === true;
@@ -5043,6 +5406,40 @@ async function handleServer(req, res, method, deps) {
5043
5406
  return writeJsonError(res, 405, `method ${method} not allowed on server`);
5044
5407
  }
5045
5408
  async function handleAccounts(req, res, method, rest, deps) {
5409
+ if (rest[0] === "route-activity" && rest.length === 1) {
5410
+ if (method !== "GET") {
5411
+ return writeJsonError(res, 405, `method ${method} not allowed on account route activity`);
5412
+ }
5413
+ const query2 = requestQuery(req);
5414
+ const parsedLimit = Number(query2.get("limit") ?? "100");
5415
+ const records = getSharedAccountRouteActivity().list({
5416
+ providerId: query2.get("providerId") ?? void 0,
5417
+ accountId: query2.get("accountId") ?? void 0,
5418
+ sessionKey: query2.get("sessionKey") ?? void 0,
5419
+ limit: Number.isFinite(parsedLimit) ? parsedLimit : 100
5420
+ });
5421
+ return writeJson3(res, 200, {
5422
+ available: true,
5423
+ records,
5424
+ capacity: ACCOUNT_ROUTE_ACTIVITY_LIMIT,
5425
+ collectedAt: Date.now()
5426
+ });
5427
+ }
5428
+ if (rest[0] === "overload-counters" && rest.length === 1) {
5429
+ if (method !== "GET") {
5430
+ return writeJsonError(res, 405, `method ${method} not allowed on overload counters`);
5431
+ }
5432
+ const query2 = requestQuery(req);
5433
+ const entries = getSharedOverloadCounter().list({
5434
+ providerId: query2.get("providerId") ?? void 0,
5435
+ accountId: query2.get("accountId") ?? void 0
5436
+ });
5437
+ return writeJson3(res, 200, {
5438
+ available: true,
5439
+ entries,
5440
+ collectedAt: Date.now()
5441
+ });
5442
+ }
5046
5443
  if (rest[0] === "allowances") {
5047
5444
  return handleAccountAllowanceApi(
5048
5445
  req,
@@ -5189,8 +5586,13 @@ async function handleAccounts(req, res, method, rest, deps) {
5189
5586
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
5190
5587
  return writeJsonError(res, 404, `account '${accountId}' not found`);
5191
5588
  }
5192
- const result = await deps.accountProbeService.probeAccount(providerId, accountId);
5193
- return writeJson3(res, 200, { ok: result.ok, marked: result.marked });
5589
+ const result = await deps.accountProbeService.testAccountConnection(providerId, accountId);
5590
+ return writeJson3(res, 200, {
5591
+ ok: result.ok,
5592
+ marked: result.marked,
5593
+ tier: result.tier,
5594
+ model: result.model
5595
+ });
5194
5596
  }
5195
5597
  if (method === "POST" && rest[2] === "label") {
5196
5598
  const accountId = rest[1];
@@ -5299,6 +5701,7 @@ async function handleCli(req, res, method, rest, deps) {
5299
5701
  const result = await handleCliLaunch(cli, body, {
5300
5702
  llmConfig: deps.llmConfig,
5301
5703
  providers,
5704
+ routeLeaseManager: deps.routeLeaseManager,
5302
5705
  opener: deps.cliTerminalOpener,
5303
5706
  probe: deps.cliPathProbe
5304
5707
  });
@@ -5561,7 +5964,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5561
5964
  }
5562
5965
 
5563
5966
  // src/admin/version.ts
5564
- var DAEMON_VERSION = true ? "0.1.6" : "0.0.0-dev";
5967
+ var DAEMON_VERSION = true ? "0.1.8" : "0.0.0-dev";
5565
5968
 
5566
5969
  // src/admin/AdminServer.ts
5567
5970
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -5669,6 +6072,10 @@ var AdminServer = class {
5669
6072
  handleAuditQuery(req, res, this.deps.auditReader);
5670
6073
  return;
5671
6074
  }
6075
+ if (path2 === "/admin/api/audit/stats" && (req.method === "GET" || req.method === "HEAD")) {
6076
+ await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
6077
+ return;
6078
+ }
5672
6079
  if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
5673
6080
  handleBillingStatus(res, this.deps.billingStatusReader);
5674
6081
  return;
@@ -5677,6 +6084,10 @@ var AdminServer = class {
5677
6084
  await handleWebhookTest(req, res);
5678
6085
  return;
5679
6086
  }
6087
+ if (path2 === "/admin/api/route-leases" || path2.startsWith("/admin/api/route-leases/")) {
6088
+ await handleRouteLeaseApi(req, res, path2, this.deps);
6089
+ return;
6090
+ }
5680
6091
  if (path2.startsWith("/admin/api/")) {
5681
6092
  await handleAdminApi(req, res, path2, this.deps);
5682
6093
  return;
@@ -5688,8 +6099,8 @@ var AdminServer = class {
5688
6099
  }
5689
6100
  /** Constant-time bearer/header check against the configured token. */
5690
6101
  isAuthorized(req, token) {
5691
- const header = req.headers["authorization"];
5692
- const bearer = typeof header === "string" && header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : void 0;
6102
+ const header2 = req.headers["authorization"];
6103
+ const bearer = typeof header2 === "string" && header2.startsWith("Bearer ") ? header2.slice("Bearer ".length).trim() : void 0;
5693
6104
  const xToken = req.headers["x-admin-token"];
5694
6105
  const presented = bearer ?? (typeof xToken === "string" ? xToken.trim() : void 0);
5695
6106
  return constantTimeEquals(presented, token);
@@ -5785,20 +6196,36 @@ var OAuthSessionStore = class {
5785
6196
  return sessionId;
5786
6197
  }
5787
6198
  /**
5788
- * SINGLE-USE consume: return + delete the session for `sessionId`, or `null`
5789
- * when it is unknown, already used, or past its TTL (in which case it is
5790
- * dropped). A `null` return means the completer must reject (no exchange, no
5791
- * write).
6199
+ * NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
6200
+ * it is unknown, already consumed, or past its TTL (an expired entry is
6201
+ * dropped here). A `null` return means the completer must reject (no
6202
+ * exchange, no write).
6203
+ *
6204
+ * Deliberately NOT a consume: the completer peeks, runs the token exchange,
6205
+ * and only {@link consume}s once a token has actually been minted. Consuming
6206
+ * up-front burned the session on EVERY failed exchange (a mistyped/expired
6207
+ * pasted code, a proxy hiccup), so the user's natural retry hit
6208
+ * "session is unknown, expired, or already used" and the login became
6209
+ * unrecoverable without restarting the whole flow.
5792
6210
  */
5793
- take(sessionId) {
6211
+ peek(sessionId) {
5794
6212
  this.sweep();
5795
6213
  const session = this.sessions.get(sessionId);
5796
6214
  if (!session) return null;
5797
- this.sessions.delete(sessionId);
5798
- if (Date.now() - session.createdAt > this.ttlMs) return null;
6215
+ if (Date.now() - session.createdAt > this.ttlMs) {
6216
+ this.sessions.delete(sessionId);
6217
+ return null;
6218
+ }
5799
6219
  return session;
5800
6220
  }
5801
- /** Drop every session past its TTL. Called on each put/take. */
6221
+ /**
6222
+ * SINGLE-USE burn: drop the session so the same `sessionId` can never be
6223
+ * completed twice. Called ONLY after a successful token exchange.
6224
+ */
6225
+ consume(sessionId) {
6226
+ this.sessions.delete(sessionId);
6227
+ }
6228
+ /** Drop every session past its TTL. Called on each put/peek. */
5802
6229
  sweep() {
5803
6230
  const now = Date.now();
5804
6231
  for (const [id, session] of this.sessions) {
@@ -5808,11 +6235,15 @@ var OAuthSessionStore = class {
5808
6235
  };
5809
6236
 
5810
6237
  // src/commands/loopbackCallback.ts
5811
- import { createServer } from "http";
6238
+ import { createServer as createServer2 } from "http";
5812
6239
  var LOOPBACK_HOST = "127.0.0.1";
5813
6240
  var LOOPBACK_PORT = 1455;
5814
6241
  var CALLBACK_PATH = "/auth/callback";
5815
6242
  var DEFAULT_TIMEOUT_MS = 5 * 6e4;
6243
+ var HTML_HEADERS = {
6244
+ "Content-Type": "text/html",
6245
+ Connection: "close"
6246
+ };
5816
6247
  function pageHtml(message) {
5817
6248
  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>`;
5818
6249
  }
@@ -5823,30 +6254,31 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
5823
6254
  if (settled) return;
5824
6255
  settled = true;
5825
6256
  clearTimeout(timer);
5826
- server2.close(() => fn());
6257
+ fn();
6258
+ server2.close();
5827
6259
  };
5828
- const server = createServer((req, res) => {
6260
+ const server = createServer2((req, res) => {
5829
6261
  const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
5830
6262
  if (url.pathname !== CALLBACK_PATH) {
5831
- res.writeHead(404, { "Content-Type": "text/html" });
6263
+ res.writeHead(404, HTML_HEADERS);
5832
6264
  res.end(pageHtml("Not found"));
5833
6265
  return;
5834
6266
  }
5835
6267
  const code = url.searchParams.get("code");
5836
6268
  const state = url.searchParams.get("state");
5837
6269
  if (!code) {
5838
- res.writeHead(400, { "Content-Type": "text/html" });
6270
+ res.writeHead(400, HTML_HEADERS);
5839
6271
  res.end(pageHtml("Login failed: missing authorization code."));
5840
6272
  finish(server, () => reject(new Error("login: callback did not include an authorization code")));
5841
6273
  return;
5842
6274
  }
5843
6275
  if (state !== expectedState) {
5844
- res.writeHead(400, { "Content-Type": "text/html" });
6276
+ res.writeHead(400, HTML_HEADERS);
5845
6277
  res.end(pageHtml("Login failed: state mismatch."));
5846
6278
  finish(server, () => reject(new Error("login: callback state did not match (possible CSRF) \u2014 aborting")));
5847
6279
  return;
5848
6280
  }
5849
- res.writeHead(200, { "Content-Type": "text/html" });
6281
+ res.writeHead(200, HTML_HEADERS);
5850
6282
  res.end(pageHtml("Login complete."));
5851
6283
  finish(server, () => resolve2(code));
5852
6284
  });
@@ -5943,30 +6375,30 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
5943
6375
  }
5944
6376
 
5945
6377
  // src/commands/paths.ts
5946
- import { dirname as dirname5, join as join5 } from "path";
6378
+ import { dirname as dirname5, join as join4 } from "path";
5947
6379
  function defaultVouchersPath(configPath) {
5948
- return join5(dirname5(configPath), "vouchers.json");
6380
+ return join4(dirname5(configPath), "vouchers.json");
5949
6381
  }
5950
6382
  function defaultIntegrationsPath(configPath) {
5951
- return join5(dirname5(configPath), "integrations.json");
6383
+ return join4(dirname5(configPath), "integrations.json");
5952
6384
  }
5953
6385
  function defaultPricingPath(configPath) {
5954
- return join5(dirname5(configPath), "pricing.json");
6386
+ return join4(dirname5(configPath), "pricing.json");
5955
6387
  }
5956
6388
  function defaultPricingRefreshStatePath(configPath) {
5957
- return join5(dirname5(configPath), "pricing-refresh.json");
6389
+ return join4(dirname5(configPath), "pricing-refresh.json");
5958
6390
  }
5959
6391
  function defaultAccountAllowancePath(configPath) {
5960
- return join5(dirname5(configPath), "allowance-cache.json");
6392
+ return join4(dirname5(configPath), "allowance-cache.json");
5961
6393
  }
5962
6394
  function defaultUsageEventsPath(configPath) {
5963
- return join5(dirname5(configPath), "usage-events.jsonl");
6395
+ return join4(dirname5(configPath), "usage-events.jsonl");
5964
6396
  }
5965
6397
  function defaultAuditDir(configPath) {
5966
- return join5(dirname5(configPath), "audit");
6398
+ return join4(dirname5(configPath), "audit");
5967
6399
  }
5968
6400
  function defaultBillingDir(configPath) {
5969
- return join5(dirname5(configPath), "billing");
6401
+ return join4(dirname5(configPath), "billing");
5970
6402
  }
5971
6403
 
5972
6404
  // src/ports/ConfigFileProviderConfigSource.ts
@@ -6274,7 +6706,7 @@ function safeStringify(value) {
6274
6706
  }
6275
6707
 
6276
6708
  // src/ports/JsonApiServerSettingsStore.ts
6277
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
6709
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
6278
6710
  import { OUTBOUND_API_SERVER_CONFIG_KEY } from "@omnicross/core/outbound-api";
6279
6711
  var JsonApiServerSettingsStore = class {
6280
6712
  /**
@@ -6301,7 +6733,7 @@ var JsonApiServerSettingsStore = class {
6301
6733
  if (key !== OUTBOUND_API_SERVER_CONFIG_KEY) return;
6302
6734
  const file = this.readFile();
6303
6735
  file.server = this.encryptSecrets(value);
6304
- writeFileSync5(this.configPath, JSON.stringify(file, null, 2) + "\n", "utf8");
6736
+ writeFileSync6(this.configPath, JSON.stringify(file, null, 2) + "\n", "utf8");
6305
6737
  }
6306
6738
  /** Encrypt the proxy passwords + webhook + billing secrets before persisting (no-op without a box). */
6307
6739
  encryptSecrets(config) {
@@ -6362,8 +6794,12 @@ var JsonlUsageEventStore = class {
6362
6794
  reasoningTokens: 0,
6363
6795
  costUsd: 0,
6364
6796
  costSavedByCacheUsd: 0,
6365
- eventCount: 0
6797
+ eventCount: 0,
6798
+ cacheEligibleEventCount: 0,
6799
+ coldCacheEventCount: 0,
6800
+ medianCacheHitRate: null
6366
6801
  };
6802
+ const perEventHitRates = [];
6367
6803
  for (const row of this.readRows(range)) {
6368
6804
  totals.inputTokens += row.inputTokens;
6369
6805
  totals.outputTokens += row.outputTokens;
@@ -6373,7 +6809,14 @@ var JsonlUsageEventStore = class {
6373
6809
  totals.costUsd += row.costUsd;
6374
6810
  totals.costSavedByCacheUsd += row.costSavedByCacheUsd;
6375
6811
  totals.eventCount += 1;
6812
+ const promptSideTokens = row.inputTokens + row.cacheReadTokens + row.cacheCreationTokens;
6813
+ if (promptSideTokens > 0) {
6814
+ totals.cacheEligibleEventCount += 1;
6815
+ if (row.cacheReadTokens === 0) totals.coldCacheEventCount += 1;
6816
+ perEventHitRates.push(row.cacheReadTokens / promptSideTokens);
6817
+ }
6376
6818
  }
6819
+ totals.medianCacheHitRate = median(perEventHitRates);
6377
6820
  return totals;
6378
6821
  }
6379
6822
  async getByModel(range) {
@@ -6607,6 +7050,15 @@ var NUMERIC_FIELDS = [
6607
7050
  ];
6608
7051
  var NULLABLE_STRING_FIELDS = ["messageId", "parentMessageId", "sessionId", "apiKeyId"];
6609
7052
  var isStringOrNull = (v) => v === null || typeof v === "string";
7053
+ var CACHE_KEY_SOURCES = /* @__PURE__ */ new Set([
7054
+ "client",
7055
+ "session-header",
7056
+ "thread-header",
7057
+ "body-session-id",
7058
+ "body-thread-id",
7059
+ "content-fingerprint",
7060
+ "none"
7061
+ ]);
6610
7062
  function isUsageEventRecord(parsed) {
6611
7063
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
6612
7064
  const r = parsed;
@@ -6614,6 +7066,10 @@ function isUsageEventRecord(parsed) {
6614
7066
  if (typeof r["providerId"] !== "string") return false;
6615
7067
  if (typeof r["model"] !== "string") return false;
6616
7068
  if (typeof r["engineOrigin"] !== "string") return false;
7069
+ if (r["cacheKeySource"] !== void 0 && (typeof r["cacheKeySource"] !== "string" || !CACHE_KEY_SOURCES.has(r["cacheKeySource"]))) return false;
7070
+ if (r["cacheKeyInjected"] !== void 0 && typeof r["cacheKeyInjected"] !== "boolean") {
7071
+ return false;
7072
+ }
6617
7073
  for (const f of NULLABLE_STRING_FIELDS) {
6618
7074
  if (!isStringOrNull(r[f])) return false;
6619
7075
  }
@@ -6623,14 +7079,30 @@ function isUsageEventRecord(parsed) {
6623
7079
  }
6624
7080
  return true;
6625
7081
  }
7082
+ function median(values) {
7083
+ if (values.length === 0) return null;
7084
+ values.sort((a, b) => a - b);
7085
+ const middle = Math.floor(values.length / 2);
7086
+ return values.length % 2 === 1 ? values[middle] : (values[middle - 1] + values[middle]) / 2;
7087
+ }
6626
7088
 
6627
7089
  // src/ports/JsonOutboundKeyDb.ts
6628
- import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
7090
+ import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
6629
7091
  var JsonOutboundKeyDb = class {
6630
- constructor(keysPath) {
7092
+ /**
7093
+ * @param secretBox OPTIONAL reversible-secret codec. When present, a created
7094
+ * key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
7095
+ * operator "view key" affordance via `outboundApiKeysReveal`). When absent the
7096
+ * store stays hash-only (byte-identical to the legacy behavior) and reveal
7097
+ * always returns `null`. Existing 1-arg call sites (tests, lightweight
7098
+ * embedders) keep working.
7099
+ */
7100
+ constructor(keysPath, secretBox3) {
6631
7101
  this.keysPath = keysPath;
7102
+ this.secretBox = secretBox3;
6632
7103
  }
6633
7104
  keysPath;
7105
+ secretBox;
6634
7106
  async outboundApiKeysList() {
6635
7107
  return this.readRows();
6636
7108
  }
@@ -6656,10 +7128,27 @@ var JsonOutboundKeyDb = class {
6656
7128
  allowedEndpoints: input.allowedEndpoints,
6657
7129
  loopbackOnly: input.loopbackOnly
6658
7130
  };
7131
+ if (input.plaintext && this.secretBox) {
7132
+ row.keySecret = this.secretBox.encrypt(input.plaintext);
7133
+ }
6659
7134
  rows.push(row);
6660
7135
  this.writeRows(rows);
6661
7136
  return row;
6662
7137
  }
7138
+ async outboundApiKeysReveal(id) {
7139
+ const rows = this.readRows();
7140
+ const row = rows.find((r) => r.id === id);
7141
+ if (!row || !row.keySecret || !this.secretBox) return null;
7142
+ return this.secretBox.decrypt(row.keySecret);
7143
+ }
7144
+ async outboundApiKeysDelete(id) {
7145
+ const rows = this.readRows();
7146
+ const idx = rows.findIndex((r) => r.id === id);
7147
+ if (idx < 0) return false;
7148
+ rows.splice(idx, 1);
7149
+ this.writeRows(rows);
7150
+ return true;
7151
+ }
6663
7152
  async outboundApiKeysRevoke(id) {
6664
7153
  return this.mutateRow(id, (row) => {
6665
7154
  if (row.revokedAt !== null) return false;
@@ -6740,7 +7229,7 @@ var JsonOutboundKeyDb = class {
6740
7229
  }
6741
7230
  }
6742
7231
  writeRows(rows) {
6743
- writeFileSync6(this.keysPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
7232
+ writeFileSync7(this.keysPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
6744
7233
  }
6745
7234
  };
6746
7235
  function applyPolicyField(row, field, value) {
@@ -6750,7 +7239,7 @@ function applyPolicyField(row, field, value) {
6750
7239
  }
6751
7240
 
6752
7241
  // src/ports/JsonPricingStore.ts
6753
- import { existsSync as existsSync9, readFileSync as readFileSync9, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "fs";
7242
+ import { existsSync as existsSync9, readFileSync as readFileSync9, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
6754
7243
  import { randomUUID as randomUUID5 } from "crypto";
6755
7244
  var JsonPricingStore = class {
6756
7245
  constructor(pricingPath) {
@@ -6891,13 +7380,13 @@ var JsonPricingStore = class {
6891
7380
  writeRows(rows) {
6892
7381
  const temporaryPath = `${this.pricingPath}.${process.pid}.${randomUUID5()}.tmp`;
6893
7382
  try {
6894
- writeFileSync7(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
7383
+ writeFileSync8(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
6895
7384
  encoding: "utf8",
6896
7385
  flag: "wx"
6897
7386
  });
6898
7387
  this.replaceFile(temporaryPath);
6899
7388
  } finally {
6900
- rmSync2(temporaryPath, { force: true });
7389
+ rmSync3(temporaryPath, { force: true });
6901
7390
  }
6902
7391
  }
6903
7392
  /** Isolated for deterministic failure testing; never removes the target. */
@@ -6912,7 +7401,7 @@ function isUsablePricingRow(value) {
6912
7401
  }
6913
7402
 
6914
7403
  // src/pricing/PricingRefreshScheduler.ts
6915
- import { existsSync as existsSync10, readFileSync as readFileSync10, renameSync as renameSync4, writeFileSync as writeFileSync8 } from "fs";
7404
+ import { existsSync as existsSync10, readFileSync as readFileSync10, renameSync as renameSync4, writeFileSync as writeFileSync9 } from "fs";
6916
7405
  var EMPTY_STATE2 = {
6917
7406
  lastAttemptAt: null,
6918
7407
  lastSuccessAt: null,
@@ -7005,7 +7494,7 @@ var PricingRefreshScheduler = class {
7005
7494
  }
7006
7495
  writeState(state) {
7007
7496
  const temporaryPath = `${this.statePath}.tmp`;
7008
- writeFileSync8(temporaryPath, `${JSON.stringify(state, null, 2)}
7497
+ writeFileSync9(temporaryPath, `${JSON.stringify(state, null, 2)}
7009
7498
  `, "utf8");
7010
7499
  renameSync4(temporaryPath, this.statePath);
7011
7500
  }
@@ -7015,7 +7504,7 @@ function finiteOrNull(value) {
7015
7504
  }
7016
7505
 
7017
7506
  // src/ports/JsonVoucherDb.ts
7018
- import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
7507
+ import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "fs";
7019
7508
  var JsonVoucherDb = class {
7020
7509
  constructor(vouchersPath) {
7021
7510
  this.vouchersPath = vouchersPath;
@@ -7102,12 +7591,12 @@ var JsonVoucherDb = class {
7102
7591
  }
7103
7592
  }
7104
7593
  writeRows(rows) {
7105
- writeFileSync9(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
7594
+ writeFileSync10(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
7106
7595
  }
7107
7596
  };
7108
7597
 
7109
7598
  // src/ports/JsonSubscriptionCredentialStore.ts
7110
- import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
7599
+ import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "fs";
7111
7600
  import { dirname as dirname6 } from "path";
7112
7601
  import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
7113
7602
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
@@ -7163,9 +7652,9 @@ function findDuplicateCredentialIds(accounts) {
7163
7652
  // src/ports/external-cli-credentials.ts
7164
7653
  import { existsSync as existsSync12, readFileSync as readFileSync12 } from "fs";
7165
7654
  import { homedir as homedir3 } from "os";
7166
- import { join as join6 } from "path";
7655
+ import { join as join5 } from "path";
7167
7656
  function externalStorePath(provider, home = homedir3()) {
7168
- return provider === "claude" ? join6(home, ".claude", ".credentials.json") : join6(home, ".codex", "auth.json");
7657
+ return provider === "claude" ? join5(home, ".claude", ".credentials.json") : join5(home, ".codex", "auth.json");
7169
7658
  }
7170
7659
  function decodeJwtExpiryMs(token) {
7171
7660
  try {
@@ -7255,9 +7744,15 @@ var JsonSubscriptionCredentialStore = class {
7255
7744
  * TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
7256
7745
  * through {@link fetchUpstream} with the account's `{ providerId, accountId }`
7257
7746
  * ctx so the per-account/provider proxy applies. `@internal` also a test seam.
7747
+ *
7748
+ * `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
7749
+ * receives a fresh access/refresh token pair. Carrying a `providerId` opts the
7750
+ * call into the upstream trace (so a failing refresh is diagnosable), and the
7751
+ * trace captures bodies verbatim — without this flag every refresh would write
7752
+ * a plaintext token pair into `upstream-trace.jsonl`.
7258
7753
  */
7259
7754
  buildRefreshFetch(providerId, accountId) {
7260
- return this.fetchImpl ?? ((url, init) => fetchUpstream3(url, init, { providerId, accountId }));
7755
+ return this.fetchImpl ?? ((url, init) => fetchUpstream3(url, init, { providerId, accountId, redactBodies: true }));
7261
7756
  }
7262
7757
  /**
7263
7758
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -7784,7 +8279,7 @@ var JsonSubscriptionCredentialStore = class {
7784
8279
  persist(config) {
7785
8280
  mkdirSync4(dirname6(this.tokensPath), { recursive: true });
7786
8281
  const encrypted = encryptTokens(config, this.box);
7787
- writeFileSync10(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
8282
+ writeFileSync11(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
7788
8283
  }
7789
8284
  /**
7790
8285
  * Read + parse `tokens.json`, tolerating a missing/corrupt file, then DECRYPT
@@ -7817,6 +8312,127 @@ var JsonSubscriptionCredentialStore = class {
7817
8312
  // src/AccountHealthProbeScheduler.ts
7818
8313
  import { fetchUpstream as fetchUpstream4 } from "@omnicross/core/pipeline/upstreamFetch";
7819
8314
 
8315
+ // src/probe/CodexGenerationProbe.ts
8316
+ import {
8317
+ DEFAULT_CODEX_CLI_HEADERS,
8318
+ codexAcceptHeader
8319
+ } from "@omnicross/core/provider-proxy/identity/codexCliHeaders";
8320
+ var CODEX_GENERATION_PROBE_MODEL = "gpt-5.6-luna";
8321
+ var CODEX_GENERATION_PROBE_URL = "https://chatgpt.com/backend-api/codex/responses";
8322
+ var MAX_STREAM_BYTES = 256 * 1024;
8323
+ var PROBE_INSTRUCTION = "Return exactly PONG and no other text.";
8324
+ function buildCodexGenerationProbeInit(token, signal) {
8325
+ return {
8326
+ method: "POST",
8327
+ signal,
8328
+ headers: {
8329
+ ...DEFAULT_CODEX_CLI_HEADERS,
8330
+ Authorization: `Bearer ${token}`,
8331
+ Accept: codexAcceptHeader(true),
8332
+ "Content-Type": "application/json"
8333
+ },
8334
+ body: JSON.stringify({
8335
+ model: CODEX_GENERATION_PROBE_MODEL,
8336
+ input: [
8337
+ {
8338
+ role: "developer",
8339
+ content: [{ type: "input_text", text: PROBE_INSTRUCTION }]
8340
+ },
8341
+ {
8342
+ role: "user",
8343
+ content: [{ type: "input_text", text: "Connection probe." }]
8344
+ }
8345
+ ],
8346
+ // GPT-5.6 otherwise defaults to medium reasoning. A connectivity probe
8347
+ // needs the lowest-cost path and no tool reasoning.
8348
+ reasoning: { effort: "none" },
8349
+ stream: true,
8350
+ store: false
8351
+ })
8352
+ };
8353
+ }
8354
+ async function readCodexGenerationProbeStream(response) {
8355
+ if (!response.body) return { completed: false, outputChars: 0 };
8356
+ const reader = response.body.getReader();
8357
+ const decoder = new TextDecoder();
8358
+ let buffer = "";
8359
+ let bytes = 0;
8360
+ let outputChars = 0;
8361
+ try {
8362
+ while (true) {
8363
+ const { done, value } = await reader.read();
8364
+ if (done) break;
8365
+ bytes += value.byteLength;
8366
+ if (bytes > MAX_STREAM_BYTES) {
8367
+ await reader.cancel();
8368
+ return { completed: false, outputChars };
8369
+ }
8370
+ buffer += decoder.decode(value, { stream: true });
8371
+ buffer = buffer.replace(/\r\n/g, "\n");
8372
+ let boundary = buffer.indexOf("\n\n");
8373
+ while (boundary >= 0) {
8374
+ const block = buffer.slice(0, boundary);
8375
+ buffer = buffer.slice(boundary + 2);
8376
+ const event = parseSseBlock(block);
8377
+ if (event) {
8378
+ const type = event["type"];
8379
+ if (type === "response.output_text.delta" && typeof event["delta"] === "string") {
8380
+ outputChars += event["delta"].length;
8381
+ } else if (type === "response.output_text.done" && typeof event["text"] === "string") {
8382
+ outputChars = Math.max(outputChars, event["text"].length);
8383
+ } else if (type === "response.failed" || type === "error") {
8384
+ await reader.cancel();
8385
+ return { completed: false, outputChars };
8386
+ } else if (type === "response.completed") {
8387
+ const completedResponse = asRecord(event["response"]);
8388
+ const status = completedResponse?.["status"];
8389
+ outputChars = Math.max(outputChars, countCompletedOutputChars(completedResponse));
8390
+ await reader.cancel();
8391
+ return {
8392
+ completed: (status === void 0 || status === "completed") && outputChars > 0,
8393
+ outputChars
8394
+ };
8395
+ }
8396
+ }
8397
+ boundary = buffer.indexOf("\n\n");
8398
+ }
8399
+ }
8400
+ } catch {
8401
+ return { completed: false, outputChars };
8402
+ } finally {
8403
+ reader.releaseLock();
8404
+ }
8405
+ return { completed: false, outputChars };
8406
+ }
8407
+ function parseSseBlock(block) {
8408
+ const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
8409
+ if (!data || data === "[DONE]") return null;
8410
+ try {
8411
+ return JSON.parse(data);
8412
+ } catch {
8413
+ return null;
8414
+ }
8415
+ }
8416
+ function asRecord(value) {
8417
+ return value !== null && typeof value === "object" ? value : void 0;
8418
+ }
8419
+ function countCompletedOutputChars(response) {
8420
+ const output = response?.["output"];
8421
+ if (!Array.isArray(output)) return 0;
8422
+ let chars = 0;
8423
+ for (const item of output) {
8424
+ const content = asRecord(item)?.["content"];
8425
+ if (!Array.isArray(content)) continue;
8426
+ for (const part of content) {
8427
+ const record = asRecord(part);
8428
+ if (record?.["type"] === "output_text" && typeof record["text"] === "string") {
8429
+ chars += record["text"].length;
8430
+ }
8431
+ }
8432
+ }
8433
+ return chars;
8434
+ }
8435
+
7820
8436
  // src/probe/ProbeStrategy.ts
7821
8437
  var PROVIDER_PROBE_PLANS = {
7822
8438
  claude: {
@@ -7944,17 +8560,17 @@ var AccountHealthProbeScheduler = class {
7944
8560
  }
7945
8561
  if (readThrew) {
7946
8562
  this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
7947
- return { ok: false, marked: false };
8563
+ return { ok: false, marked: false, tier: "local" };
7948
8564
  }
7949
8565
  if (!token) {
7950
8566
  this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
7951
8567
  this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
7952
- return { ok: false, marked: true };
8568
+ return { ok: false, marked: true, tier: "local" };
7953
8569
  }
7954
8570
  const plan = this.planFor(providerId);
7955
8571
  if (plan.kind === "local") {
7956
8572
  this.record(providerId, accountId, { ts: now, ok: true, tier: "local" });
7957
- return { ok: true, marked: false };
8573
+ return { ok: true, marked: false, tier: "local" };
7958
8574
  }
7959
8575
  const start = this.now();
7960
8576
  let status = null;
@@ -7979,7 +8595,60 @@ var AccountHealthProbeScheduler = class {
7979
8595
  latencyMs,
7980
8596
  tier: "upstream"
7981
8597
  });
7982
- return { ok: status !== null && status < 400, marked };
8598
+ return { ok: status !== null && status < 400, marked, tier: "upstream" };
8599
+ }
8600
+ /**
8601
+ * Manual connection test. Codex performs a real, quota-consuming generation;
8602
+ * every other provider keeps its existing cheap probe. Scheduled sweeps never
8603
+ * call this method, so they remain non-billable.
8604
+ */
8605
+ async testAccountConnection(providerId, accountId) {
8606
+ if (providerId !== "codex") return this.probeAccount(providerId, accountId);
8607
+ const now = this.now();
8608
+ let token;
8609
+ try {
8610
+ token = await this.store.getAccessTokenForAccount(providerId, accountId);
8611
+ } catch {
8612
+ this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
8613
+ return { ok: false, marked: false, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8614
+ }
8615
+ if (!token) {
8616
+ this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
8617
+ this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
8618
+ return { ok: false, marked: true, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8619
+ }
8620
+ const startedAt = this.now();
8621
+ let attempt = await this.runCodexGenerationAttempt(accountId, token);
8622
+ if (attempt.status === 401 && this.store.refreshAccountToken) {
8623
+ try {
8624
+ if (await this.store.refreshAccountToken(providerId, accountId)) {
8625
+ const refreshed = await this.store.getAccessTokenForAccount(providerId, accountId);
8626
+ if (refreshed) attempt = await this.runCodexGenerationAttempt(accountId, refreshed);
8627
+ }
8628
+ } catch {
8629
+ }
8630
+ }
8631
+ const latencyMs = this.now() - startedAt;
8632
+ const ok = attempt.status !== null && attempt.status >= 200 && attempt.status < 300 && attempt.completed;
8633
+ let marked = false;
8634
+ if (ok) {
8635
+ this.health.clearTransientMark(providerId, accountId);
8636
+ } else if (attempt.status === 401 || attempt.status === 403) {
8637
+ marked = this.applyOutcome(providerId, accountId, attempt.status, attempt.bodyText, now);
8638
+ }
8639
+ this.record(providerId, accountId, {
8640
+ ts: now,
8641
+ ok,
8642
+ status: attempt.status,
8643
+ latencyMs,
8644
+ tier: "generation"
8645
+ });
8646
+ return {
8647
+ ok,
8648
+ marked,
8649
+ tier: "generation",
8650
+ model: CODEX_GENERATION_PROBE_MODEL
8651
+ };
7983
8652
  }
7984
8653
  /** Per-account rolling history for the authed admin surface (design D5). */
7985
8654
  getAllHistory() {
@@ -8036,6 +8705,24 @@ var AccountHealthProbeScheduler = class {
8036
8705
  return "";
8037
8706
  }
8038
8707
  }
8708
+ async runCodexGenerationAttempt(accountId, token) {
8709
+ try {
8710
+ const timeoutMs = Math.max(this.config.timeoutMs, 15e3);
8711
+ const response = await this.fetchImpl(
8712
+ CODEX_GENERATION_PROBE_URL,
8713
+ buildCodexGenerationProbeInit(token, AbortSignal.timeout(timeoutMs)),
8714
+ { providerId: "codex", accountId, redactBodies: true }
8715
+ );
8716
+ if (response.status < 200 || response.status >= 300) {
8717
+ const bodyText = response.status === 403 ? await this.readBounded(response) : void 0;
8718
+ return { status: response.status, completed: false, bodyText };
8719
+ }
8720
+ const stream = await readCodexGenerationProbeStream(response);
8721
+ return { status: response.status, completed: stream.completed };
8722
+ } catch {
8723
+ return { status: null, completed: false };
8724
+ }
8725
+ }
8039
8726
  key(providerId, accountId) {
8040
8727
  return `${providerId}${KEY_SEP}${accountId}`;
8041
8728
  }
@@ -8131,7 +8818,7 @@ var AccountHealthSweeper = class {
8131
8818
  };
8132
8819
 
8133
8820
  // src/audit/AuditPruneSweeper.ts
8134
- import { existsSync as existsSync14, readdirSync, unlinkSync as unlinkSync3 } from "fs";
8821
+ import { existsSync as existsSync15, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
8135
8822
  import { join as join7 } from "path";
8136
8823
 
8137
8824
  // src/audit/auditFiles.ts
@@ -8154,12 +8841,213 @@ function auditFileDateMs(fileName) {
8154
8841
  return d.getTime();
8155
8842
  }
8156
8843
 
8844
+ // src/audit/auditStats.ts
8845
+ import {
8846
+ createReadStream,
8847
+ existsSync as existsSync14,
8848
+ readFileSync as readFileSync14,
8849
+ readdirSync,
8850
+ statSync as statSync3,
8851
+ writeFileSync as writeFileSync12
8852
+ } from "fs";
8853
+ import { basename, dirname as dirname7, join as join6 } from "path";
8854
+ var SIDECAR_VERSION = 1;
8855
+ var META_PREFIX_BYTES = 64 * 1024;
8856
+ var READ_CHUNK_BYTES = 4 * 1024 * 1024;
8857
+ function auditStatsFileName(auditFile) {
8858
+ return auditFile.replace(/\.jsonl$/, ".stats.json");
8859
+ }
8860
+ function readPersisted(path2) {
8861
+ if (!existsSync14(path2)) return null;
8862
+ try {
8863
+ const value = JSON.parse(readFileSync14(path2, "utf8"));
8864
+ 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)) {
8865
+ return null;
8866
+ }
8867
+ return value;
8868
+ } catch {
8869
+ return null;
8870
+ }
8871
+ }
8872
+ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
8873
+ const statsPath = join6(dirname7(auditPath), auditStatsFileName(basename(auditPath)));
8874
+ const previous = auditBytesBefore === 0 ? {
8875
+ version: SIDECAR_VERSION,
8876
+ auditBytes: 0,
8877
+ requestCount: 0,
8878
+ errorCount: 0,
8879
+ complete: true,
8880
+ minTs: null,
8881
+ maxTs: null
8882
+ } : readPersisted(statsPath);
8883
+ if (!previous || !previous.complete || previous.auditBytes !== auditBytesBefore) return;
8884
+ const next = {
8885
+ version: SIDECAR_VERSION,
8886
+ auditBytes: auditBytesAfter,
8887
+ requestCount: previous.requestCount + 1,
8888
+ errorCount: previous.errorCount + (record.status >= 400 || Boolean(record.error) ? 1 : 0),
8889
+ complete: true,
8890
+ minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
8891
+ maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
8892
+ };
8893
+ writeFileSync12(statsPath, JSON.stringify(next), "utf8");
8894
+ }
8895
+ function queryCovers(stats, from, to) {
8896
+ return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
8897
+ }
8898
+ function fileOverlaps(file, from, to) {
8899
+ const start = auditFileDateMs(file);
8900
+ if (start === null) return false;
8901
+ const date = new Date(start);
8902
+ const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
8903
+ return end > from && start <= to;
8904
+ }
8905
+ function parseMetadataPrefix(prefix, prefixTruncated) {
8906
+ const text = prefix.toString("utf8");
8907
+ const tsMatch = /(?:^|,)"ts":(-?\d+)/.exec(text);
8908
+ const statusMatch = /(?:^|,)"status":(-?\d+)/.exec(text);
8909
+ const errorMatch = /(?:^|,)"error":"((?:\\.|[^"\\])*)"/.exec(text);
8910
+ const bodyStarted = /,(?:"requestBody"|"responseBody"):/.test(text);
8911
+ return {
8912
+ ts: tsMatch ? Number(tsMatch[1]) : void 0,
8913
+ status: statusMatch ? Number(statusMatch[1]) : void 0,
8914
+ hasError: Boolean(errorMatch?.[1]),
8915
+ complete: Boolean(tsMatch && statusMatch && (!prefixTruncated || bodyStarted))
8916
+ };
8917
+ }
8918
+ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
8919
+ let requestCount = 0;
8920
+ let errorCount = 0;
8921
+ let filteredRequestCount = 0;
8922
+ let filteredErrorCount = 0;
8923
+ let minTs = null;
8924
+ let maxTs = null;
8925
+ let complete = true;
8926
+ let prefixParts = [];
8927
+ let prefixBytes = 0;
8928
+ let prefixTruncated = false;
8929
+ const consumeLine = () => {
8930
+ if (prefixBytes === 0 && !prefixTruncated) return;
8931
+ const prefix = Buffer.concat(prefixParts, prefixBytes);
8932
+ const metadata = parseMetadataPrefix(prefix, prefixTruncated);
8933
+ if (!metadata.complete || metadata.ts === void 0 || metadata.status === void 0) {
8934
+ complete = false;
8935
+ } else {
8936
+ requestCount += 1;
8937
+ const isError = metadata.status >= 400 || metadata.hasError;
8938
+ if (isError) errorCount += 1;
8939
+ minTs = minTs === null ? metadata.ts : Math.min(minTs, metadata.ts);
8940
+ maxTs = maxTs === null ? metadata.ts : Math.max(maxTs, metadata.ts);
8941
+ if (metadata.ts >= from && metadata.ts <= to) {
8942
+ filteredRequestCount += 1;
8943
+ if (isError) filteredErrorCount += 1;
8944
+ }
8945
+ }
8946
+ prefixParts = [];
8947
+ prefixBytes = 0;
8948
+ prefixTruncated = false;
8949
+ };
8950
+ if (auditBytes > startByte) {
8951
+ const stream = createReadStream(auditPath, {
8952
+ start: startByte,
8953
+ end: auditBytes - 1,
8954
+ highWaterMark: READ_CHUNK_BYTES
8955
+ });
8956
+ for await (const value of stream) {
8957
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
8958
+ let offset = 0;
8959
+ while (offset < chunk.length) {
8960
+ const newline = chunk.indexOf(10, offset);
8961
+ const end = newline === -1 ? chunk.length : newline;
8962
+ if (prefixBytes < META_PREFIX_BYTES) {
8963
+ const retained = Math.min(META_PREFIX_BYTES - prefixBytes, end - offset);
8964
+ if (retained > 0) {
8965
+ prefixParts.push(Buffer.from(chunk.subarray(offset, offset + retained)));
8966
+ prefixBytes += retained;
8967
+ }
8968
+ if (retained < end - offset) prefixTruncated = true;
8969
+ } else if (end > offset) {
8970
+ prefixTruncated = true;
8971
+ }
8972
+ if (newline === -1) break;
8973
+ consumeLine();
8974
+ offset = newline + 1;
8975
+ }
8976
+ }
8977
+ }
8978
+ if (prefixBytes > 0 || prefixTruncated) complete = false;
8979
+ return {
8980
+ all: {
8981
+ version: SIDECAR_VERSION,
8982
+ auditBytes,
8983
+ requestCount,
8984
+ errorCount,
8985
+ complete,
8986
+ minTs,
8987
+ maxTs
8988
+ },
8989
+ filtered: { requestCount: filteredRequestCount, errorCount: filteredErrorCount, complete }
8990
+ };
8991
+ }
8992
+ function mergePersistedStats(previous, appended) {
8993
+ return {
8994
+ version: SIDECAR_VERSION,
8995
+ auditBytes: appended.auditBytes,
8996
+ requestCount: previous.requestCount + appended.requestCount,
8997
+ errorCount: previous.errorCount + appended.errorCount,
8998
+ complete: previous.complete && appended.complete,
8999
+ minTs: previous.minTs === null ? appended.minTs : appended.minTs === null ? previous.minTs : Math.min(previous.minTs, appended.minTs),
9000
+ maxTs: previous.maxTs === null ? appended.maxTs : appended.maxTs === null ? previous.maxTs : Math.max(previous.maxTs, appended.maxTs)
9001
+ };
9002
+ }
9003
+ async function readAuditStats(auditDir, query2 = {}) {
9004
+ if (!existsSync14(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
9005
+ const from = typeof query2.from === "number" ? query2.from : -Infinity;
9006
+ const to = typeof query2.to === "number" ? query2.to : Infinity;
9007
+ let files;
9008
+ try {
9009
+ files = readdirSync(auditDir).filter((file) => AUDIT_FILE_RE.test(file) && fileOverlaps(file, from, to)).sort();
9010
+ } catch {
9011
+ return { requestCount: 0, errorCount: 0, complete: false };
9012
+ }
9013
+ const total = { requestCount: 0, errorCount: 0, complete: true };
9014
+ for (const file of files) {
9015
+ const auditPath = join6(auditDir, file);
9016
+ try {
9017
+ const auditBytes = statSync3(auditPath).size;
9018
+ const statsPath = join6(auditDir, auditStatsFileName(file));
9019
+ const persisted = readPersisted(statsPath);
9020
+ if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
9021
+ total.requestCount += persisted.requestCount;
9022
+ total.errorCount += persisted.errorCount;
9023
+ continue;
9024
+ }
9025
+ const resumable = persisted && persisted.complete && persisted.auditBytes < auditBytes && queryCovers(persisted, from, to) ? persisted : null;
9026
+ const scanned = await scanAuditFile(
9027
+ auditPath,
9028
+ resumable?.auditBytes ?? 0,
9029
+ auditBytes,
9030
+ from,
9031
+ to
9032
+ );
9033
+ total.requestCount += scanned.filtered.requestCount + (resumable?.requestCount ?? 0);
9034
+ total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
9035
+ total.complete = total.complete && scanned.filtered.complete;
9036
+ const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
9037
+ if (current.complete) writeFileSync12(statsPath, JSON.stringify(current), "utf8");
9038
+ } catch {
9039
+ total.complete = false;
9040
+ }
9041
+ }
9042
+ return total;
9043
+ }
9044
+
8157
9045
  // src/audit/AuditPruneSweeper.ts
8158
9046
  var DAY_MS = 24 * 60 * 6e4;
8159
9047
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
8160
9048
  var AuditPruneSweeper = class {
8161
- constructor(auditDir2, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
8162
- this.auditDir = auditDir2;
9049
+ constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
9050
+ this.auditDir = auditDir;
8163
9051
  this.logger = logger;
8164
9052
  this.config = config;
8165
9053
  this.intervalMs = intervalMs;
@@ -8206,17 +9094,19 @@ var AuditPruneSweeper = class {
8206
9094
  if (!this.config.enabled || this.sweeping) return 0;
8207
9095
  this.sweeping = true;
8208
9096
  try {
8209
- if (!existsSync14(this.auditDir)) return 0;
9097
+ if (!existsSync15(this.auditDir)) return 0;
8210
9098
  const today = new Date(this.now());
8211
9099
  const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
8212
9100
  const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
8213
9101
  let removed = 0;
8214
- for (const file of readdirSync(this.auditDir)) {
9102
+ for (const file of readdirSync2(this.auditDir)) {
8215
9103
  const dateMs = auditFileDateMs(file);
8216
9104
  if (dateMs === null || dateMs >= cutoff) continue;
8217
9105
  try {
8218
9106
  unlinkSync3(join7(this.auditDir, file));
8219
9107
  removed += 1;
9108
+ const statsPath = join7(this.auditDir, auditStatsFileName(file));
9109
+ if (existsSync15(statsPath)) unlinkSync3(statsPath);
8220
9110
  } catch (error) {
8221
9111
  this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
8222
9112
  file,
@@ -8238,15 +9128,15 @@ var AuditPruneSweeper = class {
8238
9128
  };
8239
9129
 
8240
9130
  // src/audit/auditReader.ts
8241
- import { existsSync as existsSync15, readdirSync as readdirSync2, readFileSync as readFileSync14 } from "fs";
9131
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync15 } from "fs";
8242
9132
  import { join as join8 } from "path";
8243
9133
  var DEFAULT_LIMIT = 200;
8244
9134
  var MAX_LIMIT = 2e3;
8245
- function readAuditRecords(auditDir2, query2 = {}) {
8246
- if (!existsSync15(auditDir2)) return [];
9135
+ function readAuditRecords(auditDir, query2 = {}) {
9136
+ if (!existsSync16(auditDir)) return [];
8247
9137
  let files;
8248
9138
  try {
8249
- files = readdirSync2(auditDir2).filter((f) => AUDIT_FILE_RE.test(f));
9139
+ files = readdirSync3(auditDir).filter((f) => AUDIT_FILE_RE.test(f));
8250
9140
  } catch {
8251
9141
  return [];
8252
9142
  }
@@ -8257,7 +9147,7 @@ function readAuditRecords(auditDir2, query2 = {}) {
8257
9147
  for (const file of files.sort().reverse()) {
8258
9148
  let raw;
8259
9149
  try {
8260
- raw = readFileSync14(join8(auditDir2, file), "utf8");
9150
+ raw = readFileSync15(join8(auditDir, file), "utf8");
8261
9151
  } catch {
8262
9152
  continue;
8263
9153
  }
@@ -8286,11 +9176,11 @@ function isAuditRecord(value) {
8286
9176
  }
8287
9177
 
8288
9178
  // src/audit/AuditWriter.ts
8289
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "fs";
9179
+ import { appendFileSync as appendFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync5, statSync as statSync4 } from "fs";
8290
9180
  import { join as join9 } from "path";
8291
9181
  var AuditWriter = class {
8292
- constructor(auditDir2, logger, defer = (fn) => setTimeout(fn, 0)) {
8293
- this.auditDir = auditDir2;
9182
+ constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
9183
+ this.auditDir = auditDir;
8294
9184
  this.logger = logger;
8295
9185
  this.defer = defer;
8296
9186
  }
@@ -8324,7 +9214,21 @@ var AuditWriter = class {
8324
9214
  this.dirEnsured = true;
8325
9215
  }
8326
9216
  const file = join9(this.auditDir, auditFileName(record.ts));
8327
- appendFileSync2(file, JSON.stringify(record) + "\n", "utf8");
9217
+ const line = JSON.stringify(record) + "\n";
9218
+ const auditBytesBefore = existsSync17(file) ? statSync4(file).size : 0;
9219
+ appendFileSync2(file, line, "utf8");
9220
+ try {
9221
+ updateAuditStatsAfterAppend(
9222
+ file,
9223
+ auditBytesBefore,
9224
+ auditBytesBefore + Buffer.byteLength(line, "utf8"),
9225
+ record
9226
+ );
9227
+ } catch (error) {
9228
+ this.logger.warn("[AuditWriter] failed to update audit stats", {
9229
+ error: error instanceof Error ? error.message : String(error)
9230
+ });
9231
+ }
8328
9232
  }
8329
9233
  };
8330
9234
 
@@ -8468,14 +9372,14 @@ var BillingPublisher = class {
8468
9372
  };
8469
9373
 
8470
9374
  // src/billing/billingReader.ts
8471
- import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync15 } from "fs";
9375
+ import { existsSync as existsSync18, readdirSync as readdirSync4, readFileSync as readFileSync16 } from "fs";
8472
9376
  import { join as join11 } from "path";
8473
9377
  function readBillingLedger(billingDir) {
8474
9378
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
8475
- if (!existsSync16(billingDir)) return view;
9379
+ if (!existsSync18(billingDir)) return view;
8476
9380
  let files;
8477
9381
  try {
8478
- files = readdirSync3(billingDir);
9382
+ files = readdirSync4(billingDir);
8479
9383
  } catch {
8480
9384
  return view;
8481
9385
  }
@@ -8506,7 +9410,7 @@ function readBillingStatus(billingDir) {
8506
9410
  function parseLines(dir, file) {
8507
9411
  let raw;
8508
9412
  try {
8509
- raw = readFileSync15(join11(dir, file), "utf8");
9413
+ raw = readFileSync16(join11(dir, file), "utf8");
8510
9414
  } catch {
8511
9415
  return [];
8512
9416
  }
@@ -8692,6 +9596,78 @@ var TokenRefreshScheduler = class {
8692
9596
  }
8693
9597
  };
8694
9598
 
9599
+ // src/routeLeaseSubscriptionPreflight.ts
9600
+ import {
9601
+ RouteLeaseError as RouteLeaseError3
9602
+ } from "@omnicross/core/provider-proxy";
9603
+ import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling4 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
9604
+ import { getSharedAccountHealth as getSharedAccountHealth3 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
9605
+ import { accountSupportsModel } from "@omnicross/subscriptions/scheduler/accountModelMap";
9606
+ var PROVIDERS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "opencodego"]);
9607
+ function accountArray(config, providerId) {
9608
+ const record = config;
9609
+ const key = `${providerId}Accounts`;
9610
+ const accounts = record[key];
9611
+ if (Array.isArray(accounts)) return accounts;
9612
+ const legacy = record[providerId];
9613
+ if (!legacy || typeof legacy !== "object") return [];
9614
+ const activeKey = `active${providerId[0].toUpperCase()}${providerId.slice(1)}AccountId`;
9615
+ return [{ id: String(record[activeKey] ?? "active"), enabled: true, tokens: legacy }];
9616
+ }
9617
+ function hasCredential(providerId, account) {
9618
+ const tokens = account.tokens;
9619
+ if (providerId === "opencodego") return typeof tokens.apiKey === "string" && tokens.apiKey.length > 0;
9620
+ return typeof tokens.accessToken === "string" && tokens.accessToken.length > 0;
9621
+ }
9622
+ function safeProviderId(value) {
9623
+ if (!PROVIDERS.has(value)) {
9624
+ throw new RouteLeaseError3("upstream_not_found", "subscription provider was not found");
9625
+ }
9626
+ return value;
9627
+ }
9628
+ function createRouteLeaseSubscriptionPreflight(credentials) {
9629
+ return {
9630
+ async assertAvailable(upstream, model) {
9631
+ const providerId = safeProviderId(upstream.providerId);
9632
+ const config = await credentials.getFullConfig();
9633
+ const all = accountArray(config, providerId);
9634
+ if (all.length === 0) {
9635
+ throw new RouteLeaseError3("upstream_unavailable", "subscription provider has no configured account");
9636
+ }
9637
+ let bounded = all;
9638
+ if (upstream.kind === "account") {
9639
+ bounded = all.filter((account) => account.id === upstream.accountId);
9640
+ } else if (upstream.kind === "account-group") {
9641
+ bounded = all.filter((account) => account.group?.trim() === upstream.group);
9642
+ }
9643
+ if (bounded.length === 0) {
9644
+ throw new RouteLeaseError3("upstream_not_found", "the selected subscription resource was not found");
9645
+ }
9646
+ const modelEligible = bounded.filter(
9647
+ (account) => accountSupportsModel(account.supportedModels, model)
9648
+ );
9649
+ if (modelEligible.length === 0) {
9650
+ throw new RouteLeaseError3("model_not_configured", "model is not supported by the selected subscription resource");
9651
+ }
9652
+ const credentialEligible = modelEligible.filter(
9653
+ (account) => account.enabled !== false && hasCredential(providerId, account)
9654
+ );
9655
+ const health2 = getSharedAccountHealth3();
9656
+ const allowance = getSharedAccountAllowanceScheduling4();
9657
+ const candidates = credentialEligible.filter(
9658
+ (account) => health2.isSchedulable(providerId, account.id) && allowance.preview(providerId, account.id, account.priority ?? 50).schedulable
9659
+ );
9660
+ if (candidates.length > 0) return;
9661
+ if (upstream.kind === "account") {
9662
+ throw new RouteLeaseError3("upstream_unavailable", "the selected subscription account is unavailable");
9663
+ }
9664
+ throw new RouteLeaseError3("upstream_exhausted", "the selected subscription pool has no eligible account", {
9665
+ retryAfterSeconds: 30
9666
+ });
9667
+ }
9668
+ };
9669
+ }
9670
+
8695
9671
  // src/webhook/WebhookDispatcher.ts
8696
9672
  import { createHmac as createHmac2 } from "crypto";
8697
9673
  import { fetchUpstream as fetchUpstream6 } from "@omnicross/core/pipeline/upstreamFetch";
@@ -8874,11 +9850,11 @@ function buildDaemon(config, paths) {
8874
9850
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
8875
9851
  );
8876
9852
  setSharedAccountAllowanceStore(accountAllowanceStore);
8877
- getSharedAccountAllowanceScheduling4().configure(
9853
+ getSharedAccountAllowanceScheduling5().configure(
8878
9854
  normalizeServerConfig(decryptedConfig.server).allowanceScheduling
8879
9855
  );
8880
9856
  const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
8881
- const keyDb = new JsonOutboundKeyDb(paths.keysPath);
9857
+ const keyDb = new JsonOutboundKeyDb(paths.keysPath, secretBox3);
8882
9858
  const voucherDb = new JsonVoucherDb(defaultVouchersPath(paths.configPath));
8883
9859
  const settingsStore = new JsonApiServerSettingsStore(paths.configPath, secretBox3);
8884
9860
  const integrationStateStore = new IntegrationStateStore(
@@ -8942,10 +9918,21 @@ function buildDaemon(config, paths) {
8942
9918
  onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
8943
9919
  });
8944
9920
  const providerProxy = getProviderProxy({ llmConfig, apiKeyPool, usageRecorder });
9921
+ const routeLeaseManager = new RouteLeaseManager(
9922
+ providerProxy,
9923
+ new RouteLeaseTargetResolver(llmConfig, {
9924
+ providerKeys: apiKeyPool,
9925
+ subscriptions: createRouteLeaseSubscriptionPreflight(credentialStore)
9926
+ }),
9927
+ routeLeaseDescriptorPort,
9928
+ { logger }
9929
+ );
9930
+ providerProxy.registerBeforeStop(() => routeLeaseManager.shutdown());
9931
+ providerProxy.registerBeforeStop(() => resetCliSessions());
8945
9932
  llmConfig.setReloadHook(() => apiKeyPool.invalidateCache());
8946
9933
  const accountHealthProbeScheduler = new AccountHealthProbeScheduler(
8947
9934
  credentialStore,
8948
- getSharedAccountHealth3(),
9935
+ getSharedAccountHealth4(),
8949
9936
  logger,
8950
9937
  DEFAULT_ACCOUNT_PROBE
8951
9938
  );
@@ -8979,7 +9966,7 @@ function buildDaemon(config, paths) {
8979
9966
  // lines through the injected logger (honors level/format/file sink).
8980
9967
  logger
8981
9968
  });
8982
- const auditDir2 = defaultAuditDir(paths.configPath);
9969
+ const auditDir = defaultAuditDir(paths.configPath);
8983
9970
  const billingDir = defaultBillingDir(paths.configPath);
8984
9971
  const adminServer = new AdminServer({
8985
9972
  configPath: paths.configPath,
@@ -8992,6 +9979,7 @@ function buildDaemon(config, paths) {
8992
9979
  keySpendReader: keySpendTracker,
8993
9980
  settingsStore,
8994
9981
  outboundApiServer,
9982
+ routeLeaseManager,
8995
9983
  subscriptionAccounts,
8996
9984
  accountAllowanceService,
8997
9985
  allowanceRefreshScheduler: claudeAllowanceRefreshScheduler,
@@ -9013,10 +10001,16 @@ function buildDaemon(config, paths) {
9013
10001
  // (NOT widening the least-authority writer — no token-returning read reachable).
9014
10002
  oauthSessions: new OAuthSessionStore(),
9015
10003
  // Real global fetch by default; a test seam (`paths.oauthExchangeFetch`) can
9016
- // inject a mock so no real token endpoint is hit.
9017
- // upstream-proxy: default the OAuth token-exchange fetch to the proxy-aware
9018
- // helper so interactive login honors a configured proxy (global/env layers).
9019
- oauthExchangeFetch: paths.oauthExchangeFetch ?? ((url, init) => fetchUpstream7(url, init)),
10004
+ // inject a mock so no real token endpoint is hit (one FetchLike for every
10005
+ // provider the ctx below only matters on the real egress path).
10006
+ //
10007
+ // upstream-proxy: a PER-PROVIDER factory, so the exchange carries the same
10008
+ // `{ providerId }` ctx the CLI login and the token refresh already pass.
10009
+ // Without it the interactive login resolved only the global/env proxy layers
10010
+ // — `server.proxy.byProvider[...]` was silently skipped — and the call was
10011
+ // excluded from the upstream trace, so a failing login left no evidence.
10012
+ // `redactBodies` keeps the code/verifier + minted token out of that trace.
10013
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream7(url, init, { providerId, redactBodies: true }),
9020
10014
  subscriptionAccountAppender: credentialStore,
9021
10015
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
9022
10016
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -9068,7 +10062,8 @@ function buildDaemon(config, paths) {
9068
10062
  // date-rotated audit store. Bound to the store dir here so the AdminServer
9069
10063
  // carries no path/store coupling. Records hold IP/UA/bodies → admin-only,
9070
10064
  // NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
9071
- auditReader: (query2) => readAuditRecords(auditDir2, query2),
10065
+ auditReader: (query2) => readAuditRecords(auditDir, query2),
10066
+ auditStatsReader: (query2) => readAuditStats(auditDir, query2),
9072
10067
  // billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
9073
10068
  // secret-free total/delivered/pending counts of the durable ledger.
9074
10069
  billingStatusReader: () => readBillingStatus(billingDir)
@@ -9077,10 +10072,10 @@ function buildDaemon(config, paths) {
9077
10072
  logger,
9078
10073
  fetchImpl: (url, init) => fetchUpstream7(url, init)
9079
10074
  });
9080
- setWebhookRuntime(webhookDispatcher, getSharedAccountHealth3());
9081
- const auditWriter = new AuditWriter(auditDir2, logger);
9082
- const auditPruneSweeper = new AuditPruneSweeper(auditDir2, logger, DEFAULT_AUDIT_CONFIG);
9083
- setAuditRuntime(auditWriter, auditPruneSweeper, auditDir2);
10075
+ setWebhookRuntime(webhookDispatcher, getSharedAccountHealth4());
10076
+ const auditWriter = new AuditWriter(auditDir, logger);
10077
+ const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, DEFAULT_AUDIT_CONFIG);
10078
+ setAuditRuntime(auditWriter, auditPruneSweeper);
9084
10079
  const billingPublisher = new BillingPublisher(billingDir, logger);
9085
10080
  const billingRetrySweeper = new BillingRetrySweeper(
9086
10081
  billingDir,
@@ -9092,7 +10087,7 @@ function buildDaemon(config, paths) {
9092
10087
  const tokenRefreshScheduler = new TokenRefreshScheduler(credentialStore, logger);
9093
10088
  const accountHealthSweeper = new AccountHealthSweeper(
9094
10089
  credentialStore,
9095
- getSharedAccountHealth3(),
10090
+ getSharedAccountHealth4(),
9096
10091
  logger
9097
10092
  );
9098
10093
  return {
@@ -9101,6 +10096,7 @@ function buildDaemon(config, paths) {
9101
10096
  keyDb,
9102
10097
  settingsStore,
9103
10098
  providerProxy,
10099
+ routeLeaseManager,
9104
10100
  outboundApiServer,
9105
10101
  apiKeyPool,
9106
10102
  autoDisableStore,
@@ -9144,7 +10140,7 @@ function resetDaemonSingletonsForTests() {
9144
10140
  }
9145
10141
  function isTokensStoreReadable(tokensPath) {
9146
10142
  try {
9147
- if (!existsSync17(tokensPath)) return true;
10143
+ if (!existsSync19(tokensPath)) return true;
9148
10144
  accessSync(tokensPath, fsConstants.R_OK);
9149
10145
  return true;
9150
10146
  } catch {