tokentracker-cli 0.55.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dashboard/dist/assets/{ActivityHeatmap-f31ixbyV.js → ActivityHeatmap-BzYFi7If.js} +1 -1
  2. package/dashboard/dist/assets/{Card-P4pcpfgk.js → Card-CWlC0TT9.js} +1 -1
  3. package/dashboard/dist/assets/{DashboardPage-CbKBu564.js → DashboardPage-CI6QAWEh.js} +1 -1
  4. package/dashboard/dist/assets/{DevicePage-BYPTGtFL.js → DevicePage-CkLOUytF.js} +1 -1
  5. package/dashboard/dist/assets/{DialogTitle-BZf_YGYe.js → DialogTitle-qpnoyCDp.js} +1 -1
  6. package/dashboard/dist/assets/{FadeIn-CchoMg8O.js → FadeIn-rEScv_td.js} +1 -1
  7. package/dashboard/dist/assets/{HeaderGithubStar-CCp4lXQc.js → HeaderGithubStar-DNOf-bAX.js} +1 -1
  8. package/dashboard/dist/assets/{IpCheckPage-FFn_rJ1E.js → IpCheckPage-DwsvZICX.js} +1 -1
  9. package/dashboard/dist/assets/{LandingPage-Deu1ltMr.js → LandingPage-BzQCcu83.js} +1 -1
  10. package/dashboard/dist/assets/{LeaderboardAvatar-R5cgtwIk.js → LeaderboardAvatar-BnXyZa5v.js} +1 -1
  11. package/dashboard/dist/assets/{LeaderboardPage-CNfXjJ_i.js → LeaderboardPage-W9W6St_R.js} +3 -3
  12. package/dashboard/dist/assets/{LeaderboardProfileModal-Bg5oiqmZ.js → LeaderboardProfileModal-udtOlLe2.js} +1 -1
  13. package/dashboard/dist/assets/{LeaderboardProfilePage-DTE6Jfwq.js → LeaderboardProfilePage-gSEw4uv8.js} +1 -1
  14. package/dashboard/dist/assets/LimitsPage-Cw4N6JeE.js +2 -0
  15. package/dashboard/dist/assets/{LocalOnlyNotice-DboBMrlb.js → LocalOnlyNotice-BZlvc0vN.js} +1 -1
  16. package/dashboard/dist/assets/{LoginPage-DtILt4Dm.js → LoginPage-B565FVDA.js} +1 -1
  17. package/dashboard/dist/assets/{PopoverPopup-B_qSI_Kj.js → PopoverPopup-BamnkoKk.js} +1 -1
  18. package/dashboard/dist/assets/{ResetPasswordPage-C-PiZJ1Q.js → ResetPasswordPage-C0-ziJ-w.js} +1 -1
  19. package/dashboard/dist/assets/{Select-CXseeIjs.js → Select-DT22H5j7.js} +1 -1
  20. package/dashboard/dist/assets/{SelectItemText-DpEjTcov.js → SelectItemText-B6Wn709O.js} +1 -1
  21. package/dashboard/dist/assets/{SettingsPage-pOpyqaby.js → SettingsPage-Dal75OgQ.js} +1 -1
  22. package/dashboard/dist/assets/{SkillsPage-DdIi6lYW.js → SkillsPage-HoRP1WBr.js} +1 -1
  23. package/dashboard/dist/assets/{WidgetsPage-Chb3bxVH.js → WidgetsPage-e-mw3Vkq.js} +1 -1
  24. package/dashboard/dist/assets/{WrappedPage-DdmCoaz8.js → WrappedPage-BBFbsssQ.js} +1 -1
  25. package/dashboard/dist/assets/{agent-logos-YpISvAMw.js → agent-logos-q4KY3SrS.js} +1 -1
  26. package/dashboard/dist/assets/{arrow-up-right-ThOp2PrF.js → arrow-up-right-BF3pw1i_.js} +1 -1
  27. package/dashboard/dist/assets/{download-H-ks1oyK.js → download-8G10BzKF.js} +1 -1
  28. package/dashboard/dist/assets/{info-D3b_SGE-.js → info-D62z4eaa.js} +1 -1
  29. package/dashboard/dist/assets/main-Bb0Bwbp7.css +1 -0
  30. package/dashboard/dist/assets/{main-CZFzpc5d.js → main-BqomqDjC.js} +6 -3
  31. package/dashboard/dist/assets/{use-limits-display-prefs-BzB-pF4J.js → use-limits-display-prefs-C0ttQ7qt.js} +1 -1
  32. package/dashboard/dist/assets/{use-native-settings-BrJdMq29.js → use-native-settings-DJPC20Xw.js} +1 -1
  33. package/dashboard/dist/assets/{use-usage-limits-CcbaY6uV.js → use-usage-limits-Ccr9ZCYy.js} +1 -1
  34. package/dashboard/dist/assets/{useCurrency-Bf7zAMJX.js → useCurrency-DwQhSqB1.js} +1 -1
  35. package/dashboard/dist/assets/{useScrollLock-BC_qj4dr.js → useScrollLock-DZ9md-qB.js} +1 -1
  36. package/dashboard/dist/brand-logos/mimo.svg +4 -0
  37. package/dashboard/dist/index.html +2 -2
  38. package/dashboard/dist/share.html +2 -2
  39. package/package.json +2 -2
  40. package/src/commands/init.js +13 -0
  41. package/src/commands/status.js +11 -0
  42. package/src/commands/sync.js +44 -0
  43. package/src/lib/pricing/seed-snapshot.json +1 -1
  44. package/src/lib/rollout.js +62 -0
  45. package/src/lib/usage-limits.js +139 -15
  46. package/dashboard/dist/assets/LimitsPage-plnNcsI8.js +0 -2
  47. package/dashboard/dist/assets/main-DCfktJsK.css +0 -1
