@omnicross/daemon 0.3.1 → 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
@@ -1170,22 +1170,22 @@ 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_AccountAllowanceStore7 = 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_upstreamFetch13 = 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_subscriptions9 = 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);
@@ -1367,8 +1367,187 @@ function handleKimiOAuthStatus(sessionId, deps) {
1367
1367
  return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
1368
1368
  }
1369
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
+
1370
1549
  // src/allowance/AccountAllowanceService.ts
1371
- var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1550
+ var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1372
1551
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1373
1552
 
1374
1553
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -1839,7 +2018,7 @@ var CodexAllowanceCollector = class {
1839
2018
  // src/allowance/KimiAllowanceCollector.ts
1840
2019
  var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1841
2020
  var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
1842
- var import_subscriptions3 = require("@omnicross/subscriptions");
2021
+ var import_subscriptions5 = require("@omnicross/subscriptions");
1843
2022
  var KIMI_ALLOWANCE_CACHE_MS = 5 * 6e4;
1844
2023
  var KIMI_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
1845
2024
  function finiteNumber2(value) {
@@ -1994,97 +2173,572 @@ var KimiAllowanceCollector = class {
1994
2173
  let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1995
2174
  if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1996
2175
  let response = await this.request(accountId, accessToken, tokens);
1997
- if (response.status === 401) {
1998
- const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
1999
- if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
2000
- accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
2001
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
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());
2002
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
+ }
2003
2664
  }
2004
- if (response.status === 403) {
2005
- const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
2006
- this.store.set(snapshot2);
2007
- return snapshot2;
2008
- }
2009
- if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
2665
+ if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
2010
2666
  let payload;
2011
2667
  try {
2012
2668
  payload = await response.json();
2013
2669
  } catch {
2014
- return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
2670
+ return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
2015
2671
  }
2016
2672
  const now = this.now();
2017
- const windows = parseKimiUsagePayload(payload, now);
2673
+ const windows = parseCopilotUserPayload(payload, now);
2018
2674
  const snapshot = {
2019
- providerId: "kimi",
2675
+ providerId: "copilot",
2020
2676
  accountId,
2021
2677
  source: "oauth-usage-api",
2022
2678
  observedAt: new Date(now).toISOString(),
2023
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
2024
- windows: windows.length > 0 ? windows : [
2025
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
2026
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
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" }
2027
2682
  ],
2028
- ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
2683
+ ...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
2029
2684
  };
2030
2685
  this.store.set(snapshot);
2031
2686
  return snapshot;
2032
2687
  }
2033
2688
  request(accountId, accessToken, tokens) {
2034
- return this.fetchImpl(KIMI_USAGE_URL, {
2689
+ return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
2035
2690
  method: "GET",
2036
2691
  headers: {
2037
2692
  Authorization: `Bearer ${accessToken}`,
2038
2693
  Accept: "application/json",
2039
- ...(0, import_subscriptions3.kimiFingerprintHeaders)(tokens.deviceId)
2694
+ "Content-Type": "application/json",
2695
+ ...import_subscriptions6.COPILOT_GITHUB_HEADERS
2040
2696
  },
2041
2697
  signal: AbortSignal.timeout(15e3)
2042
2698
  }, accountId);
2043
2699
  }
2044
2700
  failureSnapshot(accountId, code, now) {
2045
- const existing = this.store.get("kimi", accountId, now);
2701
+ const existing = this.store.get("copilot", accountId, now);
2046
2702
  const snapshot = existing ? {
2047
2703
  ...existing,
2048
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
2704
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
2049
2705
  windows: existing.windows.map((window) => ({
2050
2706
  ...window,
2051
2707
  state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
2052
2708
  })),
2053
2709
  lastErrorCode: code
2054
2710
  } : {
2055
- providerId: "kimi",
2711
+ providerId: "copilot",
2056
2712
  accountId,
2057
2713
  source: "oauth-usage-api",
2058
2714
  observedAt: new Date(now).toISOString(),
2059
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
2715
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
2060
2716
  windows: [
2061
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
2062
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
2717
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
2063
2718
  ],
2064
2719
  lastErrorCode: code
2065
2720
  };
2066
2721
  this.store.set(snapshot);
2067
2722
  return snapshot;
2068
2723
  }
2069
- unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
2724
+ unsupportedSnapshot(accountId, now) {
2070
2725
  return {
2071
- providerId: "kimi",
2726
+ providerId: "copilot",
2072
2727
  accountId,
2073
2728
  source: "oauth-usage-api",
2074
2729
  observedAt: new Date(now).toISOString(),
2075
2730
  windows: [
2076
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
2077
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
2731
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
2078
2732
  ],
2079
- lastErrorCode: code
2733
+ lastErrorCode: "copilot_usage_unsupported_auth"
2080
2734
  };
2081
2735
  }
2082
2736
  };
2083
2737
 
2084
2738
  // src/allowance/OpenCodeGoAllowanceCollector.ts
2085
- var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2086
- var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
2087
- var import_subscriptions4 = require("@omnicross/subscriptions");
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");
2088
2742
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
2089
2743
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
2090
2744
  function finitePercent3(value) {
@@ -2097,7 +2751,7 @@ function isoInstant2(value) {
2097
2751
  const time = Date.parse(value);
2098
2752
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
2099
2753
  }
2100
- function secondsUntil4(instant, now) {
2754
+ function secondsUntil6(instant, now) {
2101
2755
  if (!instant) return void 0;
2102
2756
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2103
2757
  }
@@ -2112,12 +2766,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
2112
2766
  usedPercent,
2113
2767
  windowMinutes: minutes,
2114
2768
  ...resetsAt !== void 0 ? { resetsAt } : {},
2115
- remainingSeconds: secondsUntil4(resetsAt, now),
2769
+ remainingSeconds: secondsUntil6(resetsAt, now),
2116
2770
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
2117
2771
  };
2118
2772
  }
