tokentracker-cli 1.1.10 → 1.1.12

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 (121) hide show
  1. package/README.md +2 -1
  2. package/dashboard/dist/assets/{AchievementBadge-CH97d6cg.js → AchievementBadge-bxsSwozZ.js} +1 -1
  3. package/dashboard/dist/assets/{AchievementsPage-Dwvj09sF.js → AchievementsPage-CCGsTNky.js} +2 -2
  4. package/dashboard/dist/assets/{AchievementsSection-D6HHK1f-.js → AchievementsSection-a-ucN3O9.js} +1 -1
  5. package/dashboard/dist/assets/{BadgeDetailModal-Bpr6rY9l.js → BadgeDetailModal-CNCCgDRL.js} +1 -1
  6. package/dashboard/dist/assets/BotAnimated-DYrmIQt7.js +1 -0
  7. package/dashboard/dist/assets/{Card-38v0-L6e.js → Card-615UteEP.js} +1 -1
  8. package/dashboard/dist/assets/{CommandPalette-Bj0e0ye0.js → CommandPalette-BzmRKASJ.js} +1 -1
  9. package/dashboard/dist/assets/{CommunityStatsModal-IoQLJCe2.js → CommunityStatsModal-DdRpM1bD.js} +1 -1
  10. package/dashboard/dist/assets/{ConfirmModal-B7uK0Wjr.js → ConfirmModal-BQIPBiA5.js} +1 -1
  11. package/dashboard/dist/assets/Controls-Cup1Mj2U.js +1 -0
  12. package/dashboard/dist/assets/DashboardPage-DF1bFyHx.js +1 -0
  13. package/dashboard/dist/assets/{DevicePage-DE-NSyZg.js → DevicePage-CC31pv5N.js} +1 -1
  14. package/dashboard/dist/assets/{DialogClose-DB6ZRDR3.js → DialogClose-CaYoc9xQ.js} +1 -1
  15. package/dashboard/dist/assets/DialogDescription-DZLOEWil.js +1 -0
  16. package/dashboard/dist/assets/{DialogTitle-CgwmTJf3.js → DialogTitle-BViOiFtR.js} +1 -1
  17. package/dashboard/dist/assets/{FadeIn-CMjPtMSB.js → FadeIn-BQYqxLXW.js} +1 -1
  18. package/dashboard/dist/assets/{HeaderGithubStar-D5cSnbcg.js → HeaderGithubStar-CpGwcrZV.js} +1 -1
  19. package/dashboard/dist/assets/{HoverTooltip-CFV8yLxb.js → HoverTooltip--hTrUe1c.js} +1 -1
  20. package/dashboard/dist/assets/{IpCheckPage-Ctu-GWJQ.js → IpCheckPage-gPQntnIE.js} +1 -1
  21. package/dashboard/dist/assets/{LandingPage-PAIF034o.js → LandingPage-Cw72oDTD.js} +2 -2
  22. package/dashboard/dist/assets/{LeaderboardAvatar-D3CsY-nP.js → LeaderboardAvatar-CnqlbA5v.js} +1 -1
  23. package/dashboard/dist/assets/{LeaderboardPage-qE8DD-Ia.js → LeaderboardPage-CvdG-SGy.js} +2 -2
  24. package/dashboard/dist/assets/{LeaderboardProfileModal-BY3uaIdF.js → LeaderboardProfileModal-CqzEW_FY.js} +4 -4
  25. package/dashboard/dist/assets/{LeaderboardProfilePage-CwX77U5Z.js → LeaderboardProfilePage-DCjJ7yF3.js} +3 -3
  26. package/dashboard/dist/assets/{LimitsPage-BlJgvFay.js → LimitsPage-DMGI3mL9.js} +2 -2
  27. package/dashboard/dist/assets/{LocalOnlyNotice-CLFKSu0V.js → LocalOnlyNotice-CpGpv1oF.js} +1 -1
  28. package/dashboard/dist/assets/{LoginCard-Bdp2gihl.js → LoginCard-B5W06Jrz.js} +1 -1
  29. package/dashboard/dist/assets/{LoginModal-o_t6uvYP.js → LoginModal-B4Y8XRkn.js} +1 -1
  30. package/dashboard/dist/assets/{LoginPage-Cc3ZHUU8.js → LoginPage-BLN-PdCh.js} +1 -1
  31. package/dashboard/dist/assets/PetPage-BvY7fR8_.js +1 -0
  32. package/dashboard/dist/assets/{PopoverPopup-CGJBBnIf.js → PopoverPopup-C4_m01Pc.js} +1 -1
  33. package/dashboard/dist/assets/{ProviderIcon-1OG4Kbkl.js → ProviderIcon-LgUYzw52.js} +1 -1
  34. package/dashboard/dist/assets/{ResetPasswordPage-DbfS1gfH.js → ResetPasswordPage-Dgzafk9_.js} +1 -1
  35. package/dashboard/dist/assets/{SegmentedControl-DPKl-28R.js → SegmentedControl-CMWf089j.js} +1 -1
  36. package/dashboard/dist/assets/{Select-BTA6mSut.js → Select-BNFp1Pww.js} +1 -1
  37. package/dashboard/dist/assets/{SelectItemText-CX5Br8hd.js → SelectItemText-Jz-4OEyW.js} +1 -1
  38. package/dashboard/dist/assets/{ServiceStatusPage-CaTOLkT7.js → ServiceStatusPage-AEW89tSP.js} +1 -1
  39. package/dashboard/dist/assets/{SessionsPage-Ixp6Fseo.js → SessionsPage-DTW1sFcW.js} +2 -2
  40. package/dashboard/dist/assets/SettingsPage-2z_a9T_C.js +2 -0
  41. package/dashboard/dist/assets/{SkillsPage-BUUfMFpU.js → SkillsPage-BkPEwhXO.js} +1 -1
  42. package/dashboard/dist/assets/{TokenGalaxy-DnfKnQhr.js → TokenGalaxy-Cs5wfOxe.js} +1 -1
  43. package/dashboard/dist/assets/{ToolbarRootContext-D0wMtL6Z.js → ToolbarRootContext-B3pyxVI-.js} +1 -1
  44. package/dashboard/dist/assets/TrendMonitor-BmSRt3h3.js +19 -0
  45. package/dashboard/dist/assets/{WidgetsPage-Bfod5aSH.js → WidgetsPage-BN5ePVqf.js} +1 -1
  46. package/dashboard/dist/assets/{WrappedPage-fYftPA8s.js → WrappedPage-DZTG3lCh.js} +1 -1
  47. package/dashboard/dist/assets/__vite-browser-external-4IDwIR3i.js +45 -0
  48. package/dashboard/dist/assets/__vite-browser-external-CAQ_i-1v.css +1 -0
  49. package/dashboard/dist/assets/{agent-logos-C0O8Lnmv.js → agent-logos-DQmv0J3b.js} +1 -1
  50. package/dashboard/dist/assets/{arrow-up-right-Bs0RpChC.js → arrow-up-right-BbkRcWv3.js} +1 -1
  51. package/dashboard/dist/assets/{check-Dj5Wi1I7.js → check-Dz72GL-k.js} +1 -1
  52. package/dashboard/dist/assets/{composite-BeHO1nUS.js → composite-COAFYYB2.js} +1 -1
  53. package/dashboard/dist/assets/{copy-Dgp1NqhD.js → copy-wEl0WhF0.js} +1 -1
  54. package/dashboard/dist/assets/{download-D1JugY5p.js → download-W7dmHuLF.js} +1 -1
  55. package/dashboard/dist/assets/{external-link-ow0tAluE.js → external-link-B-pvBbFP.js} +1 -1
  56. package/dashboard/dist/assets/{flame-Obus_5g4.js → flame-y6R5Plz2.js} +1 -1
  57. package/dashboard/dist/assets/{format-tokens-yToZ6yvw.js → format-tokens-CkWutEDc.js} +1 -1
  58. package/dashboard/dist/assets/{icons-Da1IxY6v.js → icons-C_ECRc6a.js} +1 -1
  59. package/dashboard/dist/assets/{index-0hD-aFe2.js → index-B1Am3t0P.js} +1 -1
  60. package/dashboard/dist/assets/{index-BtmxTdj8.js → index-BzmW4EmI.js} +1 -1
  61. package/dashboard/dist/assets/{index-DduY8rpi.js → index-Dtl4UhBX.js} +1 -1
  62. package/dashboard/dist/assets/{info-CQjQ1whr.js → info-CCfzQ-S6.js} +1 -1
  63. package/dashboard/dist/assets/{link-2-BGYfWbPb.js → link-2-DvFi_t5y.js} +1 -1
  64. package/dashboard/dist/assets/{loader-circle-WArW9cmn.js → loader-circle-BglSN88W.js} +1 -1
  65. package/dashboard/dist/assets/{maximize-2-Bhde1l0n.js → maximize-2-B7Nzrb8n.js} +1 -1
  66. package/dashboard/dist/assets/{modifiers.esm-BRxUZvoy.js → modifiers.esm-CsJhvsvC.js} +1 -1
  67. package/dashboard/dist/assets/{monitor-smartphone-2ZT8ACJS.js → monitor-smartphone-DpicOpX8.js} +1 -1
  68. package/dashboard/dist/assets/{plus-C_cg6gJE.js → plus-C40ubjK3.js} +1 -1
  69. package/dashboard/dist/assets/{provider-display-CM8dzzcI.js → provider-display-E2soZfeg.js} +2 -2
  70. package/dashboard/dist/assets/{react-C3vDx5Sr.js → react-BseCgHfW.js} +1 -1
  71. package/dashboard/dist/assets/{search-Vd9we7KU.js → search-Bu5sWW2G.js} +1 -1
  72. package/dashboard/dist/assets/{skills-api-CHxubvN1.js → skills-api-BBF6YhPQ.js} +1 -1
  73. package/dashboard/dist/assets/skins-Mc0sI20C.js +1 -0
  74. package/dashboard/dist/assets/{sortable.esm-rLR8Wj9r.js → sortable.esm-CLXvOgJi.js} +1 -1
  75. package/dashboard/dist/assets/{store-rdi5mnme.js → store-DdObzMvx.js} +1 -1
  76. package/dashboard/dist/assets/{terminal-xEPZhi6v.js → terminal-CRqmFLSX.js} +1 -1
  77. package/dashboard/dist/assets/{trash-Cad8nQc4.js → trash-Dknznc_u.js} +1 -1
  78. package/dashboard/dist/assets/{use-community-stats-SMq01IVW.js → use-community-stats-ZvEm6sF4.js} +1 -1
  79. package/dashboard/dist/assets/{use-latest-request-guard-CSQ3Ypu3.js → use-latest-request-guard-QHLPnnSW.js} +1 -1
  80. package/dashboard/dist/assets/{use-limits-display-prefs-DaaT6TL9.js → use-limits-display-prefs-CRg1sYpO.js} +1 -1
  81. package/dashboard/dist/assets/{use-ordered-list-g58JllvT.js → use-ordered-list-NpIo40Y4.js} +1 -1
  82. package/dashboard/dist/assets/use-pet-settings-BUroRCzh.js +2 -0
  83. package/dashboard/dist/assets/use-reduced-motion-CDg8lAbR.js +1 -0
  84. package/dashboard/dist/assets/{use-session-efficiency-pref-DyATLZ-L.js → use-session-efficiency-pref-aQVRBt9R.js} +1 -1
  85. package/dashboard/dist/assets/{use-transform-XYEzPgA-.js → use-transform-BP8NiCzk.js} +1 -1
  86. package/dashboard/dist/assets/use-usage-limits-CvIocz6v.js +1 -0
  87. package/dashboard/dist/assets/{useCurrency-4xq0xUFx.js → useCurrency-CyksuFrj.js} +1 -1
  88. package/dashboard/dist/assets/useTokenFormat-CUwCluPw.js +1 -0
  89. package/dashboard/dist/assets/{zap-InLQedtD.js → zap-BcWplbpF.js} +1 -1
  90. package/dashboard/dist/index.html +2 -2
  91. package/dashboard/dist/ip-check.html +2 -2
  92. package/dashboard/dist/leaderboard.html +2 -2
  93. package/dashboard/dist/share.html +2 -2
  94. package/package.json +3 -2
  95. package/src/commands/init.js +1 -1
  96. package/src/commands/sync.js +71 -34
  97. package/src/lib/claude-categorizer.js +4 -7
  98. package/src/lib/claude-user-identity.js +56 -0
  99. package/src/lib/cloud-sync-prefs.js +14 -0
  100. package/src/lib/cursor-store.js +636 -57
  101. package/src/lib/grok-limits.js +17 -4
  102. package/src/lib/kimi-profile.js +61 -0
  103. package/src/lib/local-api.js +17 -11
  104. package/src/lib/multi-install-parser.js +3 -1
  105. package/src/lib/pricing/seed-snapshot.json +1 -1
  106. package/src/lib/rollout.js +91 -39
  107. package/src/lib/usage-limits.js +128 -79
  108. package/dashboard/dist/assets/BotAnimated-srF64s63.js +0 -1
  109. package/dashboard/dist/assets/ClawdAnimated-C9a1u9lq.js +0 -2
  110. package/dashboard/dist/assets/Controls-D5XuFAlI.js +0 -1
  111. package/dashboard/dist/assets/DashboardPage-Ddb8k4DR.js +0 -1
  112. package/dashboard/dist/assets/DialogDescription-CaRzgdvP.js +0 -1
  113. package/dashboard/dist/assets/PetPage-DFaWnKsI.js +0 -1
  114. package/dashboard/dist/assets/SettingsPage-BmeQse01.js +0 -2
  115. package/dashboard/dist/assets/TrendMonitor-D3WafvUS.js +0 -19
  116. package/dashboard/dist/assets/__vite-browser-external-B98Yok9C.js +0 -45
  117. package/dashboard/dist/assets/__vite-browser-external-Bg0J-a5P.css +0 -1
  118. package/dashboard/dist/assets/skins-C8EyB85e.js +0 -1
  119. package/dashboard/dist/assets/use-reduced-motion-Dgdv5SSP.js +0 -1
  120. package/dashboard/dist/assets/use-usage-limits-DL260plD.js +0 -1
  121. package/dashboard/dist/assets/useTokenFormat-B6fHArH6.js +0 -1
