@omnicross/daemon 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -62,22 +62,22 @@ var import_node_fs35 = require("fs");
62
62
  var import_node_path35 = require("path");
63
63
  var import_audit_types = require("@omnicross/contracts/audit-types");
64
64
  var import_billing_types = require("@omnicross/contracts/billing-types");
65
- var import_core4 = require("@omnicross/core");
66
- var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
65
+ var import_core7 = require("@omnicross/core");
66
+ var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
67
67
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
68
68
  var import_outbound_api10 = require("@omnicross/core/outbound-api");
69
69
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
70
70
  var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
71
- var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
71
+ var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
72
72
  var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
73
- var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
73
+ var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
74
74
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
75
75
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
76
76
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
77
77
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
78
78
  var import_outbound_api11 = require("@omnicross/core/outbound-api");
79
79
  var import_usage2 = require("@omnicross/core/usage");
80
- var import_subscriptions9 = require("@omnicross/subscriptions");
80
+ var import_subscriptions12 = require("@omnicross/subscriptions");
81
81
 
82
82
  // src/admin/accountsCodexOAuth.ts
83
83
  var import_node_crypto = __toESM(require("crypto"), 1);
@@ -259,8 +259,187 @@ function handleKimiOAuthStatus(sessionId, deps) {
259
259
  return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
260
260
  }
261
261
 
262
+ // src/admin/accountsGrokOAuth.ts
263
+ var import_subscriptions3 = require("@omnicross/subscriptions");
264
+ function err3(status, message) {
265
+ return { status, body: { error: { type: "admin_api_error", message } } };
266
+ }
267
+ var DEFAULT_GROK_OAUTH_TTL_MS = 15 * 6e4;
268
+ async function handleGrokOAuthStart(deps) {
269
+ if (deps.grokSessions.isBusy()) {
270
+ return err3(409, "a grok sign-in is already in progress \u2014 finish it in the browser or cancel it");
271
+ }
272
+ const fetchImpl = deps.oauthExchangeFetch("grok");
273
+ let tokenEndpoint;
274
+ try {
275
+ tokenEndpoint = await import_subscriptions3.grokOAuth.resolveGrokTokenEndpoint(fetchImpl);
276
+ } catch (e) {
277
+ const reason = e instanceof Error ? e.message : "OIDC discovery failed";
278
+ return err3(502, `grok token-endpoint discovery failed: ${reason}`);
279
+ }
280
+ let authorization;
281
+ try {
282
+ authorization = await import_subscriptions3.grokOAuth.requestGrokDeviceAuthorization(fetchImpl);
283
+ } catch (e) {
284
+ const reason = e instanceof Error ? e.message : "device authorization failed";
285
+ return err3(502, `grok device authorization failed: ${reason}`);
286
+ }
287
+ const { sessionId, signal } = deps.grokSessions.begin();
288
+ void runGrokDevicePoll(sessionId, tokenEndpoint, authorization.deviceCode, signal, deps).catch((e) => {
289
+ const reason = e instanceof Error ? e.message : "grok sign-in failed";
290
+ deps.grokSessions.settle(sessionId, "error", reason);
291
+ });
292
+ return {
293
+ status: 200,
294
+ body: {
295
+ authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
296
+ userCode: authorization.userCode,
297
+ sessionId
298
+ }
299
+ };
300
+ }
301
+ async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, deps) {
302
+ const fetchImpl = deps.oauthExchangeFetch("grok");
303
+ const result = await import_subscriptions3.grokOAuth.awaitGrokDeviceToken(
304
+ { userCode: "", deviceCode, verificationUri: "" },
305
+ tokenEndpoint,
306
+ fetchImpl,
307
+ {
308
+ deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
309
+ sleep: (ms) => new Promise((resolve10, reject) => {
310
+ const onAbort = () => {
311
+ clearTimeout(timer);
312
+ reject(new Error("login: cancelled"));
313
+ };
314
+ const timer = setTimeout(() => {
315
+ signal.removeEventListener("abort", onAbort);
316
+ resolve10();
317
+ }, ms);
318
+ signal.addEventListener("abort", onAbort, { once: true });
319
+ })
320
+ }
321
+ );
322
+ const block = {
323
+ authMethod: "oauth",
324
+ status: "authorized",
325
+ accessToken: result.accessToken,
326
+ refreshToken: result.refreshToken,
327
+ expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
328
+ accountId: import_subscriptions3.grokOAuth.grokAccountIdFromAccessToken(result.accessToken),
329
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
330
+ };
331
+ await deps.subscriptionAccountAppender.appendProviderAccount("grok", block);
332
+ deps.grokSessions.settle(sessionId, "done");
333
+ }
334
+ function handleGrokOAuthCancel(sessionId, deps) {
335
+ if (!deps.grokSessions.cancel(sessionId)) return err3(404, "unknown or expired grok sign-in session");
336
+ return { status: 200, body: { ok: true } };
337
+ }
338
+ function handleGrokOAuthStatus(sessionId, deps) {
339
+ const s = deps.grokSessions.get(sessionId);
340
+ if (!s) return err3(404, "unknown or expired grok sign-in session");
341
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
342
+ }
343
+
344
+ // src/admin/accountsCopilotOAuth.ts
345
+ var import_subscriptions4 = require("@omnicross/subscriptions");
346
+ function err4(status, message) {
347
+ return { status, body: { error: { type: "admin_api_error", message } } };
348
+ }
349
+ var DEFAULT_COPILOT_OAUTH_TTL_MS = 15 * 6e4;
350
+ async function handleCopilotOAuthStart(deps, enterpriseUrlInput) {
351
+ if (deps.copilotSessions.isBusy()) {
352
+ return err4(409, "a copilot sign-in is already in progress \u2014 finish it in the browser or cancel it");
353
+ }
354
+ let enterpriseUrl;
355
+ if (typeof enterpriseUrlInput === "string" && enterpriseUrlInput.trim()) {
356
+ try {
357
+ enterpriseUrl = import_subscriptions4.copilotOAuth.normalizeCopilotEnterpriseDomain(enterpriseUrlInput);
358
+ } catch (e) {
359
+ const reason = e instanceof Error ? e.message : "invalid GitHub Enterprise domain";
360
+ return err4(400, `copilot ${reason}`);
361
+ }
362
+ }
363
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
364
+ let authorization;
365
+ try {
366
+ authorization = await import_subscriptions4.copilotOAuth.requestCopilotDeviceAuthorization(fetchImpl, enterpriseUrl);
367
+ } catch (e) {
368
+ const reason = e instanceof Error ? e.message : "device authorization failed";
369
+ return err4(502, `copilot device authorization failed: ${reason}`);
370
+ }
371
+ const { sessionId, signal } = deps.copilotSessions.begin();
372
+ void runCopilotDevicePoll(sessionId, authorization.deviceCode, signal, deps, enterpriseUrl).catch((e) => {
373
+ const reason = e instanceof Error ? e.message : "copilot sign-in failed";
374
+ deps.copilotSessions.settle(sessionId, "error", reason);
375
+ });
376
+ return {
377
+ status: 200,
378
+ body: {
379
+ authUrl: authorization.verificationUri,
380
+ userCode: authorization.userCode,
381
+ sessionId,
382
+ ...enterpriseUrl ? { enterpriseUrl } : {}
383
+ }
384
+ };
385
+ }
386
+ async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpriseUrl) {
387
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
388
+ const result = await import_subscriptions4.copilotOAuth.awaitCopilotDeviceToken(
389
+ { userCode: "", deviceCode, verificationUri: "", interval: 5, expiresIn: 900 },
390
+ fetchImpl,
391
+ {
392
+ deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
393
+ ...enterpriseUrl ? { enterpriseUrl } : {},
394
+ sleep: (ms) => new Promise((resolve10, reject) => {
395
+ const onAbort = () => {
396
+ clearTimeout(timer);
397
+ reject(new Error("login: cancelled"));
398
+ };
399
+ const timer = setTimeout(() => {
400
+ signal.removeEventListener("abort", onAbort);
401
+ resolve10();
402
+ }, ms);
403
+ signal.addEventListener("abort", onAbort, { once: true });
404
+ })
405
+ }
406
+ );
407
+ const identity = await import_subscriptions4.copilotOAuth.fetchCopilotIdentity(result.accessToken, fetchImpl, enterpriseUrl);
408
+ const apiEndpoint = await import_subscriptions4.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, fetchImpl, enterpriseUrl);
409
+ await import_subscriptions4.copilotOAuth.enableAllCopilotModels(
410
+ result.accessToken,
411
+ { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
412
+ fetchImpl
413
+ );
414
+ const block = {
415
+ authMethod: "oauth",
416
+ status: "authorized",
417
+ accessToken: result.accessToken,
418
+ refreshToken: result.accessToken,
419
+ expiresAt: new Date(Date.now() + import_subscriptions4.copilotOAuth.COPILOT_FAR_FUTURE_MS).toISOString(),
420
+ ...identity.accountId ? { accountId: identity.accountId } : {},
421
+ ...identity.email ? { email: identity.email } : {},
422
+ ...apiEndpoint ? { apiEndpoint } : {},
423
+ ...enterpriseUrl ? { enterpriseUrl } : {},
424
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
425
+ };
426
+ await deps.subscriptionAccountAppender.appendProviderAccount("copilot", block);
427
+ deps.copilotSessions.settle(sessionId, "done");
428
+ }
429
+ function handleCopilotOAuthCancel(sessionId, deps) {
430
+ if (!deps.copilotSessions.cancel(sessionId)) {
431
+ return err4(404, "unknown or expired copilot sign-in session");
432
+ }
433
+ return { status: 200, body: { ok: true } };
434
+ }
435
+ function handleCopilotOAuthStatus(sessionId, deps) {
436
+ const s = deps.copilotSessions.get(sessionId);
437
+ if (!s) return err4(404, "unknown or expired copilot sign-in session");
438
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
439
+ }
440
+
262
441
  // src/allowance/AccountAllowanceService.ts
263
- var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
442
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
264
443
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
265
444
 
266
445
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -731,7 +910,7 @@ var CodexAllowanceCollector = class {
731
910
  // src/allowance/KimiAllowanceCollector.ts
732
911
  var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
733
912
  var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
734
- var import_subscriptions3 = require("@omnicross/subscriptions");
913
+ var import_subscriptions5 = require("@omnicross/subscriptions");
735
914
  var KIMI_ALLOWANCE_CACHE_MS = 5 * 6e4;
736
915
  var KIMI_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
737
916
  function finiteNumber2(value) {
@@ -837,28 +1016,682 @@ function parseKimiUsagePayload(payload, now) {
837
1016
  }
838
1017
  }
839
1018
  }
