@omnicross/daemon 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -58,26 +58,26 @@ __export(src_exports, {
58
58
  module.exports = __toCommonJS(src_exports);
59
59
 
60
60
  // src/bootstrap.ts
61
- var import_node_fs34 = require("fs");
61
+ 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_AccountAllowanceStore4 = 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_upstreamFetch9 = 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_subscriptions6 = 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);
@@ -184,93 +184,1494 @@ function handleCodexOAuthStatus(sessionId, deps) {
184
184
  return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
185
185
  }
186
186
 
187
+ // src/admin/accountsKimiOAuth.ts
188
+ var import_subscriptions2 = require("@omnicross/subscriptions");
189
+ function err2(status, message) {
190
+ return { status, body: { error: { type: "admin_api_error", message } } };
191
+ }
192
+ var DEFAULT_KIMI_OAUTH_TTL_MS = 15 * 6e4;
193
+ async function handleKimiOAuthStart(deps) {
194
+ if (deps.kimiSessions.isBusy()) {
195
+ return err2(409, "a kimi sign-in is already in progress \u2014 finish it in the browser or cancel it");
196
+ }
197
+ const fetchImpl = deps.oauthExchangeFetch("kimi");
198
+ const deviceId = import_subscriptions2.kimiOAuth.generateKimiDeviceId();
199
+ const fingerprint = import_subscriptions2.kimiOAuth.kimiFingerprintHeaders(deviceId);
200
+ let authorization;
201
+ try {
202
+ authorization = await import_subscriptions2.kimiOAuth.requestDeviceAuthorization(fetchImpl, fingerprint);
203
+ } catch (e) {
204
+ const reason = e instanceof Error ? e.message : "device authorization failed";
205
+ return err2(502, `kimi device authorization failed: ${reason}`);
206
+ }
207
+ const { sessionId, signal } = deps.kimiSessions.begin();
208
+ void runKimiDevicePoll(sessionId, authorization.deviceCode, deviceId, fingerprint, signal, deps).catch(() => deps.kimiSessions.settle(sessionId, "error", "kimi sign-in failed"));
209
+ return {
210
+ status: 200,
211
+ body: {
212
+ authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
213
+ userCode: authorization.userCode,
214
+ sessionId
215
+ }
216
+ };
217
+ }
218
+ async function runKimiDevicePoll(sessionId, deviceCode, deviceId, fingerprint, signal, deps) {
219
+ const fetchImpl = deps.oauthExchangeFetch("kimi");
220
+ const result = await import_subscriptions2.kimiOAuth.awaitDeviceToken(
221
+ { userCode: "", deviceCode, verificationUri: "" },
222
+ fetchImpl,
223
+ {
224
+ fingerprint,
225
+ deadlineMs: DEFAULT_KIMI_OAUTH_TTL_MS,
226
+ sleep: (ms) => new Promise((resolve10, reject) => {
227
+ const onAbort = () => {
228
+ clearTimeout(timer);
229
+ reject(new Error("login: cancelled"));
230
+ };
231
+ const timer = setTimeout(() => {
232
+ signal.removeEventListener("abort", onAbort);
233
+ resolve10();
234
+ }, ms);
235
+ signal.addEventListener("abort", onAbort, { once: true });
236
+ })
237
+ }
238
+ );
239
+ const block = {
240
+ authMethod: "oauth",
241
+ status: "authorized",
242
+ accessToken: result.accessToken,
243
+ refreshToken: result.refreshToken,
244
+ expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
245
+ accountId: import_subscriptions2.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
246
+ deviceId,
247
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
248
+ };
249
+ await deps.subscriptionAccountAppender.appendProviderAccount("kimi", block);
250
+ deps.kimiSessions.settle(sessionId, "done");
251
+ }
252
+ function handleKimiOAuthCancel(sessionId, deps) {
253
+ if (!deps.kimiSessions.cancel(sessionId)) return err2(404, "unknown or expired kimi sign-in session");
254
+ return { status: 200, body: { ok: true } };
255
+ }
256
+ function handleKimiOAuthStatus(sessionId, deps) {
257
+ const s = deps.kimiSessions.get(sessionId);
258
+ if (!s) return err2(404, "unknown or expired kimi sign-in session");
259
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
260
+ }
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
+
187
441
  // src/allowance/AccountAllowanceService.ts
188
- var import_AccountAllowanceStore2 = require("@omnicross/core/pipeline/AccountAllowanceStore");
442
+ var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
189
443
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
190
444
 
191
- // src/allowance/ClaudeAllowanceCollector.ts
192
- var import_AccountAllowanceStore = require("@omnicross/core/pipeline/AccountAllowanceStore");
193
- var import_upstreamFetch = require("@omnicross/core/pipeline/upstreamFetch");
194
- var import_fingerprintHeaders = require("@omnicross/core/provider-proxy/identity/fingerprintHeaders");
195
- var import_SubscriptionIdentityStore = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
196
- var CLAUDE_ALLOWANCE_CACHE_MS = 5 * 6e4;
197
- var CLAUDE_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
198
- function finitePercent(value) {
445
+ // src/allowance/ClaudeAllowanceCollector.ts
446
+ var import_AccountAllowanceStore = require("@omnicross/core/pipeline/AccountAllowanceStore");
447
+ var import_upstreamFetch = require("@omnicross/core/pipeline/upstreamFetch");
448
+ var import_fingerprintHeaders = require("@omnicross/core/provider-proxy/identity/fingerprintHeaders");
449
+ var import_SubscriptionIdentityStore = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
450
+ var CLAUDE_ALLOWANCE_CACHE_MS = 5 * 6e4;
451
+ var CLAUDE_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
452
+ function finitePercent(value) {
453
+ if (value === null || value === void 0 || value === "") return null;
454
+ const number = typeof value === "number" ? value : Number(value);
455
+ return Number.isFinite(number) && number >= 0 && number <= 100 ? number : null;
456
+ }
457
+ function isoInstant(value) {
458
+ if (typeof value !== "string" || !value.trim()) return void 0;
459
+ const time = Date.parse(value);
460
+ return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
461
+ }
462
+ function secondsUntil(instant, now) {
463
+ if (!instant) return void 0;
464
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
465
+ }
466
+ function windowFromPayload(id, payload, now) {
467
+ const usedPercent = finitePercent(payload?.utilization);
468
+ const resetsAt = isoInstant(payload?.resets_at);
469
+ const isFiveHour = id === "five-hour";
470
+ return {
471
+ id,
472
+ label: isFiveHour ? "5 hours" : "7 days",
473
+ scope: "all",
474
+ usedPercent,
475
+ windowMinutes: isFiveHour ? 5 * 60 : 7 * 24 * 60,
476
+ resetsAt,
477
+ remainingSeconds: secondsUntil(resetsAt, now),
478
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
479
+ };
480
+ }
481
+ function limitEntryWindow(entries, kind) {
482
+ const entry = entries.find((candidate) => candidate.kind === kind);
483
+ if (!entry) return void 0;
484
+ return { utilization: entry.percent, resets_at: entry.resets_at };
485
+ }
486
+ function slugifyDisplayName(name) {
487
+ return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
488
+ }
489
+ function scopedWeeklyWindows(entries, now) {
490
+ const seen = /* @__PURE__ */ new Set();
491
+ const windows = [];
492
+ for (const entry of entries) {
493
+ if (entry.kind !== "weekly_scoped") continue;
494
+ const displayName = typeof entry.scope?.model?.display_name === "string" && entry.scope.model.display_name.trim() ? entry.scope.model.display_name.trim() : void 0;
495
+ if (!displayName) continue;
496
+ const slug = slugifyDisplayName(displayName);
497
+ if (!slug || seen.has(slug)) continue;
498
+ seen.add(slug);
499
+ const usedPercent = finitePercent(entry.percent);
500
+ const resetsAt = isoInstant(entry.resets_at);
501
+ windows.push({
502
+ id: `seven-day-${slug}`,
503
+ label: `7 days \xB7 ${displayName}`,
504
+ scope: "model-family",
505
+ modelFamily: slug,
506
+ usedPercent,
507
+ windowMinutes: 7 * 24 * 60,
508
+ resetsAt,
509
+ remainingSeconds: secondsUntil(resetsAt, now),
510
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
511
+ });
512
+ }
513
+ return windows;
514
+ }
515
+ function parseLimitEntries(raw) {
516
+ if (!Array.isArray(raw)) return [];
517
+ return raw.filter((entry) => !!entry && typeof entry === "object");
518
+ }
519
+ function emptyClaudeWindows(state) {
520
+ return [
521
+ {
522
+ id: "five-hour",
523
+ label: "5 hours",
524
+ scope: "all",
525
+ usedPercent: null,
526
+ windowMinutes: 5 * 60,
527
+ state
528
+ },
529
+ {
530
+ id: "seven-day",
531
+ label: "7 days",
532
+ scope: "all",
533
+ usedPercent: null,
534
+ windowMinutes: 7 * 24 * 60,
535
+ state
536
+ }
537
+ ];
538
+ }
539
+ function hasHeader(headers, name) {
540
+ const wanted = name.toLowerCase();
541
+ return Object.keys(headers).some((key) => key.toLowerCase() === wanted);
542
+ }
543
+ var ClaudeAllowanceCollector = class {
544
+ constructor(credentials, store = (0, import_AccountAllowanceStore.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch.fetchUpstream)(url, init, { providerId: "claude", accountId }), identityStore = (0, import_SubscriptionIdentityStore.getSharedIdentityStore)(), now = Date.now) {
545
+ this.credentials = credentials;
546
+ this.store = store;
547
+ this.fetchImpl = fetchImpl;
548
+ this.identityStore = identityStore;
549
+ this.now = now;
550
+ }
551
+ credentials;
552
+ store;
553
+ fetchImpl;
554
+ identityStore;
555
+ now;
556
+ inFlight = /* @__PURE__ */ new Map();
557
+ async collectMany(accounts, options = {}) {
558
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
559
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
560
+ }
561
+ collect(account, options = {}) {
562
+ const now = this.now();
563
+ const unsupported = account.tokens.isSetupToken || account.tokens.authMethod !== "oauth";
564
+ if (unsupported) {
565
+ const existing = this.store.get("claude", account.id, now);
566
+ if (existing?.windows.every((window) => window.state === "unsupported")) return Promise.resolve(existing);
567
+ const snapshot = this.unsupportedSnapshot(account.id, now);
568
+ this.store.set(snapshot);
569
+ return Promise.resolve(snapshot);
570
+ }
571
+ const cached = this.store.get("claude", account.id, now);
572
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) return Promise.resolve(cached);
573
+ const running = this.inFlight.get(account.id);
574
+ if (running) return running;
575
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "claude_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
576
+ this.inFlight.set(account.id, promise);
577
+ return promise;
578
+ }
579
+ isCacheValid(snapshot, now, refreshAheadMs) {
580
+ if (snapshot.source !== "oauth-usage-api") return false;
581
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
582
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
583
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
584
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
585
+ }
586
+ async fetchAccount(accountId) {
587
+ let token = await this.credentials.getAccessTokenForAccount("claude", accountId);
588
+ if (!token) return this.failureSnapshot(accountId, "claude_usage_token_unavailable", this.now());
589
+ let response = await this.request(accountId, token);
590
+ if (response.status === 401) {
591
+ const refreshed = await this.credentials.refreshAccountToken("claude", accountId);
592
+ if (!refreshed) return this.failureSnapshot(accountId, "claude_usage_unauthorized", this.now());
593
+ token = await this.credentials.getAccessTokenForAccount("claude", accountId);
594
+ if (!token) return this.failureSnapshot(accountId, "claude_usage_token_unavailable", this.now());
595
+ response = await this.request(accountId, token);
596
+ }
597
+ if (response.status === 403) {
598
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "claude_usage_unsupported");
599
+ this.store.set(snapshot2);
600
+ return snapshot2;
601
+ }
602
+ if (!response.ok) {
603
+ return this.failureSnapshot(accountId, "claude_usage_http_error", this.now());
604
+ }
605
+ let payload;
606
+ try {
607
+ payload = await response.json();
608
+ } catch {
609
+ return this.failureSnapshot(accountId, "claude_usage_invalid_response", this.now());
610
+ }
611
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
612
+ return this.failureSnapshot(accountId, "claude_usage_invalid_response", this.now());
613
+ }
614
+ const now = this.now();
615
+ const usage = payload;
616
+ const limitEntries = parseLimitEntries(usage.limits);
617
+ const fiveHour = usage.five_hour ?? limitEntryWindow(limitEntries, "session");
618
+ const sevenDay = usage.seven_day ?? limitEntryWindow(limitEntries, "weekly_all");
619
+ const snapshot = {
620
+ providerId: "claude",
621
+ accountId,
622
+ source: "oauth-usage-api",
623
+ observedAt: new Date(now).toISOString(),
624
+ expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
625
+ windows: [
626
+ windowFromPayload("five-hour", fiveHour, now),
627
+ windowFromPayload("seven-day", sevenDay, now),
628
+ ...scopedWeeklyWindows(limitEntries, now)
629
+ ].slice(0, 8)
630
+ };
631
+ this.store.set(snapshot);
632
+ return snapshot;
633
+ }
634
+ request(accountId, token) {
635
+ const headers = {
636
+ Authorization: `Bearer ${token}`,
637
+ Accept: "application/json",
638
+ "Content-Type": "application/json",
639
+ "anthropic-beta": "oauth-2025-04-20",
640
+ "Accept-Language": "en-US,en;q=0.9"
641
+ };
642
+ (0, import_fingerprintHeaders.applyFingerprint)(this.identityStore, headers, "claude", accountId, void 0);
643
+ if (!hasHeader(headers, "user-agent")) {
644
+ headers["User-Agent"] = "claude-cli/2.0.53 (external, cli)";
645
+ }
646
+ return this.fetchImpl(CLAUDE_USAGE_URL, {
647
+ method: "GET",
648
+ headers,
649
+ signal: AbortSignal.timeout(15e3)
650
+ }, accountId);
651
+ }
652
+ failureSnapshot(accountId, code, now) {
653
+ const existing = this.store.get("claude", accountId, now);
654
+ const snapshot = existing ? {
655
+ ...existing,
656
+ expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
657
+ windows: existing.windows.map((window) => ({
658
+ ...window,
659
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
660
+ })),
661
+ lastErrorCode: code
662
+ } : {
663
+ providerId: "claude",
664
+ accountId,
665
+ source: "oauth-usage-api",
666
+ observedAt: new Date(now).toISOString(),
667
+ expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
668
+ windows: emptyClaudeWindows("unavailable"),
669
+ lastErrorCode: code
670
+ };
671
+ this.store.set(snapshot);
672
+ return snapshot;
673
+ }
674
+ unsupportedSnapshot(accountId, now, code = "claude_usage_unsupported_auth") {
675
+ return {
676
+ providerId: "claude",
677
+ accountId,
678
+ source: "oauth-usage-api",
679
+ observedAt: new Date(now).toISOString(),
680
+ windows: emptyClaudeWindows("unsupported"),
681
+ lastErrorCode: code
682
+ };
683
+ }
684
+ };
685
+
686
+ // src/allowance/CodexAllowanceCollector.ts
687
+ var import_AccountAllowanceStore2 = require("@omnicross/core/pipeline/AccountAllowanceStore");
688
+ var import_upstreamFetch2 = require("@omnicross/core/pipeline/upstreamFetch");
689
+ var CODEX_ALLOWANCE_CACHE_MS = 5 * 6e4;
690
+ var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
691
+ var CODEX_CLI_USER_AGENT = "codex_cli_rs/0.144.5";
692
+ function finiteNumber(value) {
693
+ if (value === null || value === void 0 || value === "") return null;
694
+ const parsed = typeof value === "number" ? value : Number(value);
695
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
696
+ }
697
+ function finitePercent2(value) {
698
+ const parsed = finiteNumber(value);
699
+ return parsed !== null && parsed <= 100 ? parsed : null;
700
+ }
701
+ function epochMs(value) {
702
+ return value > 1e11 ? value : value * 1e3;
703
+ }
704
+ function secondsUntil2(instant, now) {
705
+ if (!instant) return void 0;
706
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
707
+ }
708
+ function decodeJwtClaims(token) {
709
+ const parts = token.split(".");
710
+ if (parts.length !== 3) return void 0;
711
+ try {
712
+ const json2 = Buffer.from(parts[1], "base64url").toString("utf8");
713
+ const parsed = JSON.parse(json2);
714
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
715
+ } catch {
716
+ return void 0;
717
+ }
718
+ }
719
+ function chatgptAccountIdFromClaims(claims) {
720
+ const auth = claims?.["https://api.openai.com/auth"];
721
+ if (!auth || typeof auth !== "object") return void 0;
722
+ const accountId = auth.chatgpt_account_id;
723
+ return typeof accountId === "string" && accountId.trim() ? accountId.trim() : void 0;
724
+ }
725
+ function resolveCodexChatGptAccountId(tokens) {
726
+ if (tokens.accountId?.trim()) return tokens.accountId.trim();
727
+ if (tokens.idToken) {
728
+ const fromIdToken = chatgptAccountIdFromClaims(decodeJwtClaims(tokens.idToken));
729
+ if (fromIdToken) return fromIdToken;
730
+ }
731
+ if (tokens.accessToken) {
732
+ return chatgptAccountIdFromClaims(decodeJwtClaims(tokens.accessToken));
733
+ }
734
+ return void 0;
735
+ }
736
+ function windowFromPayload2(id, payload, now) {
737
+ const usedPercent = finitePercent2(payload?.used_percent);
738
+ const resetAtSeconds = finiteNumber(payload?.reset_at);
739
+ const resetAfterSeconds = finiteNumber(payload?.reset_after_seconds);
740
+ const windowSeconds = finiteNumber(payload?.limit_window_seconds);
741
+ const resetsAt = resetAtSeconds !== null && resetAtSeconds > 0 ? new Date(epochMs(resetAtSeconds)).toISOString() : resetAfterSeconds !== null && resetAfterSeconds > 0 ? new Date(now + resetAfterSeconds * 1e3).toISOString() : void 0;
742
+ const windowMinutes = windowSeconds !== null && windowSeconds > 0 ? Math.round(windowSeconds / 60) : void 0;
743
+ return {
744
+ id,
745
+ label: id === "primary" ? "Primary" : "Secondary",
746
+ scope: "all",
747
+ usedPercent,
748
+ ...windowMinutes !== void 0 ? { windowMinutes } : {},
749
+ ...resetsAt !== void 0 ? { resetsAt } : {},
750
+ remainingSeconds: secondsUntil2(resetsAt, now),
751
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
752
+ };
753
+ }
754
+ var CodexAllowanceCollector = class {
755
+ constructor(credentials, store = (0, import_AccountAllowanceStore2.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch2.fetchUpstream)(url, init, { providerId: "codex", accountId, redactBodies: true }), now = Date.now) {
756
+ this.credentials = credentials;
757
+ this.store = store;
758
+ this.fetchImpl = fetchImpl;
759
+ this.now = now;
760
+ }
761
+ credentials;
762
+ store;
763
+ fetchImpl;
764
+ now;
765
+ inFlight = /* @__PURE__ */ new Map();
766
+ async collectMany(accounts, options = {}) {
767
+ const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
768
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
769
+ }
770
+ collect(account, options = {}) {
771
+ const now = this.now();
772
+ const unsupported = account.tokens.authMethod !== "oauth";
773
+ if (unsupported) {
774
+ const existing = this.store.get("codex", account.id, now);
775
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
776
+ return Promise.resolve(existing);
777
+ }
778
+ const snapshot = this.unsupportedSnapshot(account.id, now);
779
+ this.store.set(snapshot);
780
+ return Promise.resolve(snapshot);
781
+ }
782
+ const cached = this.store.get("codex", account.id, now);
783
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
784
+ return Promise.resolve(cached);
785
+ }
786
+ const running = this.inFlight.get(account.id);
787
+ if (running) return running;
788
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "codex_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
789
+ this.inFlight.set(account.id, promise);
790
+ return promise;
791
+ }
792
+ /**
793
+ * A response-header snapshot stays a valid cache hit only while fresh; an
794
+ * active oauth-usage snapshot is honored on the same 5-minute cadence as
795
+ * Claude's (the poll is cheap and quota is the scheduling input).
796
+ */
797
+ isCacheValid(snapshot, now, refreshAheadMs) {
798
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
799
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
800
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
801
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
802
+ }
803
+ async fetchAccount(accountId, tokens) {
804
+ let accessToken = await this.credentials.getAccessTokenForAccount("codex", accountId);
805
+ if (!accessToken) {
806
+ return this.failureSnapshot(accountId, "codex_usage_token_unavailable", this.now());
807
+ }
808
+ let response = await this.request(accountId, accessToken, tokens);
809
+ if (response.status === 401) {
810
+ const refreshed = await this.credentials.refreshAccountToken("codex", accountId);
811
+ if (!refreshed) {
812
+ return this.failureSnapshot(accountId, "codex_usage_unauthorized", this.now());
813
+ }
814
+ accessToken = await this.credentials.getAccessTokenForAccount("codex", accountId);
815
+ if (!accessToken) {
816
+ return this.failureSnapshot(accountId, "codex_usage_token_unavailable", this.now());
817
+ }
818
+ response = await this.request(accountId, accessToken, tokens);
819
+ }
820
+ if (response.status === 403) {
821
+ const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "codex_usage_unsupported");
822
+ this.store.set(snapshot2);
823
+ return snapshot2;
824
+ }
825
+ if (!response.ok) {
826
+ return this.failureSnapshot(accountId, "codex_usage_http_error", this.now());
827
+ }
828
+ let payload;
829
+ try {
830
+ payload = await response.json();
831
+ } catch {
832
+ return this.failureSnapshot(accountId, "codex_usage_invalid_response", this.now());
833
+ }
834
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
835
+ return this.failureSnapshot(accountId, "codex_usage_invalid_response", this.now());
836
+ }
837
+ const now = this.now();
838
+ const usage = payload.rate_limit;
839
+ const previous = this.store.get("codex", accountId, now);
840
+ const snapshot = {
841
+ providerId: "codex",
842
+ accountId,
843
+ source: "oauth-usage-api",
844
+ observedAt: new Date(now).toISOString(),
845
+ expiresAt: new Date(now + CODEX_ALLOWANCE_CACHE_MS).toISOString(),
846
+ windows: [
847
+ windowFromPayload2("primary", usage?.primary_window ?? void 0, now),
848
+ windowFromPayload2("secondary", usage?.secondary_window ?? void 0, now)
849
+ ],
850
+ // The wham payload has no ratio field; keep the passively-observed value.
851
+ ...previous?.primaryOverSecondaryLimitPercent !== void 0 ? { primaryOverSecondaryLimitPercent: previous.primaryOverSecondaryLimitPercent } : {}
852
+ };
853
+ this.store.set(snapshot);
854
+ return snapshot;
855
+ }
856
+ request(accountId, accessToken, tokens) {
857
+ const headers = {
858
+ Authorization: `Bearer ${accessToken}`,
859
+ Accept: "application/json",
860
+ "User-Agent": CODEX_CLI_USER_AGENT
861
+ };
862
+ const chatgptAccountId = resolveCodexChatGptAccountId(tokens);
863
+ if (chatgptAccountId) headers["ChatGPT-Account-Id"] = chatgptAccountId;
864
+ return this.fetchImpl(CODEX_USAGE_URL, {
865
+ method: "GET",
866
+ headers,
867
+ signal: AbortSignal.timeout(15e3)
868
+ }, accountId);
869
+ }
870
+ failureSnapshot(accountId, code, now) {
871
+ const existing = this.store.get("codex", accountId, now);
872
+ const snapshot = existing ? {
873
+ ...existing,
874
+ expiresAt: new Date(now + CODEX_ALLOWANCE_CACHE_MS).toISOString(),
875
+ windows: existing.windows.map((window) => ({
876
+ ...window,
877
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
878
+ })),
879
+ lastErrorCode: code
880
+ } : {
881
+ providerId: "codex",
882
+ accountId,
883
+ source: "oauth-usage-api",
884
+ observedAt: new Date(now).toISOString(),
885
+ expiresAt: new Date(now + CODEX_ALLOWANCE_CACHE_MS).toISOString(),
886
+ windows: [
887
+ { id: "primary", label: "Primary", scope: "all", usedPercent: null, state: "unavailable" },
888
+ { id: "secondary", label: "Secondary", scope: "all", usedPercent: null, state: "unavailable" }
889
+ ],
890
+ lastErrorCode: code
891
+ };
892
+ this.store.set(snapshot);
893
+ return snapshot;
894
+ }
895
+ unsupportedSnapshot(accountId, now, code = "codex_usage_unsupported_auth") {
896
+ return {
897
+ providerId: "codex",
898
+ accountId,
899
+ source: "oauth-usage-api",
900
+ observedAt: new Date(now).toISOString(),
901
+ windows: [
902
+ { id: "primary", label: "Primary", scope: "all", usedPercent: null, state: "unsupported" },
903
+ { id: "secondary", label: "Secondary", scope: "all", usedPercent: null, state: "unsupported" }
904
+ ],
905
+ lastErrorCode: code
906
+ };
907
+ }
908
+ };
909
+
910
+ // src/allowance/KimiAllowanceCollector.ts
911
+ var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
912
+ var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
913
+ var import_subscriptions5 = require("@omnicross/subscriptions");
914
+ var KIMI_ALLOWANCE_CACHE_MS = 5 * 6e4;
915
+ var KIMI_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
916
+ function finiteNumber2(value) {
917
+ if (value === null || value === void 0 || value === "") return void 0;
918
+ const parsed = typeof value === "number" ? value : Number(value);
919
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
920
+ }
921
+ function isRecord(value) {
922
+ return !!value && typeof value === "object" && !Array.isArray(value);
923
+ }
924
+ function parseResetMs(row, nowMs) {
925
+ for (const key of ["reset_at", "resetAt", "reset_time", "resetTime"]) {
926
+ const value = row[key];
927
+ if (typeof value === "string" && value.trim()) {
928
+ const parsed = Date.parse(value);
929
+ if (Number.isFinite(parsed)) return parsed;
930
+ }
931
+ const numeric = finiteNumber2(value);
932
+ if (numeric !== void 0 && numeric > 1e9) {
933
+ return numeric > 1e12 ? numeric : numeric * 1e3;
934
+ }
935
+ }
936
+ for (const key of ["reset_in", "resetIn", "ttl", "window"]) {
937
+ const seconds = finiteNumber2(row[key]);
938
+ if (seconds !== void 0) return nowMs + seconds * 1e3;
939
+ }
940
+ return void 0;
941
+ }
942
+ var MINUTE_MS = 6e4;
943
+ var HOUR_MS = 36e5;
944
+ var DAY_MS = 864e5;
945
+ function canonicalWindow(durationMs) {
946
+ if (durationMs === 5 * HOUR_MS) return { id: "five-hour", label: "5 hours", minutes: 300 };
947
+ if (durationMs === 7 * DAY_MS) return { id: "seven-day", label: "7 days", minutes: 10080 };
948
+ if (durationMs > 0 && durationMs % DAY_MS === 0) {
949
+ const days = durationMs / DAY_MS;
950
+ return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}`, minutes: Math.round(durationMs / MINUTE_MS) };
951
+ }
952
+ if (durationMs > 0 && durationMs % HOUR_MS === 0) {
953
+ const hours = durationMs / HOUR_MS;
954
+ return { id: `${hours}h`, label: `${hours} hour${hours === 1 ? "" : "s"}`, minutes: Math.round(durationMs / MINUTE_MS) };
955
+ }
956
+ return void 0;
957
+ }
958
+ function secondsUntil3(instant, now) {
959
+ if (!instant) return void 0;
960
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
961
+ }
962
+ function windowFromRow(row, fallback, now) {
963
+ const usedPercent = row?.limit !== void 0 && row.limit > 0 && row.used !== void 0 ? Math.round(Math.min(100, row.used / row.limit * 100) * 10) / 10 : null;
964
+ const resetsAt = row?.resetsAtMs !== void 0 ? new Date(row.resetsAtMs).toISOString() : void 0;
965
+ return {
966
+ id: fallback.id,
967
+ label: fallback.label,
968
+ scope: "all",
969
+ usedPercent,
970
+ windowMinutes: fallback.minutes,
971
+ ...resetsAt !== void 0 ? { resetsAt } : {},
972
+ remainingSeconds: secondsUntil3(resetsAt, now),
973
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
974
+ };
975
+ }
976
+ function parseKimiUsagePayload(payload, now) {
977
+ if (!isRecord(payload)) return [];
978
+ const byId = /* @__PURE__ */ new Map();
979
+ const rowFrom = (data) => {
980
+ const limit = finiteNumber2(data["limit"]);
981
+ let used = finiteNumber2(data["used"]);
982
+ const remaining = finiteNumber2(data["remaining"]);
983
+ if (used === void 0 && remaining !== void 0 && limit !== void 0) {
984
+ used = limit - remaining;
985
+ }
986
+ let windowDurationMs;
987
+ const windowData = isRecord(data["window"]) ? data["window"] : void 0;
988
+ const duration = finiteNumber2(windowData?.["duration"]);
989
+ const timeUnit = typeof windowData?.["timeUnit"] === "string" ? windowData["timeUnit"].toUpperCase() : "";
990
+ if (duration !== void 0) {
991
+ if (timeUnit.includes("MINUTE")) windowDurationMs = duration * MINUTE_MS;
992
+ else if (timeUnit.includes("HOUR")) windowDurationMs = duration * HOUR_MS;
993
+ else if (timeUnit.includes("DAY")) windowDurationMs = duration * DAY_MS;
994
+ else if (timeUnit.includes("WEEK")) windowDurationMs = duration * 7 * DAY_MS;
995
+ else if (timeUnit.includes("SECOND")) windowDurationMs = duration * 1e3;
996
+ }
997
+ const resetsAtMs = parseResetMs(windowData && parseResetMs(windowData, now) !== void 0 ? windowData : data, now);
998
+ return { used, limit, remaining, ...resetsAtMs !== void 0 ? { resetsAtMs } : {}, ...windowDurationMs !== void 0 ? { windowDurationMs } : {} };
999
+ };
1000
+ if (isRecord(payload["usage"])) {
1001
+ const row = rowFrom(payload["usage"]);
1002
+ const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
1003
+ byId.set("seven-day", window);
1004
+ }
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
+ });
1477
+ }
1478
+ }
1479
+ const chat = parseQuotaDetail(snapshots["chat"]);
1480
+ if (chat && !chat.unlimited && chat.entitlement > 0) {
1481
+ const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
1482
+ windows.push({
1483
+ id: "chat-monthly",
1484
+ label: "Chat (monthly)",
1485
+ scope: "all",
1486
+ usedPercent,
1487
+ windowMinutes: 30 * 24 * 60,
1488
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1489
+ remainingSeconds: secondsUntil5(resetsAt, now),
1490
+ state: "fresh"
1491
+ });
1492
+ }
1493
+ return windows.length > 0 ? windows : null;
1494
+ }
1495
+ function githubApiBase(tokens) {
1496
+ return (0, import_subscriptions6.copilotGitHubApiBase)(tokens.enterpriseUrl);
1497
+ }
1498
+ var CopilotAllowanceCollector = class {
1499
+ constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch5.fetchUpstream)(url, init, { providerId: "copilot", accountId, redactBodies: true }), now = Date.now) {
1500
+ this.credentials = credentials;
1501
+ this.store = store;
1502
+ this.fetchImpl = fetchImpl;
1503
+ this.now = now;
1504
+ }
1505
+ credentials;
1506
+ store;
1507
+ fetchImpl;
1508
+ now;
1509
+ inFlight = /* @__PURE__ */ new Map();
1510
+ async collectMany(accounts, options = {}) {
1511
+ const settled = await Promise.allSettled(
1512
+ accounts.map((account) => this.collect(account, options))
1513
+ );
1514
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1515
+ }
1516
+ collect(account, options = {}) {
1517
+ const now = this.now();
1518
+ if (account.tokens.authMethod !== "oauth") {
1519
+ const existing = this.store.get("copilot", account.id, now);
1520
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1521
+ return Promise.resolve(existing);
1522
+ }
1523
+ const snapshot = this.unsupportedSnapshot(account.id, now);
1524
+ this.store.set(snapshot);
1525
+ return Promise.resolve(snapshot);
1526
+ }
1527
+ const cached = this.store.get("copilot", account.id, now);
1528
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
1529
+ return Promise.resolve(cached);
1530
+ }
1531
+ const running = this.inFlight.get(account.id);
1532
+ if (running) return running;
1533
+ const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "copilot_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1534
+ this.inFlight.set(account.id, promise);
1535
+ return promise;
1536
+ }
1537
+ isCacheValid(snapshot, now, refreshAheadMs) {
1538
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
1539
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
1540
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
1541
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
1542
+ }
1543
+ async fetchAccount(accountId, tokens) {
1544
+ let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1545
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
1546
+ let response = await this.request(accountId, accessToken, tokens);
1547
+ if (response.status === 401 || response.status === 403) {
1548
+ const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
1549
+ if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1550
+ accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
1551
+ if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
1552
+ response = await this.request(accountId, accessToken, tokens);
1553
+ if (response.status === 401 || response.status === 403) {
1554
+ return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
1555
+ }
1556
+ }
1557
+ if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
1558
+ let payload;
1559
+ try {
1560
+ payload = await response.json();
1561
+ } catch {
1562
+ return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
1563
+ }
1564
+ const now = this.now();
1565
+ const windows = parseCopilotUserPayload(payload, now);
1566
+ const snapshot = {
1567
+ providerId: "copilot",
1568
+ accountId,
1569
+ source: "oauth-usage-api",
1570
+ observedAt: new Date(now).toISOString(),
1571
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1572
+ windows: windows ?? [
1573
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
1574
+ ],
1575
+ ...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
1576
+ };
1577
+ this.store.set(snapshot);
1578
+ return snapshot;
1579
+ }
1580
+ request(accountId, accessToken, tokens) {
1581
+ return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
1582
+ method: "GET",
1583
+ headers: {
1584
+ Authorization: `Bearer ${accessToken}`,
1585
+ Accept: "application/json",
1586
+ "Content-Type": "application/json",
1587
+ ...import_subscriptions6.COPILOT_GITHUB_HEADERS
1588
+ },
1589
+ signal: AbortSignal.timeout(15e3)
1590
+ }, accountId);
1591
+ }
1592
+ failureSnapshot(accountId, code, now) {
1593
+ const existing = this.store.get("copilot", accountId, now);
1594
+ const snapshot = existing ? {
1595
+ ...existing,
1596
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1597
+ windows: existing.windows.map((window) => ({
1598
+ ...window,
1599
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1600
+ })),
1601
+ lastErrorCode: code
1602
+ } : {
1603
+ providerId: "copilot",
1604
+ accountId,
1605
+ source: "oauth-usage-api",
1606
+ observedAt: new Date(now).toISOString(),
1607
+ expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
1608
+ windows: [
1609
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
1610
+ ],
1611
+ lastErrorCode: code
1612
+ };
1613
+ this.store.set(snapshot);
1614
+ return snapshot;
1615
+ }
1616
+ unsupportedSnapshot(accountId, now) {
1617
+ return {
1618
+ providerId: "copilot",
1619
+ accountId,
1620
+ source: "oauth-usage-api",
1621
+ observedAt: new Date(now).toISOString(),
1622
+ windows: [
1623
+ { id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
1624
+ ],
1625
+ lastErrorCode: "copilot_usage_unsupported_auth"
1626
+ };
1627
+ }
1628
+ };
1629
+
1630
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
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");
1634
+ var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
1635
+ var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
1636
+ function finitePercent3(value) {
199
1637
  if (value === null || value === void 0 || value === "") return null;
200
- const number = typeof value === "number" ? value : Number(value);
201
- return Number.isFinite(number) && number >= 0 && number <= 100 ? number : null;
1638
+ const parsed = typeof value === "number" ? value : Number(value);
1639
+ return Number.isFinite(parsed) && parsed >= 0 && parsed <= 100 ? parsed : null;
202
1640
  }
203
- function isoInstant(value) {
1641
+ function isoInstant2(value) {
204
1642
  if (typeof value !== "string" || !value.trim()) return void 0;
205
1643
  const time = Date.parse(value);
206
1644
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
207
1645
  }
208
- function secondsUntil(instant, now) {
1646
+ function secondsUntil6(instant, now) {
209
1647
  if (!instant) return void 0;
210
1648
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
211
1649
  }
212
- function windowFromPayload(id, payload, now) {
213
- const usedPercent = finitePercent(payload?.utilization);
214
- const resetsAt = isoInstant(payload?.resets_at);
215
- const isSonnet = id === "seven-day-sonnet";
216
- const isFiveHour = id === "five-hour";
1650
+ function windowFromPayload3(id, label, minutes, payload, now) {
1651
+ const statusRateLimited = payload?.status === "rate-limited";
1652
+ const usedPercent = statusRateLimited ? 100 : finitePercent3(payload?.percent);
1653
+ const resetsAt = isoInstant2(payload?.resetsAt);
217
1654
  return {
218
1655
  id,
219
- label: isFiveHour ? "5 hours" : isSonnet ? "7 days \xB7 Sonnet" : "7 days",
220
- scope: isSonnet ? "model-family" : "all",
221
- modelFamily: isSonnet ? "sonnet" : void 0,
1656
+ label,
1657
+ scope: "all",
222
1658
  usedPercent,
223
- windowMinutes: isFiveHour ? 5 * 60 : 7 * 24 * 60,
224
- resetsAt,
225
- remainingSeconds: secondsUntil(resetsAt, now),
1659
+ windowMinutes: minutes,
1660
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1661
+ remainingSeconds: secondsUntil6(resetsAt, now),
226
1662
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
227
1663
  };
228
1664
  }
229
- function emptyClaudeWindows(state) {
230
- return [
231
- {
232
- id: "five-hour",
233
- label: "5 hours",
234
- scope: "all",
235
- usedPercent: null,
236
- windowMinutes: 5 * 60,
237
- state
238
- },
239
- {
240
- id: "seven-day",
241
- label: "7 days",
242
- scope: "all",
243
- usedPercent: null,
244
- windowMinutes: 7 * 24 * 60,
245
- state
246
- },
247
- {
248
- id: "seven-day-sonnet",
249
- label: "7 days \xB7 Sonnet",
250
- scope: "model-family",
251
- modelFamily: "sonnet",
252
- usedPercent: null,
253
- windowMinutes: 7 * 24 * 60,
254
- state
255
- }
256
- ];
257
- }
258
- function hasHeader(headers, name) {
259
- const wanted = name.toLowerCase();
260
- return Object.keys(headers).some((key) => key.toLowerCase() === wanted);
261
- }
262
- var ClaudeAllowanceCollector = class {
263
- constructor(credentials, store = (0, import_AccountAllowanceStore.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch.fetchUpstream)(url, init, { providerId: "claude", accountId }), identityStore = (0, import_SubscriptionIdentityStore.getSharedIdentityStore)(), now = Date.now) {
1665
+ var OpenCodeGoAllowanceCollector = class {
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) {
264
1667
  this.credentials = credentials;
265
1668
  this.store = store;
266
1669
  this.fetchImpl = fetchImpl;
267
- this.identityStore = identityStore;
268
1670
  this.now = now;
269
1671
  }
270
1672
  credentials;
271
1673
  store;
272
1674
  fetchImpl;
273
- identityStore;
274
1675
  now;
275
1676
  inFlight = /* @__PURE__ */ new Map();
276
1677
  async collectMany(accounts, options = {}) {
@@ -279,124 +1680,77 @@ var ClaudeAllowanceCollector = class {
279
1680
  }
280
1681
  collect(account, options = {}) {
281
1682
  const now = this.now();
282
- const unsupported = account.tokens.isSetupToken || account.tokens.authMethod !== "oauth";
283
- if (unsupported) {
284
- const existing = this.store.get("claude", account.id, now);
285
- if (existing?.windows.every((window) => window.state === "unsupported")) return Promise.resolve(existing);
286
- const snapshot = this.unsupportedSnapshot(account.id, now);
287
- this.store.set(snapshot);
288
- return Promise.resolve(snapshot);
1683
+ const cached = this.store.get("opencodego", account.id, now);
1684
+ if (!options.force && cached && (cached.windows.every((window) => window.state === "unsupported") || cached.expiresAt && Date.parse(cached.expiresAt) > now + (options.refreshAheadMs ?? 0))) {
1685
+ return Promise.resolve(cached);
289
1686
  }
290
- const cached = this.store.get("claude", account.id, now);
291
- if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) return Promise.resolve(cached);
292
1687
  const running = this.inFlight.get(account.id);
293
1688
  if (running) return running;
294
- const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "claude_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
1689
+ const promise = this.fetchAccount(account).catch(() => this.failureSnapshot(account.id, this.now())).finally(() => this.inFlight.delete(account.id));
295
1690
  this.inFlight.set(account.id, promise);
296
1691
  return promise;
297
1692
  }
298
- isCacheValid(snapshot, now, refreshAheadMs) {
299
- if (snapshot.source !== "oauth-usage-api") return false;
300
- if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
301
- const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
302
- const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
303
- return Number.isFinite(expiresAt) && expiresAt > now + ahead;
304
- }
305
- async fetchAccount(accountId) {
306
- let token = await this.credentials.getAccessTokenForAccount("claude", accountId);
307
- if (!token) return this.failureSnapshot(accountId, "claude_usage_token_unavailable", this.now());
308
- let response = await this.request(accountId, token);
309
- if (response.status === 401) {
310
- const refreshed = await this.credentials.refreshAccountToken("claude", accountId);
311
- if (!refreshed) return this.failureSnapshot(accountId, "claude_usage_unauthorized", this.now());
312
- token = await this.credentials.getAccessTokenForAccount("claude", accountId);
313
- if (!token) return this.failureSnapshot(accountId, "claude_usage_token_unavailable", this.now());
314
- response = await this.request(accountId, token);
315
- }
316
- if (response.status === 403) {
317
- const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "claude_usage_unsupported");
318
- this.store.set(snapshot2);
319
- return snapshot2;
320
- }
321
- if (!response.ok) {
322
- return this.failureSnapshot(accountId, "claude_usage_http_error", this.now());
1693
+ async fetchAccount(account) {
1694
+ const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
1695
+ if (!apiKey) return this.failureSnapshot(account.id, this.now());
1696
+ const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1697
+ const response = await this.fetchImpl(`${base}/v1/usage`, {
1698
+ method: "GET",
1699
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
1700
+ signal: AbortSignal.timeout(15e3)
1701
+ }, account.id);
1702
+ if (response.status === 401 || response.status === 403) {
1703
+ return this.failureSnapshot(account.id, this.now(), "opencodego_usage_unauthorized");
323
1704
  }
1705
+ if (!response.ok) return this.failureSnapshot(account.id, this.now());
324
1706
  let payload;
325
1707
  try {
326
1708
  payload = await response.json();
327
1709
  } catch {
328
- return this.failureSnapshot(accountId, "claude_usage_invalid_response", this.now());
329
- }
330
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
331
- return this.failureSnapshot(accountId, "claude_usage_invalid_response", this.now());
1710
+ return this.failureSnapshot(account.id, this.now());
332
1711
  }
1712
+ const usage = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.usage : void 0;
333
1713
  const now = this.now();
334
- const usage = payload;
335
1714
  const snapshot = {
336
- providerId: "claude",
337
- accountId,
1715
+ providerId: "opencodego",
1716
+ accountId: account.id,
338
1717
  source: "oauth-usage-api",
339
1718
  observedAt: new Date(now).toISOString(),
340
- expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
1719
+ expiresAt: new Date(now + OPENCODEGO_ALLOWANCE_CACHE_MS).toISOString(),
1720
+ // Monthly deliberately omitted (module doc).
341
1721
  windows: [
342
- windowFromPayload("five-hour", usage.five_hour, now),
343
- windowFromPayload("seven-day", usage.seven_day, now),
344
- windowFromPayload("seven-day-sonnet", usage.seven_day_sonnet, now)
1722
+ windowFromPayload3("five-hour", "5 hours", 5 * 60, usage?.rolling ?? void 0, now),
1723
+ windowFromPayload3("seven-day", "7 days", 7 * 24 * 60, usage?.weekly ?? void 0, now)
345
1724
  ]
346
1725
  };
347
1726
  this.store.set(snapshot);
348
1727
  return snapshot;
349
1728
  }
350
- request(accountId, token) {
351
- const headers = {
352
- Authorization: `Bearer ${token}`,
353
- Accept: "application/json",
354
- "Content-Type": "application/json",
355
- "anthropic-beta": "oauth-2025-04-20",
356
- "Accept-Language": "en-US,en;q=0.9"
357
- };
358
- (0, import_fingerprintHeaders.applyFingerprint)(this.identityStore, headers, "claude", accountId, void 0);
359
- if (!hasHeader(headers, "user-agent")) {
360
- headers["User-Agent"] = "claude-cli/2.0.53 (external, cli)";
361
- }
362
- return this.fetchImpl(CLAUDE_USAGE_URL, {
363
- method: "GET",
364
- headers,
365
- signal: AbortSignal.timeout(15e3)
366
- }, accountId);
367
- }
368
- failureSnapshot(accountId, code, now) {
369
- const existing = this.store.get("claude", accountId, now);
1729
+ failureSnapshot(accountId, now, code = "opencodego_usage_request_failed") {
1730
+ const existing = this.store.get("opencodego", accountId, now);
370
1731
  const snapshot = existing ? {
371
1732
  ...existing,
372
- expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
1733
+ expiresAt: new Date(now + OPENCODEGO_ALLOWANCE_CACHE_MS).toISOString(),
373
1734
  windows: existing.windows.map((window) => ({
374
1735
  ...window,
375
- state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
1736
+ state: window.usedPercent !== null || window.resetsAt ? "stale" : window.state
376
1737
  })),
377
1738
  lastErrorCode: code
378
1739
  } : {
379
- providerId: "claude",
1740
+ providerId: "opencodego",
380
1741
  accountId,
381
1742
  source: "oauth-usage-api",
382
1743
  observedAt: new Date(now).toISOString(),
383
- expiresAt: new Date(now + CLAUDE_ALLOWANCE_CACHE_MS).toISOString(),
384
- windows: emptyClaudeWindows("unavailable"),
1744
+ expiresAt: new Date(now + OPENCODEGO_ALLOWANCE_CACHE_MS).toISOString(),
1745
+ windows: [
1746
+ { id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
1747
+ { id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
1748
+ ],
385
1749
  lastErrorCode: code
386
1750
  };
387
1751
  this.store.set(snapshot);
388
1752
  return snapshot;
389
1753
  }
390
- unsupportedSnapshot(accountId, now, code = "claude_usage_unsupported_auth") {
391
- return {
392
- providerId: "claude",
393
- accountId,
394
- source: "oauth-usage-api",
395
- observedAt: new Date(now).toISOString(),
396
- windows: emptyClaudeWindows("unsupported"),
397
- lastErrorCode: code
398
- };
399
- }
400
1754
  };
401
1755
 
402
1756
  // src/allowance/AccountAllowanceService.ts
@@ -414,26 +1768,34 @@ function codexUnavailable(accountId, now) {
414
1768
  };
415
1769
  }
416
1770
  var AccountAllowanceService = class {
417
- constructor(credentials, store = (0, import_AccountAllowanceStore2.getSharedAccountAllowanceStore)(), collector, now = Date.now) {
1771
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, now = Date.now) {
418
1772
  this.credentials = credentials;
419
1773
  this.store = store;
420
1774
  this.now = now;
421
1775
  this.claudeCollector = collector ?? new ClaudeAllowanceCollector(credentials, store);
1776
+ this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
1777
+ this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
1778
+ this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
1779
+ this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
1780
+ this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
422
1781
  }
423
1782
  credentials;
424
1783
  store;
425
1784
  now;
426
1785
  claudeCollector;
1786
+ codexCollector;
1787
+ kimiCollector;
1788
+ grokCollector;
1789
+ copilotCollector;
1790
+ opencodegoCollector;
427
1791
  /**
428
- * Read all/filtered snapshots. Claude's five-minute cache is refreshed lazily;
429
- * Codex remains passive and reports not-observed until a real model response.
1792
+ * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1793
+ * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
1794
+ * passive `x-codex-*` header tap still feeds mid-flight updates).
430
1795
  */
431
1796
  async list(filter = {}) {
432
1797
  const config = await this.credentials.getFullConfig();
433
- this.store.pruneToKnownAccounts([
434
- ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
435
- ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id }))
436
- ]);
1798
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
437
1799
  const wantsClaude = !filter.providerId || filter.providerId === "claude";
438
1800
  const claudeAccounts = (config.claudeAccounts ?? []).filter(
439
1801
  (account) => !filter.accountId || account.id === filter.accountId
@@ -444,39 +1806,124 @@ var AccountAllowanceService = class {
444
1806
  (account) => !filter.accountId || account.id === filter.accountId
445
1807
  );
446
1808
  if (wantsCodex) {
1809
+ await this.codexCollector.collectMany(codexAccounts);
447
1810
  for (const account of codexAccounts) {
448
1811
  if (!this.store.get("codex", account.id)) this.store.set(codexUnavailable(account.id, this.now()));
449
1812
  }
450
1813
  }
1814
+ const wantsKimi = !filter.providerId || filter.providerId === "kimi";
1815
+ const kimiAccounts = (config.kimiAccounts ?? []).filter(
1816
+ (account) => !filter.accountId || account.id === filter.accountId
1817
+ );
1818
+ if (wantsKimi) await this.kimiCollector.collectMany(kimiAccounts);
1819
+ const wantsOpenCodeGo = !filter.providerId || filter.providerId === "opencodego";
1820
+ const opencodegoAccounts = (config.opencodegoAccounts ?? []).filter(
1821
+ (account) => !filter.accountId || account.id === filter.accountId
1822
+ );
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);
451
1834
  const known = /* @__PURE__ */ new Set();
452
1835
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
453
1836
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
1837
+ if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
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}`);
454
1841
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
455
1842
  }