@@ -644,15 +644,28 @@ async function fetchGrokBilling(
644
644
  headers,
645
645
  deadlineMs,
646
646
  );
647
- if (creditsResult.ok) return creditsResult.body;
648
- creditsFailure = `HTTP ${creditsResult.status}`;
647
+ if (creditsResult.ok) {
648
+ // Keep the unified pool even when its fields are malformed. The caller
649
+ // must surface its parse error rather than substitute a legacy pool.
650
+ if (creditsResult.body?.config?.currentPeriod) return creditsResult.body;
651
+ try {
652
+ // Only a response without a unified period is eligible for shape
653
+ // fallback; a parseable legacy response can already be used as-is.
654
+ normalizeGrokBillingResponse(creditsResult.body);
655
+ return creditsResult.body;
656
+ } catch (error) {
657
+ creditsFailure = `unrecognized response (${error?.message || "invalid billing data"})`;
658
+ }
659
+ } else {
660
+ creditsFailure = `HTTP ${creditsResult.status}`;
661
+ }
649
662
  } catch (error) {
650
663
  if (error?.code === "GROK_AUTH_REQUIRED") throw error;
651
664
  if (error?.code === "GROK_BILLING_TIMEOUT") throw error;
652
665
  }
653
666
 
654
- // Non-auth HTTP, network, or response-decoding failure → try the legacy
655
- // shape once, while sharing the original request deadline.
667
+ // Non-auth HTTP, network, response-decoding, or shape failure → try the
668
+ // legacy shape once, while sharing the original request deadline.
656
669
  let legacyResult;
