@omnicross/daemon 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -62,22 +62,22 @@ var import_node_fs35 = require("fs");
62
62
  var import_node_path35 = require("path");
63
63
  var import_audit_types = require("@omnicross/contracts/audit-types");
64
64
  var import_billing_types = require("@omnicross/contracts/billing-types");
65
- var import_core4 = require("@omnicross/core");
65
+ var import_core7 = require("@omnicross/core");
66
66
  var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
67
67
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
68
68
  var import_outbound_api10 = require("@omnicross/core/outbound-api");
69
69
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
70
70
  var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
71
- var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
71
+ var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
72
72
  var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
73
- var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
73
+ var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
74
74
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
75
75
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
76
76
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
77
77
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
78
78
  var import_outbound_api11 = require("@omnicross/core/outbound-api");
79
79
  var import_usage2 = require("@omnicross/core/usage");
80
- var import_subscriptions9 = require("@omnicross/subscriptions");
80
+ var import_subscriptions12 = require("@omnicross/subscriptions");
81
81
 
82
82
  // src/admin/accountsCodexOAuth.ts
83
83
  var import_node_crypto = __toESM(require("crypto"), 1);
@@ -259,8 +259,187 @@ function handleKimiOAuthStatus(sessionId, deps) {
259
259
  return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
260
260
  }
261
261
 
262
+ // src/admin/accountsGrokOAuth.ts
263
+ var import_subscriptions3 = require("@omnicross/subscriptions");
264
+ function err3(status, message) {
265
+ return { status, body: { error: { type: "admin_api_error", message } } };
266
+ }
267
+ var DEFAULT_GROK_OAUTH_TTL_MS = 15 * 6e4;
268
+ async function handleGrokOAuthStart(deps) {
269
+ if (deps.grokSessions.isBusy()) {
270
+ return err3(409, "a grok sign-in is already in progress \u2014 finish it in the browser or cancel it");
271
+ }
272
+ const fetchImpl = deps.oauthExchangeFetch("grok");
273
+ let tokenEndpoint;
274
+ try {
275
+ tokenEndpoint = await import_subscriptions3.grokOAuth.resolveGrokTokenEndpoint(fetchImpl);
276
+ } catch (e) {
277
+ const reason = e instanceof Error ? e.message : "OIDC discovery failed";
278
+ return err3(502, `grok token-endpoint discovery failed: ${reason}`);
279
+ }
280
+ let authorization;
281
+ try {
282
+ authorization = await import_subscriptions3.grokOAuth.requestGrokDeviceAuthorization(fetchImpl);
283
+ } catch (e) {
284
+ const reason = e instanceof Error ? e.message : "device authorization failed";
285
+ return err3(502, `grok device authorization failed: ${reason}`);
286
+ }
287
+ const { sessionId, signal } = deps.grokSessions.begin();
288
+ void runGrokDevicePoll(sessionId, tokenEndpoint, authorization.deviceCode, signal, deps).catch((e) => {
289
+ const reason = e instanceof Error ? e.message : "grok sign-in failed";
290
+ deps.grokSessions.settle(sessionId, "error", reason);
291
+ });
292
+ return {
293
+ status: 200,
294
+ body: {
295
+ authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
296
+ userCode: authorization.userCode,
297
+ sessionId
298
+ }
299
+ };
300
+ }
301
+ async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, deps) {
302
+ const fetchImpl = deps.oauthExchangeFetch("grok");
303
+ const result = await import_subscriptions3.grokOAuth.awaitGrokDeviceToken(
304
+ { userCode: "", deviceCode, verificationUri: "" },
305
+ tokenEndpoint,
306
+ fetchImpl,
307
+ {
308
+ deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
309
+ sleep: (ms) => new Promise((resolve10, reject) => {
310
+ const onAbort = () => {
311
+ clearTimeout(timer);
312
+ reject(new Error("login: cancelled"));
313
+ };
314
+ const timer = setTimeout(() => {
315
+ signal.removeEventListener("abort", onAbort);
316
+ resolve10();
317
+ }, ms);
318
+ signal.addEventListener("abort", onAbort, { once: true });
319
+ })
320
+ }
321
+ );
322
+ const block = {
323
+ authMethod: "oauth",
324
+ status: "authorized",
325
+ accessToken: result.accessToken,
326
+ refreshToken: result.refreshToken,
327
+ expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
328
+ accountId: import_subscriptions3.grokOAuth.grokAccountIdFromAccessToken(result.accessToken),
329
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
330
+ };
331
+ await deps.subscriptionAccountAppender.appendProviderAccount("grok", block);
332
+ deps.grokSessions.settle(sessionId, "done");
333
+ }
334
+ function handleGrokOAuthCancel(sessionId, deps) {
335
+ if (!deps.grokSessions.cancel(sessionId)) return err3(404, "unknown or expired grok sign-in session");
336
+ return { status: 200, body: { ok: true } };
337
+ }
338
+ function handleGrokOAuthStatus(sessionId, deps) {
339
+ const s = deps.grokSessions.get(sessionId);
340
+ if (!s) return err3(404, "unknown or expired grok sign-in session");
341
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
342
+ }
343
+
344
+ // src/admin/accountsCopilotOAuth.ts
345
+ var import_subscriptions4 = require("@omnicross/subscriptions");
346
+ function err4(status, message) {
347
+ return { status, body: { error: { type: "admin_api_error", message } } };
348
+ }
349
+ var DEFAULT_COPILOT_OAUTH_TTL_MS = 15 * 6e4;
350
+ async function handleCopilotOAuthStart(deps, enterpriseUrlInput) {
351
+ if (deps.copilotSessions.isBusy()) {
352
+ return err4(409, "a copilot sign-in is already in progress \u2014 finish it in the browser or cancel it");
353
+ }
354
+ let enterpriseUrl;
355
+ if (typeof enterpriseUrlInput === "string" && enterpriseUrlInput.trim()) {
356
+ try {
357
+ enterpriseUrl = import_subscriptions4.copilotOAuth.normalizeCopilotEnterpriseDomain(enterpriseUrlInput);
358
+ } catch (e) {
359
+ const reason = e instanceof Error ? e.message : "invalid GitHub Enterprise domain";
360
+ return err4(400, `copilot ${reason}`);
361
+ }
362
+ }
363
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
364
+ let authorization;
365
+ try {
366
+ authorization = await import_subscriptions4.copilotOAuth.requestCopilotDeviceAuthorization(fetchImpl, enterpriseUrl);
367
+ } catch (e) {
368
+ const reason = e instanceof Error ? e.message : "device authorization failed";
369
+ return err4(502, `copilot device authorization failed: ${reason}`);
370
+ }
371
+ const { sessionId, signal } = deps.copilotSessions.begin();
372
+ void runCopilotDevicePoll(sessionId, authorization.deviceCode, signal, deps, enterpriseUrl).catch((e) => {
373
+ const reason = e instanceof Error ? e.message : "copilot sign-in failed";
374
+ deps.copilotSessions.settle(sessionId, "error", reason);
375
+ });
376
+ return {
377
+ status: 200,
378
+ body: {
379
+ authUrl: authorization.verificationUri,
380
+ userCode: authorization.userCode,
381
+ sessionId,
382
+ ...enterpriseUrl ? { enterpriseUrl } : {}
383
+ }
384
+ };
385
+ }
386
+ async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpriseUrl) {
387
+ const fetchImpl = deps.oauthExchangeFetch("copilot");
388
+ const result = await import_subscriptions4.copilotOAuth.awaitCopilotDeviceToken(
389
+ { userCode: "", deviceCode, verificationUri: "", interval: 5, expiresIn: 900 },
390
+ fetchImpl,
391
+ {
392
+ deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
393
+ ...enterpriseUrl ? { enterpriseUrl } : {},
394
+ sleep: (ms) => new Promise((resolve10, reject) => {
395
+ const onAbort = () => {
396
+ clearTimeout(timer);
397
+ reject(new Error("login: cancelled"));
398
+ };
399
+ const timer = setTimeout(() => {
400
+ signal.removeEventListener("abort", onAbort);
401
+ resolve10();
402
+ }, ms);
403
+ signal.addEventListener("abort", onAbort, { once: true });
404
+ })
405
+ }
406
+ );
407
+ const identity = await import_subscriptions4.copilotOAuth.fetchCopilotIdentity(result.accessToken, fetchImpl, enterpriseUrl);
408
+ const apiEndpoint = await import_subscriptions4.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, fetchImpl, enterpriseUrl);
409
+ await import_subscriptions4.copilotOAuth.enableAllCopilotModels(
410
+ result.accessToken,
411
+ { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
412
+ fetchImpl
413
+ );
414
+ const block = {
415
+ authMethod: "oauth",
416
+ status: "authorized",
417
+ accessToken: result.accessToken,
418
+ refreshToken: result.accessToken,
419
+ expiresAt: new Date(Date.now() + import_subscriptions4.copilotOAuth.COPILOT_FAR_FUTURE_MS).toISOString(),
420
+ ...identity.accountId ? { accountId: identity.accountId } : {},
421
+ ...identity.email ? { email: identity.email } : {},
422
+ ...apiEndpoint ? { apiEndpoint } : {},
423
+ ...enterpriseUrl ? { enterpriseUrl } : {},
424
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
425
+ };
426
+ await deps.subscriptionAccountAppender.appendProviderAccount("copilot", block);
427
+ deps.copilotSessions.settle(sessionId, "done");
428
+ }
429
+ function handleCopilotOAuthCancel(sessionId, deps) {
430
+ if (!deps.copilotSessions.cancel(sessionId)) {
431
+ return err4(404, "unknown or expired copilot sign-in session");
432
+ }
433
+ return { status: 200, body: { ok: true } };
434
+ }
435
+ function handleCopilotOAuthStatus(sessionId, deps) {
436
+ const s = deps.copilotSessions.get(sessionId);
437
+ if (!s) return err4(404, "unknown or expired copilot sign-in session");
438
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
439
+ }
440
+
262
441
  // src/allowance/AccountAllowanceService.ts
263
- var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
442
+ var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
264
443
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
265
444
 