2119
2773
  var OpenCodeGoAllowanceCollector = class {
2120
- constructor(credentials, store = (0, import_AccountAllowanceStore4.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
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) {
2121
2775
  this.credentials = credentials;
2122
2776
  this.store = store;
2123
2777
  this.fetchImpl = fetchImpl;
@@ -2147,7 +2801,7 @@ var OpenCodeGoAllowanceCollector = class {
2147
2801
  async fetchAccount(account) {
2148
2802
  const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
2149
2803
  if (!apiKey) return this.failureSnapshot(account.id, this.now());
2150
- const base = account.tokens.baseUrl ? (0, import_subscriptions4.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
2804
+ const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
2151
2805
  const response = await this.fetchImpl(`${base}/v1/usage`, {
2152
2806
  method: "GET",
2153
2807
  headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
@@ -2222,7 +2876,7 @@ function codexUnavailable(accountId, now) {
2222
2876
  };
2223
2877
  }
2224
2878
  var AccountAllowanceService = class {
2225
- constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, now = Date.now) {
2879
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, now = Date.now) {
2226
2880
  this.credentials = credentials;
2227
2881
  this.store = store;
2228
2882
  this.now = now;
@@ -2230,6 +2884,8 @@ var AccountAllowanceService = class {
2230
2884
  this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
2231
2885
  this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
2232
2886
  this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
2887
+ this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
2888
+ this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
2233
2889
  }
2234
2890
  credentials;
2235
2891
  store;
@@ -2237,6 +2893,8 @@ var AccountAllowanceService = class {
2237
2893
  claudeCollector;
2238
2894
  codexCollector;
2239
2895
  kimiCollector;
2896
+ grokCollector;
2897
+ copilotCollector;
2240
2898
  opencodegoCollector;
2241
2899
  /**
2242
2900
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
@@ -2271,11 +2929,23 @@ var AccountAllowanceService = class {
2271
2929
  (account) => !filter.accountId || account.id === filter.accountId
2272
2930
  );
2273
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);
2274
2942
  const known = /* @__PURE__ */ new Set();
2275
2943
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
2276
2944
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
2277
2945
  if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
2278
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}`);
2279
2949
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
2280
2950
  }
2281
2951
  knownAccounts(config) {
@@ -2283,7 +2953,9 @@ var AccountAllowanceService = class {
2283
2953
  ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
2284
2954
  ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
2285
2955
  ...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
2286
- ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", 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 }))
2287
2959
  ];
2288
2960
  }
2289
2961
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -2326,6 +2998,24 @@ var AccountAllowanceService = class {
2326
2998
  );
2327
2999
  return this.kimiCollector.collectMany(accounts, { force: true });
2328
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
+ }
2329
3019
  /**
2330
3020
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
2331
3021
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -2340,6 +3030,8 @@ var AccountAllowanceService = class {
2340
3030
  await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
2341
3031
  await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
2342
3032
  await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
3033
+ await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
3034
+ await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
2343
3035
  }
2344
3036
  /** Remove a cache row as soon as an account is deleted by the admin path. */
2345
3037
  removeAccountSnapshot(providerId, accountId) {
@@ -2434,7 +3126,7 @@ var ClaudeAllowanceRefreshScheduler = class {
2434
3126
  var import_node_crypto4 = require("crypto");
2435
3127
  var import_node_fs6 = require("fs");
2436
3128
  var import_node_path6 = require("path");
2437
- var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3129
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2438
3130
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
2439
3131
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
2440
3132
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -2463,7 +3155,7 @@ var JsonAccountAllowancePersistence = class {
2463
3155
  save(snapshots) {
2464
3156
  const rows = [];
2465
3157
  for (const snapshot of snapshots) {
2466
- const normalized2 = (0, import_AccountAllowanceStore6.normalizeAccountAllowanceSnapshot)(snapshot);
3158
+ const normalized2 = (0, import_AccountAllowanceStore8.normalizeAccountAllowanceSnapshot)(snapshot);
2467
3159
  if (!normalized2) continue;
2468
3160
  rows.push(normalized2);
2469
3161
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -2739,7 +3431,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
2739
3431
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
2740
3432
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
2741
3433
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
2742
- var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
3434
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
3435
+ var import_core3 = require("@omnicross/core");
2743
3436
 
2744
3437
  // src/image-generation/imagesConfigValidation.ts
2745
3438
  var import_outbound_api = require("@omnicross/core/outbound-api");
@@ -3035,6 +3728,7 @@ async function applyServerConfigTransaction(current, next, deps) {
3035
3728
 
3036
3729
  // src/config.ts
3037
3730
  var import_node_fs8 = require("fs");
3731
+ var import_core = require("@omnicross/core");
3038
3732
  var DEFAULT_ADMIN_PORT = 8766;
3039
3733
  function validateAdmin(raw) {
3040
3734
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -3091,6 +3785,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
3091
3785
  "openai-response",
3092
3786
  "gemini-code-assist"
3093
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
+ }
3094
3800
  function validateApiKeys(raw) {
3095
3801
  if (!Array.isArray(raw)) return void 0;
3096
3802
  const out = [];
@@ -3304,6 +4010,9 @@ function validateProvider(raw, index) {
3304
4010
  apiVersion,
3305
4011
  maxConcurrency,
3306
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"]),
3307
4016
  // Provider transformer config (app-parity child 5): load-guard, collapse-to-
3308
4017
  // undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
3309
4018
  // Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
@@ -3373,7 +4082,7 @@ var import_node_crypto6 = require("crypto");
3373
4082
  var import_node_fs10 = require("fs");
3374
4083
  var import_node_os3 = require("os");
3375
4084
  var import_node_path10 = require("path");
3376
- var import_core = require("@omnicross/core");
4085
+ var import_core2 = require("@omnicross/core");
3377
4086
 
3378
4087
  // src/integrations/codexAuthHelper.ts
3379
4088
  var import_node_path8 = require("path");
@@ -3854,7 +4563,7 @@ var IntegrationManager = class {
3854
4563
  if (!secret) {
3855
4564
  throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
3856
4565
  }
3857
- const effective = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4566
+ const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3858
4567
  const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
3859
4568
  const nextPermissions = [...effective];
3860
4569
  for (const required of REQUIRED_PERMISSIONS[client]) {
@@ -3952,7 +4661,7 @@ var IntegrationManager = class {
3952
4661
  return { binding, row, secret, created: false };
3953
4662
  }
3954
4663
  async createManagedClientKey(client, state) {
3955
- const created = await (0, import_core.createIntegrationKey)(
4664
+ const created = await (0, import_core2.createIntegrationKey)(
3956
4665
  this.options.keyDb,
3957
4666
  `Omnicross ${displayClient(client)} integration`,
3958
4667
  [...REQUIRED_PERMISSIONS[client]]
@@ -4044,7 +4753,7 @@ var IntegrationManager = class {
4044
4753
  const row = rows.find((candidate) => candidate.id === keyId);
4045
4754
  if (!row) return { usable: false, message: "The bound access key no longer exists." };
4046
4755
  const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
4047
- const allowedEndpoints = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4756
+ const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
4048
4757
  const status = {
4049
4758
  id: row.id,
4050
4759
  name: row.name,
@@ -4088,7 +4797,7 @@ var IntegrationManager = class {
4088
4797
  }
4089
4798
  };
4090
4799
  function hasRequiredPermissions(row, client) {
4091
- const allowed = (0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints);
4800
+ const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
4092
4801
  return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
4093
4802
  }
4094
4803
  function samePermissions(a, b) {
@@ -4257,7 +4966,10 @@ function mapPresetToProvider(preset, opts) {
4257
4966
  apiFormat: resolved.format,
4258
4967
  baseUrl: opts.baseUrlOverride ?? preset.api_base_url,
4259
4968
  apiKey: opts.key,
4260
- 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
4261
4973
  };
4262
4974
  return { provider };
4263
4975
  }
@@ -4282,7 +4994,8 @@ function listMappablePresets() {
4282
4994
  description: preset.description,
4283
4995
  features: preset.features,
4284
4996
  website: preset.website,
4285
- modelsEndpoint: preset.modelsEndpoint
4997
+ modelsEndpoint: preset.modelsEndpoint,
4998
+ extraHeaders: preset.extraHeaders
4286
4999
  });
4287
5000
  }
4288
5001
  return { mappable, excluded };
@@ -4372,11 +5085,11 @@ function preserveOutboundProxySecrets(incoming, current) {
4372
5085
  }
4373
5086
 
4374
5087
  // src/proxy/upstreamProxyResolver.ts
4375
- var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
5088
+ var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
4376
5089
  var serverProxy;
4377
5090
  function setServerProxyConfig(proxy) {
4378
5091
  serverProxy = proxy;
4379
- (0, import_upstreamFetch5.bumpUpstreamProxyGeneration)();
5092
+ (0, import_upstreamFetch7.bumpUpstreamProxyGeneration)();
4380
5093
  }
4381
5094
  function getServerProxyConfig() {
4382
5095
  return serverProxy;
@@ -4444,7 +5157,7 @@ function createUpstreamProxyResolver(src = {}) {
4444
5157
  }
4445
5158
 
4446
5159
  // src/admin/accountsOAuth.ts
4447
- var import_subscriptions5 = require("@omnicross/subscriptions");
5160
+ var import_subscriptions8 = require("@omnicross/subscriptions");
4448
5161
 
4449
5162
  // src/admin/accountsWrite.ts
4450
5163
  var VALID_PROVIDER_IDS = [
@@ -4452,7 +5165,9 @@ var VALID_PROVIDER_IDS = [
4452
5165
  "codex",
4453
5166
  "gemini",
4454
5167
  "opencodego",
4455
- "kimi"
5168
+ "kimi",
5169
+ "grok",
5170
+ "copilot"
4456
5171
  ];
4457
5172
  function asSubscriptionProviderId(id) {
4458
5173
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -4600,6 +5315,40 @@ function validateKimi(body) {
4600
5315
  copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
4601
5316
  return out;
4602
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
+ }
4603
5352
  function validateOpenCodeGo(body) {
4604
5353
  const authMethod = str(body["authMethod"]);
4605
5354
  const status = str(body["status"]);
@@ -4637,6 +5386,10 @@ function validateTokenBody(providerId, body) {
4637
5386
  return validateOpenCodeGo(body);
4638
5387
  case "kimi":
4639
5388
  return validateKimi(body);
5389
+ case "grok":
5390
+ return validateGrok(body);
5391
+ case "copilot":
5392
+ return validateCopilot(body);
4640
5393
  default:
4641
5394
  return null;
4642
5395
  }
@@ -4666,37 +5419,37 @@ async function statusEntryFor(reader, providerId) {
4666
5419
 
4667
5420
  // src/admin/accountsOAuth.ts
4668
5421
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
4669
- function err3(status, message) {
5422
+ function err5(status, message) {
4670
5423
  return { status, body: { error: { type: "admin_api_error", message } } };
4671
5424
  }
4672
5425
  function handleOAuthStart(providerId, deps) {
4673
5426
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
4674
- return err3(400, `oauth not available for provider '${providerId}'`);
5427
+ return err5(400, `oauth not available for provider '${providerId}'`);
4675
5428
  }
4676
- const flow = providerId === "claude" ? import_subscriptions5.claudeOAuth : import_subscriptions5.geminiOAuth;
5429
+ const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
4677
5430
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
4678
5431
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
4679
5432
  return { status: 200, body: { authUrl, sessionId } };
4680
5433
  }
4681
5434
  async function handleOAuthComplete(providerId, body, deps) {
4682
5435
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
4683
- return err3(400, `oauth not available for provider '${providerId}'`);
5436
+ return err5(400, `oauth not available for provider '${providerId}'`);
4684
5437
  }
4685
5438
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
4686
5439
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
4687
- if (!sessionId) return err3(400, "oauth complete requires { sessionId }");
4688
- if (!rawCode) return err3(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 }");
4689
5442
  const session = deps.oauthSessions.peek(sessionId);
4690
- if (!session) return err3(410, "oauth session is unknown, expired, or already used");
5443
+ if (!session) return err5(410, "oauth session is unknown, expired, or already used");
4691
5444
  if (session.providerId !== providerId) {
4692
- return err3(400, `oauth session does not match provider '${providerId}'`);
5445
+ return err5(400, `oauth session does not match provider '${providerId}'`);
4693
5446
  }
4694
5447
  let code = rawCode.trim();
4695
5448
  if (providerId === "claude") {
4696
5449
  const [splitCode, pastedState] = code.split("#");
4697
- if (!splitCode) return err3(400, "no authorization code was provided");
5450
+ if (!splitCode) return err5(400, "no authorization code was provided");
4698
5451
  if (pastedState && pastedState !== session.state) {
4699
- return err3(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5452
+ return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4700
5453
  }
4701
5454
  code = splitCode;
4702
5455
  }
@@ -4706,7 +5459,7 @@ async function handleOAuthComplete(providerId, body, deps) {
4706
5459
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
4707
5460
  } catch (exchangeError) {
4708
5461
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
4709
- return err3(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5462
+ return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4710
5463
  }
4711
5464
  deps.oauthSessions.consume(sessionId);
4712
5465
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -4715,7 +5468,7 @@ async function handleOAuthComplete(providerId, body, deps) {
4715
5468
  return { status: 200, body: status ? { account: status } : { ok: true } };
4716
5469
  }
4717
5470
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
4718
- const result = await import_subscriptions5.claudeOAuth.exchangeCodeForTokens(
5471
+ const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
4719
5472
  { authorizationCode: code, codeVerifier, state },
4720
5473
  exchangeFetch
4721
5474
  );
@@ -4731,7 +5484,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
4731
5484
  };
4732
5485
  }
4733
5486
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
4734
- const result = await import_subscriptions5.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
5487
+ const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
4735
5488
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
4736
5489
  return {
4737
5490
  authMethod: "oauth",
@@ -5036,8 +5789,8 @@ function errBody(message) {
5036
5789
  return { error: { type: "admin_api_error", message } };
5037
5790
  }
5038
5791
  var defaultCommandRunner = (command) => new Promise((resolve11) => {
5039
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err6, _stdout, stderr) => {
5040
- if (err6) resolve11({ ok: false, error: stderr.trim() || err6.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 });
5041
5794
  else resolve11({ ok: true });
5042
5795
  });
5043
5796
  });
@@ -5083,8 +5836,8 @@ async function handleCliLaunch(cli, body, ctx) {
5083
5836
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
5084
5837
  model: typeof body["model"] === "string" ? body["model"] : void 0
5085
5838
  });
5086
- } catch (err6) {
5087
- return { status: 400, body: errBody(err6 instanceof Error ? err6.message : "no launch target") };
5839
+ } catch (err8) {
5840
+ return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
5088
5841
  }
5089
5842
  const id = (0, import_node_crypto7.randomUUID)();
5090
5843
  let leaseId2;
@@ -5112,9 +5865,9 @@ async function handleCliLaunch(cli, body, ctx) {
5112
5865
  } else {
5113
5866
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
5114
5867
  }
5115
- } catch (err6) {
5116
- const status = err6 instanceof import_provider_proxy2.RouteLeaseError ? err6.status : 400;
5117
- return { status, body: errBody(err6 instanceof Error ? err6.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") };
5118
5871
  }
5119
5872
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
5120
5873
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -5142,9 +5895,9 @@ async function handleCliLaunch(cli, body, ctx) {
5142
5895
  onFailure: onSessionEnd
5143
5896
  });
5144
5897
  if (cleanup) openerCleanup = cleanup;
5145
- } catch (err6) {
5898
+ } catch (err8) {
5146
5899
  onSessionEnd();
5147
- return { status: 500, body: errBody(err6 instanceof Error ? err6.message : "failed to open terminal") };
5900
+ return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
5148
5901
  }
5149
5902
  if (ended) {
5150
5903
  openerCleanup?.();
@@ -5399,7 +6152,7 @@ async function runSearchLiveChecks(contributions, now = () => (/* @__PURE__ */ n
5399
6152
  }
5400
6153
 
5401
6154
  // src/search/SearchAssembly.ts
5402
- var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
6155
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
5403
6156
  var import_search = require("@omnicross/core/search");
5404
6157
  var import_api2 = require("@omnicross/core/search/api");
5405
6158
  var import_http2 = require("@omnicross/core/search/http");
@@ -5417,7 +6170,7 @@ function searchPolicyFrom(config) {
5417
6170
  };
5418
6171
  }
5419
6172
  function resolveSearchUpstreamDispatcher(url) {
5420
- return (0, import_upstreamFetch6.resolveUpstreamDispatcher)({ url });
6173
+ return (0, import_upstreamFetch8.resolveUpstreamDispatcher)({ url });
5421
6174
  }
5422
6175
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
5423
6176
  function resolveSearchUpstreamProxyConfig(url) {
@@ -5699,7 +6452,7 @@ async function handleSearchQuery(req, res, deps) {
5699
6452
  // src/admin/searchAdminView.ts
5700
6453
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
5701
6454
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
5702
- function isRecord2(value) {
6455
+ function isRecord4(value) {
5703
6456
  return value !== null && typeof value === "object" && !Array.isArray(value);
5704
6457
  }
5705
6458
  function redactSearchServerConfig(search) {
@@ -5749,13 +6502,13 @@ function resolveSecretField(entry, field, stored) {
5749
6502
  else delete entry[field];
5750
6503
  }
5751
6504
  function preserveSearchSecrets(incoming, current) {
5752
- if (!isRecord2(incoming)) return incoming;
6505
+ if (!isRecord4(incoming)) return incoming;
5753
6506
  const section = { ...incoming };
5754
6507
  const providersValue = section["providers"];
5755
- if (!isRecord2(providersValue)) return section;
6508
+ if (!isRecord4(providersValue)) return section;
5756
6509
  const providers = {};
5757
6510
  for (const [id, entryValue] of Object.entries(providersValue)) {
5758
- if (!isRecord2(entryValue)) {
6511
+ if (!isRecord4(entryValue)) {
5759
6512
  providers[id] = entryValue;
5760
6513
  continue;
5761
6514
  }
@@ -5833,7 +6586,7 @@ function parseKeyPolicyBody(body) {
5833
6586
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
5834
6587
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
5835
6588
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
5836
- function isRecord3(value) {
6589
+ function isRecord5(value) {
5837
6590
  return !!value && typeof value === "object" && !Array.isArray(value);
5838
6591
  }
5839
6592
  function nonBlank(value) {
@@ -5853,7 +6606,7 @@ function validateGatewayBindingsSegment(patch) {
5853
6606
  const ids = /* @__PURE__ */ new Set();
5854
6607
  raw.forEach((entry, index) => {
5855
6608
  const path2 = `bindings[${index}]`;
5856
- if (!isRecord3(entry)) {
6609
+ if (!isRecord5(entry)) {
5857
6610
  errors.push(`${path2} must be an object`);
5858
6611
  return;
5859
6612
  }
@@ -5882,12 +6635,12 @@ function validateGatewayBindingsSegment(patch) {
5882
6635
  } else if (entry.modelMappings.length > 100) {
5883
6636
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
5884
6637
  } else if (entry.modelMappings.some(
5885
- (mapping) => !isRecord3(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6638
+ (mapping) => !isRecord5(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5886
6639
  )) {
5887
6640
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
5888
6641
  }
5889
6642
  }
5890
- if (!isRecord3(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6643
+ if (!isRecord5(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5891
6644
  errors.push(`${path2}.target is invalid`);
5892
6645
  } else {
5893
6646
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -5902,7 +6655,7 @@ function validateGatewayBindingsSegment(patch) {
5902
6655
  }
5903
6656
  }
5904
6657
  if (entry.modelMap !== void 0) {
5905
- if (!isRecord3(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")) {
5906
6659
  errors.push(`${path2}.modelMap must contain string values`);
5907
6660
  }
5908
6661
  }
@@ -6185,7 +6938,9 @@ var PROVIDER_KEYS = {
6185
6938
  accounts: "opencodegoAccounts",
6186
6939
  active: "activeOpencodegoAccountId"
6187
6940
  },
6188
- kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
6941
+ kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6942
+ grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6943
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
6189
6944
  };
6190
6945
  function clone(value) {
6191
6946
  return JSON.parse(JSON.stringify(value));
@@ -6707,7 +7462,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
6707
7462
  }
6708
7463
 
6709
7464
  // src/admin/adminMigration.ts
6710
- function err4(status, message) {
7465
+ function err6(status, message) {
6711
7466
  return { status, body: { error: { type: "admin_api_error", message } } };
6712
7467
  }
6713
7468
  async function handleExport(body, deps) {
@@ -6717,30 +7472,30 @@ async function handleExport(body, deps) {
6717
7472
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
6718
7473
  } catch (error) {
6719
7474
  if (error instanceof WeakPassphraseError) {
6720
- return err4(400, error.message);
7475
+ return err6(400, error.message);
6721
7476
  }
6722
- return err4(500, "failed to build the migration pack");
7477
+ return err6(500, "failed to build the migration pack");
6723
7478
  }
6724
7479
  }
6725
7480
  async function handleImport(body, deps) {
6726
7481
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
6727
7482
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
6728
7483
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
6729
- if (!blob) return err4(400, "import requires { blob }");
7484
+ if (!blob) return err6(400, "import requires { blob }");
6730
7485
  try {
6731
7486
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
6732
7487
  return { status: 200, body: counts };
6733
7488
  } catch (error) {
6734
7489
  if (error instanceof WeakPassphraseError) {
6735
- return err4(400, error.message);
7490
+ return err6(400, error.message);
6736
7491
  }
6737
- return err4(400, error instanceof Error ? error.message : "import failed");
7492
+ return err6(400, error instanceof Error ? error.message : "import failed");
6738
7493
  }
6739
7494
  }
6740
7495
 
6741
7496
  // src/admin/usagePricing.ts
6742
7497
  var import_usage = require("@omnicross/core/usage");
6743
- var err5 = (status, message) => ({
7498
+ var err7 = (status, message) => ({
6744
7499
  status,
6745
7500
  body: { error: { type: "admin_api_error", message } }
6746
7501
  });
@@ -6753,7 +7508,7 @@ function parseRange(query2) {
6753
7508
  const startTs = parseFiniteInt(query2.get("startTs"));
6754
7509
  const endTs = parseFiniteInt(query2.get("endTs"));
6755
7510
  if (startTs === null || endTs === null) {
6756
- return err5(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");
6757
7512
  }
6758
7513
  return { startTs, endTs };
6759
7514
  }
@@ -6778,14 +7533,14 @@ async function handleUsageGet(view, query2, deps) {
6778
7533
  case "timeseries": {
6779
7534
  const bucket = query2.get("bucket");
6780
7535
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
6781
- return err5(400, "bucket must be one of 'hour', 'day', 'month'");
7536
+ return err7(400, "bucket must be one of 'hour', 'day', 'month'");
6782
7537
  }
6783
7538
  const now = Date.now();
6784
7539
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
6785
7540
  if (clamped.startTs < clamped.endTs) {
6786
7541
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
6787
7542
  if (projected > MAX_TIMESERIES_BUCKETS) {
6788
- return err5(
7543
+ return err7(
6789
7544
  400,
6790
7545
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
6791
7546
  );
@@ -6808,7 +7563,7 @@ async function handleUsageGet(view, query2, deps) {
6808
7563
  };
6809
7564
  }
6810
7565
  default:
6811
- return err5(404, `unknown usage view '${view ?? ""}'`);
7566
+ return err7(404, `unknown usage view '${view ?? ""}'`);
6812
7567
  }
6813
7568
  }
6814
7569
  function poolKeyLabels(cfg) {
@@ -6857,7 +7612,7 @@ async function handlePricingList(deps) {
6857
7612
  async function handlePricingUpsert(body, deps) {
6858
7613
  const input = parsePricingEntryInput(body);
6859
7614
  if (!input) {
6860
- return err5(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)");
6861
7616
  }
6862
7617
  const entry = await deps.pricingEngine.upsertManual(input);
6863
7618
  return { status: 200, body: { entry } };
@@ -6866,7 +7621,7 @@ async function handlePricingDelete(query2, deps) {
6866
7621
  const providerId = query2.get("providerId")?.trim() ?? "";
6867
7622
  const modelId = query2.get("modelId")?.trim() ?? "";
6868
7623
  if (!providerId || !modelId) {
6869
- return err5(400, "delete requires providerId and modelId query params");
7624
+ return err7(400, "delete requires providerId and modelId query params");
6870
7625
  }
6871
7626
  const deleted = await deps.pricingStore.delete(providerId, modelId);
6872
7627
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -6886,13 +7641,13 @@ async function handlePricingFetchLatest(deps) {
6886
7641
  }
6887
7642
  };
6888
7643
  } catch (e) {
6889
- return err5(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)}`);
6890
7645
  }
6891
7646
  }
6892
7647
  async function handlePricingResolveConflicts(body, deps) {
6893
7648
  const raw = body["resolutions"];
6894
7649
  if (!Array.isArray(raw)) {
6895
- return err5(400, "resolve-conflicts requires { resolutions: [...] }");
7650
+ return err7(400, "resolve-conflicts requires { resolutions: [...] }");
6896
7651
  }
6897
7652
  const currentRows = await deps.pricingStore.getAll();
6898
7653
  const userEditedKeys = new Set(
@@ -6902,21 +7657,21 @@ async function handlePricingResolveConflicts(body, deps) {
6902
7657
  const pendingIncoming = /* @__PURE__ */ new Map();
6903
7658
  let staleCount = 0;
6904
7659
  for (const item of raw) {
6905
- if (!item || typeof item !== "object") return err5(400, "invalid resolution entry");
7660
+ if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
6906
7661
  const r = item;
6907
7662
  const action = r["action"];
6908
7663
  if (action !== "overwrite" && action !== "skip") {
6909
- return err5(400, "resolution action must be 'overwrite' or 'skip'");
7664
+ return err7(400, "resolution action must be 'overwrite' or 'skip'");
6910
7665
  }
6911
7666
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
6912
7667
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
6913
7668
  if (!providerId || !modelId) {
6914
- return err5(400, "each resolution requires top-level providerId and modelId");
7669
+ return err7(400, "each resolution requires top-level providerId and modelId");
6915
7670
  }
6916
7671
  const incoming = parsePricingEntryInput(r["incoming"]);
6917
- if (!incoming) return err5(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");
6918
7673
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
6919
- return err5(400, "resolution providerId/modelId must match the echoed incoming entry");
7674
+ return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
6920
7675
  }
6921
7676
  const key = `${providerId}::${modelId}`;
6922
7677
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -6961,7 +7716,7 @@ function query(req) {
6961
7716
  }
6962
7717
  function allowanceProvider(value) {
6963
7718
  if (!value) return void 0;
6964
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
7719
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" ? value : null;
6965
7720
  }
6966
7721
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
6967
7722
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -6976,7 +7731,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6976
7731
  const pathProvider = rest.length >= 2 ? rest[0] : null;
6977
7732
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
6978
7733
  if (providerId === null) {
6979
- return writeError2(res, 400, "providerId must be claude, codex, kimi, or opencodego");
7734
+ return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, or copilot");
6980
7735
  }
6981
7736
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
6982
7737
  const allowances = await service.list({ providerId, accountId });
@@ -7018,6 +7773,26 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
7018
7773
  }
7019
7774
  return writeJson3(res, 200, { allowances: allowances2 });
7020
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
+ }
7021
7796
  const allowances = await service.refreshClaude(accountId);
7022
7797
  if (accountId && allowances.length === 0) {
7023
7798
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
@@ -7116,6 +7891,9 @@ function toProviderView(row) {
7116
7891
  apiVersion: row.apiVersion,
7117
7892
  maxConcurrency: row.maxConcurrency,
7118
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,
7119
7897
  // app-parity child 5: transformer config round-trips VERBATIM (non-secret —
7120
7898
  // transform-rule names + options, no key material; absent stays absent).
7121
7899
  transformer: row.transformer,
@@ -7185,8 +7963,8 @@ async function handleAdminApi(req, res, path2, deps) {
7185
7963
  default:
7186
7964
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
7187
7965
  }
7188
- } catch (err6) {
7189
- writeJsonError(res, 500, err6 instanceof Error ? err6.message : String(err6));
7966
+ } catch (err8) {
7967
+ writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
7190
7968
  }
7191
7969
  }
7192
7970
  function requestQuery(req) {
@@ -7344,6 +8122,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
7344
8122
  persistProviders(cfg, deps);
7345
8123
  return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
7346
8124
  }
8125
+ function expandRowExtraHeaders(row) {
8126
+ return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
8127
+ }
7347
8128
  async function handleDiscoverModels(res, id, cfg) {
7348
8129
  if (!id) return writeJsonError(res, 400, "provider id required in path");
7349
8130
  const row = cfg.providers.find((p) => p.id === id);
@@ -7357,7 +8138,8 @@ async function handleDiscoverModels(res, id, cfg) {
7357
8138
  try {
7358
8139
  const headers = { Accept: "application/json" };
7359
8140
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
7360
- const response = await (0, import_upstreamFetch7.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" });
7361
8143
  if (!response.ok) {
7362
8144
  const text = await response.text().catch(() => "");
7363
8145
  let message = text.slice(0, 300);
@@ -7374,8 +8156,8 @@ async function handleDiscoverModels(res, id, cfg) {
7374
8156
  const data = await response.json();
7375
8157
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
7376
8158
  return writeJson4(res, 200, { models });
7377
- } catch (err6) {
7378
- const message = err6 instanceof Error ? err6.message : String(err6);
8159
+ } catch (err8) {
8160
+ const message = err8 instanceof Error ? err8.message : String(err8);
7379
8161
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
7380
8162
  }
7381
8163
  }
@@ -7414,9 +8196,10 @@ async function handleTestModel(req, res, id, cfg) {
7414
8196
  messages: [{ role: "user", content: prompt }]
7415
8197
  };
7416
8198
  }
8199
+ Object.assign(headers, expandRowExtraHeaders(row));
7417
8200
  const startedAt = Date.now();
7418
8201
  try {
7419
- const response = await (0, import_upstreamFetch7.fetchUpstream)(
8202
+ const response = await (0, import_upstreamFetch9.fetchUpstream)(
7420
8203
  url,
7421
8204
  { method: "POST", headers, body: JSON.stringify(payload) },
7422
8205
  { providerId: "byo" }
@@ -7438,8 +8221,8 @@ async function handleTestModel(req, res, id, cfg) {
7438
8221
  latencyMs,
7439
8222
  sample: extractSampleText(text, row.apiFormat)
7440
8223
  });
7441
- } catch (err6) {
7442
- const message = err6 instanceof Error ? err6.message : String(err6);
8224
+ } catch (err8) {
8225
+ const message = err8 instanceof Error ? err8.message : String(err8);
7443
8226
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
7444
8227
  }
7445
8228
  }
@@ -7721,6 +8504,7 @@ function parseProviderInput(body, existing) {
7721
8504
  const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
7722
8505
  const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
7723
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"]);
7724
8508
  const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
7725
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;
7726
8510
  const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
@@ -7746,6 +8530,7 @@ function parseProviderInput(body, existing) {
7746
8530
  apiVersion,
7747
8531
  maxConcurrency,
7748
8532
  modelsEndpoint,
8533
+ extraHeaders,
7749
8534
  transformer: migrated.transformer,
7750
8535
  codingPlan,
7751
8536
  apiModes,
@@ -7767,7 +8552,10 @@ function handlePresets(res, method) {
7767
8552
  description: p.description,
7768
8553
  features: p.features,
7769
8554
  website: p.website,
7770
- 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
7771
8559
  }));
7772
8560
  return writeJson4(res, 200, { presets, excluded });
7773
8561
  }
@@ -8249,12 +9037,12 @@ async function handleAccounts(req, res, method, rest, deps) {
8249
9037
  }
8250
9038
  return writeJson4(res, 200, { ok: true, affected: result.affected });
8251
9039
  }
8252
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[3] === "status") {
8253
- const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : handleKimiOAuthStatus(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);
8254
9042
  return writeJson4(res, result.status, result.body);
8255
9043
  }
8256
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[2]) {
8257
- const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : handleKimiOAuthCancel(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);
8258
9046
  return writeJson4(res, result.status, result.body);
8259
9047
  }
8260
9048
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -8315,6 +9103,15 @@ async function handleAccounts(req, res, method, rest, deps) {
8315
9103
  const result2 = await handleKimiOAuthStart(deps);
8316
9104
  return writeJson4(res, result2.status, result2.body);
8317
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
+ }
8318
9115
  const result = handleOAuthStart(providerId, deps);
8319
9116
  return writeJson4(res, result.status, result.body);
8320
9117
  }
@@ -8809,12 +9606,12 @@ async function handlePlayground(req, res, method, deps) {
8809
9606
  const payload = body["body"];
8810
9607
  const status = deps.outboundApiServer.getStatus();
8811
9608
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
8812
- const path2 = resolvePlaygroundPath(endpoint, isRecord4(payload) ? payload : {});
9609
+ const path2 = resolvePlaygroundPath(endpoint, isRecord6(payload) ? payload : {});
8813
9610
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
8814
9611
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
8815
9612
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
8816
9613
  }
8817
- function isRecord4(v) {
9614
+ function isRecord6(v) {
8818
9615
  return !!v && typeof v === "object" && !Array.isArray(v);
8819
9616
  }
8820
9617
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -8843,8 +9640,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
8843
9640
  });
8844
9641
  }
8845
9642
  );
8846
- upstream.on("error", (err6) => {
8847
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err6.message}`);
9643
+ upstream.on("error", (err8) => {
9644
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
8848
9645
  else res.end();
8849
9646
  resolve11();
8850
9647
  });
@@ -8950,7 +9747,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
8950
9747
  }
8951
9748
 
8952
9749
  // src/admin/version.ts
8953
- var DAEMON_VERSION = true ? "0.3.1" : "0.0.0-dev";
9750
+ var DAEMON_VERSION = true ? "0.4.0" : "0.0.0-dev";
8954
9751
 
8955
9752
  // src/admin/AdminServer.ts
8956
9753
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -8993,13 +9790,13 @@ var AdminServer = class {
8993
9790
  const server = import_node_http2.default.createServer((req, res) => {
8994
9791
  this.onRequest(req, res);
8995
9792
  });
8996
- const onError = (err6) => {
8997
- if (err6.code === "EADDRINUSE" && port !== 0) {
9793
+ const onError = (err8) => {
9794
+ if (err8.code === "EADDRINUSE" && port !== 0) {
8998
9795
  server.removeListener("error", onError);
8999
9796
  this.listen(bindAddr, 0).then(resolve11, reject);
9000
9797
  return;
9001
9798
  }
9002
- reject(err6);
9799
+ reject(err8);
9003
9800
  };
9004
9801
  server.on("error", onError);
9005
9802
  server.listen(port, bindAddr, () => {
@@ -9017,8 +9814,8 @@ var AdminServer = class {
9017
9814
  }
9018
9815
  /** Per-request handler: auth gate (when a token is set) → routing. */
9019
9816
  onRequest(req, res) {
9020
- void this.dispatch(req, res).catch((err6) => {
9021
- const message = err6 instanceof Error ? err6.message : String(err6);
9817
+ void this.dispatch(req, res).catch((err8) => {
9818
+ const message = err8 instanceof Error ? err8.message : String(err8);
9022
9819
  this.deps.logger.error("[AdminServer] unhandled error:", message);
9023
9820
  if (!res.headersSent) {
9024
9821
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -9282,18 +10079,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
9282
10079
  return;
9283
10080
  }
9284
10081
  signal?.addEventListener("abort", abort, { once: true });
9285
- server.on("error", (err6) => {
10082
+ server.on("error", (err8) => {
9286
10083
  if (settled) return;
9287
10084
  settled = true;
9288
10085
  clearTimeout(timer);
9289
- if (err6.code === "EADDRINUSE") {
10086
+ if (err8.code === "EADDRINUSE") {
9290
10087
  reject(
9291
10088
  new Error(
9292
10089
  `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
9293
10090
  )
9294
10091
  );
9295
10092
  } else {
9296
- reject(err6);
10093
+ reject(err8);
9297
10094
  }