840
- return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
1019
+ return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
1020
+ }
1021
+ var KimiAllowanceCollector = class {
1022
+ constructor(credentials, store = (0, import_AccountAllowanceStore3.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch3.fetchUpstream)(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
1023
+ this.credentials = credentials;
1024
+ this.store = store;
1025
+ this.fetchImpl = fetchImpl;
1026
+ this.now = now;
1027
+ }
1028
+ credentials;
1029
+ store;
1030
+ fetchImpl;
1031
+ now;
1032
+ inFlight = /* @__PURE__ */ new Map();
1033
+ async collectMany(accounts, options = {}) {
1034
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1035
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1036
+ }
1037
+ collect(account, options = {}) {
1038
+ const now = this.now();
1039
+ if (account.tokens.authMethod !== "oauth") {
1040
+ const existing = this.store.get("kimi", account.id, now);
1041
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1042
+ return Promise.resolve(existing);
1043
+ }
1044
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1045
+ this.store.set(snapshot);
1046
+ return Promise.resolve(snapshot);
1047
+ }
1048
+ const cached = this.store.get("kimi", account.id, now);
1049
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1050
+ return Promise.resolve(cached);
1051
+ }
1052
+ const running = this.inFlight.get(account.id);
1053
+ if (running) return running;
1054
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "kimi_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1055
+ this.inFlight.set(account.id, promise);
1056
+ return promise;
1057
+ }
1058
+ isCacheValid(snapshot, now, refreshAheadMs) {
1059
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1060
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1061
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1062
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1063
+ }
1064
+ async fetchAccount(accountId, tokens) {
1065
+ let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1066
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1067
+ let response = await this.request(accountId, accessToken, tokens);
1068
+ if (response.status === 401) {
1069
+ const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
1070
+ if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
1071
+ accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1072
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1073
+ response = await this.request(accountId, accessToken, tokens);
1074
+ }
1075
+ if (response.status === 403) {
1076
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
1077
+ this.store.set(snapshot2);
1078
+ return snapshot2;
1079
+ }
1080
+ if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
1081
+ let payload;
1082
+ try {
1083
+ payload = await response.json();
1084
+ } catch {
1085
+ return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
1086
+ }
1087
+ const now = this.now();
1088
+ const windows = parseKimiUsagePayload(payload, now);
1089
+ const snapshot = {
1090
+ providerId: "kimi",
1091
+ accountId,
1092
+ source: "oauth-usage-api",
1093
+ observedAt: new Date(now).toISOString(),
1094
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1095
+ windows: windows.length > 0 ? windows : [
1096
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1097
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1098
+ ],
1099
+ ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
1100
+ };
1101
+ this.store.set(snapshot);
1102
+ return snapshot;
1103
+ }
1104
+ request(accountId, accessToken, tokens) {
1105
+ return this.fetchImpl(KIMI_USAGE_URL, {
1106
+ method: "GET",
1107
+ headers: {
1108
+ Authorization: `Bearer ${accessToken}`,
1109
+ Accept: "application/json",
1110
+ ...(0, import_subscriptions5.kimiFingerprintHeaders)(tokens.deviceId)
1111
+ },
1112
+ signal: AbortSignal.timeout(15e3)
1113
+ }, accountId);
1114
+ }
1115
+ failureSnapshot(accountId, code, now) {
1116
+ const existing = this.store.get("kimi", accountId, now);
1117
+ const snapshot = existing ? {
1118
+ ...existing,
1119
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1120
+ windows: existing.windows.map((window) => ({
1121
+ ...window,
1122
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1123
+ })),
1124
+ lastErrorCode: code
1125
+ } : {
1126
+ providerId: "kimi",
1127
+ accountId,
1128
+ source: "oauth-usage-api",
1129
+ observedAt: new Date(now).toISOString(),
1130
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1131
+ windows: [
1132
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1133
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1134
+ ],
1135
+ lastErrorCode: code
1136
+ };
1137
+ this.store.set(snapshot);
1138
+ return snapshot;
1139
+ }
1140
+ unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
1141
+ return {
1142
+ providerId: "kimi",
1143
+ accountId,
1144
+ source: "oauth-usage-api",
1145
+ observedAt: new Date(now).toISOString(),
1146
+ windows: [
1147
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
1148
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
1149
+ ],
1150
+ lastErrorCode: code
1151
+ };
1152
+ }
1153
+ };
1154
+
1155
+ // src/allowance/GrokAllowanceCollector.ts
1156
+ var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1157
+ var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
1158
+ var GROK_ALLOWANCE_CACHE_MS = 5 * 6e4;
1159
+ var GROK_BILLING_BASE = "https://cli-chat-proxy.grok.com";
1160
+ var GROK_BILLING_CREDITS_URL = `${GROK_BILLING_BASE}/v1/billing?format=credits`;
1161
+ var GROK_BILLING_MONTHLY_URL = `${GROK_BILLING_BASE}/v1/billing`;
1162
+ function isRecord2(value) {
1163
+ return !!value && typeof value === "object" && !Array.isArray(value);
1164
+ }
1165
+ function finiteNumber3(value) {
1166
+ if (value === null || value === void 0 || value === "") return void 0;
1167
+ const parsed = typeof value === "number" ? value : Number(value);
1168
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1169
+ }
1170
+ function percent(value) {
1171
+ const parsed = finiteNumber3(value);
1172
+ return parsed !== void 0 && parsed <= 100 ? parsed : void 0;
1173
+ }
1174
+ function onDemandAmount(value) {
1175
+ return isRecord2(value) ? finiteNumber3(value["val"]) : void 0;
1176
+ }
1177
+ function confirmsNoMonthlyQuota(raw) {
1178
+ const limit = onDemandAmount(raw["monthlyLimit"]);
1179
+ if (limit !== void 0) return limit === 0;
1180
+ return parseWeeklyConfig(raw)?.inferredPercent === true;
1181
+ }
1182
+ function parseWeeklyConfig(raw) {
1183
+ const period = isRecord2(raw["currentPeriod"]) ? raw["currentPeriod"] : void 0;
1184
+ if (!period) return null;
1185
+ const start = typeof period["start"] === "string" ? Date.parse(period["start"]) : Number.NaN;
1186
+ const end = typeof period["end"] === "string" ? Date.parse(period["end"]) : Number.NaN;
1187
+ const type = typeof period["type"] === "string" ? period["type"] : "";
1188
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
1189
+ if (!type.toUpperCase().includes("WEEK")) return null;
1190
+ const inferred = raw["creditUsagePercent"] === void 0 || raw["creditUsagePercent"] === null;
1191
+ let creditUsagePercent;
1192
+ if (inferred) {
1193
+ creditUsagePercent = end > Date.now() ? 0 : void 0;
1194
+ } else {
1195
+ creditUsagePercent = percent(raw["creditUsagePercent"]);
1196
+ }
1197
+ if (creditUsagePercent === void 0) return null;
1198
+ return {
1199
+ creditUsagePercent,
1200
+ inferredPercent: inferred,
1201
+ resetsAtMs: end,
1202
+ unified: raw["isUnifiedBillingUser"] === true
1203
+ };
1204
+ }
1205
+ function parseMonthlyConfig(raw) {
1206
+ const start = typeof raw["billingPeriodStart"] === "string" ? Date.parse(raw["billingPeriodStart"]) : Number.NaN;
1207
+ const end = typeof raw["billingPeriodEnd"] === "string" ? Date.parse(raw["billingPeriodEnd"]) : Number.NaN;
1208
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
1209
+ const limit = onDemandAmount(raw["monthlyLimit"]);
1210
+ const used = onDemandAmount(raw["used"]);
1211
+ if (limit === void 0 || limit <= 0 || used === void 0) return null;
1212
+ return { used, limit, periodStartMs: start, periodEndMs: end };
1213
+ }
1214
+ function secondsUntil4(instant, now) {
1215
+ if (!instant) return void 0;
1216
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1217
+ }
1218
+ var MINUTE_MS2 = 6e4;
1219
+ var DAY_MS2 = 864e5;
1220
+ var WEEK_MINUTES = 7 * 24 * 60;
1221
+ function weeklyWindow(config, now) {
1222
+ const resetsAt = new Date(config.resetsAtMs).toISOString();
1223
+ return {
1224
+ id: "seven-day",
1225
+ label: "7 days",
1226
+ scope: "all",
1227
+ usedPercent: config.creditUsagePercent,
1228
+ windowMinutes: WEEK_MINUTES,
1229
+ resetsAt,
1230
+ remainingSeconds: secondsUntil4(resetsAt, now),
1231
+ state: "fresh"
1232
+ };
1233
+ }
1234
+ function monthlyWindow(config, now) {
1235
+ const resetsAt = new Date(config.periodEndMs).toISOString();
1236
+ const days = Math.max(1, Math.round((config.periodEndMs - config.periodStartMs) / DAY_MS2));
1237
+ return {
1238
+ id: "thirty-day",
1239
+ label: days === 30 || days === 31 ? "30 days" : `${days} days`,
1240
+ scope: "all",
1241
+ usedPercent: Math.round(Math.min(100, config.used / config.limit * 100) * 10) / 10,
1242
+ windowMinutes: Math.round((config.periodEndMs - config.periodStartMs) / MINUTE_MS2),
1243
+ resetsAt,
1244
+ remainingSeconds: secondsUntil4(resetsAt, now),
1245
+ state: "fresh"
1246
+ };
1247
+ }
1248
+ function onDemandWindow(raw) {
1249
+ const cap = onDemandAmount(raw["onDemandCap"]);
1250
+ const used = onDemandAmount(raw["onDemandUsed"]);
1251
+ if (cap === void 0 || cap <= 0 || used === void 0) return null;
1252
+ return {
1253
+ id: "on-demand",
1254
+ label: "On-demand",
1255
+ scope: "all",
1256
+ usedPercent: Math.round(Math.min(100, used / cap * 100) * 10) / 10,
1257
+ state: "fresh"
1258
+ };
1259
+ }
1260
+ async function probeBilling(url, accessToken, accountId, fetchImpl) {
1261
+ try {
1262
+ const response = await fetchImpl(url, {
1263
+ method: "GET",
1264
+ headers: {
1265
+ Authorization: `Bearer ${accessToken}`,
1266
+ Accept: "application/json",
1267
+ "X-XAI-Token-Auth": "xai-grok-cli"
1268
+ },
1269
+ redirect: "error",
1270
+ signal: AbortSignal.timeout(15e3)
1271
+ }, accountId);
1272
+ if (!response.ok) return { status: response.status, payload: null };
1273
+ const payload = await response.json();
1274
+ return { status: response.status, payload: isRecord2(payload) ? payload : null };
1275
+ } catch {
1276
+ return { status: 0, payload: null };
1277
+ }
1278
+ }
1279
+ function parseGrokBillingPayloads(creditsPayload, monthlyPayload, now) {
1280
+ const creditsConfig = isRecord2(creditsPayload?.["config"]) ? creditsPayload["config"] : null;
1281
+ const monthlyConfig = isRecord2(monthlyPayload?.["config"]) ? monthlyPayload["config"] : null;
1282
+ let weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
1283
+ const unifiedFlag = creditsConfig?.["isUnifiedBillingUser"] === true;
1284
+ let monthly = monthlyConfig ? parseMonthlyConfig(monthlyConfig) : null;
1285
+ if (weekly?.inferredPercent && unifiedFlag) {
1286
+ if (monthly) {
1287
+ weekly = null;
1288
+ } else if (!monthlyConfig || !confirmsNoMonthlyQuota(monthlyConfig)) {
1289
+ weekly = null;
1290
+ }
1291
+ }
1292
+ const windows = [];
1293
+ if (weekly) windows.push(weeklyWindow(weekly, now));
1294
+ if (monthly) windows.push(monthlyWindow(monthly, now));
1295
+ const onDemandSource = monthly && monthlyConfig ? monthlyConfig : creditsConfig;
1296
+ const onDemand = onDemandSource ? onDemandWindow(onDemandSource) : null;
1297
+ if (onDemand) windows.push(onDemand);
1298
+ return windows.length > 0 ? windows : null;
1299
+ }
1300
+ var GrokAllowanceCollector = class {
1301
+ 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) {
1302
+ this.credentials = credentials;
1303
+ this.store = store;
1304
+ this.fetchImpl = fetchImpl;
1305
+ this.now = now;
1306
+ }
1307
+ credentials;
1308
+ store;
1309
+ fetchImpl;
1310
+ now;
1311
+ inFlight = /* @__PURE__ */ new Map();
1312
+ async collectMany(accounts, options = {}) {
1313
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1314
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1315
+ }
1316
+ collect(account, options = {}) {
1317
+ const now = this.now();
1318
+ if (account.tokens.authMethod !== "oauth") {
1319
+ const existing = this.store.get("grok", account.id, now);
1320
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1321
+ return Promise.resolve(existing);
1322
+ }
1323
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1324
+ this.store.set(snapshot);
1325
+ return Promise.resolve(snapshot);
1326
+ }
1327
+ const cached = this.store.get("grok", account.id, now);
1328
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1329
+ return Promise.resolve(cached);
1330
+ }
1331
+ const running = this.inFlight.get(account.id);
1332
+ if (running) return running;
1333
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "grok_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1334
+ this.inFlight.set(account.id, promise);
1335
+ return promise;
1336
+ }
1337
+ isCacheValid(snapshot, now, refreshAheadMs) {
1338
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1339
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1340
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1341
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1342
+ }
1343
+ async fetchAccount(accountId) {
1344
+ const probe = async () => {
1345
+ const accessToken = await this.credentials.getAccessTokenForAccount("grok", accountId);
1346
+ if (!accessToken) return { unauthorized: true, windows: null };
1347
+ const credits = await probeBilling(GROK_BILLING_CREDITS_URL, accessToken, accountId, this.fetchImpl);
1348
+ if (credits.status === 401 || credits.status === 403) return { unauthorized: true, windows: null };
1349
+ const creditsConfig = isRecord2(credits.payload?.["config"]) ? credits.payload["config"] : null;
1350
+ const weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
1351
+ const monthly = !weekly || creditsConfig?.["isUnifiedBillingUser"] === true ? await probeBilling(GROK_BILLING_MONTHLY_URL, accessToken, accountId, this.fetchImpl) : { status: 200, payload: null };
1352
+ if (monthly.status === 401 || monthly.status === 403) return { unauthorized: true, windows: null };
1353
+ return {
1354
+ unauthorized: false,
1355
+ windows: parseGrokBillingPayloads(credits.payload, monthly.payload, this.now())
1356
+ };
1357
+ };
1358
+ let result = await probe();
1359
+ if (result.unauthorized) {
1360
+ const refreshed = await this.credentials.refreshAccountToken("grok", accountId);
1361
+ if (!refreshed) return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
1362
+ result = await probe();
1363
+ if (result.unauthorized) {
1364
+ return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
1365
+ }
1366
+ }
1367
+ const now = this.now();
1368
+ if (result.windows && result.windows.length > 0) {
1369
+ const snapshot = {
1370
+ providerId: "grok",
1371
+ accountId,
1372
+ source: "oauth-usage-api",
1373
+ observedAt: new Date(now).toISOString(),
1374
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1375
+ windows: result.windows
1376
+ };
1377
+ this.store.set(snapshot);
1378
+ return snapshot;
1379
+ }
1380
+ return this.failureSnapshot(accountId, "grok_usage_invalid_response", now);
1381
+ }
1382
+ failureSnapshot(accountId, code, now) {
1383
+ const existing = this.store.get("grok", accountId, now);
1384
+ const snapshot = existing ? {
1385
+ ...existing,
1386
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1387
+ windows: existing.windows.map((window) => ({
1388
+ ...window,
1389
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1390
+ })),
1391
+ lastErrorCode: code
1392
+ } : {
1393
+ providerId: "grok",
1394
+ accountId,
1395
+ source: "oauth-usage-api",
1396
+ observedAt: new Date(now).toISOString(),
1397
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1398
+ windows: [
1399
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" },
1400
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unavailable" }
1401
+ ],
1402
+ lastErrorCode: code
1403
+ };
1404
+ this.store.set(snapshot);
1405
+ return snapshot;
1406
+ }
1407
+ unsupportedSnapshot(accountId, now) {
1408
+ return {
1409
+ providerId: "grok",
1410
+ accountId,
1411
+ source: "oauth-usage-api",
1412
+ observedAt: new Date(now).toISOString(),
1413
+ windows: [
1414
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" },
1415
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unsupported" }
1416
+ ],
1417
+ lastErrorCode: "grok_usage_unsupported_auth"
1418
+ };
1419
+ }
1420
+ };
1421
+
1422
+ // src/allowance/CopilotAllowanceCollector.ts
1423
+ var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1424
+ var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
1425
+ var import_subscriptions6 = require("@omnicross/subscriptions");
1426
+ var COPILOT_ALLOWANCE_CACHE_MS = 5 * 6e4;
1427
+ function isRecord3(value) {
1428
+ return !!value && typeof value === "object" && !Array.isArray(value);
1429
+ }
1430
+ function finiteNumber4(value) {
1431
+ if (value === null || value === void 0 || value === "") return void 0;
1432
+ const parsed = typeof value === "number" ? value : Number(value);
1433
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1434
+ }
1435
+ function booleanValue(value) {
1436
+ if (typeof value === "boolean") return value;
1437
+ if (value === "true") return true;
1438
+ if (value === "false") return false;
1439
+ return void 0;
1440
+ }
1441
+ function parseQuotaDetail(value) {
1442
+ if (!isRecord3(value)) return null;
1443
+ const entitlement = finiteNumber4(value["entitlement"]);
1444
+ const remaining = finiteNumber4(value["remaining"]);
1445
+ const percentRemaining = finiteNumber4(value["percent_remaining"]);
1446
+ const unlimited = booleanValue(value["unlimited"]);
1447
+ if (entitlement === void 0 || remaining === void 0 || percentRemaining === void 0 || unlimited === void 0) {
1448
+ return null;
1449
+ }
1450
+ return { entitlement, remaining, percentRemaining, unlimited };
1451
+ }
1452
+ function secondsUntil5(instant, now) {
1453
+ if (!instant) return void 0;
1454
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1455
+ }
1456
+ function parseCopilotUserPayload(payload, now) {
1457
+ if (!isRecord3(payload)) return null;
1458
+ const snapshots = isRecord3(payload["quota_snapshots"]) ? payload["quota_snapshots"] : void 0;
1459
+ if (!snapshots) return null;
1460
+ const resetRaw = payload["quota_reset_date"];
1461
+ const resetsAt = typeof resetRaw === "string" && resetRaw.trim() && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
1462
+ const windows = [];
1463
+ const premium = parseQuotaDetail(snapshots["premium_interactions"]);
1464
+ if (premium) {
1465
+ 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;
1466
+ if (usedPercent !== null) {
1467
+ windows.push({
1468
+ id: "thirty-day",
1469
+ label: "Monthly",
1470
+ scope: "all",
1471
+ usedPercent,
1472
+ windowMinutes: 30 * 24 * 60,
1473
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1474
+ remainingSeconds: secondsUntil5(resetsAt, now),
1475
+ state: "fresh"
1476
+ });
1477
+ }
1478
+ }
1479
+ const chat = parseQuotaDetail(snapshots["chat"]);
1480
+ if (chat && !chat.unlimited && chat.entitlement > 0) {
1481
+ const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
1482
+ windows.push({
1483
+ id: "chat-monthly",
1484
+ label: "Chat (monthly)",
1485
+ scope: "all",
1486
+ usedPercent,
1487
+ windowMinutes: 30 * 24 * 60,
1488
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1489
+ remainingSeconds: secondsUntil5(resetsAt, now),
1490
+ state: "fresh"
1491
+ });
1492
+ }
1493
+ return windows.length > 0 ? windows : null;
1494
+ }
1495
+ function githubApiBase(tokens) {
1496
+ return (0, import_subscriptions6.copilotGitHubApiBase)(tokens.enterpriseUrl);
1497
+ }
1498
+ var CopilotAllowanceCollector = class {
1499
+ 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) {
1500
+ this.credentials = credentials;
1501
+ this.store = store;
1502
+ this.fetchImpl = fetchImpl;
1503
+ this.now = now;
1504
+ }
1505
+ credentials;
1506
+ store;
1507
+ fetchImpl;
1508
+ now;
1509
+ inFlight = /* @__PURE__ */ new Map();
1510
+ async collectMany(accounts, options = {}) {
1511
+ const settled = await Promise.allSettled(
1512
+ accounts.map((account) => this.collect(account, options))
1513
+ );
1514
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1515
+ }
1516
+ collect(account, options = {}) {
1517
+ const now = this.now();
1518
+ if (account.tokens.authMethod !== "oauth") {
1519
+ const existing = this.store.get("copilot", account.id, now);
1520
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1521
+ return Promise.resolve(existing);
1522
+ }
1523
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1524
+ this.store.set(snapshot);
1525
+ return Promise.resolve(snapshot);
1526
+ }
1527
+ const cached = this.store.get("copilot", account.id, now);
1528
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1529
+ return Promise.resolve(cached);
1530
+ }
1531
+ const running = this.inFlight.get(account.id);
1532
+ if (running) return running;
1533
+ 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));
1534
+ this.inFlight.set(account.id, promise);
1535
+ return promise;
1536
+ }
1537
+ isCacheValid(snapshot, now, refreshAheadMs) {
1538
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1539
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1540
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1541
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1542
+ }
1543
+ async fetchAccount(accountId, tokens) {
1544
+ let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1545
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
1546
+ let response = await this.request(accountId, accessToken, tokens);
1547
+ if (response.status === 401 || response.status === 403) {
1548
+ const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
1549
+ if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1550
+ accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1551
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
1552
+ response = await this.request(accountId, accessToken, tokens);
1553
+ if (response.status === 401 || response.status === 403) {
1554
+ return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1555
+ }
1556
+ }
1557
+ if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
1558
+ let payload;
1559
+ try {
1560
+ payload = await response.json();
1561
+ } catch {
1562
+ return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
1563
+ }
1564
+ const now = this.now();
1565
+ const windows = parseCopilotUserPayload(payload, now);
1566
+ const snapshot = {
1567
+ providerId: "copilot",
1568
+ accountId,
1569
+ source: "oauth-usage-api",
1570
+ observedAt: new Date(now).toISOString(),
1571
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1572
+ windows: windows ?? [
1573
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
1574
+ ],
1575
+ ...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
1576
+ };
1577
+ this.store.set(snapshot);
1578
+ return snapshot;
1579
+ }
1580
+ request(accountId, accessToken, tokens) {
1581
+ return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
1582
+ method: "GET",
1583
+ headers: {
1584
+ Authorization: `Bearer ${accessToken}`,
1585
+ Accept: "application/json",
1586
+ "Content-Type": "application/json",
1587
+ ...import_subscriptions6.COPILOT_GITHUB_HEADERS
1588
+ },
1589
+ signal: AbortSignal.timeout(15e3)
1590
+ }, accountId);
1591
+ }
1592
+ failureSnapshot(accountId, code, now) {
1593
+ const existing = this.store.get("copilot", accountId, now);
1594
+ const snapshot = existing ? {
1595
+ ...existing,
1596
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1597
+ windows: existing.windows.map((window) => ({
1598
+ ...window,
1599
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1600
+ })),
1601
+ lastErrorCode: code
1602
+ } : {
1603
+ providerId: "copilot",
1604
+ accountId,
1605
+ source: "oauth-usage-api",
1606
+ observedAt: new Date(now).toISOString(),
1607
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1608
+ windows: [
1609
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
1610
+ ],
1611
+ lastErrorCode: code
1612
+ };
1613
+ this.store.set(snapshot);
1614
+ return snapshot;
1615
+ }
1616
+ unsupportedSnapshot(accountId, now) {
1617
+ return {
1618
+ providerId: "copilot",
1619
+ accountId,
1620
+ source: "oauth-usage-api",
1621
+ observedAt: new Date(now).toISOString(),
1622
+ windows: [
1623
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
1624
+ ],
1625
+ lastErrorCode: "copilot_usage_unsupported_auth"
1626
+ };
1627
+ }
1628
+ };
1629
+
1630
+ // src/allowance/GeminiAllowanceCollector.ts
1631
+ var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1632
+ var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1633
+ var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
1634
+ var import_transformers = require("@omnicross/core/transformer/transformers");
1635
+ var GEMINI_ALLOWANCE_CACHE_MS = 5 * 6e4;
1636
+ function isRecord4(value) {
1637
+ return !!value && typeof value === "object" && !Array.isArray(value);
841
1638
  }