266
445
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -731,7 +910,7 @@ var CodexAllowanceCollector = class {
731
910
  // src/allowance/KimiAllowanceCollector.ts
732
911
  var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
733
912
  var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
734
- var import_subscriptions3 = require("@omnicross/subscriptions");
913
+ var import_subscriptions5 = require("@omnicross/subscriptions");
735
914
  var KIMI_ALLOWANCE_CACHE_MS = 5 * 6e4;
736
915
  var KIMI_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
737
916
  function finiteNumber2(value) {
@@ -823,24 +1002,501 @@ function parseKimiUsagePayload(payload, now) {
823
1002
  const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
824
1003
  byId.set("seven-day", window);
825
1004
  }
826
- if (Array.isArray(payload["limits"])) {
827
- for (const item of payload["limits"]) {
828
- if (!isRecord(item)) continue;
829
- const detail = isRecord(item["detail"]) ? item["detail"] : item;
830
- const row = rowFrom(detail);
831
- const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
832
- if (!canonical) continue;
833
- const window = windowFromRow(row, canonical, now);
834
- const existing = byId.get(canonical.id);
835
- if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
836
- byId.set(canonical.id, window);
837
- }
1005
+ if (Array.isArray(payload["limits"])) {
1006
+ for (const item of payload["limits"]) {
1007
+ if (!isRecord(item)) continue;
1008
+ const detail = isRecord(item["detail"]) ? item["detail"] : item;
1009
+ const row = rowFrom(detail);
1010
+ const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
1011
+ if (!canonical) continue;
1012
+ const window = windowFromRow(row, canonical, now);
1013
+ const existing = byId.get(canonical.id);
1014
+ if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
1015
+ byId.set(canonical.id, window);
1016
+ }
1017
+ }
1018
+ }
1019
+ return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
1020
+ }
1021
+ var KimiAllowanceCollector = class {
1022
+ constructor(credentials, store = (0, import_AccountAllowanceStore3.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch3.fetchUpstream)(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
1023
+ this.credentials = credentials;
1024
+ this.store = store;
1025
+ this.fetchImpl = fetchImpl;
1026
+ this.now = now;
1027
+ }
1028
+ credentials;
1029
+ store;
1030
+ fetchImpl;
1031
+ now;
1032
+ inFlight = /* @__PURE__ */ new Map();
1033
+ async collectMany(accounts, options = {}) {
1034
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1035
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1036
+ }
1037
+ collect(account, options = {}) {
1038
+ const now = this.now();
1039
+ if (account.tokens.authMethod !== "oauth") {
1040
+ const existing = this.store.get("kimi", account.id, now);
1041
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1042
+ return Promise.resolve(existing);
1043
+ }
1044
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1045
+ this.store.set(snapshot);
1046
+ return Promise.resolve(snapshot);
1047
+ }
1048
+ const cached = this.store.get("kimi", account.id, now);
1049
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1050
+ return Promise.resolve(cached);
1051
+ }
1052
+ const running = this.inFlight.get(account.id);
1053
+ if (running) return running;
1054
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "kimi_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1055
+ this.inFlight.set(account.id, promise);
1056
+ return promise;
1057
+ }
1058
+ isCacheValid(snapshot, now, refreshAheadMs) {
1059
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1060
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1061
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1062
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1063
+ }
1064
+ async fetchAccount(accountId, tokens) {
1065
+ let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1066
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1067
+ let response = await this.request(accountId, accessToken, tokens);
1068
+ if (response.status === 401) {
1069
+ const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
1070
+ if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
1071
+ accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
1072
+ if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1073
+ response = await this.request(accountId, accessToken, tokens);
1074
+ }
1075
+ if (response.status === 403) {
1076
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
1077
+ this.store.set(snapshot2);
1078
+ return snapshot2;
1079
+ }
1080
+ if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
1081
+ let payload;
1082
+ try {
1083
+ payload = await response.json();
1084
+ } catch {
1085
+ return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
1086
+ }
1087
+ const now = this.now();
1088
+ const windows = parseKimiUsagePayload(payload, now);
1089
+ const snapshot = {
1090
+ providerId: "kimi",
1091
+ accountId,
1092
+ source: "oauth-usage-api",
1093
+ observedAt: new Date(now).toISOString(),
1094
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1095
+ windows: windows.length > 0 ? windows : [
1096
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1097
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1098
+ ],
1099
+ ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
1100
+ };
1101
+ this.store.set(snapshot);
1102
+ return snapshot;
1103
+ }
1104
+ request(accountId, accessToken, tokens) {
1105
+ return this.fetchImpl(KIMI_USAGE_URL, {
1106
+ method: "GET",
1107
+ headers: {
1108
+ Authorization: `Bearer ${accessToken}`,
1109
+ Accept: "application/json",
1110
+ ...(0, import_subscriptions5.kimiFingerprintHeaders)(tokens.deviceId)
1111
+ },
1112
+ signal: AbortSignal.timeout(15e3)
1113
+ }, accountId);
1114
+ }
1115
+ failureSnapshot(accountId, code, now) {
1116
+ const existing = this.store.get("kimi", accountId, now);
1117
+ const snapshot = existing ? {
1118
+ ...existing,
1119
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1120
+ windows: existing.windows.map((window) => ({
1121
+ ...window,
1122
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1123
+ })),
1124
+ lastErrorCode: code
1125
+ } : {
1126
+ providerId: "kimi",
1127
+ accountId,
1128
+ source: "oauth-usage-api",
1129
+ observedAt: new Date(now).toISOString(),
1130
+ expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1131
+ windows: [
1132
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1133
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1134
+ ],
1135
+ lastErrorCode: code
1136
+ };
1137
+ this.store.set(snapshot);
1138
+ return snapshot;
1139
+ }
1140
+ unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
1141
+ return {
1142
+ providerId: "kimi",
1143
+ accountId,
1144
+ source: "oauth-usage-api",
1145
+ observedAt: new Date(now).toISOString(),
1146
+ windows: [
1147
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
1148
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
1149
+ ],
1150
+ lastErrorCode: code
1151
+ };
1152
+ }
1153
+ };
1154
+
1155
+ // src/allowance/GrokAllowanceCollector.ts
1156
+ var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1157
+ var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
1158
+ var GROK_ALLOWANCE_CACHE_MS = 5 * 6e4;
1159
+ var GROK_BILLING_BASE = "https://cli-chat-proxy.grok.com";
1160
+ var GROK_BILLING_CREDITS_URL = `${GROK_BILLING_BASE}/v1/billing?format=credits`;
1161
+ var GROK_BILLING_MONTHLY_URL = `${GROK_BILLING_BASE}/v1/billing`;
1162
+ function isRecord2(value) {
1163
+ return !!value && typeof value === "object" && !Array.isArray(value);
1164
+ }
1165
+ function finiteNumber3(value) {
1166
+ if (value === null || value === void 0 || value === "") return void 0;
1167
+ const parsed = typeof value === "number" ? value : Number(value);
1168
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1169
+ }
1170
+ function percent(value) {
1171
+ const parsed = finiteNumber3(value);
1172
+ return parsed !== void 0 && parsed <= 100 ? parsed : void 0;
1173
+ }
1174
+ function onDemandAmount(value) {
1175
+ return isRecord2(value) ? finiteNumber3(value["val"]) : void 0;
1176
+ }
1177
+ function confirmsNoMonthlyQuota(raw) {
1178
+ const limit = onDemandAmount(raw["monthlyLimit"]);
1179
+ if (limit !== void 0) return limit === 0;
1180
+ return parseWeeklyConfig(raw)?.inferredPercent === true;
1181
+ }
1182
+ function parseWeeklyConfig(raw) {
1183
+ const period = isRecord2(raw["currentPeriod"]) ? raw["currentPeriod"] : void 0;
1184
+ if (!period) return null;
1185
+ const start = typeof period["start"] === "string" ? Date.parse(period["start"]) : Number.NaN;
1186
+ const end = typeof period["end"] === "string" ? Date.parse(period["end"]) : Number.NaN;
1187
+ const type = typeof period["type"] === "string" ? period["type"] : "";
1188
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
1189
+ if (!type.toUpperCase().includes("WEEK")) return null;
1190
+ const inferred = raw["creditUsagePercent"] === void 0 || raw["creditUsagePercent"] === null;
1191
+ let creditUsagePercent;
1192
+ if (inferred) {
1193
+ creditUsagePercent = end > Date.now() ? 0 : void 0;
1194
+ } else {
1195
+ creditUsagePercent = percent(raw["creditUsagePercent"]);
1196
+ }
1197
+ if (creditUsagePercent === void 0) return null;
1198
+ return {
1199
+ creditUsagePercent,
1200
+ inferredPercent: inferred,
1201
+ resetsAtMs: end,
1202
+ unified: raw["isUnifiedBillingUser"] === true
1203
+ };
1204
+ }
1205
+ function parseMonthlyConfig(raw) {
1206
+ const start = typeof raw["billingPeriodStart"] === "string" ? Date.parse(raw["billingPeriodStart"]) : Number.NaN;
1207
+ const end = typeof raw["billingPeriodEnd"] === "string" ? Date.parse(raw["billingPeriodEnd"]) : Number.NaN;
1208
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
1209
+ const limit = onDemandAmount(raw["monthlyLimit"]);
1210
+ const used = onDemandAmount(raw["used"]);
1211
+ if (limit === void 0 || limit <= 0 || used === void 0) return null;
1212
+ return { used, limit, periodStartMs: start, periodEndMs: end };
1213
+ }
1214
+ function secondsUntil4(instant, now) {
1215
+ if (!instant) return void 0;
1216
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1217
+ }
1218
+ var MINUTE_MS2 = 6e4;
1219
+ var DAY_MS2 = 864e5;
1220
+ var WEEK_MINUTES = 7 * 24 * 60;
1221
+ function weeklyWindow(config, now) {
1222
+ const resetsAt = new Date(config.resetsAtMs).toISOString();
1223
+ return {
1224
+ id: "seven-day",
1225
+ label: "7 days",
1226
+ scope: "all",
1227
+ usedPercent: config.creditUsagePercent,
1228
+ windowMinutes: WEEK_MINUTES,
1229
+ resetsAt,
1230
+ remainingSeconds: secondsUntil4(resetsAt, now),
1231
+ state: "fresh"
1232
+ };
1233
+ }
1234
+ function monthlyWindow(config, now) {
1235
+ const resetsAt = new Date(config.periodEndMs).toISOString();
1236
+ const days = Math.max(1, Math.round((config.periodEndMs - config.periodStartMs) / DAY_MS2));
1237
+ return {
1238
+ id: "thirty-day",
1239
+ label: days === 30 || days === 31 ? "30 days" : `${days} days`,
1240
+ scope: "all",
1241
+ usedPercent: Math.round(Math.min(100, config.used / config.limit * 100) * 10) / 10,
1242
+ windowMinutes: Math.round((config.periodEndMs - config.periodStartMs) / MINUTE_MS2),
1243
+ resetsAt,
1244
+ remainingSeconds: secondsUntil4(resetsAt, now),
1245
+ state: "fresh"
1246
+ };
1247
+ }
1248
+ function onDemandWindow(raw) {
1249
+ const cap = onDemandAmount(raw["onDemandCap"]);
1250
+ const used = onDemandAmount(raw["onDemandUsed"]);
1251
+ if (cap === void 0 || cap <= 0 || used === void 0) return null;
1252
+ return {
1253
+ id: "on-demand",
1254
+ label: "On-demand",
1255
+ scope: "all",
1256
+ usedPercent: Math.round(Math.min(100, used / cap * 100) * 10) / 10,
1257
+ state: "fresh"
1258
+ };
1259
+ }
1260
+ async function probeBilling(url, accessToken, accountId, fetchImpl) {
1261
+ try {
1262
+ const response = await fetchImpl(url, {
1263
+ method: "GET",
1264
+ headers: {
1265
+ Authorization: `Bearer ${accessToken}`,
1266
+ Accept: "application/json",
1267
+ "X-XAI-Token-Auth": "xai-grok-cli"
1268
+ },
1269
+ redirect: "error",
1270
+ signal: AbortSignal.timeout(15e3)
1271
+ }, accountId);
1272
+ if (!response.ok) return { status: response.status, payload: null };
1273
+ const payload = await response.json();
1274
+ return { status: response.status, payload: isRecord2(payload) ? payload : null };
1275
+ } catch {
1276
+ return { status: 0, payload: null };
1277
+ }
1278
+ }
1279
+ function parseGrokBillingPayloads(creditsPayload, monthlyPayload, now) {
1280
+ const creditsConfig = isRecord2(creditsPayload?.["config"]) ? creditsPayload["config"] : null;
1281
+ const monthlyConfig = isRecord2(monthlyPayload?.["config"]) ? monthlyPayload["config"] : null;
1282
+ let weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
1283
+ const unifiedFlag = creditsConfig?.["isUnifiedBillingUser"] === true;
1284
+ let monthly = monthlyConfig ? parseMonthlyConfig(monthlyConfig) : null;
1285
+ if (weekly?.inferredPercent && unifiedFlag) {
1286
+ if (monthly) {
1287
+ weekly = null;
1288
+ } else if (!monthlyConfig || !confirmsNoMonthlyQuota(monthlyConfig)) {
1289
+ weekly = null;
1290
+ }
1291
+ }
1292
+ const windows = [];
1293
+ if (weekly) windows.push(weeklyWindow(weekly, now));
1294
+ if (monthly) windows.push(monthlyWindow(monthly, now));
1295
+ const onDemandSource = monthly && monthlyConfig ? monthlyConfig : creditsConfig;
1296
+ const onDemand = onDemandSource ? onDemandWindow(onDemandSource) : null;
1297
+ if (onDemand) windows.push(onDemand);
1298
+ return windows.length > 0 ? windows : null;
1299
+ }
1300
+ var GrokAllowanceCollector = class {
1301
+ constructor(credentials, store = (0, import_AccountAllowanceStore4.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId: "grok", accountId, redactBodies: true }), now = Date.now) {
1302
+ this.credentials = credentials;
1303
+ this.store = store;
1304
+ this.fetchImpl = fetchImpl;
1305
+ this.now = now;
1306
+ }
1307
+ credentials;
1308
+ store;
1309
+ fetchImpl;
1310
+ now;
1311
+ inFlight = /* @__PURE__ */ new Map();
1312
+ async collectMany(accounts, options = {}) {
1313
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1314
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1315
+ }
1316
+ collect(account, options = {}) {
1317
+ const now = this.now();
1318
+ if (account.tokens.authMethod !== "oauth") {
1319
+ const existing = this.store.get("grok", account.id, now);
1320
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1321
+ return Promise.resolve(existing);
1322
+ }
1323
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1324
+ this.store.set(snapshot);
1325
+ return Promise.resolve(snapshot);
1326
+ }
1327
+ const cached = this.store.get("grok", account.id, now);
1328
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1329
+ return Promise.resolve(cached);
1330
+ }
1331
+ const running = this.inFlight.get(account.id);
1332
+ if (running) return running;
1333
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "grok_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1334
+ this.inFlight.set(account.id, promise);
1335
+ return promise;
1336
+ }
1337
+ isCacheValid(snapshot, now, refreshAheadMs) {
1338
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1339
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1340
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1341
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1342
+ }
1343
+ async fetchAccount(accountId) {
1344
+ const probe = async () => {
1345
+ const accessToken = await this.credentials.getAccessTokenForAccount("grok", accountId);
1346
+ if (!accessToken) return { unauthorized: true, windows: null };
1347
+ const credits = await probeBilling(GROK_BILLING_CREDITS_URL, accessToken, accountId, this.fetchImpl);
1348
+ if (credits.status === 401 || credits.status === 403) return { unauthorized: true, windows: null };
1349
+ const creditsConfig = isRecord2(credits.payload?.["config"]) ? credits.payload["config"] : null;
1350
+ const weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
1351
+ const monthly = !weekly || creditsConfig?.["isUnifiedBillingUser"] === true ? await probeBilling(GROK_BILLING_MONTHLY_URL, accessToken, accountId, this.fetchImpl) : { status: 200, payload: null };
1352
+ if (monthly.status === 401 || monthly.status === 403) return { unauthorized: true, windows: null };
1353
+ return {
1354
+ unauthorized: false,
1355
+ windows: parseGrokBillingPayloads(credits.payload, monthly.payload, this.now())
1356
+ };
1357
+ };
1358
+ let result = await probe();
1359
+ if (result.unauthorized) {
1360
+ const refreshed = await this.credentials.refreshAccountToken("grok", accountId);
1361
+ if (!refreshed) return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
1362
+ result = await probe();
1363
+ if (result.unauthorized) {
1364
+ return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
1365
+ }
1366
+ }
1367
+ const now = this.now();
1368
+ if (result.windows && result.windows.length > 0) {
1369
+ const snapshot = {
1370
+ providerId: "grok",
1371
+ accountId,
1372
+ source: "oauth-usage-api",
1373
+ observedAt: new Date(now).toISOString(),
1374
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1375
+ windows: result.windows
1376
+ };
1377
+ this.store.set(snapshot);
1378
+ return snapshot;
1379
+ }
1380
+ return this.failureSnapshot(accountId, "grok_usage_invalid_response", now);
1381
+ }
1382
+ failureSnapshot(accountId, code, now) {
1383
+ const existing = this.store.get("grok", accountId, now);
1384
+ const snapshot = existing ? {
1385
+ ...existing,
1386
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1387
+ windows: existing.windows.map((window) => ({
1388
+ ...window,
1389
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1390
+ })),
1391
+ lastErrorCode: code
1392
+ } : {
1393
+ providerId: "grok",
1394
+ accountId,
1395
+ source: "oauth-usage-api",
1396
+ observedAt: new Date(now).toISOString(),
1397
+ expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
1398
+ windows: [
1399
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" },
1400
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unavailable" }
1401
+ ],
1402
+ lastErrorCode: code
1403
+ };
1404
+ this.store.set(snapshot);
1405
+ return snapshot;
1406
+ }
1407
+ unsupportedSnapshot(accountId, now) {
1408
+ return {
1409
+ providerId: "grok",
1410
+ accountId,
1411
+ source: "oauth-usage-api",
1412
+ observedAt: new Date(now).toISOString(),
1413
+ windows: [
1414
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" },
1415
+ { id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unsupported" }
1416
+ ],
1417
+ lastErrorCode: "grok_usage_unsupported_auth"
1418
+ };
1419
+ }
1420
+ };
1421
+
1422
+ // src/allowance/CopilotAllowanceCollector.ts
1423
+ var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1424
+ var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
1425
+ var import_subscriptions6 = require("@omnicross/subscriptions");
1426
+ var COPILOT_ALLOWANCE_CACHE_MS = 5 * 6e4;
1427
+ function isRecord3(value) {
1428
+ return !!value && typeof value === "object" && !Array.isArray(value);
1429
+ }
1430
+ function finiteNumber4(value) {
1431
+ if (value === null || value === void 0 || value === "") return void 0;
1432
+ const parsed = typeof value === "number" ? value : Number(value);
1433
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1434
+ }
1435
+ function booleanValue(value) {
1436
+ if (typeof value === "boolean") return value;
1437
+ if (value === "true") return true;
1438
+ if (value === "false") return false;
1439
+ return void 0;
1440
+ }
1441
+ function parseQuotaDetail(value) {
1442
+ if (!isRecord3(value)) return null;
1443
+ const entitlement = finiteNumber4(value["entitlement"]);
1444
+ const remaining = finiteNumber4(value["remaining"]);
1445
+ const percentRemaining = finiteNumber4(value["percent_remaining"]);
1446
+ const unlimited = booleanValue(value["unlimited"]);
1447
+ if (entitlement === void 0 || remaining === void 0 || percentRemaining === void 0 || unlimited === void 0) {
1448
+ return null;
1449
+ }
1450
+ return { entitlement, remaining, percentRemaining, unlimited };
1451
+ }
1452
+ function secondsUntil5(instant, now) {
1453
+ if (!instant) return void 0;
1454
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1455
+ }
1456
+ function parseCopilotUserPayload(payload, now) {
1457
+ if (!isRecord3(payload)) return null;
1458
+ const snapshots = isRecord3(payload["quota_snapshots"]) ? payload["quota_snapshots"] : void 0;
1459
+ if (!snapshots) return null;
1460
+ const resetRaw = payload["quota_reset_date"];
1461
+ const resetsAt = typeof resetRaw === "string" && resetRaw.trim() && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
1462
+ const windows = [];
1463
+ const premium = parseQuotaDetail(snapshots["premium_interactions"]);
1464
+ if (premium) {
1465
+ const usedPercent = premium.unlimited ? 0 : premium.entitlement > 0 ? Math.round(Math.min(100, (premium.entitlement - premium.remaining) / premium.entitlement * 100) * 10) / 10 : finiteNumber4(premium.percentRemaining) !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - premium.percentRemaining)) * 10) / 10 : null;
1466
+ if (usedPercent !== null) {
1467
+ windows.push({
1468
+ id: "thirty-day",
1469
+ label: "Monthly",
1470
+ scope: "all",
1471
+ usedPercent,
1472
+ windowMinutes: 30 * 24 * 60,
1473
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1474
+ remainingSeconds: secondsUntil5(resetsAt, now),
1475
+ state: "fresh"
1476
+ });
838
1477
  }