1843
+ knownAccounts(config) {
1844
+ return [
1845
+ ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
1846
+ ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
1847
+ ...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", 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 }))
1851
+ ];
1852
+ }
456
1853
  /** Force-refresh Claude usage for one account or every stored Claude account. */
457
1854
  async refreshClaude(accountId) {
458
1855
  const config = await this.credentials.getFullConfig();
459
- this.store.pruneToKnownAccounts([
460
- ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
461
- ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id }))
462
- ]);
1856
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
463
1857
  const accounts = (config.claudeAccounts ?? []).filter(
464
1858
  (account) => !accountId || account.id === accountId
465
1859
  );
466
1860
  return this.claudeCollector.collectMany(accounts, { force: true });
467
1861
  }
468
1862
  /**
469
- * Keep Claude snapshots warm for allowance-aware routing. This deliberately
470
- * excludes Codex (whose quota is learned from real response headers) and
471
- * preserves the collector's cache + per-account in-flight coalescing.
1863
+ * Force-refresh Codex usage (`/backend-api/wham/usage`) for one account or
1864
+ * every stored Codex account. Replaces the old probe-request workaround
1865
+ * no quota is spent reading the usage endpoint.
1866
+ */
1867
+ async refreshCodex(accountId) {
1868
+ const config = await this.credentials.getFullConfig();
1869
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1870
+ const accounts = (config.codexAccounts ?? []).filter(
1871
+ (account) => !accountId || account.id === accountId
1872
+ );
1873
+ return this.codexCollector.collectMany(accounts, { force: true });
1874
+ }
1875
+ /** Force-refresh OpenCodeGo usage (`{go}/v1/usage`) for one/all accounts. */
1876
+ async refreshOpenCodeGo(accountId) {
1877
+ const config = await this.credentials.getFullConfig();
1878
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1879
+ const accounts = (config.opencodegoAccounts ?? []).filter(
1880
+ (account) => !accountId || account.id === accountId
1881
+ );
1882
+ return this.opencodegoCollector.collectMany(accounts, { force: true });
1883
+ }
1884
+ /** Force-refresh Kimi usage (`/coding/v1/usages`) for one/all accounts. */
1885
+ async refreshKimi(accountId) {
1886
+ const config = await this.credentials.getFullConfig();
1887
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
1888
+ const accounts = (config.kimiAccounts ?? []).filter(
1889
+ (account) => !accountId || account.id === accountId
1890
+ );
1891
+ return this.kimiCollector.collectMany(accounts, { force: true });
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
+ }
1911
+ /**
1912
+ * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
1913
+ * collectors preserve their cache + per-account in-flight coalescing; a tick
1914
+ * normally performs no network I/O. (Codex joined the warm path when it
1915
+ * gained an active `/wham/usage` collector — the passive `x-codex-*` header
1916
+ * tap alone could not keep the policy fed while idle.)
472
1917
  */
