@omnicross/daemon 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1166,26 +1166,26 @@ var import_http4 = require("@omnicross/core/search/http");
1166
1166
  var import_search3 = require("@omnicross/core/search");
1167
1167
 
1168
1168
  // src/bootstrap.ts
1169
- var import_node_fs35 = require("fs");
1169
+ var import_node_fs36 = require("fs");
1170
1170
  var import_node_path36 = require("path");
1171
1171
  var import_audit_types = require("@omnicross/contracts/audit-types");
1172
1172
  var import_billing_types = require("@omnicross/contracts/billing-types");
1173
- var import_core4 = require("@omnicross/core");
1173
+ var import_core7 = require("@omnicross/core");
1174
1174
  var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1175
1175
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
1176
1176
  var import_outbound_api10 = require("@omnicross/core/outbound-api");
1177
1177
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
1178
1178
  var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1179
- var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1179
+ var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1180
1180
  var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1181
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
1181
+ var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
1182
1182
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
1183
1183
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
1184
1184
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
1185
1185
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
1186
1186
  var import_outbound_api11 = require("@omnicross/core/outbound-api");
1187
1187
  var import_usage2 = require("@omnicross/core/usage");
1188
- var import_subscriptions6 = require("@omnicross/subscriptions");
1188
+ var import_subscriptions12 = require("@omnicross/subscriptions");
1189
1189
 
1190
1190
  // src/admin/accountsCodexOAuth.ts
1191
1191
  var import_node_crypto3 = __toESM(require("crypto"), 1);
@@ -1292,8 +1292,262 @@ function handleCodexOAuthStatus(sessionId, deps) {
1292
1292
  return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
1293
1293
  }
1294
1294
 
1295
+ // src/admin/accountsKimiOAuth.ts
1296
+ var import_subscriptions2 = require("@omnicross/subscriptions");
1297
+ function err2(status, message) {
1298
+ return { status, body: { error: { type: "admin_api_error", message } } };
1299
+ }
1300
+ var DEFAULT_KIMI_OAUTH_TTL_MS = 15 * 6e4;
1301
+ async function handleKimiOAuthStart(deps) {
1302
+ if (deps.kimiSessions.isBusy()) {
1303
+ return err2(409, "a kimi sign-in is already in progress \u2014 finish it in the browser or cancel it");
1304
+ }
1305
+ const fetchImpl = deps.oauthExchangeFetch("kimi");
1306
+ const deviceId = import_subscriptions2.kimiOAuth.generateKimiDeviceId();
1307
+ const fingerprint = import_subscriptions2.kimiOAuth.kimiFingerprintHeaders(deviceId);
1308
+ let authorization;
1309
+ try {
1310
+ authorization = await import_subscriptions2.kimiOAuth.requestDeviceAuthorization(fetchImpl, fingerprint);
1311
+ } catch (e) {
1312
+ const reason = e instanceof Error ? e.message : "device authorization failed";
1313
+ return err2(502, `kimi device authorization failed: ${reason}`);
1314
+ }
1315
+ const { sessionId, signal } = deps.kimiSessions.begin();
1316
+ void runKimiDevicePoll(sessionId, authorization.deviceCode, deviceId, fingerprint, signal, deps).catch(() => deps.kimiSessions.settle(sessionId, "error", "kimi sign-in failed"));
1317
+ return {
1318
+ status: 200,
1319
+ body: {
1320
+ authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
1321
+ userCode: authorization.userCode,
1322
+ sessionId
1323
+ }
1324
+ };
1325
+ }
1326
+ async function runKimiDevicePoll(sessionId, deviceCode, deviceId, fingerprint, signal, deps) {
1327
+ const fetchImpl = deps.oauthExchangeFetch("kimi");
1328
+ const result = await import_subscriptions2.kimiOAuth.awaitDeviceToken(
1329
+ { userCode: "", deviceCode, verificationUri: "" },
1330
+ fetchImpl,
1331
+ {
1332
+ fingerprint,
1333
+ deadlineMs: DEFAULT_KIMI_OAUTH_TTL_MS,
1334
+ sleep: (ms) => new Promise((resolve11, reject) => {
1335
+ const onAbort = () => {
1336
+ clearTimeout(timer);
1337
+ reject(new Error("login: cancelled"));
1338
+ };
1339
+ const timer = setTimeout(() => {
1340
+ signal.removeEventListener("abort", onAbort);
1341
+ resolve11();
1342
+ }, ms);
1343
+ signal.addEventListener("abort", onAbort, { once: true });
1344
+ })
1345
+ }
1346
+ );
1347
+ const block = {
1348
+ authMethod: "oauth",
1349
+ status: "authorized",
1350
+ accessToken: result.accessToken,
1351
+ refreshToken: result.refreshToken,
1352
+ expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
1353
+ accountId: import_subscriptions2.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
1354
+ deviceId,
1355
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
1356
+ };
1357
+ await deps.subscriptionAccountAppender.appendProviderAccount("kimi", block);
1358
+ deps.kimiSessions.settle(sessionId, "done");
1359
+ }
1360
+ function handleKimiOAuthCancel(sessionId, deps) {
1361
+ if (!deps.kimiSessions.cancel(sessionId)) return err2(404, "unknown or expired kimi sign-in session");
1362
+ return { status: 200, body: { ok: true } };
1363
+ }
1364
+ function handleKimiOAuthStatus(sessionId, deps) {
1365
+ const s = deps.kimiSessions.get(sessionId);
1366
+ if (!s) return err2(404, "unknown or expired kimi sign-in session");
1367
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
1368
+ }
1369
+
1370
+ // src/admin/accountsGrokOAuth.ts
1371
+ var import_subscriptions3 = require("@omnicross/subscriptions");
1372
+ function err3(status, message) {
1373
+ return { status, body: { error: { type: "admin_api_error", message } } };
1374
+ }
1375
+ var DEFAULT_GROK_OAUTH_TTL_MS = 15 * 6e4;
1376
+ async function handleGrokOAuthStart(deps) {
1377
+ if (deps.grokSessions.isBusy()) {
1378
+ return err3(409, "a grok sign-in is already in progress \u2014 finish it in the browser or cancel it");
1379
+ }
1380
+ const fetchImpl = deps.oauthExchangeFetch("grok");
1381
+ let tokenEndpoint;
1382
+ try {
1383
+ tokenEndpoint = await import_subscriptions3.grokOAuth.resolveGrokTokenEndpoint(fetchImpl);
1384
+ } catch (e) {
1385
+ const reason = e instanceof Error ? e.message : "OIDC discovery failed";
1386
+ return err3(502, `grok token-endpoint discovery failed: ${reason}`);
1387
+ }
1388
+ let authorization;
1389
+ try {
1390
+ authorization = await import_subscriptions3.grokOAuth.requestGrokDeviceAuthorization(fetchImpl);
1391
+ } catch (e) {
1392
+ const reason = e instanceof Error ? e.message : "device authorization failed";
1393
+ return err3(502, `grok device authorization failed: ${reason}`);
1394
+ }
1395
+ const { sessionId, signal } = deps.grokSessions.begin();
1396
+ void runGrokDevicePoll(sessionId, tokenEndpoint, authorization.deviceCode, signal, deps).catch((e) => {
1397
+ const reason = e instanceof Error ? e.message : "grok sign-in failed";
1398
+ deps.grokSessions.settle(sessionId, "error", reason);
1399
+ });
1400
+ return {
1401
+ status: 200,
1402
+ body: {
1403
+ authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
1404
+ userCode: authorization.userCode,
1405
+ sessionId
1406
+ }
1407
+ };
1408
+ }
1409
+ async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, deps) {
1410
+ const fetchImpl = deps.oauthExchangeFetch("grok");
1411
+ const result = await import_subscriptions3.grokOAuth.awaitGrokDeviceToken(
1412
+ { userCode: "", deviceCode, verificationUri: "" },
1413
+ tokenEndpoint,
1414
+ fetchImpl,
1415
+ {
1416
+ deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
1417
+ sleep: (ms) => new Promise((resolve11, reject) => {
1418
+ const onAbort = () => {
1419
+ clearTimeout(timer);
1420
+ reject(new Error("login: cancelled"));
1421
+ };
1422
+ const timer = setTimeout(() => {
1423
+ signal.removeEventListener("abort", onAbort);
1424
+ resolve11();
1425
+ }, ms);
1426
+ signal.addEventListener("abort", onAbort, { once: true });
1427
+ })
1428
+ }
1429
+ );
1430
+ const block = {
1431
+ authMethod: "oauth",
1432
+ status: "authorized",
1433
+ accessToken: result.accessToken,
1434
+ refreshToken: result.refreshToken,
1435
+ expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
1436
+ accountId: import_subscriptions3.grokOAuth.grokAccountIdFromAccessToken(result.accessToken),
1437
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
1438
+ };
1439
+ await deps.subscriptionAccountAppender.appendProviderAccount("grok", block);
1440
+ deps.grokSessions.settle(sessionId, "done");
1441
+ }
1442
+ function handleGrokOAuthCancel(sessionId, deps) {
1443
+ if (!deps.grokSessions.cancel(sessionId)) return err3(404, "unknown or expired grok sign-in session");
1444
+ return { status: 200, body: { ok: true } };
1445
+ }
1446
+ function handleGrokOAuthStatus(sessionId, deps) {
1447
+ const s = deps.grokSessions.get(sessionId);
1448
+ if (!s) return err3(404, "unknown or expired grok sign-in session");
1449
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
1450
+ }
1451
+
1452
+ // src/admin/accountsCopilotOAuth.ts
1453
+ var import_subscriptions4 = require("@omnicross/subscriptions");
1454
+ function err4(status, message) {
1455
+ return { status, body: { error: { type: "admin_api_error", message } } };
1456
+ }
1457
+ var DEFAULT_COPILOT_OAUTH_TTL_MS = 15 * 6e4;
1458
+ async function handleCopilotOAuthStart(deps, enterpriseUrlInput) {
1459
+ if (deps.copilotSessions.isBusy()) {
1460
+ return err4(409, "a copilot sign-in is already in progress \u2014 finish it in the browser or cancel it");
1461
+ }
1462
+ let enterpriseUrl;
1463
+ if (typeof enterpriseUrlInput === "string" && enterpriseUrlInput.trim()) {
1464
+ try {
1465
+ enterpriseUrl = import_subscriptions4.copilotOAuth.normalizeCopilotEnterpriseDomain(enterpriseUrlInput);
1466
+ } catch (e) {
1467
+ const reason = e instanceof Error ? e.message : "invalid GitHub Enterprise domain";
1468
+ return err4(400, `copilot ${reason}`);
1469
+ }
1470
+ }
1471
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
1472
+ let authorization;
1473
+ try {
1474
+ authorization = await import_subscriptions4.copilotOAuth.requestCopilotDeviceAuthorization(fetchImpl, enterpriseUrl);
1475
+ } catch (e) {
1476
+ const reason = e instanceof Error ? e.message : "device authorization failed";
1477
+ return err4(502, `copilot device authorization failed: ${reason}`);
1478
+ }
1479
+ const { sessionId, signal } = deps.copilotSessions.begin();
1480
+ void runCopilotDevicePoll(sessionId, authorization.deviceCode, signal, deps, enterpriseUrl).catch((e) => {
1481
+ const reason = e instanceof Error ? e.message : "copilot sign-in failed";
1482
+ deps.copilotSessions.settle(sessionId, "error", reason);
1483
+ });
1484
+ return {
1485
+ status: 200,
1486
+ body: {
1487
+ authUrl: authorization.verificationUri,
1488
+ userCode: authorization.userCode,
1489
+ sessionId,
1490
+ ...enterpriseUrl ? { enterpriseUrl } : {}
1491
+ }
1492
+ };
1493
+ }
1494
+ async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpriseUrl) {
1495
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
1496
+ const result = await import_subscriptions4.copilotOAuth.awaitCopilotDeviceToken(
1497
+ { userCode: "", deviceCode, verificationUri: "", interval: 5, expiresIn: 900 },
1498
+ fetchImpl,
1499
+ {
1500
+ deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
1501
+ ...enterpriseUrl ? { enterpriseUrl } : {},
1502
+ sleep: (ms) => new Promise((resolve11, reject) => {
1503
+ const onAbort = () => {
1504
+ clearTimeout(timer);
1505
+ reject(new Error("login: cancelled"));
1506
+ };
1507
+ const timer = setTimeout(() => {
1508
+ signal.removeEventListener("abort", onAbort);
1509
+ resolve11();
1510
+ }, ms);
1511
+ signal.addEventListener("abort", onAbort, { once: true });
1512
+ })
1513
+ }
1514
+ );
1515
+ const identity = await import_subscriptions4.copilotOAuth.fetchCopilotIdentity(result.accessToken, fetchImpl, enterpriseUrl);
1516
+ const apiEndpoint = await import_subscriptions4.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, fetchImpl, enterpriseUrl);
1517
+ await import_subscriptions4.copilotOAuth.enableAllCopilotModels(
1518
+ result.accessToken,
1519
+ { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
1520
+ fetchImpl
1521
+ );
1522
+ const block = {
1523
+ authMethod: "oauth",
1524
+ status: "authorized",
1525
+ accessToken: result.accessToken,
1526
+ refreshToken: result.accessToken,
1527
+ expiresAt: new Date(Date.now() + import_subscriptions4.copilotOAuth.COPILOT_FAR_FUTURE_MS).toISOString(),
1528
+ ...identity.accountId ? { accountId: identity.accountId } : {},
1529
+ ...identity.email ? { email: identity.email } : {},
1530
+ ...apiEndpoint ? { apiEndpoint } : {},
1531
+ ...enterpriseUrl ? { enterpriseUrl } : {},
1532
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
1533
+ };
1534
+ await deps.subscriptionAccountAppender.appendProviderAccount("copilot", block);
1535
+ deps.copilotSessions.settle(sessionId, "done");
1536
+ }
1537
+ function handleCopilotOAuthCancel(sessionId, deps) {
1538
+ if (!deps.copilotSessions.cancel(sessionId)) {
1539
+ return err4(404, "unknown or expired copilot sign-in session");
1540
+ }
1541
+ return { status: 200, body: { ok: true } };
1542
+ }
1543
+ function handleCopilotOAuthStatus(sessionId, deps) {
1544
+ const s = deps.copilotSessions.get(sessionId);
1545
+ if (!s) return err4(404, "unknown or expired copilot sign-in session");
1546
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
1547
+ }
1548
+
1295
1549
  // src/allowance/AccountAllowanceService.ts
1296
- var import_AccountAllowanceStore2 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1550
+ var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1297
1551
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1298
1552
 
