tokentracker-cli 0.83.5 → 0.83.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.
Files changed (166) hide show
  1. package/dashboard/dist/assets/{AchievementBadge-bb85jTC_.js → AchievementBadge-DmDyXJAz.js} +1 -1
  2. package/dashboard/dist/assets/{AchievementsPage-CQROtjFC.js → AchievementsPage-BMfTuXqd.js} +2 -2
  3. package/dashboard/dist/assets/{AchievementsSection-DtPA6JRC.js → AchievementsSection-Dn9Wk4pP.js} +1 -1
  4. package/dashboard/dist/assets/{BadgeDetailModal-ClNP9o6O.js → BadgeDetailModal-BiOuKQet.js} +1 -1
  5. package/dashboard/dist/assets/{Card-CODGNqLE.js → Card-WA_W0aUg.js} +1 -1
  6. package/dashboard/dist/assets/{ClawdAnimated-D4gKSsF0.js → ClawdAnimated-BINDhx9z.js} +1 -1
  7. package/dashboard/dist/assets/{CommandPalette-BIFV44le.js → CommandPalette-DPtrs3eZ.js} +1 -1
  8. package/dashboard/dist/assets/{CommunityStatsModal-CRy5X2iH.js → CommunityStatsModal-C1sZ3KwZ.js} +1 -1
  9. package/dashboard/dist/assets/{ConfirmModal-CcmMz3l0.js → ConfirmModal-DUWujtDw.js} +1 -1
  10. package/dashboard/dist/assets/DashboardPage-YEajmB-U.js +1 -0
  11. package/dashboard/dist/assets/DevicePage-B9URlU78.js +1 -0
  12. package/dashboard/dist/assets/{DialogClose-Do5zKE_e.js → DialogClose-xjinPgj0.js} +1 -1
  13. package/dashboard/dist/assets/DialogDescription-cOH4S5rw.js +1 -0
  14. package/dashboard/dist/assets/{DialogTitle-AfjYgW9_.js → DialogTitle-Cmm7Tr9m.js} +1 -1
  15. package/dashboard/dist/assets/{FadeIn-BLIoLlDr.js → FadeIn-jcFbPTOF.js} +1 -1
  16. package/dashboard/dist/assets/HeaderGithubStar-Dn6u7prD.js +1 -0
  17. package/dashboard/dist/assets/{IpCheckPage-Cp5PaKZ2.js → IpCheckPage-BM8LGcNw.js} +1 -1
  18. package/dashboard/dist/assets/{LandingPage-DVm8soRU.js → LandingPage-q9GLy3YJ.js} +2 -2
  19. package/dashboard/dist/assets/{LeaderboardAvatar-VOe0xbW6.js → LeaderboardAvatar-_2M5HnN2.js} +1 -1
  20. package/dashboard/dist/assets/LeaderboardPage-DSS4pTNm.js +2 -0
  21. package/dashboard/dist/assets/{LeaderboardProfileModal-Jd0LadRF.js → LeaderboardProfileModal-upBPylvC.js} +4 -4
  22. package/dashboard/dist/assets/{LeaderboardProfilePage-UjcQrVw9.js → LeaderboardProfilePage-BxmJjErC.js} +3 -3
  23. package/dashboard/dist/assets/{LimitsPage-BCT373SL.js → LimitsPage-DahLoAx7.js} +1 -1
  24. package/dashboard/dist/assets/{LocalOnlyNotice-B6OY1s7h.js → LocalOnlyNotice-CZCZcHZ1.js} +1 -1
  25. package/dashboard/dist/assets/{LoginCard-DSHO0tm0.js → LoginCard-Cw3H2QOQ.js} +1 -1
  26. package/dashboard/dist/assets/{LoginModal-BDWfRxca.js → LoginModal-BYidPScd.js} +1 -1
  27. package/dashboard/dist/assets/{LoginPage-C6CUveep.js → LoginPage-BBfz7idN.js} +1 -1
  28. package/dashboard/dist/assets/{PetPage-Wbdo96d7.js → PetPage-CG_v30vw.js} +1 -1
  29. package/dashboard/dist/assets/{PopoverPopup-CnBdmF9h.js → PopoverPopup-SEq9dvEQ.js} +1 -1
  30. package/dashboard/dist/assets/{ProviderIcon-BUmOfjp8.js → ProviderIcon-CjAvUaYE.js} +1 -1
  31. package/dashboard/dist/assets/{ResetPasswordPage-CoRcV6wA.js → ResetPasswordPage-B810eyXT.js} +1 -1
  32. package/dashboard/dist/assets/{Select-Bz_TBa69.js → Select-SLV7eQ5u.js} +1 -1
  33. package/dashboard/dist/assets/{SelectItemText-De1kreqq.js → SelectItemText-icj0Q7zH.js} +1 -1
  34. package/dashboard/dist/assets/{SettingsPage-BKhfZgg5.js → SettingsPage-9mkMJ04G.js} +1 -1
  35. package/dashboard/dist/assets/{SkillsPage-Dxfd-u3a.js → SkillsPage-B9uumgJS.js} +1 -1
  36. package/dashboard/dist/assets/{TokenGalaxy-F8A-Nd-g.js → TokenGalaxy-BSFUK4qR.js} +1 -1
  37. package/dashboard/dist/assets/TrendMonitor-qheD8KM4.js +19 -0
  38. package/dashboard/dist/assets/WidgetsPage-DBtJhIOw.js +1 -0
  39. package/dashboard/dist/assets/WrappedPage-Hd6sFn9s.js +1 -0
  40. package/dashboard/dist/assets/__vite-browser-external-BEMfOISl.css +1 -0
  41. package/dashboard/dist/assets/__vite-browser-external-Bu1cBb_7.js +1415 -0
  42. package/dashboard/dist/assets/{agent-logos-DlTPMVzM.js → agent-logos-Ccg1ofEC.js} +1 -1
  43. package/dashboard/dist/assets/{arrow-up-right-CPpFgxPI.js → arrow-up-right-RXrNNsG2.js} +1 -1
  44. package/dashboard/dist/assets/{check-BJqIqX_n.js → check-d-Au6Kzo.js} +1 -1
  45. package/dashboard/dist/assets/{copy-CJju6E4t.js → copy-a3tsjL_w.js} +1 -1
  46. package/dashboard/dist/assets/{download-Bd_X_ESz.js → download-DJcWUZJv.js} +1 -1
  47. package/dashboard/dist/assets/{flame-D0gF6_lO.js → flame-H8J4aVoK.js} +1 -1
  48. package/dashboard/dist/assets/{format-tokens-Bb2duR4k.js → format-tokens-BE149EAL.js} +1 -1
  49. package/dashboard/dist/assets/geist-mono-cyrillic-400-normal-C51Di1Mf.woff2 +0 -0
  50. package/dashboard/dist/assets/geist-mono-cyrillic-400-normal-CPJFfJgk.woff +0 -0
  51. package/dashboard/dist/assets/geist-mono-cyrillic-500-normal-D2cXvDHF.woff2 +0 -0
  52. package/dashboard/dist/assets/geist-mono-cyrillic-500-normal-DfuvdVgn.woff +0 -0
  53. package/dashboard/dist/assets/geist-mono-cyrillic-700-normal-BfmS5dzu.woff +0 -0
  54. package/dashboard/dist/assets/geist-mono-cyrillic-700-normal-DIjif5V2.woff2 +0 -0
  55. package/dashboard/dist/assets/geist-mono-cyrillic-900-normal-CTHwoWcu.woff2 +0 -0
  56. package/dashboard/dist/assets/geist-mono-cyrillic-900-normal-ChG74sxb.woff +0 -0
  57. package/dashboard/dist/assets/geist-mono-latin-400-normal-B2yvC1Cq.woff +0 -0
  58. package/dashboard/dist/assets/geist-mono-latin-400-normal-DTRLJnHl.woff2 +0 -0
  59. package/dashboard/dist/assets/geist-mono-latin-500-normal-D-GG86Jb.woff +0 -0
  60. package/dashboard/dist/assets/geist-mono-latin-500-normal-YINYabwD.woff2 +0 -0
  61. package/dashboard/dist/assets/geist-mono-latin-700-normal-BRX2CzoE.woff +0 -0
  62. package/dashboard/dist/assets/geist-mono-latin-700-normal-DDxuFlf6.woff2 +0 -0
  63. package/dashboard/dist/assets/geist-mono-latin-900-normal-BYFUisfb.woff +0 -0
  64. package/dashboard/dist/assets/geist-mono-latin-900-normal-COCSjcgJ.woff2 +0 -0
  65. package/dashboard/dist/assets/geist-mono-latin-ext-400-normal-CfzLURNc.woff +0 -0
  66. package/dashboard/dist/assets/geist-mono-latin-ext-400-normal-DI-rJ0UV.woff2 +0 -0
  67. package/dashboard/dist/assets/geist-mono-latin-ext-500-normal-Buglb9-a.woff2 +0 -0
  68. package/dashboard/dist/assets/geist-mono-latin-ext-500-normal-CrWEgvU_.woff +0 -0
  69. package/dashboard/dist/assets/geist-mono-latin-ext-700-normal-6Jom6Uax.woff +0 -0
  70. package/dashboard/dist/assets/geist-mono-latin-ext-700-normal-Dk9F-MRR.woff2 +0 -0
  71. package/dashboard/dist/assets/geist-mono-latin-ext-900-normal-B3bozMKY.woff2 +0 -0
  72. package/dashboard/dist/assets/geist-mono-latin-ext-900-normal-BtdMnRbI.woff +0 -0
  73. package/dashboard/dist/assets/geist-mono-symbols2-400-normal-DjbiTEEA.woff +0 -0
  74. package/dashboard/dist/assets/geist-mono-symbols2-500-normal-CmnCPGa0.woff +0 -0
  75. package/dashboard/dist/assets/geist-mono-symbols2-700-normal-u0VYbY0I.woff +0 -0
  76. package/dashboard/dist/assets/geist-mono-symbols2-900-normal-DhOOs6kU.woff +0 -0
  77. package/dashboard/dist/assets/geist-mono-vietnamese-400-normal-CZEPLOgu.woff +0 -0
  78. package/dashboard/dist/assets/geist-mono-vietnamese-500-normal-Dx9-epDo.woff +0 -0
  79. package/dashboard/dist/assets/geist-mono-vietnamese-700-normal-B0ZVBxuA.woff +0 -0
  80. package/dashboard/dist/assets/geist-mono-vietnamese-900-normal-CQ8VPR6n.woff +0 -0
  81. package/dashboard/dist/assets/{icons-CHX4hzd-.js → icons-ByTKmvAZ.js} +1 -1
  82. package/dashboard/dist/assets/{index-BvyZynlf.js → index-C3SM4kjn.js} +1 -1
  83. package/dashboard/dist/assets/{index-DuF533lT.js → index-CuUJdVq8.js} +1 -1
  84. package/dashboard/dist/assets/{index-BQenUM0D.js → index-CzxoHjXK.js} +1 -1
  85. package/dashboard/dist/assets/{info-DvFIO61W.js → info-C5mKonqx.js} +1 -1
  86. package/dashboard/dist/assets/{limits-providers-Dzhqid5x.js → limits-providers-BnqZGZmO.js} +1 -1
  87. package/dashboard/dist/assets/{link-2-WXEM8anD.js → link-2-C9q3EG5T.js} +1 -1
  88. package/dashboard/dist/assets/{loader-circle-CBitYCbd.js → loader-circle-BYnF5KTV.js} +1 -1
  89. package/dashboard/dist/assets/module-Bah3ijPg.js +2 -0
  90. package/dashboard/dist/assets/provider-display-D8ezW-m0.js +42 -0
  91. package/dashboard/dist/assets/{react-qsffbXoL.js → react-CuWBndC4.js} +1 -1
  92. package/dashboard/dist/assets/skills-api-BjmbJP9m.js +1 -0
  93. package/dashboard/dist/assets/{terminal-BFA955Sz.js → terminal-KTipHIur.js} +1 -1
  94. package/dashboard/dist/assets/{trash-2-BoxFSMOq.js → trash-2-DUi5VGSM.js} +1 -1
  95. package/dashboard/dist/assets/{use-community-stats-D_aufn0k.js → use-community-stats-DsSa_KFH.js} +1 -1
  96. package/dashboard/dist/assets/{use-limits-display-prefs-DWg_VJVc.js → use-limits-display-prefs-B-gM5IIA.js} +1 -1
  97. package/dashboard/dist/assets/{use-native-settings-RHW0eAGh.js → use-native-settings-B-GPgMwO.js} +1 -1
  98. package/dashboard/dist/assets/{use-ordered-list-cn5T3Bi0.js → use-ordered-list-CjWnQEBX.js} +1 -1
  99. package/dashboard/dist/assets/use-reduced-motion-Cln2x_5T.js +1 -0
  100. package/dashboard/dist/assets/{use-session-efficiency-pref-DRobup6T.js → use-session-efficiency-pref-B5e2s3cv.js} +1 -1
  101. package/dashboard/dist/assets/{use-transform-BlvN9UW0.js → use-transform-TQ15GATd.js} +1 -1
  102. package/dashboard/dist/assets/{use-usage-limits-Cp5aKXRQ.js → use-usage-limits-BqDW_9wW.js} +1 -1
  103. package/dashboard/dist/assets/{useCurrency-CRDGDglc.js → useCurrency-D1kHNp-X.js} +1 -1
  104. package/dashboard/dist/assets/{useScrollLock-D0qxSW2G.js → useScrollLock-DKMVyi6-.js} +1 -1
  105. package/dashboard/dist/assets/{useTokenFormat-R9Gepc9g.js → useTokenFormat-CbJjag6e.js} +1 -1
  106. package/dashboard/dist/assets/{zap-xt3KIPjK.js → zap-wfYE6Dsm.js} +1 -1
  107. package/dashboard/dist/index.html +30 -13
  108. package/dashboard/dist/ip-check.html +202 -0
  109. package/dashboard/dist/leaderboard.html +167 -0
  110. package/dashboard/dist/share.html +2 -2
  111. package/dashboard/dist/sitemap.xml +6 -6
  112. package/package.json +3 -2
  113. package/src/commands/init.js +1 -0
  114. package/src/commands/sync.js +4 -1
  115. package/src/lib/local-api.js +3 -1
  116. package/src/lib/pricing/curated-overrides.json +3 -0
  117. package/src/lib/pricing/matcher.js +27 -0
  118. package/src/lib/pricing/seed-snapshot.json +1 -1
  119. package/src/lib/rollout.js +197 -2
  120. package/src/lib/sqlite-reader.js +2 -0
  121. package/dashboard/dist/assets/DashboardPage-XeXAYgKI.js +0 -1
  122. package/dashboard/dist/assets/DevicePage-DojgM7c5.js +0 -1
  123. package/dashboard/dist/assets/DialogDescription-xAzuNBeK.js +0 -1
  124. package/dashboard/dist/assets/HeaderGithubStar-kIZC8t7g.js +0 -1
  125. package/dashboard/dist/assets/LeaderboardPage-BxqtZ5XC.js +0 -2
  126. package/dashboard/dist/assets/TrendMonitor-93OdRFml.js +0 -19
  127. package/dashboard/dist/assets/WidgetsPage-CoHxwJKq.js +0 -1
  128. package/dashboard/dist/assets/WrappedPage-BEtvNwJo.js +0 -1
  129. package/dashboard/dist/assets/__vite-browser-external-Bvb__wvZ.js +0 -1351
  130. package/dashboard/dist/assets/__vite-browser-external-ByIYTB6l.css +0 -1
  131. package/dashboard/dist/assets/geist-mono-cyrillic-400-normal-CeA7eGSt.woff +0 -0
  132. package/dashboard/dist/assets/geist-mono-cyrillic-400-normal-DoshcOXv.woff2 +0 -0
  133. package/dashboard/dist/assets/geist-mono-cyrillic-500-normal-BgLpzsdg.woff +0 -0
  134. package/dashboard/dist/assets/geist-mono-cyrillic-500-normal-BkE2O7RC.woff2 +0 -0
  135. package/dashboard/dist/assets/geist-mono-cyrillic-700-normal-4t7P5rT3.woff2 +0 -0
  136. package/dashboard/dist/assets/geist-mono-cyrillic-700-normal-DpJKySxv.woff +0 -0
  137. package/dashboard/dist/assets/geist-mono-cyrillic-900-normal-CVPizhN4.woff2 +0 -0
  138. package/dashboard/dist/assets/geist-mono-cyrillic-900-normal-DDpyx8f0.woff +0 -0
  139. package/dashboard/dist/assets/geist-mono-latin-400-normal-BXAprPdR.woff +0 -0
  140. package/dashboard/dist/assets/geist-mono-latin-400-normal-DKaoCDn5.woff2 +0 -0
  141. package/dashboard/dist/assets/geist-mono-latin-500-normal-C3sF8Y1B.woff2 +0 -0
  142. package/dashboard/dist/assets/geist-mono-latin-500-normal-YfPbDI_o.woff +0 -0
  143. package/dashboard/dist/assets/geist-mono-latin-700-normal-CzSaXH83.woff +0 -0
  144. package/dashboard/dist/assets/geist-mono-latin-700-normal-DMoeyBRY.woff2 +0 -0
  145. package/dashboard/dist/assets/geist-mono-latin-900-normal-DAGlevET.woff +0 -0
  146. package/dashboard/dist/assets/geist-mono-latin-900-normal-DVg4HgZN.woff2 +0 -0
  147. package/dashboard/dist/assets/geist-mono-latin-ext-400-normal-C1xxG8eb.woff2 +0 -0
  148. package/dashboard/dist/assets/geist-mono-latin-ext-400-normal-a1APXIwD.woff +0 -0
  149. package/dashboard/dist/assets/geist-mono-latin-ext-500-normal-CDyCFkgU.woff2 +0 -0
  150. package/dashboard/dist/assets/geist-mono-latin-ext-500-normal-CzSM7th5.woff +0 -0
  151. package/dashboard/dist/assets/geist-mono-latin-ext-700-normal-BG1muzu_.woff2 +0 -0
  152. package/dashboard/dist/assets/geist-mono-latin-ext-700-normal-BmQm3zK6.woff +0 -0
  153. package/dashboard/dist/assets/geist-mono-latin-ext-900-normal-DvYIGD1f.woff2 +0 -0
  154. package/dashboard/dist/assets/geist-mono-latin-ext-900-normal-LB8u5xx5.woff +0 -0
  155. package/dashboard/dist/assets/geist-mono-symbols2-400-normal-B5fXMCGq.woff +0 -0
  156. package/dashboard/dist/assets/geist-mono-symbols2-500-normal-BYvOiszX.woff +0 -0
  157. package/dashboard/dist/assets/geist-mono-symbols2-700-normal-nLp0AmIG.woff +0 -0
  158. package/dashboard/dist/assets/geist-mono-symbols2-900-normal-DPuoOkkO.woff +0 -0
  159. package/dashboard/dist/assets/geist-mono-vietnamese-400-normal-CyOwoevh.woff +0 -0
  160. package/dashboard/dist/assets/geist-mono-vietnamese-500-normal-Do_laDd2.woff +0 -0
  161. package/dashboard/dist/assets/geist-mono-vietnamese-700-normal-DKtT8o3X.woff +0 -0
  162. package/dashboard/dist/assets/geist-mono-vietnamese-900-normal-BAZIExb_.woff +0 -0
  163. package/dashboard/dist/assets/module-kH5GsDis.js +0 -2
  164. package/dashboard/dist/assets/provider-display-Ck8wx5F_.js +0 -42
  165. package/dashboard/dist/assets/skills-api-BGjRnLBu.js +0 -1
  166. package/dashboard/dist/assets/use-reduced-motion-Cp5udRu_.js +0 -1