473
1918
  async maintainClaudeCache(refreshAheadMs) {
474
1919
  const config = await this.credentials.getFullConfig();
475
- this.store.pruneToKnownAccounts([
476
- ...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
477
- ...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id }))
478
- ]);
1920
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
479
1921
  await this.claudeCollector.collectMany(config.claudeAccounts ?? [], { refreshAheadMs });
1922
+ await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
1923
+ await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
1924
+ await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
1925
+ await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
1926
+ await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
480
1927
  }
481
1928
  /** Remove a cache row as soon as an account is deleted by the admin path. */
482
1929
  removeAccountSnapshot(providerId, accountId) {
@@ -571,7 +2018,7 @@ var ClaudeAllowanceRefreshScheduler = class {
571
2018
  var import_node_crypto2 = require("crypto");
572
2019
  var import_node_fs = require("fs");
573
2020
  var import_node_path = require("path");
574
- var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2021
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
575
2022
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
576
2023
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
577
2024
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -600,7 +2047,7 @@ var JsonAccountAllowancePersistence = class {
600
2047
  save(snapshots) {
601
2048
  const rows = [];
602
2049
  for (const snapshot of snapshots) {
603
- const normalized2 = (0, import_AccountAllowanceStore3.normalizeAccountAllowanceSnapshot)(snapshot);
2050
+ const normalized2 = (0, import_AccountAllowanceStore8.normalizeAccountAllowanceSnapshot)(snapshot);
604
2051
  if (!normalized2) continue;
605
2052
  rows.push(normalized2);
606
2053
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -883,7 +2330,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
883
2330
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
884
2331
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
885
2332
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
886
- var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
2333
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
2334
+ var import_core3 = require("@omnicross/core");
887
2335
 
888
2336
  // src/image-generation/imagesConfigValidation.ts
889
2337
  var import_outbound_api = require("@omnicross/core/outbound-api");
@@ -1179,6 +2627,7 @@ async function applyServerConfigTransaction(current, next, deps) {
1179
2627
 
1180
2628
  // src/config.ts
1181
2629
  var import_node_fs4 = require("fs");
2630
+ var import_core = require("@omnicross/core");
1182
2631
 
1183
2632
  // src/secrets/envelope.ts
1184
2633
  var import_node_crypto4 = require("crypto");
@@ -1590,6 +3039,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
1590
3039
  "openai-response",
1591
3040
  "gemini-code-assist"
1592
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
+ }
1593
3054
  function validateApiKeys(raw) {
1594
3055
  if (!Array.isArray(raw)) return void 0;
1595
3056
  const out = [];
@@ -1803,6 +3264,9 @@ function validateProvider(raw, index) {
1803
3264
  apiVersion,
1804
3265
  maxConcurrency,
1805
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"]),
1806
3270
  // Provider transformer config (app-parity child 5): load-guard, collapse-to-
1807
3271
  // undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
1808
3272
  // Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
@@ -1872,7 +3336,7 @@ var import_node_crypto6 = require("crypto");
1872
3336
  var import_node_fs6 = require("fs");
1873
3337
  var import_node_os3 = require("os");
1874
3338
  var import_node_path6 = require("path");
1875
- var import_core = require("@omnicross/core");
3339
+ var import_core2 = require("@omnicross/core");
1876
3340
 
1877
3341
  // src/integrations/codexAuthHelper.ts
1878
3342
  var import_node_path4 = require("path");
@@ -2353,7 +3817,7 @@ var IntegrationManager = class {
2353
3817
  if (!secret) {
2354
3818
  throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
2355
3819
  }
2356
- const effective = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
3820
+ const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
2357
3821
  const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
2358
3822
  const nextPermissions = [...effective];
2359
3823
  for (const required of REQUIRED_PERMISSIONS[client]) {
@@ -2451,7 +3915,7 @@ var IntegrationManager = class {
2451
3915
  return { binding, row, secret, created: false };
2452
3916
  }
2453
3917
  async createManagedClientKey(client, state) {
2454
- const created = await (0, import_core.createIntegrationKey)(
3918
+ const created = await (0, import_core2.createIntegrationKey)(
2455
3919
  this.options.keyDb,
2456
3920
  `Omnicross ${displayClient(client)} integration`,
2457
3921
  [...REQUIRED_PERMISSIONS[client]]
@@ -2543,7 +4007,7 @@ var IntegrationManager = class {
2543
4007
  const row = rows.find((candidate) => candidate.id === keyId);
2544
4008
  if (!row) return { usable: false, message: "The bound access key no longer exists." };
2545
4009
  const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
2546
- const allowedEndpoints = [...(0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints)];
4010
+ const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
2547
4011
  const status = {
2548
4012
  id: row.id,
2549
4013
  name: row.name,
@@ -2587,7 +4051,7 @@ var IntegrationManager = class {
2587
4051
  }
2588
4052
  };
2589
4053
  function hasRequiredPermissions(row, client) {
2590
- const allowed = (0, import_core.effectiveOutboundPermissions)(row.allowedEndpoints);
4054
+ const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
2591
4055
  return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
2592
4056
  }
2593
4057
  function samePermissions(a, b) {
@@ -2761,7 +4225,8 @@ function listMappablePresets() {
2761
4225
  description: preset.description,
2762
4226
  features: preset.features,
2763
4227
  website: preset.website,
2764
- modelsEndpoint: preset.modelsEndpoint
4228
+ modelsEndpoint: preset.modelsEndpoint,
4229
+ extraHeaders: preset.extraHeaders
2765
4230
  });
2766
4231
  }
2767
4232
  return { mappable, excluded };
@@ -2851,11 +4316,11 @@ function preserveOutboundProxySecrets(incoming, current) {
2851
4316
  }
2852
4317
 
2853
4318
  // src/proxy/upstreamProxyResolver.ts
2854
- var import_upstreamFetch2 = require("@omnicross/core/pipeline/upstreamFetch");
4319
+ var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
2855
4320
  var serverProxy;
2856
4321
  function setServerProxyConfig(proxy) {
2857
4322
  serverProxy = proxy;
2858
- (0, import_upstreamFetch2.bumpUpstreamProxyGeneration)();
4323
+ (0, import_upstreamFetch7.bumpUpstreamProxyGeneration)();
2859
4324
  }
2860
4325
  function getServerProxyConfig() {
2861
4326
  return serverProxy;
@@ -2923,14 +4388,17 @@ function createUpstreamProxyResolver(src = {}) {
2923
4388
  }
2924
4389
 
2925
4390
  // src/admin/accountsOAuth.ts
2926
- var import_subscriptions2 = require("@omnicross/subscriptions");
4391
+ var import_subscriptions8 = require("@omnicross/subscriptions");
2927
4392
 
2928
4393
  // src/admin/accountsWrite.ts
2929
4394
  var VALID_PROVIDER_IDS = [
2930
4395
  "claude",
2931
4396
  "codex",
2932
4397
  "gemini",
2933
- "opencodego"
4398
+ "opencodego",
4399
+ "kimi",
4400
+ "grok",
4401
+ "copilot"
2934
4402
  ];
2935
4403
  function asSubscriptionProviderId(id) {
2936
4404
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -3066,6 +4534,52 @@ function validateGemini(body) {
3066
4534
  copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "lastRefreshedAt", "errorMessage"]);
3067
4535
  return out;
3068
4536
  }
4537
+ function validateKimi(body) {
4538
+ const authMethod = str(body["authMethod"]);
4539
+ const status = str(body["status"]);
4540
+ if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
4541
+ if (!status || !TOKEN_STATUSES.has(status)) return null;
4542
+ const out = {
4543
+ authMethod,
4544
+ status
4545
+ };
4546
+ copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
4547
+ return out;
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
+ }
3069
4583
  function validateOpenCodeGo(body) {
3070
4584
  const authMethod = str(body["authMethod"]);
3071
4585
  const status = str(body["status"]);
@@ -3101,6 +4615,12 @@ function validateTokenBody(providerId, body) {
3101
4615
  return validateGemini(body);
3102
4616
  case "opencodego":
3103
4617
  return validateOpenCodeGo(body);
4618
+ case "kimi":
4619
+ return validateKimi(body);
4620
+ case "grok":
4621
+ return validateGrok(body);
4622
+ case "copilot":
4623
+ return validateCopilot(body);
3104
4624
  default:
3105
4625
  return null;
3106
4626
  }
@@ -3130,37 +4650,37 @@ async function statusEntryFor(reader, providerId) {
3130
4650
 
3131
4651
  // src/admin/accountsOAuth.ts
3132
4652
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
3133
- function err2(status, message) {
4653
+ function err5(status, message) {
3134
4654
  return { status, body: { error: { type: "admin_api_error", message } } };
3135
4655
  }
3136
4656
  function handleOAuthStart(providerId, deps) {
3137
4657
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3138
- return err2(400, `oauth not available for provider '${providerId}'`);
4658
+ return err5(400, `oauth not available for provider '${providerId}'`);
3139
4659
  }
3140
- const flow = providerId === "claude" ? import_subscriptions2.claudeOAuth : import_subscriptions2.geminiOAuth;
4660
+ const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
3141
4661
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
3142
4662
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
3143
4663
  return { status: 200, body: { authUrl, sessionId } };
3144
4664
  }
3145
4665
  async function handleOAuthComplete(providerId, body, deps) {
3146
4666
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
3147
- return err2(400, `oauth not available for provider '${providerId}'`);
4667
+ return err5(400, `oauth not available for provider '${providerId}'`);
3148
4668
  }
3149
4669
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
3150
4670
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
3151
- if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
3152
- if (!rawCode) return err2(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 }");
3153
4673
  const session = deps.oauthSessions.peek(sessionId);
3154
- if (!session) return err2(410, "oauth session is unknown, expired, or already used");
4674
+ if (!session) return err5(410, "oauth session is unknown, expired, or already used");
3155
4675
  if (session.providerId !== providerId) {
3156
- return err2(400, `oauth session does not match provider '${providerId}'`);
4676
+ return err5(400, `oauth session does not match provider '${providerId}'`);
3157
4677
  }
3158
4678
  let code = rawCode.trim();
3159
4679
  if (providerId === "claude") {
3160
4680
  const [splitCode, pastedState] = code.split("#");
3161
- if (!splitCode) return err2(400, "no authorization code was provided");
4681
+ if (!splitCode) return err5(400, "no authorization code was provided");
3162
4682
  if (pastedState && pastedState !== session.state) {
3163
- return err2(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4683
+ return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
3164
4684
  }
3165
4685
  code = splitCode;
3166
4686
  }
@@ -3170,7 +4690,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3170
4690
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
3171
4691
  } catch (exchangeError) {
3172
4692
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
3173
- return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4693
+ return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
3174
4694
  }
3175
4695
  deps.oauthSessions.consume(sessionId);
3176
4696
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -3179,7 +4699,7 @@ async function handleOAuthComplete(providerId, body, deps) {
3179
4699
  return { status: 200, body: status ? { account: status } : { ok: true } };
3180
4700
  }
3181
4701
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3182
- const result = await import_subscriptions2.claudeOAuth.exchangeCodeForTokens(
4702
+ const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
3183
4703
  { authorizationCode: code, codeVerifier, state },
3184
4704
  exchangeFetch
3185
4705
  );
@@ -3195,7 +4715,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
3195
4715
  };
3196
4716
  }
3197
4717
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
3198
- const result = await import_subscriptions2.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
4718
+ const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
3199
4719
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
3200
4720
  return {
3201
4721
  authMethod: "oauth",
@@ -3500,8 +5020,8 @@ function errBody(message) {
3500
5020
  return { error: { type: "admin_api_error", message } };
3501
5021
  }
3502
5022
  var defaultCommandRunner = (command) => new Promise((resolve10) => {
3503
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err5, _stdout, stderr) => {
3504
- if (err5) resolve10({ ok: false, error: stderr.trim() || err5.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 });
3505
5025
  else resolve10({ ok: true });
3506
5026
  });
3507
5027
  });
@@ -3547,8 +5067,8 @@ async function handleCliLaunch(cli, body, ctx) {
3547
5067
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
3548
5068
  model: typeof body["model"] === "string" ? body["model"] : void 0
3549
5069
  });
3550
- } catch (err5) {
3551
- return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
5070
+ } catch (err8) {
5071
+ return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
3552
5072
  }
3553
5073
  const id = (0, import_node_crypto7.randomUUID)();
3554
5074
  let leaseId2;
@@ -3576,9 +5096,9 @@ async function handleCliLaunch(cli, body, ctx) {
3576
5096
  } else {
3577
5097
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3578
5098
  }
3579
- } catch (err5) {
3580
- const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
3581
- return { status, body: errBody(err5 instanceof Error ? err5.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") };
3582
5102
  }
3583
5103
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
3584
5104
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -3606,9 +5126,9 @@ async function handleCliLaunch(cli, body, ctx) {
3606
5126
  onFailure: onSessionEnd
3607
5127
  });
3608
5128
  if (cleanup) openerCleanup = cleanup;
3609
- } catch (err5) {
5129
+ } catch (err8) {
3610
5130
  onSessionEnd();
3611
- return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
5131
+ return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
3612
5132
  }
3613
5133
  if (ended) {
3614
5134
  openerCleanup?.();
@@ -3849,7 +5369,7 @@ function classifySearchFailure(stage, code) {
3849
5369
  }
3850
5370
 
3851
5371
  // src/search/SearchAssembly.ts
3852
- var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
5372
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
3853
5373
  var import_search = require("@omnicross/core/search");
3854
5374
  var import_api2 = require("@omnicross/core/search/api");
3855
5375
  var import_http2 = require("@omnicross/core/search/http");
@@ -3867,7 +5387,7 @@ function searchPolicyFrom(config) {
3867
5387
  };
3868
5388
  }
3869
5389
  function resolveSearchUpstreamDispatcher(url) {
3870
- return (0, import_upstreamFetch3.resolveUpstreamDispatcher)({ url });
5390
+ return (0, import_upstreamFetch8.resolveUpstreamDispatcher)({ url });
3871
5391
  }
3872
5392
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
3873
5393
  function resolveSearchUpstreamProxyConfig(url) {
@@ -4149,7 +5669,7 @@ async function handleSearchQuery(req, res, deps) {
4149
5669
  // src/admin/searchAdminView.ts
4150
5670
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
4151
5671
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
4152
- function isRecord(value) {
5672
+ function isRecord4(value) {
4153
5673
  return value !== null && typeof value === "object" && !Array.isArray(value);
4154
5674
  }
4155
5675
  function redactSearchServerConfig(search) {
@@ -4199,13 +5719,13 @@ function resolveSecretField(entry, field, stored) {
4199
5719
  else delete entry[field];
4200
5720
  }
4201
5721
  function preserveSearchSecrets(incoming, current) {
4202
- if (!isRecord(incoming)) return incoming;
5722
+ if (!isRecord4(incoming)) return incoming;
4203
5723
  const section = { ...incoming };
4204
5724
  const providersValue = section["providers"];
4205
- if (!isRecord(providersValue)) return section;
5725
+ if (!isRecord4(providersValue)) return section;
4206
5726
  const providers = {};
4207
5727
  for (const [id, entryValue] of Object.entries(providersValue)) {
4208
- if (!isRecord(entryValue)) {
5728
+ if (!isRecord4(entryValue)) {
4209
5729
  providers[id] = entryValue;
4210
5730
  continue;
4211
5731
  }
@@ -4283,7 +5803,7 @@ function parseKeyPolicyBody(body) {
4283
5803
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
4284
5804
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
4285
5805
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
4286
- function isRecord2(value) {
5806
+ function isRecord5(value) {
4287
5807
  return !!value && typeof value === "object" && !Array.isArray(value);
4288
5808
  }
4289
5809
  function nonBlank(value) {
@@ -4303,7 +5823,7 @@ function validateGatewayBindingsSegment(patch) {
4303
5823
  const ids = /* @__PURE__ */ new Set();
4304
5824
  raw.forEach((entry, index) => {
4305
5825
  const path2 = `bindings[${index}]`;
4306
- if (!isRecord2(entry)) {
5826
+ if (!isRecord5(entry)) {
4307
5827
  errors.push(`${path2} must be an object`);
4308
5828
  return;
4309
5829
  }
@@ -4332,12 +5852,12 @@ function validateGatewayBindingsSegment(patch) {
4332
5852
  } else if (entry.modelMappings.length > 100) {
4333
5853
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
4334
5854
  } else if (entry.modelMappings.some(
4335
- (mapping) => !isRecord2(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
5855
+ (mapping) => !isRecord5(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
4336
5856
  )) {
4337
5857
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
4338
5858
  }
4339
5859
  }
4340
- if (!isRecord2(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
5860
+ if (!isRecord5(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
4341
5861
  errors.push(`${path2}.target is invalid`);
4342
5862
  } else {
4343
5863
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -4352,7 +5872,7 @@ function validateGatewayBindingsSegment(patch) {
4352
5872
  }
4353
5873
  }
4354
5874
  if (entry.modelMap !== void 0) {
4355
- if (!isRecord2(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")) {
4356
5876
  errors.push(`${path2}.modelMap must contain string values`);
4357
5877
  }
4358
5878
  }
@@ -4650,7 +6170,10 @@ var PROVIDER_KEYS = {
4650
6170
  block: "opencodego",
4651
6171
  accounts: "opencodegoAccounts",
4652
6172
  active: "activeOpencodegoAccountId"
4653
- }
6173
+ },
6174
+ kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6175
+ grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6176
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
4654
6177
  };
4655
6178
  function clone(value) {
4656
6179
  return JSON.parse(JSON.stringify(value));
@@ -5172,7 +6695,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
5172
6695
  }
5173
6696
 
5174
6697
  // src/admin/adminMigration.ts
5175
- function err3(status, message) {
6698
+ function err6(status, message) {
5176
6699
  return { status, body: { error: { type: "admin_api_error", message } } };
5177
6700
  }
5178
6701
  async function handleExport(body, deps) {
@@ -5182,30 +6705,30 @@ async function handleExport(body, deps) {
5182
6705
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
5183
6706
  } catch (error) {
5184
6707
  if (error instanceof WeakPassphraseError) {
5185
- return err3(400, error.message);
6708
+ return err6(400, error.message);
5186
6709
  }
5187
- return err3(500, "failed to build the migration pack");
6710
+ return err6(500, "failed to build the migration pack");
5188
6711
  }
5189
6712
  }
5190
6713
  async function handleImport(body, deps) {
5191
6714
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
5192
6715
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
5193
6716
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
5194
- if (!blob) return err3(400, "import requires { blob }");
6717
+ if (!blob) return err6(400, "import requires { blob }");
5195
6718
  try {
5196
6719
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
5197
6720
  return { status: 200, body: counts };
5198
6721
  } catch (error) {
5199
6722
  if (error instanceof WeakPassphraseError) {
5200
- return err3(400, error.message);
6723
+ return err6(400, error.message);
5201
6724
  }
5202
- return err3(400, error instanceof Error ? error.message : "import failed");
6725
+ return err6(400, error instanceof Error ? error.message : "import failed");
5203
6726
  }
5204
6727
  }
5205
6728
 
5206
6729
  // src/admin/usagePricing.ts
5207
6730
  var import_usage = require("@omnicross/core/usage");
5208
- var err4 = (status, message) => ({
6731
+ var err7 = (status, message) => ({
5209
6732
  status,
5210
6733
  body: { error: { type: "admin_api_error", message } }
5211
6734
  });
@@ -5218,7 +6741,7 @@ function parseRange(query2) {
5218
6741
  const startTs = parseFiniteInt(query2.get("startTs"));
5219
6742
  const endTs = parseFiniteInt(query2.get("endTs"));
5220
6743
  if (startTs === null || endTs === null) {
5221
- return err4(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");
5222
6745
  }
5223
6746
  return { startTs, endTs };
5224
6747
  }
@@ -5243,14 +6766,14 @@ async function handleUsageGet(view, query2, deps) {
5243
6766
  case "timeseries": {
5244
6767
  const bucket = query2.get("bucket");
5245
6768
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
5246
- return err4(400, "bucket must be one of 'hour', 'day', 'month'");
6769
+ return err7(400, "bucket must be one of 'hour', 'day', 'month'");
5247
6770
  }
5248
6771
  const now = Date.now();
5249
6772
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
5250
6773
  if (clamped.startTs < clamped.endTs) {
5251
6774
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
5252
6775
  if (projected > MAX_TIMESERIES_BUCKETS) {
5253
- return err4(
6776
+ return err7(
5254
6777
  400,
5255
6778
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
5256
6779
  );
@@ -5273,7 +6796,7 @@ async function handleUsageGet(view, query2, deps) {
5273
6796
  };
5274
6797
  }
5275
6798
  default:
5276
- return err4(404, `unknown usage view '${view ?? ""}'`);
6799
+ return err7(404, `unknown usage view '${view ?? ""}'`);
5277
6800
  }
5278
6801
  }
5279
6802
  function poolKeyLabels(cfg) {
@@ -5322,7 +6845,7 @@ async function handlePricingList(deps) {
5322
6845
  async function handlePricingUpsert(body, deps) {
5323
6846
  const input = parsePricingEntryInput(body);
5324
6847
  if (!input) {
5325
- return err4(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)");
5326
6849
  }
5327
6850
  const entry = await deps.pricingEngine.upsertManual(input);
5328
6851
  return { status: 200, body: { entry } };
@@ -5331,7 +6854,7 @@ async function handlePricingDelete(query2, deps) {
5331
6854
  const providerId = query2.get("providerId")?.trim() ?? "";
5332
6855
  const modelId = query2.get("modelId")?.trim() ?? "";
5333
6856
  if (!providerId || !modelId) {
5334
- return err4(400, "delete requires providerId and modelId query params");
6857
+ return err7(400, "delete requires providerId and modelId query params");
5335
6858
  }
5336
6859
  const deleted = await deps.pricingStore.delete(providerId, modelId);
5337
6860
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -5351,13 +6874,13 @@ async function handlePricingFetchLatest(deps) {
5351
6874
  }
5352
6875
  };
5353
6876
  } catch (e) {
5354
- return err4(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)}`);
5355
6878
  }
5356
6879
  }
5357
6880
  async function handlePricingResolveConflicts(body, deps) {
5358
6881
  const raw = body["resolutions"];
5359
6882
  if (!Array.isArray(raw)) {
5360
- return err4(400, "resolve-conflicts requires { resolutions: [...] }");
6883
+ return err7(400, "resolve-conflicts requires { resolutions: [...] }");
5361
6884
  }
5362
6885
  const currentRows = await deps.pricingStore.getAll();
5363
6886
  const userEditedKeys = new Set(
@@ -5367,21 +6890,21 @@ async function handlePricingResolveConflicts(body, deps) {
5367
6890
  const pendingIncoming = /* @__PURE__ */ new Map();
5368
6891
  let staleCount = 0;
5369
6892
  for (const item of raw) {
5370
- if (!item || typeof item !== "object") return err4(400, "invalid resolution entry");
6893
+ if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
5371
6894
  const r = item;
5372
6895
  const action = r["action"];
5373
6896
  if (action !== "overwrite" && action !== "skip") {
5374
- return err4(400, "resolution action must be 'overwrite' or 'skip'");
6897
+ return err7(400, "resolution action must be 'overwrite' or 'skip'");
5375
6898
  }
5376
6899
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
5377
6900
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
5378
6901
  if (!providerId || !modelId) {
5379
- return err4(400, "each resolution requires top-level providerId and modelId");
6902
+ return err7(400, "each resolution requires top-level providerId and modelId");
5380
6903
  }
5381
6904
  const incoming = parsePricingEntryInput(r["incoming"]);
5382
- if (!incoming) return err4(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");
5383
6906
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
5384
- return err4(400, "resolution providerId/modelId must match the echoed incoming entry");
6907
+ return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
5385
6908
  }
5386
6909
  const key = `${providerId}::${modelId}`;
5387
6910
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -5426,7 +6949,7 @@ function query(req) {
5426
6949
  }
5427
6950
  function allowanceProvider(value) {
5428
6951
  if (!value) return void 0;
5429
- return value === "claude" || value === "codex" ? value : null;
6952
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" ? value : null;
5430
6953
  }
5431
6954
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
5432
6955
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -5440,7 +6963,9 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
5440
6963
  const params = query(req);
5441
6964
  const pathProvider = rest.length >= 2 ? rest[0] : null;
5442
6965
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
5443
- if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
6966
+ if (providerId === null) {
6967
+ return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, or copilot");
6968
+ }
5444
6969
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
5445
6970
  const allowances = await service.list({ providerId, accountId });
5446
6971
  return writeJson3(res, 200, { allowances });
@@ -5450,10 +6975,57 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
5450
6975
  const requestedProvider = allowanceProvider(
5451
6976
  typeof body["providerId"] === "string" ? body["providerId"] : "claude"
5452
6977
  );
5453
- if (requestedProvider !== "claude") {
5454
- return writeError2(res, 400, "only Claude allowances support explicit refresh");
6978
+ const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
6979
+ if (requestedProvider === "codex") {
6980
+ if (!service.refreshCodex) {
6981
+ return writeError2(res, 501, "codex allowance refresh is not available");
6982
+ }
6983
+ const allowances2 = await service.refreshCodex(accountId);
6984
+ if (accountId && allowances2.length === 0) {
6985
+ return writeError2(res, 404, `Codex account '${accountId}' not found`);
6986
+ }
6987
+ return writeJson3(res, 200, { allowances: allowances2 });
6988
+ }
6989
+ if (requestedProvider === "kimi") {
6990
+ if (!service.refreshKimi) {
6991
+ return writeError2(res, 501, "kimi allowance refresh is not available");
6992
+ }
6993
+ const allowances2 = await service.refreshKimi(accountId);
6994
+ if (accountId && allowances2.length === 0) {
6995
+ return writeError2(res, 404, `Kimi account '${accountId}' not found`);
6996
+ }
6997
+ return writeJson3(res, 200, { allowances: allowances2 });
6998
+ }
6999
+ if (requestedProvider === "opencodego") {
7000
+ if (!service.refreshOpenCodeGo) {
7001
+ return writeError2(res, 501, "opencodego allowance refresh is not available");
7002
+ }
7003
+ const allowances2 = await service.refreshOpenCodeGo(accountId);
7004
+ if (accountId && allowances2.length === 0) {
7005
+ return writeError2(res, 404, `OpenCodeGo account '${accountId}' not found`);
7006
+ }
7007
+ return writeJson3(res, 200, { allowances: allowances2 });
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 });
5455
7028
  }
5456
- const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
5457
7029
  const allowances = await service.refreshClaude(accountId);
5458
7030
  if (accountId && allowances.length === 0) {
5459
7031
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
@@ -5552,6 +7124,9 @@ function toProviderView(row) {
5552
7124
  apiVersion: row.apiVersion,
5553
7125
  maxConcurrency: row.maxConcurrency,
5554
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,
5555
7130
  // app-parity child 5: transformer config round-trips VERBATIM (non-secret —
5556
7131
  // transform-rule names + options, no key material; absent stays absent).
5557
7132
  transformer: row.transformer,
@@ -5621,8 +7196,8 @@ async function handleAdminApi(req, res, path2, deps) {
5621
7196
  default:
5622
7197
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
5623
7198
  }
5624
- } catch (err5) {
5625
- writeJsonError(res, 500, err5 instanceof Error ? err5.message : String(err5));
7199
+ } catch (err8) {
7200
+ writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
5626
7201
  }
5627
7202
  }
5628
7203
  function requestQuery(req) {
@@ -5692,6 +7267,9 @@ async function handleProviders(req, res, method, rest, deps) {
5692
7267
  if (method === "POST" && rest.length === 4 && rest[1] === "keys" && rest[3] === "enabled") {
5693
7268
  return await handleToggleProviderKey(req, res, rest[0], rest[2], cfg, deps);
5694
7269
  }
7270
+ if (method === "POST" && rest.length === 5 && rest[1] === "keys" && rest[3] === "quota" && rest[4] === "refresh") {
7271
+ return await handleProviderKeyQuotaRefresh(res, rest[0], rest[2], cfg, deps);
7272
+ }
5695
7273
  if (method === "PUT" && rest.length === 3 && rest[1] === "keys") {
5696
7274
  return await handleUpdateProviderKey(req, res, rest[0], rest[2], cfg, deps);
5697
7275
  }
@@ -5777,6 +7355,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
5777
7355
  persistProviders(cfg, deps);
5778
7356
  return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
5779
7357
  }
7358
+ function expandRowExtraHeaders(row) {
7359
+ return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
7360
+ }
5780
7361
  async function handleDiscoverModels(res, id, cfg) {
5781
7362
  if (!id) return writeJsonError(res, 400, "provider id required in path");
5782
7363
  const row = cfg.providers.find((p) => p.id === id);
@@ -5790,7 +7371,8 @@ async function handleDiscoverModels(res, id, cfg) {
5790
7371
  try {
5791
7372
  const headers = { Accept: "application/json" };
5792
7373
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
5793
- const response = await (0, import_upstreamFetch4.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" });
5794
7376
  if (!response.ok) {
5795
7377
  const text = await response.text().catch(() => "");
5796
7378
  let message = text.slice(0, 300);
@@ -5807,8 +7389,8 @@ async function handleDiscoverModels(res, id, cfg) {
5807
7389
  const data = await response.json();
5808
7390
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
5809
7391
  return writeJson4(res, 200, { models });
5810
- } catch (err5) {
5811
- const message = err5 instanceof Error ? err5.message : String(err5);
7392
+ } catch (err8) {
7393
+ const message = err8 instanceof Error ? err8.message : String(err8);
5812
7394
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
5813
7395
  }
5814
7396
  }
@@ -5847,9 +7429,10 @@ async function handleTestModel(req, res, id, cfg) {
5847
7429
  messages: [{ role: "user", content: prompt }]
5848
7430
  };
5849
7431
  }
7432
+ Object.assign(headers, expandRowExtraHeaders(row));
5850
7433
  const startedAt = Date.now();
5851
7434
  try {
5852
- const response = await (0, import_upstreamFetch4.fetchUpstream)(
7435
+ const response = await (0, import_upstreamFetch9.fetchUpstream)(
5853
7436
  url,
5854
7437
  { method: "POST", headers, body: JSON.stringify(payload) },
5855
7438
  { providerId: "byo" }
@@ -5871,8 +7454,8 @@ async function handleTestModel(req, res, id, cfg) {
5871
7454
  latencyMs,
5872
7455
  sample: extractSampleText(text, row.apiFormat)
5873
7456
  });
5874
- } catch (err5) {
5875
- const message = err5 instanceof Error ? err5.message : String(err5);
7457
+ } catch (err8) {
7458
+ const message = err8 instanceof Error ? err8.message : String(err8);
5876
7459
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
5877
7460
  }
5878
7461
  }
@@ -5914,7 +7497,30 @@ async function handleProviderKeys(res, id, cfg, deps) {
5914
7497
  const row = cfg.providers.find((p) => p.id === id);
5915
7498
  if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
5916
7499
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
5917
- return writeJson4(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
7500
+ const views = toPoolKeyView(row, cooldown, deps);
7501
+ if (deps.providerKeyQuota) {
7502
+ const quotas = await Promise.allSettled(
7503
+ views.map((view) => deps.providerKeyQuota.quotaFor(row, view.id))
7504
+ );
7505
+ views.forEach((view, index) => {
7506
+ const settled = quotas[index];
7507
+ if (settled.status === "fulfilled" && settled.value) view.quota = settled.value;
7508
+ });
7509
+ }
7510
+ return writeJson4(res, 200, { keys: views });
7511
+ }
7512
+ async function handleProviderKeyQuotaRefresh(res, id, keyId, cfg, deps) {
7513
+ if (!deps.providerKeyQuota) return writeJsonError(res, 501, "provider key quota is not available");
7514
+ if (!id || !keyId) return writeJsonError(res, 400, "provider id and key id required in path");
7515
+ const row = cfg.providers.find((p) => p.id === id);
7516
+ if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
7517
+ try {
7518
+ const quota = await deps.providerKeyQuota.quotaFor(row, keyId, { force: true });
7519
+ if (!quota) return writeJsonError(res, 404, `no quota endpoint for key '${keyId}'`);
7520
+ return writeJson4(res, 200, { quota });
7521
+ } catch {
7522
+ return writeJsonError(res, 502, "quota refresh failed");
7523
+ }
5918
7524
  }
5919
7525
  function parsePoolKeyInput(body, existing) {
5920
7526
  const out = {};
@@ -6131,6 +7737,7 @@ function parseProviderInput(body, existing) {
6131
7737
  const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
6132
7738
  const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
6133
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"]);
6134
7741
  const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
6135
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;
6136
7743
  const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
@@ -6156,6 +7763,7 @@ function parseProviderInput(body, existing) {
6156
7763
  apiVersion,
6157
7764
  maxConcurrency,
6158
7765
  modelsEndpoint,
7766
+ extraHeaders,
6159
7767
  transformer: migrated.transformer,
6160
7768
  codingPlan,
6161
7769
  apiModes,
@@ -6177,7 +7785,10 @@ function handlePresets(res, method) {
6177
7785
  description: p.description,
6178
7786
  features: p.features,
6179
7787
  website: p.website,
6180
- 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
6181
7792
  }));
6182
7793
  return writeJson4(res, 200, { presets, excluded });
6183
7794
  }
@@ -6659,12 +8270,12 @@ async function handleAccounts(req, res, method, rest, deps) {
6659
8270
  }
6660
8271
  return writeJson4(res, 200, { ok: true, affected: result.affected });
6661
8272
  }
6662
- if (method === "GET" && rest[0] === "codex" && rest[1] === "oauth" && rest[3] === "status") {
6663
- const result = handleCodexOAuthStatus(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);
6664
8275
  return writeJson4(res, result.status, result.body);
6665
8276
  }
6666
- if (method === "DELETE" && rest[0] === "codex" && rest[1] === "oauth" && rest[2]) {
6667
- const result = handleCodexOAuthCancel(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);
6668
8279
  return writeJson4(res, result.status, result.body);
6669
8280
  }
6670
8281
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -6717,7 +8328,24 @@ async function handleAccounts(req, res, method, rest, deps) {
6717
8328
  return writeJsonError(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
6718
8329
  }
6719
8330
  if (method === "POST" && rest[1] === "oauth" && rest[2] === "start") {
6720
- const result = providerId === "codex" ? handleCodexOAuthStart(deps) : handleOAuthStart(providerId, deps);
8331
+ if (providerId === "codex") {
8332
+ const result2 = handleCodexOAuthStart(deps);
8333
+ return writeJson4(res, result2.status, result2.body);
8334
+ }
8335
+ if (providerId === "kimi") {
8336
+ const result2 = await handleKimiOAuthStart(deps);
8337
+ return writeJson4(res, result2.status, result2.body);
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
+ }
8348
+ const result = handleOAuthStart(providerId, deps);
6721
8349
  return writeJson4(res, result.status, result.body);
6722
8350
  }
6723
8351
  if (method === "POST" && rest[1] === "oauth" && rest[2] === "complete") {
@@ -7211,12 +8839,12 @@ async function handlePlayground(req, res, method, deps) {
7211
8839
  const payload = body["body"];
7212
8840
  const status = deps.outboundApiServer.getStatus();
7213
8841
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
7214
- const path2 = resolvePlaygroundPath(endpoint, isRecord3(payload) ? payload : {});
8842
+ const path2 = resolvePlaygroundPath(endpoint, isRecord6(payload) ? payload : {});
7215
8843
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
7216
8844
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
7217
8845
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
7218
8846
  }
7219
- function isRecord3(v) {
8847
+ function isRecord6(v) {
7220
8848
  return !!v && typeof v === "object" && !Array.isArray(v);
7221
8849
  }
7222
8850
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -7245,8 +8873,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
7245
8873
  });
7246
8874
  }
7247
8875
  );
7248
- upstream.on("error", (err5) => {
7249
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err5.message}`);
8876
+ upstream.on("error", (err8) => {
8877
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
7250
8878
  else res.end();
7251
8879
  resolve10();
7252
8880
  });
@@ -7352,7 +8980,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
7352
8980
  }
7353
8981
 
7354
8982
  // src/admin/version.ts
7355
- var DAEMON_VERSION = true ? "0.3.0" : "0.0.0-dev";
8983
+ var DAEMON_VERSION = true ? "0.4.0" : "0.0.0-dev";
7356
8984
 
7357
8985
  // src/admin/AdminServer.ts
7358
8986
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -7395,13 +9023,13 @@ var AdminServer = class {
7395
9023
  const server = import_node_http2.default.createServer((req, res) => {
7396
9024
  this.onRequest(req, res);
7397
9025
  });
7398
- const onError = (err5) => {
7399
- if (err5.code === "EADDRINUSE" && port !== 0) {
9026
+ const onError = (err8) => {
9027
+ if (err8.code === "EADDRINUSE" && port !== 0) {
7400
9028
  server.removeListener("error", onError);
7401
9029
  this.listen(bindAddr, 0).then(resolve10, reject);
7402
9030
  return;
7403
9031
  }
7404
- reject(err5);
9032
+ reject(err8);
7405
9033
  };
7406
9034
  server.on("error", onError);
7407
9035
  server.listen(port, bindAddr, () => {
@@ -7419,8 +9047,8 @@ var AdminServer = class {
7419
9047
  }
7420
9048
  /** Per-request handler: auth gate (when a token is set) → routing. */
7421
9049
  onRequest(req, res) {
7422
- void this.dispatch(req, res).catch((err5) => {
7423
- const message = err5 instanceof Error ? err5.message : String(err5);
9050
+ void this.dispatch(req, res).catch((err8) => {
9051
+ const message = err8 instanceof Error ? err8.message : String(err8);
7424
9052
  this.deps.logger.error("[AdminServer] unhandled error:", message);
7425
9053
  if (!res.headersSent) {
7426
9054
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -7684,18 +9312,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
7684
9312
  return;
7685
9313
  }
7686
9314
  signal?.addEventListener("abort", abort, { once: true });
7687
- server.on("error", (err5) => {
9315
+ server.on("error", (err8) => {
7688
9316
  if (settled) return;
7689
9317
  settled = true;
7690
9318
  clearTimeout(timer);
7691
- if (err5.code === "EADDRINUSE") {
9319
+ if (err8.code === "EADDRINUSE") {
7692
9320
  reject(
7693
9321
  new Error(
7694
9322
  `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
7695
9323
  )
7696
9324
  );
7697
9325
  } else {
7698
- reject(err5);
9326
+ reject(err8);
7699
9327
  }
7700
9328
  });
7701
9329
  const timer = setTimeout(() => {
@@ -7770,6 +9398,449 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
7770
9398
  };
7771
9399
  }
7772
9400
 
9401
+ // src/allowance/ProviderKeyQuotaService.ts
9402
+ var import_core4 = require("@omnicross/core");
9403
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
9404
+
9405
+ // src/allowance/ProviderKeyQuota.ts
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) {
9412
+ if (value === null || value === void 0 || value === "") return void 0;
9413
+ const parsed = typeof value === "number" ? value : Number(value);
9414
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
9415
+ }
9416
+ function finitePercent4(value) {
9417
+ const parsed = finiteNumber5(value);
9418
+ return parsed !== void 0 && parsed <= 100 ? parsed : null;
9419
+ }
9420
+ function isoInstant3(value) {
9421
+ if (typeof value === "string" && value.trim()) {
9422
+ const time = Date.parse(value);
9423
+ if (Number.isFinite(time)) return new Date(time).toISOString();
9424
+ }
9425
+ const numeric = finiteNumber5(value);
9426
+ if (numeric !== void 0 && numeric > 1e9) {
9427
+ const ms = numeric > 1e12 ? numeric : numeric * 1e3;
9428
+ return new Date(ms).toISOString();
9429
+ }
9430
+ return void 0;
9431
+ }
9432
+ function secondsUntil7(instant, now) {
9433
+ if (!instant) return void 0;
9434
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
9435
+ }
9436
+ function isRecord7(value) {
9437
+ return !!value && typeof value === "object" && !Array.isArray(value);
9438
+ }
9439
+ function detectProviderKeyQuotaAdapter(baseUrl) {
9440
+ if (!baseUrl) return null;
9441
+ let url;
9442
+ try {
9443
+ url = new URL(baseUrl);
9444
+ } catch {
9445
+ return null;
9446
+ }
9447
+ const host = url.hostname.toLowerCase();
9448
+ const path2 = url.pathname.toLowerCase();
9449
+ if ((host === "api.z.ai" || host === "open.bigmodel.cn") && path2.includes("/coding")) {
9450
+ return "zai";
9451
+ }
9452
+ if ((host === "api.minimax.io" || host === "api.minimaxi.com") && // Token Plan rides the plain openai `/v1` (chat completions) surface; the
9453
+ // anthropic `/anthropic` rows are excluded (their usage impl is unverified).
9454
+ (path2 === "/v1" || path2 === "/v1/" || path2 === "" || path2 === "/")) {
9455
+ return "minimax-token-plan";
9456
+ }
9457
+ if (host === "api.code.umans.ai") return "umans";
9458
+ if (host === "api.synthetic.new") return "synthetic";
9459
+ if (host === "api.cline.bot") return "cline-pass";
9460
+ return null;
9461
+ }
9462
+ function providerKeyQuotaUrl(adapter, baseUrl) {
9463
+ const origin = new URL(baseUrl).origin;
9464
+ if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
9465
+ if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
9466
+ if (adapter === "umans") return `${origin}/v1/usage`;
9467
+ if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
9468
+ return `${origin}/v2/quotas`;
9469
+ }
9470
+ function providerKeyQuotaAuthHeader(adapter, key) {
9471
+ return adapter === "zai" ? key : `Bearer ${key}`;
9472
+ }
9473
+ function zaiWindowDurationMs(item) {
9474
+ const count = item.number !== void 0 && item.number > 0 ? item.number : 1;
9475
+ switch (item.unit) {
9476
+ case 3:
9477
+ return count * HOUR_MS2;
9478
+ case 4:
9479
+ return count * DAY_MS3;
9480
+ case 5:
9481
+ return count * MONTH_MS;
9482
+ case 6:
9483
+ return WEEK_MS;
9484
+ default:
9485
+ return void 0;
9486
+ }
9487
+ }
9488
+ function zaiWindowIdLabel(durationMs) {
9489
+ if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
9490
+ if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
9491
+ if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
9492
+ if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
9493
+ const days = durationMs / DAY_MS3;
9494
+ return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
9495
+ }
9496
+ if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
9497
+ const hours = durationMs / HOUR_MS2;
9498
+ return { id: `${hours}h`, label: `${hours} hour${hours === 1 ? "" : "s"}` };
9499
+ }
9500
+ return { id: "quota", label: "Quota" };
9501
+ }
9502
+ function parseZaiQuotaPayload(payload, now) {
9503
+ if (!isRecord7(payload)) return null;
9504
+ const data = isRecord7(payload["data"]) ? payload["data"] : payload;
9505
+ if (payload["success"] === false) return null;
9506
+ const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9507
+ const byWindow = /* @__PURE__ */ new Map();
9508
+ for (const raw of limits) {
9509
+ if (!isRecord7(raw)) continue;
9510
+ const item = raw;
9511
+ if (item.type === void 0) continue;
9512
+ const details = raw["usageDetails"];
9513
+ if (Array.isArray(details) && details.some((d) => isRecord7(d) && d["modelCode"] === "zread")) {
9514
+ continue;
9515
+ }
9516
+ const durationMs = zaiWindowDurationMs(item);
9517
+ const { id, label } = zaiWindowIdLabel(durationMs);
9518
+ const limit = finiteNumber5(item.usage);
9519
+ const used = finiteNumber5(item.currentValue);
9520
+ const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
9521
+ const fromPercentage = finitePercent4(item.percentage) ?? void 0;
9522
+ const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
9523
+ if (usedPercent === void 0) continue;
9524
+ const resetsAt = isoInstant3(item.nextResetTime);
9525
+ const candidate = {
9526
+ id,
9527
+ label,
9528
+ scope: "all",
9529
+ usedPercent,
9530
+ ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
9531
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9532
+ remainingSeconds: secondsUntil7(resetsAt, now),
9533
+ state: "fresh"
9534
+ };
9535
+ const existing = byWindow.get(id);
9536
+ if (!existing || (candidate.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
9537
+ byWindow.set(id, candidate);
9538
+ }
9539
+ }
9540
+ const windows = [...byWindow.values()].sort((a, b) => (a.windowMinutes ?? Number.POSITIVE_INFINITY) - (b.windowMinutes ?? Number.POSITIVE_INFINITY));
9541
+ return windows.length > 0 ? windows.slice(0, 4) : null;
9542
+ }
9543
+ var MINIMAX_STATUS_EXHAUSTED = 2;
9544
+ var MINIMAX_SHARED_BUCKET = "general";
9545
+ function parseMiniMaxBucket(value) {
9546
+ if (!isRecord7(value)) return null;
9547
+ const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
9548
+ if (!modelName) return null;
9549
+ const instant = (v) => {
9550
+ const n = finiteNumber5(v);
9551
+ return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
9552
+ };
9553
+ return {
9554
+ modelName,
9555
+ intervalEnd: instant(value["end_time"]),
9556
+ intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
9557
+ intervalStatus: finiteNumber5(value["current_interval_status"]),
9558
+ weeklyEnd: instant(value["weekly_end_time"]),
9559
+ weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
9560
+ weeklyStatus: finiteNumber5(value["current_weekly_status"])
9561
+ };
9562
+ }
9563
+ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
9564
+ const usedPercent = status === MINIMAX_STATUS_EXHAUSTED ? 100 : remainingPercent !== void 0 ? Math.round((100 - remainingPercent) * 10) / 10 : null;
9565
+ const resetsAt = resetsAtMs !== void 0 ? new Date(resetsAtMs).toISOString() : void 0;
9566
+ return {
9567
+ id,
9568
+ label,
9569
+ scope: "all",
9570
+ usedPercent,
9571
+ ...windowMinutes !== void 0 ? { windowMinutes } : {},
9572
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9573
+ remainingSeconds: secondsUntil7(resetsAt, now),
9574
+ state: usedPercent !== null ? "fresh" : "unavailable"
9575
+ };
9576
+ }
9577
+ function parseMiniMaxTokenPlanPayload(payload, now) {
9578
+ if (!isRecord7(payload)) return null;
9579
+ const baseResp = payload["base_resp"];
9580
+ if (!isRecord7(baseResp) || baseResp["status_code"] !== 0) return null;
9581
+ const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
9582
+ let general = null;
9583
+ for (const raw of buckets) {
9584
+ const bucket = parseMiniMaxBucket(raw);
9585
+ if (bucket?.modelName === MINIMAX_SHARED_BUCKET) {
9586
+ general = bucket;
9587
+ break;
9588
+ }
9589
+ }
9590
+ if (!general) return null;
9591
+ return [
9592
+ minimaxWindow(
9593
+ "five-hour",
9594
+ "5 hours",
9595
+ 5 * 60,
9596
+ general.intervalEnd,
9597
+ general.intervalRemainingPercent,
9598
+ general.intervalStatus,
9599
+ now
9600
+ ),
9601
+ minimaxWindow(
9602
+ "seven-day",
9603
+ "7 days",
9604
+ Math.round(WEEK_MS / MINUTE_MS3),
9605
+ general.weeklyEnd,
9606
+ general.weeklyRemainingPercent,
9607
+ general.weeklyStatus,
9608
+ now
9609
+ )
9610
+ ];
9611
+ }
9612
+ function parseUmansUsagePayload(payload, now) {
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"]);
9622
+ const resetsAt = isoInstant3(window?.["resets_at"]);
9623
+ let usedPercent = null;
9624
+ if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
9625
+ usedPercent = Math.round(Math.min(100, requestsInWindow / hardCap * 100) * 10) / 10;
9626
+ } else if (softLimit !== void 0 && softLimit > 0 && weightedInWindow !== void 0) {
9627
+ usedPercent = Math.round(Math.min(100, weightedInWindow / softLimit * 100) * 10) / 10;
9628
+ }
9629
+ if (usedPercent === null && resetsAt === void 0) return null;
9630
+ return [
9631
+ {
9632
+ id: "five-hour",
9633
+ label: "5 hours",
9634
+ scope: "all",
9635
+ usedPercent,
9636
+ windowMinutes: 5 * 60,
9637
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9638
+ remainingSeconds: secondsUntil7(resetsAt, now),
9639
+ state: "fresh"
9640
+ }
9641
+ ];
9642
+ }
9643
+ function parseSyntheticQuotasPayload(payload, now) {
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;
9647
+ const windows = [];
9648
+ if (fiveHour) {
9649
+ const max = finiteNumber5(fiveHour["max"]);
9650
+ const remaining = finiteNumber5(fiveHour["remaining"]);
9651
+ const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
9652
+ const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
9653
+ windows.push({
9654
+ id: "five-hour",
9655
+ label: "5 hours",
9656
+ scope: "all",
9657
+ usedPercent,
9658
+ windowMinutes: 5 * 60,
9659
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9660
+ remainingSeconds: secondsUntil7(resetsAt, now),
9661
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9662
+ });
9663
+ }
9664
+ if (weekly) {
9665
+ const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
9666
+ const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
9667
+ const resetsAt = isoInstant3(weekly["nextRegenAt"]);
9668
+ windows.push({
9669
+ id: "seven-day",
9670
+ label: "7 days",
9671
+ scope: "all",
9672
+ usedPercent,
9673
+ windowMinutes: 7 * 24 * 60,
9674
+ ...resetsAt !== void 0 ? { resetsAt } : {},
9675
+ remainingSeconds: secondsUntil7(resetsAt, now),
9676
+ state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9677
+ });
9678
+ }
9679
+ return windows.length > 0 ? windows : null;
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
+ }
9711
+
9712
+ // src/allowance/ProviderKeyQuotaService.ts
9713
+ function parseQuotaPayload(adapter, payload, now) {
9714
+ switch (adapter) {
9715
+ case "zai":
9716
+ return parseZaiQuotaPayload(payload, now);
9717
+ case "minimax-token-plan":
9718
+ return parseMiniMaxTokenPlanPayload(payload, now);
9719
+ case "umans":
9720
+ return parseUmansUsagePayload(payload, now);
9721
+ case "synthetic":
9722
+ return parseSyntheticQuotasPayload(payload, now);
9723
+ case "cline-pass":
9724
+ return parseClinePassUsageLimitsPayload(payload, now);
9725
+ }
9726
+ }
9727
+ var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
9728
+ function resolvedBaseUrl(row) {
9729
+ const modes = row.apiModes ?? [];
9730
+ const selected = row.selectedApiModeId ? modes.find((mode) => mode.id === row.selectedApiModeId) : void 0;
9731
+ const fallback = modes[0];
9732
+ const modeBase = selected?.baseUrl ?? fallback?.baseUrl;
9733
+ return modeBase ?? row.codingPlan?.baseUrl ?? row.baseUrl;
9734
+ }
9735
+ function rowKeyEntries(row) {
9736
+ const pool = (row.apiKeys ?? []).filter((entry) => entry.apiKey.length > 0);
9737
+ if (pool.length > 0) return pool.map((entry) => ({ id: entry.id, apiKey: entry.apiKey }));
9738
+ if (row.apiKey.length > 0) {
9739
+ return [{ id: `${row.id}:default`, apiKey: row.apiKey }];
9740
+ }
9741
+ return [];
9742
+ }
9743
+ var ProviderKeyQuotaService = class {
9744
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
9745
+ this.box = box;
9746
+ this.fetchImpl = fetchImpl;
9747
+ this.now = now;
9748
+ }
9749
+ box;
9750
+ fetchImpl;
9751
+ now;
9752
+ cache = /* @__PURE__ */ new Map();
9753
+ inFlight = /* @__PURE__ */ new Map();
9754
+ /**
9755
+ * Quota for one key of a provider row, or `null` when the row has no quota
9756
+ * adapter / no such key. Cache-first; concurrent reads share one flight.
9757
+ */
9758
+ async quotaFor(row, keyId, options = {}) {
9759
+ const adapter = detectProviderKeyQuotaAdapter(resolvedBaseUrl(row));
9760
+ if (!adapter) return null;
9761
+ const entry = rowKeyEntries(row).find((candidate) => candidate.id === keyId);
9762
+ if (!entry) return null;
9763
+ const cacheKey = `${row.id}\0${keyId}`;
9764
+ const now = this.now();
9765
+ const cached = this.cache.get(cacheKey);
9766
+ if (!options.force && cached && Date.parse(cached.expiresAt) > now) return cached;
9767
+ const running = this.inFlight.get(cacheKey);
9768
+ if (running) return running;
9769
+ const promise = this.fetchQuota(adapter, row, entry.apiKey, cacheKey).catch((error) => {
9770
+ void error;
9771
+ const previous = this.cache.get(cacheKey);
9772
+ if (previous) {
9773
+ const degraded = {
9774
+ ...previous,
9775
+ expiresAt: new Date(now + PROVIDER_KEY_QUOTA_CACHE_MS).toISOString(),
9776
+ windows: previous.windows.map((window) => ({
9777
+ ...window,
9778
+ state: window.usedPercent !== null || window.resetsAt ? "stale" : window.state
9779
+ })),
9780
+ errorCode: "quota_request_failed"
9781
+ };
9782
+ this.cache.set(cacheKey, degraded);
9783
+ return degraded;
9784
+ }
9785
+ return null;
9786
+ }).finally(() => this.inFlight.delete(cacheKey));
9787
+ this.inFlight.set(cacheKey, promise);
9788
+ return promise;
9789
+ }
9790
+ /** Drop cached rows for a provider (key added/removed/rotated). */
9791
+ invalidateProvider(providerRowId) {
9792
+ for (const key of this.cache.keys()) {
9793
+ if (key.startsWith(`${providerRowId}\0`)) this.cache.delete(key);
9794
+ }
9795
+ }
9796
+ async fetchQuota(adapter, row, rawKey, cacheKey) {
9797
+ const baseUrl = resolvedBaseUrl(row);
9798
+ const url = providerKeyQuotaUrl(adapter, baseUrl);
9799
+ const key = this.box.decryptMaybe(rawKey);
9800
+ const now = this.now();
9801
+ const response = await this.fetchImpl(url, {
9802
+ method: "GET",
9803
+ headers: {
9804
+ Authorization: providerKeyQuotaAuthHeader(adapter, key),
9805
+ Accept: "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)
9810
+ },
9811
+ signal: AbortSignal.timeout(15e3)
9812
+ });
9813
+ if (response.status === 401 || response.status === 403) {
9814
+ const snapshot2 = {
9815
+ adapter,
9816
+ observedAt: new Date(now).toISOString(),
9817
+ expiresAt: new Date(now + PROVIDER_KEY_QUOTA_CACHE_MS).toISOString(),
9818
+ windows: [],
9819
+ errorCode: "quota_unauthorized"
9820
+ };
9821
+ this.cache.set(cacheKey, snapshot2);
9822
+ return snapshot2;
9823
+ }
9824
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
9825
+ let payload;
9826
+ try {
9827
+ payload = await response.json();
9828
+ } catch {
9829
+ throw new Error("invalid JSON");
9830
+ }
9831
+ const windows = parseQuotaPayload(adapter, payload, now);
9832
+ const snapshot = {
9833
+ adapter,
9834
+ observedAt: new Date(now).toISOString(),
9835
+ expiresAt: new Date(now + PROVIDER_KEY_QUOTA_CACHE_MS).toISOString(),
9836
+ windows: windows ?? [],
9837
+ ...windows ? {} : { errorCode: "quota_unavailable" }
9838
+ };
9839
+ this.cache.set(cacheKey, snapshot);
9840
+ return snapshot;
9841
+ }
9842
+ };
9843
+
7773
9844
  // src/commands/paths.ts
7774
9845
  var import_node_path9 = require("path");
7775
9846
  function defaultVouchersPath(configPath) {
@@ -7806,7 +9877,7 @@ function defaultBillingDir(configPath) {
7806
9877
  // src/image-generation/ImageDoctorService.ts
7807
9878
  var import_image_generation = require("@omnicross/core/image-generation");
7808
9879
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
7809
- var import_subscriptions3 = require("@omnicross/subscriptions");
9880
+ var import_subscriptions9 = require("@omnicross/subscriptions");
7810
9881
 
7811
9882
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
7812
9883
  var import_node_crypto13 = require("crypto");
@@ -8244,7 +10315,7 @@ function createImageDoctorService(options) {
8244
10315
  paths,
8245
10316
  ttlMs: config.evidenceTtlMs
8246
10317
  }));
8247
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions3.createCodexImageLiveVerifier)({
10318
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
8248
10319
  authStrategy: strategy,
8249
10320
  generationTimeoutMs: config.queue.generationTimeoutMs
8250
10321
  }));
@@ -8606,7 +10677,7 @@ var ImageCleanupService = class {
8606
10677
  var import_node_crypto16 = require("crypto");
8607
10678
  var import_image_generation5 = require("@omnicross/core/image-generation");
8608
10679
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
8609
- var import_subscriptions4 = require("@omnicross/subscriptions");
10680
+ var import_subscriptions10 = require("@omnicross/subscriptions");
8610
10681
 
8611
10682
  // src/image-generation/ImageApiRuntimeResolver.ts
8612
10683
  var import_node_crypto14 = require("crypto");
@@ -9137,7 +11208,7 @@ function createImageRuntimeGeneration(options) {
9137
11208
  now: options.now ?? Date.now,
9138
11209
  referenceStore: options.storage.referenceStore,
9139
11210
  stateStore: options.storage.stateStore
9140
- }) : (0, import_subscriptions4.createCodexSubscriptionImageProvider)({
11211
+ }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
9141
11212
  authStrategy,
9142
11213
  evidenceSource: generationEvidenceSource,
9143
11214
  executionScheduler: scheduler,
@@ -12281,7 +14352,7 @@ var ImageRuntimeManager = class {
12281
14352
  };
12282
14353
 
12283
14354
  // src/ports/ConfigFileProviderConfigSource.ts
12284
- var import_core2 = require("@omnicross/core");
14355
+ var import_core5 = require("@omnicross/core");
12285
14356
  var EMPTY_CHAIN = {
12286
14357
  providerTransformers: [],
12287
14358
  modelTransformers: []
@@ -12306,8 +14377,8 @@ var ConfigFileProviderConfigSource = class {
12306
14377
  reloadHook;
12307
14378
  constructor(config) {
12308
14379
  for (const p of config.providers) this.providers.set(p.id, p);
12309
- this.transformerService = new import_core2.TransformerService();
12310
- void (0, import_core2.registerBuiltinTransformers)(this.transformerService);
14380
+ this.transformerService = new import_core5.TransformerService();
14381
+ void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
12311
14382
  }
12312
14383
  // ── Reload hook (key-pool design D4) ───────────────────────────────────────
12313
14384
  /**
@@ -12328,7 +14399,7 @@ var ConfigFileProviderConfigSource = class {
12328
14399
  }
12329
14400
  /** Await the built-in transformer registration (tests await this before dispatch). */
12330
14401
  async ready() {
12331
- await (0, import_core2.registerBuiltinTransformers)(this.transformerService);
14402
+ await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
12332
14403
  }
12333
14404
  // ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
12334
14405
  /**
@@ -12439,6 +14510,10 @@ function toLLMProvider(row) {
12439
14510
  // `parseProviderInput`), so customizations are preserved (the row value wins).
12440
14511
  apiModes: row.apiModes,
12441
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,
12442
14517
  // Official-Anthropic signature handling only matters for the Anthropic
12443
14518
  // ingress (deferred → 502); leave it off for the BYO transform path.
12444
14519
  isOfficial: false
@@ -13803,10 +15878,13 @@ function bucketLabel(bucketStartTs, bucket) {
13803
15878
  }
13804
15879
 
13805
15880
  // src/ports/JsonOutboundKeyDb.ts
15881
+ var import_node_fs19 = require("fs");
15882
+ var import_core6 = require("@omnicross/core");
15883
+
15884
+ // src/ports/atomicFile.ts
13806
15885
  var import_node_crypto22 = require("crypto");
13807
15886
  var import_node_fs18 = require("fs");
13808
15887
  var import_node_path22 = require("path");
13809
- var import_core3 = require("@omnicross/core");
13810
15888
  function atomicReplaceUtf8(targetPath, contents) {
13811
15889
  const tempPath = (0, import_node_path22.join)(
13812
15890
  (0, import_node_path22.dirname)(targetPath),
@@ -13836,6 +15914,8 @@ function atomicReplaceUtf8(targetPath, contents) {
13836
15914
  throw error;
13837
15915
  }
13838
15916
  }
15917
+
15918
+ // src/ports/JsonOutboundKeyDb.ts
13839
15919
  var JsonOutboundKeyDb = class {
13840
15920
  /**
13841
15921
  * @param secretBox OPTIONAL reversible-secret codec. When present, a created
@@ -13921,7 +16001,7 @@ var JsonOutboundKeyDb = class {
13921
16001
  });
13922
16002
  }
13923
16003
  async outboundApiKeysSetPermissions(id, permissions) {
13924
- const exact = (0, import_core3.validateOutboundPermissions)(permissions);
16004
+ const exact = (0, import_core6.validateOutboundPermissions)(permissions);
13925
16005
  return this.mutateRow(id, (row) => {
13926
16006
  if (row.revokedAt !== null) return false;
13927
16007
  row.allowedEndpoints = [...exact];
@@ -13978,9 +16058,9 @@ var JsonOutboundKeyDb = class {
13978
16058
  }
13979
16059
  /** Read the key rows, tolerating a missing/corrupt file (→ empty list). */
13980
16060
  readRows() {
13981
- if (!(0, import_node_fs18.existsSync)(this.keysPath)) return [];
16061
+ if (!(0, import_node_fs19.existsSync)(this.keysPath)) return [];
13982
16062
  try {
13983
- const parsed = JSON.parse((0, import_node_fs18.readFileSync)(this.keysPath, "utf8"));
16063
+ const parsed = JSON.parse((0, import_node_fs19.readFileSync)(this.keysPath, "utf8"));
13984
16064
  return Array.isArray(parsed) ? parsed : [];
13985
16065
  } catch {
13986
16066
  return [];
@@ -13997,7 +16077,7 @@ function applyPolicyField(row, field, value) {
13997
16077
  }
13998
16078
 
13999
16079
  // src/ports/JsonPricingStore.ts
14000
- var import_node_fs19 = require("fs");
16080
+ var import_node_fs20 = require("fs");
14001
16081
  var import_node_crypto23 = require("crypto");
14002
16082
  var JsonPricingStore = class {
14003
16083
  constructor(pricingPath) {
@@ -14012,9 +16092,9 @@ var JsonPricingStore = class {
14012
16092
  * otherwise unusable pricing table after a crash or manual file edit.
14013
16093
  */
14014
16094
  hasUsableSnapshot() {
14015
- if (!(0, import_node_fs19.existsSync)(this.pricingPath)) return false;
16095
+ if (!(0, import_node_fs20.existsSync)(this.pricingPath)) return false;
14016
16096
  try {
14017
- const parsed = JSON.parse((0, import_node_fs19.readFileSync)(this.pricingPath, "utf8"));
16097
+ const parsed = JSON.parse((0, import_node_fs20.readFileSync)(this.pricingPath, "utf8"));
14018
16098
  return Array.isArray(parsed) && parsed.some(isUsablePricingRow);
14019
16099
  } catch {
14020
16100
  return false;
@@ -14127,9 +16207,9 @@ var JsonPricingStore = class {
14127
16207
  }
14128
16208
  /** Read the pricing rows, tolerating a missing/corrupt file (→ empty list). */
14129
16209
  readRows() {
14130
- if (!(0, import_node_fs19.existsSync)(this.pricingPath)) return [];
16210
+ if (!(0, import_node_fs20.existsSync)(this.pricingPath)) return [];
14131
16211
  try {
14132
- const parsed = JSON.parse((0, import_node_fs19.readFileSync)(this.pricingPath, "utf8"));
16212
+ const parsed = JSON.parse((0, import_node_fs20.readFileSync)(this.pricingPath, "utf8"));
14133
16213
  return Array.isArray(parsed) ? parsed : [];
14134
16214
  } catch {
14135
16215
  return [];
@@ -14138,18 +16218,18 @@ var JsonPricingStore = class {
14138
16218
  writeRows(rows) {
14139
16219
  const temporaryPath = `${this.pricingPath}.${process.pid}.${(0, import_node_crypto23.randomUUID)()}.tmp`;
14140
16220
  try {
14141
- (0, import_node_fs19.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
16221
+ (0, import_node_fs20.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
14142
16222
  encoding: "utf8",
14143
16223
  flag: "wx"
14144
16224
  });
14145
16225
  this.replaceFile(temporaryPath);
14146
16226
  } finally {
14147
- (0, import_node_fs19.rmSync)(temporaryPath, { force: true });
16227
+ (0, import_node_fs20.rmSync)(temporaryPath, { force: true });
14148
16228
  }
14149
16229
  }
14150
16230
  /** Isolated for deterministic failure testing; never removes the target. */
14151
16231
  replaceFile(temporaryPath) {
14152
- (0, import_node_fs19.renameSync)(temporaryPath, this.pricingPath);
16232
+ (0, import_node_fs20.renameSync)(temporaryPath, this.pricingPath);
14153
16233
  }
14154
16234
  };
14155
16235
  function isUsablePricingRow(value) {
@@ -14159,7 +16239,7 @@ function isUsablePricingRow(value) {
14159
16239
  }
14160
16240
 
14161
16241
  // src/pricing/PricingRefreshScheduler.ts
14162
- var import_node_fs20 = require("fs");
16242
+ var import_node_fs21 = require("fs");
14163
16243
  var EMPTY_STATE2 = {
14164
16244
  lastAttemptAt: null,
14165
16245
  lastSuccessAt: null,
@@ -14197,9 +16277,9 @@ var PricingRefreshScheduler = class {
14197
16277
  this.timer = null;
14198
16278
  }
14199
16279
  getState() {
14200
- if (!(0, import_node_fs20.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
16280
+ if (!(0, import_node_fs21.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
14201
16281
  try {
14202
- const value = JSON.parse((0, import_node_fs20.readFileSync)(this.statePath, "utf8"));
16282
+ const value = JSON.parse((0, import_node_fs21.readFileSync)(this.statePath, "utf8"));
14203
16283
  return {
14204
16284
  lastAttemptAt: finiteOrNull(value.lastAttemptAt),
14205
16285
  lastSuccessAt: finiteOrNull(value.lastSuccessAt),
@@ -14252,9 +16332,9 @@ var PricingRefreshScheduler = class {
14252
16332
  }
14253
16333
  writeState(state) {
14254
16334
  const temporaryPath = `${this.statePath}.tmp`;
14255
- (0, import_node_fs20.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
16335
+ (0, import_node_fs21.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
14256
16336
  `, "utf8");
14257
- (0, import_node_fs20.renameSync)(temporaryPath, this.statePath);
16337
+ (0, import_node_fs21.renameSync)(temporaryPath, this.statePath);
14258
16338
  }
14259
16339
  };
14260
16340
  function finiteOrNull(value) {
@@ -14262,7 +16342,7 @@ function finiteOrNull(value) {
14262
16342
  }
14263
16343
 
14264
16344
  // src/ports/JsonVoucherDb.ts
14265
- var import_node_fs21 = require("fs");
16345
+ var import_node_fs22 = require("fs");
14266
16346
  var JsonVoucherDb = class {
14267
16347
  constructor(vouchersPath) {
14268
16348
  this.vouchersPath = vouchersPath;
@@ -14340,27 +16420,27 @@ var JsonVoucherDb = class {
14340
16420
  }
14341
16421
  /** Read the voucher rows, tolerating a missing/corrupt file (→ empty list). */
14342
16422
  readRows() {
14343
- if (!(0, import_node_fs21.existsSync)(this.vouchersPath)) return [];
16423
+ if (!(0, import_node_fs22.existsSync)(this.vouchersPath)) return [];
14344
16424
  try {
14345
- const parsed = JSON.parse((0, import_node_fs21.readFileSync)(this.vouchersPath, "utf8"));
16425
+ const parsed = JSON.parse((0, import_node_fs22.readFileSync)(this.vouchersPath, "utf8"));
14346
16426
  return Array.isArray(parsed) ? parsed : [];
14347
16427
  } catch {
14348
16428
  return [];
14349
16429
  }
14350
16430
  }
14351
16431
  writeRows(rows) {
14352
- (0, import_node_fs21.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
16432
+ (0, import_node_fs22.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
14353
16433
  }
14354
16434
  };
14355
16435
 
14356
16436
  // src/ports/JsonSubscriptionCredentialStore.ts
14357
- var import_node_fs23 = require("fs");
16437
+ var import_node_fs24 = require("fs");
14358
16438
  var import_node_path24 = require("path");
14359
16439
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
14360
16440
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
14361
- var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
16441
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
14362
16442
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
14363
- var import_subscriptions5 = require("@omnicross/subscriptions");
16443
+ var import_subscriptions11 = require("@omnicross/subscriptions");
14364
16444
 
14365
16445
  // src/ports/account-sync.ts
14366
16446
  function viewOf(tokens) {
@@ -14404,7 +16484,7 @@ function findDuplicateCredentialIds(accounts) {
14404
16484
  }
14405
16485
 
14406
16486
  // src/ports/external-cli-credentials.ts
14407
- var import_node_fs22 = require("fs");
16487
+ var import_node_fs23 = require("fs");
14408
16488
  var import_node_os5 = require("os");
14409
16489
  var import_node_path23 = require("path");
14410
16490
  function externalStorePath(provider, home = (0, import_node_os5.homedir)()) {
@@ -14457,10 +16537,10 @@ function parseCodexTokensEnvelope(raw) {
14457
16537
  }
14458
16538
  function readExternalCliCredentials(provider, home = (0, import_node_os5.homedir)()) {
14459
16539
  const path2 = externalStorePath(provider, home);
14460
- if (!(0, import_node_fs22.existsSync)(path2)) return null;
16540
+ if (!(0, import_node_fs23.existsSync)(path2)) return null;
14461
16541
  let raw;
14462
16542
  try {
14463
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
16543
+ const parsed = JSON.parse((0, import_node_fs23.readFileSync)(path2, "utf8"));
14464
16544
  raw = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
14465
16545
  } catch {
14466
16546
  return null;
@@ -14483,16 +16563,18 @@ var JsonSubscriptionCredentialStore = class {
14483
16563
  * as on relay refresh egresses from the SAME proxy IP as the
14484
16564
  * account's traffic. NOT used by any read/write path.
14485
16565
  */
14486
- constructor(tokensPath, box, fetchImpl = void 0, externalCliReader = readExternalCliCredentials) {
16566
+ constructor(tokensPath, box, fetchImpl = void 0, externalCliReader = readExternalCliCredentials, atomicReplace = atomicReplaceUtf8) {
14487
16567
  this.tokensPath = tokensPath;
14488
16568
  this.box = box;
14489
16569
  this.fetchImpl = fetchImpl;
14490
16570
  this.externalCliReader = externalCliReader;
16571
+ this.atomicReplace = atomicReplace;
14491
16572
  }
14492
16573
  tokensPath;
14493
16574
  box;
14494
16575
  fetchImpl;
14495
16576
  externalCliReader;
16577
+ atomicReplace;
14496
16578
  /**
14497
16579
  * The proxy-aware `FetchLike` for one refresh round-trip (upstream-proxy M1). A
14498
16580
  * TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
@@ -14506,7 +16588,7 @@ var JsonSubscriptionCredentialStore = class {
14506
16588
  * a plaintext token pair into `upstream-trace.jsonl`.
14507
16589
  */
14508
16590
  buildRefreshFetch(providerId, accountId) {
14509
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch5.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
16591
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
14510
16592
  }
14511
16593
  /**
14512
16594
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -14547,7 +16629,7 @@ var JsonSubscriptionCredentialStore = class {
14547
16629
  * other hot reads. Never returns token material.
14548
16630
  */
14549
16631
  getAccountProxy(providerId, accountId) {
14550
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego") {
16632
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
14551
16633
  return void 0;
14552
16634
  }
14553
16635
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -14566,7 +16648,7 @@ var JsonSubscriptionCredentialStore = class {
14566
16648
  const fingerprintOn = identityStore.isEnabled();
14567
16649
  const now = Date.now();
14568
16650
  const out = {};
14569
- for (const provider of ["claude", "codex", "gemini", "opencodego"]) {
16651
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
14570
16652
  const sanitized = sanitizeAccounts(config, provider);
14571
16653
  if (sanitized.length === 0) continue;
14572
16654
  for (const account of sanitized) {
@@ -14632,7 +16714,7 @@ var JsonSubscriptionCredentialStore = class {
14632
16714
  this.materializeMigration(config);
14633
16715
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
14634
16716
  try {
14635
- const result = await import_subscriptions5.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
16717
+ const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
14636
16718
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
14637
16719
  const next = {
14638
16720
  ...claude,
@@ -14667,7 +16749,7 @@ var JsonSubscriptionCredentialStore = class {
14667
16749
  this.materializeMigration(config);
14668
16750
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
14669
16751
  try {
14670
- const result = await import_subscriptions5.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
16752
+ const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
14671
16753
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
14672
16754
  const next = {
14673
16755
  ...codex,
@@ -14705,7 +16787,7 @@ var JsonSubscriptionCredentialStore = class {
14705
16787
  this.materializeMigration(config);
14706
16788
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
14707
16789
  try {
14708
- const result = await import_subscriptions5.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
16790
+ const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
14709
16791
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
14710
16792
  const next = {
14711
16793
  ...gemini,
@@ -14724,6 +16806,107 @@ var JsonSubscriptionCredentialStore = class {
14724
16806
  }
14725
16807
  });
14726
16808
  }
16809
+ /**
16810
+ * Refresh the Kimi Code (Moonshot) OAuth access token (device-flow grant).
16811
+ * Kimi ROTATES the refresh token, so the response's pair is written back
16812
+ * whole; the account's stable `deviceId` (fingerprint header input) is
16813
+ * preserved. The refresh call carries the CLI fingerprint headers. HONEST
16814
+ * `false` when no refresh_token.
16815
+ */
16816
+ async refreshKimiToken() {
16817
+ return this.coalesce("kimi:active", async () => {
16818
+ const config = this.readConfig();
16819
+ const active = getActiveAccount(config, "kimi");
16820
+ const kimi = active?.tokens;
16821
+ if (!active || !kimi?.refreshToken) return false;
16822
+ const capturedId = active.id;
16823
+ this.materializeMigration(config);
16824
+ const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
16825
+ try {
16826
+ const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
16827
+ kimi.refreshToken,
16828
+ refreshFetch,
16829
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
16830
+ );
16831
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16832
+ const next = {
16833
+ ...kimi,
16834
+ accessToken: result.accessToken,
16835
+ refreshToken: result.refreshToken,
16836
+ expiresAt,
16837
+ status: "authorized",
16838
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
16839
+ errorMessage: void 0,
16840
+ syncWarning: void 0
16841
+ };
16842
+ this.writeBackById("kimi", capturedId, next);
16843
+ return true;
16844
+ } catch (error) {
16845
+ this.markExpiredById("kimi", capturedId, kimi, error);
16846
+ return false;
16847
+ }
16848
+ });
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
+ }
14727
16910
  /**
14728
16911
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
14729
16912
  * account-pool resolution). It uses only that account's stored refresh
@@ -14776,7 +16959,7 @@ var JsonSubscriptionCredentialStore = class {
14776
16959
  }
14777
16960
  const oauth = account.tokens;
14778
16961
  if (!oauth.accessToken) return null;
14779
- if (providerId === "codex" || providerId === "gemini") {
16962
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
14780
16963
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
14781
16964
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
14782
16965
  if (expiringSoon && oauth.refreshToken) {
@@ -14865,8 +17048,35 @@ var JsonSubscriptionCredentialStore = class {
14865
17048
  }
14866
17049
  /** Dispatch one OAuth refresh round-trip to the provider's shared flow. */
14867
17050
  async refreshUpstream(provider, refreshToken, accountId) {
14868
- const flow = provider === "claude" ? import_subscriptions5.claudeOAuth : provider === "codex" ? import_subscriptions5.codexOAuth : import_subscriptions5.geminiOAuth;
14869
- const r = await flow.refreshAccessToken(refreshToken, this.buildRefreshFetch(provider, accountId));
17051
+ const refreshFetch = this.buildRefreshFetch(provider, accountId);
17052
+ if (provider === "kimi") {
17053
+ const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
17054
+ const deviceId = account?.tokens?.deviceId;
17055
+ const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
17056
+ refreshToken,
17057
+ refreshFetch,
17058
+ import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
17059
+ );
17060
+ return {
17061
+ accessToken: r2.accessToken,
17062
+ refreshToken: r2.refreshToken,
17063
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17064
+ };
17065
+ }
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;
17079
+ const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
14870
17080
  return {
14871
17081
  accessToken: r.accessToken,
14872
17082
  refreshToken: r.refreshToken,
@@ -15029,42 +17239,86 @@ var JsonSubscriptionCredentialStore = class {
15029
17239
  /** Write the merged config to disk as pretty JSON (mkdir parent if needed).
15030
17240
  * Encrypt-on-write: the token-material fields are encrypted (legacy plaintext
15031
17241
  * `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
15032
- * write incl. child 4's future refresh writes lands encrypted. */
17242
+ * write incl. child 4's future refresh writes lands encrypted.
17243
+ * ATOMIC: temp + fsync + rename (`atomicReplaceUtf8`) — a failed or
17244
+ * interrupted write discards only the temp file; the prior `tokens.json`
17245
+ * survives byte-equal (bare `writeFileSync` truncate-writes lost every
17246
+ * account on a mid-write failure, 2026-09-06). */
15033
17247
  persist(config) {
15034
- (0, import_node_fs23.mkdirSync)((0, import_node_path24.dirname)(this.tokensPath), { recursive: true });
17248
+ (0, import_node_fs24.mkdirSync)((0, import_node_path24.dirname)(this.tokensPath), { recursive: true });
15035
17249
  const encrypted = encryptTokens(config, this.box);
15036
- (0, import_node_fs23.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
17250
+ this.atomicReplace(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n");
15037
17251
  }
15038
17252
  /**
15039
- * Read + parse `tokens.json`, tolerating a missing/corrupt file, then DECRYPT
15040
- * the token-material fields so every getter returns plaintext (the
15041
- * subscription bearer path is byte-identical).
17253
+ * Read + parse `tokens.json`, then DECRYPT the token-material fields so every
17254
+ * getter returns plaintext (the subscription bearer path is byte-identical).
17255
+ *
17256
+ * A MISSING file is a legitimate first-boot state → minimal `{ updatedAt: '' }`.
17257
+ * A file that EXISTS but cannot be parsed as a JSON object is CORRUPT →
17258
+ * `quarantineCorrupt` moves it aside (once) before the empty config is
17259
+ * returned, so the unreadable accounts survive for manual recovery.
15042
17260
  *
15043
- * The fs-read + JSON-parse tolerance is INSIDE the try (a missing or corrupt
15044
- * file empty `{ updatedAt: '' }`). The DECRYPT runs OUTSIDE the try, so a
15045
- * wrong/missing master key or a tampered `enc:` envelope FAILS FAST with the
15046
- * box's clear, secret-free error (secrets spec "/ UX":
15047
- * SHALL fail-fast, SHALL NOT a swallowed decrypt would report "no
15048
- * tokens" and silently send the WRONG bearer upstream 401). Mirrors
15049
- * `config.ts loadConfig`, which decrypts outside its parse try.
17261
+ * The DECRYPT runs OUTSIDE any try, so a wrong/missing master key or a
17262
+ * tampered `enc:` envelope FAILS FAST with the box's clear, secret-free
17263
+ * error (secrets spec "/ UX": SHALL fail-fast, SHALL NOT a swallowed
17264
+ * decrypt would report "no tokens" and silently send the WRONG bearer
17265
+ * upstream 401). Mirrors `config.ts loadConfig`, which decrypts outside
17266
+ * its parse try.
15050
17267
  */
15051
17268
  readConfig() {
15052
- if (!(0, import_node_fs23.existsSync)(this.tokensPath)) return { updatedAt: "" };
17269
+ if (!(0, import_node_fs24.existsSync)(this.tokensPath)) return { updatedAt: "" };
15053
17270
  let parsed;
15054
17271
  try {
15055
- const raw = JSON.parse((0, import_node_fs23.readFileSync)(this.tokensPath, "utf8"));
15056
- parsed = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
17272
+ const raw = JSON.parse((0, import_node_fs24.readFileSync)(this.tokensPath, "utf8"));
17273
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
17274
+ return this.quarantineCorrupt("parsed JSON is not an object");
17275
+ }
17276
+ parsed = raw;
15057
17277
  } catch {
15058
- parsed = null;
17278
+ return this.quarantineCorrupt("unparseable JSON");
15059
17279
  }
15060
- if (!parsed) return { updatedAt: "" };
15061
17280
  const decrypted = decryptTokens(parsed, this.box);
15062
17281
  return migrateLazily(decrypted);
15063
17282
  }
17283
+ /** One-shot latch: a corrupt file is quarantined (or found unmovable) at
17284
+ * most once per process, so the hot read path never re-attempts or re-logs. */
17285
+ corruptQuarantined = false;
17286
+ /**
17287
+ * Quarantine a present-but-corrupt `tokens.json`, then treat it as empty.
17288
+ *
17289
+ * Renames the file to a sibling `tokens.json.corrupt-<stamp>` backup and
17290
+ * logs loudly (the daemon's stderr log; secret-free — reason + paths only).
17291
+ * The daemon KEEPS SERVING (API-key routing is unaffected; subscription
17292
+ * routing reports no credential, same as an absent file) while the corrupt
17293
+ * bytes survive for manual recovery — and, critically, the NEXT persist
17294
+ * (e.g. the user re-logging in) can no longer overwrite the only copy of
17295
+ * the old accounts, which is exactly how the 2026-09-06 incident turned a
17296
+ * recoverable truncated file into permanent account loss.
17297
+ *
17298
+ * Best-effort: if the rename fails (file locked, permissions), the corrupt
17299
+ * file is left in place and every later read still tolerates it as empty;
17300
+ * the latch still trips so the attempt + log happen exactly once.
17301
+ */
17302
+ quarantineCorrupt(reason) {
17303
+ if (!this.corruptQuarantined) {
17304
+ this.corruptQuarantined = true;
17305
+ const backup = `${this.tokensPath}.corrupt-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
17306
+ let moved = false;
17307
+ try {
17308
+ (0, import_node_fs24.renameSync)(this.tokensPath, backup);
17309
+ moved = true;
17310
+ } catch {
17311
+ }
17312
+ console.error(
17313
+ `[JsonSubscriptionCredentialStore] tokens.json is corrupt (${reason}); ` + (moved ? `moved to '${backup}' and treated as empty \u2014 recover accounts from that backup before re-adding them` : `could not move '${this.tokensPath}' \u2014 treated as empty`)
17314
+ );
17315
+ }
17316
+ return { updatedAt: "" };
17317
+ }
15064
17318
  };
15065
17319
 
15066
17320
  // src/AccountHealthProbeScheduler.ts
15067
- var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
17321
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
15068
17322
 
15069
17323
  // src/probe/CodexGenerationProbe.ts
15070
17324
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -15203,7 +17457,20 @@ var PROVIDER_PROBE_PLANS = {
15203
17457
  // billable/wrong endpoint). Upgrade to `{ kind:'upstream' }` once verified.
15204
17458
  codex: { kind: "local" },
15205
17459
  gemini: { kind: "local" },
15206
- opencodego: { kind: "local" }
17460
+ opencodego: { kind: "local" },
17461
+ // Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
17462
+ // collector uses it), but the probe path also needs the fingerprint headers —
17463
+ // keep the probe local until the collector covers the health surface.
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" }
15207
17474
  };
15208
17475
  function probePlanFor(providerId) {
15209
17476
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -15225,7 +17492,7 @@ var AccountHealthProbeScheduler = class {
15225
17492
  this.logger = logger;
15226
17493
  this.config = config;
15227
17494
  this.now = opts.now ?? Date.now;
15228
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch6.fetchUpstream;
17495
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch12.fetchUpstream;
15229
17496
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
15230
17497
  this.planFor = opts.planFor ?? probePlanFor;
15231
17498
  }
@@ -15569,13 +17836,13 @@ var AccountHealthSweeper = class {
15569
17836
  };
15570
17837
 
15571
17838
  // src/audit/AuditPruneSweeper.ts
15572
- var import_node_fs26 = require("fs");
17839
+ var import_node_fs27 = require("fs");
15573
17840
  var import_node_path27 = require("path");
15574
17841
  var import_promises6 = require("stream/promises");
15575
17842
  var import_node_zlib = require("zlib");
15576
17843
 
15577
17844
  // src/audit/auditDictionary.ts
15578
- var import_node_fs24 = require("fs");
17845
+ var import_node_fs25 = require("fs");
15579
17846
  var import_node_path25 = require("path");
15580
17847
 
15581
17848
  // src/audit/auditBodyStore.ts
@@ -15808,7 +18075,7 @@ function parseEntries(raw) {
15808
18075
  }
15809
18076
  function plainShards(bodiesPath) {
15810
18077
  try {
15811
- return (0, import_node_fs24.readdirSync)(bodiesPath).filter(
18078
+ return (0, import_node_fs25.readdirSync)(bodiesPath).filter(
15812
18079
  (file) => file.endsWith(".jsonl") && isSafeSessionKey(file.slice(0, -".jsonl".length))
15813
18080
  );
15814
18081
  } catch {
@@ -15833,9 +18100,9 @@ function chooseDictionary(anchors) {
15833
18100
  var EMPTY = { shards: 0, anchors: 0, savedBytes: 0 };
15834
18101
  function compactAuditDay(dayPath) {
15835
18102
  const bodiesPath = (0, import_node_path25.join)(dayPath, AUDIT_BODIES_DIR);
15836
- if (!(0, import_node_fs24.existsSync)(bodiesPath)) return EMPTY;
18103
+ if (!(0, import_node_fs25.existsSync)(bodiesPath)) return EMPTY;
15837
18104
  const dictPath = (0, import_node_path25.join)(bodiesPath, AUDIT_DICT_FILE);
15838
- if ((0, import_node_fs24.existsSync)(dictPath) || (0, import_node_fs24.existsSync)(`${dictPath}.gz`)) return EMPTY;
18105
+ if ((0, import_node_fs25.existsSync)(dictPath) || (0, import_node_fs25.existsSync)(`${dictPath}.gz`)) return EMPTY;
15839
18106
  const shardFiles = plainShards(bodiesPath);
15840
18107
  if (shardFiles.length < 2) return EMPTY;
15841
18108
  const loaded = /* @__PURE__ */ new Map();
@@ -15843,7 +18110,7 @@ function compactAuditDay(dayPath) {
15843
18110
  for (const file of shardFiles) {
15844
18111
  let entries;
15845
18112
  try {
15846
- entries = parseEntries((0, import_node_fs24.readFileSync)((0, import_node_path25.join)(bodiesPath, file), "utf8"));
18113
+ entries = parseEntries((0, import_node_fs25.readFileSync)((0, import_node_path25.join)(bodiesPath, file), "utf8"));
15847
18114
  } catch {
15848
18115
  continue;
15849
18116
  }
@@ -15860,7 +18127,7 @@ function compactAuditDay(dayPath) {
15860
18127
  ts: 0,
15861
18128
  req: { base: null, anchor: "dict", pre: 0, suf: 0, ins: dictionary }
15862
18129
  };
15863
- (0, import_node_fs24.writeFileSync)(dictPath, JSON.stringify(dictEntry) + "\n", "utf8");
18130
+ (0, import_node_fs25.writeFileSync)(dictPath, JSON.stringify(dictEntry) + "\n", "utf8");
15864
18131
  const result = { shards: 0, anchors: 0, savedBytes: 0 };
15865
18132
  for (const [file, entries] of loaded) {
15866
18133
  let changed = false;
@@ -15880,11 +18147,11 @@ function compactAuditDay(dayPath) {
15880
18147
  const target = (0, import_node_path25.join)(bodiesPath, file);
15881
18148
  const temp = `${target}.compacting`;
15882
18149
  try {
15883
- (0, import_node_fs24.writeFileSync)(temp, rewritten.map((e) => JSON.stringify(e)).join("\n") + "\n", "utf8");
15884
- (0, import_node_fs24.renameSync)(temp, target);
18150
+ (0, import_node_fs25.writeFileSync)(temp, rewritten.map((e) => JSON.stringify(e)).join("\n") + "\n", "utf8");
18151
+ (0, import_node_fs25.renameSync)(temp, target);
15885
18152
  } catch {
15886
18153
  try {
15887
- if ((0, import_node_fs24.existsSync)(temp)) (0, import_node_fs24.unlinkSync)(temp);
18154
+ if ((0, import_node_fs25.existsSync)(temp)) (0, import_node_fs25.unlinkSync)(temp);
15888
18155
  } catch {
15889
18156
  }
15890
18157
  continue;
@@ -15895,7 +18162,7 @@ function compactAuditDay(dayPath) {
15895
18162
  }
15896
18163
  if (result.shards === 0) {
15897
18164
  try {
15898
- (0, import_node_fs24.unlinkSync)(dictPath);
18165
+ (0, import_node_fs25.unlinkSync)(dictPath);
15899
18166
  } catch {
15900
18167
  }
15901
18168
  }
@@ -15903,11 +18170,11 @@ function compactAuditDay(dayPath) {
15903
18170
  }
15904
18171
  function compactAllClosedAuditDays(auditDir, now = Date.now) {
15905
18172
  const run = { days: 0, shards: 0, savedBytes: 0 };
15906
- if (!(0, import_node_fs24.existsSync)(auditDir)) return run;
18173
+ if (!(0, import_node_fs25.existsSync)(auditDir)) return run;
15907
18174
  const today = auditDayDirName(now());
15908
18175
  let names;
15909
18176
  try {
15910
- names = (0, import_node_fs24.readdirSync)(auditDir).filter(isAuditDayDir).sort();
18177
+ names = (0, import_node_fs25.readdirSync)(auditDir).filter(isAuditDayDir).sort();
15911
18178
  } catch {
15912
18179
  return run;
15913
18180
  }
@@ -15926,7 +18193,7 @@ function compactAllClosedAuditDays(auditDir, now = Date.now) {
15926
18193
  }
15927
18194
 
15928
18195
  // src/audit/auditStats.ts
15929
- var import_node_fs25 = require("fs");
18196
+ var import_node_fs26 = require("fs");
15930
18197
  var import_node_path26 = require("path");
15931
18198
  var SIDECAR_VERSION = 1;
15932
18199
  var META_PREFIX_BYTES = 64 * 1024;
@@ -15935,9 +18202,9 @@ function auditStatsFileName(auditFile) {
15935
18202
  return auditFile.replace(/\.jsonl$/, ".stats.json");
15936
18203
  }
15937
18204
  function readPersisted(path2) {
15938
- if (!(0, import_node_fs25.existsSync)(path2)) return null;
18205
+ if (!(0, import_node_fs26.existsSync)(path2)) return null;
15939
18206
  try {
15940
- const value = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8"));
18207
+ const value = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
15941
18208
  if (value.version !== SIDECAR_VERSION || !Number.isSafeInteger(value.auditBytes) || (value.auditBytes ?? -1) < 0 || !Number.isSafeInteger(value.requestCount) || (value.requestCount ?? -1) < 0 || !Number.isSafeInteger(value.errorCount) || (value.errorCount ?? -1) < 0 || (value.errorCount ?? 0) > (value.requestCount ?? -1) || typeof value.complete !== "boolean" || value.minTs !== null && !Number.isFinite(value.minTs) || value.maxTs !== null && !Number.isFinite(value.maxTs)) {
15942
18209
  return null;
15943
18210
  }
@@ -15967,7 +18234,7 @@ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfte
15967
18234
  minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
15968
18235
  maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
15969
18236
  };
15970
- (0, import_node_fs25.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
18237
+ (0, import_node_fs26.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
15971
18238
  }
15972
18239
  function queryCovers(stats, from, to) {
15973
18240
  return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
@@ -16025,7 +18292,7 @@ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
16025
18292
  prefixTruncated = false;
16026
18293
  };
16027
18294
  if (auditBytes > startByte) {
16028
- const stream = (0, import_node_fs25.createReadStream)(auditPath, {
18295
+ const stream = (0, import_node_fs26.createReadStream)(auditPath, {
16029
18296
  start: startByte,
16030
18297
  end: auditBytes - 1,
16031
18298
  highWaterMark: READ_CHUNK_BYTES2
@@ -16078,12 +18345,12 @@ function mergePersistedStats(previous, appended) {
16078
18345
  };
16079
18346
  }
16080
18347
  async function readAuditStats(auditDir, query2 = {}) {
16081
- if (!(0, import_node_fs25.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
18348
+ if (!(0, import_node_fs26.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
16082
18349
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
16083
18350
  const to = typeof query2.to === "number" ? query2.to : Infinity;
16084
18351
  let sources;
16085
18352
  try {
16086
- sources = (0, import_node_fs25.readdirSync)(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
18353
+ sources = (0, import_node_fs26.readdirSync)(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
16087
18354
  (name) => AUDIT_DAY_DIR_RE.test(name) ? {
16088
18355
  auditPath: (0, import_node_path26.join)(auditDir, name, AUDIT_META_FILE),
16089
18356
  statsPath: (0, import_node_path26.join)(auditDir, name, auditStatsFileName(AUDIT_META_FILE))
@@ -16091,14 +18358,14 @@ async function readAuditStats(auditDir, query2 = {}) {
16091
18358
  auditPath: (0, import_node_path26.join)(auditDir, name),
16092
18359
  statsPath: (0, import_node_path26.join)(auditDir, auditStatsFileName(name))
16093
18360
  }
16094
- ).filter((source) => (0, import_node_fs25.existsSync)(source.auditPath));
18361
+ ).filter((source) => (0, import_node_fs26.existsSync)(source.auditPath));
16095
18362
  } catch {
16096
18363
  return { requestCount: 0, errorCount: 0, complete: false };
16097
18364
  }
16098
18365
  const total = { requestCount: 0, errorCount: 0, complete: true };
16099
18366
  for (const { auditPath, statsPath } of sources) {
16100
18367
  try {
16101
- const auditBytes = (0, import_node_fs25.statSync)(auditPath).size;
18368
+ const auditBytes = (0, import_node_fs26.statSync)(auditPath).size;
16102
18369
  const persisted = readPersisted(statsPath);
16103
18370
  if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
16104
18371
  total.requestCount += persisted.requestCount;
@@ -16117,7 +18384,7 @@ async function readAuditStats(auditDir, query2 = {}) {
16117
18384
  total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
16118
18385
  total.complete = total.complete && scanned.filtered.complete;
16119
18386
  const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
16120
- if (current.complete) (0, import_node_fs25.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
18387
+ if (current.complete) (0, import_node_fs26.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
16121
18388
  } catch {
16122
18389
  total.complete = false;
16123
18390
  }
@@ -16126,7 +18393,7 @@ async function readAuditStats(auditDir, query2 = {}) {
16126
18393
  }
16127
18394
 
16128
18395
  // src/audit/AuditPruneSweeper.ts
16129
- var DAY_MS = 24 * 60 * 6e4;
18396
+ var DAY_MS4 = 24 * 60 * 6e4;
16130
18397
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
16131
18398
  var ARCHIVE_BATCH = 64;
16132
18399
  var AuditPruneSweeper = class {
@@ -16189,19 +18456,19 @@ var AuditPruneSweeper = class {
16189
18456
  if (!this.config.enabled || this.sweeping) return 0;
16190
18457
  this.sweeping = true;
16191
18458
  try {
16192
- if (!(0, import_node_fs26.existsSync)(this.auditDir)) return 0;
16193
- const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS;
18459
+ if (!(0, import_node_fs27.existsSync)(this.auditDir)) return 0;
18460
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
16194
18461
  let removed = 0;
16195
- for (const name of (0, import_node_fs26.readdirSync)(this.auditDir)) {
18462
+ for (const name of (0, import_node_fs27.readdirSync)(this.auditDir)) {
16196
18463
  const dateMs = auditFileDateMs(name);
16197
18464
  if (dateMs === null || dateMs >= cutoff) continue;
16198
18465
  try {
16199
18466
  if (isAuditDayDir(name)) {
16200
- (0, import_node_fs26.rmSync)((0, import_node_path27.join)(this.auditDir, name), { recursive: true, force: true });
18467
+ (0, import_node_fs27.rmSync)((0, import_node_path27.join)(this.auditDir, name), { recursive: true, force: true });
16201
18468
  } else {
16202
- (0, import_node_fs26.unlinkSync)((0, import_node_path27.join)(this.auditDir, name));
18469
+ (0, import_node_fs27.unlinkSync)((0, import_node_path27.join)(this.auditDir, name));
16203
18470
  const statsPath = (0, import_node_path27.join)(this.auditDir, auditStatsFileName(name));
16204
- if ((0, import_node_fs26.existsSync)(statsPath)) (0, import_node_fs26.unlinkSync)(statsPath);
18471
+ if ((0, import_node_fs27.existsSync)(statsPath)) (0, import_node_fs27.unlinkSync)(statsPath);
16205
18472
  }
16206
18473
  removed += 1;
16207
18474
  } catch (error) {
@@ -16231,10 +18498,10 @@ var AuditPruneSweeper = class {
16231
18498
  if (!this.config.enabled || this.archiving) return 0;
16232
18499
  this.archiving = true;
16233
18500
  try {
16234
- if (!(0, import_node_fs26.existsSync)(this.auditDir)) return 0;
18501
+ if (!(0, import_node_fs27.existsSync)(this.auditDir)) return 0;
16235
18502
  const today = this.todayMidnight();
16236
18503
  let compressed = 0;
16237
- for (const name of (0, import_node_fs26.readdirSync)(this.auditDir)) {
18504
+ for (const name of (0, import_node_fs27.readdirSync)(this.auditDir)) {
16238
18505
  if (compressed >= ARCHIVE_BATCH) break;
16239
18506
  const dateMs = auditFileDateMs(name);
16240
18507
  if (dateMs === null || dateMs >= today || !isAuditDayDir(name)) continue;
@@ -16275,7 +18542,7 @@ var AuditPruneSweeper = class {
16275
18542
  async archiveDay(bodiesPath, budget) {
16276
18543
  let shards;
16277
18544
  try {
16278
- shards = (0, import_node_fs26.readdirSync)(bodiesPath).filter((file) => file.endsWith(".jsonl"));
18545
+ shards = (0, import_node_fs27.readdirSync)(bodiesPath).filter((file) => file.endsWith(".jsonl"));
16279
18546
  } catch {
16280
18547
  return 0;
16281
18548
  }
@@ -16285,16 +18552,16 @@ var AuditPruneSweeper = class {
16285
18552
  const source = (0, import_node_path27.join)(bodiesPath, shard);
16286
18553
  const target = `${source}.gz`;
16287
18554
  try {
16288
- if ((0, import_node_fs26.existsSync)(target)) {
16289
- (0, import_node_fs26.unlinkSync)(source);
18555
+ if ((0, import_node_fs27.existsSync)(target)) {
18556
+ (0, import_node_fs27.unlinkSync)(source);
16290
18557
  continue;
16291
18558
  }
16292
- await (0, import_promises6.pipeline)((0, import_node_fs26.createReadStream)(source), (0, import_node_zlib.createGzip)(), (0, import_node_fs26.createWriteStream)(target));
16293
- (0, import_node_fs26.unlinkSync)(source);
18559
+ await (0, import_promises6.pipeline)((0, import_node_fs27.createReadStream)(source), (0, import_node_zlib.createGzip)(), (0, import_node_fs27.createWriteStream)(target));
18560
+ (0, import_node_fs27.unlinkSync)(source);
16294
18561
  compressed += 1;
16295
18562
  } catch (error) {
16296
18563
  try {
16297
- if ((0, import_node_fs26.existsSync)(target)) (0, import_node_fs26.unlinkSync)(target);
18564
+ if ((0, import_node_fs27.existsSync)(target)) (0, import_node_fs27.unlinkSync)(target);
16298
18565
  } catch {
16299
18566
  }
16300
18567
  this.logger.warn("[AuditPruneSweeper] failed to archive audit body shard", {
@@ -16308,7 +18575,7 @@ var AuditPruneSweeper = class {
16308
18575
  };
16309
18576
 
16310
18577
  // src/usage/usageMigrate.ts
16311
- var import_node_fs27 = require("fs");
18578
+ var import_node_fs28 = require("fs");
16312
18579
  var import_promises7 = require("fs/promises");
16313
18580
  var import_node_path28 = require("path");
16314
18581
  var import_node_readline = require("readline");
@@ -16355,7 +18622,7 @@ async function migrateLegacyUsageEvents(opts) {
16355
18622
  let skipped = 0;
16356
18623
  try {
16357
18624
  const reader = (0, import_node_readline.createInterface)({
16358
- input: (0, import_node_fs27.createReadStream)(eventsPath, { encoding: "utf8" }),
18625
+ input: (0, import_node_fs28.createReadStream)(eventsPath, { encoding: "utf8" }),
16359
18626
  crlfDelay: Number.POSITIVE_INFINITY
16360
18627
  });
16361
18628
  for await (const line of reader) {
@@ -16447,7 +18714,7 @@ async function closeAll(writers) {
16447
18714
  // src/usage/UsagePruneSweeper.ts
16448
18715
  var import_promises8 = require("fs/promises");
16449
18716
  var import_node_path29 = require("path");
16450
- var DAY_MS2 = 24 * 60 * 6e4;
18717
+ var DAY_MS5 = 24 * 60 * 6e4;
16451
18718
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
16452
18719
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
16453
18720
  var UsagePruneSweeper = class {
@@ -16504,7 +18771,7 @@ var UsagePruneSweeper = class {
16504
18771
  this.sweeping = true;
16505
18772
  try {
16506
18773
  const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
16507
- const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS2;
18774
+ const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
16508
18775
  let removed = 0;
16509
18776
  for (const entry of await listUsageDays(this.usageDir)) {
16510
18777
  if (!entry.hasShard) continue;
@@ -16562,12 +18829,12 @@ var UsagePruneSweeper = class {
16562
18829
  };
16563
18830
 
16564
18831
  // src/audit/auditBodyReader.ts
16565
- var import_node_fs29 = require("fs");
18832
+ var import_node_fs30 = require("fs");
16566
18833
  var import_node_path30 = require("path");
16567
18834
  var import_node_zlib2 = require("zlib");
16568
18835
 
16569
18836
  // src/audit/auditJsonl.ts
16570
- var import_node_fs28 = require("fs");
18837
+ var import_node_fs29 = require("fs");
16571
18838
  var WINDOW_BYTES = 1 << 20;
16572
18839
  var MAX_LINE_BYTES = 32 * 1024 * 1024;
16573
18840
  var NEWLINE2 = 10;
@@ -16575,9 +18842,9 @@ function forEachLineFromTail(path2, onLine) {
16575
18842
  let fd;
16576
18843
  let end;
16577
18844
  try {
16578
- end = (0, import_node_fs28.statSync)(path2).size;
18845
+ end = (0, import_node_fs29.statSync)(path2).size;
16579
18846
  if (end === 0) return;
16580
- fd = (0, import_node_fs28.openSync)(path2, "r");
18847
+ fd = (0, import_node_fs29.openSync)(path2, "r");
16581
18848
  } catch {
16582
18849
  return;
16583
18850
  }
@@ -16588,7 +18855,7 @@ function forEachLineFromTail(path2, onLine) {
16588
18855
  const window = Buffer.allocUnsafe(end - start);
16589
18856
  let read;
16590
18857
  try {
16591
- read = (0, import_node_fs28.readSync)(fd, window, 0, end - start, start);
18858
+ read = (0, import_node_fs29.readSync)(fd, window, 0, end - start, start);
16592
18859
  } catch {
16593
18860
  return;
16594
18861
  }
@@ -16616,7 +18883,7 @@ function forEachLineFromTail(path2, onLine) {
16616
18883
  }
16617
18884
  } finally {
16618
18885
  try {
16619
- (0, import_node_fs28.closeSync)(fd);
18886
+ (0, import_node_fs29.closeSync)(fd);
16620
18887
  } catch {
16621
18888
  }
16622
18889
  }
@@ -16626,10 +18893,10 @@ function forEachLineFromTail(path2, onLine) {
16626
18893
  function candidateDays(auditDir, ts) {
16627
18894
  if (typeof ts === "number" && Number.isFinite(ts)) {
16628
18895
  const named = auditDayDirName(ts);
16629
- if ((0, import_node_fs29.existsSync)((0, import_node_path30.join)(auditDir, named))) return [named];
18896
+ if ((0, import_node_fs30.existsSync)((0, import_node_path30.join)(auditDir, named))) return [named];
16630
18897
  }
16631
18898
  try {
16632
- return (0, import_node_fs29.readdirSync)(auditDir).filter(isAuditDayDir).sort().reverse();
18899
+ return (0, import_node_fs30.readdirSync)(auditDir).filter(isAuditDayDir).sort().reverse();
16633
18900
  } catch {
16634
18901
  return [];
16635
18902
  }
@@ -16637,9 +18904,9 @@ function candidateDays(auditDir, ts) {
16637
18904
  function readShard(auditDir, day, sessionKey) {
16638
18905
  const base = (0, import_node_path30.join)(auditDir, day, AUDIT_BODIES_DIR, auditBodyFileName(sessionKey));
16639
18906
  try {
16640
- if ((0, import_node_fs29.existsSync)(base)) return (0, import_node_fs29.readFileSync)(base, "utf8");
18907
+ if ((0, import_node_fs30.existsSync)(base)) return (0, import_node_fs30.readFileSync)(base, "utf8");
16641
18908
  const gz = `${base}.gz`;
16642
- if ((0, import_node_fs29.existsSync)(gz)) return (0, import_node_zlib2.gunzipSync)((0, import_node_fs29.readFileSync)(gz)).toString("utf8");
18909
+ if ((0, import_node_fs30.existsSync)(gz)) return (0, import_node_zlib2.gunzipSync)((0, import_node_fs30.readFileSync)(gz)).toString("utf8");
16643
18910
  } catch {
16644
18911
  return null;
16645
18912
  }
@@ -16672,8 +18939,8 @@ function withDictionary(auditDir, day, entries) {
16672
18939
  const base = (0, import_node_path30.join)(auditDir, day, AUDIT_BODIES_DIR, AUDIT_DICT_FILE);
16673
18940
  let raw = null;
16674
18941
  try {
16675
- if ((0, import_node_fs29.existsSync)(base)) raw = (0, import_node_fs29.readFileSync)(base, "utf8");
16676
- else if ((0, import_node_fs29.existsSync)(`${base}.gz`)) raw = (0, import_node_zlib2.gunzipSync)((0, import_node_fs29.readFileSync)(`${base}.gz`)).toString("utf8");
18942
+ if ((0, import_node_fs30.existsSync)(base)) raw = (0, import_node_fs30.readFileSync)(base, "utf8");
18943
+ else if ((0, import_node_fs30.existsSync)(`${base}.gz`)) raw = (0, import_node_zlib2.gunzipSync)((0, import_node_fs30.readFileSync)(`${base}.gz`)).toString("utf8");
16677
18944
  } catch {
16678
18945
  return entries;
16679
18946
  }
@@ -16706,7 +18973,7 @@ function reconstructRequest(entries, entry) {
16706
18973
  }
16707
18974
  function readAuditBody(auditDir, query2) {
16708
18975
  if (!isSafeSessionKey(query2.sessionKey) || !query2.id) return {};
16709
- if (!(0, import_node_fs29.existsSync)(auditDir)) return {};
18976
+ if (!(0, import_node_fs30.existsSync)(auditDir)) return {};
16710
18977
  for (const day of candidateDays(auditDir, query2.ts)) {
16711
18978
  const raw = readShard(auditDir, day, query2.sessionKey);
16712
18979
  if (raw === null) continue;
@@ -16724,7 +18991,7 @@ function readAuditBody(auditDir, query2) {
16724
18991
  function readLegacyInlineBody(auditDir, id) {
16725
18992
  let names;
16726
18993
  try {
16727
- names = (0, import_node_fs29.readdirSync)(auditDir).filter((name) => AUDIT_FILE_RE.test(name)).sort().reverse();
18994
+ names = (0, import_node_fs30.readdirSync)(auditDir).filter((name) => AUDIT_FILE_RE.test(name)).sort().reverse();
16728
18995
  } catch {
16729
18996
  return {};
16730
18997
  }
@@ -16753,7 +19020,7 @@ function readLegacyInlineBody(auditDir, id) {
16753
19020
  }
16754
19021
 
16755
19022
  // src/audit/auditReader.ts
16756
- var import_node_fs30 = require("fs");
19023
+ var import_node_fs31 = require("fs");
16757
19024
  var import_node_path31 = require("path");
16758
19025
  var DEFAULT_LIMIT = 200;
16759
19026
  var MAX_LIMIT = 2e3;
@@ -16761,7 +19028,7 @@ var OVERSCAN = 256;
16761
19028
  function daySources(auditDir) {
16762
19029
  let names;
16763
19030
  try {
16764
- names = (0, import_node_fs30.readdirSync)(auditDir);
19031
+ names = (0, import_node_fs31.readdirSync)(auditDir);
16765
19032
  } catch {
16766
19033
  return [];
16767
19034
  }
@@ -16771,7 +19038,7 @@ function daySources(auditDir) {
16771
19038
  if (dateMs === null) continue;
16772
19039
  if (AUDIT_DAY_DIR_RE.test(name)) {
16773
19040
  const path2 = (0, import_node_path31.join)(auditDir, name, AUDIT_META_FILE);
16774
- if ((0, import_node_fs30.existsSync)(path2)) sources.push({ path: path2, dateMs });
19041
+ if ((0, import_node_fs31.existsSync)(path2)) sources.push({ path: path2, dateMs });
16775
19042
  } else if (AUDIT_FILE_RE.test(name)) {
16776
19043
  sources.push({ path: (0, import_node_path31.join)(auditDir, name), dateMs });
16777
19044
  }
@@ -16789,7 +19056,7 @@ function toMetaRecord(record) {
16789
19056
  return { ...meta, hasBody: true };
16790
19057
  }
16791
19058
  function readAuditRecords(auditDir, query2 = {}) {
16792
- if (!(0, import_node_fs30.existsSync)(auditDir)) return [];
19059
+ if (!(0, import_node_fs31.existsSync)(auditDir)) return [];
16793
19060
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
16794
19061
  const to = typeof query2.to === "number" ? query2.to : Infinity;
16795
19062
  const limit = Math.min(MAX_LIMIT, Math.max(1, Math.trunc(query2.limit ?? DEFAULT_LIMIT)));
@@ -16817,7 +19084,7 @@ function readAuditRecords(auditDir, query2 = {}) {
16817
19084
  }
16818
19085
 
16819
19086
  // src/audit/AuditWriter.ts
16820
- var import_node_fs31 = require("fs");
19087
+ var import_node_fs32 = require("fs");
16821
19088
  var import_node_path32 = require("path");
16822
19089
  var AuditWriter = class {
16823
19090
  constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
@@ -16865,7 +19132,7 @@ var AuditWriter = class {
16865
19132
  /** Create a directory once per process and remember it. */
16866
19133
  ensureDir(path2) {
16867
19134
  if (!this.ensuredDirs.has(path2)) {
16868
- (0, import_node_fs31.mkdirSync)(path2, { recursive: true });
19135
+ (0, import_node_fs32.mkdirSync)(path2, { recursive: true });
16869
19136
  this.ensuredDirs.add(path2);
16870
19137
  }
16871
19138
  return path2;
@@ -16875,8 +19142,8 @@ var AuditWriter = class {
16875
19142
  const { requestBody: _req, responseBody: _res, ...meta } = record;
16876
19143
  const file = (0, import_node_path32.join)(dayPath, AUDIT_META_FILE);
16877
19144
  const line = JSON.stringify(meta) + "\n";
16878
- const bytesBefore = (0, import_node_fs31.existsSync)(file) ? (0, import_node_fs31.statSync)(file).size : 0;
16879
- (0, import_node_fs31.appendFileSync)(file, line, "utf8");
19145
+ const bytesBefore = (0, import_node_fs32.existsSync)(file) ? (0, import_node_fs32.statSync)(file).size : 0;
19146
+ (0, import_node_fs32.appendFileSync)(file, line, "utf8");
16880
19147
  try {
16881
19148
  updateAuditStatsAfterAppend(
16882
19149
  file,
@@ -16908,7 +19175,7 @@ var AuditWriter = class {
16908
19175
  const line = encodeBodyEntry(record, sessionKey, dayDir, this.bases);
16909
19176
  if (line === null) return;
16910
19177
  const bodiesPath = this.ensureDir((0, import_node_path32.join)(dayPath, AUDIT_BODIES_DIR));
16911
- (0, import_node_fs31.appendFileSync)((0, import_node_path32.join)(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
19178
+ (0, import_node_fs32.appendFileSync)((0, import_node_path32.join)(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
16912
19179
  } catch (error) {
16913
19180
  this.bases.forget(sessionKey);
16914
19181
  this.logger.warn("[AuditWriter] failed to append audit body shard", {
@@ -16920,10 +19187,10 @@ var AuditWriter = class {
16920
19187
  };
16921
19188
 
16922
19189
  // src/billing/BillingPublisher.ts
16923
- var import_node_fs32 = require("fs");
19190
+ var import_node_fs33 = require("fs");
16924
19191
  var import_node_crypto24 = require("crypto");
16925
19192
  var import_node_path33 = require("path");
16926
- var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
19193
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
16927
19194
 
16928
19195
  // src/billing/billingFiles.ts
16929
19196
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -16946,7 +19213,7 @@ var BillingPublisher = class {
16946
19213
  constructor(billingDir, logger, opts = {}) {
16947
19214
  this.billingDir = billingDir;
16948
19215
  this.logger = logger;
16949
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch7.fetchUpstream)(url, init));
19216
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init));
16950
19217
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
16951
19218
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
16952
19219
  this.now = opts.now ?? Date.now;
@@ -16994,7 +19261,7 @@ var BillingPublisher = class {
16994
19261
  appendNow(event) {
16995
19262
  this.ensureDir();
16996
19263
  const file = (0, import_node_path33.join)(this.billingDir, billingFileName(event.ts));
16997
- (0, import_node_fs32.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
19264
+ (0, import_node_fs33.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
16998
19265
  }
16999
19266
  /**
17000
19267
  * One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
@@ -17044,7 +19311,7 @@ var BillingPublisher = class {
17044
19311
  try {
17045
19312
  this.ensureDir();
17046
19313
  const file = (0, import_node_path33.join)(this.billingDir, deliveredFileName(event.ts));
17047
- (0, import_node_fs32.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
19314
+ (0, import_node_fs33.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
17048
19315
  } catch (error) {
17049
19316
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
17050
19317
  error: error instanceof Error ? error.message : String(error)
@@ -17053,20 +19320,20 @@ var BillingPublisher = class {
17053
19320
  }
17054
19321
  ensureDir() {
17055
19322
  if (this.dirEnsured) return;
17056
- (0, import_node_fs32.mkdirSync)(this.billingDir, { recursive: true });
19323
+ (0, import_node_fs33.mkdirSync)(this.billingDir, { recursive: true });
17057
19324
  this.dirEnsured = true;
17058
19325
  }
17059
19326
  };
17060
19327
 
17061
19328
  // src/billing/billingReader.ts
17062
- var import_node_fs33 = require("fs");
19329
+ var import_node_fs34 = require("fs");
17063
19330
  var import_node_path34 = require("path");
17064
19331
  function readBillingLedger(billingDir) {
17065
19332
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
17066
- if (!(0, import_node_fs33.existsSync)(billingDir)) return view;
19333
+ if (!(0, import_node_fs34.existsSync)(billingDir)) return view;
17067
19334
  let files;
17068
19335
  try {
17069
- files = (0, import_node_fs33.readdirSync)(billingDir);
19336
+ files = (0, import_node_fs34.readdirSync)(billingDir);
17070
19337
  } catch {
17071
19338
  return view;
17072
19339
  }
@@ -17097,7 +19364,7 @@ function readBillingStatus(billingDir) {
17097
19364
  function parseLines(dir, file) {
17098
19365
  let raw;
17099
19366
  try {
17100
- raw = (0, import_node_fs33.readFileSync)((0, import_node_path34.join)(dir, file), "utf8");
19367
+ raw = (0, import_node_fs34.readFileSync)((0, import_node_path34.join)(dir, file), "utf8");
17101
19368
  } catch {
17102
19369
  return [];
17103
19370
  }
@@ -17196,7 +19463,7 @@ var BillingRetrySweeper = class {
17196
19463
  // src/TokenRefreshScheduler.ts
17197
19464
  var REFRESH_LEAD_MS2 = 5 * 6e4;
17198
19465
  var SWEEP_INTERVAL_MS5 = 6e4;
17199
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini"];
19466
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
17200
19467
  var TokenRefreshScheduler = class {
17201
19468
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
17202
19469
  this.store = store;
@@ -17279,6 +19546,14 @@ var TokenRefreshScheduler = class {
17279
19546
  return this.store.refreshCodexToken();
17280
19547
  case "gemini":
17281
19548
  return this.store.refreshGeminiToken();
19549
+ case "kimi":
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();
17282
19557
  }
17283
19558
  }
17284
19559
  };
@@ -17355,7 +19630,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
17355
19630
 
17356
19631
  // src/webhook/WebhookDispatcher.ts
17357
19632
  var import_node_crypto25 = require("crypto");
17358
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
19633
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
17359
19634
  var WEBHOOK_MAX_ATTEMPTS = 3;
17360
19635
  var WEBHOOK_QUEUE_MAX = 1e3;
17361
19636
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -17375,7 +19650,7 @@ var WebhookDispatcher = class {
17375
19650
  sleep;
17376
19651
  now;
17377
19652
  constructor(opts = {}) {
17378
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init));
19653
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
17379
19654
  this.logger = opts.logger;
17380
19655
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
17381
19656
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -17461,8 +19736,8 @@ var WebhookDispatcher = class {
17461
19736
  signal: AbortSignal.timeout(this.timeoutMs)
17462
19737
  });
17463
19738
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
17464
- } catch (err5) {
17465
- return { ok: false, error: err5 instanceof Error ? err5.message : String(err5) };
19739
+ } catch (err8) {
19740
+ return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
17466
19741
  }
17467
19742
  }
17468
19743
  /**
@@ -17525,7 +19800,7 @@ function feishuText(event) {
17525
19800
  // src/bootstrap.ts
17526
19801
  var activeImageRuntimeBootstrapSession;
17527
19802
  function createImageRuntimeBootstrapSession(initialGeneration) {
17528
- const openAIOperationRegistry = new import_core4.OpenAIOperationRegistry();
19803
+ const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
17529
19804
  const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
17530
19805
  const unregisterContributions = [];
17531
19806
  try {
@@ -17586,7 +19861,7 @@ function resetImageRuntimeBootstrapSession() {
17586
19861
  function resolveLoggingConfig(configured, configPath) {
17587
19862
  const file = configured?.file ?? defaultDaemonLogPath(configPath);
17588
19863
  try {
17589
- (0, import_node_fs34.mkdirSync)(configured?.file ? (0, import_node_path35.dirname)(configured.file) : defaultLogDir(configPath), {
19864
+ (0, import_node_fs35.mkdirSync)(configured?.file ? (0, import_node_path35.dirname)(configured.file) : defaultLogDir(configPath), {
17590
19865
  recursive: true
17591
19866
  });
17592
19867
  } catch {
@@ -17604,12 +19879,12 @@ function buildDaemon(config, paths) {
17604
19879
  setSecretBox(secretBox3);
17605
19880
  setSecretBox2(secretBox3);
17606
19881
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
17607
- const accountAllowanceStore = new import_AccountAllowanceStore4.AccountAllowanceStore(
19882
+ const accountAllowanceStore = new import_AccountAllowanceStore9.AccountAllowanceStore(
17608
19883
  Date.now,
17609
19884
  void 0,
17610
19885
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
17611
19886
  );
17612
- (0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
19887
+ (0, import_AccountAllowanceStore9.setSharedAccountAllowanceStore)(accountAllowanceStore);
17613
19888
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
17614
19889
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
17615
19890
  );
@@ -17634,21 +19909,22 @@ function buildDaemon(config, paths) {
17634
19909
  claudeAllowanceRefreshScheduler.configure(
17635
19910
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
17636
19911
  );
17637
- const subscriptionAccounts = new import_subscriptions6.SubscriptionAccountService(credentialStore);
17638
- (0, import_subscriptions6.setSubscriptionAccountService)(subscriptionAccounts);
17639
- const subscriptionRegistry = new import_subscriptions6.SubscriptionProviderRegistry(
19912
+ const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
19913
+ (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
19914
+ const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
17640
19915
  subscriptionAccounts,
17641
19916
  credentialStore
17642
19917
  );
17643
- (0, import_subscriptions6.setSubscriptionProviderRegistry)(subscriptionRegistry);
19918
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
17644
19919
  setServerProxyConfig(decryptedConfig.server?.proxy);
17645
- (0, import_upstreamFetch9.setUpstreamProxyResolver)(
19920
+ (0, import_upstreamFetch15.setUpstreamProxyResolver)(
17646
19921
  createUpstreamProxyResolver({
17647
19922
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
17648
19923
  })
17649
19924
  );
17650
19925
  (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver.getGeminiCodeAssistProjectResolver)());
17651
19926
  const autoDisableStore = new AutoDisableStore();
19927
+ const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
17652
19928
  const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
17653
19929
  createPoolKeysLoader((id) => llmConfig.getProviderRow(id), autoDisableStore),
17654
19930
  resolveEnvKey,
@@ -17665,7 +19941,7 @@ function buildDaemon(config, paths) {
17665
19941
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
17666
19942
  // Catalog egress follows the same global/env proxy policy as every other
17667
19943
  // daemon upstream call; no provider/account override applies here.
17668
- fetchImpl: ((input, init) => (0, import_upstreamFetch9.fetchUpstream)(String(input), init ?? {}))
19944
+ fetchImpl: ((input, init) => (0, import_upstreamFetch15.fetchUpstream)(String(input), init ?? {}))
17669
19945
  });
17670
19946
  const pricingRefreshScheduler = new PricingRefreshScheduler(
17671
19947
  pricingEngine,
@@ -17929,6 +20205,11 @@ function buildDaemon(config, paths) {
17929
20205
  // values themselves NEVER leave (masked via `maskProviderApiKey`).
17930
20206
  apiKeyPool,
17931
20207
  autoDisableStore,
20208
+ // BYO provider-key quota (Z.AI coding plan, MiniMax Token Plan, …): a
20209
+ // read-through cached same-key usage probe surfaced on the keys view. The
20210
+ // key plaintext is resolved + decrypted inside the service and never
20211
+ // crosses back out.
20212
+ providerKeyQuota: providerKeyQuotaService,
17932
20213
  // Interactive OAuth login over admin HTTP (app-parity child 4, design
17933
20214
  // D1/D2-a). The in-memory pending-session store (NEVER serialized), the
17934
20215
  // injected token-exchange fetch (global `fetch` here; mocked in tests), and a
@@ -17945,7 +20226,7 @@ function buildDaemon(config, paths) {
17945
20226
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
17946
20227
  // excluded from the upstream trace, so a failing login left no evidence.
17947
20228
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
17948
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20229
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init, { providerId, redactBodies: true }),
17949
20230
  subscriptionAccountAppender: credentialStore,
17950
20231
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
17951
20232
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -17953,6 +20234,13 @@ function buildDaemon(config, paths) {
17953
20234
  // can inject a mock so no real port is bound.
17954
20235
  codexSessions: new CodexOAuthSessionStore(),
17955
20236
  codexAwaitLoopback: paths.codexAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal)),
20237
+ // Kimi interactive OAuth — the async DEVICE-CODE flow store (no port, no
20238
+ // paste; the app shows the verification URL + user code and polls the
20239
+ // token-free status). Token captured + persisted daemon-side.
20240
+ kimiSessions: new CodexOAuthSessionStore(),
20241
+ // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20242
+ grokSessions: new CodexOAuthSessionStore(),
20243
+ copilotSessions: new CodexOAuthSessionStore(),
17956
20244
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
17957
20245
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
17958
20246
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -18011,7 +20299,7 @@ function buildDaemon(config, paths) {
18011
20299
  });
18012
20300
  const webhookDispatcher = new WebhookDispatcher({
18013
20301
  logger,
18014
- fetchImpl: (url, init) => (0, import_upstreamFetch9.fetchUpstream)(url, init)
20302
+ fetchImpl: (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init)
18015
20303
  });
18016
20304
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
18017
20305
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -18091,9 +20379,9 @@ function resetDaemonSingletonsForTests() {
18091
20379
  (0, import_provider_proxy4.__resetProviderProxyForTests)();
18092
20380
  (0, import_outbound_api10.__resetOutboundApiServerForTests)();
18093
20381
  (0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
18094
- (0, import_subscriptions6.setSubscriptionProviderRegistry)(null);
18095
- (0, import_subscriptions6.setSubscriptionAccountService)(null);
18096
- (0, import_upstreamFetch9.setUpstreamProxyResolver)(null);
20382
+ (0, import_subscriptions12.setSubscriptionProviderRegistry)(null);
20383
+ (0, import_subscriptions12.setSubscriptionAccountService)(null);
20384
+ (0, import_upstreamFetch15.setUpstreamProxyResolver)(null);
18097
20385
  setServerProxyConfig(void 0);
18098
20386
  (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)(null);
18099
20387
  setSecretBox(null);
@@ -18102,14 +20390,14 @@ function resetDaemonSingletonsForTests() {
18102
20390
  resetAuditRuntimeForTests();
18103
20391
  resetBillingRuntimeForTests();
18104
20392
  (0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
18105
- (0, import_AccountAllowanceStore4.__resetSharedAccountAllowanceStoreForTests)();
20393
+ (0, import_AccountAllowanceStore9.__resetSharedAccountAllowanceStoreForTests)();
18106
20394
  (0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
18107
20395
  (0, import_usage2.__resetSharedUsageThroughputTrackerForTests)();
18108
20396
  }
18109
20397
  function isTokensStoreReadable(tokensPath) {
18110
20398
  try {
18111
- if (!(0, import_node_fs34.existsSync)(tokensPath)) return true;
18112
- (0, import_node_fs34.accessSync)(tokensPath, import_node_fs34.constants.R_OK);
20399
+ if (!(0, import_node_fs35.existsSync)(tokensPath)) return true;
20400
+ (0, import_node_fs35.accessSync)(tokensPath, import_node_fs35.constants.R_OK);
18113
20401
  return true;
18114
20402
  } catch {
18115
20403
  return false;