@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.cjs CHANGED
@@ -53,20 +53,21 @@ __export(src_exports, {
53
53
  module.exports = __toCommonJS(src_exports);
54
54
 
55
55
  // src/bootstrap.ts
56
- var import_node_fs22 = require("fs");
56
+ var import_node_fs23 = require("fs");
57
57
  var import_audit_types = require("@omnicross/contracts/audit-types");
58
58
  var import_billing_types = require("@omnicross/contracts/billing-types");
59
59
  var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
60
60
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
61
61
  var import_outbound_api4 = require("@omnicross/core/outbound-api");
62
62
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
63
- var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
63
+ var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
64
64
  var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
65
- var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
65
+ var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
66
66
  var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
67
67
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
68
68
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
69
- var import_provider_proxy = require("@omnicross/core/provider-proxy");
69
+ var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
70
+ var import_cli_launcher2 = require("@omnicross/cli-launcher");
70
71
  var import_outbound_api5 = require("@omnicross/core/outbound-api");
71
72
  var import_usage = require("@omnicross/core/usage");
72
73
  var import_subscriptions4 = require("@omnicross/subscriptions");
@@ -147,7 +148,7 @@ async function runCodexLoopback(sessionId, codeVerifier, state, signal, deps) {
147
148
  const code = await deps.codexAwaitLoopback(state, void 0, signal);
148
149
  const result = await import_subscriptions.codexOAuth.exchangeCodeForTokens(
149
150
  { authorizationCode: code, codeVerifier, state },
150
- deps.oauthExchangeFetch
151
+ deps.oauthExchangeFetch("codex")
151
152
  );
152
153
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
153
154
  const block = {
@@ -649,6 +650,17 @@ function handleAuditQuery(req, res, reader) {
649
650
  res.writeHead(200, { "Content-Type": "application/json" });
650
651
  res.end(JSON.stringify({ records }));
651
652
  }
653
+ async function handleAuditStatsQuery(req, res, reader) {
654
+ const url = new URL(req.url ?? "/", "http://localhost");
655
+ const query2 = {};
656
+ const from = intParam(url.searchParams.get("from"));
657
+ if (from !== void 0) query2.from = from;
658
+ const to = intParam(url.searchParams.get("to"));
659
+ if (to !== void 0) query2.to = to;
660
+ const stats = reader ? await reader(query2) : { requestCount: 0, errorCount: 0, complete: true };
661
+ res.writeHead(200, { "Content-Type": "application/json" });
662
+ res.end(JSON.stringify(stats));
663
+ }
652
664
 
653
665
  // src/admin/billingStatusApi.ts
654
666
  function handleBillingStatus(res, reader) {
@@ -745,6 +757,88 @@ async function handleWebhookTest(req, res) {
745
757
  res.end(JSON.stringify({ result }));
746
758
  }
747
759
 
760
+ // src/admin/routeLeaseApi.ts
761
+ var import_provider_proxy = require("@omnicross/core/provider-proxy");
762
+ var MAX_BODY_BYTES = 64 * 1024;
763
+ var SAFE_LEASE_ID = /^[A-Za-z0-9-]{1,128}$/u;
764
+ async function readJson(req) {
765
+ const chunks = [];
766
+ let bytes = 0;
767
+ for await (const chunk of req) {
768
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
769
+ bytes += buffer.length;
770
+ if (bytes > MAX_BODY_BYTES) throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is too large");
771
+ chunks.push(buffer);
772
+ }
773
+ if (chunks.length === 0) return {};
774
+ try {
775
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
776
+ } catch {
777
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is not valid JSON");
778
+ }
779
+ }
780
+ function json(res, status, body, noStore = false) {
781
+ res.statusCode = status;
782
+ res.setHeader("Content-Type", "application/json");
783
+ if (noStore) res.setHeader("Cache-Control", "no-store");
784
+ res.end(JSON.stringify(body));
785
+ }
786
+ function leaseId(value) {
787
+ if (!value || !SAFE_LEASE_ID.test(value)) throw new import_provider_proxy.RouteLeaseError("invalid_request", "lease id is invalid");
788
+ return value;
789
+ }
790
+ function header(req, name) {
791
+ const value = req.headers[name.toLowerCase()];
792
+ return Array.isArray(value) ? value[0] : value;
793
+ }
794
+ function writeError(res, error, noStore) {
795
+ const safe = error instanceof import_provider_proxy.RouteLeaseError ? error : new import_provider_proxy.RouteLeaseError("upstream_unavailable", "route lease operation failed safely");
796
+ if (safe.retryAfterSeconds !== void 0) res.setHeader("Retry-After", String(safe.retryAfterSeconds));
797
+ json(res, safe.status, safe.toResponse(), noStore);
798
+ }
799
+ async function handleRouteLeaseApi(req, res, path2, deps) {
800
+ const method = (req.method ?? "GET").toUpperCase();
801
+ const noStore = method === "POST" && (path2 === "/admin/api/route-leases" || path2.endsWith("/renew"));
802
+ try {
803
+ if (!(0, import_provider_proxy.isLoopbackAddress)(req.socket.remoteAddress)) {
804
+ throw new import_provider_proxy.RouteLeaseError("control_unauthorized", "route lease control plane is loopback only");
805
+ }
806
+ const manager = deps.routeLeaseManager;
807
+ if (!manager) throw new import_provider_proxy.RouteLeaseError("daemon_not_ready", "route lease manager is unavailable");
808
+ const base = "/admin/api/route-leases";
809
+ const suffix = path2.slice(base.length).replace(/^\/+|\/+$/gu, "");
810
+ const segments = suffix ? suffix.split("/") : [];
811
+ if (segments.length === 1 && segments[0] === "capabilities") {
812
+ if (method !== "GET" && method !== "HEAD") throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
813
+ return json(res, 200, import_provider_proxy.ROUTE_LEASE_CAPABILITIES);
814
+ }
815
+ if (segments.length === 0) {
816
+ if (method === "GET") return json(res, 200, { leases: manager.list() });
817
+ if (method === "POST") {
818
+ const outcome = await manager.createFromRequest(await readJson(req), header(req, "idempotency-key"));
819
+ return json(res, outcome.created ? 201 : 200, outcome.result, true);
820
+ }
821
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
822
+ }
823
+ const id = leaseId(segments[0]);
824
+ if (segments.length === 1) {
825
+ if (method === "GET") return json(res, 200, manager.get(id));
826
+ if (method === "DELETE") return json(res, 200, manager.release(id));
827
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
828
+ }
829
+ if (segments.length === 2 && segments[1] === "renew" && method === "POST") {
830
+ const body = await readJson(req);
831
+ const ttl = (0, import_provider_proxy.normalizeRouteLeaseTtl)(
832
+ body && typeof body === "object" && !Array.isArray(body) ? body.ttlSeconds : void 0
833
+ );
834
+ return json(res, 200, manager.renew(id, ttl), true);
835
+ }
836
+ throw new import_provider_proxy.RouteLeaseError("lease_not_found", "route lease endpoint was not found");
837
+ } catch (error) {
838
+ writeError(res, error, noStore);
839
+ }
840
+ }
841
+
748
842
  // src/admin/adminApi.ts
749
843
  var import_node_http = __toESM(require("http"), 1);
750
844
  var import_outbound_api2 = require("@omnicross/core/outbound-api");
@@ -2144,7 +2238,13 @@ function listMappablePresets() {
2144
2238
  name: preset.name,
2145
2239
  apiFormat: resolved.format,
2146
2240
  baseUrl: preset.api_base_url,
2147
- models: Array.isArray(preset.models) ? preset.models : []
2241
+ models: Array.isArray(preset.models) ? preset.models : [],
2242
+ nameKey: preset.nameKey,
2243
+ icon: preset.icon,
2244
+ description: preset.description,
2245
+ features: preset.features,
2246
+ website: preset.website,
2247
+ modelsEndpoint: preset.modelsEndpoint
2148
2248
  });
2149
2249
  }
2150
2250
  return { mappable, excluded };
@@ -2533,7 +2633,7 @@ async function handleOAuthComplete(providerId, body, deps) {
2533
2633
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
2534
2634
  if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
2535
2635
  if (!rawCode) return err2(400, "oauth complete requires { code }");
2536
- const session = deps.oauthSessions.take(sessionId);
2636
+ const session = deps.oauthSessions.peek(sessionId);
2537
2637
  if (!session) return err2(410, "oauth session is unknown, expired, or already used");
2538
2638
  if (session.providerId !== providerId) {
2539
2639
  return err2(400, `oauth session does not match provider '${providerId}'`);
@@ -2547,13 +2647,15 @@ async function handleOAuthComplete(providerId, body, deps) {
2547
2647
  }
2548
2648
  code = splitCode;
2549
2649
  }
2650
+ const exchangeFetch = deps.oauthExchangeFetch(providerId);
2550
2651
  let block;
2551
2652
  try {
2552
- block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, deps.oauthExchangeFetch) : await exchangeGemini(code, session.codeVerifier, deps.oauthExchangeFetch);
2653
+ block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
2553
2654
  } catch (exchangeError) {
2554
2655
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
2555
2656
  return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
2556
2657
  }
2658
+ deps.oauthSessions.consume(sessionId);
2557
2659
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
2558
2660
  await deps.subscriptionAccountAppender.appendProviderAccount(providerId, block, label);
2559
2661
  const status = await statusEntryFor(deps.subscriptionAccounts, providerId);
@@ -2592,8 +2694,34 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
2592
2694
  var import_node_child_process = require("child_process");
2593
2695
  var import_node_crypto6 = require("crypto");
2594
2696
  var import_node_fs6 = require("fs");
2697
+ var import_node_net = require("net");
2698
+ var import_node_os3 = require("os");
2595
2699
  var import_node_path5 = require("path");
2596
2700
  var import_cli_launcher = require("@omnicross/cli-launcher");
2701
+ var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
2702
+
2703
+ // src/routeLeaseRenewal.ts
2704
+ var TERMINAL_LEASE_TTL_SECONDS = 600;
2705
+ var TERMINAL_LEASE_RENEW_INTERVAL_MS = 5 * 60 * 1e3;
2706
+ var TERMINAL_LEASE_MAX_LIFETIME_MS = 24 * 60 * 60 * 1e3;
2707
+ function startTerminalLeaseRenewal(manager, leaseId2) {
2708
+ const stopAt = Date.now() + TERMINAL_LEASE_MAX_LIFETIME_MS;
2709
+ const timer = setInterval(() => {
2710
+ if (Date.now() >= stopAt) {
2711
+ clearInterval(timer);
2712
+ return;
2713
+ }
2714
+ try {
2715
+ manager.renew(leaseId2, TERMINAL_LEASE_TTL_SECONDS);
2716
+ } catch {
2717
+ clearInterval(timer);
2718
+ }
2719
+ }, TERMINAL_LEASE_RENEW_INTERVAL_MS);
2720
+ timer.unref?.();
2721
+ return () => clearInterval(timer);
2722
+ }
2723
+
2724
+ // src/admin/cliLaunch.ts
2597
2725
  var LAUNCHABLE_CLIS = [
2598
2726
  { id: "claude", displayName: "Claude Code", command: "claude" },
2599
2727
  { id: "codex", displayName: "Codex CLI", command: "codex" },
@@ -2674,34 +2802,183 @@ async function buildLaunchEnv(cli, llmConfig, target) {
2674
2802
  function shq(s) {
2675
2803
  return `'${s.replace(/'/g, `'\\''`)}'`;
2676
2804
  }
2677
- var defaultTerminalOpener = ({ cli, command, extraArgs, env, cwd, platform }) => {
2805
+ var MAC_TERMINAL_BOOTSTRAP_SOURCE = `
2806
+ 'use strict';
2807
+ const fs = require('node:fs');
2808
+ const net = require('node:net');
2809
+ const { spawn } = require('node:child_process');
2810
+ const [socketPath, launchDir, cwd, command, ...args] = process.argv.slice(2);
2811
+ let payload = '';
2812
+ const socket = net.createConnection(socketPath);
2813
+ socket.setEncoding('utf8');
2814
+ socket.on('data', (chunk) => { payload += chunk; });
2815
+ socket.on('end', () => {
2816
+ const descriptor = JSON.parse(payload);
2817
+ if (!descriptor || Array.isArray(descriptor) || Object.values(descriptor).some((value) => typeof value !== 'string')) {
2818
+ throw new Error('invalid terminal launch descriptor');
2819
+ }
2820
+ try { fs.rmSync(launchDir, { recursive: true, force: true }); } catch {}
2821
+ const child = spawn(command, args, {
2822
+ cwd: cwd || undefined,
2823
+ env: { ...process.env, ...descriptor },
2824
+ stdio: 'inherit',
2825
+ });
2826
+ child.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
2827
+ child.on('exit', (code, signal) => {
2828
+ if (signal) process.kill(process.pid, signal);
2829
+ else process.exitCode = code == null ? 1 : code;
2830
+ });
2831
+ });
2832
+ socket.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
2833
+ `;
2834
+ var MAC_TERMINAL_IPC_TIMEOUT_MS = 12e4;
2835
+ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }, spawnProcess = import_node_child_process.spawn, macIpc = {}) {
2678
2836
  const childEnv = { ...process.env, ...env };
2679
2837
  if (platform === "win32") {
2680
2838
  const args = ["/c", "start", `"omnicross ${cli}"`];
2681
2839
  if (cwd) args.push("/D", `"${cwd}"`);
2682
2840
  args.push("cmd", "/k", command, ...extraArgs);
2683
- (0, import_node_child_process.spawn)(process.env["ComSpec"] || "cmd.exe", args, {
2841
+ spawnProcess(process.env["ComSpec"] || "cmd.exe", args, {
2684
2842
  env: childEnv,
2685
2843
  windowsVerbatimArguments: true,
2686
2844
  detached: true,
2687
2845
  stdio: "ignore"
2688
2846
  }).unref();
2689
- return;
2847
+ return () => {
2848
+ };
2690
2849
  }
2691
- const exportLine = Object.entries(env).map(([k, v]) => `export ${k}=${shq(v)}`).join("; ");
2692
2850
  const runLine = [command, ...extraArgs].map(shq).join(" ");
2693
- const script = `${exportLine}; ${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
2851
+ const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
2694
2852
  if (platform === "darwin") {
2695
- const osa = `tell application "Terminal" to do script ${JSON.stringify(script)}`;
2696
- (0, import_node_child_process.spawn)("osascript", ["-e", osa], { detached: true, stdio: "ignore" }).unref();
2697
- return;
2853
+ const launchDir = (0, import_node_fs6.mkdtempSync)((0, import_node_path5.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
2854
+ const commandFile = (0, import_node_path5.join)(launchDir, "launch.command");
2855
+ const bootstrapFile = (0, import_node_path5.join)(launchDir, "bootstrap.cjs");
2856
+ const socketPath = macIpc.socketPath ?? (0, import_node_path5.join)(launchDir, "descriptor.sock");
2857
+ const openerEnv = { ...process.env };
2858
+ for (const key of Object.keys(env)) delete openerEnv[key];
2859
+ let claimed = false;
2860
+ let cleaned = false;
2861
+ let failureNotified = false;
2862
+ let timer;
2863
+ const notifyFailure = () => {
2864
+ cleanup();
2865
+ if (failureNotified) return;
2866
+ failureNotified = true;
2867
+ try {
2868
+ onFailure?.();
2869
+ } catch {
2870
+ }
2871
+ };
2872
+ const handleLaunchFailure = () => {
2873
+ if (claimed) cleanup();
2874
+ else notifyFailure();
2875
+ };
2876
+ const sockets = /* @__PURE__ */ new Set();
2877
+ const server = (0, import_node_net.createServer)((socket) => {
2878
+ socket.unref();
2879
+ sockets.add(socket);
2880
+ socket.once("close", () => sockets.delete(socket));
2881
+ try {
2882
+ macIpc.onAccepted?.(socket);
2883
+ } catch {
2884
+ cleanup();
2885
+ return;
2886
+ }
2887
+ if (claimed || cleaned) {
2888
+ socket.destroy();
2889
+ return;
2890
+ }
2891
+ claimed = true;
2892
+ try {
2893
+ macIpc.onClaimed?.();
2894
+ if (cleaned) return;
2895
+ socket.end(JSON.stringify(env), cleanup);
2896
+ } catch {
2897
+ cleanup();
2898
+ }
2899
+ });
2900
+ const cleanup = () => {
2901
+ if (!cleaned) {
2902
+ cleaned = true;
2903
+ if (timer) clearTimeout(timer);
2904
+ for (const socket of sockets) socket.destroy();
2905
+ sockets.clear();
2906
+ try {
2907
+ server.close();
2908
+ } catch {
2909
+ }
2910
+ }
2911
+ try {
2912
+ if (macIpc.removeArtifacts) {
2913
+ macIpc.removeArtifacts(launchDir);
2914
+ } else {
2915
+ (0, import_node_fs6.rmSync)(launchDir, {
2916
+ recursive: true,
2917
+ force: true,
2918
+ maxRetries: 3,
2919
+ retryDelay: 20
2920
+ });
2921
+ }
2922
+ } catch {
2923
+ }
2924
+ };
2925
+ try {
2926
+ (0, import_node_fs6.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
2927
+ (0, import_node_fs6.writeFileSync)(commandFile, `#!/bin/bash
2928
+ rm -f -- "$0"
2929
+ exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
2930
+ `, {
2931
+ encoding: "utf8",
2932
+ mode: 448
2933
+ });
2934
+ (0, import_node_fs6.chmodSync)(commandFile, 448);
2935
+ (0, import_node_fs6.chmodSync)(bootstrapFile, 448);
2936
+ server.once("error", handleLaunchFailure);
2937
+ server.listen(socketPath, () => {
2938
+ if (cleaned) return;
2939
+ try {
2940
+ macIpc.onListening?.();
2941
+ if (cleaned) return;
2942
+ if (process.platform !== "win32") (0, import_node_fs6.chmodSync)(socketPath, 384);
2943
+ const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
2944
+ env: openerEnv,
2945
+ detached: true,
2946
+ stdio: "ignore"
2947
+ });
2948
+ opener.once("error", handleLaunchFailure);
2949
+ opener.unref();
2950
+ server.unref();
2951
+ } catch {
2952
+ handleLaunchFailure();
2953
+ }
2954
+ });
2955
+ timer = setTimeout(handleLaunchFailure, macIpc.timeoutMs ?? MAC_TERMINAL_IPC_TIMEOUT_MS);
2956
+ timer.unref?.();
2957
+ return cleanup;
2958
+ } catch (error) {
2959
+ cleanup();
2960
+ throw error;
2961
+ }
2698
2962
  }
2699
- (0, import_node_child_process.spawn)("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
2963
+ spawnProcess("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
2964
+ env: childEnv,
2700
2965
  detached: true,
2701
2966
  stdio: "ignore"
2702
2967
  }).unref();
2703
- };
2968
+ return () => {
2969
+ };
2970
+ }
2971
+ var defaultTerminalOpener = (input) => openTerminal(input);
2704
2972
  var sessions = /* @__PURE__ */ new Map();
2973
+ function resetCliSessions() {
2974
+ for (const s of sessions.values()) {
2975
+ try {
2976
+ s.onSessionEnd();
2977
+ } catch {
2978
+ }
2979
+ }
2980
+ sessions.clear();
2981
+ }
2705
2982
  function errBody(message) {
2706
2983
  return { error: { type: "admin_api_error", message } };
2707
2984
  }
@@ -2756,29 +3033,81 @@ async function handleCliLaunch(cli, body, ctx) {
2756
3033
  } catch (err5) {
2757
3034
  return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
2758
3035
  }
3036
+ const id = (0, import_node_crypto6.randomUUID)();
3037
+ let leaseId2;
2759
3038
  let launch;
2760
3039
  try {
2761
- launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3040
+ if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
3041
+ const outcome = await ctx.routeLeaseManager.createFromRequest({
3042
+ schemaVersion: import_provider_proxy2.ROUTE_LEASE_REQUEST_SCHEMA,
3043
+ consumer: "omnicross-terminal",
3044
+ runtime: cli,
3045
+ upstream: { kind: "provider", providerId: target.providerId },
3046
+ model: target.model,
3047
+ execution: { sessionId: id }
3048
+ }, `omnicross-terminal:${id}`);
3049
+ leaseId2 = outcome.result.leaseId;
3050
+ const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
3051
+ launch = {
3052
+ env: outcome.result.launch.env,
3053
+ extraArgs: outcome.result.launch.extraArgs,
3054
+ onSessionEnd: () => {
3055
+ stopRenewal();
3056
+ ctx.routeLeaseManager?.release(outcome.result.leaseId);
3057
+ }
3058
+ };
3059
+ } else {
3060
+ launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3061
+ }
2762
3062
  } catch (err5) {
2763
- return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
3063
+ const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
3064
+ return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
2764
3065
  }
2765
3066
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
2766
3067
  const opener = ctx.opener ?? defaultTerminalOpener;
3068
+ let openerCleanup;
3069
+ let ended = false;
3070
+ let published = false;
3071
+ const onSessionEnd = () => {
3072
+ if (ended) return;
3073
+ ended = true;
3074
+ if (published) sessions.delete(id);
3075
+ try {
3076
+ openerCleanup?.();
3077
+ } finally {
3078
+ launch.onSessionEnd();
3079
+ }
3080
+ };
2767
3081
  try {
2768
- opener({ cli, command: meta.command, extraArgs: launch.extraArgs ?? [], env: launch.env, cwd, platform });
3082
+ const cleanup = opener({
3083
+ cli,
3084
+ command: meta.command,
3085
+ extraArgs: launch.extraArgs ?? [],
3086
+ env: launch.env,
3087
+ cwd,
3088
+ platform,
3089
+ onFailure: onSessionEnd
3090
+ });
3091
+ if (cleanup) openerCleanup = cleanup;
2769
3092
  } catch (err5) {
2770
- launch.onSessionEnd();
3093
+ onSessionEnd();
2771
3094
  return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
2772
3095
  }
2773
- const id = (0, import_node_crypto6.randomUUID)();
3096
+ if (ended) {
3097
+ openerCleanup?.();
3098
+ return { status: 500, body: errBody("failed to open terminal") };
3099
+ }
2774
3100
  sessions.set(id, {
2775
3101
  id,
2776
3102
  cli,
2777
3103
  providerId: target.providerId,
2778
3104
  model: target.model,
3105
+ ...leaseId2 ? { leaseId: leaseId2 } : {},
2779
3106
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2780
- onSessionEnd: launch.onSessionEnd
3107
+ onSessionEnd
2781
3108
  });
3109
+ published = true;
3110
+ if (ended) sessions.delete(id);
2782
3111
  return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
2783
3112
  }
2784
3113
 
@@ -2798,8 +3127,8 @@ function validateAuditSegment(patch) {
2798
3127
  }
2799
3128
  }
2800
3129
  const maxBodyBytes = audit["maxBodyBytes"];
2801
- if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < 0)) {
2802
- errors.push("audit.maxBodyBytes must be a non-negative number");
3130
+ if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < -1)) {
3131
+ errors.push("audit.maxBodyBytes must be -1 or a non-negative number");
2803
3132
  }