@@ -2520,6 +2520,67 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
2520
2520
  return out;
2521
2521
  }
2522
2522
 
2523
+ // Mimo (mimocode) reuses OpenCode's `message` table schema, but its DB ALSO
2524
+ // contains the user's imported Claude Code history: on install, mimocode reads
2525
+ // ~/.claude/projects/*.jsonl and copies those sessions into its own DB,
2526
+ // recording each in the `claude_import` table (source_path → session_id +
2527
+ // message_ids). Those imported messages are already counted by the Claude
2528
+ // parser, so counting them here would double-count Claude usage AND mislabel it
2529
+ // as "mimo".
2530
+ //
2531
+ // `message_ids` was added to claude_import via a migration, so rows written by
2532
+ // an older mimocode have it NULL. For those we fall back to excluding the whole
2533
+ // imported session by session_id — a claude_import.session_id is always an
2534
+ // import-created session, never a native mimo one, so this is safe. Rows that
2535
+ // DO carry message_ids use precise per-id exclusion, which preserves any native
2536
+ // turns the user later added to an imported session.
2537
+ function readMimoImportedKeys(dbPath, sqliteOptions = {}) {
2538
+ const sql = `SELECT session_id, message_ids FROM claude_import`;
2539
+ let rows;
2540
+ try {
2541
+ rows = readSqliteJsonRows(dbPath, sql, {
2542
+ label: "Mimo import",
2543
+ maxBuffer: 200 * 1024 * 1024,
2544
+ timeout: 30_000,
2545
+ ...sqliteOptions,
2546
+ });
2547
+ } catch (_e) {
2548
+ // claude_import table absent (older/newer mimocode) → treat as no imports.
2549
+ return { ids: new Set(), sessions: new Set() };
2550
+ }
2551
+ const ids = new Set();
2552
+ const sessions = new Set();
2553
+ for (const row of rows) {
2554
+ if (!row) continue;
2555
+ let arr = null;
2556
+ if (typeof row.message_ids === "string") {
2557
+ try {
2558
+ arr = JSON.parse(row.message_ids);
2559
+ } catch (_e) {
2560
+ arr = null;
2561
+ }
2562
+ }
2563
+ if (Array.isArray(arr) && arr.length > 0) {
2564
+ for (const id of arr) if (typeof id === "string") ids.add(id);
2565
+ } else if (typeof row.session_id === "string" && row.session_id) {
2566
+ sessions.add(row.session_id);
2567
+ }
2568
+ }
2569
+ return { ids, sessions };
2570
+ }
2571
+
2572
+ // Read only NATIVE mimo assistant messages — token-bearing rows that are not
2573
+ // part of any claude_import row (by message id, or session id for legacy import
2574
+ // rows without message_ids). See readMimoImportedKeys for why.
2575
+ function readMimoDbMessages(dbPath, sqliteOptions = {}) {
2576
+ if (!dbPath || !fssync.existsSync(dbPath)) return [];
2577
+ const all = readOpencodeDbMessages(dbPath, sqliteOptions);
2578
+ if (all.length === 0) return all;
2579
+ const { ids, sessions } = readMimoImportedKeys(dbPath, sqliteOptions);
2580
+ if (ids.size === 0 && sessions.size === 0) return all;
2581
+ return all.filter((m) => !ids.has(m.id) && !sessions.has(m.sessionID));
2582
+ }
2583
+
2523
2584
  async function parseOpencodeDbIncremental({
2524
2585
  dbMessages,
2525
2586
  cursors,
@@ -9033,6 +9094,7 @@ module.exports = {
9033
9094
  listGeminiSessionFiles,
9034
9095
  listOpencodeMessageFiles,
9035
9096
  readOpencodeDbMessages,
9097
+ readMimoDbMessages,
9036
9098
  resolveKiroDbPath,
9037
9099
  resolveKiroJsonlPath,
9038
9100
  resolveHermesPath,
@@ -5,6 +5,7 @@ const os = require("node:os");
5
5
  const path = require("node:path");
6
6
  const http = require("node:http");
7
7
  const https = require("node:https");
8
+ const { performance } = require("node:perf_hooks");
8
9
 
9
10
  const {
10
11
  detectClaudeCodeSubscriptionDetails,
@@ -174,6 +175,8 @@ async function fetchClaudeUsageLimits(accessToken, { fetchImpl = fetch, maxAttem
174
175
  // reading mislabels it as "5h". Aligned with steipete/CodexBar's rate-window normalizer.
175
176
  const CODEX_SESSION_WINDOW_SECONDS = 18000;
176
177
  const CODEX_WEEKLY_WINDOW_SECONDS = 604800;
178
+ const CODEX_RESET_CREDIT_LIST_TIMEOUT_MS = 3000;
179
+ const CODEX_RESET_CREDIT_LIST_TIMEOUT_GUARD_MS = 25;
177
180
 
178
181
  function classifyCodexWindow(window) {
179
182
  if (!window || typeof window !== "object") return null;
@@ -291,9 +294,103 @@ function normalizeCodexSparkRateWindows(additionalRateLimits) {
291
294
  };
292
295
  }
293
296
 
297
+ function normalizeCodexResetCreditCount(value) {
298
+ return Number.isInteger(value) && value >= 0 ? value : null;
299
+ }
300
+
301
+ function normalizeCodexResetCredit(row, nowMs) {
302
+ if (!row || typeof row !== "object" || Array.isArray(row)) return null;
303
+ if (row.status !== "available") return null;
304
+
305
+ const hasResetType = row.reset_type !== undefined && row.reset_type !== null;
306
+ if (hasResetType && row.reset_type !== "codex_rate_limits") return null;
307
+
308
+ const expiresAt = row.expires_at;
309
+ if (typeof expiresAt !== "string") return null;
310
+ const expiresAtMs = Date.parse(expiresAt);
311
+ if (!Number.isFinite(expiresAtMs) || expiresAtMs < nowMs) return null;
312
+
313
+ const credit = {
314
+ status: row.status,
315
+ expires_at: expiresAt,
316
+ };
317
+ if (typeof row.reset_type === "string") {
318
+ credit.reset_type = row.reset_type;
319
+ }
320
+ if (typeof row.granted_at === "string") {
321
+ credit.granted_at = row.granted_at;
322
+ }
323
+ return { credit, expiresAtMs };
324
+ }
325
+
326
+ function normalizeCodexResetCredits(resetCredits, nowMs = Date.now()) {
327
+ if (!resetCredits || typeof resetCredits !== "object" || Array.isArray(resetCredits)) return null;
328
+
329
+ const availableCount = normalizeCodexResetCreditCount(resetCredits.available_count);
330
+ const totalEarnedCount = normalizeCodexResetCreditCount(resetCredits.total_earned_count);
331
+ const normalized = [];
332
+ if (Array.isArray(resetCredits.credits) && availableCount !== 0) {
333
+ for (const row of resetCredits.credits) {
334
+ const entry = normalizeCodexResetCredit(row, nowMs);
335
+ if (entry) normalized.push(entry);
336
+ }
337
+ }
338
+
339
+ const credits = normalized
340
+ .sort((a, b) => a.expiresAtMs - b.expiresAtMs)
341
+ .slice(0, 50)
342
+ .map((entry) => entry.credit);
343
+
344
+ if (availableCount === null && totalEarnedCount === null && credits.length === 0) {
345
+ return null;
346
+ }
347
+
348
+ return {
349
+ available_count: availableCount,
350
+ total_earned_count: totalEarnedCount,
351
+ credits: availableCount === 0 ? [] : credits,
352
+ };
353
+ }
354
+
355
+ function codexResetCreditListTimeoutMs(remainingProviderBudgetMs) {
356
+ if (!Number.isFinite(remainingProviderBudgetMs)) {
357
+ return CODEX_RESET_CREDIT_LIST_TIMEOUT_MS;
358
+ }
359
+ if (remainingProviderBudgetMs <= 0) return 0;
360
+ const guardedBudgetMs = Math.floor(remainingProviderBudgetMs - CODEX_RESET_CREDIT_LIST_TIMEOUT_GUARD_MS);
361
+ if (guardedBudgetMs <= 0) return 0;
362
+ return Math.min(CODEX_RESET_CREDIT_LIST_TIMEOUT_MS, guardedBudgetMs);
363
+ }
364
+
365
+ async function fetchCodexResetCreditList(fetchImpl, headers, timeoutMs = CODEX_RESET_CREDIT_LIST_TIMEOUT_MS) {
366
+ let timer = null;
367
+ try {
368
+ const request = Promise.resolve()
369
+ .then(() => fetchImpl("https://chatgpt.com/backend-api/wham/rate-limit-reset-credits", {
370
+ method: "GET",
371
+ headers,
372
+ }))
373
+ .then(async (res) => {
374
+ if (!res.ok) return null;
375
+ return normalizeCodexResetCredits(await res.json());
376
+ });
377
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
378
+ return await request;
379
+ }
380
+ const timeout = new Promise((resolve) => {
381
+ timer = setTimeout(() => resolve(null), timeoutMs);
382
+ });
383
+ return await Promise.race([request, timeout]);
384
+ } catch (_err) {
385
+ return null;
386
+ } finally {
387
+ if (timer) clearTimeout(timer);
388
+ }
389
+ }
390
+
294
391
  async function fetchCodexUsageLimits(
295
392
  accessToken,
296
- { fetchImpl = fetch, accountId = null } = {},
393
+ { fetchImpl = fetch, accountId = null, providerTimeoutMs = DEFAULT_PROVIDER_TIMEOUT_MS } = {},
297
394
  ) {
298
395
  const headers = {
299
396
  Authorization: `Bearer ${accessToken}`,
@@ -305,27 +402,53 @@ async function fetchCodexUsageLimits(
305
402
  headers["ChatGPT-Account-Id"] = accountId;
306
403
  }
307
404
 
308
- const res = await fetchImpl("https://chatgpt.com/backend-api/wham/usage", {
309
- method: "GET",
310
- headers,
311
- });
312
- // 401/403/404 from wham means "no usage data available for this auth state" — render
313
- // a neutral empty state instead of a red "Fetch failed" error.
314
- if (res.status === 401 || res.status === 403 || res.status === 404) {
405
+ const startedAtMs = performance.now();
406
+ const usage = await withProviderTimeout(Promise.resolve()
407
+ .then(() => fetchImpl("https://chatgpt.com/backend-api/wham/usage", {
408
+ method: "GET",
409
+ headers,
410
+ }))
411
+ .then(async (res) => {
412
+ // 401/403/404 from wham means "no usage data available for this auth state" — render
413
+ // a neutral empty state instead of a red "Fetch failed" error.
414
+ if (res.status === 401 || res.status === 403 || res.status === 404) {
415
+ return { body: null };
416
+ }
417
+ if (res.status !== 200) {
418
+ throw new Error(`Codex API returned ${res.status}`);
419
+ }
420
+ return { body: await res.json() };
421
+ }), "Codex", providerTimeoutMs);
422
+ if (!usage.body) {
315
423
  return {
316
424
  primary_window: null,
317
425
  secondary_window: null,
318
426
  spark_primary_window: null,
319
427
  spark_secondary_window: null,
428
+ reset_credits: null,
320
429
  };
321
430
  }
322
- if (!res.ok) {
323
- throw new Error(`Codex API returned ${res.status}`);
431
+ const body = usage.body;
432
+ let resetCredits = normalizeCodexResetCredits(body.rate_limit_reset_credits);
433
+ // This semi-private sibling endpoint is read-only; /wham/usage remains the stable count fallback.
434
+ const remainingProviderBudgetMs = Number.isFinite(providerTimeoutMs) && providerTimeoutMs > 0
435
+ ? providerTimeoutMs - (performance.now() - startedAtMs)
436
+ : CODEX_RESET_CREDIT_LIST_TIMEOUT_MS;
437
+ const resetCreditListTimeoutMs = codexResetCreditListTimeoutMs(remainingProviderBudgetMs);
438
+ if (resetCreditListTimeoutMs > 0) {
439
+ const resetCreditsList = await fetchCodexResetCreditList(
440
+ fetchImpl,
441
+ headers,
442
+ resetCreditListTimeoutMs,
443
+ );
444
+ if (resetCreditsList) {
445
+ resetCredits = resetCreditsList;
446
+ }
324
447
  }
325
- const body = await res.json();
326
448
  return {
327
449
  ...normalizeCodexRateWindows(body.rate_limit || {}),
328
450
  ...normalizeCodexSparkRateWindows(body.additional_rate_limits),
451
+ reset_credits: resetCredits,
329
452
  };
330
453
  }
331
454
 
@@ -2174,11 +2297,11 @@ async function fetchUsageLimitsUncached({
2174
2297
  )
2175
2298
  : Promise.resolve(null),
2176
2299
  codexToken
2177
- ? withProviderTimeout(
2178
- fetchCodexUsageLimits(codexToken, { fetchImpl: providerFetch, accountId: codexAccountId }),
2179
- "Codex",
2300
+ ? fetchCodexUsageLimits(codexToken, {
2301
+ fetchImpl: providerFetch,
2302
+ accountId: codexAccountId,
2180
2303
  providerTimeoutMs,
2181
- ).then(
2304
+ }).then(
2182
2305
  (value) => ({ status: "fulfilled", value }),
2183
2306
  (reason) => ({ status: "rejected", reason }),
2184
2307
  )
@@ -2257,6 +2380,7 @@ async function fetchUsageLimitsUncached({
2257
2380
  secondary_window: codexResult.value.secondary_window,
2258
2381
  spark_primary_window: codexResult.value.spark_primary_window,
2259
2382
  spark_secondary_window: codexResult.value.spark_secondary_window,
2383
+ reset_credits: codexResult.value.reset_credits,
2260
2384
  };
2261
2385
  }
2262
2386
 
@@ -1,2 +0,0 @@
1
- import{j as i,V as M,r as f,G as d,U as C,aG as $,i as D,L as A,aH as W}from"./main-CZFzpc5d.js";import{u as G}from"./use-usage-limits-CcbaY6uV.js";import{L as u,a as H,l as g,b as U,u as z}from"./use-limits-display-prefs-BzB-pF4J.js";import{C as E}from"./Card-P4pcpfgk.js";import{F as B}from"./FadeIn-CchoMg8O.js";import{L as V}from"./LocalOnlyNotice-DboBMrlb.js";import"./arrow-up-right-ThOp2PrF.js";import"./download-H-ks1oyK.js";const X=[3,2,3,3,2,2,3];function h({className:e}){return i.jsx("div",{className:M("rounded bg-oai-gray-200/70 dark:bg-oai-gray-800/70 animate-pulse",e)})}function Y(){return i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(h,{className:"h-3 w-12 shrink-0"}),i.jsx(h,{className:"flex-1 h-1.5 rounded-full min-w-0"}),i.jsx(h,{className:"h-3 w-[30px] shrink-0"}),i.jsx(h,{className:"h-3 w-6 shrink-0"})]})}function q({bars:e,index:t}){const r=t%3===0?"w-24":t%3===1?"w-20":"w-[4.5rem]";return i.jsxs("div",{className:"flex flex-col gap-1.5",children:[i.jsxs("div",{className:"flex items-center gap-1.5",children:[i.jsx(h,{className:"h-[14px] w-[14px] rounded shrink-0"}),i.jsx(h,{className:M("h-4",r)})]}),Array.from({length:e},(a,n)=>i.jsx(Y,{},n))]})}function J(){return i.jsx(E,{children:i.jsxs("div",{className:"flex flex-col gap-3",children:[i.jsx(h,{className:"h-3.5 w-28"}),X.map((e,t)=>i.jsx(q,{bars:e,index:t},t))]})})}function Q(e,t){if(!(e>0))return null;const r=(e-t)/e;return Number.isFinite(r)?Math.min(Math.max(r,0),1):null}function Z(e,t,r=.03){return e>t+r}function ee(e){const t=Math.max(0,Math.floor(e)),r=Math.floor(t/3600);return r>24?`${Math.floor(r/24)}d`:r>0?`${r}h`:`${Math.floor(t/60)}m`}function te(e,t){if(typeof e.windowSeconds=="number")return e.windowSeconds;if(e.windowSecondsField&&t){const r=t[e.windowSecondsField];return typeof r=="number"&&r>0?r:null}return null}function S(e){return e==null?NaN:typeof e=="number"?e*1e3:Date.parse(e)}function ie({usedPercent:e,windowSeconds:t,resetMs:r,mode:a,now:n=Date.now()}){const o=Math.min(Math.max(Number(e)||0,0),100)/100,s={pacePercent:null,paceOver:!1,expectedPercent:null,runsOutEta:null,projectedEnd:null};if(!(t>0)||!Number.isFinite(r))return s;const c=Math.max(0,(r-n)/1e3),l=Q(t,c);if(l==null)return s;if(s.expectedPercent=Math.round(l*100),s.paceOver=Z(o,l),o>=.05){const m=a==="remaining"?1-l:l;s.pacePercent=m*100}if(l>.02&&o>0){const m=t*l,x=o/m,p=o/l;p>=1&&x>0?s.runsOutEta=ee((1-o)/x):s.projectedEnd=Math.round(Math.min(p,1)*100)}return s}const I={claude:{windows(e){return[{key:"5h",labelKey:"limits.label.claude_5h",window:e.five_hour,pctField:"utilization",resetField:"resets_at",windowSeconds:5*3600},{key:"7d",labelKey:"limits.label.claude_7d",window:e.seven_day,pctField:"utilization",resetField:"resets_at",windowSeconds:7*86400},{key:"opus",labelKey:"limits.label.claude_opus",window:e.seven_day_opus,pctField:"utilization",resetField:"resets_at",windowSeconds:7*86400}]}},codex:{windows(e){return[{key:"5h",labelKey:"limits.label.codex_5h",window:e.primary_window,windowSecondsField:"limit_window_seconds"},{key:"7d",labelKey:"limits.label.codex_7d",window:e.secondary_window,windowSecondsField:"limit_window_seconds"},{key:"spark-5h",labelKey:"limits.label.codex_spark_5h",window:e.spark_primary_window,windowSecondsField:"limit_window_seconds"},{key:"spark-7d",labelKey:"limits.label.codex_spark_7d",window:e.spark_secondary_window,windowSecondsField:"limit_window_seconds"}]}},cursor:{windows(e){return[{key:"plan",labelKey:"limits.label.cursor_plan",window:e.primary_window},{key:"auto",labelKey:"limits.label.cursor_auto",window:e.secondary_window},{key:"api",labelKey:"limits.label.cursor_api",window:e.tertiary_window}]}},gemini:{windows(e){return[{key:"pro",labelKey:"limits.label.gemini_pro",window:e.primary_window},{key:"flash",labelKey:"limits.label.gemini_flash",window:e.secondary_window},{key:"lite",labelKey:"limits.label.gemini_lite",window:e.tertiary_window}]}},kimi:{extra:"kimi_parallel",windows(e){return[{key:"weekly",labelKey:"limits.label.kimi_weekly",window:e.primary_window,windowSeconds:7*86400},{key:"5h",labelKey:"limits.label.kimi_5h",window:e.secondary_window,windowSeconds:5*3600},{key:"total",labelKey:"limits.label.kimi_total",window:e.tertiary_window}]}},kiro:{windows(e){return[{key:"month",labelKey:"limits.label.kiro_month",window:e.primary_window},{key:"bonus",labelKey:"limits.label.kiro_bonus",window:e.secondary_window}]}},grok:{windows(e){return[{key:"month",labelKey:"limits.label.grok_month",window:e.primary_window},{key:"ondemand",labelKey:"limits.label.grok_ondemand",window:e.secondary_window}]}},antigravity:{windows(e){return[{key:"claude",labelKey:"limits.label.antigravity_claude",window:e.primary_window},{key:"gpro",labelKey:"limits.label.antigravity_gpro",window:e.secondary_window},{key:"flash",labelKey:"limits.label.antigravity_flash",window:e.tertiary_window}]}},copilot:{extra:"copilot_otel",windows(e){return[{key:"premium",labelKey:"limits.label.copilot_premium",window:e.primary_window},{key:"chat",labelKey:"limits.label.copilot_chat",window:e.secondary_window}]}}},re="shrink-0 text-oai-black dark:text-oai-white";function ne(e){const t=S(e);if(!Number.isFinite(t))return null;const r=t-Date.now();if(r<=0)return d("shared.time.now");const a=Math.floor(r/6e4);if(a<60)return`${a}m`;const n=Math.floor(a/60);return n<24?`${n}h`:`${Math.floor(n/24)}d`}function ae(e,t){const r=t===u.REMAINING?100-e:e;return r>=90?"bg-red-500":r>=70?"bg-amber-500":"bg-emerald-500"}function b(e,t="used_percent"){return e?t==="utilization"?e.utilization:e.used_percent:null}function L(e,t="reset_at"){return e?t==="resets_at"?e.resets_at:e.reset_at:null}function le(e,t){return ie({usedPercent:b(e.window,e.pctField),windowSeconds:te(e,e.window),resetMs:S(L(e.window,e.resetField)),mode:t})}function oe({label:e,pct:t,reset:r,mode:a=u.USED,pacePercent:n=null,paceOver:o=!1}){const s=Math.max(0,Math.min(100,Number(t)||0)),c=a===u.REMAINING?100-s:s,l=Math.round(c),m=c>0&&l===0?Math.max(c,.35):c;let x=String(l);c>0&&l===0&&(x=d("limits.bar.sub_one_percent"));const p=n==null?null:Math.max(0,Math.min(100,n));return i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("span",{"data-limit-label":"",className:"text-[11px] text-oai-gray-500 dark:text-oai-gray-400 shrink-0 whitespace-nowrap",style:{width:"var(--tt-limits-label-w)"},children:e}),i.jsxs("div",{className:"relative flex-1 bg-oai-gray-100 dark:bg-oai-gray-700/50 rounded-full h-1.5 overflow-hidden",children:[i.jsx("div",{className:`${ae(c,a)} rounded-full h-full transition-[width] duration-500 ease-out`,style:{width:`${m}%`,minWidth:c>0?"3px":0}}),p!=null&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"absolute top-0 h-full bg-oai-gray-100 dark:bg-oai-gray-700/50",style:{left:`calc(${p}% - 3px)`,width:"6px"}}),i.jsx("div",{className:`absolute top-0 h-full ${o?"bg-red-500":"bg-emerald-500"}`,style:{left:`calc(${p}% - 1px)`,width:"2px"}})]})]}),i.jsxs("span",{className:"text-[11px] tabular-nums text-oai-gray-500 dark:text-oai-gray-400 w-9 text-right shrink-0 whitespace-nowrap",children:[x,"%"]}),r&&i.jsx("span",{className:"text-[10px] text-oai-gray-400 dark:text-oai-gray-500 w-6 text-right shrink-0",children:r})]})}function se(e,t,r){const a=d(e.labelKey),n=r===u.REMAINING,o=l=>n?100-l:l;if(t.expectedPercent==null){const l=Math.round(Math.max(0,Math.min(100,Number(b(e.window,e.pctField))||0)));return n?d("limits.explain.remaining",{label:a,used:o(l)}):d("limits.explain.used",{label:a,used:l})}if(t.paceOver){if(t.runsOutEta)return d("limits.explain.ahead_eta",{label:a,eta:t.runsOutEta});const l=o(t.projectedEnd??100);return d(n?"limits.explain.ahead_pct_remaining":"limits.explain.ahead_pct",{label:a,pct:l})}const s=Math.round(Math.max(0,Math.min(100,Number(b(e.window,e.pctField))||0))),c=o(t.projectedEnd??s);return d(n?"limits.explain.on_track_remaining":"limits.explain.on_track",{label:a,pct:c})}function de({rows:e,mode:t}){if(e.length===0)return null;const r=t===u.REMAINING;return i.jsxs("div",{className:"mt-1 flex flex-col gap-1",children:[e.map(({spec:a,pace:n})=>i.jsx("div",{className:"text-[11px] leading-snug text-oai-gray-600 dark:text-oai-gray-300",children:se(a,n,t)},a.key)),i.jsx("div",{className:"mt-1 pt-1.5 border-t border-oai-gray-200/70 dark:border-oai-gray-700/50 text-[10.5px] leading-snug text-oai-gray-400 dark:text-oai-gray-500",children:d(r?"limits.explain.body_remaining":"limits.explain.body")})]})}function _({name:e,providerId:t,children:r,expandable:a=!1,expanded:n=!1,onToggle:o}){const s=U(t),c=i.jsxs("div",{className:"flex items-center gap-1.5",children:[s?i.jsx(C,{provider:s,size:14,className:re}):null,i.jsx("span",{className:"text-sm font-medium text-oai-black dark:text-oai-white",children:e})]});return a?i.jsxs("div",{role:"button",tabIndex:0,"aria-expanded":n,onClick:o,onKeyDown:l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),o?.())},className:"flex flex-col gap-1.5 -mx-1.5 px-1.5 py-1 rounded-lg cursor-pointer transition-colors hover:bg-oai-gray-50 dark:hover:bg-oai-gray-800/40 aria-expanded:bg-oai-gray-50 dark:aria-expanded:bg-oai-gray-800/40",children:[c,r]}):i.jsxs("div",{className:"flex flex-col gap-1.5",children:[c,r]})}const ce=H;function y({children:e,tone:t="neutral"}){const r=t==="error"?"text-red-600 dark:text-red-400":"text-oai-gray-500 dark:text-oai-gray-400";return i.jsx("div",{className:`text-[11px] leading-snug ${r}`,children:e})}function me({rows:e,mode:t,extra:r=null}){const a=e.length===0&&!r;return i.jsxs(i.Fragment,{children:[e.map(({spec:n,pace:o})=>i.jsx(oe,{label:d(n.labelKey),pct:b(n.window,n.pctField),reset:ne(L(n.window,n.resetField)),mode:t,pacePercent:o.pacePercent,paceOver:o.paceOver},n.key)),a?i.jsx(y,{children:d("limits.status.no_data")}):null,r]})}function ue(e,t){return e==="kimi_parallel"&&t.parallel_limit?i.jsx(y,{children:d("limits.label.kimi_parallel",{count:t.parallel_limit})}):e==="copilot_otel"&&!t.otel_has_files&&!t.otel_enabled?i.jsx(we,{defaultDir:t.otel_default_dir}):null}function xe(e,t,r,a,n,o){const s=I[e];if(!s)return null;const c=s.windows(t).filter(m=>m.window).map(m=>({spec:m,pace:le(m,a)})),l=ue(s.extra,t);return i.jsxs(_,{name:r,providerId:e,expandable:c.length>0,expanded:n,onToggle:o,children:[i.jsx(me,{mode:a,rows:c,extra:l}),n?i.jsx(de,{rows:c,mode:a}):null]},e)}function pe(e,t,r,a,n){if(!I[e])return null;if(!t?.configured)return i.jsx(_,{name:g(e),providerId:e,children:i.jsx(y,{children:d("limits.status.not_connected")})},e);if(t.error)return i.jsx(_,{name:g(e),providerId:e,children:i.jsx(y,{tone:"error",children:d("shared.error.prefix",{error:t.error})})},e);const o=g(e),s=t.plan_label?`${o} ${t.plan_label}`:o;return xe(e,t,s,r,a,n)}function we({defaultDir:e}){const[t,r]=f.useState(!1),n=["export COPILOT_OTEL_ENABLED=true","export COPILOT_OTEL_EXPORTER_TYPE=file",`export COPILOT_OTEL_FILE_EXPORTER_PATH="${e||"$HOME/.copilot/otel"}/copilot-otel-$(date +%Y%m%d).jsonl"`].join(`
2
- `),o=async s=>{s.stopPropagation();try{await navigator.clipboard.writeText(n),r(!0),setTimeout(()=>r(!1),1600)}catch{}};return i.jsxs("div",{className:"mt-1 rounded-md border border-amber-300/60 dark:border-amber-700/40 bg-amber-50/50 dark:bg-amber-900/10 px-2.5 py-2 text-[11px] text-oai-gray-600 dark:text-oai-gray-300",children:[i.jsx("div",{className:"font-medium text-oai-gray-700 dark:text-oai-gray-200",children:d("limits.copilot.otelHint.title")}),i.jsx("div",{className:"mt-0.5 leading-snug",children:d("limits.copilot.otelHint.body")}),i.jsx("pre",{className:"mt-1.5 overflow-x-auto rounded bg-oai-gray-100 dark:bg-oai-gray-900/60 px-2 py-1.5 font-mono text-[10.5px] leading-tight whitespace-pre",children:n}),i.jsx("button",{type:"button",onClick:o,className:"mt-1 inline-flex items-center gap-1 rounded border border-oai-gray-300 dark:border-oai-gray-700 px-1.5 py-0.5 text-[10.5px] text-oai-gray-700 dark:text-oai-gray-200 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-800 transition-colors",children:t?d("limits.copilot.otelHint.copied"):d("limits.copilot.otelHint.copy")})]})}function he(e){const[t,r]=f.useState(0);return f.useLayoutEffect(()=>{const a=e.current;if(!a)return;const n=a.querySelectorAll("[data-limit-label]");let o=0;const s=n.length>0?document.createElement("canvas").getContext("2d"):null;if(s){const l=window.getComputedStyle(n[0]);s.font=`${l.fontStyle} ${l.fontWeight} ${l.fontSize} ${l.fontFamily}`;for(const m of n)o=Math.max(o,s.measureText(m.textContent).width)}const c=Math.ceil(o);r(l=>l===c?l:c)}),t}function fe({claude:e,codex:t,cursor:r,gemini:a,kimi:n,kiro:o,grok:s,antigravity:c,copilot:l,order:m,visibility:x,displayMode:p}){const P={claude:e,codex:t,cursor:r,gemini:a,kimi:n,kiro:o,grok:s,antigravity:c,copilot:l},k=f.useRef(null),j=he(k),[F,O]=f.useState(null),R=Array.isArray(m)&&m.length>0?m:ce,v=p===u.REMAINING?u.REMAINING:u.USED,K=v===u.REMAINING?d("limits.settings.display_mode_remaining"):d("limits.settings.display_mode_used"),N=R.filter(w=>!x||x[w]!==!1).map(w=>pe(w,P[w],v,F===w,()=>O(T=>T===w?null:w))).filter(Boolean);return i.jsx(B,{delay:.15,children:i.jsx(E,{children:i.jsxs("div",{ref:k,className:"flex flex-col gap-3",style:j>0?{"--tt-limits-label-w":`${j}px`}:void 0,children:[i.jsxs("h3",{className:"text-sm font-medium text-oai-gray-500 dark:text-oai-gray-300 uppercase tracking-wide",children:[d("limits.panel.title"),d("limits.panel.mode_separator"),K]}),N.length>0?N:i.jsx(y,{children:d("limits.status.all_hidden")})]})})})}const ye=typeof window<"u"&&(window.location.hostname==="localhost"||window.location.hostname==="127.0.0.1");function Ee(){const e=$(),{data:t,error:r,isLoading:a}=G(e?{initialRefresh:!0,initialState:e,publishToPreloadCache:!0}:{initialRefresh:!0,publishToPreloadCache:!0}),n=z();return!ye&&!D()?i.jsx("div",{className:"flex flex-col flex-1 text-oai-black dark:text-oai-white font-oai antialiased",children:i.jsx(V,{})}):i.jsx("div",{className:"flex flex-col flex-1 text-oai-black dark:text-oai-white font-oai antialiased",children:i.jsx("main",{className:"flex-1 pt-8 sm:pt-10 pb-12 sm:pb-16",children:i.jsxs("div",{className:"mx-auto max-w-6xl px-4 sm:px-6",children:[i.jsxs("div",{className:"flex flex-row items-start justify-between gap-4 mb-8",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsx("h1",{className:"text-3xl sm:text-4xl font-semibold tracking-tight text-oai-black dark:text-white mb-3",children:d("nav.limits")}),i.jsx("p",{className:"text-oai-gray-500 dark:text-oai-gray-400 text-sm sm:text-base",children:d("limits.page.subtitle")})]}),i.jsx(A,{to:"/settings","aria-label":d("limits.page.openSettings"),title:d("limits.page.openSettings"),className:"shrink-0 inline-flex h-9 w-9 items-center justify-center rounded-lg border border-oai-gray-200 dark:border-oai-gray-800 text-oai-gray-600 dark:text-oai-gray-400 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-800 hover:text-oai-black dark:hover:text-white transition-colors no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-oai-brand-500",children:i.jsx(W,{className:"h-4 w-4","aria-hidden":!0})})]}),a?i.jsx(J,{}):i.jsxs(i.Fragment,{children:[r?i.jsx("p",{className:"mb-4 text-sm text-red-500 dark:text-red-400",children:d("shared.error.prefix",{error:r})}):null,i.jsx(fe,{claude:t?.claude,codex:t?.codex,cursor:t?.cursor,gemini:t?.gemini,kimi:t?.kimi,kiro:t?.kiro,grok:t?.grok,antigravity:t?.antigravity,copilot:t?.copilot,order:n.order,visibility:n.visibility,displayMode:n.displayMode})]})]})})})}export{Ee as LimitsPage};