@omnicross/daemon 0.1.6 → 0.1.7

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,7 +53,7 @@ __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");
@@ -147,7 +147,7 @@ async function runCodexLoopback(sessionId, codeVerifier, state, signal, deps) {
147
147
  const code = await deps.codexAwaitLoopback(state, void 0, signal);
148
148
  const result = await import_subscriptions.codexOAuth.exchangeCodeForTokens(
149
149
  { authorizationCode: code, codeVerifier, state },
150
- deps.oauthExchangeFetch
150
+ deps.oauthExchangeFetch("codex")
151
151
  );
152
152
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
153
153
  const block = {
@@ -649,6 +649,17 @@ function handleAuditQuery(req, res, reader) {
649
649
  res.writeHead(200, { "Content-Type": "application/json" });
650
650
  res.end(JSON.stringify({ records }));
651
651
  }
652
+ async function handleAuditStatsQuery(req, res, reader) {
653
+ const url = new URL(req.url ?? "/", "http://localhost");
654
+ const query2 = {};
655
+ const from = intParam(url.searchParams.get("from"));
656
+ if (from !== void 0) query2.from = from;
657
+ const to = intParam(url.searchParams.get("to"));
658
+ if (to !== void 0) query2.to = to;
659
+ const stats = reader ? await reader(query2) : { requestCount: 0, errorCount: 0, complete: true };
660
+ res.writeHead(200, { "Content-Type": "application/json" });
661
+ res.end(JSON.stringify(stats));
662
+ }
652
663
 
653
664
  // src/admin/billingStatusApi.ts
654
665
  function handleBillingStatus(res, reader) {
@@ -2144,7 +2155,13 @@ function listMappablePresets() {
2144
2155
  name: preset.name,
2145
2156
  apiFormat: resolved.format,
2146
2157
  baseUrl: preset.api_base_url,
2147
- models: Array.isArray(preset.models) ? preset.models : []
2158
+ models: Array.isArray(preset.models) ? preset.models : [],
2159
+ nameKey: preset.nameKey,
2160
+ icon: preset.icon,
2161
+ description: preset.description,
2162
+ features: preset.features,
2163
+ website: preset.website,
2164
+ modelsEndpoint: preset.modelsEndpoint
2148
2165
  });
2149
2166
  }
2150
2167
  return { mappable, excluded };
@@ -2533,7 +2550,7 @@ async function handleOAuthComplete(providerId, body, deps) {
2533
2550
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
2534
2551
  if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
2535
2552
  if (!rawCode) return err2(400, "oauth complete requires { code }");
2536
- const session = deps.oauthSessions.take(sessionId);
2553
+ const session = deps.oauthSessions.peek(sessionId);
2537
2554
  if (!session) return err2(410, "oauth session is unknown, expired, or already used");
2538
2555
  if (session.providerId !== providerId) {
2539
2556
  return err2(400, `oauth session does not match provider '${providerId}'`);
@@ -2547,13 +2564,15 @@ async function handleOAuthComplete(providerId, body, deps) {
2547
2564
  }
2548
2565
  code = splitCode;
2549
2566
  }
2567
+ const exchangeFetch = deps.oauthExchangeFetch(providerId);
2550
2568
  let block;
2551
2569
  try {
2552
- block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, deps.oauthExchangeFetch) : await exchangeGemini(code, session.codeVerifier, deps.oauthExchangeFetch);
2570
+ block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
2553
2571
  } catch (exchangeError) {
2554
2572
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
2555
2573
  return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
2556
2574
  }
2575
+ deps.oauthSessions.consume(sessionId);
2557
2576
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
2558
2577
  await deps.subscriptionAccountAppender.appendProviderAccount(providerId, block, label);
2559
2578
  const status = await statusEntryFor(deps.subscriptionAccounts, providerId);
@@ -2798,8 +2817,8 @@ function validateAuditSegment(patch) {
2798
2817
  }
2799
2818
  }
2800
2819
  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");
2820
+ if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < -1)) {
2821
+ errors.push("audit.maxBodyBytes must be -1 or a non-negative number");
2803
2822
  }
2804
2823
  const retentionDays = audit["retentionDays"];