839
1478
  }
840
- return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
1479
+ const chat = parseQuotaDetail(snapshots["chat"]);
1480
+ if (chat && !chat.unlimited && chat.entitlement > 0) {
1481
+ const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
1482
+ windows.push({
1483
+ id: "chat-monthly",
1484
+ label: "Chat (monthly)",
1485
+ scope: "all",
1486
+ usedPercent,
1487
+ windowMinutes: 30 * 24 * 60,
1488
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1489
+ remainingSeconds: secondsUntil5(resetsAt, now),
1490
+ state: "fresh"
1491
+ });
1492
+ }
1493
+ return windows.length > 0 ? windows : null;
841
1494
  }
842
- var KimiAllowanceCollector = class {
843
- constructor(credentials, store = (0, import_AccountAllowanceStore3.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch3.fetchUpstream)(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
1495
+ function githubApiBase(tokens) {
1496
+ return (0, import_subscriptions6.copilotGitHubApiBase)(tokens.enterpriseUrl);
1497
+ }
1498
+ var CopilotAllowanceCollector = class {
1499
+ constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch5.fetchUpstream)(url, init, { providerId: "copilot", accountId, redactBodies: true }), now = Date.now) {
844
1500
  this.credentials = credentials;
845
1501
  this.store = store;
846
1502
  this.fetchImpl = fetchImpl;
@@ -852,13 +1508,15 @@ var KimiAllowanceCollector = class {
852
1508
  now;
853
1509
  inFlight = /* @__PURE__ */ new Map();
854
1510
  async collectMany(accounts, options = {}) {
855
- const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
1511
+ const settled = await Promise.allSettled(
1512
+ accounts.map((account) => this.collect(account, options))
1513
+ );
856
1514
  return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
857
1515
  }
858
1516
  collect(account, options = {}) {
859
1517
  const now = this.now();
860
1518
  if (account.tokens.authMethod !== "oauth") {
861
- const existing = this.store.get("kimi", account.id, now);
1519
+ const existing = this.store.get("copilot", account.id, now);
862
1520
  if (existing?.windows.every((window) => window.state === "unsupported")) {
863
1521
  return Promise.resolve(existing);
864
1522
  }
@@ -866,13 +1524,13 @@ var KimiAllowanceCollector = class {
866
1524
  this.store.set(snapshot);
867
1525
  return Promise.resolve(snapshot);
868
1526
  }
869
- const cached = this.store.get("kimi", account.id, now);
1527
+ const cached = this.store.get("copilot", account.id, now);
870
1528
  if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
871
1529
  return Promise.resolve(cached);
872
1530
  }
873
1531
  const running = this.inFlight.get(account.id);
874
1532
  if (running) return running;
875
- const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "kimi_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1533
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "copilot_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
876
1534
  this.inFlight.set(account.id, promise);
877
1535
  return promise;
878
1536
  }
@@ -883,100 +1541,96 @@ var KimiAllowanceCollector = class {
883
1541
  return Number.isFinite(expiresAt) && expiresAt > now + ahead;
884
1542
  }
885
1543
  async fetchAccount(accountId, tokens) {
886
- let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
887
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1544
+ let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1545
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
888
1546
  let response = await this.request(accountId, accessToken, tokens);
889
- if (response.status === 401) {
890
- const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
891
- if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
892
- accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
893
- if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
1547
+ if (response.status === 401 || response.status === 403) {
1548
+ const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
1549
+ if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1550
+ accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1551
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
894
1552
  response = await this.request(accountId, accessToken, tokens);
1553
+ if (response.status === 401 || response.status === 403) {
1554
+ return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1555
+ }
895
1556
  }
896
- if (response.status === 403) {
897
- const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
898
- this.store.set(snapshot2);
899
- return snapshot2;
900
- }
901
- if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
1557
+ if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
902
1558
  let payload;
903
1559
  try {
904
1560
  payload = await response.json();
905
1561
  } catch {
906
- return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
1562
+ return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
907
1563
  }
908
1564
  const now = this.now();
909
- const windows = parseKimiUsagePayload(payload, now);
1565
+ const windows = parseCopilotUserPayload(payload, now);
910
1566
  const snapshot = {
911
- providerId: "kimi",
1567
+ providerId: "copilot",
912
1568
  accountId,
913
1569
  source: "oauth-usage-api",
914
1570
  observedAt: new Date(now).toISOString(),
915
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
916
- windows: windows.length > 0 ? windows : [
917
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
918
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1571
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1572
+ windows: windows ?? [
1573
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
919
1574
  ],
920
- ...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
1575
+ ...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
921
1576
  };
922
1577
  this.store.set(snapshot);
923
1578
  return snapshot;
924
1579
  }
925
1580
  request(accountId, accessToken, tokens) {
926
- return this.fetchImpl(KIMI_USAGE_URL, {
1581
+ return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
927
1582
  method: "GET",
928
1583
  headers: {
929
1584
  Authorization: `Bearer ${accessToken}`,
930
1585
  Accept: "application/json",
931
- ...(0, import_subscriptions3.kimiFingerprintHeaders)(tokens.deviceId)
1586
+ "Content-Type": "application/json",
1587
+ ...import_subscriptions6.COPILOT_GITHUB_HEADERS
932
1588
  },
933
1589
  signal: AbortSignal.timeout(15e3)
934
1590
  }, accountId);
935
1591
  }
936
1592
  failureSnapshot(accountId, code, now) {
937
- const existing = this.store.get("kimi", accountId, now);
1593
+ const existing = this.store.get("copilot", accountId, now);
938
1594
  const snapshot = existing ? {
939
1595
  ...existing,
940
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1596
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
941
1597
  windows: existing.windows.map((window) => ({
942
1598
  ...window,
943
1599
  state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
944
1600
  })),
945
1601
  lastErrorCode: code
946
1602
  } : {
947
- providerId: "kimi",
1603
+ providerId: "copilot",
948
1604
  accountId,
949
1605
  source: "oauth-usage-api",
950
1606
  observedAt: new Date(now).toISOString(),
951
- expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
1607
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
952
1608
  windows: [
953
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
954
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1609
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
955
1610
  ],
956
1611
  lastErrorCode: code
957
1612
  };
958
1613
  this.store.set(snapshot);
959
1614
  return snapshot;
960
1615
  }
961
- unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
1616
+ unsupportedSnapshot(accountId, now) {
962
1617
  return {
963
- providerId: "kimi",
1618
+ providerId: "copilot",
964
1619
  accountId,
965
1620
  source: "oauth-usage-api",
966
1621
  observedAt: new Date(now).toISOString(),
967
1622
  windows: [
968
- { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
969
- { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
1623
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
970
1624
  ],
971
- lastErrorCode: code
1625
+ lastErrorCode: "copilot_usage_unsupported_auth"
972
1626
  };
973
1627
  }
974
1628
  };
975
1629
 
976
1630
  // src/allowance/OpenCodeGoAllowanceCollector.ts
977
- var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
978
- var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
979
- var import_subscriptions4 = require("@omnicross/subscriptions");
1631
+ var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1632
+ var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
1633
+ var import_subscriptions7 = require("@omnicross/subscriptions");
980
1634
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
981
1635
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
982
1636
  function finitePercent3(value) {
@@ -989,7 +1643,7 @@ function isoInstant2(value) {
989
1643
  const time = Date.parse(value);
990
1644
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
991
1645
  }
992
- function secondsUntil4(instant, now) {
1646
+ function secondsUntil6(instant, now) {
993
1647
  if (!instant) return void 0;
994
1648
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
995
1649
  }
@@ -1004,12 +1658,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
1004
1658
  usedPercent,
1005
1659
  windowMinutes: minutes,
1006
1660
  ...resetsAt !== void 0 ? { resetsAt } : {},
1007
- remainingSeconds: secondsUntil4(resetsAt, now),
1661
+ remainingSeconds: secondsUntil6(resetsAt, now),
1008
1662
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1009
1663
  };
1010
1664
  }
1011
1665
  var OpenCodeGoAllowanceCollector = class {
1012
- constructor(credentials, store = (0, import_AccountAllowanceStore4.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
1666
+ constructor(credentials, store = (0, import_AccountAllowanceStore6.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch6.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
1013
1667
  this.credentials = credentials;
1014
1668
  this.store = store;
1015
1669
  this.fetchImpl = fetchImpl;
@@ -1039,7 +1693,7 @@ var OpenCodeGoAllowanceCollector = class {
1039
1693
  async fetchAccount(account) {
1040
1694
  const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
1041
1695
  if (!apiKey) return this.failureSnapshot(account.id, this.now());
1042
- const base = account.tokens.baseUrl ? (0, import_subscriptions4.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1696
+ const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1043
1697
  const response = await this.fetchImpl(`${base}/v1/usage`, {
1044
1698
  method: "GET",
1045
1699
  headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
@@ -1114,7 +1768,7 @@ function codexUnavailable(accountId, now) {
1114
1768
  };
1115
1769
  }
1116
1770
  var AccountAllowanceService = class {
1117
- constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, now = Date.now) {
1771
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, now = Date.now) {
1118
1772
  this.credentials = credentials;
1119
1773
  this.store = store;
1120
1774
  this.now = now;
@@ -1122,6 +1776,8 @@ var AccountAllowanceService = class {
1122
1776
  this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
1123
1777
  this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
1124
1778
  this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
1779
+ this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
1780
+ this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
1125
1781
  }
1126
1782
  credentials;
1127
1783
  store;
@@ -1129,6 +1785,8 @@ var AccountAllowanceService = class {
1129
1785
  claudeCollector;
1130
1786
  codexCollector;
1131
1787
  kimiCollector;
1788
+ grokCollector;
1789
+ copilotCollector;
1132
1790
  opencodegoCollector;
1133
1791
  /**
1134
1792
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
@@ -1163,11 +1821,23 @@ var AccountAllowanceService = class {
1163
1821
  (account) => !filter.accountId || account.id === filter.accountId
1164
1822
  );
1165
1823
  if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
1824
+ const wantsGrok = !filter.providerId || filter.providerId === "grok";
1825
+ const grokAccounts = (config.grokAccounts ?? []).filter(
1826
+ (account) => !filter.accountId || account.id === filter.accountId
1827
+ );
1828
+ if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
1829
+ const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
1830
+ const copilotAccounts = (config.copilotAccounts ?? []).filter(
1831
+ (account) => !filter.accountId || account.id === filter.accountId
1832
+ );
1833
+ if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
1166
1834
  const known = /* @__PURE__ */ new Set();
1167
1835
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
1168
1836
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
1169
1837
  if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
1170
1838
  if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
1839
+ if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
1840
+ if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
1171
1841
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
1172
1842
  }
1173
1843
  knownAccounts(config) {
@@ -1175,7 +1845,9 @@ var AccountAllowanceService = class {
1175
1845
  ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1176
1846
  ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
1177
1847
  ...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
1178
- ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id }))
1848
+ ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
1849
+ ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
1850
+ ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id }))
1179
1851
  ];
1180
1852
  }
1181
1853
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -1218,6 +1890,24 @@ var AccountAllowanceService = class {
1218
1890
  );
1219
1891
  return this.kimiCollector.collectMany(accounts, { force: true });
1220
1892
  }
1893
+ /** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
1894
+ async refreshCopilot(accountId) {
1895
+ const config = await this.credentials.getFullConfig();
1896
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1897
+ const accounts = (config.copilotAccounts ?? []).filter(
1898
+ (account) => !accountId || account.id === accountId
1899
+ );
1900
+ return this.copilotCollector.collectMany(accounts, { force: true });
1901
+ }
1902
+ /** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
1903
+ async refreshGrok(accountId) {
1904
+ const config = await this.credentials.getFullConfig();
1905
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1906
+ const accounts = (config.grokAccounts ?? []).filter(
1907
+ (account) => !accountId || account.id === accountId
1908
+ );
1909
+ return this.grokCollector.collectMany(accounts, { force: true });
1910
+ }
1221
1911
  /**
1222
1912
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
1223
1913
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -1232,6 +1922,8 @@ var AccountAllowanceService = class {
1232
1922
  await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
1233
1923
  await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
1234
1924
  await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
1925
+ await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
1926
+ await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
1235
1927
  }
1236
1928
  /** Remove a cache row as soon as an account is deleted by the admin path. */
1237
1929
  removeAccountSnapshot(providerId, accountId) {
@@ -1326,7 +2018,7 @@ var ClaudeAllowanceRefreshScheduler = class {
1326
2018
  var import_node_crypto2 = require("crypto");
1327
2019
  var import_node_fs = require("fs");
1328
2020
  var import_node_path = require("path");
1329
- var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2021
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1330
2022
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
1331
2023
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
1332
2024
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -1355,7 +2047,7 @@ var JsonAccountAllowancePersistence = class {
1355
2047
  save(snapshots) {
1356
2048
  const rows = [];
1357
2049
  for (const snapshot of snapshots) {
1358
- const normalized2 = (0, import_AccountAllowanceStore6.normalizeAccountAllowanceSnapshot)(snapshot);
2050
+ const normalized2 = (0, import_AccountAllowanceStore8.normalizeAccountAllowanceSnapshot)(snapshot);
1359
2051
  if (!normalized2) continue;
1360
2052
  rows.push(normalized2);
1361
2053
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -1638,7 +2330,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
1638
2330
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
1639
2331
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1640
2332
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1641
- var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
2333
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
2334
+ var import_core3 = require("@omnicross/core");
1642
2335
 
1643
2336
  // src/image-generation/imagesConfigValidation.ts
1644
2337
  var import_outbound_api = require("@omnicross/core/outbound-api");
@@ -1934,6 +2627,7 @@ async function applyServerConfigTransaction(current, next, deps) {
1934
2627
 
1935
2628
  // src/config.ts
1936
2629
  var import_node_fs4 = require("fs");
2630
+ var import_core = require("@omnicross/core");
1937
2631
 
1938
2632
  // src/secrets/envelope.ts
1939
2633
  var import_node_crypto4 = require("crypto");
@@ -2345,6 +3039,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
2345
3039
  "openai-response",
2346
3040
  "gemini-code-assist"
2347
3041
  ];
3042
+ function validateExtraHeaders(raw) {
3043
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3044
+ const reserved = import_core.EXTRA_HEADER_RESERVED_NAMES;
3045
+ const out = {};
3046
+ for (const [name, value] of Object.entries(raw)) {
3047
+ if (!name.trim()) continue;
3048
+ if (typeof value !== "string") continue;
3049
+ if (reserved.has(name.toLowerCase())) continue;
3050
+ out[name] = value;
3051
+ }
3052
+ return Object.keys(out).length > 0 ? out : void 0;
3053
+ }
2348
3054
  function validateApiKeys(raw) {
2349
3055
  if (!Array.isArray(raw)) return void 0;
2350
3056
  const out = [];
@@ -2558,6 +3264,9 @@ function validateProvider(raw, index) {
2558
3264
  apiVersion,
2559
3265
  maxConcurrency,
2560
3266
  modelsEndpoint,
3267
+ // Static extra headers: load-guard (reserved names dropped), collapse-to-
3268
+ // undefined; enforced by the outbound header funnel + admin probes.
3269
+ extraHeaders: validateExtraHeaders(p["extraHeaders"]),
2561
3270
  // Provider transformer config (app-parity child 5): load-guard, collapse-to-
2562
3271
  // undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
2563
3272
  // Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
@@ -2627,7 +3336,7 @@ var import_node_crypto6 = require("crypto");
2627
3336
  var import_node_fs6 = require("fs");
2628
3337
  var import_node_os3 = require("os");
2629
3338
  var import_node_path6 = require("path");
2630
- var import_core = require("@omnicross/core");
3339
+ var import_core2 = require("@omnicross/core");
2631
3340
 
2632
3341
  // src/integrations/codexAuthHelper.ts
2633
3342
  var import_node_path4 = require("path");
@@ -3108,7 +3817,7 @@ var IntegrationManager = class {
3108
3817
  if (!secret) {
3109
3818
  throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
3110
3819
  }
3111
- const effective = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
3820
+ const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3112
3821
  const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
3113
3822
  const nextPermissions = [...effective];
3114
3823
  for (const required of REQUIRED_PERMISSIONS[client]) {
@@ -3206,7 +3915,7 @@ var IntegrationManager = class {
3206
3915
  return { binding, row, secret, created: false };
3207
3916
  }
3208
3917
  async createManagedClientKey(client, state) {
3209
- const created = await (0, import_core.createIntegrationKey)(
3918
+ const created = await (0, import_core2.createIntegrationKey)(
3210
3919
  this.options.keyDb,
3211
3920
  `Omnicross ${displayClient(client)} integration`,
3212
3921
  [...REQUIRED_PERMISSIONS[client]]
@@ -3298,7 +4007,7 @@ var IntegrationManager = class {
3298
4007
  const row = rows.find((candidate) => candidate.id === keyId);
3299
4008
  if (!row) return { usable: false, message: "The bound access key no longer exists." };
3300
4009
  const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
3301
- const allowedEndpoints = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4010
+ const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
3302
4011
  const status = {
3303
4012
  id: row.id,
3304
4013
  name: row.name,
@@ -3342,7 +4051,7 @@ var IntegrationManager = class {
3342
4051
  }
3343
4052
  };
3344
4053
  function hasRequiredPermissions(row, client) {
3345
- const allowed = (0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints);
4054
+ const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
3346
4055
  return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
3347
4056
  }
3348
4057
  function samePermissions(a, b) {
@@ -3516,7 +4225,8 @@ function listMappablePresets() {
3516
4225
  description: preset.description,
3517
4226
  features: preset.features,
3518
4227
  website: preset.website,
3519
- modelsEndpoint: preset.modelsEndpoint
4228
+ modelsEndpoint: preset.modelsEndpoint,
4229
+ extraHeaders: preset.extraHeaders
3520
4230
  });
3521
4231
  }
3522
4232
  return { mappable, excluded };
@@ -3606,11 +4316,11 @@ function preserveOutboundProxySecrets(incoming, current) {
3606
4316
  }
3607
4317
 
3608
4318
  // src/proxy/upstreamProxyResolver.ts
3609
- var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
4319
+ var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
3610
4320
  var serverProxy;
3611
4321
  function setServerProxyConfig(proxy) {
3612
4322
  serverProxy = proxy;
3613
- (0, import_upstreamFetch5.bumpUpstreamProxyGeneration)();
4323
+ (0, import_upstreamFetch7.bumpUpstreamProxyGeneration)();
3614
4324
  }
3615
4325
  function getServerProxyConfig() {
3616
4326
  return serverProxy;
@@ -3678,7 +4388,7 @@ function createUpstreamProxyResolver(src = {}) {
3678
4388
  }
3679
4389
 
3680
4390
  // src/admin/accountsOAuth.ts
3681
- var import_subscriptions5 = require("@omnicross/subscriptions");
4391
+ var import_subscriptions8 = require("@omnicross/subscriptions");
3682
4392
 
3683
4393
  // src/admin/accountsWrite.ts
3684
4394
  var VALID_PROVIDER_IDS = [
@@ -3686,7 +4396,9 @@ var VALID_PROVIDER_IDS = [
3686
4396
  "codex",
3687
4397
  "gemini",
3688
4398
  "opencodego",
3689
- "kimi"
4399
+ "kimi",
4400
+ "grok",
4401
+ "copilot"
3690
4402
  ];
3691
4403
  function asSubscriptionProviderId(id) {
3692
4404
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -3834,6 +4546,40 @@ function validateKimi(body) {
3834
4546
  copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
3835
4547
  return out;
3836
4548
  }
4549
+ function validateGrok(body) {
4550
+ const authMethod = str(body["authMethod"]);
4551
+ const status = str(body["status"]);
4552
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4553
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4554
+ const out = {
4555
+ authMethod,
4556
+ status
4557
+ };
4558
+ copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
4559
+ return out;
4560
+ }
4561
+ function validateCopilot(body) {
4562
+ const authMethod = str(body["authMethod"]);
4563
+ const status = str(body["status"]);
4564
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4565
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4566
+ const out = {
4567
+ authMethod,
4568
+ status
4569
+ };
4570
+ copyOptional(out, body, [
4571
+ "accessToken",
4572
+ "refreshToken",
4573
+ "expiresAt",
4574
+ "accountId",
4575
+ "email",
4576
+ "apiEndpoint",
4577
+ "enterpriseUrl",
4578
+ "lastRefreshedAt",
4579
+ "errorMessage"
4580
+ ]);
4581
+ return out;
4582
+ }
3837
4583
  function validateOpenCodeGo(body) {
3838
4584
  const authMethod = str(body["authMethod"]);
3839
4585
  const status = str(body["status"]);
@@ -3871,6 +4617,10 @@ function validateTokenBody(providerId, body) {
3871
4617
  return validateOpenCodeGo(body);
3872
4618
  case "kimi":
3873
4619
  return validateKimi(body);
4620
+ case "grok":
4621
+ return validateGrok(body);
4622
+ case "copilot":
4623
+ return validateCopilot(body);
3874
4624
  default:
3875
4625
  return null;
3876
4626
  }
@@ -3900,37 +4650,37 @@ async function statusEntryFor(reader, providerId) {
3900
4650
 
3901
4651
  // src/admin/accountsOAuth.ts
3902
4652
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
3903
- function err3(status, message) {
4653
+ function err5(status, message) {
3904
4654
  return { status, body: { error: { type: "admin_api_error", message } } };
3905
4655
  }
3906
4656
  function handleOAuthStart(providerId, deps) {
3907
4657
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3908
- return err3(400, `oauth not available for provider '${providerId}'`);
4658
+ return err5(400, `oauth not available for provider '${providerId}'`);
3909
4659
  }
3910
- const flow = providerId === "claude" ? import_subscriptions5.claudeOAuth : import_subscriptions5.geminiOAuth;
4660
+ const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
3911
4661
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
3912
4662
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
3913
4663
  return { status: 200, body: { authUrl, sessionId } };
3914
4664
  }
3915
4665
  async function handleOAuthComplete(providerId, body, deps) {
3916
4666
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3917
- return err3(400, `oauth not available for provider '${providerId}'`);
4667
+ return err5(400, `oauth not available for provider '${providerId}'`);
3918
4668
  }
3919
4669
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
3920
4670
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
3921
- if (!sessionId) return err3(400, "oauth complete requires { sessionId }");
3922
- if (!rawCode) return err3(400, "oauth complete requires { code }");
4671
+ if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
4672
+ if (!rawCode) return err5(400, "oauth complete requires { code }");
3923
4673
  const session = deps.oauthSessions.peek(sessionId);
3924
- if (!session) return err3(410, "oauth session is unknown, expired, or already used");
4674
+ if (!session) return err5(410, "oauth session is unknown, expired, or already used");
3925
4675
  if (session.providerId !== providerId) {
3926
- return err3(400, `oauth session does not match provider '${providerId}'`);
4676
+ return err5(400, `oauth session does not match provider '${providerId}'`);
3927
4677
  }
3928
4678
  let code = rawCode.trim();
3929
4679
  if (providerId === "claude") {
3930
4680
  const [splitCode, pastedState] = code.split("#");
3931
- if (!splitCode) return err3(400, "no authorization code was provided");
4681
+ if (!splitCode) return err5(400, "no authorization code was provided");
3932
4682
  if (pastedState && pastedState !== session.state) {
3933
- return err3(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4683
+ return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
3934
4684
  }
3935
4685
  code = splitCode;
3936
4686
  }
@@ -3940,7 +4690,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3940
4690
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
3941
4691
  } catch (exchangeError) {
3942
4692
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
3943
- return err3(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4693
+ return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
3944
4694
  }
3945
4695
  deps.oauthSessions.consume(sessionId);
3946
4696
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -3949,7 +4699,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3949
4699
  return { status: 200, body: status ? { account: status } : { ok: true } };
3950
4700
  }
3951
4701
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3952
- const result = await import_subscriptions5.claudeOAuth.exchangeCodeForTokens(
4702
+ const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
3953
4703
  { authorizationCode: code, codeVerifier, state },
3954
4704
  exchangeFetch
3955
4705
  );
@@ -3965,7 +4715,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3965
4715
  };
3966
4716
  }
3967
4717
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
3968
- const result = await import_subscriptions5.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
4718
+ const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
3969
4719
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
3970
4720
  return {
3971
4721
  authMethod: "oauth",
@@ -4270,8 +5020,8 @@ function errBody(message) {
4270
5020
  return { error: { type: "admin_api_error", message } };
4271
5021
  }
4272
5022
  var defaultCommandRunner = (command) => new Promise((resolve10) => {
4273
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err6, _stdout, stderr) => {
4274
- if (err6) resolve10({ ok: false, error: stderr.trim() || err6.message });
5023
+ (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5024
+ if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
4275
5025
  else resolve10({ ok: true });
4276
5026
  });
4277
5027
  });
@@ -4317,8 +5067,8 @@ async function handleCliLaunch(cli, body, ctx) {
4317
5067
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
4318
5068
  model: typeof body["model"] === "string" ? body["model"] : void 0
4319
5069
  });
4320
- } catch (err6) {
4321
- return { status: 400, body: errBody(err6 instanceof Error ? err6.message : "no launch target") };
5070
+ } catch (err8) {
5071
+ return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
4322
5072
  }
4323
5073
  const id = (0, import_node_crypto7.randomUUID)();
4324
5074
  let leaseId2;
@@ -4346,9 +5096,9 @@ async function handleCliLaunch(cli, body, ctx) {
4346
5096
  } else {
4347
5097
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
4348
5098
  }
4349
- } catch (err6) {
4350
- const status = err6 instanceof import_provider_proxy2.RouteLeaseError ? err6.status : 400;
4351
- return { status, body: errBody(err6 instanceof Error ? err6.message : "failed to build launch env") };
5099
+ } catch (err8) {
5100
+ const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
5101
+ return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
4352
5102
  }
4353
5103
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
4354
5104
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -4376,9 +5126,9 @@ async function handleCliLaunch(cli, body, ctx) {
4376
5126
  onFailure: onSessionEnd
4377
5127
  });
4378
5128
  if (cleanup) openerCleanup = cleanup;
4379
- } catch (err6) {
5129
+ } catch (err8) {
4380
5130
  onSessionEnd();
4381
- return { status: 500, body: errBody(err6 instanceof Error ? err6.message : "failed to open terminal") };
5131
+ return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
4382
5132
  }
4383
5133
  if (ended) {
4384
5134
  openerCleanup?.();
@@ -4619,7 +5369,7 @@ function classifySearchFailure(stage, code) {
4619
5369
  }
4620
5370
 
4621
5371
  // src/search/SearchAssembly.ts
4622
- var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
5372
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
4623
5373
  var import_search = require("@omnicross/core/search");
4624
5374
  var import_api2 = require("@omnicross/core/search/api");
4625
5375
  var import_http2 = require("@omnicross/core/search/http");
@@ -4637,7 +5387,7 @@ function searchPolicyFrom(config) {
4637
5387
  };
4638
5388
  }
4639
5389
  function resolveSearchUpstreamDispatcher(url) {
4640
- return (0, import_upstreamFetch6.resolveUpstreamDispatcher)({ url });
5390
+ return (0, import_upstreamFetch8.resolveUpstreamDispatcher)({ url });
4641
5391
  }
4642
5392
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
4643
5393
  function resolveSearchUpstreamProxyConfig(url) {
@@ -4919,7 +5669,7 @@ async function handleSearchQuery(req, res, deps) {
4919
5669
  // src/admin/searchAdminView.ts
4920
5670
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
4921
5671
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
4922
- function isRecord2(value) {
5672
+ function isRecord4(value) {
4923
5673
  return value !== null && typeof value === "object" && !Array.isArray(value);
4924
5674
  }
4925
5675
  function redactSearchServerConfig(search) {
@@ -4969,13 +5719,13 @@ function resolveSecretField(entry, field, stored) {
4969
5719
  else delete entry[field];
4970
5720
  }
4971
5721
  function preserveSearchSecrets(incoming, current) {
4972
- if (!isRecord2(incoming)) return incoming;
5722
+ if (!isRecord4(incoming)) return incoming;
4973
5723
  const section = { ...incoming };
4974
5724
  const providersValue = section["providers"];
4975
- if (!isRecord2(providersValue)) return section;
5725
+ if (!isRecord4(providersValue)) return section;
4976
5726
  const providers = {};
4977
5727
  for (const [id, entryValue] of Object.entries(providersValue)) {
4978
- if (!isRecord2(entryValue)) {
5728
+ if (!isRecord4(entryValue)) {
4979
5729
  providers[id] = entryValue;
4980
5730
  continue;
4981
5731
  }
@@ -5053,7 +5803,7 @@ function parseKeyPolicyBody(body) {
5053
5803
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
5054
5804
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
5055
5805
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
5056
- function isRecord3(value) {
5806
+ function isRecord5(value) {
5057
5807
  return !!value && typeof value === "object" && !Array.isArray(value);
5058
5808
  }
5059
5809
  function nonBlank(value) {
@@ -5073,7 +5823,7 @@ function validateGatewayBindingsSegment(patch) {
5073
5823
  const ids = /* @__PURE__ */ new Set();
5074
5824
  raw.forEach((entry, index) => {
5075
5825
  const path2 = `bindings[${index}]`;
5076
- if (!isRecord3(entry)) {
5826
+ if (!isRecord5(entry)) {
5077
5827
  errors.push(`${path2} must be an object`);
5078
5828
  return;
5079
5829
  }
@@ -5102,12 +5852,12 @@ function validateGatewayBindingsSegment(patch) {
5102
5852
  } else if (entry.modelMappings.length > 100) {
5103
5853
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
5104
5854
  } else if (entry.modelMappings.some(
5105
- (mapping) => !isRecord3(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5855
+ (mapping) => !isRecord5(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5106
5856
  )) {
5107
5857
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
5108
5858
  }
5109
5859
  }
5110
- if (!isRecord3(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5860
+ if (!isRecord5(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5111
5861
  errors.push(`${path2}.target is invalid`);
5112
5862
  } else {
5113
5863
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -5122,7 +5872,7 @@ function validateGatewayBindingsSegment(patch) {
5122
5872
  }
5123
5873
  }
5124
5874
  if (entry.modelMap !== void 0) {
5125
- if (!isRecord3(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
5875
+ if (!isRecord5(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
5126
5876
  errors.push(`${path2}.modelMap must contain string values`);
5127
5877
  }
5128
5878
  }
@@ -5421,7 +6171,9 @@ var PROVIDER_KEYS = {
5421
6171
  accounts: "opencodegoAccounts",
5422
6172
  active: "activeOpencodegoAccountId"
5423
6173
  },
5424
- kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
6174
+ kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6175
+ grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6176
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
5425
6177
  };
5426
6178
  function clone(value) {
5427
6179
  return JSON.parse(JSON.stringify(value));
@@ -5943,7 +6695,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
5943
6695
  }
5944
6696
 
5945
6697
  // src/admin/adminMigration.ts
5946
- function err4(status, message) {
6698
+ function err6(status, message) {
5947
6699
  return { status, body: { error: { type: "admin_api_error", message } } };
5948
6700
  }
5949
6701
  async function handleExport(body, deps) {
@@ -5953,30 +6705,30 @@ async function handleExport(body, deps) {
5953
6705
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
5954
6706
  } catch (error) {
5955
6707
  if (error instanceof WeakPassphraseError) {
5956
- return err4(400, error.message);
6708
+ return err6(400, error.message);
5957
6709
  }
5958
- return err4(500, "failed to build the migration pack");
6710
+ return err6(500, "failed to build the migration pack");
5959
6711
  }
5960
6712
  }
5961
6713
  async function handleImport(body, deps) {
5962
6714
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
5963
6715
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
5964
6716
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
5965
- if (!blob) return err4(400, "import requires { blob }");
6717
+ if (!blob) return err6(400, "import requires { blob }");
5966
6718
  try {
5967
6719
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
5968
6720
  return { status: 200, body: counts };
5969
6721
  } catch (error) {
5970
6722
  if (error instanceof WeakPassphraseError) {
5971
- return err4(400, error.message);
6723
+ return err6(400, error.message);
5972
6724
  }
5973
- return err4(400, error instanceof Error ? error.message : "import failed");
6725
+ return err6(400, error instanceof Error ? error.message : "import failed");
5974
6726
  }
5975
6727
  }
5976
6728
 
5977
6729
  // src/admin/usagePricing.ts
5978
6730
  var import_usage = require("@omnicross/core/usage");
5979
- var err5 = (status, message) => ({
6731
+ var err7 = (status, message) => ({
5980
6732
  status,
5981
6733
  body: { error: { type: "admin_api_error", message } }
5982
6734
  });
@@ -5989,7 +6741,7 @@ function parseRange(query2) {
5989
6741
  const startTs = parseFiniteInt(query2.get("startTs"));
5990
6742
  const endTs = parseFiniteInt(query2.get("endTs"));
5991
6743
  if (startTs === null || endTs === null) {
5992
- return err5(400, "startTs and endTs are required finite-integer unix-millis query params");
6744
+ return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
5993
6745
  }
5994
6746
  return { startTs, endTs };
5995
6747
  }
@@ -6014,14 +6766,14 @@ async function handleUsageGet(view, query2, deps) {
6014
6766
  case "timeseries": {
6015
6767
  const bucket = query2.get("bucket");
6016
6768
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
6017
- return err5(400, "bucket must be one of 'hour', 'day', 'month'");
6769
+ return err7(400, "bucket must be one of 'hour', 'day', 'month'");
6018
6770
  }
6019
6771
  const now = Date.now();
6020
6772
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
6021
6773
  if (clamped.startTs < clamped.endTs) {
6022
6774
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
6023
6775
  if (projected > MAX_TIMESERIES_BUCKETS) {
6024
- return err5(
6776
+ return err7(
6025
6777
  400,
6026
6778
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
6027
6779
  );
@@ -6044,7 +6796,7 @@ async function handleUsageGet(view, query2, deps) {
6044
6796
  };
6045
6797
  }
6046
6798
  default:
6047
- return err5(404, `unknown usage view '${view ?? ""}'`);
6799
+ return err7(404, `unknown usage view '${view ?? ""}'`);
6048
6800
  }
6049
6801
  }
6050
6802
  function poolKeyLabels(cfg) {
@@ -6093,7 +6845,7 @@ async function handlePricingList(deps) {
6093
6845
  async function handlePricingUpsert(body, deps) {
6094
6846
  const input = parsePricingEntryInput(body);
6095
6847
  if (!input) {
6096
- return err5(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
6848
+ return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
6097
6849
  }
6098
6850
  const entry = await deps.pricingEngine.upsertManual(input);
6099
6851
  return { status: 200, body: { entry } };
@@ -6102,7 +6854,7 @@ async function handlePricingDelete(query2, deps) {
6102
6854
  const providerId = query2.get("providerId")?.trim() ?? "";
6103
6855
  const modelId = query2.get("modelId")?.trim() ?? "";
6104
6856
  if (!providerId || !modelId) {
6105
- return err5(400, "delete requires providerId and modelId query params");
6857
+ return err7(400, "delete requires providerId and modelId query params");
6106
6858
  }
6107
6859
  const deleted = await deps.pricingStore.delete(providerId, modelId);
6108
6860
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -6122,13 +6874,13 @@ async function handlePricingFetchLatest(deps) {
6122
6874
  }
6123
6875
  };
6124
6876
  } catch (e) {
6125
- return err5(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
6877
+ return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
6126
6878
  }
6127
6879
  }
6128
6880
  async function handlePricingResolveConflicts(body, deps) {
6129
6881
  const raw = body["resolutions"];
6130
6882
  if (!Array.isArray(raw)) {
6131
- return err5(400, "resolve-conflicts requires { resolutions: [...] }");
6883
+ return err7(400, "resolve-conflicts requires { resolutions: [...] }");
6132
6884
  }
6133
6885
  const currentRows = await deps.pricingStore.getAll();
6134
6886
  const userEditedKeys = new Set(
@@ -6138,21 +6890,21 @@ async function handlePricingResolveConflicts(body, deps) {
6138
6890
  const pendingIncoming = /* @__PURE__ */ new Map();
6139
6891
  let staleCount = 0;
6140
6892
  for (const item of raw) {
6141
- if (!item || typeof item !== "object") return err5(400, "invalid resolution entry");
6893
+ if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
6142
6894
  const r = item;
6143
6895
  const action = r["action"];
6144
6896
  if (action !== "overwrite" && action !== "skip") {
6145
- return err5(400, "resolution action must be 'overwrite' or 'skip'");
6897
+ return err7(400, "resolution action must be 'overwrite' or 'skip'");
6146
6898
  }
6147
6899
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
6148
6900
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
6149
6901
  if (!providerId || !modelId) {
6150
- return err5(400, "each resolution requires top-level providerId and modelId");
6902
+ return err7(400, "each resolution requires top-level providerId and modelId");
6151
6903
  }
6152
6904
  const incoming = parsePricingEntryInput(r["incoming"]);
6153
- if (!incoming) return err5(400, "each resolution must echo a valid incoming pricing entry");
6905
+ if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
6154
6906
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
6155
- return err5(400, "resolution providerId/modelId must match the echoed incoming entry");
6907
+ return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
6156
6908
  }
6157
6909
  const key = `${providerId}::${modelId}`;
6158
6910
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -6197,7 +6949,7 @@ function query(req) {
6197
6949
  }
6198
6950
  function allowanceProvider(value) {
6199
6951
  if (!value) return void 0;
6200
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
6952
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" ? value : null;
6201
6953
  }
6202
6954
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
6203
6955
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -6212,7 +6964,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6212
6964
  const pathProvider = rest.length >= 2 ? rest[0] : null;
6213
6965
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
6214
6966
  if (providerId === null) {
6215
- return writeError2(res, 400, "providerId must be claude, codex, kimi, or opencodego");
6967
+ return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, or copilot");
6216
6968
  }
6217
6969
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
6218
6970
  const allowances = await service.list({ providerId, accountId });
@@ -6254,6 +7006,26 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
6254
7006
  }
6255
7007
  return writeJson3(res, 200, { allowances: allowances2 });
6256
7008
  }
7009
+ if (requestedProvider === "copilot") {
7010
+ if (!service.refreshCopilot) {
7011
+ return writeError2(res, 501, "copilot allowance refresh is not available");
7012
+ }
7013
+ const allowances2 = await service.refreshCopilot(accountId);
7014
+ if (accountId && allowances2.length === 0) {
7015
+ return writeError2(res, 404, `Copilot account '${accountId}' not found`);
7016
+ }
7017
+ return writeJson3(res, 200, { allowances: allowances2 });
7018
+ }
7019
+ if (requestedProvider === "grok") {
7020
+ if (!service.refreshGrok) {
7021
+ return writeError2(res, 501, "grok allowance refresh is not available");
7022
+ }
7023
+ const allowances2 = await service.refreshGrok(accountId);
7024
+ if (accountId && allowances2.length === 0) {
7025
+ return writeError2(res, 404, `Grok account '${accountId}' not found`);
7026
+ }
7027
+ return writeJson3(res, 200, { allowances: allowances2 });
7028
+ }
6257
7029
  const allowances = await service.refreshClaude(accountId);
6258
7030
  if (accountId && allowances.length === 0) {
6259
7031
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
@@ -6352,6 +7124,9 @@ function toProviderView(row) {
6352
7124
  apiVersion: row.apiVersion,
6353
7125
  maxConcurrency: row.maxConcurrency,
6354
7126
  modelsEndpoint: row.modelsEndpoint,
7127
+ // Static extra headers round-trip VERBATIM (non-secret identity values;
7128
+ // auth/content names were already dropped at the write/load gate).
7129
+ extraHeaders: row.extraHeaders,
6355
7130
  // app-parity child 5: transformer config round-trips VERBATIM (non-secret —
6356
7131
  // transform-rule names + options, no key material; absent stays absent).
6357
7132
  transformer: row.transformer,
@@ -6421,8 +7196,8 @@ async function handleAdminApi(req, res, path2, deps) {
6421
7196
  default:
6422
7197
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
6423
7198
  }
6424
- } catch (err6) {
6425
- writeJsonError(res, 500, err6 instanceof Error ? err6.message : String(err6));
7199
+ } catch (err8) {
7200
+ writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
6426
7201
  }
6427
7202
  }
6428
7203
  function requestQuery(req) {
@@ -6580,6 +7355,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
6580
7355
  persistProviders(cfg, deps);
6581
7356
  return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
6582
7357
  }
7358
+ function expandRowExtraHeaders(row) {
7359
+ return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
7360
+ }
6583
7361
  async function handleDiscoverModels(res, id, cfg) {
6584
7362
  if (!id) return writeJsonError(res, 400, "provider id required in path");
6585
7363
  const row = cfg.providers.find((p) => p.id === id);
@@ -6593,7 +7371,8 @@ async function handleDiscoverModels(res, id, cfg) {
6593
7371
  try {
6594
7372
  const headers = { Accept: "application/json" };
6595
7373
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
6596
- const response = await (0, import_upstreamFetch7.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
7374
+ Object.assign(headers, expandRowExtraHeaders(row));
7375
+ const response = await (0, import_upstreamFetch9.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
6597
7376
  if (!response.ok) {
6598
7377
  const text = await response.text().catch(() => "");
6599
7378
  let message = text.slice(0, 300);
@@ -6610,8 +7389,8 @@ async function handleDiscoverModels(res, id, cfg) {
6610
7389
  const data = await response.json();
6611
7390
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
6612
7391
  return writeJson4(res, 200, { models });
6613
- } catch (err6) {
6614
- const message = err6 instanceof Error ? err6.message : String(err6);
7392
+ } catch (err8) {
7393
+ const message = err8 instanceof Error ? err8.message : String(err8);
6615
7394
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
6616
7395
  }
6617
7396
  }
@@ -6650,9 +7429,10 @@ async function handleTestModel(req, res, id, cfg) {
6650
7429
  messages: [{ role: "user", content: prompt }]
6651
7430
  };
6652
7431
  }
7432
+ Object.assign(headers, expandRowExtraHeaders(row));
6653
7433
  const startedAt = Date.now();
6654
7434
  try {
6655
- const response = await (0, import_upstreamFetch7.fetchUpstream)(
7435
+ const response = await (0, import_upstreamFetch9.fetchUpstream)(
6656
7436
  url,
6657
7437
  { method: "POST", headers, body: JSON.stringify(payload) },
6658
7438
  { providerId: "byo" }
@@ -6674,8 +7454,8 @@ async function handleTestModel(req, res, id, cfg) {
6674
7454
  latencyMs,
6675
7455
  sample: extractSampleText(text, row.apiFormat)
6676
7456
  });
6677
- } catch (err6) {
6678
- const message = err6 instanceof Error ? err6.message : String(err6);
7457
+ } catch (err8) {
7458
+ const message = err8 instanceof Error ? err8.message : String(err8);
6679
7459
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
6680
7460
  }
6681
7461
  }
@@ -6957,6 +7737,7 @@ function parseProviderInput(body, existing) {
6957
7737
  const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
6958
7738
  const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
6959
7739
  const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
7740
+ const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
6960
7741
  const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
6961
7742
  const codingPlan = body["codingPlan"] === null ? void 0 : body["codingPlan"] === void 0 ? existing?.codingPlan : body["codingPlan"] && typeof body["codingPlan"] === "object" && !Array.isArray(body["codingPlan"]) ? parseCodingPlanInput(body["codingPlan"], existing?.codingPlan) : existing?.codingPlan;
6962
7743
  const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
@@ -6982,6 +7763,7 @@ function parseProviderInput(body, existing) {
6982
7763
  apiVersion,
6983
7764
  maxConcurrency,
6984
7765
  modelsEndpoint,
7766
+ extraHeaders,
6985
7767
  transformer: migrated.transformer,
6986
7768
  codingPlan,
6987
7769
  apiModes,
@@ -7003,7 +7785,10 @@ function handlePresets(res, method) {
7003
7785
  description: p.description,
7004
7786
  features: p.features,
7005
7787
  website: p.website,
7006
- modelsEndpoint: p.modelsEndpoint
7788
+ modelsEndpoint: p.modelsEndpoint,
7789
+ // Static extra headers ride along so `addFromPreset` can seed them onto the
7790
+ // row (the write gateway re-validates via the shared allowlist).
7791
+ extraHeaders: p.extraHeaders
7007
7792
  }));
7008
7793
  return writeJson4(res, 200, { presets, excluded });
7009
7794
  }
@@ -7485,12 +8270,12 @@ async function handleAccounts(req, res, method, rest, deps) {
7485
8270
  }
7486
8271
  return writeJson4(res, 200, { ok: true, affected: result.affected });
7487
8272
  }
7488
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[3] === "status") {
7489
- const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : handleKimiOAuthStatus(rest[2], deps);
8273
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
8274
+ const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : handleCopilotOAuthStatus(rest[2], deps);
7490
8275
  return writeJson4(res, result.status, result.body);
7491
8276
  }
7492
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[2]) {
7493
- const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : handleKimiOAuthCancel(rest[2], deps);
8277
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
8278
+ const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : handleCopilotOAuthCancel(rest[2], deps);
7494
8279
  return writeJson4(res, result.status, result.body);
7495
8280
  }
7496
8281
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -7551,6 +8336,15 @@ async function handleAccounts(req, res, method, rest, deps) {
7551
8336
  const result2 = await handleKimiOAuthStart(deps);
7552
8337
  return writeJson4(res, result2.status, result2.body);
7553
8338
  }
8339
+ if (providerId === "grok") {
8340
+ const result2 = await handleGrokOAuthStart(deps);
8341
+ return writeJson4(res, result2.status, result2.body);
8342
+ }
8343
+ if (providerId === "copilot") {
8344
+ const body2 = await readJsonBody4(req);
8345
+ const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
8346
+ return writeJson4(res, result2.status, result2.body);
8347
+ }
7554
8348
  const result = handleOAuthStart(providerId, deps);
7555
8349
  return writeJson4(res, result.status, result.body);
7556
8350
  }
@@ -8045,12 +8839,12 @@ async function handlePlayground(req, res, method, deps) {
8045
8839
  const payload = body["body"];
8046
8840
  const status = deps.outboundApiServer.getStatus();
8047
8841
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
8048
- const path2 = resolvePlaygroundPath(endpoint, isRecord4(payload) ? payload : {});
8842
+ const path2 = resolvePlaygroundPath(endpoint, isRecord6(payload) ? payload : {});
8049
8843
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
8050
8844
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
8051
8845
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
8052
8846
  }
8053
- function isRecord4(v) {
8847
+ function isRecord6(v) {
8054
8848
  return !!v && typeof v === "object" && !Array.isArray(v);
8055
8849
  }
8056
8850
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -8079,8 +8873,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
8079
8873
  });
8080
8874
  }
8081
8875
  );
8082
- upstream.on("error", (err6) => {
8083
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err6.message}`);
8876
+ upstream.on("error", (err8) => {
8877
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
8084
8878
  else res.end();
8085
8879
  resolve10();
8086
8880
  });
@@ -8186,7 +8980,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
8186
8980
  }
8187
8981
 
8188
8982
  // src/admin/version.ts
8189
- var DAEMON_VERSION = true ? "0.3.1" : "0.0.0-dev";
8983
+ var DAEMON_VERSION = true ? "0.4.0" : "0.0.0-dev";
8190
8984
 
8191
8985
  // src/admin/AdminServer.ts
8192
8986
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -8229,13 +9023,13 @@ var AdminServer = class {
8229
9023
  const server = import_node_http2.default.createServer((req, res) => {
8230
9024
  this.onRequest(req, res);
8231
9025
  });
8232
- const onError = (err6) => {
8233
- if (err6.code === "EADDRINUSE" && port !== 0) {
9026
+ const onError = (err8) => {
9027
+ if (err8.code === "EADDRINUSE" && port !== 0) {
8234
9028
  server.removeListener("error", onError);
8235
9029
  this.listen(bindAddr, 0).then(resolve10, reject);
8236
9030
  return;
8237
9031
  }
8238
- reject(err6);
9032
+ reject(err8);
8239
9033
  };
8240
9034
  server.on("error", onError);
8241
9035
  server.listen(port, bindAddr, () => {
@@ -8253,8 +9047,8 @@ var AdminServer = class {
8253
9047
  }
8254
9048
  /** Per-request handler: auth gate (when a token is set) → routing. */
8255
9049
  onRequest(req, res) {
8256
- void this.dispatch(req, res).catch((err6) => {
8257
- const message = err6 instanceof Error ? err6.message : String(err6);
9050
+ void this.dispatch(req, res).catch((err8) => {
9051
+ const message = err8 instanceof Error ? err8.message : String(err8);
8258
9052
  this.deps.logger.error("[AdminServer] unhandled error:", message);
8259
9053
  if (!res.headersSent) {
8260
9054
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -8518,18 +9312,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
8518
9312
  return;
8519
9313
  }
8520
9314
  signal?.addEventListener("abort", abort, { once: true });
8521
- server.on("error", (err6) => {
9315
+ server.on("error", (err8) => {
8522
9316
  if (settled) return;
8523
9317
  settled = true;
8524
9318
  clearTimeout(timer);
8525
- if (err6.code === "EADDRINUSE") {
9319
+ if (err8.code === "EADDRINUSE") {
8526
9320
  reject(
8527
9321
  new Error(
8528
9322
  `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
8529
9323
  )
8530
9324
  );
8531
9325
  } else {
8532
- reject(err6);
9326
+ reject(err8);
8533
9327
  }
8534
9328
  });
8535
9329
  const timer = setTimeout(() => {
@@ -8605,21 +9399,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
8605
9399
  }
8606
9400
 
8607
9401
  // src/allowance/ProviderKeyQuotaService.ts
8608
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
9402
+ var import_core4 = require("@omnicross/core");
9403
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
8609
9404
 
8610
9405
  // src/allowance/ProviderKeyQuota.ts
8611
- var MINUTE_MS2 = 6e4;
8612
- var HOUR_MS2 = 60 * MINUTE_MS2;
8613
- var DAY_MS2 = 24 * HOUR_MS2;
8614
- var WEEK_MS = 7 * DAY_MS2;
8615
- var MONTH_MS = 30 * DAY_MS2;
8616
- function finiteNumber3(value) {
9406
+ var MINUTE_MS3 = 6e4;
9407
+ var HOUR_MS2 = 60 * MINUTE_MS3;
9408
+ var DAY_MS3 = 24 * HOUR_MS2;
9409
+ var WEEK_MS = 7 * DAY_MS3;
9410
+ var MONTH_MS = 30 * DAY_MS3;
9411
+ function finiteNumber5(value) {
8617
9412
  if (value === null || value === void 0 || value === "") return void 0;
8618
9413
  const parsed = typeof value === "number" ? value : Number(value);
8619
9414
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
8620
9415
  }
8621
9416
  function finitePercent4(value) {
8622
- const parsed = finiteNumber3(value);
9417
+ const parsed = finiteNumber5(value);
8623
9418
  return parsed !== void 0 && parsed <= 100 ? parsed : null;
8624
9419
  }
8625
9420
  function isoInstant3(value) {
@@ -8627,18 +9422,18 @@ function isoInstant3(value) {
8627
9422
  const time = Date.parse(value);
8628
9423
  if (Number.isFinite(time)) return new Date(time).toISOString();
8629
9424
  }
8630
- const numeric = finiteNumber3(value);
9425
+ const numeric = finiteNumber5(value);
8631
9426
  if (numeric !== void 0 && numeric > 1e9) {
8632
9427
  const ms = numeric > 1e12 ? numeric : numeric * 1e3;
8633
9428
  return new Date(ms).toISOString();
8634
9429
  }
8635
9430
  return void 0;
8636
9431
  }
8637
- function secondsUntil5(instant, now) {
9432
+ function secondsUntil7(instant, now) {
8638
9433
  if (!instant) return void 0;
8639
9434
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
8640
9435
  }
8641
- function isRecord5(value) {
9436
+ function isRecord7(value) {
8642
9437
  return !!value && typeof value === "object" && !Array.isArray(value);
8643
9438
  }
8644
9439
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -8661,6 +9456,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
8661
9456
  }
8662
9457
  if (host === "api.code.umans.ai") return "umans";
8663
9458
  if (host === "api.synthetic.new") return "synthetic";
9459
+ if (host === "api.cline.bot") return "cline-pass";
8664
9460
  return null;
8665
9461
  }
8666
9462
  function providerKeyQuotaUrl(adapter, baseUrl) {
@@ -8668,6 +9464,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
8668
9464
  if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
8669
9465
  if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
8670
9466
  if (adapter === "umans") return `${origin}/v1/usage`;
9467
+ if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
8671
9468
  return `${origin}/v2/quotas`;
8672
9469
  }
8673
9470
  function providerKeyQuotaAuthHeader(adapter, key) {
@@ -8679,7 +9476,7 @@ function zaiWindowDurationMs(item) {
8679
9476
  case 3:
8680
9477
  return count * HOUR_MS2;
8681
9478
  case 4:
8682
- return count * DAY_MS2;
9479
+ return count * DAY_MS3;
8683
9480
  case 5:
8684
9481
  return count * MONTH_MS;
8685
9482
  case 6:
@@ -8692,8 +9489,8 @@ function zaiWindowIdLabel(durationMs) {
8692
9489
  if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
8693
9490
  if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
8694
9491
  if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
8695
- if (durationMs !== void 0 && durationMs % DAY_MS2 === 0) {
8696
- const days = durationMs / DAY_MS2;
9492
+ if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
9493
+ const days = durationMs / DAY_MS3;
8697
9494
  return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
8698
9495
  }
8699
9496
  if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
@@ -8703,23 +9500,23 @@ function zaiWindowIdLabel(durationMs) {
8703
9500
  return { id: "quota", label: "Quota" };
8704
9501
  }
8705
9502
  function parseZaiQuotaPayload(payload, now) {
8706
- if (!isRecord5(payload)) return null;
8707
- const data = isRecord5(payload["data"]) ? payload["data"] : payload;
9503
+ if (!isRecord7(payload)) return null;
9504
+ const data = isRecord7(payload["data"]) ? payload["data"] : payload;
8708
9505
  if (payload["success"] === false) return null;
8709
9506
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
8710
9507
  const byWindow = /* @__PURE__ */ new Map();
8711
9508
  for (const raw of limits) {
8712
- if (!isRecord5(raw)) continue;
9509
+ if (!isRecord7(raw)) continue;
8713
9510
  const item = raw;
8714
9511
  if (item.type === void 0) continue;
8715
9512
  const details = raw["usageDetails"];
8716
- if (Array.isArray(details) && details.some((d) => isRecord5(d) && d["modelCode"] === "zread")) {
9513
+ if (Array.isArray(details) && details.some((d) => isRecord7(d) && d["modelCode"] === "zread")) {
8717
9514
  continue;
8718
9515
  }
8719
9516
  const durationMs = zaiWindowDurationMs(item);
8720
9517
  const { id, label } = zaiWindowIdLabel(durationMs);
8721
- const limit = finiteNumber3(item.usage);
8722
- const used = finiteNumber3(item.currentValue);
9518
+ const limit = finiteNumber5(item.usage);
9519
+ const used = finiteNumber5(item.currentValue);
8723
9520
  const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
8724
9521
  const fromPercentage = finitePercent4(item.percentage) ?? void 0;
8725
9522
  const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
@@ -8730,9 +9527,9 @@ function parseZaiQuotaPayload(payload, now) {
8730
9527
  label,
8731
9528
  scope: "all",
8732
9529
  usedPercent,
8733
- ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS2) } : {},
9530
+ ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
8734
9531
  ...resetsAt !== void 0 ? { resetsAt } : {},
8735
- remainingSeconds: secondsUntil5(resetsAt, now),
9532
+ remainingSeconds: secondsUntil7(resetsAt, now),
8736
9533
  state: "fresh"
8737
9534
  };
8738
9535
  const existing = byWindow.get(id);
@@ -8746,21 +9543,21 @@ function parseZaiQuotaPayload(payload, now) {
8746
9543
  var MINIMAX_STATUS_EXHAUSTED = 2;
8747
9544
  var MINIMAX_SHARED_BUCKET = "general";
8748
9545
  function parseMiniMaxBucket(value) {
8749
- if (!isRecord5(value)) return null;
9546
+ if (!isRecord7(value)) return null;
8750
9547
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
8751
9548
  if (!modelName) return null;
8752
9549
  const instant = (v) => {
8753
- const n = finiteNumber3(v);
9550
+ const n = finiteNumber5(v);
8754
9551
  return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
8755
9552
  };
8756
9553
  return {
8757
9554
  modelName,
8758
9555
  intervalEnd: instant(value["end_time"]),
8759
- intervalRemainingPercent: finiteNumber3(value["current_interval_remaining_percent"]),
8760
- intervalStatus: finiteNumber3(value["current_interval_status"]),
9556
+ intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
9557
+ intervalStatus: finiteNumber5(value["current_interval_status"]),
8761
9558
  weeklyEnd: instant(value["weekly_end_time"]),
8762
- weeklyRemainingPercent: finiteNumber3(value["current_weekly_remaining_percent"]),
8763
- weeklyStatus: finiteNumber3(value["current_weekly_status"])
9559
+ weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
9560
+ weeklyStatus: finiteNumber5(value["current_weekly_status"])
8764
9561
  };
8765
9562
  }
8766
9563
  function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
@@ -8773,14 +9570,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
8773
9570
  usedPercent,
8774
9571
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
8775
9572
  ...resetsAt !== void 0 ? { resetsAt } : {},
8776
- remainingSeconds: secondsUntil5(resetsAt, now),
9573
+ remainingSeconds: secondsUntil7(resetsAt, now),
8777
9574
  state: usedPercent !== null ? "fresh" : "unavailable"
8778
9575
  };
8779
9576
  }
8780
9577
  function parseMiniMaxTokenPlanPayload(payload, now) {
8781
- if (!isRecord5(payload)) return null;
9578
+ if (!isRecord7(payload)) return null;
8782
9579
  const baseResp = payload["base_resp"];
8783
- if (!isRecord5(baseResp) || baseResp["status_code"] !== 0) return null;
9580
+ if (!isRecord7(baseResp) || baseResp["status_code"] !== 0) return null;
8784
9581
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
8785
9582
  let general = null;
8786
9583
  for (const raw of buckets) {
@@ -8804,7 +9601,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
8804
9601
  minimaxWindow(
8805
9602
  "seven-day",
8806
9603
  "7 days",
8807
- Math.round(WEEK_MS / MINUTE_MS2),
9604
+ Math.round(WEEK_MS / MINUTE_MS3),
8808
9605
  general.weeklyEnd,
8809
9606
  general.weeklyRemainingPercent,
8810
9607
  general.weeklyStatus,
@@ -8813,15 +9610,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
8813
9610
  ];
8814
9611
  }
8815
9612
  function parseUmansUsagePayload(payload, now) {
8816
- if (!isRecord5(payload)) return null;
8817
- const limits = isRecord5(payload["limits"]) ? payload["limits"] : void 0;
8818
- const requests = limits && isRecord5(limits["requests"]) ? limits["requests"] : void 0;
8819
- const usage = isRecord5(payload["usage"]) ? payload["usage"] : void 0;
8820
- const window = isRecord5(payload["window"]) ? payload["window"] : void 0;
8821
- const hardCap = finiteNumber3(requests?.["hard_cap"]);
8822
- const softLimit = finiteNumber3(requests?.["limit"]);
8823
- const requestsInWindow = finiteNumber3(usage?.["requests_in_window"]);
8824
- const weightedInWindow = finiteNumber3(usage?.["weighted_in_window"]);
9613
+ if (!isRecord7(payload)) return null;
9614
+ const limits = isRecord7(payload["limits"]) ? payload["limits"] : void 0;
9615
+ const requests = limits && isRecord7(limits["requests"]) ? limits["requests"] : void 0;
9616
+ const usage = isRecord7(payload["usage"]) ? payload["usage"] : void 0;
9617
+ const window = isRecord7(payload["window"]) ? payload["window"] : void 0;
9618
+ const hardCap = finiteNumber5(requests?.["hard_cap"]);
9619
+ const softLimit = finiteNumber5(requests?.["limit"]);
9620
+ const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
9621
+ const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
8825
9622
  const resetsAt = isoInstant3(window?.["resets_at"]);
8826
9623
  let usedPercent = null;
8827
9624
  if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
@@ -8838,19 +9635,19 @@ function parseUmansUsagePayload(payload, now) {
8838
9635
  usedPercent,
8839
9636
  windowMinutes: 5 * 60,
8840
9637
  ...resetsAt !== void 0 ? { resetsAt } : {},
8841
- remainingSeconds: secondsUntil5(resetsAt, now),
9638
+ remainingSeconds: secondsUntil7(resetsAt, now),
8842
9639
  state: "fresh"
8843
9640
  }
8844
9641
  ];
8845
9642
  }
8846
9643
  function parseSyntheticQuotasPayload(payload, now) {
8847
- if (!isRecord5(payload)) return null;
8848
- const fiveHour = isRecord5(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
8849
- const weekly = isRecord5(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
9644
+ if (!isRecord7(payload)) return null;
9645
+ const fiveHour = isRecord7(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
9646
+ const weekly = isRecord7(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
8850
9647
  const windows = [];
8851
9648
  if (fiveHour) {
8852
- const max = finiteNumber3(fiveHour["max"]);
8853
- const remaining = finiteNumber3(fiveHour["remaining"]);
9649
+ const max = finiteNumber5(fiveHour["max"]);
9650
+ const remaining = finiteNumber5(fiveHour["remaining"]);
8854
9651
  const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
8855
9652
  const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
8856
9653
  windows.push({
@@ -8860,12 +9657,12 @@ function parseSyntheticQuotasPayload(payload, now) {
8860
9657
  usedPercent,
8861
9658
  windowMinutes: 5 * 60,
8862
9659
  ...resetsAt !== void 0 ? { resetsAt } : {},
8863
- remainingSeconds: secondsUntil5(resetsAt, now),
9660
+ remainingSeconds: secondsUntil7(resetsAt, now),
8864
9661
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
8865
9662
  });
8866
9663
  }
8867
9664
  if (weekly) {
8868
- const percentRemaining = finiteNumber3(weekly["percentRemaining"]);
9665
+ const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
8869
9666
  const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
8870
9667
  const resetsAt = isoInstant3(weekly["nextRegenAt"]);
8871
9668
  windows.push({
@@ -8875,12 +9672,42 @@ function parseSyntheticQuotasPayload(payload, now) {
8875
9672
  usedPercent,
8876
9673
  windowMinutes: 7 * 24 * 60,
8877
9674
  ...resetsAt !== void 0 ? { resetsAt } : {},
8878
- remainingSeconds: secondsUntil5(resetsAt, now),
9675
+ remainingSeconds: secondsUntil7(resetsAt, now),
8879
9676
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
8880
9677
  });
8881
9678
  }
8882
9679
  return windows.length > 0 ? windows : null;
8883
9680
  }
9681
+ var CLINE_WINDOW_CONFIG = {
9682
+ five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
9683
+ weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
9684
+ monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
9685
+ };
9686
+ function parseClinePassUsageLimitsPayload(payload, now) {
9687
+ if (!isRecord7(payload)) return null;
9688
+ const data = isRecord7(payload["data"]) ? payload["data"] : payload;
9689
+ const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9690
+ const windows = [];
9691
+ for (const raw of limits) {
9692
+ if (!isRecord7(raw)) continue;
9693
+ const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
9694
+ if (!config) continue;
9695
+ const usedPercent = finitePercent4(raw["percentUsed"]);
9696
+ if (usedPercent === null) continue;
9697
+ const resetsAt = isoInstant3(raw["resetsAt"]);
9698
+ windows.push({
9699
+ id: config.id,
9700
+ label: config.label,
9701
+ scope: "all",
9702
+ usedPercent,
9703
+ windowMinutes: config.minutes,
9704
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9705
+ remainingSeconds: secondsUntil7(resetsAt, now),
9706
+ state: "fresh"
9707
+ });
9708
+ }
9709
+ return windows.length > 0 ? windows : null;
9710
+ }
8884
9711
 
8885
9712
  // src/allowance/ProviderKeyQuotaService.ts
8886
9713
  function parseQuotaPayload(adapter, payload, now) {
@@ -8893,6 +9720,8 @@ function parseQuotaPayload(adapter, payload, now) {
8893
9720
  return parseUmansUsagePayload(payload, now);
8894
9721
  case "synthetic":
8895
9722
  return parseSyntheticQuotasPayload(payload, now);
9723
+ case "cline-pass":
9724
+ return parseClinePassUsageLimitsPayload(payload, now);
8896
9725
  }
8897
9726
  }
8898
9727
  var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
@@ -8912,7 +9741,7 @@ function rowKeyEntries(row) {
8912
9741
  return [];
8913
9742
  }
8914
9743
  var ProviderKeyQuotaService = class {
8915
- constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
9744
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
8916
9745
  this.box = box;
8917
9746
  this.fetchImpl = fetchImpl;
8918
9747
  this.now = now;
@@ -8974,7 +9803,10 @@ var ProviderKeyQuotaService = class {
8974
9803
  headers: {
8975
9804
  Authorization: providerKeyQuotaAuthHeader(adapter, key),
8976
9805
  Accept: "application/json",
8977
- "Content-Type": "application/json"
9806
+ "Content-Type": "application/json",
9807
+ // The row's static identity headers ride along — the Cline usage
9808
+ // endpoint sits behind the SAME client-identity 403 gate as inference.
9809
+ ...(0, import_core4.mergeExtraHeaders)({}, row.extraHeaders)
8978
9810
  },
8979
9811
  signal: AbortSignal.timeout(15e3)
8980
9812
  });
@@ -9045,7 +9877,7 @@ function defaultBillingDir(configPath) {
9045
9877
  // src/image-generation/ImageDoctorService.ts
9046
9878
  var import_image_generation = require("@omnicross/core/image-generation");
9047
9879
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
9048
- var import_subscriptions6 = require("@omnicross/subscriptions");
9880
+ var import_subscriptions9 = require("@omnicross/subscriptions");
9049
9881
 
9050
9882
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
9051
9883
  var import_node_crypto13 = require("crypto");
@@ -9483,7 +10315,7 @@ function createImageDoctorService(options) {
9483
10315
  paths,
9484
10316
  ttlMs: config.evidenceTtlMs
9485
10317
  }));
9486
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions6.createCodexImageLiveVerifier)({
10318
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
9487
10319
  authStrategy: strategy,
9488
10320
  generationTimeoutMs: config.queue.generationTimeoutMs
9489
10321
  }));
@@ -9845,7 +10677,7 @@ var ImageCleanupService = class {
9845
10677
  var import_node_crypto16 = require("crypto");
9846
10678
  var import_image_generation5 = require("@omnicross/core/image-generation");
9847
10679
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
9848
- var import_subscriptions7 = require("@omnicross/subscriptions");
10680
+ var import_subscriptions10 = require("@omnicross/subscriptions");
9849
10681
 
9850
10682
  // src/image-generation/ImageApiRuntimeResolver.ts
9851
10683
  var import_node_crypto14 = require("crypto");
@@ -10376,7 +11208,7 @@ function createImageRuntimeGeneration(options) {
10376
11208
  now: options.now ?? Date.now,
10377
11209
  referenceStore: options.storage.referenceStore,
10378
11210
  stateStore: options.storage.stateStore
10379
- }) : (0, import_subscriptions7.createCodexSubscriptionImageProvider)({
11211
+ }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
10380
11212
  authStrategy,
10381
11213
  evidenceSource: generationEvidenceSource,
10382
11214
  executionScheduler: scheduler,
@@ -13520,7 +14352,7 @@ var ImageRuntimeManager = class {
13520
14352
  };
13521
14353
 
13522
14354
  // src/ports/ConfigFileProviderConfigSource.ts
13523
- var import_core2 = require("@omnicross/core");
14355
+ var import_core5 = require("@omnicross/core");
13524
14356
  var EMPTY_CHAIN = {
13525
14357
  providerTransformers: [],
13526
14358
  modelTransformers: []
@@ -13545,8 +14377,8 @@ var ConfigFileProviderConfigSource = class {
13545
14377
  reloadHook;
13546
14378
  constructor(config) {
13547
14379
  for (const p of config.providers) this.providers.set(p.id, p);
13548
- this.transformerService = new import_core2.TransformerService();
13549
- void (0, import_core2.registerBuiltinTransformers)(this.transformerService);
14380
+ this.transformerService = new import_core5.TransformerService();
14381
+ void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
13550
14382
  }
13551
14383
  // ── Reload hook (key-pool design D4) ───────────────────────────────────────
13552
14384
  /**
@@ -13567,7 +14399,7 @@ var ConfigFileProviderConfigSource = class {
13567
14399
  }
13568
14400
  /** Await the built-in transformer registration (tests await this before dispatch). */
13569
14401
  async ready() {
13570
- await (0, import_core2.registerBuiltinTransformers)(this.transformerService);
14402
+ await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
13571
14403
  }
13572
14404
  // ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
13573
14405
  /**
@@ -13678,6 +14510,10 @@ function toLLMProvider(row) {
13678
14510
  // `parseProviderInput`), so customizations are preserved (the row value wins).
13679
14511
  apiModes: row.apiModes,
13680
14512
  selectedApiModeId: row.selectedApiModeId,
14513
+ // Static extra request headers ride along verbatim (load-guarded — no
14514
+ // auth/content names); core's `getProviderHeaders` merges them into every
14515
+ // BYO request, and the same-format relay path inherits that funnel.
14516
+ extraHeaders: row.extraHeaders,
13681
14517
  // Official-Anthropic signature handling only matters for the Anthropic
13682
14518
  // ingress (deferred → 502); leave it off for the BYO transform path.
13683
14519
  isOfficial: false
@@ -15043,7 +15879,7 @@ function bucketLabel(bucketStartTs, bucket) {
15043
15879
 
15044
15880
  // src/ports/JsonOutboundKeyDb.ts
15045
15881
  var import_node_fs19 = require("fs");
15046
- var import_core3 = require("@omnicross/core");
15882
+ var import_core6 = require("@omnicross/core");
15047
15883
 
15048
15884
  // src/ports/atomicFile.ts
15049
15885
  var import_node_crypto22 = require("crypto");
@@ -15165,7 +16001,7 @@ var JsonOutboundKeyDb = class {
15165
16001
  });
15166
16002
  }
15167
16003
  async outboundApiKeysSetPermissions(id, permissions) {
15168
- const exact = (0, import_core3.validateOutboundPermissions)(permissions);
16004
+ const exact = (0, import_core6.validateOutboundPermissions)(permissions);
15169
16005
  return this.mutateRow(id, (row) => {
15170
16006
  if (row.revokedAt !== null) return false;
15171
16007
  row.allowedEndpoints = [...exact];
@@ -15602,9 +16438,9 @@ var import_node_fs24 = require("fs");
15602
16438
  var import_node_path24 = require("path");
15603
16439
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
15604
16440
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
15605
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
16441
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
15606
16442
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
15607
- var import_subscriptions8 = require("@omnicross/subscriptions");
16443
+ var import_subscriptions11 = require("@omnicross/subscriptions");
15608
16444
 
15609
16445
  // src/ports/account-sync.ts
15610
16446
  function viewOf(tokens) {
@@ -15752,7 +16588,7 @@ var JsonSubscriptionCredentialStore = class {
15752
16588
  * a plaintext token pair into `upstream-trace.jsonl`.
15753
16589
  */
15754
16590
  buildRefreshFetch(providerId, accountId) {
15755
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
16591
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
15756
16592
  }
15757
16593
  /**
15758
16594
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -15793,7 +16629,7 @@ var JsonSubscriptionCredentialStore = class {
15793
16629
  * other hot reads. Never returns token material.
15794
16630
  */
15795
16631
  getAccountProxy(providerId, accountId) {
15796
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
16632
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
15797
16633
  return void 0;
15798
16634
  }
15799
16635
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -15812,7 +16648,7 @@ var JsonSubscriptionCredentialStore = class {
15812
16648
  const fingerprintOn = identityStore.isEnabled();
15813
16649
  const now = Date.now();
15814
16650
  const out = {};
15815
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
16651
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
15816
16652
  const sanitized = sanitizeAccounts(config, provider);
15817
16653
  if (sanitized.length === 0) continue;
15818
16654
  for (const account of sanitized) {
@@ -15878,7 +16714,7 @@ var JsonSubscriptionCredentialStore = class {
15878
16714
  this.materializeMigration(config);
15879
16715
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
15880
16716
  try {
15881
- const result = await import_subscriptions8.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
16717
+ const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
15882
16718
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15883
16719
  const next = {
15884
16720
  ...claude,
@@ -15913,7 +16749,7 @@ var JsonSubscriptionCredentialStore = class {
15913
16749
  this.materializeMigration(config);
15914
16750
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
15915
16751
  try {
15916
- const result = await import_subscriptions8.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
16752
+ const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
15917
16753
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15918
16754
  const next = {
15919
16755
  ...codex,
@@ -15951,7 +16787,7 @@ var JsonSubscriptionCredentialStore = class {
15951
16787
  this.materializeMigration(config);
15952
16788
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
15953
16789
  try {
15954
- const result = await import_subscriptions8.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
16790
+ const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
15955
16791
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15956
16792
  const next = {
15957
16793
  ...gemini,
@@ -15987,10 +16823,10 @@ var JsonSubscriptionCredentialStore = class {
15987
16823
  this.materializeMigration(config);
15988
16824
  const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
15989
16825
  try {
15990
- const result = await import_subscriptions8.kimiOAuth.refreshAccessToken(
16826
+ const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
15991
16827
  kimi.refreshToken,
15992
16828
  refreshFetch,
15993
- import_subscriptions8.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
16829
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
15994
16830
  );
15995
16831
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
15996
16832
  const next = {
@@ -16011,6 +16847,66 @@ var JsonSubscriptionCredentialStore = class {
16011
16847
  }
16012
16848
  });
16013
16849
  }
16850
+ /**
16851
+ * Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
16852
+ * resolved through OIDC discovery on every refresh (process-cached 1h by the
16853
+ * flow module) so a rotated endpoint document is picked up without a daemon
16854
+ * restart. HONEST `false` when no refresh_token.
16855
+ */
16856
+ async refreshGrokToken() {
16857
+ return this.coalesce("grok:active", async () => {
16858
+ const config = this.readConfig();
16859
+ const active = getActiveAccount(config, "grok");
16860
+ const grok = active?.tokens;
16861
+ if (!active || !grok?.refreshToken) return false;
16862
+ const capturedId = active.id;
16863
+ this.materializeMigration(config);
16864
+ const refreshFetch = this.buildRefreshFetch("grok", capturedId);
16865
+ try {
16866
+ const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
16867
+ const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
16868
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16869
+ const next = {
16870
+ ...grok,
16871
+ accessToken: result.accessToken,
16872
+ refreshToken: result.refreshToken,
16873
+ expiresAt,
16874
+ status: "authorized",
16875
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
16876
+ errorMessage: void 0,
16877
+ syncWarning: void 0
16878
+ };
16879
+ this.writeBackById("grok", capturedId, next);
16880
+ return true;
16881
+ } catch (error) {
16882
+ this.markExpiredById("grok", capturedId, grok, error);
16883
+ return false;
16884
+ }
16885
+ });
16886
+ }
16887
+ /**
16888
+ * "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
16889
+ * tokens are long-lived with no exchange endpoint). A call here means the
16890
+ * strategy saw a 401 (the token was revoked); mark the account `expired`
16891
+ * with a re-authenticate message and return `false` (the proxy then declines
16892
+ * the retry instead of looping on a dead token).
16893
+ */
16894
+ async refreshCopilotToken() {
16895
+ return this.coalesce("copilot:active", async () => {
16896
+ const config = this.readConfig();
16897
+ const active = getActiveAccount(config, "copilot");
16898
+ const copilot = active?.tokens;
16899
+ if (!active || !copilot?.accessToken) return false;
16900
+ this.materializeMigration(config);
16901
+ this.markExpiredById(
16902
+ "copilot",
16903
+ active.id,
16904
+ copilot,
16905
+ new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
16906
+ );
16907
+ return false;
16908
+ });
16909
+ }
16014
16910
  /**
16015
16911
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
16016
16912
  * account-pool resolution). It uses only that account's stored refresh
@@ -16063,7 +16959,7 @@ var JsonSubscriptionCredentialStore = class {
16063
16959
  }
16064
16960
  const oauth = account.tokens;
16065
16961
  if (!oauth.accessToken) return null;
16066
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
16962
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
16067
16963
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
16068
16964
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
16069
16965
  if (expiringSoon && oauth.refreshToken) {
@@ -16156,10 +17052,10 @@ var JsonSubscriptionCredentialStore = class {
16156
17052
  if (provider === "kimi") {
16157
17053
  const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
16158
17054
  const deviceId = account?.tokens?.deviceId;
16159
- const r2 = await import_subscriptions8.kimiOAuth.refreshAccessToken(
17055
+ const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
16160
17056
  refreshToken,
16161
17057
  refreshFetch,
16162
- import_subscriptions8.kimiOAuth.kimiFingerprintHeaders(deviceId)
17058
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
16163
17059
  );
16164
17060
  return {
16165
17061
  accessToken: r2.accessToken,
@@ -16167,7 +17063,19 @@ var JsonSubscriptionCredentialStore = class {
16167
17063
  expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
16168
17064
  };
16169
17065
  }
16170
- const flow = provider === "claude" ? import_subscriptions8.claudeOAuth : provider === "codex" ? import_subscriptions8.codexOAuth : import_subscriptions8.geminiOAuth;
17066
+ if (provider === "grok") {
17067
+ const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17068
+ const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
17069
+ return {
17070
+ accessToken: r2.accessToken,
17071
+ refreshToken: r2.refreshToken,
17072
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17073
+ };
17074
+ }
17075
+ if (provider === "copilot") {
17076
+ throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
17077
+ }
17078
+ const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
16171
17079
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
16172
17080
  return {
16173
17081
  accessToken: r.accessToken,
@@ -16410,7 +17318,7 @@ var JsonSubscriptionCredentialStore = class {
16410
17318
  };
16411
17319
 
16412
17320
  // src/AccountHealthProbeScheduler.ts
16413
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
17321
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
16414
17322
 
16415
17323
  // src/probe/CodexGenerationProbe.ts
16416
17324
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -16553,7 +17461,16 @@ var PROVIDER_PROBE_PLANS = {
16553
17461
  // Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
16554
17462
  // collector uses it), but the probe path also needs the fingerprint headers —
16555
17463
  // keep the probe local until the collector covers the health surface.
16556
- kimi: { kind: "local" }
17464
+ kimi: { kind: "local" },
17465
+ // Grok's billing proxy is a verified FREE authed GET (the allowance collector
17466
+ // uses it) but it REJECTS non-OAuth credentials and sits on a separate host
17467
+ // with its own product-gate header — keep the probe local, the collector
17468
+ // owns the health surface.
17469
+ grok: { kind: "local" },
17470
+ // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
17471
+ // authed GET but lives on api.github.com with its own auth dialect and a
17472
+ // monthly-only window — the allowance collector owns the health surface.
17473
+ copilot: { kind: "local" }
16557
17474
  };
16558
17475
  function probePlanFor(providerId) {
16559
17476
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -16575,7 +17492,7 @@ var AccountHealthProbeScheduler = class {
16575
17492
  this.logger = logger;
16576
17493
  this.config = config;
16577
17494
  this.now = opts.now ?? Date.now;
16578
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch10.fetchUpstream;
17495
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch12.fetchUpstream;
16579
17496
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
16580
17497
  this.planFor = opts.planFor ?? probePlanFor;
16581
17498
  }
@@ -17476,7 +18393,7 @@ async function readAuditStats(auditDir, query2 = {}) {
17476
18393
  }
17477
18394
 
17478
18395
  // src/audit/AuditPruneSweeper.ts
17479
- var DAY_MS3 = 24 * 60 * 6e4;
18396
+ var DAY_MS4 = 24 * 60 * 6e4;
17480
18397
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
17481
18398
  var ARCHIVE_BATCH = 64;
17482
18399
  var AuditPruneSweeper = class {
@@ -17540,7 +18457,7 @@ var AuditPruneSweeper = class {
17540
18457
  this.sweeping = true;
17541
18458
  try {
17542
18459
  if (!(0, import_node_fs27.existsSync)(this.auditDir)) return 0;
17543
- const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS3;
18460
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
17544
18461
  let removed = 0;
17545
18462
  for (const name of (0, import_node_fs27.readdirSync)(this.auditDir)) {
17546
18463
  const dateMs = auditFileDateMs(name);
@@ -17797,7 +18714,7 @@ async function closeAll(writers) {
17797
18714
  // src/usage/UsagePruneSweeper.ts
17798
18715
  var import_promises8 = require("fs/promises");
17799
18716
  var import_node_path29 = require("path");
17800
- var DAY_MS4 = 24 * 60 * 6e4;
18717
+ var DAY_MS5 = 24 * 60 * 6e4;
17801
18718
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
17802
18719
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
17803
18720
  var UsagePruneSweeper = class {
@@ -17854,7 +18771,7 @@ var UsagePruneSweeper = class {
17854
18771
  this.sweeping = true;
17855
18772
  try {
17856
18773
  const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
17857
- const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS4;
18774
+ const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
17858
18775
  let removed = 0;
17859
18776
  for (const entry of await listUsageDays(this.usageDir)) {
17860
18777
  if (!entry.hasShard) continue;
@@ -18273,7 +19190,7 @@ var AuditWriter = class {
18273
19190
  var import_node_fs33 = require("fs");
18274
19191
  var import_node_crypto24 = require("crypto");
18275
19192
  var import_node_path33 = require("path");
18276
- var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
19193
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
18277
19194
 
18278
19195
  // src/billing/billingFiles.ts
18279
19196
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -18296,7 +19213,7 @@ var BillingPublisher = class {
18296
19213
  constructor(billingDir, logger, opts = {}) {
18297
19214
  this.billingDir = billingDir;
18298
19215
  this.logger = logger;
18299
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init));
19216
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init));
18300
19217
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
18301
19218
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
18302
19219
  this.now = opts.now ?? Date.now;
@@ -18546,7 +19463,7 @@ var BillingRetrySweeper = class {
18546
19463
  // src/TokenRefreshScheduler.ts
18547
19464
  var REFRESH_LEAD_MS2 = 5 * 6e4;
18548
19465
  var SWEEP_INTERVAL_MS5 = 6e4;
18549
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
19466
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
18550
19467
  var TokenRefreshScheduler = class {
18551
19468
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
18552
19469
  this.store = store;
@@ -18631,6 +19548,12 @@ var TokenRefreshScheduler = class {
18631
19548
  return this.store.refreshGeminiToken();
18632
19549
  case "kimi":
18633
19550
  return this.store.refreshKimiToken();
19551
+ case "grok":
19552
+ return this.store.refreshGrokToken();
19553
+ // ghu_ tokens never near-expire (far-future expiresAt), so the sweep
19554
+ // never reaches this — the branch exists for union totality.
19555
+ case "copilot":
19556
+ return this.store.refreshCopilotToken();
18634
19557
  }
18635
19558
  }
18636
19559
  };
@@ -18707,7 +19630,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
18707
19630
 
18708
19631
  // src/webhook/WebhookDispatcher.ts
18709
19632
  var import_node_crypto25 = require("crypto");
18710
- var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
19633
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
18711
19634
  var WEBHOOK_MAX_ATTEMPTS = 3;
18712
19635
  var WEBHOOK_QUEUE_MAX = 1e3;
18713
19636
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -18727,7 +19650,7 @@ var WebhookDispatcher = class {
18727
19650
  sleep;
18728
19651
  now;
18729
19652
  constructor(opts = {}) {
18730
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init));
19653
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
18731
19654
  this.logger = opts.logger;
18732
19655
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
18733
19656
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -18813,8 +19736,8 @@ var WebhookDispatcher = class {
18813
19736
  signal: AbortSignal.timeout(this.timeoutMs)
18814
19737
  });
18815
19738
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
18816
- } catch (err6) {
18817
- return { ok: false, error: err6 instanceof Error ? err6.message : String(err6) };
19739
+ } catch (err8) {
19740
+ return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
18818
19741
  }
18819
19742
  }
18820
19743
  /**
@@ -18877,7 +19800,7 @@ function feishuText(event) {
18877
19800
  // src/bootstrap.ts
18878
19801
  var activeImageRuntimeBootstrapSession;
18879
19802
  function createImageRuntimeBootstrapSession(initialGeneration) {
18880
- const openAIOperationRegistry = new import_core4.OpenAIOperationRegistry();
19803
+ const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
18881
19804
  const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
18882
19805
  const unregisterContributions = [];
18883
19806
  try {
@@ -18956,12 +19879,12 @@ function buildDaemon(config, paths) {
18956
19879
  setSecretBox(secretBox3);
18957
19880
  setSecretBox2(secretBox3);
18958
19881
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
18959
- const accountAllowanceStore = new import_AccountAllowanceStore7.AccountAllowanceStore(
19882
+ const accountAllowanceStore = new import_AccountAllowanceStore9.AccountAllowanceStore(
18960
19883
  Date.now,
18961
19884
  void 0,
18962
19885
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
18963
19886
  );
18964
- (0, import_AccountAllowanceStore7.setSharedAccountAllowanceStore)(accountAllowanceStore);
19887
+ (0, import_AccountAllowanceStore9.setSharedAccountAllowanceStore)(accountAllowanceStore);
18965
19888
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
18966
19889
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
18967
19890
  );
@@ -18986,15 +19909,15 @@ function buildDaemon(config, paths) {
18986
19909
  claudeAllowanceRefreshScheduler.configure(
18987
19910
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
18988
19911
  );
18989
- const subscriptionAccounts = new import_subscriptions9.SubscriptionAccountService(credentialStore);
18990
- (0, import_subscriptions9.setSubscriptionAccountService)(subscriptionAccounts);
18991
- const subscriptionRegistry = new import_subscriptions9.SubscriptionProviderRegistry(
19912
+ const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
19913
+ (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
19914
+ const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
18992
19915
  subscriptionAccounts,
18993
19916
  credentialStore
18994
19917
  );
18995
- (0, import_subscriptions9.setSubscriptionProviderRegistry)(subscriptionRegistry);
19918
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
18996
19919
  setServerProxyConfig(decryptedConfig.server?.proxy);
18997
- (0, import_upstreamFetch13.setUpstreamProxyResolver)(
19920
+ (0, import_upstreamFetch15.setUpstreamProxyResolver)(
18998
19921
  createUpstreamProxyResolver({
18999
19922
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
19000
19923
  })
@@ -19018,7 +19941,7 @@ function buildDaemon(config, paths) {
19018
19941
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
19019
19942
  // Catalog egress follows the same global/env proxy policy as every other
19020
19943
  // daemon upstream call; no provider/account override applies here.
19021
- fetchImpl: ((input, init) => (0, import_upstreamFetch13.fetchUpstream)(String(input), init ?? {}))
19944
+ fetchImpl: ((input, init) => (0, import_upstreamFetch15.fetchUpstream)(String(input), init ?? {}))
19022
19945
  });
19023
19946
  const pricingRefreshScheduler = new PricingRefreshScheduler(
19024
19947
  pricingEngine,
@@ -19303,7 +20226,7 @@ function buildDaemon(config, paths) {
19303
20226
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
19304
20227
  // excluded from the upstream trace, so a failing login left no evidence.
19305
20228
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
19306
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20229
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init, { providerId, redactBodies: true }),
19307
20230
  subscriptionAccountAppender: credentialStore,
19308
20231
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
19309
20232
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -19315,6 +20238,9 @@ function buildDaemon(config, paths) {
19315
20238
  // paste; the app shows the verification URL + user code and polls the
19316
20239
  // token-free status). Token captured + persisted daemon-side.
19317
20240
  kimiSessions: new CodexOAuthSessionStore(),
20241
+ // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20242
+ grokSessions: new CodexOAuthSessionStore(),
20243
+ copilotSessions: new CodexOAuthSessionStore(),
19318
20244
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
19319
20245
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
19320
20246
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -19373,7 +20299,7 @@ function buildDaemon(config, paths) {
19373
20299
  });
19374
20300
  const webhookDispatcher = new WebhookDispatcher({
19375
20301
  logger,
19376
- fetchImpl: (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init)
20302
+ fetchImpl: (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init)
19377
20303
  });
19378
20304
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
19379
20305
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -19453,9 +20379,9 @@ function resetDaemonSingletonsForTests() {
19453
20379
  (0, import_provider_proxy4.__resetProviderProxyForTests)();
19454
20380
  (0, import_outbound_api10.__resetOutboundApiServerForTests)();
19455
20381
  (0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
19456
- (0, import_subscriptions9.setSubscriptionProviderRegistry)(null);
19457
- (0, import_subscriptions9.setSubscriptionAccountService)(null);
19458
- (0, import_upstreamFetch13.setUpstreamProxyResolver)(null);
20382
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(null);
20383
+ (0, import_subscriptions12.setSubscriptionAccountService)(null);
20384
+ (0, import_upstreamFetch15.setUpstreamProxyResolver)(null);
19459
20385
  setServerProxyConfig(void 0);
19460
20386
  (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)(null);
19461
20387
  setSecretBox(null);
@@ -19464,7 +20390,7 @@ function resetDaemonSingletonsForTests() {
19464
20390
  resetAuditRuntimeForTests();
19465
20391
  resetBillingRuntimeForTests();
19466
20392
  (0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
19467
- (0, import_AccountAllowanceStore7.__resetSharedAccountAllowanceStoreForTests)();
20393
+ (0, import_AccountAllowanceStore9.__resetSharedAccountAllowanceStoreForTests)();
19468
20394
  (0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
19469
20395
  (0, import_usage2.__resetSharedUsageThroughputTrackerForTests)();
19470
20396
  }