657
670
  try {
658
671
  legacyResult = await fetchGrokBillingAttempt(
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const os = require("node:os");
5
+ const path = require("node:path");
6
+ const { parse } = require("smol-toml");
7
+ const { expandHome } = require("./scan-roots");
8
+
9
+ const MAINLAND = { oauthHost: "https://auth.kimi.com", baseUrl: "https://api.kimi.com/coding/v1" };
10
+ const GLOBAL = { oauthHost: "https://auth.kimi.ai", baseUrl: "https://api.kimi.ai/coding/v1" };
11
+
12
+ function endpoint(value, fallback) {
13
+ return typeof value === "string" ? value.trim().replace(/\/+$/, "") : fallback;
14
+ }
15
+
16
+ // The two supported official endpoint pairs have stable upstream credential
17
+ // slots. The global suffix is SHA-256(JSON.stringify({ oauthHost, baseUrl }))
18
+ // truncated to 16 hex characters, matching managed-kimi-code.ts. Keeping the
19
+ // filenames constant also prevents remote configuration from shaping paths.
20
+ function credentialKey(oauthHost, baseUrl) {
21
+ return oauthHost === GLOBAL.oauthHost && baseUrl === GLOBAL.baseUrl
22
+ ? "kimi-code-env-0e4f99c69cc27850" : "kimi-code";
23
+ }
24
+
25
+ function resolveKimiProfile({ home, env = process.env } = {}) {
26
+ const base = home || os.homedir();
27
+ const explicit = expandHome(env?.KIMI_HOME, base);
28
+ const explicitCode = expandHome(env?.KIMI_CODE_HOME, base);
29
+ const codeHome = explicit || explicitCode || path.join(base, ".kimi-code");
30
+ const codeConfig = path.join(codeHome, "config.toml");
31
+ let provider = null;
32
+ let error = null;
33
+ if (fs.existsSync(codeConfig)) {
34
+ try {
35
+ provider = parse(fs.readFileSync(codeConfig, "utf8"))?.providers?.["managed:kimi-code"] || null;
36
+ } catch {
37
+ error = "Could not parse Kimi Code config.toml";
38
+ }
39
+ }
40
+ let hasCodeLogin = false;
41
+ try {
42
+ hasCodeLogin = Boolean(JSON.parse(fs.readFileSync(path.join(codeHome, "credentials", "kimi-code.json"), "utf8"))?.access_token);
43
+ } catch { /* No default-slot login. */ }
44
+ const hasEnvOverride = env?.KIMI_CODE_BASE_URL != null || env?.KIMI_CODE_OAUTH_HOST != null || env?.KIMI_OAUTH_HOST != null;
45
+ const kimiHome = explicit || explicitCode || provider || error || hasCodeLogin || hasEnvOverride
46
+ ? codeHome : path.join(base, ".kimi");
47
+ const oauthHost = endpoint(hasEnvOverride ? env?.KIMI_CODE_OAUTH_HOST ?? env?.KIMI_OAUTH_HOST : provider?.oauth?.oauth_host, MAINLAND.oauthHost);
48
+ const baseUrl = endpoint(env?.KIMI_CODE_BASE_URL ?? provider?.base_url, MAINLAND.baseUrl);
49
+ if (![MAINLAND, GLOBAL].some((region) => region.oauthHost === oauthHost && region.baseUrl === baseUrl)) {
50
+ error = "Unsupported Kimi quota endpoints; configure a matching official mainland or global profile";
51
+ }
52
+ if (provider?.oauth?.storage && provider.oauth.storage !== "file") {
53
+ error = "Kimi quota supports file credentials; the configured credential storage is unsupported";
54
+ }
55
+ // Derive the endpoint-scoped slot, just as upstream does when a stored key
56
+ // mismatches the endpoints. Never read an unrelated slot or legacy login.
57
+ const credsPath = path.join(kimiHome, "credentials", `${credentialKey(oauthHost, baseUrl)}.json`);
58
+ return { home: kimiHome, credsPath, oauthHost, baseUrl, error, configured: fs.existsSync(path.join(kimiHome, "config.toml")) };
59
+ }
60
+
61
+ module.exports = { resolveKimiProfile };
@@ -1357,23 +1357,25 @@ function createLocalApiHandler({ queuePath, serverVersion = null }) {
1357
1357
  // sync is on. Cloud sync is a dashboard (WebView) preference persisted in
1358
1358
  // localStorage; the dashboard mirrors it here via POST
1359
1359
  // /functions/tokentracker-cloud-sync-pref so the auth-unaware popover can key
1360
- // off the same flag. Defaults ON, exactly like the dashboard toggle — every
1361
- // consumer additionally requires a relayed refresh token, so the default only
1362
- // takes effect for signed-in users; an explicit {enabled:false} still wins.
1360
+ // off the same flag. Defaults OFF, exactly like the dashboard toggle;
1361
+ // existing saved choices are preserved.
1363
1362
  const cloudSyncPrefPath = path.join(trackerDataDir, "cloud-sync-pref.json");
1364
1363
  let cloudSyncPrefCache;
1365
1364
  let cloudSyncPrefGeneration = 0;
1366
1365
  function getCloudSyncPref() {
1367
1366
  if (cloudSyncPrefCache === undefined) {
1368
- try {
1369
- cloudSyncPrefCache = JSON.parse(fs.readFileSync(cloudSyncPrefPath, "utf8"))?.enabled !== false;
1370
- } catch {
1371
- cloudSyncPrefCache = true;
1372
- }
1367
+ cloudSyncPrefCache = require("./cloud-sync-prefs").readCloudSyncEnabled(trackerDataDir);
1373
1368
  }
1374
1369
  return cloudSyncPrefCache;
1375
1370
  }
1376
- function setCloudSyncPref(enabled) {
1371
+ function setCloudSyncPref(enabled, changedAtMs = Date.now()) {
1372
+ // Multiple dashboard windows can deliver mirrors out of order. Keep the
1373
+ // newest saved choice; old files without an ordering marker remain valid.
1374
+ try {
1375
+ const saved = JSON.parse(fs.readFileSync(cloudSyncPrefPath, "utf8"));
1376
+ if (Number(saved?.changedAtMs || 0) > changedAtMs ||
1377
+ (changedAtMs > 0 && saved?.changedAtMs === changedAtMs && saved?.enabled === false && enabled)) return;
1378
+ } catch { /* first choice or an unreadable preference */ }
1377
1379
  if (getCloudSyncPref() !== Boolean(enabled)) {
1378
1380
  cloudSyncPrefGeneration += 1;
1379
1381
  clearLocalSyncDeviceTokenCache();
@@ -1384,7 +1386,7 @@ function createLocalApiHandler({ queuePath, serverVersion = null }) {
1384
1386
  if (!fs.existsSync(trackerDataDir)) fs.mkdirSync(trackerDataDir, { recursive: true });
1385
1387
  fs.writeFileSync(
1386
1388
  cloudSyncPrefPath,
1387
- JSON.stringify({ enabled: cloudSyncPrefCache, updatedAt: new Date().toISOString() }),
1389
+ JSON.stringify({ enabled: cloudSyncPrefCache, changedAtMs, updatedAt: new Date().toISOString() }),
1388
1390
  { encoding: "utf8", mode: 0o600 },
1389
1391
  );
1390
1392
  } catch (e) {
@@ -2875,7 +2877,11 @@ function createLocalApiHandler({ queuePath, serverVersion = null }) {
2875
2877
  json(res, { ok: false, error: "enabled must be a boolean" }, 400);
2876
2878
  return true;
2877
2879
  }
2878
- setCloudSyncPref(body.enabled);
2880
+ if (body.changedAtMs != null && (!Number.isSafeInteger(body.changedAtMs) || body.changedAtMs < 0)) {
2881
+ json(res, { ok: false, error: "changedAtMs must be a nonnegative safe integer" }, 400);
2882
+ return true;
2883
+ }
2884
+ setCloudSyncPref(body.enabled, body.changedAtMs ?? Date.now());
2879
2885
  json(res, { ok: true, enabled: getCloudSyncPref() });
2880
2886
  return true;
2881
2887
  }
@@ -47,7 +47,9 @@ async function multiInstallParse({ paths, parserFn, providerName, cursors, getPa
47
47
  eventsAggregated += result.eventsAggregated || 0;
48
48
  bucketsQueued += result.bucketsQueued || 0;
49
49
  } catch (parseErr) {
50
- cursors[providerName] = ns;
50
+ if (parseErr?.code !== "TOKENTRACKER_CURSOR_STORE_RETRY") {
51
+ cursors[providerName] = ns;
52
+ }
51
53
  throw parseErr;
52
54
  }
53
55
  }