2805
2824
  if (retentionDays !== void 0 && (typeof retentionDays !== "number" || !Number.isFinite(retentionDays) || retentionDays < 0)) {
@@ -3234,18 +3253,16 @@ function preserveWebhookSecrets(incoming, current) {
3234
3253
  }
3235
3254
 
3236
3255
  // src/audit/auditRuntime.ts
3237
- var import_node_path6 = require("path");
3238
3256
  var import_auditSink = require("@omnicross/core/pipeline/auditSink");
3239
3257
  var import_upstreamTrace = require("@omnicross/core/pipeline/upstreamTrace");
3240
3258
  var writer = null;
3241
3259
  var sweeper = null;
3242
- var auditDir = "";
3243
- function setAuditRuntime(w, s, dir) {
3260
+ function setAuditRuntime(w, s) {
3244
3261
  writer = w;
3245
3262
  sweeper = s;
3246
- auditDir = dir;
3247
3263
  }
3248
3264
  function applyAuditConfig(config) {
3265
+ (0, import_upstreamTrace.setUpstreamTracePath)(null);
3249
3266
  const enabled = config?.enabled === true && writer !== null;
3250
3267
  if (enabled && config) {
3251
3268
  (0, import_auditSink.setAuditCaptureConfig)(config);
@@ -3255,11 +3272,9 @@ function applyAuditConfig(config) {
3255
3272
  sweeper.configure(config);
3256
3273
  sweeper.start();
3257
3274
  }
3258
- (0, import_upstreamTrace.setUpstreamTracePath)(config.captureBodies ? (0, import_node_path6.join)(auditDir, "upstream-trace.jsonl") : null);
3259
3275
  } else {
3260
3276
  (0, import_auditSink.setAuditCaptureConfig)(null);
3261
3277
  (0, import_auditSink.setAuditSink)(null);
3262
- (0, import_upstreamTrace.setUpstreamTracePath)(null);
3263
3278
  if (sweeper) {
3264
3279
  if (config) sweeper.configure(config);
3265
3280
  sweeper.dispose();
@@ -3273,7 +3288,6 @@ function resetAuditRuntimeForTests() {
3273
3288
  if (sweeper) sweeper.dispose();
3274
3289
  writer = null;
3275
3290
  sweeper = null;
3276
- auditDir = "";
3277
3291
  }
3278
3292
 
3279
3293
  // src/billing/billingRuntime.ts
@@ -4118,6 +4132,8 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
4118
4132
  }
4119
4133
 
4120
4134
  // src/admin/adminApi.ts
4135
+ var import_AccountRouteActivity = require("@omnicross/core/pipeline/AccountRouteActivity");
4136
+ var import_ServerOverloadCounter = require("@omnicross/core/pipeline/ServerOverloadCounter");
4121
4137
  function readBody(req) {
4122
4138
  return new Promise((resolve2, reject) => {
4123
4139
  const chunks = [];
@@ -4154,6 +4170,9 @@ function toKeyInfo(row) {
4154
4170
  id: row.id,
4155
4171
  name: row.name,
4156
4172
  keyPrefix: row.keyPrefix,
4173
+ // True only when a reversible `keySecret` envelope was persisted at creation
4174
+ // — gates the UI "view key" eye. Legacy hash-only rows read as absent.
4175
+ revealable: Boolean(row.keySecret),
4157
4176
  enabled: row.enabled,
4158
4177
  createdAt: row.createdAt,
4159
4178
  lastUsedAt: row.lastUsedAt,
@@ -4809,7 +4828,13 @@ function handlePresets(res, method) {
4809
4828
  name: p.name,
4810
4829
  apiFormat: p.apiFormat,
4811
4830
  baseUrl: p.baseUrl,
4812
- models: p.models
4831
+ models: p.models,
4832
+ nameKey: p.nameKey,
4833
+ icon: p.icon,
4834
+ description: p.description,
4835
+ features: p.features,
4836
+ website: p.website,
4837
+ modelsEndpoint: p.modelsEndpoint
4813
4838
  }));
4814
4839
  return writeJson3(res, 200, { presets, excluded });
4815
4840
  }
@@ -4843,12 +4868,27 @@ async function handleKeys(req, res, method, rest, deps) {
4843
4868
  plaintextOnce: created.plaintextOnce
4844
4869
  });
4845
4870
  }
4871
+ if (method === "GET" && rest.length === 2 && rest[1] === "reveal") {
4872
+ const revealed = await deps.keyDb.outboundApiKeysReveal(rest[0]);
4873
+ if (revealed !== null) return writeJson3(res, 200, { key: revealed });
4874
+ const exists = (await deps.keyDb.outboundApiKeysList()).some((r) => r.id === rest[0]);
4875
+ if (!exists) return writeJsonError(res, 404, `key '${rest[0]}' not found`);
4876
+ return writeJsonError(
4877
+ res,
4878
+ 409,
4879
+ `key '${rest[0]}' is not revealable (created before revealable key storage)`
4880
+ );
4881
+ }
4846
4882
  const id = rest[0];
4847
4883
  const action = rest[1];
4848
4884
  if (method === "POST" && id && action === "revoke") {
4849
4885
  const ok = await deps.keyDb.outboundApiKeysRevoke(id);
4850
4886
  return writeJson3(res, ok ? 200 : 404, { ok });
4851
4887
  }
4888
+ if (method === "DELETE" && id && !action) {
4889
+ const ok = await deps.keyDb.outboundApiKeysDelete(id);
4890
+ return writeJson3(res, ok ? 200 : 404, { ok });
4891
+ }
4852
4892
  if (method === "POST" && id && action === "enabled") {
4853
4893
  const body = await readJsonBody3(req);
4854
4894
  const enabled = body["enabled"] === true;
@@ -5025,6 +5065,40 @@ async function handleServer(req, res, method, deps) {
5025
5065
  return writeJsonError(res, 405, `method ${method} not allowed on server`);
5026
5066
  }
5027
5067
  async function handleAccounts(req, res, method, rest, deps) {
5068
+ if (rest[0] === "route-activity" && rest.length === 1) {
5069
+ if (method !== "GET") {
5070
+ return writeJsonError(res, 405, `method ${method} not allowed on account route activity`);
5071
+ }
5072
+ const query2 = requestQuery(req);
5073
+ const parsedLimit = Number(query2.get("limit") ?? "100");
5074
+ const records = (0, import_AccountRouteActivity.getSharedAccountRouteActivity)().list({
5075
+ providerId: query2.get("providerId") ?? void 0,
5076
+ accountId: query2.get("accountId") ?? void 0,
5077
+ sessionKey: query2.get("sessionKey") ?? void 0,
5078
+ limit: Number.isFinite(parsedLimit) ? parsedLimit : 100
5079
+ });
5080
+ return writeJson3(res, 200, {
5081
+ available: true,
5082
+ records,
5083
+ capacity: import_AccountRouteActivity.ACCOUNT_ROUTE_ACTIVITY_LIMIT,
5084
+ collectedAt: Date.now()
5085
+ });
5086
+ }
5087
+ if (rest[0] === "overload-counters" && rest.length === 1) {
5088
+ if (method !== "GET") {
5089
+ return writeJsonError(res, 405, `method ${method} not allowed on overload counters`);
5090
+ }
5091
+ const query2 = requestQuery(req);
5092
+ const entries = (0, import_ServerOverloadCounter.getSharedOverloadCounter)().list({
5093
+ providerId: query2.get("providerId") ?? void 0,
5094
+ accountId: query2.get("accountId") ?? void 0
5095
+ });
5096
+ return writeJson3(res, 200, {
5097
+ available: true,
5098
+ entries,
5099
+ collectedAt: Date.now()
5100
+ });
5101
+ }
5028
5102
  if (rest[0] === "allowances") {
5029
5103
  return handleAccountAllowanceApi(
5030
5104
  req,
@@ -5171,8 +5245,13 @@ async function handleAccounts(req, res, method, rest, deps) {
5171
5245
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
5172
5246
  return writeJsonError(res, 404, `account '${accountId}' not found`);
5173
5247
  }
5174
- const result = await deps.accountProbeService.probeAccount(providerId, accountId);
5175
- return writeJson3(res, 200, { ok: result.ok, marked: result.marked });
5248
+ const result = await deps.accountProbeService.testAccountConnection(providerId, accountId);
5249
+ return writeJson3(res, 200, {
5250
+ ok: result.ok,
5251
+ marked: result.marked,
5252
+ tier: result.tier,
5253
+ model: result.model
5254
+ });
5176
5255
  }
5177
5256
  if (method === "POST" && rest[2] === "label") {
5178
5257
  const accountId = rest[1];
@@ -5451,7 +5530,7 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
5451
5530
  var import_node_fs7 = require("fs");
5452
5531
  var import_promises = require("fs/promises");
5453
5532
  var import_node_module = require("module");
5454
- var import_node_path7 = __toESM(require("path"), 1);
5533
+ var import_node_path6 = __toESM(require("path"), 1);
5455
5534
  var import_meta = {};
5456
5535
  var CONTENT_TYPES = {
5457
5536
  ".html": "text/html; charset=utf-8",
@@ -5472,13 +5551,13 @@ var CONTENT_TYPES = {
5472
5551
  function resolveUiDist() {
5473
5552
  const fromEnv = process.env["OMNICROSS_UI_DIST"];
5474
5553
  if (fromEnv) {
5475
- return (0, import_node_fs7.existsSync)(import_node_path7.default.join(fromEnv, "index.html")) ? import_node_path7.default.resolve(fromEnv) : null;
5554
+ return (0, import_node_fs7.existsSync)(import_node_path6.default.join(fromEnv, "index.html")) ? import_node_path6.default.resolve(fromEnv) : null;
5476
5555
  }
5477
5556
  try {
5478
5557
  const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
5479
5558
  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;
5559
+ const dist = import_node_path6.default.join(import_node_path6.default.dirname(pkgJson), "dist");
5560
+ return (0, import_node_fs7.existsSync)(import_node_path6.default.join(dist, "index.html")) ? dist : null;
5482
5561
  } catch {
5483
5562
  return null;
5484
5563
  }
@@ -5520,16 +5599,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5520
5599
  res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
5521
5600
  return true;
5522
5601
  }
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)) {
5602
+ const filePath = import_node_path6.default.resolve(uiDist, rel === "" ? "index.html" : rel);
5603
+ if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path6.default.sep)) {
5525
5604
  res.writeHead(403, { "Content-Type": "application/json" });
5526
5605
  res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
5527
5606
  return true;
5528
5607
  }
5529
5608
  let target = filePath;
5530
5609
  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");
5610
+ if (import_node_path6.default.extname(rel) === "") {
5611
+ target = import_node_path6.default.join(uiDist, "index.html");
5533
5612
  } else {
5534
5613
  res.writeHead(404, { "Content-Type": "application/json" });
5535
5614
  res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
@@ -5537,14 +5616,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
5537
5616
  }
5538
5617
  }
5539
5618
  const body = await (0, import_promises.readFile)(target);
5540
- const type = CONTENT_TYPES[import_node_path7.default.extname(target).toLowerCase()] ?? "application/octet-stream";
5619
+ const type = CONTENT_TYPES[import_node_path6.default.extname(target).toLowerCase()] ?? "application/octet-stream";
5541
5620
  res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
5542
5621
  res.end(req.method === "HEAD" ? void 0 : body);
5543
5622
  return true;
5544
5623
  }
5545
5624
 
5546
5625
  // src/admin/version.ts
5547
- var DAEMON_VERSION = true ? "0.1.6" : "0.0.0-dev";
5626
+ var DAEMON_VERSION = true ? "0.1.7" : "0.0.0-dev";
5548
5627
 
5549
5628
  // src/admin/AdminServer.ts
5550
5629
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -5652,6 +5731,10 @@ var AdminServer = class {
5652
5731
  handleAuditQuery(req, res, this.deps.auditReader);
5653
5732
  return;
5654
5733
  }
5734
+ if (path2 === "/admin/api/audit/stats" && (req.method === "GET" || req.method === "HEAD")) {
5735
+ await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
5736
+ return;
5737
+ }
5655
5738
  if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
5656
5739
  handleBillingStatus(res, this.deps.billingStatusReader);
5657
5740
  return;
@@ -5768,20 +5851,36 @@ var OAuthSessionStore = class {
5768
5851
  return sessionId;
5769
5852
  }
5770
5853
  /**
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).
5854
+ * NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
5855
+ * it is unknown, already consumed, or past its TTL (an expired entry is
5856
+ * dropped here). A `null` return means the completer must reject (no
5857
+ * exchange, no write).
5858
+ *
5859
+ * Deliberately NOT a consume: the completer peeks, runs the token exchange,
5860
+ * and only {@link consume}s once a token has actually been minted. Consuming
5861
+ * up-front burned the session on EVERY failed exchange (a mistyped/expired
5862
+ * pasted code, a proxy hiccup), so the user's natural retry hit
5863
+ * "session is unknown, expired, or already used" and the login became
5864
+ * unrecoverable without restarting the whole flow.
5775
5865
  */
5776
- take(sessionId) {
5866
+ peek(sessionId) {
5777
5867
  this.sweep();
5778
5868
  const session = this.sessions.get(sessionId);
5779
5869
  if (!session) return null;
5780
- this.sessions.delete(sessionId);
5781
- if (Date.now() - session.createdAt > this.ttlMs) return null;
5870
+ if (Date.now() - session.createdAt > this.ttlMs) {
5871
+ this.sessions.delete(sessionId);
5872
+ return null;
5873
+ }
5782
5874
  return session;
5783
5875
  }
5784
- /** Drop every session past its TTL. Called on each put/take. */
5876
+ /**
5877
+ * SINGLE-USE burn: drop the session so the same `sessionId` can never be
5878
+ * completed twice. Called ONLY after a successful token exchange.
5879
+ */
5880
+ consume(sessionId) {
5881
+ this.sessions.delete(sessionId);
5882
+ }
5883
+ /** Drop every session past its TTL. Called on each put/peek. */
5785
5884
  sweep() {
5786
5885
  const now = Date.now();
5787
5886
  for (const [id, session] of this.sessions) {
@@ -5796,6 +5895,10 @@ var LOOPBACK_HOST = "127.0.0.1";
5796
5895
  var LOOPBACK_PORT = 1455;
5797
5896
  var CALLBACK_PATH = "/auth/callback";
5798
5897
  var DEFAULT_TIMEOUT_MS = 5 * 6e4;
5898
+ var HTML_HEADERS = {
5899
+ "Content-Type": "text/html",
5900
+ Connection: "close"
5901
+ };
5799
5902
  function pageHtml(message) {
5800
5903
  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
5904
  }
@@ -5806,30 +5909,31 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
5806
5909
  if (settled) return;
5807
5910
  settled = true;
5808
5911
  clearTimeout(timer);
5809
- server2.close(() => fn());
5912
+ fn();
5913
+ server2.close();
5810
5914
  };
5811
5915
  const server = (0, import_node_http3.createServer)((req, res) => {
5812
5916
  const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
5813
5917
  if (url.pathname !== CALLBACK_PATH) {
5814
- res.writeHead(404, { "Content-Type": "text/html" });
5918
+ res.writeHead(404, HTML_HEADERS);
5815
5919
  res.end(pageHtml("Not found"));
5816
5920
  return;
5817
5921
  }
5818
5922
  const code = url.searchParams.get("code");
5819
5923
  const state = url.searchParams.get("state");
5820
5924
  if (!code) {
5821
- res.writeHead(400, { "Content-Type": "text/html" });
5925
+ res.writeHead(400, HTML_HEADERS);
5822
5926
  res.end(pageHtml("Login failed: missing authorization code."));
5823
5927
  finish(server, () => reject(new Error("login: callback did not include an authorization code")));
5824
5928
  return;
5825
5929
  }
5826
5930
  if (state !== expectedState) {
5827
- res.writeHead(400, { "Content-Type": "text/html" });
5931
+ res.writeHead(400, HTML_HEADERS);
5828
5932
  res.end(pageHtml("Login failed: state mismatch."));
5829
5933
  finish(server, () => reject(new Error("login: callback state did not match (possible CSRF) \u2014 aborting")));
5830
5934
  return;
5831
5935
  }
5832
- res.writeHead(200, { "Content-Type": "text/html" });
5936
+ res.writeHead(200, HTML_HEADERS);
5833
5937
  res.end(pageHtml("Login complete."));
5834
5938
  finish(server, () => resolve2(code));
5835
5939
  });
@@ -5926,30 +6030,30 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
5926
6030
  }
5927
6031
 
5928
6032
  // src/commands/paths.ts
5929
- var import_node_path8 = require("path");
6033
+ var import_node_path7 = require("path");
5930
6034
  function defaultVouchersPath(configPath) {
5931
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "vouchers.json");
6035
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "vouchers.json");
5932
6036
  }
5933
6037
  function defaultIntegrationsPath(configPath) {
5934
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "integrations.json");
6038
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "integrations.json");
5935
6039
  }
5936
6040
  function defaultPricingPath(configPath) {
5937
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "pricing.json");
6041
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "pricing.json");
5938
6042
  }
