@narumitw/pi-usage 0.57.0 → 0.59.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.ts CHANGED
@@ -109,7 +109,7 @@ var UsageCache = class {
109
109
  this.sweepExpired(now);
110
110
  return this.entries.get(cacheKey(providerId, fingerprint))?.report;
111
111
  }
112
- set(providerId, fingerprint, report, now = Date.now()) {
112
+ set(providerId, fingerprint, report2, now = Date.now()) {
113
113
  this.sweepExpired(now);
114
114
  const key = cacheKey(providerId, fingerprint);
115
115
  this.entries.delete(key);
@@ -118,7 +118,7 @@ var UsageCache = class {
118
118
  if (oldest === void 0) break;
119
119
  this.entries.delete(oldest);
120
120
  }
121
- this.entries.set(key, { createdAt: now, report });
121
+ this.entries.set(key, { createdAt: now, report: report2 });
122
122
  }
123
123
  clearProvider(providerId) {
124
124
  for (const key of this.entries.keys()) {
@@ -328,13 +328,56 @@ function cloneOAuthCredential(value) {
328
328
  import { randomBytes } from "node:crypto";
329
329
  import { readStoredCredential as readStoredCredential2 } from "@earendil-works/pi-coding-agent";
330
330
 
331
+ // src/providers/baseten.ts
332
+ var DECIMAL_AMOUNT = /^(?:0|[1-9]\d*)(?:\.\d+)?$/u;
333
+ function normalizeBasetenBillingUsagePayload(payload, capturedAt) {
334
+ if (payload.model_apis_usage === void 0 || payload.model_apis_usage === null) {
335
+ return report(capturedAt, [], ["Baseten returned no Model APIs usage for the last 30 days."]);
336
+ }
337
+ const usage = asObject(payload.model_apis_usage);
338
+ if (!usage) throw new Error("Baseten Model APIs usage was not an object.");
339
+ const metrics = [
340
+ metric("gross-usage", "Gross usage", usage.total),
341
+ metric("credits-used", "Credits used", usage.credits_used),
342
+ metric("net-subtotal", "Net subtotal", usage.subtotal)
343
+ ];
344
+ return report(capturedAt, metrics);
345
+ }
346
+ function report(capturedAt, metrics, notes) {
347
+ return {
348
+ providerId: "baseten",
349
+ providerName: "Baseten",
350
+ capturedAt,
351
+ source: "baseten-billing-usage-summary",
352
+ semantics: { kind: "api-key", label: "Organization Model APIs spend" },
353
+ buckets: [],
354
+ metrics,
355
+ ...notes ? { notes } : {}
356
+ };
357
+ }
358
+ function metric(id, label, value) {
359
+ const amount2 = decimalAmount(value, label);
360
+ return { id, label, value: amount2, unit: "currency", currency: "USD" };
361
+ }
362
+ function decimalAmount(value, label) {
363
+ const normalized = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
364
+ if (typeof normalized !== "string" || normalized.length > 64 || !DECIMAL_AMOUNT.test(normalized)) {
365
+ throw new Error(`Baseten ${label.toLowerCase()} was not a valid nonnegative amount.`);
366
+ }
367
+ return normalized;
368
+ }
369
+ function asObject(value) {
370
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
371
+ return value;
372
+ }
373
+
331
374
  // src/providers/codex.ts
332
375
  function normalizeCodexBackendPayload(payload, capturedAt) {
333
376
  const buckets = [];
334
377
  normalizeRateLimitGroup(buckets, "codex", "Codex", payload.rate_limit, false);
335
378
  const additional = Array.isArray(payload.additional_rate_limits) ? payload.additional_rate_limits : [];
336
379
  for (const item of additional) {
337
- const value = asObject(item);
380
+ const value = asObject2(item);
338
381
  const id = asString(value?.metered_feature) ?? asString(value?.limit_name);
339
382
  if (!value || !id) continue;
340
383
  try {
@@ -349,7 +392,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
349
392
  }
350
393
  }
351
394
  const metrics = [];
352
- const credits = asObject(payload.credits);
395
+ const credits = asObject2(payload.credits);
353
396
  if (credits?.has_credits === true) {
354
397
  if (credits.unlimited === true) {
355
398
  metrics.push({ id: "credits", label: "Credits", value: "unlimited" });
@@ -364,7 +407,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
364
407
  } else if (credits?.has_credits === false) {
365
408
  metrics.push({ id: "credits", label: "Credits", value: "none" });
366
409
  }
367
- const resetCredits = asObject(payload.rate_limit_reset_credits);
410
+ const resetCredits = asObject2(payload.rate_limit_reset_credits);
368
411
  const resetCount = asNonnegativeInteger(resetCredits?.available_count);
369
412
  if (resetCount !== void 0) {
370
413
  metrics.push({
@@ -394,7 +437,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
394
437
  }
395
438
  function normalizeRateLimitGroup(buckets, groupId, groupLabel, raw, optional) {
396
439
  if (raw === void 0 || raw === null) return;
397
- const details = asObject(raw);
440
+ const details = asObject2(raw);
398
441
  if (!details) {
399
442
  if (optional) return;
400
443
  throw new Error("Codex rate limit was not an object.");
@@ -404,7 +447,7 @@ function normalizeRateLimitGroup(buckets, groupId, groupLabel, raw, optional) {
404
447
  }
405
448
  function addWindow(buckets, groupId, groupLabel, position, raw) {
406
449
  if (raw === void 0 || raw === null) return;
407
- const value = asObject(raw);
450
+ const value = asObject2(raw);
408
451
  if (!value) throw new Error("Codex rate-limit window was not an object.");
409
452
  const used = asNumber(value.used_percent);
410
453
  if (used === void 0) return;
@@ -424,7 +467,7 @@ function addWindow(buckets, groupId, groupLabel, position, raw) {
424
467
  ...resetsAt !== void 0 ? { resetsAt } : {}
425
468
  });
426
469
  }
427
- function asObject(value) {
470
+ function asObject2(value) {
428
471
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
429
472
  return value;
430
473
  }
@@ -465,7 +508,7 @@ function normalizeDeepSeekBalancePayload(payload, capturedAt) {
465
508
  }
466
509
  const balances = /* @__PURE__ */ new Map();
467
510
  for (const raw of payload.balance_infos) {
468
- const balance = asObject2(raw);
511
+ const balance = asObject3(raw);
469
512
  if (!balance) throw new Error("DeepSeek API balance row was not an object.");
470
513
  const currency = deepSeekCurrency(balance.currency);
471
514
  if (!currency) throw new Error("DeepSeek API balance row returned an unsupported currency.");
@@ -473,7 +516,7 @@ function normalizeDeepSeekBalancePayload(payload, capturedAt) {
473
516
  throw new Error(`DeepSeek API balance response repeated ${currency}.`);
474
517
  }
475
518
  for (const [, label, field] of BALANCE_FIELDS) {
476
- if (!decimalAmount(balance[field])) {
519
+ if (!decimalAmount2(balance[field])) {
477
520
  throw new Error(`DeepSeek API balance ${label.toLowerCase()} was not a valid amount.`);
478
521
  }
479
522
  }
@@ -509,21 +552,174 @@ function normalizeDeepSeekBalancePayload(payload, capturedAt) {
509
552
  metrics
510
553
  };
511
554
  }
512
- function asObject2(value) {
555
+ function asObject3(value) {
513
556
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
514
557
  return value;
515
558
  }
516
559
  function deepSeekCurrency(value) {
517
560
  return CURRENCIES.find((currency) => currency === value);
518
561
  }
519
- function decimalAmount(value) {
562
+ function decimalAmount2(value) {
520
563
  return typeof value === "string" && value.length <= 64 && /^(?:0|[1-9]\d*)(?:\.\d+)?$/u.test(value);
521
564
  }
522
565
 
566
+ // src/providers/fireworks.ts
567
+ var NANOS_PER_UNIT = 1000000000n;
568
+ var CURRENCY_PATTERN = /^[A-Z]{3}$/u;
569
+ var ACCOUNT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$/u;
570
+ var INTEGER_PATTERN = /^-?\d+$/u;
571
+ var INT64_MIN = -(2n ** 63n);
572
+ var INT64_MAX = 2n ** 63n - 1n;
573
+ var MAX_UNITS_CHARS = 20;
574
+ var MAX_NANOS_CHARS = 11;
575
+ var SERIES_KEYS = ["serverless", "dedicated", "training", "other"];
576
+ var SERIES_LABELS = {
577
+ serverless: "Serverless",
578
+ dedicated: "Dedicated deployments",
579
+ training: "Training",
580
+ other: "Other"
581
+ };
582
+ function isFireworksAccountId(value) {
583
+ return typeof value === "string" && ACCOUNT_ID_PATTERN.test(value);
584
+ }
585
+ function normalizeFireworksAccountsPayload(payload) {
586
+ if (!Array.isArray(payload.accounts)) {
587
+ throw new Error("Fireworks accounts response did not contain an accounts array.");
588
+ }
589
+ const accounts = [];
590
+ for (const raw of payload.accounts) {
591
+ const account = asObject4(raw);
592
+ if (!account) throw new Error("Fireworks accounts response row was not an object.");
593
+ if (typeof account.name !== "string") {
594
+ throw new Error("Fireworks accounts response omitted the account resource name.");
595
+ }
596
+ const match = /^accounts\/([^/]+)$/u.exec(account.name);
597
+ if (!match || !isFireworksAccountId(match[1])) {
598
+ throw new Error("Fireworks accounts response returned an unsafe account resource name.");
599
+ }
600
+ const accountId = match[1];
601
+ if (accounts.includes(accountId)) {
602
+ throw new Error(`Fireworks accounts response repeated ${accountId}.`);
603
+ }
604
+ accounts.push(accountId);
605
+ }
606
+ return accounts;
607
+ }
608
+ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt) {
609
+ if (!isFireworksAccountId(accountId)) {
610
+ throw new Error("Fireworks billing summary received an unsafe account identifier.");
611
+ }
612
+ if (payload.lineItems !== void 0 && !Array.isArray(payload.lineItems)) {
613
+ throw new Error("Fireworks billing summary lineItems was not an array.");
614
+ }
615
+ const totals = /* @__PURE__ */ new Map();
616
+ for (const raw of payload.lineItems ?? []) {
617
+ const lineItem = asObject4(raw);
618
+ if (!lineItem) throw new Error("Fireworks billing line item was not an object.");
619
+ const cost = moneyAmount(lineItem.totalCost, "line item total cost");
620
+ const series = seriesKey(lineItem.series);
621
+ let amounts = totals.get(cost.currency);
622
+ if (!amounts) {
623
+ amounts = /* @__PURE__ */ new Map();
624
+ totals.set(cost.currency, amounts);
625
+ }
626
+ amounts.set(series, (amounts.get(series) ?? 0n) + cost.amount);
627
+ }
628
+ const metrics = [];
629
+ for (const [currency, amounts] of totals) {
630
+ metrics.push({
631
+ id: `${currency.toLowerCase()}-total`,
632
+ label: "Total spend",
633
+ value: formatMoneyAmount(sumSeries(amounts)),
634
+ unit: "currency",
635
+ currency
636
+ });
637
+ for (const series of SERIES_KEYS) {
638
+ const amount2 = amounts.get(series);
639
+ if (amount2 === void 0) continue;
640
+ metrics.push({
641
+ id: `${currency.toLowerCase()}-${series}`,
642
+ label: SERIES_LABELS[series],
643
+ value: formatMoneyAmount(amount2),
644
+ unit: "currency",
645
+ currency
646
+ });
647
+ }
648
+ }
649
+ const notes = [
650
+ "Rated line items may differ from the final invoice once credits or adjustments are applied."
651
+ ];
652
+ if (metrics.length === 0) {
653
+ notes.push("Fireworks returned no rated line items for the last 30 days.");
654
+ }
655
+ return {
656
+ providerId: "fireworks",
657
+ providerName: "Fireworks",
658
+ capturedAt,
659
+ source: "fireworks-billing-summary",
660
+ semantics: { kind: "api-key", label: "Fireworks API spend" },
661
+ accountLabel: sanitizeDisplayText(accountId, 80),
662
+ buckets: [],
663
+ metrics,
664
+ notes
665
+ };
666
+ }
667
+ function moneyAmount(value, description) {
668
+ const money = asObject4(value);
669
+ if (!money) throw new Error(`Fireworks billing ${description} was not a money object.`);
670
+ const currency = typeof money.currencyCode === "string" ? money.currencyCode : void 0;
671
+ if (!currency || !CURRENCY_PATTERN.test(currency)) {
672
+ throw new Error(`Fireworks billing ${description} currency was not an ISO 4217 code.`);
673
+ }
674
+ const units = money.units === void 0 ? 0n : integerComponent(money.units, description, "whole units", MAX_UNITS_CHARS);
675
+ if (units < INT64_MIN || units > INT64_MAX) {
676
+ throw new Error(`Fireworks billing ${description} whole units exceeded the int64 range.`);
677
+ }
678
+ const nanos = money.nanos === void 0 ? 0n : integerComponent(money.nanos, description, "nano units", MAX_NANOS_CHARS);
679
+ if (nanos <= -NANOS_PER_UNIT || nanos >= NANOS_PER_UNIT) {
680
+ throw new Error(`Fireworks billing ${description} nano units exceeded the Money range.`);
681
+ }
682
+ if (units > 0n && nanos < 0n || units < 0n && nanos > 0n) {
683
+ throw new Error(`Fireworks billing ${description} mixed unit and nano signs.`);
684
+ }
685
+ return { currency, amount: units * NANOS_PER_UNIT + nanos };
686
+ }
687
+ function integerComponent(value, description, component, maxChars) {
688
+ const text = typeof value === "number" && Number.isSafeInteger(value) ? String(value) : typeof value === "string" && INTEGER_PATTERN.test(value) ? value : void 0;
689
+ if (text === void 0 || text.length > maxChars) {
690
+ throw new Error(`Fireworks billing ${description} ${component} was not a bounded integer.`);
691
+ }
692
+ return BigInt(text);
693
+ }
694
+ function seriesKey(value) {
695
+ if (value === void 0 || value === null) return "other";
696
+ if (typeof value !== "string") throw new Error("Fireworks billing line item series was invalid.");
697
+ if (value === "SERVERLESS") return "serverless";
698
+ if (value === "DEDICATED_DEPLOYMENT") return "dedicated";
699
+ if (value === "TRAINING") return "training";
700
+ return "other";
701
+ }
702
+ function sumSeries(amounts) {
703
+ let total = 0n;
704
+ for (const amount2 of amounts.values()) total += amount2;
705
+ return total;
706
+ }
707
+ function formatMoneyAmount(amount2) {
708
+ const negative = amount2 < 0n;
709
+ const magnitude = negative ? -amount2 : amount2;
710
+ const units = magnitude / NANOS_PER_UNIT;
711
+ const nanos = (magnitude % NANOS_PER_UNIT).toString().padStart(9, "0").replace(/0+$/u, "");
712
+ return `${negative ? "-" : ""}${units.toString()}${nanos ? `.${nanos}` : ""}`;
713
+ }
714
+ function asObject4(value) {
715
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
716
+ return value;
717
+ }
718
+
523
719
  // src/providers/github-copilot.ts
524
720
  function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
525
- const snapshots = asObject3(payload.quota_snapshots);
526
- const premium = asObject3(snapshots?.premium_interactions);
721
+ const snapshots = asObject5(payload.quota_snapshots);
722
+ const premium = asObject5(snapshots?.premium_interactions);
527
723
  const metrics = [];
528
724
  let semanticsLabel;
529
725
  let bucket;
@@ -564,8 +760,8 @@ function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
564
760
  };
565
761
  }
566
762
  } else {
567
- const limited = asObject3(payload.limited_user_quotas);
568
- const monthly = asObject3(payload.monthly_quotas);
763
+ const limited = asObject5(payload.limited_user_quotas);
764
+ const monthly = asObject5(payload.monthly_quotas);
569
765
  const remaining = asNonnegativeNumber(limited?.chat);
570
766
  const entitlement = asNonnegativeNumber(monthly?.chat);
571
767
  if (remaining === void 0 || entitlement === void 0) {
@@ -604,7 +800,7 @@ function resetTimestamp(payload) {
604
800
  const milliseconds = Date.parse(raw);
605
801
  return Number.isNaN(milliseconds) ? {} : { resetsAt: Math.floor(milliseconds / 1e3) };
606
802
  }
607
- function asObject3(value) {
803
+ function asObject5(value) {
608
804
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
609
805
  return value;
610
806
  }
@@ -627,7 +823,7 @@ var DAILY_WINDOW_MINUTES = 1440;
627
823
  var WEEKLY_WINDOW_MINUTES = 10080;
628
824
  var FIXED_POINT_UNITS_PER_CENT = 1e6;
629
825
  function normalizeKimiCodingUsagePayload(payload, capturedAt) {
630
- const root = asObject4(payload);
826
+ const root = asObject6(payload);
631
827
  if (!root) throw new Error("Kimi Coding usage response was not an object.");
632
828
  const candidates = [];
633
829
  let omittedWindow = false;
@@ -636,7 +832,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
636
832
  else if (root.usage !== void 0) omittedWindow = true;
637
833
  if (Array.isArray(root.limits)) {
638
834
  for (const raw of root.limits) {
639
- const item = asObject4(raw);
835
+ const item = asObject6(raw);
640
836
  const windowMinutes = parseWindowMinutes(item?.window);
641
837
  const label = sanitizedLabel(item?.name);
642
838
  const bucket = windowMinutes === void 0 ? void 0 : parseUsageRow(item?.detail, windowMinutes, label ?? defaultWindowLabel(windowMinutes));
@@ -673,7 +869,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
673
869
  };
674
870
  }
675
871
  function parseUsageRow(value, windowMinutes, label) {
676
- const row = asObject4(value);
872
+ const row = asObject6(value);
677
873
  if (!row) return void 0;
678
874
  const used = asNonnegativeInteger2(row.used);
679
875
  const limit = asNonnegativeInteger2(row.limit);
@@ -691,7 +887,7 @@ function parseUsageRow(value, windowMinutes, label) {
691
887
  };
692
888
  }
693
889
  function parseWindowMinutes(value) {
694
- const window = asObject4(value);
890
+ const window = asObject6(value);
695
891
  if (!window) return void 0;
696
892
  const duration = asPositiveInteger(window.duration);
697
893
  if (duration === void 0) return void 0;
@@ -701,8 +897,8 @@ function parseWindowMinutes(value) {
701
897
  return Number.isSafeInteger(minutes) ? minutes : void 0;
702
898
  }
703
899
  function parseBoosterWallet(value) {
704
- const wallet = asObject4(value);
705
- const balance = asObject4(wallet?.balance);
900
+ const wallet = asObject6(value);
901
+ const balance = asObject6(wallet?.balance);
706
902
  if (!wallet || !balance || balance.type !== "BOOSTER") return [];
707
903
  const totalRaw = asPositiveInteger(balance.amount);
708
904
  if (totalRaw === void 0) return [];
@@ -753,7 +949,7 @@ function parseBoosterWallet(value) {
753
949
  return metrics;
754
950
  }
755
951
  function parseMoney(value) {
756
- const money = asObject4(value);
952
+ const money = asObject6(value);
757
953
  if (!money) return void 0;
758
954
  const cents = asNonnegativeInteger2(money.priceInCents);
759
955
  if (cents === void 0) return void 0;
@@ -767,7 +963,7 @@ function fixedPointToMajor(value) {
767
963
  const major = roundedCents / 100;
768
964
  return Number.isSafeInteger(roundedCents) && Number.isFinite(major) ? major : void 0;
769
965
  }
770
- function asObject4(value) {
966
+ function asObject6(value) {
771
967
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
772
968
  return value;
773
969
  }
@@ -834,6 +1030,246 @@ function defaultWindowLabel(minutes) {
834
1030
  return `${minutes}m window`;
835
1031
  }
836
1032
 
1033
+ // src/providers/minimax.ts
1034
+ var PROVIDERS = {
1035
+ minimax: { name: "MiniMax", currency: "USD" },
1036
+ "minimax-cn": { name: "MiniMax CN", currency: "CNY" }
1037
+ };
1038
+ var DECIMAL_AMOUNT2 = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/u;
1039
+ var PERCENT_TOLERANCE = 1;
1040
+ function miniMaxUsageKind(apiKey) {
1041
+ return apiKey.startsWith("sk-api-") ? "account-balance" : "token-plan";
1042
+ }
1043
+ function normalizeMiniMaxUsagePayload(providerId, kind, payload, capturedAt) {
1044
+ return kind === "account-balance" ? normalizeBalance(providerId, payload, capturedAt) : normalizeTokenPlan(providerId, payload, capturedAt);
1045
+ }
1046
+ function normalizeBalance(providerId, payload, capturedAt) {
1047
+ assertSuccess(payload);
1048
+ const provider = PROVIDERS[providerId];
1049
+ const metrics = [
1050
+ balanceMetric(
1051
+ "available-balance",
1052
+ "Available balance",
1053
+ payload.available_amount,
1054
+ provider.currency
1055
+ ),
1056
+ balanceMetric("cash-balance", "Cash balance", payload.cash_balance, provider.currency, true),
1057
+ balanceMetric("voucher-balance", "Voucher balance", payload.voucher_balance, provider.currency),
1058
+ balanceMetric("credit-balance", "Credit balance", payload.credit_balance, provider.currency),
1059
+ balanceMetric("owed-amount", "Owed amount", payload.owed_amount, provider.currency)
1060
+ ];
1061
+ return {
1062
+ providerId,
1063
+ providerName: provider.name,
1064
+ capturedAt,
1065
+ source: "minimax-account-balance",
1066
+ semantics: { kind: "api-key", label: "MiniMax pay-as-you-go account balance" },
1067
+ buckets: [],
1068
+ metrics
1069
+ };
1070
+ }
1071
+ function normalizeTokenPlan(providerId, payload, capturedAt) {
1072
+ assertSuccess(payload);
1073
+ if (!Array.isArray(payload.model_remains) || payload.model_remains.length === 0) {
1074
+ throw new Error("MiniMax Token Plan returned no quota rows.");
1075
+ }
1076
+ const provider = PROVIDERS[providerId];
1077
+ const buckets = [];
1078
+ const groups = /* @__PURE__ */ new Set();
1079
+ for (const [index, raw] of payload.model_remains.entries()) {
1080
+ const row = asObject7(raw);
1081
+ if (!row) throw new Error("MiniMax Token Plan quota row was not an object.");
1082
+ const groupLabel = safeLabel(row.model_name, `Quota ${index + 1}`);
1083
+ const groupId = uniqueGroupId(groupLabel, index, groups);
1084
+ buckets.push(
1085
+ normalizeWindow(row, {
1086
+ id: `${groupId}:interval`,
1087
+ label: "Rolling window",
1088
+ groupId,
1089
+ groupLabel,
1090
+ countField: "current_interval_usage_count",
1091
+ totalField: "current_interval_total_count",
1092
+ percentField: "current_interval_remaining_percent",
1093
+ statusField: "current_interval_status",
1094
+ startField: "start_time",
1095
+ endField: "end_time"
1096
+ }),
1097
+ normalizeWindow(row, {
1098
+ id: `${groupId}:weekly`,
1099
+ label: "Weekly window",
1100
+ groupId,
1101
+ groupLabel,
1102
+ countField: "current_weekly_usage_count",
1103
+ totalField: "current_weekly_total_count",
1104
+ percentField: "current_weekly_remaining_percent",
1105
+ statusField: "current_weekly_status",
1106
+ startField: "weekly_start_time",
1107
+ endField: "weekly_end_time",
1108
+ boostPermille: row.weekly_boost_permille
1109
+ })
1110
+ );
1111
+ }
1112
+ return {
1113
+ providerId,
1114
+ providerName: provider.name,
1115
+ capturedAt,
1116
+ source: "minimax-token-plan",
1117
+ semantics: { kind: "consumer-subscription", label: "MiniMax Token Plan quota" },
1118
+ buckets,
1119
+ metrics: []
1120
+ };
1121
+ }
1122
+ function normalizeWindow(row, fields) {
1123
+ const status = optionalInteger(row[fields.statusField], fields.statusField);
1124
+ if (status !== void 0 && ![1, 2, 3].includes(status)) {
1125
+ throw new Error(`MiniMax Token Plan ${fields.label} status was unsupported.`);
1126
+ }
1127
+ const percent = optionalPercent(row[fields.percentField], fields.percentField);
1128
+ validateBoost(fields.boostPermille);
1129
+ const start = timestamp(row[fields.startField], fields.startField);
1130
+ const end = timestamp(row[fields.endField], fields.endField);
1131
+ if (end < start) throw new Error(`MiniMax Token Plan ${fields.label} timestamps were reversed.`);
1132
+ const resetsAt = Math.floor(end / 1e3);
1133
+ const windowMinutes = Math.max(1, Math.round((end - start) / 6e4));
1134
+ if (status === 3) {
1135
+ return {
1136
+ id: fields.id,
1137
+ label: fields.label,
1138
+ groupId: fields.groupId,
1139
+ groupLabel: fields.groupLabel,
1140
+ remaining: 100,
1141
+ unit: "percent",
1142
+ period: "unlimited",
1143
+ windowMinutes
1144
+ };
1145
+ }
1146
+ const total = nonnegativeInteger(row[fields.totalField], fields.totalField);
1147
+ const count = nonnegativeInteger(row[fields.countField], fields.countField);
1148
+ const resolved = resolveQuotaCounts(count, total, percent);
1149
+ if (!resolved) throw new Error(`MiniMax Token Plan ${fields.label} counts were inconsistent.`);
1150
+ return {
1151
+ id: fields.id,
1152
+ label: fields.label,
1153
+ groupId: fields.groupId,
1154
+ groupLabel: fields.groupLabel,
1155
+ ...resolved,
1156
+ unit: "count",
1157
+ windowMinutes,
1158
+ resetsAt
1159
+ };
1160
+ }
1161
+ function resolveQuotaCounts(reportedCount, total, remainingPercent) {
1162
+ if (total <= 0 || reportedCount > total) return void 0;
1163
+ let remaining = reportedCount;
1164
+ if (remainingPercent !== void 0) {
1165
+ const asRemaining = reportedCount / total * 100;
1166
+ const asUsed = (total - reportedCount) / total * 100;
1167
+ const remainingDistance = Math.abs(asRemaining - remainingPercent);
1168
+ const usedDistance = Math.abs(asUsed - remainingPercent);
1169
+ if (Math.min(remainingDistance, usedDistance) > PERCENT_TOLERANCE) return void 0;
1170
+ if (usedDistance < remainingDistance) remaining = total - reportedCount;
1171
+ }
1172
+ return { used: total - remaining, remaining, limit: total };
1173
+ }
1174
+ function assertSuccess(payload) {
1175
+ const base = asObject7(payload.base_resp);
1176
+ if (base?.status_code !== 0) {
1177
+ throw new Error("MiniMax usage response did not report success.");
1178
+ }
1179
+ }
1180
+ function balanceMetric(id, label, value, currency, allowNegative = false) {
1181
+ if (typeof value !== "string" || value.length > 64 || !DECIMAL_AMOUNT2.test(value) || !allowNegative && value.startsWith("-")) {
1182
+ throw new Error(`MiniMax ${label.toLowerCase()} was not a valid amount.`);
1183
+ }
1184
+ return { id, label, value, unit: "currency", currency };
1185
+ }
1186
+ function asObject7(value) {
1187
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1188
+ return value;
1189
+ }
1190
+ function safeLabel(value, fallback) {
1191
+ if (typeof value !== "string") throw new Error("MiniMax Token Plan model name was not a string.");
1192
+ return sanitizeDisplayText(value, 80) || fallback;
1193
+ }
1194
+ function uniqueGroupId(label, index, groups) {
1195
+ const base = label.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-|-$/gu, "") || "quota";
1196
+ const id = groups.has(base) ? `${base}-${index + 1}` : base;
1197
+ groups.add(id);
1198
+ return id;
1199
+ }
1200
+ function nonnegativeInteger(value, field) {
1201
+ if (!Number.isSafeInteger(value) || value < 0) {
1202
+ throw new Error(`MiniMax Token Plan ${field} was not a nonnegative safe integer.`);
1203
+ }
1204
+ return value;
1205
+ }
1206
+ function optionalInteger(value, field) {
1207
+ if (value === void 0 || value === null) return void 0;
1208
+ return nonnegativeInteger(value, field);
1209
+ }
1210
+ function optionalPercent(value, field) {
1211
+ if (value === void 0 || value === null) return void 0;
1212
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 100) {
1213
+ throw new Error(`MiniMax Token Plan ${field} was not a percentage.`);
1214
+ }
1215
+ return value;
1216
+ }
1217
+ function validateBoost(boost) {
1218
+ if (boost === void 0 || boost === null) return;
1219
+ const permille = nonnegativeInteger(boost, "weekly_boost_permille");
1220
+ if (permille > 1e4) throw new Error("MiniMax Token Plan weekly boost was unreasonable.");
1221
+ }
1222
+ function timestamp(value, field) {
1223
+ if (!Number.isSafeInteger(value) || value <= 0) {
1224
+ throw new Error(`MiniMax Token Plan ${field} was not a valid timestamp.`);
1225
+ }
1226
+ return value;
1227
+ }
1228
+
1229
+ // src/providers/moonshot.ts
1230
+ var PROVIDERS2 = {
1231
+ moonshotai: { name: "Moonshot AI", currency: "USD" },
1232
+ "moonshotai-cn": { name: "Moonshot AI CN", currency: "CNY" }
1233
+ };
1234
+ function normalizeMoonshotBalancePayload(providerId, payload, capturedAt) {
1235
+ if (payload.code !== 0 || payload.status !== true) {
1236
+ throw new Error("Moonshot AI balance response did not report success.");
1237
+ }
1238
+ const data = asObject8(payload.data);
1239
+ if (!data) throw new Error("Moonshot AI balance response data was not an object.");
1240
+ const provider = PROVIDERS2[providerId];
1241
+ const available = amount(data.available_balance, "available balance", false);
1242
+ const voucher = amount(data.voucher_balance, "voucher balance", false);
1243
+ const cash = amount(data.cash_balance, "cash balance", true);
1244
+ const metrics = [
1245
+ currencyMetric("available-balance", "Available balance", available, provider.currency),
1246
+ currencyMetric("voucher-balance", "Voucher balance", voucher, provider.currency),
1247
+ currencyMetric("cash-balance", "Cash balance", cash, provider.currency)
1248
+ ];
1249
+ return {
1250
+ providerId,
1251
+ providerName: provider.name,
1252
+ capturedAt,
1253
+ source: "moonshot-balance",
1254
+ semantics: { kind: "api-key", label: "Moonshot API account balance" },
1255
+ buckets: [],
1256
+ metrics
1257
+ };
1258
+ }
1259
+ function currencyMetric(id, label, value, currency) {
1260
+ return { id, label, value, unit: "currency", currency };
1261
+ }
1262
+ function asObject8(value) {
1263
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1264
+ return value;
1265
+ }
1266
+ function amount(value, label, allowNegative) {
1267
+ if (typeof value !== "number" || !Number.isFinite(value) || !allowNegative && value < 0 || Math.abs(value) > Number.MAX_SAFE_INTEGER) {
1268
+ throw new Error(`Moonshot AI ${label} was not a valid amount.`);
1269
+ }
1270
+ return String(value);
1271
+ }
1272
+
837
1273
  // src/providers/opencode-zen.ts
838
1274
  var ZEN_WINDOWS = [
839
1275
  { key: "rolling", label: "Rolling" },
@@ -841,12 +1277,12 @@ var ZEN_WINDOWS = [
841
1277
  { key: "monthly", label: "Monthly" }
842
1278
  ];
843
1279
  function normalizeOpenCodeZenPayload(payload, capturedAt) {
844
- const usage = asObject5(payload.usage);
1280
+ const usage = asObject9(payload.usage);
845
1281
  if (!usage) throw new Error("OpenCode Zen usage response was not an object.");
846
1282
  const buckets = [];
847
1283
  const notes = [];
848
1284
  for (const window of ZEN_WINDOWS) {
849
- const raw = asObject5(usage[window.key]);
1285
+ const raw = asObject9(usage[window.key]);
850
1286
  if (!raw) continue;
851
1287
  const status = asString3(raw.status);
852
1288
  if (status !== "ok" && status !== "rate-limited") {
@@ -883,7 +1319,7 @@ function normalizeOpenCodeZenPayload(payload, capturedAt) {
883
1319
  ...notes.length > 0 ? { notes } : {}
884
1320
  };
885
1321
  }
886
- function asObject5(value) {
1322
+ function asObject9(value) {
887
1323
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
888
1324
  return value;
889
1325
  }
@@ -907,7 +1343,7 @@ function clampPercent2(value) {
907
1343
 
908
1344
  // src/providers/openrouter.ts
909
1345
  function normalizeOpenRouterKeyPayload(payload, capturedAt) {
910
- const data = asObject6(payload.data);
1346
+ const data = asObject10(payload.data);
911
1347
  if (!data) throw new Error("OpenRouter key response data was not an object.");
912
1348
  const limit = asNonnegativeNumber3(data.limit);
913
1349
  const remaining = asNonnegativeNumber3(data.limit_remaining);
@@ -949,11 +1385,11 @@ function normalizeOpenRouterKeyPayload(payload, capturedAt) {
949
1385
  };
950
1386
  }
951
1387
  function addUsageMetric(metrics, id, label, value) {
952
- const amount = typeof value === "number" ? asNonnegativeNumber3(value) : void 0;
953
- if (amount === void 0) return;
954
- metrics.push({ id, label, value: amount, unit: "usd" });
1388
+ const amount2 = typeof value === "number" ? asNonnegativeNumber3(value) : void 0;
1389
+ if (amount2 === void 0) return;
1390
+ metrics.push({ id, label, value: amount2, unit: "usd" });
955
1391
  }
956
- function asObject6(value) {
1392
+ function asObject10(value) {
957
1393
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
958
1394
  return value;
959
1395
  }
@@ -966,6 +1402,44 @@ function asNonnegativeNumber3(value) {
966
1402
  return value;
967
1403
  }
968
1404
 
1405
+ // src/providers/vercel-ai-gateway.ts
1406
+ var DECIMAL_AMOUNT3 = /^(?:0|[1-9]\d*)(?:\.\d+)?$/u;
1407
+ function normalizeVercelAIGatewayCreditsPayload(payload, capturedAt) {
1408
+ const balance = decimalAmount3(payload.balance, "balance");
1409
+ const totalUsed = decimalAmount3(payload.total_used, "total used");
1410
+ const metrics = [
1411
+ {
1412
+ id: "credit-balance",
1413
+ label: "Credit balance",
1414
+ value: balance,
1415
+ unit: "currency",
1416
+ currency: "USD"
1417
+ },
1418
+ {
1419
+ id: "lifetime-spend",
1420
+ label: "Lifetime spend",
1421
+ value: totalUsed,
1422
+ unit: "currency",
1423
+ currency: "USD"
1424
+ }
1425
+ ];
1426
+ return {
1427
+ providerId: "vercel-ai-gateway",
1428
+ providerName: "Vercel AI Gateway",
1429
+ capturedAt,
1430
+ source: "vercel-ai-gateway-credits",
1431
+ semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
1432
+ buckets: [],
1433
+ metrics
1434
+ };
1435
+ }
1436
+ function decimalAmount3(value, label) {
1437
+ if (typeof value !== "string" || value.length > 64 || !DECIMAL_AMOUNT3.test(value)) {
1438
+ throw new Error(`Vercel AI Gateway ${label} was not a valid nonnegative amount.`);
1439
+ }
1440
+ return value;
1441
+ }
1442
+
969
1443
  // src/providers/xai.ts
970
1444
  var MAX_SAFE_CENTS = Number.MAX_SAFE_INTEGER;
971
1445
  function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
@@ -983,7 +1457,7 @@ function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
983
1457
  config.billingPeriodStart,
984
1458
  config.billingPeriodEnd
985
1459
  );
986
- const preferredPercent = optionalPercent(config.creditUsagePercent, "creditUsagePercent");
1460
+ const preferredPercent = optionalPercent2(config.creditUsagePercent, "creditUsagePercent");
987
1461
  if (preferredPercent !== void 0) {
988
1462
  buckets.push({
989
1463
  id: "included-allowance",
@@ -1093,7 +1567,7 @@ function optionalUsd(value, field) {
1093
1567
  }
1094
1568
  return cents / 100;
1095
1569
  }
1096
- function optionalPercent(value, field) {
1570
+ function optionalPercent2(value, field) {
1097
1571
  if (value === void 0 || value === null) return void 0;
1098
1572
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 100) {
1099
1573
  throw new Error(`xAI billing ${field} was outside 0\u2013100.`);
@@ -1131,13 +1605,13 @@ function isRecord2(value) {
1131
1605
  var FIVE_HOUR_WINDOW_MINUTES2 = 300;
1132
1606
  var WEEKLY_WINDOW_MINUTES2 = 10080;
1133
1607
  function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt) {
1134
- const data = asObject7(payload.data);
1608
+ const data = asObject11(payload.data);
1135
1609
  if (!data) throw new Error("Z.AI quota response data was not an object.");
1136
1610
  const limits = Array.isArray(data.limits) ? data.limits : [];
1137
1611
  const buckets = [];
1138
1612
  const metrics = [];
1139
1613
  for (const raw of limits) {
1140
- const limit = asObject7(raw);
1614
+ const limit = asObject11(raw);
1141
1615
  if (!limit) continue;
1142
1616
  const type = asString5(limit.type);
1143
1617
  const unit = asNonnegativeNumber4(limit.unit);
@@ -1209,7 +1683,7 @@ function addCountBucket(buckets, limit, id, label, windowMinutes) {
1209
1683
  function addUsageDetailMetrics(metrics, value) {
1210
1684
  if (!Array.isArray(value)) return;
1211
1685
  for (const raw of value) {
1212
- const detail = asObject7(raw);
1686
+ const detail = asObject11(raw);
1213
1687
  if (!detail) continue;
1214
1688
  const label = asString5(detail.modelCode);
1215
1689
  const usage = asNonnegativeNumber4(detail.usage);
@@ -1217,7 +1691,7 @@ function addUsageDetailMetrics(metrics, value) {
1217
1691
  metrics.push({ id: `mcp-${kebabCase(label)}`, label, value: usage, unit: "count" });
1218
1692
  }
1219
1693
  }
1220
- function asObject7(value) {
1694
+ function asObject11(value) {
1221
1695
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1222
1696
  return value;
1223
1697
  }
@@ -1242,12 +1716,27 @@ function clampPercent3(value) {
1242
1716
  }
1243
1717
 
1244
1718
  // src/query.ts
1719
+ var BASETEN_BILLING_USAGE_URL = "https://api.baseten.co/v1/billing/usage_summary";
1720
+ var BASETEN_USAGE_WINDOW_DAYS = 30;
1245
1721
  var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
1246
1722
  var DEEPSEEK_BALANCE_URL = "https://api.deepseek.com/user/balance";
1723
+ var FIREWORKS_BILLING_SUMMARY_ORIGIN = "https://api.fireworks.ai";
1724
+ var FIREWORKS_SPEND_WINDOW_DAYS = 30;
1725
+ var FIREWORKS_MAX_ACCOUNT_PAGES = 5;
1247
1726
  var GITHUB_COPILOT_USAGE_URL = "https://api.github.com/copilot_internal/user";
1248
1727
  var OPENROUTER_KEY_URL = "https://openrouter.ai/api/v1/key";
1728
+ var VERCEL_AI_GATEWAY_CREDITS_URL = "https://ai-gateway.vercel.sh/v1/credits";
1249
1729
  var OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usage";
1250
1730
  var KIMI_CODING_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
1731
+ var MINIMAX_API_ROOTS = Object.freeze({
1732
+ minimax: "https://api.minimax.io",
1733
+ "minimax-cn": "https://api.minimaxi.com"
1734
+ });
1735
+ var MOONSHOT_BALANCE_URLS = Object.freeze({
1736
+ moonshotai: "https://api.moonshot.ai/v1/users/me/balance",
1737
+ "moonshotai-cn": "https://api.moonshot.cn/v1/users/me/balance"
1738
+ });
1739
+ var SHARED_MOONSHOT_ENV_VAR = "MOONSHOT_API_KEY";
1251
1740
  var XAI_USER_URL = "https://cli-chat-proxy.grok.com/v1/user?include=subscription";
1252
1741
  var XAI_BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
1253
1742
  var XAI_CLIENT_HEADERS = Object.freeze({
@@ -1259,6 +1748,27 @@ var MAX_SUCCESS_BODY_BYTES = 64 * 1024;
1259
1748
  var MAX_ERROR_BODY_BYTES = 4 * 1024;
1260
1749
  var AUTH_FINGERPRINT_SALT = randomBytes(32);
1261
1750
  var SUPPORTED_ADAPTERS = [
1751
+ {
1752
+ id: "baseten",
1753
+ displayName: "Baseten",
1754
+ semantics: { kind: "api-key", label: "Organization Model APIs spend" },
1755
+ async query(auth, signal, timeoutMs, guard) {
1756
+ if (!guard) throw new Error("Baseten billing usage requires request-boundary revalidation.");
1757
+ const startedAt = Date.now();
1758
+ await guard();
1759
+ const windowAt = Date.now();
1760
+ const payload = await fetchProviderJson(
1761
+ basetenBillingUsageUrl(windowAt),
1762
+ auth,
1763
+ signal,
1764
+ remainingTimeout(timeoutMs, startedAt, "fetching Baseten billing usage"),
1765
+ "Baseten billing usage endpoint",
1766
+ { redirect: "error" }
1767
+ );
1768
+ await guard();
1769
+ return normalizeBasetenBillingUsagePayload(payload, Date.now());
1770
+ }
1771
+ },
1262
1772
  {
1263
1773
  id: "openai-codex",
1264
1774
  displayName: "OpenAI Codex",
@@ -1331,6 +1841,56 @@ var SUPPORTED_ADAPTERS = [
1331
1841
  return normalizeOpenRouterKeyPayload(payload, Date.now());
1332
1842
  }
1333
1843
  },
1844
+ {
1845
+ id: "vercel-ai-gateway",
1846
+ displayName: "Vercel AI Gateway",
1847
+ semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
1848
+ async query(auth, signal, timeoutMs, guard) {
1849
+ if (!guard)
1850
+ throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
1851
+ const startedAt = Date.now();
1852
+ await guard();
1853
+ const payload = await fetchProviderJson(
1854
+ VERCEL_AI_GATEWAY_CREDITS_URL,
1855
+ auth,
1856
+ signal,
1857
+ remainingTimeout(timeoutMs, startedAt, "fetching Vercel AI Gateway credits"),
1858
+ "Vercel AI Gateway credits endpoint",
1859
+ { redirect: "error" }
1860
+ );
1861
+ await guard();
1862
+ return normalizeVercelAIGatewayCreditsPayload(payload, Date.now());
1863
+ }
1864
+ },
1865
+ {
1866
+ id: "fireworks",
1867
+ displayName: "Fireworks",
1868
+ semantics: { kind: "api-key", label: "Fireworks API spend" },
1869
+ async query(auth, signal, timeoutMs, guard, settings) {
1870
+ if (!guard) throw new Error("Fireworks API spend requires request-boundary revalidation.");
1871
+ const startedAt = Date.now();
1872
+ await guard();
1873
+ const accountId = await resolveFireworksAccountId(
1874
+ auth,
1875
+ signal,
1876
+ remainingTimeout(timeoutMs, startedAt, "resolving the Fireworks account"),
1877
+ guard,
1878
+ settings?.fireworksAccountId
1879
+ );
1880
+ await guard();
1881
+ const billingWindowAt = Date.now();
1882
+ const payload = await fetchProviderJson(
1883
+ fireworksBillingSummaryUrl(accountId, billingWindowAt),
1884
+ auth,
1885
+ signal,
1886
+ remainingTimeout(timeoutMs, startedAt, "fetching Fireworks rated spend"),
1887
+ "Fireworks billing summary endpoint",
1888
+ { redirect: "error" }
1889
+ );
1890
+ await guard();
1891
+ return normalizeFireworksBillingSummaryPayload(payload, accountId, Date.now());
1892
+ }
1893
+ },
1334
1894
  {
1335
1895
  id: "opencode-go",
1336
1896
  displayName: "OpenCode Go",
@@ -1362,6 +1922,38 @@ var SUPPORTED_ADAPTERS = [
1362
1922
  return normalizeKimiCodingUsagePayload(payload, Date.now());
1363
1923
  }
1364
1924
  },
1925
+ {
1926
+ id: "minimax",
1927
+ displayName: "MiniMax",
1928
+ semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
1929
+ async query(auth, signal, timeoutMs, guard) {
1930
+ return queryMiniMaxUsage("minimax", auth, signal, timeoutMs, guard);
1931
+ }
1932
+ },
1933
+ {
1934
+ id: "minimax-cn",
1935
+ displayName: "MiniMax CN",
1936
+ semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
1937
+ async query(auth, signal, timeoutMs, guard) {
1938
+ return queryMiniMaxUsage("minimax-cn", auth, signal, timeoutMs, guard);
1939
+ }
1940
+ },
1941
+ {
1942
+ id: "moonshotai",
1943
+ displayName: "Moonshot AI",
1944
+ semantics: { kind: "api-key", label: "Moonshot API account balance" },
1945
+ async query(auth, signal, timeoutMs, guard) {
1946
+ return queryMoonshotBalance("moonshotai", auth, signal, timeoutMs, guard);
1947
+ }
1948
+ },
1949
+ {
1950
+ id: "moonshotai-cn",
1951
+ displayName: "Moonshot AI CN",
1952
+ semantics: { kind: "api-key", label: "Moonshot API account balance" },
1953
+ async query(auth, signal, timeoutMs, guard) {
1954
+ return queryMoonshotBalance("moonshotai-cn", auth, signal, timeoutMs, guard);
1955
+ }
1956
+ },
1365
1957
  {
1366
1958
  id: "zai",
1367
1959
  displayName: "Z.AI",
@@ -1470,17 +2062,20 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
1470
2062
  if (!result.ok) throw new Error(redactUsageError(result.error));
1471
2063
  return authorizationFrom(result) ? result : void 0;
1472
2064
  };
1473
- if (adapter.id !== "deepseek") modelAuth = await resolveCurrentModelAuth();
2065
+ const resolveSelectedAuthLast = ["deepseek", "minimax", "minimax-cn"].includes(adapter.id);
2066
+ if (!resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
1474
2067
  if (typeof registry.getProviderAuth !== "function") {
1475
2068
  throw new Error("pi-usage requires Pi 0.81.0 or newer to validate resolved provider auth.");
1476
2069
  }
2070
+ if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
1477
2071
  const providerResult = await registry.getProviderAuth(adapter.id);
2072
+ if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
1478
2073
  if (providerResult?.auth.baseUrl && !hasOfficialUrlOrigin(providerResult.auth.baseUrl, adapter.id)) {
1479
2074
  throw new Error(
1480
2075
  `${adapter.displayName} usage cannot send a proxy-resolved credential to the official usage endpoint.`
1481
2076
  );
1482
2077
  }
1483
- if (adapter.id === "deepseek") modelAuth = await resolveCurrentModelAuth();
2078
+ if (resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
1484
2079
  const auth = modelAuth ?? providerResult?.auth;
1485
2080
  if (!auth) return void 0;
1486
2081
  if (adapter.id === "github-copilot") {
@@ -1535,9 +2130,9 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
1535
2130
  model
1536
2131
  };
1537
2132
  }
1538
- async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard) {
2133
+ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard, settings) {
1539
2134
  try {
1540
- return await adapter.query(auth, signal, timeoutMs, guard);
2135
+ return await adapter.query(auth, signal, timeoutMs, guard, settings);
1541
2136
  } catch (error) {
1542
2137
  if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
1543
2138
  throw new Error(redactUsageError(errorMessage(error), auth.secrets));
@@ -1545,11 +2140,30 @@ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard) {
1545
2140
  }
1546
2141
  function providerIsConfigured(ctx, providerId) {
1547
2142
  try {
1548
- return ctx.modelRegistry.getProviderAuthStatus(providerId).configured;
2143
+ const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
2144
+ return status.configured && moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
1549
2145
  } catch {
1550
- return candidateModels(ctx, providerId).length > 0;
2146
+ return !isMoonshotSiblingProvider(ctx, providerId) && candidateModels(ctx, providerId).length > 0;
1551
2147
  }
1552
2148
  }
2149
+ function moonshotProviderAuthIsAllowed(ctx, providerId) {
2150
+ if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
2151
+ try {
2152
+ const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
2153
+ return moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
2154
+ } catch {
2155
+ return false;
2156
+ }
2157
+ }
2158
+ function moonshotProviderAuthSourceIsAllowed(ctx, providerId, source, label) {
2159
+ if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
2160
+ if (source === void 0) return false;
2161
+ if (source !== "environment") return true;
2162
+ return label !== void 0 && !label.split(",").map((name) => name.trim()).includes(SHARED_MOONSHOT_ENV_VAR);
2163
+ }
2164
+ function isMoonshotSiblingProvider(ctx, providerId) {
2165
+ return (providerId === "moonshotai" || providerId === "moonshotai-cn") && ctx.model?.provider !== providerId;
2166
+ }
1553
2167
  function candidateModels(ctx, providerId) {
1554
2168
  const candidates = [];
1555
2169
  const seen = /* @__PURE__ */ new Set();
@@ -1678,7 +2292,7 @@ function resolveXaiUsageAuth(auth, model, salt, candidates) {
1678
2292
  const matches = [];
1679
2293
  for (const candidate of candidates) {
1680
2294
  try {
1681
- const credential = asObject8(candidate);
2295
+ const credential = asObject12(candidate);
1682
2296
  if (credential?.type !== "oauth") continue;
1683
2297
  sawOAuth = true;
1684
2298
  if (credential.access !== resolvedAccess) continue;
@@ -1732,7 +2346,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
1732
2346
  const matches = /* @__PURE__ */ new Map();
1733
2347
  for (const candidate of candidates) {
1734
2348
  try {
1735
- const credential = asObject8(candidate);
2349
+ const credential = asObject12(candidate);
1736
2350
  if (credential?.type !== "oauth") continue;
1737
2351
  sawOAuth = true;
1738
2352
  const storedAccess2 = typeof credential.access === "string" && credential.access ? credential.access : void 0;
@@ -1794,7 +2408,7 @@ function bearerToken(authorization) {
1794
2408
  const match = /^Bearer\s+(.+)$/iu.exec(authorization ?? "");
1795
2409
  return match?.[1];
1796
2410
  }
1797
- function asObject8(value) {
2411
+ function asObject12(value) {
1798
2412
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1799
2413
  return value;
1800
2414
  }
@@ -1812,11 +2426,20 @@ function hasOfficialOrigin(model, providerId) {
1812
2426
  function hasOfficialUrlOrigin(value, providerId) {
1813
2427
  try {
1814
2428
  const url = new URL(value);
2429
+ if (providerId === "baseten") {
2430
+ return ["https://inference.baseten.co", "https://api.baseten.co"].includes(url.origin);
2431
+ }
1815
2432
  if (providerId === "openai-codex") return url.origin === "https://chatgpt.com";
1816
2433
  if (providerId === "deepseek") return url.origin === "https://api.deepseek.com";
2434
+ if (providerId === "fireworks") return url.origin === FIREWORKS_BILLING_SUMMARY_ORIGIN;
1817
2435
  if (providerId === "openrouter") return url.origin === "https://openrouter.ai";
2436
+ if (providerId === "vercel-ai-gateway") return url.origin === "https://ai-gateway.vercel.sh";
1818
2437
  if (providerId === "opencode-go") return url.origin === "https://opencode.ai";
1819
2438
  if (providerId === "kimi-coding") return url.origin === "https://api.kimi.com";
2439
+ if (providerId === "minimax") return url.origin === "https://api.minimax.io";
2440
+ if (providerId === "minimax-cn") return url.origin === "https://api.minimaxi.com";
2441
+ if (providerId === "moonshotai") return url.origin === "https://api.moonshot.ai";
2442
+ if (providerId === "moonshotai-cn") return url.origin === "https://api.moonshot.cn";
1820
2443
  if (providerId === "xai") return url.origin === "https://api.x.ai";
1821
2444
  if (providerId === "zai") return url.origin === "https://api.z.ai";
1822
2445
  if (providerId === "zai-coding-cn") return url.origin === "https://open.bigmodel.cn";
@@ -1843,11 +2466,130 @@ function validatedXaiUserId(value) {
1843
2466
  }
1844
2467
  return value;
1845
2468
  }
1846
- function remainingTimeout(timeoutMs, startedAt) {
2469
+ function basetenBillingUsageUrl(windowAt) {
2470
+ const url = new URL(BASETEN_BILLING_USAGE_URL);
2471
+ url.searchParams.set(
2472
+ "start_date",
2473
+ new Date(windowAt - BASETEN_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3).toISOString()
2474
+ );
2475
+ url.searchParams.set("end_date", new Date(windowAt).toISOString());
2476
+ return url.toString();
2477
+ }
2478
+ async function queryMiniMaxUsage(providerId, auth, signal, timeoutMs, guard) {
2479
+ if (!guard) throw new Error("MiniMax usage requires request-boundary revalidation.");
2480
+ const apiKey = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
2481
+ if (!apiKey) throw new Error("MiniMax runtime API key was unavailable.");
2482
+ const kind = miniMaxUsageKind(apiKey);
2483
+ const path = kind === "account-balance" ? "/account/query_balance" : "/v1/token_plan/remains";
2484
+ const startedAt = Date.now();
2485
+ await guard();
2486
+ const payload = await fetchProviderJson(
2487
+ `${MINIMAX_API_ROOTS[providerId]}${path}`,
2488
+ auth,
2489
+ signal,
2490
+ remainingTimeout(timeoutMs, startedAt, "fetching MiniMax usage"),
2491
+ "MiniMax usage endpoint",
2492
+ { redirect: "error" }
2493
+ );
2494
+ await guard();
2495
+ return normalizeMiniMaxUsagePayload(providerId, kind, payload, Date.now());
2496
+ }
2497
+ async function queryMoonshotBalance(providerId, auth, signal, timeoutMs, guard) {
2498
+ if (!guard) throw new Error("Moonshot AI balance requires request-boundary revalidation.");
2499
+ const startedAt = Date.now();
2500
+ await guard();
2501
+ const payload = await fetchProviderJson(
2502
+ MOONSHOT_BALANCE_URLS[providerId],
2503
+ auth,
2504
+ signal,
2505
+ remainingTimeout(timeoutMs, startedAt, "fetching Moonshot AI balance"),
2506
+ "Moonshot AI balance endpoint",
2507
+ { redirect: "error" }
2508
+ );
2509
+ await guard();
2510
+ return normalizeMoonshotBalancePayload(providerId, payload, Date.now());
2511
+ }
2512
+ function remainingTimeout(timeoutMs, startedAt, description = "fetching xAI consumer usage") {
1847
2513
  const remaining = timeoutMs - (Date.now() - startedAt);
1848
- if (remaining <= 0) throw new Error("Timed out while fetching xAI consumer usage.");
2514
+ if (remaining <= 0) throw new Error(`Timed out while ${description}.`);
1849
2515
  return remaining;
1850
2516
  }
2517
+ async function resolveFireworksAccountId(auth, signal, timeoutMs, guard, configuredAccountId) {
2518
+ if (configuredAccountId !== void 0 && !isFireworksAccountId(configuredAccountId)) {
2519
+ throw new Error("The Fireworks account setting was not a safe account slug.");
2520
+ }
2521
+ const startedAt = Date.now();
2522
+ const accounts = [];
2523
+ let pageToken;
2524
+ for (let page = 0; page < FIREWORKS_MAX_ACCOUNT_PAGES; page += 1) {
2525
+ await guard();
2526
+ const payload = await fetchProviderJson(
2527
+ fireworksAccountsUrl(pageToken),
2528
+ auth,
2529
+ signal,
2530
+ remainingTimeout(timeoutMs, startedAt, "fetching Fireworks accounts"),
2531
+ "Fireworks accounts endpoint",
2532
+ { redirect: "error" }
2533
+ );
2534
+ for (const accountId of normalizeFireworksAccountsPayload(
2535
+ payload
2536
+ )) {
2537
+ if (accounts.includes(accountId)) {
2538
+ throw new Error(`Fireworks accounts listing repeated ${accountId}.`);
2539
+ }
2540
+ accounts.push(accountId);
2541
+ if (configuredAccountId === accountId) return accountId;
2542
+ }
2543
+ pageToken = fireworksNextPageToken(payload.nextPageToken);
2544
+ if (!pageToken) break;
2545
+ }
2546
+ if (pageToken) {
2547
+ throw new Error(
2548
+ configuredAccountId ? `The configured Fireworks account was not found within the first ${FIREWORKS_MAX_ACCOUNT_PAGES} listing pages.` : `Fireworks account listing exceeded ${FIREWORKS_MAX_ACCOUNT_PAGES} pages; set fireworksAccountId in pi-usage.json to an account returned in those pages.`
2549
+ );
2550
+ }
2551
+ if (accounts.length === 0) {
2552
+ throw new Error("Fireworks account discovery returned no accounts for this API key.");
2553
+ }
2554
+ if (configuredAccountId) {
2555
+ throw new Error(
2556
+ "The configured Fireworks account does not match an account visible to this API key."
2557
+ );
2558
+ }
2559
+ if (accounts.length === 1) return accounts[0];
2560
+ const preview = accounts.slice(0, 8).join(", ");
2561
+ const suffix = accounts.length > 8 ? ` \u2026and ${accounts.length - 8} more` : "";
2562
+ throw new Error(
2563
+ `The Fireworks key can see ${accounts.length} accounts (${preview}${suffix}); set fireworksAccountId in pi-usage.json to one of them.`
2564
+ );
2565
+ }
2566
+ function fireworksAccountsUrl(pageToken) {
2567
+ const url = new URL("/v1/accounts", FIREWORKS_BILLING_SUMMARY_ORIGIN);
2568
+ url.searchParams.set("pageSize", "200");
2569
+ if (pageToken !== void 0) url.searchParams.set("pageToken", pageToken);
2570
+ return url.toString();
2571
+ }
2572
+ function fireworksNextPageToken(value) {
2573
+ if (value === void 0 || value === null) return void 0;
2574
+ if (typeof value !== "string" || !value || value.length > 512) {
2575
+ throw new Error("Fireworks accounts listing returned an invalid page token.");
2576
+ }
2577
+ return value;
2578
+ }
2579
+ function fireworksBillingSummaryUrl(accountId, startedAt) {
2580
+ const dayMs = 24 * 60 * 60 * 1e3;
2581
+ const dayFloor = (time) => `${new Date(time).toISOString().slice(0, 10)}T00:00:00Z`;
2582
+ const url = new URL(
2583
+ `/v1/accounts/${accountId}/billing/summary`,
2584
+ FIREWORKS_BILLING_SUMMARY_ORIGIN
2585
+ );
2586
+ url.searchParams.set(
2587
+ "startTime",
2588
+ dayFloor(startedAt - (FIREWORKS_SPEND_WINDOW_DAYS - 1) * dayMs)
2589
+ );
2590
+ url.searchParams.set("endTime", dayFloor(startedAt + dayMs));
2591
+ return url.toString();
2592
+ }
1851
2593
  function zaiMonitorUrl(baseUrl) {
1852
2594
  const base = baseUrl?.trim();
1853
2595
  if (!base) throw new Error("Z.AI model base URL is unavailable.");
@@ -1868,12 +2610,12 @@ var CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-r
1868
2610
  var CODEX_RESET_CONSUME_URL = `${CODEX_RESET_CREDITS_URL}/consume`;
1869
2611
  var MAX_RESET_OPTIONS = 32;
1870
2612
  var MAX_CREDIT_ID_CHARS = 1024;
1871
- function codexResetCount(report) {
1872
- const value = report.metrics.find((metric) => metric.id === "reset-credits")?.value;
2613
+ function codexResetCount(report2) {
2614
+ const value = report2.metrics.find((metric2) => metric2.id === "reset-credits")?.value;
1873
2615
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1874
2616
  }
1875
- function codexResetActionDescription(report) {
1876
- const count = codexResetCount(report);
2617
+ function codexResetActionDescription(report2) {
2618
+ const count = codexResetCount(report2);
1877
2619
  if (count === void 0) return "Check reset availability.";
1878
2620
  if (count === 0) return "No usage limit resets available.";
1879
2621
  return `You have ${count} ${resetLabel(count)} available.`;
@@ -1986,14 +2728,14 @@ async function consumeCodexResetCredit(auth, option, redeemRequestId, signal, ti
1986
2728
  if (!isCodexResetOutcomeCode(code)) {
1987
2729
  throw new Error("Codex reset consume endpoint returned an unknown outcome code.");
1988
2730
  }
1989
- const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger(payload.windows_reset);
2731
+ const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger2(payload.windows_reset);
1990
2732
  if (windowsReset === void 0) {
1991
2733
  throw new Error("Codex reset consume endpoint returned an invalid windows_reset value.");
1992
2734
  }
1993
2735
  return { code, windowsReset };
1994
2736
  }
1995
2737
  function normalizeCodexResetCreditsPayload(payload) {
1996
- const availableCount = nonnegativeInteger(payload.available_count);
2738
+ const availableCount = nonnegativeInteger2(payload.available_count);
1997
2739
  if (availableCount === void 0) {
1998
2740
  throw new Error("Codex reset credits response returned an invalid available_count.");
1999
2741
  }
@@ -2001,7 +2743,7 @@ function normalizeCodexResetCreditsPayload(payload) {
2001
2743
  if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
2002
2744
  throw new Error("Codex reset credits response returned invalid credits.");
2003
2745
  }
2004
- const options = (rawCredits ?? []).map(asObject9).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
2746
+ const options = (rawCredits ?? []).map(asObject13).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
2005
2747
  (left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
2006
2748
  ).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
2007
2749
  if (availableCount > 0 && options.length === 0) {
@@ -2016,7 +2758,7 @@ function selectCodexResetCredential(candidates, resolvedAccess, resolvedAccountI
2016
2758
  const matches = /* @__PURE__ */ new Map();
2017
2759
  for (const candidate of candidates) {
2018
2760
  try {
2019
- const credential = asObject9(candidate);
2761
+ const credential = asObject13(candidate);
2020
2762
  if (credential?.type !== "oauth") continue;
2021
2763
  sawOAuth = true;
2022
2764
  const storedAccess = asNonemptyString(credential.access);
@@ -2055,7 +2797,7 @@ function codexAccountIdFromAccessToken(access) {
2055
2797
  const parts = access.split(".");
2056
2798
  if (parts.length !== 3 || !parts[1]) return void 0;
2057
2799
  const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
2058
- const claims = asObject9(asObject9(payload)?.["https://api.openai.com/auth"]);
2800
+ const claims = asObject13(asObject13(payload)?.["https://api.openai.com/auth"]);
2059
2801
  return validHeaderValue(claims?.chatgpt_account_id);
2060
2802
  } catch {
2061
2803
  return void 0;
@@ -2087,7 +2829,7 @@ function normalizeResetOption(credit) {
2087
2829
  function isCodexResetOutcomeCode(value) {
2088
2830
  return value === "reset" || value === "nothing_to_reset" || value === "no_credit" || value === "already_redeemed";
2089
2831
  }
2090
- function asObject9(value) {
2832
+ function asObject13(value) {
2091
2833
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
2092
2834
  return value;
2093
2835
  }
@@ -2109,7 +2851,7 @@ function validHeaderValue(value) {
2109
2851
  if (/[^\x20-\x7e]/u.test(value)) return void 0;
2110
2852
  return value;
2111
2853
  }
2112
- function nonnegativeInteger(value) {
2854
+ function nonnegativeInteger2(value) {
2113
2855
  const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
2114
2856
  if (!Number.isSafeInteger(parsed) || parsed < 0) return void 0;
2115
2857
  return parsed;
@@ -2126,43 +2868,59 @@ function headerValue2(headers, name) {
2126
2868
  // src/format.ts
2127
2869
  var BAR_SEGMENTS = 20;
2128
2870
  var VALUE_COLUMN = 29;
2129
- function formatUsageReport(report, displayState) {
2871
+ function formatUsageReport(report2, displayState) {
2130
2872
  const stateLabel = displayState === "current" ? "Current" : "Configured";
2131
- const title = report.providerId === "deepseek" ? "DeepSeek API Balance" : `${report.providerName} Usage`;
2873
+ const title = report2.providerId === "baseten" ? "Baseten Model APIs Spend" : report2.providerId === "deepseek" ? "DeepSeek API Balance" : report2.providerId === "fireworks" ? "Fireworks API Spend" : report2.providerId === "vercel-ai-gateway" ? "Vercel AI Gateway Credits" : report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn" ? `${report2.providerName} Balance` : report2.providerId === "minimax" || report2.providerId === "minimax-cn" ? report2.source === "minimax-account-balance" ? `${report2.providerName} API Balance` : `${report2.providerName} Token Plan` : `${report2.providerName} Usage`;
2132
2874
  const lines = [`${title} \xB7 ${stateLabel}`];
2133
- if (report.accountLabel) lines.push(`Account: ${report.accountLabel}`);
2134
- lines.push(`Semantics: ${report.semantics.label}`, "");
2135
- if (report.providerId === "openai-codex") formatCodexReport(lines, report);
2136
- else if (report.providerId === "deepseek") formatDeepSeekReport(lines, report);
2137
- else if (report.providerId === "github-copilot") formatGitHubCopilotReport(lines, report);
2138
- else if (report.providerId === "openrouter") formatOpenRouterReport(lines, report);
2139
- else if (report.providerId === "opencode-go") formatOpenCodeZenReport(lines, report);
2140
- else if (report.providerId === "kimi-coding") formatKimiCodingReport(lines, report);
2141
- else if (report.providerId === "xai") formatXaiReport(lines, report);
2142
- else if (report.providerId === "zai" || report.providerId === "zai-coding-cn") {
2143
- formatZaiReport(lines, report);
2144
- } else formatGenericReport(lines, report);
2145
- if (report.notes) {
2146
- for (const note of report.notes) lines.push(note);
2875
+ if (report2.accountLabel) lines.push(`Account: ${report2.accountLabel}`);
2876
+ lines.push(`Semantics: ${report2.semantics.label}`, "");
2877
+ if (report2.providerId === "baseten") formatBasetenReport(lines, report2);
2878
+ else if (report2.providerId === "openai-codex") formatCodexReport(lines, report2);
2879
+ else if (report2.providerId === "deepseek") formatDeepSeekReport(lines, report2);
2880
+ else if (report2.providerId === "fireworks") formatFireworksReport(lines, report2);
2881
+ else if (report2.providerId === "vercel-ai-gateway") formatVercelAIGatewayReport(lines, report2);
2882
+ else if (report2.providerId === "github-copilot") formatGitHubCopilotReport(lines, report2);
2883
+ else if (report2.providerId === "openrouter") formatOpenRouterReport(lines, report2);
2884
+ else if (report2.providerId === "opencode-go") formatOpenCodeZenReport(lines, report2);
2885
+ else if (report2.providerId === "kimi-coding") formatKimiCodingReport(lines, report2);
2886
+ else if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
2887
+ formatMoonshotReport(lines, report2);
2888
+ } else if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
2889
+ formatMiniMaxReport(lines, report2);
2890
+ } else if (report2.providerId === "xai") formatXaiReport(lines, report2);
2891
+ else if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
2892
+ formatZaiReport(lines, report2);
2893
+ } else formatGenericReport(lines, report2);
2894
+ if (report2.notes) {
2895
+ for (const note of report2.notes) lines.push(note);
2147
2896
  }
2148
2897
  return lines.join("\n").trimEnd();
2149
2898
  }
2150
- function formatUsageStatusline(report, model, now = Date.now(), showCodexResetCountdown = true) {
2151
- if (report.providerId === "openai-codex") {
2152
- return formatCodexStatusline(report, model, now, showCodexResetCountdown);
2153
- }
2154
- if (report.providerId === "deepseek") return formatDeepSeekStatusline(report);
2155
- if (report.providerId === "github-copilot") return formatGitHubCopilotStatusline(report);
2156
- if (report.providerId === "openrouter") {
2157
- const limit = report.buckets.find((bucket) => bucket.id === "key-limit");
2899
+ function formatUsageStatusline(report2, model, now = Date.now(), showCodexResetCountdown = true) {
2900
+ if (report2.providerId === "baseten") return formatBasetenStatusline(report2);
2901
+ if (report2.providerId === "openai-codex") {
2902
+ return formatCodexStatusline(report2, model, now, showCodexResetCountdown);
2903
+ }
2904
+ if (report2.providerId === "deepseek") return formatDeepSeekStatusline(report2);
2905
+ if (report2.providerId === "fireworks") return formatFireworksStatusline(report2);
2906
+ if (report2.providerId === "vercel-ai-gateway") return formatVercelAIGatewayStatusline(report2);
2907
+ if (report2.providerId === "github-copilot") return formatGitHubCopilotStatusline(report2);
2908
+ if (report2.providerId === "openrouter") {
2909
+ const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
2158
2910
  if (limit?.remaining !== void 0) return `openrouter ${formatUsd(limit.remaining)} left`;
2159
- const total = report.metrics.find((metric) => metric.id === "usage-total");
2911
+ const total = report2.metrics.find((metric2) => metric2.id === "usage-total");
2160
2912
  if (typeof total?.value === "number") return `openrouter ${formatUsd(total.value)} used`;
2161
2913
  }
2162
- if (report.providerId === "opencode-go") return formatOpenCodeZenStatusline(report);
2163
- if (report.providerId === "kimi-coding") return formatKimiCodingStatusline(report);
2164
- if (report.providerId === "zai" || report.providerId === "zai-coding-cn") {
2165
- return formatZaiStatusline(report);
2914
+ if (report2.providerId === "opencode-go") return formatOpenCodeZenStatusline(report2);
2915
+ if (report2.providerId === "kimi-coding") return formatKimiCodingStatusline(report2);
2916
+ if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
2917
+ return formatMoonshotStatusline(report2);
2918
+ }
2919
+ if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
2920
+ return formatMiniMaxStatusline(report2, model);
2921
+ }
2922
+ if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
2923
+ return formatZaiStatusline(report2);
2166
2924
  }
2167
2925
  return void 0;
2168
2926
  }
@@ -2175,9 +2933,19 @@ function formatProviderStates(states) {
2175
2933
  ${status}: ${state.message}`;
2176
2934
  }).join("\n\n");
2177
2935
  }
2178
- function formatCodexReport(lines, report) {
2936
+ function formatBasetenReport(lines, report2) {
2937
+ lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days`);
2938
+ for (const metric2 of report2.metrics) {
2939
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
2940
+ }
2941
+ }
2942
+ function formatBasetenStatusline(report2) {
2943
+ const subtotal = report2.metrics.find((metric2) => metric2.id === "net-subtotal");
2944
+ return subtotal ? `baseten USD ${subtotal.value} net` : "baseten no Model APIs usage";
2945
+ }
2946
+ function formatCodexReport(lines, report2) {
2179
2947
  let previousGroup;
2180
- for (const bucket of report.buckets) {
2948
+ for (const bucket of report2.buckets) {
2181
2949
  const group = bucket.groupId ?? bucket.id;
2182
2950
  if (group !== previousGroup && group !== "codex") {
2183
2951
  lines.push(`${bucket.groupLabel ?? group} limit:`);
@@ -2187,43 +2955,75 @@ function formatCodexReport(lines, report) {
2187
2955
  const label = `${formatWindowLabel(bucket.windowMinutes, fallback, false)} limit:`;
2188
2956
  lines.push(`${label.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
2189
2957
  }
2190
- for (const metric of report.metrics) {
2191
- if (metric.id === "reset-credits") {
2192
- lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric.value} available`);
2193
- } else if (metric.id === "credits") {
2958
+ for (const metric2 of report2.metrics) {
2959
+ if (metric2.id === "reset-credits") {
2960
+ lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
2961
+ } else if (metric2.id === "credits") {
2194
2962
  lines.push(
2195
- `${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
2963
+ `${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2196
2964
  );
2197
2965
  }
2198
2966
  }
2199
2967
  }
2200
- function formatDeepSeekReport(lines, report) {
2201
- const availability = report.metrics.find((metric) => metric.id === "api-availability");
2968
+ function formatDeepSeekReport(lines, report2) {
2969
+ const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
2202
2970
  lines.push(
2203
2971
  `${"API calls:".padEnd(VALUE_COLUMN)}${availability?.value === "available" ? "Available" : "Unavailable"}`
2204
2972
  );
2205
2973
  for (const currency of ["CNY", "USD"]) {
2206
- const metrics = report.metrics.filter((metric) => metric.currency === currency);
2974
+ const metrics = report2.metrics.filter((metric2) => metric2.currency === currency);
2207
2975
  if (metrics.length === 0) continue;
2208
2976
  lines.push("", `${currency} balance:`);
2209
- for (const metric of metrics) {
2210
- lines.push(`${`${metric.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric.value}`);
2977
+ for (const metric2 of metrics) {
2978
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
2211
2979
  }
2212
2980
  }
2213
2981
  }
2214
- function formatDeepSeekStatusline(report) {
2215
- const availability = report.metrics.find((metric) => metric.id === "api-availability");
2982
+ function formatDeepSeekStatusline(report2) {
2983
+ const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
2216
2984
  if (availability?.value !== "available") return "deepseek API unavailable";
2217
2985
  const totals = ["CNY", "USD"].flatMap((currency) => {
2218
- const metric = report.metrics.find(
2986
+ const metric2 = report2.metrics.find(
2219
2987
  (candidate) => candidate.id === `${currency.toLowerCase()}-total`
2220
2988
  );
2221
- return metric ? [`${currency} ${metric.value}`] : [];
2989
+ return metric2 ? [`${currency} ${metric2.value}`] : [];
2222
2990
  });
2223
2991
  return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
2224
2992
  }
2225
- function formatGitHubCopilotReport(lines, report) {
2226
- const quota = findGitHubCopilotQuota(report);
2993
+ function formatFireworksReport(lines, report2) {
2994
+ lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days (rated)`);
2995
+ for (const currency of fireworksCurrencies(report2)) {
2996
+ lines.push("", `${currency} rated spend:`);
2997
+ for (const metric2 of report2.metrics) {
2998
+ if (metric2.currency !== currency) continue;
2999
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
3000
+ }
3001
+ }
3002
+ }
3003
+ function formatFireworksStatusline(report2) {
3004
+ const totals = report2.metrics.filter((metric2) => metric2.id.endsWith("-total"));
3005
+ if (totals.length === 0) return "fireworks no rated usage";
3006
+ return `fireworks ${totals.map((metric2) => `${metric2.currency} ${metric2.value}`).join(" \xB7 ")}`;
3007
+ }
3008
+ function fireworksCurrencies(report2) {
3009
+ const currencies = [];
3010
+ for (const metric2 of report2.metrics) {
3011
+ if (!metric2.currency || currencies.includes(metric2.currency)) continue;
3012
+ currencies.push(metric2.currency);
3013
+ }
3014
+ return currencies;
3015
+ }
3016
+ function formatVercelAIGatewayReport(lines, report2) {
3017
+ for (const metric2 of report2.metrics) {
3018
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
3019
+ }
3020
+ }
3021
+ function formatVercelAIGatewayStatusline(report2) {
3022
+ const balance = report2.metrics.find((metric2) => metric2.id === "credit-balance");
3023
+ return balance ? `vercel USD ${balance.value} left` : "vercel credits unavailable";
3024
+ }
3025
+ function formatGitHubCopilotReport(lines, report2) {
3026
+ const quota = findGitHubCopilotQuota(report2);
2227
3027
  if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
2228
3028
  lines.push(`${`${quota?.label ?? "Copilot quota"}:`.padEnd(VALUE_COLUMN)}unlimited`);
2229
3029
  return;
@@ -2233,23 +3033,23 @@ function formatGitHubCopilotReport(lines, report) {
2233
3033
  lines.push(
2234
3034
  `${`${quota.label}:`.padEnd(VALUE_COLUMN)}${quota.remaining} of ${quota.limit} left \xB7 ${percent}%${reset}`
2235
3035
  );
2236
- const overage = report.metrics.find((metric) => metric.id === "overage-used");
3036
+ const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
2237
3037
  if (typeof overage?.value === "number" && overage.value > 0) {
2238
3038
  lines.push(`${"Additional usage:".padEnd(VALUE_COLUMN)}${overage.value} ${quota.label}`);
2239
3039
  }
2240
3040
  }
2241
- function formatGitHubCopilotStatusline(report) {
2242
- const quota = findGitHubCopilotQuota(report);
3041
+ function formatGitHubCopilotStatusline(report2) {
3042
+ const quota = findGitHubCopilotQuota(report2);
2243
3043
  const kind = compactGitHubCopilotQuotaKind(quota);
2244
3044
  if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
2245
3045
  return `copilot ${kind} unlimited`;
2246
3046
  }
2247
- const overage = report.metrics.find((metric) => metric.id === "overage-used");
3047
+ const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
2248
3048
  const overageSuffix = typeof overage?.value === "number" && overage.value > 0 ? ` +${overage.value} over` : "";
2249
3049
  return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
2250
3050
  }
2251
- function findGitHubCopilotQuota(report) {
2252
- return report.buckets.find(
3051
+ function findGitHubCopilotQuota(report2) {
3052
+ return report2.buckets.find(
2253
3053
  (bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
2254
3054
  );
2255
3055
  }
@@ -2262,37 +3062,37 @@ function percentRemaining(bucket) {
2262
3062
  if (!bucket.limit || bucket.remaining === void 0) return 0;
2263
3063
  return Math.round(clampPercent4(bucket.remaining / bucket.limit * 100));
2264
3064
  }
2265
- function formatOpenRouterReport(lines, report) {
2266
- const limit = report.buckets.find((bucket) => bucket.id === "key-limit");
3065
+ function formatOpenRouterReport(lines, report2) {
3066
+ const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
2267
3067
  if (limit) {
2268
3068
  const period = limit.period ? ` (${limit.period})` : "";
2269
3069
  const value = limit.remaining === void 0 ? `${formatUsd(limit.limit ?? 0)} cap; remaining unavailable` : `${formatUsd(limit.remaining)} of ${formatUsd(limit.limit ?? 0)} left`;
2270
3070
  lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
2271
3071
  }
2272
- for (const metric of report.metrics) {
3072
+ for (const metric2 of report2.metrics) {
2273
3073
  lines.push(
2274
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3074
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2275
3075
  );
2276
3076
  }
2277
3077
  }
2278
- function formatOpenCodeZenReport(lines, report) {
2279
- for (const bucket of report.buckets) {
3078
+ function formatOpenCodeZenReport(lines, report2) {
3079
+ for (const bucket of report2.buckets) {
2280
3080
  const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2281
3081
  const used = bucket.used ?? "unavailable";
2282
3082
  lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${used}% used${reset}`);
2283
3083
  }
2284
3084
  }
2285
- function formatOpenCodeZenStatusline(report) {
3085
+ function formatOpenCodeZenStatusline(report2) {
2286
3086
  const parts = ["zen"];
2287
- for (const bucket of report.buckets) {
3087
+ for (const bucket of report2.buckets) {
2288
3088
  if (bucket.used === void 0) continue;
2289
3089
  const compact = bucket.id === "rolling" ? "r" : bucket.id === "weekly" ? "w" : "m";
2290
3090
  parts.push(`${clampPercent4(bucket.used).toFixed(0)}% ${compact}`);
2291
3091
  }
2292
3092
  return parts.length > 1 ? parts.join(" ") : void 0;
2293
3093
  }
2294
- function formatKimiCodingReport(lines, report) {
2295
- for (const bucket of report.buckets) {
3094
+ function formatKimiCodingReport(lines, report2) {
3095
+ for (const bucket of report2.buckets) {
2296
3096
  const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2297
3097
  if (bucket.used === void 0 || bucket.limit === void 0) {
2298
3098
  lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}unavailable${reset}`);
@@ -2302,10 +3102,10 @@ function formatKimiCodingReport(lines, report) {
2302
3102
  `${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${bucket.used} of ${bucket.limit} used \xB7 ${percentRemaining(bucket)}% left${reset}`
2303
3103
  );
2304
3104
  }
2305
- const balance = report.metrics.find((metric) => metric.id === "booster-balance");
2306
- const total = report.metrics.find((metric) => metric.id === "booster-total");
2307
- const monthlyUsed = report.metrics.find((metric) => metric.id === "booster-monthly-used");
2308
- const monthlyLimit = report.metrics.find((metric) => metric.id === "booster-monthly-limit");
3105
+ const balance = report2.metrics.find((metric2) => metric2.id === "booster-balance");
3106
+ const total = report2.metrics.find((metric2) => metric2.id === "booster-total");
3107
+ const monthlyUsed = report2.metrics.find((metric2) => metric2.id === "booster-monthly-used");
3108
+ const monthlyLimit = report2.metrics.find((metric2) => metric2.id === "booster-monthly-limit");
2309
3109
  if (!balance && !monthlyUsed && !monthlyLimit) return;
2310
3110
  lines.push("", "Extra usage wallet:");
2311
3111
  if (balance) {
@@ -2319,10 +3119,10 @@ function formatKimiCodingReport(lines, report) {
2319
3119
  lines.push(`${"Monthly limit:".padEnd(VALUE_COLUMN)}${formatCurrencyMetric(monthlyLimit)}`);
2320
3120
  }
2321
3121
  }
2322
- function formatKimiCodingStatusline(report) {
2323
- const fiveHour = report.buckets.find((bucket) => bucket.id === "five-hour");
2324
- const weekly = report.buckets.find((bucket) => bucket.id === "weekly");
2325
- const subWindow = fiveHour ?? report.buckets.find((bucket) => bucket.id !== "weekly");
3122
+ function formatKimiCodingStatusline(report2) {
3123
+ const fiveHour = report2.buckets.find((bucket) => bucket.id === "five-hour");
3124
+ const weekly = report2.buckets.find((bucket) => bucket.id === "weekly");
3125
+ const subWindow = fiveHour ?? report2.buckets.find((bucket) => bucket.id !== "weekly");
2326
3126
  const selected = [subWindow, weekly].filter(
2327
3127
  (bucket, index, buckets) => bucket !== void 0 && buckets.indexOf(bucket) === index
2328
3128
  );
@@ -2336,10 +3136,98 @@ function formatKimiCodingStatusline(report) {
2336
3136
  }
2337
3137
  return parts.length > 1 ? parts.join(" ") : void 0;
2338
3138
  }
2339
- function formatZaiStatusline(report) {
3139
+ function formatMoonshotReport(lines, report2) {
3140
+ for (const metric2 of report2.metrics) {
3141
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
3142
+ }
3143
+ }
3144
+ function formatMoonshotStatusline(report2) {
3145
+ const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
3146
+ if (!available) return "moonshot balance unavailable";
3147
+ return `moonshot ${available.currency ?? ""} ${available.value}`.replace(/\s+/gu, " ");
3148
+ }
3149
+ function formatMiniMaxReport(lines, report2) {
3150
+ if (report2.source === "minimax-account-balance") {
3151
+ for (const metric2 of report2.metrics) {
3152
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
3153
+ }
3154
+ return;
3155
+ }
3156
+ let previousGroup;
3157
+ for (const bucket of report2.buckets) {
3158
+ if (bucket.groupId !== previousGroup) lines.push(`${bucket.groupLabel ?? "Token Plan"}:`);
3159
+ previousGroup = bucket.groupId;
3160
+ const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
3161
+ const value = bucket.period === "unlimited" ? "unlimited" : bucket.limit && bucket.remaining !== void 0 ? `${bucket.remaining} of ${bucket.limit} left \xB7 ${percentRemaining(bucket)}%${reset}` : "unavailable";
3162
+ lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}`);
3163
+ }
3164
+ }
3165
+ function formatMiniMaxStatusline(report2, model) {
3166
+ const prefix = report2.providerId === "minimax-cn" ? "minimax cn" : "minimax";
3167
+ if (report2.source === "minimax-account-balance") {
3168
+ const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
3169
+ return available ? `${prefix} ${available.currency} ${available.value}` : void 0;
3170
+ }
3171
+ const selectedGroup = selectMiniMaxGroup(report2, model);
3172
+ if (!selectedGroup) return void 0;
3173
+ const selected = report2.buckets.filter((bucket) => bucket.groupId === selectedGroup);
3174
+ const parts = [prefix];
3175
+ for (const bucket of selected) {
3176
+ const fallback = bucket.id.endsWith(":weekly") ? "weekly" : "5h";
3177
+ const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
3178
+ if (bucket.period === "unlimited") {
3179
+ parts.push(`unlimited ${window}`);
3180
+ continue;
3181
+ }
3182
+ if (!bucket.limit || bucket.remaining === void 0) continue;
3183
+ parts.push(`${percentRemaining(bucket)}% ${window}`);
3184
+ }
3185
+ return parts.length > 1 ? parts.join(" ") : void 0;
3186
+ }
3187
+ function selectMiniMaxGroup(report2, model) {
3188
+ const groups = [
3189
+ ...new Set(
3190
+ report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
3191
+ )
3192
+ ];
3193
+ if (groups.length <= 1) return groups[0];
3194
+ if (model?.provider !== report2.providerId) return void 0;
3195
+ const modelKeys = [model.id, model.name].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
3196
+ const candidates = groups.map((group) => {
3197
+ const bucket = report2.buckets.find((candidate) => candidate.groupId === group);
3198
+ const patterns = [bucket?.groupLabel, ...bucket?.modelKeys ?? [], group].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
3199
+ return { group, patterns };
3200
+ });
3201
+ const exact = candidates.find(
3202
+ ({ patterns }) => patterns.some((pattern) => !pattern.includes("*") && modelKeys.includes(pattern))
3203
+ );
3204
+ if (exact) return exact.group;
3205
+ return candidates.find(
3206
+ ({ patterns }) => patterns.some(
3207
+ (pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
3208
+ )
3209
+ )?.group;
3210
+ }
3211
+ function normalizeMiniMaxModelKey(value) {
3212
+ const key = value?.toLowerCase().replace(/[^a-z0-9*]+/gu, "");
3213
+ return key && /[a-z0-9]/u.test(key) ? key : void 0;
3214
+ }
3215
+ function wildcardKeyMatches(pattern, value) {
3216
+ if (!pattern.includes("*")) return pattern === value;
3217
+ const segments = pattern.split("*").filter(Boolean);
3218
+ let offset = 0;
3219
+ for (const [index, segment] of segments.entries()) {
3220
+ const found = value.indexOf(segment, offset);
3221
+ if (found < 0 || index === 0 && !pattern.startsWith("*") && found !== 0) return false;
3222
+ offset = found + segment.length;
3223
+ }
3224
+ const last = segments.at(-1);
3225
+ return pattern.endsWith("*") || last !== void 0 && value.endsWith(last);
3226
+ }
3227
+ function formatZaiStatusline(report2) {
2340
3228
  const selected = [
2341
- report.buckets.find((bucket) => bucket.id === "five-hour"),
2342
- report.buckets.find((bucket) => bucket.id === "weekly")
3229
+ report2.buckets.find((bucket) => bucket.id === "five-hour"),
3230
+ report2.buckets.find((bucket) => bucket.id === "weekly")
2343
3231
  ];
2344
3232
  const parts = ["zai"];
2345
3233
  for (const bucket of selected) {
@@ -2351,15 +3239,15 @@ function formatZaiStatusline(report) {
2351
3239
  }
2352
3240
  return parts.length > 1 ? parts.join(" ") : void 0;
2353
3241
  }
2354
- function formatCurrencyMetric(metric) {
2355
- if (typeof metric.value !== "number") return String(metric.value);
2356
- if (!metric.currency) return "unavailable";
2357
- if (metric.currency === "USD") return `$${metric.value.toFixed(2)}`;
2358
- if (metric.currency === "CNY") return `\xA5${metric.value.toFixed(2)}`;
2359
- return `${metric.value.toFixed(2)} ${metric.currency}`;
3242
+ function formatCurrencyMetric(metric2) {
3243
+ if (typeof metric2.value !== "number") return String(metric2.value);
3244
+ if (!metric2.currency) return "unavailable";
3245
+ if (metric2.currency === "USD") return `$${metric2.value.toFixed(2)}`;
3246
+ if (metric2.currency === "CNY") return `\xA5${metric2.value.toFixed(2)}`;
3247
+ return `${metric2.value.toFixed(2)} ${metric2.currency}`;
2360
3248
  }
2361
- function formatXaiReport(lines, report) {
2362
- const included = report.buckets.find((bucket) => bucket.id === "included-allowance");
3249
+ function formatXaiReport(lines, report2) {
3250
+ const included = report2.buckets.find((bucket) => bucket.id === "included-allowance");
2363
3251
  if (included) {
2364
3252
  let value = "unavailable";
2365
3253
  if (included.unit === "percent" && included.used !== void 0) {
@@ -2375,20 +3263,20 @@ function formatXaiReport(lines, report) {
2375
3263
  const reset = included.resetsAt ? ` (resets ${formatReset(included.resetsAt)})` : "";
2376
3264
  lines.push(`${"Included allowance:".padEnd(VALUE_COLUMN)}${value}${period}${reset}`);
2377
3265
  }
2378
- const onDemand = report.buckets.find((bucket) => bucket.id === "on-demand");
3266
+ const onDemand = report2.buckets.find((bucket) => bucket.id === "on-demand");
2379
3267
  if (onDemand) {
2380
3268
  let value = onDemand.used === void 0 ? "usage unavailable" : `${formatUsd(onDemand.used)} used`;
2381
3269
  if (onDemand.limit !== void 0) value += ` of ${formatUsd(onDemand.limit)} cap`;
2382
3270
  lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
2383
3271
  }
2384
- for (const metric of report.metrics) {
3272
+ for (const metric2 of report2.metrics) {
2385
3273
  lines.push(
2386
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3274
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2387
3275
  );
2388
3276
  }
2389
3277
  }
2390
- function formatZaiReport(lines, report) {
2391
- for (const bucket of report.buckets) {
3278
+ function formatZaiReport(lines, report2) {
3279
+ for (const bucket of report2.buckets) {
2392
3280
  const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2393
3281
  let value = "unavailable";
2394
3282
  if (bucket.unit === "percent" && bucket.used !== void 0) {
@@ -2404,28 +3292,28 @@ function formatZaiReport(lines, report) {
2404
3292
  }
2405
3293
  lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
2406
3294
  }
2407
- for (const metric of report.metrics) {
3295
+ for (const metric2 of report2.metrics) {
2408
3296
  lines.push(
2409
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3297
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2410
3298
  );
2411
3299
  }
2412
3300
  }
2413
- function formatGenericReport(lines, report) {
2414
- for (const bucket of report.buckets) {
3301
+ function formatGenericReport(lines, report2) {
3302
+ for (const bucket of report2.buckets) {
2415
3303
  lines.push(
2416
3304
  `${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(bucket.remaining ?? bucket.used ?? "unavailable", bucket.unit)}`
2417
3305
  );
2418
3306
  }
2419
- for (const metric of report.metrics) {
3307
+ for (const metric2 of report2.metrics) {
2420
3308
  lines.push(
2421
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3309
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2422
3310
  );
2423
3311
  }
2424
3312
  }
2425
- function formatCodexStatusline(report, model, now = Date.now(), showResetCountdown = true) {
2426
- const group = selectCodexGroup(report, model);
2427
- if (!group) return formatCodexCreditsStatus(report);
2428
- const buckets = report.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
3313
+ function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
3314
+ const group = selectCodexGroup(report2, model);
3315
+ if (!group) return formatCodexCreditsStatus(report2);
3316
+ const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
2429
3317
  const labelBucket = buckets[0];
2430
3318
  const parts = [
2431
3319
  group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
@@ -2442,24 +3330,24 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
2442
3330
  const reset = formatResetCountdown(bucket.resetsAt, now);
2443
3331
  parts.push(`${percent} ${reset ? `\u21BB ${reset}` : window}`);
2444
3332
  }
2445
- return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report);
3333
+ return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report2);
2446
3334
  }
2447
- function formatCodexCreditsStatus(report) {
2448
- const credits = report.metrics.find((metric) => metric.id === "credits");
3335
+ function formatCodexCreditsStatus(report2) {
3336
+ const credits = report2.metrics.find((metric2) => metric2.id === "credits");
2449
3337
  if (!credits) return "codex usage unavailable";
2450
3338
  if (credits.value === "none") return "codex no credits";
2451
3339
  if (credits.value === "available") return "codex credits available";
2452
3340
  if (credits.value === "unlimited") return "codex credits unlimited";
2453
3341
  return `codex ${formatMetricValue(credits.value, "count")} credits`;
2454
3342
  }
2455
- function selectCodexGroup(report, model) {
2456
- const groups = [...new Set(report.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
3343
+ function selectCodexGroup(report2, model) {
3344
+ const groups = [...new Set(report2.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
2457
3345
  if (model?.provider !== "openai-codex") {
2458
3346
  return groups.includes("codex") ? "codex" : groups[0];
2459
3347
  }
2460
3348
  const modelKeys = normalizedModelKeys(model);
2461
3349
  for (const group of groups) {
2462
- const bucket = report.buckets.find(
3350
+ const bucket = report2.buckets.find(
2463
3351
  (candidate) => (candidate.groupId ?? candidate.id) === group
2464
3352
  );
2465
3353
  const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
@@ -2583,9 +3471,13 @@ function normalizeUsageSettings(value) {
2583
3471
  if (Object.hasOwn(value, "codexStatusResetCountdown") && typeof value.codexStatusResetCountdown !== "boolean") {
2584
3472
  return void 0;
2585
3473
  }
3474
+ if (Object.hasOwn(value, "fireworksAccountId") && !isFireworksAccountId(value.fireworksAccountId)) {
3475
+ return void 0;
3476
+ }
2586
3477
  return {
2587
3478
  codexFastMode: typeof value.codexFastMode === "boolean" ? value.codexFastMode : DEFAULT_USAGE_SETTINGS.codexFastMode,
2588
- codexStatusResetCountdown: typeof value.codexStatusResetCountdown === "boolean" ? value.codexStatusResetCountdown : DEFAULT_USAGE_SETTINGS.codexStatusResetCountdown
3479
+ codexStatusResetCountdown: typeof value.codexStatusResetCountdown === "boolean" ? value.codexStatusResetCountdown : DEFAULT_USAGE_SETTINGS.codexStatusResetCountdown,
3480
+ ...isFireworksAccountId(value.fireworksAccountId) ? { fireworksAccountId: value.fireworksAccountId } : {}
2589
3481
  };
2590
3482
  }
2591
3483
  async function loadUsageSettings(path = usageSettingsPath(), signal) {
@@ -2669,7 +3561,11 @@ async function saveUsageSettingsPatch(path, patch, operations, signal) {
2669
3561
  if (latest.kind === "invalid") {
2670
3562
  throw new Error("Cannot overwrite an invalid pi-usage.json; repair it and reload first");
2671
3563
  }
2672
- const document = { ...latest.document, ...patch };
3564
+ const document = { ...latest.document };
3565
+ for (const [key, value] of Object.entries(patch)) {
3566
+ if (value === void 0) delete document[key];
3567
+ else document[key] = value;
3568
+ }
2673
3569
  const settings = normalizeUsageSettings(document);
2674
3570
  if (!settings) throw new Error("Refusing to save invalid pi-usage settings");
2675
3571
  const directory = dirname(path);
@@ -2715,7 +3611,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
2715
3611
  // src/codex-fast-runtime.ts
2716
3612
  var NO_FAST_REQUEST = /* @__PURE__ */ Symbol("no-fast-request");
2717
3613
  var FAST_USAGE_WARNING = "Fast is about 1.5\xD7 faster and uses more of your plan allowance.";
2718
- function registerCodexFastMode(pi, settingsRuntime, refreshStatus) {
3614
+ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {}) {
2719
3615
  let sessionController = new AbortController();
2720
3616
  let generation = 0;
2721
3617
  const pendingFastRequests = /* @__PURE__ */ new Map();
@@ -2771,37 +3667,42 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus) {
2771
3667
  await toggle(ctx, !availability.enabled);
2772
3668
  }
2773
3669
  });
2774
- pi.on("session_start", async (_event, ctx) => {
3670
+ const prepareSession = (ctx) => {
3671
+ const sessionId = ctx.sessionManager.getSessionId();
2775
3672
  generation += 1;
2776
3673
  sessionController.abort();
2777
3674
  pendingFastRequests.clear();
2778
3675
  sessionController = new AbortController();
2779
3676
  const ownerGeneration = generation;
2780
- const sessionId = ctx.sessionManager.getSessionId();
2781
- let state;
2782
- try {
2783
- state = await settingsRuntime.reload(sessionController.signal);
2784
- } catch (error) {
2785
- if (sessionController.signal.aborted || ownerGeneration !== generation) return;
2786
- if (ctx.hasUI) {
3677
+ return (async () => {
3678
+ let state;
3679
+ try {
3680
+ state = await settingsRuntime.reload(sessionController.signal);
3681
+ } catch (error) {
3682
+ if (sessionController.signal.aborted || ownerGeneration !== generation) return;
3683
+ if (ctx.hasUI) {
3684
+ ctx.ui.notify(
3685
+ `Could not load pi-usage.json; using defaults. ${errorMessage(error)}`,
3686
+ "warning"
3687
+ );
3688
+ }
3689
+ return;
3690
+ }
3691
+ if (sessionController.signal.aborted || ownerGeneration !== generation || ctx.sessionManager.getSessionId() !== sessionId) {
3692
+ return;
3693
+ }
3694
+ if (ctx.hasUI && state.kind === "invalid") {
2787
3695
  ctx.ui.notify(
2788
- `Could not load pi-usage.json; using defaults. ${errorMessage(error)}`,
3696
+ `Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`,
2789
3697
  "warning"
2790
3698
  );
2791
3699
  }
2792
- return;
2793
- }
2794
- if (sessionController.signal.aborted || ownerGeneration !== generation || ctx.sessionManager.getSessionId() !== sessionId) {
2795
- return;
2796
- }
2797
- if (ctx.hasUI && state.kind === "invalid") {
2798
- ctx.ui.notify(
2799
- `Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`,
2800
- "warning"
2801
- );
2802
- }
2803
- refreshStatus(ctx);
2804
- });
3700
+ refreshStatus(ctx);
3701
+ })();
3702
+ };
3703
+ if (options.registerSessionStart !== false) {
3704
+ pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
3705
+ }
2805
3706
  pi.on("before_provider_request", (event, ctx) => {
2806
3707
  const rewritten = rewriteCodexFastPayload(
2807
3708
  event.payload,
@@ -2834,6 +3735,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus) {
2834
3735
  await settingsRuntime.flush();
2835
3736
  });
2836
3737
  return {
3738
+ prepareSession,
2837
3739
  availability(model) {
2838
3740
  return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
2839
3741
  },
@@ -2912,6 +3814,8 @@ import {
2912
3814
  SettingsList,
2913
3815
  Text
2914
3816
  } from "@earendil-works/pi-tui";
3817
+ var AUTO = "Auto";
3818
+ var EDIT = "Edit\u2026";
2915
3819
  var OFF = "Off";
2916
3820
  var ON = "On";
2917
3821
  async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent, onApplied) {
@@ -2919,7 +3823,23 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
2919
3823
  if (ctx.hasUI) ctx.ui.notify(`Edit settings manually: ${settingsRuntime.get().path}`, "info");
2920
3824
  return false;
2921
3825
  }
2922
- if (parentSignal.aborted || !isCurrent()) return false;
3826
+ let changed = false;
3827
+ while (!parentSignal.aborted && isCurrent()) {
3828
+ const result = await showSettingsList(ctx, settingsRuntime, parentSignal, isCurrent, onApplied);
3829
+ if (!result) return changed;
3830
+ changed ||= result.changed;
3831
+ if (!result.editFireworksAccount) return changed;
3832
+ changed ||= await editFireworksAccount(
3833
+ ctx,
3834
+ settingsRuntime,
3835
+ parentSignal,
3836
+ isCurrent,
3837
+ onApplied
3838
+ );
3839
+ }
3840
+ return changed;
3841
+ }
3842
+ async function showSettingsList(ctx, settingsRuntime, parentSignal, isCurrent, onApplied) {
2923
3843
  return ctx.ui.custom((tui, theme, _keybindings, done) => {
2924
3844
  const localController = new AbortController();
2925
3845
  const signal = AbortSignal.any([parentSignal, localController.signal]);
@@ -2927,6 +3847,7 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
2927
3847
  let closing = false;
2928
3848
  let saveQueue = Promise.resolve();
2929
3849
  const state = settingsRuntime.get();
3850
+ const fireworksValue = state.settings.fireworksAccountId ?? AUTO;
2930
3851
  const items = [
2931
3852
  {
2932
3853
  id: "codexFastMode",
@@ -2941,6 +3862,13 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
2941
3862
  description: "Show time remaining until each Codex usage limit resets.",
2942
3863
  currentValue: state.settings.codexStatusResetCountdown ? ON : OFF,
2943
3864
  values: [OFF, ON]
3865
+ },
3866
+ {
3867
+ id: "fireworksAccountId",
3868
+ label: "Fireworks account",
3869
+ description: "Select Edit to enter a visible account slug, or submit blank to clear it.",
3870
+ currentValue: fireworksValue,
3871
+ values: state.settings.fireworksAccountId ? [state.settings.fireworksAccountId, EDIT] : [AUTO, EDIT]
2944
3872
  }
2945
3873
  ];
2946
3874
  const container = new Container();
@@ -2950,7 +3878,36 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
2950
3878
  if (closing) return;
2951
3879
  closing = true;
2952
3880
  localController.abort();
2953
- done(changed);
3881
+ done({ changed, editFireworksAccount: false });
3882
+ };
3883
+ const queueUpdate = (id, requested, display) => {
3884
+ saveQueue = saveQueue.then(async () => {
3885
+ const previous = settingsRuntime.get().settings[id];
3886
+ if (settingsRuntime.get().kind === "invalid") {
3887
+ settingsList.updateValue(id, displaySetting(id, previous));
3888
+ if (!signal.aborted && isCurrent()) {
3889
+ ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
3890
+ tui.requestRender();
3891
+ }
3892
+ return;
3893
+ }
3894
+ try {
3895
+ await settingsRuntime.update({ [id]: requested }, signal);
3896
+ } catch (error) {
3897
+ if (signal.aborted || !isCurrent()) return;
3898
+ settingsList.updateValue(id, displaySetting(id, previous));
3899
+ ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
3900
+ tui.requestRender();
3901
+ return;
3902
+ }
3903
+ if (previous !== requested) {
3904
+ changed = true;
3905
+ onApplied(id);
3906
+ }
3907
+ if (signal.aborted || !isCurrent()) return;
3908
+ settingsList.updateValue(id, display);
3909
+ tui.requestRender();
3910
+ });
2954
3911
  };
2955
3912
  settingsList = new SettingsList(
2956
3913
  items,
@@ -2958,35 +3915,18 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
2958
3915
  getSettingsListTheme(),
2959
3916
  (id, value) => {
2960
3917
  if (closing || signal.aborted || !isCurrent()) return;
2961
- const settingId = id;
2962
- const requested = value !== OFF;
2963
- saveQueue = saveQueue.then(async () => {
2964
- const previous = settingsRuntime.get().settings[settingId];
2965
- if (settingsRuntime.get().kind === "invalid") {
2966
- settingsList.updateValue(id, displayValue(previous));
2967
- if (!signal.aborted && isCurrent()) {
2968
- ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
2969
- tui.requestRender();
2970
- }
2971
- return;
2972
- }
2973
- try {
2974
- await settingsRuntime.update({ [settingId]: requested }, signal);
2975
- } catch (error) {
2976
- if (signal.aborted || !isCurrent()) return;
2977
- settingsList.updateValue(id, displayValue(previous));
2978
- ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
2979
- tui.requestRender();
2980
- return;
2981
- }
2982
- if (previous !== requested) {
2983
- changed = true;
2984
- onApplied(settingId);
3918
+ if (id === "fireworksAccountId") {
3919
+ if (value === EDIT) {
3920
+ saveQueue = saveQueue.then(() => {
3921
+ if (closing || signal.aborted || !isCurrent()) return;
3922
+ closing = true;
3923
+ done({ changed, editFireworksAccount: true });
3924
+ });
2985
3925
  }
2986
- if (signal.aborted || !isCurrent()) return;
2987
- settingsList.updateValue(id, displayValue(requested));
2988
- tui.requestRender();
2989
- });
3926
+ return;
3927
+ }
3928
+ const settingId = id;
3929
+ queueUpdate(settingId, value !== OFF, value);
2990
3930
  },
2991
3931
  cancel
2992
3932
  );
@@ -3008,8 +3948,41 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
3008
3948
  };
3009
3949
  });
3010
3950
  }
3011
- function displayValue(enabled) {
3012
- return enabled ? ON : OFF;
3951
+ async function editFireworksAccount(ctx, settingsRuntime, signal, isCurrent, onApplied) {
3952
+ while (!signal.aborted && isCurrent()) {
3953
+ const state = settingsRuntime.get();
3954
+ if (state.kind === "invalid") {
3955
+ ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
3956
+ return false;
3957
+ }
3958
+ const entered = await ctx.ui.input(
3959
+ "Fireworks account slug \xB7 submit blank for Auto",
3960
+ state.settings.fireworksAccountId ?? "Example: acme",
3961
+ { signal }
3962
+ );
3963
+ if (signal.aborted || !isCurrent() || entered === void 0) return false;
3964
+ const normalized = entered.trim();
3965
+ const requested = normalized || void 0;
3966
+ if (requested !== void 0 && !isFireworksAccountId(requested)) {
3967
+ ctx.ui.notify("Enter a URL-safe Fireworks account slug.", "warning");
3968
+ continue;
3969
+ }
3970
+ if (requested === state.settings.fireworksAccountId) return false;
3971
+ try {
3972
+ await settingsRuntime.update({ fireworksAccountId: requested }, signal);
3973
+ } catch (error) {
3974
+ if (signal.aborted || !isCurrent()) return false;
3975
+ ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
3976
+ return false;
3977
+ }
3978
+ onApplied("fireworksAccountId");
3979
+ return true;
3980
+ }
3981
+ return false;
3982
+ }
3983
+ function displaySetting(id, value) {
3984
+ if (id === "fireworksAccountId") return typeof value === "string" ? value : AUTO;
3985
+ return value ? ON : OFF;
3013
3986
  }
3014
3987
 
3015
3988
  // src/usage.ts
@@ -3120,9 +4093,7 @@ function usageExtension(pi, dependencies = {}) {
3120
4093
  const generation = statusGeneration;
3121
4094
  statusCountdownTimer = setTimeout(() => {
3122
4095
  statusCountdownTimer = void 0;
3123
- if (!sessionActive || generation !== statusGeneration || modelIdentity(ctx.model) !== modelIdentity(model)) {
3124
- return;
3125
- }
4096
+ if (!sessionActive || generation !== statusGeneration) return;
3126
4097
  publishStatus(ctx, outcome, model, false);
3127
4098
  }, STATUS_COUNTDOWN_REFRESH_MS);
3128
4099
  statusCountdownTimer.unref?.();
@@ -3152,6 +4123,8 @@ function usageExtension(pi, dependencies = {}) {
3152
4123
  const expectedSessionGeneration = sessionGeneration;
3153
4124
  const expectedSessionId = ctx.sessionManager.getSessionId();
3154
4125
  const expectedModelIdentity = modelIdentity(ctx.model);
4126
+ const expectedFireworksAccountId = adapter.id === "fireworks" ? settingsRuntime.get().settings.fireworksAccountId : void 0;
4127
+ const querySettings = adapter.id === "fireworks" ? { fireworksAccountId: expectedFireworksAccountId } : void 0;
3155
4128
  let auth;
3156
4129
  try {
3157
4130
  auth = await awaitWithDeadline(
@@ -3175,8 +4148,18 @@ function usageExtension(pi, dependencies = {}) {
3175
4148
  }
3176
4149
  };
3177
4150
  }
3178
- const requiresRequestBoundaryGuard = adapter.id === "deepseek" || adapter.id === "xai";
3179
- const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity;
4151
+ const requiresRequestBoundaryGuard = [
4152
+ "baseten",
4153
+ "deepseek",
4154
+ "fireworks",
4155
+ "minimax",
4156
+ "minimax-cn",
4157
+ "moonshotai",
4158
+ "moonshotai-cn",
4159
+ "vercel-ai-gateway",
4160
+ "xai"
4161
+ ].includes(adapter.id);
4162
+ const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.id === "fireworks" && settingsRuntime.get().settings.fireworksAccountId !== expectedFireworksAccountId;
3180
4163
  if (requiresRequestBoundaryGuard && requestContextChanged()) throw abortError();
3181
4164
  if (!auth) {
3182
4165
  if (displayState === "current") {
@@ -3193,10 +4176,11 @@ function usageExtension(pi, dependencies = {}) {
3193
4176
  authState: "unavailable"
3194
4177
  };
3195
4178
  }
4179
+ const queryFingerprint = adapter.id === "fireworks" ? `${auth.fingerprint}:account:${expectedFireworksAccountId ?? "auto"}` : auth.fingerprint;
3196
4180
  if (displayState === "current") {
3197
- transitionCurrentIdentity(`${adapter.id}:${auth.fingerprint}`, adapter.id);
4181
+ transitionCurrentIdentity(`${adapter.id}:${queryFingerprint}`, adapter.id);
3198
4182
  }
3199
- const cached = !force ? cache.get(adapter.id, auth.fingerprint) : void 0;
4183
+ const cached = !force ? cache.get(adapter.id, queryFingerprint) : void 0;
3200
4184
  if (cached) {
3201
4185
  return {
3202
4186
  state: {
@@ -3209,7 +4193,7 @@ function usageExtension(pi, dependencies = {}) {
3209
4193
  fingerprint: auth.fingerprint
3210
4194
  };
3211
4195
  }
3212
- const failureKey = `${adapter.id}:${auth.fingerprint}`;
4196
+ const failureKey = `${adapter.id}:${queryFingerprint}`;
3213
4197
  const previousFailure = failureBackoff.get(failureKey);
3214
4198
  if (!force && previousFailure && previousFailure.until > Date.now()) {
3215
4199
  return {
@@ -3227,7 +4211,7 @@ function usageExtension(pi, dependencies = {}) {
3227
4211
  querySequence += 1;
3228
4212
  const queryId = querySequence;
3229
4213
  setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES);
3230
- let deepSeekAuthChanged = false;
4214
+ let retryableAuthChanged = false;
3231
4215
  try {
3232
4216
  const remainingMs = Math.max(1, deadlineAt - Date.now());
3233
4217
  const guard = requiresRequestBoundaryGuard ? async () => {
@@ -3240,17 +4224,26 @@ function usageExtension(pi, dependencies = {}) {
3240
4224
  );
3241
4225
  if (signal.aborted || requestContextChanged()) throw abortError();
3242
4226
  if (revalidated?.fingerprint !== auth.fingerprint) {
3243
- if (adapter.id === "deepseek") {
3244
- deepSeekAuthChanged = true;
3245
- throw new Error("DeepSeek runtime credential changed during the balance query.");
4227
+ if (["deepseek", "minimax", "minimax-cn"].includes(adapter.id)) {
4228
+ retryableAuthChanged = true;
4229
+ throw new Error(
4230
+ `${adapter.displayName} runtime credential changed during the usage query.`
4231
+ );
3246
4232
  }
3247
4233
  throw abortError();
3248
4234
  }
3249
4235
  } : void 0;
3250
- const report = await queryProviderUsage(adapter, auth, signal, remainingMs, guard);
4236
+ const report2 = await queryProviderUsage(
4237
+ adapter,
4238
+ auth,
4239
+ signal,
4240
+ remainingMs,
4241
+ guard,
4242
+ querySettings
4243
+ );
3251
4244
  if (guard) await guard();
3252
4245
  if (latestQueries.get(failureKey) === queryId) {
3253
- cache.set(adapter.id, auth.fingerprint, report);
4246
+ cache.set(adapter.id, queryFingerprint, report2);
3254
4247
  failureBackoff.delete(failureKey);
3255
4248
  }
3256
4249
  return {
@@ -3259,13 +4252,13 @@ function usageExtension(pi, dependencies = {}) {
3259
4252
  providerName: adapter.displayName,
3260
4253
  displayState,
3261
4254
  status: "ready",
3262
- report
4255
+ report: report2
3263
4256
  },
3264
4257
  fingerprint: auth.fingerprint
3265
4258
  };
3266
4259
  } catch (error) {
3267
4260
  if (isStaleExtensionContextError(error) || isAbortError3(error)) throw error;
3268
- if (deepSeekAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
4261
+ if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
3269
4262
  if (latestQueries.get(failureKey) === queryId) latestQueries.delete(failureKey);
3270
4263
  return queryAdapterState(
3271
4264
  ctx,
@@ -3880,7 +4873,7 @@ function usageExtension(pi, dependencies = {}) {
3880
4873
  }
3881
4874
  }
3882
4875
  });
3883
- pi.on("session_start", (_event, ctx) => {
4876
+ pi.on("session_start", async (_event, ctx) => {
3884
4877
  sessionGeneration += 1;
3885
4878
  statusGeneration += 1;
3886
4879
  clearStatusTimers();
@@ -3888,7 +4881,13 @@ function usageExtension(pi, dependencies = {}) {
3888
4881
  activeControllers.clear();
3889
4882
  statusController = void 0;
3890
4883
  sessionActive = true;
3891
- startStatusRefresh(ctx, ctx.model, false);
4884
+ const ownerGeneration = sessionGeneration;
4885
+ try {
4886
+ await fastRuntime.prepareSession(ctx);
4887
+ } catch (error) {
4888
+ if (isStaleExtensionContextError(error) || ownerGeneration !== sessionGeneration) return;
4889
+ throw error;
4890
+ }
3892
4891
  });
3893
4892
  pi.on("session_tree", (_event, ctx) => {
3894
4893
  startStatusRefresh(ctx, ctx.model, false);
@@ -3916,7 +4915,8 @@ function usageExtension(pi, dependencies = {}) {
3916
4915
  fastRuntime = registerCodexFastMode(
3917
4916
  pi,
3918
4917
  settingsRuntime,
3919
- (ctx) => startStatusRefresh(ctx, ctx.model, false)
4918
+ (ctx) => startStatusRefresh(ctx, ctx.model, false),
4919
+ { registerSessionStart: false }
3920
4920
  );
3921
4921
  }
3922
4922
  export {
@@ -3946,14 +4946,21 @@ export {
3946
4946
  isStaleExtensionContextError,
3947
4947
  listCodexResetCredits,
3948
4948
  loadUsageSettings,
4949
+ miniMaxUsageKind,
4950
+ normalizeBasetenBillingUsagePayload,
3949
4951
  normalizeCodexBackendPayload,
3950
4952
  normalizeCodexResetCreditsPayload,
3951
4953
  normalizeDeepSeekBalancePayload,
4954
+ normalizeFireworksAccountsPayload,
4955
+ normalizeFireworksBillingSummaryPayload,
3952
4956
  normalizeGitHubCopilotUsagePayload,
3953
4957
  normalizeKimiCodingUsagePayload,
4958
+ normalizeMiniMaxUsagePayload,
4959
+ normalizeMoonshotBalancePayload,
3954
4960
  normalizeOpenCodeZenPayload,
3955
4961
  normalizeOpenRouterKeyPayload,
3956
4962
  normalizeUsageSettings,
4963
+ normalizeVercelAIGatewayCreditsPayload,
3957
4964
  normalizeXaiBillingPayload,
3958
4965
  normalizeZaiQuotaPayload,
3959
4966
  providerIsConfigured,