1299
1553
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -1320,13 +1574,11 @@ function secondsUntil(instant, now) {
1320
1574
  function windowFromPayload(id, payload, now) {
1321
1575
  const usedPercent = finitePercent(payload?.utilization);
1322
1576
  const resetsAt = isoInstant(payload?.resets_at);
1323
- const isSonnet = id === "seven-day-sonnet";
1324
1577
  const isFiveHour = id === "five-hour";
1325
1578
  return {
1326
1579
  id,
1327
- label: isFiveHour ? "5 hours" : isSonnet ? "7 days \xB7 Sonnet" : "7 days",
1328
- scope: isSonnet ? "model-family" : "all",
1329
- modelFamily: isSonnet ? "sonnet" : void 0,
1580
+ label: isFiveHour ? "5 hours" : "7 days",
1581
+ scope: "all",
1330
1582
  usedPercent,
1331
1583
  windowMinutes: isFiveHour ? 5 * 60 : 7 * 24 * 60,
1332
1584
  resetsAt,
@@ -1334,6 +1586,44 @@ function windowFromPayload(id, payload, now) {
1334
1586
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1335
1587
  };
1336
1588
  }
1589
+ function limitEntryWindow(entries, kind) {
1590
+ const entry = entries.find((candidate) => candidate.kind === kind);
1591
+ if (!entry) return void 0;
1592
+ return { utilization: entry.percent, resets_at: entry.resets_at };
1593
+ }
1594
+ function slugifyDisplayName(name) {
1595
+ return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1596
+ }
1597
+ function scopedWeeklyWindows(entries, now) {
1598
+ const seen = /* @__PURE__ */ new Set();
1599
+ const windows = [];
1600
+ for (const entry of entries) {
1601
+ if (entry.kind !== "weekly_scoped") continue;
1602
+ const displayName = typeof entry.scope?.model?.display_name === "string" && entry.scope.model.display_name.trim() ? entry.scope.model.display_name.trim() : void 0;
1603
+ if (!displayName) continue;
1604
+ const slug = slugifyDisplayName(displayName);
1605
+ if (!slug || seen.has(slug)) continue;
1606
+ seen.add(slug);
1607
+ const usedPercent = finitePercent(entry.percent);
1608
+ const resetsAt = isoInstant(entry.resets_at);
1609
+ windows.push({
1610
+ id: `seven-day-${slug}`,
1611
+ label: `7 days \xB7 ${displayName}`,
1612
+ scope: "model-family",
1613
+ modelFamily: slug,
1614
+ usedPercent,
1615
+ windowMinutes: 7 * 24 * 60,
1616
+ resetsAt,
1617
+ remainingSeconds: secondsUntil(resetsAt, now),
1618
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1619
+ });
1620
+ }
1621
+ return windows;
1622
+ }
1623
+ function parseLimitEntries(raw) {
1624
+ if (!Array.isArray(raw)) return [];
1625
+ return raw.filter((entry) => !!entry && typeof entry === "object");
1626
+ }
1337
1627
  function emptyClaudeWindows(state) {
1338
1628
  return [
1339
1629
  {
@@ -1351,15 +1641,6 @@ function emptyClaudeWindows(state) {
1351
1641
  usedPercent: null,
1352
1642
  windowMinutes: 7 * 24 * 60,
1353
1643
  state
1354
- },
1355
- {
1356
- id: "seven-day-sonnet",
1357
- label: "7 days \xB7 Sonnet",
1358
- scope: "model-family",
1359
- modelFamily: "sonnet",
1360
- usedPercent: null,
1361
- windowMinutes: 7 * 24 * 60,
1362
- state
1363
1644
  }
1364
1645
  ];
1365
1646
  }
@@ -1440,6 +1721,9 @@ var ClaudeAllowanceCollector = class {
1440
1721
  }
1441
1722
  const now = this.now();
1442
1723
  const usage = payload;
1724
+ const limitEntries = parseLimitEntries(usage.limits);
1725
+ const fiveHour = usage.five_hour ?? limitEntryWindow(limitEntries, "session");
1726
+ const sevenDay = usage.seven_day ?? limitEntryWindow(limitEntries, "weekly_all");
1443
1727
  const snapshot = {
1444
1728
  providerId: "claude",
1445
1729
  accountId,
@@ -1447,10 +1731,10 @@ var ClaudeAllowanceCollector = class {
1447
1731
  observedAt: new Date(now).toISOString(),
1448
1732
  expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
1449
1733
  windows: [
1450
- windowFromPayload("five-hour", usage.five_hour, now),
1451
- windowFromPayload("seven-day", usage.seven_day, now),
1452
- windowFromPayload("seven-day-sonnet", usage.seven_day_sonnet, now)
1453
- ]
1734
+ windowFromPayload("five-hour", fiveHour, now),
1735
+ windowFromPayload("seven-day", sevenDay, now),
1736
+ ...scopedWeeklyWindows(limitEntries, now)
1737
+ ].slice(0, 8)
1454
1738
  };
1455
1739
  this.store.set(snapshot);
1456
1740
  return snapshot;
@@ -1501,9 +1785,1079 @@ var ClaudeAllowanceCollector = class {
1501
1785
  accountId,
1502
1786
  source: "oauth-usage-api",
1503
1787
  observedAt: new Date(now).toISOString(),
1504
- windows: emptyClaudeWindows("unsupported"),
1788
+ windows: emptyClaudeWindows("unsupported"),
1789
+ lastErrorCode: code
1790
+ };
1791
+ }
1792
+ };
1793
+
1794
+ // src/allowance/CodexAllowanceCollector.ts
1795
+ var import_AccountAllowanceStore2 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1796
+ var import_upstreamFetch2 = require("@omnicross/core/pipeline/upstreamFetch");
1797
+ var CODEX_ALLOWANCE_CACHE_MS = 5 * 6e4;
1798
+ var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
1799
+ var CODEX_CLI_USER_AGENT = "codex_cli_rs/0.144.5";
1800
+ function finiteNumber(value) {
1801
+ if (value === null || value === void 0 || value === "") return null;
1802
+ const parsed = typeof value === "number" ? value : Number(value);
1803
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
1804
+ }
1805
+ function finitePercent2(value) {
1806
+ const parsed = finiteNumber(value);
1807
+ return parsed !== null && parsed <= 100 ? parsed : null;
1808
+ }
1809
+ function epochMs(value) {
1810
+ return value > 1e11 ? value : value * 1e3;
1811
+ }
1812
+ function secondsUntil2(instant, now) {
1813
+ if (!instant) return void 0;
1814
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1815
+ }
1816
+ function decodeJwtClaims(token) {
1817
+ const parts = token.split(".");
1818
+ if (parts.length !== 3) return void 0;
1819
+ try {
1820
+ const json2 = Buffer.from(parts[1], "base64url").toString("utf8");
1821
+ const parsed = JSON.parse(json2);
1822
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
1823
+ } catch {
1824
+ return void 0;
1825
+ }
1826
+ }
1827
+ function chatgptAccountIdFromClaims(claims) {
1828
+ const auth = claims?.["https://api.openai.com/auth"];
1829
+ if (!auth || typeof auth !== "object") return void 0;
1830
+ const accountId = auth.chatgpt_account_id;
1831
+ return typeof accountId === "string" && accountId.trim() ? accountId.trim() : void 0;
1832
+ }
1833
+ function resolveCodexChatGptAccountId(tokens) {
1834
+ if (tokens.accountId?.trim()) return tokens.accountId.trim();
1835
+ if (tokens.idToken) {
1836
+ const fromIdToken = chatgptAccountIdFromClaims(decodeJwtClaims(tokens.idToken));
1837
+ if (fromIdToken) return fromIdToken;
1838
+ }
1839
+ if (tokens.accessToken) {
1840
+ return chatgptAccountIdFromClaims(decodeJwtClaims(tokens.accessToken));
1841
+ }
1842
+ return void 0;
1843
+ }
1844
+ function windowFromPayload2(id, payload, now) {
1845
+ const usedPercent = finitePercent2(payload?.used_percent);
1846
+ const resetAtSeconds = finiteNumber(payload?.reset_at);
1847
+ const resetAfterSeconds = finiteNumber(payload?.reset_after_seconds);
1848
+ const windowSeconds = finiteNumber(payload?.limit_window_seconds);
1849
+ const resetsAt = resetAtSeconds !== null && resetAtSeconds > 0 ? new Date(epochMs(resetAtSeconds)).toISOString() : resetAfterSeconds !== null && resetAfterSeconds > 0 ? new Date(now + resetAfterSeconds * 1e3).toISOString() : void 0;
1850
+ const windowMinutes = windowSeconds !== null && windowSeconds > 0 ? Math.round(windowSeconds / 60) : void 0;
1851
+ return {
1852
+ id,
1853
+ label: id === "primary" ? "Primary" : "Secondary",
1854
+ scope: "all",
1855
+ usedPercent,
1856
+ ...windowMinutes !== void 0 ? { windowMinutes } : {},
1857
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1858
+ remainingSeconds: secondsUntil2(resetsAt, now),
1859
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1860
+ };
1861
+ }
1862
+ var CodexAllowanceCollector = class {
1863
+ constructor(credentials, store = (0, import_AccountAllowanceStore2.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch2.fetchUpstream)(url, init, { providerId: "codex", accountId, redactBodies: true }), now = Date.now) {
1864
+ this.credentials = credentials;
1865
+ this.store = store;
1866
+ this.fetchImpl = fetchImpl;
1867
+ this.now = now;
1868
+ }
1869
+ credentials;
1870
+ store;
1871
+ fetchImpl;
1872
+ now;
1873
+ inFlight = /* @__PURE__ */ new Map();
1874
+ async collectMany(accounts, options = {}) {
1875
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1876
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1877
+ }
1878
+ collect(account, options = {}) {
1879
+ const now = this.now();
1880
+ const unsupported = account.tokens.authMethod !== "oauth";
1881
+ if (unsupported) {
1882
+ const existing = this.store.get("codex", account.id, now);
1883
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1884
+ return Promise.resolve(existing);
1885
+ }
1886
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1887
+ this.store.set(snapshot);
1888
+ return Promise.resolve(snapshot);
1889
+ }
1890
+ const cached = this.store.get("codex", account.id, now);
1891
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1892
+ return Promise.resolve(cached);
1893
+ }
1894
+ const running = this.inFlight.get(account.id);
1895
+ if (running) return running;
1896
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "codex_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1897
+ this.inFlight.set(account.id, promise);
1898
+ return promise;
1899
+ }
1900
+ /**
1901
+ * A response-header snapshot stays a valid cache hit only while fresh; an
1902
+ * active oauth-usage snapshot is honored on the same 5-minute cadence as
1903
+ * Claude's (the poll is cheap and quota is the scheduling input).
1904
+ */
1905
+ isCacheValid(snapshot, now, refreshAheadMs) {
1906
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1907
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1908
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1909
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1910
+ }
1911
+ async fetchAccount(accountId, tokens) {
1912
+ let accessToken = await this.credentials.getAccessTokenForAccount("codex", accountId);
1913
+ if (!accessToken) {
1914
+ return this.failureSnapshot(accountId, "codex_usage_token_unavailable", this.now());
1915
+ }
1916
+ let response = await this.request(accountId, accessToken, tokens);
1917
+ if (response.status === 401) {
1918
+ const refreshed = await this.credentials.refreshAccountToken("codex", accountId);
1919
+ if (!refreshed) {
1920
+ return this.failureSnapshot(accountId, "codex_usage_unauthorized", this.now());
1921
+ }
1922
+ accessToken = await this.credentials.getAccessTokenForAccount("codex", accountId);
1923
+ if (!accessToken) {
1924
+ return this.failureSnapshot(accountId, "codex_usage_token_unavailable", this.now());
1925
+ }
1926
+ response = await this.request(accountId, accessToken, tokens);
1927
+ }
1928
+ if (response.status === 403) {
1929
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "codex_usage_unsupported");
1930
+ this.store.set(snapshot2);
1931
+ return snapshot2;
1932
+ }
1933
+ if (!response.ok) {
1934
+ return this.failureSnapshot(accountId, "codex_usage_http_error", this.now());
1935
+ }
1936
+ let payload;
1937
+ try {
1938
+ payload = await response.json();
1939
+ } catch {
1940
+ return this.failureSnapshot(accountId, "codex_usage_invalid_response", this.now());
1941
+ }
1942
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
1943
+ return this.failureSnapshot(accountId, "codex_usage_invalid_response", this.now());
1944
+ }
1945
+ const now = this.now();
1946
+ const usage = payload.rate_limit;
1947
+ const previous = this.store.get("codex", accountId, now);
1948
+ const snapshot = {
1949
+ providerId: "codex",
1950
+ accountId,
1951
+ source: "oauth-usage-api",
1952
+ observedAt: new Date(now).toISOString(),
1953
+ expiresAt: new Date(now + CODEX_ALLOWANCE_CACHE_MS).toISOString(),
1954
+ windows: [
1955
+ windowFromPayload2("primary", usage?.primary_window ?? void 0, now),
1956
+ windowFromPayload2("secondary", usage?.secondary_window ?? void 0, now)
1957
+ ],
1958
+ // The wham payload has no ratio field; keep the passively-observed value.
1959
+ ...previous?.primaryOverSecondaryLimitPercent !== void 0 ? { primaryOverSecondaryLimitPercent: previous.primaryOverSecondaryLimitPercent } : {}
1960
+ };
1961
+ this.store.set(snapshot);
1962
+ return snapshot;
1963
+ }
1964
+ request(accountId, accessToken, tokens) {
1965
+ const headers = {
1966
+ Authorization: `Bearer ${accessToken}`,
1967
+ Accept: "application/json",
1968
+ "User-Agent": CODEX_CLI_USER_AGENT
1969
+ };
1970
+ const chatgptAccountId = resolveCodexChatGptAccountId(tokens);
1971
+ if (chatgptAccountId) headers["ChatGPT-Account-Id"] = chatgptAccountId;
1972
+ return this.fetchImpl(CODEX_USAGE_URL, {
1973
+ method: "GET",
1974
+ headers,
1975
+ signal: AbortSignal.timeout(15e3)
1976
+ }, accountId);
1977
+ }
1978
+ failureSnapshot(accountId, code, now) {
1979
+ const existing = this.store.get("codex", accountId, now);
1980
+ const snapshot = existing ? {
1981
+ ...existing,
1982
+ expiresAt: new Date(now + CODEX_ALLOWANCE_CACHE_MS).toISOString(),
1983
+ windows: existing.windows.map((window) => ({
1984
+ ...window,
1985
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1986
+ })),
1987
+ lastErrorCode: code
1988
+ } : {
1989
+ providerId: "codex",
1990
+ accountId,
1991
+ source: "oauth-usage-api",
1992
+ observedAt: new Date(now).toISOString(),
1993
+ expiresAt: new Date(now + CODEX_ALLOWANCE_CACHE_MS).toISOString(),
1994
+ windows: [
1995
+ { id: "primary", label: "Primary", scope: "all", usedPercent: null, state: "unavailable" },
1996
+ { id: "secondary", label: "Secondary", scope: "all", usedPercent: null, state: "unavailable" }
1997
+ ],
1998
+ lastErrorCode: code
1999
+ };
2000
+ this.store.set(snapshot);
2001
+ return snapshot;
2002
+ }
2003
+ unsupportedSnapshot(accountId, now, code = "codex_usage_unsupported_auth") {
2004
+ return {
2005
+ providerId: "codex",
2006
+ accountId,
2007
+ source: "oauth-usage-api",
2008
+ observedAt: new Date(now).toISOString(),
2009
+ windows: [
2010
+ { id: "primary", label: "Primary", scope: "all", usedPercent: null, state: "unsupported" },
2011
+ { id: "secondary", label: "Secondary", scope: "all", usedPercent: null, state: "unsupported" }
2012
+ ],
2013
+ lastErrorCode: code
2014
+ };
2015
+ }
2016
+ };
2017
+
2018
+ // src/allowance/KimiAllowanceCollector.ts
2019
+ var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2020
+ var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
2021
+ var import_subscriptions5 = require("@omnicross/subscriptions");
2022
+ var KIMI_ALLOWANCE_CACHE_MS = 5 * 6e4;
2023
+ var KIMI_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
2024
+ function finiteNumber2(value) {
2025
+ if (value === null || value === void 0 || value === "") return void 0;
2026
+ const parsed = typeof value === "number" ? value : Number(value);
2027
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
2028
+ }
2029
+ function isRecord(value) {
2030
+ return !!value && typeof value === "object" && !Array.isArray(value);
2031
+ }
2032
+ function parseResetMs(row, nowMs) {
2033
+ for (const key of ["reset_at", "resetAt", "reset_time", "resetTime"]) {
2034
+ const value = row[key];
2035
+ if (typeof value === "string" && value.trim()) {
2036
+ const parsed = Date.parse(value);
2037
+ if (Number.isFinite(parsed)) return parsed;
2038
+ }
2039
+ const numeric = finiteNumber2(value);
2040
+ if (numeric !== void 0 && numeric > 1e9) {
2041
+ return numeric > 1e12 ? numeric : numeric * 1e3;
2042
+ }
2043
+ }
2044
+ for (const key of ["reset_in", "resetIn", "ttl", "window"]) {
2045
+ const seconds = finiteNumber2(row[key]);
2046
+ if (seconds !== void 0) return nowMs + seconds * 1e3;
2047
+ }
2048
+ return void 0;
2049
+ }
2050
+ var MINUTE_MS = 6e4;
2051
+ var HOUR_MS = 36e5;
2052
+ var DAY_MS = 864e5;
2053
+ function canonicalWindow(durationMs) {
2054
+ if (durationMs === 5 * HOUR_MS) return { id: "five-hour", label: "5 hours", minutes: 300 };
2055
+ if (durationMs === 7 * DAY_MS) return { id: "seven-day", label: "7 days", minutes: 10080 };
2056
+ if (durationMs > 0 && durationMs % DAY_MS === 0) {
2057
+ const days = durationMs / DAY_MS;
2058
+ return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}`, minutes: Math.round(durationMs / MINUTE_MS) };
2059
+ }
2060
+ if (durationMs > 0 && durationMs % HOUR_MS === 0) {
2061
+ const hours = durationMs / HOUR_MS;
2062
+ return { id: `${hours}h`, label: `${hours} hour${hours === 1 ? "" : "s"}`, minutes: Math.round(durationMs / MINUTE_MS) };
2063
+ }
2064
+ return void 0;
2065
+ }
2066
+ function secondsUntil3(instant, now) {
2067
+ if (!instant) return void 0;
2068
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2069
+ }
2070
+ function windowFromRow(row, fallback, now) {
2071
+ const usedPercent = row?.limit !== void 0 && row.limit > 0 && row.used !== void 0 ? Math.round(Math.min(100, row.used / row.limit * 100) * 10) / 10 : null;
2072
+ const resetsAt = row?.resetsAtMs !== void 0 ? new Date(row.resetsAtMs).toISOString() : void 0;
2073
+ return {
2074
+ id: fallback.id,
2075
+ label: fallback.label,
2076
+ scope: "all",
2077
+ usedPercent,
2078
+ windowMinutes: fallback.minutes,
2079
+ ...resetsAt !== void 0 ? { resetsAt } : {},
2080
+ remainingSeconds: secondsUntil3(resetsAt, now),
2081
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
2082
+ };
2083
+ }
2084
+ function parseKimiUsagePayload(payload, now) {
2085
+ if (!isRecord(payload)) return [];
2086
+ const byId = /* @__PURE__ */ new Map();
2087
+ const rowFrom = (data) => {
2088
+ const limit = finiteNumber2(data["limit"]);
2089
+ let used = finiteNumber2(data["used"]);
2090
+ const remaining = finiteNumber2(data["remaining"]);
2091
+ if (used === void 0 && remaining !== void 0 && limit !== void 0) {
2092
+ used = limit - remaining;
2093
+ }
2094
+ let windowDurationMs;
2095
+ const windowData = isRecord(data["window"]) ? data["window"] : void 0;
2096
+ const duration = finiteNumber2(windowData?.["duration"]);
2097
+ const timeUnit = typeof windowData?.["timeUnit"] === "string" ? windowData["timeUnit"].toUpperCase() : "";
2098
+ if (duration !== void 0) {
2099
+ if (timeUnit.includes("MINUTE")) windowDurationMs = duration * MINUTE_MS;
2100
+ else if (timeUnit.includes("HOUR")) windowDurationMs = duration * HOUR_MS;
2101
+ else if (timeUnit.includes("DAY")) windowDurationMs = duration * DAY_MS;
2102
+ else if (timeUnit.includes("WEEK")) windowDurationMs = duration * 7 * DAY_MS;
2103
+ else if (timeUnit.includes("SECOND")) windowDurationMs = duration * 1e3;
2104
+ }
2105
+ const resetsAtMs = parseResetMs(windowData && parseResetMs(windowData, now) !== void 0 ? windowData : data, now);
2106
+ return { used, limit, remaining, ...resetsAtMs !== void 0 ? { resetsAtMs } : {}, ...windowDurationMs !== void 0 ? { windowDurationMs } : {} };
2107
+ };
2108
+ if (isRecord(payload["usage"])) {
2109
+ const row = rowFrom(payload["usage"]);
2110
+ const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
2111
+ byId.set("seven-day", window);
2112
+ }
2113
+ if (Array.isArray(payload["limits"])) {
2114
+ for (const item of payload["limits"]) {
2115
+ if (!isRecord(item)) continue;
2116
+ const detail = isRecord(item["detail"]) ? item["detail"] : item;
2117
+ const row = rowFrom(detail);
2118
+ const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
2119
+ if (!canonical) continue;
2120
+ const window = windowFromRow(row, canonical, now);
2121
+ const existing = byId.get(canonical.id);
2122
+ if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
2123
+ byId.set(canonical.id, window);
2124
+ }
2125
+ }
2126
+ }
2127
+ return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
2128
+ }
2129
+ var KimiAllowanceCollector = class {
2130
+ constructor(credentials, store = (0, import_AccountAllowanceStore3.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch3.fetchUpstream)(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
2131
+ this.credentials = credentials;
2132
+ this.store = store;
2133
+ this.fetchImpl = fetchImpl;
2134
+ this.now = now;
2135
+ }
2136
+ credentials;
2137
+ store;
2138
+ fetchImpl;
2139
+ now;
2140
+ inFlight = /* @__PURE__ */ new Map();
2141
+ async collectMany(accounts, options = {}) {
2142
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
2143
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
2144
+ }
2145
+ collect(account, options = {}) {
2146
+ const now = this.now();
2147
+ if (account.tokens.authMethod !== "oauth") {
2148
+ const existing = this.store.get("kimi", account.id, now);
2149
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
2150
+ return Promise.resolve(existing);
2151
+ }
2152
+ const snapshot = this.unsupportedSnapshot(account.id, now);
2153
+ this.store.set(snapshot);
2154
+ return Promise.resolve(snapshot);
2155
+ }
2156
+ const cached = this.store.get("kimi", account.id, now);
2157
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
2158
+ return Promise.resolve(cached);
2159
+ }
2160
+ const running = this.inFlight.get(account.id);
2161
+ if (running) return running;
2162
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "kimi_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
2163
+ this.inFlight.set(account.id, promise);
2164
+ return promise;
2165
+ }
2166
+ isCacheValid(snapshot, now, refreshAheadMs) {
2167
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
2168
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
2169
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
2170
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
2171
+ }
2172
+ async fetchAccount(accountId, tokens) {
2173
+ let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
2174
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
2175
+ let response = await this.request(accountId, accessToken, tokens);
2176
+ if (response.status === 401) {
2177
+ const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
2178
+ if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
2179
+ accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
2180
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
2181
+ response = await this.request(accountId, accessToken, tokens);
2182
+ }
2183
+ if (response.status === 403) {
2184
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
2185
+ this.store.set(snapshot2);
2186
+ return snapshot2;
2187
+ }
2188
+ if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
2189
+ let payload;
2190
+ try {
2191
+ payload = await response.json();
2192
+ } catch {
2193
+ return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
2194
+ }
2195
+ const now = this.now();
2196
+ const windows = parseKimiUsagePayload(payload, now);
2197
+ const snapshot = {
2198
+ providerId: "kimi",
2199
+ accountId,
2200
+ source: "oauth-usage-api",
2201
+ observedAt: new Date(now).toISOString(),
2202
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
2203
+ windows: windows.length > 0 ? windows : [
2204
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
2205
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
2206
+ ],
2207
+ ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
2208
+ };
2209
+ this.store.set(snapshot);
2210
+ return snapshot;
2211
+ }
2212
+ request(accountId, accessToken, tokens) {
2213
+ return this.fetchImpl(KIMI_USAGE_URL, {
2214
+ method: "GET",
2215
+ headers: {
2216
+ Authorization: `Bearer ${accessToken}`,
2217
+ Accept: "application/json",
2218
+ ...(0, import_subscriptions5.kimiFingerprintHeaders)(tokens.deviceId)
2219
+ },
2220
+ signal: AbortSignal.timeout(15e3)
2221
+ }, accountId);
2222
+ }
2223
+ failureSnapshot(accountId, code, now) {
2224
+ const existing = this.store.get("kimi", accountId, now);
2225
+ const snapshot = existing ? {
2226
+ ...existing,
2227
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
2228
+ windows: existing.windows.map((window) => ({
2229
+ ...window,
2230
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
2231
+ })),
2232
+ lastErrorCode: code
2233
+ } : {
2234
+ providerId: "kimi",
2235
+ accountId,
2236
+ source: "oauth-usage-api",
2237
+ observedAt: new Date(now).toISOString(),
2238
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
2239
+ windows: [
2240
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
2241
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
2242
+ ],
2243
+ lastErrorCode: code
2244
+ };
2245
+ this.store.set(snapshot);
2246
+ return snapshot;
2247
+ }
2248
+ unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
2249
+ return {
2250
+ providerId: "kimi",
2251
+ accountId,
2252
+ source: "oauth-usage-api",
2253
+ observedAt: new Date(now).toISOString(),
2254
+ windows: [
2255
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
2256
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
2257
+ ],
2258
+ lastErrorCode: code
2259
+ };
2260
+ }
2261
+ };
2262
+
2263
+ // src/allowance/GrokAllowanceCollector.ts
2264
+ var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2265
+ var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
2266
+ var GROK_ALLOWANCE_CACHE_MS = 5 * 6e4;
2267
+ var GROK_BILLING_BASE = "https://cli-chat-proxy.grok.com";
2268
+ var GROK_BILLING_CREDITS_URL = `${GROK_BILLING_BASE}/v1/billing?format=credits`;
2269
+ var GROK_BILLING_MONTHLY_URL = `${GROK_BILLING_BASE}/v1/billing`;
2270
+ function isRecord2(value) {
2271
+ return !!value && typeof value === "object" && !Array.isArray(value);
2272
+ }
2273
+ function finiteNumber3(value) {
2274
+ if (value === null || value === void 0 || value === "") return void 0;
2275
+ const parsed = typeof value === "number" ? value : Number(value);
2276
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
2277
+ }
2278
+ function percent(value) {
2279
+ const parsed = finiteNumber3(value);
2280
+ return parsed !== void 0 && parsed <= 100 ? parsed : void 0;
2281
+ }
2282
+ function onDemandAmount(value) {
2283
+ return isRecord2(value) ? finiteNumber3(value["val"]) : void 0;
2284
+ }
2285
+ function confirmsNoMonthlyQuota(raw) {
2286
+ const limit = onDemandAmount(raw["monthlyLimit"]);
2287
+ if (limit !== void 0) return limit === 0;
2288
+ return parseWeeklyConfig(raw)?.inferredPercent === true;
2289
+ }
2290
+ function parseWeeklyConfig(raw) {
2291
+ const period = isRecord2(raw["currentPeriod"]) ? raw["currentPeriod"] : void 0;
2292
+ if (!period) return null;
2293
+ const start = typeof period["start"] === "string" ? Date.parse(period["start"]) : Number.NaN;
2294
+ const end = typeof period["end"] === "string" ? Date.parse(period["end"]) : Number.NaN;
2295
+ const type = typeof period["type"] === "string" ? period["type"] : "";
2296
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
2297
+ if (!type.toUpperCase().includes("WEEK")) return null;
2298
+ const inferred = raw["creditUsagePercent"] === void 0 || raw["creditUsagePercent"] === null;
2299
+ let creditUsagePercent;
2300
+ if (inferred) {
2301
+ creditUsagePercent = end > Date.now() ? 0 : void 0;
2302
+ } else {
2303
+ creditUsagePercent = percent(raw["creditUsagePercent"]);
2304
+ }
2305
+ if (creditUsagePercent === void 0) return null;
2306
+ return {
2307
+ creditUsagePercent,
2308
+ inferredPercent: inferred,
2309
+ resetsAtMs: end,
2310
+ unified: raw["isUnifiedBillingUser"] === true
2311
+ };
2312
+ }
2313
+ function parseMonthlyConfig(raw) {
2314
+ const start = typeof raw["billingPeriodStart"] === "string" ? Date.parse(raw["billingPeriodStart"]) : Number.NaN;
2315
+ const end = typeof raw["billingPeriodEnd"] === "string" ? Date.parse(raw["billingPeriodEnd"]) : Number.NaN;
2316
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
2317
+ const limit = onDemandAmount(raw["monthlyLimit"]);
2318
+ const used = onDemandAmount(raw["used"]);
2319
+ if (limit === void 0 || limit <= 0 || used === void 0) return null;
2320
+ return { used, limit, periodStartMs: start, periodEndMs: end };
2321
+ }
2322
+ function secondsUntil4(instant, now) {
2323
+ if (!instant) return void 0;
2324
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2325
+ }
2326
+ var MINUTE_MS2 = 6e4;
2327
+ var DAY_MS2 = 864e5;
2328
+ var WEEK_MINUTES = 7 * 24 * 60;
2329
+ function weeklyWindow(config, now) {
2330
+ const resetsAt = new Date(config.resetsAtMs).toISOString();
2331
+ return {
2332
+ id: "seven-day",
2333
+ label: "7 days",
2334
+ scope: "all",
2335
+ usedPercent: config.creditUsagePercent,
2336
+ windowMinutes: WEEK_MINUTES,
2337
+ resetsAt,
2338
+ remainingSeconds: secondsUntil4(resetsAt, now),
2339
+ state: "fresh"
2340
+ };
2341
+ }
2342
+ function monthlyWindow(config, now) {
2343
+ const resetsAt = new Date(config.periodEndMs).toISOString();
2344
+ const days = Math.max(1, Math.round((config.periodEndMs - config.periodStartMs) / DAY_MS2));
2345
+ return {
2346
+ id: "thirty-day",
2347
+ label: days === 30 || days === 31 ? "30 days" : `${days} days`,
2348
+ scope: "all",
2349
+ usedPercent: Math.round(Math.min(100, config.used / config.limit * 100) * 10) / 10,
2350
+ windowMinutes: Math.round((config.periodEndMs - config.periodStartMs) / MINUTE_MS2),
2351
+ resetsAt,
2352
+ remainingSeconds: secondsUntil4(resetsAt, now),
2353
+ state: "fresh"
2354
+ };
2355
+ }
2356
+ function onDemandWindow(raw) {
2357
+ const cap = onDemandAmount(raw["onDemandCap"]);
2358
+ const used = onDemandAmount(raw["onDemandUsed"]);
2359
+ if (cap === void 0 || cap <= 0 || used === void 0) return null;
2360
+ return {
2361
+ id: "on-demand",
2362
+ label: "On-demand",
2363
+ scope: "all",
2364
+ usedPercent: Math.round(Math.min(100, used / cap * 100) * 10) / 10,
2365
+ state: "fresh"
2366
+ };
2367
+ }
2368
+ async function probeBilling(url, accessToken, accountId, fetchImpl) {
2369
+ try {
2370
+ const response = await fetchImpl(url, {
2371
+ method: "GET",
2372
+ headers: {
2373
+ Authorization: `Bearer ${accessToken}`,
2374
+ Accept: "application/json",
2375
+ "X-XAI-Token-Auth": "xai-grok-cli"
2376
+ },
2377
+ redirect: "error",
2378
+ signal: AbortSignal.timeout(15e3)
2379
+ }, accountId);
2380
+ if (!response.ok) return { status: response.status, payload: null };
2381
+ const payload = await response.json();
2382
+ return { status: response.status, payload: isRecord2(payload) ? payload : null };
2383
+ } catch {
2384
+ return { status: 0, payload: null };
2385
+ }
2386
+ }
2387
+ function parseGrokBillingPayloads(creditsPayload, monthlyPayload, now) {
2388
+ const creditsConfig = isRecord2(creditsPayload?.["config"]) ? creditsPayload["config"] : null;
2389
+ const monthlyConfig = isRecord2(monthlyPayload?.["config"]) ? monthlyPayload["config"] : null;
2390
+ let weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
2391
+ const unifiedFlag = creditsConfig?.["isUnifiedBillingUser"] === true;
2392
+ let monthly = monthlyConfig ? parseMonthlyConfig(monthlyConfig) : null;
2393
+ if (weekly?.inferredPercent && unifiedFlag) {
2394
+ if (monthly) {
2395
+ weekly = null;
2396
+ } else if (!monthlyConfig || !confirmsNoMonthlyQuota(monthlyConfig)) {
2397
+ weekly = null;
2398
+ }
2399
+ }
2400
+ const windows = [];
2401
+ if (weekly) windows.push(weeklyWindow(weekly, now));
2402
+ if (monthly) windows.push(monthlyWindow(monthly, now));
2403
+ const onDemandSource = monthly && monthlyConfig ? monthlyConfig : creditsConfig;
2404
+ const onDemand = onDemandSource ? onDemandWindow(onDemandSource) : null;
2405
+ if (onDemand) windows.push(onDemand);
2406
+ return windows.length > 0 ? windows : null;
2407
+ }
2408
+ var GrokAllowanceCollector = class {
2409
+ constructor(credentials, store = (0, import_AccountAllowanceStore4.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId: "grok", accountId, redactBodies: true }), now = Date.now) {
2410
+ this.credentials = credentials;
2411
+ this.store = store;
2412
+ this.fetchImpl = fetchImpl;
2413
+ this.now = now;
2414
+ }
2415
+ credentials;
2416
+ store;
2417
+ fetchImpl;
2418
+ now;
2419
+ inFlight = /* @__PURE__ */ new Map();
2420
+ async collectMany(accounts, options = {}) {
2421
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
2422
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
2423
+ }
2424
+ collect(account, options = {}) {
2425
+ const now = this.now();
2426
+ if (account.tokens.authMethod !== "oauth") {
2427
+ const existing = this.store.get("grok", account.id, now);
2428
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
2429
+ return Promise.resolve(existing);
2430
+ }
2431
+ const snapshot = this.unsupportedSnapshot(account.id, now);
2432
+ this.store.set(snapshot);
2433
+ return Promise.resolve(snapshot);
2434
+ }
2435
+ const cached = this.store.get("grok", account.id, now);
2436
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
2437
+ return Promise.resolve(cached);
2438
+ }
2439
+ const running = this.inFlight.get(account.id);
2440
+ if (running) return running;
2441
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "grok_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
2442
+ this.inFlight.set(account.id, promise);
2443
+ return promise;
2444
+ }
2445
+ isCacheValid(snapshot, now, refreshAheadMs) {
2446
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
2447
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
2448
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
2449
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
2450
+ }
2451
+ async fetchAccount(accountId) {
2452
+ const probe = async () => {
2453
+ const accessToken = await this.credentials.getAccessTokenForAccount("grok", accountId);
2454
+ if (!accessToken) return { unauthorized: true, windows: null };
2455
+ const credits = await probeBilling(GROK_BILLING_CREDITS_URL, accessToken, accountId, this.fetchImpl);
2456
+ if (credits.status === 401 || credits.status === 403) return { unauthorized: true, windows: null };
2457
+ const creditsConfig = isRecord2(credits.payload?.["config"]) ? credits.payload["config"] : null;
2458
+ const weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
2459
+ const monthly = !weekly || creditsConfig?.["isUnifiedBillingUser"] === true ? await probeBilling(GROK_BILLING_MONTHLY_URL, accessToken, accountId, this.fetchImpl) : { status: 200, payload: null };
2460
+ if (monthly.status === 401 || monthly.status === 403) return { unauthorized: true, windows: null };
2461
+ return {
2462
+ unauthorized: false,
2463
+ windows: parseGrokBillingPayloads(credits.payload, monthly.payload, this.now())
2464
+ };
2465
+ };
2466
+ let result = await probe();
2467
+ if (result.unauthorized) {
2468
+ const refreshed = await this.credentials.refreshAccountToken("grok", accountId);
2469
+ if (!refreshed) return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
2470
+ result = await probe();
2471
+ if (result.unauthorized) {
2472
+ return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
2473
+ }
2474
+ }
2475
+ const now = this.now();
2476
+ if (result.windows && result.windows.length > 0) {
2477
+ const snapshot = {
2478
+ providerId: "grok",
2479
+ accountId,
2480
+ source: "oauth-usage-api",
2481
+ observedAt: new Date(now).toISOString(),
2482
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
2483
+ windows: result.windows
2484
+ };
2485
+ this.store.set(snapshot);
2486
+ return snapshot;
2487
+ }
2488
+ return this.failureSnapshot(accountId, "grok_usage_invalid_response", now);
2489
+ }
2490
+ failureSnapshot(accountId, code, now) {
2491
+ const existing = this.store.get("grok", accountId, now);
2492
+ const snapshot = existing ? {
2493
+ ...existing,
2494
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
2495
+ windows: existing.windows.map((window) => ({
2496
+ ...window,
2497
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
2498
+ })),
2499
+ lastErrorCode: code
2500
+ } : {
2501
+ providerId: "grok",
2502
+ accountId,
2503
+ source: "oauth-usage-api",
2504
+ observedAt: new Date(now).toISOString(),
2505
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
2506
+ windows: [
2507
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" },
2508
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unavailable" }
2509
+ ],
2510
+ lastErrorCode: code
2511
+ };
2512
+ this.store.set(snapshot);
2513
+ return snapshot;
2514
+ }
2515
+ unsupportedSnapshot(accountId, now) {
2516
+ return {
2517
+ providerId: "grok",
2518
+ accountId,
2519
+ source: "oauth-usage-api",
2520
+ observedAt: new Date(now).toISOString(),
2521
+ windows: [
2522
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" },
2523
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unsupported" }
2524
+ ],
2525
+ lastErrorCode: "grok_usage_unsupported_auth"
2526
+ };
2527
+ }
2528
+ };
2529
+
2530
+ // src/allowance/CopilotAllowanceCollector.ts
2531
+ var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2532
+ var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
2533
+ var import_subscriptions6 = require("@omnicross/subscriptions");
2534
+ var COPILOT_ALLOWANCE_CACHE_MS = 5 * 6e4;
2535
+ function isRecord3(value) {
2536
+ return !!value && typeof value === "object" && !Array.isArray(value);
2537
+ }
2538
+ function finiteNumber4(value) {
2539
+ if (value === null || value === void 0 || value === "") return void 0;
2540
+ const parsed = typeof value === "number" ? value : Number(value);
2541
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
2542
+ }
2543
+ function booleanValue(value) {
2544
+ if (typeof value === "boolean") return value;
2545
+ if (value === "true") return true;
2546
+ if (value === "false") return false;
2547
+ return void 0;
2548
+ }
2549
+ function parseQuotaDetail(value) {
2550
+ if (!isRecord3(value)) return null;
2551
+ const entitlement = finiteNumber4(value["entitlement"]);
2552
+ const remaining = finiteNumber4(value["remaining"]);
2553
+ const percentRemaining = finiteNumber4(value["percent_remaining"]);
2554
+ const unlimited = booleanValue(value["unlimited"]);
2555
+ if (entitlement === void 0 || remaining === void 0 || percentRemaining === void 0 || unlimited === void 0) {
2556
+ return null;
2557
+ }
2558
+ return { entitlement, remaining, percentRemaining, unlimited };
2559
+ }
2560
+ function secondsUntil5(instant, now) {
2561
+ if (!instant) return void 0;
2562
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2563
+ }
2564
+ function parseCopilotUserPayload(payload, now) {
2565
+ if (!isRecord3(payload)) return null;
2566
+ const snapshots = isRecord3(payload["quota_snapshots"]) ? payload["quota_snapshots"] : void 0;
2567
+ if (!snapshots) return null;
2568
+ const resetRaw = payload["quota_reset_date"];
2569
+ const resetsAt = typeof resetRaw === "string" && resetRaw.trim() && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
2570
+ const windows = [];
2571
+ const premium = parseQuotaDetail(snapshots["premium_interactions"]);
2572
+ if (premium) {
2573
+ const usedPercent = premium.unlimited ? 0 : premium.entitlement > 0 ? Math.round(Math.min(100, (premium.entitlement - premium.remaining) / premium.entitlement * 100) * 10) / 10 : finiteNumber4(premium.percentRemaining) !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - premium.percentRemaining)) * 10) / 10 : null;
2574
+ if (usedPercent !== null) {
2575
+ windows.push({
2576
+ id: "thirty-day",
2577
+ label: "Monthly",
2578
+ scope: "all",
2579
+ usedPercent,
2580
+ windowMinutes: 30 * 24 * 60,
2581
+ ...resetsAt !== void 0 ? { resetsAt } : {},
2582
+ remainingSeconds: secondsUntil5(resetsAt, now),
2583
+ state: "fresh"
2584
+ });
2585
+ }
2586
+ }
2587
+ const chat = parseQuotaDetail(snapshots["chat"]);
2588
+ if (chat && !chat.unlimited && chat.entitlement > 0) {
2589
+ const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
2590
+ windows.push({
2591
+ id: "chat-monthly",
2592
+ label: "Chat (monthly)",
2593
+ scope: "all",
2594
+ usedPercent,
2595
+ windowMinutes: 30 * 24 * 60,
2596
+ ...resetsAt !== void 0 ? { resetsAt } : {},
2597
+ remainingSeconds: secondsUntil5(resetsAt, now),
2598
+ state: "fresh"
2599
+ });
2600
+ }
2601
+ return windows.length > 0 ? windows : null;
2602
+ }
2603
+ function githubApiBase(tokens) {
2604
+ return (0, import_subscriptions6.copilotGitHubApiBase)(tokens.enterpriseUrl);
2605
+ }
2606
+ var CopilotAllowanceCollector = class {
2607
+ constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch5.fetchUpstream)(url, init, { providerId: "copilot", accountId, redactBodies: true }), now = Date.now) {
2608
+ this.credentials = credentials;
2609
+ this.store = store;
2610
+ this.fetchImpl = fetchImpl;
2611
+ this.now = now;
2612
+ }
2613
+ credentials;
2614
+ store;
2615
+ fetchImpl;
2616
+ now;
2617
+ inFlight = /* @__PURE__ */ new Map();
2618
+ async collectMany(accounts, options = {}) {
2619
+ const settled = await Promise.allSettled(
2620
+ accounts.map((account) => this.collect(account, options))
2621
+ );
2622
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
2623
+ }
2624
+ collect(account, options = {}) {
2625
+ const now = this.now();
2626
+ if (account.tokens.authMethod !== "oauth") {
2627
+ const existing = this.store.get("copilot", account.id, now);
2628
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
2629
+ return Promise.resolve(existing);
2630
+ }
2631
+ const snapshot = this.unsupportedSnapshot(account.id, now);
2632
+ this.store.set(snapshot);
2633
+ return Promise.resolve(snapshot);
2634
+ }
2635
+ const cached = this.store.get("copilot", account.id, now);
2636
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
2637
+ return Promise.resolve(cached);
2638
+ }
2639
+ const running = this.inFlight.get(account.id);
2640
+ if (running) return running;
2641
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "copilot_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
2642
+ this.inFlight.set(account.id, promise);
2643
+ return promise;
2644
+ }
2645
+ isCacheValid(snapshot, now, refreshAheadMs) {
2646
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
2647
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
2648
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
2649
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
2650
+ }
2651
+ async fetchAccount(accountId, tokens) {
2652
+ let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
2653
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
2654
+ let response = await this.request(accountId, accessToken, tokens);
2655
+ if (response.status === 401 || response.status === 403) {
2656
+ const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
2657
+ if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
2658
+ accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
2659
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
2660
+ response = await this.request(accountId, accessToken, tokens);
2661
+ if (response.status === 401 || response.status === 403) {
2662
+ return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
2663
+ }
2664
+ }
2665
+ if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
2666
+ let payload;
2667
+ try {
2668
+ payload = await response.json();
2669
+ } catch {
2670
+ return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
2671
+ }
2672
+ const now = this.now();
2673
+ const windows = parseCopilotUserPayload(payload, now);
2674
+ const snapshot = {
2675
+ providerId: "copilot",
2676
+ accountId,
2677
+ source: "oauth-usage-api",
2678
+ observedAt: new Date(now).toISOString(),
2679
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
2680
+ windows: windows ?? [
2681
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
2682
+ ],
2683
+ ...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
2684
+ };
2685
+ this.store.set(snapshot);
2686
+ return snapshot;
2687
+ }
2688
+ request(accountId, accessToken, tokens) {
2689
+ return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
2690
+ method: "GET",
2691
+ headers: {
2692
+ Authorization: `Bearer ${accessToken}`,
2693
+ Accept: "application/json",
2694
+ "Content-Type": "application/json",
2695
+ ...import_subscriptions6.COPILOT_GITHUB_HEADERS
2696
+ },
2697
+ signal: AbortSignal.timeout(15e3)
2698
+ }, accountId);
2699
+ }
2700
+ failureSnapshot(accountId, code, now) {
2701
+ const existing = this.store.get("copilot", accountId, now);
2702
+ const snapshot = existing ? {
2703
+ ...existing,
2704
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
2705
+ windows: existing.windows.map((window) => ({
2706
+ ...window,
2707
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
2708
+ })),
2709
+ lastErrorCode: code
2710
+ } : {
2711
+ providerId: "copilot",
2712
+ accountId,
2713
+ source: "oauth-usage-api",
2714
+ observedAt: new Date(now).toISOString(),
2715
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
2716
+ windows: [
2717
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
2718
+ ],
2719
+ lastErrorCode: code
2720
+ };
2721
+ this.store.set(snapshot);
2722
+ return snapshot;
2723
+ }
2724
+ unsupportedSnapshot(accountId, now) {
2725
+ return {
2726
+ providerId: "copilot",
2727
+ accountId,
2728
+ source: "oauth-usage-api",
2729
+ observedAt: new Date(now).toISOString(),
2730
+ windows: [
2731
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
2732
+ ],
2733
+ lastErrorCode: "copilot_usage_unsupported_auth"
2734
+ };
2735
+ }
2736
+ };
2737
+
2738
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
2739
+ var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2740
+ var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
2741
+ var import_subscriptions7 = require("@omnicross/subscriptions");
2742
+ var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
2743
+ var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
2744
+ function finitePercent3(value) {
2745
+ if (value === null || value === void 0 || value === "") return null;
2746
+ const parsed = typeof value === "number" ? value : Number(value);
2747
+ return Number.isFinite(parsed) && parsed >= 0 && parsed <= 100 ? parsed : null;
2748
+ }
2749
+ function isoInstant2(value) {
2750
+ if (typeof value !== "string" || !value.trim()) return void 0;
2751
+ const time = Date.parse(value);
2752
+ return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
2753
+ }
2754
+ function secondsUntil6(instant, now) {
2755
+ if (!instant) return void 0;
2756
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2757
+ }
2758
+ function windowFromPayload3(id, label, minutes, payload, now) {
2759
+ const statusRateLimited = payload?.status === "rate-limited";
2760
+ const usedPercent = statusRateLimited ? 100 : finitePercent3(payload?.percent);
2761
+ const resetsAt = isoInstant2(payload?.resetsAt);
2762
+ return {
2763
+ id,
2764
+ label,
2765
+ scope: "all",
2766
+ usedPercent,
2767
+ windowMinutes: minutes,
2768
+ ...resetsAt !== void 0 ? { resetsAt } : {},
2769
+ remainingSeconds: secondsUntil6(resetsAt, now),
2770
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
2771
+ };
2772
+ }
2773
+ var OpenCodeGoAllowanceCollector = class {
2774
+ constructor(credentials, store = (0, import_AccountAllowanceStore6.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch6.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
2775
+ this.credentials = credentials;
2776
+ this.store = store;
2777
+ this.fetchImpl = fetchImpl;
2778
+ this.now = now;
2779
+ }
2780
+ credentials;
2781
+ store;
2782
+ fetchImpl;
2783
+ now;
2784
+ inFlight = /* @__PURE__ */ new Map();
2785
+ async collectMany(accounts, options = {}) {
2786
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
2787
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
2788
+ }
2789
+ collect(account, options = {}) {
2790
+ const now = this.now();
2791
+ const cached = this.store.get("opencodego", account.id, now);
2792
+ if (!options.force && cached && (cached.windows.every((window) => window.state === "unsupported") || cached.expiresAt && Date.parse(cached.expiresAt) > now + (options.refreshAheadMs ?? 0))) {
2793
+ return Promise.resolve(cached);
2794
+ }
2795
+ const running = this.inFlight.get(account.id);
2796
+ if (running) return running;
2797
+ const promise = this.fetchAccount(account).catch(() => this.failureSnapshot(account.id, this.now())).finally(() => this.inFlight.delete(account.id));
2798
+ this.inFlight.set(account.id, promise);
2799
+ return promise;
2800
+ }
2801
+ async fetchAccount(account) {
2802
+ const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
2803
+ if (!apiKey) return this.failureSnapshot(account.id, this.now());
2804
+ const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
2805
+ const response = await this.fetchImpl(`${base}/v1/usage`, {
2806
+ method: "GET",
2807
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
2808
+ signal: AbortSignal.timeout(15e3)
2809
+ }, account.id);
2810
+ if (response.status === 401 || response.status === 403) {
2811
+ return this.failureSnapshot(account.id, this.now(), "opencodego_usage_unauthorized");
2812
+ }
2813
+ if (!response.ok) return this.failureSnapshot(account.id, this.now());
2814
+ let payload;
2815
+ try {
2816
+ payload = await response.json();
2817
+ } catch {
2818
+ return this.failureSnapshot(account.id, this.now());
2819
+ }
2820
+ const usage = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.usage : void 0;
2821
+ const now = this.now();
2822
+ const snapshot = {
2823
+ providerId: "opencodego",
2824
+ accountId: account.id,
2825
+ source: "oauth-usage-api",
2826
+ observedAt: new Date(now).toISOString(),
2827
+ expiresAt: new Date(now + OPENCODEGO_ALLOWANCE_CACHE_MS).toISOString(),
2828
+ // Monthly deliberately omitted (module doc).
2829
+ windows: [
2830
+ windowFromPayload3("five-hour", "5 hours", 5 * 60, usage?.rolling ?? void 0, now),
2831
+ windowFromPayload3("seven-day", "7 days", 7 * 24 * 60, usage?.weekly ?? void 0, now)
2832
+ ]
2833
+ };
2834
+ this.store.set(snapshot);
2835
+ return snapshot;
2836
+ }
2837
+ failureSnapshot(accountId, now, code = "opencodego_usage_request_failed") {
2838
+ const existing = this.store.get("opencodego", accountId, now);
2839
+ const snapshot = existing ? {
2840
+ ...existing,
2841
+ expiresAt: new Date(now + OPENCODEGO_ALLOWANCE_CACHE_MS).toISOString(),
2842
+ windows: existing.windows.map((window) => ({
2843
+ ...window,
2844
+ state: window.usedPercent !== null || window.resetsAt ? "stale" : window.state
2845
+ })),
2846
+ lastErrorCode: code
2847
+ } : {
2848
+ providerId: "opencodego",
2849
+ accountId,
2850
+ source: "oauth-usage-api",
2851
+ observedAt: new Date(now).toISOString(),
2852
+ expiresAt: new Date(now + OPENCODEGO_ALLOWANCE_CACHE_MS).toISOString(),
2853
+ windows: [
2854
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
2855
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
2856
+ ],
1505
2857
  lastErrorCode: code
1506
2858
  };
2859
+ this.store.set(snapshot);
2860
+ return snapshot;
1507
2861
  }
1508
2862
  };
1509
2863
 
@@ -1522,26 +2876,34 @@ function codexUnavailable(accountId, now) {
1522
2876
  };
1523
2877
  }
1524
2878
  var AccountAllowanceService = class {
1525
- constructor(credentials, store = (0, import_AccountAllowanceStore2.getSharedAccountAllowanceStore)(), collector, now = Date.now) {
2879
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, now = Date.now) {
1526
2880
  this.credentials = credentials;
1527
2881
  this.store = store;
1528
2882
  this.now = now;
1529
2883
  this.claudeCollector = collector ?? new ClaudeAllowanceCollector(credentials, store);
2884
+ this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
2885
+ this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
2886
+ this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
2887
+ this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
2888
+ this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
1530
2889
  }
1531
2890
  credentials;
1532
2891
  store;
1533
2892
  now;
1534
2893
  claudeCollector;
2894
+ codexCollector;
2895
+ kimiCollector;
2896
+ grokCollector;
2897
+ copilotCollector;
2898
+ opencodegoCollector;
1535
2899
  /**
1536
- * Read all/filtered snapshots. Claude's five-minute cache is refreshed lazily;
1537
- * Codex remains passive and reports not-observed until a real model response.
2900
+ * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
2901
+ * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
2902
+ * passive `x-codex-*` header tap still feeds mid-flight updates).
1538
2903
  */
1539
2904
  async list(filter = {}) {
1540
2905
  const config = await this.credentials.getFullConfig();
1541
- this.store.pruneToKnownAccounts([
1542
- ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1543
- ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id }))
1544
- ]);
2906
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1545
2907
  const wantsClaude = !filter.providerId || filter.providerId === "claude";
1546
2908
  const claudeAccounts = (config.claudeAccounts ?? []).filter(
1547
2909
  (account) => !filter.accountId || account.id === filter.accountId
@@ -1552,39 +2914,124 @@ var AccountAllowanceService = class {
1552
2914
  (account) => !filter.accountId || account.id === filter.accountId
1553
2915
  );
1554
2916
  if (wantsCodex) {
2917
+ await this.codexCollector.collectMany(codexAccounts);
1555
2918
  for (const account of codexAccounts) {
1556
2919
  if (!this.store.get("codex", account.id)) this.store.set(codexUnavailable(account.id, this.now()));
1557
2920
  }
1558
2921
  }
2922
+ const wantsKimi = !filter.providerId || filter.providerId === "kimi";
2923
+ const kimiAccounts = (config.kimiAccounts ?? []).filter(
2924
+ (account) => !filter.accountId || account.id === filter.accountId
2925
+ );
2926
+ if (wantsKimi) await this.kimiCollector.collectMany(kimiAccounts);
2927
+ const wantsOpenCodeGo = !filter.providerId || filter.providerId === "opencodego";
2928
+ const opencodegoAccounts = (config.opencodegoAccounts ?? []).filter(
2929
+ (account) => !filter.accountId || account.id === filter.accountId
2930
+ );
2931
+ if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
2932
+ const wantsGrok = !filter.providerId || filter.providerId === "grok";
2933
+ const grokAccounts = (config.grokAccounts ?? []).filter(
2934
+ (account) => !filter.accountId || account.id === filter.accountId
2935
+ );
2936
+ if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
2937
+ const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
2938
+ const copilotAccounts = (config.copilotAccounts ?? []).filter(
2939
+ (account) => !filter.accountId || account.id === filter.accountId
2940
+ );
2941
+ if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
1559
2942
  const known = /* @__PURE__ */ new Set();
1560
2943
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
1561
2944
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
2945
+ if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
2946
+ if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
2947
+ if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
2948
+ if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
1562
2949
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
1563
2950
  }
2951
+ knownAccounts(config) {
2952
+ return [
2953
+ ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
2954
+ ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
2955
+ ...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
2956
+ ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
2957
+ ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
2958
+ ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id }))
2959
+ ];
2960
+ }
1564
2961
  /** Force-refresh Claude usage for one account or every stored Claude account. */
1565
2962
  async refreshClaude(accountId) {
1566
2963
  const config = await this.credentials.getFullConfig();
1567
- this.store.pruneToKnownAccounts([
1568
- ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1569
- ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id }))
1570
- ]);
2964
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1571
2965
  const accounts = (config.claudeAccounts ?? []).filter(
1572
2966
  (account) => !accountId || account.id === accountId
1573
2967
  );
1574
2968
  return this.claudeCollector.collectMany(accounts, { force: true });
1575
2969
  }
1576
2970
  /**
1577
- * Keep Claude snapshots warm for allowance-aware routing. This deliberately
1578
- * excludes Codex (whose quota is learned from real response headers) and
1579
- * preserves the collector's cache + per-account in-flight coalescing.
2971
+ * Force-refresh Codex usage (`/backend-api/wham/usage`) for one account or
2972
+ * every stored Codex account. Replaces the old probe-request workaround
2973
+ * no quota is spent reading the usage endpoint.
2974
+ */
2975
+ async refreshCodex(accountId) {
2976
+ const config = await this.credentials.getFullConfig();
2977
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2978
+ const accounts = (config.codexAccounts ?? []).filter(
2979
+ (account) => !accountId || account.id === accountId
2980
+ );
2981
+ return this.codexCollector.collectMany(accounts, { force: true });
2982
+ }
2983
+ /** Force-refresh OpenCodeGo usage (`{go}/v1/usage`) for one/all accounts. */
2984
+ async refreshOpenCodeGo(accountId) {
2985
+ const config = await this.credentials.getFullConfig();
2986
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2987
+ const accounts = (config.opencodegoAccounts ?? []).filter(
2988
+ (account) => !accountId || account.id === accountId
2989
+ );
2990
+ return this.opencodegoCollector.collectMany(accounts, { force: true });
2991
+ }
2992
+ /** Force-refresh Kimi usage (`/coding/v1/usages`) for one/all accounts. */
2993
+ async refreshKimi(accountId) {
2994
+ const config = await this.credentials.getFullConfig();
2995
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2996
+ const accounts = (config.kimiAccounts ?? []).filter(
2997
+ (account) => !accountId || account.id === accountId
2998
+ );
2999
+ return this.kimiCollector.collectMany(accounts, { force: true });
3000
+ }
3001
+ /** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
3002
+ async refreshCopilot(accountId) {
3003
+ const config = await this.credentials.getFullConfig();
3004
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
3005
+ const accounts = (config.copilotAccounts ?? []).filter(
3006
+ (account) => !accountId || account.id === accountId
3007
+ );
3008
+ return this.copilotCollector.collectMany(accounts, { force: true });
3009
+ }
3010
+ /** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
3011
+ async refreshGrok(accountId) {
3012
+ const config = await this.credentials.getFullConfig();
3013
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
3014
+ const accounts = (config.grokAccounts ?? []).filter(
3015
+ (account) => !accountId || account.id === accountId
3016
+ );
3017
+ return this.grokCollector.collectMany(accounts, { force: true });
3018
+ }
3019
+ /**
3020
+ * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
3021
+ * collectors preserve their cache + per-account in-flight coalescing; a tick
3022
+ * normally performs no network I/O. (Codex joined the warm path when it
3023
+ * gained an active `/wham/usage` collector — the passive `x-codex-*` header
3024
+ * tap alone could not keep the policy fed while idle.)
1580
3025
  */
1581
3026
  async maintainClaudeCache(refreshAheadMs) {
1582
3027
  const config = await this.credentials.getFullConfig();
1583
- this.store.pruneToKnownAccounts([
1584
- ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1585
- ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id }))
1586
- ]);
3028
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1587
3029
  await this.claudeCollector.collectMany(config.claudeAccounts ?? [], { refreshAheadMs });
3030
+ await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
3031
+ await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
3032
+ await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
3033
+ await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
3034
+ await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
1588
3035
  }
1589
3036
  /** Remove a cache row as soon as an account is deleted by the admin path. */
1590
3037
  removeAccountSnapshot(providerId, accountId) {
@@ -1679,7 +3126,7 @@ var ClaudeAllowanceRefreshScheduler = class {
1679
3126
  var import_node_crypto4 = require("crypto");
1680
3127
  var import_node_fs6 = require("fs");
1681
3128
  var import_node_path6 = require("path");
1682
- var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3129
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1683
3130
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
1684
3131
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
1685
3132
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -1708,7 +3155,7 @@ var JsonAccountAllowancePersistence = class {
1708
3155
  save(snapshots) {
1709
3156
  const rows = [];
1710
3157
  for (const snapshot of snapshots) {
1711
- const normalized2 = (0, import_AccountAllowanceStore3.normalizeAccountAllowanceSnapshot)(snapshot);
3158
+ const normalized2 = (0, import_AccountAllowanceStore8.normalizeAccountAllowanceSnapshot)(snapshot);
1712
3159
  if (!normalized2) continue;
1713
3160
  rows.push(normalized2);
1714
3161
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -1984,7 +3431,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
1984
3431
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
1985
3432
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1986
3433
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1987
- var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
3434
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
3435
+ var import_core3 = require("@omnicross/core");
1988
3436
 
1989
3437
  // src/image-generation/imagesConfigValidation.ts
1990
3438
  var import_outbound_api = require("@omnicross/core/outbound-api");
@@ -2280,6 +3728,7 @@ async function applyServerConfigTransaction(current, next, deps) {
2280
3728
 
2281
3729
  // src/config.ts
2282
3730
  var import_node_fs8 = require("fs");
3731
+ var import_core = require("@omnicross/core");
2283
3732
  var DEFAULT_ADMIN_PORT = 8766;
2284
3733
  function validateAdmin(raw) {
2285
3734
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -2336,6 +3785,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
2336
3785
  "openai-response",
2337
3786
  "gemini-code-assist"
2338
3787
  ];
3788
+ function validateExtraHeaders(raw) {
3789
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3790
+ const reserved = import_core.EXTRA_HEADER_RESERVED_NAMES;
3791
+ const out = {};
3792
+ for (const [name, value] of Object.entries(raw)) {
3793
+ if (!name.trim()) continue;
3794
+ if (typeof value !== "string") continue;
3795
+ if (reserved.has(name.toLowerCase())) continue;
3796
+ out[name] = value;
3797
+ }
3798
+ return Object.keys(out).length > 0 ? out : void 0;
3799
+ }
2339
3800
  function validateApiKeys(raw) {
2340
3801
  if (!Array.isArray(raw)) return void 0;
2341
3802
  const out = [];
@@ -2549,6 +4010,9 @@ function validateProvider(raw, index) {
2549
4010
  apiVersion,
2550
4011
  maxConcurrency,
2551
4012
  modelsEndpoint,
4013
+ // Static extra headers: load-guard (reserved names dropped), collapse-to-
4014
+ // undefined; enforced by the outbound header funnel + admin probes.
4015
+ extraHeaders: validateExtraHeaders(p["extraHeaders"]),
2552
4016
  // Provider transformer config (app-parity child 5): load-guard, collapse-to-
2553
4017
  // undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
2554
4018
  // Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
@@ -2618,7 +4082,7 @@ var import_node_crypto6 = require("crypto");
2618
4082
  var import_node_fs10 = require("fs");
2619
4083
  var import_node_os3 = require("os");
2620
4084
  var import_node_path10 = require("path");
2621
- var import_core = require("@omnicross/core");
4085
+ var import_core2 = require("@omnicross/core");
2622
4086
 
2623
4087
  // src/integrations/codexAuthHelper.ts
2624
4088
  var import_node_path8 = require("path");
@@ -3099,7 +4563,7 @@ var IntegrationManager = class {
3099
4563
  if (!secret) {
3100
4564
  throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
3101
4565
  }
3102
- const effective = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4566
+ const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3103
4567
  const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
3104
4568
  const nextPermissions = [...effective];
3105
4569
  for (const required of REQUIRED_PERMISSIONS[client]) {
@@ -3197,7 +4661,7 @@ var IntegrationManager = class {
3197
4661
  return { binding, row, secret, created: false };
3198
4662
  }
3199
4663
  async createManagedClientKey(client, state) {
3200
- const created = await (0, import_core.createIntegrationKey)(
4664
+ const created = await (0, import_core2.createIntegrationKey)(
3201
4665
  this.options.keyDb,
3202
4666
  `Omnicross ${displayClient(client)} integration`,
3203
4667
  [...REQUIRED_PERMISSIONS[client]]
@@ -3289,7 +4753,7 @@ var IntegrationManager = class {
3289
4753
  const row = rows.find((candidate) => candidate.id === keyId);
3290
4754
  if (!row) return { usable: false, message: "The bound access key no longer exists." };
3291
4755
  const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
3292
- const allowedEndpoints = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4756
+ const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3293
4757
  const status = {
3294
4758
  id: row.id,
3295
4759
  name: row.name,
@@ -3333,7 +4797,7 @@ var IntegrationManager = class {
3333
4797
  }
3334
4798
  };
3335
4799
  function hasRequiredPermissions(row, client) {
3336
- const allowed = (0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints);
4800
+ const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
3337
4801
  return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
3338
4802
  }
3339
4803
  function samePermissions(a, b) {
@@ -3502,7 +4966,10 @@ function mapPresetToProvider(preset, opts) {
3502
4966
  apiFormat: resolved.format,
3503
4967
  baseUrl: opts.baseUrlOverride ?? preset.api_base_url,
3504
4968
  apiKey: opts.key,
3505
- models: Array.isArray(preset.models) ? preset.models : void 0
4969
+ models: Array.isArray(preset.models) ? preset.models : void 0,
4970
+ // Static identity headers (e.g. the Cline client set) survive the mapping —
4971
+ // the CLI-seeded row needs them as much as an admin-API-created one.
4972
+ extraHeaders: preset.extraHeaders
3506
4973
  };
3507
4974
  return { provider };
3508
4975
  }
@@ -3527,7 +4994,8 @@ function listMappablePresets() {
3527
4994
  description: preset.description,
3528
4995
  features: preset.features,
3529
4996
  website: preset.website,
3530
- modelsEndpoint: preset.modelsEndpoint
4997
+ modelsEndpoint: preset.modelsEndpoint,
4998
+ extraHeaders: preset.extraHeaders
3531
4999
  });
3532
5000
  }
3533
5001
  return { mappable, excluded };
@@ -3617,11 +5085,11 @@ function preserveOutboundProxySecrets(incoming, current) {
3617
5085
  }
3618
5086
 
3619
5087
  // src/proxy/upstreamProxyResolver.ts
3620
- var import_upstreamFetch2 = require("@omnicross/core/pipeline/upstreamFetch");
5088
+ var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
3621
5089
  var serverProxy;
3622
5090
  function setServerProxyConfig(proxy) {
3623
5091
  serverProxy = proxy;
3624
- (0, import_upstreamFetch2.bumpUpstreamProxyGeneration)();
5092
+ (0, import_upstreamFetch7.bumpUpstreamProxyGeneration)();
3625
5093
  }
3626
5094
  function getServerProxyConfig() {
3627
5095
  return serverProxy;
@@ -3689,14 +5157,17 @@ function createUpstreamProxyResolver(src = {}) {
3689
5157
  }
3690
5158
 
3691
5159
  // src/admin/accountsOAuth.ts
3692
- var import_subscriptions2 = require("@omnicross/subscriptions");
5160
+ var import_subscriptions8 = require("@omnicross/subscriptions");
3693
5161
 
3694
5162
  // src/admin/accountsWrite.ts
3695
5163
  var VALID_PROVIDER_IDS = [
3696
5164
  "claude",
3697
5165
  "codex",
3698
5166
  "gemini",
3699
- "opencodego"
5167
+ "opencodego",
5168
+ "kimi",
5169
+ "grok",
5170
+ "copilot"
3700
5171
  ];
3701
5172
  function asSubscriptionProviderId(id) {
3702
5173
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -3832,6 +5303,52 @@ function validateGemini(body) {
3832
5303
  copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "lastRefreshedAt", "errorMessage"]);
3833
5304
  return out;
3834
5305
  }
5306
+ function validateKimi(body) {
5307
+ const authMethod = str(body["authMethod"]);
5308
+ const status = str(body["status"]);
5309
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
5310
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
5311
+ const out = {
5312
+ authMethod,
5313
+ status
5314
+ };
5315
+ copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
5316
+ return out;
5317
+ }
5318
+ function validateGrok(body) {
5319
+ const authMethod = str(body["authMethod"]);
5320
+ const status = str(body["status"]);
5321
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
5322
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
5323
+ const out = {
5324
+ authMethod,
5325
+ status
5326
+ };
5327
+ copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
5328
+ return out;
5329
+ }
5330
+ function validateCopilot(body) {
5331
+ const authMethod = str(body["authMethod"]);
5332
+ const status = str(body["status"]);
5333
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
5334
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
5335
+ const out = {
5336
+ authMethod,
5337
+ status
5338
+ };
5339
+ copyOptional(out, body, [
5340
+ "accessToken",
5341
+ "refreshToken",
5342
+ "expiresAt",
5343
+ "accountId",
5344
+ "email",
5345
+ "apiEndpoint",
5346
+ "enterpriseUrl",
5347
+ "lastRefreshedAt",
5348
+ "errorMessage"
5349
+ ]);
5350
+ return out;
5351
+ }
3835
5352
  function validateOpenCodeGo(body) {
3836
5353
  const authMethod = str(body["authMethod"]);
3837
5354
  const status = str(body["status"]);
@@ -3867,6 +5384,12 @@ function validateTokenBody(providerId, body) {
3867
5384
  return validateGemini(body);
3868
5385
  case "opencodego":
3869
5386
  return validateOpenCodeGo(body);
5387
+ case "kimi":
5388
+ return validateKimi(body);
5389
+ case "grok":
5390
+ return validateGrok(body);
5391
+ case "copilot":
5392
+ return validateCopilot(body);
3870
5393
  default:
3871
5394
  return null;
3872
5395
  }
@@ -3896,37 +5419,37 @@ async function statusEntryFor(reader, providerId) {
3896
5419
 
3897
5420
  // src/admin/accountsOAuth.ts
3898
5421
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
3899
- function err2(status, message) {
5422
+ function err5(status, message) {
3900
5423
  return { status, body: { error: { type: "admin_api_error", message } } };
3901
5424
  }
3902
5425
  function handleOAuthStart(providerId, deps) {
3903
5426
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3904
- return err2(400, `oauth not available for provider '${providerId}'`);
5427
+ return err5(400, `oauth not available for provider '${providerId}'`);
3905
5428
  }
3906
- const flow = providerId === "claude" ? import_subscriptions2.claudeOAuth : import_subscriptions2.geminiOAuth;
5429
+ const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
3907
5430
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
3908
5431
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
3909
5432
  return { status: 200, body: { authUrl, sessionId } };
3910
5433
  }
3911
5434
  async function handleOAuthComplete(providerId, body, deps) {
3912
5435
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3913
- return err2(400, `oauth not available for provider '${providerId}'`);
5436
+ return err5(400, `oauth not available for provider '${providerId}'`);
3914
5437
  }
3915
5438
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
3916
5439
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
3917
- if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
3918
- if (!rawCode) return err2(400, "oauth complete requires { code }");
5440
+ if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
5441
+ if (!rawCode) return err5(400, "oauth complete requires { code }");
3919
5442
  const session = deps.oauthSessions.peek(sessionId);
3920
- if (!session) return err2(410, "oauth session is unknown, expired, or already used");
5443
+ if (!session) return err5(410, "oauth session is unknown, expired, or already used");
3921
5444
  if (session.providerId !== providerId) {
3922
- return err2(400, `oauth session does not match provider '${providerId}'`);
5445
+ return err5(400, `oauth session does not match provider '${providerId}'`);
3923
5446
  }
3924
5447
  let code = rawCode.trim();
3925
5448
  if (providerId === "claude") {
3926
5449
  const [splitCode, pastedState] = code.split("#");
3927
- if (!splitCode) return err2(400, "no authorization code was provided");
5450
+ if (!splitCode) return err5(400, "no authorization code was provided");
3928
5451
  if (pastedState && pastedState !== session.state) {
3929
- return err2(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5452
+ return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
3930
5453
  }
3931
5454
  code = splitCode;
3932
5455
  }
@@ -3936,7 +5459,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3936
5459
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
3937
5460
  } catch (exchangeError) {
3938
5461
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
3939
- return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5462
+ return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
3940
5463
  }
3941
5464
  deps.oauthSessions.consume(sessionId);
3942
5465
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -3945,7 +5468,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3945
5468
  return { status: 200, body: status ? { account: status } : { ok: true } };
3946
5469
  }
3947
5470
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3948
- const result = await import_subscriptions2.claudeOAuth.exchangeCodeForTokens(
5471
+ const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
3949
5472
  { authorizationCode: code, codeVerifier, state },
3950
5473
  exchangeFetch
3951
5474
  );
@@ -3961,7 +5484,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3961
5484
  };
3962
5485
  }
3963
5486
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
3964
- const result = await import_subscriptions2.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
5487
+ const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
3965
5488
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
3966
5489
  return {
3967
5490
  authMethod: "oauth",
@@ -4266,8 +5789,8 @@ function errBody(message) {
4266
5789
  return { error: { type: "admin_api_error", message } };
4267
5790
  }
4268
5791
  var defaultCommandRunner = (command) => new Promise((resolve11) => {
4269
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err5, _stdout, stderr) => {
4270
- if (err5) resolve11({ ok: false, error: stderr.trim() || err5.message });
5792
+ (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5793
+ if (err8) resolve11({ ok: false, error: stderr.trim() || err8.message });
4271
5794
  else resolve11({ ok: true });
4272
5795
  });
4273
5796
  });
@@ -4313,8 +5836,8 @@ async function handleCliLaunch(cli, body, ctx) {
4313
5836
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
4314
5837
  model: typeof body["model"] === "string" ? body["model"] : void 0
4315
5838
  });
4316
- } catch (err5) {
4317
- return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
5839
+ } catch (err8) {
5840
+ return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
4318
5841
  }
4319
5842
  const id = (0, import_node_crypto7.randomUUID)();
4320
5843
  let leaseId2;
@@ -4342,9 +5865,9 @@ async function handleCliLaunch(cli, body, ctx) {
4342
5865
  } else {
4343
5866
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
4344
5867
  }
4345
- } catch (err5) {
4346
- const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
4347
- return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
5868
+ } catch (err8) {
5869
+ const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
5870
+ return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
4348
5871
  }
4349
5872
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
4350
5873
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -4372,9 +5895,9 @@ async function handleCliLaunch(cli, body, ctx) {
4372
5895
  onFailure: onSessionEnd
4373
5896
  });
4374
5897
  if (cleanup) openerCleanup = cleanup;
4375
- } catch (err5) {
5898
+ } catch (err8) {
4376
5899
  onSessionEnd();
4377
- return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
5900
+ return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
4378
5901
  }
4379
5902
  if (ended) {
4380
5903
  openerCleanup?.();
@@ -4629,7 +6152,7 @@ async function runSearchLiveChecks(contributions, now = () => (/* @__PURE__ */ n
4629
6152
  }
4630
6153
 
4631
6154
  // src/search/SearchAssembly.ts
4632
- var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
6155
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
4633
6156
  var import_search = require("@omnicross/core/search");
4634
6157
  var import_api2 = require("@omnicross/core/search/api");
4635
6158
  var import_http2 = require("@omnicross/core/search/http");
@@ -4647,7 +6170,7 @@ function searchPolicyFrom(config) {
4647
6170
  };
4648
6171
  }
4649
6172
  function resolveSearchUpstreamDispatcher(url) {
4650
- return (0, import_upstreamFetch3.resolveUpstreamDispatcher)({ url });
6173
+ return (0, import_upstreamFetch8.resolveUpstreamDispatcher)({ url });
4651
6174
  }
4652
6175
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
4653
6176
  function resolveSearchUpstreamProxyConfig(url) {
@@ -4929,7 +6452,7 @@ async function handleSearchQuery(req, res, deps) {
4929
6452
  // src/admin/searchAdminView.ts
4930
6453
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
4931
6454
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
4932
- function isRecord(value) {
6455
+ function isRecord4(value) {
4933
6456
  return value !== null && typeof value === "object" && !Array.isArray(value);
4934
6457
  }
4935
6458
  function redactSearchServerConfig(search) {
@@ -4979,13 +6502,13 @@ function resolveSecretField(entry, field, stored) {
4979
6502
  else delete entry[field];
4980
6503
  }
4981
6504
  function preserveSearchSecrets(incoming, current) {
4982
- if (!isRecord(incoming)) return incoming;
6505
+ if (!isRecord4(incoming)) return incoming;
4983
6506
  const section = { ...incoming };
4984
6507
  const providersValue = section["providers"];
4985
- if (!isRecord(providersValue)) return section;
6508
+ if (!isRecord4(providersValue)) return section;
4986
6509
  const providers = {};
4987
6510
  for (const [id, entryValue] of Object.entries(providersValue)) {
4988
- if (!isRecord(entryValue)) {
6511
+ if (!isRecord4(entryValue)) {
4989
6512
  providers[id] = entryValue;
4990
6513
  continue;
4991
6514
  }
@@ -5063,7 +6586,7 @@ function parseKeyPolicyBody(body) {
5063
6586
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
5064
6587
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
5065
6588
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
5066
- function isRecord2(value) {
6589
+ function isRecord5(value) {
5067
6590
  return !!value && typeof value === "object" && !Array.isArray(value);
5068
6591
  }
5069
6592
  function nonBlank(value) {
@@ -5083,7 +6606,7 @@ function validateGatewayBindingsSegment(patch) {
5083
6606
  const ids = /* @__PURE__ */ new Set();
5084
6607
  raw.forEach((entry, index) => {
5085
6608
  const path2 = `bindings[${index}]`;
5086
- if (!isRecord2(entry)) {
6609
+ if (!isRecord5(entry)) {
5087
6610
  errors.push(`${path2} must be an object`);
5088
6611
  return;
5089
6612
  }
@@ -5112,12 +6635,12 @@ function validateGatewayBindingsSegment(patch) {
5112
6635
  } else if (entry.modelMappings.length > 100) {
5113
6636
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
5114
6637
  } else if (entry.modelMappings.some(
5115
- (mapping) => !isRecord2(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6638
+ (mapping) => !isRecord5(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5116
6639
  )) {
5117
6640
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
5118
6641
  }
5119
6642
  }
5120
- if (!isRecord2(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6643
+ if (!isRecord5(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5121
6644
  errors.push(`${path2}.target is invalid`);
5122
6645
  } else {
5123
6646
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -5132,7 +6655,7 @@ function validateGatewayBindingsSegment(patch) {
5132
6655
  }
5133
6656
  }
5134
6657
  if (entry.modelMap !== void 0) {
5135
- if (!isRecord2(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6658
+ if (!isRecord5(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
5136
6659
  errors.push(`${path2}.modelMap must contain string values`);
5137
6660
  }
5138
6661
  }
@@ -5414,7 +6937,10 @@ var PROVIDER_KEYS = {
5414
6937
  block: "opencodego",
5415
6938
  accounts: "opencodegoAccounts",
5416
6939
  active: "activeOpencodegoAccountId"
5417
- }
6940
+ },
6941
+ kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6942
+ grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6943
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
5418
6944
  };
5419
6945
  function clone(value) {
5420
6946
  return JSON.parse(JSON.stringify(value));
@@ -5936,7 +7462,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
5936
7462
  }
5937
7463
 
5938
7464
  // src/admin/adminMigration.ts
5939
- function err3(status, message) {
7465
+ function err6(status, message) {
5940
7466
  return { status, body: { error: { type: "admin_api_error", message } } };
5941
7467
  }
5942
7468
  async function handleExport(body, deps) {
@@ -5946,30 +7472,30 @@ async function handleExport(body, deps) {
5946
7472
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
5947
7473
  } catch (error) {
5948
7474
  if (error instanceof WeakPassphraseError) {
5949
- return err3(400, error.message);
7475
+ return err6(400, error.message);
5950
7476
  }
5951
- return err3(500, "failed to build the migration pack");
7477
+ return err6(500, "failed to build the migration pack");
5952
7478
  }
5953
7479
  }
5954
7480
  async function handleImport(body, deps) {
5955
7481
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
5956
7482
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
5957
7483
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
5958
- if (!blob) return err3(400, "import requires { blob }");
7484
+ if (!blob) return err6(400, "import requires { blob }");
5959
7485
  try {
5960
7486
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
5961
7487
  return { status: 200, body: counts };
5962
7488
  } catch (error) {
5963
7489
  if (error instanceof WeakPassphraseError) {
5964
- return err3(400, error.message);
7490
+ return err6(400, error.message);
5965
7491
  }
5966
- return err3(400, error instanceof Error ? error.message : "import failed");
7492
+ return err6(400, error instanceof Error ? error.message : "import failed");
5967
7493
  }
5968
7494
  }
5969
7495
 
5970
7496
  // src/admin/usagePricing.ts
5971
7497
  var import_usage = require("@omnicross/core/usage");
5972
- var err4 = (status, message) => ({
7498
+ var err7 = (status, message) => ({
5973
7499
  status,
5974
7500
  body: { error: { type: "admin_api_error", message } }
5975
7501
  });
@@ -5982,7 +7508,7 @@ function parseRange(query2) {
5982
7508
  const startTs = parseFiniteInt(query2.get("startTs"));
5983
7509
  const endTs = parseFiniteInt(query2.get("endTs"));
5984
7510
  if (startTs === null || endTs === null) {
5985
- return err4(400, "startTs and endTs are required finite-integer unix-millis query params");
7511
+ return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
5986
7512
  }
5987
7513
  return { startTs, endTs };
5988
7514
  }
@@ -6007,14 +7533,14 @@ async function handleUsageGet(view, query2, deps) {
6007
7533
  case "timeseries": {
6008
7534
  const bucket = query2.get("bucket");
6009
7535
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
6010
- return err4(400, "bucket must be one of 'hour', 'day', 'month'");
7536
+ return err7(400, "bucket must be one of 'hour', 'day', 'month'");
6011
7537
  }
6012
7538
  const now = Date.now();
6013
7539
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
6014
7540
  if (clamped.startTs < clamped.endTs) {
6015
7541
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
6016
7542
  if (projected > MAX_TIMESERIES_BUCKETS) {
6017
- return err4(
7543
+ return err7(
6018
7544
  400,
6019
7545
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
6020
7546
  );
@@ -6037,7 +7563,7 @@ async function handleUsageGet(view, query2, deps) {
6037
7563
  };
6038
7564
  }
6039
7565
  default:
6040
- return err4(404, `unknown usage view '${view ?? ""}'`);
7566
+ return err7(404, `unknown usage view '${view ?? ""}'`);
6041
7567
  }
6042
7568
  }
6043
7569
  function poolKeyLabels(cfg) {
@@ -6086,7 +7612,7 @@ async function handlePricingList(deps) {
6086
7612
  async function handlePricingUpsert(body, deps) {
6087
7613
  const input = parsePricingEntryInput(body);
6088
7614
  if (!input) {
6089
- return err4(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7615
+ return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
6090
7616
  }
6091
7617
  const entry = await deps.pricingEngine.upsertManual(input);
6092
7618
  return { status: 200, body: { entry } };
@@ -6095,7 +7621,7 @@ async function handlePricingDelete(query2, deps) {
6095
7621
  const providerId = query2.get("providerId")?.trim() ?? "";
6096
7622
  const modelId = query2.get("modelId")?.trim() ?? "";
6097
7623
  if (!providerId || !modelId) {
6098
- return err4(400, "delete requires providerId and modelId query params");
7624
+ return err7(400, "delete requires providerId and modelId query params");
6099
7625
  }
6100
7626
  const deleted = await deps.pricingStore.delete(providerId, modelId);
6101
7627
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -6115,13 +7641,13 @@ async function handlePricingFetchLatest(deps) {
6115
7641
  }
6116
7642
  };
6117
7643
  } catch (e) {
6118
- return err4(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7644
+ return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
6119
7645
  }
6120
7646
  }
6121
7647
  async function handlePricingResolveConflicts(body, deps) {
6122
7648
  const raw = body["resolutions"];
6123
7649
  if (!Array.isArray(raw)) {
6124
- return err4(400, "resolve-conflicts requires { resolutions: [...] }");
7650
+ return err7(400, "resolve-conflicts requires { resolutions: [...] }");
6125
7651
  }
6126
7652
  const currentRows = await deps.pricingStore.getAll();
6127
7653
  const userEditedKeys = new Set(
@@ -6131,21 +7657,21 @@ async function handlePricingResolveConflicts(body, deps) {
6131
7657
  const pendingIncoming = /* @__PURE__ */ new Map();
6132
7658
  let staleCount = 0;
6133
7659
  for (const item of raw) {
6134
- if (!item || typeof item !== "object") return err4(400, "invalid resolution entry");
7660
+ if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
6135
7661
  const r = item;
6136
7662
  const action = r["action"];
6137
7663
  if (action !== "overwrite" && action !== "skip") {
6138
- return err4(400, "resolution action must be 'overwrite' or 'skip'");
7664
+ return err7(400, "resolution action must be 'overwrite' or 'skip'");
6139
7665
  }
6140
7666
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
6141
7667
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
6142
7668
  if (!providerId || !modelId) {
6143
- return err4(400, "each resolution requires top-level providerId and modelId");
7669
+ return err7(400, "each resolution requires top-level providerId and modelId");
6144
7670
  }
6145
7671
  const incoming = parsePricingEntryInput(r["incoming"]);
6146
- if (!incoming) return err4(400, "each resolution must echo a valid incoming pricing entry");
7672
+ if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
6147
7673
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
6148
- return err4(400, "resolution providerId/modelId must match the echoed incoming entry");
7674
+ return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
6149
7675
  }
6150
7676
  const key = `${providerId}::${modelId}`;
6151
7677
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -6190,7 +7716,7 @@ function query(req) {
6190
7716
  }
6191
7717
  function allowanceProvider(value) {
6192
7718
  if (!value) return void 0;
6193
- return value === "claude" || value === "codex" ? value : null;
7719
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" ? value : null;
6194
7720
  }
6195
7721
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
6196
7722
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -6204,7 +7730,9 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6204
7730
  const params = query(req);
6205
7731
  const pathProvider = rest.length >= 2 ? rest[0] : null;
6206
7732
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
6207
- if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
7733
+ if (providerId === null) {
7734
+ return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, or copilot");
7735
+ }
6208
7736
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
6209
7737
  const allowances = await service.list({ providerId, accountId });
6210
7738
  return writeJson3(res, 200, { allowances });
@@ -6214,10 +7742,57 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6214
7742
  const requestedProvider = allowanceProvider(
6215
7743
  typeof body["providerId"] === "string" ? body["providerId"] : "claude"
6216
7744
  );
6217
- if (requestedProvider !== "claude") {
6218
- return writeError2(res, 400, "only Claude allowances support explicit refresh");
6219
- }
6220
7745
  const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
7746
+ if (requestedProvider === "codex") {
7747
+ if (!service.refreshCodex) {
7748
+ return writeError2(res, 501, "codex allowance refresh is not available");
7749
+ }
7750
+ const allowances2 = await service.refreshCodex(accountId);
7751
+ if (accountId && allowances2.length === 0) {
7752
+ return writeError2(res, 404, `Codex account '${accountId}' not found`);
7753
+ }
7754
+ return writeJson3(res, 200, { allowances: allowances2 });
7755
+ }
7756
+ if (requestedProvider === "kimi") {
7757
+ if (!service.refreshKimi) {
7758
+ return writeError2(res, 501, "kimi allowance refresh is not available");
7759
+ }
7760
+ const allowances2 = await service.refreshKimi(accountId);
7761
+ if (accountId && allowances2.length === 0) {
7762
+ return writeError2(res, 404, `Kimi account '${accountId}' not found`);
7763
+ }
7764
+ return writeJson3(res, 200, { allowances: allowances2 });
7765
+ }
7766
+ if (requestedProvider === "opencodego") {
7767
+ if (!service.refreshOpenCodeGo) {
7768
+ return writeError2(res, 501, "opencodego allowance refresh is not available");
7769
+ }
7770
+ const allowances2 = await service.refreshOpenCodeGo(accountId);
7771
+ if (accountId && allowances2.length === 0) {
7772
+ return writeError2(res, 404, `OpenCodeGo account '${accountId}' not found`);
7773
+ }
7774
+ return writeJson3(res, 200, { allowances: allowances2 });
7775
+ }
7776
+ if (requestedProvider === "copilot") {
7777
+ if (!service.refreshCopilot) {
7778
+ return writeError2(res, 501, "copilot allowance refresh is not available");
7779
+ }
7780
+ const allowances2 = await service.refreshCopilot(accountId);
7781
+ if (accountId && allowances2.length === 0) {
7782
+ return writeError2(res, 404, `Copilot account '${accountId}' not found`);
7783
+ }
7784
+ return writeJson3(res, 200, { allowances: allowances2 });
7785
+ }
7786
+ if (requestedProvider === "grok") {
7787
+ if (!service.refreshGrok) {
7788
+ return writeError2(res, 501, "grok allowance refresh is not available");
7789
+ }
7790
+ const allowances2 = await service.refreshGrok(accountId);
7791
+ if (accountId && allowances2.length === 0) {
7792
+ return writeError2(res, 404, `Grok account '${accountId}' not found`);
7793
+ }
7794
+ return writeJson3(res, 200, { allowances: allowances2 });
7795
+ }
6221
7796
  const allowances = await service.refreshClaude(accountId);
6222
7797
  if (accountId && allowances.length === 0) {
6223
7798
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
@@ -6316,6 +7891,9 @@ function toProviderView(row) {
6316
7891
  apiVersion: row.apiVersion,
6317
7892
  maxConcurrency: row.maxConcurrency,
6318
7893
  modelsEndpoint: row.modelsEndpoint,
7894
+ // Static extra headers round-trip VERBATIM (non-secret identity values;
7895
+ // auth/content names were already dropped at the write/load gate).
7896
+ extraHeaders: row.extraHeaders,
6319
7897
  // app-parity child 5: transformer config round-trips VERBATIM (non-secret —
6320
7898
  // transform-rule names + options, no key material; absent stays absent).
6321
7899
  transformer: row.transformer,
@@ -6385,8 +7963,8 @@ async function handleAdminApi(req, res, path2, deps) {
6385
7963
  default:
6386
7964
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
6387
7965
  }
6388
- } catch (err5) {
6389
- writeJsonError(res, 500, err5 instanceof Error ? err5.message : String(err5));
7966
+ } catch (err8) {
7967
+ writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
6390
7968
  }
6391
7969
  }
6392
7970
  function requestQuery(req) {
@@ -6456,6 +8034,9 @@ async function handleProviders(req, res, method, rest, deps) {
6456
8034
  if (method === "POST" && rest.length === 4 && rest[1] === "keys" && rest[3] === "enabled") {
6457
8035
  return await handleToggleProviderKey(req, res, rest[0], rest[2], cfg, deps);
6458
8036
  }
8037
+ if (method === "POST" && rest.length === 5 && rest[1] === "keys" && rest[3] === "quota" && rest[4] === "refresh") {
8038
+ return await handleProviderKeyQuotaRefresh(res, rest[0], rest[2], cfg, deps);
8039
+ }
6459
8040
  if (method === "PUT" && rest.length === 3 && rest[1] === "keys") {
6460
8041
  return await handleUpdateProviderKey(req, res, rest[0], rest[2], cfg, deps);
6461
8042
  }
@@ -6541,6 +8122,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
6541
8122
  persistProviders(cfg, deps);
6542
8123
  return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
6543
8124
  }
8125
+ function expandRowExtraHeaders(row) {
8126
+ return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
8127
+ }
6544
8128
  async function handleDiscoverModels(res, id, cfg) {
6545
8129
  if (!id) return writeJsonError(res, 400, "provider id required in path");
6546
8130
  const row = cfg.providers.find((p) => p.id === id);
@@ -6554,7 +8138,8 @@ async function handleDiscoverModels(res, id, cfg) {
6554
8138
  try {
6555
8139
  const headers = { Accept: "application/json" };
6556
8140
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
6557
- const response = await (0, import_upstreamFetch4.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
8141
+ Object.assign(headers, expandRowExtraHeaders(row));
8142
+ const response = await (0, import_upstreamFetch9.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
6558
8143
  if (!response.ok) {
6559
8144
  const text = await response.text().catch(() => "");
6560
8145
  let message = text.slice(0, 300);
@@ -6571,8 +8156,8 @@ async function handleDiscoverModels(res, id, cfg) {
6571
8156
  const data = await response.json();
6572
8157
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
6573
8158
  return writeJson4(res, 200, { models });
6574
- } catch (err5) {
6575
- const message = err5 instanceof Error ? err5.message : String(err5);
8159
+ } catch (err8) {
8160
+ const message = err8 instanceof Error ? err8.message : String(err8);
6576
8161
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
6577
8162
  }
6578
8163
  }
@@ -6611,9 +8196,10 @@ async function handleTestModel(req, res, id, cfg) {
6611
8196
  messages: [{ role: "user", content: prompt }]
6612
8197
  };
6613
8198
  }
8199
+ Object.assign(headers, expandRowExtraHeaders(row));
6614
8200
  const startedAt = Date.now();
6615
8201
  try {
6616
- const response = await (0, import_upstreamFetch4.fetchUpstream)(
8202
+ const response = await (0, import_upstreamFetch9.fetchUpstream)(
6617
8203
  url,
6618
8204
  { method: "POST", headers, body: JSON.stringify(payload) },
6619
8205
  { providerId: "byo" }
@@ -6635,8 +8221,8 @@ async function handleTestModel(req, res, id, cfg) {
6635
8221
  latencyMs,
6636
8222
  sample: extractSampleText(text, row.apiFormat)
6637
8223
  });
6638
- } catch (err5) {
6639
- const message = err5 instanceof Error ? err5.message : String(err5);
8224
+ } catch (err8) {
8225
+ const message = err8 instanceof Error ? err8.message : String(err8);
6640
8226
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
6641
8227
  }
6642
8228
  }
@@ -6678,7 +8264,30 @@ async function handleProviderKeys(res, id, cfg, deps) {
6678
8264
  const row = cfg.providers.find((p) => p.id === id);
6679
8265
  if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
6680
8266
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
6681
- return writeJson4(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
8267
+ const views = toPoolKeyView(row, cooldown, deps);
8268
+ if (deps.providerKeyQuota) {
8269
+ const quotas = await Promise.allSettled(
8270
+ views.map((view) => deps.providerKeyQuota.quotaFor(row, view.id))
8271
+ );
8272
+ views.forEach((view, index) => {
8273
+ const settled = quotas[index];
8274
+ if (settled.status === "fulfilled" && settled.value) view.quota = settled.value;
8275
+ });
8276
+ }
8277
+ return writeJson4(res, 200, { keys: views });
8278
+ }
8279
+ async function handleProviderKeyQuotaRefresh(res, id, keyId, cfg, deps) {
8280
+ if (!deps.providerKeyQuota) return writeJsonError(res, 501, "provider key quota is not available");
8281
+ if (!id || !keyId) return writeJsonError(res, 400, "provider id and key id required in path");
8282
+ const row = cfg.providers.find((p) => p.id === id);
8283
+ if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
8284
+ try {
8285
+ const quota = await deps.providerKeyQuota.quotaFor(row, keyId, { force: true });
8286
+ if (!quota) return writeJsonError(res, 404, `no quota endpoint for key '${keyId}'`);
8287
+ return writeJson4(res, 200, { quota });
8288
+ } catch {
8289
+ return writeJsonError(res, 502, "quota refresh failed");
8290
+ }
6682
8291
  }
6683
8292
  function parsePoolKeyInput(body, existing) {
6684
8293
  const out = {};
@@ -6895,6 +8504,7 @@ function parseProviderInput(body, existing) {
6895
8504
  const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
6896
8505
  const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
6897
8506
  const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
8507
+ const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
6898
8508
  const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
6899
8509
  const codingPlan = body["codingPlan"] === null ? void 0 : body["codingPlan"] === void 0 ? existing?.codingPlan : body["codingPlan"] && typeof body["codingPlan"] === "object" && !Array.isArray(body["codingPlan"]) ? parseCodingPlanInput(body["codingPlan"], existing?.codingPlan) : existing?.codingPlan;
6900
8510
  const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
@@ -6920,6 +8530,7 @@ function parseProviderInput(body, existing) {
6920
8530
  apiVersion,
6921
8531
  maxConcurrency,
6922
8532
  modelsEndpoint,
8533
+ extraHeaders,
6923
8534
  transformer: migrated.transformer,
6924
8535
  codingPlan,
6925
8536
  apiModes,
@@ -6941,7 +8552,10 @@ function handlePresets(res, method) {
6941
8552
  description: p.description,
6942
8553
  features: p.features,
6943
8554
  website: p.website,
6944
- modelsEndpoint: p.modelsEndpoint
8555
+ modelsEndpoint: p.modelsEndpoint,
8556
+ // Static extra headers ride along so `addFromPreset` can seed them onto the
8557
+ // row (the write gateway re-validates via the shared allowlist).
8558
+ extraHeaders: p.extraHeaders
6945
8559
  }));
6946
8560
  return writeJson4(res, 200, { presets, excluded });
6947
8561
  }
@@ -7423,12 +9037,12 @@ async function handleAccounts(req, res, method, rest, deps) {
7423
9037
  }
7424
9038
  return writeJson4(res, 200, { ok: true, affected: result.affected });
7425
9039
  }
7426
- if (method === "GET" && rest[0] === "codex" && rest[1] === "oauth" && rest[3] === "status") {
7427
- const result = handleCodexOAuthStatus(rest[2], deps);
9040
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
9041
+ const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : handleCopilotOAuthStatus(rest[2], deps);
7428
9042
  return writeJson4(res, result.status, result.body);
7429
9043
  }
7430
- if (method === "DELETE" && rest[0] === "codex" && rest[1] === "oauth" && rest[2]) {
7431
- const result = handleCodexOAuthCancel(rest[2], deps);
9044
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
9045
+ const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : handleCopilotOAuthCancel(rest[2], deps);
7432
9046
  return writeJson4(res, result.status, result.body);
7433
9047
  }
7434
9048
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -7481,7 +9095,24 @@ async function handleAccounts(req, res, method, rest, deps) {
7481
9095
  return writeJsonError(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
7482
9096
  }
7483
9097
  if (method === "POST" && rest[1] === "oauth" && rest[2] === "start") {
7484
- const result = providerId === "codex" ? handleCodexOAuthStart(deps) : handleOAuthStart(providerId, deps);
9098
+ if (providerId === "codex") {
9099
+ const result2 = handleCodexOAuthStart(deps);
9100
+ return writeJson4(res, result2.status, result2.body);
9101
+ }
9102
+ if (providerId === "kimi") {
9103
+ const result2 = await handleKimiOAuthStart(deps);
9104
+ return writeJson4(res, result2.status, result2.body);
9105
+ }
9106
+ if (providerId === "grok") {
9107
+ const result2 = await handleGrokOAuthStart(deps);
9108
+ return writeJson4(res, result2.status, result2.body);
9109
+ }
9110
+ if (providerId === "copilot") {
9111
+ const body2 = await readJsonBody4(req);
9112
+ const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
9113
+ return writeJson4(res, result2.status, result2.body);
9114
+ }
9115
+ const result = handleOAuthStart(providerId, deps);
7485
9116
  return writeJson4(res, result.status, result.body);
7486
9117
  }
7487
9118
  if (method === "POST" && rest[1] === "oauth" && rest[2] === "complete") {
@@ -7975,12 +9606,12 @@ async function handlePlayground(req, res, method, deps) {
7975
9606
  const payload = body["body"];
7976
9607
  const status = deps.outboundApiServer.getStatus();
7977
9608
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
7978
- const path2 = resolvePlaygroundPath(endpoint, isRecord3(payload) ? payload : {});
9609
+ const path2 = resolvePlaygroundPath(endpoint, isRecord6(payload) ? payload : {});
7979
9610
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
7980
9611
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
7981
9612
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
7982
9613
  }
7983
- function isRecord3(v) {
9614
+ function isRecord6(v) {
7984
9615
  return !!v && typeof v === "object" && !Array.isArray(v);
7985
9616
  }
7986
9617
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -8009,8 +9640,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
8009
9640
  });
8010
9641
  }
8011
9642
  );
8012
- upstream.on("error", (err5) => {
8013
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err5.message}`);
9643
+ upstream.on("error", (err8) => {
9644
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
8014
9645
  else res.end();
8015
9646
  resolve11();
8016
9647
  });