9298
10095
  });
9299
10096
  const timer = setTimeout(() => {
@@ -9369,21 +10166,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
9369
10166
  }
9370
10167
 
9371
10168
  // src/allowance/ProviderKeyQuotaService.ts
9372
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
10169
+ var import_core4 = require("@omnicross/core");
10170
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
9373
10171
 
9374
10172
  // src/allowance/ProviderKeyQuota.ts
9375
- var MINUTE_MS2 = 6e4;
9376
- var HOUR_MS2 = 60 * MINUTE_MS2;
9377
- var DAY_MS2 = 24 * HOUR_MS2;
9378
- var WEEK_MS = 7 * DAY_MS2;
9379
- var MONTH_MS = 30 * DAY_MS2;
9380
- function finiteNumber3(value) {
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) {
9381
10179
  if (value === null || value === void 0 || value === "") return void 0;
9382
10180
  const parsed = typeof value === "number" ? value : Number(value);
9383
10181
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
9384
10182
  }
9385
10183
  function finitePercent4(value) {
9386
- const parsed = finiteNumber3(value);
10184
+ const parsed = finiteNumber5(value);
9387
10185
  return parsed !== void 0 && parsed <= 100 ? parsed : null;
9388
10186
  }
9389
10187
  function isoInstant3(value) {
@@ -9391,18 +10189,18 @@ function isoInstant3(value) {
9391
10189
  const time = Date.parse(value);
9392
10190
  if (Number.isFinite(time)) return new Date(time).toISOString();
9393
10191
  }
9394
- const numeric = finiteNumber3(value);
10192
+ const numeric = finiteNumber5(value);
9395
10193
  if (numeric !== void 0 && numeric > 1e9) {
9396
10194
  const ms = numeric > 1e12 ? numeric : numeric * 1e3;
9397
10195
  return new Date(ms).toISOString();
9398
10196
  }
9399
10197
  return void 0;
9400
10198
  }
9401
- function secondsUntil5(instant, now) {
10199
+ function secondsUntil7(instant, now) {
9402
10200
  if (!instant) return void 0;
9403
10201
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
9404
10202
  }
9405
- function isRecord5(value) {
10203
+ function isRecord7(value) {
9406
10204
  return !!value && typeof value === "object" && !Array.isArray(value);
9407
10205
  }
9408
10206
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -9425,6 +10223,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
9425
10223
  }
9426
10224
  if (host === "api.code.umans.ai") return "umans";
9427
10225
  if (host === "api.synthetic.new") return "synthetic";
10226
+ if (host === "api.cline.bot") return "cline-pass";
9428
10227
  return null;
9429
10228
  }
9430
10229
  function providerKeyQuotaUrl(adapter, baseUrl) {
@@ -9432,6 +10231,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
9432
10231
  if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
9433
10232
  if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
9434
10233
  if (adapter === "umans") return `${origin}/v1/usage`;
10234
+ if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
9435
10235
  return `${origin}/v2/quotas`;
9436
10236
  }
9437
10237
  function providerKeyQuotaAuthHeader(adapter, key) {
@@ -9443,7 +10243,7 @@ function zaiWindowDurationMs(item) {
9443
10243
  case 3:
9444
10244
  return count * HOUR_MS2;
9445
10245
  case 4:
9446
- return count * DAY_MS2;
10246
+ return count * DAY_MS3;
9447
10247
  case 5:
9448
10248
  return count * MONTH_MS;
9449
10249
  case 6:
@@ -9456,8 +10256,8 @@ function zaiWindowIdLabel(durationMs) {
9456
10256
  if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
9457
10257
  if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
9458
10258
  if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
9459
- if (durationMs !== void 0 && durationMs % DAY_MS2 === 0) {
9460
- const days = durationMs / DAY_MS2;
10259
+ if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
10260
+ const days = durationMs / DAY_MS3;
9461
10261
  return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
9462
10262
  }
9463
10263
  if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
@@ -9467,23 +10267,23 @@ function zaiWindowIdLabel(durationMs) {
9467
10267
  return { id: "quota", label: "Quota" };
9468
10268
  }
9469
10269
  function parseZaiQuotaPayload(payload, now) {
9470
- if (!isRecord5(payload)) return null;
9471
- const data = isRecord5(payload["data"]) ? payload["data"] : payload;
10270
+ if (!isRecord7(payload)) return null;
10271
+ const data = isRecord7(payload["data"]) ? payload["data"] : payload;
9472
10272
  if (payload["success"] === false) return null;
9473
10273
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9474
10274
  const byWindow = /* @__PURE__ */ new Map();
9475
10275
  for (const raw of limits) {
9476
- if (!isRecord5(raw)) continue;
10276
+ if (!isRecord7(raw)) continue;
9477
10277
  const item = raw;
9478
10278
  if (item.type === void 0) continue;
9479
10279
  const details = raw["usageDetails"];
9480
- if (Array.isArray(details) && details.some((d) => isRecord5(d) && d["modelCode"] === "zread")) {
10280
+ if (Array.isArray(details) && details.some((d) => isRecord7(d) && d["modelCode"] === "zread")) {
9481
10281
  continue;
9482
10282
  }
9483
10283
  const durationMs = zaiWindowDurationMs(item);
9484
10284
  const { id, label } = zaiWindowIdLabel(durationMs);
9485
- const limit = finiteNumber3(item.usage);
9486
- const used = finiteNumber3(item.currentValue);
10285
+ const limit = finiteNumber5(item.usage);
10286
+ const used = finiteNumber5(item.currentValue);
9487
10287
  const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
9488
10288
  const fromPercentage = finitePercent4(item.percentage) ?? void 0;
9489
10289
  const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
@@ -9494,9 +10294,9 @@ function parseZaiQuotaPayload(payload, now) {
9494
10294
  label,
9495
10295
  scope: "all",
9496
10296
  usedPercent,
9497
- ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS2) } : {},
10297
+ ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
9498
10298
  ...resetsAt !== void 0 ? { resetsAt } : {},
9499
- remainingSeconds: secondsUntil5(resetsAt, now),
10299
+ remainingSeconds: secondsUntil7(resetsAt, now),
9500
10300
  state: "fresh"
9501
10301
  };
9502
10302
  const existing = byWindow.get(id);
@@ -9510,21 +10310,21 @@ function parseZaiQuotaPayload(payload, now) {
9510
10310
  var MINIMAX_STATUS_EXHAUSTED = 2;
9511
10311
  var MINIMAX_SHARED_BUCKET = "general";
9512
10312
  function parseMiniMaxBucket(value) {
9513
- if (!isRecord5(value)) return null;
10313
+ if (!isRecord7(value)) return null;
9514
10314
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
9515
10315
  if (!modelName) return null;
9516
10316
  const instant = (v) => {
9517
- const n = finiteNumber3(v);
10317
+ const n = finiteNumber5(v);
9518
10318
  return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
9519
10319
  };
9520
10320
  return {
9521
10321
  modelName,
9522
10322
  intervalEnd: instant(value["end_time"]),
9523
- intervalRemainingPercent: finiteNumber3(value["current_interval_remaining_percent"]),
9524
- intervalStatus: finiteNumber3(value["current_interval_status"]),
10323
+ intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
10324
+ intervalStatus: finiteNumber5(value["current_interval_status"]),
9525
10325
  weeklyEnd: instant(value["weekly_end_time"]),
9526
- weeklyRemainingPercent: finiteNumber3(value["current_weekly_remaining_percent"]),
9527
- weeklyStatus: finiteNumber3(value["current_weekly_status"])
10326
+ weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
10327
+ weeklyStatus: finiteNumber5(value["current_weekly_status"])
9528
10328
  };
9529
10329
  }
9530
10330
  function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
@@ -9537,14 +10337,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
9537
10337
  usedPercent,
9538
10338
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
9539
10339
  ...resetsAt !== void 0 ? { resetsAt } : {},
9540
- remainingSeconds: secondsUntil5(resetsAt, now),
10340
+ remainingSeconds: secondsUntil7(resetsAt, now),
9541
10341
  state: usedPercent !== null ? "fresh" : "unavailable"
9542
10342
  };
9543
10343
  }
9544
10344
  function parseMiniMaxTokenPlanPayload(payload, now) {
9545
- if (!isRecord5(payload)) return null;
10345
+ if (!isRecord7(payload)) return null;
9546
10346
  const baseResp = payload["base_resp"];
9547
- if (!isRecord5(baseResp) || baseResp["status_code"] !== 0) return null;
10347
+ if (!isRecord7(baseResp) || baseResp["status_code"] !== 0) return null;
9548
10348
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
9549
10349
  let general = null;
9550
10350
  for (const raw of buckets) {
@@ -9568,7 +10368,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
9568
10368
  minimaxWindow(
9569
10369
  "seven-day",
9570
10370
  "7 days",
9571
- Math.round(WEEK_MS / MINUTE_MS2),
10371
+ Math.round(WEEK_MS / MINUTE_MS3),
9572
10372
  general.weeklyEnd,
9573
10373
  general.weeklyRemainingPercent,
9574
10374
  general.weeklyStatus,
@@ -9577,15 +10377,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
9577
10377
  ];
9578
10378
  }
9579
10379
  function parseUmansUsagePayload(payload, now) {
9580
- if (!isRecord5(payload)) return null;
9581
- const limits = isRecord5(payload["limits"]) ? payload["limits"] : void 0;
9582
- const requests = limits && isRecord5(limits["requests"]) ? limits["requests"] : void 0;
9583
- const usage = isRecord5(payload["usage"]) ? payload["usage"] : void 0;
9584
- const window = isRecord5(payload["window"]) ? payload["window"] : void 0;
9585
- const hardCap = finiteNumber3(requests?.["hard_cap"]);
9586
- const softLimit = finiteNumber3(requests?.["limit"]);
9587
- const requestsInWindow = finiteNumber3(usage?.["requests_in_window"]);
9588
- const weightedInWindow = finiteNumber3(usage?.["weighted_in_window"]);
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"]);
9589
10389
  const resetsAt = isoInstant3(window?.["resets_at"]);
9590
10390
  let usedPercent = null;
9591
10391
  if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
@@ -9602,19 +10402,19 @@ function parseUmansUsagePayload(payload, now) {
9602
10402
  usedPercent,
9603
10403
  windowMinutes: 5 * 60,
9604
10404
  ...resetsAt !== void 0 ? { resetsAt } : {},
9605
- remainingSeconds: secondsUntil5(resetsAt, now),
10405
+ remainingSeconds: secondsUntil7(resetsAt, now),
9606
10406
  state: "fresh"
9607
10407
  }
9608
10408
  ];
9609
10409
  }
9610
10410
  function parseSyntheticQuotasPayload(payload, now) {
9611
- if (!isRecord5(payload)) return null;
9612
- const fiveHour = isRecord5(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
9613
- const weekly = isRecord5(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
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;
9614
10414
  const windows = [];
9615
10415
  if (fiveHour) {
9616
- const max = finiteNumber3(fiveHour["max"]);
9617
- const remaining = finiteNumber3(fiveHour["remaining"]);
10416
+ const max = finiteNumber5(fiveHour["max"]);
10417
+ const remaining = finiteNumber5(fiveHour["remaining"]);
9618
10418
  const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
9619
10419
  const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
9620
10420
  windows.push({
@@ -9624,12 +10424,12 @@ function parseSyntheticQuotasPayload(payload, now) {
9624
10424
  usedPercent,
9625
10425
  windowMinutes: 5 * 60,
9626
10426
  ...resetsAt !== void 0 ? { resetsAt } : {},
9627
- remainingSeconds: secondsUntil5(resetsAt, now),
10427
+ remainingSeconds: secondsUntil7(resetsAt, now),
9628
10428
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9629
10429
  });
9630
10430
  }
9631
10431
  if (weekly) {
9632
- const percentRemaining = finiteNumber3(weekly["percentRemaining"]);
10432
+ const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
9633
10433
  const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
9634
10434
  const resetsAt = isoInstant3(weekly["nextRegenAt"]);
9635
10435
  windows.push({
@@ -9639,12 +10439,42 @@ function parseSyntheticQuotasPayload(payload, now) {
9639
10439
  usedPercent,
9640
10440
  windowMinutes: 7 * 24 * 60,
9641
10441
  ...resetsAt !== void 0 ? { resetsAt } : {},
9642
- remainingSeconds: secondsUntil5(resetsAt, now),
10442
+ remainingSeconds: secondsUntil7(resetsAt, now),
9643
10443
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9644
10444
  });
9645
10445
  }
9646
10446
  return windows.length > 0 ? windows : null;
9647
10447
  }
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;
10477
+ }
9648
10478
 
9649
10479
  // src/allowance/ProviderKeyQuotaService.ts
9650
10480
  function parseQuotaPayload(adapter, payload, now) {
@@ -9657,6 +10487,8 @@ function parseQuotaPayload(adapter, payload, now) {
9657
10487
  return parseUmansUsagePayload(payload, now);
9658
10488
  case "synthetic":
9659
10489
  return parseSyntheticQuotasPayload(payload, now);
10490
+ case "cline-pass":
10491
+ return parseClinePassUsageLimitsPayload(payload, now);
9660
10492
  }
9661
10493
  }
9662
10494
  var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
@@ -9676,7 +10508,7 @@ function rowKeyEntries(row) {
9676
10508
  return [];
9677
10509
  }
9678
10510
  var ProviderKeyQuotaService = class {
9679
- constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
10511
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
9680
10512
  this.box = box;
9681
10513
  this.fetchImpl = fetchImpl;
9682
10514
  this.now = now;
@@ -9738,7 +10570,10 @@ var ProviderKeyQuotaService = class {
9738
10570
  headers: {
9739
10571
  Authorization: providerKeyQuotaAuthHeader(adapter, key),
9740
10572
  Accept: "application/json",
9741
- "Content-Type": "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)
9742
10577
  },
9743
10578
  signal: AbortSignal.timeout(15e3)
9744
10579
  });
@@ -9776,7 +10611,7 @@ var ProviderKeyQuotaService = class {
9776
10611
  // src/image-generation/ImageDoctorService.ts
9777
10612
  var import_image_generation = require("@omnicross/core/image-generation");
9778
10613
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
9779
- var import_subscriptions6 = require("@omnicross/subscriptions");
10614
+ var import_subscriptions9 = require("@omnicross/subscriptions");
9780
10615
 
9781
10616
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
9782
10617
  var import_node_crypto13 = require("crypto");
@@ -10214,7 +11049,7 @@ function createImageDoctorService(options) {
10214
11049
  paths,
10215
11050
  ttlMs: config.evidenceTtlMs
10216
11051
  }));
10217
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions6.createCodexImageLiveVerifier)({
11052
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
10218
11053
  authStrategy: strategy,
10219
11054
  generationTimeoutMs: config.queue.generationTimeoutMs
10220
11055
  }));
@@ -10576,7 +11411,7 @@ var ImageCleanupService = class {
10576
11411
  var import_node_crypto16 = require("crypto");
10577
11412
  var import_image_generation5 = require("@omnicross/core/image-generation");
10578
11413
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
10579
- var import_subscriptions7 = require("@omnicross/subscriptions");
11414
+ var import_subscriptions10 = require("@omnicross/subscriptions");
10580
11415
 
10581
11416
  // src/image-generation/ImageApiRuntimeResolver.ts
10582
11417
  var import_node_crypto14 = require("crypto");
@@ -11107,7 +11942,7 @@ function createImageRuntimeGeneration(options) {
11107
11942
  now: options.now ?? Date.now,
11108
11943
  referenceStore: options.storage.referenceStore,
11109
11944
  stateStore: options.storage.stateStore
11110
- }) : (0, import_subscriptions7.createCodexSubscriptionImageProvider)({
11945
+ }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
11111
11946
  authStrategy,
11112
11947
  evidenceSource: generationEvidenceSource,
11113
11948
  executionScheduler: scheduler,
@@ -14251,7 +15086,7 @@ var ImageRuntimeManager = class {
14251
15086
  };
14252
15087
 
14253
15088
  // src/ports/ConfigFileProviderConfigSource.ts
14254
- var import_core2 = require("@omnicross/core");
15089
+ var import_core5 = require("@omnicross/core");
14255
15090
  var EMPTY_CHAIN = {
14256
15091
  providerTransformers: [],
14257
15092
  modelTransformers: []
@@ -14276,8 +15111,8 @@ var ConfigFileProviderConfigSource = class {
14276
15111
  reloadHook;
14277
15112
  constructor(config) {
14278
15113
  for (const p of config.providers) this.providers.set(p.id, p);
14279
- this.transformerService = new import_core2.TransformerService();
14280
- void (0, import_core2.registerBuiltinTransformers)(this.transformerService);
15114
+ this.transformerService = new import_core5.TransformerService();
15115
+ void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
14281
15116
  }
14282
15117
  // ── Reload hook (key-pool design D4) ───────────────────────────────────────
14283
15118
  /**
@@ -14298,7 +15133,7 @@ var ConfigFileProviderConfigSource = class {
14298
15133
  }
14299
15134
  /** Await the built-in transformer registration (tests await this before dispatch). */
14300
15135
  async ready() {
14301
- await (0, import_core2.registerBuiltinTransformers)(this.transformerService);
15136
+ await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
14302
15137
  }
14303
15138
  // ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
14304
15139
  /**
@@ -14409,6 +15244,10 @@ function toLLMProvider(row) {
14409
15244
  // `parseProviderInput`), so customizations are preserved (the row value wins).
14410
15245
  apiModes: row.apiModes,
14411
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,
14412
15251
  // Official-Anthropic signature handling only matters for the Anthropic
14413
15252
  // ingress (deferred → 502); leave it off for the BYO transform path.
14414
15253
  isOfficial: false
@@ -15774,7 +16613,7 @@ function bucketLabel(bucketStartTs, bucket) {
15774
16613
 
15775
16614
  // src/ports/JsonOutboundKeyDb.ts
15776
16615
  var import_node_fs23 = require("fs");
15777
- var import_core3 = require("@omnicross/core");
16616
+ var import_core6 = require("@omnicross/core");
15778
16617
 
15779
16618
  // src/ports/atomicFile.ts
15780
16619
  var import_node_crypto22 = require("crypto");
@@ -15896,7 +16735,7 @@ var JsonOutboundKeyDb = class {
15896
16735
  });
15897
16736
  }
15898
16737
  async outboundApiKeysSetPermissions(id, permissions) {
15899
- const exact = (0, import_core3.validateOutboundPermissions)(permissions);
16738
+ const exact = (0, import_core6.validateOutboundPermissions)(permissions);
15900
16739
  return this.mutateRow(id, (row) => {
15901
16740
  if (row.revokedAt !== null) return false;
15902
16741
  row.allowedEndpoints = [...exact];
@@ -16333,9 +17172,9 @@ var import_node_fs28 = require("fs");
16333
17172
  var import_node_path27 = require("path");
16334
17173
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
16335
17174
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
16336
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
17175
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
16337
17176
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
16338
- var import_subscriptions8 = require("@omnicross/subscriptions");
17177
+ var import_subscriptions11 = require("@omnicross/subscriptions");
16339
17178
 
16340
17179
  // src/ports/account-sync.ts
16341
17180
  function viewOf(tokens) {
@@ -16483,7 +17322,7 @@ var JsonSubscriptionCredentialStore = class {
16483
17322
  * a plaintext token pair into `upstream-trace.jsonl`.
16484
17323
  */
16485
17324
  buildRefreshFetch(providerId, accountId) {
16486
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
17325
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
16487
17326
  }
16488
17327
  /**
16489
17328
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -16524,7 +17363,7 @@ var JsonSubscriptionCredentialStore = class {
16524
17363
  * other hot reads. Never returns token material.
16525
17364
  */
16526
17365
  getAccountProxy(providerId, accountId) {
16527
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
17366
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
16528
17367
  return void 0;
16529
17368
  }
16530
17369
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -16543,7 +17382,7 @@ var JsonSubscriptionCredentialStore = class {
16543
17382
  const fingerprintOn = identityStore.isEnabled();
16544
17383
  const now = Date.now();
16545
17384
  const out = {};
16546
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
17385
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
16547
17386
  const sanitized = sanitizeAccounts(config, provider);
16548
17387
  if (sanitized.length === 0) continue;
16549
17388
  for (const account of sanitized) {
@@ -16609,7 +17448,7 @@ var JsonSubscriptionCredentialStore = class {
16609
17448
  this.materializeMigration(config);
16610
17449
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
16611
17450
  try {
16612
- const result = await import_subscriptions8.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
17451
+ const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
16613
17452
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16614
17453
  const next = {
16615
17454
  ...claude,
@@ -16644,7 +17483,7 @@ var JsonSubscriptionCredentialStore = class {
16644
17483
  this.materializeMigration(config);
16645
17484
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
16646
17485
  try {
16647
- const result = await import_subscriptions8.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
17486
+ const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
16648
17487
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16649
17488
  const next = {
16650
17489
  ...codex,
@@ -16682,7 +17521,7 @@ var JsonSubscriptionCredentialStore = class {
16682
17521
  this.materializeMigration(config);
16683
17522
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
16684
17523
  try {
16685
- const result = await import_subscriptions8.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17524
+ const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
16686
17525
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16687
17526
  const next = {
16688
17527
  ...gemini,
@@ -16718,10 +17557,10 @@ var JsonSubscriptionCredentialStore = class {
16718
17557
  this.materializeMigration(config);
16719
17558
  const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
16720
17559
  try {
16721
- const result = await import_subscriptions8.kimiOAuth.refreshAccessToken(
17560
+ const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
16722
17561
  kimi.refreshToken,
16723
17562
  refreshFetch,
16724
- import_subscriptions8.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17563
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
16725
17564
  );
16726
17565
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16727
17566
  const next = {
@@ -16742,6 +17581,66 @@ var JsonSubscriptionCredentialStore = class {
16742
17581
  }
16743
17582
  });
16744
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
+ }
16745
17644
  /**
16746
17645
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
16747
17646
  * account-pool resolution). It uses only that account's stored refresh
@@ -16794,7 +17693,7 @@ var JsonSubscriptionCredentialStore = class {
16794
17693
  }
16795
17694
  const oauth = account.tokens;
16796
17695
  if (!oauth.accessToken) return null;
16797
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
17696
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
16798
17697
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
16799
17698
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
16800
17699
  if (expiringSoon && oauth.refreshToken) {
@@ -16887,10 +17786,10 @@ var JsonSubscriptionCredentialStore = class {
16887
17786
  if (provider === "kimi") {
16888
17787
  const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
16889
17788
  const deviceId = account?.tokens?.deviceId;
16890
- const r2 = await import_subscriptions8.kimiOAuth.refreshAccessToken(
17789
+ const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
16891
17790
  refreshToken,
16892
17791
  refreshFetch,
16893
- import_subscriptions8.kimiOAuth.kimiFingerprintHeaders(deviceId)
17792
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
16894
17793
  );
16895
17794
  return {
16896
17795
  accessToken: r2.accessToken,
@@ -16898,7 +17797,19 @@ var JsonSubscriptionCredentialStore = class {
16898
17797
  expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
16899
17798
  };
16900
17799
  }
16901
- const flow = provider === "claude" ? import_subscriptions8.claudeOAuth : provider === "codex" ? import_subscriptions8.codexOAuth : import_subscriptions8.geminiOAuth;
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;
16902
17813
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
16903
17814
  return {
16904
17815
  accessToken: r.accessToken,
@@ -17141,7 +18052,7 @@ var JsonSubscriptionCredentialStore = class {
17141
18052
  };
17142
18053
 
17143
18054
  // src/AccountHealthProbeScheduler.ts
17144
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
18055
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
17145
18056
 
17146
18057
  // src/probe/CodexGenerationProbe.ts
17147
18058
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -17284,7 +18195,16 @@ var PROVIDER_PROBE_PLANS = {
17284
18195
  // Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
17285
18196
  // collector uses it), but the probe path also needs the fingerprint headers —
17286
18197
  // keep the probe local until the collector covers the health surface.
17287
- kimi: { kind: "local" }
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" }
17288
18208
  };
17289
18209
  function probePlanFor(providerId) {
17290
18210
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -17306,7 +18226,7 @@ var AccountHealthProbeScheduler = class {
17306
18226
  this.logger = logger;
17307
18227
  this.config = config;
17308
18228
  this.now = opts.now ?? Date.now;
17309
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch10.fetchUpstream;
18229
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch12.fetchUpstream;
17310
18230
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
17311
18231
  this.planFor = opts.planFor ?? probePlanFor;
17312
18232
  }
@@ -17856,7 +18776,7 @@ async function readAuditStats(auditDir, query2 = {}) {
17856
18776
  }
17857
18777
 
17858
18778
  // src/audit/AuditPruneSweeper.ts
17859
- var DAY_MS3 = 24 * 60 * 6e4;
18779
+ var DAY_MS4 = 24 * 60 * 6e4;
17860
18780
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
17861
18781
  var ARCHIVE_BATCH = 64;
17862
18782
  var AuditPruneSweeper = class {
@@ -17920,7 +18840,7 @@ var AuditPruneSweeper = class {
17920
18840
  this.sweeping = true;
17921
18841
  try {
17922
18842
  if (!(0, import_node_fs30.existsSync)(this.auditDir)) return 0;
17923
- const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS3;
18843
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
17924
18844
  let removed = 0;
17925
18845
  for (const name of (0, import_node_fs30.readdirSync)(this.auditDir)) {
17926
18846
  const dateMs = auditFileDateMs(name);
@@ -18177,7 +19097,7 @@ async function closeAll(writers) {
18177
19097
  // src/usage/UsagePruneSweeper.ts
18178
19098
  var import_promises8 = require("fs/promises");
18179
19099
  var import_node_path31 = require("path");
18180
- var DAY_MS4 = 24 * 60 * 6e4;
19100
+ var DAY_MS5 = 24 * 60 * 6e4;
18181
19101
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
18182
19102
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
18183
19103
  var UsagePruneSweeper = class {
@@ -18234,7 +19154,7 @@ var UsagePruneSweeper = class {
18234
19154
  this.sweeping = true;
18235
19155
  try {
18236
19156
  const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
18237
- const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS4;
19157
+ const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
18238
19158
  let removed = 0;
18239
19159
  for (const entry of await listUsageDays(this.usageDir)) {
18240
19160
  if (!entry.hasShard) continue;
@@ -18462,7 +19382,7 @@ var AuditWriter = class {
18462
19382
  var import_node_fs34 = require("fs");
18463
19383
  var import_node_crypto24 = require("crypto");
18464
19384
  var import_node_path34 = require("path");
18465
- var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
19385
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
18466
19386
 
18467
19387
  // src/billing/billingFiles.ts
18468
19388
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -18485,7 +19405,7 @@ var BillingPublisher = class {
18485
19405
  constructor(billingDir, logger, opts = {}) {
18486
19406
  this.billingDir = billingDir;
18487
19407
  this.logger = logger;
18488
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init));
19408
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init));
18489
19409
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
18490
19410
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
18491
19411
  this.now = opts.now ?? Date.now;
@@ -18735,7 +19655,7 @@ var BillingRetrySweeper = class {
18735
19655
  // src/TokenRefreshScheduler.ts
18736
19656
  var REFRESH_LEAD_MS2 = 5 * 6e4;
18737
19657
  var SWEEP_INTERVAL_MS5 = 6e4;
18738
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
19658
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
18739
19659
  var TokenRefreshScheduler = class {
18740
19660
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
18741
19661
  this.store = store;
@@ -18820,6 +19740,12 @@ var TokenRefreshScheduler = class {
18820
19740
  return this.store.refreshGeminiToken();
18821
19741
  case "kimi":
18822
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();
18823
19749
  }
18824
19750
  }
18825
19751
  };
@@ -18896,7 +19822,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
18896
19822
 
18897
19823
  // src/webhook/WebhookDispatcher.ts
18898
19824
  var import_node_crypto25 = require("crypto");
18899
- var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
19825
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
18900
19826
  var WEBHOOK_MAX_ATTEMPTS = 3;
18901
19827
  var WEBHOOK_QUEUE_MAX = 1e3;
18902
19828
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -18916,7 +19842,7 @@ var WebhookDispatcher = class {
18916
19842
  sleep;
18917
19843
  now;
18918
19844
  constructor(opts = {}) {
18919
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init));
19845
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
18920
19846
  this.logger = opts.logger;
18921
19847
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
18922
19848
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -19002,8 +19928,8 @@ var WebhookDispatcher = class {
19002
19928
  signal: AbortSignal.timeout(this.timeoutMs)
19003
19929
  });
19004
19930
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
19005
- } catch (err6) {
19006
- return { ok: false, error: err6 instanceof Error ? err6.message : String(err6) };
19931
+ } catch (err8) {
19932
+ return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
19007
19933
  }
19008
19934
  }
19009
19935
  /**
@@ -19066,7 +19992,7 @@ function feishuText(event) {
19066
19992
  // src/bootstrap.ts
19067
19993
  var activeImageRuntimeBootstrapSession;
19068
19994
  function createImageRuntimeBootstrapSession(initialGeneration) {
19069
- const openAIOperationRegistry = new import_core4.OpenAIOperationRegistry();
19995
+ const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
19070
19996
  const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
19071
19997
  const unregisterContributions = [];
19072
19998
  try {
@@ -19140,12 +20066,12 @@ function buildDaemon(config, paths) {
19140
20066
  setSecretBox(secretBox3);
19141
20067
  setSecretBox2(secretBox3);
19142
20068
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
19143
- const accountAllowanceStore = new import_AccountAllowanceStore7.AccountAllowanceStore(
20069
+ const accountAllowanceStore = new import_AccountAllowanceStore9.AccountAllowanceStore(
19144
20070
  Date.now,
19145
20071
  void 0,
19146
20072
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
19147
20073
  );
19148
- (0, import_AccountAllowanceStore7.setSharedAccountAllowanceStore)(accountAllowanceStore);
20074
+ (0, import_AccountAllowanceStore9.setSharedAccountAllowanceStore)(accountAllowanceStore);
19149
20075
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
19150
20076
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
19151
20077
  );
@@ -19170,15 +20096,15 @@ function buildDaemon(config, paths) {
19170
20096
  claudeAllowanceRefreshScheduler.configure(
19171
20097
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
19172
20098
  );
19173
- const subscriptionAccounts = new import_subscriptions9.SubscriptionAccountService(credentialStore);
19174
- (0, import_subscriptions9.setSubscriptionAccountService)(subscriptionAccounts);
19175
- const subscriptionRegistry = new import_subscriptions9.SubscriptionProviderRegistry(
20099
+ const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
20100
+ (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
20101
+ const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
19176
20102
  subscriptionAccounts,
19177
20103
  credentialStore
19178
20104
  );
19179
- (0, import_subscriptions9.setSubscriptionProviderRegistry)(subscriptionRegistry);
20105
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
19180
20106
  setServerProxyConfig(decryptedConfig.server?.proxy);
19181
- (0, import_upstreamFetch13.setUpstreamProxyResolver)(
20107
+ (0, import_upstreamFetch15.setUpstreamProxyResolver)(
19182
20108
  createUpstreamProxyResolver({
19183
20109
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
19184
20110
  })
@@ -19202,7 +20128,7 @@ function buildDaemon(config, paths) {
19202
20128
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
19203
20129
  // Catalog egress follows the same global/env proxy policy as every other
19204
20130
  // daemon upstream call; no provider/account override applies here.
19205
- fetchImpl: ((input, init) => (0, import_upstreamFetch13.fetchUpstream)(String(input), init ?? {}))
20131
+ fetchImpl: ((input, init) => (0, import_upstreamFetch15.fetchUpstream)(String(input), init ?? {}))
19206
20132
  });
19207
20133
  const pricingRefreshScheduler = new PricingRefreshScheduler(
19208
20134
  pricingEngine,
@@ -19487,7 +20413,7 @@ function buildDaemon(config, paths) {
19487
20413
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
19488
20414
  // excluded from the upstream trace, so a failing login left no evidence.
19489
20415
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
19490
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20416
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init, { providerId, redactBodies: true }),
19491
20417
  subscriptionAccountAppender: credentialStore,
19492
20418
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
19493
20419
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -19499,6 +20425,9 @@ function buildDaemon(config, paths) {
19499
20425
  // paste; the app shows the verification URL + user code and polls the
19500
20426
  // token-free status). Token captured + persisted daemon-side.
19501
20427
  kimiSessions: new CodexOAuthSessionStore(),
20428
+ // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20429
+ grokSessions: new CodexOAuthSessionStore(),
20430
+ copilotSessions: new CodexOAuthSessionStore(),
19502
20431
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
19503
20432
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
19504
20433
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -19557,7 +20486,7 @@ function buildDaemon(config, paths) {
19557
20486
  });
19558
20487
  const webhookDispatcher = new WebhookDispatcher({
19559
20488
  logger,
19560
- fetchImpl: (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init)
20489
+ fetchImpl: (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init)
19561
20490
  });
19562
20491
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
19563
20492
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -19871,11 +20800,11 @@ async function runLiveProbe(url, key, fetchImpl = fetch) {
19871
20800
  status: res.status,
19872
20801
  estimateHeader: res.headers.get("x-omnicross-count-estimate")
19873
20802
  };
19874
- } catch (err6) {
20803
+ } catch (err8) {
19875
20804
  return {
19876
20805
  status: null,
19877
20806
  estimateHeader: null,
19878
- error: err6 instanceof Error ? err6.message : String(err6)
20807
+ error: err8 instanceof Error ? err8.message : String(err8)
19879
20808
  };
19880
20809
  }
19881
20810
  }
@@ -20282,9 +21211,9 @@ async function runLaunch(argv, deps) {
20282
21211
  await daemon.llmConfig.ready();
20283
21212
  await daemon.migrateUsageStore();
20284
21213
  await daemon.providerProxy.start();
20285
- } catch (err6) {
21214
+ } catch (err8) {
20286
21215
  await shutdownLaunchDaemon(daemon);
20287
- throw err6;
21216
+ throw err8;
20288
21217
  }
20289
21218
  let launch;
20290
21219
  try {
@@ -20292,9 +21221,9 @@ async function runLaunch(argv, deps) {
20292
21221
  providerId: values.provider,
20293
21222
  model: values.model
20294
21223
  });
20295
- } catch (err6) {
21224
+ } catch (err8) {
20296
21225
  await shutdownLaunchDaemon(daemon);
20297
- throw err6;
21226
+ throw err8;
20298
21227
  }
20299
21228
  try {
20300
21229
  const plan = buildCliSpawnPlan({
@@ -20399,9 +21328,9 @@ function spawnCliInherit(plan) {
20399
21328
  process.removeListener("SIGINT", onSignal);
20400
21329
  process.removeListener("SIGTERM", onSignal);
20401
21330
  };
20402
- child.on("error", (err6) => {
21331
+ child.on("error", (err8) => {
20403
21332
  detach();
20404
- if (err6.code === "ENOENT") {
21333
+ if (err8.code === "ENOENT") {
20405
21334
  reject(
20406
21335
  new Error(
20407
21336
  `launch: "${plan.command}" not found on PATH \u2014 install the CLI first.`
@@ -20409,7 +21338,7 @@ function spawnCliInherit(plan) {
20409
21338
  );
20410
21339
  return;
20411
21340
  }
20412
- reject(err6);
21341
+ reject(err8);
20413
21342
  });
20414
21343
  child.on("exit", (code, signal) => {
20415
21344
  detach();
@@ -20422,9 +21351,9 @@ function spawnCliInherit(plan) {
20422
21351
  var import_node_child_process3 = require("child_process");
20423
21352
  var import_node_readline2 = require("readline");
20424
21353
  var import_node_util7 = require("util");
20425
- var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
20426
- var import_subscriptions10 = require("@omnicross/subscriptions");
20427
- var PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
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"];
20428
21357
  async function runLogin(argv, deps) {
20429
21358
  const { values, positionals } = (0, import_node_util7.parseArgs)({
20430
21359
  args: argv,
@@ -20432,7 +21361,9 @@ async function runLogin(argv, deps) {
20432
21361
  config: { type: "string", short: "c" },
20433
21362
  "master-key-file": { type: "string" },
20434
21363
  // Optional user label for the appended account (multi-account).
20435
- label: { type: "string" }
21364
+ label: { type: "string" },
21365
+ // Optional GitHub Enterprise domain for `login copilot` (GHE accounts).
21366
+ enterprise: { type: "string" }
20436
21367
  },
20437
21368
  allowPositionals: true
20438
21369
  });
@@ -20446,46 +21377,55 @@ async function runLogin(argv, deps) {
20446
21377
  if (!values.config) {
20447
21378
  throw new Error("login: --config <path> is required");
20448
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;
20449
21384
  const resolved = {
20450
21385
  openBrowser: deps?.openBrowser ?? openBrowser,
20451
21386
  promptPaste: deps?.promptPaste ?? promptPaste,
20452
21387
  awaitLoopback: deps?.awaitLoopback ?? ((state) => awaitLoopbackCode(state)),
20453
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)),
20454
21391
  tokensFetch: deps?.tokensFetch
20455
21392
  };
20456
21393
  const resolvedOpenBrowser = resolved.openBrowser;
20457
21394
  const box = resolveSecretBox(values["master-key-file"]);
20458
21395
  setSecretBox(box);
20459
- (0, import_upstreamFetch14.setUpstreamProxyResolver)(createUpstreamProxyResolver());
21396
+ (0, import_upstreamFetch16.setUpstreamProxyResolver)(createUpstreamProxyResolver());
20460
21397
  try {
20461
21398
  const tokensPath = defaultTokensPath(values.config);
20462
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
21399
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
20463
21400
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
20464
21401
  const expiresAt = await runProviderLogin(
20465
21402
  provider,
20466
21403
  store,
20467
21404
  resolved,
20468
21405
  exchangeFetch,
20469
- values.label
21406
+ values.label,
21407
+ enterpriseDomain
20470
21408
  );
20471
21409
  console.info(`Logged in to '${provider}' \u2192 ${tokensPath}`);
20472
21410
  console.info(` token: [stored, encrypted] expiresAt: ${expiresAt ?? "n/a"}`);
20473
21411
  } finally {
20474
21412
  setSecretBox(null);
20475
- (0, import_upstreamFetch14.setUpstreamProxyResolver)(null);
21413
+ (0, import_upstreamFetch16.setUpstreamProxyResolver)(null);
20476
21414
  }
20477
21415
  }
20478
- async function runProviderLogin(provider, store, deps, exchangeFetch, label) {
21416
+ async function runProviderLogin(provider, store, deps, exchangeFetch, label, enterpriseUrl) {
20479
21417
  if (provider === "codex") return loginCodex(store, deps, exchangeFetch, label);
20480
21418
  if (provider === "claude") return loginClaude(store, deps, exchangeFetch, label);
20481
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);
20482
21422
  return loginGemini(store, deps, exchangeFetch, label);
20483
21423
  }
20484
21424
  async function loginCodex(store, deps, exchangeFetch, label) {
20485
- const { authUrl, codeVerifier, state } = import_subscriptions10.codexOAuth.generateAuthParams();
21425
+ const { authUrl, codeVerifier, state } = import_subscriptions13.codexOAuth.generateAuthParams();
20486
21426
  await presentUrl(authUrl, deps);
20487
21427
  const code = await deps.awaitLoopback(state);
20488
- const result = await import_subscriptions10.codexOAuth.exchangeCodeForTokens(
21428
+ const result = await import_subscriptions13.codexOAuth.exchangeCodeForTokens(
20489
21429
  { authorizationCode: code, codeVerifier, state },
20490
21430
  exchangeFetch
20491
21431
  );
@@ -20504,7 +21444,7 @@ async function loginCodex(store, deps, exchangeFetch, label) {
20504
21444
  return expiresAt;
20505
21445
  }
20506
21446
  async function loginClaude(store, deps, exchangeFetch, label) {
20507
- const { authUrl, codeVerifier, state } = import_subscriptions10.claudeOAuth.generateAuthParams();
21447
+ const { authUrl, codeVerifier, state } = import_subscriptions13.claudeOAuth.generateAuthParams();
20508
21448
  await presentUrl(authUrl, deps);
20509
21449
  const pasted = (await deps.promptPaste("Paste the authorization code (code#state): ")).trim();
20510
21450
  const [code, pastedState] = pasted.split("#");
@@ -20512,7 +21452,7 @@ async function loginClaude(store, deps, exchangeFetch, label) {
20512
21452
  if (pastedState && pastedState !== state) {
20513
21453
  throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
20514
21454
  }
20515
- const result = await import_subscriptions10.claudeOAuth.exchangeCodeForTokens(
21455
+ const result = await import_subscriptions13.claudeOAuth.exchangeCodeForTokens(
20516
21456
  { authorizationCode: code, codeVerifier, state },
20517
21457
  exchangeFetch
20518
21458
  );
@@ -20531,11 +21471,11 @@ async function loginClaude(store, deps, exchangeFetch, label) {
20531
21471
  return expiresAt;
20532
21472
  }
20533
21473
  async function loginGemini(store, deps, exchangeFetch, label) {
20534
- const { authUrl, codeVerifier } = import_subscriptions10.geminiOAuth.generateAuthParams();
21474
+ const { authUrl, codeVerifier } = import_subscriptions13.geminiOAuth.generateAuthParams();
20535
21475
  await presentUrl(authUrl, deps);
20536
21476
  const code = (await deps.promptPaste("Paste the authorization code: ")).trim();
20537
21477
  if (!code) throw new Error("login: no authorization code was pasted");
20538
- const result = await import_subscriptions10.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
21478
+ const result = await import_subscriptions13.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
20539
21479
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
20540
21480
  const block = {
20541
21481
  authMethod: "oauth",
@@ -20550,9 +21490,9 @@ async function loginGemini(store, deps, exchangeFetch, label) {
20550
21490
  return expiresAt;
20551
21491
  }
20552
21492
  async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
20553
- const deviceId = import_subscriptions10.kimiOAuth.generateKimiDeviceId();
20554
- const fingerprint = import_subscriptions10.kimiOAuth.kimiFingerprintHeaders(deviceId);
20555
- const authorization = await import_subscriptions10.kimiOAuth.requestDeviceAuthorization(exchangeFetch, fingerprint);
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);
20556
21496
  const url = authorization.verificationUriComplete ?? authorization.verificationUri;
20557
21497
  console.info("Open this URL in your browser and approve the request:");
20558
21498
  console.info(` ${url}`);
@@ -20560,14 +21500,14 @@ async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
20560
21500
  console.info(` Then enter this code: ${authorization.userCode}`);
20561
21501
  }
20562
21502
  await openBrowserFn(url).catch(() => false);
20563
- const result = await import_subscriptions10.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
21503
+ const result = await import_subscriptions13.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
20564
21504
  fingerprint,
20565
21505
  onPending: () => process.stdout.write(".")
20566
21506
  });
20567
21507
  console.info("");
20568
21508
  return {
20569
21509
  ...result,
20570
- accountId: import_subscriptions10.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
21510
+ accountId: import_subscriptions13.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
20571
21511
  deviceId
20572
21512
  };
20573
21513
  }
@@ -20588,6 +21528,90 @@ async function loginKimi(store, deps, exchangeFetch, label) {
20588
21528
  logMasked("kimi", result.accessToken);
20589
21529
  return expiresAt;
20590
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
+ }
20591
21615
  function isLoginProvider(value) {
20592
21616
  return PROVIDERS2.includes(value);
20593
21617
  }
@@ -21293,7 +22317,7 @@ async function main() {
21293
22317
  process.exitCode = 1;
21294
22318
  }
21295
22319
  }
21296
- main().catch((err6) => {
21297
- console.error(err6 instanceof Error ? err6.message : String(err6));
22320
+ main().catch((err8) => {
22321
+ console.error(err8 instanceof Error ? err8.message : String(err8));
21298
22322
  process.exitCode = 1;
21299
22323
  });