842
- var KimiAllowanceCollector = class {
843
- constructor(credentials, store = (0, import_AccountAllowanceStore3.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch3.fetchUpstream)(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
1639
+ function secondsUntil6(instant, now) {
1640
+ if (!instant) return void 0;
1641
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1642
+ }
1643
+ function parseGeminiQuotaPayload(payload, now) {
1644
+ if (!isRecord4(payload)) return null;
1645
+ const buckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
1646
+ const windows = [];
1647
+ const seen = /* @__PURE__ */ new Set();
1648
+ for (const raw of buckets) {
1649
+ if (!isRecord4(raw)) continue;
1650
+ const modelId = typeof raw["modelId"] === "string" && raw["modelId"].trim() ? raw["modelId"].trim() : void 0;
1651
+ const id = `gemini:${modelId ?? "all"}`;
1652
+ if (seen.has(id)) continue;
1653
+ seen.add(id);
1654
+ const fractionRaw = typeof raw["remainingFraction"] === "number" ? raw["remainingFraction"] : Number(raw["remainingFraction"]);
1655
+ const usedPercent = Number.isFinite(fractionRaw) ? Math.round(Math.min(100, Math.max(0, (1 - Math.min(1, Math.max(0, fractionRaw))) * 100)) * 10) / 10 : null;
1656
+ const resetRaw = typeof raw["resetTime"] === "string" && raw["resetTime"].trim() ? raw["resetTime"] : void 0;
1657
+ const resetsAt = resetRaw !== void 0 && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
1658
+ windows.push({
1659
+ id,
1660
+ label: modelId ? `Gemini ${modelId}` : "Gemini quota",
1661
+ scope: modelId ? "model-family" : "all",
1662
+ ...modelId ? { modelFamily: modelId } : {},
1663
+ usedPercent,
1664
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1665
+ remainingSeconds: secondsUntil6(resetsAt, now),
1666
+ state: "fresh"
1667
+ });
1668
+ }
1669
+ return windows.length > 0 ? windows : null;
1670
+ }
1671
+ var GeminiAllowanceCollector = class {
1672
+ constructor(credentials, store = (0, import_AccountAllowanceStore6.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch6.fetchUpstream)(url, init, { providerId: "gemini", accountId, redactBodies: true }), now = Date.now, projectResolver = (0, import_GeminiCodeAssistProjectResolver.getGeminiCodeAssistProjectResolver)()) {
844
1673
  this.credentials = credentials;
845
1674
  this.store = store;
846
1675
  this.fetchImpl = fetchImpl;
847
1676
  this.now = now;
1677
+ this.projectResolver = projectResolver;
848
1678
  }
849
1679
  credentials;
850
1680
  store;
851
1681
  fetchImpl;
852
1682
  now;
1683
+ projectResolver;
853
1684
  inFlight = /* @__PURE__ */ new Map();
854
1685
  async collectMany(accounts, options = {}) {
855
- const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1686
+ const settled = await Promise.allSettled(
1687
+ accounts.map((account) => this.collect(account, options))
1688
+ );
856
1689
  return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
857
1690
  }
858
1691
  collect(account, options = {}) {
859
1692
  const now = this.now();
860
1693
  if (account.tokens.authMethod !== "oauth") {
861
- const existing = this.store.get("kimi", account.id, now);
1694
+ const existing = this.store.get("gemini", account.id, now);
862
1695
  if (existing?.windows.every((window) => window.state === "unsupported")) {
863
1696
  return Promise.resolve(existing);
864
1697
  }
@@ -866,13 +1699,13 @@ var KimiAllowanceCollector = class {
866
1699
  this.store.set(snapshot);
867
1700
  return Promise.resolve(snapshot);
868
1701
  }
869
- const cached = this.store.get("kimi", account.id, now);
1702
+ const cached = this.store.get("gemini", account.id, now);
870
1703
  if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
871
1704
  return Promise.resolve(cached);
872
1705
  }
873
1706
  const running = this.inFlight.get(account.id);
874
1707
  if (running) return running;
875
- const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "kimi_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1708
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "gemini_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
876
1709
  this.inFlight.set(account.id, promise);
877
1710
  return promise;
878
1711
  }
@@ -882,101 +1715,104 @@ var KimiAllowanceCollector = class {
882
1715
  const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
883
1716
  return Number.isFinite(expiresAt) && expiresAt > now + ahead;
884
1717
  }
885
- async fetchAccount(accountId, tokens) {
886
- let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
887
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
888
- let response = await this.request(accountId, accessToken, tokens);
889
- if (response.status === 401) {
890
- const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
891
- if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
892
- accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
893
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
894
- response = await this.request(accountId, accessToken, tokens);
1718
+ async fetchAccount(accountId) {
1719
+ let accessToken = await this.credentials.getAccessTokenForAccount("gemini", accountId);
1720
+ if (!accessToken) return this.failureSnapshot(accountId, "gemini_usage_token_unavailable", this.now());
1721
+ let project;
1722
+ try {
1723
+ project = await this.projectResolver.resolveProject(accessToken);
1724
+ } catch {
1725
+ project = void 0;
895
1726
  }
896
- if (response.status === 403) {
897
- const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
898
- this.store.set(snapshot2);
899
- return snapshot2;
1727
+ let response = await this.request(accountId, accessToken, project);
1728
+ if (response.status === 401 || response.status === 403) {
1729
+ const refreshed = await this.credentials.refreshAccountToken("gemini", accountId);
1730
+ if (!refreshed) return this.failureSnapshot(accountId, "gemini_usage_unauthorized", this.now());
1731
+ accessToken = await this.credentials.getAccessTokenForAccount("gemini", accountId);
1732
+ if (!accessToken) return this.failureSnapshot(accountId, "gemini_usage_token_unavailable", this.now());
1733
+ response = await this.request(accountId, accessToken, project);
1734
+ if (response.status === 401 || response.status === 403) {
1735
+ return this.failureSnapshot(accountId, "gemini_usage_unauthorized", this.now());
1736
+ }
900
1737
  }
901
- if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
1738
+ if (!response.ok) return this.failureSnapshot(accountId, "gemini_usage_http_error", this.now());
902
1739
  let payload;
903
1740
  try {
904
1741
  payload = await response.json();
905
1742
  } catch {
906
- return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
1743
+ return this.failureSnapshot(accountId, "gemini_usage_invalid_response", this.now());
907
1744
  }
908
1745
  const now = this.now();
909
- const windows = parseKimiUsagePayload(payload, now);
1746
+ const windows = parseGeminiQuotaPayload(payload, now);
910
1747
  const snapshot = {
911
- providerId: "kimi",
1748
+ providerId: "gemini",
912
1749
  accountId,
913
1750
  source: "oauth-usage-api",
914
1751
  observedAt: new Date(now).toISOString(),
915
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
916
- windows: windows.length > 0 ? windows : [
917
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
918
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1752
+ expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
1753
+ windows: windows ?? [
1754
+ { id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unavailable" }
919
1755
  ],
920
- ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
1756
+ ...windows ? {} : { lastErrorCode: "gemini_usage_invalid_response" }
921
1757
  };
922
1758
  this.store.set(snapshot);
923
1759
  return snapshot;
924
1760
  }
925
- request(accountId, accessToken, tokens) {
926
- return this.fetchImpl(KIMI_USAGE_URL, {
927
- method: "GET",
1761
+ request(accountId, accessToken, project) {
1762
+ return this.fetchImpl(`${(0, import_transformers.resolveCodeAssistEndpoint)()}/v1internal:retrieveUserQuota`, {
1763
+ method: "POST",
928
1764
  headers: {
929
1765
  Authorization: `Bearer ${accessToken}`,
930
1766
  Accept: "application/json",
931
- ...(0, import_subscriptions3.kimiFingerprintHeaders)(tokens.deviceId)
1767
+ "Content-Type": "application/json",
1768
+ ...(0, import_transformers.getGeminiCliIdentityHeaders)()
932
1769
  },
1770
+ body: JSON.stringify(project ? { project } : {}),
933
1771
  signal: AbortSignal.timeout(15e3)
934
1772
  }, accountId);
935
1773
  }
936
1774
  failureSnapshot(accountId, code, now) {
937
- const existing = this.store.get("kimi", accountId, now);
1775
+ const existing = this.store.get("gemini", accountId, now);
938
1776
  const snapshot = existing ? {
939
1777
  ...existing,
940
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1778
+ expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
941
1779
  windows: existing.windows.map((window) => ({
942
1780
  ...window,
943
1781
  state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
944
1782
  })),
945
1783
  lastErrorCode: code
946
1784
  } : {
947
- providerId: "kimi",
1785
+ providerId: "gemini",
948
1786
  accountId,
949
1787
  source: "oauth-usage-api",
950
1788
  observedAt: new Date(now).toISOString(),
951
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1789
+ expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
952
1790
  windows: [
953
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
954
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1791
+ { id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unavailable" }
955
1792
  ],
956
1793
  lastErrorCode: code
957
1794
  };
958
1795
  this.store.set(snapshot);
959
1796
  return snapshot;
960
1797
  }
961
- unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
1798
+ unsupportedSnapshot(accountId, now) {
962
1799
  return {
963
- providerId: "kimi",
1800
+ providerId: "gemini",
964
1801
  accountId,
965
1802
  source: "oauth-usage-api",
966
1803
  observedAt: new Date(now).toISOString(),
967
1804
  windows: [
968
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
969
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
1805
+ { id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unsupported" }
970
1806
  ],
971
- lastErrorCode: code
1807
+ lastErrorCode: "gemini_usage_unsupported_auth"
972
1808
  };
973
1809
  }
974
1810
  };
975
1811
 
976
1812
  // src/allowance/OpenCodeGoAllowanceCollector.ts
977
- var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
978
- var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
979
- var import_subscriptions4 = require("@omnicross/subscriptions");
1813
+ var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1814
+ var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
1815
+ var import_subscriptions7 = require("@omnicross/subscriptions");
980
1816
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
981
1817
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
982
1818
  function finitePercent3(value) {
@@ -989,7 +1825,7 @@ function isoInstant2(value) {
989
1825
  const time = Date.parse(value);
990
1826
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
991
1827
  }
992
- function secondsUntil4(instant, now) {
1828
+ function secondsUntil7(instant, now) {
993
1829
  if (!instant) return void 0;
994
1830
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
995
1831
  }
@@ -1004,12 +1840,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
1004
1840
  usedPercent,
1005
1841
  windowMinutes: minutes,
1006
1842
  ...resetsAt !== void 0 ? { resetsAt } : {},
1007
- remainingSeconds: secondsUntil4(resetsAt, now),
1843
+ remainingSeconds: secondsUntil7(resetsAt, now),
1008
1844
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1009
1845
  };
1010
1846
  }
1011
1847
  var OpenCodeGoAllowanceCollector = class {
1012
- 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) {
1848
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
1013
1849
  this.credentials = credentials;
1014
1850
  this.store = store;
1015
1851
  this.fetchImpl = fetchImpl;
@@ -1039,7 +1875,7 @@ var OpenCodeGoAllowanceCollector = class {
1039
1875
  async fetchAccount(account) {
1040
1876
  const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
1041
1877
  if (!apiKey) return this.failureSnapshot(account.id, this.now());
1042
- const base = account.tokens.baseUrl ? (0, import_subscriptions4.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1878
+ const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1043
1879
  const response = await this.fetchImpl(`${base}/v1/usage`, {
1044
1880
  method: "GET",
1045
1881
  headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
@@ -1114,7 +1950,7 @@ function codexUnavailable(accountId, now) {
1114
1950
  };
1115
1951
  }
1116
1952
  var AccountAllowanceService = class {
1117
- constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, now = Date.now) {
1953
+ constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
1118
1954
  this.credentials = credentials;
1119
1955
  this.store = store;
1120
1956
  this.now = now;
@@ -1122,6 +1958,9 @@ var AccountAllowanceService = class {
1122
1958
  this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
1123
1959
  this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
1124
1960
  this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
1961
+ this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
1962
+ this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
1963
+ this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
1125
1964
  }
1126
1965
  credentials;
1127
1966
  store;
@@ -1129,7 +1968,10 @@ var AccountAllowanceService = class {
1129
1968
  claudeCollector;
1130
1969
  codexCollector;
1131
1970
  kimiCollector;
1971
+ grokCollector;
1972
+ copilotCollector;
1132
1973
  opencodegoCollector;
1974
+ geminiCollector;
1133
1975
  /**
1134
1976
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1135
1977
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -1163,11 +2005,29 @@ var AccountAllowanceService = class {
1163
2005
  (account) => !filter.accountId || account.id === filter.accountId
1164
2006
  );
1165
2007
  if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
2008
+ const wantsGrok = !filter.providerId || filter.providerId === "grok";
2009
+ const grokAccounts = (config.grokAccounts ?? []).filter(
2010
+ (account) => !filter.accountId || account.id === filter.accountId
2011
+ );
2012
+ if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
2013
+ const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
2014
+ const copilotAccounts = (config.copilotAccounts ?? []).filter(
2015
+ (account) => !filter.accountId || account.id === filter.accountId
2016
+ );
2017
+ if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
2018
+ const wantsGemini = !filter.providerId || filter.providerId === "gemini";
2019
+ const geminiAccounts = (config.geminiAccounts ?? []).filter(
2020
+ (account) => !filter.accountId || account.id === filter.accountId
2021
+ );
2022
+ if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
1166
2023
  const known = /* @__PURE__ */ new Set();
1167
2024
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
1168
2025
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
1169
2026
  if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
1170
2027
  if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
2028
+ if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
2029
+ if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
2030
+ if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
1171
2031
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
1172
2032
  }
1173
2033
  knownAccounts(config) {
@@ -1175,7 +2035,10 @@ var AccountAllowanceService = class {
1175
2035
  ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1176
2036
  ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
1177
2037
  ...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
1178
- ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id }))
2038
+ ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
2039
+ ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
2040
+ ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
2041
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
1179
2042
  ];
1180
2043
  }
1181
2044
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -1218,6 +2081,33 @@ var AccountAllowanceService = class {
1218
2081
  );
1219
2082
  return this.kimiCollector.collectMany(accounts, { force: true });
1220
2083
  }
2084
+ /** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
2085
+ async refreshCopilot(accountId) {
2086
+ const config = await this.credentials.getFullConfig();
2087
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2088
+ const accounts = (config.copilotAccounts ?? []).filter(
2089
+ (account) => !accountId || account.id === accountId
2090
+ );
2091
+ return this.copilotCollector.collectMany(accounts, { force: true });
2092
+ }
2093
+ /** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
2094
+ async refreshGrok(accountId) {
2095
+ const config = await this.credentials.getFullConfig();
2096
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2097
+ const accounts = (config.grokAccounts ?? []).filter(
2098
+ (account) => !accountId || account.id === accountId
2099
+ );
2100
+ return this.grokCollector.collectMany(accounts, { force: true });
2101
+ }
2102
+ /** Force-refresh Gemini usage (Code Assist retrieveUserQuota) for one/all accounts. */
2103
+ async refreshGemini(accountId) {
2104
+ const config = await this.credentials.getFullConfig();
2105
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2106
+ const accounts = (config.geminiAccounts ?? []).filter(
2107
+ (account) => !accountId || account.id === accountId
2108
+ );
2109
+ return this.geminiCollector.collectMany(accounts, { force: true });
2110
+ }
1221
2111
  /**
1222
2112
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
1223
2113
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -1232,6 +2122,9 @@ var AccountAllowanceService = class {
1232
2122
  await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
1233
2123
  await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
1234
2124
  await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
2125
+ await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
2126
+ await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
2127
+ await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
1235
2128
  }
1236
2129
  /** Remove a cache row as soon as an account is deleted by the admin path. */
1237
2130
  removeAccountSnapshot(providerId, accountId) {
@@ -1326,7 +2219,7 @@ var ClaudeAllowanceRefreshScheduler = class {
1326
2219
  var import_node_crypto2 = require("crypto");
1327
2220
  var import_node_fs = require("fs");
1328
2221
  var import_node_path = require("path");
1329
- var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2222
+ var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1330
2223
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
1331
2224
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
1332
2225
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -1355,7 +2248,7 @@ var JsonAccountAllowancePersistence = class {
1355
2248
  save(snapshots) {
1356
2249
  const rows = [];
1357
2250
  for (const snapshot of snapshots) {
1358
- const normalized2 = (0, import_AccountAllowanceStore6.normalizeAccountAllowanceSnapshot)(snapshot);
2251
+ const normalized2 = (0, import_AccountAllowanceStore9.normalizeAccountAllowanceSnapshot)(snapshot);
1359
2252
  if (!normalized2) continue;
1360
2253
  rows.push(normalized2);
1361
2254
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -1638,7 +2531,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
1638
2531
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
1639
2532
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1640
2533
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1641
- var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
2534
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
2535
+ var import_core3 = require("@omnicross/core");
1642
2536
 
1643
2537
  // src/image-generation/imagesConfigValidation.ts
1644
2538
  var import_outbound_api = require("@omnicross/core/outbound-api");
@@ -1934,6 +2828,7 @@ async function applyServerConfigTransaction(current, next, deps) {
1934
2828
 
1935
2829
  // src/config.ts
1936
2830
  var import_node_fs4 = require("fs");
2831
+ var import_core = require("@omnicross/core");
1937
2832
 
1938
2833
  // src/secrets/envelope.ts
1939
2834
  var import_node_crypto4 = require("crypto");
@@ -2345,6 +3240,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
2345
3240
  "openai-response",
2346
3241
  "gemini-code-assist"
2347
3242
  ];
3243
+ function validateExtraHeaders(raw) {
3244
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3245
+ const reserved = import_core.EXTRA_HEADER_RESERVED_NAMES;
3246
+ const out = {};
3247
+ for (const [name, value] of Object.entries(raw)) {
3248
+ if (!name.trim()) continue;
3249
+ if (typeof value !== "string") continue;
3250
+ if (reserved.has(name.toLowerCase())) continue;
3251
+ out[name] = value;
3252
+ }
3253
+ return Object.keys(out).length > 0 ? out : void 0;
3254
+ }
2348
3255
  function validateApiKeys(raw) {
2349
3256
  if (!Array.isArray(raw)) return void 0;
2350
3257
  const out = [];
@@ -2558,6 +3465,9 @@ function validateProvider(raw, index) {
2558
3465
  apiVersion,
2559
3466
  maxConcurrency,
2560
3467
  modelsEndpoint,
3468
+ // Static extra headers: load-guard (reserved names dropped), collapse-to-
3469
+ // undefined; enforced by the outbound header funnel + admin probes.
3470
+ extraHeaders: validateExtraHeaders(p["extraHeaders"]),
2561
3471
  // Provider transformer config (app-parity child 5): load-guard, collapse-to-
2562
3472
  // undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
2563
3473
  // Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
@@ -2627,7 +3537,7 @@ var import_node_crypto6 = require("crypto");
2627
3537
  var import_node_fs6 = require("fs");
2628
3538
  var import_node_os3 = require("os");
2629
3539
  var import_node_path6 = require("path");
2630
- var import_core = require("@omnicross/core");
3540
+ var import_core2 = require("@omnicross/core");
2631
3541
 
2632
3542
  // src/integrations/codexAuthHelper.ts
2633
3543
  var import_node_path4 = require("path");
@@ -3108,7 +4018,7 @@ var IntegrationManager = class {
3108
4018
  if (!secret) {
3109
4019
  throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
3110
4020
  }
3111
- const effective = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4021
+ const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3112
4022
  const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
3113
4023
  const nextPermissions = [...effective];
3114
4024
  for (const required of REQUIRED_PERMISSIONS[client]) {
@@ -3206,7 +4116,7 @@ var IntegrationManager = class {
3206
4116
  return { binding, row, secret, created: false };
3207
4117
  }
3208
4118
  async createManagedClientKey(client, state) {
3209
- const created = await (0, import_core.createIntegrationKey)(
4119
+ const created = await (0, import_core2.createIntegrationKey)(
3210
4120
  this.options.keyDb,
3211
4121
  `Omnicross ${displayClient(client)} integration`,
3212
4122
  [...REQUIRED_PERMISSIONS[client]]
@@ -3298,7 +4208,7 @@ var IntegrationManager = class {
3298
4208
  const row = rows.find((candidate) => candidate.id === keyId);
3299
4209
  if (!row) return { usable: false, message: "The bound access key no longer exists." };
3300
4210
  const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
3301
- const allowedEndpoints = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4211
+ const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3302
4212
  const status = {
3303
4213
  id: row.id,
3304
4214
  name: row.name,
@@ -3342,7 +4252,7 @@ var IntegrationManager = class {
3342
4252
  }
3343
4253
  };
3344
4254
  function hasRequiredPermissions(row, client) {
3345
- const allowed = (0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints);
4255
+ const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
3346
4256
  return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
3347
4257
  }
3348
4258
  function samePermissions(a, b) {
@@ -3516,7 +4426,8 @@ function listMappablePresets() {
3516
4426
  description: preset.description,
3517
4427
  features: preset.features,
3518
4428
  website: preset.website,
3519
- modelsEndpoint: preset.modelsEndpoint
4429
+ modelsEndpoint: preset.modelsEndpoint,
4430
+ extraHeaders: preset.extraHeaders
3520
4431
  });
3521
4432
  }
3522
4433
  return { mappable, excluded };
@@ -3606,11 +4517,11 @@ function preserveOutboundProxySecrets(incoming, current) {
3606
4517
  }
3607
4518
 
3608
4519
  // src/proxy/upstreamProxyResolver.ts
3609
- var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
4520
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
3610
4521
  var serverProxy;
3611
4522
  function setServerProxyConfig(proxy) {
3612
4523
  serverProxy = proxy;
3613
- (0, import_upstreamFetch5.bumpUpstreamProxyGeneration)();
4524
+ (0, import_upstreamFetch8.bumpUpstreamProxyGeneration)();
3614
4525
  }
3615
4526
  function getServerProxyConfig() {
3616
4527
  return serverProxy;
@@ -3678,7 +4589,7 @@ function createUpstreamProxyResolver(src = {}) {
3678
4589
  }
3679
4590
 
3680
4591
  // src/admin/accountsOAuth.ts
3681
- var import_subscriptions5 = require("@omnicross/subscriptions");
4592
+ var import_subscriptions8 = require("@omnicross/subscriptions");
3682
4593
 
3683
4594
  // src/admin/accountsWrite.ts
3684
4595
  var VALID_PROVIDER_IDS = [
@@ -3686,7 +4597,9 @@ var VALID_PROVIDER_IDS = [
3686
4597
  "codex",
3687
4598
  "gemini",
3688
4599
  "opencodego",
3689
- "kimi"
4600
+ "kimi",
4601
+ "grok",
4602
+ "copilot"
3690
4603
  ];
3691
4604
  function asSubscriptionProviderId(id) {
3692
4605
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -3834,6 +4747,40 @@ function validateKimi(body) {
3834
4747
  copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
3835
4748
  return out;
3836
4749
  }
4750
+ function validateGrok(body) {
4751
+ const authMethod = str(body["authMethod"]);
4752
+ const status = str(body["status"]);
4753
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4754
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4755
+ const out = {
4756
+ authMethod,
4757
+ status
4758
+ };
4759
+ copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
4760
+ return out;
4761
+ }
4762
+ function validateCopilot(body) {
4763
+ const authMethod = str(body["authMethod"]);
4764
+ const status = str(body["status"]);
4765
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4766
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4767
+ const out = {
4768
+ authMethod,
4769
+ status
4770
+ };
4771
+ copyOptional(out, body, [
4772
+ "accessToken",
4773
+ "refreshToken",
4774
+ "expiresAt",
4775
+ "accountId",
4776
+ "email",
4777
+ "apiEndpoint",
4778
+ "enterpriseUrl",
4779
+ "lastRefreshedAt",
4780
+ "errorMessage"
4781
+ ]);
4782
+ return out;
4783
+ }
3837
4784
  function validateOpenCodeGo(body) {
3838
4785
  const authMethod = str(body["authMethod"]);
3839
4786
  const status = str(body["status"]);
@@ -3871,6 +4818,10 @@ function validateTokenBody(providerId, body) {
3871
4818
  return validateOpenCodeGo(body);
3872
4819
  case "kimi":
3873
4820
  return validateKimi(body);
4821
+ case "grok":
4822
+ return validateGrok(body);
4823
+ case "copilot":
4824
+ return validateCopilot(body);
3874
4825
  default:
3875
4826
  return null;
3876
4827
  }
@@ -3900,37 +4851,37 @@ async function statusEntryFor(reader, providerId) {
3900
4851
 
3901
4852
  // src/admin/accountsOAuth.ts
3902
4853
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
3903
- function err3(status, message) {
4854
+ function err5(status, message) {
3904
4855
  return { status, body: { error: { type: "admin_api_error", message } } };
3905
4856
  }
3906
4857
  function handleOAuthStart(providerId, deps) {
3907
4858
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3908
- return err3(400, `oauth not available for provider '${providerId}'`);
4859
+ return err5(400, `oauth not available for provider '${providerId}'`);
3909
4860
  }
3910
- const flow = providerId === "claude" ? import_subscriptions5.claudeOAuth : import_subscriptions5.geminiOAuth;
4861
+ const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
3911
4862
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
3912
4863
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
3913
4864
  return { status: 200, body: { authUrl, sessionId } };
3914
4865
  }
3915
4866
  async function handleOAuthComplete(providerId, body, deps) {
3916
4867
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3917
- return err3(400, `oauth not available for provider '${providerId}'`);
4868
+ return err5(400, `oauth not available for provider '${providerId}'`);
3918
4869
  }
3919
4870
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
3920
4871
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
3921
- if (!sessionId) return err3(400, "oauth complete requires { sessionId }");
3922
- if (!rawCode) return err3(400, "oauth complete requires { code }");
4872
+ if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
4873
+ if (!rawCode) return err5(400, "oauth complete requires { code }");
3923
4874
  const session = deps.oauthSessions.peek(sessionId);
3924
- if (!session) return err3(410, "oauth session is unknown, expired, or already used");
4875
+ if (!session) return err5(410, "oauth session is unknown, expired, or already used");
3925
4876
  if (session.providerId !== providerId) {
3926
- return err3(400, `oauth session does not match provider '${providerId}'`);
4877
+ return err5(400, `oauth session does not match provider '${providerId}'`);
3927
4878
  }
3928
4879
  let code = rawCode.trim();
3929
4880
  if (providerId === "claude") {
3930
4881
  const [splitCode, pastedState] = code.split("#");
3931
- if (!splitCode) return err3(400, "no authorization code was provided");
4882
+ if (!splitCode) return err5(400, "no authorization code was provided");
3932
4883
  if (pastedState && pastedState !== session.state) {
3933
- return err3(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4884
+ return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
3934
4885
  }
3935
4886
  code = splitCode;
3936
4887
  }
@@ -3940,7 +4891,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3940
4891
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
3941
4892
  } catch (exchangeError) {
3942
4893
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
3943
- return err3(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4894
+ return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
3944
4895
  }
3945
4896
  deps.oauthSessions.consume(sessionId);
3946
4897
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -3949,7 +4900,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3949
4900
  return { status: 200, body: status ? { account: status } : { ok: true } };
3950
4901
  }
3951
4902
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3952
- const result = await import_subscriptions5.claudeOAuth.exchangeCodeForTokens(
4903
+ const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
3953
4904
  { authorizationCode: code, codeVerifier, state },
3954
4905
  exchangeFetch
3955
4906
  );
@@ -3965,7 +4916,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3965
4916
  };
3966
4917
  }
3967
4918
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
3968
- const result = await import_subscriptions5.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
4919
+ const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
3969
4920
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
3970
4921
  return {
3971
4922
  authMethod: "oauth",
@@ -4270,8 +5221,8 @@ function errBody(message) {
4270
5221
  return { error: { type: "admin_api_error", message } };
4271
5222
  }
4272
5223
  var defaultCommandRunner = (command) => new Promise((resolve10) => {
4273
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err6, _stdout, stderr) => {
4274
- if (err6) resolve10({ ok: false, error: stderr.trim() || err6.message });
5224
+ (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5225
+ if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
4275
5226
  else resolve10({ ok: true });
4276
5227
  });
4277
5228
  });
@@ -4317,8 +5268,8 @@ async function handleCliLaunch(cli, body, ctx) {
4317
5268
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
4318
5269
  model: typeof body["model"] === "string" ? body["model"] : void 0
4319
5270
  });
4320
- } catch (err6) {
4321
- return { status: 400, body: errBody(err6 instanceof Error ? err6.message : "no launch target") };
5271
+ } catch (err8) {
5272
+ return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
4322
5273
  }
4323
5274
  const id = (0, import_node_crypto7.randomUUID)();
4324
5275
  let leaseId2;
@@ -4346,9 +5297,9 @@ async function handleCliLaunch(cli, body, ctx) {
4346
5297
  } else {
4347
5298
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
4348
5299
  }
4349
- } catch (err6) {
4350
- const status = err6 instanceof import_provider_proxy2.RouteLeaseError ? err6.status : 400;
4351
- return { status, body: errBody(err6 instanceof Error ? err6.message : "failed to build launch env") };
5300
+ } catch (err8) {
5301
+ const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
5302
+ return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
4352
5303
  }
4353
5304
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
4354
5305
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -4376,9 +5327,9 @@ async function handleCliLaunch(cli, body, ctx) {
4376
5327
  onFailure: onSessionEnd
4377
5328
  });
4378
5329
  if (cleanup) openerCleanup = cleanup;
4379
- } catch (err6) {
5330
+ } catch (err8) {
4380
5331
  onSessionEnd();
4381
- return { status: 500, body: errBody(err6 instanceof Error ? err6.message : "failed to open terminal") };
5332
+ return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
4382
5333
  }
4383
5334
  if (ended) {
4384
5335
  openerCleanup?.();
@@ -4619,7 +5570,7 @@ function classifySearchFailure(stage, code) {
4619
5570
  }
4620
5571
 
4621
5572
  // src/search/SearchAssembly.ts
4622
- var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
5573
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
4623
5574
  var import_search = require("@omnicross/core/search");
4624
5575
  var import_api2 = require("@omnicross/core/search/api");
4625
5576
  var import_http2 = require("@omnicross/core/search/http");
@@ -4637,7 +5588,7 @@ function searchPolicyFrom(config) {
4637
5588
  };
4638
5589
  }
4639
5590
  function resolveSearchUpstreamDispatcher(url) {
4640
- return (0, import_upstreamFetch6.resolveUpstreamDispatcher)({ url });
5591
+ return (0, import_upstreamFetch9.resolveUpstreamDispatcher)({ url });
4641
5592
  }
4642
5593
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
4643
5594
  function resolveSearchUpstreamProxyConfig(url) {
@@ -4919,7 +5870,7 @@ async function handleSearchQuery(req, res, deps) {
4919
5870
  // src/admin/searchAdminView.ts
4920
5871
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
4921
5872
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
4922
- function isRecord2(value) {
5873
+ function isRecord5(value) {
4923
5874
  return value !== null && typeof value === "object" && !Array.isArray(value);
4924
5875
  }
4925
5876
  function redactSearchServerConfig(search) {
@@ -4969,13 +5920,13 @@ function resolveSecretField(entry, field, stored) {
4969
5920
  else delete entry[field];
4970
5921
  }
4971
5922
  function preserveSearchSecrets(incoming, current) {
4972
- if (!isRecord2(incoming)) return incoming;
5923
+ if (!isRecord5(incoming)) return incoming;
4973
5924
  const section = { ...incoming };
4974
5925
  const providersValue = section["providers"];
4975
- if (!isRecord2(providersValue)) return section;
5926
+ if (!isRecord5(providersValue)) return section;
4976
5927
  const providers = {};
4977
5928
  for (const [id, entryValue] of Object.entries(providersValue)) {
4978
- if (!isRecord2(entryValue)) {
5929
+ if (!isRecord5(entryValue)) {
4979
5930
  providers[id] = entryValue;
4980
5931
  continue;
4981
5932
  }
@@ -5053,7 +6004,7 @@ function parseKeyPolicyBody(body) {
5053
6004
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
5054
6005
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
5055
6006
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
5056
- function isRecord3(value) {
6007
+ function isRecord6(value) {
5057
6008
  return !!value && typeof value === "object" && !Array.isArray(value);
5058
6009
  }
5059
6010
  function nonBlank(value) {
@@ -5073,7 +6024,7 @@ function validateGatewayBindingsSegment(patch) {
5073
6024
  const ids = /* @__PURE__ */ new Set();
5074
6025
  raw.forEach((entry, index) => {
5075
6026
  const path2 = `bindings[${index}]`;
5076
- if (!isRecord3(entry)) {
6027
+ if (!isRecord6(entry)) {
5077
6028
  errors.push(`${path2} must be an object`);
5078
6029
  return;
5079
6030
  }
@@ -5102,12 +6053,12 @@ function validateGatewayBindingsSegment(patch) {
5102
6053
  } else if (entry.modelMappings.length > 100) {
5103
6054
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
5104
6055
  } else if (entry.modelMappings.some(
5105
- (mapping) => !isRecord3(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6056
+ (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5106
6057
  )) {
5107
6058
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
5108
6059
  }
5109
6060
  }
5110
- if (!isRecord3(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6061
+ if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5111
6062
  errors.push(`${path2}.target is invalid`);
5112
6063
  } else {
5113
6064
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -5122,7 +6073,7 @@ function validateGatewayBindingsSegment(patch) {
5122
6073
  }
5123
6074
  }
5124
6075
  if (entry.modelMap !== void 0) {
5125
- if (!isRecord3(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6076
+ if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
5126
6077
  errors.push(`${path2}.modelMap must contain string values`);
5127
6078
  }
5128
6079
  }
@@ -5421,7 +6372,9 @@ var PROVIDER_KEYS = {
5421
6372
  accounts: "opencodegoAccounts",
5422
6373
  active: "activeOpencodegoAccountId"
5423
6374
  },
5424
- kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
6375
+ kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6376
+ grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6377
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
5425
6378
  };
5426
6379
  function clone(value) {
5427
6380
  return JSON.parse(JSON.stringify(value));
@@ -5943,7 +6896,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
5943
6896
  }
5944
6897
 
5945
6898
  // src/admin/adminMigration.ts
5946
- function err4(status, message) {
6899
+ function err6(status, message) {
5947
6900
  return { status, body: { error: { type: "admin_api_error", message } } };
5948
6901
  }
5949
6902
  async function handleExport(body, deps) {
@@ -5953,30 +6906,30 @@ async function handleExport(body, deps) {
5953
6906
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
5954
6907
  } catch (error) {
5955
6908
  if (error instanceof WeakPassphraseError) {
5956
- return err4(400, error.message);
6909
+ return err6(400, error.message);
5957
6910
  }
5958
- return err4(500, "failed to build the migration pack");
6911
+ return err6(500, "failed to build the migration pack");
5959
6912
  }
5960
6913
  }
5961
6914
  async function handleImport(body, deps) {
5962
6915
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
5963
6916
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
5964
6917
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
5965
- if (!blob) return err4(400, "import requires { blob }");
6918
+ if (!blob) return err6(400, "import requires { blob }");
5966
6919
  try {
5967
6920
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
5968
6921
  return { status: 200, body: counts };
5969
6922
  } catch (error) {
5970
6923
  if (error instanceof WeakPassphraseError) {
5971
- return err4(400, error.message);
6924
+ return err6(400, error.message);
5972
6925
  }
5973
- return err4(400, error instanceof Error ? error.message : "import failed");
6926
+ return err6(400, error instanceof Error ? error.message : "import failed");
5974
6927
  }
5975
6928
  }
5976
6929
 
5977
6930
  // src/admin/usagePricing.ts
5978
6931
  var import_usage = require("@omnicross/core/usage");
5979
- var err5 = (status, message) => ({
6932
+ var err7 = (status, message) => ({
5980
6933
  status,
5981
6934
  body: { error: { type: "admin_api_error", message } }
5982
6935
  });
@@ -5989,7 +6942,7 @@ function parseRange(query2) {
5989
6942
  const startTs = parseFiniteInt(query2.get("startTs"));
5990
6943
  const endTs = parseFiniteInt(query2.get("endTs"));
5991
6944
  if (startTs === null || endTs === null) {
5992
- return err5(400, "startTs and endTs are required finite-integer unix-millis query params");
6945
+ return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
5993
6946
  }
5994
6947
  return { startTs, endTs };
5995
6948
  }
@@ -6014,14 +6967,14 @@ async function handleUsageGet(view, query2, deps) {
6014
6967
  case "timeseries": {
6015
6968
  const bucket = query2.get("bucket");
6016
6969
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
6017
- return err5(400, "bucket must be one of 'hour', 'day', 'month'");
6970
+ return err7(400, "bucket must be one of 'hour', 'day', 'month'");
6018
6971
  }
6019
6972
  const now = Date.now();
6020
6973
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
6021
6974
  if (clamped.startTs < clamped.endTs) {
6022
6975
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
6023
6976
  if (projected > MAX_TIMESERIES_BUCKETS) {
6024
- return err5(
6977
+ return err7(
6025
6978
  400,
6026
6979
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
6027
6980
  );
@@ -6044,7 +6997,7 @@ async function handleUsageGet(view, query2, deps) {
6044
6997
  };
6045
6998
  }
6046
6999
  default:
6047
- return err5(404, `unknown usage view '${view ?? ""}'`);
7000
+ return err7(404, `unknown usage view '${view ?? ""}'`);
6048
7001
  }
6049
7002
  }
6050
7003
  function poolKeyLabels(cfg) {
@@ -6093,7 +7046,7 @@ async function handlePricingList(deps) {
6093
7046
  async function handlePricingUpsert(body, deps) {
6094
7047
  const input = parsePricingEntryInput(body);
6095
7048
  if (!input) {
6096
- return err5(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7049
+ return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
6097
7050
  }
6098
7051
  const entry = await deps.pricingEngine.upsertManual(input);
6099
7052
  return { status: 200, body: { entry } };
@@ -6102,7 +7055,7 @@ async function handlePricingDelete(query2, deps) {
6102
7055
  const providerId = query2.get("providerId")?.trim() ?? "";
6103
7056
  const modelId = query2.get("modelId")?.trim() ?? "";
6104
7057
  if (!providerId || !modelId) {
6105
- return err5(400, "delete requires providerId and modelId query params");
7058
+ return err7(400, "delete requires providerId and modelId query params");
6106
7059
  }
6107
7060
  const deleted = await deps.pricingStore.delete(providerId, modelId);
6108
7061
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -6122,13 +7075,13 @@ async function handlePricingFetchLatest(deps) {
6122
7075
  }
6123
7076
  };
6124
7077
  } catch (e) {
6125
- return err5(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7078
+ return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
6126
7079
  }
6127
7080
  }
6128
7081
  async function handlePricingResolveConflicts(body, deps) {
6129
7082
  const raw = body["resolutions"];
6130
7083
  if (!Array.isArray(raw)) {
6131
- return err5(400, "resolve-conflicts requires { resolutions: [...] }");
7084
+ return err7(400, "resolve-conflicts requires { resolutions: [...] }");
6132
7085
  }
6133
7086
  const currentRows = await deps.pricingStore.getAll();
6134
7087
  const userEditedKeys = new Set(
@@ -6138,21 +7091,21 @@ async function handlePricingResolveConflicts(body, deps) {
6138
7091
  const pendingIncoming = /* @__PURE__ */ new Map();
6139
7092
  let staleCount = 0;
6140
7093
  for (const item of raw) {
6141
- if (!item || typeof item !== "object") return err5(400, "invalid resolution entry");
7094
+ if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
6142
7095
  const r = item;
6143
7096
  const action = r["action"];
6144
7097
  if (action !== "overwrite" && action !== "skip") {
6145
- return err5(400, "resolution action must be 'overwrite' or 'skip'");
7098
+ return err7(400, "resolution action must be 'overwrite' or 'skip'");
6146
7099
  }
6147
7100
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
6148
7101
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
6149
7102
  if (!providerId || !modelId) {
6150
- return err5(400, "each resolution requires top-level providerId and modelId");
7103
+ return err7(400, "each resolution requires top-level providerId and modelId");
6151
7104
  }
6152
7105
  const incoming = parsePricingEntryInput(r["incoming"]);
6153
- if (!incoming) return err5(400, "each resolution must echo a valid incoming pricing entry");
7106
+ if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
6154
7107
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
6155
- return err5(400, "resolution providerId/modelId must match the echoed incoming entry");
7108
+ return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
6156
7109
  }
6157
7110
  const key = `${providerId}::${modelId}`;
6158
7111
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -6197,7 +7150,7 @@ function query(req) {
6197
7150
  }
6198
7151
  function allowanceProvider(value) {
6199
7152
  if (!value) return void 0;
6200
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
7153
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
6201
7154
  }
6202
7155
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
6203
7156
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -6212,7 +7165,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6212
7165
  const pathProvider = rest.length >= 2 ? rest[0] : null;
6213
7166
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
6214
7167
  if (providerId === null) {
6215
- return writeError2(res, 400, "providerId must be claude, codex, kimi, or opencodego");
7168
+ return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, copilot, or gemini");
6216
7169
  }
6217
7170
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
6218
7171
  const allowances = await service.list({ providerId, accountId });
@@ -6254,6 +7207,36 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6254
7207
  }
6255
7208
  return writeJson3(res, 200, { allowances: allowances2 });
6256
7209
  }
7210
+ if (requestedProvider === "copilot") {
7211
+ if (!service.refreshCopilot) {
7212
+ return writeError2(res, 501, "copilot allowance refresh is not available");
7213
+ }
7214
+ const allowances2 = await service.refreshCopilot(accountId);
7215
+ if (accountId && allowances2.length === 0) {
7216
+ return writeError2(res, 404, `Copilot account '${accountId}' not found`);
7217
+ }
7218
+ return writeJson3(res, 200, { allowances: allowances2 });
7219
+ }
7220
+ if (requestedProvider === "grok") {
7221
+ if (!service.refreshGrok) {
7222
+ return writeError2(res, 501, "grok allowance refresh is not available");
7223
+ }
7224
+ const allowances2 = await service.refreshGrok(accountId);
7225
+ if (accountId && allowances2.length === 0) {
7226
+ return writeError2(res, 404, `Grok account '${accountId}' not found`);
7227
+ }
7228
+ return writeJson3(res, 200, { allowances: allowances2 });
7229
+ }
7230
+ if (requestedProvider === "gemini") {
7231
+ if (!service.refreshGemini) {
7232
+ return writeError2(res, 501, "gemini allowance refresh is not available");
7233
+ }
7234
+ const allowances2 = await service.refreshGemini(accountId);
7235
+ if (accountId && allowances2.length === 0) {
7236
+ return writeError2(res, 404, `Gemini account '${accountId}' not found`);
7237
+ }
7238
+ return writeJson3(res, 200, { allowances: allowances2 });
7239
+ }
6257
7240
  const allowances = await service.refreshClaude(accountId);
6258
7241
  if (accountId && allowances.length === 0) {
6259
7242
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
@@ -6352,6 +7335,9 @@ function toProviderView(row) {
6352
7335
  apiVersion: row.apiVersion,
6353
7336
  maxConcurrency: row.maxConcurrency,
6354
7337
  modelsEndpoint: row.modelsEndpoint,
7338
+ // Static extra headers round-trip VERBATIM (non-secret identity values;
7339
+ // auth/content names were already dropped at the write/load gate).
7340
+ extraHeaders: row.extraHeaders,
6355
7341
  // app-parity child 5: transformer config round-trips VERBATIM (non-secret —
6356
7342
  // transform-rule names + options, no key material; absent stays absent).
6357
7343
  transformer: row.transformer,
@@ -6421,8 +7407,8 @@ async function handleAdminApi(req, res, path2, deps) {
6421
7407
  default:
6422
7408
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
6423
7409
  }
6424
- } catch (err6) {
6425
- writeJsonError(res, 500, err6 instanceof Error ? err6.message : String(err6));
7410
+ } catch (err8) {
7411
+ writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
6426
7412
  }
6427
7413
  }
6428
7414
  function requestQuery(req) {
@@ -6580,6 +7566,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
6580
7566
  persistProviders(cfg, deps);
6581
7567
  return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
6582
7568
  }
7569
+ function expandRowExtraHeaders(row) {
7570
+ return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
7571
+ }
6583
7572
  async function handleDiscoverModels(res, id, cfg) {
6584
7573
  if (!id) return writeJsonError(res, 400, "provider id required in path");
6585
7574
  const row = cfg.providers.find((p) => p.id === id);
@@ -6593,7 +7582,8 @@ async function handleDiscoverModels(res, id, cfg) {
6593
7582
  try {
6594
7583
  const headers = { Accept: "application/json" };
6595
7584
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
6596
- const response = await (0, import_upstreamFetch7.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
7585
+ Object.assign(headers, expandRowExtraHeaders(row));
7586
+ const response = await (0, import_upstreamFetch10.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
6597
7587
  if (!response.ok) {
6598
7588
  const text = await response.text().catch(() => "");
6599
7589
  let message = text.slice(0, 300);
@@ -6610,8 +7600,8 @@ async function handleDiscoverModels(res, id, cfg) {
6610
7600
  const data = await response.json();
6611
7601
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
6612
7602
  return writeJson4(res, 200, { models });
6613
- } catch (err6) {
6614
- const message = err6 instanceof Error ? err6.message : String(err6);
7603
+ } catch (err8) {
7604
+ const message = err8 instanceof Error ? err8.message : String(err8);
6615
7605
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
6616
7606
  }
6617
7607
  }
@@ -6650,9 +7640,10 @@ async function handleTestModel(req, res, id, cfg) {
6650
7640
  messages: [{ role: "user", content: prompt }]
6651
7641
  };
6652
7642
  }
7643
+ Object.assign(headers, expandRowExtraHeaders(row));
6653
7644
  const startedAt = Date.now();
6654
7645
  try {
6655
- const response = await (0, import_upstreamFetch7.fetchUpstream)(
7646
+ const response = await (0, import_upstreamFetch10.fetchUpstream)(
6656
7647
  url,
6657
7648
  { method: "POST", headers, body: JSON.stringify(payload) },
6658
7649
  { providerId: "byo" }
@@ -6674,8 +7665,8 @@ async function handleTestModel(req, res, id, cfg) {
6674
7665
  latencyMs,
6675
7666
  sample: extractSampleText(text, row.apiFormat)
6676
7667
  });
6677
- } catch (err6) {
6678
- const message = err6 instanceof Error ? err6.message : String(err6);
7668
+ } catch (err8) {
7669
+ const message = err8 instanceof Error ? err8.message : String(err8);
6679
7670
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
6680
7671
  }
6681
7672
  }
@@ -6957,6 +7948,7 @@ function parseProviderInput(body, existing) {
6957
7948
  const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
6958
7949
  const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
6959
7950
  const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
7951
+ const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
6960
7952
  const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
6961
7953
  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;
6962
7954
  const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
@@ -6982,6 +7974,7 @@ function parseProviderInput(body, existing) {
6982
7974
  apiVersion,
6983
7975
  maxConcurrency,
6984
7976
  modelsEndpoint,
7977
+ extraHeaders,
6985
7978
  transformer: migrated.transformer,
6986
7979
  codingPlan,
6987
7980
  apiModes,
@@ -7003,7 +7996,10 @@ function handlePresets(res, method) {
7003
7996
  description: p.description,
7004
7997
  features: p.features,
7005
7998
  website: p.website,
7006
- modelsEndpoint: p.modelsEndpoint
7999
+ modelsEndpoint: p.modelsEndpoint,
8000
+ // Static extra headers ride along so `addFromPreset` can seed them onto the
8001
+ // row (the write gateway re-validates via the shared allowlist).
8002
+ extraHeaders: p.extraHeaders
7007
8003
  }));
7008
8004
  return writeJson4(res, 200, { presets, excluded });
7009
8005
  }
@@ -7485,12 +8481,12 @@ async function handleAccounts(req, res, method, rest, deps) {
7485
8481
  }
7486
8482
  return writeJson4(res, 200, { ok: true, affected: result.affected });
7487
8483
  }
7488
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[3] === "status") {
7489
- const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : handleKimiOAuthStatus(rest[2], deps);
8484
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
8485
+ 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);
7490
8486
  return writeJson4(res, result.status, result.body);
7491
8487
  }
7492
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[2]) {
7493
- const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : handleKimiOAuthCancel(rest[2], deps);
8488
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
8489
+ 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);
7494
8490
  return writeJson4(res, result.status, result.body);
7495
8491
  }
7496
8492
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -7551,6 +8547,15 @@ async function handleAccounts(req, res, method, rest, deps) {
7551
8547
  const result2 = await handleKimiOAuthStart(deps);
7552
8548
  return writeJson4(res, result2.status, result2.body);
7553
8549
  }
8550
+ if (providerId === "grok") {
8551
+ const result2 = await handleGrokOAuthStart(deps);
8552
+ return writeJson4(res, result2.status, result2.body);
8553
+ }
8554
+ if (providerId === "copilot") {
8555
+ const body2 = await readJsonBody4(req);
8556
+ const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
8557
+ return writeJson4(res, result2.status, result2.body);
8558
+ }
7554
8559
  const result = handleOAuthStart(providerId, deps);
7555
8560
  return writeJson4(res, result.status, result.body);
7556
8561
  }
@@ -8045,12 +9050,12 @@ async function handlePlayground(req, res, method, deps) {
8045
9050
  const payload = body["body"];
8046
9051
  const status = deps.outboundApiServer.getStatus();
8047
9052
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
8048
- const path2 = resolvePlaygroundPath(endpoint, isRecord4(payload) ? payload : {});
9053
+ const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
8049
9054
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
8050
9055
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
8051
9056
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
8052
9057
  }
8053
- function isRecord4(v) {
9058
+ function isRecord7(v) {
8054
9059
  return !!v && typeof v === "object" && !Array.isArray(v);
8055
9060
  }
8056
9061
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -8079,8 +9084,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
8079
9084
  });
8080
9085
  }
8081
9086
  );
8082
- upstream.on("error", (err6) => {
8083
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err6.message}`);
9087
+ upstream.on("error", (err8) => {
9088
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
8084
9089
  else res.end();
8085
9090
  resolve10();
8086
9091
  });
@@ -8186,7 +9191,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
8186
9191
  }
8187
9192
 
8188
9193
  // src/admin/version.ts
8189
- var DAEMON_VERSION = true ? "0.3.1" : "0.0.0-dev";
9194
+ var DAEMON_VERSION = true ? "0.4.1" : "0.0.0-dev";
8190
9195
 
8191
9196
  // src/admin/AdminServer.ts
8192
9197
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -8229,13 +9234,13 @@ var AdminServer = class {
8229
9234
  const server = import_node_http2.default.createServer((req, res) => {
8230
9235
  this.onRequest(req, res);
8231
9236
  });
8232
- const onError = (err6) => {
8233
- if (err6.code === "EADDRINUSE" && port !== 0) {
9237
+ const onError = (err8) => {
9238
+ if (err8.code === "EADDRINUSE" && port !== 0) {
8234
9239
  server.removeListener("error", onError);
8235
9240
  this.listen(bindAddr, 0).then(resolve10, reject);
8236
9241
  return;
8237
9242
  }
8238
- reject(err6);
9243
+ reject(err8);
8239
9244
  };
8240
9245
  server.on("error", onError);
8241
9246
  server.listen(port, bindAddr, () => {
@@ -8253,8 +9258,8 @@ var AdminServer = class {
8253
9258
  }
8254
9259
  /** Per-request handler: auth gate (when a token is set) → routing. */
8255
9260
  onRequest(req, res) {
8256
- void this.dispatch(req, res).catch((err6) => {
8257
- const message = err6 instanceof Error ? err6.message : String(err6);
9261
+ void this.dispatch(req, res).catch((err8) => {
9262
+ const message = err8 instanceof Error ? err8.message : String(err8);
8258
9263
  this.deps.logger.error("[AdminServer] unhandled error:", message);
8259
9264
  if (!res.headersSent) {
8260
9265
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -8518,18 +9523,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
8518
9523
  return;
8519
9524
  }
8520
9525
  signal?.addEventListener("abort", abort, { once: true });
8521
- server.on("error", (err6) => {
9526
+ server.on("error", (err8) => {
8522
9527
  if (settled) return;
8523
9528
  settled = true;
8524
9529
  clearTimeout(timer);
8525
- if (err6.code === "EADDRINUSE") {
9530
+ if (err8.code === "EADDRINUSE") {
8526
9531
  reject(
8527
9532
  new Error(
8528
9533
  `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
8529
9534
  )
8530
9535
  );
8531
9536
  } else {
8532
- reject(err6);
9537
+ reject(err8);
8533
9538
  }
8534
9539
  });
8535
9540
  const timer = setTimeout(() => {
@@ -8605,21 +9610,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
8605
9610
  }
8606
9611
 
8607
9612
  // src/allowance/ProviderKeyQuotaService.ts
8608
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
9613
+ var import_core4 = require("@omnicross/core");
9614
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
8609
9615
 
8610
9616
  // src/allowance/ProviderKeyQuota.ts
8611
- var MINUTE_MS2 = 6e4;
8612
- var HOUR_MS2 = 60 * MINUTE_MS2;
8613
- var DAY_MS2 = 24 * HOUR_MS2;
8614
- var WEEK_MS = 7 * DAY_MS2;
8615
- var MONTH_MS = 30 * DAY_MS2;
8616
- function finiteNumber3(value) {
9617
+ var MINUTE_MS3 = 6e4;
9618
+ var HOUR_MS2 = 60 * MINUTE_MS3;
9619
+ var DAY_MS3 = 24 * HOUR_MS2;
9620
+ var WEEK_MS = 7 * DAY_MS3;
9621
+ var MONTH_MS = 30 * DAY_MS3;
9622
+ function finiteNumber5(value) {
8617
9623
  if (value === null || value === void 0 || value === "") return void 0;
8618
9624
  const parsed = typeof value === "number" ? value : Number(value);
8619
9625
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
8620
9626
  }
8621
9627
  function finitePercent4(value) {
8622
- const parsed = finiteNumber3(value);
9628
+ const parsed = finiteNumber5(value);
8623
9629
  return parsed !== void 0 && parsed <= 100 ? parsed : null;
8624
9630
  }
8625
9631
  function isoInstant3(value) {
@@ -8627,18 +9633,18 @@ function isoInstant3(value) {
8627
9633
  const time = Date.parse(value);
8628
9634
  if (Number.isFinite(time)) return new Date(time).toISOString();
8629
9635
  }
8630
- const numeric = finiteNumber3(value);
9636
+ const numeric = finiteNumber5(value);
8631
9637
  if (numeric !== void 0 && numeric > 1e9) {
8632
9638
  const ms = numeric > 1e12 ? numeric : numeric * 1e3;
8633
9639
  return new Date(ms).toISOString();
8634
9640
  }
8635
9641
  return void 0;
8636
9642
  }
8637
- function secondsUntil5(instant, now) {
9643
+ function secondsUntil8(instant, now) {
8638
9644
  if (!instant) return void 0;
8639
9645
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
8640
9646
  }
8641
- function isRecord5(value) {
9647
+ function isRecord8(value) {
8642
9648
  return !!value && typeof value === "object" && !Array.isArray(value);
8643
9649
  }
8644
9650
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -8651,7 +9657,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
8651
9657
  }
8652
9658
  const host = url.hostname.toLowerCase();
8653
9659
  const path2 = url.pathname.toLowerCase();
8654
- if ((host === "api.z.ai" || host === "open.bigmodel.cn") && path2.includes("/coding")) {
9660
+ if ((host === "api.z.ai" || host === "open.bigmodel.cn") && (path2.includes("/coding") || path2.includes("/anthropic"))) {
8655
9661
  return "zai";
8656
9662
  }
8657
9663
  if ((host === "api.minimax.io" || host === "api.minimaxi.com") && // Token Plan rides the plain openai `/v1` (chat completions) surface; the
@@ -8661,6 +9667,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
8661
9667
  }
8662
9668
  if (host === "api.code.umans.ai") return "umans";
8663
9669
  if (host === "api.synthetic.new") return "synthetic";
9670
+ if (host === "api.cline.bot") return "cline-pass";
8664
9671
  return null;
8665
9672
  }
8666
9673
  function providerKeyQuotaUrl(adapter, baseUrl) {
@@ -8668,6 +9675,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
8668
9675
  if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
8669
9676
  if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
8670
9677
  if (adapter === "umans") return `${origin}/v1/usage`;
9678
+ if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
8671
9679
  return `${origin}/v2/quotas`;
8672
9680
  }
8673
9681
  function providerKeyQuotaAuthHeader(adapter, key) {
@@ -8679,7 +9687,7 @@ function zaiWindowDurationMs(item) {
8679
9687
  case 3:
8680
9688
  return count * HOUR_MS2;
8681
9689
  case 4:
8682
- return count * DAY_MS2;
9690
+ return count * DAY_MS3;
8683
9691
  case 5:
8684
9692
  return count * MONTH_MS;
8685
9693
  case 6:
@@ -8692,8 +9700,8 @@ function zaiWindowIdLabel(durationMs) {
8692
9700
  if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
8693
9701
  if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
8694
9702
  if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
8695
- if (durationMs !== void 0 && durationMs % DAY_MS2 === 0) {
8696
- const days = durationMs / DAY_MS2;
9703
+ if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
9704
+ const days = durationMs / DAY_MS3;
8697
9705
  return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
8698
9706
  }
8699
9707
  if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
@@ -8703,23 +9711,23 @@ function zaiWindowIdLabel(durationMs) {
8703
9711
  return { id: "quota", label: "Quota" };
8704
9712
  }
8705
9713
  function parseZaiQuotaPayload(payload, now) {
8706
- if (!isRecord5(payload)) return null;
8707
- const data = isRecord5(payload["data"]) ? payload["data"] : payload;
9714
+ if (!isRecord8(payload)) return null;
9715
+ const data = isRecord8(payload["data"]) ? payload["data"] : payload;
8708
9716
  if (payload["success"] === false) return null;
8709
9717
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
8710
9718
  const byWindow = /* @__PURE__ */ new Map();
8711
9719
  for (const raw of limits) {
8712
- if (!isRecord5(raw)) continue;
9720
+ if (!isRecord8(raw)) continue;
8713
9721
  const item = raw;
8714
9722
  if (item.type === void 0) continue;
8715
9723
  const details = raw["usageDetails"];
8716
- if (Array.isArray(details) && details.some((d) => isRecord5(d) && d["modelCode"] === "zread")) {
9724
+ if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
8717
9725
  continue;
8718
9726
  }
8719
9727
  const durationMs = zaiWindowDurationMs(item);
8720
9728
  const { id, label } = zaiWindowIdLabel(durationMs);
8721
- const limit = finiteNumber3(item.usage);
8722
- const used = finiteNumber3(item.currentValue);
9729
+ const limit = finiteNumber5(item.usage);
9730
+ const used = finiteNumber5(item.currentValue);
8723
9731
  const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
8724
9732
  const fromPercentage = finitePercent4(item.percentage) ?? void 0;
8725
9733
  const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
@@ -8730,9 +9738,9 @@ function parseZaiQuotaPayload(payload, now) {
8730
9738
  label,
8731
9739
  scope: "all",
8732
9740
  usedPercent,
8733
- ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS2) } : {},
9741
+ ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
8734
9742
  ...resetsAt !== void 0 ? { resetsAt } : {},
8735
- remainingSeconds: secondsUntil5(resetsAt, now),
9743
+ remainingSeconds: secondsUntil8(resetsAt, now),
8736
9744
  state: "fresh"
8737
9745
  };
8738
9746
  const existing = byWindow.get(id);
@@ -8746,21 +9754,21 @@ function parseZaiQuotaPayload(payload, now) {
8746
9754
  var MINIMAX_STATUS_EXHAUSTED = 2;
8747
9755
  var MINIMAX_SHARED_BUCKET = "general";
8748
9756
  function parseMiniMaxBucket(value) {
8749
- if (!isRecord5(value)) return null;
9757
+ if (!isRecord8(value)) return null;
8750
9758
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
8751
9759
  if (!modelName) return null;
8752
9760
  const instant = (v) => {
8753
- const n = finiteNumber3(v);
9761
+ const n = finiteNumber5(v);
8754
9762
  return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
8755
9763
  };
8756
9764
  return {
8757
9765
  modelName,
8758
9766
  intervalEnd: instant(value["end_time"]),
8759
- intervalRemainingPercent: finiteNumber3(value["current_interval_remaining_percent"]),
8760
- intervalStatus: finiteNumber3(value["current_interval_status"]),
9767
+ intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
9768
+ intervalStatus: finiteNumber5(value["current_interval_status"]),
8761
9769
  weeklyEnd: instant(value["weekly_end_time"]),
8762
- weeklyRemainingPercent: finiteNumber3(value["current_weekly_remaining_percent"]),
8763
- weeklyStatus: finiteNumber3(value["current_weekly_status"])
9770
+ weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
9771
+ weeklyStatus: finiteNumber5(value["current_weekly_status"])
8764
9772
  };
8765
9773
  }
8766
9774
  function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
@@ -8773,14 +9781,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
8773
9781
  usedPercent,
8774
9782
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
8775
9783
  ...resetsAt !== void 0 ? { resetsAt } : {},
8776
- remainingSeconds: secondsUntil5(resetsAt, now),
9784
+ remainingSeconds: secondsUntil8(resetsAt, now),
8777
9785
  state: usedPercent !== null ? "fresh" : "unavailable"
8778
9786
  };
8779
9787
  }
8780
9788
  function parseMiniMaxTokenPlanPayload(payload, now) {
8781
- if (!isRecord5(payload)) return null;
9789
+ if (!isRecord8(payload)) return null;
8782
9790
  const baseResp = payload["base_resp"];
8783
- if (!isRecord5(baseResp) || baseResp["status_code"] !== 0) return null;
9791
+ if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
8784
9792
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
8785
9793
  let general = null;
8786
9794
  for (const raw of buckets) {
@@ -8804,7 +9812,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
8804
9812
  minimaxWindow(
8805
9813
  "seven-day",
8806
9814
  "7 days",
8807
- Math.round(WEEK_MS / MINUTE_MS2),
9815
+ Math.round(WEEK_MS / MINUTE_MS3),
8808
9816
  general.weeklyEnd,
8809
9817
  general.weeklyRemainingPercent,
8810
9818
  general.weeklyStatus,
@@ -8813,15 +9821,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
8813
9821
  ];
8814
9822
  }
8815
9823
  function parseUmansUsagePayload(payload, now) {
8816
- if (!isRecord5(payload)) return null;
8817
- const limits = isRecord5(payload["limits"]) ? payload["limits"] : void 0;
8818
- const requests = limits && isRecord5(limits["requests"]) ? limits["requests"] : void 0;
8819
- const usage = isRecord5(payload["usage"]) ? payload["usage"] : void 0;
8820
- const window = isRecord5(payload["window"]) ? payload["window"] : void 0;
8821
- const hardCap = finiteNumber3(requests?.["hard_cap"]);
8822
- const softLimit = finiteNumber3(requests?.["limit"]);
8823
- const requestsInWindow = finiteNumber3(usage?.["requests_in_window"]);
8824
- const weightedInWindow = finiteNumber3(usage?.["weighted_in_window"]);
9824
+ if (!isRecord8(payload)) return null;
9825
+ const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
9826
+ const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
9827
+ const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
9828
+ const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
9829
+ const hardCap = finiteNumber5(requests?.["hard_cap"]);
9830
+ const softLimit = finiteNumber5(requests?.["limit"]);
9831
+ const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
9832
+ const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
8825
9833
  const resetsAt = isoInstant3(window?.["resets_at"]);
8826
9834
  let usedPercent = null;
8827
9835
  if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
@@ -8838,19 +9846,19 @@ function parseUmansUsagePayload(payload, now) {
8838
9846
  usedPercent,
8839
9847
  windowMinutes: 5 * 60,
8840
9848
  ...resetsAt !== void 0 ? { resetsAt } : {},
8841
- remainingSeconds: secondsUntil5(resetsAt, now),
9849
+ remainingSeconds: secondsUntil8(resetsAt, now),
8842
9850
  state: "fresh"
8843
9851
  }
8844
9852
  ];
8845
9853
  }
8846
9854
  function parseSyntheticQuotasPayload(payload, now) {
8847
- if (!isRecord5(payload)) return null;
8848
- const fiveHour = isRecord5(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
8849
- const weekly = isRecord5(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
9855
+ if (!isRecord8(payload)) return null;
9856
+ const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
9857
+ const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
8850
9858
  const windows = [];
8851
9859
  if (fiveHour) {
8852
- const max = finiteNumber3(fiveHour["max"]);
8853
- const remaining = finiteNumber3(fiveHour["remaining"]);
9860
+ const max = finiteNumber5(fiveHour["max"]);
9861
+ const remaining = finiteNumber5(fiveHour["remaining"]);
8854
9862
  const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
8855
9863
  const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
8856
9864
  windows.push({
@@ -8860,12 +9868,12 @@ function parseSyntheticQuotasPayload(payload, now) {
8860
9868
  usedPercent,
8861
9869
  windowMinutes: 5 * 60,
8862
9870
  ...resetsAt !== void 0 ? { resetsAt } : {},
8863
- remainingSeconds: secondsUntil5(resetsAt, now),
9871
+ remainingSeconds: secondsUntil8(resetsAt, now),
8864
9872
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
8865
9873
  });
8866
9874
  }
8867
9875
  if (weekly) {
8868
- const percentRemaining = finiteNumber3(weekly["percentRemaining"]);
9876
+ const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
8869
9877
  const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
8870
9878
  const resetsAt = isoInstant3(weekly["nextRegenAt"]);
8871
9879
  windows.push({
@@ -8875,12 +9883,42 @@ function parseSyntheticQuotasPayload(payload, now) {
8875
9883
  usedPercent,
8876
9884
  windowMinutes: 7 * 24 * 60,
8877
9885
  ...resetsAt !== void 0 ? { resetsAt } : {},
8878
- remainingSeconds: secondsUntil5(resetsAt, now),
9886
+ remainingSeconds: secondsUntil8(resetsAt, now),
8879
9887
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
8880
9888
  });
8881
9889
  }
8882
9890
  return windows.length > 0 ? windows : null;
8883
9891
  }
9892
+ var CLINE_WINDOW_CONFIG = {
9893
+ five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
9894
+ weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
9895
+ monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
9896
+ };
9897
+ function parseClinePassUsageLimitsPayload(payload, now) {
9898
+ if (!isRecord8(payload)) return null;
9899
+ const data = isRecord8(payload["data"]) ? payload["data"] : payload;
9900
+ const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9901
+ const windows = [];
9902
+ for (const raw of limits) {
9903
+ if (!isRecord8(raw)) continue;
9904
+ const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
9905
+ if (!config) continue;
9906
+ const usedPercent = finitePercent4(raw["percentUsed"]);
9907
+ if (usedPercent === null) continue;
9908
+ const resetsAt = isoInstant3(raw["resetsAt"]);
9909
+ windows.push({
9910
+ id: config.id,
9911
+ label: config.label,
9912
+ scope: "all",
9913
+ usedPercent,
9914
+ windowMinutes: config.minutes,
9915
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9916
+ remainingSeconds: secondsUntil8(resetsAt, now),
9917
+ state: "fresh"
9918
+ });
9919
+ }
9920
+ return windows.length > 0 ? windows : null;
9921
+ }
8884
9922
 
8885
9923
  // src/allowance/ProviderKeyQuotaService.ts
8886
9924
  function parseQuotaPayload(adapter, payload, now) {
@@ -8893,6 +9931,8 @@ function parseQuotaPayload(adapter, payload, now) {
8893
9931
  return parseUmansUsagePayload(payload, now);
8894
9932
  case "synthetic":
8895
9933
  return parseSyntheticQuotasPayload(payload, now);
9934
+ case "cline-pass":
9935
+ return parseClinePassUsageLimitsPayload(payload, now);
8896
9936
  }
8897
9937
  }
8898
9938
  var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
@@ -8912,7 +9952,7 @@ function rowKeyEntries(row) {
8912
9952
  return [];
8913
9953
  }
8914
9954
  var ProviderKeyQuotaService = class {
8915
- constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
9955
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
8916
9956
  this.box = box;
8917
9957
  this.fetchImpl = fetchImpl;
8918
9958
  this.now = now;
@@ -8974,7 +10014,10 @@ var ProviderKeyQuotaService = class {
8974
10014
  headers: {
8975
10015
  Authorization: providerKeyQuotaAuthHeader(adapter, key),
8976
10016
  Accept: "application/json",
8977
- "Content-Type": "application/json"
10017
+ "Content-Type": "application/json",
10018
+ // The row's static identity headers ride along — the Cline usage
10019
+ // endpoint sits behind the SAME client-identity 403 gate as inference.
10020
+ ...(0, import_core4.mergeExtraHeaders)({}, row.extraHeaders)
8978
10021
  },
8979
10022
  signal: AbortSignal.timeout(15e3)
8980
10023
  });
@@ -9045,7 +10088,7 @@ function defaultBillingDir(configPath) {
9045
10088
  // src/image-generation/ImageDoctorService.ts
9046
10089
  var import_image_generation = require("@omnicross/core/image-generation");
9047
10090
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
9048
- var import_subscriptions6 = require("@omnicross/subscriptions");
10091
+ var import_subscriptions9 = require("@omnicross/subscriptions");
9049
10092
 
9050
10093
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
9051
10094
  var import_node_crypto13 = require("crypto");
@@ -9483,7 +10526,7 @@ function createImageDoctorService(options) {
9483
10526
  paths,
9484
10527
  ttlMs: config.evidenceTtlMs
9485
10528
  }));
9486
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions6.createCodexImageLiveVerifier)({
10529
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
9487
10530
  authStrategy: strategy,
9488
10531
  generationTimeoutMs: config.queue.generationTimeoutMs
9489
10532
  }));
@@ -9845,7 +10888,7 @@ var ImageCleanupService = class {
9845
10888
  var import_node_crypto16 = require("crypto");
9846
10889
  var import_image_generation5 = require("@omnicross/core/image-generation");
9847
10890
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
9848
- var import_subscriptions7 = require("@omnicross/subscriptions");
10891
+ var import_subscriptions10 = require("@omnicross/subscriptions");
9849
10892
 
9850
10893
  // src/image-generation/ImageApiRuntimeResolver.ts
9851
10894
  var import_node_crypto14 = require("crypto");
@@ -10376,7 +11419,7 @@ function createImageRuntimeGeneration(options) {
10376
11419
  now: options.now ?? Date.now,
10377
11420
  referenceStore: options.storage.referenceStore,
10378
11421
  stateStore: options.storage.stateStore
10379
- }) : (0, import_subscriptions7.createCodexSubscriptionImageProvider)({
11422
+ }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
10380
11423
  authStrategy,
10381
11424
  evidenceSource: generationEvidenceSource,
10382
11425
  executionScheduler: scheduler,
@@ -13520,7 +14563,7 @@ var ImageRuntimeManager = class {
13520
14563
  };
13521
14564
 
13522
14565
  // src/ports/ConfigFileProviderConfigSource.ts
13523
- var import_core2 = require("@omnicross/core");
14566
+ var import_core5 = require("@omnicross/core");
13524
14567
  var EMPTY_CHAIN = {
13525
14568
  providerTransformers: [],
13526
14569
  modelTransformers: []
@@ -13545,8 +14588,8 @@ var ConfigFileProviderConfigSource = class {
13545
14588
  reloadHook;
13546
14589
  constructor(config) {
13547
14590
  for (const p of config.providers) this.providers.set(p.id, p);
13548
- this.transformerService = new import_core2.TransformerService();
13549
- void (0, import_core2.registerBuiltinTransformers)(this.transformerService);
14591
+ this.transformerService = new import_core5.TransformerService();
14592
+ void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
13550
14593
  }
13551
14594
  // ── Reload hook (key-pool design D4) ───────────────────────────────────────
13552
14595
  /**
@@ -13567,7 +14610,7 @@ var ConfigFileProviderConfigSource = class {
13567
14610
  }
13568
14611
  /** Await the built-in transformer registration (tests await this before dispatch). */
13569
14612
  async ready() {
13570
- await (0, import_core2.registerBuiltinTransformers)(this.transformerService);
14613
+ await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
13571
14614
  }
13572
14615
  // ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
13573
14616
  /**
@@ -13678,6 +14721,10 @@ function toLLMProvider(row) {
13678
14721
  // `parseProviderInput`), so customizations are preserved (the row value wins).
13679
14722
  apiModes: row.apiModes,
13680
14723
  selectedApiModeId: row.selectedApiModeId,
14724
+ // Static extra request headers ride along verbatim (load-guarded — no
14725
+ // auth/content names); core's `getProviderHeaders` merges them into every
14726
+ // BYO request, and the same-format relay path inherits that funnel.
14727
+ extraHeaders: row.extraHeaders,
13681
14728
  // Official-Anthropic signature handling only matters for the Anthropic
13682
14729
  // ingress (deferred → 502); leave it off for the BYO transform path.
13683
14730
  isOfficial: false
@@ -15043,7 +16090,7 @@ function bucketLabel(bucketStartTs, bucket) {
15043
16090
 
15044
16091
  // src/ports/JsonOutboundKeyDb.ts
15045
16092
  var import_node_fs19 = require("fs");
15046
- var import_core3 = require("@omnicross/core");
16093
+ var import_core6 = require("@omnicross/core");
15047
16094
 
15048
16095
  // src/ports/atomicFile.ts
15049
16096
  var import_node_crypto22 = require("crypto");
@@ -15165,7 +16212,7 @@ var JsonOutboundKeyDb = class {
15165
16212
  });
15166
16213
  }
15167
16214
  async outboundApiKeysSetPermissions(id, permissions) {
15168
- const exact = (0, import_core3.validateOutboundPermissions)(permissions);
16215
+ const exact = (0, import_core6.validateOutboundPermissions)(permissions);
15169
16216
  return this.mutateRow(id, (row) => {
15170
16217
  if (row.revokedAt !== null) return false;
15171
16218
  row.allowedEndpoints = [...exact];
@@ -15602,9 +16649,9 @@ var import_node_fs24 = require("fs");
15602
16649
  var import_node_path24 = require("path");
15603
16650
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
15604
16651
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
15605
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
16652
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
15606
16653
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
15607
- var import_subscriptions8 = require("@omnicross/subscriptions");
16654
+ var import_subscriptions11 = require("@omnicross/subscriptions");
15608
16655
 
15609
16656
  // src/ports/account-sync.ts
15610
16657
  function viewOf(tokens) {
@@ -15752,7 +16799,7 @@ var JsonSubscriptionCredentialStore = class {
15752
16799
  * a plaintext token pair into `upstream-trace.jsonl`.
15753
16800
  */
15754
16801
  buildRefreshFetch(providerId, accountId) {
15755
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
16802
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
15756
16803
  }
15757
16804
  /**
15758
16805
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -15793,7 +16840,7 @@ var JsonSubscriptionCredentialStore = class {
15793
16840
  * other hot reads. Never returns token material.
15794
16841
  */
15795
16842
  getAccountProxy(providerId, accountId) {
15796
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
16843
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
15797
16844
  return void 0;
15798
16845
  }
15799
16846
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -15812,7 +16859,7 @@ var JsonSubscriptionCredentialStore = class {
15812
16859
  const fingerprintOn = identityStore.isEnabled();
15813
16860
  const now = Date.now();
15814
16861
  const out = {};
15815
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
16862
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
15816
16863
  const sanitized = sanitizeAccounts(config, provider);
15817
16864
  if (sanitized.length === 0) continue;
15818
16865
  for (const account of sanitized) {
@@ -15878,7 +16925,7 @@ var JsonSubscriptionCredentialStore = class {
15878
16925
  this.materializeMigration(config);
15879
16926
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
15880
16927
  try {
15881
- const result = await import_subscriptions8.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
16928
+ const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
15882
16929
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15883
16930
  const next = {
15884
16931
  ...claude,
@@ -15913,7 +16960,7 @@ var JsonSubscriptionCredentialStore = class {
15913
16960
  this.materializeMigration(config);
15914
16961
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
15915
16962
  try {
15916
- const result = await import_subscriptions8.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
16963
+ const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
15917
16964
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15918
16965
  const next = {
15919
16966
  ...codex,
@@ -15951,7 +16998,7 @@ var JsonSubscriptionCredentialStore = class {
15951
16998
  this.materializeMigration(config);
15952
16999
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
15953
17000
  try {
15954
- const result = await import_subscriptions8.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17001
+ const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
15955
17002
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15956
17003
  const next = {
15957
17004
  ...gemini,
@@ -15987,10 +17034,10 @@ var JsonSubscriptionCredentialStore = class {
15987
17034
  this.materializeMigration(config);
15988
17035
  const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
15989
17036
  try {
15990
- const result = await import_subscriptions8.kimiOAuth.refreshAccessToken(
17037
+ const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
15991
17038
  kimi.refreshToken,
15992
17039
  refreshFetch,
15993
- import_subscriptions8.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17040
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
15994
17041
  );
15995
17042
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15996
17043
  const next = {
@@ -16011,6 +17058,66 @@ var JsonSubscriptionCredentialStore = class {
16011
17058
  }
16012
17059
  });
16013
17060
  }
17061
+ /**
17062
+ * Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
17063
+ * resolved through OIDC discovery on every refresh (process-cached 1h by the
17064
+ * flow module) so a rotated endpoint document is picked up without a daemon
17065
+ * restart. HONEST `false` when no refresh_token.
17066
+ */
17067
+ async refreshGrokToken() {
17068
+ return this.coalesce("grok:active", async () => {
17069
+ const config = this.readConfig();
17070
+ const active = getActiveAccount(config, "grok");
17071
+ const grok = active?.tokens;
17072
+ if (!active || !grok?.refreshToken) return false;
17073
+ const capturedId = active.id;
17074
+ this.materializeMigration(config);
17075
+ const refreshFetch = this.buildRefreshFetch("grok", capturedId);
17076
+ try {
17077
+ const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17078
+ const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17079
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17080
+ const next = {
17081
+ ...grok,
17082
+ accessToken: result.accessToken,
17083
+ refreshToken: result.refreshToken,
17084
+ expiresAt,
17085
+ status: "authorized",
17086
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
17087
+ errorMessage: void 0,
17088
+ syncWarning: void 0
17089
+ };
17090
+ this.writeBackById("grok", capturedId, next);
17091
+ return true;
17092
+ } catch (error) {
17093
+ this.markExpiredById("grok", capturedId, grok, error);
17094
+ return false;
17095
+ }
17096
+ });
17097
+ }
17098
+ /**
17099
+ * "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
17100
+ * tokens are long-lived with no exchange endpoint). A call here means the
17101
+ * strategy saw a 401 (the token was revoked); mark the account `expired`
17102
+ * with a re-authenticate message and return `false` (the proxy then declines
17103
+ * the retry instead of looping on a dead token).
17104
+ */
17105
+ async refreshCopilotToken() {
17106
+ return this.coalesce("copilot:active", async () => {
17107
+ const config = this.readConfig();
17108
+ const active = getActiveAccount(config, "copilot");
17109
+ const copilot = active?.tokens;
17110
+ if (!active || !copilot?.accessToken) return false;
17111
+ this.materializeMigration(config);
17112
+ this.markExpiredById(
17113
+ "copilot",
17114
+ active.id,
17115
+ copilot,
17116
+ new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
17117
+ );
17118
+ return false;
17119
+ });
17120
+ }
16014
17121
  /**
16015
17122
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
16016
17123
  * account-pool resolution). It uses only that account's stored refresh
@@ -16063,7 +17170,7 @@ var JsonSubscriptionCredentialStore = class {
16063
17170
  }
16064
17171
  const oauth = account.tokens;
16065
17172
  if (!oauth.accessToken) return null;
16066
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
17173
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
16067
17174
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
16068
17175
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
16069
17176
  if (expiringSoon && oauth.refreshToken) {
@@ -16156,10 +17263,10 @@ var JsonSubscriptionCredentialStore = class {
16156
17263
  if (provider === "kimi") {
16157
17264
  const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
16158
17265
  const deviceId = account?.tokens?.deviceId;
16159
- const r2 = await import_subscriptions8.kimiOAuth.refreshAccessToken(
17266
+ const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
16160
17267
  refreshToken,
16161
17268
  refreshFetch,
16162
- import_subscriptions8.kimiOAuth.kimiFingerprintHeaders(deviceId)
17269
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
16163
17270
  );
16164
17271
  return {
16165
17272
  accessToken: r2.accessToken,
@@ -16167,7 +17274,19 @@ var JsonSubscriptionCredentialStore = class {
16167
17274
  expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
16168
17275
  };
16169
17276
  }
16170
- const flow = provider === "claude" ? import_subscriptions8.claudeOAuth : provider === "codex" ? import_subscriptions8.codexOAuth : import_subscriptions8.geminiOAuth;
17277
+ if (provider === "grok") {
17278
+ const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17279
+ const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
17280
+ return {
17281
+ accessToken: r2.accessToken,
17282
+ refreshToken: r2.refreshToken,
17283
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17284
+ };
17285
+ }
17286
+ if (provider === "copilot") {
17287
+ throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
17288
+ }
17289
+ const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
16171
17290
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
16172
17291
  return {
16173
17292
  accessToken: r.accessToken,
@@ -16410,7 +17529,7 @@ var JsonSubscriptionCredentialStore = class {
16410
17529
  };
16411
17530
 
16412
17531
  // src/AccountHealthProbeScheduler.ts
16413
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
17532
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
16414
17533
 
16415
17534
  // src/probe/CodexGenerationProbe.ts
16416
17535
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -16553,7 +17672,16 @@ var PROVIDER_PROBE_PLANS = {
16553
17672
  // Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
16554
17673
  // collector uses it), but the probe path also needs the fingerprint headers —
16555
17674
  // keep the probe local until the collector covers the health surface.
16556
- kimi: { kind: "local" }
17675
+ kimi: { kind: "local" },
17676
+ // Grok's billing proxy is a verified FREE authed GET (the allowance collector
17677
+ // uses it) but it REJECTS non-OAuth credentials and sits on a separate host
17678
+ // with its own product-gate header — keep the probe local, the collector
17679
+ // owns the health surface.
17680
+ grok: { kind: "local" },
17681
+ // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
17682
+ // authed GET but lives on api.github.com with its own auth dialect and a
17683
+ // monthly-only window — the allowance collector owns the health surface.
17684
+ copilot: { kind: "local" }
16557
17685
  };
16558
17686
  function probePlanFor(providerId) {
16559
17687
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -16575,7 +17703,7 @@ var AccountHealthProbeScheduler = class {
16575
17703
  this.logger = logger;
16576
17704
  this.config = config;
16577
17705
  this.now = opts.now ?? Date.now;
16578
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch10.fetchUpstream;
17706
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch13.fetchUpstream;
16579
17707
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
16580
17708
  this.planFor = opts.planFor ?? probePlanFor;
16581
17709
  }
@@ -17476,7 +18604,7 @@ async function readAuditStats(auditDir, query2 = {}) {
17476
18604
  }
17477
18605
 
17478
18606
  // src/audit/AuditPruneSweeper.ts
17479
- var DAY_MS3 = 24 * 60 * 6e4;
18607
+ var DAY_MS4 = 24 * 60 * 6e4;
17480
18608
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
17481
18609
  var ARCHIVE_BATCH = 64;
17482
18610
  var AuditPruneSweeper = class {
@@ -17540,7 +18668,7 @@ var AuditPruneSweeper = class {
17540
18668
  this.sweeping = true;
17541
18669
  try {
17542
18670
  if (!(0, import_node_fs27.existsSync)(this.auditDir)) return 0;
17543
- const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS3;
18671
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
17544
18672
  let removed = 0;
17545
18673
  for (const name of (0, import_node_fs27.readdirSync)(this.auditDir)) {
17546
18674
  const dateMs = auditFileDateMs(name);
@@ -17797,7 +18925,7 @@ async function closeAll(writers) {
17797
18925
  // src/usage/UsagePruneSweeper.ts
17798
18926
  var import_promises8 = require("fs/promises");
17799
18927
  var import_node_path29 = require("path");
17800
- var DAY_MS4 = 24 * 60 * 6e4;
18928
+ var DAY_MS5 = 24 * 60 * 6e4;
17801
18929
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
17802
18930
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
17803
18931
  var UsagePruneSweeper = class {
@@ -17854,7 +18982,7 @@ var UsagePruneSweeper = class {
17854
18982
  this.sweeping = true;
17855
18983
  try {
17856
18984
  const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
17857
- const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS4;
18985
+ const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
17858
18986
  let removed = 0;
17859
18987
  for (const entry of await listUsageDays(this.usageDir)) {
17860
18988
  if (!entry.hasShard) continue;
@@ -18273,7 +19401,7 @@ var AuditWriter = class {
18273
19401
  var import_node_fs33 = require("fs");
18274
19402
  var import_node_crypto24 = require("crypto");
18275
19403
  var import_node_path33 = require("path");
18276
- var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
19404
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
18277
19405
 
18278
19406
  // src/billing/billingFiles.ts
18279
19407
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -18296,7 +19424,7 @@ var BillingPublisher = class {
18296
19424
  constructor(billingDir, logger, opts = {}) {
18297
19425
  this.billingDir = billingDir;
18298
19426
  this.logger = logger;
18299
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init));
19427
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
18300
19428
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
18301
19429
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
18302
19430
  this.now = opts.now ?? Date.now;
@@ -18546,7 +19674,7 @@ var BillingRetrySweeper = class {
18546
19674
  // src/TokenRefreshScheduler.ts
18547
19675
  var REFRESH_LEAD_MS2 = 5 * 6e4;
18548
19676
  var SWEEP_INTERVAL_MS5 = 6e4;
18549
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
19677
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
18550
19678
  var TokenRefreshScheduler = class {
18551
19679
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
18552
19680
  this.store = store;
@@ -18631,6 +19759,12 @@ var TokenRefreshScheduler = class {
18631
19759
  return this.store.refreshGeminiToken();
18632
19760
  case "kimi":
18633
19761
  return this.store.refreshKimiToken();
19762
+ case "grok":
19763
+ return this.store.refreshGrokToken();
19764
+ // ghu_ tokens never near-expire (far-future expiresAt), so the sweep
19765
+ // never reaches this — the branch exists for union totality.
19766
+ case "copilot":
19767
+ return this.store.refreshCopilotToken();
18634
19768
  }
18635
19769
  }
18636
19770
  };
@@ -18707,7 +19841,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
18707
19841
 
18708
19842
  // src/webhook/WebhookDispatcher.ts
18709
19843
  var import_node_crypto25 = require("crypto");
18710
- var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
19844
+ var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
18711
19845
  var WEBHOOK_MAX_ATTEMPTS = 3;
18712
19846
  var WEBHOOK_QUEUE_MAX = 1e3;
18713
19847
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -18727,7 +19861,7 @@ var WebhookDispatcher = class {
18727
19861
  sleep;
18728
19862
  now;
18729
19863
  constructor(opts = {}) {
18730
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init));
19864
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init));
18731
19865
  this.logger = opts.logger;
18732
19866
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
18733
19867
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -18813,8 +19947,8 @@ var WebhookDispatcher = class {
18813
19947
  signal: AbortSignal.timeout(this.timeoutMs)
18814
19948
  });
18815
19949
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
18816
- } catch (err6) {
18817
- return { ok: false, error: err6 instanceof Error ? err6.message : String(err6) };
19950
+ } catch (err8) {
19951
+ return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
18818
19952
  }
18819
19953
  }
18820
19954
  /**
@@ -18877,7 +20011,7 @@ function feishuText(event) {
18877
20011
  // src/bootstrap.ts
18878
20012
  var activeImageRuntimeBootstrapSession;
18879
20013
  function createImageRuntimeBootstrapSession(initialGeneration) {
18880
- const openAIOperationRegistry = new import_core4.OpenAIOperationRegistry();
20014
+ const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
18881
20015
  const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
18882
20016
  const unregisterContributions = [];
18883
20017
  try {
@@ -18956,12 +20090,12 @@ function buildDaemon(config, paths) {
18956
20090
  setSecretBox(secretBox3);
18957
20091
  setSecretBox2(secretBox3);
18958
20092
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
18959
- const accountAllowanceStore = new import_AccountAllowanceStore7.AccountAllowanceStore(
20093
+ const accountAllowanceStore = new import_AccountAllowanceStore10.AccountAllowanceStore(
18960
20094
  Date.now,
18961
20095
  void 0,
18962
20096
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
18963
20097
  );
18964
- (0, import_AccountAllowanceStore7.setSharedAccountAllowanceStore)(accountAllowanceStore);
20098
+ (0, import_AccountAllowanceStore10.setSharedAccountAllowanceStore)(accountAllowanceStore);
18965
20099
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
18966
20100
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
18967
20101
  );
@@ -18986,20 +20120,20 @@ function buildDaemon(config, paths) {
18986
20120
  claudeAllowanceRefreshScheduler.configure(
18987
20121
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
18988
20122
  );
18989
- const subscriptionAccounts = new import_subscriptions9.SubscriptionAccountService(credentialStore);
18990
- (0, import_subscriptions9.setSubscriptionAccountService)(subscriptionAccounts);
18991
- const subscriptionRegistry = new import_subscriptions9.SubscriptionProviderRegistry(
20123
+ const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
20124
+ (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
20125
+ const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
18992
20126
  subscriptionAccounts,
18993
20127
  credentialStore
18994
20128
  );
18995
- (0, import_subscriptions9.setSubscriptionProviderRegistry)(subscriptionRegistry);
20129
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
18996
20130
  setServerProxyConfig(decryptedConfig.server?.proxy);
18997
- (0, import_upstreamFetch13.setUpstreamProxyResolver)(
20131
+ (0, import_upstreamFetch16.setUpstreamProxyResolver)(
18998
20132
  createUpstreamProxyResolver({
18999
20133
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
19000
20134
  })
19001
20135
  );
19002
- (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver.getGeminiCodeAssistProjectResolver)());
20136
+ (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver2.getGeminiCodeAssistProjectResolver)());
19003
20137
  const autoDisableStore = new AutoDisableStore();
19004
20138
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
19005
20139
  const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
@@ -19018,7 +20152,7 @@ function buildDaemon(config, paths) {
19018
20152
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
19019
20153
  // Catalog egress follows the same global/env proxy policy as every other
19020
20154
  // daemon upstream call; no provider/account override applies here.
19021
- fetchImpl: ((input, init) => (0, import_upstreamFetch13.fetchUpstream)(String(input), init ?? {}))
20155
+ fetchImpl: ((input, init) => (0, import_upstreamFetch16.fetchUpstream)(String(input), init ?? {}))
19022
20156
  });
19023
20157
  const pricingRefreshScheduler = new PricingRefreshScheduler(
19024
20158
  pricingEngine,
@@ -19303,7 +20437,7 @@ function buildDaemon(config, paths) {
19303
20437
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
19304
20438
  // excluded from the upstream trace, so a failing login left no evidence.
19305
20439
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
19306
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20440
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId, redactBodies: true }),
19307
20441
  subscriptionAccountAppender: credentialStore,
19308
20442
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
19309
20443
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -19315,6 +20449,9 @@ function buildDaemon(config, paths) {
19315
20449
  // paste; the app shows the verification URL + user code and polls the
19316
20450
  // token-free status). Token captured + persisted daemon-side.
19317
20451
  kimiSessions: new CodexOAuthSessionStore(),
20452
+ // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20453
+ grokSessions: new CodexOAuthSessionStore(),
20454
+ copilotSessions: new CodexOAuthSessionStore(),
19318
20455
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
19319
20456
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
19320
20457
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -19373,7 +20510,7 @@ function buildDaemon(config, paths) {
19373
20510
  });
19374
20511
  const webhookDispatcher = new WebhookDispatcher({
19375
20512
  logger,
19376
- fetchImpl: (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init)
20513
+ fetchImpl: (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init)
19377
20514
  });
19378
20515
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
19379
20516
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -19453,9 +20590,9 @@ function resetDaemonSingletonsForTests() {
19453
20590
  (0, import_provider_proxy4.__resetProviderProxyForTests)();
19454
20591
  (0, import_outbound_api10.__resetOutboundApiServerForTests)();
19455
20592
  (0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
19456
- (0, import_subscriptions9.setSubscriptionProviderRegistry)(null);
19457
- (0, import_subscriptions9.setSubscriptionAccountService)(null);
19458
- (0, import_upstreamFetch13.setUpstreamProxyResolver)(null);
20593
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(null);
20594
+ (0, import_subscriptions12.setSubscriptionAccountService)(null);
20595
+ (0, import_upstreamFetch16.setUpstreamProxyResolver)(null);
19459
20596
  setServerProxyConfig(void 0);
19460
20597
  (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)(null);
19461
20598
  setSecretBox(null);
@@ -19464,7 +20601,7 @@ function resetDaemonSingletonsForTests() {
19464
20601
  resetAuditRuntimeForTests();
19465
20602
  resetBillingRuntimeForTests();
19466
20603
  (0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
19467
- (0, import_AccountAllowanceStore7.__resetSharedAccountAllowanceStoreForTests)();
20604
+ (0, import_AccountAllowanceStore10.__resetSharedAccountAllowanceStoreForTests)();
19468
20605
  (0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
19469
20606
  (0, import_usage2.__resetSharedUsageThroughputTrackerForTests)();
19470
20607
  }