@@ -8116,7 +9747,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
8116
9747
  }
8117
9748
 
8118
9749
  // src/admin/version.ts
8119
- var DAEMON_VERSION = true ? "0.3.0" : "0.0.0-dev";
9750
+ var DAEMON_VERSION = true ? "0.4.0" : "0.0.0-dev";
8120
9751
 
8121
9752
  // src/admin/AdminServer.ts
8122
9753
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -8159,13 +9790,13 @@ var AdminServer = class {
8159
9790
  const server = import_node_http2.default.createServer((req, res) => {
8160
9791
  this.onRequest(req, res);
8161
9792
  });
8162
- const onError = (err5) => {
8163
- if (err5.code === "EADDRINUSE" && port !== 0) {
9793
+ const onError = (err8) => {
9794
+ if (err8.code === "EADDRINUSE" && port !== 0) {
8164
9795
  server.removeListener("error", onError);
8165
9796
  this.listen(bindAddr, 0).then(resolve11, reject);
8166
9797
  return;
8167
9798
  }
8168
- reject(err5);
9799
+ reject(err8);
8169
9800
  };
8170
9801
  server.on("error", onError);
8171
9802
  server.listen(port, bindAddr, () => {
@@ -8183,8 +9814,8 @@ var AdminServer = class {
8183
9814
  }
8184
9815
  /** Per-request handler: auth gate (when a token is set) → routing. */
8185
9816
  onRequest(req, res) {
8186
- void this.dispatch(req, res).catch((err5) => {
8187
- const message = err5 instanceof Error ? err5.message : String(err5);
9817
+ void this.dispatch(req, res).catch((err8) => {
9818
+ const message = err8 instanceof Error ? err8.message : String(err8);
8188
9819
  this.deps.logger.error("[AdminServer] unhandled error:", message);
8189
9820
  if (!res.headersSent) {
8190
9821
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -8448,18 +10079,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
8448
10079
  return;
8449
10080
  }
8450
10081
  signal?.addEventListener("abort", abort, { once: true });
8451
- server.on("error", (err5) => {
10082
+ server.on("error", (err8) => {
8452
10083
  if (settled) return;
8453
10084
  settled = true;
8454
10085
  clearTimeout(timer);
8455
- if (err5.code === "EADDRINUSE") {
10086
+ if (err8.code === "EADDRINUSE") {
8456
10087
  reject(
8457
10088
  new Error(
8458
10089
  `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
8459
10090
  )
8460
10091
  );
8461
10092
  } else {
8462
- reject(err5);
10093
+ reject(err8);
8463
10094
  }
8464
10095
  });
8465
10096
  const timer = setTimeout(() => {
@@ -8489,55 +10120,498 @@ var AutoDisableStore = class {
8489
10120
  clear() {
8490
10121
  this.records.clear();
8491
10122
  }
8492
- };
8493
-
8494
- // src/pool/loadPoolKeys.ts
8495
- var secretBox2 = null;
8496
- function setSecretBox2(box) {
8497
- secretBox2 = box;
10123
+ };
10124
+
10125
+ // src/pool/loadPoolKeys.ts
10126
+ var secretBox2 = null;
10127
+ function setSecretBox2(box) {
10128
+ secretBox2 = box;
10129
+ }
10130
+ function readKeyValue(rawKey) {
10131
+ return secretBox2 ? secretBox2.decryptMaybe(rawKey) : rawKey;
10132
+ }
10133
+ function normalizeEntry(providerId, entry, sortOrder, autoDisabled) {
10134
+ const enabledInConfig = entry.enabled !== false;
10135
+ const enabled = enabledInConfig && !autoDisabled.isDisabled(entry.id);
10136
+ return {
10137
+ id: entry.id,
10138
+ providerId,
10139
+ label: entry.label && entry.label.length > 0 ? entry.label : entry.id,
10140
+ apiKey: readKeyValue(entry.apiKey),
10141
+ enabled,
10142
+ weight: typeof entry.weight === "number" && Number.isFinite(entry.weight) ? entry.weight : 1,
10143
+ sortOrder
10144
+ };
10145
+ }
10146
+ function createPoolKeysLoader(getProviderRow, autoDisabled) {
10147
+ return async (providerId) => {
10148
+ const row = getProviderRow(providerId);
10149
+ if (!row) return [];
10150
+ const pool = (row.apiKeys ?? []).filter((k) => k.apiKey.length > 0);
10151
+ if (pool.length > 0) {
10152
+ return pool.map((entry, i) => normalizeEntry(providerId, entry, i, autoDisabled));
10153
+ }
10154
+ if (row.apiKey.length > 0) {
10155
+ return [
10156
+ normalizeEntry(
10157
+ providerId,
10158
+ { id: `${providerId}:default`, apiKey: row.apiKey, weight: 1, enabled: true },
10159
+ 0,
10160
+ autoDisabled
10161
+ )
10162
+ ];
10163
+ }
10164
+ return [];
10165
+ };
10166
+ }
10167
+
10168
+ // src/allowance/ProviderKeyQuotaService.ts
10169
+ var import_core4 = require("@omnicross/core");
10170
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
10171
+
10172
+ // src/allowance/ProviderKeyQuota.ts
10173
+ var MINUTE_MS3 = 6e4;
10174
+ var HOUR_MS2 = 60 * MINUTE_MS3;
10175
+ var DAY_MS3 = 24 * HOUR_MS2;
10176
+ var WEEK_MS = 7 * DAY_MS3;
10177
+ var MONTH_MS = 30 * DAY_MS3;
10178
+ function finiteNumber5(value) {
10179
+ if (value === null || value === void 0 || value === "") return void 0;
10180
+ const parsed = typeof value === "number" ? value : Number(value);
10181
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
10182
+ }
10183
+ function finitePercent4(value) {
10184
+ const parsed = finiteNumber5(value);
10185
+ return parsed !== void 0 && parsed <= 100 ? parsed : null;
10186
+ }
10187
+ function isoInstant3(value) {
10188
+ if (typeof value === "string" && value.trim()) {
10189
+ const time = Date.parse(value);
10190
+ if (Number.isFinite(time)) return new Date(time).toISOString();
10191
+ }
10192
+ const numeric = finiteNumber5(value);
10193
+ if (numeric !== void 0 && numeric > 1e9) {
10194
+ const ms = numeric > 1e12 ? numeric : numeric * 1e3;
10195
+ return new Date(ms).toISOString();
10196
+ }
10197
+ return void 0;
10198
+ }
10199
+ function secondsUntil7(instant, now) {
10200
+ if (!instant) return void 0;
10201
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
10202
+ }
10203
+ function isRecord7(value) {
10204
+ return !!value && typeof value === "object" && !Array.isArray(value);
10205
+ }
10206
+ function detectProviderKeyQuotaAdapter(baseUrl) {
10207
+ if (!baseUrl) return null;
10208
+ let url;
10209
+ try {
10210
+ url = new URL(baseUrl);
10211
+ } catch {
10212
+ return null;
10213
+ }
10214
+ const host = url.hostname.toLowerCase();
10215
+ const path2 = url.pathname.toLowerCase();
10216
+ if ((host === "api.z.ai" || host === "open.bigmodel.cn") && path2.includes("/coding")) {
10217
+ return "zai";
10218
+ }
10219
+ if ((host === "api.minimax.io" || host === "api.minimaxi.com") && // Token Plan rides the plain openai `/v1` (chat completions) surface; the
10220
+ // anthropic `/anthropic` rows are excluded (their usage impl is unverified).
10221
+ (path2 === "/v1" || path2 === "/v1/" || path2 === "" || path2 === "/")) {
10222
+ return "minimax-token-plan";
10223
+ }
10224
+ if (host === "api.code.umans.ai") return "umans";
10225
+ if (host === "api.synthetic.new") return "synthetic";
10226
+ if (host === "api.cline.bot") return "cline-pass";
10227
+ return null;
10228
+ }
10229
+ function providerKeyQuotaUrl(adapter, baseUrl) {
10230
+ const origin = new URL(baseUrl).origin;
10231
+ if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
10232
+ if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
10233
+ if (adapter === "umans") return `${origin}/v1/usage`;
10234
+ if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
10235
+ return `${origin}/v2/quotas`;
10236
+ }
10237
+ function providerKeyQuotaAuthHeader(adapter, key) {
10238
+ return adapter === "zai" ? key : `Bearer ${key}`;
10239
+ }
10240
+ function zaiWindowDurationMs(item) {
10241
+ const count = item.number !== void 0 && item.number > 0 ? item.number : 1;
10242
+ switch (item.unit) {
10243
+ case 3:
10244
+ return count * HOUR_MS2;
10245
+ case 4:
10246
+ return count * DAY_MS3;
10247
+ case 5:
10248
+ return count * MONTH_MS;
10249
+ case 6:
10250
+ return WEEK_MS;
10251
+ default:
10252
+ return void 0;
10253
+ }
10254
+ }
10255
+ function zaiWindowIdLabel(durationMs) {
10256
+ if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
10257
+ if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
10258
+ if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
10259
+ if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
10260
+ const days = durationMs / DAY_MS3;
10261
+ return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
10262
+ }
10263
+ if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
10264
+ const hours = durationMs / HOUR_MS2;
10265
+ return { id: `${hours}h`, label: `${hours} hour${hours === 1 ? "" : "s"}` };
10266
+ }
10267
+ return { id: "quota", label: "Quota" };
10268
+ }
10269
+ function parseZaiQuotaPayload(payload, now) {
10270
+ if (!isRecord7(payload)) return null;
10271
+ const data = isRecord7(payload["data"]) ? payload["data"] : payload;
10272
+ if (payload["success"] === false) return null;
10273
+ const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10274
+ const byWindow = /* @__PURE__ */ new Map();
10275
+ for (const raw of limits) {
10276
+ if (!isRecord7(raw)) continue;
10277
+ const item = raw;
10278
+ if (item.type === void 0) continue;
10279
+ const details = raw["usageDetails"];
10280
+ if (Array.isArray(details) && details.some((d) => isRecord7(d) && d["modelCode"] === "zread")) {
10281
+ continue;
10282
+ }
10283
+ const durationMs = zaiWindowDurationMs(item);
10284
+ const { id, label } = zaiWindowIdLabel(durationMs);
10285
+ const limit = finiteNumber5(item.usage);
10286
+ const used = finiteNumber5(item.currentValue);
10287
+ const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
10288
+ const fromPercentage = finitePercent4(item.percentage) ?? void 0;
10289
+ const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
10290
+ if (usedPercent === void 0) continue;
10291
+ const resetsAt = isoInstant3(item.nextResetTime);
10292
+ const candidate = {
10293
+ id,
10294
+ label,
10295
+ scope: "all",
10296
+ usedPercent,
10297
+ ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
10298
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10299
+ remainingSeconds: secondsUntil7(resetsAt, now),
10300
+ state: "fresh"
10301
+ };
10302
+ const existing = byWindow.get(id);
10303
+ if (!existing || (candidate.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
10304
+ byWindow.set(id, candidate);
10305
+ }
10306
+ }
10307
+ const windows = [...byWindow.values()].sort((a, b) => (a.windowMinutes ?? Number.POSITIVE_INFINITY) - (b.windowMinutes ?? Number.POSITIVE_INFINITY));
10308
+ return windows.length > 0 ? windows.slice(0, 4) : null;
10309
+ }
10310
+ var MINIMAX_STATUS_EXHAUSTED = 2;
10311
+ var MINIMAX_SHARED_BUCKET = "general";
10312
+ function parseMiniMaxBucket(value) {
10313
+ if (!isRecord7(value)) return null;
10314
+ const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
10315
+ if (!modelName) return null;
10316
+ const instant = (v) => {
10317
+ const n = finiteNumber5(v);
10318
+ return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
10319
+ };
10320
+ return {
10321
+ modelName,
10322
+ intervalEnd: instant(value["end_time"]),
10323
+ intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
10324
+ intervalStatus: finiteNumber5(value["current_interval_status"]),
10325
+ weeklyEnd: instant(value["weekly_end_time"]),
10326
+ weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
10327
+ weeklyStatus: finiteNumber5(value["current_weekly_status"])
10328
+ };
10329
+ }
10330
+ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
10331
+ const usedPercent = status === MINIMAX_STATUS_EXHAUSTED ? 100 : remainingPercent !== void 0 ? Math.round((100 - remainingPercent) * 10) / 10 : null;
10332
+ const resetsAt = resetsAtMs !== void 0 ? new Date(resetsAtMs).toISOString() : void 0;
10333
+ return {
10334
+ id,
10335
+ label,
10336
+ scope: "all",
10337
+ usedPercent,
10338
+ ...windowMinutes !== void 0 ? { windowMinutes } : {},
10339
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10340
+ remainingSeconds: secondsUntil7(resetsAt, now),
10341
+ state: usedPercent !== null ? "fresh" : "unavailable"
10342
+ };
10343
+ }
10344
+ function parseMiniMaxTokenPlanPayload(payload, now) {
10345
+ if (!isRecord7(payload)) return null;
10346
+ const baseResp = payload["base_resp"];
10347
+ if (!isRecord7(baseResp) || baseResp["status_code"] !== 0) return null;
10348
+ const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
10349
+ let general = null;
10350
+ for (const raw of buckets) {
10351
+ const bucket = parseMiniMaxBucket(raw);
10352
+ if (bucket?.modelName === MINIMAX_SHARED_BUCKET) {
10353
+ general = bucket;
10354
+ break;
10355
+ }
10356
+ }
10357
+ if (!general) return null;
10358
+ return [
10359
+ minimaxWindow(
10360
+ "five-hour",
10361
+ "5 hours",
10362
+ 5 * 60,
10363
+ general.intervalEnd,
10364
+ general.intervalRemainingPercent,
10365
+ general.intervalStatus,
10366
+ now
10367
+ ),
10368
+ minimaxWindow(
10369
+ "seven-day",
10370
+ "7 days",
10371
+ Math.round(WEEK_MS / MINUTE_MS3),
10372
+ general.weeklyEnd,
10373
+ general.weeklyRemainingPercent,
10374
+ general.weeklyStatus,
10375
+ now
10376
+ )
10377
+ ];
10378
+ }
10379
+ function parseUmansUsagePayload(payload, now) {
10380
+ if (!isRecord7(payload)) return null;
10381
+ const limits = isRecord7(payload["limits"]) ? payload["limits"] : void 0;
10382
+ const requests = limits && isRecord7(limits["requests"]) ? limits["requests"] : void 0;
10383
+ const usage = isRecord7(payload["usage"]) ? payload["usage"] : void 0;
10384
+ const window = isRecord7(payload["window"]) ? payload["window"] : void 0;
10385
+ const hardCap = finiteNumber5(requests?.["hard_cap"]);
10386
+ const softLimit = finiteNumber5(requests?.["limit"]);
10387
+ const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
10388
+ const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
10389
+ const resetsAt = isoInstant3(window?.["resets_at"]);
10390
+ let usedPercent = null;
10391
+ if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
10392
+ usedPercent = Math.round(Math.min(100, requestsInWindow / hardCap * 100) * 10) / 10;
10393
+ } else if (softLimit !== void 0 && softLimit > 0 && weightedInWindow !== void 0) {
10394
+ usedPercent = Math.round(Math.min(100, weightedInWindow / softLimit * 100) * 10) / 10;
10395
+ }
10396
+ if (usedPercent === null && resetsAt === void 0) return null;
10397
+ return [
10398
+ {
10399
+ id: "five-hour",
10400
+ label: "5 hours",
10401
+ scope: "all",
10402
+ usedPercent,
10403
+ windowMinutes: 5 * 60,
10404
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10405
+ remainingSeconds: secondsUntil7(resetsAt, now),
10406
+ state: "fresh"
10407
+ }
10408
+ ];
10409
+ }
10410
+ function parseSyntheticQuotasPayload(payload, now) {
10411
+ if (!isRecord7(payload)) return null;
10412
+ const fiveHour = isRecord7(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
10413
+ const weekly = isRecord7(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10414
+ const windows = [];
10415
+ if (fiveHour) {
10416
+ const max = finiteNumber5(fiveHour["max"]);
10417
+ const remaining = finiteNumber5(fiveHour["remaining"]);
10418
+ const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
10419
+ const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
10420
+ windows.push({
10421
+ id: "five-hour",
10422
+ label: "5 hours",
10423
+ scope: "all",
10424
+ usedPercent,
10425
+ windowMinutes: 5 * 60,
10426
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10427
+ remainingSeconds: secondsUntil7(resetsAt, now),
10428
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10429
+ });
10430
+ }
10431
+ if (weekly) {
10432
+ const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
10433
+ const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
10434
+ const resetsAt = isoInstant3(weekly["nextRegenAt"]);
10435
+ windows.push({
10436
+ id: "seven-day",
10437
+ label: "7 days",
10438
+ scope: "all",
10439
+ usedPercent,
10440
+ windowMinutes: 7 * 24 * 60,
10441
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10442
+ remainingSeconds: secondsUntil7(resetsAt, now),
10443
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10444
+ });
10445
+ }
10446
+ return windows.length > 0 ? windows : null;
8498
10447
  }
8499
- function readKeyValue(rawKey) {
8500
- return secretBox2 ? secretBox2.decryptMaybe(rawKey) : rawKey;
10448
+ var CLINE_WINDOW_CONFIG = {
10449
+ five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
10450
+ weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
10451
+ monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
10452
+ };
10453
+ function parseClinePassUsageLimitsPayload(payload, now) {
10454
+ if (!isRecord7(payload)) return null;
10455
+ const data = isRecord7(payload["data"]) ? payload["data"] : payload;
10456
+ const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10457
+ const windows = [];
10458
+ for (const raw of limits) {
10459
+ if (!isRecord7(raw)) continue;
10460
+ const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
10461
+ if (!config) continue;
10462
+ const usedPercent = finitePercent4(raw["percentUsed"]);
10463
+ if (usedPercent === null) continue;
10464
+ const resetsAt = isoInstant3(raw["resetsAt"]);
10465
+ windows.push({
10466
+ id: config.id,
10467
+ label: config.label,
10468
+ scope: "all",
10469
+ usedPercent,
10470
+ windowMinutes: config.minutes,
10471
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10472
+ remainingSeconds: secondsUntil7(resetsAt, now),
10473
+ state: "fresh"
10474
+ });
10475
+ }
10476
+ return windows.length > 0 ? windows : null;
8501
10477
  }
8502
- function normalizeEntry(providerId, entry, sortOrder, autoDisabled) {
8503
- const enabledInConfig = entry.enabled !== false;
8504
- const enabled = enabledInConfig && !autoDisabled.isDisabled(entry.id);
8505
- return {
8506
- id: entry.id,
8507
- providerId,
8508
- label: entry.label && entry.label.length > 0 ? entry.label : entry.id,
8509
- apiKey: readKeyValue(entry.apiKey),
8510
- enabled,
8511
- weight: typeof entry.weight === "number" && Number.isFinite(entry.weight) ? entry.weight : 1,
8512
- sortOrder
8513
- };
10478
+
10479
+ // src/allowance/ProviderKeyQuotaService.ts
10480
+ function parseQuotaPayload(adapter, payload, now) {
10481
+ switch (adapter) {
10482
+ case "zai":
10483
+ return parseZaiQuotaPayload(payload, now);
10484
+ case "minimax-token-plan":
10485
+ return parseMiniMaxTokenPlanPayload(payload, now);
10486
+ case "umans":
10487
+ return parseUmansUsagePayload(payload, now);
10488
+ case "synthetic":
10489
+ return parseSyntheticQuotasPayload(payload, now);
10490
+ case "cline-pass":
10491
+ return parseClinePassUsageLimitsPayload(payload, now);
10492
+ }
10493
+ }
10494
+ var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
10495
+ function resolvedBaseUrl(row) {
10496
+ const modes = row.apiModes ?? [];
10497
+ const selected = row.selectedApiModeId ? modes.find((mode) => mode.id === row.selectedApiModeId) : void 0;
10498
+ const fallback = modes[0];
10499
+ const modeBase = selected?.baseUrl ?? fallback?.baseUrl;
10500
+ return modeBase ?? row.codingPlan?.baseUrl ?? row.baseUrl;
10501
+ }
10502
+ function rowKeyEntries(row) {
10503
+ const pool = (row.apiKeys ?? []).filter((entry) => entry.apiKey.length > 0);
10504
+ if (pool.length > 0) return pool.map((entry) => ({ id: entry.id, apiKey: entry.apiKey }));
10505
+ if (row.apiKey.length > 0) {
10506
+ return [{ id: `${row.id}:default`, apiKey: row.apiKey }];
10507
+ }
10508
+ return [];
8514
10509
  }
8515
- function createPoolKeysLoader(getProviderRow, autoDisabled) {
8516
- return async (providerId) => {
8517
- const row = getProviderRow(providerId);
8518
- if (!row) return [];
8519
- const pool = (row.apiKeys ?? []).filter((k) => k.apiKey.length > 0);
8520
- if (pool.length > 0) {
8521
- return pool.map((entry, i) => normalizeEntry(providerId, entry, i, autoDisabled));
10510
+ var ProviderKeyQuotaService = class {
10511
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
10512
+ this.box = box;
10513
+ this.fetchImpl = fetchImpl;
10514
+ this.now = now;
10515
+ }
10516
+ box;
10517
+ fetchImpl;
10518
+ now;
10519
+ cache = /* @__PURE__ */ new Map();
10520
+ inFlight = /* @__PURE__ */ new Map();
10521
+ /**
10522
+ * Quota for one key of a provider row, or `null` when the row has no quota
10523
+ * adapter / no such key. Cache-first; concurrent reads share one flight.
10524
+ */
10525
+ async quotaFor(row, keyId, options = {}) {
10526
+ const adapter = detectProviderKeyQuotaAdapter(resolvedBaseUrl(row));
10527
+ if (!adapter) return null;
10528
+ const entry = rowKeyEntries(row).find((candidate) => candidate.id === keyId);
10529
+ if (!entry) return null;
10530
+ const cacheKey = `${row.id}\0${keyId}`;
10531
+ const now = this.now();
10532
+ const cached = this.cache.get(cacheKey);
10533
+ if (!options.force && cached && Date.parse(cached.expiresAt) > now) return cached;
10534
+ const running = this.inFlight.get(cacheKey);
10535
+ if (running) return running;
10536
+ const promise = this.fetchQuota(adapter, row, entry.apiKey, cacheKey).catch((error) => {
10537
+ void error;
10538
+ const previous = this.cache.get(cacheKey);
10539
+ if (previous) {
10540
+ const degraded = {
10541
+ ...previous,
10542
+ expiresAt: new Date(now + PROVIDER_KEY_QUOTA_CACHE_MS).toISOString(),
10543
+ windows: previous.windows.map((window) => ({
10544
+ ...window,
10545
+ state: window.usedPercent !== null || window.resetsAt ? "stale" : window.state
10546
+ })),
10547
+ errorCode: "quota_request_failed"
10548
+ };
10549
+ this.cache.set(cacheKey, degraded);
10550
+ return degraded;
10551
+ }
10552
+ return null;
10553
+ }).finally(() => this.inFlight.delete(cacheKey));
10554
+ this.inFlight.set(cacheKey, promise);
10555
+ return promise;
10556
+ }
10557
+ /** Drop cached rows for a provider (key added/removed/rotated). */
10558
+ invalidateProvider(providerRowId) {
10559
+ for (const key of this.cache.keys()) {
10560
+ if (key.startsWith(`${providerRowId}\0`)) this.cache.delete(key);
8522
10561
  }
8523
- if (row.apiKey.length > 0) {
8524
- return [
8525
- normalizeEntry(
8526
- providerId,
8527
- { id: `${providerId}:default`, apiKey: row.apiKey, weight: 1, enabled: true },
8528
- 0,
8529
- autoDisabled
8530
- )
8531
- ];
10562
+ }
10563
+ async fetchQuota(adapter, row, rawKey, cacheKey) {
10564
+ const baseUrl = resolvedBaseUrl(row);
10565
+ const url = providerKeyQuotaUrl(adapter, baseUrl);
10566
+ const key = this.box.decryptMaybe(rawKey);
10567
+ const now = this.now();
10568
+ const response = await this.fetchImpl(url, {
10569
+ method: "GET",
10570
+ headers: {
10571
+ Authorization: providerKeyQuotaAuthHeader(adapter, key),
10572
+ Accept: "application/json",
10573
+ "Content-Type": "application/json",
10574
+ // The row's static identity headers ride along — the Cline usage
10575
+ // endpoint sits behind the SAME client-identity 403 gate as inference.
10576
+ ...(0, import_core4.mergeExtraHeaders)({}, row.extraHeaders)
10577
+ },
10578
+ signal: AbortSignal.timeout(15e3)
10579
+ });
10580
+ if (response.status === 401 || response.status === 403) {
10581
+ const snapshot2 = {
10582
+ adapter,
10583
+ observedAt: new Date(now).toISOString(),
10584
+ expiresAt: new Date(now + PROVIDER_KEY_QUOTA_CACHE_MS).toISOString(),
10585
+ windows: [],
10586
+ errorCode: "quota_unauthorized"
10587
+ };
10588
+ this.cache.set(cacheKey, snapshot2);
10589
+ return snapshot2;
8532
10590
  }
8533
- return [];
8534
- };
8535
- }
10591
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
10592
+ let payload;
10593
+ try {
10594
+ payload = await response.json();
10595
+ } catch {
10596
+ throw new Error("invalid JSON");
10597
+ }
10598
+ const windows = parseQuotaPayload(adapter, payload, now);
10599
+ const snapshot = {
10600
+ adapter,
10601
+ observedAt: new Date(now).toISOString(),
10602
+ expiresAt: new Date(now + PROVIDER_KEY_QUOTA_CACHE_MS).toISOString(),
10603
+ windows: windows ?? [],
10604
+ ...windows ? {} : { errorCode: "quota_unavailable" }
10605
+ };
10606
+ this.cache.set(cacheKey, snapshot);
10607
+ return snapshot;
10608
+ }
10609
+ };
8536
10610
 
8537
10611
  // src/image-generation/ImageDoctorService.ts
8538
10612
  var import_image_generation = require("@omnicross/core/image-generation");
8539
10613
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
8540
- var import_subscriptions3 = require("@omnicross/subscriptions");
10614
+ var import_subscriptions9 = require("@omnicross/subscriptions");
8541
10615
 
8542
10616
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
8543
10617
  var import_node_crypto13 = require("crypto");
@@ -8975,7 +11049,7 @@ function createImageDoctorService(options) {
8975
11049
  paths,
8976
11050
  ttlMs: config.evidenceTtlMs
8977
11051
  }));
8978
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions3.createCodexImageLiveVerifier)({
11052
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
8979
11053
  authStrategy: strategy,
8980
11054
  generationTimeoutMs: config.queue.generationTimeoutMs
8981
11055
  }));
@@ -9337,7 +11411,7 @@ var ImageCleanupService = class {
9337
11411
  var import_node_crypto16 = require("crypto");
9338
11412
  var import_image_generation5 = require("@omnicross/core/image-generation");
9339
11413
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
9340
- var import_subscriptions4 = require("@omnicross/subscriptions");
11414
+ var import_subscriptions10 = require("@omnicross/subscriptions");
9341
11415
 
9342
11416
  // src/image-generation/ImageApiRuntimeResolver.ts
9343
11417
  var import_node_crypto14 = require("crypto");
@@ -9868,7 +11942,7 @@ function createImageRuntimeGeneration(options) {
9868
11942
  now: options.now ?? Date.now,
9869
11943
  referenceStore: options.storage.referenceStore,
9870
11944
  stateStore: options.storage.stateStore
9871
- }) : (0, import_subscriptions4.createCodexSubscriptionImageProvider)({
11945
+ }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
9872
11946
  authStrategy,
9873
11947
  evidenceSource: generationEvidenceSource,
9874
11948
  executionScheduler: scheduler,
@@ -13012,7 +15086,7 @@ var ImageRuntimeManager = class {
13012
15086
  };
13013
15087
 
13014
15088
  // src/ports/ConfigFileProviderConfigSource.ts
13015
- var import_core2 = require("@omnicross/core");
15089
+ var import_core5 = require("@omnicross/core");
13016
15090
  var EMPTY_CHAIN = {
13017
15091
  providerTransformers: [],
13018
15092
  modelTransformers: []
@@ -13037,8 +15111,8 @@ var ConfigFileProviderConfigSource = class {
13037
15111
  reloadHook;
13038
15112
  constructor(config) {
13039
15113
  for (const p of config.providers) this.providers.set(p.id, p);
13040
- this.transformerService = new import_core2.TransformerService();
13041
- void (0, import_core2.registerBuiltinTransformers)(this.transformerService);
15114
+ this.transformerService = new import_core5.TransformerService();
15115
+ void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
13042
15116
  }
13043
15117
  // ── Reload hook (key-pool design D4) ───────────────────────────────────────
13044
15118
  /**
@@ -13059,7 +15133,7 @@ var ConfigFileProviderConfigSource = class {
13059
15133
  }
13060
15134
  /** Await the built-in transformer registration (tests await this before dispatch). */
13061
15135
  async ready() {
13062
- await (0, import_core2.registerBuiltinTransformers)(this.transformerService);
15136
+ await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
13063
15137
  }
13064
15138
  // ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
13065
15139
  /**
@@ -13170,6 +15244,10 @@ function toLLMProvider(row) {
13170
15244
  // `parseProviderInput`), so customizations are preserved (the row value wins).
13171
15245
  apiModes: row.apiModes,
13172
15246
  selectedApiModeId: row.selectedApiModeId,
15247
+ // Static extra request headers ride along verbatim (load-guarded — no
15248
+ // auth/content names); core's `getProviderHeaders` merges them into every
15249
+ // BYO request, and the same-format relay path inherits that funnel.
15250
+ extraHeaders: row.extraHeaders,
13173
15251
  // Official-Anthropic signature handling only matters for the Anthropic
13174
15252
  // ingress (deferred → 502); leave it off for the BYO transform path.
13175
15253
  isOfficial: false
@@ -14534,10 +16612,13 @@ function bucketLabel(bucketStartTs, bucket) {
14534
16612
  }
14535
16613
 
14536
16614
  // src/ports/JsonOutboundKeyDb.ts
16615
+ var import_node_fs23 = require("fs");
16616
+ var import_core6 = require("@omnicross/core");
16617
+
16618
+ // src/ports/atomicFile.ts
14537
16619
  var import_node_crypto22 = require("crypto");
14538
16620
  var import_node_fs22 = require("fs");
14539
16621
  var import_node_path25 = require("path");
14540
- var import_core3 = require("@omnicross/core");
14541
16622
  function atomicReplaceUtf8(targetPath, contents) {
14542
16623
  const tempPath = (0, import_node_path25.join)(
14543
16624
  (0, import_node_path25.dirname)(targetPath),
@@ -14567,6 +16648,8 @@ function atomicReplaceUtf8(targetPath, contents) {
14567
16648
  throw error;
14568
16649
  }
14569
16650
  }
16651
+
16652
+ // src/ports/JsonOutboundKeyDb.ts
14570
16653
  var JsonOutboundKeyDb = class {
14571
16654
  /**
14572
16655
  * @param secretBox OPTIONAL reversible-secret codec. When present, a created
@@ -14652,7 +16735,7 @@ var JsonOutboundKeyDb = class {
14652
16735
  });
14653
16736
  }
14654
16737
  async outboundApiKeysSetPermissions(id, permissions) {
14655
- const exact = (0, import_core3.validateOutboundPermissions)(permissions);
16738
+ const exact = (0, import_core6.validateOutboundPermissions)(permissions);
14656
16739
  return this.mutateRow(id, (row) => {
14657
16740
  if (row.revokedAt !== null) return false;
14658
16741
  row.allowedEndpoints = [...exact];
@@ -14709,9 +16792,9 @@ var JsonOutboundKeyDb = class {
14709
16792
  }
14710
16793
  /** Read the key rows, tolerating a missing/corrupt file (→ empty list). */
14711
16794
  readRows() {
14712
- if (!(0, import_node_fs22.existsSync)(this.keysPath)) return [];
16795
+ if (!(0, import_node_fs23.existsSync)(this.keysPath)) return [];
14713
16796
  try {
14714
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(this.keysPath, "utf8"));
16797
+ const parsed = JSON.parse((0, import_node_fs23.readFileSync)(this.keysPath, "utf8"));
14715
16798
  return Array.isArray(parsed) ? parsed : [];
14716
16799
  } catch {
14717
16800
  return [];
@@ -14728,7 +16811,7 @@ function applyPolicyField(row, field, value) {
14728
16811
  }
14729
16812
 
14730
16813
  // src/ports/JsonPricingStore.ts
14731
- var import_node_fs23 = require("fs");
16814
+ var import_node_fs24 = require("fs");
14732
16815
  var import_node_crypto23 = require("crypto");
14733
16816
  var JsonPricingStore = class {
14734
16817
  constructor(pricingPath) {
@@ -14743,9 +16826,9 @@ var JsonPricingStore = class {
14743
16826
  * otherwise unusable pricing table after a crash or manual file edit.
14744
16827
  */
14745
16828
  hasUsableSnapshot() {
14746
- if (!(0, import_node_fs23.existsSync)(this.pricingPath)) return false;
16829
+ if (!(0, import_node_fs24.existsSync)(this.pricingPath)) return false;
14747
16830
  try {
14748
- const parsed = JSON.parse((0, import_node_fs23.readFileSync)(this.pricingPath, "utf8"));
16831
+ const parsed = JSON.parse((0, import_node_fs24.readFileSync)(this.pricingPath, "utf8"));
14749
16832
  return Array.isArray(parsed) && parsed.some(isUsablePricingRow);
14750
16833
  } catch {
14751
16834
  return false;
@@ -14858,9 +16941,9 @@ var JsonPricingStore = class {
14858
16941
  }
14859
16942
  /** Read the pricing rows, tolerating a missing/corrupt file (→ empty list). */
14860
16943
  readRows() {
14861
- if (!(0, import_node_fs23.existsSync)(this.pricingPath)) return [];
16944
+ if (!(0, import_node_fs24.existsSync)(this.pricingPath)) return [];
14862
16945
  try {
14863
- const parsed = JSON.parse((0, import_node_fs23.readFileSync)(this.pricingPath, "utf8"));
16946
+ const parsed = JSON.parse((0, import_node_fs24.readFileSync)(this.pricingPath, "utf8"));
14864
16947
  return Array.isArray(parsed) ? parsed : [];
14865
16948
  } catch {
14866
16949
  return [];
@@ -14869,18 +16952,18 @@ var JsonPricingStore = class {
14869
16952
  writeRows(rows) {
14870
16953
  const temporaryPath = `${this.pricingPath}.${process.pid}.${(0, import_node_crypto23.randomUUID)()}.tmp`;
14871
16954
  try {
14872
- (0, import_node_fs23.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
16955
+ (0, import_node_fs24.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
14873
16956
  encoding: "utf8",
14874
16957
  flag: "wx"
14875
16958
  });
14876
16959
  this.replaceFile(temporaryPath);
14877
16960
  } finally {
14878
- (0, import_node_fs23.rmSync)(temporaryPath, { force: true });
16961
+ (0, import_node_fs24.rmSync)(temporaryPath, { force: true });
14879
16962
  }
14880
16963
  }
14881
16964
  /** Isolated for deterministic failure testing; never removes the target. */
14882
16965
  replaceFile(temporaryPath) {
14883
- (0, import_node_fs23.renameSync)(temporaryPath, this.pricingPath);
16966
+ (0, import_node_fs24.renameSync)(temporaryPath, this.pricingPath);
14884
16967
  }
14885
16968
  };
14886
16969
  function isUsablePricingRow(value) {
@@ -14890,7 +16973,7 @@ function isUsablePricingRow(value) {
14890
16973
  }
14891
16974
 
14892
16975
  // src/pricing/PricingRefreshScheduler.ts
14893
- var import_node_fs24 = require("fs");
16976
+ var import_node_fs25 = require("fs");
14894
16977
  var EMPTY_STATE2 = {
14895
16978
  lastAttemptAt: null,
14896
16979
  lastSuccessAt: null,
@@ -14928,9 +17011,9 @@ var PricingRefreshScheduler = class {
14928
17011
  this.timer = null;
14929
17012
  }
14930
17013
  getState() {
14931
- if (!(0, import_node_fs24.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
17014
+ if (!(0, import_node_fs25.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
14932
17015
  try {
14933
- const value = JSON.parse((0, import_node_fs24.readFileSync)(this.statePath, "utf8"));
17016
+ const value = JSON.parse((0, import_node_fs25.readFileSync)(this.statePath, "utf8"));
14934
17017
  return {
14935
17018
  lastAttemptAt: finiteOrNull(value.lastAttemptAt),
14936
17019
  lastSuccessAt: finiteOrNull(value.lastSuccessAt),
@@ -14983,9 +17066,9 @@ var PricingRefreshScheduler = class {
14983
17066
  }
14984
17067
  writeState(state) {
14985
17068
  const temporaryPath = `${this.statePath}.tmp`;
14986
- (0, import_node_fs24.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
17069
+ (0, import_node_fs25.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
14987
17070
  `, "utf8");
14988
- (0, import_node_fs24.renameSync)(temporaryPath, this.statePath);
17071
+ (0, import_node_fs25.renameSync)(temporaryPath, this.statePath);
14989
17072
  }
14990
17073
  };
14991
17074
  function finiteOrNull(value) {
@@ -14993,7 +17076,7 @@ function finiteOrNull(value) {
14993
17076
  }
14994
17077
 
14995
17078
  // src/ports/JsonVoucherDb.ts
14996
- var import_node_fs25 = require("fs");
17079
+ var import_node_fs26 = require("fs");
14997
17080
  var JsonVoucherDb = class {
14998
17081
  constructor(vouchersPath) {
14999
17082
  this.vouchersPath = vouchersPath;
@@ -15071,27 +17154,27 @@ var JsonVoucherDb = class {
15071
17154
  }
15072
17155
  /** Read the voucher rows, tolerating a missing/corrupt file (→ empty list). */
15073
17156
  readRows() {
15074
- if (!(0, import_node_fs25.existsSync)(this.vouchersPath)) return [];
17157
+ if (!(0, import_node_fs26.existsSync)(this.vouchersPath)) return [];
15075
17158
  try {
15076
- const parsed = JSON.parse((0, import_node_fs25.readFileSync)(this.vouchersPath, "utf8"));
17159
+ const parsed = JSON.parse((0, import_node_fs26.readFileSync)(this.vouchersPath, "utf8"));
15077
17160
  return Array.isArray(parsed) ? parsed : [];
15078
17161
  } catch {
15079
17162
  return [];
15080
17163
  }
15081
17164
  }
15082
17165
  writeRows(rows) {
15083
- (0, import_node_fs25.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
17166
+ (0, import_node_fs26.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
15084
17167
  }
15085
17168
  };
15086
17169
 
15087
17170
  // src/ports/JsonSubscriptionCredentialStore.ts
15088
- var import_node_fs27 = require("fs");
17171
+ var import_node_fs28 = require("fs");
15089
17172
  var import_node_path27 = require("path");
15090
17173
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
15091
17174
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
15092
- var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
17175
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
15093
17176
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
15094
- var import_subscriptions5 = require("@omnicross/subscriptions");
17177
+ var import_subscriptions11 = require("@omnicross/subscriptions");
15095
17178
 
15096
17179
  // src/ports/account-sync.ts
15097
17180
  function viewOf(tokens) {
@@ -15135,7 +17218,7 @@ function findDuplicateCredentialIds(accounts) {
15135
17218
  }
15136
17219
 
15137
17220
  // src/ports/external-cli-credentials.ts
15138
- var import_node_fs26 = require("fs");
17221
+ var import_node_fs27 = require("fs");
15139
17222
  var import_node_os5 = require("os");
15140
17223
  var import_node_path26 = require("path");
15141
17224
  function externalStorePath(provider, home = (0, import_node_os5.homedir)()) {
@@ -15188,10 +17271,10 @@ function parseCodexTokensEnvelope(raw) {
15188
17271
  }
15189
17272
  function readExternalCliCredentials(provider, home = (0, import_node_os5.homedir)()) {
15190
17273
  const path2 = externalStorePath(provider, home);
15191
- if (!(0, import_node_fs26.existsSync)(path2)) return null;
17274
+ if (!(0, import_node_fs27.existsSync)(path2)) return null;
15192
17275
  let raw;
15193
17276
  try {
15194
- const parsed = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
17277
+ const parsed = JSON.parse((0, import_node_fs27.readFileSync)(path2, "utf8"));
15195
17278
  raw = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
15196
17279
  } catch {
15197
17280
  return null;
@@ -15214,16 +17297,18 @@ var JsonSubscriptionCredentialStore = class {
15214
17297
  * as on relay refresh egresses from the SAME proxy IP as the
15215
17298
  * account's traffic. NOT used by any read/write path.
15216
17299
  */
15217
- constructor(tokensPath, box, fetchImpl = void 0, externalCliReader = readExternalCliCredentials) {
17300
+ constructor(tokensPath, box, fetchImpl = void 0, externalCliReader = readExternalCliCredentials, atomicReplace = atomicReplaceUtf8) {
15218
17301
  this.tokensPath = tokensPath;
15219
17302
  this.box = box;
15220
17303
  this.fetchImpl = fetchImpl;
15221
17304
  this.externalCliReader = externalCliReader;
17305
+ this.atomicReplace = atomicReplace;
15222
17306
  }
15223
17307
  tokensPath;
15224
17308
  box;
15225
17309
  fetchImpl;
15226
17310
  externalCliReader;
17311
+ atomicReplace;
15227
17312
  /**
15228
17313
  * The proxy-aware `FetchLike` for one refresh round-trip (upstream-proxy M1). A
15229
17314
  * TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
@@ -15237,7 +17322,7 @@ var JsonSubscriptionCredentialStore = class {
15237
17322
  * a plaintext token pair into `upstream-trace.jsonl`.
15238
17323
  */
15239
17324
  buildRefreshFetch(providerId, accountId) {
15240
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch5.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
17325
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
15241
17326
  }
15242
17327
  /**
15243
17328
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -15278,7 +17363,7 @@ var JsonSubscriptionCredentialStore = class {
15278
17363
  * other hot reads. Never returns token material.
15279
17364
  */
15280
17365
  getAccountProxy(providerId, accountId) {
15281
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego") {
17366
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
15282
17367
  return void 0;
15283
17368
  }
15284
17369
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -15297,7 +17382,7 @@ var JsonSubscriptionCredentialStore = class {
15297
17382
  const fingerprintOn = identityStore.isEnabled();
15298
17383
  const now = Date.now();
15299
17384
  const out = {};
15300
- for (const provider of ["claude", "codex", "gemini", "opencodego"]) {
17385
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
15301
17386
  const sanitized = sanitizeAccounts(config, provider);
15302
17387
  if (sanitized.length === 0) continue;
15303
17388
  for (const account of sanitized) {
@@ -15363,7 +17448,7 @@ var JsonSubscriptionCredentialStore = class {
15363
17448
  this.materializeMigration(config);
15364
17449
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
15365
17450
  try {
15366
- const result = await import_subscriptions5.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
17451
+ const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
15367
17452
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15368
17453
  const next = {
15369
17454
  ...claude,
@@ -15398,7 +17483,7 @@ var JsonSubscriptionCredentialStore = class {
15398
17483
  this.materializeMigration(config);
15399
17484
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
15400
17485
  try {
15401
- const result = await import_subscriptions5.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
17486
+ const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
15402
17487
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15403
17488
  const next = {
15404
17489
  ...codex,
@@ -15436,7 +17521,7 @@ var JsonSubscriptionCredentialStore = class {
15436
17521
  this.materializeMigration(config);
15437
17522
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
15438
17523
  try {
15439
- const result = await import_subscriptions5.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17524
+ const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
15440
17525
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15441
17526
  const next = {
15442
17527
  ...gemini,
@@ -15455,6 +17540,107 @@ var JsonSubscriptionCredentialStore = class {
15455
17540
  }
15456
17541
  });
15457
17542
  }
17543
+ /**
17544
+ * Refresh the Kimi Code (Moonshot) OAuth access token (device-flow grant).
17545
+ * Kimi ROTATES the refresh token, so the response's pair is written back
17546
+ * whole; the account's stable `deviceId` (fingerprint header input) is
17547
+ * preserved. The refresh call carries the CLI fingerprint headers. HONEST
17548
+ * `false` when no refresh_token.
17549
+ */
17550
+ async refreshKimiToken() {
17551
+ return this.coalesce("kimi:active", async () => {
17552
+ const config = this.readConfig();
17553
+ const active = getActiveAccount(config, "kimi");
17554
+ const kimi = active?.tokens;
17555
+ if (!active || !kimi?.refreshToken) return false;
17556
+ const capturedId = active.id;
17557
+ this.materializeMigration(config);
17558
+ const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
17559
+ try {
17560
+ const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
17561
+ kimi.refreshToken,
17562
+ refreshFetch,
17563
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17564
+ );
17565
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17566
+ const next = {
17567
+ ...kimi,
17568
+ accessToken: result.accessToken,
17569
+ refreshToken: result.refreshToken,
17570
+ expiresAt,
17571
+ status: "authorized",
17572
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
17573
+ errorMessage: void 0,
17574
+ syncWarning: void 0
17575
+ };
17576
+ this.writeBackById("kimi", capturedId, next);
17577
+ return true;
17578
+ } catch (error) {
17579
+ this.markExpiredById("kimi", capturedId, kimi, error);
17580
+ return false;
17581
+ }
17582
+ });
17583
+ }
17584
+ /**
17585
+ * Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
17586
+ * resolved through OIDC discovery on every refresh (process-cached 1h by the
17587
+ * flow module) so a rotated endpoint document is picked up without a daemon
17588
+ * restart. HONEST `false` when no refresh_token.
17589
+ */
17590
+ async refreshGrokToken() {
17591
+ return this.coalesce("grok:active", async () => {
17592
+ const config = this.readConfig();
17593
+ const active = getActiveAccount(config, "grok");
17594
+ const grok = active?.tokens;
17595
+ if (!active || !grok?.refreshToken) return false;
17596
+ const capturedId = active.id;
17597
+ this.materializeMigration(config);
17598
+ const refreshFetch = this.buildRefreshFetch("grok", capturedId);
17599
+ try {
17600
+ const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17601
+ const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17602
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17603
+ const next = {
17604
+ ...grok,
17605
+ accessToken: result.accessToken,
17606
+ refreshToken: result.refreshToken,
17607
+ expiresAt,
17608
+ status: "authorized",
17609
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
17610
+ errorMessage: void 0,
17611
+ syncWarning: void 0
17612
+ };
17613
+ this.writeBackById("grok", capturedId, next);
17614
+ return true;
17615
+ } catch (error) {
17616
+ this.markExpiredById("grok", capturedId, grok, error);
17617
+ return false;
17618
+ }
17619
+ });
17620
+ }
17621
+ /**
17622
+ * "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
17623
+ * tokens are long-lived with no exchange endpoint). A call here means the
17624
+ * strategy saw a 401 (the token was revoked); mark the account `expired`
17625
+ * with a re-authenticate message and return `false` (the proxy then declines
17626
+ * the retry instead of looping on a dead token).
17627
+ */
17628
+ async refreshCopilotToken() {
17629
+ return this.coalesce("copilot:active", async () => {
17630
+ const config = this.readConfig();
17631
+ const active = getActiveAccount(config, "copilot");
17632
+ const copilot = active?.tokens;
17633
+ if (!active || !copilot?.accessToken) return false;
17634
+ this.materializeMigration(config);
17635
+ this.markExpiredById(
17636
+ "copilot",
17637
+ active.id,
17638
+ copilot,
17639
+ new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
17640
+ );
17641
+ return false;
17642
+ });
17643
+ }
15458
17644
  /**
15459
17645
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
15460
17646
  * account-pool resolution). It uses only that account's stored refresh
@@ -15507,7 +17693,7 @@ var JsonSubscriptionCredentialStore = class {
15507
17693
  }
15508
17694
  const oauth = account.tokens;
15509
17695
  if (!oauth.accessToken) return null;
15510
- if (providerId === "codex" || providerId === "gemini") {
17696
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
15511
17697
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
15512
17698
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
15513
17699
  if (expiringSoon && oauth.refreshToken) {
@@ -15596,8 +17782,35 @@ var JsonSubscriptionCredentialStore = class {
15596
17782
  }
15597
17783
  /** Dispatch one OAuth refresh round-trip to the provider's shared flow. */
15598
17784
  async refreshUpstream(provider, refreshToken, accountId) {
15599
- const flow = provider === "claude" ? import_subscriptions5.claudeOAuth : provider === "codex" ? import_subscriptions5.codexOAuth : import_subscriptions5.geminiOAuth;
15600
- const r = await flow.refreshAccessToken(refreshToken, this.buildRefreshFetch(provider, accountId));
17785
+ const refreshFetch = this.buildRefreshFetch(provider, accountId);
17786
+ if (provider === "kimi") {
17787
+ const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
17788
+ const deviceId = account?.tokens?.deviceId;
17789
+ const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
17790
+ refreshToken,
17791
+ refreshFetch,
17792
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
17793
+ );
17794
+ return {
17795
+ accessToken: r2.accessToken,
17796
+ refreshToken: r2.refreshToken,
17797
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17798
+ };
17799
+ }
17800
+ if (provider === "grok") {
17801
+ const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17802
+ const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
17803
+ return {
17804
+ accessToken: r2.accessToken,
17805
+ refreshToken: r2.refreshToken,
17806
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17807
+ };
17808
+ }
17809
+ if (provider === "copilot") {
17810
+ throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
17811
+ }
17812
+ const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
17813
+ const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
15601
17814
  return {
15602
17815
  accessToken: r.accessToken,
15603
17816
  refreshToken: r.refreshToken,
@@ -15760,42 +17973,86 @@ var JsonSubscriptionCredentialStore = class {
15760
17973
  /** Write the merged config to disk as pretty JSON (mkdir parent if needed).
15761
17974
  * Encrypt-on-write: the token-material fields are encrypted (legacy plaintext
15762
17975
  * `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
15763
- * write incl. child 4's future refresh writes lands encrypted. */
17976
+ * write incl. child 4's future refresh writes lands encrypted.
17977
+ * ATOMIC: temp + fsync + rename (`atomicReplaceUtf8`) — a failed or
17978
+ * interrupted write discards only the temp file; the prior `tokens.json`
17979
+ * survives byte-equal (bare `writeFileSync` truncate-writes lost every
17980
+ * account on a mid-write failure, 2026-09-06). */
15764
17981
  persist(config) {
15765
- (0, import_node_fs27.mkdirSync)((0, import_node_path27.dirname)(this.tokensPath), { recursive: true });
17982
+ (0, import_node_fs28.mkdirSync)((0, import_node_path27.dirname)(this.tokensPath), { recursive: true });
15766
17983
  const encrypted = encryptTokens(config, this.box);
15767
- (0, import_node_fs27.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
17984
+ this.atomicReplace(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n");
15768
17985
  }
15769
17986
  /**
15770
- * Read + parse `tokens.json`, tolerating a missing/corrupt file, then DECRYPT
15771
- * the token-material fields so every getter returns plaintext (the
15772
- * subscription bearer path is byte-identical).
17987
+ * Read + parse `tokens.json`, then DECRYPT the token-material fields so every
17988
+ * getter returns plaintext (the subscription bearer path is byte-identical).
15773
17989
  *
15774
- * The fs-read + JSON-parse tolerance is INSIDE the try (a missing or corrupt
15775
- * file empty `{ updatedAt: '' }`). The DECRYPT runs OUTSIDE the try, so a
15776
- * wrong/missing master key or a tampered `enc:` envelope FAILS FAST with the
15777
- * box's clear, secret-free error (secrets spec "/ UX":
15778
- * SHALL fail-fast, SHALL NOT a swallowed decrypt would report "no
15779
- * tokens" and silently send the WRONG bearer upstream 401). Mirrors
15780
- * `config.ts loadConfig`, which decrypts outside its parse try.
17990
+ * A MISSING file is a legitimate first-boot state minimal `{ updatedAt: '' }`.
17991
+ * A file that EXISTS but cannot be parsed as a JSON object is CORRUPT
17992
+ * `quarantineCorrupt` moves it aside (once) before the empty config is
17993
+ * returned, so the unreadable accounts survive for manual recovery.
17994
+ *
17995
+ * The DECRYPT runs OUTSIDE any try, so a wrong/missing master key or a
17996
+ * tampered `enc:` envelope FAILS FAST with the box's clear, secret-free
17997
+ * error (secrets spec "/ UX": SHALL fail-fast, SHALL NOT a swallowed
17998
+ * decrypt would report "no tokens" and silently send the WRONG bearer
17999
+ * upstream 401). Mirrors `config.ts loadConfig`, which decrypts outside
18000
+ * its parse try.
15781
18001
  */
15782
18002
  readConfig() {
15783
- if (!(0, import_node_fs27.existsSync)(this.tokensPath)) return { updatedAt: "" };
18003
+ if (!(0, import_node_fs28.existsSync)(this.tokensPath)) return { updatedAt: "" };
15784
18004
  let parsed;
15785
18005
  try {
15786
- const raw = JSON.parse((0, import_node_fs27.readFileSync)(this.tokensPath, "utf8"));
15787
- parsed = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
18006
+ const raw = JSON.parse((0, import_node_fs28.readFileSync)(this.tokensPath, "utf8"));
18007
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
18008
+ return this.quarantineCorrupt("parsed JSON is not an object");
18009
+ }
18010
+ parsed = raw;
15788
18011
  } catch {
15789
- parsed = null;
18012
+ return this.quarantineCorrupt("unparseable JSON");
15790
18013
  }
15791
- if (!parsed) return { updatedAt: "" };
15792
18014
  const decrypted = decryptTokens(parsed, this.box);
15793
18015
  return migrateLazily(decrypted);
15794
18016
  }
18017
+ /** One-shot latch: a corrupt file is quarantined (or found unmovable) at
18018
+ * most once per process, so the hot read path never re-attempts or re-logs. */
18019
+ corruptQuarantined = false;
18020
+ /**
18021
+ * Quarantine a present-but-corrupt `tokens.json`, then treat it as empty.
18022
+ *
18023
+ * Renames the file to a sibling `tokens.json.corrupt-<stamp>` backup and
18024
+ * logs loudly (the daemon's stderr log; secret-free — reason + paths only).
18025
+ * The daemon KEEPS SERVING (API-key routing is unaffected; subscription
18026
+ * routing reports no credential, same as an absent file) while the corrupt
18027
+ * bytes survive for manual recovery — and, critically, the NEXT persist
18028
+ * (e.g. the user re-logging in) can no longer overwrite the only copy of
18029
+ * the old accounts, which is exactly how the 2026-09-06 incident turned a
18030
+ * recoverable truncated file into permanent account loss.
18031
+ *
18032
+ * Best-effort: if the rename fails (file locked, permissions), the corrupt
18033
+ * file is left in place and every later read still tolerates it as empty;
18034
+ * the latch still trips so the attempt + log happen exactly once.
18035
+ */
18036
+ quarantineCorrupt(reason) {
18037
+ if (!this.corruptQuarantined) {
18038
+ this.corruptQuarantined = true;
18039
+ const backup = `${this.tokensPath}.corrupt-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
18040
+ let moved = false;
18041
+ try {
18042
+ (0, import_node_fs28.renameSync)(this.tokensPath, backup);
18043
+ moved = true;
18044
+ } catch {
18045
+ }
18046
+ console.error(
18047
+ `[JsonSubscriptionCredentialStore] tokens.json is corrupt (${reason}); ` + (moved ? `moved to '${backup}' and treated as empty \u2014 recover accounts from that backup before re-adding them` : `could not move '${this.tokensPath}' \u2014 treated as empty`)
18048
+ );
18049
+ }
18050
+ return { updatedAt: "" };
18051
+ }
15795
18052
  };
15796
18053
 
15797
18054
  // src/AccountHealthProbeScheduler.ts
15798
- var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
18055
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
15799
18056
 
15800
18057
  // src/probe/CodexGenerationProbe.ts
15801
18058
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -15934,7 +18191,20 @@ var PROVIDER_PROBE_PLANS = {
15934
18191
  // billable/wrong endpoint). Upgrade to `{ kind:'upstream' }` once verified.
15935
18192
  codex: { kind: "local" },
15936
18193
  gemini: { kind: "local" },
15937
- opencodego: { kind: "local" }
18194
+ opencodego: { kind: "local" },
18195
+ // Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
18196
+ // collector uses it), but the probe path also needs the fingerprint headers —
18197
+ // keep the probe local until the collector covers the health surface.
18198
+ kimi: { kind: "local" },
18199
+ // Grok's billing proxy is a verified FREE authed GET (the allowance collector
18200
+ // uses it) but it REJECTS non-OAuth credentials and sits on a separate host
18201
+ // with its own product-gate header — keep the probe local, the collector
18202
+ // owns the health surface.
18203
+ grok: { kind: "local" },
18204
+ // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
18205
+ // authed GET but lives on api.github.com with its own auth dialect and a
18206
+ // monthly-only window — the allowance collector owns the health surface.
18207
+ copilot: { kind: "local" }
15938
18208
  };
15939
18209
  function probePlanFor(providerId) {
15940
18210
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -15956,7 +18226,7 @@ var AccountHealthProbeScheduler = class {
15956
18226
  this.logger = logger;
15957
18227
  this.config = config;
15958
18228
  this.now = opts.now ?? Date.now;
15959
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch6.fetchUpstream;
18229
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch12.fetchUpstream;
15960
18230
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
15961
18231
  this.planFor = opts.planFor ?? probePlanFor;
15962
18232
  }
@@ -16300,13 +18570,13 @@ var AccountHealthSweeper = class {
16300
18570
  };
16301
18571
 
16302
18572
  // src/audit/AuditPruneSweeper.ts
16303
- var import_node_fs29 = require("fs");
18573
+ var import_node_fs30 = require("fs");
16304
18574
  var import_node_path29 = require("path");
16305
18575
  var import_promises6 = require("stream/promises");
16306
18576
  var import_node_zlib2 = require("zlib");
16307
18577
 
16308
18578
  // src/audit/auditStats.ts
16309
- var import_node_fs28 = require("fs");
18579
+ var import_node_fs29 = require("fs");
16310
18580
  var import_node_path28 = require("path");
16311
18581
  var SIDECAR_VERSION = 1;
16312
18582
  var META_PREFIX_BYTES = 64 * 1024;
@@ -16315,9 +18585,9 @@ function auditStatsFileName(auditFile) {
16315
18585
  return auditFile.replace(/\.jsonl$/, ".stats.json");
16316
18586
  }
16317
18587
  function readPersisted(path2) {
16318
- if (!(0, import_node_fs28.existsSync)(path2)) return null;
18588
+ if (!(0, import_node_fs29.existsSync)(path2)) return null;
16319
18589
  try {
16320
- const value = JSON.parse((0, import_node_fs28.readFileSync)(path2, "utf8"));
18590
+ const value = JSON.parse((0, import_node_fs29.readFileSync)(path2, "utf8"));
16321
18591
  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)) {
16322
18592
  return null;
16323
18593
  }
@@ -16347,7 +18617,7 @@ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfte
16347
18617
  minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
16348
18618
  maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
16349
18619
  };
16350
- (0, import_node_fs28.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
18620
+ (0, import_node_fs29.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
16351
18621
  }
16352
18622
  function queryCovers(stats, from, to) {
16353
18623
  return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
@@ -16405,7 +18675,7 @@ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
16405
18675
  prefixTruncated = false;
16406
18676
  };
16407
18677
  if (auditBytes > startByte) {
16408
- const stream = (0, import_node_fs28.createReadStream)(auditPath, {
18678
+ const stream = (0, import_node_fs29.createReadStream)(auditPath, {
16409
18679
  start: startByte,
16410
18680
  end: auditBytes - 1,
16411
18681
  highWaterMark: READ_CHUNK_BYTES2
@@ -16458,12 +18728,12 @@ function mergePersistedStats(previous, appended) {
16458
18728
  };
16459
18729
  }
16460
18730
  async function readAuditStats(auditDir, query2 = {}) {
16461
- if (!(0, import_node_fs28.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
18731
+ if (!(0, import_node_fs29.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
16462
18732
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
16463
18733
  const to = typeof query2.to === "number" ? query2.to : Infinity;
16464
18734
  let sources;
16465
18735
  try {
16466
- sources = (0, import_node_fs28.readdirSync)(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
18736
+ sources = (0, import_node_fs29.readdirSync)(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
16467
18737
  (name) => AUDIT_DAY_DIR_RE.test(name) ? {
16468
18738
  auditPath: (0, import_node_path28.join)(auditDir, name, AUDIT_META_FILE),
16469
18739
  statsPath: (0, import_node_path28.join)(auditDir, name, auditStatsFileName(AUDIT_META_FILE))
@@ -16471,14 +18741,14 @@ async function readAuditStats(auditDir, query2 = {}) {
16471
18741
  auditPath: (0, import_node_path28.join)(auditDir, name),
16472
18742
  statsPath: (0, import_node_path28.join)(auditDir, auditStatsFileName(name))
16473
18743
  }
16474
- ).filter((source) => (0, import_node_fs28.existsSync)(source.auditPath));
18744
+ ).filter((source) => (0, import_node_fs29.existsSync)(source.auditPath));
16475
18745
  } catch {
16476
18746
  return { requestCount: 0, errorCount: 0, complete: false };
16477
18747
  }
16478
18748
  const total = { requestCount: 0, errorCount: 0, complete: true };
16479
18749
  for (const { auditPath, statsPath } of sources) {
16480
18750
  try {
16481
- const auditBytes = (0, import_node_fs28.statSync)(auditPath).size;
18751
+ const auditBytes = (0, import_node_fs29.statSync)(auditPath).size;
16482
18752
  const persisted = readPersisted(statsPath);
16483
18753
  if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
16484
18754
  total.requestCount += persisted.requestCount;
@@ -16497,7 +18767,7 @@ async function readAuditStats(auditDir, query2 = {}) {
16497
18767
  total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
16498
18768
  total.complete = total.complete && scanned.filtered.complete;
16499
18769
  const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
16500
- if (current.complete) (0, import_node_fs28.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
18770
+ if (current.complete) (0, import_node_fs29.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
16501
18771
  } catch {
16502
18772
  total.complete = false;
16503
18773
  }
@@ -16506,7 +18776,7 @@ async function readAuditStats(auditDir, query2 = {}) {
16506
18776
  }
16507
18777
 
16508
18778
  // src/audit/AuditPruneSweeper.ts
16509
- var DAY_MS = 24 * 60 * 6e4;
18779
+ var DAY_MS4 = 24 * 60 * 6e4;
16510
18780
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
16511
18781
  var ARCHIVE_BATCH = 64;
16512
18782
  var AuditPruneSweeper = class {
@@ -16569,19 +18839,19 @@ var AuditPruneSweeper = class {
16569
18839
  if (!this.config.enabled || this.sweeping) return 0;
16570
18840
  this.sweeping = true;
16571
18841
  try {
16572
- if (!(0, import_node_fs29.existsSync)(this.auditDir)) return 0;
16573
- const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS;
18842
+ if (!(0, import_node_fs30.existsSync)(this.auditDir)) return 0;
18843
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
16574
18844
  let removed = 0;
16575
- for (const name of (0, import_node_fs29.readdirSync)(this.auditDir)) {
18845
+ for (const name of (0, import_node_fs30.readdirSync)(this.auditDir)) {
16576
18846
  const dateMs = auditFileDateMs(name);
16577
18847
  if (dateMs === null || dateMs >= cutoff) continue;
16578
18848
  try {
16579
18849
  if (isAuditDayDir(name)) {
16580
- (0, import_node_fs29.rmSync)((0, import_node_path29.join)(this.auditDir, name), { recursive: true, force: true });
18850
+ (0, import_node_fs30.rmSync)((0, import_node_path29.join)(this.auditDir, name), { recursive: true, force: true });
16581
18851
  } else {
16582
- (0, import_node_fs29.unlinkSync)((0, import_node_path29.join)(this.auditDir, name));
18852
+ (0, import_node_fs30.unlinkSync)((0, import_node_path29.join)(this.auditDir, name));
16583
18853
  const statsPath = (0, import_node_path29.join)(this.auditDir, auditStatsFileName(name));
16584
- if ((0, import_node_fs29.existsSync)(statsPath)) (0, import_node_fs29.unlinkSync)(statsPath);
18854
+ if ((0, import_node_fs30.existsSync)(statsPath)) (0, import_node_fs30.unlinkSync)(statsPath);
16585
18855
  }
16586
18856
  removed += 1;
16587
18857
  } catch (error) {
@@ -16611,10 +18881,10 @@ var AuditPruneSweeper = class {
16611
18881
  if (!this.config.enabled || this.archiving) return 0;
16612
18882
  this.archiving = true;
16613
18883
  try {
16614
- if (!(0, import_node_fs29.existsSync)(this.auditDir)) return 0;
18884
+ if (!(0, import_node_fs30.existsSync)(this.auditDir)) return 0;
16615
18885
  const today = this.todayMidnight();
16616
18886
  let compressed = 0;
16617
- for (const name of (0, import_node_fs29.readdirSync)(this.auditDir)) {
18887
+ for (const name of (0, import_node_fs30.readdirSync)(this.auditDir)) {
16618
18888
  if (compressed >= ARCHIVE_BATCH) break;
16619
18889
  const dateMs = auditFileDateMs(name);
16620
18890
  if (dateMs === null || dateMs >= today || !isAuditDayDir(name)) continue;
@@ -16655,7 +18925,7 @@ var AuditPruneSweeper = class {
16655
18925
  async archiveDay(bodiesPath, budget) {
16656
18926
  let shards;
16657
18927
  try {
16658
- shards = (0, import_node_fs29.readdirSync)(bodiesPath).filter((file) => file.endsWith(".jsonl"));
18928
+ shards = (0, import_node_fs30.readdirSync)(bodiesPath).filter((file) => file.endsWith(".jsonl"));
16659
18929
  } catch {
16660
18930
  return 0;
16661
18931
  }
@@ -16665,16 +18935,16 @@ var AuditPruneSweeper = class {
16665
18935
  const source = (0, import_node_path29.join)(bodiesPath, shard);
16666
18936
  const target = `${source}.gz`;
16667
18937
  try {
16668
- if ((0, import_node_fs29.existsSync)(target)) {
16669
- (0, import_node_fs29.unlinkSync)(source);
18938
+ if ((0, import_node_fs30.existsSync)(target)) {
18939
+ (0, import_node_fs30.unlinkSync)(source);
16670
18940
  continue;
16671
18941
  }
16672
- await (0, import_promises6.pipeline)((0, import_node_fs29.createReadStream)(source), (0, import_node_zlib2.createGzip)(), (0, import_node_fs29.createWriteStream)(target));
16673
- (0, import_node_fs29.unlinkSync)(source);
18942
+ await (0, import_promises6.pipeline)((0, import_node_fs30.createReadStream)(source), (0, import_node_zlib2.createGzip)(), (0, import_node_fs30.createWriteStream)(target));
18943
+ (0, import_node_fs30.unlinkSync)(source);
16674
18944
  compressed += 1;
16675
18945
  } catch (error) {
16676
18946
  try {
16677
- if ((0, import_node_fs29.existsSync)(target)) (0, import_node_fs29.unlinkSync)(target);
18947
+ if ((0, import_node_fs30.existsSync)(target)) (0, import_node_fs30.unlinkSync)(target);
16678
18948
  } catch {
16679
18949
  }
16680
18950
  this.logger.warn("[AuditPruneSweeper] failed to archive audit body shard", {
@@ -16688,7 +18958,7 @@ var AuditPruneSweeper = class {
16688
18958
  };
16689
18959
 
16690
18960
  // src/usage/usageMigrate.ts
16691
- var import_node_fs30 = require("fs");
18961
+ var import_node_fs31 = require("fs");
16692
18962
  var import_promises7 = require("fs/promises");
16693
18963
  var import_node_path30 = require("path");
16694
18964
  var import_node_readline = require("readline");
@@ -16735,7 +19005,7 @@ async function migrateLegacyUsageEvents(opts) {
16735
19005
  let skipped = 0;
16736
19006
  try {
16737
19007
  const reader = (0, import_node_readline.createInterface)({
16738
- input: (0, import_node_fs30.createReadStream)(eventsPath, { encoding: "utf8" }),
19008
+ input: (0, import_node_fs31.createReadStream)(eventsPath, { encoding: "utf8" }),
16739
19009
  crlfDelay: Number.POSITIVE_INFINITY
16740
19010
  });
16741
19011
  for await (const line of reader) {
@@ -16827,7 +19097,7 @@ async function closeAll(writers) {
16827
19097
  // src/usage/UsagePruneSweeper.ts
16828
19098
  var import_promises8 = require("fs/promises");
16829
19099
  var import_node_path31 = require("path");
16830
- var DAY_MS2 = 24 * 60 * 6e4;
19100
+ var DAY_MS5 = 24 * 60 * 6e4;
16831
19101
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
16832
19102
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
16833
19103
  var UsagePruneSweeper = class {
@@ -16884,7 +19154,7 @@ var UsagePruneSweeper = class {
16884
19154
  this.sweeping = true;
16885
19155
  try {
16886
19156
  const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
16887
- const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS2;
19157
+ const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
16888
19158
  let removed = 0;
16889
19159
  for (const entry of await listUsageDays(this.usageDir)) {
16890
19160
  if (!entry.hasShard) continue;
@@ -16942,7 +19212,7 @@ var UsagePruneSweeper = class {
16942
19212
  };
16943
19213
 
16944
19214
  // src/audit/auditReader.ts
16945
- var import_node_fs31 = require("fs");
19215
+ var import_node_fs32 = require("fs");
16946
19216
  var import_node_path32 = require("path");
16947
19217
  var DEFAULT_LIMIT = 200;
16948
19218
  var MAX_LIMIT = 2e3;
@@ -16950,7 +19220,7 @@ var OVERSCAN = 256;
16950
19220
  function daySources(auditDir) {
16951
19221
  let names;
16952
19222
  try {
16953
- names = (0, import_node_fs31.readdirSync)(auditDir);
19223
+ names = (0, import_node_fs32.readdirSync)(auditDir);
16954
19224
  } catch {
16955
19225
  return [];
16956
19226
  }
@@ -16960,7 +19230,7 @@ function daySources(auditDir) {
16960
19230
  if (dateMs === null) continue;
16961
19231
  if (AUDIT_DAY_DIR_RE.test(name)) {
16962
19232
  const path2 = (0, import_node_path32.join)(auditDir, name, AUDIT_META_FILE);
16963
- if ((0, import_node_fs31.existsSync)(path2)) sources.push({ path: path2, dateMs });
19233
+ if ((0, import_node_fs32.existsSync)(path2)) sources.push({ path: path2, dateMs });
16964
19234
  } else if (AUDIT_FILE_RE.test(name)) {
16965
19235
  sources.push({ path: (0, import_node_path32.join)(auditDir, name), dateMs });
16966
19236
  }
@@ -16978,7 +19248,7 @@ function toMetaRecord(record) {
16978
19248
  return { ...meta, hasBody: true };
16979
19249
  }
16980
19250
  function readAuditRecords(auditDir, query2 = {}) {
16981
- if (!(0, import_node_fs31.existsSync)(auditDir)) return [];
19251
+ if (!(0, import_node_fs32.existsSync)(auditDir)) return [];
16982
19252
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
16983
19253
  const to = typeof query2.to === "number" ? query2.to : Infinity;
16984
19254
  const limit = Math.min(MAX_LIMIT, Math.max(1, Math.trunc(query2.limit ?? DEFAULT_LIMIT)));
@@ -17006,7 +19276,7 @@ function readAuditRecords(auditDir, query2 = {}) {
17006
19276
  }
17007
19277
 
17008
19278
  // src/audit/AuditWriter.ts
17009
- var import_node_fs32 = require("fs");
19279
+ var import_node_fs33 = require("fs");
17010
19280
  var import_node_path33 = require("path");
17011
19281
  var AuditWriter = class {
17012
19282
  constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
@@ -17054,7 +19324,7 @@ var AuditWriter = class {
17054
19324
  /** Create a directory once per process and remember it. */
17055
19325
  ensureDir(path2) {
17056
19326
  if (!this.ensuredDirs.has(path2)) {
17057
- (0, import_node_fs32.mkdirSync)(path2, { recursive: true });
19327
+ (0, import_node_fs33.mkdirSync)(path2, { recursive: true });
17058
19328
  this.ensuredDirs.add(path2);
17059
19329
  }
17060
19330
  return path2;
@@ -17064,8 +19334,8 @@ var AuditWriter = class {
17064
19334
  const { requestBody: _req, responseBody: _res, ...meta } = record;
17065
19335
  const file = (0, import_node_path33.join)(dayPath, AUDIT_META_FILE);
17066
19336
  const line = JSON.stringify(meta) + "\n";
17067
- const bytesBefore = (0, import_node_fs32.existsSync)(file) ? (0, import_node_fs32.statSync)(file).size : 0;
17068
- (0, import_node_fs32.appendFileSync)(file, line, "utf8");
19337
+ const bytesBefore = (0, import_node_fs33.existsSync)(file) ? (0, import_node_fs33.statSync)(file).size : 0;
19338
+ (0, import_node_fs33.appendFileSync)(file, line, "utf8");
17069
19339
  try {
17070
19340
  updateAuditStatsAfterAppend(
17071
19341
  file,
@@ -17097,7 +19367,7 @@ var AuditWriter = class {
17097
19367
  const line = encodeBodyEntry(record, sessionKey, dayDir, this.bases);
17098
19368
  if (line === null) return;
17099
19369
  const bodiesPath = this.ensureDir((0, import_node_path33.join)(dayPath, AUDIT_BODIES_DIR));
17100
- (0, import_node_fs32.appendFileSync)((0, import_node_path33.join)(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
19370
+ (0, import_node_fs33.appendFileSync)((0, import_node_path33.join)(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
17101
19371
  } catch (error) {
17102
19372
  this.bases.forget(sessionKey);
17103
19373
  this.logger.warn("[AuditWriter] failed to append audit body shard", {
@@ -17109,10 +19379,10 @@ var AuditWriter = class {
17109
19379
  };
17110
19380
 
17111
19381
  // src/billing/BillingPublisher.ts
17112
- var import_node_fs33 = require("fs");
19382
+ var import_node_fs34 = require("fs");
17113
19383
  var import_node_crypto24 = require("crypto");
17114
19384
  var import_node_path34 = require("path");
17115
- var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
19385
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
17116
19386
 
17117
19387
  // src/billing/billingFiles.ts
17118
19388
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -17135,7 +19405,7 @@ var BillingPublisher = class {
17135
19405
  constructor(billingDir, logger, opts = {}) {
17136
19406
  this.billingDir = billingDir;
17137
19407
  this.logger = logger;
17138
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch7.fetchUpstream)(url, init));
19408
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init));
17139
19409
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
17140
19410
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
17141
19411
  this.now = opts.now ?? Date.now;
@@ -17183,7 +19453,7 @@ var BillingPublisher = class {
17183
19453
  appendNow(event) {
17184
19454
  this.ensureDir();
17185
19455
  const file = (0, import_node_path34.join)(this.billingDir, billingFileName(event.ts));
17186
- (0, import_node_fs33.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
19456
+ (0, import_node_fs34.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
17187
19457
  }
17188
19458
  /**
17189
19459
  * One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
@@ -17233,7 +19503,7 @@ var BillingPublisher = class {
17233
19503
  try {
17234
19504
  this.ensureDir();
17235
19505
  const file = (0, import_node_path34.join)(this.billingDir, deliveredFileName(event.ts));
17236
- (0, import_node_fs33.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
19506
+ (0, import_node_fs34.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
17237
19507
  } catch (error) {
17238
19508
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
17239
19509
  error: error instanceof Error ? error.message : String(error)
@@ -17242,20 +19512,20 @@ var BillingPublisher = class {
17242
19512
  }
17243
19513
  ensureDir() {
17244
19514
  if (this.dirEnsured) return;
17245
- (0, import_node_fs33.mkdirSync)(this.billingDir, { recursive: true });
19515
+ (0, import_node_fs34.mkdirSync)(this.billingDir, { recursive: true });
17246
19516
  this.dirEnsured = true;
17247
19517
  }
17248
19518
  };
17249
19519
 
17250
19520
  // src/billing/billingReader.ts
17251
- var import_node_fs34 = require("fs");
19521
+ var import_node_fs35 = require("fs");
17252
19522
  var import_node_path35 = require("path");
17253
19523
  function readBillingLedger(billingDir) {
17254
19524
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
17255
- if (!(0, import_node_fs34.existsSync)(billingDir)) return view;
19525
+ if (!(0, import_node_fs35.existsSync)(billingDir)) return view;
17256
19526
  let files;
17257
19527
  try {
17258
- files = (0, import_node_fs34.readdirSync)(billingDir);
19528
+ files = (0, import_node_fs35.readdirSync)(billingDir);
17259
19529
  } catch {
17260
19530
  return view;
17261
19531
  }
@@ -17286,7 +19556,7 @@ function readBillingStatus(billingDir) {
17286
19556
  function parseLines(dir, file) {
17287
19557
  let raw;
17288
19558
  try {
17289
- raw = (0, import_node_fs34.readFileSync)((0, import_node_path35.join)(dir, file), "utf8");
19559
+ raw = (0, import_node_fs35.readFileSync)((0, import_node_path35.join)(dir, file), "utf8");
17290
19560
  } catch {
17291
19561
  return [];
17292
19562
  }
@@ -17385,7 +19655,7 @@ var BillingRetrySweeper = class {
17385
19655
  // src/TokenRefreshScheduler.ts
17386
19656
  var REFRESH_LEAD_MS2 = 5 * 6e4;
17387
19657
  var SWEEP_INTERVAL_MS5 = 6e4;
17388
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini"];
19658
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
17389
19659
  var TokenRefreshScheduler = class {
17390
19660
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
17391
19661
  this.store = store;
@@ -17468,6 +19738,14 @@ var TokenRefreshScheduler = class {
17468
19738
  return this.store.refreshCodexToken();
17469
19739
  case "gemini":
17470
19740
  return this.store.refreshGeminiToken();
19741
+ case "kimi":
19742
+ return this.store.refreshKimiToken();
19743
+ case "grok":
19744
+ return this.store.refreshGrokToken();
19745
+ // ghu_ tokens never near-expire (far-future expiresAt), so the sweep
19746
+ // never reaches this — the branch exists for union totality.
19747
+ case "copilot":
19748
+ return this.store.refreshCopilotToken();
17471
19749
  }
17472
19750
  }
17473
19751
  };
@@ -17544,7 +19822,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
17544
19822
 
17545
19823
  // src/webhook/WebhookDispatcher.ts
17546
19824
  var import_node_crypto25 = require("crypto");
17547
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
19825
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
17548
19826
  var WEBHOOK_MAX_ATTEMPTS = 3;
17549
19827
  var WEBHOOK_QUEUE_MAX = 1e3;
17550
19828
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -17564,7 +19842,7 @@ var WebhookDispatcher = class {
17564
19842
  sleep;
17565
19843
  now;
17566
19844
  constructor(opts = {}) {
17567
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init));
19845
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
17568
19846
  this.logger = opts.logger;
17569
19847
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
17570
19848
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -17650,8 +19928,8 @@ var WebhookDispatcher = class {
17650
19928
  signal: AbortSignal.timeout(this.timeoutMs)
17651
19929
  });
17652
19930
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
17653
- } catch (err5) {
17654
- return { ok: false, error: err5 instanceof Error ? err5.message : String(err5) };
19931
+ } catch (err8) {
19932
+ return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
17655
19933
  }
17656
19934
  }
17657
19935
  /**
@@ -17714,7 +19992,7 @@ function feishuText(event) {
17714
19992
  // src/bootstrap.ts
17715
19993
  var activeImageRuntimeBootstrapSession;
17716
19994
  function createImageRuntimeBootstrapSession(initialGeneration) {
17717
- const openAIOperationRegistry = new import_core4.OpenAIOperationRegistry();
19995
+ const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
17718
19996
  const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
17719
19997
  const unregisterContributions = [];
17720
19998
  try {
@@ -17770,7 +20048,7 @@ function installImageRuntimeBootstrapSession(initialGeneration) {
17770
20048
  function resolveLoggingConfig(configured, configPath) {
17771
20049
  const file = configured?.file ?? defaultDaemonLogPath(configPath);
17772
20050
  try {
17773
- (0, import_node_fs35.mkdirSync)(configured?.file ? (0, import_node_path36.dirname)(configured.file) : defaultLogDir(configPath), {
20051
+ (0, import_node_fs36.mkdirSync)(configured?.file ? (0, import_node_path36.dirname)(configured.file) : defaultLogDir(configPath), {
17774
20052
  recursive: true
17775
20053
  });
17776
20054
  } catch {
@@ -17788,12 +20066,12 @@ function buildDaemon(config, paths) {
17788
20066
  setSecretBox(secretBox3);
17789
20067
  setSecretBox2(secretBox3);
17790
20068
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
17791
- const accountAllowanceStore = new import_AccountAllowanceStore4.AccountAllowanceStore(
20069
+ const accountAllowanceStore = new import_AccountAllowanceStore9.AccountAllowanceStore(
17792
20070
  Date.now,
17793
20071
  void 0,
17794
20072
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
17795
20073
  );
17796
- (0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
20074
+ (0, import_AccountAllowanceStore9.setSharedAccountAllowanceStore)(accountAllowanceStore);
17797
20075
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
17798
20076
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
17799
20077
  );
@@ -17818,21 +20096,22 @@ function buildDaemon(config, paths) {
17818
20096
  claudeAllowanceRefreshScheduler.configure(
17819
20097
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
17820
20098
  );
17821
- const subscriptionAccounts = new import_subscriptions6.SubscriptionAccountService(credentialStore);
17822
- (0, import_subscriptions6.setSubscriptionAccountService)(subscriptionAccounts);
17823
- const subscriptionRegistry = new import_subscriptions6.SubscriptionProviderRegistry(
20099
+ const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
20100
+ (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
20101
+ const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
17824
20102
  subscriptionAccounts,
17825
20103
  credentialStore
17826
20104
  );
17827
- (0, import_subscriptions6.setSubscriptionProviderRegistry)(subscriptionRegistry);
20105
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
17828
20106
  setServerProxyConfig(decryptedConfig.server?.proxy);
17829
- (0, import_upstreamFetch9.setUpstreamProxyResolver)(
20107
+ (0, import_upstreamFetch15.setUpstreamProxyResolver)(
17830
20108
  createUpstreamProxyResolver({
17831
20109
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
17832
20110
  })
17833
20111
  );
17834
20112
  (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver.getGeminiCodeAssistProjectResolver)());
17835
20113
  const autoDisableStore = new AutoDisableStore();
20114
+ const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
17836
20115
  const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
17837
20116
  createPoolKeysLoader((id) => llmConfig.getProviderRow(id), autoDisableStore),
17838
20117
  resolveEnvKey,
@@ -17849,7 +20128,7 @@ function buildDaemon(config, paths) {
17849
20128
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
17850
20129
  // Catalog egress follows the same global/env proxy policy as every other
17851
20130
  // daemon upstream call; no provider/account override applies here.
17852
- fetchImpl: ((input, init) => (0, import_upstreamFetch9.fetchUpstream)(String(input), init ?? {}))
20131
+ fetchImpl: ((input, init) => (0, import_upstreamFetch15.fetchUpstream)(String(input), init ?? {}))
17853
20132
  });
17854
20133
  const pricingRefreshScheduler = new PricingRefreshScheduler(
17855
20134
  pricingEngine,
@@ -18113,6 +20392,11 @@ function buildDaemon(config, paths) {
18113
20392
  // values themselves NEVER leave (masked via `maskProviderApiKey`).
18114
20393
  apiKeyPool,
18115
20394
  autoDisableStore,
20395
+ // BYO provider-key quota (Z.AI coding plan, MiniMax Token Plan, …): a
20396
+ // read-through cached same-key usage probe surfaced on the keys view. The
20397
+ // key plaintext is resolved + decrypted inside the service and never
20398
+ // crosses back out.
20399
+ providerKeyQuota: providerKeyQuotaService,
18116
20400
  // Interactive OAuth login over admin HTTP (app-parity child 4, design
18117
20401
  // D1/D2-a). The in-memory pending-session store (NEVER serialized), the
18118
20402
  // injected token-exchange fetch (global `fetch` here; mocked in tests), and a
@@ -18129,7 +20413,7 @@ function buildDaemon(config, paths) {
18129
20413
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
18130
20414
  // excluded from the upstream trace, so a failing login left no evidence.
18131
20415
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
18132
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20416
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init, { providerId, redactBodies: true }),
18133
20417
  subscriptionAccountAppender: credentialStore,
18134
20418
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
18135
20419
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -18137,6 +20421,13 @@ function buildDaemon(config, paths) {
18137
20421
  // can inject a mock so no real port is bound.
18138
20422
  codexSessions: new CodexOAuthSessionStore(),
18139
20423
  codexAwaitLoopback: paths.codexAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal)),
20424
+ // Kimi interactive OAuth — the async DEVICE-CODE flow store (no port, no
20425
+ // paste; the app shows the verification URL + user code and polls the
20426
+ // token-free status). Token captured + persisted daemon-side.
20427
+ kimiSessions: new CodexOAuthSessionStore(),
20428
+ // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20429
+ grokSessions: new CodexOAuthSessionStore(),
20430
+ copilotSessions: new CodexOAuthSessionStore(),
18140
20431
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
18141
20432
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
18142
20433
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -18195,7 +20486,7 @@ function buildDaemon(config, paths) {
18195
20486
  });
18196
20487
  const webhookDispatcher = new WebhookDispatcher({
18197
20488
  logger,
18198
- fetchImpl: (url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init)
20489
+ fetchImpl: (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init)
18199
20490
  });
18200
20491
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
18201
20492
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -18272,8 +20563,8 @@ function buildDaemon(config, paths) {
18272
20563
  }
18273
20564
  function isTokensStoreReadable(tokensPath) {
18274
20565
  try {
18275
- if (!(0, import_node_fs35.existsSync)(tokensPath)) return true;
18276
- (0, import_node_fs35.accessSync)(tokensPath, import_node_fs35.constants.R_OK);
20566
+ if (!(0, import_node_fs36.existsSync)(tokensPath)) return true;
20567
+ (0, import_node_fs36.accessSync)(tokensPath, import_node_fs36.constants.R_OK);
18277
20568
  return true;
18278
20569
  } catch {
18279
20570
  return false;
@@ -18509,11 +20800,11 @@ async function runLiveProbe(url, key, fetchImpl = fetch) {
18509
20800
  status: res.status,
18510
20801
  estimateHeader: res.headers.get("x-omnicross-count-estimate")
18511
20802
  };
18512
- } catch (err5) {
20803
+ } catch (err8) {
18513
20804
  return {
18514
20805
  status: null,
18515
20806
  estimateHeader: null,
18516
- error: err5 instanceof Error ? err5.message : String(err5)
20807
+ error: err8 instanceof Error ? err8.message : String(err8)
18517
20808
  };
18518
20809
  }
18519
20810
  }
@@ -18601,7 +20892,7 @@ async function runDoctor(argv, fetchImpl = fetch) {
18601
20892
  }
18602
20893
 
18603
20894
  // src/commands/import-ccr.ts
18604
- var import_node_fs36 = require("fs");
20895
+ var import_node_fs37 = require("fs");
18605
20896
  var import_node_util3 = require("util");
18606
20897
 
18607
20898
  // src/ccr-import.ts
@@ -18696,7 +20987,7 @@ async function runImportCcr(argv) {
18696
20987
  const outPath = values.out ?? "omnicross.config.json";
18697
20988
  let raw;
18698
20989
  try {
18699
- raw = JSON.parse((0, import_node_fs36.readFileSync)(ccrPath, "utf8"));
20990
+ raw = JSON.parse((0, import_node_fs37.readFileSync)(ccrPath, "utf8"));
18700
20991
  } catch {
18701
20992
  throw new Error(`import-ccr: cannot read or parse '${ccrPath}'`);
18702
20993
  }
@@ -18834,7 +21125,7 @@ async function keysRevoke(db, id) {
18834
21125
  // src/commands/launch.ts
18835
21126
  var import_node_child_process2 = require("child_process");
18836
21127
  var import_node_crypto26 = require("crypto");
18837
- var import_node_fs37 = require("fs");
21128
+ var import_node_fs38 = require("fs");
18838
21129
  var import_node_path38 = require("path");
18839
21130
  var import_node_util6 = require("util");
18840
21131
  var import_cli_launcher3 = require("@omnicross/cli-launcher");
@@ -18879,7 +21170,7 @@ function resolveInPathDefault(candidate) {
18879
21170
  const segments = (process.env["PATH"] ?? "").split(import_node_path38.delimiter).filter(Boolean);
18880
21171
  for (const seg of segments) {
18881
21172
  const full = (0, import_node_path38.join)(seg, candidate);
18882
- if ((0, import_node_fs37.existsSync)(full)) return full;
21173
+ if ((0, import_node_fs38.existsSync)(full)) return full;
18883
21174
  }
18884
21175
  return null;
18885
21176
  }
@@ -18920,9 +21211,9 @@ async function runLaunch(argv, deps) {
18920
21211
  await daemon.llmConfig.ready();
18921
21212
  await daemon.migrateUsageStore();
18922
21213
  await daemon.providerProxy.start();
18923
- } catch (err5) {
21214
+ } catch (err8) {
18924
21215
  await shutdownLaunchDaemon(daemon);
18925
- throw err5;
21216
+ throw err8;
18926
21217
  }
18927
21218
  let launch;
18928
21219
  try {
@@ -18930,9 +21221,9 @@ async function runLaunch(argv, deps) {
18930
21221
  providerId: values.provider,
18931
21222
  model: values.model
18932
21223
  });
18933
- } catch (err5) {
21224
+ } catch (err8) {
18934
21225
  await shutdownLaunchDaemon(daemon);
18935
- throw err5;
21226
+ throw err8;
18936
21227
  }
18937
21228
  try {
18938
21229
  const plan = buildCliSpawnPlan({
@@ -19037,9 +21328,9 @@ function spawnCliInherit(plan) {
19037
21328
  process.removeListener("SIGINT", onSignal);
19038
21329
  process.removeListener("SIGTERM", onSignal);
19039
21330
  };
19040
- child.on("error", (err5) => {
21331
+ child.on("error", (err8) => {
19041
21332
  detach();
19042
- if (err5.code === "ENOENT") {
21333
+ if (err8.code === "ENOENT") {
19043
21334
  reject(
19044
21335
  new Error(
19045
21336
  `launch: "${plan.command}" not found on PATH \u2014 install the CLI first.`
@@ -19047,7 +21338,7 @@ function spawnCliInherit(plan) {
19047
21338
  );
19048
21339
  return;
19049
21340
  }
19050
- reject(err5);
21341
+ reject(err8);
19051
21342
  });
19052
21343
  child.on("exit", (code, signal) => {
19053
21344
  detach();
@@ -19060,9 +21351,9 @@ function spawnCliInherit(plan) {
19060
21351
  var import_node_child_process3 = require("child_process");
19061
21352
  var import_node_readline2 = require("readline");
19062
21353
  var import_node_util7 = require("util");
19063
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
19064
- var import_subscriptions7 = require("@omnicross/subscriptions");
19065
- var PROVIDERS2 = ["claude", "codex", "gemini"];
21354
+ var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
21355
+ var import_subscriptions13 = require("@omnicross/subscriptions");
21356
+ var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
19066
21357
  async function runLogin(argv, deps) {
19067
21358
  const { values, positionals } = (0, import_node_util7.parseArgs)({
19068
21359
  args: argv,
@@ -19070,7 +21361,9 @@ async function runLogin(argv, deps) {
19070
21361
  config: { type: "string", short: "c" },
19071
21362
  "master-key-file": { type: "string" },
19072
21363
  // Optional user label for the appended account (multi-account).
19073
- label: { type: "string" }
21364
+ label: { type: "string" },
21365
+ // Optional GitHub Enterprise domain for `login copilot` (GHE accounts).
21366
+ enterprise: { type: "string" }
19074
21367
  },
19075
21368
  allowPositionals: true
19076
21369
  });
@@ -19084,43 +21377,55 @@ async function runLogin(argv, deps) {
19084
21377
  if (!values.config) {
19085
21378
  throw new Error("login: --config <path> is required");
19086
21379
  }
21380
+ if (values.enterprise !== void 0 && provider !== "copilot") {
21381
+ throw new Error("login: --enterprise is only supported for the copilot provider");
21382
+ }
21383
+ const enterpriseDomain = values.enterprise !== void 0 ? import_subscriptions13.copilotOAuth.normalizeCopilotEnterpriseDomain(values.enterprise) : void 0;
19087
21384
  const resolved = {
19088
21385
  openBrowser: deps?.openBrowser ?? openBrowser,
19089
21386
  promptPaste: deps?.promptPaste ?? promptPaste,
19090
21387
  awaitLoopback: deps?.awaitLoopback ?? ((state) => awaitLoopbackCode(state)),
21388
+ awaitKimiDevice: deps?.awaitKimiDevice ?? ((fetchImpl) => runKimiDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21389
+ awaitGrokDevice: deps?.awaitGrokDevice ?? ((fetchImpl) => runGrokDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21390
+ awaitCopilotDevice: deps?.awaitCopilotDevice ?? ((fetchImpl, enterpriseUrl) => runCopilotDeviceFlow(fetchImpl, resolvedOpenBrowser, enterpriseUrl)),
19091
21391
  tokensFetch: deps?.tokensFetch
19092
21392
  };
21393
+ const resolvedOpenBrowser = resolved.openBrowser;
19093
21394
  const box = resolveSecretBox(values["master-key-file"]);
19094
21395
  setSecretBox(box);
19095
- (0, import_upstreamFetch10.setUpstreamProxyResolver)(createUpstreamProxyResolver());
21396
+ (0, import_upstreamFetch16.setUpstreamProxyResolver)(createUpstreamProxyResolver());
19096
21397
  try {
19097
21398
  const tokensPath = defaultTokensPath(values.config);
19098
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
21399
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
19099
21400
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
19100
21401
  const expiresAt = await runProviderLogin(
19101
21402
  provider,
19102
21403
  store,
19103
21404
  resolved,
19104
21405
  exchangeFetch,
19105
- values.label
21406
+ values.label,
21407
+ enterpriseDomain
19106
21408
  );
19107
21409
  console.info(`Logged in to '${provider}' \u2192 ${tokensPath}`);
19108
21410
  console.info(` token: [stored, encrypted] expiresAt: ${expiresAt ?? "n/a"}`);
19109
21411
  } finally {
19110
21412
  setSecretBox(null);
19111
- (0, import_upstreamFetch10.setUpstreamProxyResolver)(null);
21413
+ (0, import_upstreamFetch16.setUpstreamProxyResolver)(null);
19112
21414
  }
19113
21415
  }
19114
- async function runProviderLogin(provider, store, deps, exchangeFetch, label) {
21416
+ async function runProviderLogin(provider, store, deps, exchangeFetch, label, enterpriseUrl) {
19115
21417
  if (provider === "codex") return loginCodex(store, deps, exchangeFetch, label);
19116
21418
  if (provider === "claude") return loginClaude(store, deps, exchangeFetch, label);
21419
+ if (provider === "kimi") return loginKimi(store, deps, exchangeFetch, label);
21420
+ if (provider === "grok") return loginGrok(store, deps, exchangeFetch, label);
21421
+ if (provider === "copilot") return loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl);
19117
21422
  return loginGemini(store, deps, exchangeFetch, label);
19118
21423
  }
19119
21424
  async function loginCodex(store, deps, exchangeFetch, label) {
19120
- const { authUrl, codeVerifier, state } = import_subscriptions7.codexOAuth.generateAuthParams();
21425
+ const { authUrl, codeVerifier, state } = import_subscriptions13.codexOAuth.generateAuthParams();
19121
21426
  await presentUrl(authUrl, deps);
19122
21427
  const code = await deps.awaitLoopback(state);
19123
- const result = await import_subscriptions7.codexOAuth.exchangeCodeForTokens(
21428
+ const result = await import_subscriptions13.codexOAuth.exchangeCodeForTokens(
19124
21429
  { authorizationCode: code, codeVerifier, state },
19125
21430
  exchangeFetch
19126
21431
  );
@@ -19139,7 +21444,7 @@ async function loginCodex(store, deps, exchangeFetch, label) {
19139
21444
  return expiresAt;
19140
21445
  }
19141
21446
  async function loginClaude(store, deps, exchangeFetch, label) {
19142
- const { authUrl, codeVerifier, state } = import_subscriptions7.claudeOAuth.generateAuthParams();
21447
+ const { authUrl, codeVerifier, state } = import_subscriptions13.claudeOAuth.generateAuthParams();
19143
21448
  await presentUrl(authUrl, deps);
19144
21449
  const pasted = (await deps.promptPaste("Paste the authorization code (code#state): ")).trim();
19145
21450
  const [code, pastedState] = pasted.split("#");
@@ -19147,7 +21452,7 @@ async function loginClaude(store, deps, exchangeFetch, label) {
19147
21452
  if (pastedState && pastedState !== state) {
19148
21453
  throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
19149
21454
  }
19150
- const result = await import_subscriptions7.claudeOAuth.exchangeCodeForTokens(
21455
+ const result = await import_subscriptions13.claudeOAuth.exchangeCodeForTokens(
19151
21456
  { authorizationCode: code, codeVerifier, state },
19152
21457
  exchangeFetch
19153
21458
  );
@@ -19166,11 +21471,11 @@ async function loginClaude(store, deps, exchangeFetch, label) {
19166
21471
  return expiresAt;
19167
21472
  }
19168
21473
  async function loginGemini(store, deps, exchangeFetch, label) {
19169
- const { authUrl, codeVerifier } = import_subscriptions7.geminiOAuth.generateAuthParams();
21474
+ const { authUrl, codeVerifier } = import_subscriptions13.geminiOAuth.generateAuthParams();
19170
21475
  await presentUrl(authUrl, deps);
19171
21476
  const code = (await deps.promptPaste("Paste the authorization code: ")).trim();
19172
21477
  if (!code) throw new Error("login: no authorization code was pasted");
19173
- const result = await import_subscriptions7.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
21478
+ const result = await import_subscriptions13.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
19174
21479
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
19175
21480
  const block = {
19176
21481
  authMethod: "oauth",
@@ -19184,6 +21489,129 @@ async function loginGemini(store, deps, exchangeFetch, label) {
19184
21489
  logMasked("gemini", result.accessToken);
19185
21490
  return expiresAt;
19186
21491
  }
21492
+ async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
21493
+ const deviceId = import_subscriptions13.kimiOAuth.generateKimiDeviceId();
21494
+ const fingerprint = import_subscriptions13.kimiOAuth.kimiFingerprintHeaders(deviceId);
21495
+ const authorization = await import_subscriptions13.kimiOAuth.requestDeviceAuthorization(exchangeFetch, fingerprint);
21496
+ const url = authorization.verificationUriComplete ?? authorization.verificationUri;
21497
+ console.info("Open this URL in your browser and approve the request:");
21498
+ console.info(` ${url}`);
21499
+ if (!authorization.verificationUriComplete) {
21500
+ console.info(` Then enter this code: ${authorization.userCode}`);
21501
+ }
21502
+ await openBrowserFn(url).catch(() => false);
21503
+ const result = await import_subscriptions13.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
21504
+ fingerprint,
21505
+ onPending: () => process.stdout.write(".")
21506
+ });
21507
+ console.info("");
21508
+ return {
21509
+ ...result,
21510
+ accountId: import_subscriptions13.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
21511
+ deviceId
21512
+ };
21513
+ }
21514
+ async function loginKimi(store, deps, exchangeFetch, label) {
21515
+ const result = await deps.awaitKimiDevice(exchangeFetch);
21516
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
21517
+ const block = {
21518
+ authMethod: "oauth",
21519
+ status: "authorized",
21520
+ accessToken: result.accessToken,
21521
+ refreshToken: result.refreshToken,
21522
+ expiresAt,
21523
+ ...result.accountId ? { accountId: result.accountId } : {},
21524
+ deviceId: result.deviceId,
21525
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
21526
+ };
21527
+ await store.appendProviderAccount("kimi", block, label);
21528
+ logMasked("kimi", result.accessToken);
21529
+ return expiresAt;
21530
+ }
21531
+ async function runGrokDeviceFlow(exchangeFetch, openBrowserFn) {
21532
+ const tokenEndpoint = await import_subscriptions13.grokOAuth.resolveGrokTokenEndpoint(exchangeFetch);
21533
+ const authorization = await import_subscriptions13.grokOAuth.requestGrokDeviceAuthorization(exchangeFetch);
21534
+ const url = authorization.verificationUriComplete ?? authorization.verificationUri;
21535
+ console.info("Open this URL in your browser and approve the request:");
21536
+ console.info(` ${url}`);
21537
+ if (!authorization.verificationUriComplete) {
21538
+ console.info(` Then enter this code: ${authorization.userCode}`);
21539
+ }
21540
+ await openBrowserFn(url).catch(() => false);
21541
+ const result = await import_subscriptions13.grokOAuth.awaitGrokDeviceToken(authorization, tokenEndpoint, exchangeFetch, {
21542
+ onPending: () => process.stdout.write(".")
21543
+ });
21544
+ console.info("");
21545
+ return {
21546
+ ...result,
21547
+ accountId: import_subscriptions13.grokOAuth.grokAccountIdFromAccessToken(result.accessToken)
21548
+ };
21549
+ }
21550
+ async function loginGrok(store, deps, exchangeFetch, label) {
21551
+ const result = await deps.awaitGrokDevice(exchangeFetch);
21552
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
21553
+ const block = {
21554
+ authMethod: "oauth",
21555
+ status: "authorized",
21556
+ accessToken: result.accessToken,
21557
+ refreshToken: result.refreshToken,
21558
+ expiresAt,
21559
+ ...result.accountId ? { accountId: result.accountId } : {},
21560
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
21561
+ };
21562
+ await store.appendProviderAccount("grok", block, label);
21563
+ logMasked("grok", result.accessToken);
21564
+ return expiresAt;
21565
+ }
21566
+ async function runCopilotDeviceFlow(exchangeFetch, openBrowserFn, enterpriseUrl) {
21567
+ if (enterpriseUrl) console.info(`Using GitHub Enterprise host: ${enterpriseUrl}`);
21568
+ const authorization = await import_subscriptions13.copilotOAuth.requestCopilotDeviceAuthorization(exchangeFetch, enterpriseUrl);
21569
+ const url = authorization.verificationUri;
21570
+ console.info("Open this URL in your browser and approve the request:");
21571
+ console.info(` ${url}`);
21572
+ console.info(` Then enter this code: ${authorization.userCode}`);
21573
+ await openBrowserFn(url).catch(() => false);
21574
+ const result = await import_subscriptions13.copilotOAuth.awaitCopilotDeviceToken(authorization, exchangeFetch, {
21575
+ onPending: () => process.stdout.write("."),
21576
+ ...enterpriseUrl ? { enterpriseUrl } : {}
21577
+ });
21578
+ console.info("");
21579
+ const identity = await import_subscriptions13.copilotOAuth.fetchCopilotIdentity(result.accessToken, exchangeFetch, enterpriseUrl);
21580
+ const apiEndpoint = await import_subscriptions13.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, exchangeFetch, enterpriseUrl);
21581
+ console.info("Enabling Copilot models (policy)...");
21582
+ await import_subscriptions13.copilotOAuth.enableAllCopilotModels(
21583
+ result.accessToken,
21584
+ { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
21585
+ exchangeFetch
21586
+ );
21587
+ return {
21588
+ accessToken: result.accessToken,
21589
+ expiresIn: Math.floor(import_subscriptions13.copilotOAuth.COPILOT_FAR_FUTURE_MS / 1e3),
21590
+ ...identity,
21591
+ ...apiEndpoint ? { apiEndpoint } : {}
21592
+ };
21593
+ }
21594
+ async function loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl) {
21595
+ const result = await deps.awaitCopilotDevice(exchangeFetch, enterpriseUrl);
21596
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
21597
+ const block = {
21598
+ authMethod: "oauth",
21599
+ status: "authorized",
21600
+ accessToken: result.accessToken,
21601
+ // ghu_ tokens have no refresh lifecycle — the same token doubles as the
21602
+ // stored refresh credential so generic refresh paths stay well-formed.
21603
+ refreshToken: result.accessToken,
21604
+ expiresAt,
21605
+ ...result.accountId ? { accountId: result.accountId } : {},
21606
+ ...result.email ? { email: result.email } : {},
21607
+ ...result.apiEndpoint ? { apiEndpoint: result.apiEndpoint } : {},
21608
+ ...enterpriseUrl ? { enterpriseUrl } : {},
21609
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
21610
+ };
21611
+ await store.appendProviderAccount("copilot", block, label);
21612
+ logMasked("copilot", result.accessToken);
21613
+ return expiresAt;
21614
+ }
19187
21615
  function isLoginProvider(value) {
19188
21616
  return PROVIDERS2.includes(value);
19189
21617
  }
@@ -19381,7 +21809,7 @@ function providersRmKey(configPath, providerId, keyId) {
19381
21809
  }
19382
21810
 
19383
21811
  // src/commands/secrets.ts
19384
- var import_node_fs38 = require("fs");
21812
+ var import_node_fs39 = require("fs");
19385
21813
  var import_node_util9 = require("util");
19386
21814
  async function runSecrets(argv) {
19387
21815
  const { values, positionals } = (0, import_node_util9.parseArgs)({
@@ -19454,12 +21882,12 @@ function secretsStatus(args) {
19454
21882
  reportField("admin.token", cfg.admin.token);
19455
21883
  }
19456
21884
  const tokensPath = defaultTokensPath(args.config);
19457
- if ((0, import_node_fs38.existsSync)(tokensPath)) {
21885
+ if ((0, import_node_fs39.existsSync)(tokensPath)) {
19458
21886
  console.info(`Secret status for ${tokensPath}:`);
19459
21887
  reportTokenFields(tokensPath);
19460
21888
  }
19461
21889
  const integrationsPath = defaultIntegrationsPath(args.config);
19462
- if ((0, import_node_fs38.existsSync)(integrationsPath)) {
21890
+ if ((0, import_node_fs39.existsSync)(integrationsPath)) {
19463
21891
  const state = readRawJson(integrationsPath);
19464
21892
  const key = state.gatewayKey;
19465
21893
  if (key && typeof key === "object" && !Array.isArray(key)) {
@@ -19513,8 +21941,8 @@ async function secretsRotate(args) {
19513
21941
  const integrationsPath = defaultIntegrationsPath(args.config);
19514
21942
  try {
19515
21943
  cfg = loadConfig(args.config);
19516
- if ((0, import_node_fs38.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
19517
- if ((0, import_node_fs38.existsSync)(integrationsPath)) {
21944
+ if ((0, import_node_fs39.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
21945
+ if ((0, import_node_fs39.existsSync)(integrationsPath)) {
19518
21946
  integrationsPlain = new IntegrationStateStore(integrationsPath, oldBox).load();
19519
21947
  }
19520
21948
  } finally {
@@ -19549,20 +21977,20 @@ function secretsDecrypt(args) {
19549
21977
  let tokensPlain = null;
19550
21978
  try {
19551
21979
  cfg = loadConfig(args.config);
19552
- if ((0, import_node_fs38.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
21980
+ if ((0, import_node_fs39.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
19553
21981
  } finally {
19554
21982
  setSecretBox(null);
19555
21983
  }
19556
21984
  saveConfig(args.config, cfg);
19557
21985
  if (tokensPlain) {
19558
- (0, import_node_fs38.writeFileSync)(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
21986
+ atomicReplaceUtf8(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n");
19559
21987
  }
19560
21988
  console.info(`Decrypted secrets to plaintext in ${args.config}` + tokensSuffix(args.config));
19561
21989
  }
19562
21990
  function readRawConfig(path2) {
19563
21991
  let parsed;
19564
21992
  try {
19565
- parsed = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
21993
+ parsed = JSON.parse((0, import_node_fs39.readFileSync)(path2, "utf8"));
19566
21994
  } catch {
19567
21995
  throw new Error(`secrets: cannot read or parse '${path2}'`);
19568
21996
  }
@@ -19570,7 +21998,7 @@ function readRawConfig(path2) {
19570
21998
  }
19571
21999
  function readRawJson(path2) {
19572
22000
  try {
19573
- const parsed = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
22001
+ const parsed = JSON.parse((0, import_node_fs39.readFileSync)(path2, "utf8"));
19574
22002
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19575
22003
  return parsed;
19576
22004
  }
@@ -19580,13 +22008,13 @@ function readRawJson(path2) {
19580
22008
  }
19581
22009
  function encryptTokensFileInPlace(configPath, box) {
19582
22010
  const tokensPath = defaultTokensPath(configPath);
19583
- if (!(0, import_node_fs38.existsSync)(tokensPath)) return;
22011
+ if (!(0, import_node_fs39.existsSync)(tokensPath)) return;
19584
22012
  const plain = decryptTokensFile(tokensPath, box);
19585
22013
  writeTokensEncrypted(tokensPath, plain, box);
19586
22014
  }
19587
22015
  function rewriteIntegrationState(configPath, readBox, writeBox) {
19588
22016
  const path2 = defaultIntegrationsPath(configPath);
19589
- if (!(0, import_node_fs38.existsSync)(path2)) return;
22017
+ if (!(0, import_node_fs39.existsSync)(path2)) return;
19590
22018
  const state = new IntegrationStateStore(path2, readBox).load();
19591
22019
  new IntegrationStateStore(path2, writeBox).save(state);
19592
22020
  }
@@ -19599,7 +22027,7 @@ function writeTokensEncrypted(tokensPath, plain, box) {
19599
22027
  { updatedAt: "", ...plain },
19600
22028
  box
19601
22029
  );
19602
- (0, import_node_fs38.writeFileSync)(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
22030
+ atomicReplaceUtf8(tokensPath, JSON.stringify(encrypted, null, 2) + "\n");
19603
22031
  }
19604
22032
  var TOKEN_FIELDS2 = {
19605
22033
  claude: ["accessToken", "refreshToken"],
@@ -19622,7 +22050,7 @@ function walkTokens(raw, fn) {
19622
22050
  return next;
19623
22051
  }
19624
22052
  function tokensSuffix(configPath) {
19625
- return (0, import_node_fs38.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
22053
+ return (0, import_node_fs39.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
19626
22054
  }
19627
22055
 
19628
22056
  // src/commands/start.ts
@@ -19889,7 +22317,7 @@ async function main() {
19889
22317
  process.exitCode = 1;
19890
22318
  }
19891
22319
  }
19892
- main().catch((err5) => {
19893
- console.error(err5 instanceof Error ? err5.message : String(err5));
22320
+ main().catch((err8) => {
22321
+ console.error(err8 instanceof Error ? err8.message : String(err8));
19894
22322
  process.exitCode = 1;
19895
22323
  });