@narumitw/pi-usage 0.60.4 → 0.60.7
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 +131 -63
- package/dist/index.ts.map +4 -4
- package/docs/providers.md +8 -1
- package/package.json +2 -2
- package/src/core.ts +4 -4
- package/src/providers/zai-errors.ts +94 -0
- package/src/providers/zai.ts +7 -13
- package/src/query.ts +10 -11
- package/src/types.ts +6 -1
- package/src/usage-settings-ui.ts +21 -39
- package/src/usage.ts +6 -12
package/dist/index.ts
CHANGED
|
@@ -120,6 +120,9 @@ var UsageCache = class {
|
|
|
120
120
|
}
|
|
121
121
|
this.entries.set(key, { createdAt: now, report: report2 });
|
|
122
122
|
}
|
|
123
|
+
delete(providerId, fingerprint) {
|
|
124
|
+
this.entries.delete(cacheKey(providerId, fingerprint));
|
|
125
|
+
}
|
|
123
126
|
clearProvider(providerId) {
|
|
124
127
|
for (const key of this.entries.keys()) {
|
|
125
128
|
if (key.startsWith(`${providerId}:`)) this.entries.delete(key);
|
|
@@ -239,8 +242,6 @@ function redactUsageError(value, secrets = []) {
|
|
|
239
242
|
function errorMessage(error) {
|
|
240
243
|
return sanitizeDisplayText(error instanceof Error ? error.message : String(error), 600);
|
|
241
244
|
}
|
|
242
|
-
var UsageUnsupportedError = class extends Error {
|
|
243
|
-
};
|
|
244
245
|
function abortError() {
|
|
245
246
|
return Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
246
247
|
}
|
|
@@ -1732,22 +1733,98 @@ function isRecord2(value) {
|
|
|
1732
1733
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1733
1734
|
}
|
|
1734
1735
|
|
|
1736
|
+
// src/providers/zai-errors.ts
|
|
1737
|
+
var ERROR_MESSAGES = {
|
|
1738
|
+
"1000": "Authentication failed. Check your API key.",
|
|
1739
|
+
"1001": "Authentication header missing. Check your API key.",
|
|
1740
|
+
"1003": "Authentication token expired. Obtain a new token.",
|
|
1741
|
+
"1005": "Two-factor authentication required.",
|
|
1742
|
+
"1113": "Insufficient balance or no resource package. Recharge your account.",
|
|
1743
|
+
"1200": "API call error. Try again later.",
|
|
1744
|
+
"1210": "Invalid API parameter. Check the API documentation.",
|
|
1745
|
+
"1211": "Unknown model. Check the model ID.",
|
|
1746
|
+
"1212": "This model does not support the requested method.",
|
|
1747
|
+
"1213": "A required parameter is missing.",
|
|
1748
|
+
"1214": "Invalid parameter. Check the API documentation.",
|
|
1749
|
+
"1215": "Conflicting parameters. Check the API documentation.",
|
|
1750
|
+
"1220": "Access denied. Check your permissions.",
|
|
1751
|
+
"1221": "This API has been taken offline.",
|
|
1752
|
+
"1222": "This API does not exist.",
|
|
1753
|
+
"1230": "API processing error. Try again later.",
|
|
1754
|
+
"1234": "Network error. Try again later.",
|
|
1755
|
+
"1261": "Prompt too long. Reduce the input length.",
|
|
1756
|
+
"1301": "Content rejected by the safety policy.",
|
|
1757
|
+
"1302": "Request rate limit reached. Try again later.",
|
|
1758
|
+
"1305": "Service overloaded. Try again later.",
|
|
1759
|
+
"1308": "Usage limit reached. Wait for the quota reset.",
|
|
1760
|
+
"1309": "GLM Coding Plan expired. Renew your subscription.",
|
|
1761
|
+
"1310": "Weekly or monthly limit exhausted. Wait for the quota reset.",
|
|
1762
|
+
"1311": "Your subscription does not include this model.",
|
|
1763
|
+
"1313": "Request frequency restricted by the Fair Usage Policy. Contact support.",
|
|
1764
|
+
"1314": "Enterprise package expired. Contact your administrator.",
|
|
1765
|
+
"1315": "This API key requires an enterprise coding package scenario. Replace the key.",
|
|
1766
|
+
"1316": "5-hour limit reached; insufficient balance for extra usage. Wait for reset.",
|
|
1767
|
+
"1317": "7-day limit reached; insufficient balance for extra usage. Wait for reset.",
|
|
1768
|
+
"1318": "5-hour limit reached; extra usage blocked by monthly spend limit.",
|
|
1769
|
+
"1319": "7-day limit reached; extra usage blocked by monthly spend limit.",
|
|
1770
|
+
"1320": "5-hour limit reached; extra usage blocked by monthly spend limit.",
|
|
1771
|
+
"1321": "7-day limit reached; extra usage blocked by monthly spend limit."
|
|
1772
|
+
};
|
|
1773
|
+
var HTTP_MESSAGES = {
|
|
1774
|
+
400: "Invalid request. Check the API documentation.",
|
|
1775
|
+
401: "Authentication failed. Check your API key.",
|
|
1776
|
+
403: "Access denied. Check your permissions.",
|
|
1777
|
+
429: "Request or usage limit reached. Try again later.",
|
|
1778
|
+
500: "Internal error. Try again later."
|
|
1779
|
+
};
|
|
1780
|
+
function zaiPayloadError(payload) {
|
|
1781
|
+
const object = asObject11(payload);
|
|
1782
|
+
if (!object) return void 0;
|
|
1783
|
+
const nested = asObject11(object.error);
|
|
1784
|
+
const rawCode = nested?.code === void 0 ? object.code : nested.code;
|
|
1785
|
+
const code = errorCode(rawCode);
|
|
1786
|
+
if (object.error === void 0 && object.success !== false && (rawCode === void 0 || code === "0" || code === "200")) {
|
|
1787
|
+
return void 0;
|
|
1788
|
+
}
|
|
1789
|
+
return code && code !== "0" && code !== "200" ? `Z.AI ${code}: ${ERROR_MESSAGES[code] ?? "API request failed."}` : "Z.AI: API request failed.";
|
|
1790
|
+
}
|
|
1791
|
+
function zaiResponseError(status, text) {
|
|
1792
|
+
let payload;
|
|
1793
|
+
try {
|
|
1794
|
+
payload = JSON.parse(text);
|
|
1795
|
+
} catch {
|
|
1796
|
+
if (status >= 200 && status < 300) return "Z.AI: Invalid JSON response.";
|
|
1797
|
+
}
|
|
1798
|
+
const error = zaiPayloadError(payload);
|
|
1799
|
+
if (error) return error;
|
|
1800
|
+
if (status < 200 || status >= 300) {
|
|
1801
|
+
return `Z.AI HTTP ${status}: ${HTTP_MESSAGES[status] ?? "API request failed."}`;
|
|
1802
|
+
}
|
|
1803
|
+
return void 0;
|
|
1804
|
+
}
|
|
1805
|
+
function errorCode(value) {
|
|
1806
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 9999) {
|
|
1807
|
+
return String(value);
|
|
1808
|
+
}
|
|
1809
|
+
return typeof value === "string" && /^(?:0|[1-9]\d{0,3})$/u.test(value) ? value : void 0;
|
|
1810
|
+
}
|
|
1811
|
+
function asObject11(value) {
|
|
1812
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1735
1815
|
// src/providers/zai.ts
|
|
1736
1816
|
var FIVE_HOUR_WINDOW_MINUTES2 = 300;
|
|
1737
1817
|
var WEEKLY_WINDOW_MINUTES2 = 10080;
|
|
1738
1818
|
function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt, plan) {
|
|
1739
|
-
const
|
|
1740
|
-
if (
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
`No GLM Coding Plan on this Z.AI credential; API usage is not metered.${reason ? ` Z.AI reported: ${reason}` : ""}`
|
|
1744
|
-
);
|
|
1745
|
-
}
|
|
1819
|
+
const error = zaiPayloadError(payload);
|
|
1820
|
+
if (error) throw new Error(error);
|
|
1821
|
+
const data = asObject12(payload.data);
|
|
1822
|
+
if (!data) throw new Error("Z.AI quota response data was not an object.");
|
|
1746
1823
|
const limits = Array.isArray(data.limits) ? data.limits : [];
|
|
1747
1824
|
const buckets = [];
|
|
1748
1825
|
const metrics = [];
|
|
1749
1826
|
for (const raw of limits) {
|
|
1750
|
-
const limit =
|
|
1827
|
+
const limit = asObject12(raw);
|
|
1751
1828
|
if (!limit) continue;
|
|
1752
1829
|
const type = asString5(limit.type);
|
|
1753
1830
|
const unit = asNonnegativeNumber4(limit.unit);
|
|
@@ -1796,14 +1873,11 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt,
|
|
|
1796
1873
|
};
|
|
1797
1874
|
}
|
|
1798
1875
|
function normalizeZaiSubscriptionPayload(payload) {
|
|
1799
|
-
if (payload
|
|
1800
|
-
if (typeof payload.code === "number" && payload.code !== 0 && payload.code !== 200) {
|
|
1801
|
-
return void 0;
|
|
1802
|
-
}
|
|
1876
|
+
if (zaiPayloadError(payload)) return void 0;
|
|
1803
1877
|
if (!Array.isArray(payload.data)) return void 0;
|
|
1804
1878
|
const candidates = [];
|
|
1805
1879
|
for (const raw of payload.data) {
|
|
1806
|
-
const entry =
|
|
1880
|
+
const entry = asObject12(raw);
|
|
1807
1881
|
if (!entry) continue;
|
|
1808
1882
|
const name = asString5(entry.productName);
|
|
1809
1883
|
if (!name) continue;
|
|
@@ -1881,7 +1955,7 @@ function addCountBucket(buckets, limit, id, label, windowMinutes) {
|
|
|
1881
1955
|
function addUsageDetailMetrics(metrics, value) {
|
|
1882
1956
|
if (!Array.isArray(value)) return;
|
|
1883
1957
|
for (const raw of value) {
|
|
1884
|
-
const detail =
|
|
1958
|
+
const detail = asObject12(raw);
|
|
1885
1959
|
if (!detail) continue;
|
|
1886
1960
|
const label = asString5(detail.modelCode);
|
|
1887
1961
|
const usage = asNonnegativeNumber4(detail.usage);
|
|
@@ -1889,7 +1963,7 @@ function addUsageDetailMetrics(metrics, value) {
|
|
|
1889
1963
|
metrics.push({ id: `mcp-${kebabCase(label)}`, label, value: usage, unit: "count" });
|
|
1890
1964
|
}
|
|
1891
1965
|
}
|
|
1892
|
-
function
|
|
1966
|
+
function asObject12(value) {
|
|
1893
1967
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1894
1968
|
return value;
|
|
1895
1969
|
}
|
|
@@ -2227,6 +2301,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2227
2301
|
{
|
|
2228
2302
|
id: "zai",
|
|
2229
2303
|
displayName: "Z.AI",
|
|
2304
|
+
invalidateCacheOnFailure: true,
|
|
2230
2305
|
semantics: { kind: "consumer-subscription", label: "GLM Coding Plan usage" },
|
|
2231
2306
|
async query(auth, signal, timeoutMs, guard) {
|
|
2232
2307
|
return queryZaiUsage("zai", "Z.AI", auth, signal, timeoutMs, guard);
|
|
@@ -2235,6 +2310,7 @@ var SUPPORTED_ADAPTERS = [
|
|
|
2235
2310
|
{
|
|
2236
2311
|
id: "zai-coding-cn",
|
|
2237
2312
|
displayName: "Z.AI Coding CN",
|
|
2313
|
+
invalidateCacheOnFailure: true,
|
|
2238
2314
|
semantics: { kind: "consumer-subscription", label: "GLM Coding Plan usage" },
|
|
2239
2315
|
async query(auth, signal, timeoutMs, guard) {
|
|
2240
2316
|
return queryZaiUsage("zai-coding-cn", "Z.AI Coding CN", auth, signal, timeoutMs, guard);
|
|
@@ -2455,8 +2531,7 @@ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard, targe
|
|
|
2455
2531
|
);
|
|
2456
2532
|
} catch (error) {
|
|
2457
2533
|
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
2458
|
-
|
|
2459
|
-
throw error instanceof UsageUnsupportedError ? new UsageUnsupportedError(message) : new Error(message);
|
|
2534
|
+
throw new Error(redactUsageError(errorMessage(error), auth.secrets));
|
|
2460
2535
|
}
|
|
2461
2536
|
}
|
|
2462
2537
|
function providerIsConfigured(ctx, providerId) {
|
|
@@ -2537,6 +2612,8 @@ async function fetchProviderJson(url, auth, signal, timeoutMs, description, requ
|
|
|
2537
2612
|
);
|
|
2538
2613
|
if (controller.signal.aborted)
|
|
2539
2614
|
throw Object.assign(new Error("Usage query aborted."), { name: "AbortError" });
|
|
2615
|
+
const responseError = request.responseError?.(response.status, text);
|
|
2616
|
+
if (responseError) throw new Error(responseError);
|
|
2540
2617
|
if (!response.ok) {
|
|
2541
2618
|
throw new Error(
|
|
2542
2619
|
`${description} returned ${response.status} ${response.statusText}: ${redactUsageError(text, auth.secrets)}`
|
|
@@ -2613,7 +2690,7 @@ function resolveXaiUsageAuth(auth, model, salt, candidates) {
|
|
|
2613
2690
|
const matches = [];
|
|
2614
2691
|
for (const candidate of candidates) {
|
|
2615
2692
|
try {
|
|
2616
|
-
const credential =
|
|
2693
|
+
const credential = asObject13(candidate);
|
|
2617
2694
|
if (credential?.type !== "oauth") continue;
|
|
2618
2695
|
sawOAuth = true;
|
|
2619
2696
|
if (credential.access !== resolvedAccess) continue;
|
|
@@ -2667,7 +2744,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
|
|
|
2667
2744
|
const matches = /* @__PURE__ */ new Map();
|
|
2668
2745
|
for (const candidate of candidates) {
|
|
2669
2746
|
try {
|
|
2670
|
-
const credential =
|
|
2747
|
+
const credential = asObject13(candidate);
|
|
2671
2748
|
if (credential?.type !== "oauth") continue;
|
|
2672
2749
|
sawOAuth = true;
|
|
2673
2750
|
const storedAccess2 = typeof credential.access === "string" && credential.access ? credential.access : void 0;
|
|
@@ -2729,7 +2806,7 @@ function bearerToken(authorization) {
|
|
|
2729
2806
|
const match = /^Bearer\s+(.+)$/iu.exec(authorization ?? "");
|
|
2730
2807
|
return match?.[1];
|
|
2731
2808
|
}
|
|
2732
|
-
function
|
|
2809
|
+
function asObject13(value) {
|
|
2733
2810
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2734
2811
|
return value;
|
|
2735
2812
|
}
|
|
@@ -2858,7 +2935,8 @@ async function queryZaiUsage(providerId, providerName, auth, signal, timeoutMs,
|
|
|
2858
2935
|
zaiMonitorAuth(auth),
|
|
2859
2936
|
signal,
|
|
2860
2937
|
remainingTimeout2(timeoutMs, startedAt, `fetching ${providerName} quota`),
|
|
2861
|
-
`${providerName} quota endpoint
|
|
2938
|
+
`${providerName} quota endpoint`,
|
|
2939
|
+
{ responseError: zaiResponseError }
|
|
2862
2940
|
);
|
|
2863
2941
|
await guard();
|
|
2864
2942
|
const planTimeoutMs = timeoutMs - (Date.now() - startedAt);
|
|
@@ -2873,7 +2951,8 @@ async function fetchZaiPlan(providerName, auth, signal, timeoutMs) {
|
|
|
2873
2951
|
zaiMonitorAuth(auth),
|
|
2874
2952
|
signal,
|
|
2875
2953
|
timeoutMs,
|
|
2876
|
-
`${providerName} plan endpoint
|
|
2954
|
+
`${providerName} plan endpoint`,
|
|
2955
|
+
{ responseError: zaiResponseError }
|
|
2877
2956
|
);
|
|
2878
2957
|
return normalizeZaiSubscriptionPayload(payload);
|
|
2879
2958
|
} catch (error) {
|
|
@@ -3023,7 +3102,7 @@ function normalizeCodexResetCreditsPayload(payload) {
|
|
|
3023
3102
|
if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
|
|
3024
3103
|
throw new Error("Codex reset credits response returned invalid credits.");
|
|
3025
3104
|
}
|
|
3026
|
-
const options = (rawCredits ?? []).map(
|
|
3105
|
+
const options = (rawCredits ?? []).map(asObject14).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
|
|
3027
3106
|
(left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
|
|
3028
3107
|
).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
|
|
3029
3108
|
if (availableCount > 0 && options.length === 0) {
|
|
@@ -3038,7 +3117,7 @@ function selectCodexResetCredential(candidates, resolvedAccess, resolvedAccountI
|
|
|
3038
3117
|
const matches = /* @__PURE__ */ new Map();
|
|
3039
3118
|
for (const candidate of candidates) {
|
|
3040
3119
|
try {
|
|
3041
|
-
const credential =
|
|
3120
|
+
const credential = asObject14(candidate);
|
|
3042
3121
|
if (credential?.type !== "oauth") continue;
|
|
3043
3122
|
sawOAuth = true;
|
|
3044
3123
|
const storedAccess = asNonemptyString(credential.access);
|
|
@@ -3077,7 +3156,7 @@ function codexAccountIdFromAccessToken(access) {
|
|
|
3077
3156
|
const parts = access.split(".");
|
|
3078
3157
|
if (parts.length !== 3 || !parts[1]) return void 0;
|
|
3079
3158
|
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
3080
|
-
const claims =
|
|
3159
|
+
const claims = asObject14(asObject14(payload)?.["https://api.openai.com/auth"]);
|
|
3081
3160
|
return validHeaderValue(claims?.chatgpt_account_id);
|
|
3082
3161
|
} catch {
|
|
3083
3162
|
return void 0;
|
|
@@ -3109,7 +3188,7 @@ function normalizeResetOption(credit) {
|
|
|
3109
3188
|
function isCodexResetOutcomeCode(value) {
|
|
3110
3189
|
return value === "reset" || value === "nothing_to_reset" || value === "no_credit" || value === "already_redeemed";
|
|
3111
3190
|
}
|
|
3112
|
-
function
|
|
3191
|
+
function asObject14(value) {
|
|
3113
3192
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3114
3193
|
return value;
|
|
3115
3194
|
}
|
|
@@ -4217,33 +4296,15 @@ import { stripVTControlCharacters } from "node:util";
|
|
|
4217
4296
|
import {
|
|
4218
4297
|
getSettingsListTheme
|
|
4219
4298
|
} from "@earendil-works/pi-coding-agent";
|
|
4220
|
-
import {
|
|
4221
|
-
Container,
|
|
4222
|
-
Key,
|
|
4223
|
-
matchesKey,
|
|
4224
|
-
SettingsList,
|
|
4225
|
-
Text
|
|
4226
|
-
} from "@earendil-works/pi-tui";
|
|
4299
|
+
import { Key, matchesKey, SettingsList, Text } from "@earendil-works/pi-tui";
|
|
4227
4300
|
var OFF = "Off";
|
|
4228
4301
|
var ON = "On";
|
|
4229
|
-
function fitSettingsRows(lines, maxRows) {
|
|
4230
|
-
if (lines.length <= maxRows) return lines;
|
|
4231
|
-
const content = lines.filter((line) => stripVTControlCharacters(line).trim().length > 0);
|
|
4232
|
-
if (content.length <= maxRows) return content;
|
|
4233
|
-
const selectedIndex = content.findIndex(
|
|
4234
|
-
(line) => /^[→›]\s/u.test(stripVTControlCharacters(line))
|
|
4235
|
-
);
|
|
4236
|
-
if (selectedIndex < 0) return content.slice(0, maxRows);
|
|
4237
|
-
return content.map((line, index) => ({ index, line })).sort(
|
|
4238
|
-
(left, right) => Math.abs(left.index - selectedIndex) - Math.abs(right.index - selectedIndex) || left.index - right.index
|
|
4239
|
-
).slice(0, maxRows).sort((left, right) => left.index - right.index).map(({ line }) => line);
|
|
4240
|
-
}
|
|
4241
4302
|
async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent, onApplied) {
|
|
4242
4303
|
if (ctx.mode !== "tui") {
|
|
4243
4304
|
if (ctx.hasUI) ctx.ui.notify(`Edit settings manually: ${settingsRuntime.get().path}`, "info");
|
|
4244
4305
|
return false;
|
|
4245
4306
|
}
|
|
4246
|
-
const { HorizontalRule } = await import("@narumitw/pi-tui-kit");
|
|
4307
|
+
const { HorizontalRule, renderBoundedFrame } = await import("@narumitw/pi-tui-kit");
|
|
4247
4308
|
if (parentSignal.aborted || !isCurrent()) return false;
|
|
4248
4309
|
return await ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
4249
4310
|
const localController = new AbortController();
|
|
@@ -4268,9 +4329,7 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
4268
4329
|
values: [OFF, ON]
|
|
4269
4330
|
}
|
|
4270
4331
|
];
|
|
4271
|
-
const container = new Container();
|
|
4272
4332
|
const rule = new HorizontalRule({ ruleStyle: (text) => theme.fg("border", text) });
|
|
4273
|
-
container.addChild(new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 1));
|
|
4274
4333
|
let settingsList;
|
|
4275
4334
|
const cancel = () => {
|
|
4276
4335
|
if (closing) return;
|
|
@@ -4317,20 +4376,29 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
4317
4376
|
},
|
|
4318
4377
|
cancel
|
|
4319
4378
|
);
|
|
4320
|
-
container.addChild(settingsList);
|
|
4321
4379
|
parentSignal.addEventListener("abort", cancel, { once: true });
|
|
4322
4380
|
return {
|
|
4323
4381
|
render(width) {
|
|
4324
|
-
const
|
|
4382
|
+
const title = new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 0).render(
|
|
4383
|
+
width
|
|
4384
|
+
);
|
|
4385
|
+
const content = settingsList.render(width);
|
|
4386
|
+
const focusedRow = content.findIndex(
|
|
4387
|
+
(line) => /^[→›]\s/u.test(stripVTControlCharacters(line))
|
|
4388
|
+
);
|
|
4325
4389
|
const terminalRows = Number.isFinite(tui.terminal?.rows) ? Math.floor(tui.terminal.rows) : 24;
|
|
4326
|
-
const availableRows = Math.max(1, terminalRows - 3);
|
|
4327
|
-
if (content.length + 2 > availableRows) {
|
|
4328
|
-
return fitSettingsRows(content, availableRows);
|
|
4329
|
-
}
|
|
4330
4390
|
const [ruleLine = ""] = rule.render(width);
|
|
4331
|
-
return
|
|
4391
|
+
return renderBoundedFrame({
|
|
4392
|
+
width,
|
|
4393
|
+
maxRows: Math.max(1, terminalRows - 3),
|
|
4394
|
+
rule: ruleLine,
|
|
4395
|
+
title,
|
|
4396
|
+
content,
|
|
4397
|
+
priorityRows: focusedRow < 0 ? [] : [focusedRow],
|
|
4398
|
+
focusedRow
|
|
4399
|
+
});
|
|
4332
4400
|
},
|
|
4333
|
-
invalidate: () =>
|
|
4401
|
+
invalidate: () => settingsList.invalidate(),
|
|
4334
4402
|
handleInput(data) {
|
|
4335
4403
|
if (closing) return;
|
|
4336
4404
|
if (matchesKey(data, Key.ctrl("c"))) cancel();
|
|
@@ -4568,7 +4636,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4568
4636
|
providerId: adapter.id,
|
|
4569
4637
|
providerName,
|
|
4570
4638
|
displayState,
|
|
4571
|
-
status:
|
|
4639
|
+
status: "query-failed",
|
|
4572
4640
|
message: previousDiscoveryFailure.message
|
|
4573
4641
|
},
|
|
4574
4642
|
fingerprint: auth.fingerprint,
|
|
@@ -4627,7 +4695,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4627
4695
|
providerId: adapter.id,
|
|
4628
4696
|
providerName,
|
|
4629
4697
|
displayState,
|
|
4630
|
-
status:
|
|
4698
|
+
status: "query-failed",
|
|
4631
4699
|
message: previousFailure.message
|
|
4632
4700
|
},
|
|
4633
4701
|
fingerprint: auth.fingerprint,
|
|
@@ -4680,16 +4748,16 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4680
4748
|
);
|
|
4681
4749
|
}
|
|
4682
4750
|
const message = errorMessage(error);
|
|
4683
|
-
const status = error instanceof UsageUnsupportedError ? "unsupported" : "query-failed";
|
|
4684
4751
|
const now = Date.now();
|
|
4685
4752
|
for (const [key, failure] of failureBackoff) {
|
|
4686
4753
|
if (failure.until <= now) failureBackoff.delete(key);
|
|
4687
4754
|
}
|
|
4688
4755
|
if (queryId === void 0 || latestQueries.get(failureKey) === queryId) {
|
|
4756
|
+
if (adapter.invalidateCacheOnFailure) cache.delete(adapter.id, queryFingerprint);
|
|
4689
4757
|
setBoundedMap(
|
|
4690
4758
|
failureBackoff,
|
|
4691
4759
|
failureKey,
|
|
4692
|
-
{ until: now + FAILURE_BACKOFF_MS, message
|
|
4760
|
+
{ until: now + FAILURE_BACKOFF_MS, message },
|
|
4693
4761
|
MAX_ACCOUNT_STATES
|
|
4694
4762
|
);
|
|
4695
4763
|
}
|
|
@@ -4698,7 +4766,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
4698
4766
|
providerId: adapter.id,
|
|
4699
4767
|
providerName,
|
|
4700
4768
|
displayState,
|
|
4701
|
-
status,
|
|
4769
|
+
status: "query-failed",
|
|
4702
4770
|
message
|
|
4703
4771
|
},
|
|
4704
4772
|
fingerprint: auth.fingerprint,
|