@@ -0,0 +1,202 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Claude IP Check — Exit IP Reputation, Geo &amp; Risk Score</title>
7
+ <meta name="description" content="Free Claude IP check: see the exit IP used to reach Claude Code plus reputation, geo and cleanliness/risk (纯净度/风险) signals that can trigger sign-in blocks or rate limits." />
8
+ <meta property="og:site_name" content="Token Tracker" />
9
+ <meta property="og:title" content="Claude IP Check — Exit IP Reputation, Geo &amp; Risk Score" />
10
+ <meta property="og:description" content="Free Claude IP check: see the exit IP used to reach Claude Code plus reputation, geo and cleanliness/risk (纯净度/风险) signals that can trigger sign-in blocks or rate limits." />
11
+ <meta property="og:image" content="https://www.tokentracker.cc/dashboard-dark.png" />
12
+ <meta property="og:type" content="website" />
13
+ <meta property="og:url" content="https://www.tokentracker.cc/ip-check" />
14
+ <meta name="twitter:card" content="summary_large_image" />
15
+ <meta name="twitter:title" content="Claude IP Check — Exit IP Reputation, Geo &amp; Risk Score" />
16
+ <meta name="twitter:description" content="Free Claude IP check: see the exit IP used to reach Claude Code plus reputation, geo and cleanliness/risk (纯净度/风险) signals that can trigger sign-in blocks or rate limits." />
17
+ <meta name="twitter:image" content="https://www.tokentracker.cc/dashboard-dark.png" />
18
+ <link rel="canonical" href="https://www.tokentracker.cc/ip-check" />
19
+ <link rel="icon" href="/icon.svg" type="image/svg+xml" />
20
+ <link rel="icon" href="/favicon.ico" sizes="any" />
21
+ <link rel="icon" href="/favicon-32.png" sizes="32x32" type="image/png" />
22
+ <link rel="icon" href="/favicon-16.png" sizes="16x16" type="image/png" />
23
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
24
+ <meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
25
+ <meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" />
26
+ <script>
27
+ // ES2022 built-in polyfills for WebKit < 15.4 (macOS 12.0 Monterey ships Safari 15.0).
28
+ // Base UI uses Object.hasOwn and TrendMonitor uses Array.prototype.at — both land in
29
+ // Safari 15.4; esbuild down-levels syntax but never polyfills built-ins, so without this
30
+ // the dashboard crashes with "Object.hasOwn is not a function". Run before the bundle.
31
+ (function () {
32
+ try {
33
+ if (typeof Object.hasOwn !== "function") {
34
+ Object.defineProperty(Object, "hasOwn", {
35
+ value: function (o, k) { return Object.prototype.hasOwnProperty.call(o, k); },
36
+ configurable: true, writable: true,
37
+ });
38
+ }
39
+ function at(n) {
40
+ n = Math.trunc(n) || 0;
41
+ if (n < 0) n += this.length;
42
+ return n < 0 || n >= this.length ? undefined : this[n];
43
+ }
44
+ if (typeof Array.prototype.at !== "function") {
45
+ Object.defineProperty(Array.prototype, "at", { value: at, configurable: true, writable: true });
46
+ }
47
+ if (typeof String.prototype.at !== "function") {
48
+ Object.defineProperty(String.prototype, "at", { value: at, configurable: true, writable: true });
49
+ }
50
+ } catch (e) {}
51
+ })();
52
+ document.documentElement.classList.add("js");
53
+ // TokenTrackerBar WKWebView: mark before first paint so inline CSS below can clear html/body (NSVisualEffectView shows through).
54
+ (function () {
55
+ try {
56
+ if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.nativeBridge) {
57
+ document.documentElement.classList.add("native-app");
58
+ }
59
+ } catch (e) {}
60
+ })();
61
+ // Sync theme before first paint to prevent dark→light flash (FOUC)
62
+ (function(){
63
+ var t;
64
+ try { t = localStorage.getItem("tokentracker-theme"); } catch(e) {}
65
+ var dark = t === "dark" || (t !== "light" && matchMedia("(prefers-color-scheme:dark)").matches);
66
+ if (dark) document.documentElement.classList.add("dark");
67
+ })();
68
+ </script>
69
+ <style>
70
+ /* Prevent dark flash: set background before CSS loads */
71
+ html { background: #fafafa; }
72
+ html.dark { background: #0a0a0a; }
73
+ /* Native app: must override the two lines above — otherwise WKWebView stays opaque over NSVisualEffectView */
74
+ html.native-app,
75
+ html.native-app.dark {
76
+ background: transparent !important;
77
+ }
78
+ html.native-app body {
79
+ background: transparent !important;
80
+ }
81
+
82
+ .js .aeo-seed-content {
83
+ display: none;
84
+ }
85
+
86
+ .aeo-seed-content {
87
+ margin: 0;
88
+ padding: 1.5rem;
89
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
90
+ line-height: 1.55;
91
+ }
92
+
93
+ .aeo-seed-content h1,
94
+ .aeo-seed-content h2,
95
+ .aeo-seed-content h3 {
96
+ margin: 0.75rem 0;
97
+ }
98
+ </style>
99
+ <script type="application/ld+json">
100
+ {
101
+ "@context": "https://schema.org",
102
+ "@graph": [
103
+ {
104
+ "@type": "Organization",
105
+ "@id": "https://www.tokentracker.cc/#organization",
106
+ "name": "Token Tracker",
107
+ "url": "https://www.tokentracker.cc/"
108
+ },
109
+ {
110
+ "@type": "WebPage",
111
+ "@id": "https://www.tokentracker.cc/ip-check#webpage",
112
+ "url": "https://www.tokentracker.cc/ip-check",
113
+ "name": "Claude IP Check — Exit IP Reputation, Geo & Risk Score",
114
+ "isPartOf": {
115
+ "@id": "https://www.tokentracker.cc/#website"
116
+ },
117
+ "description": "Check the exit IP used to reach Claude Code, with reputation, geolocation and cleanliness/risk (纯净度/风险) signals."
118
+ },
119
+ {
120
+ "@type": "BreadcrumbList",
121
+ "itemListElement": [
122
+ {
123
+ "@type": "ListItem",
124
+ "position": 1,
125
+ "name": "Home",
126
+ "item": "https://www.tokentracker.cc/"
127
+ },
128
+ {
129
+ "@type": "ListItem",
130
+ "position": 2,
131
+ "name": "Claude IP Check",
132
+ "item": "https://www.tokentracker.cc/ip-check"
133
+ }
134
+ ]
135
+ },
136
+ {
137
+ "@type": "FAQPage",
138
+ "mainEntity": [
139
+ {
140
+ "@type": "Question",
141
+ "name": "What is a Claude IP check?",
142
+ "acceptedAnswer": {
143
+ "@type": "Answer",
144
+ "text": "A Claude IP check shows the public exit IP that your network uses to reach Claude Code and Claude.ai, along with its reputation, geolocation and cleanliness/risk score, so you can tell whether the IP is likely to trigger sign-in blocks, verification, or rate limits."
145
+ }
146
+ },
147
+ {
148
+ "@type": "Question",
149
+ "name": "Why does my Claude exit IP reputation matter?",
150
+ "acceptedAnswer": {
151
+ "@type": "Answer",
152
+ "text": "Anthropic and its anti-abuse providers score the reputation of the exit IP. Shared, datacenter, VPN, or previously abused IPs (low 纯净度 / high 风险) are more likely to face extra verification, throttling, or blocked logins, even on a paid plan."
153
+ }
154
+ },
155
+ {
156
+ "@type": "Question",
157
+ "name": "How do I check the exit IP used for Claude Code?",
158
+ "acceptedAnswer": {
159
+ "@type": "Answer",
160
+ "text": "Open the Token Tracker IP check page. It detects your current public exit IP and shows its geolocation, network type, and reputation/risk signals so you can decide whether to switch networks before using Claude Code."
161
+ }
162
+ }
163
+ ]
164
+ }
165
+ ]
166
+ }
167
+ </script>
168
+ <script type="module" crossorigin src="/assets/__vite-browser-external-Bu1cBb_7.js"></script>
169
+ <link rel="stylesheet" crossorigin href="/assets/__vite-browser-external-BEMfOISl.css">
170
+ </head>
171
+ <body>
172
+ <main class="aeo-seed-content" aria-label="Claude IP Check AI-readable summary">
173
+ <h1>Claude IP Check: exit IP reputation, geolocation and cleanliness/risk score</h1>
174
+ <p>
175
+ This free Claude IP check detects the public exit IP your network uses to reach Claude Code and
176
+ Claude.ai, then reports its reputation, geolocation, network type, and a cleanliness/risk score.
177
+ A low-reputation, datacenter, VPN, or previously abused exit IP is more likely to trigger extra
178
+ sign-in verification, rate limiting, or blocked logins — even on a paid Claude plan.
179
+ </p>
180
+ <h2>Claude IP 纯净度与风险检测</h2>
181
+ <p>
182
+ 本页用于检测你访问 Claude Code / Claude.ai 时使用的出口 IP:展示该 IP 的归属地、网络类型、
183
+ 信誉度与"纯净度 / 风险"评分。共享 IP、机房 IP、VPN 或历史被滥用的 IP 通常纯净度低、风险高,
184
+ 更容易触发 Claude 的登录验证、限速甚至封禁。检测后可据此决定是否更换网络再使用 Claude Code。
185
+ </p>
186
+ <h2>What this Claude IP check reports</h2>
187
+ <ul>
188
+ <li>Your current public exit IP address (the IP Anthropic actually sees).</li>
189
+ <li>Geolocation and network type (residential, datacenter, mobile, VPN/proxy).</li>
190
+ <li>IP reputation and a cleanliness/risk score (纯净度 / 风险).</li>
191
+ <li>Whether the IP is likely to trigger Claude sign-in verification or rate limits.</li>
192
+ </ul>
193
+ <h2>Part of Token Tracker</h2>
194
+ <p>
195
+ Token Tracker is a free, open-source, local-first dashboard that monitors AI token usage and cost
196
+ across 27 AI coding tools including Claude Code. Install with <code>npx tokentracker-cli</code>.
197
+ </p>
198
+ </main>
199
+
200
+ <div id="root"></div>
201
+ </body>
202
+ </html>
@@ -0,0 +1,167 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AI Coding Token Usage Leaderboard — Claude, Codex, Cursor</title>
7
+ <meta name="description" content="Public Token Tracker leaderboard ranking AI coding token usage across Claude Code, Codex, Cursor, Gemini and 27 tools. Opt-in, privacy-first — token counts only, never prompts." />
8
+ <meta property="og:site_name" content="Token Tracker" />
9
+ <meta property="og:title" content="AI Coding Token Usage Leaderboard — Claude, Codex, Cursor" />
10
+ <meta property="og:description" content="Public Token Tracker leaderboard ranking AI coding token usage across Claude Code, Codex, Cursor, Gemini and 27 tools. Opt-in, privacy-first — token counts only, never prompts." />
11
+ <meta property="og:image" content="https://www.tokentracker.cc/dashboard-dark.png" />
12
+ <meta property="og:type" content="website" />
13
+ <meta property="og:url" content="https://www.tokentracker.cc/leaderboard" />
14
+ <meta name="twitter:card" content="summary_large_image" />
15
+ <meta name="twitter:title" content="AI Coding Token Usage Leaderboard — Claude, Codex, Cursor" />
16
+ <meta name="twitter:description" content="Public Token Tracker leaderboard ranking AI coding token usage across Claude Code, Codex, Cursor, Gemini and 27 tools. Opt-in, privacy-first — token counts only, never prompts." />
17
+ <meta name="twitter:image" content="https://www.tokentracker.cc/dashboard-dark.png" />
18
+ <link rel="canonical" href="https://www.tokentracker.cc/leaderboard" />
19
+ <link rel="icon" href="/icon.svg" type="image/svg+xml" />
20
+ <link rel="icon" href="/favicon.ico" sizes="any" />
21
+ <link rel="icon" href="/favicon-32.png" sizes="32x32" type="image/png" />
22
+ <link rel="icon" href="/favicon-16.png" sizes="16x16" type="image/png" />
23
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
24
+ <meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
25
+ <meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" />
26
+ <script>
27
+ // ES2022 built-in polyfills for WebKit < 15.4 (macOS 12.0 Monterey ships Safari 15.0).
28
+ // Base UI uses Object.hasOwn and TrendMonitor uses Array.prototype.at — both land in
29
+ // Safari 15.4; esbuild down-levels syntax but never polyfills built-ins, so without this
30
+ // the dashboard crashes with "Object.hasOwn is not a function". Run before the bundle.
31
+ (function () {
32
+ try {
33
+ if (typeof Object.hasOwn !== "function") {
34
+ Object.defineProperty(Object, "hasOwn", {
35
+ value: function (o, k) { return Object.prototype.hasOwnProperty.call(o, k); },
36
+ configurable: true, writable: true,
37
+ });
38
+ }
39
+ function at(n) {
40
+ n = Math.trunc(n) || 0;
41
+ if (n < 0) n += this.length;
42
+ return n < 0 || n >= this.length ? undefined : this[n];
43
+ }
44
+ if (typeof Array.prototype.at !== "function") {
45
+ Object.defineProperty(Array.prototype, "at", { value: at, configurable: true, writable: true });
46
+ }
47
+ if (typeof String.prototype.at !== "function") {
48
+ Object.defineProperty(String.prototype, "at", { value: at, configurable: true, writable: true });
49
+ }
50
+ } catch (e) {}
51
+ })();
52
+ document.documentElement.classList.add("js");
53
+ // TokenTrackerBar WKWebView: mark before first paint so inline CSS below can clear html/body (NSVisualEffectView shows through).
54
+ (function () {
55
+ try {
56
+ if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.nativeBridge) {
57
+ document.documentElement.classList.add("native-app");
58
+ }
59
+ } catch (e) {}
60
+ })();
61
+ // Sync theme before first paint to prevent dark→light flash (FOUC)
62
+ (function(){
63
+ var t;
64
+ try { t = localStorage.getItem("tokentracker-theme"); } catch(e) {}
65
+ var dark = t === "dark" || (t !== "light" && matchMedia("(prefers-color-scheme:dark)").matches);
66
+ if (dark) document.documentElement.classList.add("dark");
67
+ })();
68
+ </script>
69
+ <style>
70
+ /* Prevent dark flash: set background before CSS loads */
71
+ html { background: #fafafa; }
72
+ html.dark { background: #0a0a0a; }
73
+ /* Native app: must override the two lines above — otherwise WKWebView stays opaque over NSVisualEffectView */
74
+ html.native-app,
75
+ html.native-app.dark {
76
+ background: transparent !important;
77
+ }
78
+ html.native-app body {
79
+ background: transparent !important;
80
+ }
81
+
82
+ .js .aeo-seed-content {
83
+ display: none;
84
+ }
85
+
86
+ .aeo-seed-content {
87
+ margin: 0;
88
+ padding: 1.5rem;
89
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
90
+ line-height: 1.55;
91
+ }
92
+
93
+ .aeo-seed-content h1,
94
+ .aeo-seed-content h2,
95
+ .aeo-seed-content h3 {
96
+ margin: 0.75rem 0;
97
+ }
98
+ </style>
99
+ <script type="application/ld+json">
100
+ {
101
+ "@context": "https://schema.org",
102
+ "@graph": [
103
+ {
104
+ "@type": "Organization",
105
+ "@id": "https://www.tokentracker.cc/#organization",
106
+ "name": "Token Tracker",
107
+ "url": "https://www.tokentracker.cc/"
108
+ },
109
+ {
110
+ "@type": "WebPage",
111
+ "@id": "https://www.tokentracker.cc/leaderboard#webpage",
112
+ "url": "https://www.tokentracker.cc/leaderboard",
113
+ "name": "AI Coding Token Usage Leaderboard",
114
+ "isPartOf": {
115
+ "@id": "https://www.tokentracker.cc/#website"
116
+ },
117
+ "description": "Public leaderboard ranking opt-in AI coding token usage across Claude Code, Codex, Cursor, Gemini and 27 tools."
118
+ },
119
+ {
120
+ "@type": "BreadcrumbList",
121
+ "itemListElement": [
122
+ {
123
+ "@type": "ListItem",
124
+ "position": 1,
125
+ "name": "Home",
126
+ "item": "https://www.tokentracker.cc/"
127
+ },
128
+ {
129
+ "@type": "ListItem",
130
+ "position": 2,
131
+ "name": "Leaderboard",
132
+ "item": "https://www.tokentracker.cc/leaderboard"
133
+ }
134
+ ]
135
+ }
136
+ ]
137
+ }
138
+ </script>
139
+ <script type="module" crossorigin src="/assets/__vite-browser-external-Bu1cBb_7.js"></script>
140
+ <link rel="stylesheet" crossorigin href="/assets/__vite-browser-external-BEMfOISl.css">
141
+ </head>
142
+ <body>
143
+ <main class="aeo-seed-content" aria-label="AI Coding Token Usage Leaderboard AI-readable summary">
144
+ <h1>AI coding token usage leaderboard</h1>
145
+ <p>
146
+ The Token Tracker leaderboard ranks opt-in AI coding token usage across Claude Code, OpenAI Codex,
147
+ Cursor, Gemini CLI and 27 supported tools. It is privacy-first: entries are opt-in and expose token
148
+ counts only — never prompts or conversation content. See how your AI coding token consumption
149
+ compares with other developers by model, tool, and time window.
150
+ </p>
151
+ <h2>How the leaderboard works</h2>
152
+ <ul>
153
+ <li>Opt-in only — you choose whether to appear, using a public display name.</li>
154
+ <li>Token counts only — never prompts, code, or conversation content.</li>
155
+ <li>Ranks usage across Claude Code, Codex, Cursor, Gemini and 27 AI coding tools.</li>
156
+ <li>Powered by optional Token Tracker cloud sync; local-first by default.</li>
157
+ </ul>
158
+ <h2>Part of Token Tracker</h2>
159
+ <p>
160
+ Token Tracker is a free, open-source, local-first dashboard that monitors AI token usage and cost
161
+ across 27 AI coding tools. Install with <code>npx tokentracker-cli</code>.
162
+ </p>
163
+ </main>
164
+
165
+ <div id="root"></div>
166
+ </body>
167
+ </html>
@@ -75,8 +75,8 @@
75
75
  "description": "Shareable Token Tracker dashboard snapshot."
76
76
  }
77
77
  </script>
78
- <script type="module" crossorigin src="/assets/__vite-browser-external-Bvb__wvZ.js"></script>
79
- <link rel="stylesheet" crossorigin href="/assets/__vite-browser-external-ByIYTB6l.css">
78
+ <script type="module" crossorigin src="/assets/__vite-browser-external-Bu1cBb_7.js"></script>
79
+ <link rel="stylesheet" crossorigin href="/assets/__vite-browser-external-BEMfOISl.css">
80
80
  </head>
81
81
  <body>
82
82
  <main class="aeo-seed-content" aria-label="Token Tracker share page summary">
@@ -2,25 +2,25 @@
2
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
3
  <url>
4
4
  <loc>https://www.tokentracker.cc/</loc>
5
- <lastmod>2026-05-07</lastmod>
5
+ <lastmod>2026-07-22</lastmod>
6
6
  <changefreq>weekly</changefreq>
7
7
  <priority>1.0</priority>
8
8
  </url>
9
9
  <url>
10
10
  <loc>https://www.tokentracker.cc/leaderboard</loc>
11
- <lastmod>2026-05-07</lastmod>
11
+ <lastmod>2026-07-22</lastmod>
12
12
  <changefreq>daily</changefreq>
13
13
  <priority>0.9</priority>
14
14
  </url>
15
15
  <url>
16
16
  <loc>https://www.tokentracker.cc/ip-check</loc>
17
- <lastmod>2026-05-07</lastmod>
18
- <changefreq>monthly</changefreq>
19
- <priority>0.5</priority>
17
+ <lastmod>2026-07-22</lastmod>
18
+ <changefreq>weekly</changefreq>
19
+ <priority>0.7</priority>
20
20
  </url>
21
21
  <url>
22
22
  <loc>https://www.tokentracker.cc/share</loc>
23
- <lastmod>2026-05-07</lastmod>
23
+ <lastmod>2026-07-22</lastmod>
24
24
  <changefreq>weekly</changefreq>
25
25
  <priority>0.4</priority>
26
26
  </url>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokentracker-cli",
3
- "version": "0.83.5",
3
+ "version": "0.83.7",
4
4
  "description": "Local-first AI coding token usage and cost tracker for 27 tools, with a dashboard, desktop pet, widgets, achievements, and native macOS/Windows apps.",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "access": "public"
22
22
  },
23
23
  "scripts": {
24
- "ci:local": "npm test && npm run validate:copy && npm run validate:ui-hardcode && npm run validate:guardrails && node --test test/architecture-guardrails.test.js && npm --prefix dashboard run build",
24
+ "ci:local": "npm test && npm run validate:copy && npm run validate:locale && npm run validate:ui-hardcode && npm run validate:guardrails && node --test test/architecture-guardrails.test.js && npm --prefix dashboard run build",
25
25
  "copy:pull": "node scripts/copy-sync.cjs pull",
26
26
  "copy:push": "node scripts/copy-sync.cjs push",
27
27
  "dashboard:build": "npm --prefix dashboard run build",
@@ -36,6 +36,7 @@
36
36
  "prepublishOnly": "node scripts/build-pricing-seed.cjs",
37
37
  "test": "node --test test/*.test.js",
38
38
  "validate:copy": "node scripts/validate-copy-registry.cjs",
39
+ "validate:locale": "node scripts/validate-locale-coverage.cjs",
39
40
  "validate:guardrails": "node scripts/validate-architecture-guardrails.cjs",
40
41
  "validate:retros": "node scripts/validate-retros.cjs",
41
42
  "validate:ui-hardcode": "node scripts/ops/validate-ui-hardcode.cjs",
@@ -1225,6 +1225,7 @@ function spawnDetached(argv) {
1225
1225
  try {
1226
1226
  const child = cp.spawn(argv[0], argv.slice(1), {
1227
1227
  detached: true,
1228
+ windowsHide: true,
1228
1229
  stdio: 'ignore',
1229
1230
  env: process.env
1230
1231
  });
@@ -436,7 +436,9 @@ async function cmdSync(argv, context = {}) {
436
436
  : null;
437
437
 
438
438
  const autoSourceScope = resolveAutoSourceScope(opts);
439
- const isBackgroundLightweightSync = opts.auto && opts.background && !opts.drain;
439
+ // --background controls local scan breadth; --drain only controls upload
440
+ // depth and lock priority. Plain `sync --drain` remains a full source scan.
441
+ const isBackgroundLightweightSync = opts.auto && opts.background;
440
442
  const isBackgroundAllLocalSync = isBackgroundLightweightSync && opts.allLocalSources;
441
443
  const isFullSourceScan = !autoSourceScope && !isBackgroundLightweightSync;
442
444
  const sourceAllowed = (...sources) => {
@@ -1496,6 +1498,7 @@ async function cmdSync(argv, context = {}) {
1496
1498
  subagentFiles: ompSubagentFiles,
1497
1499
  cursors,
1498
1500
  queuePath,
1501
+ projectQueuePath,
1499
1502
  env: process.env,
1500
1503
  onProgress: (p) => {
1501
1504
  if (!progress?.enabled) return;
@@ -1919,7 +1919,9 @@ function createLocalApiHandler({ queuePath }) {
1919
1919
  }
1920
1920
  const extraEnv = {};
1921
1921
  const drain = body.drain === true;
1922
- const auto = body.auto === true && !drain;
1922
+ // Native Sync Now combines an incremental background scan with a full
1923
+ // cloud drain. A plain {drain:true} request remains an exhaustive sync.
1924
+ const auto = body.auto === true;
1923
1925
  const background =
1924
1926
  auto && (body.background === true || body.lightweight === true);
1925
1927
  // The local server is the trust boundary for cloud-sync preferences.
@@ -8,6 +8,7 @@
8
8
  "claude-fable-5": { "input": 10, "output": 50, "cache_read": 1, "cache_write": 12.5, "note": "Fable 5 — Anthropic's top tier above Opus. Not yet in LiteLLM. $10/$50 per MTok; cache_read 0.1x, cache_write 1.25x. Remove once LiteLLM carries it." },
9
9
  "claude-opus-4-8": { "input": 5, "output": 25, "cache_read": 0.5, "cache_write": 6.25, "note": "Opus 4.8 not yet in LiteLLM. Pin to the standard Opus tier (same as 4.6/4.7); remove once LiteLLM carries it." },
10
10
  "claude-sonnet-5": { "input": 3, "output": 15, "cache_read": 0.3, "cache_write": 3.75, "note": "Sonnet 5. LiteLLM added this model on ~2026-06-30 with matching rates, but pin explicitly so pricing is correct immediately rather than depending on the 24h local pricing-cache refresh cycle." },
11
+ "claude-haiku-4-5": { "input": 1, "output": 5, "cache_read": 0.1, "cache_write": 1.25, "note": "Canonical undated alias emitted by Cursor. Pin to the same rates as claude-haiku-4-5-20251001 so local cost does not depend on which dated LiteLLM aliases are present in the current cache." },
11
12
  "gpt-5.6-sol": { "input": 5, "output": 30, "cache_read": 0.5, "cache_write": 6.25, "note": "GPT-5.6 family (public 2026-07-09). Flagship tier. Not yet in LiteLLM. developers.openai.com/api/docs/pricing: $5/$30 per MTok, cached input 0.1x, cache write 1.25x. Codex emits gpt-5.6-sol (+ reasoning-effort variants like gpt-5.6-solhigh, caught by fuzzy). Remove once LiteLLM carries it." },
12
13
  "gpt-5.6-terra": { "input": 2.5, "output": 15, "cache_read": 0.25, "cache_write": 3.125, "note": "GPT-5.6 balanced default tier. See gpt-5.6-sol." },
13
14
  "gpt-5.6-luna": { "input": 1, "output": 6, "cache_read": 0.1, "cache_write": 1.25, "note": "GPT-5.6 lightweight/cost-efficient tier. See gpt-5.6-sol." },
@@ -26,6 +27,8 @@
26
27
  "deepseek-v4-pro": { "input": 0.435,"output": 0.87, "cache_read": 0.003625, "cache_write": 0.435 },
27
28
  "deepseek-chat": { "input": 0.14, "output": 0.28, "cache_read": 0.0028, "cache_write": 0.14 },
28
29
  "grok-build": { "input": 1.25, "output": 2.50, "cache_read": 0.20, "note": "Grok Build TUI estimate. Local telemetry currently exposes totalTokens without a stable prompt/output/cache split, so TokenTracker estimates input/output split until Grok exposes per-call usage details." },
30
+ "cursor-grok-4.5": { "input": 2.00, "output": 6.00, "cache_read": 0.50, "cache_write": 0, "note": "Cursor Grok 4.5 base rate. Cursor Models & Pricing: $2/M input, $0.50/M cached input, $6/M output; no cache-write rate is published." },
31
+ "cursor-grok-4.5-fast": { "input": 4.00, "output": 18.00, "cache_read": 1.00, "cache_write": 0, "note": "Cursor Grok 4.5 Fast rate. Cursor publishes $4/M input and $18/M output; the Cursor usage breakdown reports $1/M cached input. Kept separate from the cheaper base SKU." },
29
32
  "grok-4-0709": { "input": 3.00, "output": 15.00, "cache_read": 0.75 },
30
33
  "grok-4": { "input": 3.00, "output": 15.00, "cache_read": 0.75 },
31
34
  "grok-4-latest": { "input": 3.00, "output": 15.00, "cache_read": 0.75 },
@@ -119,6 +119,31 @@ function normalizeClaudeModel(model) {
119
119
  return m;
120
120
  }
121
121
 
122
+ // Cursor decorates model ids with reasoning effort and sometimes places the
123
+ // Claude version before the tier. Normalize those lookup-only aliases while
124
+ // preserving Grok 4.5's distinct Fast SKU (its rate is not the base rate).
125
+ function normalizeCursorModel(model) {
126
+ if (!model || typeof model !== "string") return model;
127
+ let m = model
128
+ .trim()
129
+ .replace(/\([^)]*\)/g, " ")
130
+ .toLowerCase()
131
+ .replace(/[^a-z0-9.]+/g, "-")
132
+ .replace(/^-+|-+$/g, "")
133
+ .replace(/-{2,}/g, "-");
134
+ const parts = m.split("-");
135
+ const isFast = parts.includes("fast");
136
+
137
+ if (/^(?:cursor-)?grok-4[.-]5(?:-|$)/.test(m)) {
138
+ return isFast ? "cursor-grok-4.5-fast" : "cursor-grok-4.5";
139
+ }
140
+
141
+ const decorations = new Set(["thinking", "xhigh", "high", "medium", "low", "fast"]);
142
+ m = parts.filter((part) => !decorations.has(part)).join("-");
143
+ if (m.startsWith("claude-")) return normalizeClaudeModel(m);
144
+ return m;
145
+ }
146
+
122
147
  // WorkBuddy's auto-router records the model as the literal "auto" and never
123
148
  // exposes the underlying model it picked. That collides with Cursor's curated
124
149
  // alias ("auto" -> "composer-1"), which would misprice WorkBuddy usage as
@@ -141,6 +166,7 @@ function normalizeWorkbuddyModel(model) {
141
166
  const SOURCE_MODEL_NORMALIZERS = {
142
167
  antigravity: normalizeAntigravityModel,
143
168
  claude: normalizeClaudeModel,
169
+ cursor: normalizeCursorModel,
144
170
  "pi-anthropic": normalizeClaudeModel,
145
171
  zed: normalizeZedModel,
146
172
  workbuddy: normalizeWorkbuddyModel,
@@ -337,6 +363,7 @@ module.exports = {
337
363
  stripReasoningSuffix,
338
364
  normalizeAntigravityModel,
339
365
  normalizeClaudeModel,
366
+ normalizeCursorModel,
340
367
  normalizeZedModel,
341
368
  convertLitellmEntry,
342
369
  buildLitellmPerMillionMap,