tokentracker-cli 0.43.0 → 0.44.1
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/dashboard/dist/assets/{ActivityHeatmap-0IDxIr7i.js → ActivityHeatmap-Ba6Gf4TR.js} +1 -1
- package/dashboard/dist/assets/{Card-hVCKEGdC.js → Card-C91m34GQ.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-C3QvJSI2.js → DashboardPage-CNanPHSx.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-UVSutySl.js → DevicePage-BEmsLIAp.js} +1 -1
- package/dashboard/dist/assets/{DialogTitle-D0S8c1BO.js → DialogTitle-XRmWoBSR.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-anio8NgI.js → FadeIn-q9JURSK-.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-wRjA_Fvu.js → HeaderGithubStar-DyqWyfr_.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-vl0aIVv0.js → IpCheckPage-B7SnyHbd.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-CJO4q92s.js → LandingPage-B6FNNQTm.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardAvatar-CjPVgiDo.js → LeaderboardAvatar-CKwYyDx3.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-DiQn0DqL.js → LeaderboardPage-ppzIcAqO.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfileModal-yovVjgnB.js → LeaderboardProfileModal-CS9v3_P5.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardProfilePage-C0vqt4m5.js → LeaderboardProfilePage-Bo_bgL58.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-8o294HKr.js → LimitsPage-DS-hOIBo.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-BQsPhRvE.js → LocalOnlyNotice-DEvHdHfe.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-D8hQf3xT.js → LoginPage-B2PpoMz4.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-rhSAh0x6.js → PopoverPopup-Biu6xF-0.js} +1 -1
- package/dashboard/dist/assets/{Select-ByLRQqzg.js → Select-7ll8aOrD.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-CHHy8UA1.js → SelectItemText-LT3pggjS.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-DGyuX3ua.js → SettingsPage-DnUfjcf_.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-CMsfSZar.js → SkillsPage-BgOXQ-tc.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DavgYHA1.js → WidgetsPage-bb233cRe.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-BARpWxxH.js → WrappedPage-zz5LMyBl.js} +1 -1
- package/dashboard/dist/assets/{agent-logos-BsEMlmFc.js → agent-logos-BCIWowJy.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-Nh5NXsRd.js → arrow-up-right-DVgPAXIn.js} +1 -1
- package/dashboard/dist/assets/{download-Bz-ad2Zi.js → download-D_jlB4ad.js} +1 -1
- package/dashboard/dist/assets/{info-Edlzr0qR.js → info-B6z0r43K.js} +1 -1
- package/dashboard/dist/assets/{main-CGYVeoRd.js → main-BKWG2HXF.js} +2 -2
- package/dashboard/dist/assets/{use-limits-display-prefs-Cc82ZSkQ.js → use-limits-display-prefs-BszlyiM-.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-rTdpowec.js → use-native-settings-CE-ofZ6y.js} +1 -1
- package/dashboard/dist/assets/use-usage-limits-C9JiBxl3.js +1 -0
- package/dashboard/dist/assets/{useCurrency-BY5HnhWy.js → useCurrency-BQcSptXu.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-oNpe5Ufe.js → useScrollLock-Cbkcni3m.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/status.js +13 -2
- package/src/commands/sync.js +1 -1
- package/src/lib/pricing/matcher.js +33 -5
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +19 -5
- package/src/lib/usage-limits.js +161 -7
- package/dashboard/dist/assets/use-usage-limits-DFjNciSe.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -5229,7 +5229,7 @@ async function parseRoocodeIncremental({
|
|
|
5229
5229
|
}
|
|
5230
5230
|
|
|
5231
5231
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
5232
|
-
// Zed Agent (
|
|
5232
|
+
// Zed Agent (all model providers — hosted "zed.dev" and bring-your-own alike)
|
|
5233
5233
|
//
|
|
5234
5234
|
// Data: SQLite at
|
|
5235
5235
|
// macOS: ~/Library/Application Support/Zed/threads/threads.db
|
|
@@ -5249,11 +5249,21 @@ async function parseRoocodeIncremental({
|
|
|
5249
5249
|
// antigravity cumulative-delta pattern: keep last-seen totals per thread in
|
|
5250
5250
|
// `cursors.zed.threadTotals`, emit (current - previous) on each sync.
|
|
5251
5251
|
//
|
|
5252
|
-
//
|
|
5253
|
-
//
|
|
5252
|
+
// Providers already reported by a dedicated parser are skipped to avoid
|
|
5253
|
+
// double-counting (see ZED_DOUBLE_COUNTED_PROVIDERS — empty today). Model names
|
|
5254
|
+
// are normalized for pricing in the matcher (normalizeZedModel), not here, so
|
|
5255
|
+
// the real Zed model name is preserved for display.
|
|
5254
5256
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
5255
5257
|
|
|
5256
|
-
|
|
5258
|
+
// Providers whose usage is ALSO captured by a dedicated TokenTracker parser, so
|
|
5259
|
+
// counting them via the Zed thread store would double-count. Zed's native model
|
|
5260
|
+
// providers (zed.dev, copilot_chat, openai*, anthropic, google, ollama,
|
|
5261
|
+
// lmstudio, …) do NOT overlap: e.g. Zed's copilot_chat talks to the Copilot API
|
|
5262
|
+
// directly and never writes ~/.copilot/otel, which is what the Copilot parser
|
|
5263
|
+
// reads. The set is therefore empty today; it's the extension point if Zed ever
|
|
5264
|
+
// persists external-ACP-agent usage (Claude Code / Codex run inside Zed) into
|
|
5265
|
+
// threads.db with a recognizable provider id.
|
|
5266
|
+
const ZED_DOUBLE_COUNTED_PROVIDERS = new Set();
|
|
5257
5267
|
const MAX_ZED_THREAD_JSON_BYTES = 32 * 1024 * 1024;
|
|
5258
5268
|
|
|
5259
5269
|
function resolveZedDbPath(env = process.env) {
|
|
@@ -5347,7 +5357,11 @@ function extractZedTotals(thread) {
|
|
|
5347
5357
|
const model = thread.model;
|
|
5348
5358
|
if (!model || typeof model !== "object") return null;
|
|
5349
5359
|
const provider = typeof model.provider === "string" ? model.provider.trim() : "";
|
|
5350
|
-
|
|
5360
|
+
// Count usage for ALL providers — Zed-hosted (zed.dev) and bring-your-own
|
|
5361
|
+
// (copilot_chat, openai-subscribed, anthropic, lmstudio, …) alike. Only skip
|
|
5362
|
+
// providers whose usage a dedicated parser already reports (see
|
|
5363
|
+
// ZED_DOUBLE_COUNTED_PROVIDERS).
|
|
5364
|
+
if (provider && ZED_DOUBLE_COUNTED_PROVIDERS.has(provider.toLowerCase())) return null;
|
|
5351
5365
|
const modelId = typeof model.model === "string" ? model.model.trim() : "";
|
|
5352
5366
|
if (!modelId) return null;
|
|
5353
5367
|
|
package/src/lib/usage-limits.js
CHANGED
|
@@ -30,6 +30,19 @@ const DEFAULT_PROVIDER_TIMEOUT_MS = 15_000;
|
|
|
30
30
|
const ANTIGRAVITY_LIMITS_CACHE_FILE = "usage-limits-cache.json";
|
|
31
31
|
const ANTIGRAVITY_LIMITS_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
32
32
|
const ANTIGRAVITY_LIMITS_CACHE_UNKNOWN_RESET_TTL_MS = 12 * 60 * 60 * 1000;
|
|
33
|
+
// Claude shares its OAuth usage endpoint budget with Claude Code itself, so a transient
|
|
34
|
+
// 429 is common. Persist the last successful read so the panel can keep showing it instead
|
|
35
|
+
// of flashing a red error. Separate file from Antigravity's (whose writer rewrites the whole
|
|
36
|
+
// file with only its own key, so a shared file would clobber).
|
|
37
|
+
const CLAUDE_LIMITS_CACHE_FILE = "claude-usage-limits-cache.json";
|
|
38
|
+
const CLAUDE_LIMITS_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
39
|
+
// A 429 from the usage endpoint carries a long `retry-after` (often 20+ minutes). Persist
|
|
40
|
+
// the cooldown so every surface — this process, the menu bar app's embedded server, a later
|
|
41
|
+
// restart — stops calling until it expires. Hammering during the cooldown just renews the
|
|
42
|
+
// penalty, which is what kept the panel stuck on the error.
|
|
43
|
+
const CLAUDE_RATE_LIMIT_FILE = "claude-usage-rate-limit.json";
|
|
44
|
+
const CLAUDE_RATE_LIMIT_DEFAULT_COOLDOWN_SEC = 5 * 60;
|
|
45
|
+
const CLAUDE_RATE_LIMIT_MAX_COOLDOWN_SEC = 60 * 60;
|
|
33
46
|
|
|
34
47
|
function clampPercent(value) {
|
|
35
48
|
if (value === null || value === undefined || value === "") return null;
|
|
@@ -99,6 +112,20 @@ function withProviderTimeout(promise, label, timeoutMs) {
|
|
|
99
112
|
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
100
113
|
}
|
|
101
114
|
|
|
115
|
+
function parseRetryAfterSeconds(headers) {
|
|
116
|
+
const ra = headers?.get ? headers.get("retry-after") : null;
|
|
117
|
+
const sec = ra ? Number.parseInt(ra, 10) : NaN;
|
|
118
|
+
return Number.isFinite(sec) && sec > 0 ? sec : null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function formatClaudeRateLimitMessage(retryAfterSec) {
|
|
122
|
+
if (Number.isFinite(retryAfterSec) && retryAfterSec > 0) {
|
|
123
|
+
const mins = Math.ceil(retryAfterSec / 60);
|
|
124
|
+
return `Claude API rate limited (429) — retry in ~${mins}m.`;
|
|
125
|
+
}
|
|
126
|
+
return "Claude API rate limited (429) — retry shortly.";
|
|
127
|
+
}
|
|
128
|
+
|
|
102
129
|
async function fetchClaudeUsageLimits(accessToken, { fetchImpl = fetch, maxAttempts = 3 } = {}) {
|
|
103
130
|
const url = "https://api.anthropic.com/api/oauth/usage";
|
|
104
131
|
const headers = {
|
|
@@ -120,9 +147,11 @@ async function fetchClaudeUsageLimits(accessToken, { fetchImpl = fetch, maxAttem
|
|
|
120
147
|
}
|
|
121
148
|
if (!res.ok) {
|
|
122
149
|
if (res.status === 429) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
const retryAfterSec = parseRetryAfterSeconds(res.headers);
|
|
151
|
+
const err = new Error(formatClaudeRateLimitMessage(retryAfterSec));
|
|
152
|
+
err.code = "RATE_LIMITED";
|
|
153
|
+
err.retryAfterSec = retryAfterSec;
|
|
154
|
+
throw err;
|
|
126
155
|
}
|
|
127
156
|
throw new Error(`Claude API returned ${res.status}`);
|
|
128
157
|
}
|
|
@@ -1271,6 +1300,107 @@ function writeAntigravityLimitsCache(limits, { home, nowMs = Date.now() } = {})
|
|
|
1271
1300
|
} catch (_error) {}
|
|
1272
1301
|
}
|
|
1273
1302
|
|
|
1303
|
+
function resolveClaudeLimitsCachePath({ home } = {}) {
|
|
1304
|
+
return path.join(home || os.homedir(), ".tokentracker", "tracker", CLAUDE_LIMITS_CACHE_FILE);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// Claude windows carry their own `resets_at`; a window whose reset has already passed is
|
|
1308
|
+
// stale data, not a usable fallback, so drop it. Windows without a reset stamp are kept
|
|
1309
|
+
// (the overall cached_at max-age gate already bounds them).
|
|
1310
|
+
function isClaudeCacheWindowUsable(window, { nowMs } = {}) {
|
|
1311
|
+
if (!window || typeof window !== "object") return false;
|
|
1312
|
+
const resetAtMs = parseTimeMs(window.resets_at);
|
|
1313
|
+
if (resetAtMs === null) return true;
|
|
1314
|
+
return resetAtMs > nowMs;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
function hasClaudeWindow(limits) {
|
|
1318
|
+
return Boolean(limits?.five_hour || limits?.seven_day || limits?.seven_day_opus);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
function normalizeClaudeCachedLimits(raw, { nowMs = Date.now() } = {}) {
|
|
1322
|
+
const cachedAtMs = parseTimeMs(raw?.cached_at);
|
|
1323
|
+
if (!Number.isFinite(cachedAtMs)) return null;
|
|
1324
|
+
if (cachedAtMs > nowMs + 60_000) return null;
|
|
1325
|
+
if (nowMs - cachedAtMs > CLAUDE_LIMITS_CACHE_MAX_AGE_MS) return null;
|
|
1326
|
+
|
|
1327
|
+
const cached = {
|
|
1328
|
+
configured: true,
|
|
1329
|
+
error: null,
|
|
1330
|
+
five_hour: isClaudeCacheWindowUsable(raw?.five_hour, { nowMs }) ? raw.five_hour : null,
|
|
1331
|
+
seven_day: isClaudeCacheWindowUsable(raw?.seven_day, { nowMs }) ? raw.seven_day : null,
|
|
1332
|
+
seven_day_opus: isClaudeCacheWindowUsable(raw?.seven_day_opus, { nowMs }) ? raw.seven_day_opus : null,
|
|
1333
|
+
extra_usage: raw?.extra_usage ?? null,
|
|
1334
|
+
stale: true,
|
|
1335
|
+
cached_at: raw.cached_at,
|
|
1336
|
+
};
|
|
1337
|
+
return hasClaudeWindow(cached) ? cached : null;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
function readClaudeLimitsCache({ home, nowMs = Date.now() } = {}) {
|
|
1341
|
+
const cachePath = resolveClaudeLimitsCachePath({ home });
|
|
1342
|
+
try {
|
|
1343
|
+
const parsed = JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
1344
|
+
return normalizeClaudeCachedLimits(parsed?.claude, { nowMs });
|
|
1345
|
+
} catch (_error) {
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
function writeClaudeLimitsCache(limits, { home, nowMs = Date.now() } = {}) {
|
|
1351
|
+
if (!limits?.configured || limits.error || !hasClaudeWindow(limits)) return;
|
|
1352
|
+
const cachePath = resolveClaudeLimitsCachePath({ home });
|
|
1353
|
+
const payload = {
|
|
1354
|
+
claude: {
|
|
1355
|
+
five_hour: limits.five_hour || null,
|
|
1356
|
+
seven_day: limits.seven_day || null,
|
|
1357
|
+
seven_day_opus: limits.seven_day_opus || null,
|
|
1358
|
+
extra_usage: limits.extra_usage || null,
|
|
1359
|
+
cached_at: new Date(nowMs).toISOString(),
|
|
1360
|
+
},
|
|
1361
|
+
};
|
|
1362
|
+
try {
|
|
1363
|
+
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
|
1364
|
+
const tmpPath = `${cachePath}.${process.pid}.tmp`;
|
|
1365
|
+
fs.writeFileSync(tmpPath, JSON.stringify(payload, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
1366
|
+
fs.renameSync(tmpPath, cachePath);
|
|
1367
|
+
} catch (_error) {}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
function resolveClaudeRateLimitPath({ home } = {}) {
|
|
1371
|
+
return path.join(home || os.homedir(), ".tokentracker", "tracker", CLAUDE_RATE_LIMIT_FILE);
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// Returns the cooldown expiry in ms if a 429 cooldown is still active, else null.
|
|
1375
|
+
function readClaudeRateLimitRetryAtMs({ home, nowMs = Date.now() } = {}) {
|
|
1376
|
+
try {
|
|
1377
|
+
const parsed = JSON.parse(fs.readFileSync(resolveClaudeRateLimitPath({ home }), "utf8"));
|
|
1378
|
+
const retryAtMs = parseTimeMs(parsed?.retry_at);
|
|
1379
|
+
if (retryAtMs !== null && retryAtMs > nowMs) return retryAtMs;
|
|
1380
|
+
} catch (_error) {}
|
|
1381
|
+
return null;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
function writeClaudeRateLimitCooldown(retryAfterSec, { home, nowMs = Date.now() } = {}) {
|
|
1385
|
+
const sec = Number.isFinite(retryAfterSec) && retryAfterSec > 0
|
|
1386
|
+
? Math.min(retryAfterSec, CLAUDE_RATE_LIMIT_MAX_COOLDOWN_SEC)
|
|
1387
|
+
: CLAUDE_RATE_LIMIT_DEFAULT_COOLDOWN_SEC;
|
|
1388
|
+
const cachePath = resolveClaudeRateLimitPath({ home });
|
|
1389
|
+
const payload = { retry_at: new Date(nowMs + sec * 1000).toISOString() };
|
|
1390
|
+
try {
|
|
1391
|
+
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
|
1392
|
+
const tmpPath = `${cachePath}.${process.pid}.tmp`;
|
|
1393
|
+
fs.writeFileSync(tmpPath, JSON.stringify(payload, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
1394
|
+
fs.renameSync(tmpPath, cachePath);
|
|
1395
|
+
} catch (_error) {}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
function clearClaudeRateLimitCooldown({ home } = {}) {
|
|
1399
|
+
try {
|
|
1400
|
+
fs.unlinkSync(resolveClaudeRateLimitPath({ home }));
|
|
1401
|
+
} catch (_error) {}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1274
1404
|
function resolveLsofBinary({ commandRunner } = {}) {
|
|
1275
1405
|
for (const candidate of ["/usr/sbin/lsof", "/usr/bin/lsof"]) {
|
|
1276
1406
|
if (fs.existsSync(candidate)) return candidate;
|
|
@@ -1698,9 +1828,13 @@ async function getUsageLimits({
|
|
|
1698
1828
|
const codexAccountId = codexAuthRefreshed?.accountId || null;
|
|
1699
1829
|
const codexPlanType = codexAuthRefreshed?.planType || null;
|
|
1700
1830
|
|
|
1831
|
+
// Skip the upstream Claude call entirely while a 429 cooldown is active — calling again
|
|
1832
|
+
// just renews the penalty. The result handling below serves cache or a cooldown message.
|
|
1833
|
+
const claudeRetryAtMs = claudeToken ? readClaudeRateLimitRetryAtMs({ home, nowMs }) : null;
|
|
1834
|
+
|
|
1701
1835
|
const providerFetch = withFetchTimeout(fetchImpl, providerTimeoutMs);
|
|
1702
1836
|
const [claudeResult, codexResult, cursor, kimi, gemini, kiro, antigravity, copilot, grok] = await Promise.all([
|
|
1703
|
-
claudeToken
|
|
1837
|
+
claudeToken && !claudeRetryAtMs
|
|
1704
1838
|
? withProviderTimeout(fetchClaudeUsageLimits(claudeToken, { fetchImpl: providerFetch, maxAttempts: 1 }), "Claude", providerTimeoutMs).then(
|
|
1705
1839
|
(value) => ({ status: "fulfilled", value }),
|
|
1706
1840
|
(reason) => ({ status: "rejected", reason }),
|
|
@@ -1733,9 +1867,7 @@ async function getUsageLimits({
|
|
|
1733
1867
|
let claude;
|
|
1734
1868
|
if (!claudeToken) {
|
|
1735
1869
|
claude = { configured: false };
|
|
1736
|
-
} else if (
|
|
1737
|
-
claude = { configured: true, error: claudeResult?.reason?.message || "Unknown error" };
|
|
1738
|
-
} else {
|
|
1870
|
+
} else if (claudeResult && claudeResult.status === "fulfilled") {
|
|
1739
1871
|
claude = {
|
|
1740
1872
|
configured: true,
|
|
1741
1873
|
error: null,
|
|
@@ -1744,6 +1876,28 @@ async function getUsageLimits({
|
|
|
1744
1876
|
seven_day_opus: claudeResult.value.seven_day_opus,
|
|
1745
1877
|
extra_usage: claudeResult.value.extra_usage,
|
|
1746
1878
|
};
|
|
1879
|
+
writeClaudeLimitsCache(claude, { home, nowMs });
|
|
1880
|
+
clearClaudeRateLimitCooldown({ home });
|
|
1881
|
+
} else {
|
|
1882
|
+
// Either a fresh 429 (record its cooldown) or a call we skipped because a cooldown was
|
|
1883
|
+
// already active. Serve the last successful read so the bars stay visible; otherwise
|
|
1884
|
+
// surface an accurate "retry in ~Nm" message rather than the misleading hardcoded one.
|
|
1885
|
+
const reason = claudeResult?.reason;
|
|
1886
|
+
if (reason?.code === "RATE_LIMITED") {
|
|
1887
|
+
writeClaudeRateLimitCooldown(reason.retryAfterSec, { home, nowMs });
|
|
1888
|
+
}
|
|
1889
|
+
const cached = readClaudeLimitsCache({ home, nowMs });
|
|
1890
|
+
if (cached) {
|
|
1891
|
+
claude = cached;
|
|
1892
|
+
} else {
|
|
1893
|
+
const retryAtMs = readClaudeRateLimitRetryAtMs({ home, nowMs }) || claudeRetryAtMs;
|
|
1894
|
+
claude = {
|
|
1895
|
+
configured: true,
|
|
1896
|
+
error: retryAtMs
|
|
1897
|
+
? formatClaudeRateLimitMessage(Math.round((retryAtMs - nowMs) / 1000))
|
|
1898
|
+
: reason?.message || "Unknown error",
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1747
1901
|
}
|
|
1748
1902
|
|
|
1749
1903
|
let codex;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as a,ab as m,aI as f}from"./main-CGYVeoRd.js";function p(s){const r=!!s?.initialState,[h,c]=a.useState(()=>r?s?.initialState?.data??null:null),[S,l]=a.useState(()=>r?s?.initialState?.error??null:null),[g,b]=a.useState(!r),i=!!s?.initialRefresh,o=!!s?.publishToPreloadCache,n=a.useCallback((e,t)=>{!o||!e||typeof e!="object"||m(e,{source:t})},[o]),d=a.useCallback(async()=>{try{const e=await f({refresh:!0}),t=e&&typeof e=="object"?e:null;c(t),l(null),n(t,"manual-refresh")}catch(e){l(e?.message||String(e))}},[n]);return a.useEffect(()=>{if(r&&!i)return;let e=!1;return(async()=>{try{const t=await f(i?{refresh:!0}:{});if(e)return;const u=t&&typeof t=="object"?t:null;c(u),l(null),n(u,"page-load")}catch(t){if(e)return;l(t?.message||String(t))}finally{e||b(!1)}})(),()=>{e=!0}},[r,i,n]),{data:h,error:S,isLoading:g,refresh:d}}export{p as u};
|