tokentracker-cli 0.87.2 → 0.87.4

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 (100) hide show
  1. package/dashboard/dist/assets/{AchievementBadge-C468-Rsw.js → AchievementBadge-jaWv39Mh.js} +1 -1
  2. package/dashboard/dist/assets/{AchievementsPage-CZWzSdiH.js → AchievementsPage-CqIWdffx.js} +2 -2
  3. package/dashboard/dist/assets/{AchievementsSection-DXt6VbwH.js → AchievementsSection-RAoIBoQ_.js} +1 -1
  4. package/dashboard/dist/assets/{BadgeDetailModal-BtGvpqQm.js → BadgeDetailModal-CYaSfxwZ.js} +1 -1
  5. package/dashboard/dist/assets/{Card-DZ-_fXkw.js → Card-Cl4XFCGL.js} +1 -1
  6. package/dashboard/dist/assets/{ClawdAnimated-9rXaHo1-.js → ClawdAnimated-DuFB46-u.js} +1 -1
  7. package/dashboard/dist/assets/{CommandPalette-sqIvZNsH.js → CommandPalette-CLfTNQK0.js} +1 -1
  8. package/dashboard/dist/assets/{CommunityStatsModal-c8VohIqQ.js → CommunityStatsModal-DCRCXmPl.js} +1 -1
  9. package/dashboard/dist/assets/{ConfirmModal-Ct2HLdds.js → ConfirmModal-B0IuSw4g.js} +1 -1
  10. package/dashboard/dist/assets/{Controls-DPtXGUGi.js → Controls-BJF1FutB.js} +1 -1
  11. package/dashboard/dist/assets/DashboardPage-BFthq-Oc.js +1 -0
  12. package/dashboard/dist/assets/{DevicePage-Ds4GEuqY.js → DevicePage-iZn2m4Y3.js} +1 -1
  13. package/dashboard/dist/assets/{DialogClose-B2IAbJG4.js → DialogClose-CdPKVRcX.js} +1 -1
  14. package/dashboard/dist/assets/DialogDescription-pCAELf1b.js +1 -0
  15. package/dashboard/dist/assets/{DialogTitle-BIwLH6gA.js → DialogTitle-Ul-NH9HD.js} +1 -1
  16. package/dashboard/dist/assets/{FadeIn-DPS7_DOB.js → FadeIn-Bb3pNOAn.js} +1 -1
  17. package/dashboard/dist/assets/{HeaderGithubStar-CsSgr9Hd.js → HeaderGithubStar-CtUK-3_x.js} +1 -1
  18. package/dashboard/dist/assets/{HoverTooltip-CLGZW2d-.js → HoverTooltip-B3TmAZtV.js} +1 -1
  19. package/dashboard/dist/assets/{IpCheckPage-DEM_uk69.js → IpCheckPage-CXcY3jc-.js} +1 -1
  20. package/dashboard/dist/assets/{LandingPage-BQ3YzZ68.js → LandingPage-BK4sn4MV.js} +2 -2
  21. package/dashboard/dist/assets/{LeaderboardAvatar-ySznr4Ml.js → LeaderboardAvatar-AYzG1gTH.js} +1 -1
  22. package/dashboard/dist/assets/LeaderboardPage-DhKcc74d.js +2 -0
  23. package/dashboard/dist/assets/{LeaderboardProfileModal-Drvsb5xF.js → LeaderboardProfileModal-DvmDBmOL.js} +3 -3
  24. package/dashboard/dist/assets/{LeaderboardProfilePage-BD0P-zZF.js → LeaderboardProfilePage-1_GGQngL.js} +1 -1
  25. package/dashboard/dist/assets/{LimitsPage-Mbn2mj6S.js → LimitsPage-dSEtf2TB.js} +1 -1
  26. package/dashboard/dist/assets/{LocalOnlyNotice-BsKgtoVa.js → LocalOnlyNotice-Bo1dtxi6.js} +1 -1
  27. package/dashboard/dist/assets/{LoginCard-CTQDdHcx.js → LoginCard-BpjNU-ah.js} +1 -1
  28. package/dashboard/dist/assets/{LoginModal-BxCyLDEW.js → LoginModal-D3_vPG1R.js} +1 -1
  29. package/dashboard/dist/assets/{LoginPage-ftxnX8g1.js → LoginPage-BoeLhbwK.js} +1 -1
  30. package/dashboard/dist/assets/{PetPage-CQsfqsm8.js → PetPage-BnkNWvcV.js} +1 -1
  31. package/dashboard/dist/assets/PopoverPopup-CkaOLLN4.js +1 -0
  32. package/dashboard/dist/assets/{ProviderIcon-7Tkq9_m6.js → ProviderIcon-B3hZ1YWD.js} +1 -1
  33. package/dashboard/dist/assets/{ResetPasswordPage-D-MPpQd1.js → ResetPasswordPage-BusTiA5M.js} +1 -1
  34. package/dashboard/dist/assets/{SegmentedControl-CYFrzu9w.js → SegmentedControl-C_IwmWnO.js} +1 -1
  35. package/dashboard/dist/assets/{Select-Dp4V9p6t.js → Select-Dj3hUGFb.js} +1 -1
  36. package/dashboard/dist/assets/SelectItemText-BWaMX4pY.js +1 -0
  37. package/dashboard/dist/assets/{ServiceStatusPage-BT6hvvLW.js → ServiceStatusPage-BnnCouAs.js} +1 -1
  38. package/dashboard/dist/assets/{SessionsPage-BopeZBiH.js → SessionsPage-DMU5CiFf.js} +1 -1
  39. package/dashboard/dist/assets/SettingsPage-_cJl0qwK.js +1 -0
  40. package/dashboard/dist/assets/{SkillsPage-Cr8O6eOH.js → SkillsPage-Cz3tV65I.js} +1 -1
  41. package/dashboard/dist/assets/{TokenGalaxy-BoUsrUEs.js → TokenGalaxy-BddGGmti.js} +1 -1
  42. package/dashboard/dist/assets/{ToolbarRootContext-CwRaHhMN.js → ToolbarRootContext-Q_DQJlr5.js} +1 -1
  43. package/dashboard/dist/assets/{TrendMonitor-BV2ugEsw.js → TrendMonitor-CVi7mLtI.js} +1 -1
  44. package/dashboard/dist/assets/{WidgetsPage-B7r4mvrw.js → WidgetsPage-BdIGupvg.js} +1 -1
  45. package/dashboard/dist/assets/{WrappedPage-CFU9l22i.js → WrappedPage-BB-orT9Q.js} +1 -1
  46. package/dashboard/dist/assets/{__vite-browser-external-Db9onipF.js → __vite-browser-external-egzerGU6.js} +2 -2
  47. package/dashboard/dist/assets/{agent-logos-DSSn_SPi.js → agent-logos-B2pH4QTS.js} +1 -1
  48. package/dashboard/dist/assets/{arrow-up-right-COvrArNz.js → arrow-up-right-CEUtBwnj.js} +1 -1
  49. package/dashboard/dist/assets/{check-CasSqiev.js → check-Ct-iMhaB.js} +1 -1
  50. package/dashboard/dist/assets/{chevron-right-B1PMeNoD.js → chevron-right-CIcqYgwy.js} +1 -1
  51. package/dashboard/dist/assets/{copy-D67vycfp.js → copy-Bx07orpr.js} +1 -1
  52. package/dashboard/dist/assets/{download-adOCFO2v.js → download-6N9dBj_W.js} +1 -1
  53. package/dashboard/dist/assets/{external-link-DVanKEuy.js → external-link-B39v_fs8.js} +1 -1
  54. package/dashboard/dist/assets/{flame-RbiHZM9b.js → flame-xbjyxu-1.js} +1 -1
  55. package/dashboard/dist/assets/{format-tokens-DhMp1e1L.js → format-tokens-C1ZXX8ed.js} +1 -1
  56. package/dashboard/dist/assets/{icons-BC0p_aGr.js → icons-D7dTRGnv.js} +1 -1
  57. package/dashboard/dist/assets/{index-A41xjc83.js → index-BJ8Q1dU0.js} +1 -1
  58. package/dashboard/dist/assets/{index-DrgBqR3o.js → index-MbSf_y6N.js} +1 -1
  59. package/dashboard/dist/assets/{index-CaRyTJ6K.js → index-pxtsHew5.js} +1 -1
  60. package/dashboard/dist/assets/{info-D9LwqlnC.js → info-YSmBFAMa.js} +1 -1
  61. package/dashboard/dist/assets/{limits-providers-CRHpXhmW.js → limits-providers-BDltKBG_.js} +1 -1
  62. package/dashboard/dist/assets/{link-2-B5f4qFR0.js → link-2--CbT8swK.js} +1 -1
  63. package/dashboard/dist/assets/{loader-circle-DCmwZEdS.js → loader-circle-B5Hs89F2.js} +1 -1
  64. package/dashboard/dist/assets/{maximize-2-BMalEDCZ.js → maximize-2-Cj3P-Bay.js} +1 -1
  65. package/dashboard/dist/assets/modifiers.esm-BXOR3VJH.js +1 -0
  66. package/dashboard/dist/assets/{provider-display-qMFRUZHm.js → provider-display-BXtFP7Ak.js} +1 -1
  67. package/dashboard/dist/assets/{react-BnaPNGj8.js → react-DujpLuOh.js} +1 -1
  68. package/dashboard/dist/assets/{search-BrqBkLs2.js → search-BswhdD2a.js} +1 -1
  69. package/dashboard/dist/assets/{skills-api-vo3iM6yD.js → skills-api-CGohvSGo.js} +1 -1
  70. package/dashboard/dist/assets/sortable.esm-BXiHjoqY.js +5 -0
  71. package/dashboard/dist/assets/{store-BwMVXuz3.js → store-BTdeRhbU.js} +1 -1
  72. package/dashboard/dist/assets/{terminal-BiyUh_8k.js → terminal-DawYBEVr.js} +1 -1
  73. package/dashboard/dist/assets/{trash-2-DAr4sqkX.js → trash-2-CSt4wZ-I.js} +1 -1
  74. package/dashboard/dist/assets/{use-community-stats-Cg48Zphy.js → use-community-stats-CHZTziox.js} +1 -1
  75. package/dashboard/dist/assets/{use-limits-display-prefs-DfKtH1Zn.js → use-limits-display-prefs-ChK-GCxK.js} +1 -1
  76. package/dashboard/dist/assets/use-ordered-list-DyyjthSr.js +1 -0
  77. package/dashboard/dist/assets/use-reduced-motion-B9hTo-eX.js +1 -0
  78. package/dashboard/dist/assets/{use-session-efficiency-pref-CMDTCAAd.js → use-session-efficiency-pref-Dv1clCTZ.js} +1 -1
  79. package/dashboard/dist/assets/{use-transform-B2d9Txt5.js → use-transform-DyBvIIFA.js} +1 -1
  80. package/dashboard/dist/assets/{use-usage-limits-CJbTUl9W.js → use-usage-limits-DrhY6h3M.js} +1 -1
  81. package/dashboard/dist/assets/{useCurrency-B0hJte5f.js → useCurrency-BgFo76Yb.js} +1 -1
  82. package/dashboard/dist/assets/{useScrollLock-DuosKdSB.js → useScrollLock-DPW-g15w.js} +1 -1
  83. package/dashboard/dist/assets/{useTokenFormat-DB8pKLFM.js → useTokenFormat-DrVDs8zo.js} +1 -1
  84. package/dashboard/dist/assets/{zap-rbzC4XgP.js → zap-Dsg_ZyH3.js} +1 -1
  85. package/dashboard/dist/index.html +1 -1
  86. package/dashboard/dist/ip-check.html +1 -1
  87. package/dashboard/dist/leaderboard.html +1 -1
  88. package/dashboard/dist/share.html +1 -1
  89. package/package.json +1 -1
  90. package/src/lib/codex-token-refresh.js +35 -7
  91. package/src/lib/pricing/seed-snapshot.json +1 -1
  92. package/src/lib/usage-limits.js +39 -28
  93. package/dashboard/dist/assets/DashboardPage-C65hbl8o.js +0 -1
  94. package/dashboard/dist/assets/DialogDescription-DeRza-LI.js +0 -1
  95. package/dashboard/dist/assets/LeaderboardPage-Br4JCoVE.js +0 -2
  96. package/dashboard/dist/assets/PopoverPopup-C16r8jQC.js +0 -1
  97. package/dashboard/dist/assets/SelectItemText-CxhBeoxx.js +0 -1
  98. package/dashboard/dist/assets/SettingsPage-D03GJJBd.js +0 -1
  99. package/dashboard/dist/assets/use-ordered-list-CnXfrWeF.js +0 -5
  100. package/dashboard/dist/assets/use-reduced-motion-BIgYrbON.js +0 -1
