@narumitw/pi-usage 0.58.0 → 0.60.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,14 +552,14 @@ 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
 
@@ -545,7 +588,7 @@ function normalizeFireworksAccountsPayload(payload) {
545
588
  }
546
589
  const accounts = [];
547
590
  for (const raw of payload.accounts) {
548
- const account = asObject3(raw);
591
+ const account = asObject4(raw);
549
592
  if (!account) throw new Error("Fireworks accounts response row was not an object.");
550
593
  if (typeof account.name !== "string") {
551
594
  throw new Error("Fireworks accounts response omitted the account resource name.");
@@ -571,7 +614,7 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
571
614
  }
572
615
  const totals = /* @__PURE__ */ new Map();
573
616
  for (const raw of payload.lineItems ?? []) {
574
- const lineItem = asObject3(raw);
617
+ const lineItem = asObject4(raw);
575
618
  if (!lineItem) throw new Error("Fireworks billing line item was not an object.");
576
619
  const cost = moneyAmount(lineItem.totalCost, "line item total cost");
577
620
  const series = seriesKey(lineItem.series);
@@ -592,12 +635,12 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
592
635
  currency
593
636
  });
594
637
  for (const series of SERIES_KEYS) {
595
- const amount = amounts.get(series);
596
- if (amount === void 0) continue;
638
+ const amount2 = amounts.get(series);
639
+ if (amount2 === void 0) continue;
597
640
  metrics.push({
598
641
  id: `${currency.toLowerCase()}-${series}`,
599
642
  label: SERIES_LABELS[series],
600
- value: formatMoneyAmount(amount),
643
+ value: formatMoneyAmount(amount2),
601
644
  unit: "currency",
602
645
  currency
603
646
  });
@@ -622,7 +665,7 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
622
665
  };
623
666
  }
