@narumitw/pi-usage 0.60.7 → 0.60.9
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/README.md +1 -1
- package/dist/index.ts +91 -340
- package/dist/index.ts.map +2 -2
- package/docs/providers.md +2 -1
- package/package.json +73 -74
- package/src/codex-fast-runtime.ts +148 -184
- package/src/codex-fast.ts +73 -83
- package/src/codex-resets.ts +249 -278
- package/src/core.ts +204 -206
- package/src/format.ts +519 -574
- package/src/index.ts +77 -77
- package/src/oauth-credential-source.ts +57 -65
- package/src/providers/baseten.ts +32 -36
- package/src/providers/codex.ts +109 -120
- package/src/providers/deepseek.ts +59 -64
- package/src/providers/fireworks.ts +219 -238
- package/src/providers/github-copilot.ts +89 -95
- package/src/providers/kimi-coding.ts +202 -213
- package/src/providers/minimax.ts +214 -219
- package/src/providers/moonshot.ts +41 -46
- package/src/providers/opencode-zen.ts +56 -59
- package/src/providers/openrouter.ts +50 -53
- package/src/providers/vercel-ai-gateway.ts +33 -33
- package/src/providers/xai.ts +141 -148
- package/src/providers/zai-errors.ts +75 -75
- package/src/providers/zai.ts +173 -189
- package/src/query.ts +887 -967
- package/src/settings.ts +275 -304
- package/src/types.ts +145 -145
- package/src/usage-helpers.ts +18 -18
- package/src/usage-settings-ui.ts +117 -126
- package/src/usage-targets.ts +98 -114
- package/src/usage.ts +1264 -1426
package/dist/index.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { calculateCost, hasApi } from "@earendil-works/pi-ai";
|
|
|
6
6
|
var CODEX_FAST_SERVICE_TIER = "priority";
|
|
7
7
|
var CODEX_STANDARD_SERVICE_TIER = "default";
|
|
8
8
|
var CODEX_FAST_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
9
|
-
"gpt-5.4",
|
|
10
9
|
"gpt-5.5",
|
|
11
10
|
"gpt-5.6-luna",
|
|
12
11
|
"gpt-5.6-sol",
|
|
@@ -80,9 +79,7 @@ function hasCompleteUsage(value) {
|
|
|
80
79
|
);
|
|
81
80
|
}
|
|
82
81
|
function costsEqual(left, right) {
|
|
83
|
-
return ["input", "output", "cacheRead", "cacheWrite", "total"].every(
|
|
84
|
-
(key) => left[key] === right[key]
|
|
85
|
-
);
|
|
82
|
+
return ["input", "output", "cacheRead", "cacheWrite", "total"].every((key) => left[key] === right[key]);
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
// src/codex-resets.ts
|
|
@@ -157,8 +154,7 @@ function fingerprintResolvedAuth(auth, salt) {
|
|
|
157
154
|
}
|
|
158
155
|
async function runWithConcurrency(items, limit, worker, signal) {
|
|
159
156
|
if (signal.aborted) throw abortError();
|
|
160
|
-
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
161
|
-
throw new Error("Concurrency limit must be positive.");
|
|
157
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new Error("Concurrency limit must be positive.");
|
|
162
158
|
const results = new Array(items.length);
|
|
163
159
|
let nextIndex = 0;
|
|
164
160
|
const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
@@ -194,10 +190,9 @@ async function awaitWithDeadline(operation, signal, timeoutMs, description) {
|
|
|
194
190
|
"abort",
|
|
195
191
|
() => {
|
|
196
192
|
reject(
|
|
197
|
-
signal.aborted ? abortError() : Object.assign(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
193
|
+
signal.aborted ? abortError() : Object.assign(new Error(`Timed out after ${Math.round(timeoutMs / 1e3)}s ${description}.`), {
|
|
194
|
+
name: "TimeoutError"
|
|
195
|
+
})
|
|
201
196
|
);
|
|
202
197
|
},
|
|
203
198
|
{ once: true }
|
|
@@ -283,9 +278,7 @@ function truncate(value, maxChars) {
|
|
|
283
278
|
}
|
|
284
279
|
|
|
285
280
|
// src/oauth-credential-source.ts
|
|
286
|
-
import {
|
|
287
|
-
readStoredCredential
|
|
288
|
-
} from "@earendil-works/pi-coding-agent";
|
|
281
|
+
import { readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
289
282
|
var OAUTH_CREDENTIAL_SOURCE_CHANNEL = "oauth:credential-source:v1";
|
|
290
283
|
function createOAuthCredentialCandidateReader(pi, credentialReader = readStoredCredential) {
|
|
291
284
|
return (ctx, providerId) => collectOAuthCredentialCandidates(pi, ctx, providerId, credentialReader);
|
|
@@ -397,13 +390,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
|
|
|
397
390
|
const id = asString(value?.metered_feature) ?? asString(value?.limit_name);
|
|
398
391
|
if (!value || !id) continue;
|
|
399
392
|
try {
|
|
400
|
-
normalizeRateLimitGroup(
|
|
401
|
-
buckets,
|
|
402
|
-
id,
|
|
403
|
-
asString(value.limit_name) ?? id,
|
|
404
|
-
value.rate_limit,
|
|
405
|
-
true
|
|
406
|
-
);
|
|
393
|
+
normalizeRateLimitGroup(buckets, id, asString(value.limit_name) ?? id, value.rate_limit, true);
|
|
407
394
|
} catch {
|
|
408
395
|
}
|
|
409
396
|
}
|
|
@@ -657,9 +644,7 @@ function createFireworksAdapter(fetchProviderJson2) {
|
|
|
657
644
|
if (!pageToken) break;
|
|
658
645
|
}
|
|
659
646
|
if (pageToken) {
|
|
660
|
-
throw new Error(
|
|
661
|
-
`Fireworks account listing exceeded ${FIREWORKS_MAX_ACCOUNT_PAGES} pages.`
|
|
662
|
-
);
|
|
647
|
+
throw new Error(`Fireworks account listing exceeded ${FIREWORKS_MAX_ACCOUNT_PAGES} pages.`);
|
|
663
648
|
}
|
|
664
649
|
return accounts.map((id) => ({ id, label: id }));
|
|
665
650
|
}
|
|
@@ -726,9 +711,7 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
|
|
|
726
711
|
});
|
|
727
712
|
}
|
|
728
713
|
}
|
|
729
|
-
const notes = [
|
|
730
|
-
"Rated line items may differ from the final invoice once credits or adjustments are applied."
|
|
731
|
-
];
|
|
714
|
+
const notes = ["Rated line items may differ from the final invoice once credits or adjustments are applied."];
|
|
732
715
|
if (metrics.length === 0) {
|
|
733
716
|
notes.push("Fireworks returned no rated line items for the last 30 days.");
|
|
734
717
|
}
|
|
@@ -807,14 +790,8 @@ function fireworksNextPageToken(value) {
|
|
|
807
790
|
function fireworksBillingSummaryUrl(accountId, startedAt) {
|
|
808
791
|
const dayMs = 24 * 60 * 60 * 1e3;
|
|
809
792
|
const dayFloor = (time) => `${new Date(time).toISOString().slice(0, 10)}T00:00:00Z`;
|
|
810
|
-
const url = new URL(
|
|
811
|
-
|
|
812
|
-
FIREWORKS_BILLING_SUMMARY_ORIGIN
|
|
813
|
-
);
|
|
814
|
-
url.searchParams.set(
|
|
815
|
-
"startTime",
|
|
816
|
-
dayFloor(startedAt - (FIREWORKS_SPEND_WINDOW_DAYS - 1) * dayMs)
|
|
817
|
-
);
|
|
793
|
+
const url = new URL(`/v1/accounts/${accountId}/billing/summary`, FIREWORKS_BILLING_SUMMARY_ORIGIN);
|
|
794
|
+
url.searchParams.set("startTime", dayFloor(startedAt - (FIREWORKS_SPEND_WINDOW_DAYS - 1) * dayMs));
|
|
818
795
|
url.searchParams.set("endTime", dayFloor(startedAt + dayMs));
|
|
819
796
|
return url.toString();
|
|
820
797
|
}
|
|
@@ -848,10 +825,7 @@ function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
|
|
|
848
825
|
if (entitlement === void 0 || rawRemaining === void 0) {
|
|
849
826
|
throw new Error(`GitHub Copilot ${label.toLowerCase()} quota was incomplete.`);
|
|
850
827
|
}
|
|
851
|
-
const overageUsed = Math.max(
|
|
852
|
-
asNonnegativeNumber(premium.overage_count) ?? 0,
|
|
853
|
-
Math.max(0, -rawRemaining)
|
|
854
|
-
);
|
|
828
|
+
const overageUsed = Math.max(asNonnegativeNumber(premium.overage_count) ?? 0, Math.max(0, -rawRemaining));
|
|
855
829
|
if (overageUsed > 0) {
|
|
856
830
|
metrics.push({
|
|
857
831
|
id: "overage-used",
|
|
@@ -983,15 +957,21 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
|
983
957
|
function parseUsageRow(value, windowMinutes, label) {
|
|
984
958
|
const row = asObject6(value);
|
|
985
959
|
if (!row) return void 0;
|
|
986
|
-
const used = asNonnegativeInteger2(row.used);
|
|
987
960
|
const limit = asNonnegativeInteger2(row.limit);
|
|
988
|
-
if (
|
|
961
|
+
if (limit === void 0 || limit === 0) return void 0;
|
|
962
|
+
const usedRaw = asNonnegativeInteger2(row.used);
|
|
963
|
+
const remainingRaw = asNonnegativeInteger2(row.remaining);
|
|
964
|
+
if (row.used !== void 0 && usedRaw === void 0 || row.remaining !== void 0 && remainingRaw === void 0) {
|
|
965
|
+
return void 0;
|
|
966
|
+
}
|
|
967
|
+
const used = usedRaw ?? (remainingRaw === void 0 ? 0 : Math.max(0, limit - remainingRaw));
|
|
968
|
+
const remaining = remainingRaw ?? Math.max(0, limit - used);
|
|
989
969
|
const resetsAt = asIsoEpochSeconds(row.resetTime);
|
|
990
970
|
return {
|
|
991
971
|
id: windowId(windowMinutes),
|
|
992
972
|
label,
|
|
993
973
|
used,
|
|
994
|
-
remaining
|
|
974
|
+
remaining,
|
|
995
975
|
limit,
|
|
996
976
|
unit: "count",
|
|
997
977
|
windowMinutes,
|
|
@@ -1018,9 +998,7 @@ function parseBoosterWallet(value) {
|
|
|
1018
998
|
const monthlyLimit = parseMoney(wallet.monthlyChargeLimit);
|
|
1019
999
|
const monthlyUsed = parseMoney(wallet.monthlyUsed);
|
|
1020
1000
|
const currencies = new Set(
|
|
1021
|
-
[monthlyLimit?.currency, monthlyUsed?.currency].filter(
|
|
1022
|
-
(currency2) => currency2 !== void 0
|
|
1023
|
-
)
|
|
1001
|
+
[monthlyLimit?.currency, monthlyUsed?.currency].filter((currency2) => currency2 !== void 0)
|
|
1024
1002
|
);
|
|
1025
1003
|
if (currencies.size !== 1) return [];
|
|
1026
1004
|
const currency = currencies.values().next().value;
|
|
@@ -1091,22 +1069,9 @@ function asPositiveInteger(value) {
|
|
|
1091
1069
|
}
|
|
1092
1070
|
function asIsoEpochSeconds(value) {
|
|
1093
1071
|
if (typeof value !== "string") return void 0;
|
|
1094
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|([+-])(\d{2}):(\d{2}))$/u.exec(
|
|
1095
|
-
value
|
|
1096
|
-
);
|
|
1072
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|([+-])(\d{2}):(\d{2}))$/u.exec(value);
|
|
1097
1073
|
if (!match) return void 0;
|
|
1098
|
-
const [
|
|
1099
|
-
,
|
|
1100
|
-
yearText,
|
|
1101
|
-
monthText,
|
|
1102
|
-
dayText,
|
|
1103
|
-
hourText,
|
|
1104
|
-
minuteText,
|
|
1105
|
-
secondText,
|
|
1106
|
-
,
|
|
1107
|
-
offsetHour,
|
|
1108
|
-
offsetMinute
|
|
1109
|
-
] = match;
|
|
1074
|
+
const [, yearText, monthText, dayText, hourText, minuteText, secondText, , offsetHour, offsetMinute] = match;
|
|
1110
1075
|
const year = Number(yearText);
|
|
1111
1076
|
const month = Number(monthText);
|
|
1112
1077
|
const day = Number(dayText);
|
|
@@ -1159,12 +1124,7 @@ function normalizeBalance(providerId, payload, capturedAt) {
|
|
|
1159
1124
|
assertSuccess(payload);
|
|
1160
1125
|
const provider = PROVIDERS[providerId];
|
|
1161
1126
|
const metrics = [
|
|
1162
|
-
balanceMetric(
|
|
1163
|
-
"available-balance",
|
|
1164
|
-
"Available balance",
|
|
1165
|
-
payload.available_amount,
|
|
1166
|
-
provider.currency
|
|
1167
|
-
),
|
|
1127
|
+
balanceMetric("available-balance", "Available balance", payload.available_amount, provider.currency),
|
|
1168
1128
|
balanceMetric("cash-balance", "Cash balance", payload.cash_balance, provider.currency, true),
|
|
1169
1129
|
balanceMetric("voucher-balance", "Voucher balance", payload.voucher_balance, provider.currency),
|
|
1170
1130
|
balanceMetric("credit-balance", "Credit balance", payload.credit_balance, provider.currency),
|
|
@@ -1584,11 +1544,7 @@ function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
|
|
|
1584
1544
|
const metrics = [];
|
|
1585
1545
|
const notes = [];
|
|
1586
1546
|
if (config) {
|
|
1587
|
-
const period = normalizePeriod(
|
|
1588
|
-
config.currentPeriod,
|
|
1589
|
-
config.billingPeriodStart,
|
|
1590
|
-
config.billingPeriodEnd
|
|
1591
|
-
);
|
|
1547
|
+
const period = normalizePeriod(config.currentPeriod, config.billingPeriodStart, config.billingPeriodEnd);
|
|
1592
1548
|
const preferredPercent = optionalPercent2(config.creditUsagePercent, "creditUsagePercent");
|
|
1593
1549
|
if (preferredPercent !== void 0) {
|
|
1594
1550
|
buckets.push({
|
|
@@ -1686,8 +1642,7 @@ function normalizePeriod(currentPeriod, legacyStart, legacyEnd) {
|
|
|
1686
1642
|
function periodLabel(type, start) {
|
|
1687
1643
|
if (type === "USAGE_PERIOD_TYPE_WEEKLY") return "Weekly";
|
|
1688
1644
|
if (type === "USAGE_PERIOD_TYPE_MONTHLY") return "Monthly";
|
|
1689
|
-
if (type)
|
|
1690
|
-
return sanitizeDisplayText(type.replace(/^USAGE_PERIOD_TYPE_/u, "").replaceAll("_", " "), 40);
|
|
1645
|
+
if (type) return sanitizeDisplayText(type.replace(/^USAGE_PERIOD_TYPE_/u, "").replaceAll("_", " "), 40);
|
|
1691
1646
|
return start === void 0 ? void 0 : "Current period";
|
|
1692
1647
|
}
|
|
1693
1648
|
function optionalUsd(value, field) {
|
|
@@ -1833,13 +1788,7 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt,
|
|
|
1833
1788
|
addCountBucket(buckets, limit, "mcp-monthly", "MCP monthly allowance");
|
|
1834
1789
|
addUsageDetailMetrics(metrics, limit.usageDetails);
|
|
1835
1790
|
} else if (isPlanUsage && unit === 3) {
|
|
1836
|
-
addPercentBucket(
|
|
1837
|
-
buckets,
|
|
1838
|
-
limit,
|
|
1839
|
-
"five-hour",
|
|
1840
|
-
sessionWindowLabel(limit),
|
|
1841
|
-
sessionWindowMinutes(limit)
|
|
1842
|
-
);
|
|
1791
|
+
addPercentBucket(buckets, limit, "five-hour", sessionWindowLabel(limit), sessionWindowMinutes(limit));
|
|
1843
1792
|
} else if (isPlanUsage && unit === 6) {
|
|
1844
1793
|
const used = asNonnegativeNumber4(limit.currentValue);
|
|
1845
1794
|
const quota = asNonnegativeNumber4(limit.usage);
|
|
@@ -1857,9 +1806,7 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt,
|
|
|
1857
1806
|
const level = asString5(data.level);
|
|
1858
1807
|
const planLabel = plan?.name ?? level;
|
|
1859
1808
|
if (planLabel) {
|
|
1860
|
-
notes.push(
|
|
1861
|
-
plan?.renewsAt ? `Plan: ${planLabel} \xB7 renews ${plan.renewsAt}` : `Plan: ${planLabel}`
|
|
1862
|
-
);
|
|
1809
|
+
notes.push(plan?.renewsAt ? `Plan: ${planLabel} \xB7 renews ${plan.renewsAt}` : `Plan: ${planLabel}`);
|
|
1863
1810
|
}
|
|
1864
1811
|
return {
|
|
1865
1812
|
providerId,
|
|
@@ -1894,13 +1841,7 @@ function normalizeZaiSubscriptionPayload(payload) {
|
|
|
1894
1841
|
(candidate) => candidate.status !== void 0 || candidate.inCurrentPeriod !== void 0
|
|
1895
1842
|
);
|
|
1896
1843
|
if (!hasStateMetadata) return candidates[0]?.plan;
|
|
1897
|
-
return candidates.find(
|
|
1898
|
-
(candidate) => candidate.inCurrentPeriod === true && candidate.status === "VALID"
|
|
1899
|
-
)?.plan ?? candidates.find(
|
|
1900
|
-
(candidate) => candidate.inCurrentPeriod === true && candidate.status === void 0
|
|
1901
|
-
)?.plan ?? candidates.find(
|
|
1902
|
-
(candidate) => candidate.status === "VALID" && candidate.inCurrentPeriod === void 0
|
|
1903
|
-
)?.plan;
|
|
1844
|
+
return candidates.find((candidate) => candidate.inCurrentPeriod === true && candidate.status === "VALID")?.plan ?? candidates.find((candidate) => candidate.inCurrentPeriod === true && candidate.status === void 0)?.plan ?? candidates.find((candidate) => candidate.status === "VALID" && candidate.inCurrentPeriod === void 0)?.plan;
|
|
1904
1845
|
}
|
|
1905
1846
|
function planRenewalDate(value) {
|
|
1906
1847
|
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}/u.test(value)) return value.slice(0, 10);
|
|
@@ -2018,12 +1959,7 @@ async function listUsageTargets(adapter, auth, signal, timeoutMs, guard) {
|
|
|
2018
1959
|
if (!adapter.targets) return [];
|
|
2019
1960
|
const startedAt = Date.now();
|
|
2020
1961
|
await guard();
|
|
2021
|
-
const listed = await adapter.targets.list(
|
|
2022
|
-
auth,
|
|
2023
|
-
signal,
|
|
2024
|
-
remainingTargetTimeout(timeoutMs, startedAt),
|
|
2025
|
-
guard
|
|
2026
|
-
);
|
|
1962
|
+
const listed = await adapter.targets.list(auth, signal, remainingTargetTimeout(timeoutMs, startedAt), guard);
|
|
2027
1963
|
await guard();
|
|
2028
1964
|
remainingTargetTimeout(timeoutMs, startedAt);
|
|
2029
1965
|
const choices = normalizeUsageTargets(listed);
|
|
@@ -2149,13 +2085,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2149
2085
|
label: "ChatGPT subscription limits"
|
|
2150
2086
|
},
|
|
2151
2087
|
async query(auth, signal, timeoutMs) {
|
|
2152
|
-
const payload = await fetchProviderJson(
|
|
2153
|
-
CODEX_USAGE_URL,
|
|
2154
|
-
auth,
|
|
2155
|
-
signal,
|
|
2156
|
-
timeoutMs,
|
|
2157
|
-
"Codex usage endpoint"
|
|
2158
|
-
);
|
|
2088
|
+
const payload = await fetchProviderJson(CODEX_USAGE_URL, auth, signal, timeoutMs, "Codex usage endpoint");
|
|
2159
2089
|
return normalizeCodexBackendPayload(payload, Date.now());
|
|
2160
2090
|
}
|
|
2161
2091
|
},
|
|
@@ -2203,13 +2133,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2203
2133
|
displayName: "OpenRouter",
|
|
2204
2134
|
semantics: { kind: "api-key", label: "API-key spend limits" },
|
|
2205
2135
|
async query(auth, signal, timeoutMs) {
|
|
2206
|
-
const payload = await fetchProviderJson(
|
|
2207
|
-
OPENROUTER_KEY_URL,
|
|
2208
|
-
auth,
|
|
2209
|
-
signal,
|
|
2210
|
-
timeoutMs,
|
|
2211
|
-
"OpenRouter key endpoint"
|
|
2212
|
-
);
|
|
2136
|
+
const payload = await fetchProviderJson(OPENROUTER_KEY_URL, auth, signal, timeoutMs, "OpenRouter key endpoint");
|
|
2213
2137
|
return normalizeOpenRouterKeyPayload(payload, Date.now());
|
|
2214
2138
|
}
|
|
2215
2139
|
},
|
|
@@ -2218,8 +2142,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2218
2142
|
displayName: "Vercel AI Gateway",
|
|
2219
2143
|
semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
|
|
2220
2144
|
async query(auth, signal, timeoutMs, guard) {
|
|
2221
|
-
if (!guard)
|
|
2222
|
-
throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
2145
|
+
if (!guard) throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
2223
2146
|
const startedAt = Date.now();
|
|
2224
2147
|
await guard();
|
|
2225
2148
|
const payload = await fetchProviderJson(
|
|
@@ -2376,9 +2299,7 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
2376
2299
|
`${adapter.displayName} usage cannot send a custom provider base URL credential to the official usage endpoint.`
|
|
2377
2300
|
);
|
|
2378
2301
|
}
|
|
2379
|
-
const model = candidateModels(ctx, adapter.id).find(
|
|
2380
|
-
(candidate) => hasOfficialOrigin(candidate, adapter.id)
|
|
2381
|
-
);
|
|
2302
|
+
const model = candidateModels(ctx, adapter.id).find((candidate) => hasOfficialOrigin(candidate, adapter.id));
|
|
2382
2303
|
if (!model) return void 0;
|
|
2383
2304
|
const registry = ctx.modelRegistry;
|
|
2384
2305
|
const provider = registry.getProvider?.(adapter.id);
|
|
@@ -2453,15 +2374,7 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
2453
2374
|
if (!offered.ok) {
|
|
2454
2375
|
throw new Error("GitHub Copilot OAuth credential discovery failed closed.");
|
|
2455
2376
|
}
|
|
2456
|
-
return finalize(
|
|
2457
|
-
resolveGitHubCopilotUsageAuth(
|
|
2458
|
-
auth,
|
|
2459
|
-
model,
|
|
2460
|
-
salt,
|
|
2461
|
-
offered.candidates,
|
|
2462
|
-
offered.offeredCount === 0
|
|
2463
|
-
)
|
|
2464
|
-
);
|
|
2377
|
+
return finalize(resolveGitHubCopilotUsageAuth(auth, model, salt, offered.candidates, offered.offeredCount === 0));
|
|
2465
2378
|
}
|
|
2466
2379
|
if (adapter.id === "xai") {
|
|
2467
2380
|
const offered = candidateReader ? candidateReader(ctx, adapter.id) : fallbackOAuthCredentialCandidates(adapter.id, credentialReader);
|
|
@@ -2601,8 +2514,7 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2601
2514
|
signal: controller.signal
|
|
2602
2515
|
});
|
|
2603
2516
|
if (response.redirected) throw new Error(`${description} refused a redirected response.`);
|
|
2604
|
-
if (controller.signal.aborted)
|
|
2605
|
-
throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2517
|
+
if (controller.signal.aborted) throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2606
2518
|
const text = await readBoundedResponse(
|
|
2607
2519
|
response,
|
|
2608
2520
|
response.ok ? MAX_SUCCESS_BODY_BYTES : MAX_ERROR_BODY_BYTES,
|
|
@@ -2610,8 +2522,7 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2610
2522
|
description,
|
|
2611
2523
|
controller.signal
|
|
2612
2524
|
);
|
|
2613
|
-
if (controller.signal.aborted)
|
|
2614
|
-
throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2525
|
+
if (controller.signal.aborted) throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2615
2526
|
const responseError = request.responseError?.(response.status, text);
|
|
2616
2527
|
if (responseError) throw new Error(responseError);
|
|
2617
2528
|
if (!response.ok) {
|
|
@@ -2633,8 +2544,7 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2633
2544
|
if (timedOut) {
|
|
2634
2545
|
throw new Error(`Timed out after ${Math.round(timeoutMs / 1e3)}s while fetching usage.`);
|
|
2635
2546
|
}
|
|
2636
|
-
if (signal.aborted)
|
|
2637
|
-
throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2547
|
+
if (signal.aborted) throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2638
2548
|
throw error;
|
|
2639
2549
|
} finally {
|
|
2640
2550
|
clearTimeout(timeout);
|
|
@@ -2769,9 +2679,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
|
|
|
2769
2679
|
}
|
|
2770
2680
|
if (sawIncompleteMatch) throw new Error("GitHub Copilot OAuth credentials were incomplete.");
|
|
2771
2681
|
if (matches.size > 1) {
|
|
2772
|
-
throw new Error(
|
|
2773
|
-
"Conflicting OAuth credentials match the active GitHub Copilot runtime account."
|
|
2774
|
-
);
|
|
2682
|
+
throw new Error("Conflicting OAuth credentials match the active GitHub Copilot runtime account.");
|
|
2775
2683
|
}
|
|
2776
2684
|
const match = matches.values().next().value;
|
|
2777
2685
|
if (!match) {
|
|
@@ -2850,9 +2758,7 @@ function hasOfficialUrlOrigin(value, providerId) {
|
|
|
2850
2758
|
}
|
|
2851
2759
|
}
|
|
2852
2760
|
function headerValue(headers, name) {
|
|
2853
|
-
const entry = Object.entries(headers ?? {}).find(
|
|
2854
|
-
([candidate]) => candidate.toLowerCase() === name.toLowerCase()
|
|
2855
|
-
);
|
|
2761
|
+
const entry = Object.entries(headers ?? {}).find(([candidate]) => candidate.toLowerCase() === name.toLowerCase());
|
|
2856
2762
|
return entry?.[1] ?? void 0;
|
|
2857
2763
|
}
|
|
2858
2764
|
function hasHeader(headers, name) {
|
|
@@ -3051,9 +2957,7 @@ async function resolveCodexResetAuth(ctx, salt = AUTH_FINGERPRINT_SALT, credenti
|
|
|
3051
2957
|
apiKey: resolvedAccess,
|
|
3052
2958
|
headers,
|
|
3053
2959
|
fingerprint: fingerprintResolvedAuth({ headers }, salt),
|
|
3054
|
-
secrets: [
|
|
3055
|
-
.../* @__PURE__ */ new Set([...auth.secrets, storedAccess, resolvedAccess, authorization, accountId])
|
|
3056
|
-
],
|
|
2960
|
+
secrets: [.../* @__PURE__ */ new Set([...auth.secrets, storedAccess, resolvedAccess, authorization, accountId])],
|
|
3057
2961
|
model: auth.model
|
|
3058
2962
|
};
|
|
3059
2963
|
}
|
|
@@ -3102,9 +3006,7 @@ function normalizeCodexResetCreditsPayload(payload) {
|
|
|
3102
3006
|
if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
|
|
3103
3007
|
throw new Error("Codex reset credits response returned invalid credits.");
|
|
3104
3008
|
}
|
|
3105
|
-
const options = (rawCredits ?? []).map(asObject14).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
|
|
3106
|
-
(left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
|
|
3107
|
-
).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
|
|
3009
|
+
const options = (rawCredits ?? []).map(asObject14).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort((left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
|
|
3108
3010
|
if (availableCount > 0 && options.length === 0) {
|
|
3109
3011
|
options.push(genericCodexResetOption());
|
|
3110
3012
|
}
|
|
@@ -3219,9 +3121,7 @@ function bearerToken2(authorization) {
|
|
|
3219
3121
|
return /^Bearer\s+(.+)$/iu.exec(authorization ?? "")?.[1];
|
|
3220
3122
|
}
|
|
3221
3123
|
function headerValue2(headers, name) {
|
|
3222
|
-
return Object.entries(headers).find(
|
|
3223
|
-
([candidate]) => candidate.toLowerCase() === name.toLowerCase()
|
|
3224
|
-
)?.[1];
|
|
3124
|
+
return Object.entries(headers).find(([candidate]) => candidate.toLowerCase() === name.toLowerCase())?.[1];
|
|
3225
3125
|
}
|
|
3226
3126
|
|
|
3227
3127
|
// src/format.ts
|
|
@@ -3322,9 +3222,7 @@ function formatCodexReport(lines, report2) {
|
|
|
3322
3222
|
if (metric2.id === "reset-credits") {
|
|
3323
3223
|
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
|
|
3324
3224
|
} else if (metric2.id === "credits") {
|
|
3325
|
-
lines.push(
|
|
3326
|
-
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3327
|
-
);
|
|
3225
|
+
lines.push(`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3328
3226
|
}
|
|
3329
3227
|
}
|
|
3330
3228
|
}
|
|
@@ -3346,9 +3244,7 @@ function formatDeepSeekStatusline(report2) {
|
|
|
3346
3244
|
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
3347
3245
|
if (availability?.value !== "available") return "deepseek API unavailable";
|
|
3348
3246
|
const totals = ["CNY", "USD"].flatMap((currency) => {
|
|
3349
|
-
const metric2 = report2.metrics.find(
|
|
3350
|
-
(candidate) => candidate.id === `${currency.toLowerCase()}-total`
|
|
3351
|
-
);
|
|
3247
|
+
const metric2 = report2.metrics.find((candidate) => candidate.id === `${currency.toLowerCase()}-total`);
|
|
3352
3248
|
return metric2 ? [`${currency} ${metric2.value}`] : [];
|
|
3353
3249
|
});
|
|
3354
3250
|
return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
|
|
@@ -3412,9 +3308,7 @@ function formatGitHubCopilotStatusline(report2) {
|
|
|
3412
3308
|
return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
|
|
3413
3309
|
}
|
|
3414
3310
|
function findGitHubCopilotQuota(report2) {
|
|
3415
|
-
return report2.buckets.find(
|
|
3416
|
-
(bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
|
|
3417
|
-
);
|
|
3311
|
+
return report2.buckets.find((bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id));
|
|
3418
3312
|
}
|
|
3419
3313
|
function compactGitHubCopilotQuotaKind(bucket) {
|
|
3420
3314
|
if (bucket?.id === "ai-credits") return "credits";
|
|
@@ -3433,9 +3327,7 @@ function formatOpenRouterReport(lines, report2) {
|
|
|
3433
3327
|
lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
3434
3328
|
}
|
|
3435
3329
|
for (const metric2 of report2.metrics) {
|
|
3436
|
-
lines.push(
|
|
3437
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3438
|
-
);
|
|
3330
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3439
3331
|
}
|
|
3440
3332
|
}
|
|
3441
3333
|
function formatOpenCodeZenReport(lines, report2) {
|
|
@@ -3497,9 +3389,7 @@ function formatKimiCodingStatusline(report2) {
|
|
|
3497
3389
|
for (const bucket of selected) {
|
|
3498
3390
|
if (!bucket.limit || bucket.remaining === void 0) continue;
|
|
3499
3391
|
const fallback = bucket.id === "weekly" ? "weekly" : "5h";
|
|
3500
|
-
parts.push(
|
|
3501
|
-
`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`
|
|
3502
|
-
);
|
|
3392
|
+
parts.push(`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`);
|
|
3503
3393
|
}
|
|
3504
3394
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3505
3395
|
}
|
|
@@ -3557,9 +3447,7 @@ function formatMiniMaxStatusline(report2, model) {
|
|
|
3557
3447
|
}
|
|
3558
3448
|
function selectMiniMaxGroup(report2, model) {
|
|
3559
3449
|
const groups = [
|
|
3560
|
-
...new Set(
|
|
3561
|
-
report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
|
|
3562
|
-
)
|
|
3450
|
+
...new Set(report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0))
|
|
3563
3451
|
];
|
|
3564
3452
|
if (groups.length <= 1) return groups[0];
|
|
3565
3453
|
if (model && model.provider !== report2.providerId) return void 0;
|
|
@@ -3575,9 +3463,7 @@ function selectMiniMaxGroup(report2, model) {
|
|
|
3575
3463
|
);
|
|
3576
3464
|
if (exact) return exact.group;
|
|
3577
3465
|
const wildcard = candidates.find(
|
|
3578
|
-
({ patterns }) => patterns.some(
|
|
3579
|
-
(pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
|
|
3580
|
-
)
|
|
3466
|
+
({ patterns }) => patterns.some((pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key)))
|
|
3581
3467
|
);
|
|
3582
3468
|
if (wildcard) return wildcard.group;
|
|
3583
3469
|
}
|
|
@@ -3608,9 +3494,7 @@ function formatZaiStatusline(report2) {
|
|
|
3608
3494
|
for (const bucket of selected) {
|
|
3609
3495
|
if (!bucket?.limit || bucket.remaining === void 0) continue;
|
|
3610
3496
|
const fallback = bucket.id === "weekly" ? "weekly" : "5h";
|
|
3611
|
-
parts.push(
|
|
3612
|
-
`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`
|
|
3613
|
-
);
|
|
3497
|
+
parts.push(`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`);
|
|
3614
3498
|
}
|
|
3615
3499
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3616
3500
|
}
|
|
@@ -3644,9 +3528,7 @@ function formatXaiReport(lines, report2) {
|
|
|
3644
3528
|
lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
|
|
3645
3529
|
}
|
|
3646
3530
|
for (const metric2 of report2.metrics) {
|
|
3647
|
-
lines.push(
|
|
3648
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3649
|
-
);
|
|
3531
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3650
3532
|
}
|
|
3651
3533
|
}
|
|
3652
3534
|
function formatZaiReport(lines, report2) {
|
|
@@ -3668,9 +3550,7 @@ function formatZaiReport(lines, report2) {
|
|
|
3668
3550
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
|
|
3669
3551
|
}
|
|
3670
3552
|
for (const metric2 of report2.metrics) {
|
|
3671
|
-
lines.push(
|
|
3672
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3673
|
-
);
|
|
3553
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3674
3554
|
}
|
|
3675
3555
|
}
|
|
3676
3556
|
function formatGenericReport(lines, report2) {
|
|
@@ -3680,9 +3560,7 @@ function formatGenericReport(lines, report2) {
|
|
|
3680
3560
|
);
|
|
3681
3561
|
}
|
|
3682
3562
|
for (const metric2 of report2.metrics) {
|
|
3683
|
-
lines.push(
|
|
3684
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3685
|
-
);
|
|
3563
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3686
3564
|
}
|
|
3687
3565
|
}
|
|
3688
3566
|
function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
|
|
@@ -3690,9 +3568,7 @@ function formatCodexStatusline(report2, model, now = Date.now(), showResetCountd
|
|
|
3690
3568
|
if (!group) return formatCodexCreditsStatus(report2);
|
|
3691
3569
|
const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
|
|
3692
3570
|
const labelBucket = buckets[0];
|
|
3693
|
-
const parts = [
|
|
3694
|
-
group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
|
|
3695
|
-
];
|
|
3571
|
+
const parts = [group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`];
|
|
3696
3572
|
for (const bucket of buckets) {
|
|
3697
3573
|
if (bucket.remaining === void 0) continue;
|
|
3698
3574
|
const percent = `${clampPercent4(bucket.remaining).toFixed(0)}%`;
|
|
@@ -3722,9 +3598,7 @@ function selectCodexGroup(report2, model) {
|
|
|
3722
3598
|
}
|
|
3723
3599
|
const modelKeys = normalizedModelKeys(model);
|
|
3724
3600
|
for (const group of groups) {
|
|
3725
|
-
const bucket = report2.buckets.find(
|
|
3726
|
-
(candidate) => (candidate.groupId ?? candidate.id) === group
|
|
3727
|
-
);
|
|
3601
|
+
const bucket = report2.buckets.find((candidate) => (candidate.groupId ?? candidate.id) === group);
|
|
3728
3602
|
const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
|
|
3729
3603
|
if (keys.some((key) => modelKeys.has(key))) return group;
|
|
3730
3604
|
}
|
|
@@ -3787,20 +3661,15 @@ function formatWindowLabel(minutes, fallback, compact) {
|
|
|
3787
3661
|
return `${minutes}m`;
|
|
3788
3662
|
}
|
|
3789
3663
|
function formatResetCountdown(resetsAt, now) {
|
|
3790
|
-
if (resetsAt === void 0 || !Number.isFinite(resetsAt) || !Number.isFinite(now))
|
|
3791
|
-
return void 0;
|
|
3664
|
+
if (resetsAt === void 0 || !Number.isFinite(resetsAt) || !Number.isFinite(now)) return void 0;
|
|
3792
3665
|
const totalMinutes = Math.max(0, Math.ceil((resetsAt * 1e3 - now) / 6e4));
|
|
3793
3666
|
const days = Math.floor(totalMinutes / 1440);
|
|
3794
3667
|
const hours = Math.floor(totalMinutes % 1440 / 60);
|
|
3795
3668
|
const minutes = totalMinutes % 60;
|
|
3796
3669
|
if (days > 0) {
|
|
3797
|
-
return [
|
|
3798
|
-
`${String(days)}d`,
|
|
3799
|
-
hours > 0 ? `${String(hours)}h` : minutes > 0 ? `${String(minutes)}m` : ""
|
|
3800
|
-
].filter(Boolean).join("");
|
|
3670
|
+
return [`${String(days)}d`, hours > 0 ? `${String(hours)}h` : minutes > 0 ? `${String(minutes)}m` : ""].filter(Boolean).join("");
|
|
3801
3671
|
}
|
|
3802
|
-
if (hours > 0)
|
|
3803
|
-
return [`${String(hours)}h`, minutes > 0 ? `${String(minutes)}m` : ""].filter(Boolean).join("");
|
|
3672
|
+
if (hours > 0) return [`${String(hours)}h`, minutes > 0 ? `${String(minutes)}m` : ""].filter(Boolean).join("");
|
|
3804
3673
|
return `${String(minutes)}m`;
|
|
3805
3674
|
}
|
|
3806
3675
|
function formatMetricValue(value, unit) {
|
|
@@ -3938,24 +3807,13 @@ function createUsageSettingsRuntime(options = {}) {
|
|
|
3938
3807
|
return structuredClone(state);
|
|
3939
3808
|
}),
|
|
3940
3809
|
updateSelectedTarget: (providerId, targetId, signal, checkPublishedSelection) => enqueue(async () => {
|
|
3941
|
-
const transaction = await saveUsageTargetSelection(
|
|
3942
|
-
path,
|
|
3943
|
-
providerId,
|
|
3944
|
-
targetId,
|
|
3945
|
-
operations,
|
|
3946
|
-
signal
|
|
3947
|
-
);
|
|
3810
|
+
const transaction = await saveUsageTargetSelection(path, providerId, targetId, operations, signal);
|
|
3948
3811
|
try {
|
|
3949
3812
|
await checkPublishedSelection?.();
|
|
3950
3813
|
throwIfAborted(signal);
|
|
3951
3814
|
} catch (error) {
|
|
3952
3815
|
try {
|
|
3953
|
-
await restoreUsageSettingsState(
|
|
3954
|
-
path,
|
|
3955
|
-
transaction.saved,
|
|
3956
|
-
transaction.previous,
|
|
3957
|
-
operations
|
|
3958
|
-
);
|
|
3816
|
+
await restoreUsageSettingsState(path, transaction.saved, transaction.previous, operations);
|
|
3959
3817
|
state = transaction.previous;
|
|
3960
3818
|
} catch (rollbackError) {
|
|
3961
3819
|
state = await loadUsageSettings(path);
|
|
@@ -4133,10 +3991,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4133
3991
|
return;
|
|
4134
3992
|
}
|
|
4135
3993
|
if (!ctx.hasUI) throw new Error("/fast requires TUI or RPC mode.");
|
|
4136
|
-
const availability = codexFastAvailability(
|
|
4137
|
-
ctx.model,
|
|
4138
|
-
settingsRuntime.get().settings.codexFastMode
|
|
4139
|
-
);
|
|
3994
|
+
const availability = codexFastAvailability(ctx.model, settingsRuntime.get().settings.codexFastMode);
|
|
4140
3995
|
if (availability.kind === "not-codex") {
|
|
4141
3996
|
ctx.ui.notify("/fast is available only for the active OpenAI Codex model.", "warning");
|
|
4142
3997
|
return;
|
|
@@ -4146,10 +4001,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4146
4001
|
return;
|
|
4147
4002
|
}
|
|
4148
4003
|
if (settingsRuntime.get().kind === "invalid") {
|
|
4149
|
-
ctx.ui.notify(
|
|
4150
|
-
"pi-usage.json is invalid; repair it and run /reload before changing Fast mode.",
|
|
4151
|
-
"error"
|
|
4152
|
-
);
|
|
4004
|
+
ctx.ui.notify("pi-usage.json is invalid; repair it and run /reload before changing Fast mode.", "error");
|
|
4153
4005
|
return;
|
|
4154
4006
|
}
|
|
4155
4007
|
await toggle(ctx, !availability.enabled);
|
|
@@ -4169,10 +4021,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4169
4021
|
} catch (error) {
|
|
4170
4022
|
if (sessionController.signal.aborted || ownerGeneration !== generation) return;
|
|
4171
4023
|
if (ctx.hasUI) {
|
|
4172
|
-
ctx.ui.notify(
|
|
4173
|
-
`Could not load pi-usage.json; using defaults. ${errorMessage(error)}`,
|
|
4174
|
-
"warning"
|
|
4175
|
-
);
|
|
4024
|
+
ctx.ui.notify(`Could not load pi-usage.json; using defaults. ${errorMessage(error)}`, "warning");
|
|
4176
4025
|
}
|
|
4177
4026
|
return;
|
|
4178
4027
|
}
|
|
@@ -4180,10 +4029,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4180
4029
|
return;
|
|
4181
4030
|
}
|
|
4182
4031
|
if (ctx.hasUI && state.kind === "invalid") {
|
|
4183
|
-
ctx.ui.notify(
|
|
4184
|
-
`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`,
|
|
4185
|
-
"warning"
|
|
4186
|
-
);
|
|
4032
|
+
ctx.ui.notify(`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`, "warning");
|
|
4187
4033
|
}
|
|
4188
4034
|
refreshStatus(ctx);
|
|
4189
4035
|
})();
|
|
@@ -4192,11 +4038,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4192
4038
|
pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
|
|
4193
4039
|
}
|
|
4194
4040
|
pi.on("before_provider_request", (event, ctx) => {
|
|
4195
|
-
const rewritten = rewriteCodexFastPayload(
|
|
4196
|
-
event.payload,
|
|
4197
|
-
ctx.model,
|
|
4198
|
-
settingsRuntime.get().settings.codexFastMode
|
|
4199
|
-
);
|
|
4041
|
+
const rewritten = rewriteCodexFastPayload(event.payload, ctx.model, settingsRuntime.get().settings.codexFastMode);
|
|
4200
4042
|
const key = activeRequestKey(ctx);
|
|
4201
4043
|
if (key && ctx.model) {
|
|
4202
4044
|
pendingFastRequests.set(key, {
|
|
@@ -4209,11 +4051,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4209
4051
|
pi.on("message_end", (event, ctx) => {
|
|
4210
4052
|
const request = consumeFastRequest(ctx, event.message, pendingFastRequests);
|
|
4211
4053
|
if (request === NO_FAST_REQUEST) return void 0;
|
|
4212
|
-
const message = correctCodexFastMessageCost(
|
|
4213
|
-
event.message,
|
|
4214
|
-
request.model,
|
|
4215
|
-
request.fastRequested
|
|
4216
|
-
);
|
|
4054
|
+
const message = correctCodexFastMessageCost(event.message, request.model, request.fastRequested);
|
|
4217
4055
|
return message ? { message } : void 0;
|
|
4218
4056
|
});
|
|
4219
4057
|
pi.on("session_shutdown", async () => {
|
|
@@ -4228,10 +4066,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4228
4066
|
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
|
|
4229
4067
|
},
|
|
4230
4068
|
decorateStatus(model, status) {
|
|
4231
|
-
return codexFastStatusLabel(
|
|
4232
|
-
status,
|
|
4233
|
-
codexFastIsEffective(model, settingsRuntime.get().settings.codexFastMode)
|
|
4234
|
-
);
|
|
4069
|
+
return codexFastStatusLabel(status, codexFastIsEffective(model, settingsRuntime.get().settings.codexFastMode));
|
|
4235
4070
|
},
|
|
4236
4071
|
toggle
|
|
4237
4072
|
};
|
|
@@ -4293,9 +4128,7 @@ function isTimeoutError(error) {
|
|
|
4293
4128
|
|
|
4294
4129
|
// src/usage-settings-ui.ts
|
|
4295
4130
|
import { stripVTControlCharacters } from "node:util";
|
|
4296
|
-
import {
|
|
4297
|
-
getSettingsListTheme
|
|
4298
|
-
} from "@earendil-works/pi-coding-agent";
|
|
4131
|
+
import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
4299
4132
|
import { Key, matchesKey, SettingsList, Text } from "@earendil-works/pi-tui";
|
|
4300
4133
|
var OFF = "Off";
|
|
4301
4134
|
var ON = "On";
|
|
@@ -4379,13 +4212,9 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
4379
4212
|
parentSignal.addEventListener("abort", cancel, { once: true });
|
|
4380
4213
|
return {
|
|
4381
4214
|
render(width) {
|
|
4382
|
-
const title = new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 0).render(
|
|
4383
|
-
width
|
|
4384
|
-
);
|
|
4215
|
+
const title = new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 0).render(width);
|
|
4385
4216
|
const content = settingsList.render(width);
|
|
4386
|
-
const focusedRow = content.findIndex(
|
|
4387
|
-
(line) => /^[→›]\s/u.test(stripVTControlCharacters(line))
|
|
4388
|
-
);
|
|
4217
|
+
const focusedRow = content.findIndex((line) => /^[→›]\s/u.test(stripVTControlCharacters(line)));
|
|
4389
4218
|
const terminalRows = Number.isFinite(tui.terminal?.rows) ? Math.floor(tui.terminal.rows) : 24;
|
|
4390
4219
|
const [ruleLine = ""] = rule.render(width);
|
|
4391
4220
|
return renderBoundedFrame({
|
|
@@ -4507,12 +4336,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4507
4336
|
}
|
|
4508
4337
|
const showCodexResetCountdown = outcome.state.report.providerId === "openai-codex" && settingsRuntime.get().settings.codexStatusResetCountdown;
|
|
4509
4338
|
const now = Date.now();
|
|
4510
|
-
const rawValue = formatUsageStatusline(
|
|
4511
|
-
outcome.state.report,
|
|
4512
|
-
model,
|
|
4513
|
-
now,
|
|
4514
|
-
showCodexResetCountdown
|
|
4515
|
-
);
|
|
4339
|
+
const rawValue = formatUsageStatusline(outcome.state.report, model, now, showCodexResetCountdown);
|
|
4516
4340
|
const value = rawValue ? fastRuntime.decorateStatus(model, rawValue) : void 0;
|
|
4517
4341
|
if (!safeSetStatus(ctx, value)) return;
|
|
4518
4342
|
if (shouldSchedule && sessionActive) scheduleStatusRefresh(ctx, model);
|
|
@@ -4737,15 +4561,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4737
4561
|
if (queryId !== void 0 && latestQueries.get(failureKey) === queryId) {
|
|
4738
4562
|
latestQueries.delete(failureKey);
|
|
4739
4563
|
}
|
|
4740
|
-
return queryAdapterState(
|
|
4741
|
-
ctx,
|
|
4742
|
-
adapter,
|
|
4743
|
-
displayState,
|
|
4744
|
-
true,
|
|
4745
|
-
signal,
|
|
4746
|
-
authRetry + 1,
|
|
4747
|
-
deadlineAt
|
|
4748
|
-
);
|
|
4564
|
+
return queryAdapterState(ctx, adapter, displayState, true, signal, authRetry + 1, deadlineAt);
|
|
4749
4565
|
}
|
|
4750
4566
|
const message = errorMessage(error);
|
|
4751
4567
|
const now = Date.now();
|
|
@@ -4754,12 +4570,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4754
4570
|
}
|
|
4755
4571
|
if (queryId === void 0 || latestQueries.get(failureKey) === queryId) {
|
|
4756
4572
|
if (adapter.invalidateCacheOnFailure) cache.delete(adapter.id, queryFingerprint);
|
|
4757
|
-
setBoundedMap(
|
|
4758
|
-
failureBackoff,
|
|
4759
|
-
failureKey,
|
|
4760
|
-
{ until: now + FAILURE_BACKOFF_MS, message },
|
|
4761
|
-
MAX_ACCOUNT_STATES
|
|
4762
|
-
);
|
|
4573
|
+
setBoundedMap(failureBackoff, failureKey, { until: now + FAILURE_BACKOFF_MS, message }, MAX_ACCOUNT_STATES);
|
|
4763
4574
|
}
|
|
4764
4575
|
return {
|
|
4765
4576
|
state: {
|
|
@@ -4801,13 +4612,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4801
4612
|
throw abortError();
|
|
4802
4613
|
}
|
|
4803
4614
|
};
|
|
4804
|
-
const choices = await listUsageTargets(
|
|
4805
|
-
adapter,
|
|
4806
|
-
auth,
|
|
4807
|
-
signal,
|
|
4808
|
-
Math.max(1, deadlineAt - Date.now()),
|
|
4809
|
-
guard
|
|
4810
|
-
);
|
|
4615
|
+
const choices = await listUsageTargets(adapter, auth, signal, Math.max(1, deadlineAt - Date.now()), guard);
|
|
4811
4616
|
return { choices, fingerprint: auth.fingerprint };
|
|
4812
4617
|
};
|
|
4813
4618
|
const queryCurrentState = async (ctx, model, force, signal) => {
|
|
@@ -4959,12 +4764,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4959
4764
|
const controller = new AbortController();
|
|
4960
4765
|
activeControllers.add(controller);
|
|
4961
4766
|
try {
|
|
4962
|
-
let stableCurrent = await queryStableCurrent(
|
|
4963
|
-
ctx,
|
|
4964
|
-
false,
|
|
4965
|
-
controller,
|
|
4966
|
-
"Checking current usage\u2026"
|
|
4967
|
-
);
|
|
4767
|
+
let stableCurrent = await queryStableCurrent(ctx, false, controller, "Checking current usage\u2026");
|
|
4968
4768
|
if (!stableCurrent) return;
|
|
4969
4769
|
publishStableCurrent(ctx, stableCurrent);
|
|
4970
4770
|
let current = stableCurrent.outcome;
|
|
@@ -5206,12 +5006,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5206
5006
|
(signal) => queryAdapterState(ctx, adapter, "configured", true, signal)
|
|
5207
5007
|
);
|
|
5208
5008
|
if (!outcome) return { kind: "stay" };
|
|
5209
|
-
const revalidated = await queryStableCurrent(
|
|
5210
|
-
ctx,
|
|
5211
|
-
false,
|
|
5212
|
-
controller,
|
|
5213
|
-
"Revalidating current usage\u2026"
|
|
5214
|
-
);
|
|
5009
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Revalidating current usage\u2026");
|
|
5215
5010
|
if (!revalidated) return { kind: "stay" };
|
|
5216
5011
|
stableCurrent = revalidated;
|
|
5217
5012
|
current = revalidated.outcome;
|
|
@@ -5240,12 +5035,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5240
5035
|
}
|
|
5241
5036
|
);
|
|
5242
5037
|
fastState = settingsRuntime.get();
|
|
5243
|
-
const revalidated = await queryStableCurrent(
|
|
5244
|
-
ctx,
|
|
5245
|
-
false,
|
|
5246
|
-
controller,
|
|
5247
|
-
"Applying usage settings\u2026"
|
|
5248
|
-
);
|
|
5038
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Applying usage settings\u2026");
|
|
5249
5039
|
if (!revalidated) return { kind: "stay" };
|
|
5250
5040
|
stableCurrent = revalidated;
|
|
5251
5041
|
current = revalidated.outcome;
|
|
@@ -5297,9 +5087,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5297
5087
|
"revalidating current Codex reset authentication"
|
|
5298
5088
|
);
|
|
5299
5089
|
if (modelIdentity(ctx.model) !== expectedModel || revalidated.fingerprint !== auth.fingerprint) {
|
|
5300
|
-
throw new Error(
|
|
5301
|
-
"The active Codex model or account changed while loading usage limit resets."
|
|
5302
|
-
);
|
|
5090
|
+
throw new Error("The active Codex model or account changed while loading usage limit resets.");
|
|
5303
5091
|
}
|
|
5304
5092
|
return { availability, auth, expectedModel };
|
|
5305
5093
|
}
|
|
@@ -5356,28 +5144,14 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5356
5144
|
"revalidating current Codex reset authentication"
|
|
5357
5145
|
);
|
|
5358
5146
|
if (modelIdentity(ctx.model) !== expectedModel || auth.fingerprint !== expectedFingerprint) {
|
|
5359
|
-
throw new Error(
|
|
5360
|
-
"The active Codex model or account changed; the reset was not used."
|
|
5361
|
-
);
|
|
5147
|
+
throw new Error("The active Codex model or account changed; the reset was not used.");
|
|
5362
5148
|
}
|
|
5363
|
-
const outcome = await consumeCodexResetCredit(
|
|
5364
|
-
auth,
|
|
5365
|
-
option,
|
|
5366
|
-
attemptId,
|
|
5367
|
-
signal,
|
|
5368
|
-
DEFAULT_TIMEOUT_MS
|
|
5369
|
-
);
|
|
5149
|
+
const outcome = await consumeCodexResetCredit(auth, option, attemptId, signal, DEFAULT_TIMEOUT_MS);
|
|
5370
5150
|
invalidateProviderState("openai-codex");
|
|
5371
5151
|
const model = ctx.model;
|
|
5372
5152
|
if (modelIdentity(model) !== expectedModel) return { outcome };
|
|
5373
5153
|
const refreshed = await queryCurrentState(ctx, model, true, signal);
|
|
5374
|
-
const stable = await outcomeStillCurrent(
|
|
5375
|
-
ctx,
|
|
5376
|
-
model,
|
|
5377
|
-
menuGeneration,
|
|
5378
|
-
refreshed,
|
|
5379
|
-
signal
|
|
5380
|
-
);
|
|
5154
|
+
const stable = await outcomeStillCurrent(ctx, model, menuGeneration, refreshed, signal);
|
|
5381
5155
|
return stable ? { outcome, refreshed, model } : { outcome };
|
|
5382
5156
|
},
|
|
5383
5157
|
false
|
|
@@ -5407,12 +5181,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5407
5181
|
return { kind: "to", screen: "reset-picker" };
|
|
5408
5182
|
},
|
|
5409
5183
|
refresh: async () => {
|
|
5410
|
-
const refreshed = await queryStableCurrent(
|
|
5411
|
-
ctx,
|
|
5412
|
-
true,
|
|
5413
|
-
controller,
|
|
5414
|
-
"Refreshing current usage\u2026"
|
|
5415
|
-
);
|
|
5184
|
+
const refreshed = await queryStableCurrent(ctx, true, controller, "Refreshing current usage\u2026");
|
|
5416
5185
|
if (!refreshed) return { kind: "stay" };
|
|
5417
5186
|
stableCurrent = refreshed;
|
|
5418
5187
|
publishStableCurrent(ctx, refreshed);
|
|
@@ -5421,9 +5190,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5421
5190
|
return { kind: "stay" };
|
|
5422
5191
|
},
|
|
5423
5192
|
another: async () => {
|
|
5424
|
-
const others = configuredAdapters(ctx).filter(
|
|
5425
|
-
(adapter) => adapter.id !== ctx.model?.provider
|
|
5426
|
-
);
|
|
5193
|
+
const others = configuredAdapters(ctx).filter((adapter) => adapter.id !== ctx.model?.provider);
|
|
5427
5194
|
if (others.length === 0) {
|
|
5428
5195
|
ctx.ui.notify("No other supported provider has configured runtime auth.", "info");
|
|
5429
5196
|
return { kind: "stay" };
|
|
@@ -5454,12 +5221,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5454
5221
|
);
|
|
5455
5222
|
if (!outcome) return { kind: "back" };
|
|
5456
5223
|
}
|
|
5457
|
-
const revalidated = await queryStableCurrent(
|
|
5458
|
-
ctx,
|
|
5459
|
-
false,
|
|
5460
|
-
controller,
|
|
5461
|
-
"Revalidating current usage\u2026"
|
|
5462
|
-
);
|
|
5224
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Revalidating current usage\u2026");
|
|
5463
5225
|
if (!revalidated) return { kind: "back" };
|
|
5464
5226
|
stableCurrent = revalidated;
|
|
5465
5227
|
current = revalidated.outcome;
|
|
@@ -5502,12 +5264,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5502
5264
|
message: errorMessage(result.reason)
|
|
5503
5265
|
};
|
|
5504
5266
|
});
|
|
5505
|
-
const revalidated = await queryStableCurrent(
|
|
5506
|
-
ctx,
|
|
5507
|
-
false,
|
|
5508
|
-
controller,
|
|
5509
|
-
"Revalidating current usage\u2026"
|
|
5510
|
-
);
|
|
5267
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Revalidating current usage\u2026");
|
|
5511
5268
|
if (!revalidated) return { kind: "stay" };
|
|
5512
5269
|
stableCurrent = revalidated;
|
|
5513
5270
|
current = revalidated.outcome;
|
|
@@ -5533,10 +5290,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5533
5290
|
description: "Show usage for the current runtime account",
|
|
5534
5291
|
handler: async (args, ctx) => {
|
|
5535
5292
|
if (args.trim()) {
|
|
5536
|
-
ctx.ui.notify(
|
|
5537
|
-
"/usage does not accept arguments; choose an action from its menu.",
|
|
5538
|
-
"warning"
|
|
5539
|
-
);
|
|
5293
|
+
ctx.ui.notify("/usage does not accept arguments; choose an action from its menu.", "warning");
|
|
5540
5294
|
return;
|
|
5541
5295
|
}
|
|
5542
5296
|
try {
|
|
@@ -5586,12 +5340,9 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5586
5340
|
activeCurrentIdentity = void 0;
|
|
5587
5341
|
safeSetStatus(ctx, void 0);
|
|
5588
5342
|
});
|
|
5589
|
-
fastRuntime = registerCodexFastMode(
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
(ctx) => startStatusRefresh(ctx, ctx.model, false),
|
|
5593
|
-
{ registerSessionStart: false }
|
|
5594
|
-
);
|
|
5343
|
+
fastRuntime = registerCodexFastMode(pi, settingsRuntime, (ctx) => startStatusRefresh(ctx, ctx.model, false), {
|
|
5344
|
+
registerSessionStart: false
|
|
5345
|
+
});
|
|
5595
5346
|
}
|
|
5596
5347
|
export {
|
|
5597
5348
|
CODEX_FAST_MODEL_IDS,
|