@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.js CHANGED
@@ -4,7 +4,7 @@ import { dirname as dirname17 } from "path";
4
4
  import { DEFAULT_AUDIT_CONFIG } from "@omnicross/contracts/audit-types";
5
5
  import { DEFAULT_BILLING_CONFIG } from "@omnicross/contracts/billing-types";
6
6
  import { OpenAIOperationRegistry } from "@omnicross/core";
7
- import { getGeminiCodeAssistProjectResolver } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
7
+ import { getGeminiCodeAssistProjectResolver as getGeminiCodeAssistProjectResolver2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
8
8
  import { ApiKeyPoolService } from "@omnicross/core/completion/ApiKeyPoolService";
9
9
  import {
10
10
  __resetOutboundApiServerForTests,
@@ -18,14 +18,14 @@ import { setSubscriptionRegistryForOutbound } from "@omnicross/core/outbound-api
18
18
  import { getSharedAccountHealth as getSharedAccountHealth4 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
19
19
  import {
20
20
  __resetSharedAccountAllowanceStoreForTests,
21
- AccountAllowanceStore as AccountAllowanceStore6,
21
+ AccountAllowanceStore as AccountAllowanceStore9,
22
22
  setSharedAccountAllowanceStore
23
23
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
24
24
  import {
25
25
  __resetSharedAccountAllowanceSchedulingForTests,
26
26
  getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling5
27
27
  } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
28
- import { fetchUpstream as fetchUpstream11, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
28
+ import { fetchUpstream as fetchUpstream14, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
29
29
  import { __resetSharedIdentityStoreForTests } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
30
30
  import { setGeminiCodeAssistResolver } from "@omnicross/core/ports/gemini-code-assist-resolver";
31
31
  import {
@@ -230,9 +230,188 @@ function handleKimiOAuthStatus(sessionId, deps) {
230
230
  return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
231
231
  }
232
232
 
233
+ // src/admin/accountsGrokOAuth.ts
234
+ import { grokOAuth } from "@omnicross/subscriptions";
235
+ function err3(status, message) {
236
+ return { status, body: { error: { type: "admin_api_error", message } } };
237
+ }
238
+ var DEFAULT_GROK_OAUTH_TTL_MS = 15 * 6e4;
239
+ async function handleGrokOAuthStart(deps) {
240
+ if (deps.grokSessions.isBusy()) {
241
+ return err3(409, "a grok sign-in is already in progress \u2014 finish it in the browser or cancel it");
242
+ }
243
+ const fetchImpl = deps.oauthExchangeFetch("grok");
244
+ let tokenEndpoint;
245
+ try {
246
+ tokenEndpoint = await grokOAuth.resolveGrokTokenEndpoint(fetchImpl);
247
+ } catch (e) {
248
+ const reason = e instanceof Error ? e.message : "OIDC discovery failed";
249
+ return err3(502, `grok token-endpoint discovery failed: ${reason}`);
250
+ }
251
+ let authorization;
252
+ try {
253
+ authorization = await grokOAuth.requestGrokDeviceAuthorization(fetchImpl);
254
+ } catch (e) {
255
+ const reason = e instanceof Error ? e.message : "device authorization failed";
256
+ return err3(502, `grok device authorization failed: ${reason}`);
257
+ }
258
+ const { sessionId, signal } = deps.grokSessions.begin();
259
+ void runGrokDevicePoll(sessionId, tokenEndpoint, authorization.deviceCode, signal, deps).catch((e) => {
260
+ const reason = e instanceof Error ? e.message : "grok sign-in failed";
261
+ deps.grokSessions.settle(sessionId, "error", reason);
262
+ });
263
+ return {
264
+ status: 200,
265
+ body: {
266
+ authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
267
+ userCode: authorization.userCode,
268
+ sessionId
269
+ }
270
+ };
271
+ }
272
+ async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, deps) {
273
+ const fetchImpl = deps.oauthExchangeFetch("grok");
274
+ const result = await grokOAuth.awaitGrokDeviceToken(
275
+ { userCode: "", deviceCode, verificationUri: "" },
276
+ tokenEndpoint,
277
+ fetchImpl,
278
+ {
279
+ deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
280
+ sleep: (ms) => new Promise((resolve10, reject) => {
281
+ const onAbort = () => {
282
+ clearTimeout(timer);
283
+ reject(new Error("login: cancelled"));
284
+ };
285
+ const timer = setTimeout(() => {
286
+ signal.removeEventListener("abort", onAbort);
287
+ resolve10();
288
+ }, ms);
289
+ signal.addEventListener("abort", onAbort, { once: true });
290
+ })
291
+ }
292
+ );
293
+ const block = {
294
+ authMethod: "oauth",
295
+ status: "authorized",
296
+ accessToken: result.accessToken,
297
+ refreshToken: result.refreshToken,
298
+ expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
299
+ accountId: grokOAuth.grokAccountIdFromAccessToken(result.accessToken),
300
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
301
+ };
302
+ await deps.subscriptionAccountAppender.appendProviderAccount("grok", block);
303
+ deps.grokSessions.settle(sessionId, "done");
304
+ }
305
+ function handleGrokOAuthCancel(sessionId, deps) {
306
+ if (!deps.grokSessions.cancel(sessionId)) return err3(404, "unknown or expired grok sign-in session");
307
+ return { status: 200, body: { ok: true } };
308
+ }
309
+ function handleGrokOAuthStatus(sessionId, deps) {
310
+ const s = deps.grokSessions.get(sessionId);
311
+ if (!s) return err3(404, "unknown or expired grok sign-in session");
312
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
313
+ }
314
+
315
+ // src/admin/accountsCopilotOAuth.ts
316
+ import { copilotOAuth } from "@omnicross/subscriptions";
317
+ function err4(status, message) {
318
+ return { status, body: { error: { type: "admin_api_error", message } } };
319
+ }
320
+ var DEFAULT_COPILOT_OAUTH_TTL_MS = 15 * 6e4;
321
+ async function handleCopilotOAuthStart(deps, enterpriseUrlInput) {
322
+ if (deps.copilotSessions.isBusy()) {
323
+ return err4(409, "a copilot sign-in is already in progress \u2014 finish it in the browser or cancel it");
324
+ }
325
+ let enterpriseUrl;
326
+ if (typeof enterpriseUrlInput === "string" && enterpriseUrlInput.trim()) {
327
+ try {
328
+ enterpriseUrl = copilotOAuth.normalizeCopilotEnterpriseDomain(enterpriseUrlInput);
329
+ } catch (e) {
330
+ const reason = e instanceof Error ? e.message : "invalid GitHub Enterprise domain";
331
+ return err4(400, `copilot ${reason}`);
332
+ }
333
+ }
334
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
335
+ let authorization;
336
+ try {
337
+ authorization = await copilotOAuth.requestCopilotDeviceAuthorization(fetchImpl, enterpriseUrl);
338
+ } catch (e) {
339
+ const reason = e instanceof Error ? e.message : "device authorization failed";
340
+ return err4(502, `copilot device authorization failed: ${reason}`);
341
+ }
342
+ const { sessionId, signal } = deps.copilotSessions.begin();
343
+ void runCopilotDevicePoll(sessionId, authorization.deviceCode, signal, deps, enterpriseUrl).catch((e) => {
344
+ const reason = e instanceof Error ? e.message : "copilot sign-in failed";
345
+ deps.copilotSessions.settle(sessionId, "error", reason);
346
+ });
347
+ return {
348
+ status: 200,
349
+ body: {
350
+ authUrl: authorization.verificationUri,
351
+ userCode: authorization.userCode,
352
+ sessionId,
353
+ ...enterpriseUrl ? { enterpriseUrl } : {}
354
+ }
355
+ };
356
+ }
357
+ async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpriseUrl) {
358
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
359
+ const result = await copilotOAuth.awaitCopilotDeviceToken(
360
+ { userCode: "", deviceCode, verificationUri: "", interval: 5, expiresIn: 900 },
361
+ fetchImpl,
362
+ {
363
+ deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
364
+ ...enterpriseUrl ? { enterpriseUrl } : {},
365
+ sleep: (ms) => new Promise((resolve10, reject) => {
366
+ const onAbort = () => {
367
+ clearTimeout(timer);
368
+ reject(new Error("login: cancelled"));
369
+ };
370
+ const timer = setTimeout(() => {
371
+ signal.removeEventListener("abort", onAbort);
372
+ resolve10();
373
+ }, ms);
374
+ signal.addEventListener("abort", onAbort, { once: true });
375
+ })
376
+ }
377
+ );
378
+ const identity = await copilotOAuth.fetchCopilotIdentity(result.accessToken, fetchImpl, enterpriseUrl);
379
+ const apiEndpoint = await copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, fetchImpl, enterpriseUrl);
380
+ await copilotOAuth.enableAllCopilotModels(
381
+ result.accessToken,
382
+ { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
383
+ fetchImpl
384
+ );
385
+ const block = {
386
+ authMethod: "oauth",
387
+ status: "authorized",
388
+ accessToken: result.accessToken,
389
+ refreshToken: result.accessToken,
390
+ expiresAt: new Date(Date.now() + copilotOAuth.COPILOT_FAR_FUTURE_MS).toISOString(),
391
+ ...identity.accountId ? { accountId: identity.accountId } : {},
392
+ ...identity.email ? { email: identity.email } : {},
393
+ ...apiEndpoint ? { apiEndpoint } : {},
394
+ ...enterpriseUrl ? { enterpriseUrl } : {},
395
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
396
+ };
397
+ await deps.subscriptionAccountAppender.appendProviderAccount("copilot", block);
398
+ deps.copilotSessions.settle(sessionId, "done");
399
+ }
400
+ function handleCopilotOAuthCancel(sessionId, deps) {
401
+ if (!deps.copilotSessions.cancel(sessionId)) {
402
+ return err4(404, "unknown or expired copilot sign-in session");
403
+ }
404
+ return { status: 200, body: { ok: true } };
405
+ }
406
+ function handleCopilotOAuthStatus(sessionId, deps) {
407
+ const s = deps.copilotSessions.get(sessionId);
408
+ if (!s) return err4(404, "unknown or expired copilot sign-in session");
409
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
410
+ }
411
+
233
412
  // src/allowance/AccountAllowanceService.ts
234
413
  import {
235
- getSharedAccountAllowanceStore as getSharedAccountAllowanceStore5
414
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore8
236
415
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
237
416
  import {
238
417
  getSharedAccountAllowanceScheduling
@@ -806,42 +985,705 @@ function parseKimiUsagePayload(payload, now) {
806
985
  const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
807
986
  byId.set("seven-day", window);
808
987
  }
809
- if (Array.isArray(payload["limits"])) {
810
- for (const item of payload["limits"]) {
811
- if (!isRecord(item)) continue;
812
- const detail = isRecord(item["detail"]) ? item["detail"] : item;
813
- const row = rowFrom(detail);
814
- const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
815
- if (!canonical) continue;
816
- const window = windowFromRow(row, canonical, now);
817
- const existing = byId.get(canonical.id);
818
- if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
819
- byId.set(canonical.id, window);
820
- }
821
- }
988
+ if (Array.isArray(payload["limits"])) {
989
+ for (const item of payload["limits"]) {
990
+ if (!isRecord(item)) continue;
991
+ const detail = isRecord(item["detail"]) ? item["detail"] : item;
992
+ const row = rowFrom(detail);
993
+ const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
994
+ if (!canonical) continue;
995
+ const window = windowFromRow(row, canonical, now);
996
+ const existing = byId.get(canonical.id);
997
+ if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
998
+ byId.set(canonical.id, window);
999
+ }
1000
+ }
1001
+ }
1002
+ return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
1003
+ }
1004
+ var KimiAllowanceCollector = class {
1005
+ constructor(credentials, store = getSharedAccountAllowanceStore3(), fetchImpl = (url, init, accountId) => fetchUpstream3(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
1006
+ this.credentials = credentials;
1007
+ this.store = store;
1008
+ this.fetchImpl = fetchImpl;
1009
+ this.now = now;
1010
+ }
1011
+ credentials;
1012
+ store;
1013
+ fetchImpl;
1014
+ now;
1015
+ inFlight = /* @__PURE__ */ new Map();
1016
+ async collectMany(accounts, options = {}) {
1017
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1018
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1019
+ }
1020
+ collect(account, options = {}) {
1021
+ const now = this.now();
1022
+ if (account.tokens.authMethod !== "oauth") {
1023
+ const existing = this.store.get("kimi", account.id, now);
1024
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1025
+ return Promise.resolve(existing);
1026
+ }
1027
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1028
+ this.store.set(snapshot);
1029
+ return Promise.resolve(snapshot);
1030
+ }
1031
+ const cached = this.store.get("kimi", account.id, now);
1032
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1033
+ return Promise.resolve(cached);
1034
+ }
1035
+ const running = this.inFlight.get(account.id);
1036
+ if (running) return running;
1037
+ 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));
1038
+ this.inFlight.set(account.id, promise);
1039
+ return promise;
1040
+ }
1041
+ isCacheValid(snapshot, now, refreshAheadMs) {
1042
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1043
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1044
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1045
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1046
+ }
1047
+ async fetchAccount(accountId, tokens) {
1048
+ let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1049
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1050
+ let response = await this.request(accountId, accessToken, tokens);
1051
+ if (response.status === 401) {
1052
+ const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
1053
+ if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
1054
+ accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1055
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1056
+ response = await this.request(accountId, accessToken, tokens);
1057
+ }
1058
+ if (response.status === 403) {
1059
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
1060
+ this.store.set(snapshot2);
1061
+ return snapshot2;
1062
+ }
1063
+ if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
1064
+ let payload;
1065
+ try {
1066
+ payload = await response.json();
1067
+ } catch {
1068
+ return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
1069
+ }
1070
+ const now = this.now();
1071
+ const windows = parseKimiUsagePayload(payload, now);
1072
+ const snapshot = {
1073
+ providerId: "kimi",
1074
+ accountId,
1075
+ source: "oauth-usage-api",
1076
+ observedAt: new Date(now).toISOString(),
1077
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1078
+ windows: windows.length > 0 ? windows : [
1079
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1080
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1081
+ ],
1082
+ ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
1083
+ };
1084
+ this.store.set(snapshot);
1085
+ return snapshot;
1086
+ }
1087
+ request(accountId, accessToken, tokens) {
1088
+ return this.fetchImpl(KIMI_USAGE_URL, {
1089
+ method: "GET",
1090
+ headers: {
1091
+ Authorization: `Bearer ${accessToken}`,
1092
+ Accept: "application/json",
1093
+ ...kimiFingerprintHeaders(tokens.deviceId)
1094
+ },
1095
+ signal: AbortSignal.timeout(15e3)
1096
+ }, accountId);
1097
+ }
1098
+ failureSnapshot(accountId, code, now) {
1099
+ const existing = this.store.get("kimi", accountId, now);
1100
+ const snapshot = existing ? {
1101
+ ...existing,
1102
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1103
+ windows: existing.windows.map((window) => ({
1104
+ ...window,
1105
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1106
+ })),
1107
+ lastErrorCode: code
1108
+ } : {
1109
+ providerId: "kimi",
1110
+ accountId,
1111
+ source: "oauth-usage-api",
1112
+ observedAt: new Date(now).toISOString(),
1113
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1114
+ windows: [
1115
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1116
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1117
+ ],
1118
+ lastErrorCode: code
1119
+ };
1120
+ this.store.set(snapshot);
1121
+ return snapshot;
1122
+ }
1123
+ unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
1124
+ return {
1125
+ providerId: "kimi",
1126
+ accountId,
1127
+ source: "oauth-usage-api",
1128
+ observedAt: new Date(now).toISOString(),
1129
+ windows: [
1130
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
1131
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
1132
+ ],
1133
+ lastErrorCode: code
1134
+ };
1135
+ }
1136
+ };
1137
+
1138
+ // src/allowance/GrokAllowanceCollector.ts
1139
+ import {
1140
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore4
1141
+ } from "@omnicross/core/pipeline/AccountAllowanceStore";
1142
+ import { fetchUpstream as fetchUpstream4 } from "@omnicross/core/pipeline/upstreamFetch";
1143
+ var GROK_ALLOWANCE_CACHE_MS = 5 * 6e4;
1144
+ var GROK_BILLING_BASE = "https://cli-chat-proxy.grok.com";
1145
+ var GROK_BILLING_CREDITS_URL = `${GROK_BILLING_BASE}/v1/billing?format=credits`;
1146
+ var GROK_BILLING_MONTHLY_URL = `${GROK_BILLING_BASE}/v1/billing`;
1147
+ function isRecord2(value) {
1148
+ return !!value && typeof value === "object" && !Array.isArray(value);
1149
+ }
1150
+ function finiteNumber3(value) {
1151
+ if (value === null || value === void 0 || value === "") return void 0;
1152
+ const parsed = typeof value === "number" ? value : Number(value);
1153
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1154
+ }
1155
+ function percent(value) {
1156
+ const parsed = finiteNumber3(value);
1157
+ return parsed !== void 0 && parsed <= 100 ? parsed : void 0;
1158
+ }
1159
+ function onDemandAmount(value) {
1160
+ return isRecord2(value) ? finiteNumber3(value["val"]) : void 0;
1161
+ }
1162
+ function confirmsNoMonthlyQuota(raw) {
1163
+ const limit = onDemandAmount(raw["monthlyLimit"]);
1164
+ if (limit !== void 0) return limit === 0;
1165
+ return parseWeeklyConfig(raw)?.inferredPercent === true;
1166
+ }
1167
+ function parseWeeklyConfig(raw) {
1168
+ const period = isRecord2(raw["currentPeriod"]) ? raw["currentPeriod"] : void 0;
1169
+ if (!period) return null;
1170
+ const start = typeof period["start"] === "string" ? Date.parse(period["start"]) : Number.NaN;
1171
+ const end = typeof period["end"] === "string" ? Date.parse(period["end"]) : Number.NaN;
1172
+ const type = typeof period["type"] === "string" ? period["type"] : "";
1173
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
1174
+ if (!type.toUpperCase().includes("WEEK")) return null;
1175
+ const inferred = raw["creditUsagePercent"] === void 0 || raw["creditUsagePercent"] === null;
1176
+ let creditUsagePercent;
1177
+ if (inferred) {
1178
+ creditUsagePercent = end > Date.now() ? 0 : void 0;
1179
+ } else {
1180
+ creditUsagePercent = percent(raw["creditUsagePercent"]);
1181
+ }
1182
+ if (creditUsagePercent === void 0) return null;
1183
+ return {
1184
+ creditUsagePercent,
1185
+ inferredPercent: inferred,
1186
+ resetsAtMs: end,
1187
+ unified: raw["isUnifiedBillingUser"] === true
1188
+ };
1189
+ }
1190
+ function parseMonthlyConfig(raw) {
1191
+ const start = typeof raw["billingPeriodStart"] === "string" ? Date.parse(raw["billingPeriodStart"]) : Number.NaN;
1192
+ const end = typeof raw["billingPeriodEnd"] === "string" ? Date.parse(raw["billingPeriodEnd"]) : Number.NaN;
1193
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
1194
+ const limit = onDemandAmount(raw["monthlyLimit"]);
1195
+ const used = onDemandAmount(raw["used"]);
1196
+ if (limit === void 0 || limit <= 0 || used === void 0) return null;
1197
+ return { used, limit, periodStartMs: start, periodEndMs: end };
1198
+ }
1199
+ function secondsUntil4(instant, now) {
1200
+ if (!instant) return void 0;
1201
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1202
+ }
1203
+ var MINUTE_MS2 = 6e4;
1204
+ var DAY_MS2 = 864e5;
1205
+ var WEEK_MINUTES = 7 * 24 * 60;
1206
+ function weeklyWindow(config, now) {
1207
+ const resetsAt = new Date(config.resetsAtMs).toISOString();
1208
+ return {
1209
+ id: "seven-day",
1210
+ label: "7 days",
1211
+ scope: "all",
1212
+ usedPercent: config.creditUsagePercent,
1213
+ windowMinutes: WEEK_MINUTES,
1214
+ resetsAt,
1215
+ remainingSeconds: secondsUntil4(resetsAt, now),
1216
+ state: "fresh"
1217
+ };
1218
+ }
1219
+ function monthlyWindow(config, now) {
1220
+ const resetsAt = new Date(config.periodEndMs).toISOString();
1221
+ const days = Math.max(1, Math.round((config.periodEndMs - config.periodStartMs) / DAY_MS2));
1222
+ return {
1223
+ id: "thirty-day",
1224
+ label: days === 30 || days === 31 ? "30 days" : `${days} days`,
1225
+ scope: "all",
1226
+ usedPercent: Math.round(Math.min(100, config.used / config.limit * 100) * 10) / 10,
1227
+ windowMinutes: Math.round((config.periodEndMs - config.periodStartMs) / MINUTE_MS2),
1228
+ resetsAt,
1229
+ remainingSeconds: secondsUntil4(resetsAt, now),
1230
+ state: "fresh"
1231
+ };
1232
+ }
1233
+ function onDemandWindow(raw) {
1234
+ const cap = onDemandAmount(raw["onDemandCap"]);
1235
+ const used = onDemandAmount(raw["onDemandUsed"]);
1236
+ if (cap === void 0 || cap <= 0 || used === void 0) return null;
1237
+ return {
1238
+ id: "on-demand",
1239
+ label: "On-demand",
1240
+ scope: "all",
1241
+ usedPercent: Math.round(Math.min(100, used / cap * 100) * 10) / 10,
1242
+ state: "fresh"
1243
+ };
1244
+ }
1245
+ async function probeBilling(url, accessToken, accountId, fetchImpl) {
1246
+ try {
1247
+ const response = await fetchImpl(url, {
1248
+ method: "GET",
1249
+ headers: {
1250
+ Authorization: `Bearer ${accessToken}`,
1251
+ Accept: "application/json",
1252
+ "X-XAI-Token-Auth": "xai-grok-cli"
1253
+ },
1254
+ redirect: "error",
1255
+ signal: AbortSignal.timeout(15e3)
1256
+ }, accountId);
1257
+ if (!response.ok) return { status: response.status, payload: null };
1258
+ const payload = await response.json();
1259
+ return { status: response.status, payload: isRecord2(payload) ? payload : null };
1260
+ } catch {
1261
+ return { status: 0, payload: null };
1262
+ }
1263
+ }
1264
+ function parseGrokBillingPayloads(creditsPayload, monthlyPayload, now) {
1265
+ const creditsConfig = isRecord2(creditsPayload?.["config"]) ? creditsPayload["config"] : null;
1266
+ const monthlyConfig = isRecord2(monthlyPayload?.["config"]) ? monthlyPayload["config"] : null;
1267
+ let weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
1268
+ const unifiedFlag = creditsConfig?.["isUnifiedBillingUser"] === true;
1269
+ let monthly = monthlyConfig ? parseMonthlyConfig(monthlyConfig) : null;
1270
+ if (weekly?.inferredPercent && unifiedFlag) {
1271
+ if (monthly) {
1272
+ weekly = null;
1273
+ } else if (!monthlyConfig || !confirmsNoMonthlyQuota(monthlyConfig)) {
1274
+ weekly = null;
1275
+ }
1276
+ }
1277
+ const windows = [];
1278
+ if (weekly) windows.push(weeklyWindow(weekly, now));
1279
+ if (monthly) windows.push(monthlyWindow(monthly, now));
1280
+ const onDemandSource = monthly && monthlyConfig ? monthlyConfig : creditsConfig;
1281
+ const onDemand = onDemandSource ? onDemandWindow(onDemandSource) : null;
1282
+ if (onDemand) windows.push(onDemand);
1283
+ return windows.length > 0 ? windows : null;
1284
+ }
1285
+ var GrokAllowanceCollector = class {
1286
+ constructor(credentials, store = getSharedAccountAllowanceStore4(), fetchImpl = (url, init, accountId) => fetchUpstream4(url, init, { providerId: "grok", accountId, redactBodies: true }), now = Date.now) {
1287
+ this.credentials = credentials;
1288
+ this.store = store;
1289
+ this.fetchImpl = fetchImpl;
1290
+ this.now = now;
1291
+ }
1292
+ credentials;
1293
+ store;
1294
+ fetchImpl;
1295
+ now;
1296
+ inFlight = /* @__PURE__ */ new Map();
1297
+ async collectMany(accounts, options = {}) {
1298
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1299
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1300
+ }
1301
+ collect(account, options = {}) {
1302
+ const now = this.now();
1303
+ if (account.tokens.authMethod !== "oauth") {
1304
+ const existing = this.store.get("grok", account.id, now);
1305
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1306
+ return Promise.resolve(existing);
1307
+ }
1308
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1309
+ this.store.set(snapshot);
1310
+ return Promise.resolve(snapshot);
1311
+ }
1312
+ const cached = this.store.get("grok", account.id, now);
1313
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1314
+ return Promise.resolve(cached);
1315
+ }
1316
+ const running = this.inFlight.get(account.id);
1317
+ if (running) return running;
1318
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "grok_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1319
+ this.inFlight.set(account.id, promise);
1320
+ return promise;
1321
+ }
1322
+ isCacheValid(snapshot, now, refreshAheadMs) {
1323
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1324
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1325
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1326
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1327
+ }
1328
+ async fetchAccount(accountId) {
1329
+ const probe = async () => {
1330
+ const accessToken = await this.credentials.getAccessTokenForAccount("grok", accountId);
1331
+ if (!accessToken) return { unauthorized: true, windows: null };
1332
+ const credits = await probeBilling(GROK_BILLING_CREDITS_URL, accessToken, accountId, this.fetchImpl);
1333
+ if (credits.status === 401 || credits.status === 403) return { unauthorized: true, windows: null };
1334
+ const creditsConfig = isRecord2(credits.payload?.["config"]) ? credits.payload["config"] : null;
1335
+ const weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
1336
+ const monthly = !weekly || creditsConfig?.["isUnifiedBillingUser"] === true ? await probeBilling(GROK_BILLING_MONTHLY_URL, accessToken, accountId, this.fetchImpl) : { status: 200, payload: null };
1337
+ if (monthly.status === 401 || monthly.status === 403) return { unauthorized: true, windows: null };
1338
+ return {
1339
+ unauthorized: false,
1340
+ windows: parseGrokBillingPayloads(credits.payload, monthly.payload, this.now())
1341
+ };
1342
+ };
1343
+ let result = await probe();
1344
+ if (result.unauthorized) {
1345
+ const refreshed = await this.credentials.refreshAccountToken("grok", accountId);
1346
+ if (!refreshed) return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
1347
+ result = await probe();
1348
+ if (result.unauthorized) {
1349
+ return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
1350
+ }
1351
+ }
1352
+ const now = this.now();
1353
+ if (result.windows && result.windows.length > 0) {
1354
+ const snapshot = {
1355
+ providerId: "grok",
1356
+ accountId,
1357
+ source: "oauth-usage-api",
1358
+ observedAt: new Date(now).toISOString(),
1359
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1360
+ windows: result.windows
1361
+ };
1362
+ this.store.set(snapshot);
1363
+ return snapshot;
1364
+ }
1365
+ return this.failureSnapshot(accountId, "grok_usage_invalid_response", now);
1366
+ }
1367
+ failureSnapshot(accountId, code, now) {
1368
+ const existing = this.store.get("grok", accountId, now);
1369
+ const snapshot = existing ? {
1370
+ ...existing,
1371
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1372
+ windows: existing.windows.map((window) => ({
1373
+ ...window,
1374
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1375
+ })),
1376
+ lastErrorCode: code
1377
+ } : {
1378
+ providerId: "grok",
1379
+ accountId,
1380
+ source: "oauth-usage-api",
1381
+ observedAt: new Date(now).toISOString(),
1382
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1383
+ windows: [
1384
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" },
1385
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unavailable" }
1386
+ ],
1387
+ lastErrorCode: code
1388
+ };
1389
+ this.store.set(snapshot);
1390
+ return snapshot;
1391
+ }
1392
+ unsupportedSnapshot(accountId, now) {
1393
+ return {
1394
+ providerId: "grok",
1395
+ accountId,
1396
+ source: "oauth-usage-api",
1397
+ observedAt: new Date(now).toISOString(),
1398
+ windows: [
1399
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" },
1400
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unsupported" }
1401
+ ],
1402
+ lastErrorCode: "grok_usage_unsupported_auth"
1403
+ };
1404
+ }
1405
+ };
1406
+
1407
+ // src/allowance/CopilotAllowanceCollector.ts
1408
+ import {
1409
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore5
1410
+ } from "@omnicross/core/pipeline/AccountAllowanceStore";
1411
+ import { fetchUpstream as fetchUpstream5 } from "@omnicross/core/pipeline/upstreamFetch";
1412
+ import { COPILOT_GITHUB_HEADERS, copilotGitHubApiBase } from "@omnicross/subscriptions";
1413
+ var COPILOT_ALLOWANCE_CACHE_MS = 5 * 6e4;
1414
+ function isRecord3(value) {
1415
+ return !!value && typeof value === "object" && !Array.isArray(value);
1416
+ }
1417
+ function finiteNumber4(value) {
1418
+ if (value === null || value === void 0 || value === "") return void 0;
1419
+ const parsed = typeof value === "number" ? value : Number(value);
1420
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1421
+ }
1422
+ function booleanValue(value) {
1423
+ if (typeof value === "boolean") return value;
1424
+ if (value === "true") return true;
1425
+ if (value === "false") return false;
1426
+ return void 0;
1427
+ }
1428
+ function parseQuotaDetail(value) {
1429
+ if (!isRecord3(value)) return null;
1430
+ const entitlement = finiteNumber4(value["entitlement"]);
1431
+ const remaining = finiteNumber4(value["remaining"]);
1432
+ const percentRemaining = finiteNumber4(value["percent_remaining"]);
1433
+ const unlimited = booleanValue(value["unlimited"]);
1434
+ if (entitlement === void 0 || remaining === void 0 || percentRemaining === void 0 || unlimited === void 0) {
1435
+ return null;
1436
+ }
1437
+ return { entitlement, remaining, percentRemaining, unlimited };
1438
+ }
1439
+ function secondsUntil5(instant, now) {
1440
+ if (!instant) return void 0;
1441
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1442
+ }
1443
+ function parseCopilotUserPayload(payload, now) {
1444
+ if (!isRecord3(payload)) return null;
1445
+ const snapshots = isRecord3(payload["quota_snapshots"]) ? payload["quota_snapshots"] : void 0;
1446
+ if (!snapshots) return null;
1447
+ const resetRaw = payload["quota_reset_date"];
1448
+ const resetsAt = typeof resetRaw === "string" && resetRaw.trim() && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
1449
+ const windows = [];
1450
+ const premium = parseQuotaDetail(snapshots["premium_interactions"]);
1451
+ if (premium) {
1452
+ 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;
1453
+ if (usedPercent !== null) {
1454
+ windows.push({
1455
+ id: "thirty-day",
1456
+ label: "Monthly",
1457
+ scope: "all",
1458
+ usedPercent,
1459
+ windowMinutes: 30 * 24 * 60,
1460
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1461
+ remainingSeconds: secondsUntil5(resetsAt, now),
1462
+ state: "fresh"
1463
+ });
1464
+ }
1465
+ }
1466
+ const chat = parseQuotaDetail(snapshots["chat"]);
1467
+ if (chat && !chat.unlimited && chat.entitlement > 0) {
1468
+ const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
1469
+ windows.push({
1470
+ id: "chat-monthly",
1471
+ label: "Chat (monthly)",
1472
+ scope: "all",
1473
+ usedPercent,
1474
+ windowMinutes: 30 * 24 * 60,
1475
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1476
+ remainingSeconds: secondsUntil5(resetsAt, now),
1477
+ state: "fresh"
1478
+ });
1479
+ }
1480
+ return windows.length > 0 ? windows : null;
1481
+ }
1482
+ function githubApiBase(tokens) {
1483
+ return copilotGitHubApiBase(tokens.enterpriseUrl);
1484
+ }
1485
+ var CopilotAllowanceCollector = class {
1486
+ constructor(credentials, store = getSharedAccountAllowanceStore5(), fetchImpl = (url, init, accountId) => fetchUpstream5(url, init, { providerId: "copilot", accountId, redactBodies: true }), now = Date.now) {
1487
+ this.credentials = credentials;
1488
+ this.store = store;
1489
+ this.fetchImpl = fetchImpl;
1490
+ this.now = now;
1491
+ }
1492
+ credentials;
1493
+ store;
1494
+ fetchImpl;
1495
+ now;
1496
+ inFlight = /* @__PURE__ */ new Map();
1497
+ async collectMany(accounts, options = {}) {
1498
+ const settled = await Promise.allSettled(
1499
+ accounts.map((account) => this.collect(account, options))
1500
+ );
1501
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1502
+ }
1503
+ collect(account, options = {}) {
1504
+ const now = this.now();
1505
+ if (account.tokens.authMethod !== "oauth") {
1506
+ const existing = this.store.get("copilot", account.id, now);
1507
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1508
+ return Promise.resolve(existing);
1509
+ }
1510
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1511
+ this.store.set(snapshot);
1512
+ return Promise.resolve(snapshot);
1513
+ }
1514
+ const cached = this.store.get("copilot", account.id, now);
1515
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1516
+ return Promise.resolve(cached);
1517
+ }
1518
+ const running = this.inFlight.get(account.id);
1519
+ if (running) return running;
1520
+ 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));
1521
+ this.inFlight.set(account.id, promise);
1522
+ return promise;
1523
+ }
1524
+ isCacheValid(snapshot, now, refreshAheadMs) {
1525
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1526
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1527
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1528
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1529
+ }
1530
+ async fetchAccount(accountId, tokens) {
1531
+ let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1532
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
1533
+ let response = await this.request(accountId, accessToken, tokens);
1534
+ if (response.status === 401 || response.status === 403) {
1535
+ const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
1536
+ if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1537
+ accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1538
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
1539
+ response = await this.request(accountId, accessToken, tokens);
1540
+ if (response.status === 401 || response.status === 403) {
1541
+ return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1542
+ }
1543
+ }
1544
+ if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
1545
+ let payload;
1546
+ try {
1547
+ payload = await response.json();
1548
+ } catch {
1549
+ return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
1550
+ }
1551
+ const now = this.now();
1552
+ const windows = parseCopilotUserPayload(payload, now);
1553
+ const snapshot = {
1554
+ providerId: "copilot",
1555
+ accountId,
1556
+ source: "oauth-usage-api",
1557
+ observedAt: new Date(now).toISOString(),
1558
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1559
+ windows: windows ?? [
1560
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
1561
+ ],
1562
+ ...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
1563
+ };
1564
+ this.store.set(snapshot);
1565
+ return snapshot;
1566
+ }
1567
+ request(accountId, accessToken, tokens) {
1568
+ return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
1569
+ method: "GET",
1570
+ headers: {
1571
+ Authorization: `Bearer ${accessToken}`,
1572
+ Accept: "application/json",
1573
+ "Content-Type": "application/json",
1574
+ ...COPILOT_GITHUB_HEADERS
1575
+ },
1576
+ signal: AbortSignal.timeout(15e3)
1577
+ }, accountId);
1578
+ }
1579
+ failureSnapshot(accountId, code, now) {
1580
+ const existing = this.store.get("copilot", accountId, now);
1581
+ const snapshot = existing ? {
1582
+ ...existing,
1583
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1584
+ windows: existing.windows.map((window) => ({
1585
+ ...window,
1586
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1587
+ })),
1588
+ lastErrorCode: code
1589
+ } : {
1590
+ providerId: "copilot",
1591
+ accountId,
1592
+ source: "oauth-usage-api",
1593
+ observedAt: new Date(now).toISOString(),
1594
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1595
+ windows: [
1596
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
1597
+ ],
1598
+ lastErrorCode: code
1599
+ };
1600
+ this.store.set(snapshot);
1601
+ return snapshot;
1602
+ }
1603
+ unsupportedSnapshot(accountId, now) {
1604
+ return {
1605
+ providerId: "copilot",
1606
+ accountId,
1607
+ source: "oauth-usage-api",
1608
+ observedAt: new Date(now).toISOString(),
1609
+ windows: [
1610
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
1611
+ ],
1612
+ lastErrorCode: "copilot_usage_unsupported_auth"
1613
+ };
822
1614
  }