2804
3133
  const retentionDays = audit["retentionDays"];
2805
3134
  if (retentionDays !== void 0 && (typeof retentionDays !== "number" || !Number.isFinite(retentionDays) || retentionDays < 0)) {
@@ -3234,18 +3563,16 @@ function preserveWebhookSecrets(incoming, current) {
3234
3563
  }
3235
3564
 
3236
3565
  // src/audit/auditRuntime.ts
3237
- var import_node_path6 = require("path");
3238
3566
  var import_auditSink = require("@omnicross/core/pipeline/auditSink");
3239
3567
  var import_upstreamTrace = require("@omnicross/core/pipeline/upstreamTrace");
3240
3568
  var writer = null;
3241
3569
  var sweeper = null;
3242
- var auditDir = "";
3243
- function setAuditRuntime(w, s, dir) {
3570
+ function setAuditRuntime(w, s) {
3244
3571
  writer = w;
3245
3572
  sweeper = s;
3246
- auditDir = dir;
3247
3573
  }
3248
3574
  function applyAuditConfig(config) {
3575
+ (0, import_upstreamTrace.setUpstreamTracePath)(null);
3249
3576
  const enabled = config?.enabled === true && writer !== null;
3250
3577
  if (enabled && config) {
3251
3578
  (0, import_auditSink.setAuditCaptureConfig)(config);
@@ -3255,11 +3582,9 @@ function applyAuditConfig(config) {
3255
3582
  sweeper.configure(config);
3256
3583
  sweeper.start();
3257
3584
  }
3258
- (0, import_upstreamTrace.setUpstreamTracePath)(config.captureBodies ? (0, import_node_path6.join)(auditDir, "upstream-trace.jsonl") : null);
3259
3585
  } else {
3260
3586
  (0, import_auditSink.setAuditCaptureConfig)(null);
3261
3587
  (0, import_auditSink.setAuditSink)(null);
3262
- (0, import_upstreamTrace.setUpstreamTracePath)(null);
3263
3588
  if (sweeper) {
3264
3589
  if (config) sweeper.configure(config);
3265
3590
  sweeper.dispose();
@@ -3273,7 +3598,6 @@ function resetAuditRuntimeForTests() {
3273
3598
  if (sweeper) sweeper.dispose();
3274
3599
  writer = null;
3275
3600
  sweeper = null;
3276
- auditDir = "";
3277
3601
  }
3278
3602
 
3279
3603
  // src/billing/billingRuntime.ts
@@ -3675,7 +3999,7 @@ function sealPack(bundleJson, passphrase) {
3675
3999
  cipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
3676
4000
  const ciphertext = Buffer.concat([cipher.update(bundleJson, "utf8"), cipher.final()]);
3677
4001
  const tag = cipher.getAuthTag();
3678
- const header = {
4002
+ const header2 = {
3679
4003
  magic: PACK_MAGIC,
3680
4004
  v: PACK_VERSION,
3681
4005
  kdf: KDF_ALGORITHM,
@@ -3686,7 +4010,7 @@ function sealPack(bundleJson, passphrase) {
3686
4010
  iv: iv.toString("base64"),
3687
4011
  tag: tag.toString("base64")
3688
4012
  };
3689
- return `${PACK_PREFIX}${toB64Url(JSON.stringify(header))}.${ciphertext.toString("base64")}`;
4013
+ return `${PACK_PREFIX}${toB64Url(JSON.stringify(header2))}.${ciphertext.toString("base64")}`;
3690
4014
  }
3691
4015
  function parsePack(packString) {
3692
4016
  if (typeof packString !== "string" || !packString.startsWith(PACK_PREFIX)) {
@@ -3697,28 +4021,28 @@ function parsePack(packString) {
3697
4021
  if (dot < 0) throw new PackAuthError("migration pack is malformed (missing body)");
3698
4022
  const headerB64Url = rest.slice(0, dot);
3699
4023
  const ctB64 = rest.slice(dot + 1);
3700
- let header;
4024
+ let header2;
3701
4025
  try {
3702
- header = JSON.parse(fromB64Url(headerB64Url));
4026
+ header2 = JSON.parse(fromB64Url(headerB64Url));
3703
4027
  } catch {
3704
4028
  throw new PackAuthError("migration pack is malformed (unreadable header)");
3705
4029
  }
3706
- 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") {
4030
+ 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") {
3707
4031
  throw new PackAuthError("migration pack is malformed (unsupported header)");
3708
4032
  }
3709
4033
  const ciphertext = Buffer.from(ctB64, "base64");
3710
- return { header, ciphertext };
4034
+ return { header: header2, ciphertext };
3711
4035
  }
3712
4036
  function openPack(packString, passphrase) {
3713
4037
  assertPassphraseStrength(passphrase);
3714
- const { header, ciphertext } = parsePack(packString);
3715
- const salt = Buffer.from(header.salt, "base64");
3716
- const iv = Buffer.from(header.iv, "base64");
3717
- const tag = Buffer.from(header.tag, "base64");
4038
+ const { header: header2, ciphertext } = parsePack(packString);
4039
+ const salt = Buffer.from(header2.salt, "base64");
4040
+ const iv = Buffer.from(header2.iv, "base64");
4041
+ const tag = Buffer.from(header2.tag, "base64");
3718
4042
  if (iv.length !== IV_BYTES2 || tag.length !== TAG_BYTES2) {
3719
4043
  throw new PackAuthError("migration pack is malformed (invalid iv/tag length)");
3720
4044
  }
3721
- const key = deriveKey(passphrase, salt, header.N, header.r, header.p);
4045
+ const key = deriveKey(passphrase, salt, header2.N, header2.r, header2.p);
3722
4046
  const decipher = (0, import_node_crypto8.createDecipheriv)("aes-256-gcm", key, iv);
3723
4047
  decipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
3724
4048
  decipher.setAuthTag(tag);
@@ -4054,10 +4378,10 @@ function writeJson2(res, status, body) {
4054
4378
  res.writeHead(status, { "Content-Type": "application/json" });
4055
4379
  res.end(JSON.stringify(body));
4056
4380
  }
4057
- function writeError(res, status, message) {
4381
+ function writeError2(res, status, message) {
4058
4382
  writeJson2(res, status, { error: { type: "account_allowance_error", message } });
4059
4383
  }
4060
- function readJson(req) {
4384
+ function readJson2(req) {
4061
4385
  return new Promise((resolve2, reject) => {
4062
4386
  const chunks = [];
4063
4387
  req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
@@ -4083,10 +4407,10 @@ function allowanceProvider(value) {
4083
4407
  return value === "claude" || value === "codex" ? value : null;
4084
4408
  }
4085
4409
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
4086
- if (!service) return writeError(res, 501, "account allowance service is not available");
4410
+ if (!service) return writeError2(res, 501, "account allowance service is not available");
4087
4411
  if (method === "GET" && rest.length === 1 && rest[0] === "scheduling") {
4088
4412
  if (!service.getSchedulingStatus) {
4089
- return writeError(res, 501, "allowance scheduling diagnostics are not available");
4413
+ return writeError2(res, 501, "allowance scheduling diagnostics are not available");
4090
4414
  }
4091
4415
  return writeJson2(res, 200, { scheduling: service.getSchedulingStatus() });
4092
4416
  }
@@ -4094,30 +4418,32 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
4094
4418
  const params = query(req);
4095
4419
  const pathProvider = rest.length >= 2 ? rest[0] : null;
4096
4420
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
4097
- if (providerId === null) return writeError(res, 400, "providerId must be claude or codex");
4421
+ if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
4098
4422
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
4099
4423
  const allowances = await service.list({ providerId, accountId });
4100
4424
  return writeJson2(res, 200, { allowances });
4101
4425
  }
4102
4426
  if (method === "POST" && rest[0] === "refresh") {
4103
- const body = await readJson(req);
4427
+ const body = await readJson2(req);
4104
4428
  const requestedProvider = allowanceProvider(
4105
4429
  typeof body["providerId"] === "string" ? body["providerId"] : "claude"
4106
4430
  );
4107
4431
  if (requestedProvider !== "claude") {
4108
- return writeError(res, 400, "only Claude allowances support explicit refresh");
4432
+ return writeError2(res, 400, "only Claude allowances support explicit refresh");
4109
4433
  }
4110
4434
  const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
4111
4435
  const allowances = await service.refreshClaude(accountId);
4112
4436
  if (accountId && allowances.length === 0) {
4113
- return writeError(res, 404, `Claude account '${accountId}' not found`);
4437
+ return writeError2(res, 404, `Claude account '${accountId}' not found`);
4114
4438
  }
4115
4439
  return writeJson2(res, 200, { allowances });
4116
4440
  }
4117
- return writeError(res, 405, `method ${method} not allowed on account allowances`);
4441
+ return writeError2(res, 405, `method ${method} not allowed on account allowances`);
4118
4442
  }
4119
4443
 
4120
4444
  // src/admin/adminApi.ts
4445
+ var import_AccountRouteActivity = require("@omnicross/core/pipeline/AccountRouteActivity");
4446
+ var import_ServerOverloadCounter = require("@omnicross/core/pipeline/ServerOverloadCounter");
4121
4447
  function readBody(req) {
4122
4448
  return new Promise((resolve2, reject) => {
4123
4449
  const chunks = [];
@@ -4154,6 +4480,9 @@ function toKeyInfo(row) {
4154
4480
  id: row.id,
4155
4481
  name: row.name,
4156
4482
  keyPrefix: row.keyPrefix,
4483
+ // True only when a reversible `keySecret` envelope was persisted at creation
4484
+ // — gates the UI "view key" eye. Legacy hash-only rows read as absent.
4485
+ revealable: Boolean(row.keySecret),
4157
4486
  enabled: row.enabled,
4158
4487
  createdAt: row.createdAt,
4159
4488
  lastUsedAt: row.lastUsedAt,
@@ -4809,7 +5138,13 @@ function handlePresets(res, method) {
4809
5138
  name: p.name,
4810
5139
  apiFormat: p.apiFormat,
4811
5140
  baseUrl: p.baseUrl,
4812
- models: p.models
5141
+ models: p.models,
5142
+ nameKey: p.nameKey,
5143
+ icon: p.icon,
5144
+ description: p.description,
5145
+ features: p.features,
5146
+ website: p.website,
5147
+ modelsEndpoint: p.modelsEndpoint
4813
5148
  }));
4814
5149
  return writeJson3(res, 200, { presets, excluded });
4815
5150
  }
@@ -4843,12 +5178,27 @@ async function handleKeys(req, res, method, rest, deps) {
4843
5178
  plaintextOnce: created.plaintextOnce
4844
5179
  });
4845
5180
  }
5181
+ if (method === "GET" && rest.length === 2 && rest[1] === "reveal") {
5182
+ const revealed = await deps.keyDb.outboundApiKeysReveal(rest[0]);
5183
+ if (revealed !== null) return writeJson3(res, 200, { key: revealed });
5184
+ const exists = (await deps.keyDb.outboundApiKeysList()).some((r) => r.id === rest[0]);
5185
+ if (!exists) return writeJsonError(res, 404, `key '${rest[0]}' not found`);
5186
+ return writeJsonError(
5187
+ res,
5188
+ 409,
5189
+ `key '${rest[0]}' is not revealable (created before revealable key storage)`
5190
+ );
5191
+ }
4846
5192
  const id = rest[0];
4847
5193
  const action = rest[1];
4848
5194
  if (method === "POST" && id && action === "revoke") {
4849
5195
  const ok = await deps.keyDb.outboundApiKeysRevoke(id);
4850
5196
  return writeJson3(res, ok ? 200 : 404, { ok });
4851
5197
  }
5198
+ if (method === "DELETE" && id && !action) {
5199
+ const ok = await deps.keyDb.outboundApiKeysDelete(id);
5200
+ return writeJson3(res, ok ? 200 : 404, { ok });
5201
+ }
4852
5202
  if (method === "POST" && id && action === "enabled") {
4853
5203
  const body = await readJsonBody3(req);
4854
5204
  const enabled = body["enabled"] === true;
@@ -5025,6 +5375,40 @@ async function handleServer(req, res, method, deps) {
5025
5375
  return writeJsonError(res, 405, `method ${method} not allowed on server`);
5026
5376
  }
5027
5377
  async function handleAccounts(req, res, method, rest, deps) {
5378
+ if (rest[0] === "route-activity" && rest.length === 1) {
5379
+ if (method !== "GET") {
5380
+ return writeJsonError(res, 405, `method ${method} not allowed on account route activity`);
5381
+ }
5382
+ const query2 = requestQuery(req);
5383
+ const parsedLimit = Number(query2.get("limit") ?? "100");
5384
+ const records = (0, import_AccountRouteActivity.getSharedAccountRouteActivity)().list({
5385
+ providerId: query2.get("providerId") ?? void 0,
5386
+ accountId: query2.get("accountId") ?? void 0,
5387
+ sessionKey: query2.get("sessionKey") ?? void 0,
5388
+ limit: Number.isFinite(parsedLimit) ? parsedLimit : 100
5389
+ });
5390
+ return writeJson3(res, 200, {
5391
+ available: true,
5392
+ records,
5393
+ capacity: import_AccountRouteActivity.ACCOUNT_ROUTE_ACTIVITY_LIMIT,
5394
+ collectedAt: Date.now()
5395
+ });
5396
+ }
5397
+ if (rest[0] === "overload-counters" && rest.length === 1) {
5398
+ if (method !== "GET") {
5399
+ return writeJsonError(res, 405, `method ${method} not allowed on overload counters`);
5400
+ }
5401
+ const query2 = requestQuery(req);
5402
+ const entries = (0, import_ServerOverloadCounter.getSharedOverloadCounter)().list({
5403
+ providerId: query2.get("providerId") ?? void 0,
5404
+ accountId: query2.get("accountId") ?? void 0
5405
+ });
5406
+ return writeJson3(res, 200, {
5407
+ available: true,
5408
+ entries,
5409
+ collectedAt: Date.now()
5410
+ });
5411
+ }
5028
5412
  if (rest[0] === "allowances") {
5029
5413
  return handleAccountAllowanceApi(
5030
5414
  req,
@@ -5171,8 +5555,13 @@ async function handleAccounts(req, res, method, rest, deps) {
5171
5555
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
5172
5556
  return writeJsonError(res, 404, `account '${accountId}' not found`);
5173
5557
  }
5174
- const result = await deps.accountProbeService.probeAccount(providerId, accountId);
5175
- return writeJson3(res, 200, { ok: result.ok, marked: result.marked });
5558
+ const result = await deps.accountProbeService.testAccountConnection(providerId, accountId);
5559
+ return writeJson3(res, 200, {
5560
+ ok: result.ok,
5561
+ marked: result.marked,
5562
+ tier: result.tier,
5563
+ model: result.model
5564
+ });
5176
5565
  }
5177
5566
  if (method === "POST" && rest[2] === "label") {
5178
5567
  const accountId = rest[1];
@@ -5281,6 +5670,7 @@ async function handleCli(req, res, method, rest, deps) {
5281
5670
  const result = await handleCliLaunch(cli, body, {
5282
5671
  llmConfig: deps.llmConfig,
5283
5672
  providers,
5673
+ routeLeaseManager: deps.routeLeaseManager,
5284
5674
  opener: deps.cliTerminalOpener,
5285
5675
  probe: deps.cliPathProbe
5286
5676
  });
@@ -5451,7 +5841,7 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
5451
5841
  var import_node_fs7 = require("fs");
5452
5842
  var import_promises = require("fs/promises");
5453
5843
  var import_node_module = require("module");
5454
- var import_node_path7 = __toESM(require("path"), 1);
5844
+ var import_node_path6 = __toESM(require("path"), 1);
5455
5845
  var import_meta = {};
5456
5846
  var CONTENT_TYPES = {
5457
5847
  ".html": "text/html; charset=utf-8",
@@ -5472,13 +5862,13 @@ var CONTENT_TYPES = {
5472
5862
  function resolveUiDist() {
5473
5863
  const fromEnv = process.env["OMNICROSS_UI_DIST"];
5474
5864
  if (fromEnv) {
5475
- return (0, import_node_fs7.existsSync)(import_node_path7.default.join(fromEnv, "index.html")) ? import_node_path7.default.resolve(fromEnv) : null;
5865
+ return (0, import_node_fs7.existsSync)(import_node_path6.default.join(fromEnv, "index.html")) ? import_node_path6.default.resolve(fromEnv) : null;
5476
5866
  }
5477
5867
  try {
5478
5868
  const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
5479
5869
  const pkgJson = req.resolve("@omnicross/ui/package.json");
5480
- const dist = import_node_path7.default.join(import_node_path7.default.dirname(pkgJson), "dist");
5481
- return (0, import_node_fs7.existsSync)(import_node_path7.default.join(dist, "index.html")) ? dist : null;
5870
+ const dist = import_node_path6.default.join(import_node_path6.default.dirname(pkgJson), "dist");
5871
+ return (0, import_node_fs7.existsSync)(import_node_path6.default.join(dist, "index.html")) ? dist : null;
5482
5872
  } catch {
5483
5873
  return null;
5484
5874
  }
@@ -5520,16 +5910,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5520
5910
  res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
5521
5911
  return true;
5522
5912
  }
5523
- const filePath = import_node_path7.default.resolve(uiDist, rel === "" ? "index.html" : rel);
5524
- if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path7.default.sep)) {
5913
+ const filePath = import_node_path6.default.resolve(uiDist, rel === "" ? "index.html" : rel);
5914
+ if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path6.default.sep)) {
5525
5915
  res.writeHead(403, { "Content-Type": "application/json" });
5526
5916
  res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
5527
5917
  return true;
5528
5918
  }
5529
5919
  let target = filePath;
5530
5920
  if (!(0, import_node_fs7.existsSync)(target) || (0, import_node_fs7.statSync)(target).isDirectory()) {
5531
- if (import_node_path7.default.extname(rel) === "") {
5532
- target = import_node_path7.default.join(uiDist, "index.html");
5921
+ if (import_node_path6.default.extname(rel) === "") {
5922
+ target = import_node_path6.default.join(uiDist, "index.html");
5533
5923
  } else {
5534
5924
  res.writeHead(404, { "Content-Type": "application/json" });
5535
5925
  res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
@@ -5537,14 +5927,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5537
5927
  }
5538
5928
  }
5539
5929
  const body = await (0, import_promises.readFile)(target);
5540
- const type = CONTENT_TYPES[import_node_path7.default.extname(target).toLowerCase()] ?? "application/octet-stream";
5930
+ const type = CONTENT_TYPES[import_node_path6.default.extname(target).toLowerCase()] ?? "application/octet-stream";
5541
5931
  res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
5542
5932
  res.end(req.method === "HEAD" ? void 0 : body);
5543
5933
  return true;
5544
5934
  }
5545
5935
 
5546
5936
  // src/admin/version.ts
5547
- var DAEMON_VERSION = true ? "0.1.6" : "0.0.0-dev";
5937
+ var DAEMON_VERSION = true ? "0.1.8" : "0.0.0-dev";
5548
5938
 
5549
5939
  // src/admin/AdminServer.ts
5550
5940
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -5652,6 +6042,10 @@ var AdminServer = class {
5652
6042
  handleAuditQuery(req, res, this.deps.auditReader);
5653
6043
  return;
5654
6044
  }
6045
+ if (path2 === "/admin/api/audit/stats" && (req.method === "GET" || req.method === "HEAD")) {
6046
+ await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
6047
+ return;
6048
+ }
5655
6049
  if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
5656
6050
  handleBillingStatus(res, this.deps.billingStatusReader);
5657
6051
  return;
@@ -5660,6 +6054,10 @@ var AdminServer = class {
5660
6054
  await handleWebhookTest(req, res);
5661
6055
  return;
5662
6056
  }
6057
+ if (path2 === "/admin/api/route-leases" || path2.startsWith("/admin/api/route-leases/")) {
6058
+ await handleRouteLeaseApi(req, res, path2, this.deps);
6059
+ return;
6060
+ }
5663
6061
  if (path2.startsWith("/admin/api/")) {
5664
6062
  await handleAdminApi(req, res, path2, this.deps);
5665
6063
  return;
@@ -5671,8 +6069,8 @@ var AdminServer = class {
5671
6069
  }
5672
6070
  /** Constant-time bearer/header check against the configured token. */
5673
6071
  isAuthorized(req, token) {
5674
- const header = req.headers["authorization"];
5675
- const bearer = typeof header === "string" && header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : void 0;
6072
+ const header2 = req.headers["authorization"];
6073
+ const bearer = typeof header2 === "string" && header2.startsWith("Bearer ") ? header2.slice("Bearer ".length).trim() : void 0;
5676
6074
  const xToken = req.headers["x-admin-token"];
5677
6075
  const presented = bearer ?? (typeof xToken === "string" ? xToken.trim() : void 0);
5678
6076
  return constantTimeEquals(presented, token);
@@ -5768,20 +6166,36 @@ var OAuthSessionStore = class {
5768
6166
  return sessionId;
5769
6167
  }
5770
6168
  /**
5771
- * SINGLE-USE consume: return + delete the session for `sessionId`, or `null`
5772
- * when it is unknown, already used, or past its TTL (in which case it is
5773
- * dropped). A `null` return means the completer must reject (no exchange, no
5774
- * write).
6169
+ * NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
6170
+ * it is unknown, already consumed, or past its TTL (an expired entry is
6171
+ * dropped here). A `null` return means the completer must reject (no
6172
+ * exchange, no write).
6173
+ *
6174
+ * Deliberately NOT a consume: the completer peeks, runs the token exchange,
6175
+ * and only {@link consume}s once a token has actually been minted. Consuming
6176
+ * up-front burned the session on EVERY failed exchange (a mistyped/expired
6177
+ * pasted code, a proxy hiccup), so the user's natural retry hit
6178
+ * "session is unknown, expired, or already used" and the login became
6179
+ * unrecoverable without restarting the whole flow.
5775
6180
  */
5776
- take(sessionId) {
6181
+ peek(sessionId) {
5777
6182
  this.sweep();
5778
6183
  const session = this.sessions.get(sessionId);
5779
6184
  if (!session) return null;
5780
- this.sessions.delete(sessionId);
5781
- if (Date.now() - session.createdAt > this.ttlMs) return null;
6185
+ if (Date.now() - session.createdAt > this.ttlMs) {
6186
+ this.sessions.delete(sessionId);
6187
+ return null;
6188
+ }
5782
6189
  return session;
5783
6190
  }
5784
- /** Drop every session past its TTL. Called on each put/take. */
6191
+ /**
6192
+ * SINGLE-USE burn: drop the session so the same `sessionId` can never be
6193
+ * completed twice. Called ONLY after a successful token exchange.
6194
+ */
6195
+ consume(sessionId) {
6196
+ this.sessions.delete(sessionId);
6197
+ }
6198
+ /** Drop every session past its TTL. Called on each put/peek. */
5785
6199
  sweep() {
5786
6200
  const now = Date.now();
5787
6201
  for (const [id, session] of this.sessions) {
@@ -5796,6 +6210,10 @@ var LOOPBACK_HOST = "127.0.0.1";
5796
6210
  var LOOPBACK_PORT = 1455;
5797
6211
  var CALLBACK_PATH = "/auth/callback";
5798
6212
  var DEFAULT_TIMEOUT_MS = 5 * 6e4;
6213
+ var HTML_HEADERS = {
6214
+ "Content-Type": "text/html",
6215
+ Connection: "close"
6216
+ };
5799
6217
  function pageHtml(message) {
5800
6218
  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>`;
5801
6219
  }
@@ -5806,30 +6224,31 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
5806
6224
  if (settled) return;
5807
6225
  settled = true;
5808
6226
  clearTimeout(timer);
5809
- server2.close(() => fn());
6227
+ fn();
6228
+ server2.close();
5810
6229
  };
5811
6230
  const server = (0, import_node_http3.createServer)((req, res) => {
5812
6231
  const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
5813
6232
  if (url.pathname !== CALLBACK_PATH) {
5814
- res.writeHead(404, { "Content-Type": "text/html" });
6233
+ res.writeHead(404, HTML_HEADERS);
5815
6234
  res.end(pageHtml("Not found"));
5816
6235
  return;
5817
6236
  }
5818
6237
  const code = url.searchParams.get("code");
5819
6238
  const state = url.searchParams.get("state");
5820
6239
  if (!code) {
5821
- res.writeHead(400, { "Content-Type": "text/html" });
6240
+ res.writeHead(400, HTML_HEADERS);
5822
6241
  res.end(pageHtml("Login failed: missing authorization code."));
5823
6242
  finish(server, () => reject(new Error("login: callback did not include an authorization code")));
5824
6243
  return;
5825
6244
  }
5826
6245
  if (state !== expectedState) {
5827
- res.writeHead(400, { "Content-Type": "text/html" });
6246
+ res.writeHead(400, HTML_HEADERS);
5828
6247
  res.end(pageHtml("Login failed: state mismatch."));
5829
6248
  finish(server, () => reject(new Error("login: callback state did not match (possible CSRF) \u2014 aborting")));
5830
6249
  return;
5831
6250
  }
5832
- res.writeHead(200, { "Content-Type": "text/html" });
6251
+ res.writeHead(200, HTML_HEADERS);
5833
6252
  res.end(pageHtml("Login complete."));
5834
6253
  finish(server, () => resolve2(code));
5835
6254
  });
@@ -5926,30 +6345,30 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
5926
6345
  }
5927
6346
 
5928
6347
  // src/commands/paths.ts
5929
- var import_node_path8 = require("path");
6348
+ var import_node_path7 = require("path");
5930
6349
  function defaultVouchersPath(configPath) {
5931
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "vouchers.json");
6350
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "vouchers.json");
5932
6351
  }
5933
6352
  function defaultIntegrationsPath(configPath) {
5934
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "integrations.json");
6353
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "integrations.json");
5935
6354
  }
5936
6355
  function defaultPricingPath(configPath) {
5937
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "pricing.json");
6356
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "pricing.json");
5938
6357
  }
5939
6358
  function defaultPricingRefreshStatePath(configPath) {
5940
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "pricing-refresh.json");
6359
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "pricing-refresh.json");
5941
6360
  }
5942
6361
  function defaultAccountAllowancePath(configPath) {
5943
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "allowance-cache.json");
6362
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "allowance-cache.json");
5944
6363
  }
5945
6364
  function defaultUsageEventsPath(configPath) {
5946
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "usage-events.jsonl");
6365
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "usage-events.jsonl");
5947
6366
  }
5948
6367
  function defaultAuditDir(configPath) {
5949
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "audit");
6368
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "audit");
5950
6369
  }
5951
6370
  function defaultBillingDir(configPath) {
5952
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "billing");
6371
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "billing");
5953
6372
  }
5954
6373
 
5955
6374
  // src/ports/ConfigFileProviderConfigSource.ts
@@ -6342,8 +6761,12 @@ var JsonlUsageEventStore = class {
6342
6761
  reasoningTokens: 0,
6343
6762
  costUsd: 0,
6344
6763
  costSavedByCacheUsd: 0,
6345
- eventCount: 0
6764
+ eventCount: 0,
6765
+ cacheEligibleEventCount: 0,
6766
+ coldCacheEventCount: 0,
6767
+ medianCacheHitRate: null
6346
6768
  };
6769
+ const perEventHitRates = [];
6347
6770
  for (const row of this.readRows(range)) {
6348
6771
  totals.inputTokens += row.inputTokens;
6349
6772
  totals.outputTokens += row.outputTokens;
@@ -6353,7 +6776,14 @@ var JsonlUsageEventStore = class {
6353
6776
  totals.costUsd += row.costUsd;
6354
6777
  totals.costSavedByCacheUsd += row.costSavedByCacheUsd;
6355
6778
  totals.eventCount += 1;
6779
+ const promptSideTokens = row.inputTokens + row.cacheReadTokens + row.cacheCreationTokens;
6780
+ if (promptSideTokens > 0) {
6781
+ totals.cacheEligibleEventCount += 1;
6782
+ if (row.cacheReadTokens === 0) totals.coldCacheEventCount += 1;
6783
+ perEventHitRates.push(row.cacheReadTokens / promptSideTokens);
6784
+ }
6356
6785
  }
6786
+ totals.medianCacheHitRate = median(perEventHitRates);
6357
6787
  return totals;
6358
6788
  }
6359
6789
  async getByModel(range) {
@@ -6587,6 +7017,15 @@ var NUMERIC_FIELDS = [
6587
7017
  ];
6588
7018
  var NULLABLE_STRING_FIELDS = ["messageId", "parentMessageId", "sessionId", "apiKeyId"];
6589
7019
  var isStringOrNull = (v) => v === null || typeof v === "string";
7020
+ var CACHE_KEY_SOURCES = /* @__PURE__ */ new Set([
7021
+ "client",
7022
+ "session-header",
7023
+ "thread-header",
7024
+ "body-session-id",
7025
+ "body-thread-id",
7026
+ "content-fingerprint",
7027
+ "none"
7028
+ ]);
6590
7029
  function isUsageEventRecord(parsed) {
6591
7030
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
6592
7031
  const r = parsed;
@@ -6594,6 +7033,10 @@ function isUsageEventRecord(parsed) {
6594
7033
  if (typeof r["providerId"] !== "string") return false;
6595
7034
  if (typeof r["model"] !== "string") return false;
6596
7035
  if (typeof r["engineOrigin"] !== "string") return false;
7036
+ if (r["cacheKeySource"] !== void 0 && (typeof r["cacheKeySource"] !== "string" || !CACHE_KEY_SOURCES.has(r["cacheKeySource"]))) return false;
7037
+ if (r["cacheKeyInjected"] !== void 0 && typeof r["cacheKeyInjected"] !== "boolean") {
7038
+ return false;
7039
+ }
6597
7040
  for (const f of NULLABLE_STRING_FIELDS) {
6598
7041
  if (!isStringOrNull(r[f])) return false;
6599
7042
  }
@@ -6603,14 +7046,30 @@ function isUsageEventRecord(parsed) {
6603
7046
  }
6604
7047
  return true;
6605
7048
  }
7049
+ function median(values) {
7050
+ if (values.length === 0) return null;
7051
+ values.sort((a, b) => a - b);
7052
+ const middle = Math.floor(values.length / 2);
7053
+ return values.length % 2 === 1 ? values[middle] : (values[middle - 1] + values[middle]) / 2;
7054
+ }
6606
7055
 
6607
7056
  // src/ports/JsonOutboundKeyDb.ts
6608
7057
  var import_node_fs11 = require("fs");
6609
7058
  var JsonOutboundKeyDb = class {
6610
- constructor(keysPath) {
7059
+ /**
7060
+ * @param secretBox OPTIONAL reversible-secret codec. When present, a created
7061
+ * key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
7062
+ * operator "view key" affordance via `outboundApiKeysReveal`). When absent the
7063
+ * store stays hash-only (byte-identical to the legacy behavior) and reveal
7064
+ * always returns `null`. Existing 1-arg call sites (tests, lightweight
7065
+ * embedders) keep working.
7066
+ */
7067
+ constructor(keysPath, secretBox3) {
6611
7068
  this.keysPath = keysPath;
7069
+ this.secretBox = secretBox3;
6612
7070
  }
6613
7071
  keysPath;
7072
+ secretBox;
6614
7073
  async outboundApiKeysList() {
6615
7074
  return this.readRows();
6616
7075
  }
@@ -6636,10 +7095,27 @@ var JsonOutboundKeyDb = class {
6636
7095
  allowedEndpoints: input.allowedEndpoints,
6637
7096
  loopbackOnly: input.loopbackOnly
6638
7097
  };
7098
+ if (input.plaintext && this.secretBox) {
7099
+ row.keySecret = this.secretBox.encrypt(input.plaintext);
7100
+ }
6639
7101
  rows.push(row);
6640
7102
  this.writeRows(rows);
6641
7103
  return row;
6642
7104
  }
7105
+ async outboundApiKeysReveal(id) {
7106
+ const rows = this.readRows();
7107
+ const row = rows.find((r) => r.id === id);
7108
+ if (!row || !row.keySecret || !this.secretBox) return null;
7109
+ return this.secretBox.decrypt(row.keySecret);
7110
+ }
7111
+ async outboundApiKeysDelete(id) {
7112
+ const rows = this.readRows();
7113
+ const idx = rows.findIndex((r) => r.id === id);
7114
+ if (idx < 0) return false;
7115
+ rows.splice(idx, 1);
7116
+ this.writeRows(rows);
7117
+ return true;
7118
+ }
6643
7119
  async outboundApiKeysRevoke(id) {
6644
7120
  return this.mutateRow(id, (row) => {
6645
7121
  if (row.revokedAt !== null) return false;
@@ -7088,7 +7564,7 @@ var JsonVoucherDb = class {
7088
7564
 
7089
7565
  // src/ports/JsonSubscriptionCredentialStore.ts
7090
7566
  var import_node_fs16 = require("fs");
7091
- var import_node_path10 = require("path");
7567
+ var import_node_path9 = require("path");
7092
7568
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
7093
7569
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
7094
7570
  var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -7138,10 +7614,10 @@ function findDuplicateCredentialIds(accounts) {
7138
7614
 
7139
7615
  // src/ports/external-cli-credentials.ts
7140
7616
  var import_node_fs15 = require("fs");
7141
- var import_node_os3 = require("os");
7142
- var import_node_path9 = require("path");
7143
- function externalStorePath(provider, home = (0, import_node_os3.homedir)()) {
7144
- return provider === "claude" ? (0, import_node_path9.join)(home, ".claude", ".credentials.json") : (0, import_node_path9.join)(home, ".codex", "auth.json");
7617
+ var import_node_os4 = require("os");
7618
+ var import_node_path8 = require("path");
7619
+ function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
7620
+ return provider === "claude" ? (0, import_node_path8.join)(home, ".claude", ".credentials.json") : (0, import_node_path8.join)(home, ".codex", "auth.json");
7145
7621
  }
7146
7622
  function decodeJwtExpiryMs(token) {
7147
7623
  try {
@@ -7188,7 +7664,7 @@ function parseCodexTokensEnvelope(raw) {
7188
7664
  }
7189
7665
  return parsed;
7190
7666
  }
7191
- function readExternalCliCredentials(provider, home = (0, import_node_os3.homedir)()) {
7667
+ function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
7192
7668
  const path2 = externalStorePath(provider, home);
7193
7669
  if (!(0, import_node_fs15.existsSync)(path2)) return null;
7194
7670
  let raw;
@@ -7231,9 +7707,15 @@ var JsonSubscriptionCredentialStore = class {
7231
7707
  * TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
7232
7708
  * through {@link fetchUpstream} with the account's `{ providerId, accountId }`
7233
7709
  * ctx so the per-account/provider proxy applies. `@internal` also a test seam.
7710
+ *
7711
+ * `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
7712
+ * receives a fresh access/refresh token pair. Carrying a `providerId` opts the
7713
+ * call into the upstream trace (so a failing refresh is diagnosable), and the
7714
+ * trace captures bodies verbatim — without this flag every refresh would write
7715
+ * a plaintext token pair into `upstream-trace.jsonl`.
7234
7716
  */
7235
7717
  buildRefreshFetch(providerId, accountId) {
7236
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId }));
7718
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
7237
7719
  }
7238
7720
  /**
7239
7721
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -7758,7 +8240,7 @@ var JsonSubscriptionCredentialStore = class {
7758
8240
  * `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
7759
8241
  * write incl. child 4's future refresh writes lands encrypted. */
7760
8242
  persist(config) {
7761
- (0, import_node_fs16.mkdirSync)((0, import_node_path10.dirname)(this.tokensPath), { recursive: true });
8243
+ (0, import_node_fs16.mkdirSync)((0, import_node_path9.dirname)(this.tokensPath), { recursive: true });
7762
8244
  const encrypted = encryptTokens(config, this.box);
7763
8245
  (0, import_node_fs16.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
7764
8246
  }
@@ -7793,6 +8275,124 @@ var JsonSubscriptionCredentialStore = class {
7793
8275
  // src/AccountHealthProbeScheduler.ts
7794
8276
  var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
7795
8277
 
8278
+ // src/probe/CodexGenerationProbe.ts
8279
+ var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
8280
+ var CODEX_GENERATION_PROBE_MODEL = "gpt-5.6-luna";
8281
+ var CODEX_GENERATION_PROBE_URL = "https://chatgpt.com/backend-api/codex/responses";
8282
+ var MAX_STREAM_BYTES = 256 * 1024;
8283
+ var PROBE_INSTRUCTION = "Return exactly PONG and no other text.";
8284
+ function buildCodexGenerationProbeInit(token, signal) {
8285
+ return {
8286
+ method: "POST",
8287
+ signal,
8288
+ headers: {
8289
+ ...import_codexCliHeaders.DEFAULT_CODEX_CLI_HEADERS,
8290
+ Authorization: `Bearer ${token}`,
8291
+ Accept: (0, import_codexCliHeaders.codexAcceptHeader)(true),
8292
+ "Content-Type": "application/json"
8293
+ },
8294
+ body: JSON.stringify({
8295
+ model: CODEX_GENERATION_PROBE_MODEL,
8296
+ input: [
8297
+ {
8298
+ role: "developer",
8299
+ content: [{ type: "input_text", text: PROBE_INSTRUCTION }]
8300
+ },
8301
+ {
8302
+ role: "user",
8303
+ content: [{ type: "input_text", text: "Connection probe." }]
8304
+ }
8305
+ ],
8306
+ // GPT-5.6 otherwise defaults to medium reasoning. A connectivity probe
8307
+ // needs the lowest-cost path and no tool reasoning.
8308
+ reasoning: { effort: "none" },
8309
+ stream: true,
8310
+ store: false
8311
+ })
8312
+ };
8313
+ }
8314
+ async function readCodexGenerationProbeStream(response) {
8315
+ if (!response.body) return { completed: false, outputChars: 0 };
8316
+ const reader = response.body.getReader();
8317
+ const decoder = new TextDecoder();
8318
+ let buffer = "";
8319
+ let bytes = 0;
8320
+ let outputChars = 0;
8321
+ try {
8322
+ while (true) {
8323
+ const { done, value } = await reader.read();
8324
+ if (done) break;
8325
+ bytes += value.byteLength;
8326
+ if (bytes > MAX_STREAM_BYTES) {
8327
+ await reader.cancel();
8328
+ return { completed: false, outputChars };
8329
+ }
8330
+ buffer += decoder.decode(value, { stream: true });
8331
+ buffer = buffer.replace(/\r\n/g, "\n");
8332
+ let boundary = buffer.indexOf("\n\n");
8333
+ while (boundary >= 0) {
8334
+ const block = buffer.slice(0, boundary);
8335
+ buffer = buffer.slice(boundary + 2);
8336
+ const event = parseSseBlock(block);
8337
+ if (event) {
8338
+ const type = event["type"];
8339
+ if (type === "response.output_text.delta" && typeof event["delta"] === "string") {
8340
+ outputChars += event["delta"].length;
8341
+ } else if (type === "response.output_text.done" && typeof event["text"] === "string") {
8342
+ outputChars = Math.max(outputChars, event["text"].length);
8343
+ } else if (type === "response.failed" || type === "error") {
8344
+ await reader.cancel();
8345
+ return { completed: false, outputChars };
8346
+ } else if (type === "response.completed") {
8347
+ const completedResponse = asRecord(event["response"]);
8348
+ const status = completedResponse?.["status"];
8349
+ outputChars = Math.max(outputChars, countCompletedOutputChars(completedResponse));
8350
+ await reader.cancel();
8351
+ return {
8352
+ completed: (status === void 0 || status === "completed") && outputChars > 0,
8353
+ outputChars
8354
+ };
8355
+ }
8356
+ }
8357
+ boundary = buffer.indexOf("\n\n");
8358
+ }
8359
+ }
8360
+ } catch {
8361
+ return { completed: false, outputChars };
8362
+ } finally {
8363
+ reader.releaseLock();
8364
+ }
8365
+ return { completed: false, outputChars };
8366
+ }
8367
+ function parseSseBlock(block) {
8368
+ const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
8369
+ if (!data || data === "[DONE]") return null;
8370
+ try {
8371
+ return JSON.parse(data);
8372
+ } catch {
8373
+ return null;
8374
+ }
8375
+ }
8376
+ function asRecord(value) {
8377
+ return value !== null && typeof value === "object" ? value : void 0;
8378
+ }
8379
+ function countCompletedOutputChars(response) {
8380
+ const output = response?.["output"];
8381
+ if (!Array.isArray(output)) return 0;
8382
+ let chars = 0;
8383
+ for (const item of output) {
8384
+ const content = asRecord(item)?.["content"];
8385
+ if (!Array.isArray(content)) continue;
8386
+ for (const part of content) {
8387
+ const record = asRecord(part);
8388
+ if (record?.["type"] === "output_text" && typeof record["text"] === "string") {
8389
+ chars += record["text"].length;
8390
+ }
8391
+ }
8392
+ }
8393
+ return chars;
8394
+ }
8395
+
7796
8396
  // src/probe/ProbeStrategy.ts
7797
8397
  var PROVIDER_PROBE_PLANS = {
7798
8398
  claude: {
@@ -7920,17 +8520,17 @@ var AccountHealthProbeScheduler = class {
7920
8520
  }
7921
8521
  if (readThrew) {
7922
8522
  this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
7923
- return { ok: false, marked: false };
8523
+ return { ok: false, marked: false, tier: "local" };
7924
8524
  }
7925
8525
  if (!token) {
7926
8526
  this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
7927
8527
  this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
7928
- return { ok: false, marked: true };
8528
+ return { ok: false, marked: true, tier: "local" };
7929
8529
  }
7930
8530
  const plan = this.planFor(providerId);
7931
8531
  if (plan.kind === "local") {
7932
8532
  this.record(providerId, accountId, { ts: now, ok: true, tier: "local" });
7933
- return { ok: true, marked: false };
8533
+ return { ok: true, marked: false, tier: "local" };
7934
8534
  }
7935
8535
  const start = this.now();
7936
8536
  let status = null;
@@ -7955,7 +8555,60 @@ var AccountHealthProbeScheduler = class {
7955
8555
  latencyMs,
7956
8556
  tier: "upstream"
7957
8557
  });
7958
- return { ok: status !== null && status < 400, marked };
8558
+ return { ok: status !== null && status < 400, marked, tier: "upstream" };
8559
+ }
8560
+ /**
8561
+ * Manual connection test. Codex performs a real, quota-consuming generation;
8562
+ * every other provider keeps its existing cheap probe. Scheduled sweeps never
8563
+ * call this method, so they remain non-billable.
8564
+ */
8565
+ async testAccountConnection(providerId, accountId) {
8566
+ if (providerId !== "codex") return this.probeAccount(providerId, accountId);
8567
+ const now = this.now();
8568
+ let token;
8569
+ try {
8570
+ token = await this.store.getAccessTokenForAccount(providerId, accountId);
8571
+ } catch {
8572
+ this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
8573
+ return { ok: false, marked: false, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8574
+ }
8575
+ if (!token) {
8576
+ this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
8577
+ this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
8578
+ return { ok: false, marked: true, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8579
+ }
8580
+ const startedAt = this.now();
8581
+ let attempt = await this.runCodexGenerationAttempt(accountId, token);
8582
+ if (attempt.status === 401 && this.store.refreshAccountToken) {
8583
+ try {
8584
+ if (await this.store.refreshAccountToken(providerId, accountId)) {
8585
+ const refreshed = await this.store.getAccessTokenForAccount(providerId, accountId);
8586
+ if (refreshed) attempt = await this.runCodexGenerationAttempt(accountId, refreshed);
8587
+ }
8588
+ } catch {
8589
+ }
8590
+ }
8591
+ const latencyMs = this.now() - startedAt;
8592
+ const ok = attempt.status !== null && attempt.status >= 200 && attempt.status < 300 && attempt.completed;
8593
+ let marked = false;
8594
+ if (ok) {
8595
+ this.health.clearTransientMark(providerId, accountId);
8596
+ } else if (attempt.status === 401 || attempt.status === 403) {
8597
+ marked = this.applyOutcome(providerId, accountId, attempt.status, attempt.bodyText, now);
8598
+ }
8599
+ this.record(providerId, accountId, {
8600
+ ts: now,
8601
+ ok,
8602
+ status: attempt.status,
8603
+ latencyMs,
8604
+ tier: "generation"
8605
+ });
8606
+ return {
8607
+ ok,
8608
+ marked,
8609
+ tier: "generation",
8610
+ model: CODEX_GENERATION_PROBE_MODEL
8611
+ };
7959
8612
  }
7960
8613
  /** Per-account rolling history for the authed admin surface (design D5). */
7961
8614
  getAllHistory() {
@@ -8012,6 +8665,24 @@ var AccountHealthProbeScheduler = class {
8012
8665
  return "";
8013
8666
  }
8014
8667
  }
8668
+ async runCodexGenerationAttempt(accountId, token) {
8669
+ try {
8670
+ const timeoutMs = Math.max(this.config.timeoutMs, 15e3);
8671
+ const response = await this.fetchImpl(
8672
+ CODEX_GENERATION_PROBE_URL,
8673
+ buildCodexGenerationProbeInit(token, AbortSignal.timeout(timeoutMs)),
8674
+ { providerId: "codex", accountId, redactBodies: true }
8675
+ );
8676
+ if (response.status < 200 || response.status >= 300) {
8677
+ const bodyText = response.status === 403 ? await this.readBounded(response) : void 0;
8678
+ return { status: response.status, completed: false, bodyText };
8679
+ }
8680
+ const stream = await readCodexGenerationProbeStream(response);
8681
+ return { status: response.status, completed: stream.completed };
8682
+ } catch {
8683
+ return { status: null, completed: false };
8684
+ }
8685
+ }
8015
8686
  key(providerId, accountId) {
8016
8687
  return `${providerId}${KEY_SEP}${accountId}`;
8017
8688
  }
@@ -8107,7 +8778,7 @@ var AccountHealthSweeper = class {
8107
8778
  };
8108
8779
 
8109
8780
  // src/audit/AuditPruneSweeper.ts
8110
- var import_node_fs17 = require("fs");
8781
+ var import_node_fs18 = require("fs");
8111
8782
  var import_node_path11 = require("path");
8112
8783
 
8113
8784
  // src/audit/auditFiles.ts
@@ -8130,12 +8801,206 @@ function auditFileDateMs(fileName) {
8130
8801
  return d.getTime();
8131
8802
  }
8132
8803
 
8804
+ // src/audit/auditStats.ts
8805
+ var import_node_fs17 = require("fs");
8806
+ var import_node_path10 = require("path");
8807
+ var SIDECAR_VERSION = 1;
8808
+ var META_PREFIX_BYTES = 64 * 1024;
8809
+ var READ_CHUNK_BYTES = 4 * 1024 * 1024;
8810
+ function auditStatsFileName(auditFile) {
8811
+ return auditFile.replace(/\.jsonl$/, ".stats.json");
8812
+ }
8813
+ function readPersisted(path2) {
8814
+ if (!(0, import_node_fs17.existsSync)(path2)) return null;
8815
+ try {
8816
+ const value = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
8817
+ 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)) {
8818
+ return null;
8819
+ }
8820
+ return value;
8821
+ } catch {
8822
+ return null;
8823
+ }
8824
+ }
8825
+ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
8826
+ const statsPath = (0, import_node_path10.join)((0, import_node_path10.dirname)(auditPath), auditStatsFileName((0, import_node_path10.basename)(auditPath)));
8827
+ const previous = auditBytesBefore === 0 ? {
8828
+ version: SIDECAR_VERSION,
8829
+ auditBytes: 0,
8830
+ requestCount: 0,
8831
+ errorCount: 0,
8832
+ complete: true,
8833
+ minTs: null,
8834
+ maxTs: null
8835
+ } : readPersisted(statsPath);
8836
+ if (!previous || !previous.complete || previous.auditBytes !== auditBytesBefore) return;
8837
+ const next = {
8838
+ version: SIDECAR_VERSION,
8839
+ auditBytes: auditBytesAfter,
8840
+ requestCount: previous.requestCount + 1,
8841
+ errorCount: previous.errorCount + (record.status >= 400 || Boolean(record.error) ? 1 : 0),
8842
+ complete: true,
8843
+ minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
8844
+ maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
8845
+ };
8846
+ (0, import_node_fs17.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
8847
+ }
8848
+ function queryCovers(stats, from, to) {
8849
+ return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
8850
+ }
8851
+ function fileOverlaps(file, from, to) {
8852
+ const start = auditFileDateMs(file);
8853
+ if (start === null) return false;
8854
+ const date = new Date(start);
8855
+ const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
8856
+ return end > from && start <= to;
8857
+ }
8858
+ function parseMetadataPrefix(prefix, prefixTruncated) {
8859
+ const text = prefix.toString("utf8");
8860
+ const tsMatch = /(?:^|,)"ts":(-?\d+)/.exec(text);
8861
+ const statusMatch = /(?:^|,)"status":(-?\d+)/.exec(text);
8862
+ const errorMatch = /(?:^|,)"error":"((?:\\.|[^"\\])*)"/.exec(text);
8863
+ const bodyStarted = /,(?:"requestBody"|"responseBody"):/.test(text);
8864
+ return {
8865
+ ts: tsMatch ? Number(tsMatch[1]) : void 0,
8866
+ status: statusMatch ? Number(statusMatch[1]) : void 0,
8867
+ hasError: Boolean(errorMatch?.[1]),
8868
+ complete: Boolean(tsMatch && statusMatch && (!prefixTruncated || bodyStarted))
8869
+ };
8870
+ }
8871
+ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
8872
+ let requestCount = 0;
8873
+ let errorCount = 0;
8874
+ let filteredRequestCount = 0;
8875
+ let filteredErrorCount = 0;
8876
+ let minTs = null;
8877
+ let maxTs = null;
8878
+ let complete = true;
8879
+ let prefixParts = [];
8880
+ let prefixBytes = 0;
8881
+ let prefixTruncated = false;
8882
+ const consumeLine = () => {
8883
+ if (prefixBytes === 0 && !prefixTruncated) return;
8884
+ const prefix = Buffer.concat(prefixParts, prefixBytes);
8885
+ const metadata = parseMetadataPrefix(prefix, prefixTruncated);
8886
+ if (!metadata.complete || metadata.ts === void 0 || metadata.status === void 0) {
8887
+ complete = false;
8888
+ } else {
8889
+ requestCount += 1;
8890
+ const isError = metadata.status >= 400 || metadata.hasError;
8891
+ if (isError) errorCount += 1;
8892
+ minTs = minTs === null ? metadata.ts : Math.min(minTs, metadata.ts);
8893
+ maxTs = maxTs === null ? metadata.ts : Math.max(maxTs, metadata.ts);
8894
+ if (metadata.ts >= from && metadata.ts <= to) {
8895
+ filteredRequestCount += 1;
8896
+ if (isError) filteredErrorCount += 1;
8897
+ }
8898
+ }
8899
+ prefixParts = [];
8900
+ prefixBytes = 0;
8901
+ prefixTruncated = false;
8902
+ };
8903
+ if (auditBytes > startByte) {
8904
+ const stream = (0, import_node_fs17.createReadStream)(auditPath, {
8905
+ start: startByte,
8906
+ end: auditBytes - 1,
8907
+ highWaterMark: READ_CHUNK_BYTES
8908
+ });
8909
+ for await (const value of stream) {
8910
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
8911
+ let offset = 0;
8912
+ while (offset < chunk.length) {
8913
+ const newline = chunk.indexOf(10, offset);
8914
+ const end = newline === -1 ? chunk.length : newline;
8915
+ if (prefixBytes < META_PREFIX_BYTES) {
8916
+ const retained = Math.min(META_PREFIX_BYTES - prefixBytes, end - offset);
8917
+ if (retained > 0) {
8918
+ prefixParts.push(Buffer.from(chunk.subarray(offset, offset + retained)));
8919
+ prefixBytes += retained;
8920
+ }
8921
+ if (retained < end - offset) prefixTruncated = true;
8922
+ } else if (end > offset) {
8923
+ prefixTruncated = true;
8924
+ }
8925
+ if (newline === -1) break;
8926
+ consumeLine();
8927
+ offset = newline + 1;
8928
+ }
8929
+ }
8930
+ }
8931
+ if (prefixBytes > 0 || prefixTruncated) complete = false;
8932
+ return {
8933
+ all: {
8934
+ version: SIDECAR_VERSION,
8935
+ auditBytes,
8936
+ requestCount,
8937
+ errorCount,
8938
+ complete,
8939
+ minTs,
8940
+ maxTs
8941
+ },
8942
+ filtered: { requestCount: filteredRequestCount, errorCount: filteredErrorCount, complete }
8943
+ };
8944
+ }
8945
+ function mergePersistedStats(previous, appended) {
8946
+ return {
8947
+ version: SIDECAR_VERSION,
8948
+ auditBytes: appended.auditBytes,
8949
+ requestCount: previous.requestCount + appended.requestCount,
8950
+ errorCount: previous.errorCount + appended.errorCount,
8951
+ complete: previous.complete && appended.complete,
8952
+ minTs: previous.minTs === null ? appended.minTs : appended.minTs === null ? previous.minTs : Math.min(previous.minTs, appended.minTs),
8953
+ maxTs: previous.maxTs === null ? appended.maxTs : appended.maxTs === null ? previous.maxTs : Math.max(previous.maxTs, appended.maxTs)
8954
+ };
8955
+ }
8956
+ async function readAuditStats(auditDir, query2 = {}) {
8957
+ if (!(0, import_node_fs17.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
8958
+ const from = typeof query2.from === "number" ? query2.from : -Infinity;
8959
+ const to = typeof query2.to === "number" ? query2.to : Infinity;
8960
+ let files;
8961
+ try {
8962
+ files = (0, import_node_fs17.readdirSync)(auditDir).filter((file) => AUDIT_FILE_RE.test(file) && fileOverlaps(file, from, to)).sort();
8963
+ } catch {
8964
+ return { requestCount: 0, errorCount: 0, complete: false };
8965
+ }
8966
+ const total = { requestCount: 0, errorCount: 0, complete: true };
8967
+ for (const file of files) {
8968
+ const auditPath = (0, import_node_path10.join)(auditDir, file);
8969
+ try {
8970
+ const auditBytes = (0, import_node_fs17.statSync)(auditPath).size;
8971
+ const statsPath = (0, import_node_path10.join)(auditDir, auditStatsFileName(file));
8972
+ const persisted = readPersisted(statsPath);
8973
+ if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
8974
+ total.requestCount += persisted.requestCount;
8975
+ total.errorCount += persisted.errorCount;
8976
+ continue;
8977
+ }
8978
+ const resumable = persisted && persisted.complete && persisted.auditBytes < auditBytes && queryCovers(persisted, from, to) ? persisted : null;
8979
+ const scanned = await scanAuditFile(
8980
+ auditPath,
8981
+ resumable?.auditBytes ?? 0,
8982
+ auditBytes,
8983
+ from,
8984
+ to
8985
+ );
8986
+ total.requestCount += scanned.filtered.requestCount + (resumable?.requestCount ?? 0);
8987
+ total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
8988
+ total.complete = total.complete && scanned.filtered.complete;
8989
+ const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
8990
+ if (current.complete) (0, import_node_fs17.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
8991
+ } catch {
8992
+ total.complete = false;
8993
+ }
8994
+ }
8995
+ return total;
8996
+ }
8997
+
8133
8998
  // src/audit/AuditPruneSweeper.ts
8134
8999
  var DAY_MS = 24 * 60 * 6e4;
8135
9000
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
8136
9001
  var AuditPruneSweeper = class {
8137
- constructor(auditDir2, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
8138
- this.auditDir = auditDir2;
9002
+ constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
9003
+ this.auditDir = auditDir;
8139
9004
  this.logger = logger;
8140
9005
  this.config = config;
8141
9006
  this.intervalMs = intervalMs;
@@ -8182,17 +9047,19 @@ var AuditPruneSweeper = class {
8182
9047
  if (!this.config.enabled || this.sweeping) return 0;
8183
9048
  this.sweeping = true;
8184
9049
  try {
8185
- if (!(0, import_node_fs17.existsSync)(this.auditDir)) return 0;
9050
+ if (!(0, import_node_fs18.existsSync)(this.auditDir)) return 0;
8186
9051
  const today = new Date(this.now());
8187
9052
  const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
8188
9053
  const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
8189
9054
  let removed = 0;
8190
- for (const file of (0, import_node_fs17.readdirSync)(this.auditDir)) {
9055
+ for (const file of (0, import_node_fs18.readdirSync)(this.auditDir)) {
8191
9056
  const dateMs = auditFileDateMs(file);
8192
9057
  if (dateMs === null || dateMs >= cutoff) continue;
8193
9058
  try {
8194
- (0, import_node_fs17.unlinkSync)((0, import_node_path11.join)(this.auditDir, file));
9059
+ (0, import_node_fs18.unlinkSync)((0, import_node_path11.join)(this.auditDir, file));
8195
9060
  removed += 1;
9061
+ const statsPath = (0, import_node_path11.join)(this.auditDir, auditStatsFileName(file));
9062
+ if ((0, import_node_fs18.existsSync)(statsPath)) (0, import_node_fs18.unlinkSync)(statsPath);
8196
9063
  } catch (error) {
8197
9064
  this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
8198
9065
  file,
@@ -8214,15 +9081,15 @@ var AuditPruneSweeper = class {
8214
9081
  };
8215
9082
 
8216
9083
  // src/audit/auditReader.ts
8217
- var import_node_fs18 = require("fs");
9084
+ var import_node_fs19 = require("fs");
8218
9085
  var import_node_path12 = require("path");
8219
9086
  var DEFAULT_LIMIT = 200;
8220
9087
  var MAX_LIMIT = 2e3;
8221
- function readAuditRecords(auditDir2, query2 = {}) {
8222
- if (!(0, import_node_fs18.existsSync)(auditDir2)) return [];
9088
+ function readAuditRecords(auditDir, query2 = {}) {
9089
+ if (!(0, import_node_fs19.existsSync)(auditDir)) return [];
8223
9090
  let files;
8224
9091
  try {
8225
- files = (0, import_node_fs18.readdirSync)(auditDir2).filter((f) => AUDIT_FILE_RE.test(f));
9092
+ files = (0, import_node_fs19.readdirSync)(auditDir).filter((f) => AUDIT_FILE_RE.test(f));
8226
9093
  } catch {
8227
9094
  return [];
8228
9095
  }
@@ -8233,7 +9100,7 @@ function readAuditRecords(auditDir2, query2 = {}) {
8233
9100
  for (const file of files.sort().reverse()) {
8234
9101
  let raw;
8235
9102
  try {
8236
- raw = (0, import_node_fs18.readFileSync)((0, import_node_path12.join)(auditDir2, file), "utf8");
9103
+ raw = (0, import_node_fs19.readFileSync)((0, import_node_path12.join)(auditDir, file), "utf8");
8237
9104
  } catch {
8238
9105
  continue;
8239
9106
  }
@@ -8262,11 +9129,11 @@ function isAuditRecord(value) {
8262
9129
  }
8263
9130
 
8264
9131
  // src/audit/AuditWriter.ts
8265
- var import_node_fs19 = require("fs");
9132
+ var import_node_fs20 = require("fs");
8266
9133
  var import_node_path13 = require("path");
8267
9134
  var AuditWriter = class {
8268
- constructor(auditDir2, logger, defer = (fn) => setTimeout(fn, 0)) {
8269
- this.auditDir = auditDir2;
9135
+ constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
9136
+ this.auditDir = auditDir;
8270
9137
  this.logger = logger;
8271
9138
  this.defer = defer;
8272
9139
  }
@@ -8296,16 +9163,30 @@ var AuditWriter = class {
8296
9163
  */
8297
9164
  appendNow(record) {
8298
9165
  if (!this.dirEnsured) {
8299
- (0, import_node_fs19.mkdirSync)(this.auditDir, { recursive: true });
9166
+ (0, import_node_fs20.mkdirSync)(this.auditDir, { recursive: true });
8300
9167
  this.dirEnsured = true;
8301
9168
  }
8302
9169
  const file = (0, import_node_path13.join)(this.auditDir, auditFileName(record.ts));
8303
- (0, import_node_fs19.appendFileSync)(file, JSON.stringify(record) + "\n", "utf8");
9170
+ const line = JSON.stringify(record) + "\n";
9171
+ const auditBytesBefore = (0, import_node_fs20.existsSync)(file) ? (0, import_node_fs20.statSync)(file).size : 0;
9172
+ (0, import_node_fs20.appendFileSync)(file, line, "utf8");
9173
+ try {
9174
+ updateAuditStatsAfterAppend(
9175
+ file,
9176
+ auditBytesBefore,
9177
+ auditBytesBefore + Buffer.byteLength(line, "utf8"),
9178
+ record
9179
+ );
9180
+ } catch (error) {
9181
+ this.logger.warn("[AuditWriter] failed to update audit stats", {
9182
+ error: error instanceof Error ? error.message : String(error)
9183
+ });
9184
+ }
8304
9185
  }
8305
9186
  };
8306
9187
 
8307
9188
  // src/billing/BillingPublisher.ts
8308
- var import_node_fs20 = require("fs");
9189
+ var import_node_fs21 = require("fs");
8309
9190
  var import_node_crypto13 = require("crypto");
8310
9191
  var import_node_path14 = require("path");
8311
9192
  var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -8379,7 +9260,7 @@ var BillingPublisher = class {
8379
9260
  appendNow(event) {
8380
9261
  this.ensureDir();
8381
9262
  const file = (0, import_node_path14.join)(this.billingDir, billingFileName(event.ts));
8382
- (0, import_node_fs20.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
9263
+ (0, import_node_fs21.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
8383
9264
  }
8384
9265
  /**
8385
9266
  * One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
@@ -8429,7 +9310,7 @@ var BillingPublisher = class {
8429
9310
  try {
8430
9311
  this.ensureDir();
8431
9312
  const file = (0, import_node_path14.join)(this.billingDir, deliveredFileName(event.ts));
8432
- (0, import_node_fs20.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
9313
+ (0, import_node_fs21.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
8433
9314
  } catch (error) {
8434
9315
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
8435
9316
  error: error instanceof Error ? error.message : String(error)
@@ -8438,20 +9319,20 @@ var BillingPublisher = class {
8438
9319
  }
8439
9320
  ensureDir() {
8440
9321
  if (this.dirEnsured) return;
8441
- (0, import_node_fs20.mkdirSync)(this.billingDir, { recursive: true });
9322
+ (0, import_node_fs21.mkdirSync)(this.billingDir, { recursive: true });
8442
9323
  this.dirEnsured = true;
8443
9324
  }
8444
9325
  };
8445
9326
 
8446
9327
  // src/billing/billingReader.ts
8447
- var import_node_fs21 = require("fs");
9328
+ var import_node_fs22 = require("fs");
8448
9329
  var import_node_path15 = require("path");
8449
9330
  function readBillingLedger(billingDir) {
8450
9331
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
8451
- if (!(0, import_node_fs21.existsSync)(billingDir)) return view;
9332
+ if (!(0, import_node_fs22.existsSync)(billingDir)) return view;
8452
9333
  let files;
8453
9334
  try {
8454
- files = (0, import_node_fs21.readdirSync)(billingDir);
9335
+ files = (0, import_node_fs22.readdirSync)(billingDir);
8455
9336
  } catch {
8456
9337
  return view;
8457
9338
  }
@@ -8482,7 +9363,7 @@ function readBillingStatus(billingDir) {
8482
9363
  function parseLines(dir, file) {
8483
9364
  let raw;
8484
9365
  try {
8485
- raw = (0, import_node_fs21.readFileSync)((0, import_node_path15.join)(dir, file), "utf8");
9366
+ raw = (0, import_node_fs22.readFileSync)((0, import_node_path15.join)(dir, file), "utf8");
8486
9367
  } catch {
8487
9368
  return [];
8488
9369
  }
@@ -8668,6 +9549,76 @@ var TokenRefreshScheduler = class {
8668
9549
  }
8669
9550
  };
8670
9551
 
9552
+ // src/routeLeaseSubscriptionPreflight.ts
9553
+ var import_provider_proxy3 = require("@omnicross/core/provider-proxy");
9554
+ var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
9555
+ var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
9556
+ var import_accountModelMap = require("@omnicross/subscriptions/scheduler/accountModelMap");
9557
+ var PROVIDERS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "opencodego"]);
9558
+ function accountArray(config, providerId) {
9559
+ const record = config;
9560
+ const key = `${providerId}Accounts`;
9561
+ const accounts = record[key];
9562
+ if (Array.isArray(accounts)) return accounts;
9563
+ const legacy = record[providerId];
9564
+ if (!legacy || typeof legacy !== "object") return [];
9565
+ const activeKey = `active${providerId[0].toUpperCase()}${providerId.slice(1)}AccountId`;
9566
+ return [{ id: String(record[activeKey] ?? "active"), enabled: true, tokens: legacy }];
9567
+ }
9568
+ function hasCredential(providerId, account) {
9569
+ const tokens = account.tokens;
9570
+ if (providerId === "opencodego") return typeof tokens.apiKey === "string" && tokens.apiKey.length > 0;
9571
+ return typeof tokens.accessToken === "string" && tokens.accessToken.length > 0;
9572
+ }
9573
+ function safeProviderId(value) {
9574
+ if (!PROVIDERS.has(value)) {
9575
+ throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "subscription provider was not found");
9576
+ }
9577
+ return value;
9578
+ }
9579
+ function createRouteLeaseSubscriptionPreflight(credentials) {
9580
+ return {
9581
+ async assertAvailable(upstream, model) {
9582
+ const providerId = safeProviderId(upstream.providerId);
9583
+ const config = await credentials.getFullConfig();
9584
+ const all = accountArray(config, providerId);
9585
+ if (all.length === 0) {
9586
+ throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "subscription provider has no configured account");
9587
+ }
9588
+ let bounded = all;
9589
+ if (upstream.kind === "account") {
9590
+ bounded = all.filter((account) => account.id === upstream.accountId);
9591
+ } else if (upstream.kind === "account-group") {
9592
+ bounded = all.filter((account) => account.group?.trim() === upstream.group);
9593
+ }
9594
+ if (bounded.length === 0) {
9595
+ throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "the selected subscription resource was not found");
9596
+ }
9597
+ const modelEligible = bounded.filter(
9598
+ (account) => (0, import_accountModelMap.accountSupportsModel)(account.supportedModels, model)
9599
+ );
9600
+ if (modelEligible.length === 0) {
9601
+ throw new import_provider_proxy3.RouteLeaseError("model_not_configured", "model is not supported by the selected subscription resource");
9602
+ }
9603
+ const credentialEligible = modelEligible.filter(
9604
+ (account) => account.enabled !== false && hasCredential(providerId, account)
9605
+ );
9606
+ const health2 = (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)();
9607
+ const allowance = (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)();
9608
+ const candidates = credentialEligible.filter(
9609
+ (account) => health2.isSchedulable(providerId, account.id) && allowance.preview(providerId, account.id, account.priority ?? 50).schedulable
9610
+ );
9611
+ if (candidates.length > 0) return;
9612
+ if (upstream.kind === "account") {
9613
+ throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "the selected subscription account is unavailable");
9614
+ }
9615
+ throw new import_provider_proxy3.RouteLeaseError("upstream_exhausted", "the selected subscription pool has no eligible account", {
9616
+ retryAfterSeconds: 30
9617
+ });
9618
+ }
9619
+ };
9620
+ }
9621
+
8671
9622
  // src/webhook/WebhookDispatcher.ts
8672
9623
  var import_node_crypto14 = require("crypto");
8673
9624
  var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -8850,11 +9801,11 @@ function buildDaemon(config, paths) {
8850
9801
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
8851
9802
  );
8852
9803
  (0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
8853
- (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)().configure(
9804
+ (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
8854
9805
  (0, import_outbound_api4.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
8855
9806
  );
8856
9807
  const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
8857
- const keyDb = new JsonOutboundKeyDb(paths.keysPath);
9808
+ const keyDb = new JsonOutboundKeyDb(paths.keysPath, secretBox3);
8858
9809
  const voucherDb = new JsonVoucherDb(defaultVouchersPath(paths.configPath));
8859
9810
  const settingsStore = new JsonApiServerSettingsStore(paths.configPath, secretBox3);
8860
9811
  const integrationStateStore = new IntegrationStateStore(
@@ -8917,11 +9868,22 @@ function buildDaemon(config, paths) {
8917
9868
  const usageRecorder = new import_usage.UsageRecorder(usageEventStore, pricingEngine, logger, {
8918
9869
  onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
8919
9870
  });
8920
- const providerProxy = (0, import_provider_proxy.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
9871
+ const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
9872
+ const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
9873
+ providerProxy,
9874
+ new import_provider_proxy4.RouteLeaseTargetResolver(llmConfig, {
9875
+ providerKeys: apiKeyPool,
9876
+ subscriptions: createRouteLeaseSubscriptionPreflight(credentialStore)
9877
+ }),
9878
+ import_cli_launcher2.routeLeaseDescriptorPort,
9879
+ { logger }
9880
+ );
9881
+ providerProxy.registerBeforeStop(() => routeLeaseManager.shutdown());
9882
+ providerProxy.registerBeforeStop(() => resetCliSessions());
8921
9883
  llmConfig.setReloadHook(() => apiKeyPool.invalidateCache());
8922
9884
  const accountHealthProbeScheduler = new AccountHealthProbeScheduler(
8923
9885
  credentialStore,
8924
- (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)(),
9886
+ (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
8925
9887
  logger,
8926
9888
  import_outbound_api4.DEFAULT_ACCOUNT_PROBE
8927
9889
  );
@@ -8955,7 +9917,7 @@ function buildDaemon(config, paths) {
8955
9917
  // lines through the injected logger (honors level/format/file sink).
8956
9918
  logger
8957
9919
  });
8958
- const auditDir2 = defaultAuditDir(paths.configPath);
9920
+ const auditDir = defaultAuditDir(paths.configPath);
8959
9921
  const billingDir = defaultBillingDir(paths.configPath);
8960
9922
  const adminServer = new AdminServer({
8961
9923
  configPath: paths.configPath,
@@ -8968,6 +9930,7 @@ function buildDaemon(config, paths) {
8968
9930
  keySpendReader: keySpendTracker,
8969
9931
  settingsStore,
8970
9932
  outboundApiServer,
9933
+ routeLeaseManager,
8971
9934
  subscriptionAccounts,
8972
9935
  accountAllowanceService,
8973
9936
  allowanceRefreshScheduler: claudeAllowanceRefreshScheduler,
@@ -8989,10 +9952,16 @@ function buildDaemon(config, paths) {
8989
9952
  // (NOT widening the least-authority writer — no token-returning read reachable).
8990
9953
  oauthSessions: new OAuthSessionStore(),
8991
9954
  // Real global fetch by default; a test seam (`paths.oauthExchangeFetch`) can
8992
- // inject a mock so no real token endpoint is hit.
8993
- // upstream-proxy: default the OAuth token-exchange fetch to the proxy-aware
8994
- // helper so interactive login honors a configured proxy (global/env layers).
8995
- oauthExchangeFetch: paths.oauthExchangeFetch ?? ((url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)),
9955
+ // inject a mock so no real token endpoint is hit (one FetchLike for every
9956
+ // provider the ctx below only matters on the real egress path).
9957
+ //
9958
+ // upstream-proxy: a PER-PROVIDER factory, so the exchange carries the same
9959
+ // `{ providerId }` ctx the CLI login and the token refresh already pass.
9960
+ // Without it the interactive login resolved only the global/env proxy layers
9961
+ // — `server.proxy.byProvider[...]` was silently skipped — and the call was
9962
+ // excluded from the upstream trace, so a failing login left no evidence.
9963
+ // `redactBodies` keeps the code/verifier + minted token out of that trace.
9964
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId, redactBodies: true }),
8996
9965
  subscriptionAccountAppender: credentialStore,
8997
9966
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
8998
9967
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -9044,7 +10013,8 @@ function buildDaemon(config, paths) {
9044
10013
  // date-rotated audit store. Bound to the store dir here so the AdminServer
9045
10014
  // carries no path/store coupling. Records hold IP/UA/bodies → admin-only,
9046
10015
  // NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
9047
- auditReader: (query2) => readAuditRecords(auditDir2, query2),
10016
+ auditReader: (query2) => readAuditRecords(auditDir, query2),
10017
+ auditStatsReader: (query2) => readAuditStats(auditDir, query2),
9048
10018
  // billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
9049
10019
  // secret-free total/delivered/pending counts of the durable ledger.
9050
10020
  billingStatusReader: () => readBillingStatus(billingDir)
@@ -9053,10 +10023,10 @@ function buildDaemon(config, paths) {
9053
10023
  logger,
9054
10024
  fetchImpl: (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)
9055
10025
  });
9056
- setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)());
9057
- const auditWriter = new AuditWriter(auditDir2, logger);
9058
- const auditPruneSweeper = new AuditPruneSweeper(auditDir2, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
9059
- setAuditRuntime(auditWriter, auditPruneSweeper, auditDir2);
10026
+ setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
10027
+ const auditWriter = new AuditWriter(auditDir, logger);
10028
+ const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
10029
+ setAuditRuntime(auditWriter, auditPruneSweeper);
9060
10030
  const billingPublisher = new BillingPublisher(billingDir, logger);
9061
10031
  const billingRetrySweeper = new BillingRetrySweeper(
9062
10032
  billingDir,
@@ -9068,7 +10038,7 @@ function buildDaemon(config, paths) {
9068
10038
  const tokenRefreshScheduler = new TokenRefreshScheduler(credentialStore, logger);
9069
10039
  const accountHealthSweeper = new AccountHealthSweeper(
9070
10040
  credentialStore,
9071
- (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)(),
10041
+ (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
9072
10042
  logger
9073
10043
  );
9074
10044
  return {
@@ -9077,6 +10047,7 @@ function buildDaemon(config, paths) {
9077
10047
  keyDb,
9078
10048
  settingsStore,
9079
10049
  providerProxy,
10050
+ routeLeaseManager,
9080
10051
  outboundApiServer,
9081
10052
  apiKeyPool,
9082
10053
  autoDisableStore,
@@ -9101,7 +10072,7 @@ function buildDaemon(config, paths) {
9101
10072
  };
9102
10073
  }
9103
10074
  function resetDaemonSingletonsForTests() {
9104
- (0, import_provider_proxy.__resetProviderProxyForTests)();
10075
+ (0, import_provider_proxy4.__resetProviderProxyForTests)();
9105
10076
  (0, import_outbound_api4.__resetOutboundApiServerForTests)();
9106
10077
  (0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
9107
10078
  (0, import_subscriptions4.setSubscriptionProviderRegistry)(null);
@@ -9116,12 +10087,12 @@ function resetDaemonSingletonsForTests() {
9116
10087
  resetBillingRuntimeForTests();
9117
10088
  (0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
9118
10089
  (0, import_AccountAllowanceStore4.__resetSharedAccountAllowanceStoreForTests)();
9119
- (0, import_AccountAllowanceScheduling4.__resetSharedAccountAllowanceSchedulingForTests)();
10090
+ (0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
9120
10091
  }
9121
10092
  function isTokensStoreReadable(tokensPath) {
9122
10093
  try {
9123
- if (!(0, import_node_fs22.existsSync)(tokensPath)) return true;
9124
- (0, import_node_fs22.accessSync)(tokensPath, import_node_fs22.constants.R_OK);
10094
+ if (!(0, import_node_fs23.existsSync)(tokensPath)) return true;
10095
+ (0, import_node_fs23.accessSync)(tokensPath, import_node_fs23.constants.R_OK);
9125
10096
  return true;
9126
10097
  } catch {
9127
10098
  return false;