@narumitw/pi-usage 0.60.6 → 0.60.8
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 +104 -363
- 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 +74 -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 +118 -145
- package/src/usage-targets.ts +98 -114
- package/src/usage.ts +1264 -1426
package/dist/index.ts
CHANGED
|
@@ -80,9 +80,7 @@ function hasCompleteUsage(value) {
|
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
function costsEqual(left, right) {
|
|
83
|
-
return ["input", "output", "cacheRead", "cacheWrite", "total"].every(
|
|
84
|
-
(key) => left[key] === right[key]
|
|
85
|
-
);
|
|
83
|
+
return ["input", "output", "cacheRead", "cacheWrite", "total"].every((key) => left[key] === right[key]);
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
// src/codex-resets.ts
|
|
@@ -157,8 +155,7 @@ function fingerprintResolvedAuth(auth, salt) {
|
|
|
157
155
|
}
|
|
158
156
|
async function runWithConcurrency(items, limit, worker, signal) {
|
|
159
157
|
if (signal.aborted) throw abortError();
|
|
160
|
-
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
161
|
-
throw new Error("Concurrency limit must be positive.");
|
|
158
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new Error("Concurrency limit must be positive.");
|
|
162
159
|
const results = new Array(items.length);
|
|
163
160
|
let nextIndex = 0;
|
|
164
161
|
const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
@@ -194,10 +191,9 @@ async function awaitWithDeadline(operation, signal, timeoutMs, description) {
|
|
|
194
191
|
"abort",
|
|
195
192
|
() => {
|
|
196
193
|
reject(
|
|
197
|
-
signal.aborted ? abortError() : Object.assign(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
194
|
+
signal.aborted ? abortError() : Object.assign(new Error(`Timed out after ${Math.round(timeoutMs / 1e3)}s ${description}.`), {
|
|
195
|
+
name: "TimeoutError"
|
|
196
|
+
})
|
|
201
197
|
);
|
|
202
198
|
},
|
|
203
199
|
{ once: true }
|
|
@@ -283,9 +279,7 @@ function truncate(value, maxChars) {
|
|
|
283
279
|
}
|
|
284
280
|
|
|
285
281
|
// src/oauth-credential-source.ts
|
|
286
|
-
import {
|
|
287
|
-
readStoredCredential
|
|
288
|
-
} from "@earendil-works/pi-coding-agent";
|
|
282
|
+
import { readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
289
283
|
var OAUTH_CREDENTIAL_SOURCE_CHANNEL = "oauth:credential-source:v1";
|
|
290
284
|
function createOAuthCredentialCandidateReader(pi, credentialReader = readStoredCredential) {
|
|
291
285
|
return (ctx, providerId) => collectOAuthCredentialCandidates(pi, ctx, providerId, credentialReader);
|
|
@@ -397,13 +391,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
|
|
|
397
391
|
const id = asString(value?.metered_feature) ?? asString(value?.limit_name);
|
|
398
392
|
if (!value || !id) continue;
|
|
399
393
|
try {
|
|
400
|
-
normalizeRateLimitGroup(
|
|
401
|
-
buckets,
|
|
402
|
-
id,
|
|
403
|
-
asString(value.limit_name) ?? id,
|
|
404
|
-
value.rate_limit,
|
|
405
|
-
true
|
|
406
|
-
);
|
|
394
|
+
normalizeRateLimitGroup(buckets, id, asString(value.limit_name) ?? id, value.rate_limit, true);
|
|
407
395
|
} catch {
|
|
408
396
|
}
|
|
409
397
|
}
|
|
@@ -657,9 +645,7 @@ function createFireworksAdapter(fetchProviderJson2) {
|
|
|
657
645
|
if (!pageToken) break;
|
|
658
646
|
}
|
|
659
647
|
if (pageToken) {
|
|
660
|
-
throw new Error(
|
|
661
|
-
`Fireworks account listing exceeded ${FIREWORKS_MAX_ACCOUNT_PAGES} pages.`
|
|
662
|
-
);
|
|
648
|
+
throw new Error(`Fireworks account listing exceeded ${FIREWORKS_MAX_ACCOUNT_PAGES} pages.`);
|
|
663
649
|
}
|
|
664
650
|
return accounts.map((id) => ({ id, label: id }));
|
|
665
651
|
}
|
|
@@ -726,9 +712,7 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
|
|
|
726
712
|
});
|
|
727
713
|
}
|
|
728
714
|
}
|
|
729
|
-
const notes = [
|
|
730
|
-
"Rated line items may differ from the final invoice once credits or adjustments are applied."
|
|
731
|
-
];
|
|
715
|
+
const notes = ["Rated line items may differ from the final invoice once credits or adjustments are applied."];
|
|
732
716
|
if (metrics.length === 0) {
|
|
733
717
|
notes.push("Fireworks returned no rated line items for the last 30 days.");
|
|
734
718
|
}
|
|
@@ -807,14 +791,8 @@ function fireworksNextPageToken(value) {
|
|
|
807
791
|
function fireworksBillingSummaryUrl(accountId, startedAt) {
|
|
808
792
|
const dayMs = 24 * 60 * 60 * 1e3;
|
|
809
793
|
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
|
-
);
|
|
794
|
+
const url = new URL(`/v1/accounts/${accountId}/billing/summary`, FIREWORKS_BILLING_SUMMARY_ORIGIN);
|
|
795
|
+
url.searchParams.set("startTime", dayFloor(startedAt - (FIREWORKS_SPEND_WINDOW_DAYS - 1) * dayMs));
|
|
818
796
|
url.searchParams.set("endTime", dayFloor(startedAt + dayMs));
|
|
819
797
|
return url.toString();
|
|
820
798
|
}
|
|
@@ -848,10 +826,7 @@ function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
|
|
|
848
826
|
if (entitlement === void 0 || rawRemaining === void 0) {
|
|
849
827
|
throw new Error(`GitHub Copilot ${label.toLowerCase()} quota was incomplete.`);
|
|
850
828
|
}
|
|
851
|
-
const overageUsed = Math.max(
|
|
852
|
-
asNonnegativeNumber(premium.overage_count) ?? 0,
|
|
853
|
-
Math.max(0, -rawRemaining)
|
|
854
|
-
);
|
|
829
|
+
const overageUsed = Math.max(asNonnegativeNumber(premium.overage_count) ?? 0, Math.max(0, -rawRemaining));
|
|
855
830
|
if (overageUsed > 0) {
|
|
856
831
|
metrics.push({
|
|
857
832
|
id: "overage-used",
|
|
@@ -983,15 +958,21 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
|
983
958
|
function parseUsageRow(value, windowMinutes, label) {
|
|
984
959
|
const row = asObject6(value);
|
|
985
960
|
if (!row) return void 0;
|
|
986
|
-
const used = asNonnegativeInteger2(row.used);
|
|
987
961
|
const limit = asNonnegativeInteger2(row.limit);
|
|
988
|
-
if (
|
|
962
|
+
if (limit === void 0 || limit === 0) return void 0;
|
|
963
|
+
const usedRaw = asNonnegativeInteger2(row.used);
|
|
964
|
+
const remainingRaw = asNonnegativeInteger2(row.remaining);
|
|
965
|
+
if (row.used !== void 0 && usedRaw === void 0 || row.remaining !== void 0 && remainingRaw === void 0) {
|
|
966
|
+
return void 0;
|
|
967
|
+
}
|
|
968
|
+
const used = usedRaw ?? (remainingRaw === void 0 ? 0 : Math.max(0, limit - remainingRaw));
|
|
969
|
+
const remaining = remainingRaw ?? Math.max(0, limit - used);
|
|
989
970
|
const resetsAt = asIsoEpochSeconds(row.resetTime);
|
|
990
971
|
return {
|
|
991
972
|
id: windowId(windowMinutes),
|
|
992
973
|
label,
|
|
993
974
|
used,
|
|
994
|
-
remaining
|
|
975
|
+
remaining,
|
|
995
976
|
limit,
|
|
996
977
|
unit: "count",
|
|
997
978
|
windowMinutes,
|
|
@@ -1018,9 +999,7 @@ function parseBoosterWallet(value) {
|
|
|
1018
999
|
const monthlyLimit = parseMoney(wallet.monthlyChargeLimit);
|
|
1019
1000
|
const monthlyUsed = parseMoney(wallet.monthlyUsed);
|
|
1020
1001
|
const currencies = new Set(
|
|
1021
|
-
[monthlyLimit?.currency, monthlyUsed?.currency].filter(
|
|
1022
|
-
(currency2) => currency2 !== void 0
|
|
1023
|
-
)
|
|
1002
|
+
[monthlyLimit?.currency, monthlyUsed?.currency].filter((currency2) => currency2 !== void 0)
|
|
1024
1003
|
);
|
|
1025
1004
|
if (currencies.size !== 1) return [];
|
|
1026
1005
|
const currency = currencies.values().next().value;
|
|
@@ -1091,22 +1070,9 @@ function asPositiveInteger(value) {
|
|
|
1091
1070
|
}
|
|
1092
1071
|
function asIsoEpochSeconds(value) {
|
|
1093
1072
|
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
|
-
);
|
|
1073
|
+
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
1074
|
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;
|
|
1075
|
+
const [, yearText, monthText, dayText, hourText, minuteText, secondText, , offsetHour, offsetMinute] = match;
|
|
1110
1076
|
const year = Number(yearText);
|
|
1111
1077
|
const month = Number(monthText);
|
|
1112
1078
|
const day = Number(dayText);
|
|
@@ -1159,12 +1125,7 @@ function normalizeBalance(providerId, payload, capturedAt) {
|
|
|
1159
1125
|
assertSuccess(payload);
|
|
1160
1126
|
const provider = PROVIDERS[providerId];
|
|
1161
1127
|
const metrics = [
|
|
1162
|
-
balanceMetric(
|
|
1163
|
-
"available-balance",
|
|
1164
|
-
"Available balance",
|
|
1165
|
-
payload.available_amount,
|
|
1166
|
-
provider.currency
|
|
1167
|
-
),
|
|
1128
|
+
balanceMetric("available-balance", "Available balance", payload.available_amount, provider.currency),
|
|
1168
1129
|
balanceMetric("cash-balance", "Cash balance", payload.cash_balance, provider.currency, true),
|
|
1169
1130
|
balanceMetric("voucher-balance", "Voucher balance", payload.voucher_balance, provider.currency),
|
|
1170
1131
|
balanceMetric("credit-balance", "Credit balance", payload.credit_balance, provider.currency),
|
|
@@ -1584,11 +1545,7 @@ function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
|
|
|
1584
1545
|
const metrics = [];
|
|
1585
1546
|
const notes = [];
|
|
1586
1547
|
if (config) {
|
|
1587
|
-
const period = normalizePeriod(
|
|
1588
|
-
config.currentPeriod,
|
|
1589
|
-
config.billingPeriodStart,
|
|
1590
|
-
config.billingPeriodEnd
|
|
1591
|
-
);
|
|
1548
|
+
const period = normalizePeriod(config.currentPeriod, config.billingPeriodStart, config.billingPeriodEnd);
|
|
1592
1549
|
const preferredPercent = optionalPercent2(config.creditUsagePercent, "creditUsagePercent");
|
|
1593
1550
|
if (preferredPercent !== void 0) {
|
|
1594
1551
|
buckets.push({
|
|
@@ -1686,8 +1643,7 @@ function normalizePeriod(currentPeriod, legacyStart, legacyEnd) {
|
|
|
1686
1643
|
function periodLabel(type, start) {
|
|
1687
1644
|
if (type === "USAGE_PERIOD_TYPE_WEEKLY") return "Weekly";
|
|
1688
1645
|
if (type === "USAGE_PERIOD_TYPE_MONTHLY") return "Monthly";
|
|
1689
|
-
if (type)
|
|
1690
|
-
return sanitizeDisplayText(type.replace(/^USAGE_PERIOD_TYPE_/u, "").replaceAll("_", " "), 40);
|
|
1646
|
+
if (type) return sanitizeDisplayText(type.replace(/^USAGE_PERIOD_TYPE_/u, "").replaceAll("_", " "), 40);
|
|
1691
1647
|
return start === void 0 ? void 0 : "Current period";
|
|
1692
1648
|
}
|
|
1693
1649
|
function optionalUsd(value, field) {
|
|
@@ -1833,13 +1789,7 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt,
|
|
|
1833
1789
|
addCountBucket(buckets, limit, "mcp-monthly", "MCP monthly allowance");
|
|
1834
1790
|
addUsageDetailMetrics(metrics, limit.usageDetails);
|
|
1835
1791
|
} else if (isPlanUsage && unit === 3) {
|
|
1836
|
-
addPercentBucket(
|
|
1837
|
-
buckets,
|
|
1838
|
-
limit,
|
|
1839
|
-
"five-hour",
|
|
1840
|
-
sessionWindowLabel(limit),
|
|
1841
|
-
sessionWindowMinutes(limit)
|
|
1842
|
-
);
|
|
1792
|
+
addPercentBucket(buckets, limit, "five-hour", sessionWindowLabel(limit), sessionWindowMinutes(limit));
|
|
1843
1793
|
} else if (isPlanUsage && unit === 6) {
|
|
1844
1794
|
const used = asNonnegativeNumber4(limit.currentValue);
|
|
1845
1795
|
const quota = asNonnegativeNumber4(limit.usage);
|
|
@@ -1857,9 +1807,7 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt,
|
|
|
1857
1807
|
const level = asString5(data.level);
|
|
1858
1808
|
const planLabel = plan?.name ?? level;
|
|
1859
1809
|
if (planLabel) {
|
|
1860
|
-
notes.push(
|
|
1861
|
-
plan?.renewsAt ? `Plan: ${planLabel} \xB7 renews ${plan.renewsAt}` : `Plan: ${planLabel}`
|
|
1862
|
-
);
|
|
1810
|
+
notes.push(plan?.renewsAt ? `Plan: ${planLabel} \xB7 renews ${plan.renewsAt}` : `Plan: ${planLabel}`);
|
|
1863
1811
|
}
|
|
1864
1812
|
return {
|
|
1865
1813
|
providerId,
|
|
@@ -1894,13 +1842,7 @@ function normalizeZaiSubscriptionPayload(payload) {
|
|
|
1894
1842
|
(candidate) => candidate.status !== void 0 || candidate.inCurrentPeriod !== void 0
|
|
1895
1843
|
);
|
|
1896
1844
|
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;
|
|
1845
|
+
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
1846
|
}
|
|
1905
1847
|
function planRenewalDate(value) {
|
|
1906
1848
|
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}/u.test(value)) return value.slice(0, 10);
|
|
@@ -2018,12 +1960,7 @@ async function listUsageTargets(adapter, auth, signal, timeoutMs, guard) {
|
|
|
2018
1960
|
if (!adapter.targets) return [];
|
|
2019
1961
|
const startedAt = Date.now();
|
|
2020
1962
|
await guard();
|
|
2021
|
-
const listed = await adapter.targets.list(
|
|
2022
|
-
auth,
|
|
2023
|
-
signal,
|
|
2024
|
-
remainingTargetTimeout(timeoutMs, startedAt),
|
|
2025
|
-
guard
|
|
2026
|
-
);
|
|
1963
|
+
const listed = await adapter.targets.list(auth, signal, remainingTargetTimeout(timeoutMs, startedAt), guard);
|
|
2027
1964
|
await guard();
|
|
2028
1965
|
remainingTargetTimeout(timeoutMs, startedAt);
|
|
2029
1966
|
const choices = normalizeUsageTargets(listed);
|
|
@@ -2149,13 +2086,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2149
2086
|
label: "ChatGPT subscription limits"
|
|
2150
2087
|
},
|
|
2151
2088
|
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
|
-
);
|
|
2089
|
+
const payload = await fetchProviderJson(CODEX_USAGE_URL, auth, signal, timeoutMs, "Codex usage endpoint");
|
|
2159
2090
|
return normalizeCodexBackendPayload(payload, Date.now());
|
|
2160
2091
|
}
|
|
2161
2092
|
},
|
|
@@ -2203,13 +2134,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2203
2134
|
displayName: "OpenRouter",
|
|
2204
2135
|
semantics: { kind: "api-key", label: "API-key spend limits" },
|
|
2205
2136
|
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
|
-
);
|
|
2137
|
+
const payload = await fetchProviderJson(OPENROUTER_KEY_URL, auth, signal, timeoutMs, "OpenRouter key endpoint");
|
|
2213
2138
|
return normalizeOpenRouterKeyPayload(payload, Date.now());
|
|
2214
2139
|
}
|
|
2215
2140
|
},
|
|
@@ -2218,8 +2143,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2218
2143
|
displayName: "Vercel AI Gateway",
|
|
2219
2144
|
semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
|
|
2220
2145
|
async query(auth, signal, timeoutMs, guard) {
|
|
2221
|
-
if (!guard)
|
|
2222
|
-
throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
2146
|
+
if (!guard) throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
2223
2147
|
const startedAt = Date.now();
|
|
2224
2148
|
await guard();
|
|
2225
2149
|
const payload = await fetchProviderJson(
|
|
@@ -2376,9 +2300,7 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
2376
2300
|
`${adapter.displayName} usage cannot send a custom provider base URL credential to the official usage endpoint.`
|
|
2377
2301
|
);
|
|
2378
2302
|
}
|
|
2379
|
-
const model = candidateModels(ctx, adapter.id).find(
|
|
2380
|
-
(candidate) => hasOfficialOrigin(candidate, adapter.id)
|
|
2381
|
-
);
|
|
2303
|
+
const model = candidateModels(ctx, adapter.id).find((candidate) => hasOfficialOrigin(candidate, adapter.id));
|
|
2382
2304
|
if (!model) return void 0;
|
|
2383
2305
|
const registry = ctx.modelRegistry;
|
|
2384
2306
|
const provider = registry.getProvider?.(adapter.id);
|
|
@@ -2453,15 +2375,7 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
2453
2375
|
if (!offered.ok) {
|
|
2454
2376
|
throw new Error("GitHub Copilot OAuth credential discovery failed closed.");
|
|
2455
2377
|
}
|
|
2456
|
-
return finalize(
|
|
2457
|
-
resolveGitHubCopilotUsageAuth(
|
|
2458
|
-
auth,
|
|
2459
|
-
model,
|
|
2460
|
-
salt,
|
|
2461
|
-
offered.candidates,
|
|
2462
|
-
offered.offeredCount === 0
|
|
2463
|
-
)
|
|
2464
|
-
);
|
|
2378
|
+
return finalize(resolveGitHubCopilotUsageAuth(auth, model, salt, offered.candidates, offered.offeredCount === 0));
|
|
2465
2379
|
}
|
|
2466
2380
|
if (adapter.id === "xai") {
|
|
2467
2381
|
const offered = candidateReader ? candidateReader(ctx, adapter.id) : fallbackOAuthCredentialCandidates(adapter.id, credentialReader);
|
|
@@ -2601,8 +2515,7 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2601
2515
|
signal: controller.signal
|
|
2602
2516
|
});
|
|
2603
2517
|
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" });
|
|
2518
|
+
if (controller.signal.aborted) throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2606
2519
|
const text = await readBoundedResponse(
|
|
2607
2520
|
response,
|
|
2608
2521
|
response.ok ? MAX_SUCCESS_BODY_BYTES : MAX_ERROR_BODY_BYTES,
|
|
@@ -2610,8 +2523,7 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2610
2523
|
description,
|
|
2611
2524
|
controller.signal
|
|
2612
2525
|
);
|
|
2613
|
-
if (controller.signal.aborted)
|
|
2614
|
-
throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2526
|
+
if (controller.signal.aborted) throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2615
2527
|
const responseError = request.responseError?.(response.status, text);
|
|
2616
2528
|
if (responseError) throw new Error(responseError);
|
|
2617
2529
|
if (!response.ok) {
|
|
@@ -2633,8 +2545,7 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2633
2545
|
if (timedOut) {
|
|
2634
2546
|
throw new Error(`Timed out after ${Math.round(timeoutMs / 1e3)}s while fetching usage.`);
|
|
2635
2547
|
}
|
|
2636
|
-
if (signal.aborted)
|
|
2637
|
-
throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2548
|
+
if (signal.aborted) throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2638
2549
|
throw error;
|
|
2639
2550
|
} finally {
|
|
2640
2551
|
clearTimeout(timeout);
|
|
@@ -2769,9 +2680,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
|
|
|
2769
2680
|
}
|
|
2770
2681
|
if (sawIncompleteMatch) throw new Error("GitHub Copilot OAuth credentials were incomplete.");
|
|
2771
2682
|
if (matches.size > 1) {
|
|
2772
|
-
throw new Error(
|
|
2773
|
-
"Conflicting OAuth credentials match the active GitHub Copilot runtime account."
|
|
2774
|
-
);
|
|
2683
|
+
throw new Error("Conflicting OAuth credentials match the active GitHub Copilot runtime account.");
|
|
2775
2684
|
}
|
|
2776
2685
|
const match = matches.values().next().value;
|
|
2777
2686
|
if (!match) {
|
|
@@ -2850,9 +2759,7 @@ function hasOfficialUrlOrigin(value, providerId) {
|
|
|
2850
2759
|
}
|
|
2851
2760
|
}
|
|
2852
2761
|
function headerValue(headers, name) {
|
|
2853
|
-
const entry = Object.entries(headers ?? {}).find(
|
|
2854
|
-
([candidate]) => candidate.toLowerCase() === name.toLowerCase()
|
|
2855
|
-
);
|
|
2762
|
+
const entry = Object.entries(headers ?? {}).find(([candidate]) => candidate.toLowerCase() === name.toLowerCase());
|
|
2856
2763
|
return entry?.[1] ?? void 0;
|
|
2857
2764
|
}
|
|
2858
2765
|
function hasHeader(headers, name) {
|
|
@@ -3051,9 +2958,7 @@ async function resolveCodexResetAuth(ctx, salt = AUTH_FINGERPRINT_SALT, credenti
|
|
|
3051
2958
|
apiKey: resolvedAccess,
|
|
3052
2959
|
headers,
|
|
3053
2960
|
fingerprint: fingerprintResolvedAuth({ headers }, salt),
|
|
3054
|
-
secrets: [
|
|
3055
|
-
.../* @__PURE__ */ new Set([...auth.secrets, storedAccess, resolvedAccess, authorization, accountId])
|
|
3056
|
-
],
|
|
2961
|
+
secrets: [.../* @__PURE__ */ new Set([...auth.secrets, storedAccess, resolvedAccess, authorization, accountId])],
|
|
3057
2962
|
model: auth.model
|
|
3058
2963
|
};
|
|
3059
2964
|
}
|
|
@@ -3102,9 +3007,7 @@ function normalizeCodexResetCreditsPayload(payload) {
|
|
|
3102
3007
|
if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
|
|
3103
3008
|
throw new Error("Codex reset credits response returned invalid credits.");
|
|
3104
3009
|
}
|
|
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));
|
|
3010
|
+
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
3011
|
if (availableCount > 0 && options.length === 0) {
|
|
3109
3012
|
options.push(genericCodexResetOption());
|
|
3110
3013
|
}
|
|
@@ -3219,9 +3122,7 @@ function bearerToken2(authorization) {
|
|
|
3219
3122
|
return /^Bearer\s+(.+)$/iu.exec(authorization ?? "")?.[1];
|
|
3220
3123
|
}
|
|
3221
3124
|
function headerValue2(headers, name) {
|
|
3222
|
-
return Object.entries(headers).find(
|
|
3223
|
-
([candidate]) => candidate.toLowerCase() === name.toLowerCase()
|
|
3224
|
-
)?.[1];
|
|
3125
|
+
return Object.entries(headers).find(([candidate]) => candidate.toLowerCase() === name.toLowerCase())?.[1];
|
|
3225
3126
|
}
|
|
3226
3127
|
|
|
3227
3128
|
// src/format.ts
|
|
@@ -3322,9 +3223,7 @@ function formatCodexReport(lines, report2) {
|
|
|
3322
3223
|
if (metric2.id === "reset-credits") {
|
|
3323
3224
|
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
|
|
3324
3225
|
} else if (metric2.id === "credits") {
|
|
3325
|
-
lines.push(
|
|
3326
|
-
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3327
|
-
);
|
|
3226
|
+
lines.push(`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3328
3227
|
}
|
|
3329
3228
|
}
|
|
3330
3229
|
}
|
|
@@ -3346,9 +3245,7 @@ function formatDeepSeekStatusline(report2) {
|
|
|
3346
3245
|
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
3347
3246
|
if (availability?.value !== "available") return "deepseek API unavailable";
|
|
3348
3247
|
const totals = ["CNY", "USD"].flatMap((currency) => {
|
|
3349
|
-
const metric2 = report2.metrics.find(
|
|
3350
|
-
(candidate) => candidate.id === `${currency.toLowerCase()}-total`
|
|
3351
|
-
);
|
|
3248
|
+
const metric2 = report2.metrics.find((candidate) => candidate.id === `${currency.toLowerCase()}-total`);
|
|
3352
3249
|
return metric2 ? [`${currency} ${metric2.value}`] : [];
|
|
3353
3250
|
});
|
|
3354
3251
|
return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
|
|
@@ -3412,9 +3309,7 @@ function formatGitHubCopilotStatusline(report2) {
|
|
|
3412
3309
|
return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
|
|
3413
3310
|
}
|
|
3414
3311
|
function findGitHubCopilotQuota(report2) {
|
|
3415
|
-
return report2.buckets.find(
|
|
3416
|
-
(bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
|
|
3417
|
-
);
|
|
3312
|
+
return report2.buckets.find((bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id));
|
|
3418
3313
|
}
|
|
3419
3314
|
function compactGitHubCopilotQuotaKind(bucket) {
|
|
3420
3315
|
if (bucket?.id === "ai-credits") return "credits";
|
|
@@ -3433,9 +3328,7 @@ function formatOpenRouterReport(lines, report2) {
|
|
|
3433
3328
|
lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
3434
3329
|
}
|
|
3435
3330
|
for (const metric2 of report2.metrics) {
|
|
3436
|
-
lines.push(
|
|
3437
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3438
|
-
);
|
|
3331
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3439
3332
|
}
|
|
3440
3333
|
}
|
|
3441
3334
|
function formatOpenCodeZenReport(lines, report2) {
|
|
@@ -3497,9 +3390,7 @@ function formatKimiCodingStatusline(report2) {
|
|
|
3497
3390
|
for (const bucket of selected) {
|
|
3498
3391
|
if (!bucket.limit || bucket.remaining === void 0) continue;
|
|
3499
3392
|
const fallback = bucket.id === "weekly" ? "weekly" : "5h";
|
|
3500
|
-
parts.push(
|
|
3501
|
-
`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`
|
|
3502
|
-
);
|
|
3393
|
+
parts.push(`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`);
|
|
3503
3394
|
}
|
|
3504
3395
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3505
3396
|
}
|
|
@@ -3557,9 +3448,7 @@ function formatMiniMaxStatusline(report2, model) {
|
|
|
3557
3448
|
}
|
|
3558
3449
|
function selectMiniMaxGroup(report2, model) {
|
|
3559
3450
|
const groups = [
|
|
3560
|
-
...new Set(
|
|
3561
|
-
report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
|
|
3562
|
-
)
|
|
3451
|
+
...new Set(report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0))
|
|
3563
3452
|
];
|
|
3564
3453
|
if (groups.length <= 1) return groups[0];
|
|
3565
3454
|
if (model && model.provider !== report2.providerId) return void 0;
|
|
@@ -3575,9 +3464,7 @@ function selectMiniMaxGroup(report2, model) {
|
|
|
3575
3464
|
);
|
|
3576
3465
|
if (exact) return exact.group;
|
|
3577
3466
|
const wildcard = candidates.find(
|
|
3578
|
-
({ patterns }) => patterns.some(
|
|
3579
|
-
(pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
|
|
3580
|
-
)
|
|
3467
|
+
({ patterns }) => patterns.some((pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key)))
|
|
3581
3468
|
);
|
|
3582
3469
|
if (wildcard) return wildcard.group;
|
|
3583
3470
|
}
|
|
@@ -3608,9 +3495,7 @@ function formatZaiStatusline(report2) {
|
|
|
3608
3495
|
for (const bucket of selected) {
|
|
3609
3496
|
if (!bucket?.limit || bucket.remaining === void 0) continue;
|
|
3610
3497
|
const fallback = bucket.id === "weekly" ? "weekly" : "5h";
|
|
3611
|
-
parts.push(
|
|
3612
|
-
`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`
|
|
3613
|
-
);
|
|
3498
|
+
parts.push(`${percentRemaining(bucket)}% ${formatWindowLabel(bucket.windowMinutes, fallback, true)}`);
|
|
3614
3499
|
}
|
|
3615
3500
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3616
3501
|
}
|
|
@@ -3644,9 +3529,7 @@ function formatXaiReport(lines, report2) {
|
|
|
3644
3529
|
lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
|
|
3645
3530
|
}
|
|
3646
3531
|
for (const metric2 of report2.metrics) {
|
|
3647
|
-
lines.push(
|
|
3648
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3649
|
-
);
|
|
3532
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3650
3533
|
}
|
|
3651
3534
|
}
|
|
3652
3535
|
function formatZaiReport(lines, report2) {
|
|
@@ -3668,9 +3551,7 @@ function formatZaiReport(lines, report2) {
|
|
|
3668
3551
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
|
|
3669
3552
|
}
|
|
3670
3553
|
for (const metric2 of report2.metrics) {
|
|
3671
|
-
lines.push(
|
|
3672
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3673
|
-
);
|
|
3554
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3674
3555
|
}
|
|
3675
3556
|
}
|
|
3676
3557
|
function formatGenericReport(lines, report2) {
|
|
@@ -3680,9 +3561,7 @@ function formatGenericReport(lines, report2) {
|
|
|
3680
3561
|
);
|
|
3681
3562
|
}
|
|
3682
3563
|
for (const metric2 of report2.metrics) {
|
|
3683
|
-
lines.push(
|
|
3684
|
-
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
3685
|
-
);
|
|
3564
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`);
|
|
3686
3565
|
}
|
|
3687
3566
|
}
|
|
3688
3567
|
function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
|
|
@@ -3690,9 +3569,7 @@ function formatCodexStatusline(report2, model, now = Date.now(), showResetCountd
|
|
|
3690
3569
|
if (!group) return formatCodexCreditsStatus(report2);
|
|
3691
3570
|
const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
|
|
3692
3571
|
const labelBucket = buckets[0];
|
|
3693
|
-
const parts = [
|
|
3694
|
-
group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
|
|
3695
|
-
];
|
|
3572
|
+
const parts = [group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`];
|
|
3696
3573
|
for (const bucket of buckets) {
|
|
3697
3574
|
if (bucket.remaining === void 0) continue;
|
|
3698
3575
|
const percent = `${clampPercent4(bucket.remaining).toFixed(0)}%`;
|
|
@@ -3722,9 +3599,7 @@ function selectCodexGroup(report2, model) {
|
|
|
3722
3599
|
}
|
|
3723
3600
|
const modelKeys = normalizedModelKeys(model);
|
|
3724
3601
|
for (const group of groups) {
|
|
3725
|
-
const bucket = report2.buckets.find(
|
|
3726
|
-
(candidate) => (candidate.groupId ?? candidate.id) === group
|
|
3727
|
-
);
|
|
3602
|
+
const bucket = report2.buckets.find((candidate) => (candidate.groupId ?? candidate.id) === group);
|
|
3728
3603
|
const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
|
|
3729
3604
|
if (keys.some((key) => modelKeys.has(key))) return group;
|
|
3730
3605
|
}
|
|
@@ -3787,20 +3662,15 @@ function formatWindowLabel(minutes, fallback, compact) {
|
|
|
3787
3662
|
return `${minutes}m`;
|
|
3788
3663
|
}
|
|
3789
3664
|
function formatResetCountdown(resetsAt, now) {
|
|
3790
|
-
if (resetsAt === void 0 || !Number.isFinite(resetsAt) || !Number.isFinite(now))
|
|
3791
|
-
return void 0;
|
|
3665
|
+
if (resetsAt === void 0 || !Number.isFinite(resetsAt) || !Number.isFinite(now)) return void 0;
|
|
3792
3666
|
const totalMinutes = Math.max(0, Math.ceil((resetsAt * 1e3 - now) / 6e4));
|
|
3793
3667
|
const days = Math.floor(totalMinutes / 1440);
|
|
3794
3668
|
const hours = Math.floor(totalMinutes % 1440 / 60);
|
|
3795
3669
|
const minutes = totalMinutes % 60;
|
|
3796
3670
|
if (days > 0) {
|
|
3797
|
-
return [
|
|
3798
|
-
`${String(days)}d`,
|
|
3799
|
-
hours > 0 ? `${String(hours)}h` : minutes > 0 ? `${String(minutes)}m` : ""
|
|
3800
|
-
].filter(Boolean).join("");
|
|
3671
|
+
return [`${String(days)}d`, hours > 0 ? `${String(hours)}h` : minutes > 0 ? `${String(minutes)}m` : ""].filter(Boolean).join("");
|
|
3801
3672
|
}
|
|
3802
|
-
if (hours > 0)
|
|
3803
|
-
return [`${String(hours)}h`, minutes > 0 ? `${String(minutes)}m` : ""].filter(Boolean).join("");
|
|
3673
|
+
if (hours > 0) return [`${String(hours)}h`, minutes > 0 ? `${String(minutes)}m` : ""].filter(Boolean).join("");
|
|
3804
3674
|
return `${String(minutes)}m`;
|
|
3805
3675
|
}
|
|
3806
3676
|
function formatMetricValue(value, unit) {
|
|
@@ -3938,24 +3808,13 @@ function createUsageSettingsRuntime(options = {}) {
|
|
|
3938
3808
|
return structuredClone(state);
|
|
3939
3809
|
}),
|
|
3940
3810
|
updateSelectedTarget: (providerId, targetId, signal, checkPublishedSelection) => enqueue(async () => {
|
|
3941
|
-
const transaction = await saveUsageTargetSelection(
|
|
3942
|
-
path,
|
|
3943
|
-
providerId,
|
|
3944
|
-
targetId,
|
|
3945
|
-
operations,
|
|
3946
|
-
signal
|
|
3947
|
-
);
|
|
3811
|
+
const transaction = await saveUsageTargetSelection(path, providerId, targetId, operations, signal);
|
|
3948
3812
|
try {
|
|
3949
3813
|
await checkPublishedSelection?.();
|
|
3950
3814
|
throwIfAborted(signal);
|
|
3951
3815
|
} catch (error) {
|
|
3952
3816
|
try {
|
|
3953
|
-
await restoreUsageSettingsState(
|
|
3954
|
-
path,
|
|
3955
|
-
transaction.saved,
|
|
3956
|
-
transaction.previous,
|
|
3957
|
-
operations
|
|
3958
|
-
);
|
|
3817
|
+
await restoreUsageSettingsState(path, transaction.saved, transaction.previous, operations);
|
|
3959
3818
|
state = transaction.previous;
|
|
3960
3819
|
} catch (rollbackError) {
|
|
3961
3820
|
state = await loadUsageSettings(path);
|
|
@@ -4133,10 +3992,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4133
3992
|
return;
|
|
4134
3993
|
}
|
|
4135
3994
|
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
|
-
);
|
|
3995
|
+
const availability = codexFastAvailability(ctx.model, settingsRuntime.get().settings.codexFastMode);
|
|
4140
3996
|
if (availability.kind === "not-codex") {
|
|
4141
3997
|
ctx.ui.notify("/fast is available only for the active OpenAI Codex model.", "warning");
|
|
4142
3998
|
return;
|
|
@@ -4146,10 +4002,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4146
4002
|
return;
|
|
4147
4003
|
}
|
|
4148
4004
|
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
|
-
);
|
|
4005
|
+
ctx.ui.notify("pi-usage.json is invalid; repair it and run /reload before changing Fast mode.", "error");
|
|
4153
4006
|
return;
|
|
4154
4007
|
}
|
|
4155
4008
|
await toggle(ctx, !availability.enabled);
|
|
@@ -4169,10 +4022,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4169
4022
|
} catch (error) {
|
|
4170
4023
|
if (sessionController.signal.aborted || ownerGeneration !== generation) return;
|
|
4171
4024
|
if (ctx.hasUI) {
|
|
4172
|
-
ctx.ui.notify(
|
|
4173
|
-
`Could not load pi-usage.json; using defaults. ${errorMessage(error)}`,
|
|
4174
|
-
"warning"
|
|
4175
|
-
);
|
|
4025
|
+
ctx.ui.notify(`Could not load pi-usage.json; using defaults. ${errorMessage(error)}`, "warning");
|
|
4176
4026
|
}
|
|
4177
4027
|
return;
|
|
4178
4028
|
}
|
|
@@ -4180,10 +4030,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4180
4030
|
return;
|
|
4181
4031
|
}
|
|
4182
4032
|
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
|
-
);
|
|
4033
|
+
ctx.ui.notify(`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`, "warning");
|
|
4187
4034
|
}
|
|
4188
4035
|
refreshStatus(ctx);
|
|
4189
4036
|
})();
|
|
@@ -4192,11 +4039,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4192
4039
|
pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
|
|
4193
4040
|
}
|
|
4194
4041
|
pi.on("before_provider_request", (event, ctx) => {
|
|
4195
|
-
const rewritten = rewriteCodexFastPayload(
|
|
4196
|
-
event.payload,
|
|
4197
|
-
ctx.model,
|
|
4198
|
-
settingsRuntime.get().settings.codexFastMode
|
|
4199
|
-
);
|
|
4042
|
+
const rewritten = rewriteCodexFastPayload(event.payload, ctx.model, settingsRuntime.get().settings.codexFastMode);
|
|
4200
4043
|
const key = activeRequestKey(ctx);
|
|
4201
4044
|
if (key && ctx.model) {
|
|
4202
4045
|
pendingFastRequests.set(key, {
|
|
@@ -4209,11 +4052,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4209
4052
|
pi.on("message_end", (event, ctx) => {
|
|
4210
4053
|
const request = consumeFastRequest(ctx, event.message, pendingFastRequests);
|
|
4211
4054
|
if (request === NO_FAST_REQUEST) return void 0;
|
|
4212
|
-
const message = correctCodexFastMessageCost(
|
|
4213
|
-
event.message,
|
|
4214
|
-
request.model,
|
|
4215
|
-
request.fastRequested
|
|
4216
|
-
);
|
|
4055
|
+
const message = correctCodexFastMessageCost(event.message, request.model, request.fastRequested);
|
|
4217
4056
|
return message ? { message } : void 0;
|
|
4218
4057
|
});
|
|
4219
4058
|
pi.on("session_shutdown", async () => {
|
|
@@ -4228,10 +4067,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
4228
4067
|
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
|
|
4229
4068
|
},
|
|
4230
4069
|
decorateStatus(model, status) {
|
|
4231
|
-
return codexFastStatusLabel(
|
|
4232
|
-
status,
|
|
4233
|
-
codexFastIsEffective(model, settingsRuntime.get().settings.codexFastMode)
|
|
4234
|
-
);
|
|
4070
|
+
return codexFastStatusLabel(status, codexFastIsEffective(model, settingsRuntime.get().settings.codexFastMode));
|
|
4235
4071
|
},
|
|
4236
4072
|
toggle
|
|
4237
4073
|
};
|
|
@@ -4293,36 +4129,16 @@ function isTimeoutError(error) {
|
|
|
4293
4129
|
|
|
4294
4130
|
// src/usage-settings-ui.ts
|
|
4295
4131
|
import { stripVTControlCharacters } from "node:util";
|
|
4296
|
-
import {
|
|
4297
|
-
|
|
4298
|
-
} from "@earendil-works/pi-coding-agent";
|
|
4299
|
-
import {
|
|
4300
|
-
Container,
|
|
4301
|
-
Key,
|
|
4302
|
-
matchesKey,
|
|
4303
|
-
SettingsList,
|
|
4304
|
-
Text
|
|
4305
|
-
} from "@earendil-works/pi-tui";
|
|
4132
|
+
import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
4133
|
+
import { Key, matchesKey, SettingsList, Text } from "@earendil-works/pi-tui";
|
|
4306
4134
|
var OFF = "Off";
|
|
4307
4135
|
var ON = "On";
|
|
4308
|
-
function fitSettingsRows(lines, maxRows) {
|
|
4309
|
-
if (lines.length <= maxRows) return lines;
|
|
4310
|
-
const content = lines.filter((line) => stripVTControlCharacters(line).trim().length > 0);
|
|
4311
|
-
if (content.length <= maxRows) return content;
|
|
4312
|
-
const selectedIndex = content.findIndex(
|
|
4313
|
-
(line) => /^[→›]\s/u.test(stripVTControlCharacters(line))
|
|
4314
|
-
);
|
|
4315
|
-
if (selectedIndex < 0) return content.slice(0, maxRows);
|
|
4316
|
-
return content.map((line, index) => ({ index, line })).sort(
|
|
4317
|
-
(left, right) => Math.abs(left.index - selectedIndex) - Math.abs(right.index - selectedIndex) || left.index - right.index
|
|
4318
|
-
).slice(0, maxRows).sort((left, right) => left.index - right.index).map(({ line }) => line);
|
|
4319
|
-
}
|
|
4320
4136
|
async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent, onApplied) {
|
|
4321
4137
|
if (ctx.mode !== "tui") {
|
|
4322
4138
|
if (ctx.hasUI) ctx.ui.notify(`Edit settings manually: ${settingsRuntime.get().path}`, "info");
|
|
4323
4139
|
return false;
|
|
4324
4140
|
}
|
|
4325
|
-
const { HorizontalRule } = await import("@narumitw/pi-tui-kit");
|
|
4141
|
+
const { HorizontalRule, renderBoundedFrame } = await import("@narumitw/pi-tui-kit");
|
|
4326
4142
|
if (parentSignal.aborted || !isCurrent()) return false;
|
|
4327
4143
|
return await ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
4328
4144
|
const localController = new AbortController();
|
|
@@ -4347,9 +4163,7 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
4347
4163
|
values: [OFF, ON]
|
|
4348
4164
|
}
|
|
4349
4165
|
];
|
|
4350
|
-
const container = new Container();
|
|
4351
4166
|
const rule = new HorizontalRule({ ruleStyle: (text) => theme.fg("border", text) });
|
|
4352
|
-
container.addChild(new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 1));
|
|
4353
4167
|
let settingsList;
|
|
4354
4168
|
const cancel = () => {
|
|
4355
4169
|
if (closing) return;
|
|
@@ -4396,20 +4210,25 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
4396
4210
|
},
|
|
4397
4211
|
cancel
|
|
4398
4212
|
);
|
|
4399
|
-
container.addChild(settingsList);
|
|
4400
4213
|
parentSignal.addEventListener("abort", cancel, { once: true });
|
|
4401
4214
|
return {
|
|
4402
4215
|
render(width) {
|
|
4403
|
-
const
|
|
4216
|
+
const title = new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 0).render(width);
|
|
4217
|
+
const content = settingsList.render(width);
|
|
4218
|
+
const focusedRow = content.findIndex((line) => /^[→›]\s/u.test(stripVTControlCharacters(line)));
|
|
4404
4219
|
const terminalRows = Number.isFinite(tui.terminal?.rows) ? Math.floor(tui.terminal.rows) : 24;
|
|
4405
|
-
const availableRows = Math.max(1, terminalRows - 3);
|
|
4406
|
-
if (content.length + 2 > availableRows) {
|
|
4407
|
-
return fitSettingsRows(content, availableRows);
|
|
4408
|
-
}
|
|
4409
4220
|
const [ruleLine = ""] = rule.render(width);
|
|
4410
|
-
return
|
|
4221
|
+
return renderBoundedFrame({
|
|
4222
|
+
width,
|
|
4223
|
+
maxRows: Math.max(1, terminalRows - 3),
|
|
4224
|
+
rule: ruleLine,
|
|
4225
|
+
title,
|
|
4226
|
+
content,
|
|
4227
|
+
priorityRows: focusedRow < 0 ? [] : [focusedRow],
|
|
4228
|
+
focusedRow
|
|
4229
|
+
});
|
|
4411
4230
|
},
|
|
4412
|
-
invalidate: () =>
|
|
4231
|
+
invalidate: () => settingsList.invalidate(),
|
|
4413
4232
|
handleInput(data) {
|
|
4414
4233
|
if (closing) return;
|
|
4415
4234
|
if (matchesKey(data, Key.ctrl("c"))) cancel();
|
|
@@ -4518,12 +4337,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4518
4337
|
}
|
|
4519
4338
|
const showCodexResetCountdown = outcome.state.report.providerId === "openai-codex" && settingsRuntime.get().settings.codexStatusResetCountdown;
|
|
4520
4339
|
const now = Date.now();
|
|
4521
|
-
const rawValue = formatUsageStatusline(
|
|
4522
|
-
outcome.state.report,
|
|
4523
|
-
model,
|
|
4524
|
-
now,
|
|
4525
|
-
showCodexResetCountdown
|
|
4526
|
-
);
|
|
4340
|
+
const rawValue = formatUsageStatusline(outcome.state.report, model, now, showCodexResetCountdown);
|
|
4527
4341
|
const value = rawValue ? fastRuntime.decorateStatus(model, rawValue) : void 0;
|
|
4528
4342
|
if (!safeSetStatus(ctx, value)) return;
|
|
4529
4343
|
if (shouldSchedule && sessionActive) scheduleStatusRefresh(ctx, model);
|
|
@@ -4748,15 +4562,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4748
4562
|
if (queryId !== void 0 && latestQueries.get(failureKey) === queryId) {
|
|
4749
4563
|
latestQueries.delete(failureKey);
|
|
4750
4564
|
}
|
|
4751
|
-
return queryAdapterState(
|
|
4752
|
-
ctx,
|
|
4753
|
-
adapter,
|
|
4754
|
-
displayState,
|
|
4755
|
-
true,
|
|
4756
|
-
signal,
|
|
4757
|
-
authRetry + 1,
|
|
4758
|
-
deadlineAt
|
|
4759
|
-
);
|
|
4565
|
+
return queryAdapterState(ctx, adapter, displayState, true, signal, authRetry + 1, deadlineAt);
|
|
4760
4566
|
}
|
|
4761
4567
|
const message = errorMessage(error);
|
|
4762
4568
|
const now = Date.now();
|
|
@@ -4765,12 +4571,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4765
4571
|
}
|
|
4766
4572
|
if (queryId === void 0 || latestQueries.get(failureKey) === queryId) {
|
|
4767
4573
|
if (adapter.invalidateCacheOnFailure) cache.delete(adapter.id, queryFingerprint);
|
|
4768
|
-
setBoundedMap(
|
|
4769
|
-
failureBackoff,
|
|
4770
|
-
failureKey,
|
|
4771
|
-
{ until: now + FAILURE_BACKOFF_MS, message },
|
|
4772
|
-
MAX_ACCOUNT_STATES
|
|
4773
|
-
);
|
|
4574
|
+
setBoundedMap(failureBackoff, failureKey, { until: now + FAILURE_BACKOFF_MS, message }, MAX_ACCOUNT_STATES);
|
|
4774
4575
|
}
|
|
4775
4576
|
return {
|
|
4776
4577
|
state: {
|
|
@@ -4812,13 +4613,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4812
4613
|
throw abortError();
|
|
4813
4614
|
}
|
|
4814
4615
|
};
|
|
4815
|
-
const choices = await listUsageTargets(
|
|
4816
|
-
adapter,
|
|
4817
|
-
auth,
|
|
4818
|
-
signal,
|
|
4819
|
-
Math.max(1, deadlineAt - Date.now()),
|
|
4820
|
-
guard
|
|
4821
|
-
);
|
|
4616
|
+
const choices = await listUsageTargets(adapter, auth, signal, Math.max(1, deadlineAt - Date.now()), guard);
|
|
4822
4617
|
return { choices, fingerprint: auth.fingerprint };
|
|
4823
4618
|
};
|
|
4824
4619
|
const queryCurrentState = async (ctx, model, force, signal) => {
|
|
@@ -4970,12 +4765,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4970
4765
|
const controller = new AbortController();
|
|
4971
4766
|
activeControllers.add(controller);
|
|
4972
4767
|
try {
|
|
4973
|
-
let stableCurrent = await queryStableCurrent(
|
|
4974
|
-
ctx,
|
|
4975
|
-
false,
|
|
4976
|
-
controller,
|
|
4977
|
-
"Checking current usage\u2026"
|
|
4978
|
-
);
|
|
4768
|
+
let stableCurrent = await queryStableCurrent(ctx, false, controller, "Checking current usage\u2026");
|
|
4979
4769
|
if (!stableCurrent) return;
|
|
4980
4770
|
publishStableCurrent(ctx, stableCurrent);
|
|
4981
4771
|
let current = stableCurrent.outcome;
|
|
@@ -5217,12 +5007,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5217
5007
|
(signal) => queryAdapterState(ctx, adapter, "configured", true, signal)
|
|
5218
5008
|
);
|
|
5219
5009
|
if (!outcome) return { kind: "stay" };
|
|
5220
|
-
const revalidated = await queryStableCurrent(
|
|
5221
|
-
ctx,
|
|
5222
|
-
false,
|
|
5223
|
-
controller,
|
|
5224
|
-
"Revalidating current usage\u2026"
|
|
5225
|
-
);
|
|
5010
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Revalidating current usage\u2026");
|
|
5226
5011
|
if (!revalidated) return { kind: "stay" };
|
|
5227
5012
|
stableCurrent = revalidated;
|
|
5228
5013
|
current = revalidated.outcome;
|
|
@@ -5251,12 +5036,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5251
5036
|
}
|
|
5252
5037
|
);
|
|
5253
5038
|
fastState = settingsRuntime.get();
|
|
5254
|
-
const revalidated = await queryStableCurrent(
|
|
5255
|
-
ctx,
|
|
5256
|
-
false,
|
|
5257
|
-
controller,
|
|
5258
|
-
"Applying usage settings\u2026"
|
|
5259
|
-
);
|
|
5039
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Applying usage settings\u2026");
|
|
5260
5040
|
if (!revalidated) return { kind: "stay" };
|
|
5261
5041
|
stableCurrent = revalidated;
|
|
5262
5042
|
current = revalidated.outcome;
|
|
@@ -5308,9 +5088,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5308
5088
|
"revalidating current Codex reset authentication"
|
|
5309
5089
|
);
|
|
5310
5090
|
if (modelIdentity(ctx.model) !== expectedModel || revalidated.fingerprint !== auth.fingerprint) {
|
|
5311
|
-
throw new Error(
|
|
5312
|
-
"The active Codex model or account changed while loading usage limit resets."
|
|
5313
|
-
);
|
|
5091
|
+
throw new Error("The active Codex model or account changed while loading usage limit resets.");
|
|
5314
5092
|
}
|
|
5315
5093
|
return { availability, auth, expectedModel };
|
|
5316
5094
|
}
|
|
@@ -5367,28 +5145,14 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5367
5145
|
"revalidating current Codex reset authentication"
|
|
5368
5146
|
);
|
|
5369
5147
|
if (modelIdentity(ctx.model) !== expectedModel || auth.fingerprint !== expectedFingerprint) {
|
|
5370
|
-
throw new Error(
|
|
5371
|
-
"The active Codex model or account changed; the reset was not used."
|
|
5372
|
-
);
|
|
5148
|
+
throw new Error("The active Codex model or account changed; the reset was not used.");
|
|
5373
5149
|
}
|
|
5374
|
-
const outcome = await consumeCodexResetCredit(
|
|
5375
|
-
auth,
|
|
5376
|
-
option,
|
|
5377
|
-
attemptId,
|
|
5378
|
-
signal,
|
|
5379
|
-
DEFAULT_TIMEOUT_MS
|
|
5380
|
-
);
|
|
5150
|
+
const outcome = await consumeCodexResetCredit(auth, option, attemptId, signal, DEFAULT_TIMEOUT_MS);
|
|
5381
5151
|
invalidateProviderState("openai-codex");
|
|
5382
5152
|
const model = ctx.model;
|
|
5383
5153
|
if (modelIdentity(model) !== expectedModel) return { outcome };
|
|
5384
5154
|
const refreshed = await queryCurrentState(ctx, model, true, signal);
|
|
5385
|
-
const stable = await outcomeStillCurrent(
|
|
5386
|
-
ctx,
|
|
5387
|
-
model,
|
|
5388
|
-
menuGeneration,
|
|
5389
|
-
refreshed,
|
|
5390
|
-
signal
|
|
5391
|
-
);
|
|
5155
|
+
const stable = await outcomeStillCurrent(ctx, model, menuGeneration, refreshed, signal);
|
|
5392
5156
|
return stable ? { outcome, refreshed, model } : { outcome };
|
|
5393
5157
|
},
|
|
5394
5158
|
false
|
|
@@ -5418,12 +5182,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5418
5182
|
return { kind: "to", screen: "reset-picker" };
|
|
5419
5183
|
},
|
|
5420
5184
|
refresh: async () => {
|
|
5421
|
-
const refreshed = await queryStableCurrent(
|
|
5422
|
-
ctx,
|
|
5423
|
-
true,
|
|
5424
|
-
controller,
|
|
5425
|
-
"Refreshing current usage\u2026"
|
|
5426
|
-
);
|
|
5185
|
+
const refreshed = await queryStableCurrent(ctx, true, controller, "Refreshing current usage\u2026");
|
|
5427
5186
|
if (!refreshed) return { kind: "stay" };
|
|
5428
5187
|
stableCurrent = refreshed;
|
|
5429
5188
|
publishStableCurrent(ctx, refreshed);
|
|
@@ -5432,9 +5191,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5432
5191
|
return { kind: "stay" };
|
|
5433
5192
|
},
|
|
5434
5193
|
another: async () => {
|
|
5435
|
-
const others = configuredAdapters(ctx).filter(
|
|
5436
|
-
(adapter) => adapter.id !== ctx.model?.provider
|
|
5437
|
-
);
|
|
5194
|
+
const others = configuredAdapters(ctx).filter((adapter) => adapter.id !== ctx.model?.provider);
|
|
5438
5195
|
if (others.length === 0) {
|
|
5439
5196
|
ctx.ui.notify("No other supported provider has configured runtime auth.", "info");
|
|
5440
5197
|
return { kind: "stay" };
|
|
@@ -5465,12 +5222,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5465
5222
|
);
|
|
5466
5223
|
if (!outcome) return { kind: "back" };
|
|
5467
5224
|
}
|
|
5468
|
-
const revalidated = await queryStableCurrent(
|
|
5469
|
-
ctx,
|
|
5470
|
-
false,
|
|
5471
|
-
controller,
|
|
5472
|
-
"Revalidating current usage\u2026"
|
|
5473
|
-
);
|
|
5225
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Revalidating current usage\u2026");
|
|
5474
5226
|
if (!revalidated) return { kind: "back" };
|
|
5475
5227
|
stableCurrent = revalidated;
|
|
5476
5228
|
current = revalidated.outcome;
|
|
@@ -5513,12 +5265,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5513
5265
|
message: errorMessage(result.reason)
|
|
5514
5266
|
};
|
|
5515
5267
|
});
|
|
5516
|
-
const revalidated = await queryStableCurrent(
|
|
5517
|
-
ctx,
|
|
5518
|
-
false,
|
|
5519
|
-
controller,
|
|
5520
|
-
"Revalidating current usage\u2026"
|
|
5521
|
-
);
|
|
5268
|
+
const revalidated = await queryStableCurrent(ctx, false, controller, "Revalidating current usage\u2026");
|
|
5522
5269
|
if (!revalidated) return { kind: "stay" };
|
|
5523
5270
|
stableCurrent = revalidated;
|
|
5524
5271
|
current = revalidated.outcome;
|
|
@@ -5544,10 +5291,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5544
5291
|
description: "Show usage for the current runtime account",
|
|
5545
5292
|
handler: async (args, ctx) => {
|
|
5546
5293
|
if (args.trim()) {
|
|
5547
|
-
ctx.ui.notify(
|
|
5548
|
-
"/usage does not accept arguments; choose an action from its menu.",
|
|
5549
|
-
"warning"
|
|
5550
|
-
);
|
|
5294
|
+
ctx.ui.notify("/usage does not accept arguments; choose an action from its menu.", "warning");
|
|
5551
5295
|
return;
|
|
5552
5296
|
}
|
|
5553
5297
|
try {
|
|
@@ -5597,12 +5341,9 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
5597
5341
|
activeCurrentIdentity = void 0;
|
|
5598
5342
|
safeSetStatus(ctx, void 0);
|
|
5599
5343
|
});
|
|
5600
|
-
fastRuntime = registerCodexFastMode(
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
(ctx) => startStatusRefresh(ctx, ctx.model, false),
|
|
5604
|
-
{ registerSessionStart: false }
|
|
5605
|
-
);
|
|
5344
|
+
fastRuntime = registerCodexFastMode(pi, settingsRuntime, (ctx) => startStatusRefresh(ctx, ctx.model, false), {
|
|
5345
|
+
registerSessionStart: false
|
|
5346
|
+
});
|
|
5606
5347
|
}
|
|
5607
5348
|
export {
|
|
5608
5349
|
CODEX_FAST_MODEL_IDS,
|