823
- return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
1615
+ };
1616
+
1617
+ // src/allowance/GeminiAllowanceCollector.ts
1618
+ import { getGeminiCodeAssistProjectResolver } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
1619
+ import {
1620
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore6
1621
+ } from "@omnicross/core/pipeline/AccountAllowanceStore";
1622
+ import { fetchUpstream as fetchUpstream6 } from "@omnicross/core/pipeline/upstreamFetch";
1623
+ import {
1624
+ getGeminiCliIdentityHeaders,
1625
+ resolveCodeAssistEndpoint
1626
+ } from "@omnicross/core/transformer/transformers";
1627
+ var GEMINI_ALLOWANCE_CACHE_MS = 5 * 6e4;
1628
+ function isRecord4(value) {
1629
+ return !!value && typeof value === "object" && !Array.isArray(value);
824
1630
  }
825
- var KimiAllowanceCollector = class {
826
- constructor(credentials, store = getSharedAccountAllowanceStore3(), fetchImpl = (url, init, accountId) => fetchUpstream3(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
1631
+ function secondsUntil6(instant, now) {
1632
+ if (!instant) return void 0;
1633
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1634
+ }
1635
+ function parseGeminiQuotaPayload(payload, now) {
1636
+ if (!isRecord4(payload)) return null;
1637
+ const buckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
1638
+ const windows = [];
1639
+ const seen = /* @__PURE__ */ new Set();
1640
+ for (const raw of buckets) {
1641
+ if (!isRecord4(raw)) continue;
1642
+ const modelId = typeof raw["modelId"] === "string" && raw["modelId"].trim() ? raw["modelId"].trim() : void 0;
1643
+ const id = `gemini:${modelId ?? "all"}`;
1644
+ if (seen.has(id)) continue;
1645
+ seen.add(id);
1646
+ const fractionRaw = typeof raw["remainingFraction"] === "number" ? raw["remainingFraction"] : Number(raw["remainingFraction"]);
1647
+ 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;
1648
+ const resetRaw = typeof raw["resetTime"] === "string" && raw["resetTime"].trim() ? raw["resetTime"] : void 0;
1649
+ const resetsAt = resetRaw !== void 0 && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
1650
+ windows.push({
1651
+ id,
1652
+ label: modelId ? `Gemini ${modelId}` : "Gemini quota",
1653
+ scope: modelId ? "model-family" : "all",
1654
+ ...modelId ? { modelFamily: modelId } : {},
1655
+ usedPercent,
1656
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1657
+ remainingSeconds: secondsUntil6(resetsAt, now),
1658
+ state: "fresh"
1659
+ });
1660
+ }
1661
+ return windows.length > 0 ? windows : null;
1662
+ }
1663
+ var GeminiAllowanceCollector = class {
1664
+ constructor(credentials, store = getSharedAccountAllowanceStore6(), fetchImpl = (url, init, accountId) => fetchUpstream6(url, init, { providerId: "gemini", accountId, redactBodies: true }), now = Date.now, projectResolver = getGeminiCodeAssistProjectResolver()) {
827
1665
  this.credentials = credentials;
828
1666
  this.store = store;
829
1667
  this.fetchImpl = fetchImpl;
830
1668
  this.now = now;
1669
+ this.projectResolver = projectResolver;
831
1670
  }
832
1671
  credentials;
833
1672
  store;
834
1673
  fetchImpl;
835
1674
  now;
1675
+ projectResolver;
836
1676
  inFlight = /* @__PURE__ */ new Map();
837
1677
  async collectMany(accounts, options = {}) {
838
- const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1678
+ const settled = await Promise.allSettled(
1679
+ accounts.map((account) => this.collect(account, options))
1680
+ );
839
1681
  return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
840
1682
  }
841
1683
  collect(account, options = {}) {
842
1684
  const now = this.now();
843
1685
  if (account.tokens.authMethod !== "oauth") {
844
- const existing = this.store.get("kimi", account.id, now);
1686
+ const existing = this.store.get("gemini", account.id, now);
845
1687
  if (existing?.windows.every((window) => window.state === "unsupported")) {
846
1688
  return Promise.resolve(existing);
847
1689
  }
@@ -849,13 +1691,13 @@ var KimiAllowanceCollector = class {
849
1691
  this.store.set(snapshot);
850
1692
  return Promise.resolve(snapshot);
851
1693
  }
852
- const cached = this.store.get("kimi", account.id, now);
1694
+ const cached = this.store.get("gemini", account.id, now);
853
1695
  if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
854
1696
  return Promise.resolve(cached);
855
1697
  }
856
1698
  const running = this.inFlight.get(account.id);
857
1699
  if (running) return running;
858
- 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));
1700
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "gemini_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
859
1701
  this.inFlight.set(account.id, promise);
860
1702
  return promise;
861
1703
  }
@@ -865,102 +1707,105 @@ var KimiAllowanceCollector = class {
865
1707
  const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
866
1708
  return Number.isFinite(expiresAt) && expiresAt > now + ahead;
867
1709
  }
868
- async fetchAccount(accountId, tokens) {
869
- let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
870
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
871
- let response = await this.request(accountId, accessToken, tokens);
872
- if (response.status === 401) {
873
- const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
874
- if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
875
- accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
876
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
877
- response = await this.request(accountId, accessToken, tokens);
1710
+ async fetchAccount(accountId) {
1711
+ let accessToken = await this.credentials.getAccessTokenForAccount("gemini", accountId);
1712
+ if (!accessToken) return this.failureSnapshot(accountId, "gemini_usage_token_unavailable", this.now());
1713
+ let project;
1714
+ try {
1715
+ project = await this.projectResolver.resolveProject(accessToken);
1716
+ } catch {
1717
+ project = void 0;
878
1718
  }
879
- if (response.status === 403) {
880
- const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
881
- this.store.set(snapshot2);
882
- return snapshot2;
1719
+ let response = await this.request(accountId, accessToken, project);
1720
+ if (response.status === 401 || response.status === 403) {
1721
+ const refreshed = await this.credentials.refreshAccountToken("gemini", accountId);
1722
+ if (!refreshed) return this.failureSnapshot(accountId, "gemini_usage_unauthorized", this.now());
1723
+ accessToken = await this.credentials.getAccessTokenForAccount("gemini", accountId);
1724
+ if (!accessToken) return this.failureSnapshot(accountId, "gemini_usage_token_unavailable", this.now());
1725
+ response = await this.request(accountId, accessToken, project);
1726
+ if (response.status === 401 || response.status === 403) {
1727
+ return this.failureSnapshot(accountId, "gemini_usage_unauthorized", this.now());
1728
+ }
883
1729
  }
884
- if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
1730
+ if (!response.ok) return this.failureSnapshot(accountId, "gemini_usage_http_error", this.now());
885
1731
  let payload;
886
1732
  try {
887
1733
  payload = await response.json();
888
1734
  } catch {
889
- return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
1735
+ return this.failureSnapshot(accountId, "gemini_usage_invalid_response", this.now());
890
1736
  }
891
1737
  const now = this.now();
892
- const windows = parseKimiUsagePayload(payload, now);
1738
+ const windows = parseGeminiQuotaPayload(payload, now);
893
1739
  const snapshot = {
894
- providerId: "kimi",
1740
+ providerId: "gemini",
895
1741
  accountId,
896
1742
  source: "oauth-usage-api",
897
1743
  observedAt: new Date(now).toISOString(),
898
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
899
- windows: windows.length > 0 ? windows : [
900
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
901
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1744
+ expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
1745
+ windows: windows ?? [
1746
+ { id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unavailable" }
902
1747
  ],
903
- ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
1748
+ ...windows ? {} : { lastErrorCode: "gemini_usage_invalid_response" }
904
1749
  };
905
1750
  this.store.set(snapshot);
906
1751
  return snapshot;
907
1752
  }
908
- request(accountId, accessToken, tokens) {
909
- return this.fetchImpl(KIMI_USAGE_URL, {
910
- method: "GET",
1753
+ request(accountId, accessToken, project) {
1754
+ return this.fetchImpl(`${resolveCodeAssistEndpoint()}/v1internal:retrieveUserQuota`, {
1755
+ method: "POST",
911
1756
  headers: {
912
1757
  Authorization: `Bearer ${accessToken}`,
913
1758
  Accept: "application/json",
914
- ...kimiFingerprintHeaders(tokens.deviceId)
1759
+ "Content-Type": "application/json",
1760
+ ...getGeminiCliIdentityHeaders()
915
1761
  },
1762
+ body: JSON.stringify(project ? { project } : {}),
916
1763
  signal: AbortSignal.timeout(15e3)
917
1764
  }, accountId);
918
1765
  }
919
1766
  failureSnapshot(accountId, code, now) {
920
- const existing = this.store.get("kimi", accountId, now);
1767
+ const existing = this.store.get("gemini", accountId, now);
921
1768
  const snapshot = existing ? {
922
1769
  ...existing,
923
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1770
+ expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
924
1771
  windows: existing.windows.map((window) => ({
925
1772
  ...window,
926
1773
  state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
927
1774
  })),
928
1775
  lastErrorCode: code
929
1776
  } : {
930
- providerId: "kimi",
1777
+ providerId: "gemini",
931
1778
  accountId,
932
1779
  source: "oauth-usage-api",
933
1780
  observedAt: new Date(now).toISOString(),
934
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1781
+ expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
935
1782
  windows: [
936
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
937
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1783
+ { id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unavailable" }
938
1784
  ],
939
1785
  lastErrorCode: code
940
1786
  };
941
1787
  this.store.set(snapshot);
942
1788
  return snapshot;
943
1789
  }
944
- unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
1790
+ unsupportedSnapshot(accountId, now) {
945
1791
  return {
946
- providerId: "kimi",
1792
+ providerId: "gemini",
947
1793
  accountId,
948
1794
  source: "oauth-usage-api",
949
1795
  observedAt: new Date(now).toISOString(),
950
1796
  windows: [
951
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
952
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
1797
+ { id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unsupported" }
953
1798
  ],
954
- lastErrorCode: code
1799
+ lastErrorCode: "gemini_usage_unsupported_auth"
955
1800
  };
956
1801
  }
957
1802
  };
958
1803
 
959
1804
  // src/allowance/OpenCodeGoAllowanceCollector.ts
960
1805
  import {
961
- getSharedAccountAllowanceStore as getSharedAccountAllowanceStore4
1806
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore7
962
1807
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
963
- import { fetchUpstream as fetchUpstream4 } from "@omnicross/core/pipeline/upstreamFetch";
1808
+ import { fetchUpstream as fetchUpstream7 } from "@omnicross/core/pipeline/upstreamFetch";
964
1809
  import { normalizeOpenCodeGoBaseUrl } from "@omnicross/subscriptions";
965
1810
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
966
1811
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
@@ -974,7 +1819,7 @@ function isoInstant2(value) {
974
1819
  const time = Date.parse(value);
975
1820
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
976
1821
  }
977
- function secondsUntil4(instant, now) {
1822
+ function secondsUntil7(instant, now) {
978
1823
  if (!instant) return void 0;
979
1824
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
980
1825
  }
@@ -989,12 +1834,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
989
1834
  usedPercent,
990
1835
  windowMinutes: minutes,
991
1836
  ...resetsAt !== void 0 ? { resetsAt } : {},
992
- remainingSeconds: secondsUntil4(resetsAt, now),
1837
+ remainingSeconds: secondsUntil7(resetsAt, now),
993
1838
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
994
1839
  };
995
1840
  }
996
1841
  var OpenCodeGoAllowanceCollector = class {
997
- constructor(credentials, store = getSharedAccountAllowanceStore4(), fetchImpl = (url, init, accountId) => fetchUpstream4(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
1842
+ constructor(credentials, store = getSharedAccountAllowanceStore7(), fetchImpl = (url, init, accountId) => fetchUpstream7(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
998
1843
  this.credentials = credentials;
999
1844
  this.store = store;
1000
1845
  this.fetchImpl = fetchImpl;
@@ -1099,7 +1944,7 @@ function codexUnavailable(accountId, now) {
1099
1944
  };
1100
1945
  }
1101
1946
  var AccountAllowanceService = class {
1102
- constructor(credentials, store = getSharedAccountAllowanceStore5(), collector, codexCollector, kimiCollector, opencodegoCollector, now = Date.now) {
1947
+ constructor(credentials, store = getSharedAccountAllowanceStore8(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
1103
1948
  this.credentials = credentials;
1104
1949
  this.store = store;
1105
1950
  this.now = now;
@@ -1107,6 +1952,9 @@ var AccountAllowanceService = class {
1107
1952
  this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
1108
1953
  this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
1109
1954
  this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
1955
+ this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
1956
+ this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
1957
+ this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
1110
1958
  }
1111
1959
  credentials;
1112
1960
  store;
@@ -1114,7 +1962,10 @@ var AccountAllowanceService = class {
1114
1962
  claudeCollector;
1115
1963
  codexCollector;
1116
1964
  kimiCollector;
1965
+ grokCollector;
1966
+ copilotCollector;
1117
1967
  opencodegoCollector;
1968
+ geminiCollector;
1118
1969
  /**
1119
1970
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1120
1971
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -1148,11 +1999,29 @@ var AccountAllowanceService = class {
1148
1999
  (account) => !filter.accountId || account.id === filter.accountId
1149
2000
  );
1150
2001
  if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
2002
+ const wantsGrok = !filter.providerId || filter.providerId === "grok";
2003
+ const grokAccounts = (config.grokAccounts ?? []).filter(
2004
+ (account) => !filter.accountId || account.id === filter.accountId
2005
+ );
2006
+ if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
2007
+ const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
2008
+ const copilotAccounts = (config.copilotAccounts ?? []).filter(
2009
+ (account) => !filter.accountId || account.id === filter.accountId
2010
+ );
2011
+ if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
2012
+ const wantsGemini = !filter.providerId || filter.providerId === "gemini";
2013
+ const geminiAccounts = (config.geminiAccounts ?? []).filter(
2014
+ (account) => !filter.accountId || account.id === filter.accountId
2015
+ );
2016
+ if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
1151
2017
  const known = /* @__PURE__ */ new Set();
1152
2018
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
1153
2019
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
1154
2020
  if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
1155
2021
  if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
2022
+ if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
2023
+ if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
2024
+ if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
1156
2025
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
1157
2026
  }
1158
2027
  knownAccounts(config) {
@@ -1160,7 +2029,10 @@ var AccountAllowanceService = class {
1160
2029
  ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1161
2030
  ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
1162
2031
  ...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
1163
- ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id }))
2032
+ ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
2033
+ ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
2034
+ ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
2035
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
1164
2036
  ];
1165
2037
  }
1166
2038
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -1203,6 +2075,33 @@ var AccountAllowanceService = class {
1203
2075
  );
1204
2076
  return this.kimiCollector.collectMany(accounts, { force: true });
1205
2077
  }
2078
+ /** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
2079
+ async refreshCopilot(accountId) {
2080
+ const config = await this.credentials.getFullConfig();
2081
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2082
+ const accounts = (config.copilotAccounts ?? []).filter(
2083
+ (account) => !accountId || account.id === accountId
2084
+ );
2085
+ return this.copilotCollector.collectMany(accounts, { force: true });
2086
+ }
2087
+ /** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
2088
+ async refreshGrok(accountId) {
2089
+ const config = await this.credentials.getFullConfig();
2090
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2091
+ const accounts = (config.grokAccounts ?? []).filter(
2092
+ (account) => !accountId || account.id === accountId
2093
+ );
2094
+ return this.grokCollector.collectMany(accounts, { force: true });
2095
+ }
2096
+ /** Force-refresh Gemini usage (Code Assist retrieveUserQuota) for one/all accounts. */
2097
+ async refreshGemini(accountId) {
2098
+ const config = await this.credentials.getFullConfig();
2099
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2100
+ const accounts = (config.geminiAccounts ?? []).filter(
2101
+ (account) => !accountId || account.id === accountId
2102
+ );
2103
+ return this.geminiCollector.collectMany(accounts, { force: true });
2104
+ }
1206
2105
  /**
1207
2106
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
1208
2107
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -1217,6 +2116,9 @@ var AccountAllowanceService = class {
1217
2116
  await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
1218
2117
  await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
1219
2118
  await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
2119
+ await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
2120
+ await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
2121
+ await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
1220
2122
  }
1221
2123
  /** Remove a cache row as soon as an account is deleted by the admin path. */
1222
2124
  removeAccountSnapshot(providerId, accountId) {
@@ -1653,7 +2555,8 @@ import {
1653
2555
  } from "@omnicross/contracts/image-generation-types";
1654
2556
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling2 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
1655
2557
  import { getSharedAccountHealth } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
1656
- import { fetchUpstream as fetchUpstream5 } from "@omnicross/core/pipeline/upstreamFetch";
2558
+ import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
2559
+ import { mergeExtraHeaders } from "@omnicross/core";
1657
2560
 
1658
2561
  // src/image-generation/imagesConfigValidation.ts
1659
2562
  import { validateImagesServerConfig } from "@omnicross/core/outbound-api";
@@ -1966,6 +2869,7 @@ async function applyServerConfigTransaction(current, next, deps) {
1966
2869
 
1967
2870
  // src/config.ts
1968
2871
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
2872
+ import { EXTRA_HEADER_RESERVED_NAMES } from "@omnicross/core";
1969
2873
 
1970
2874
  // src/secrets/envelope.ts
1971
2875
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
@@ -2377,6 +3281,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
2377
3281
  "openai-response",
2378
3282
  "gemini-code-assist"
2379
3283
  ];
3284
+ function validateExtraHeaders(raw) {
3285
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3286
+ const reserved = EXTRA_HEADER_RESERVED_NAMES;
3287
+ const out = {};
3288
+ for (const [name, value] of Object.entries(raw)) {
3289
+ if (!name.trim()) continue;
3290
+ if (typeof value !== "string") continue;
3291
+ if (reserved.has(name.toLowerCase())) continue;
3292
+ out[name] = value;
3293
+ }
3294
+ return Object.keys(out).length > 0 ? out : void 0;
3295
+ }
2380
3296
  function validateApiKeys(raw) {
2381
3297
  if (!Array.isArray(raw)) return void 0;
2382
3298
  const out = [];
@@ -2590,6 +3506,9 @@ function validateProvider(raw, index) {
2590
3506
  apiVersion,
2591
3507
  maxConcurrency,
2592
3508
  modelsEndpoint,
3509
+ // Static extra headers: load-guard (reserved names dropped), collapse-to-
3510
+ // undefined; enforced by the outbound header funnel + admin probes.
3511
+ extraHeaders: validateExtraHeaders(p["extraHeaders"]),
2593
3512
  // Provider transformer config (app-parity child 5): load-guard, collapse-to-
2594
3513
  // undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
2595
3514
  // Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
@@ -3559,7 +4478,8 @@ function listMappablePresets() {
3559
4478
  description: preset.description,
3560
4479
  features: preset.features,
3561
4480
  website: preset.website,
3562
- modelsEndpoint: preset.modelsEndpoint
4481
+ modelsEndpoint: preset.modelsEndpoint,
4482
+ extraHeaders: preset.extraHeaders
3563
4483
  });
3564
4484
  }
3565
4485
  return { mappable, excluded };
@@ -3731,7 +4651,9 @@ var VALID_PROVIDER_IDS = [
3731
4651
  "codex",
3732
4652
  "gemini",
3733
4653
  "opencodego",
3734
- "kimi"
4654
+ "kimi",
4655
+ "grok",
4656
+ "copilot"
3735
4657
  ];
3736
4658
  function asSubscriptionProviderId(id) {
3737
4659
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -3879,6 +4801,40 @@ function validateKimi(body) {
3879
4801
  copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
3880
4802
  return out;
3881
4803
  }
4804
+ function validateGrok(body) {
4805
+ const authMethod = str(body["authMethod"]);
4806
+ const status = str(body["status"]);
4807
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4808
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4809
+ const out = {
4810
+ authMethod,
4811
+ status
4812
+ };
4813
+ copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
4814
+ return out;
4815
+ }
4816
+ function validateCopilot(body) {
4817
+ const authMethod = str(body["authMethod"]);
4818
+ const status = str(body["status"]);
4819
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4820
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4821
+ const out = {
4822
+ authMethod,
4823
+ status
4824
+ };
4825
+ copyOptional(out, body, [
4826
+ "accessToken",
4827
+ "refreshToken",
4828
+ "expiresAt",
4829
+ "accountId",
4830
+ "email",
4831
+ "apiEndpoint",
4832
+ "enterpriseUrl",
4833
+ "lastRefreshedAt",
4834
+ "errorMessage"
4835
+ ]);
4836
+ return out;
4837
+ }
3882
4838
  function validateOpenCodeGo(body) {
3883
4839
  const authMethod = str(body["authMethod"]);
3884
4840
  const status = str(body["status"]);
@@ -3916,6 +4872,10 @@ function validateTokenBody(providerId, body) {
3916
4872
  return validateOpenCodeGo(body);
3917
4873
  case "kimi":
3918
4874
  return validateKimi(body);
4875
+ case "grok":
4876
+ return validateGrok(body);
4877
+ case "copilot":
4878
+ return validateCopilot(body);
3919
4879
  default:
3920
4880
  return null;
3921
4881
  }
@@ -3945,12 +4905,12 @@ async function statusEntryFor(reader, providerId) {
3945
4905
 
3946
4906
  // src/admin/accountsOAuth.ts
3947
4907
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
3948
- function err3(status, message) {
4908
+ function err5(status, message) {
3949
4909
  return { status, body: { error: { type: "admin_api_error", message } } };
3950
4910
  }
3951
4911
  function handleOAuthStart(providerId, deps) {
3952
4912
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3953
- return err3(400, `oauth not available for provider '${providerId}'`);
4913
+ return err5(400, `oauth not available for provider '${providerId}'`);
3954
4914
  }
3955
4915
  const flow = providerId === "claude" ? claudeOAuth : geminiOAuth;
3956
4916
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
@@ -3959,23 +4919,23 @@ function handleOAuthStart(providerId, deps) {
3959
4919
  }
3960
4920
  async function handleOAuthComplete(providerId, body, deps) {
3961
4921
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3962
- return err3(400, `oauth not available for provider '${providerId}'`);
4922
+ return err5(400, `oauth not available for provider '${providerId}'`);
3963
4923
  }
3964
4924
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
3965
4925
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
3966
- if (!sessionId) return err3(400, "oauth complete requires { sessionId }");
3967
- if (!rawCode) return err3(400, "oauth complete requires { code }");
4926
+ if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
4927
+ if (!rawCode) return err5(400, "oauth complete requires { code }");
3968
4928
  const session = deps.oauthSessions.peek(sessionId);
3969
- if (!session) return err3(410, "oauth session is unknown, expired, or already used");
4929
+ if (!session) return err5(410, "oauth session is unknown, expired, or already used");
3970
4930
  if (session.providerId !== providerId) {
3971
- return err3(400, `oauth session does not match provider '${providerId}'`);
4931
+ return err5(400, `oauth session does not match provider '${providerId}'`);
3972
4932
  }
3973
4933
  let code = rawCode.trim();
3974
4934
  if (providerId === "claude") {
3975
4935
  const [splitCode, pastedState] = code.split("#");
3976
- if (!splitCode) return err3(400, "no authorization code was provided");
4936
+ if (!splitCode) return err5(400, "no authorization code was provided");
3977
4937
  if (pastedState && pastedState !== session.state) {
3978
- return err3(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4938
+ return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
3979
4939
  }
3980
4940
  code = splitCode;
3981
4941
  }
@@ -3985,7 +4945,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3985
4945
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
3986
4946
  } catch (exchangeError) {
3987
4947
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
3988
- return err3(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4948
+ return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
3989
4949
  }
3990
4950
  deps.oauthSessions.consume(sessionId);
3991
4951
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -4323,8 +5283,8 @@ function errBody(message) {
4323
5283
  return { error: { type: "admin_api_error", message } };
4324
5284
  }
4325
5285
  var defaultCommandRunner = (command) => new Promise((resolve10) => {
4326
- exec(command, { timeout: 18e4 }, (err6, _stdout, stderr) => {
4327
- if (err6) resolve10({ ok: false, error: stderr.trim() || err6.message });
5286
+ exec(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5287
+ if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
4328
5288
  else resolve10({ ok: true });
4329
5289
  });
4330
5290
  });
@@ -4370,8 +5330,8 @@ async function handleCliLaunch(cli, body, ctx) {
4370
5330
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
4371
5331
  model: typeof body["model"] === "string" ? body["model"] : void 0
4372
5332
  });
4373
- } catch (err6) {
4374
- return { status: 400, body: errBody(err6 instanceof Error ? err6.message : "no launch target") };
5333
+ } catch (err8) {
5334
+ return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
4375
5335
  }
4376
5336
  const id = randomUUID2();
4377
5337
  let leaseId2;
@@ -4399,9 +5359,9 @@ async function handleCliLaunch(cli, body, ctx) {
4399
5359
  } else {
4400
5360
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
4401
5361
  }
4402
- } catch (err6) {
4403
- const status = err6 instanceof RouteLeaseError2 ? err6.status : 400;
4404
- return { status, body: errBody(err6 instanceof Error ? err6.message : "failed to build launch env") };
5362
+ } catch (err8) {
5363
+ const status = err8 instanceof RouteLeaseError2 ? err8.status : 400;
5364
+ return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
4405
5365
  }
4406
5366
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
4407
5367
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -4429,9 +5389,9 @@ async function handleCliLaunch(cli, body, ctx) {
4429
5389
  onFailure: onSessionEnd
4430
5390
  });
4431
5391
  if (cleanup) openerCleanup = cleanup;
4432
- } catch (err6) {
5392
+ } catch (err8) {
4433
5393
  onSessionEnd();
4434
- return { status: 500, body: errBody(err6 instanceof Error ? err6.message : "failed to open terminal") };
5394
+ return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
4435
5395
  }
4436
5396
  if (ended) {
4437
5397
  openerCleanup?.();
@@ -4980,7 +5940,7 @@ async function handleSearchQuery(req, res, deps) {
4980
5940
  // src/admin/searchAdminView.ts
4981
5941
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
4982
5942
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
4983
- function isRecord2(value) {
5943
+ function isRecord5(value) {
4984
5944
  return value !== null && typeof value === "object" && !Array.isArray(value);
4985
5945
  }
4986
5946
  function redactSearchServerConfig(search) {
@@ -5030,13 +5990,13 @@ function resolveSecretField(entry, field, stored) {
5030
5990
  else delete entry[field];
5031
5991
  }
5032
5992
  function preserveSearchSecrets(incoming, current) {
5033
- if (!isRecord2(incoming)) return incoming;
5993
+ if (!isRecord5(incoming)) return incoming;
5034
5994
  const section = { ...incoming };
5035
5995
  const providersValue = section["providers"];
5036
- if (!isRecord2(providersValue)) return section;
5996
+ if (!isRecord5(providersValue)) return section;
5037
5997
  const providers = {};
5038
5998
  for (const [id, entryValue] of Object.entries(providersValue)) {
5039
- if (!isRecord2(entryValue)) {
5999
+ if (!isRecord5(entryValue)) {
5040
6000
  providers[id] = entryValue;
5041
6001
  continue;
5042
6002
  }
@@ -5114,7 +6074,7 @@ function parseKeyPolicyBody(body) {
5114
6074
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
5115
6075
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
5116
6076
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
5117
- function isRecord3(value) {
6077
+ function isRecord6(value) {
5118
6078
  return !!value && typeof value === "object" && !Array.isArray(value);
5119
6079
  }
5120
6080
  function nonBlank(value) {
@@ -5134,7 +6094,7 @@ function validateGatewayBindingsSegment(patch) {
5134
6094
  const ids = /* @__PURE__ */ new Set();
5135
6095
  raw.forEach((entry, index) => {
5136
6096
  const path2 = `bindings[${index}]`;
5137
- if (!isRecord3(entry)) {
6097
+ if (!isRecord6(entry)) {
5138
6098
  errors.push(`${path2} must be an object`);
5139
6099
  return;
5140
6100
  }
@@ -5163,12 +6123,12 @@ function validateGatewayBindingsSegment(patch) {
5163
6123
  } else if (entry.modelMappings.length > 100) {
5164
6124
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
5165
6125
  } else if (entry.modelMappings.some(
5166
- (mapping) => !isRecord3(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6126
+ (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5167
6127
  )) {
5168
6128
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
5169
6129
  }
5170
6130
  }
5171
- if (!isRecord3(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6131
+ if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5172
6132
  errors.push(`${path2}.target is invalid`);
5173
6133
  } else {
5174
6134
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -5183,7 +6143,7 @@ function validateGatewayBindingsSegment(patch) {
5183
6143
  }
5184
6144
  }
5185
6145
  if (entry.modelMap !== void 0) {
5186
- if (!isRecord3(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6146
+ if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
5187
6147
  errors.push(`${path2}.modelMap must contain string values`);
5188
6148
  }
5189
6149
  }
@@ -5494,7 +6454,9 @@ var PROVIDER_KEYS = {
5494
6454
  accounts: "opencodegoAccounts",
5495
6455
  active: "activeOpencodegoAccountId"
5496
6456
  },
5497
- kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
6457
+ kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6458
+ grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6459
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
5498
6460
  };
5499
6461
  function clone(value) {
5500
6462
  return JSON.parse(JSON.stringify(value));
@@ -6016,7 +6978,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
6016
6978
  }
6017
6979
 
6018
6980
  // src/admin/adminMigration.ts
6019
- function err4(status, message) {
6981
+ function err6(status, message) {
6020
6982
  return { status, body: { error: { type: "admin_api_error", message } } };
6021
6983
  }
6022
6984
  async function handleExport(body, deps) {
@@ -6026,30 +6988,30 @@ async function handleExport(body, deps) {
6026
6988
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
6027
6989
  } catch (error) {
6028
6990
  if (error instanceof WeakPassphraseError) {
6029
- return err4(400, error.message);
6991
+ return err6(400, error.message);
6030
6992
  }
6031
- return err4(500, "failed to build the migration pack");
6993
+ return err6(500, "failed to build the migration pack");
6032
6994
  }
6033
6995
  }
6034
6996
  async function handleImport(body, deps) {
6035
6997
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
6036
6998
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
6037
6999
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
6038
- if (!blob) return err4(400, "import requires { blob }");
7000
+ if (!blob) return err6(400, "import requires { blob }");
6039
7001
  try {
6040
7002
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
6041
7003
  return { status: 200, body: counts };
6042
7004
  } catch (error) {
6043
7005
  if (error instanceof WeakPassphraseError) {
6044
- return err4(400, error.message);
7006
+ return err6(400, error.message);
6045
7007
  }
6046
- return err4(400, error instanceof Error ? error.message : "import failed");
7008
+ return err6(400, error instanceof Error ? error.message : "import failed");
6047
7009
  }
6048
7010
  }
6049
7011
 
6050
7012
  // src/admin/usagePricing.ts
6051
7013
  import { getSharedUsageThroughputTracker } from "@omnicross/core/usage";
6052
- var err5 = (status, message) => ({
7014
+ var err7 = (status, message) => ({
6053
7015
  status,
6054
7016
  body: { error: { type: "admin_api_error", message } }
6055
7017
  });
@@ -6062,7 +7024,7 @@ function parseRange(query2) {
6062
7024
  const startTs = parseFiniteInt(query2.get("startTs"));
6063
7025
  const endTs = parseFiniteInt(query2.get("endTs"));
6064
7026
  if (startTs === null || endTs === null) {
6065
- return err5(400, "startTs and endTs are required finite-integer unix-millis query params");
7027
+ return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
6066
7028
  }
6067
7029
  return { startTs, endTs };
6068
7030
  }
@@ -6087,14 +7049,14 @@ async function handleUsageGet(view, query2, deps) {
6087
7049
  case "timeseries": {
6088
7050
  const bucket = query2.get("bucket");
6089
7051
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
6090
- return err5(400, "bucket must be one of 'hour', 'day', 'month'");
7052
+ return err7(400, "bucket must be one of 'hour', 'day', 'month'");
6091
7053
  }
6092
7054
  const now = Date.now();
6093
7055
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
6094
7056
  if (clamped.startTs < clamped.endTs) {
6095
7057
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
6096
7058
  if (projected > MAX_TIMESERIES_BUCKETS) {
6097
- return err5(
7059
+ return err7(
6098
7060
  400,
6099
7061
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
6100
7062
  );
@@ -6117,7 +7079,7 @@ async function handleUsageGet(view, query2, deps) {
6117
7079
  };
6118
7080
  }
6119
7081
  default:
6120
- return err5(404, `unknown usage view '${view ?? ""}'`);
7082
+ return err7(404, `unknown usage view '${view ?? ""}'`);
6121
7083
  }
6122
7084
  }
6123
7085
  function poolKeyLabels(cfg) {
@@ -6166,7 +7128,7 @@ async function handlePricingList(deps) {
6166
7128
  async function handlePricingUpsert(body, deps) {
6167
7129
  const input = parsePricingEntryInput(body);
6168
7130
  if (!input) {
6169
- return err5(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7131
+ return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
6170
7132
  }
6171
7133
  const entry = await deps.pricingEngine.upsertManual(input);
6172
7134
  return { status: 200, body: { entry } };
@@ -6175,7 +7137,7 @@ async function handlePricingDelete(query2, deps) {
6175
7137
  const providerId = query2.get("providerId")?.trim() ?? "";
6176
7138
  const modelId = query2.get("modelId")?.trim() ?? "";
6177
7139
  if (!providerId || !modelId) {
6178
- return err5(400, "delete requires providerId and modelId query params");
7140
+ return err7(400, "delete requires providerId and modelId query params");
6179
7141
  }
6180
7142
  const deleted = await deps.pricingStore.delete(providerId, modelId);
6181
7143
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -6195,13 +7157,13 @@ async function handlePricingFetchLatest(deps) {
6195
7157
  }
6196
7158
  };
6197
7159
  } catch (e) {
6198
- return err5(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7160
+ return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
6199
7161
  }
6200
7162
  }
6201
7163
  async function handlePricingResolveConflicts(body, deps) {
6202
7164
  const raw = body["resolutions"];
6203
7165
  if (!Array.isArray(raw)) {
6204
- return err5(400, "resolve-conflicts requires { resolutions: [...] }");
7166
+ return err7(400, "resolve-conflicts requires { resolutions: [...] }");
6205
7167
  }
6206
7168
  const currentRows = await deps.pricingStore.getAll();
6207
7169
  const userEditedKeys = new Set(
@@ -6211,21 +7173,21 @@ async function handlePricingResolveConflicts(body, deps) {
6211
7173
  const pendingIncoming = /* @__PURE__ */ new Map();
6212
7174
  let staleCount = 0;
6213
7175
  for (const item of raw) {
6214
- if (!item || typeof item !== "object") return err5(400, "invalid resolution entry");
7176
+ if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
6215
7177
  const r = item;
6216
7178
  const action = r["action"];
6217
7179
  if (action !== "overwrite" && action !== "skip") {
6218
- return err5(400, "resolution action must be 'overwrite' or 'skip'");
7180
+ return err7(400, "resolution action must be 'overwrite' or 'skip'");
6219
7181
  }
6220
7182
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
6221
7183
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
6222
7184
  if (!providerId || !modelId) {
6223
- return err5(400, "each resolution requires top-level providerId and modelId");
7185
+ return err7(400, "each resolution requires top-level providerId and modelId");
6224
7186
  }
6225
7187
  const incoming = parsePricingEntryInput(r["incoming"]);
6226
- if (!incoming) return err5(400, "each resolution must echo a valid incoming pricing entry");
7188
+ if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
6227
7189
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
6228
- return err5(400, "resolution providerId/modelId must match the echoed incoming entry");
7190
+ return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
6229
7191
  }
6230
7192
  const key = `${providerId}::${modelId}`;
6231
7193
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -6270,7 +7232,7 @@ function query(req) {
6270
7232
  }
6271
7233
  function allowanceProvider(value) {
6272
7234
  if (!value) return void 0;
6273
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
7235
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
6274
7236
  }
6275
7237
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
6276
7238
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -6285,7 +7247,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6285
7247
  const pathProvider = rest.length >= 2 ? rest[0] : null;
6286
7248
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
6287
7249
  if (providerId === null) {
6288
- return writeError2(res, 400, "providerId must be claude, codex, kimi, or opencodego");
7250
+ return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, copilot, or gemini");
6289
7251
  }
6290
7252
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
6291
7253
  const allowances = await service.list({ providerId, accountId });
@@ -6327,6 +7289,36 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6327
7289
  }
6328
7290
  return writeJson3(res, 200, { allowances: allowances2 });
6329
7291
  }
7292
+ if (requestedProvider === "copilot") {
7293
+ if (!service.refreshCopilot) {
7294
+ return writeError2(res, 501, "copilot allowance refresh is not available");
7295
+ }
7296
+ const allowances2 = await service.refreshCopilot(accountId);
7297
+ if (accountId && allowances2.length === 0) {
7298
+ return writeError2(res, 404, `Copilot account '${accountId}' not found`);
7299
+ }
7300
+ return writeJson3(res, 200, { allowances: allowances2 });
7301
+ }
7302
+ if (requestedProvider === "grok") {
7303
+ if (!service.refreshGrok) {
7304
+ return writeError2(res, 501, "grok allowance refresh is not available");
7305
+ }
7306
+ const allowances2 = await service.refreshGrok(accountId);
7307
+ if (accountId && allowances2.length === 0) {
7308
+ return writeError2(res, 404, `Grok account '${accountId}' not found`);
7309
+ }
7310
+ return writeJson3(res, 200, { allowances: allowances2 });
7311
+ }
7312
+ if (requestedProvider === "gemini") {
7313
+ if (!service.refreshGemini) {
7314
+ return writeError2(res, 501, "gemini allowance refresh is not available");
7315
+ }
7316
+ const allowances2 = await service.refreshGemini(accountId);
7317
+ if (accountId && allowances2.length === 0) {
7318
+ return writeError2(res, 404, `Gemini account '${accountId}' not found`);
7319
+ }
7320
+ return writeJson3(res, 200, { allowances: allowances2 });
7321
+ }
6330
7322
  const allowances = await service.refreshClaude(accountId);
6331
7323
  if (accountId && allowances.length === 0) {
6332
7324
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
@@ -6428,6 +7420,9 @@ function toProviderView(row) {
6428
7420
  apiVersion: row.apiVersion,
6429
7421
  maxConcurrency: row.maxConcurrency,
6430
7422
  modelsEndpoint: row.modelsEndpoint,
7423
+ // Static extra headers round-trip VERBATIM (non-secret identity values;
7424
+ // auth/content names were already dropped at the write/load gate).
7425
+ extraHeaders: row.extraHeaders,
6431
7426
  // app-parity child 5: transformer config round-trips VERBATIM (non-secret —
6432
7427
  // transform-rule names + options, no key material; absent stays absent).
6433
7428
  transformer: row.transformer,
@@ -6497,8 +7492,8 @@ async function handleAdminApi(req, res, path2, deps) {
6497
7492
  default:
6498
7493
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
6499
7494
  }
6500
- } catch (err6) {
6501
- writeJsonError(res, 500, err6 instanceof Error ? err6.message : String(err6));
7495
+ } catch (err8) {
7496
+ writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
6502
7497
  }
6503
7498
  }
6504
7499
  function requestQuery(req) {
@@ -6656,6 +7651,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
6656
7651
  persistProviders(cfg, deps);
6657
7652
  return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
6658
7653
  }
7654
+ function expandRowExtraHeaders(row) {
7655
+ return mergeExtraHeaders({}, row.extraHeaders);
7656
+ }
6659
7657
  async function handleDiscoverModels(res, id, cfg) {
6660
7658
  if (!id) return writeJsonError(res, 400, "provider id required in path");
6661
7659
  const row = cfg.providers.find((p) => p.id === id);
@@ -6669,7 +7667,8 @@ async function handleDiscoverModels(res, id, cfg) {
6669
7667
  try {
6670
7668
  const headers = { Accept: "application/json" };
6671
7669
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
6672
- const response = await fetchUpstream5(url, { method: "GET", headers }, { providerId: "byo" });
7670
+ Object.assign(headers, expandRowExtraHeaders(row));
7671
+ const response = await fetchUpstream8(url, { method: "GET", headers }, { providerId: "byo" });
6673
7672
  if (!response.ok) {
6674
7673
  const text = await response.text().catch(() => "");
6675
7674
  let message = text.slice(0, 300);
@@ -6686,8 +7685,8 @@ async function handleDiscoverModels(res, id, cfg) {
6686
7685
  const data = await response.json();
6687
7686
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
6688
7687
  return writeJson4(res, 200, { models });
6689
- } catch (err6) {
6690
- const message = err6 instanceof Error ? err6.message : String(err6);
7688
+ } catch (err8) {
7689
+ const message = err8 instanceof Error ? err8.message : String(err8);
6691
7690
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
6692
7691
  }
6693
7692
  }
@@ -6726,9 +7725,10 @@ async function handleTestModel(req, res, id, cfg) {
6726
7725
  messages: [{ role: "user", content: prompt }]
6727
7726
  };
6728
7727
  }
7728
+ Object.assign(headers, expandRowExtraHeaders(row));
6729
7729
  const startedAt = Date.now();
6730
7730
  try {
6731
- const response = await fetchUpstream5(
7731
+ const response = await fetchUpstream8(
6732
7732
  url,
6733
7733
  { method: "POST", headers, body: JSON.stringify(payload) },
6734
7734
  { providerId: "byo" }
@@ -6750,8 +7750,8 @@ async function handleTestModel(req, res, id, cfg) {
6750
7750
  latencyMs,
6751
7751
  sample: extractSampleText(text, row.apiFormat)
6752
7752
  });
6753
- } catch (err6) {
6754
- const message = err6 instanceof Error ? err6.message : String(err6);
7753
+ } catch (err8) {
7754
+ const message = err8 instanceof Error ? err8.message : String(err8);
6755
7755
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
6756
7756
  }
6757
7757
  }
@@ -7033,6 +8033,7 @@ function parseProviderInput(body, existing) {
7033
8033
  const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
7034
8034
  const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
7035
8035
  const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
8036
+ const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
7036
8037
  const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
7037
8038
  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;
7038
8039
  const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
@@ -7058,6 +8059,7 @@ function parseProviderInput(body, existing) {
7058
8059
  apiVersion,
7059
8060
  maxConcurrency,
7060
8061
  modelsEndpoint,
8062
+ extraHeaders,
7061
8063
  transformer: migrated.transformer,
7062
8064
  codingPlan,
7063
8065
  apiModes,
@@ -7079,7 +8081,10 @@ function handlePresets(res, method) {
7079
8081
  description: p.description,
7080
8082
  features: p.features,
7081
8083
  website: p.website,
7082
- modelsEndpoint: p.modelsEndpoint
8084
+ modelsEndpoint: p.modelsEndpoint,
8085
+ // Static extra headers ride along so `addFromPreset` can seed them onto the
8086
+ // row (the write gateway re-validates via the shared allowlist).
8087
+ extraHeaders: p.extraHeaders
7083
8088
  }));
7084
8089
  return writeJson4(res, 200, { presets, excluded });
7085
8090
  }
@@ -7561,12 +8566,12 @@ async function handleAccounts(req, res, method, rest, deps) {
7561
8566
  }
7562
8567
  return writeJson4(res, 200, { ok: true, affected: result.affected });
7563
8568
  }
7564
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[3] === "status") {
7565
- const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : handleKimiOAuthStatus(rest[2], deps);
8569
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
8570
+ 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);
7566
8571
  return writeJson4(res, result.status, result.body);
7567
8572
  }
7568
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[2]) {
7569
- const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : handleKimiOAuthCancel(rest[2], deps);
8573
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
8574
+ 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);
7570
8575
  return writeJson4(res, result.status, result.body);
7571
8576
  }
7572
8577
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -7627,6 +8632,15 @@ async function handleAccounts(req, res, method, rest, deps) {
7627
8632
  const result2 = await handleKimiOAuthStart(deps);
7628
8633
  return writeJson4(res, result2.status, result2.body);
7629
8634
  }
8635
+ if (providerId === "grok") {
8636
+ const result2 = await handleGrokOAuthStart(deps);
8637
+ return writeJson4(res, result2.status, result2.body);
8638
+ }
8639
+ if (providerId === "copilot") {
8640
+ const body2 = await readJsonBody4(req);
8641
+ const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
8642
+ return writeJson4(res, result2.status, result2.body);
8643
+ }
7630
8644
  const result = handleOAuthStart(providerId, deps);
7631
8645
  return writeJson4(res, result.status, result.body);
7632
8646
  }
@@ -8121,12 +9135,12 @@ async function handlePlayground(req, res, method, deps) {
8121
9135
  const payload = body["body"];
8122
9136
  const status = deps.outboundApiServer.getStatus();
8123
9137
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
8124
- const path2 = resolvePlaygroundPath(endpoint, isRecord4(payload) ? payload : {});
9138
+ const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
8125
9139
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
8126
9140
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
8127
9141
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
8128
9142
  }
8129
- function isRecord4(v) {
9143
+ function isRecord7(v) {
8130
9144
  return !!v && typeof v === "object" && !Array.isArray(v);
8131
9145
  }
8132
9146
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -8155,8 +9169,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
8155
9169
  });
8156
9170
  }
8157
9171
  );
8158
- upstream.on("error", (err6) => {
8159
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err6.message}`);
9172
+ upstream.on("error", (err8) => {
9173
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
8160
9174
  else res.end();
8161
9175
  resolve10();
8162
9176
  });
@@ -8261,7 +9275,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
8261
9275
  }
8262
9276
 
8263
9277
  // src/admin/version.ts
8264
- var DAEMON_VERSION = true ? "0.3.1" : "0.0.0-dev";
9278
+ var DAEMON_VERSION = true ? "0.4.1" : "0.0.0-dev";
8265
9279
 
8266
9280
  // src/admin/AdminServer.ts
8267
9281
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -8304,13 +9318,13 @@ var AdminServer = class {
8304
9318
  const server = http2.createServer((req, res) => {
8305
9319
  this.onRequest(req, res);
8306
9320
  });
8307
- const onError = (err6) => {
8308
- if (err6.code === "EADDRINUSE" && port !== 0) {
9321
+ const onError = (err8) => {
9322
+ if (err8.code === "EADDRINUSE" && port !== 0) {
8309
9323
  server.removeListener("error", onError);
8310
9324
  this.listen(bindAddr, 0).then(resolve10, reject);
8311
9325
  return;
8312
9326
  }
8313
- reject(err6);
9327
+ reject(err8);
8314
9328
  };
8315
9329
  server.on("error", onError);
8316
9330
  server.listen(port, bindAddr, () => {
@@ -8328,8 +9342,8 @@ var AdminServer = class {
8328
9342
  }
8329
9343
  /** Per-request handler: auth gate (when a token is set) → routing. */
8330
9344
  onRequest(req, res) {
8331
- void this.dispatch(req, res).catch((err6) => {
8332
- const message = err6 instanceof Error ? err6.message : String(err6);
9345
+ void this.dispatch(req, res).catch((err8) => {
9346
+ const message = err8 instanceof Error ? err8.message : String(err8);
8333
9347
  this.deps.logger.error("[AdminServer] unhandled error:", message);
8334
9348
  if (!res.headersSent) {
8335
9349
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -8593,18 +9607,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
8593
9607
  return;
8594
9608
  }
8595
9609
  signal?.addEventListener("abort", abort, { once: true });
8596
- server.on("error", (err6) => {
9610
+ server.on("error", (err8) => {
8597
9611
  if (settled) return;
8598
9612
  settled = true;
8599
9613
  clearTimeout(timer);
8600
- if (err6.code === "EADDRINUSE") {
9614
+ if (err8.code === "EADDRINUSE") {
8601
9615
  reject(
8602
9616
  new Error(
8603
9617
  `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
8604
9618
  )
8605
9619
  );
8606
9620
  } else {
8607
- reject(err6);
9621
+ reject(err8);
8608
9622
  }
8609
9623
  });
8610
9624
  const timer = setTimeout(() => {
@@ -8680,21 +9694,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
8680
9694
  }
8681
9695
 
8682
9696
  // src/allowance/ProviderKeyQuotaService.ts
8683
- import { fetchUpstream as fetchUpstream6 } from "@omnicross/core/pipeline/upstreamFetch";
9697
+ import { mergeExtraHeaders as mergeExtraHeaders2 } from "@omnicross/core";
9698
+ import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
8684
9699
 
8685
9700
  // src/allowance/ProviderKeyQuota.ts
8686
- var MINUTE_MS2 = 6e4;
8687
- var HOUR_MS2 = 60 * MINUTE_MS2;
8688
- var DAY_MS2 = 24 * HOUR_MS2;
8689
- var WEEK_MS = 7 * DAY_MS2;
8690
- var MONTH_MS = 30 * DAY_MS2;
8691
- function finiteNumber3(value) {
9701
+ var MINUTE_MS3 = 6e4;
9702
+ var HOUR_MS2 = 60 * MINUTE_MS3;
9703
+ var DAY_MS3 = 24 * HOUR_MS2;
9704
+ var WEEK_MS = 7 * DAY_MS3;
9705
+ var MONTH_MS = 30 * DAY_MS3;
9706
+ function finiteNumber5(value) {
8692
9707
  if (value === null || value === void 0 || value === "") return void 0;
8693
9708
  const parsed = typeof value === "number" ? value : Number(value);
8694
9709
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
8695
9710
  }
8696
9711
  function finitePercent4(value) {
8697
- const parsed = finiteNumber3(value);
9712
+ const parsed = finiteNumber5(value);
8698
9713
  return parsed !== void 0 && parsed <= 100 ? parsed : null;
8699
9714
  }
8700
9715
  function isoInstant3(value) {
@@ -8702,18 +9717,18 @@ function isoInstant3(value) {
8702
9717
  const time = Date.parse(value);
8703
9718
  if (Number.isFinite(time)) return new Date(time).toISOString();
8704
9719
  }
8705
- const numeric = finiteNumber3(value);
9720
+ const numeric = finiteNumber5(value);
8706
9721
  if (numeric !== void 0 && numeric > 1e9) {
8707
9722
  const ms = numeric > 1e12 ? numeric : numeric * 1e3;
8708
9723
  return new Date(ms).toISOString();
8709
9724
  }
8710
9725
  return void 0;
8711
9726
  }
8712
- function secondsUntil5(instant, now) {
9727
+ function secondsUntil8(instant, now) {
8713
9728
  if (!instant) return void 0;
8714
9729
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
8715
9730
  }
8716
- function isRecord5(value) {
9731
+ function isRecord8(value) {
8717
9732
  return !!value && typeof value === "object" && !Array.isArray(value);
8718
9733
  }
8719
9734
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -8726,7 +9741,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
8726
9741
  }
8727
9742
  const host = url.hostname.toLowerCase();
8728
9743
  const path2 = url.pathname.toLowerCase();
8729
- if ((host === "api.z.ai" || host === "open.bigmodel.cn") && path2.includes("/coding")) {
9744
+ if ((host === "api.z.ai" || host === "open.bigmodel.cn") && (path2.includes("/coding") || path2.includes("/anthropic"))) {
8730
9745
  return "zai";
8731
9746
  }
8732
9747
  if ((host === "api.minimax.io" || host === "api.minimaxi.com") && // Token Plan rides the plain openai `/v1` (chat completions) surface; the
@@ -8736,6 +9751,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
8736
9751
  }
8737
9752
  if (host === "api.code.umans.ai") return "umans";
8738
9753
  if (host === "api.synthetic.new") return "synthetic";
9754
+ if (host === "api.cline.bot") return "cline-pass";
8739
9755
  return null;
8740
9756
  }
8741
9757
  function providerKeyQuotaUrl(adapter, baseUrl) {
@@ -8743,6 +9759,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
8743
9759
  if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
8744
9760
  if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
8745
9761
  if (adapter === "umans") return `${origin}/v1/usage`;
9762
+ if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
8746
9763
  return `${origin}/v2/quotas`;
8747
9764
  }
8748
9765
  function providerKeyQuotaAuthHeader(adapter, key) {
@@ -8754,7 +9771,7 @@ function zaiWindowDurationMs(item) {
8754
9771
  case 3:
8755
9772
  return count * HOUR_MS2;
8756
9773
  case 4:
8757
- return count * DAY_MS2;
9774
+ return count * DAY_MS3;
8758
9775
  case 5:
8759
9776
  return count * MONTH_MS;
8760
9777
  case 6:
@@ -8767,8 +9784,8 @@ function zaiWindowIdLabel(durationMs) {
8767
9784
  if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
8768
9785
  if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
8769
9786
  if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
8770
- if (durationMs !== void 0 && durationMs % DAY_MS2 === 0) {
8771
- const days = durationMs / DAY_MS2;
9787
+ if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
9788
+ const days = durationMs / DAY_MS3;
8772
9789
  return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
8773
9790
  }
8774
9791
  if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
@@ -8778,23 +9795,23 @@ function zaiWindowIdLabel(durationMs) {
8778
9795
  return { id: "quota", label: "Quota" };
8779
9796
  }
8780
9797
  function parseZaiQuotaPayload(payload, now) {
8781
- if (!isRecord5(payload)) return null;
8782
- const data = isRecord5(payload["data"]) ? payload["data"] : payload;
9798
+ if (!isRecord8(payload)) return null;
9799
+ const data = isRecord8(payload["data"]) ? payload["data"] : payload;
8783
9800
  if (payload["success"] === false) return null;
8784
9801
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
8785
9802
  const byWindow = /* @__PURE__ */ new Map();
8786
9803
  for (const raw of limits) {
8787
- if (!isRecord5(raw)) continue;
9804
+ if (!isRecord8(raw)) continue;
8788
9805
  const item = raw;
8789
9806
  if (item.type === void 0) continue;
8790
9807
  const details = raw["usageDetails"];
8791
- if (Array.isArray(details) && details.some((d) => isRecord5(d) && d["modelCode"] === "zread")) {
9808
+ if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
8792
9809
  continue;
8793
9810
  }
8794
9811
  const durationMs = zaiWindowDurationMs(item);
8795
9812
  const { id, label } = zaiWindowIdLabel(durationMs);
8796
- const limit = finiteNumber3(item.usage);
8797
- const used = finiteNumber3(item.currentValue);
9813
+ const limit = finiteNumber5(item.usage);
9814
+ const used = finiteNumber5(item.currentValue);
8798
9815
  const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
8799
9816
  const fromPercentage = finitePercent4(item.percentage) ?? void 0;
8800
9817
  const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
@@ -8805,9 +9822,9 @@ function parseZaiQuotaPayload(payload, now) {
8805
9822
  label,
8806
9823
  scope: "all",
8807
9824
  usedPercent,
8808
- ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS2) } : {},
9825
+ ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
8809
9826
  ...resetsAt !== void 0 ? { resetsAt } : {},
8810
- remainingSeconds: secondsUntil5(resetsAt, now),
9827
+ remainingSeconds: secondsUntil8(resetsAt, now),
8811
9828
  state: "fresh"
8812
9829
  };
8813
9830
  const existing = byWindow.get(id);
@@ -8821,21 +9838,21 @@ function parseZaiQuotaPayload(payload, now) {
8821
9838
  var MINIMAX_STATUS_EXHAUSTED = 2;
8822
9839
  var MINIMAX_SHARED_BUCKET = "general";
8823
9840
  function parseMiniMaxBucket(value) {
8824
- if (!isRecord5(value)) return null;
9841
+ if (!isRecord8(value)) return null;
8825
9842
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
8826
9843
  if (!modelName) return null;
8827
9844
  const instant = (v) => {
8828
- const n = finiteNumber3(v);
9845
+ const n = finiteNumber5(v);
8829
9846
  return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
8830
9847
  };
8831
9848
  return {
8832
9849
  modelName,
8833
9850
  intervalEnd: instant(value["end_time"]),
8834
- intervalRemainingPercent: finiteNumber3(value["current_interval_remaining_percent"]),
8835
- intervalStatus: finiteNumber3(value["current_interval_status"]),
9851
+ intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
9852
+ intervalStatus: finiteNumber5(value["current_interval_status"]),
8836
9853
  weeklyEnd: instant(value["weekly_end_time"]),
8837
- weeklyRemainingPercent: finiteNumber3(value["current_weekly_remaining_percent"]),
8838
- weeklyStatus: finiteNumber3(value["current_weekly_status"])
9854
+ weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
9855
+ weeklyStatus: finiteNumber5(value["current_weekly_status"])
8839
9856
  };
8840
9857
  }
8841
9858
  function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
@@ -8848,14 +9865,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
8848
9865
  usedPercent,
8849
9866
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
8850
9867
  ...resetsAt !== void 0 ? { resetsAt } : {},
8851
- remainingSeconds: secondsUntil5(resetsAt, now),
9868
+ remainingSeconds: secondsUntil8(resetsAt, now),
8852
9869
  state: usedPercent !== null ? "fresh" : "unavailable"
8853
9870
  };
8854
9871
  }
8855
9872
  function parseMiniMaxTokenPlanPayload(payload, now) {
8856
- if (!isRecord5(payload)) return null;
9873
+ if (!isRecord8(payload)) return null;
8857
9874
  const baseResp = payload["base_resp"];
8858
- if (!isRecord5(baseResp) || baseResp["status_code"] !== 0) return null;
9875
+ if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
8859
9876
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
8860
9877
  let general = null;
8861
9878
  for (const raw of buckets) {
@@ -8879,7 +9896,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
8879
9896
  minimaxWindow(
8880
9897
  "seven-day",
8881
9898
  "7 days",
8882
- Math.round(WEEK_MS / MINUTE_MS2),
9899
+ Math.round(WEEK_MS / MINUTE_MS3),
8883
9900
  general.weeklyEnd,
8884
9901
  general.weeklyRemainingPercent,
8885
9902
  general.weeklyStatus,
@@ -8888,15 +9905,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
8888
9905
  ];
8889
9906
  }
8890
9907
  function parseUmansUsagePayload(payload, now) {
8891
- if (!isRecord5(payload)) return null;
8892
- const limits = isRecord5(payload["limits"]) ? payload["limits"] : void 0;
8893
- const requests = limits && isRecord5(limits["requests"]) ? limits["requests"] : void 0;
8894
- const usage = isRecord5(payload["usage"]) ? payload["usage"] : void 0;
8895
- const window = isRecord5(payload["window"]) ? payload["window"] : void 0;
8896
- const hardCap = finiteNumber3(requests?.["hard_cap"]);
8897
- const softLimit = finiteNumber3(requests?.["limit"]);
8898
- const requestsInWindow = finiteNumber3(usage?.["requests_in_window"]);
8899
- const weightedInWindow = finiteNumber3(usage?.["weighted_in_window"]);
9908
+ if (!isRecord8(payload)) return null;
9909
+ const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
9910
+ const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
9911
+ const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
9912
+ const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
9913
+ const hardCap = finiteNumber5(requests?.["hard_cap"]);
9914
+ const softLimit = finiteNumber5(requests?.["limit"]);
9915
+ const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
9916
+ const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
8900
9917
  const resetsAt = isoInstant3(window?.["resets_at"]);
8901
9918
  let usedPercent = null;
8902
9919
  if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
@@ -8913,19 +9930,19 @@ function parseUmansUsagePayload(payload, now) {
8913
9930
  usedPercent,
8914
9931
  windowMinutes: 5 * 60,
8915
9932
  ...resetsAt !== void 0 ? { resetsAt } : {},
8916
- remainingSeconds: secondsUntil5(resetsAt, now),
9933
+ remainingSeconds: secondsUntil8(resetsAt, now),
8917
9934
  state: "fresh"
8918
9935
  }
8919
9936
  ];
8920
9937
  }
8921
9938
  function parseSyntheticQuotasPayload(payload, now) {
8922
- if (!isRecord5(payload)) return null;
8923
- const fiveHour = isRecord5(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
8924
- const weekly = isRecord5(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
9939
+ if (!isRecord8(payload)) return null;
9940
+ const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
9941
+ const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
8925
9942
  const windows = [];
8926
9943
  if (fiveHour) {
8927
- const max = finiteNumber3(fiveHour["max"]);
8928
- const remaining = finiteNumber3(fiveHour["remaining"]);
9944
+ const max = finiteNumber5(fiveHour["max"]);
9945
+ const remaining = finiteNumber5(fiveHour["remaining"]);
8929
9946
  const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
8930
9947
  const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
8931
9948
  windows.push({
@@ -8935,12 +9952,12 @@ function parseSyntheticQuotasPayload(payload, now) {
8935
9952
  usedPercent,
8936
9953
  windowMinutes: 5 * 60,
8937
9954
  ...resetsAt !== void 0 ? { resetsAt } : {},
8938
- remainingSeconds: secondsUntil5(resetsAt, now),
9955
+ remainingSeconds: secondsUntil8(resetsAt, now),
8939
9956
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
8940
9957
  });
8941
9958
  }
8942
9959
  if (weekly) {
8943
- const percentRemaining = finiteNumber3(weekly["percentRemaining"]);
9960
+ const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
8944
9961
  const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
8945
9962
  const resetsAt = isoInstant3(weekly["nextRegenAt"]);
8946
9963
  windows.push({
@@ -8950,12 +9967,42 @@ function parseSyntheticQuotasPayload(payload, now) {
8950
9967
  usedPercent,
8951
9968
  windowMinutes: 7 * 24 * 60,
8952
9969
  ...resetsAt !== void 0 ? { resetsAt } : {},
8953
- remainingSeconds: secondsUntil5(resetsAt, now),
9970
+ remainingSeconds: secondsUntil8(resetsAt, now),
8954
9971
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
8955
9972
  });
8956
9973
  }
8957
9974
  return windows.length > 0 ? windows : null;
8958
9975
  }
9976
+ var CLINE_WINDOW_CONFIG = {
9977
+ five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
9978
+ weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
9979
+ monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
9980
+ };
9981
+ function parseClinePassUsageLimitsPayload(payload, now) {
9982
+ if (!isRecord8(payload)) return null;
9983
+ const data = isRecord8(payload["data"]) ? payload["data"] : payload;
9984
+ const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9985
+ const windows = [];
9986
+ for (const raw of limits) {
9987
+ if (!isRecord8(raw)) continue;
9988
+ const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
9989
+ if (!config) continue;
9990
+ const usedPercent = finitePercent4(raw["percentUsed"]);
9991
+ if (usedPercent === null) continue;
9992
+ const resetsAt = isoInstant3(raw["resetsAt"]);
9993
+ windows.push({
9994
+ id: config.id,
9995
+ label: config.label,
9996
+ scope: "all",
9997
+ usedPercent,
9998
+ windowMinutes: config.minutes,
9999
+ ...resetsAt !== void 0 ? { resetsAt } : {},
10000
+ remainingSeconds: secondsUntil8(resetsAt, now),
10001
+ state: "fresh"
10002
+ });
10003
+ }
10004
+ return windows.length > 0 ? windows : null;
10005
+ }
8959
10006
 
8960
10007
  // src/allowance/ProviderKeyQuotaService.ts
8961
10008
  function parseQuotaPayload(adapter, payload, now) {
@@ -8968,6 +10015,8 @@ function parseQuotaPayload(adapter, payload, now) {
8968
10015
  return parseUmansUsagePayload(payload, now);
8969
10016
  case "synthetic":
8970
10017
  return parseSyntheticQuotasPayload(payload, now);
10018
+ case "cline-pass":
10019
+ return parseClinePassUsageLimitsPayload(payload, now);
8971
10020
  }
8972
10021
  }
8973
10022
  var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
@@ -8987,7 +10036,7 @@ function rowKeyEntries(row) {
8987
10036
  return [];
8988
10037
  }
8989
10038
  var ProviderKeyQuotaService = class {
8990
- constructor(box, fetchImpl = (url, init) => fetchUpstream6(url, init, { redactBodies: true }), now = Date.now) {
10039
+ constructor(box, fetchImpl = (url, init) => fetchUpstream9(url, init, { redactBodies: true }), now = Date.now) {
8991
10040
  this.box = box;
8992
10041
  this.fetchImpl = fetchImpl;
8993
10042
  this.now = now;
@@ -9049,7 +10098,10 @@ var ProviderKeyQuotaService = class {
9049
10098
  headers: {
9050
10099
  Authorization: providerKeyQuotaAuthHeader(adapter, key),
9051
10100
  Accept: "application/json",
9052
- "Content-Type": "application/json"
10101
+ "Content-Type": "application/json",
10102
+ // The row's static identity headers ride along — the Cline usage
10103
+ // endpoint sits behind the SAME client-identity 403 gate as inference.
10104
+ ...mergeExtraHeaders2({}, row.extraHeaders)
9053
10105
  },
9054
10106
  signal: AbortSignal.timeout(15e3)
9055
10107
  });
@@ -13854,6 +14906,10 @@ function toLLMProvider(row) {
13854
14906
  // `parseProviderInput`), so customizations are preserved (the row value wins).
13855
14907
  apiModes: row.apiModes,
13856
14908
  selectedApiModeId: row.selectedApiModeId,
14909
+ // Static extra request headers ride along verbatim (load-guarded — no
14910
+ // auth/content names); core's `getProviderHeaders` merges them into every
14911
+ // BYO request, and the same-format relay path inherits that funnel.
14912
+ extraHeaders: row.extraHeaders,
13857
14913
  // Official-Anthropic signature handling only matters for the Anthropic
13858
14914
  // ingress (deferred → 502); leave it off for the BYO transform path.
13859
14915
  isOfficial: false
@@ -15803,12 +16859,13 @@ import { existsSync as existsSync22, mkdirSync as mkdirSync6, readFileSync as re
15803
16859
  import { dirname as dirname15 } from "path";
15804
16860
  import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
15805
16861
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
15806
- import { fetchUpstream as fetchUpstream7 } from "@omnicross/core/pipeline/upstreamFetch";
16862
+ import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
15807
16863
  import { getSharedIdentityStore as getSharedIdentityStore2 } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
15808
16864
  import {
15809
16865
  claudeOAuth as claudeOAuth2,
15810
16866
  codexOAuth as codexOAuth2,
15811
16867
  geminiOAuth as geminiOAuth2,
16868
+ grokOAuth as grokOAuth2,
15812
16869
  kimiOAuth as kimiOAuth2
15813
16870
  } from "@omnicross/subscriptions";
15814
16871
 
@@ -15958,7 +17015,7 @@ var JsonSubscriptionCredentialStore = class {
15958
17015
  * a plaintext token pair into `upstream-trace.jsonl`.
15959
17016
  */
15960
17017
  buildRefreshFetch(providerId, accountId) {
15961
- return this.fetchImpl ?? ((url, init) => fetchUpstream7(url, init, { providerId, accountId, redactBodies: true }));
17018
+ return this.fetchImpl ?? ((url, init) => fetchUpstream10(url, init, { providerId, accountId, redactBodies: true }));
15962
17019
  }
15963
17020
  /**
15964
17021
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -15999,7 +17056,7 @@ var JsonSubscriptionCredentialStore = class {
15999
17056
  * other hot reads. Never returns token material.
16000
17057
  */
16001
17058
  getAccountProxy(providerId, accountId) {
16002
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
17059
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
16003
17060
  return void 0;
16004
17061
  }
16005
17062
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -16018,7 +17075,7 @@ var JsonSubscriptionCredentialStore = class {
16018
17075
  const fingerprintOn = identityStore.isEnabled();
16019
17076
  const now = Date.now();
16020
17077
  const out = {};
16021
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
17078
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
16022
17079
  const sanitized = sanitizeAccounts(config, provider);
16023
17080
  if (sanitized.length === 0) continue;
16024
17081
  for (const account of sanitized) {
@@ -16217,6 +17274,66 @@ var JsonSubscriptionCredentialStore = class {
16217
17274
  }
16218
17275
  });
16219
17276
  }
17277
+ /**
17278
+ * Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
17279
+ * resolved through OIDC discovery on every refresh (process-cached 1h by the
17280
+ * flow module) so a rotated endpoint document is picked up without a daemon
17281
+ * restart. HONEST `false` when no refresh_token.
17282
+ */
17283
+ async refreshGrokToken() {
17284
+ return this.coalesce("grok:active", async () => {
17285
+ const config = this.readConfig();
17286
+ const active = getActiveAccount(config, "grok");
17287
+ const grok = active?.tokens;
17288
+ if (!active || !grok?.refreshToken) return false;
17289
+ const capturedId = active.id;
17290
+ this.materializeMigration(config);
17291
+ const refreshFetch = this.buildRefreshFetch("grok", capturedId);
17292
+ try {
17293
+ const tokenEndpoint = await grokOAuth2.resolveGrokTokenEndpoint(refreshFetch);
17294
+ const result = await grokOAuth2.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17295
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17296
+ const next = {
17297
+ ...grok,
17298
+ accessToken: result.accessToken,
17299
+ refreshToken: result.refreshToken,
17300
+ expiresAt,
17301
+ status: "authorized",
17302
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
17303
+ errorMessage: void 0,
17304
+ syncWarning: void 0
17305
+ };
17306
+ this.writeBackById("grok", capturedId, next);
17307
+ return true;
17308
+ } catch (error) {
17309
+ this.markExpiredById("grok", capturedId, grok, error);
17310
+ return false;
17311
+ }
17312
+ });
17313
+ }
17314
+ /**
17315
+ * "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
17316
+ * tokens are long-lived with no exchange endpoint). A call here means the
17317
+ * strategy saw a 401 (the token was revoked); mark the account `expired`
17318
+ * with a re-authenticate message and return `false` (the proxy then declines
17319
+ * the retry instead of looping on a dead token).
17320
+ */
17321
+ async refreshCopilotToken() {
17322
+ return this.coalesce("copilot:active", async () => {
17323
+ const config = this.readConfig();
17324
+ const active = getActiveAccount(config, "copilot");
17325
+ const copilot = active?.tokens;
17326
+ if (!active || !copilot?.accessToken) return false;
17327
+ this.materializeMigration(config);
17328
+ this.markExpiredById(
17329
+ "copilot",
17330
+ active.id,
17331
+ copilot,
17332
+ new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
17333
+ );
17334
+ return false;
17335
+ });
17336
+ }
16220
17337
  /**
16221
17338
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
16222
17339
  * account-pool resolution). It uses only that account's stored refresh
@@ -16269,7 +17386,7 @@ var JsonSubscriptionCredentialStore = class {
16269
17386
  }
16270
17387
  const oauth = account.tokens;
16271
17388
  if (!oauth.accessToken) return null;
16272
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
17389
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
16273
17390
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
16274
17391
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
16275
17392
  if (expiringSoon && oauth.refreshToken) {
@@ -16373,6 +17490,18 @@ var JsonSubscriptionCredentialStore = class {
16373
17490
  expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
16374
17491
  };
16375
17492
  }
17493
+ if (provider === "grok") {
17494
+ const tokenEndpoint = await grokOAuth2.resolveGrokTokenEndpoint(refreshFetch);
17495
+ const r2 = await grokOAuth2.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
17496
+ return {
17497
+ accessToken: r2.accessToken,
17498
+ refreshToken: r2.refreshToken,
17499
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17500
+ };
17501
+ }
17502
+ if (provider === "copilot") {
17503
+ throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
17504
+ }
16376
17505
  const flow = provider === "claude" ? claudeOAuth2 : provider === "codex" ? codexOAuth2 : geminiOAuth2;
16377
17506
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
16378
17507
  return {
@@ -16616,7 +17745,7 @@ var JsonSubscriptionCredentialStore = class {
16616
17745
  };
16617
17746
 
16618
17747
  // src/AccountHealthProbeScheduler.ts
16619
- import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
17748
+ import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
16620
17749
 
16621
17750
  // src/probe/CodexGenerationProbe.ts
16622
17751
  import {
@@ -16762,7 +17891,16 @@ var PROVIDER_PROBE_PLANS = {
16762
17891
  // Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
16763
17892
  // collector uses it), but the probe path also needs the fingerprint headers —
16764
17893
  // keep the probe local until the collector covers the health surface.
16765
- kimi: { kind: "local" }
17894
+ kimi: { kind: "local" },
17895
+ // Grok's billing proxy is a verified FREE authed GET (the allowance collector
17896
+ // uses it) but it REJECTS non-OAuth credentials and sits on a separate host
17897
+ // with its own product-gate header — keep the probe local, the collector
17898
+ // owns the health surface.
17899
+ grok: { kind: "local" },
17900
+ // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
17901
+ // authed GET but lives on api.github.com with its own auth dialect and a
17902
+ // monthly-only window — the allowance collector owns the health surface.
17903
+ copilot: { kind: "local" }
16766
17904
  };
16767
17905
  function probePlanFor(providerId) {
16768
17906
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -16784,7 +17922,7 @@ var AccountHealthProbeScheduler = class {
16784
17922
  this.logger = logger;
16785
17923
  this.config = config;
16786
17924
  this.now = opts.now ?? Date.now;
16787
- this.fetchImpl = opts.fetchImpl ?? fetchUpstream8;
17925
+ this.fetchImpl = opts.fetchImpl ?? fetchUpstream11;
16788
17926
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
16789
17927
  this.planFor = opts.planFor ?? probePlanFor;
16790
17928
  }
@@ -17692,7 +18830,7 @@ async function readAuditStats(auditDir, query2 = {}) {
17692
18830
  }
17693
18831
 
17694
18832
  // src/audit/AuditPruneSweeper.ts
17695
- var DAY_MS3 = 24 * 60 * 6e4;
18833
+ var DAY_MS4 = 24 * 60 * 6e4;
17696
18834
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
17697
18835
  var ARCHIVE_BATCH = 64;
17698
18836
  var AuditPruneSweeper = class {
@@ -17756,7 +18894,7 @@ var AuditPruneSweeper = class {
17756
18894
  this.sweeping = true;
17757
18895
  try {
17758
18896
  if (!existsSync25(this.auditDir)) return 0;
17759
- const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS3;
18897
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
17760
18898
  let removed = 0;
17761
18899
  for (const name of readdirSync6(this.auditDir)) {
17762
18900
  const dateMs = auditFileDateMs(name);
@@ -18013,7 +19151,7 @@ async function closeAll(writers) {
18013
19151
  // src/usage/UsagePruneSweeper.ts
18014
19152
  import { unlink as unlink3 } from "fs/promises";
18015
19153
  import { join as join22 } from "path";
18016
- var DAY_MS4 = 24 * 60 * 6e4;
19154
+ var DAY_MS5 = 24 * 60 * 6e4;
18017
19155
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
18018
19156
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
18019
19157
  var UsagePruneSweeper = class {
@@ -18070,7 +19208,7 @@ var UsagePruneSweeper = class {
18070
19208
  this.sweeping = true;
18071
19209
  try {
18072
19210
  const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
18073
- const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS4;
19211
+ const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
18074
19212
  let removed = 0;
18075
19213
  for (const entry of await listUsageDays(this.usageDir)) {
18076
19214
  if (!entry.hasShard) continue;
@@ -18489,7 +19627,7 @@ var AuditWriter = class {
18489
19627
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
18490
19628
  import { createHmac as createHmac5 } from "crypto";
18491
19629
  import { join as join26 } from "path";
18492
- import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
19630
+ import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
18493
19631
 
18494
19632
  // src/billing/billingFiles.ts
18495
19633
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -18512,7 +19650,7 @@ var BillingPublisher = class {
18512
19650
  constructor(billingDir, logger, opts = {}) {
18513
19651
  this.billingDir = billingDir;
18514
19652
  this.logger = logger;
18515
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream9(url, init));
19653
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream12(url, init));
18516
19654
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
18517
19655
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
18518
19656
  this.now = opts.now ?? Date.now;
@@ -18762,7 +19900,7 @@ var BillingRetrySweeper = class {
18762
19900
  // src/TokenRefreshScheduler.ts
18763
19901
  var REFRESH_LEAD_MS2 = 5 * 6e4;
18764
19902
  var SWEEP_INTERVAL_MS5 = 6e4;
18765
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
19903
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
18766
19904
  var TokenRefreshScheduler = class {
18767
19905
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
18768
19906
  this.store = store;
@@ -18847,6 +19985,12 @@ var TokenRefreshScheduler = class {
18847
19985
  return this.store.refreshGeminiToken();
18848
19986
  case "kimi":
18849
19987
  return this.store.refreshKimiToken();
19988
+ case "grok":
19989
+ return this.store.refreshGrokToken();
19990
+ // ghu_ tokens never near-expire (far-future expiresAt), so the sweep
19991
+ // never reaches this — the branch exists for union totality.
19992
+ case "copilot":
19993
+ return this.store.refreshCopilotToken();
18850
19994
  }
18851
19995
  }
18852
19996
  };
@@ -18925,7 +20069,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
18925
20069
 
18926
20070
  // src/webhook/WebhookDispatcher.ts
18927
20071
  import { createHmac as createHmac6 } from "crypto";
18928
- import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
20072
+ import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
18929
20073
  var WEBHOOK_MAX_ATTEMPTS = 3;
18930
20074
  var WEBHOOK_QUEUE_MAX = 1e3;
18931
20075
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -18945,7 +20089,7 @@ var WebhookDispatcher = class {
18945
20089
  sleep;
18946
20090
  now;
18947
20091
  constructor(opts = {}) {
18948
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream10(url, init));
20092
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream13(url, init));
18949
20093
  this.logger = opts.logger;
18950
20094
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
18951
20095
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -19031,8 +20175,8 @@ var WebhookDispatcher = class {
19031
20175
  signal: AbortSignal.timeout(this.timeoutMs)
19032
20176
  });
19033
20177
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
19034
- } catch (err6) {
19035
- return { ok: false, error: err6 instanceof Error ? err6.message : String(err6) };
20178
+ } catch (err8) {
20179
+ return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
19036
20180
  }
19037
20181
  }
19038
20182
  /**
@@ -19174,7 +20318,7 @@ function buildDaemon(config, paths) {
19174
20318
  setSecretBox(secretBox3);
19175
20319
  setSecretBox2(secretBox3);
19176
20320
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
19177
- const accountAllowanceStore = new AccountAllowanceStore6(
20321
+ const accountAllowanceStore = new AccountAllowanceStore9(
19178
20322
  Date.now,
19179
20323
  void 0,
19180
20324
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
@@ -19217,7 +20361,7 @@ function buildDaemon(config, paths) {
19217
20361
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
19218
20362
  })
19219
20363
  );
19220
- setGeminiCodeAssistResolver(getGeminiCodeAssistProjectResolver());
20364
+ setGeminiCodeAssistResolver(getGeminiCodeAssistProjectResolver2());
19221
20365
  const autoDisableStore = new AutoDisableStore();
19222
20366
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
19223
20367
  const apiKeyPool = new ApiKeyPoolService(
@@ -19236,7 +20380,7 @@ function buildDaemon(config, paths) {
19236
20380
  const pricingEngine = new PricingEngine(pricingStore, logger, {
19237
20381
  // Catalog egress follows the same global/env proxy policy as every other
19238
20382
  // daemon upstream call; no provider/account override applies here.
19239
- fetchImpl: ((input, init) => fetchUpstream11(String(input), init ?? {}))
20383
+ fetchImpl: ((input, init) => fetchUpstream14(String(input), init ?? {}))
19240
20384
  });
19241
20385
  const pricingRefreshScheduler = new PricingRefreshScheduler(
19242
20386
  pricingEngine,
@@ -19521,7 +20665,7 @@ function buildDaemon(config, paths) {
19521
20665
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
19522
20666
  // excluded from the upstream trace, so a failing login left no evidence.
19523
20667
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
19524
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream11(url, init, { providerId, redactBodies: true }),
20668
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream14(url, init, { providerId, redactBodies: true }),
19525
20669
  subscriptionAccountAppender: credentialStore,
19526
20670
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
19527
20671
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -19533,6 +20677,9 @@ function buildDaemon(config, paths) {
19533
20677
  // paste; the app shows the verification URL + user code and polls the
19534
20678
  // token-free status). Token captured + persisted daemon-side.
19535
20679
  kimiSessions: new CodexOAuthSessionStore(),
20680
+ // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20681
+ grokSessions: new CodexOAuthSessionStore(),
20682
+ copilotSessions: new CodexOAuthSessionStore(),
19536
20683
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
19537
20684
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
19538
20685
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -19591,7 +20738,7 @@ function buildDaemon(config, paths) {
19591
20738
  });
19592
20739
  const webhookDispatcher = new WebhookDispatcher({
19593
20740
  logger,
19594
- fetchImpl: (url, init) => fetchUpstream11(url, init)
20741
+ fetchImpl: (url, init) => fetchUpstream14(url, init)
19595
20742
  });
19596
20743
  setWebhookRuntime(webhookDispatcher, getSharedAccountHealth4());
19597
20744
  const auditWriter = new AuditWriter(auditDir, logger);