5939
6043
  function defaultPricingRefreshStatePath(configPath) {
5940
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "pricing-refresh.json");
6044
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "pricing-refresh.json");
5941
6045
  }
5942
6046
  function defaultAccountAllowancePath(configPath) {
5943
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "allowance-cache.json");
6047
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "allowance-cache.json");
5944
6048
  }
5945
6049
  function defaultUsageEventsPath(configPath) {
5946
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "usage-events.jsonl");
6050
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "usage-events.jsonl");
5947
6051
  }
5948
6052
  function defaultAuditDir(configPath) {
5949
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "audit");
6053
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "audit");
5950
6054
  }
5951
6055
  function defaultBillingDir(configPath) {
5952
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(configPath), "billing");
6056
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "billing");
5953
6057
  }
5954
6058
 
5955
6059
  // src/ports/ConfigFileProviderConfigSource.ts
@@ -6342,8 +6446,12 @@ var JsonlUsageEventStore = class {
6342
6446
  reasoningTokens: 0,
6343
6447
  costUsd: 0,
6344
6448
  costSavedByCacheUsd: 0,
6345
- eventCount: 0
6449
+ eventCount: 0,
6450
+ cacheEligibleEventCount: 0,
6451
+ coldCacheEventCount: 0,
6452
+ medianCacheHitRate: null
6346
6453
  };
6454
+ const perEventHitRates = [];
6347
6455
  for (const row of this.readRows(range)) {
6348
6456
  totals.inputTokens += row.inputTokens;
6349
6457
  totals.outputTokens += row.outputTokens;
@@ -6353,7 +6461,14 @@ var JsonlUsageEventStore = class {
6353
6461
  totals.costUsd += row.costUsd;
6354
6462
  totals.costSavedByCacheUsd += row.costSavedByCacheUsd;
6355
6463
  totals.eventCount += 1;
6464
+ const promptSideTokens = row.inputTokens + row.cacheReadTokens + row.cacheCreationTokens;
6465
+ if (promptSideTokens > 0) {
6466
+ totals.cacheEligibleEventCount += 1;
6467
+ if (row.cacheReadTokens === 0) totals.coldCacheEventCount += 1;
6468
+ perEventHitRates.push(row.cacheReadTokens / promptSideTokens);
6469
+ }
6356
6470
  }
6471
+ totals.medianCacheHitRate = median(perEventHitRates);
6357
6472
  return totals;
6358
6473
  }