624
667
  function moneyAmount(value, description) {
625
- const money = asObject3(value);
668
+ const money = asObject4(value);
626
669
  if (!money) throw new Error(`Fireworks billing ${description} was not a money object.`);
627
670
  const currency = typeof money.currencyCode === "string" ? money.currencyCode : void 0;
628
671
  if (!currency || !CURRENCY_PATTERN.test(currency)) {
@@ -658,25 +701,25 @@ function seriesKey(value) {
658
701
  }
659
702
  function sumSeries(amounts) {
660
703
  let total = 0n;
661
- for (const amount of amounts.values()) total += amount;
704
+ for (const amount2 of amounts.values()) total += amount2;
662
705
  return total;
663
706
  }
664
- function formatMoneyAmount(amount) {
665
- const negative = amount < 0n;
666
- const magnitude = negative ? -amount : amount;
707
+ function formatMoneyAmount(amount2) {
708
+ const negative = amount2 < 0n;
709
+ const magnitude = negative ? -amount2 : amount2;
667
710
  const units = magnitude / NANOS_PER_UNIT;
668
711
  const nanos = (magnitude % NANOS_PER_UNIT).toString().padStart(9, "0").replace(/0+$/u, "");
669
712
  return `${negative ? "-" : ""}${units.toString()}${nanos ? `.${nanos}` : ""}`;
670
713
  }
671
- function asObject3(value) {
714
+ function asObject4(value) {
672
715
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
673
716
  return value;
674
717
  }
675
718
 
676
719
  // src/providers/github-copilot.ts
677
720
  function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
678
- const snapshots = asObject4(payload.quota_snapshots);
679
- const premium = asObject4(snapshots?.premium_interactions);
721
+ const snapshots = asObject5(payload.quota_snapshots);
722
+ const premium = asObject5(snapshots?.premium_interactions);
680
723
  const metrics = [];
681
724
  let semanticsLabel;
682
725
  let bucket;
@@ -717,8 +760,8 @@ function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
717
760
  };
718
761
  }
719
762
  } else {
720
- const limited = asObject4(payload.limited_user_quotas);
721
- const monthly = asObject4(payload.monthly_quotas);
763
+ const limited = asObject5(payload.limited_user_quotas);
764
+ const monthly = asObject5(payload.monthly_quotas);
722
765
  const remaining = asNonnegativeNumber(limited?.chat);
723
766
  const entitlement = asNonnegativeNumber(monthly?.chat);
724
767
  if (remaining === void 0 || entitlement === void 0) {
@@ -757,7 +800,7 @@ function resetTimestamp(payload) {
757
800
  const milliseconds = Date.parse(raw);
758
801
  return Number.isNaN(milliseconds) ? {} : { resetsAt: Math.floor(milliseconds / 1e3) };
759
802
  }
760
- function asObject4(value) {
803
+ function asObject5(value) {
761
804
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
762
805
  return value;
763
806
  }
@@ -780,7 +823,7 @@ var DAILY_WINDOW_MINUTES = 1440;
780
823
  var WEEKLY_WINDOW_MINUTES = 10080;
781
824
  var FIXED_POINT_UNITS_PER_CENT = 1e6;
782
825
  function normalizeKimiCodingUsagePayload(payload, capturedAt) {
783
- const root = asObject5(payload);
826
+ const root = asObject6(payload);
784
827
  if (!root) throw new Error("Kimi Coding usage response was not an object.");
785
828
  const candidates = [];
786
829
  let omittedWindow = false;
@@ -789,7 +832,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
789
832
  else if (root.usage !== void 0) omittedWindow = true;
790
833
  if (Array.isArray(root.limits)) {
791
834
  for (const raw of root.limits) {
792
- const item = asObject5(raw);
835
+ const item = asObject6(raw);
793
836
  const windowMinutes = parseWindowMinutes(item?.window);
794
837
  const label = sanitizedLabel(item?.name);
795
838
  const bucket = windowMinutes === void 0 ? void 0 : parseUsageRow(item?.detail, windowMinutes, label ?? defaultWindowLabel(windowMinutes));
@@ -826,7 +869,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
826
869
  };
827
870
  }
828
871
  function parseUsageRow(value, windowMinutes, label) {
829
- const row = asObject5(value);
872
+ const row = asObject6(value);
830
873
  if (!row) return void 0;
831
874
  const used = asNonnegativeInteger2(row.used);
832
875
  const limit = asNonnegativeInteger2(row.limit);
@@ -844,7 +887,7 @@ function parseUsageRow(value, windowMinutes, label) {
844
887
  };
845
888
  }
846
889
  function parseWindowMinutes(value) {
847
- const window = asObject5(value);
890
+ const window = asObject6(value);
848
891
  if (!window) return void 0;
849
892
  const duration = asPositiveInteger(window.duration);
850
893
  if (duration === void 0) return void 0;
@@ -854,8 +897,8 @@ function parseWindowMinutes(value) {
854
897
  return Number.isSafeInteger(minutes) ? minutes : void 0;
855
898
  }
856
899
  function parseBoosterWallet(value) {
857
- const wallet = asObject5(value);
858
- const balance = asObject5(wallet?.balance);
900
+ const wallet = asObject6(value);
901
+ const balance = asObject6(wallet?.balance);
859
902
  if (!wallet || !balance || balance.type !== "BOOSTER") return [];
860
903
  const totalRaw = asPositiveInteger(balance.amount);
861
904
  if (totalRaw === void 0) return [];
@@ -906,7 +949,7 @@ function parseBoosterWallet(value) {
906
949
  return metrics;
907
950
  }
908
951
  function parseMoney(value) {
909
- const money = asObject5(value);
952
+ const money = asObject6(value);
910
953
  if (!money) return void 0;
911
954
  const cents = asNonnegativeInteger2(money.priceInCents);
912
955
  if (cents === void 0) return void 0;
@@ -920,7 +963,7 @@ function fixedPointToMajor(value) {
920
963
  const major = roundedCents / 100;
921
964
  return Number.isSafeInteger(roundedCents) && Number.isFinite(major) ? major : void 0;
922
965
  }
923
- function asObject5(value) {
966
+ function asObject6(value) {
924
967
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
925
968
  return value;
926
969
  }
@@ -987,6 +1030,246 @@ function defaultWindowLabel(minutes) {
987
1030
  return `${minutes}m window`;
988
1031
  }
989
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
+
990
1273
  // src/providers/opencode-zen.ts
991
1274
  var ZEN_WINDOWS = [
992
1275
  { key: "rolling", label: "Rolling" },
@@ -994,12 +1277,12 @@ var ZEN_WINDOWS = [
994
1277
  { key: "monthly", label: "Monthly" }
995
1278
  ];
996
1279
  function normalizeOpenCodeZenPayload(payload, capturedAt) {
997
- const usage = asObject6(payload.usage);
1280
+ const usage = asObject9(payload.usage);
998
1281
  if (!usage) throw new Error("OpenCode Zen usage response was not an object.");
999
1282
  const buckets = [];
1000
1283
  const notes = [];
1001
1284
  for (const window of ZEN_WINDOWS) {
1002
- const raw = asObject6(usage[window.key]);
1285
+ const raw = asObject9(usage[window.key]);
1003
1286
  if (!raw) continue;
1004
1287
  const status = asString3(raw.status);
1005
1288
  if (status !== "ok" && status !== "rate-limited") {
@@ -1036,7 +1319,7 @@ function normalizeOpenCodeZenPayload(payload, capturedAt) {
1036
1319
  ...notes.length > 0 ? { notes } : {}
1037
1320
  };
1038
1321
  }
1039
- function asObject6(value) {
1322
+ function asObject9(value) {
1040
1323
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1041
1324
  return value;
1042
1325
  }
@@ -1060,7 +1343,7 @@ function clampPercent2(value) {
1060
1343
 
1061
1344
  // src/providers/openrouter.ts
1062
1345
  function normalizeOpenRouterKeyPayload(payload, capturedAt) {
1063
- const data = asObject7(payload.data);
1346
+ const data = asObject10(payload.data);
1064
1347
  if (!data) throw new Error("OpenRouter key response data was not an object.");
1065
1348
  const limit = asNonnegativeNumber3(data.limit);
1066
1349
  const remaining = asNonnegativeNumber3(data.limit_remaining);
@@ -1102,11 +1385,11 @@ function normalizeOpenRouterKeyPayload(payload, capturedAt) {
1102
1385
  };
1103
1386
  }
1104
1387
  function addUsageMetric(metrics, id, label, value) {
1105
- const amount = typeof value === "number" ? asNonnegativeNumber3(value) : void 0;
1106
- if (amount === void 0) return;
1107
- 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" });
1108
1391
  }
1109
- function asObject7(value) {
1392
+ function asObject10(value) {
1110
1393
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1111
1394
  return value;
1112
1395
  }
@@ -1119,6 +1402,44 @@ function asNonnegativeNumber3(value) {
1119
1402
  return value;
1120
1403
  }
1121
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
+
1122
1443
  // src/providers/xai.ts
1123
1444
  var MAX_SAFE_CENTS = Number.MAX_SAFE_INTEGER;
1124
1445
  function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
@@ -1136,7 +1457,7 @@ function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
1136
1457
  config.billingPeriodStart,
1137
1458
  config.billingPeriodEnd
1138
1459
  );
1139
- const preferredPercent = optionalPercent(config.creditUsagePercent, "creditUsagePercent");
1460
+ const preferredPercent = optionalPercent2(config.creditUsagePercent, "creditUsagePercent");
1140
1461
  if (preferredPercent !== void 0) {
1141
1462
  buckets.push({
1142
1463
  id: "included-allowance",
@@ -1246,7 +1567,7 @@ function optionalUsd(value, field) {
1246
1567
  }
1247
1568
  return cents / 100;
1248
1569
  }
1249
- function optionalPercent(value, field) {
1570
+ function optionalPercent2(value, field) {
1250
1571
  if (value === void 0 || value === null) return void 0;
1251
1572
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 100) {
1252
1573
  throw new Error(`xAI billing ${field} was outside 0\u2013100.`);
@@ -1283,14 +1604,14 @@ function isRecord2(value) {
1283
1604
  // src/providers/zai.ts
1284
1605
  var FIVE_HOUR_WINDOW_MINUTES2 = 300;
1285
1606
  var WEEKLY_WINDOW_MINUTES2 = 10080;
1286
- function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt) {
1287
- const data = asObject8(payload.data);
1607
+ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt, plan) {
1608
+ const data = asObject11(payload.data);
1288
1609
  if (!data) throw new Error("Z.AI quota response data was not an object.");
1289
1610
  const limits = Array.isArray(data.limits) ? data.limits : [];
1290
1611
  const buckets = [];
1291
1612
  const metrics = [];
1292
1613
  for (const raw of limits) {
1293
- const limit = asObject8(raw);
1614
+ const limit = asObject11(raw);
1294
1615
  if (!limit) continue;
1295
1616
  const type = asString5(limit.type);
1296
1617
  const unit = asNonnegativeNumber4(limit.unit);
@@ -1299,14 +1620,20 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt)
1299
1620
  addCountBucket(buckets, limit, "mcp-monthly", "MCP monthly allowance");
1300
1621
  addUsageDetailMetrics(metrics, limit.usageDetails);
1301
1622
  } else if (isPlanUsage && unit === 3) {
1302
- addPercentBucket(buckets, limit, "five-hour", "5h window", FIVE_HOUR_WINDOW_MINUTES2);
1623
+ addPercentBucket(
1624
+ buckets,
1625
+ limit,
1626
+ "five-hour",
1627
+ sessionWindowLabel(limit),
1628
+ sessionWindowMinutes(limit)
1629
+ );
1303
1630
  } else if (isPlanUsage && unit === 6) {
1304
1631
  const used = asNonnegativeNumber4(limit.currentValue);
1305
1632
  const quota = asNonnegativeNumber4(limit.usage);
1306
1633
  if (used !== void 0 && quota !== void 0) {
1307
- addCountBucket(buckets, limit, "weekly", "Weekly window", WEEKLY_WINDOW_MINUTES2);
1634
+ addCountBucket(buckets, limit, "weekly", "Weekly window", weeklyWindowMinutes(limit));
1308
1635
  } else {
1309
- addPercentBucket(buckets, limit, "weekly", "Weekly window", WEEKLY_WINDOW_MINUTES2);
1636
+ addPercentBucket(buckets, limit, "weekly", "Weekly window", weeklyWindowMinutes(limit));
1310
1637
  }
1311
1638
  }
1312
1639
  }
@@ -1315,7 +1642,12 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt)
1315
1642
  }
1316
1643
  const notes = [];
1317
1644
  const level = asString5(data.level);
1318
- if (level) notes.push(`Plan: ${level}`);
1645
+ const planLabel = plan?.name ?? level;
1646
+ if (planLabel) {
1647
+ notes.push(
1648
+ plan?.renewsAt ? `Plan: ${planLabel} \xB7 renews ${plan.renewsAt}` : `Plan: ${planLabel}`
1649
+ );
1650
+ }
1319
1651
  return {
1320
1652
  providerId,
1321
1653
  providerName,
@@ -1327,6 +1659,57 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt)
1327
1659
  ...notes.length > 0 ? { notes } : {}
1328
1660
  };
1329
1661
  }
1662
+ function normalizeZaiSubscriptionPayload(payload) {
1663
+ if (payload.success === false) return void 0;
1664
+ if (typeof payload.code === "number" && payload.code !== 0 && payload.code !== 200) {
1665
+ return void 0;
1666
+ }
1667
+ if (!Array.isArray(payload.data)) return void 0;
1668
+ const candidates = [];
1669
+ for (const raw of payload.data) {
1670
+ const entry = asObject11(raw);
1671
+ if (!entry) continue;
1672
+ const name = asString5(entry.productName);
1673
+ if (!name) continue;
1674
+ const renewsAt = planRenewalDate(entry.nextRenewTime);
1675
+ const status = asString5(entry.status)?.toUpperCase();
1676
+ const inCurrentPeriod = asBoolean(entry.inCurrentPeriod);
1677
+ candidates.push({
1678
+ plan: { name, ...renewsAt !== void 0 ? { renewsAt } : {} },
1679
+ ...status !== void 0 ? { status } : {},
1680
+ ...inCurrentPeriod !== void 0 ? { inCurrentPeriod } : {}
1681
+ });
1682
+ }
1683
+ const hasStateMetadata = candidates.some(
1684
+ (candidate) => candidate.status !== void 0 || candidate.inCurrentPeriod !== void 0
1685
+ );
1686
+ if (!hasStateMetadata) return candidates[0]?.plan;
1687
+ return candidates.find(
1688
+ (candidate) => candidate.inCurrentPeriod === true && candidate.status === "VALID"
1689
+ )?.plan ?? candidates.find(
1690
+ (candidate) => candidate.inCurrentPeriod === true && candidate.status === void 0
1691
+ )?.plan ?? candidates.find(
1692
+ (candidate) => candidate.status === "VALID" && candidate.inCurrentPeriod === void 0
1693
+ )?.plan;
1694
+ }
1695
+ function planRenewalDate(value) {
1696
+ if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}/u.test(value)) return value.slice(0, 10);
1697
+ const millis = asNonnegativeNumber4(value);
1698
+ if (millis === void 0 || millis === 0) return void 0;
1699
+ return new Date(millis).toISOString().slice(0, 10);
1700
+ }
1701
+ function sessionWindowMinutes(limit) {
1702
+ const hours = asPositiveNumber(limit.number);
1703
+ return hours === void 0 ? FIVE_HOUR_WINDOW_MINUTES2 : Math.round(hours * 60);
1704
+ }
1705
+ function sessionWindowLabel(limit) {
1706
+ const minutes = sessionWindowMinutes(limit);
1707
+ return minutes === FIVE_HOUR_WINDOW_MINUTES2 ? "5h window" : `${Math.round(minutes / 60)}h window`;
1708
+ }
1709
+ function weeklyWindowMinutes(limit) {
1710
+ const weeks = asPositiveNumber(limit.number);
1711
+ return weeks === void 0 ? WEEKLY_WINDOW_MINUTES2 : Math.round(weeks * WEEKLY_WINDOW_MINUTES2);
1712
+ }
1330
1713
  function addPercentBucket(buckets, limit, id, label, windowMinutes) {
1331
1714
  const used = asNonnegativeNumber4(limit.percentage);
1332
1715
  if (used === void 0) return;
@@ -1362,7 +1745,7 @@ function addCountBucket(buckets, limit, id, label, windowMinutes) {
1362
1745
  function addUsageDetailMetrics(metrics, value) {
1363
1746
  if (!Array.isArray(value)) return;
1364
1747
  for (const raw of value) {
1365
- const detail = asObject8(raw);
1748
+ const detail = asObject11(raw);
1366
1749
  if (!detail) continue;
1367
1750
  const label = asString5(detail.modelCode);
1368
1751
  const usage = asNonnegativeNumber4(detail.usage);
@@ -1370,7 +1753,7 @@ function addUsageDetailMetrics(metrics, value) {
1370
1753
  metrics.push({ id: `mcp-${kebabCase(label)}`, label, value: usage, unit: "count" });
1371
1754
  }
1372
1755
  }
1373
- function asObject8(value) {
1756
+ function asObject11(value) {
1374
1757
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1375
1758
  return value;
1376
1759
  }
@@ -1382,6 +1765,16 @@ function asNonnegativeNumber4(value) {
1382
1765
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
1383
1766
  return value;
1384
1767
  }
1768
+ function asPositiveNumber(value) {
1769
+ const number = asNonnegativeNumber4(value);
1770
+ return number !== void 0 && number > 0 ? number : void 0;
1771
+ }
1772
+ function asBoolean(value) {
1773
+ if (typeof value === "boolean") return value;
1774
+ if (value === 1) return true;
1775
+ if (value === 0) return false;
1776
+ return void 0;
1777
+ }
1385
1778
  function asEpochSeconds2(value) {
1386
1779
  const millis = asNonnegativeNumber4(value);
1387
1780
  if (millis === void 0) return void 0;
@@ -1395,6 +1788,8 @@ function clampPercent3(value) {
1395
1788
  }
1396
1789
 
1397
1790
  // src/query.ts
1791
+ var BASETEN_BILLING_USAGE_URL = "https://api.baseten.co/v1/billing/usage_summary";
1792
+ var BASETEN_USAGE_WINDOW_DAYS = 30;
1398
1793
  var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
1399
1794
  var DEEPSEEK_BALANCE_URL = "https://api.deepseek.com/user/balance";
1400
1795
  var FIREWORKS_BILLING_SUMMARY_ORIGIN = "https://api.fireworks.ai";
@@ -1402,8 +1797,18 @@ var FIREWORKS_SPEND_WINDOW_DAYS = 30;
1402
1797
  var FIREWORKS_MAX_ACCOUNT_PAGES = 5;
1403
1798
  var GITHUB_COPILOT_USAGE_URL = "https://api.github.com/copilot_internal/user";
1404
1799
  var OPENROUTER_KEY_URL = "https://openrouter.ai/api/v1/key";
1800
+ var VERCEL_AI_GATEWAY_CREDITS_URL = "https://ai-gateway.vercel.sh/v1/credits";
1405
1801
  var OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usage";
1406
1802
  var KIMI_CODING_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
1803
+ var MINIMAX_API_ROOTS = Object.freeze({
1804
+ minimax: "https://api.minimax.io",
1805
+ "minimax-cn": "https://api.minimaxi.com"
1806
+ });
1807
+ var MOONSHOT_BALANCE_URLS = Object.freeze({
1808
+ moonshotai: "https://api.moonshot.ai/v1/users/me/balance",
1809
+ "moonshotai-cn": "https://api.moonshot.cn/v1/users/me/balance"
1810
+ });
1811
+ var SHARED_MOONSHOT_ENV_VAR = "MOONSHOT_API_KEY";
1407
1812
  var XAI_USER_URL = "https://cli-chat-proxy.grok.com/v1/user?include=subscription";
1408
1813
  var XAI_BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
1409
1814
  var XAI_CLIENT_HEADERS = Object.freeze({
@@ -1415,6 +1820,27 @@ var MAX_SUCCESS_BODY_BYTES = 64 * 1024;
1415
1820
  var MAX_ERROR_BODY_BYTES = 4 * 1024;
1416
1821
  var AUTH_FINGERPRINT_SALT = randomBytes(32);
1417
1822
  var SUPPORTED_ADAPTERS = [
1823
+ {
1824
+ id: "baseten",
1825
+ displayName: "Baseten",
1826
+ semantics: { kind: "api-key", label: "Organization Model APIs spend" },
1827
+ async query(auth, signal, timeoutMs, guard) {
1828
+ if (!guard) throw new Error("Baseten billing usage requires request-boundary revalidation.");
1829
+ const startedAt = Date.now();
1830
+ await guard();
1831
+ const windowAt = Date.now();
1832
+ const payload = await fetchProviderJson(
1833
+ basetenBillingUsageUrl(windowAt),
1834
+ auth,
1835
+ signal,
1836
+ remainingTimeout(timeoutMs, startedAt, "fetching Baseten billing usage"),
1837
+ "Baseten billing usage endpoint",
1838
+ { redirect: "error" }
1839
+ );
1840
+ await guard();
1841
+ return normalizeBasetenBillingUsagePayload(payload, Date.now());
1842
+ }
1843
+ },
1418
1844
  {
1419
1845
  id: "openai-codex",
1420
1846
  displayName: "OpenAI Codex",
@@ -1487,6 +1913,27 @@ var SUPPORTED_ADAPTERS = [
1487
1913
  return normalizeOpenRouterKeyPayload(payload, Date.now());
1488
1914
  }
1489
1915
  },
1916
+ {
1917
+ id: "vercel-ai-gateway",
1918
+ displayName: "Vercel AI Gateway",
1919
+ semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
1920
+ async query(auth, signal, timeoutMs, guard) {
1921
+ if (!guard)
1922
+ throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
1923
+ const startedAt = Date.now();
1924
+ await guard();
1925
+ const payload = await fetchProviderJson(
1926
+ VERCEL_AI_GATEWAY_CREDITS_URL,
1927
+ auth,
1928
+ signal,
1929
+ remainingTimeout(timeoutMs, startedAt, "fetching Vercel AI Gateway credits"),
1930
+ "Vercel AI Gateway credits endpoint",
1931
+ { redirect: "error" }
1932
+ );
1933
+ await guard();
1934
+ return normalizeVercelAIGatewayCreditsPayload(payload, Date.now());
1935
+ }
1936
+ },
1490
1937
  {
1491
1938
  id: "fireworks",
1492
1939
  displayName: "Fireworks",
@@ -1547,39 +1994,52 @@ var SUPPORTED_ADAPTERS = [
1547
1994
  return normalizeKimiCodingUsagePayload(payload, Date.now());
1548
1995
  }
1549
1996
  },
1997
+ {
1998
+ id: "minimax",
1999
+ displayName: "MiniMax",
2000
+ semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
2001
+ async query(auth, signal, timeoutMs, guard) {
2002
+ return queryMiniMaxUsage("minimax", auth, signal, timeoutMs, guard);
2003
+ }
2004
+ },
2005
+ {
2006
+ id: "minimax-cn",
2007
+ displayName: "MiniMax CN",
2008
+ semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
2009
+ async query(auth, signal, timeoutMs, guard) {
2010
+ return queryMiniMaxUsage("minimax-cn", auth, signal, timeoutMs, guard);
2011
+ }
2012
+ },
2013
+ {
2014
+ id: "moonshotai",
2015
+ displayName: "Moonshot AI",
2016
+ semantics: { kind: "api-key", label: "Moonshot API account balance" },
2017
+ async query(auth, signal, timeoutMs, guard) {
2018
+ return queryMoonshotBalance("moonshotai", auth, signal, timeoutMs, guard);
2019
+ }
2020
+ },
2021
+ {
2022
+ id: "moonshotai-cn",
2023
+ displayName: "Moonshot AI CN",
2024
+ semantics: { kind: "api-key", label: "Moonshot API account balance" },
2025
+ async query(auth, signal, timeoutMs, guard) {
2026
+ return queryMoonshotBalance("moonshotai-cn", auth, signal, timeoutMs, guard);
2027
+ }
2028
+ },
1550
2029
  {
1551
2030
  id: "zai",
1552
2031
  displayName: "Z.AI",
1553
2032
  semantics: { kind: "consumer-subscription", label: "GLM Coding Plan usage" },
1554
- async query(auth, signal, timeoutMs) {
1555
- const payload = await fetchProviderJson(
1556
- zaiMonitorUrl(auth.model.baseUrl),
1557
- zaiMonitorAuth(auth),
1558
- signal,
1559
- timeoutMs,
1560
- "Z.AI quota endpoint"
1561
- );
1562
- return normalizeZaiQuotaPayload("zai", "Z.AI", payload, Date.now());
2033
+ async query(auth, signal, timeoutMs, guard) {
2034
+ return queryZaiUsage("zai", "Z.AI", auth, signal, timeoutMs, guard);
1563
2035
  }
1564
2036
  },
1565
2037
  {
1566
2038
  id: "zai-coding-cn",
1567
2039
  displayName: "Z.AI Coding CN",
1568
2040
  semantics: { kind: "consumer-subscription", label: "GLM Coding Plan usage" },
1569
- async query(auth, signal, timeoutMs) {
1570
- const payload = await fetchProviderJson(
1571
- zaiMonitorUrl(auth.model.baseUrl),
1572
- zaiMonitorAuth(auth),
1573
- signal,
1574
- timeoutMs,
1575
- "Z.AI Coding CN quota endpoint"
1576
- );
1577
- return normalizeZaiQuotaPayload(
1578
- "zai-coding-cn",
1579
- "Z.AI Coding CN",
1580
- payload,
1581
- Date.now()
1582
- );
2041
+ async query(auth, signal, timeoutMs, guard) {
2042
+ return queryZaiUsage("zai-coding-cn", "Z.AI Coding CN", auth, signal, timeoutMs, guard);
1583
2043
  }
1584
2044
  }
1585
2045
  ];
@@ -1655,17 +2115,20 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
1655
2115
  if (!result.ok) throw new Error(redactUsageError(result.error));
1656
2116
  return authorizationFrom(result) ? result : void 0;
1657
2117
  };
1658
- if (adapter.id !== "deepseek") modelAuth = await resolveCurrentModelAuth();
2118
+ const resolveSelectedAuthLast = ["deepseek", "minimax", "minimax-cn"].includes(adapter.id);
2119
+ if (!resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
1659
2120
  if (typeof registry.getProviderAuth !== "function") {
1660
2121
  throw new Error("pi-usage requires Pi 0.81.0 or newer to validate resolved provider auth.");
1661
2122
  }
2123
+ if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
1662
2124
  const providerResult = await registry.getProviderAuth(adapter.id);
2125
+ if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
1663
2126
  if (providerResult?.auth.baseUrl && !hasOfficialUrlOrigin(providerResult.auth.baseUrl, adapter.id)) {
1664
2127
  throw new Error(
1665
2128
  `${adapter.displayName} usage cannot send a proxy-resolved credential to the official usage endpoint.`
1666
2129
  );
1667
2130
  }
1668
- if (adapter.id === "deepseek") modelAuth = await resolveCurrentModelAuth();
2131
+ if (resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
1669
2132
  const auth = modelAuth ?? providerResult?.auth;
1670
2133
  if (!auth) return void 0;
1671
2134
  if (adapter.id === "github-copilot") {
@@ -1730,11 +2193,30 @@ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard, setti
1730
2193
  }
1731
2194
  function providerIsConfigured(ctx, providerId) {
1732
2195
  try {
1733
- return ctx.modelRegistry.getProviderAuthStatus(providerId).configured;
2196
+ const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
2197
+ return status.configured && moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
1734
2198
  } catch {
1735
- return candidateModels(ctx, providerId).length > 0;
2199
+ return !isMoonshotSiblingProvider(ctx, providerId) && candidateModels(ctx, providerId).length > 0;
1736
2200
  }
1737
2201
  }
2202
+ function moonshotProviderAuthIsAllowed(ctx, providerId) {
2203
+ if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
2204
+ try {
2205
+ const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
2206
+ return moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
2207
+ } catch {
2208
+ return false;
2209
+ }
2210
+ }
2211
+ function moonshotProviderAuthSourceIsAllowed(ctx, providerId, source, label) {
2212
+ if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
2213
+ if (source === void 0) return false;
2214
+ if (source !== "environment") return true;
2215
+ return label !== void 0 && !label.split(",").map((name) => name.trim()).includes(SHARED_MOONSHOT_ENV_VAR);
2216
+ }
2217
+ function isMoonshotSiblingProvider(ctx, providerId) {
2218
+ return (providerId === "moonshotai" || providerId === "moonshotai-cn") && ctx.model?.provider !== providerId;
2219
+ }
1738
2220
  function candidateModels(ctx, providerId) {
1739
2221
  const candidates = [];
1740
2222
  const seen = /* @__PURE__ */ new Set();
@@ -1863,7 +2345,7 @@ function resolveXaiUsageAuth(auth, model, salt, candidates) {
1863
2345
  const matches = [];
1864
2346
  for (const candidate of candidates) {
1865
2347
  try {
1866
- const credential = asObject9(candidate);
2348
+ const credential = asObject12(candidate);
1867
2349
  if (credential?.type !== "oauth") continue;
1868
2350
  sawOAuth = true;
1869
2351
  if (credential.access !== resolvedAccess) continue;
@@ -1917,7 +2399,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
1917
2399
  const matches = /* @__PURE__ */ new Map();
1918
2400
  for (const candidate of candidates) {
1919
2401
  try {
1920
- const credential = asObject9(candidate);
2402
+ const credential = asObject12(candidate);
1921
2403
  if (credential?.type !== "oauth") continue;
1922
2404
  sawOAuth = true;
1923
2405
  const storedAccess2 = typeof credential.access === "string" && credential.access ? credential.access : void 0;
@@ -1979,7 +2461,7 @@ function bearerToken(authorization) {
1979
2461
  const match = /^Bearer\s+(.+)$/iu.exec(authorization ?? "");
1980
2462
  return match?.[1];
1981
2463
  }
1982
- function asObject9(value) {
2464
+ function asObject12(value) {
1983
2465
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1984
2466
  return value;
1985
2467
  }
@@ -1997,12 +2479,20 @@ function hasOfficialOrigin(model, providerId) {
1997
2479
  function hasOfficialUrlOrigin(value, providerId) {
1998
2480
  try {
1999
2481
  const url = new URL(value);
2482
+ if (providerId === "baseten") {
2483
+ return ["https://inference.baseten.co", "https://api.baseten.co"].includes(url.origin);
2484
+ }
2000
2485
  if (providerId === "openai-codex") return url.origin === "https://chatgpt.com";
2001
2486
  if (providerId === "deepseek") return url.origin === "https://api.deepseek.com";
2002
2487
  if (providerId === "fireworks") return url.origin === FIREWORKS_BILLING_SUMMARY_ORIGIN;
2003
2488
  if (providerId === "openrouter") return url.origin === "https://openrouter.ai";
2489
+ if (providerId === "vercel-ai-gateway") return url.origin === "https://ai-gateway.vercel.sh";
2004
2490
  if (providerId === "opencode-go") return url.origin === "https://opencode.ai";
2005
2491
  if (providerId === "kimi-coding") return url.origin === "https://api.kimi.com";
2492
+ if (providerId === "minimax") return url.origin === "https://api.minimax.io";
2493
+ if (providerId === "minimax-cn") return url.origin === "https://api.minimaxi.com";
2494
+ if (providerId === "moonshotai") return url.origin === "https://api.moonshot.ai";
2495
+ if (providerId === "moonshotai-cn") return url.origin === "https://api.moonshot.cn";
2006
2496
  if (providerId === "xai") return url.origin === "https://api.x.ai";
2007
2497
  if (providerId === "zai") return url.origin === "https://api.z.ai";
2008
2498
  if (providerId === "zai-coding-cn") return url.origin === "https://open.bigmodel.cn";
@@ -2029,6 +2519,49 @@ function validatedXaiUserId(value) {
2029
2519
  }
2030
2520
  return value;
2031
2521
  }
2522
+ function basetenBillingUsageUrl(windowAt) {
2523
+ const url = new URL(BASETEN_BILLING_USAGE_URL);
2524
+ url.searchParams.set(
2525
+ "start_date",
2526
+ new Date(windowAt - BASETEN_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3).toISOString()
2527
+ );
2528
+ url.searchParams.set("end_date", new Date(windowAt).toISOString());
2529
+ return url.toString();
2530
+ }
2531
+ async function queryMiniMaxUsage(providerId, auth, signal, timeoutMs, guard) {
2532
+ if (!guard) throw new Error("MiniMax usage requires request-boundary revalidation.");
2533
+ const apiKey = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
2534
+ if (!apiKey) throw new Error("MiniMax runtime API key was unavailable.");
2535
+ const kind = miniMaxUsageKind(apiKey);
2536
+ const path = kind === "account-balance" ? "/account/query_balance" : "/v1/token_plan/remains";
2537
+ const startedAt = Date.now();
2538
+ await guard();
2539
+ const payload = await fetchProviderJson(
2540
+ `${MINIMAX_API_ROOTS[providerId]}${path}`,
2541
+ auth,
2542
+ signal,
2543
+ remainingTimeout(timeoutMs, startedAt, "fetching MiniMax usage"),
2544
+ "MiniMax usage endpoint",
2545
+ { redirect: "error" }
2546
+ );
2547
+ await guard();
2548
+ return normalizeMiniMaxUsagePayload(providerId, kind, payload, Date.now());
2549
+ }
2550
+ async function queryMoonshotBalance(providerId, auth, signal, timeoutMs, guard) {
2551
+ if (!guard) throw new Error("Moonshot AI balance requires request-boundary revalidation.");
2552
+ const startedAt = Date.now();
2553
+ await guard();
2554
+ const payload = await fetchProviderJson(
2555
+ MOONSHOT_BALANCE_URLS[providerId],
2556
+ auth,
2557
+ signal,
2558
+ remainingTimeout(timeoutMs, startedAt, "fetching Moonshot AI balance"),
2559
+ "Moonshot AI balance endpoint",
2560
+ { redirect: "error" }
2561
+ );
2562
+ await guard();
2563
+ return normalizeMoonshotBalancePayload(providerId, payload, Date.now());
2564
+ }
2032
2565
  function remainingTimeout(timeoutMs, startedAt, description = "fetching xAI consumer usage") {
2033
2566
  const remaining = timeoutMs - (Date.now() - startedAt);
2034
2567
  if (remaining <= 0) throw new Error(`Timed out while ${description}.`);
@@ -2110,10 +2643,13 @@ function fireworksBillingSummaryUrl(accountId, startedAt) {
2110
2643
  url.searchParams.set("endTime", dayFloor(startedAt + dayMs));
2111
2644
  return url.toString();
2112
2645
  }
2113
- function zaiMonitorUrl(baseUrl) {
2646
+ function zaiOrigin(baseUrl) {
2114
2647
  const base = baseUrl?.trim();
2115
2648
  if (!base) throw new Error("Z.AI model base URL is unavailable.");
2116
- return `${new URL(base).origin}/api/monitor/usage/quota/limit`;
2649
+ return new URL(base).origin;
2650
+ }
2651
+ function zaiMonitorUrl(baseUrl) {
2652
+ return `${zaiOrigin(baseUrl)}/api/monitor/usage/quota/limit`;
2117
2653
  }
2118
2654
  function zaiMonitorAuth(auth) {
2119
2655
  const authorization = headerValue(auth.headers, "Authorization");
@@ -2121,6 +2657,38 @@ function zaiMonitorAuth(auth) {
2121
2657
  if (token === void 0 || token === authorization) return auth;
2122
2658
  return { ...auth, headers: { ...auth.headers, Authorization: token } };
2123
2659
  }
2660
+ async function queryZaiUsage(providerId, providerName, auth, signal, timeoutMs, guard) {
2661
+ if (!guard) throw new Error("Z.AI usage requires request-boundary revalidation.");
2662
+ const startedAt = Date.now();
2663
+ await guard();
2664
+ const payload = await fetchProviderJson(
2665
+ zaiMonitorUrl(auth.model.baseUrl),
2666
+ zaiMonitorAuth(auth),
2667
+ signal,
2668
+ remainingTimeout(timeoutMs, startedAt, `fetching ${providerName} quota`),
2669
+ `${providerName} quota endpoint`
2670
+ );
2671
+ await guard();
2672
+ const planTimeoutMs = timeoutMs - (Date.now() - startedAt);
2673
+ const plan = await fetchZaiPlan(providerName, auth, signal, planTimeoutMs);
2674
+ return normalizeZaiQuotaPayload(providerId, providerName, payload, Date.now(), plan);
2675
+ }
2676
+ async function fetchZaiPlan(providerName, auth, signal, timeoutMs) {
2677
+ if (timeoutMs <= 0 || signal.aborted) return void 0;
2678
+ try {
2679
+ const payload = await fetchProviderJson(
2680
+ `${zaiOrigin(auth.model.baseUrl)}/api/biz/subscription/list`,
2681
+ zaiMonitorAuth(auth),
2682
+ signal,
2683
+ timeoutMs,
2684
+ `${providerName} plan endpoint`
2685
+ );
2686
+ return normalizeZaiSubscriptionPayload(payload);
2687
+ } catch (error) {
2688
+ if (isAbortError(error)) throw error;
2689
+ return void 0;
2690
+ }
2691
+ }
2124
2692
  function isAbortError(error) {
2125
2693
  return error instanceof Error && error.name === "AbortError";
2126
2694
  }
@@ -2130,12 +2698,12 @@ var CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-r
2130
2698
  var CODEX_RESET_CONSUME_URL = `${CODEX_RESET_CREDITS_URL}/consume`;
2131
2699
  var MAX_RESET_OPTIONS = 32;
2132
2700
  var MAX_CREDIT_ID_CHARS = 1024;
2133
- function codexResetCount(report) {
2134
- const value = report.metrics.find((metric) => metric.id === "reset-credits")?.value;
2701
+ function codexResetCount(report2) {
2702
+ const value = report2.metrics.find((metric2) => metric2.id === "reset-credits")?.value;
2135
2703
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
2136
2704
  }
2137
- function codexResetActionDescription(report) {
2138
- const count = codexResetCount(report);
2705
+ function codexResetActionDescription(report2) {
2706
+ const count = codexResetCount(report2);
2139
2707
  if (count === void 0) return "Check reset availability.";
2140
2708
  if (count === 0) return "No usage limit resets available.";
2141
2709
  return `You have ${count} ${resetLabel(count)} available.`;
@@ -2248,14 +2816,14 @@ async function consumeCodexResetCredit(auth, option, redeemRequestId, signal, ti
2248
2816
  if (!isCodexResetOutcomeCode(code)) {
2249
2817
  throw new Error("Codex reset consume endpoint returned an unknown outcome code.");
2250
2818
  }
2251
- const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger(payload.windows_reset);
2819
+ const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger2(payload.windows_reset);
2252
2820
  if (windowsReset === void 0) {
2253
2821
  throw new Error("Codex reset consume endpoint returned an invalid windows_reset value.");
2254
2822
  }
2255
2823
  return { code, windowsReset };
2256
2824
  }
2257
2825
  function normalizeCodexResetCreditsPayload(payload) {
2258
- const availableCount = nonnegativeInteger(payload.available_count);
2826
+ const availableCount = nonnegativeInteger2(payload.available_count);
2259
2827
  if (availableCount === void 0) {
2260
2828
  throw new Error("Codex reset credits response returned an invalid available_count.");
2261
2829
  }
@@ -2263,7 +2831,7 @@ function normalizeCodexResetCreditsPayload(payload) {
2263
2831
  if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
2264
2832
  throw new Error("Codex reset credits response returned invalid credits.");
2265
2833
  }
2266
- const options = (rawCredits ?? []).map(asObject10).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
2834
+ const options = (rawCredits ?? []).map(asObject13).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
2267
2835
  (left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
2268
2836
  ).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
2269
2837
  if (availableCount > 0 && options.length === 0) {
@@ -2278,7 +2846,7 @@ function selectCodexResetCredential(candidates, resolvedAccess, resolvedAccountI
2278
2846
  const matches = /* @__PURE__ */ new Map();
2279
2847
  for (const candidate of candidates) {
2280
2848
  try {
2281
- const credential = asObject10(candidate);
2849
+ const credential = asObject13(candidate);
2282
2850
  if (credential?.type !== "oauth") continue;
2283
2851
  sawOAuth = true;
2284
2852
  const storedAccess = asNonemptyString(credential.access);
@@ -2317,7 +2885,7 @@ function codexAccountIdFromAccessToken(access) {
2317
2885
  const parts = access.split(".");
2318
2886
  if (parts.length !== 3 || !parts[1]) return void 0;
2319
2887
  const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
2320
- const claims = asObject10(asObject10(payload)?.["https://api.openai.com/auth"]);
2888
+ const claims = asObject13(asObject13(payload)?.["https://api.openai.com/auth"]);
2321
2889
  return validHeaderValue(claims?.chatgpt_account_id);
2322
2890
  } catch {
2323
2891
  return void 0;
@@ -2349,7 +2917,7 @@ function normalizeResetOption(credit) {
2349
2917
  function isCodexResetOutcomeCode(value) {
2350
2918
  return value === "reset" || value === "nothing_to_reset" || value === "no_credit" || value === "already_redeemed";
2351
2919
  }
2352
- function asObject10(value) {
2920
+ function asObject13(value) {
2353
2921
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
2354
2922
  return value;
2355
2923
  }
@@ -2371,7 +2939,7 @@ function validHeaderValue(value) {
2371
2939
  if (/[^\x20-\x7e]/u.test(value)) return void 0;
2372
2940
  return value;
2373
2941
  }
2374
- function nonnegativeInteger(value) {
2942
+ function nonnegativeInteger2(value) {
2375
2943
  const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
2376
2944
  if (!Number.isSafeInteger(parsed) || parsed < 0) return void 0;
2377
2945
  return parsed;
@@ -2388,45 +2956,59 @@ function headerValue2(headers, name) {
2388
2956
  // src/format.ts
2389
2957
  var BAR_SEGMENTS = 20;
2390
2958
  var VALUE_COLUMN = 29;
2391
- function formatUsageReport(report, displayState) {
2959
+ function formatUsageReport(report2, displayState) {
2392
2960
  const stateLabel = displayState === "current" ? "Current" : "Configured";
2393
- const title = report.providerId === "deepseek" ? "DeepSeek API Balance" : report.providerId === "fireworks" ? "Fireworks API Spend" : `${report.providerName} Usage`;
2961
+ 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`;
2394
2962
  const lines = [`${title} \xB7 ${stateLabel}`];
2395
- if (report.accountLabel) lines.push(`Account: ${report.accountLabel}`);
2396
- lines.push(`Semantics: ${report.semantics.label}`, "");
2397
- if (report.providerId === "openai-codex") formatCodexReport(lines, report);
2398
- else if (report.providerId === "deepseek") formatDeepSeekReport(lines, report);
2399
- else if (report.providerId === "fireworks") formatFireworksReport(lines, report);
2400
- else if (report.providerId === "github-copilot") formatGitHubCopilotReport(lines, report);
2401
- else if (report.providerId === "openrouter") formatOpenRouterReport(lines, report);
2402
- else if (report.providerId === "opencode-go") formatOpenCodeZenReport(lines, report);
2403
- else if (report.providerId === "kimi-coding") formatKimiCodingReport(lines, report);
2404
- else if (report.providerId === "xai") formatXaiReport(lines, report);
2405
- else if (report.providerId === "zai" || report.providerId === "zai-coding-cn") {
2406
- formatZaiReport(lines, report);
2407
- } else formatGenericReport(lines, report);
2408
- if (report.notes) {
2409
- for (const note of report.notes) lines.push(note);
2963
+ if (report2.accountLabel) lines.push(`Account: ${report2.accountLabel}`);
2964
+ lines.push(`Semantics: ${report2.semantics.label}`, "");
2965
+ if (report2.providerId === "baseten") formatBasetenReport(lines, report2);
2966
+ else if (report2.providerId === "openai-codex") formatCodexReport(lines, report2);
2967
+ else if (report2.providerId === "deepseek") formatDeepSeekReport(lines, report2);
2968
+ else if (report2.providerId === "fireworks") formatFireworksReport(lines, report2);
2969
+ else if (report2.providerId === "vercel-ai-gateway") formatVercelAIGatewayReport(lines, report2);
2970
+ else if (report2.providerId === "github-copilot") formatGitHubCopilotReport(lines, report2);
2971
+ else if (report2.providerId === "openrouter") formatOpenRouterReport(lines, report2);
2972
+ else if (report2.providerId === "opencode-go") formatOpenCodeZenReport(lines, report2);
2973
+ else if (report2.providerId === "kimi-coding") formatKimiCodingReport(lines, report2);
2974
+ else if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
2975
+ formatMoonshotReport(lines, report2);
2976
+ } else if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
2977
+ formatMiniMaxReport(lines, report2);
2978
+ } else if (report2.providerId === "xai") formatXaiReport(lines, report2);
2979
+ else if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
2980
+ formatZaiReport(lines, report2);
2981
+ } else formatGenericReport(lines, report2);
2982
+ if (report2.notes) {
2983
+ for (const note of report2.notes) lines.push(note);
2410
2984
  }
2411
2985
  return lines.join("\n").trimEnd();
2412
2986
  }
2413
- function formatUsageStatusline(report, model, now = Date.now(), showCodexResetCountdown = true) {
2414
- if (report.providerId === "openai-codex") {
2415
- return formatCodexStatusline(report, model, now, showCodexResetCountdown);
2416
- }
2417
- if (report.providerId === "deepseek") return formatDeepSeekStatusline(report);
2418
- if (report.providerId === "fireworks") return formatFireworksStatusline(report);
2419
- if (report.providerId === "github-copilot") return formatGitHubCopilotStatusline(report);
2420
- if (report.providerId === "openrouter") {
2421
- const limit = report.buckets.find((bucket) => bucket.id === "key-limit");
2987
+ function formatUsageStatusline(report2, model, now = Date.now(), showCodexResetCountdown = true) {
2988
+ if (report2.providerId === "baseten") return formatBasetenStatusline(report2);
2989
+ if (report2.providerId === "openai-codex") {
2990
+ return formatCodexStatusline(report2, model, now, showCodexResetCountdown);
2991
+ }
2992
+ if (report2.providerId === "deepseek") return formatDeepSeekStatusline(report2);
2993
+ if (report2.providerId === "fireworks") return formatFireworksStatusline(report2);
2994
+ if (report2.providerId === "vercel-ai-gateway") return formatVercelAIGatewayStatusline(report2);
2995
+ if (report2.providerId === "github-copilot") return formatGitHubCopilotStatusline(report2);
2996
+ if (report2.providerId === "openrouter") {
2997
+ const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
2422
2998
  if (limit?.remaining !== void 0) return `openrouter ${formatUsd(limit.remaining)} left`;
2423
- const total = report.metrics.find((metric) => metric.id === "usage-total");
2999
+ const total = report2.metrics.find((metric2) => metric2.id === "usage-total");
2424
3000
  if (typeof total?.value === "number") return `openrouter ${formatUsd(total.value)} used`;
2425
3001
  }
2426
- if (report.providerId === "opencode-go") return formatOpenCodeZenStatusline(report);
2427
- if (report.providerId === "kimi-coding") return formatKimiCodingStatusline(report);
2428
- if (report.providerId === "zai" || report.providerId === "zai-coding-cn") {
2429
- return formatZaiStatusline(report);
3002
+ if (report2.providerId === "opencode-go") return formatOpenCodeZenStatusline(report2);
3003
+ if (report2.providerId === "kimi-coding") return formatKimiCodingStatusline(report2);
3004
+ if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
3005
+ return formatMoonshotStatusline(report2);
3006
+ }
3007
+ if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
3008
+ return formatMiniMaxStatusline(report2, model);
3009
+ }
3010
+ if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
3011
+ return formatZaiStatusline(report2);
2430
3012
  }
2431
3013
  return void 0;
2432
3014
  }
@@ -2439,9 +3021,19 @@ function formatProviderStates(states) {
2439
3021
  ${status}: ${state.message}`;
2440
3022
  }).join("\n\n");
2441
3023
  }
2442
- function formatCodexReport(lines, report) {
3024
+ function formatBasetenReport(lines, report2) {
3025
+ lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days`);
3026
+ for (const metric2 of report2.metrics) {
3027
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
3028
+ }
3029
+ }
3030
+ function formatBasetenStatusline(report2) {
3031
+ const subtotal = report2.metrics.find((metric2) => metric2.id === "net-subtotal");
3032
+ return subtotal ? `baseten USD ${subtotal.value} net` : "baseten no Model APIs usage";
3033
+ }
3034
+ function formatCodexReport(lines, report2) {
2443
3035
  let previousGroup;
2444
- for (const bucket of report.buckets) {
3036
+ for (const bucket of report2.buckets) {
2445
3037
  const group = bucket.groupId ?? bucket.id;
2446
3038
  if (group !== previousGroup && group !== "codex") {
2447
3039
  lines.push(`${bucket.groupLabel ?? group} limit:`);
@@ -2451,66 +3043,75 @@ function formatCodexReport(lines, report) {
2451
3043
  const label = `${formatWindowLabel(bucket.windowMinutes, fallback, false)} limit:`;
2452
3044
  lines.push(`${label.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
2453
3045
  }
2454
- for (const metric of report.metrics) {
2455
- if (metric.id === "reset-credits") {
2456
- lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric.value} available`);
2457
- } else if (metric.id === "credits") {
3046
+ for (const metric2 of report2.metrics) {
3047
+ if (metric2.id === "reset-credits") {
3048
+ lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
3049
+ } else if (metric2.id === "credits") {
2458
3050
  lines.push(
2459
- `${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3051
+ `${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2460
3052
  );
2461
3053
  }
2462
3054
  }
2463
3055
  }
2464
- function formatDeepSeekReport(lines, report) {
2465
- const availability = report.metrics.find((metric) => metric.id === "api-availability");
3056
+ function formatDeepSeekReport(lines, report2) {
3057
+ const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
2466
3058
  lines.push(
2467
3059
  `${"API calls:".padEnd(VALUE_COLUMN)}${availability?.value === "available" ? "Available" : "Unavailable"}`
2468
3060
  );
2469
3061
  for (const currency of ["CNY", "USD"]) {
2470
- const metrics = report.metrics.filter((metric) => metric.currency === currency);
3062
+ const metrics = report2.metrics.filter((metric2) => metric2.currency === currency);
2471
3063
  if (metrics.length === 0) continue;
2472
3064
  lines.push("", `${currency} balance:`);
2473
- for (const metric of metrics) {
2474
- lines.push(`${`${metric.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric.value}`);
3065
+ for (const metric2 of metrics) {
3066
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
2475
3067
  }
2476
3068
  }
2477
3069
  }
2478
- function formatDeepSeekStatusline(report) {
2479
- const availability = report.metrics.find((metric) => metric.id === "api-availability");
3070
+ function formatDeepSeekStatusline(report2) {
3071
+ const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
2480
3072
  if (availability?.value !== "available") return "deepseek API unavailable";
2481
3073
  const totals = ["CNY", "USD"].flatMap((currency) => {
2482
- const metric = report.metrics.find(
3074
+ const metric2 = report2.metrics.find(
2483
3075
  (candidate) => candidate.id === `${currency.toLowerCase()}-total`
2484
3076
  );
2485
- return metric ? [`${currency} ${metric.value}`] : [];
3077
+ return metric2 ? [`${currency} ${metric2.value}`] : [];
2486
3078
  });
2487
3079
  return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
2488
3080
  }
2489
- function formatFireworksReport(lines, report) {
3081
+ function formatFireworksReport(lines, report2) {
2490
3082
  lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days (rated)`);
2491
- for (const currency of fireworksCurrencies(report)) {
3083
+ for (const currency of fireworksCurrencies(report2)) {
2492
3084
  lines.push("", `${currency} rated spend:`);
2493
- for (const metric of report.metrics) {
2494
- if (metric.currency !== currency) continue;
2495
- lines.push(`${`${metric.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric.value}`);
3085
+ for (const metric2 of report2.metrics) {
3086
+ if (metric2.currency !== currency) continue;
3087
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
2496
3088
  }
2497
3089
  }
2498
3090
  }
2499
- function formatFireworksStatusline(report) {
2500
- const totals = report.metrics.filter((metric) => metric.id.endsWith("-total"));
3091
+ function formatFireworksStatusline(report2) {
3092
+ const totals = report2.metrics.filter((metric2) => metric2.id.endsWith("-total"));
2501
3093
  if (totals.length === 0) return "fireworks no rated usage";
2502
- return `fireworks ${totals.map((metric) => `${metric.currency} ${metric.value}`).join(" \xB7 ")}`;
3094
+ return `fireworks ${totals.map((metric2) => `${metric2.currency} ${metric2.value}`).join(" \xB7 ")}`;
2503
3095
  }
2504
- function fireworksCurrencies(report) {
3096
+ function fireworksCurrencies(report2) {
2505
3097
  const currencies = [];
2506
- for (const metric of report.metrics) {
2507
- if (!metric.currency || currencies.includes(metric.currency)) continue;
2508
- currencies.push(metric.currency);
3098
+ for (const metric2 of report2.metrics) {
3099
+ if (!metric2.currency || currencies.includes(metric2.currency)) continue;
3100
+ currencies.push(metric2.currency);
2509
3101
  }
2510
3102
  return currencies;
2511
3103
  }
2512
- function formatGitHubCopilotReport(lines, report) {
2513
- const quota = findGitHubCopilotQuota(report);
3104
+ function formatVercelAIGatewayReport(lines, report2) {
3105
+ for (const metric2 of report2.metrics) {
3106
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
3107
+ }
3108
+ }
3109
+ function formatVercelAIGatewayStatusline(report2) {
3110
+ const balance = report2.metrics.find((metric2) => metric2.id === "credit-balance");
3111
+ return balance ? `vercel USD ${balance.value} left` : "vercel credits unavailable";
3112
+ }
3113
+ function formatGitHubCopilotReport(lines, report2) {
3114
+ const quota = findGitHubCopilotQuota(report2);
2514
3115
  if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
2515
3116
  lines.push(`${`${quota?.label ?? "Copilot quota"}:`.padEnd(VALUE_COLUMN)}unlimited`);
2516
3117
  return;
@@ -2520,23 +3121,23 @@ function formatGitHubCopilotReport(lines, report) {
2520
3121
  lines.push(
2521
3122
  `${`${quota.label}:`.padEnd(VALUE_COLUMN)}${quota.remaining} of ${quota.limit} left \xB7 ${percent}%${reset}`
2522
3123
  );
2523
- const overage = report.metrics.find((metric) => metric.id === "overage-used");
3124
+ const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
2524
3125
  if (typeof overage?.value === "number" && overage.value > 0) {
2525
3126
  lines.push(`${"Additional usage:".padEnd(VALUE_COLUMN)}${overage.value} ${quota.label}`);
2526
3127
  }
2527
3128
  }
2528
- function formatGitHubCopilotStatusline(report) {
2529
- const quota = findGitHubCopilotQuota(report);
3129
+ function formatGitHubCopilotStatusline(report2) {
3130
+ const quota = findGitHubCopilotQuota(report2);
2530
3131
  const kind = compactGitHubCopilotQuotaKind(quota);
2531
3132
  if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
2532
3133
  return `copilot ${kind} unlimited`;
2533
3134
  }
2534
- const overage = report.metrics.find((metric) => metric.id === "overage-used");
3135
+ const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
2535
3136
  const overageSuffix = typeof overage?.value === "number" && overage.value > 0 ? ` +${overage.value} over` : "";
2536
3137
  return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
2537
3138
  }
2538
- function findGitHubCopilotQuota(report) {
2539
- return report.buckets.find(
3139
+ function findGitHubCopilotQuota(report2) {
3140
+ return report2.buckets.find(
2540
3141
  (bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
2541
3142
  );
2542
3143
  }
@@ -2549,37 +3150,41 @@ function percentRemaining(bucket) {
2549
3150
  if (!bucket.limit || bucket.remaining === void 0) return 0;
2550
3151
  return Math.round(clampPercent4(bucket.remaining / bucket.limit * 100));
2551
3152
  }
2552
- function formatOpenRouterReport(lines, report) {
2553
- const limit = report.buckets.find((bucket) => bucket.id === "key-limit");
3153
+ function formatOpenRouterReport(lines, report2) {
3154
+ const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
2554
3155
  if (limit) {
2555
3156
  const period = limit.period ? ` (${limit.period})` : "";
2556
3157
  const value = limit.remaining === void 0 ? `${formatUsd(limit.limit ?? 0)} cap; remaining unavailable` : `${formatUsd(limit.remaining)} of ${formatUsd(limit.limit ?? 0)} left`;
2557
3158
  lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
2558
3159
  }
2559
- for (const metric of report.metrics) {
3160
+ for (const metric2 of report2.metrics) {
2560
3161
  lines.push(
2561
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3162
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2562
3163
  );
2563
3164
  }
2564
3165
  }
2565
- function formatOpenCodeZenReport(lines, report) {
2566
- for (const bucket of report.buckets) {
3166
+ function formatOpenCodeZenReport(lines, report2) {
3167
+ for (const bucket of report2.buckets) {
3168
+ if (bucket.unit === "percent" && bucket.used !== void 0) {
3169
+ lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
3170
+ continue;
3171
+ }
2567
3172
  const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2568
3173
  const used = bucket.used ?? "unavailable";
2569
3174
  lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${used}% used${reset}`);
2570
3175
  }
2571
3176
  }
2572
- function formatOpenCodeZenStatusline(report) {
3177
+ function formatOpenCodeZenStatusline(report2) {
2573
3178
  const parts = ["zen"];
2574
- for (const bucket of report.buckets) {
3179
+ for (const bucket of report2.buckets) {
2575
3180
  if (bucket.used === void 0) continue;
2576
3181
  const compact = bucket.id === "rolling" ? "r" : bucket.id === "weekly" ? "w" : "m";
2577
3182
  parts.push(`${clampPercent4(bucket.used).toFixed(0)}% ${compact}`);
2578
3183
  }
2579
3184
  return parts.length > 1 ? parts.join(" ") : void 0;
2580
3185
  }
2581
- function formatKimiCodingReport(lines, report) {
2582
- for (const bucket of report.buckets) {
3186
+ function formatKimiCodingReport(lines, report2) {
3187
+ for (const bucket of report2.buckets) {
2583
3188
  const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2584
3189
  if (bucket.used === void 0 || bucket.limit === void 0) {
2585
3190
  lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}unavailable${reset}`);
@@ -2589,10 +3194,10 @@ function formatKimiCodingReport(lines, report) {
2589
3194
  `${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${bucket.used} of ${bucket.limit} used \xB7 ${percentRemaining(bucket)}% left${reset}`
2590
3195
  );
2591
3196
  }
2592
- const balance = report.metrics.find((metric) => metric.id === "booster-balance");
2593
- const total = report.metrics.find((metric) => metric.id === "booster-total");
2594
- const monthlyUsed = report.metrics.find((metric) => metric.id === "booster-monthly-used");
2595
- const monthlyLimit = report.metrics.find((metric) => metric.id === "booster-monthly-limit");
3197
+ const balance = report2.metrics.find((metric2) => metric2.id === "booster-balance");
3198
+ const total = report2.metrics.find((metric2) => metric2.id === "booster-total");
3199
+ const monthlyUsed = report2.metrics.find((metric2) => metric2.id === "booster-monthly-used");
3200
+ const monthlyLimit = report2.metrics.find((metric2) => metric2.id === "booster-monthly-limit");
2596
3201
  if (!balance && !monthlyUsed && !monthlyLimit) return;
2597
3202
  lines.push("", "Extra usage wallet:");
2598
3203
  if (balance) {
@@ -2606,10 +3211,10 @@ function formatKimiCodingReport(lines, report) {
2606
3211
  lines.push(`${"Monthly limit:".padEnd(VALUE_COLUMN)}${formatCurrencyMetric(monthlyLimit)}`);
2607
3212
  }
2608
3213
  }
2609
- function formatKimiCodingStatusline(report) {
2610
- const fiveHour = report.buckets.find((bucket) => bucket.id === "five-hour");
2611
- const weekly = report.buckets.find((bucket) => bucket.id === "weekly");
2612
- const subWindow = fiveHour ?? report.buckets.find((bucket) => bucket.id !== "weekly");
3214
+ function formatKimiCodingStatusline(report2) {
3215
+ const fiveHour = report2.buckets.find((bucket) => bucket.id === "five-hour");
3216
+ const weekly = report2.buckets.find((bucket) => bucket.id === "weekly");
3217
+ const subWindow = fiveHour ?? report2.buckets.find((bucket) => bucket.id !== "weekly");
2613
3218
  const selected = [subWindow, weekly].filter(
2614
3219
  (bucket, index, buckets) => bucket !== void 0 && buckets.indexOf(bucket) === index
2615
3220
  );
@@ -2623,10 +3228,98 @@ function formatKimiCodingStatusline(report) {
2623
3228
  }
2624
3229
  return parts.length > 1 ? parts.join(" ") : void 0;
2625
3230
  }
2626
- function formatZaiStatusline(report) {
3231
+ function formatMoonshotReport(lines, report2) {
3232
+ for (const metric2 of report2.metrics) {
3233
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
3234
+ }
3235
+ }
3236
+ function formatMoonshotStatusline(report2) {
3237
+ const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
3238
+ if (!available) return "moonshot balance unavailable";
3239
+ return `moonshot ${available.currency ?? ""} ${available.value}`.replace(/\s+/gu, " ");
3240
+ }
3241
+ function formatMiniMaxReport(lines, report2) {
3242
+ if (report2.source === "minimax-account-balance") {
3243
+ for (const metric2 of report2.metrics) {
3244
+ lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
3245
+ }
3246
+ return;
3247
+ }
3248
+ let previousGroup;
3249
+ for (const bucket of report2.buckets) {
3250
+ if (bucket.groupId !== previousGroup) lines.push(`${bucket.groupLabel ?? "Token Plan"}:`);
3251
+ previousGroup = bucket.groupId;
3252
+ const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
3253
+ const value = bucket.period === "unlimited" ? "unlimited" : bucket.limit && bucket.remaining !== void 0 ? `${bucket.remaining} of ${bucket.limit} left \xB7 ${percentRemaining(bucket)}%${reset}` : "unavailable";
3254
+ lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}`);
3255
+ }
3256
+ }
3257
+ function formatMiniMaxStatusline(report2, model) {
3258
+ const prefix = report2.providerId === "minimax-cn" ? "minimax cn" : "minimax";
3259
+ if (report2.source === "minimax-account-balance") {
3260
+ const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
3261
+ return available ? `${prefix} ${available.currency} ${available.value}` : void 0;
3262
+ }
3263
+ const selectedGroup = selectMiniMaxGroup(report2, model);
3264
+ if (!selectedGroup) return void 0;
3265
+ const selected = report2.buckets.filter((bucket) => bucket.groupId === selectedGroup);
3266
+ const parts = [prefix];
3267
+ for (const bucket of selected) {
3268
+ const fallback = bucket.id.endsWith(":weekly") ? "weekly" : "5h";
3269
+ const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
3270
+ if (bucket.period === "unlimited") {
3271
+ parts.push(`unlimited ${window}`);
3272
+ continue;
3273
+ }
3274
+ if (!bucket.limit || bucket.remaining === void 0) continue;
3275
+ parts.push(`${percentRemaining(bucket)}% ${window}`);
3276
+ }
3277
+ return parts.length > 1 ? parts.join(" ") : void 0;
3278
+ }
3279
+ function selectMiniMaxGroup(report2, model) {
3280
+ const groups = [
3281
+ ...new Set(
3282
+ report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
3283
+ )
3284
+ ];
3285
+ if (groups.length <= 1) return groups[0];
3286
+ if (model?.provider !== report2.providerId) return void 0;
3287
+ const modelKeys = [model.id, model.name].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
3288
+ const candidates = groups.map((group) => {
3289
+ const bucket = report2.buckets.find((candidate) => candidate.groupId === group);
3290
+ const patterns = [bucket?.groupLabel, ...bucket?.modelKeys ?? [], group].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
3291
+ return { group, patterns };
3292
+ });
3293
+ const exact = candidates.find(
3294
+ ({ patterns }) => patterns.some((pattern) => !pattern.includes("*") && modelKeys.includes(pattern))
3295
+ );
3296
+ if (exact) return exact.group;
3297
+ return candidates.find(
3298
+ ({ patterns }) => patterns.some(
3299
+ (pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
3300
+ )
3301
+ )?.group;
3302
+ }
3303
+ function normalizeMiniMaxModelKey(value) {
3304
+ const key = value?.toLowerCase().replace(/[^a-z0-9*]+/gu, "");
3305
+ return key && /[a-z0-9]/u.test(key) ? key : void 0;
3306
+ }
3307
+ function wildcardKeyMatches(pattern, value) {
3308
+ if (!pattern.includes("*")) return pattern === value;
3309
+ const segments = pattern.split("*").filter(Boolean);
3310
+ let offset = 0;
3311
+ for (const [index, segment] of segments.entries()) {
3312
+ const found = value.indexOf(segment, offset);
3313
+ if (found < 0 || index === 0 && !pattern.startsWith("*") && found !== 0) return false;
3314
+ offset = found + segment.length;
3315
+ }
3316
+ const last = segments.at(-1);
3317
+ return pattern.endsWith("*") || last !== void 0 && value.endsWith(last);
3318
+ }
3319
+ function formatZaiStatusline(report2) {
2627
3320
  const selected = [
2628
- report.buckets.find((bucket) => bucket.id === "five-hour"),
2629
- report.buckets.find((bucket) => bucket.id === "weekly")
3321
+ report2.buckets.find((bucket) => bucket.id === "five-hour"),
3322
+ report2.buckets.find((bucket) => bucket.id === "weekly")
2630
3323
  ];
2631
3324
  const parts = ["zai"];
2632
3325
  for (const bucket of selected) {
@@ -2638,20 +3331,19 @@ function formatZaiStatusline(report) {
2638
3331
  }
2639
3332
  return parts.length > 1 ? parts.join(" ") : void 0;
2640
3333
  }
2641
- function formatCurrencyMetric(metric) {
2642
- if (typeof metric.value !== "number") return String(metric.value);
2643
- if (!metric.currency) return "unavailable";
2644
- if (metric.currency === "USD") return `$${metric.value.toFixed(2)}`;
2645
- if (metric.currency === "CNY") return `\xA5${metric.value.toFixed(2)}`;
2646
- return `${metric.value.toFixed(2)} ${metric.currency}`;
3334
+ function formatCurrencyMetric(metric2) {
3335
+ if (typeof metric2.value !== "number") return String(metric2.value);
3336
+ if (!metric2.currency) return "unavailable";
3337
+ if (metric2.currency === "USD") return `$${metric2.value.toFixed(2)}`;
3338
+ if (metric2.currency === "CNY") return `\xA5${metric2.value.toFixed(2)}`;
3339
+ return `${metric2.value.toFixed(2)} ${metric2.currency}`;
2647
3340
  }
2648
- function formatXaiReport(lines, report) {
2649
- const included = report.buckets.find((bucket) => bucket.id === "included-allowance");
3341
+ function formatXaiReport(lines, report2) {
3342
+ const included = report2.buckets.find((bucket) => bucket.id === "included-allowance");
2650
3343
  if (included) {
2651
3344
  let value = "unavailable";
2652
3345
  if (included.unit === "percent" && included.used !== void 0) {
2653
- value = `${included.used}% used`;
2654
- if (included.remaining !== void 0) value += ` \xB7 ${included.remaining}% left`;
3346
+ value = formatPercentBar(included);
2655
3347
  } else if (included.used !== void 0) {
2656
3348
  value = `${formatUsd(included.used)} used`;
2657
3349
  if (included.limit !== void 0) value += ` of ${formatUsd(included.limit)}`;
@@ -2662,26 +3354,27 @@ function formatXaiReport(lines, report) {
2662
3354
  const reset = included.resetsAt ? ` (resets ${formatReset(included.resetsAt)})` : "";
2663
3355
  lines.push(`${"Included allowance:".padEnd(VALUE_COLUMN)}${value}${period}${reset}`);
2664
3356
  }
2665
- const onDemand = report.buckets.find((bucket) => bucket.id === "on-demand");
3357
+ const onDemand = report2.buckets.find((bucket) => bucket.id === "on-demand");
2666
3358
  if (onDemand) {
2667
3359
  let value = onDemand.used === void 0 ? "usage unavailable" : `${formatUsd(onDemand.used)} used`;
2668
3360
  if (onDemand.limit !== void 0) value += ` of ${formatUsd(onDemand.limit)} cap`;
2669
3361
  lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
2670
3362
  }
2671
- for (const metric of report.metrics) {
3363
+ for (const metric2 of report2.metrics) {
2672
3364
  lines.push(
2673
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3365
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2674
3366
  );
2675
3367
  }
2676
3368
  }
2677
- function formatZaiReport(lines, report) {
2678
- for (const bucket of report.buckets) {
3369
+ function formatZaiReport(lines, report2) {
3370
+ for (const bucket of report2.buckets) {
3371
+ if (bucket.unit === "percent" && bucket.used !== void 0) {
3372
+ lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
3373
+ continue;
3374
+ }
2679
3375
  const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2680
3376
  let value = "unavailable";
2681
- if (bucket.unit === "percent" && bucket.used !== void 0) {
2682
- value = `${bucket.used}% used`;
2683
- if (bucket.remaining !== void 0) value += ` \xB7 ${bucket.remaining}% left`;
2684
- } else if (bucket.used !== void 0 && bucket.limit !== void 0) {
3377
+ if (bucket.used !== void 0 && bucket.limit !== void 0) {
2685
3378
  value = `${bucket.used} of ${bucket.limit} used`;
2686
3379
  if (bucket.remaining !== void 0) value += ` \xB7 ${bucket.remaining} left`;
2687
3380
  } else if (bucket.used !== void 0) {
@@ -2691,28 +3384,28 @@ function formatZaiReport(lines, report) {
2691
3384
  }
2692
3385
  lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
2693
3386
  }
2694
- for (const metric of report.metrics) {
3387
+ for (const metric2 of report2.metrics) {
2695
3388
  lines.push(
2696
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3389
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2697
3390
  );
2698
3391
  }
2699
3392
  }
2700
- function formatGenericReport(lines, report) {
2701
- for (const bucket of report.buckets) {
3393
+ function formatGenericReport(lines, report2) {
3394
+ for (const bucket of report2.buckets) {
2702
3395
  lines.push(
2703
3396
  `${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(bucket.remaining ?? bucket.used ?? "unavailable", bucket.unit)}`
2704
3397
  );
2705
3398
  }
2706
- for (const metric of report.metrics) {
3399
+ for (const metric2 of report2.metrics) {
2707
3400
  lines.push(
2708
- `${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`
3401
+ `${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
2709
3402
  );
2710
3403
  }
2711
3404
  }
2712
- function formatCodexStatusline(report, model, now = Date.now(), showResetCountdown = true) {
2713
- const group = selectCodexGroup(report, model);
2714
- if (!group) return formatCodexCreditsStatus(report);
2715
- const buckets = report.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
3405
+ function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
3406
+ const group = selectCodexGroup(report2, model);
3407
+ if (!group) return formatCodexCreditsStatus(report2);
3408
+ const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
2716
3409
  const labelBucket = buckets[0];
2717
3410
  const parts = [
2718
3411
  group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
@@ -2729,24 +3422,24 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
2729
3422
  const reset = formatResetCountdown(bucket.resetsAt, now);
2730
3423
  parts.push(`${percent} ${reset ? `\u21BB ${reset}` : window}`);
2731
3424
  }
2732
- return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report);
3425
+ return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report2);
2733
3426
  }
2734
- function formatCodexCreditsStatus(report) {
2735
- const credits = report.metrics.find((metric) => metric.id === "credits");
3427
+ function formatCodexCreditsStatus(report2) {
3428
+ const credits = report2.metrics.find((metric2) => metric2.id === "credits");
2736
3429
  if (!credits) return "codex usage unavailable";
2737
3430
  if (credits.value === "none") return "codex no credits";
2738
3431
  if (credits.value === "available") return "codex credits available";
2739
3432
  if (credits.value === "unlimited") return "codex credits unlimited";
2740
3433
  return `codex ${formatMetricValue(credits.value, "count")} credits`;
2741
3434
  }
2742
- function selectCodexGroup(report, model) {
2743
- const groups = [...new Set(report.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
3435
+ function selectCodexGroup(report2, model) {
3436
+ const groups = [...new Set(report2.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
2744
3437
  if (model?.provider !== "openai-codex") {
2745
3438
  return groups.includes("codex") ? "codex" : groups[0];
2746
3439
  }
2747
3440
  const modelKeys = normalizedModelKeys(model);
2748
3441
  for (const group of groups) {
2749
- const bucket = report.buckets.find(
3442
+ const bucket = report2.buckets.find(
2750
3443
  (candidate) => (candidate.groupId ?? candidate.id) === group
2751
3444
  );
2752
3445
  const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
@@ -2793,10 +3486,12 @@ function compactLimitLabel(label) {
2793
3486
  return (suffix || normalized).toLowerCase().replace(/\s+/g, " ");
2794
3487
  }
2795
3488
  function formatPercentBucket(bucket) {
3489
+ return `${formatPercentBar(bucket)}${bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : ""}`;
3490
+ }
3491
+ function formatPercentBar(bucket) {
2796
3492
  const remaining = clampPercent4(bucket.remaining ?? 0);
2797
3493
  const filled = Math.round(remaining / 100 * BAR_SEGMENTS);
2798
- const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
2799
- return `[${"\u2588".repeat(filled)}${"\u2591".repeat(BAR_SEGMENTS - filled)}] ${remaining.toFixed(0)}% left${reset}`;
3494
+ return `[${"\u2588".repeat(filled)}${"\u2591".repeat(BAR_SEGMENTS - filled)}] ${remaining.toFixed(0)}% left`;
2800
3495
  }
2801
3496
  function formatWindowLabel(minutes, fallback, compact) {
2802
3497
  if (!minutes || !Number.isFinite(minutes) || minutes <= 0) {
@@ -3492,9 +4187,7 @@ function usageExtension(pi, dependencies = {}) {
3492
4187
  const generation = statusGeneration;
3493
4188
  statusCountdownTimer = setTimeout(() => {
3494
4189
  statusCountdownTimer = void 0;
3495
- if (!sessionActive || generation !== statusGeneration || modelIdentity(ctx.model) !== modelIdentity(model)) {
3496
- return;
3497
- }
4190
+ if (!sessionActive || generation !== statusGeneration) return;
3498
4191
  publishStatus(ctx, outcome, model, false);
3499
4192
  }, STATUS_COUNTDOWN_REFRESH_MS);
3500
4193
  statusCountdownTimer.unref?.();
@@ -3549,7 +4242,19 @@ function usageExtension(pi, dependencies = {}) {
3549
4242
  }
3550
4243
  };
3551
4244
  }
3552
- const requiresRequestBoundaryGuard = ["deepseek", "fireworks", "xai"].includes(adapter.id);
4245
+ const requiresRequestBoundaryGuard = [
4246
+ "baseten",
4247
+ "deepseek",
4248
+ "fireworks",
4249
+ "minimax",
4250
+ "minimax-cn",
4251
+ "moonshotai",
4252
+ "moonshotai-cn",
4253
+ "vercel-ai-gateway",
4254
+ "xai",
4255
+ "zai",
4256
+ "zai-coding-cn"
4257
+ ].includes(adapter.id);
3553
4258
  const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.id === "fireworks" && settingsRuntime.get().settings.fireworksAccountId !== expectedFireworksAccountId;
3554
4259
  if (requiresRequestBoundaryGuard && requestContextChanged()) throw abortError();
3555
4260
  if (!auth) {
@@ -3602,7 +4307,7 @@ function usageExtension(pi, dependencies = {}) {
3602
4307
  querySequence += 1;
3603
4308
  const queryId = querySequence;
3604
4309
  setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES);
3605
- let deepSeekAuthChanged = false;
4310
+ let retryableAuthChanged = false;
3606
4311
  try {
3607
4312
  const remainingMs = Math.max(1, deadlineAt - Date.now());
3608
4313
  const guard = requiresRequestBoundaryGuard ? async () => {
@@ -3615,14 +4320,16 @@ function usageExtension(pi, dependencies = {}) {
3615
4320
  );
3616
4321
  if (signal.aborted || requestContextChanged()) throw abortError();
3617
4322
  if (revalidated?.fingerprint !== auth.fingerprint) {
3618
- if (adapter.id === "deepseek") {
3619
- deepSeekAuthChanged = true;
3620
- throw new Error("DeepSeek runtime credential changed during the balance query.");
4323
+ if (["deepseek", "minimax", "minimax-cn"].includes(adapter.id)) {
4324
+ retryableAuthChanged = true;
4325
+ throw new Error(
4326
+ `${adapter.displayName} runtime credential changed during the usage query.`
4327
+ );
3621
4328
  }
3622
4329
  throw abortError();
3623
4330
  }
3624
4331
  } : void 0;
3625
- const report = await queryProviderUsage(
4332
+ const report2 = await queryProviderUsage(
3626
4333
  adapter,
3627
4334
  auth,
3628
4335
  signal,
@@ -3632,7 +4339,7 @@ function usageExtension(pi, dependencies = {}) {
3632
4339
  );
3633
4340
  if (guard) await guard();
3634
4341
  if (latestQueries.get(failureKey) === queryId) {
3635
- cache.set(adapter.id, queryFingerprint, report);
4342
+ cache.set(adapter.id, queryFingerprint, report2);
3636
4343
  failureBackoff.delete(failureKey);
3637
4344
  }
3638
4345
  return {
@@ -3641,13 +4348,13 @@ function usageExtension(pi, dependencies = {}) {
3641
4348
  providerName: adapter.displayName,
3642
4349
  displayState,
3643
4350
  status: "ready",
3644
- report
4351
+ report: report2
3645
4352
  },
3646
4353
  fingerprint: auth.fingerprint
3647
4354
  };
3648
4355
  } catch (error) {
3649
4356
  if (isStaleExtensionContextError(error) || isAbortError3(error)) throw error;
3650
- if (deepSeekAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
4357
+ if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
3651
4358
  if (latestQueries.get(failureKey) === queryId) latestQueries.delete(failureKey);
3652
4359
  return queryAdapterState(
3653
4360
  ctx,
@@ -4335,6 +5042,8 @@ export {
4335
5042
  isStaleExtensionContextError,
4336
5043
  listCodexResetCredits,
4337
5044
  loadUsageSettings,
5045
+ miniMaxUsageKind,
5046
+ normalizeBasetenBillingUsagePayload,
4338
5047
  normalizeCodexBackendPayload,
4339
5048
  normalizeCodexResetCreditsPayload,
4340
5049
  normalizeDeepSeekBalancePayload,
@@ -4342,11 +5051,15 @@ export {
4342
5051
  normalizeFireworksBillingSummaryPayload,
4343
5052
  normalizeGitHubCopilotUsagePayload,
4344
5053
  normalizeKimiCodingUsagePayload,
5054
+ normalizeMiniMaxUsagePayload,
5055
+ normalizeMoonshotBalancePayload,
4345
5056
  normalizeOpenCodeZenPayload,
4346
5057
  normalizeOpenRouterKeyPayload,
4347
5058
  normalizeUsageSettings,
5059
+ normalizeVercelAIGatewayCreditsPayload,
4348
5060
  normalizeXaiBillingPayload,
4349
5061
  normalizeZaiQuotaPayload,
5062
+ normalizeZaiSubscriptionPayload,
4350
5063
  providerIsConfigured,
4351
5064
  queryProviderUsage,
4352
5065
  redactUsageError,