@@ -523,15 +523,16 @@ async function fetchCodexUsageLimits(
523
523
  // 401/403/404 from wham means "no usage data available for this auth state" — render
524
524
  // a neutral empty state instead of a red "Fetch failed" error.
525
525
  if (res.status === 401 || res.status === 403 || res.status === 404) {
526
- return { body: null };
526
+ return { body: null, status: res.status };
527
527
  }
528
528
  if (res.status !== 200) {
529
529
  throw new Error(`Codex API returned ${res.status}`);
530
530
  }
531
- return { body: await res.json() };
531
+ return { body: await res.json(), status: res.status };
532
532
  }), "Codex", providerTimeoutMs);
533
533
  if (!usage.body) {
534
534
  return {
535
+ upstream_status: usage.status,
535
536
  primary_window: null,
536
537
  secondary_window: null,
537
538
  credit_window: null,
@@ -558,6 +559,7 @@ async function fetchCodexUsageLimits(
558
559
  }
559
560
  }
560
561
  return {
562
+ upstream_status: usage.status,
561
563
  ...normalizeCodexRateWindows(body.rate_limit || {}),
562
564
  credit_window: normalizeCodexCreditWindow(body.spend_control?.individual_limit),
563
565
  ...normalizeCodexSparkRateWindows(body.additional_rate_limits),
@@ -3051,14 +3053,14 @@ async function fetchUsageLimitsUncached({
3051
3053
  ]);
3052
3054
  const claudePlanType = claudeSubscription?.planType || null;
3053
3055
 
3054
- // Proactively refresh Codex tokens that are >8 days stale, mirroring CodexBar's
3055
- // CodexTokenRefresher.swift. Without this, users who logged in once and didn't run
3056
- // `codex` for >a week get wham 401 "Fetch failed" (issue #52). Best-effort: any
3057
- // refresh failure falls through to using the existing (possibly stale) token, then the
3058
- // 4xx graceful path in fetchCodexUsageLimits surfaces a neutral state instead of red.
3056
+ // Match the official Codex CLI: prefer the access token's JWT expiry and refresh only
3057
+ // within five minutes of it; fall back to last_refresh >8 days for opaque/legacy tokens.
3058
+ // Best-effort: a refresh failure still falls through to the existing access token.
3059
3059
  let refreshError = null;
3060
3060
  let codexAuthRefreshed = codexAuth;
3061
- if (codexAuth && isTokenStale(codexAuth.lastRefresh) && codexAuth.refreshToken) {
3061
+ if (codexAuth
3062
+ && isTokenStale(codexAuth.lastRefresh, nowMs, codexAuth.accessToken)
3063
+ && codexAuth.refreshToken) {
3062
3064
  try {
3063
3065
  const newTokens = await refreshCodexTokens({
3064
3066
  refreshToken: codexAuth.refreshToken,
@@ -3225,28 +3227,18 @@ async function fetchUsageLimitsUncached({
3225
3227
  claude.service_status = claudeServiceStatus;
3226
3228
  }
3227
3229
 
3230
+ const codexRefreshRequiresReauth = refreshError?.code === "REFRESH_TOKEN_EXPIRED";
3231
+ const codexLiveUsageSucceeded = codexResult?.status === "fulfilled"
3232
+ && codexResult.value.upstream_status === 200;
3228
3233
  let codex;
3229
3234
  if (!codexToken) {
3230
3235
  codex = { configured: false };
3231
- } else if (refreshError && refreshError.code === "REFRESH_TOKEN_EXPIRED") {
3232
- // Refresh token is dead — the user must re-run `codex` to log in again. Surface a
3233
- // specific, actionable message rather than the generic "Fetch failed".
3234
- codex = {
3235
- configured: true,
3236
- error: refreshError.message,
3237
- auth_action_required: "reauth",
3238
- };
3239
- } else if (!codexResult || codexResult.status === "rejected") {
3240
- // Live fetch failed or timed out (Codex hits chatgpt.com fresh every poll with no
3241
- // rate-limit cooldown, so a slow network shows up here often). Serve the last successful
3242
- // read so the bars stay visible instead of a red error, mirroring the Claude stale path.
3243
- const cached = readCodexLimitsCache({ home, nowMs });
3244
- if (cached) {
3245
- codex = cached;
3246
- } else {
3247
- codex = { configured: true, error: codexResult?.reason?.message || "Unknown error" };
3248
- }
3249
- } else {
3236
+ } else if (codexResult?.status === "fulfilled"
3237
+ && (!codexRefreshRequiresReauth || codexLiveUsageSucceeded)) {
3238
+ // A proactive refresh can fail while the existing access token is still valid.
3239
+ // Prefer a confirmed 200 live usage read over the refresh error so usable quota
3240
+ // data is not discarded before the access token actually expires. A neutral
3241
+ // 401/403/404 no-data response must not mask a failed refresh.
3250
3242
  codex = {
3251
3243
  configured: true,
3252
3244
  error: null,
@@ -3257,13 +3249,32 @@ async function fetchUsageLimitsUncached({
3257
3249
  spark_primary_window: codexResult.value.spark_primary_window,
3258
3250
  spark_secondary_window: codexResult.value.spark_secondary_window,
3259
3251
  reset_credits: codexResult.value.reset_credits,
3260
- // Live read is current as of now; the stale fallback path above serves the
3252
+ // Live read is current as of now; the stale fallback path below serves the
3261
3253
  // disk cache with `stale: true`. Always emitting both lets the client show a
3262
3254
  // data-age label uniformly (see the Claude live-success block).
3263
3255
  stale: false,
3264
3256
  cached_at: new Date(nowMs).toISOString(),
3265
3257
  };
3266
3258
  writeCodexLimitsCache(codex, { home, nowMs });
3259
+ } else if (codexRefreshRequiresReauth) {
3260
+ // Refresh token is dead — the user must re-run `codex` to log in again. Surface a
3261
+ // specific, actionable message rather than the generic "Fetch failed", but only
3262
+ // after the existing access token also failed to fetch live usage above.
3263
+ codex = {
3264
+ configured: true,
3265
+ error: refreshError.message,
3266
+ auth_action_required: "reauth",
3267
+ };
3268
+ } else if (!codexResult || codexResult.status === "rejected") {
3269
+ // Live fetch failed or timed out (Codex hits chatgpt.com fresh every poll with no
3270
+ // rate-limit cooldown, so a slow network shows up here often). Serve the last successful
3271
+ // read so the bars stay visible instead of a red error, mirroring the Claude stale path.
3272
+ const cached = readCodexLimitsCache({ home, nowMs });
3273
+ if (cached) {
3274
+ codex = cached;
3275
+ } else {
3276
+ codex = { configured: true, error: codexResult?.reason?.message || "Unknown error" };
3277
+ }
3267
3278
  }
3268
3279
 
3269
3280
  const data = {