6359
6474
  async getByModel(range) {
@@ -6587,6 +6702,15 @@ var NUMERIC_FIELDS = [
6587
6702
  ];
6588
6703
  var NULLABLE_STRING_FIELDS = ["messageId", "parentMessageId", "sessionId", "apiKeyId"];
6589
6704
  var isStringOrNull = (v) => v === null || typeof v === "string";
6705
+ var CACHE_KEY_SOURCES = /* @__PURE__ */ new Set([
6706
+ "client",
6707
+ "session-header",
6708
+ "thread-header",
6709
+ "body-session-id",
6710
+ "body-thread-id",
6711
+ "content-fingerprint",
6712
+ "none"
6713
+ ]);
6590
6714
  function isUsageEventRecord(parsed) {
6591
6715
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
6592
6716
  const r = parsed;
@@ -6594,6 +6718,10 @@ function isUsageEventRecord(parsed) {
6594
6718
  if (typeof r["providerId"] !== "string") return false;
6595
6719
  if (typeof r["model"] !== "string") return false;
6596
6720
  if (typeof r["engineOrigin"] !== "string") return false;
6721
+ if (r["cacheKeySource"] !== void 0 && (typeof r["cacheKeySource"] !== "string" || !CACHE_KEY_SOURCES.has(r["cacheKeySource"]))) return false;
6722
+ if (r["cacheKeyInjected"] !== void 0 && typeof r["cacheKeyInjected"] !== "boolean") {
6723
+ return false;
6724
+ }
6597
6725
  for (const f of NULLABLE_STRING_FIELDS) {
6598
6726
  if (!isStringOrNull(r[f])) return false;
6599
6727
  }
@@ -6603,14 +6731,30 @@ function isUsageEventRecord(parsed) {
6603
6731
  }
6604
6732
  return true;
6605
6733
  }
6734
+ function median(values) {
6735
+ if (values.length === 0) return null;
6736
+ values.sort((a, b) => a - b);
6737
+ const middle = Math.floor(values.length / 2);
6738
+ return values.length % 2 === 1 ? values[middle] : (values[middle - 1] + values[middle]) / 2;
6739
+ }
6606
6740
 
6607
6741
  // src/ports/JsonOutboundKeyDb.ts
6608
6742
  var import_node_fs11 = require("fs");
6609
6743
  var JsonOutboundKeyDb = class {
6610
- constructor(keysPath) {
6744
+ /**
6745
+ * @param secretBox OPTIONAL reversible-secret codec. When present, a created
6746
+ * key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
6747
+ * operator "view key" affordance via `outboundApiKeysReveal`). When absent the
6748
+ * store stays hash-only (byte-identical to the legacy behavior) and reveal
6749
+ * always returns `null`. Existing 1-arg call sites (tests, lightweight
6750
+ * embedders) keep working.
6751
+ */
6752
+ constructor(keysPath, secretBox3) {
6611
6753
  this.keysPath = keysPath;
6754
+ this.secretBox = secretBox3;
6612
6755
  }
6613
6756
  keysPath;
6757
+ secretBox;
6614
6758
  async outboundApiKeysList() {
6615
6759
  return this.readRows();
6616
6760
  }
@@ -6636,10 +6780,27 @@ var JsonOutboundKeyDb = class {
6636
6780
  allowedEndpoints: input.allowedEndpoints,
6637
6781
  loopbackOnly: input.loopbackOnly
6638
6782
  };
6783
+ if (input.plaintext && this.secretBox) {
6784
+ row.keySecret = this.secretBox.encrypt(input.plaintext);
6785
+ }
6639
6786
  rows.push(row);
6640
6787
  this.writeRows(rows);
6641
6788
  return row;
6642
6789
  }
6790
+ async outboundApiKeysReveal(id) {
6791
+ const rows = this.readRows();
6792
+ const row = rows.find((r) => r.id === id);
6793
+ if (!row || !row.keySecret || !this.secretBox) return null;
6794
+ return this.secretBox.decrypt(row.keySecret);
6795
+ }
6796
+ async outboundApiKeysDelete(id) {
6797
+ const rows = this.readRows();
6798
+ const idx = rows.findIndex((r) => r.id === id);
6799
+ if (idx < 0) return false;
6800
+ rows.splice(idx, 1);
6801
+ this.writeRows(rows);
6802
+ return true;
6803
+ }
6643
6804
  async outboundApiKeysRevoke(id) {
6644
6805
  return this.mutateRow(id, (row) => {
6645
6806
  if (row.revokedAt !== null) return false;
@@ -7088,7 +7249,7 @@ var JsonVoucherDb = class {
7088
7249
 
7089
7250
  // src/ports/JsonSubscriptionCredentialStore.ts
7090
7251
  var import_node_fs16 = require("fs");
7091
- var import_node_path10 = require("path");
7252
+ var import_node_path9 = require("path");
7092
7253
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
7093
7254
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
7094
7255
  var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -7139,9 +7300,9 @@ function findDuplicateCredentialIds(accounts) {
7139
7300
  // src/ports/external-cli-credentials.ts
7140
7301
  var import_node_fs15 = require("fs");
7141
7302
  var import_node_os3 = require("os");
7142
- var import_node_path9 = require("path");
7303
+ var import_node_path8 = require("path");
7143
7304
  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");
7305
+ return provider === "claude" ? (0, import_node_path8.join)(home, ".claude", ".credentials.json") : (0, import_node_path8.join)(home, ".codex", "auth.json");
7145
7306
  }
7146
7307
  function decodeJwtExpiryMs(token) {
7147
7308
  try {
@@ -7231,9 +7392,15 @@ var JsonSubscriptionCredentialStore = class {
7231
7392
  * TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
7232
7393
  * through {@link fetchUpstream} with the account's `{ providerId, accountId }`
7233
7394
  * ctx so the per-account/provider proxy applies. `@internal` also a test seam.
7395
+ *
7396
+ * `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
7397
+ * receives a fresh access/refresh token pair. Carrying a `providerId` opts the
7398
+ * call into the upstream trace (so a failing refresh is diagnosable), and the
7399
+ * trace captures bodies verbatim — without this flag every refresh would write
7400
+ * a plaintext token pair into `upstream-trace.jsonl`.
7234
7401
  */
7235
7402
  buildRefreshFetch(providerId, accountId) {
7236
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId }));
7403
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
7237
7404
  }
7238
7405
  /**
7239
7406
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -7758,7 +7925,7 @@ var JsonSubscriptionCredentialStore = class {
7758
7925
  * `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
7759
7926
  * write incl. child 4's future refresh writes lands encrypted. */
7760
7927
  persist(config) {
7761
- (0, import_node_fs16.mkdirSync)((0, import_node_path10.dirname)(this.tokensPath), { recursive: true });
7928
+ (0, import_node_fs16.mkdirSync)((0, import_node_path9.dirname)(this.tokensPath), { recursive: true });
7762
7929
  const encrypted = encryptTokens(config, this.box);
7763
7930
  (0, import_node_fs16.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
7764
7931
  }
@@ -7793,6 +7960,124 @@ var JsonSubscriptionCredentialStore = class {
7793
7960
  // src/AccountHealthProbeScheduler.ts
7794
7961
  var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
7795
7962
 
7963
+ // src/probe/CodexGenerationProbe.ts
7964
+ var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
7965
+ var CODEX_GENERATION_PROBE_MODEL = "gpt-5.6-luna";
7966
+ var CODEX_GENERATION_PROBE_URL = "https://chatgpt.com/backend-api/codex/responses";
7967
+ var MAX_STREAM_BYTES = 256 * 1024;
7968
+ var PROBE_INSTRUCTION = "Return exactly PONG and no other text.";
7969
+ function buildCodexGenerationProbeInit(token, signal) {
7970
+ return {
7971
+ method: "POST",
7972
+ signal,
7973
+ headers: {
7974
+ ...import_codexCliHeaders.DEFAULT_CODEX_CLI_HEADERS,
7975
+ Authorization: `Bearer ${token}`,
7976
+ Accept: (0, import_codexCliHeaders.codexAcceptHeader)(true),
7977
+ "Content-Type": "application/json"
7978
+ },
7979
+ body: JSON.stringify({
7980
+ model: CODEX_GENERATION_PROBE_MODEL,
7981
+ input: [
7982
+ {
7983
+ role: "developer",
7984
+ content: [{ type: "input_text", text: PROBE_INSTRUCTION }]
7985
+ },
7986
+ {
7987
+ role: "user",
7988
+ content: [{ type: "input_text", text: "Connection probe." }]
7989
+ }
7990
+ ],
7991
+ // GPT-5.6 otherwise defaults to medium reasoning. A connectivity probe
7992
+ // needs the lowest-cost path and no tool reasoning.
7993
+ reasoning: { effort: "none" },
7994
+ stream: true,
7995
+ store: false
7996
+ })
7997
+ };
7998
+ }
7999
+ async function readCodexGenerationProbeStream(response) {
8000
+ if (!response.body) return { completed: false, outputChars: 0 };
8001
+ const reader = response.body.getReader();
8002
+ const decoder = new TextDecoder();
8003
+ let buffer = "";
8004
+ let bytes = 0;
8005
+ let outputChars = 0;
8006
+ try {
8007
+ while (true) {
8008
+ const { done, value } = await reader.read();
8009
+ if (done) break;
8010
+ bytes += value.byteLength;
8011
+ if (bytes > MAX_STREAM_BYTES) {
8012
+ await reader.cancel();
8013
+ return { completed: false, outputChars };
8014
+ }
8015
+ buffer += decoder.decode(value, { stream: true });
8016
+ buffer = buffer.replace(/\r\n/g, "\n");
8017
+ let boundary = buffer.indexOf("\n\n");
8018
+ while (boundary >= 0) {
8019
+ const block = buffer.slice(0, boundary);
8020
+ buffer = buffer.slice(boundary + 2);
8021
+ const event = parseSseBlock(block);
8022
+ if (event) {
8023
+ const type = event["type"];
8024
+ if (type === "response.output_text.delta" && typeof event["delta"] === "string") {
8025
+ outputChars += event["delta"].length;
8026
+ } else if (type === "response.output_text.done" && typeof event["text"] === "string") {
8027
+ outputChars = Math.max(outputChars, event["text"].length);
8028
+ } else if (type === "response.failed" || type === "error") {
8029
+ await reader.cancel();
8030
+ return { completed: false, outputChars };
8031
+ } else if (type === "response.completed") {
8032
+ const completedResponse = asRecord(event["response"]);
8033
+ const status = completedResponse?.["status"];
8034
+ outputChars = Math.max(outputChars, countCompletedOutputChars(completedResponse));
8035
+ await reader.cancel();
8036
+ return {
8037
+ completed: (status === void 0 || status === "completed") && outputChars > 0,
8038
+ outputChars
8039
+ };
8040
+ }
8041
+ }
8042
+ boundary = buffer.indexOf("\n\n");
8043
+ }
8044
+ }
8045
+ } catch {
8046
+ return { completed: false, outputChars };
8047
+ } finally {
8048
+ reader.releaseLock();
8049
+ }
8050
+ return { completed: false, outputChars };
8051
+ }
8052
+ function parseSseBlock(block) {
8053
+ const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
8054
+ if (!data || data === "[DONE]") return null;
8055
+ try {
8056
+ return JSON.parse(data);
8057
+ } catch {
8058
+ return null;
8059
+ }
8060
+ }
8061
+ function asRecord(value) {
8062
+ return value !== null && typeof value === "object" ? value : void 0;
8063
+ }
8064
+ function countCompletedOutputChars(response) {
8065
+ const output = response?.["output"];
8066
+ if (!Array.isArray(output)) return 0;
8067
+ let chars = 0;
8068
+ for (const item of output) {
8069
+ const content = asRecord(item)?.["content"];
8070
+ if (!Array.isArray(content)) continue;
8071
+ for (const part of content) {
8072
+ const record = asRecord(part);
8073
+ if (record?.["type"] === "output_text" && typeof record["text"] === "string") {
8074
+ chars += record["text"].length;
8075
+ }
8076
+ }
8077
+ }
8078
+ return chars;
8079
+ }
8080
+
7796
8081
  // src/probe/ProbeStrategy.ts
7797
8082
  var PROVIDER_PROBE_PLANS = {
7798
8083
  claude: {
@@ -7920,17 +8205,17 @@ var AccountHealthProbeScheduler = class {
7920
8205
  }
7921
8206
  if (readThrew) {
7922
8207
  this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
7923
- return { ok: false, marked: false };
8208
+ return { ok: false, marked: false, tier: "local" };
7924
8209
  }
7925
8210
  if (!token) {
7926
8211
  this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
7927
8212
  this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
7928
- return { ok: false, marked: true };
8213
+ return { ok: false, marked: true, tier: "local" };
7929
8214
  }
7930
8215
  const plan = this.planFor(providerId);
7931
8216
  if (plan.kind === "local") {
7932
8217
  this.record(providerId, accountId, { ts: now, ok: true, tier: "local" });
7933
- return { ok: true, marked: false };
8218
+ return { ok: true, marked: false, tier: "local" };
7934
8219
  }
7935
8220
  const start = this.now();
7936
8221
  let status = null;
@@ -7955,7 +8240,60 @@ var AccountHealthProbeScheduler = class {
7955
8240
  latencyMs,
7956
8241
  tier: "upstream"
7957
8242
  });
7958
- return { ok: status !== null && status < 400, marked };
8243
+ return { ok: status !== null && status < 400, marked, tier: "upstream" };
8244
+ }
8245
+ /**
8246
+ * Manual connection test. Codex performs a real, quota-consuming generation;
8247
+ * every other provider keeps its existing cheap probe. Scheduled sweeps never
8248
+ * call this method, so they remain non-billable.
8249
+ */
8250
+ async testAccountConnection(providerId, accountId) {
8251
+ if (providerId !== "codex") return this.probeAccount(providerId, accountId);
8252
+ const now = this.now();
8253
+ let token;
8254
+ try {
8255
+ token = await this.store.getAccessTokenForAccount(providerId, accountId);
8256
+ } catch {
8257
+ this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
8258
+ return { ok: false, marked: false, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8259
+ }
8260
+ if (!token) {
8261
+ this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
8262
+ this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
8263
+ return { ok: false, marked: true, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
8264
+ }
8265
+ const startedAt = this.now();
8266
+ let attempt = await this.runCodexGenerationAttempt(accountId, token);
8267
+ if (attempt.status === 401 && this.store.refreshAccountToken) {
8268
+ try {
8269
+ if (await this.store.refreshAccountToken(providerId, accountId)) {
8270
+ const refreshed = await this.store.getAccessTokenForAccount(providerId, accountId);
8271
+ if (refreshed) attempt = await this.runCodexGenerationAttempt(accountId, refreshed);
8272
+ }
8273
+ } catch {
8274
+ }
8275
+ }
8276
+ const latencyMs = this.now() - startedAt;
8277
+ const ok = attempt.status !== null && attempt.status >= 200 && attempt.status < 300 && attempt.completed;
8278
+ let marked = false;
8279
+ if (ok) {
8280
+ this.health.clearTransientMark(providerId, accountId);
8281
+ } else if (attempt.status === 401 || attempt.status === 403) {
8282
+ marked = this.applyOutcome(providerId, accountId, attempt.status, attempt.bodyText, now);
8283
+ }
8284
+ this.record(providerId, accountId, {
8285
+ ts: now,
8286
+ ok,
8287
+ status: attempt.status,
8288
+ latencyMs,
8289
+ tier: "generation"
8290
+ });
8291
+ return {
8292
+ ok,
8293
+ marked,
8294
+ tier: "generation",
8295
+ model: CODEX_GENERATION_PROBE_MODEL
8296
+ };
7959
8297
  }
7960
8298
  /** Per-account rolling history for the authed admin surface (design D5). */
7961
8299
  getAllHistory() {
@@ -8012,6 +8350,24 @@ var AccountHealthProbeScheduler = class {
8012
8350
  return "";
8013
8351
  }
8014
8352
  }
8353
+ async runCodexGenerationAttempt(accountId, token) {
8354
+ try {
8355
+ const timeoutMs = Math.max(this.config.timeoutMs, 15e3);
8356
+ const response = await this.fetchImpl(
8357
+ CODEX_GENERATION_PROBE_URL,
8358
+ buildCodexGenerationProbeInit(token, AbortSignal.timeout(timeoutMs)),
8359
+ { providerId: "codex", accountId, redactBodies: true }
8360
+ );
8361
+ if (response.status < 200 || response.status >= 300) {
8362
+ const bodyText = response.status === 403 ? await this.readBounded(response) : void 0;
8363
+ return { status: response.status, completed: false, bodyText };
8364
+ }
8365
+ const stream = await readCodexGenerationProbeStream(response);
8366
+ return { status: response.status, completed: stream.completed };
8367
+ } catch {
8368
+ return { status: null, completed: false };
8369
+ }
8370
+ }
8015
8371
  key(providerId, accountId) {
8016
8372
  return `${providerId}${KEY_SEP}${accountId}`;
8017
8373
  }
@@ -8107,7 +8463,7 @@ var AccountHealthSweeper = class {
8107
8463
  };
8108
8464
 
8109
8465
  // src/audit/AuditPruneSweeper.ts
8110
- var import_node_fs17 = require("fs");
8466
+ var import_node_fs18 = require("fs");
8111
8467
  var import_node_path11 = require("path");
8112
8468
 
8113
8469
  // src/audit/auditFiles.ts
@@ -8130,12 +8486,206 @@ function auditFileDateMs(fileName) {
8130
8486
  return d.getTime();
8131
8487
  }
8132
8488
 
8489
+ // src/audit/auditStats.ts
8490
+ var import_node_fs17 = require("fs");
8491
+ var import_node_path10 = require("path");
8492
+ var SIDECAR_VERSION = 1;
8493
+ var META_PREFIX_BYTES = 64 * 1024;
8494
+ var READ_CHUNK_BYTES = 4 * 1024 * 1024;
8495
+ function auditStatsFileName(auditFile) {
8496
+ return auditFile.replace(/\.jsonl$/, ".stats.json");
8497
+ }
8498
+ function readPersisted(path2) {
8499
+ if (!(0, import_node_fs17.existsSync)(path2)) return null;
8500
+ try {
8501
+ const value = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
8502
+ 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)) {
8503
+ return null;
8504
+ }
8505
+ return value;
8506
+ } catch {
8507
+ return null;
8508
+ }
8509
+ }
8510
+ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
8511
+ const statsPath = (0, import_node_path10.join)((0, import_node_path10.dirname)(auditPath), auditStatsFileName((0, import_node_path10.basename)(auditPath)));
8512
+ const previous = auditBytesBefore === 0 ? {
8513
+ version: SIDECAR_VERSION,
8514
+ auditBytes: 0,
8515
+ requestCount: 0,
8516
+ errorCount: 0,
8517
+ complete: true,
8518
+ minTs: null,
8519
+ maxTs: null
8520
+ } : readPersisted(statsPath);
8521
+ if (!previous || !previous.complete || previous.auditBytes !== auditBytesBefore) return;
8522
+ const next = {
8523
+ version: SIDECAR_VERSION,
8524
+ auditBytes: auditBytesAfter,
8525
+ requestCount: previous.requestCount + 1,
8526
+ errorCount: previous.errorCount + (record.status >= 400 || Boolean(record.error) ? 1 : 0),
8527
+ complete: true,
8528
+ minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
8529
+ maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
8530
+ };
8531
+ (0, import_node_fs17.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
8532
+ }
8533
+ function queryCovers(stats, from, to) {
8534
+ return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
8535
+ }
8536
+ function fileOverlaps(file, from, to) {
8537
+ const start = auditFileDateMs(file);
8538
+ if (start === null) return false;
8539
+ const date = new Date(start);
8540
+ const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
8541
+ return end > from && start <= to;
8542
+ }
8543
+ function parseMetadataPrefix(prefix, prefixTruncated) {
8544
+ const text = prefix.toString("utf8");
8545
+ const tsMatch = /(?:^|,)"ts":(-?\d+)/.exec(text);
8546
+ const statusMatch = /(?:^|,)"status":(-?\d+)/.exec(text);
8547
+ const errorMatch = /(?:^|,)"error":"((?:\\.|[^"\\])*)"/.exec(text);
8548
+ const bodyStarted = /,(?:"requestBody"|"responseBody"):/.test(text);
8549
+ return {
8550
+ ts: tsMatch ? Number(tsMatch[1]) : void 0,
8551
+ status: statusMatch ? Number(statusMatch[1]) : void 0,
8552
+ hasError: Boolean(errorMatch?.[1]),
8553
+ complete: Boolean(tsMatch && statusMatch && (!prefixTruncated || bodyStarted))
8554
+ };
8555
+ }
8556
+ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
8557
+ let requestCount = 0;
8558
+ let errorCount = 0;
8559
+ let filteredRequestCount = 0;
8560
+ let filteredErrorCount = 0;
8561
+ let minTs = null;
8562
+ let maxTs = null;
8563
+ let complete = true;
8564
+ let prefixParts = [];
8565
+ let prefixBytes = 0;
8566
+ let prefixTruncated = false;
8567
+ const consumeLine = () => {
8568
+ if (prefixBytes === 0 && !prefixTruncated) return;
8569
+ const prefix = Buffer.concat(prefixParts, prefixBytes);
8570
+ const metadata = parseMetadataPrefix(prefix, prefixTruncated);
8571
+ if (!metadata.complete || metadata.ts === void 0 || metadata.status === void 0) {
8572
+ complete = false;
8573
+ } else {
8574
+ requestCount += 1;
8575
+ const isError = metadata.status >= 400 || metadata.hasError;
8576
+ if (isError) errorCount += 1;
8577
+ minTs = minTs === null ? metadata.ts : Math.min(minTs, metadata.ts);
8578
+ maxTs = maxTs === null ? metadata.ts : Math.max(maxTs, metadata.ts);
8579
+ if (metadata.ts >= from && metadata.ts <= to) {
8580
+ filteredRequestCount += 1;
8581
+ if (isError) filteredErrorCount += 1;
8582
+ }
8583
+ }
8584
+ prefixParts = [];
8585
+ prefixBytes = 0;
8586
+ prefixTruncated = false;
8587
+ };
8588
+ if (auditBytes > startByte) {
8589
+ const stream = (0, import_node_fs17.createReadStream)(auditPath, {
8590
+ start: startByte,
8591
+ end: auditBytes - 1,
8592
+ highWaterMark: READ_CHUNK_BYTES
8593
+ });
8594
+ for await (const value of stream) {
8595
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
8596
+ let offset = 0;
8597
+ while (offset < chunk.length) {
8598
+ const newline = chunk.indexOf(10, offset);
8599
+ const end = newline === -1 ? chunk.length : newline;
8600
+ if (prefixBytes < META_PREFIX_BYTES) {
8601
+ const retained = Math.min(META_PREFIX_BYTES - prefixBytes, end - offset);
8602
+ if (retained > 0) {
8603
+ prefixParts.push(Buffer.from(chunk.subarray(offset, offset + retained)));
8604
+ prefixBytes += retained;
8605
+ }
8606
+ if (retained < end - offset) prefixTruncated = true;
8607
+ } else if (end > offset) {
8608
+ prefixTruncated = true;
8609
+ }
8610
+ if (newline === -1) break;
8611
+ consumeLine();
8612
+ offset = newline + 1;
8613
+ }
8614
+ }
8615
+ }
8616
+ if (prefixBytes > 0 || prefixTruncated) complete = false;
8617
+ return {
8618
+ all: {
8619
+ version: SIDECAR_VERSION,
8620
+ auditBytes,
8621
+ requestCount,
8622
+ errorCount,
8623
+ complete,
8624
+ minTs,
8625
+ maxTs
8626
+ },
8627
+ filtered: { requestCount: filteredRequestCount, errorCount: filteredErrorCount, complete }
8628
+ };
8629
+ }
8630
+ function mergePersistedStats(previous, appended) {
8631
+ return {
8632
+ version: SIDECAR_VERSION,
8633
+ auditBytes: appended.auditBytes,
8634
+ requestCount: previous.requestCount + appended.requestCount,
8635
+ errorCount: previous.errorCount + appended.errorCount,
8636
+ complete: previous.complete && appended.complete,
8637
+ minTs: previous.minTs === null ? appended.minTs : appended.minTs === null ? previous.minTs : Math.min(previous.minTs, appended.minTs),
8638
+ maxTs: previous.maxTs === null ? appended.maxTs : appended.maxTs === null ? previous.maxTs : Math.max(previous.maxTs, appended.maxTs)
8639
+ };
8640
+ }
8641
+ async function readAuditStats(auditDir, query2 = {}) {
8642
+ if (!(0, import_node_fs17.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
8643
+ const from = typeof query2.from === "number" ? query2.from : -Infinity;
8644
+ const to = typeof query2.to === "number" ? query2.to : Infinity;
8645
+ let files;
8646
+ try {
8647
+ files = (0, import_node_fs17.readdirSync)(auditDir).filter((file) => AUDIT_FILE_RE.test(file) && fileOverlaps(file, from, to)).sort();
8648
+ } catch {
8649
+ return { requestCount: 0, errorCount: 0, complete: false };
8650
+ }
8651
+ const total = { requestCount: 0, errorCount: 0, complete: true };
8652
+ for (const file of files) {
8653
+ const auditPath = (0, import_node_path10.join)(auditDir, file);
8654
+ try {
8655
+ const auditBytes = (0, import_node_fs17.statSync)(auditPath).size;
8656
+ const statsPath = (0, import_node_path10.join)(auditDir, auditStatsFileName(file));
8657
+ const persisted = readPersisted(statsPath);
8658
+ if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
8659
+ total.requestCount += persisted.requestCount;
8660
+ total.errorCount += persisted.errorCount;
8661
+ continue;
8662
+ }
8663
+ const resumable = persisted && persisted.complete && persisted.auditBytes < auditBytes && queryCovers(persisted, from, to) ? persisted : null;
8664
+ const scanned = await scanAuditFile(
8665
+ auditPath,
8666
+ resumable?.auditBytes ?? 0,
8667
+ auditBytes,
8668
+ from,
8669
+ to
8670
+ );
8671
+ total.requestCount += scanned.filtered.requestCount + (resumable?.requestCount ?? 0);
8672
+ total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
8673
+ total.complete = total.complete && scanned.filtered.complete;
8674
+ const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
8675
+ if (current.complete) (0, import_node_fs17.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
8676
+ } catch {
8677
+ total.complete = false;
8678
+ }
8679
+ }
8680
+ return total;
8681
+ }
8682
+
8133
8683
  // src/audit/AuditPruneSweeper.ts
8134
8684
  var DAY_MS = 24 * 60 * 6e4;
8135
8685
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
8136
8686
  var AuditPruneSweeper = class {
8137
- constructor(auditDir2, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
8138
- this.auditDir = auditDir2;
8687
+ constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
8688
+ this.auditDir = auditDir;
8139
8689
  this.logger = logger;
8140
8690
  this.config = config;
8141
8691
  this.intervalMs = intervalMs;
@@ -8182,17 +8732,19 @@ var AuditPruneSweeper = class {
8182
8732
  if (!this.config.enabled || this.sweeping) return 0;
8183
8733
  this.sweeping = true;
8184
8734
  try {
8185
- if (!(0, import_node_fs17.existsSync)(this.auditDir)) return 0;
8735
+ if (!(0, import_node_fs18.existsSync)(this.auditDir)) return 0;
8186
8736
  const today = new Date(this.now());
8187
8737
  const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
8188
8738
  const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
8189
8739
  let removed = 0;
8190
- for (const file of (0, import_node_fs17.readdirSync)(this.auditDir)) {
8740
+ for (const file of (0, import_node_fs18.readdirSync)(this.auditDir)) {
8191
8741
  const dateMs = auditFileDateMs(file);
8192
8742
  if (dateMs === null || dateMs >= cutoff) continue;
8193
8743
  try {
8194
- (0, import_node_fs17.unlinkSync)((0, import_node_path11.join)(this.auditDir, file));
8744
+ (0, import_node_fs18.unlinkSync)((0, import_node_path11.join)(this.auditDir, file));
8195
8745
  removed += 1;
8746
+ const statsPath = (0, import_node_path11.join)(this.auditDir, auditStatsFileName(file));
8747
+ if ((0, import_node_fs18.existsSync)(statsPath)) (0, import_node_fs18.unlinkSync)(statsPath);
8196
8748
  } catch (error) {
8197
8749
  this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
8198
8750
  file,
@@ -8214,15 +8766,15 @@ var AuditPruneSweeper = class {
8214
8766
  };
8215
8767
 
8216
8768
  // src/audit/auditReader.ts
8217
- var import_node_fs18 = require("fs");
8769
+ var import_node_fs19 = require("fs");
8218
8770
  var import_node_path12 = require("path");
8219
8771
  var DEFAULT_LIMIT = 200;
8220
8772
  var MAX_LIMIT = 2e3;
8221
- function readAuditRecords(auditDir2, query2 = {}) {
8222
- if (!(0, import_node_fs18.existsSync)(auditDir2)) return [];
8773
+ function readAuditRecords(auditDir, query2 = {}) {
8774
+ if (!(0, import_node_fs19.existsSync)(auditDir)) return [];
8223
8775
  let files;
8224
8776
  try {
8225
- files = (0, import_node_fs18.readdirSync)(auditDir2).filter((f) => AUDIT_FILE_RE.test(f));
8777
+ files = (0, import_node_fs19.readdirSync)(auditDir).filter((f) => AUDIT_FILE_RE.test(f));
8226
8778
  } catch {
8227
8779
  return [];
8228
8780
  }
@@ -8233,7 +8785,7 @@ function readAuditRecords(auditDir2, query2 = {}) {
8233
8785
  for (const file of files.sort().reverse()) {
8234
8786
  let raw;
8235
8787
  try {
8236
- raw = (0, import_node_fs18.readFileSync)((0, import_node_path12.join)(auditDir2, file), "utf8");
8788
+ raw = (0, import_node_fs19.readFileSync)((0, import_node_path12.join)(auditDir, file), "utf8");
8237
8789
  } catch {
8238
8790
  continue;
8239
8791
  }
@@ -8262,11 +8814,11 @@ function isAuditRecord(value) {
8262
8814
  }
8263
8815
 
8264
8816
  // src/audit/AuditWriter.ts
8265
- var import_node_fs19 = require("fs");
8817
+ var import_node_fs20 = require("fs");
8266
8818
  var import_node_path13 = require("path");
8267
8819
  var AuditWriter = class {
8268
- constructor(auditDir2, logger, defer = (fn) => setTimeout(fn, 0)) {
8269
- this.auditDir = auditDir2;
8820
+ constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
8821
+ this.auditDir = auditDir;
8270
8822
  this.logger = logger;
8271
8823
  this.defer = defer;
8272
8824
  }
@@ -8296,16 +8848,30 @@ var AuditWriter = class {
8296
8848
  */
8297
8849
  appendNow(record) {
8298
8850
  if (!this.dirEnsured) {
8299
- (0, import_node_fs19.mkdirSync)(this.auditDir, { recursive: true });
8851
+ (0, import_node_fs20.mkdirSync)(this.auditDir, { recursive: true });
8300
8852
  this.dirEnsured = true;
8301
8853
  }
8302
8854
  const file = (0, import_node_path13.join)(this.auditDir, auditFileName(record.ts));
8303
- (0, import_node_fs19.appendFileSync)(file, JSON.stringify(record) + "\n", "utf8");
8855
+ const line = JSON.stringify(record) + "\n";
8856
+ const auditBytesBefore = (0, import_node_fs20.existsSync)(file) ? (0, import_node_fs20.statSync)(file).size : 0;
8857
+ (0, import_node_fs20.appendFileSync)(file, line, "utf8");
8858
+ try {
8859
+ updateAuditStatsAfterAppend(
8860
+ file,
8861
+ auditBytesBefore,
8862
+ auditBytesBefore + Buffer.byteLength(line, "utf8"),
8863
+ record
8864
+ );
8865
+ } catch (error) {
8866
+ this.logger.warn("[AuditWriter] failed to update audit stats", {
8867
+ error: error instanceof Error ? error.message : String(error)
8868
+ });
8869
+ }
8304
8870
  }
8305
8871
  };
8306
8872
 
8307
8873
  // src/billing/BillingPublisher.ts
8308
- var import_node_fs20 = require("fs");
8874
+ var import_node_fs21 = require("fs");
8309
8875
  var import_node_crypto13 = require("crypto");
8310
8876
  var import_node_path14 = require("path");
8311
8877
  var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -8379,7 +8945,7 @@ var BillingPublisher = class {
8379
8945
  appendNow(event) {
8380
8946
  this.ensureDir();
8381
8947
  const file = (0, import_node_path14.join)(this.billingDir, billingFileName(event.ts));
8382
- (0, import_node_fs20.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
8948
+ (0, import_node_fs21.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
8383
8949
  }
8384
8950
  /**
8385
8951
  * One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
@@ -8429,7 +8995,7 @@ var BillingPublisher = class {
8429
8995
  try {
8430
8996
  this.ensureDir();
8431
8997
  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");
8998
+ (0, import_node_fs21.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
8433
8999
  } catch (error) {
8434
9000
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
8435
9001
  error: error instanceof Error ? error.message : String(error)
@@ -8438,20 +9004,20 @@ var BillingPublisher = class {
8438
9004
  }
8439
9005
  ensureDir() {
8440
9006
  if (this.dirEnsured) return;
8441
- (0, import_node_fs20.mkdirSync)(this.billingDir, { recursive: true });
9007
+ (0, import_node_fs21.mkdirSync)(this.billingDir, { recursive: true });
8442
9008
  this.dirEnsured = true;
8443
9009
  }
8444
9010
  };
8445
9011
 
8446
9012
  // src/billing/billingReader.ts
8447
- var import_node_fs21 = require("fs");
9013
+ var import_node_fs22 = require("fs");
8448
9014
  var import_node_path15 = require("path");
8449
9015
  function readBillingLedger(billingDir) {
8450
9016
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
8451
- if (!(0, import_node_fs21.existsSync)(billingDir)) return view;
9017
+ if (!(0, import_node_fs22.existsSync)(billingDir)) return view;
8452
9018
  let files;
8453
9019
  try {
8454
- files = (0, import_node_fs21.readdirSync)(billingDir);
9020
+ files = (0, import_node_fs22.readdirSync)(billingDir);
8455
9021
  } catch {
8456
9022
  return view;
8457
9023
  }
@@ -8482,7 +9048,7 @@ function readBillingStatus(billingDir) {
8482
9048
  function parseLines(dir, file) {
8483
9049
  let raw;
8484
9050
  try {
8485
- raw = (0, import_node_fs21.readFileSync)((0, import_node_path15.join)(dir, file), "utf8");
9051
+ raw = (0, import_node_fs22.readFileSync)((0, import_node_path15.join)(dir, file), "utf8");
8486
9052
  } catch {
8487
9053
  return [];
8488
9054
  }
@@ -8854,7 +9420,7 @@ function buildDaemon(config, paths) {
8854
9420
  (0, import_outbound_api4.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
8855
9421
  );
8856
9422
  const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
8857
- const keyDb = new JsonOutboundKeyDb(paths.keysPath);
9423
+ const keyDb = new JsonOutboundKeyDb(paths.keysPath, secretBox3);
8858
9424
  const voucherDb = new JsonVoucherDb(defaultVouchersPath(paths.configPath));
8859
9425
  const settingsStore = new JsonApiServerSettingsStore(paths.configPath, secretBox3);
8860
9426
  const integrationStateStore = new IntegrationStateStore(
@@ -8955,7 +9521,7 @@ function buildDaemon(config, paths) {
8955
9521
  // lines through the injected logger (honors level/format/file sink).
8956
9522
  logger
8957
9523
  });
8958
- const auditDir2 = defaultAuditDir(paths.configPath);
9524
+ const auditDir = defaultAuditDir(paths.configPath);
8959
9525
  const billingDir = defaultBillingDir(paths.configPath);
8960
9526
  const adminServer = new AdminServer({
8961
9527
  configPath: paths.configPath,
@@ -8989,10 +9555,16 @@ function buildDaemon(config, paths) {
8989
9555
  // (NOT widening the least-authority writer — no token-returning read reachable).
8990
9556
  oauthSessions: new OAuthSessionStore(),
8991
9557
  // 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)),
9558
+ // inject a mock so no real token endpoint is hit (one FetchLike for every
9559
+ // provider the ctx below only matters on the real egress path).
9560
+ //
9561
+ // upstream-proxy: a PER-PROVIDER factory, so the exchange carries the same
9562
+ // `{ providerId }` ctx the CLI login and the token refresh already pass.
9563
+ // Without it the interactive login resolved only the global/env proxy layers
9564
+ // — `server.proxy.byProvider[...]` was silently skipped — and the call was
9565
+ // excluded from the upstream trace, so a failing login left no evidence.
9566
+ // `redactBodies` keeps the code/verifier + minted token out of that trace.
9567
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId, redactBodies: true }),
8996
9568
  subscriptionAccountAppender: credentialStore,
8997
9569
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
8998
9570
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -9044,7 +9616,8 @@ function buildDaemon(config, paths) {
9044
9616
  // date-rotated audit store. Bound to the store dir here so the AdminServer
9045
9617
  // carries no path/store coupling. Records hold IP/UA/bodies → admin-only,
9046
9618
  // NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
9047
- auditReader: (query2) => readAuditRecords(auditDir2, query2),
9619
+ auditReader: (query2) => readAuditRecords(auditDir, query2),
9620
+ auditStatsReader: (query2) => readAuditStats(auditDir, query2),
9048
9621
  // billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
9049
9622
  // secret-free total/delivered/pending counts of the durable ledger.
9050
9623
  billingStatusReader: () => readBillingStatus(billingDir)
@@ -9054,9 +9627,9 @@ function buildDaemon(config, paths) {
9054
9627
  fetchImpl: (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)
9055
9628
  });
9056
9629
  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);
9630
+ const auditWriter = new AuditWriter(auditDir, logger);
9631
+ const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
9632
+ setAuditRuntime(auditWriter, auditPruneSweeper);
9060
9633
  const billingPublisher = new BillingPublisher(billingDir, logger);
9061
9634
  const billingRetrySweeper = new BillingRetrySweeper(
9062
9635
  billingDir,
@@ -9120,8 +9693,8 @@ function resetDaemonSingletonsForTests() {
9120
9693
  }
9121
9694
  function isTokensStoreReadable(tokensPath) {
9122
9695
  try {
9123
- if (!(0, import_node_fs22.existsSync)(tokensPath)) return true;
9124
- (0, import_node_fs22.accessSync)(tokensPath, import_node_fs22.constants.R_OK);
9696
+ if (!(0, import_node_fs23.existsSync)(tokensPath)) return true;
9697
+ (0, import_node_fs23.accessSync)(tokensPath, import_node_fs23.constants.R_OK);
9125
9698
  return true;
9126
9699
  } catch {
9127
9700
  return false;