@ipv9/tokentracker-cli 0.39.33 → 0.39.35

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 (49) hide show
  1. package/README.md +48 -5
  2. package/dashboard/dist/assets/{ActivityHeatmap-B8dR4C_0.js → ActivityHeatmap-rUm9bSZ9.js} +1 -1
  3. package/dashboard/dist/assets/{Card-UnYzwQJR.js → Card-YWr91b5b.js} +1 -1
  4. package/dashboard/dist/assets/DashboardPage-DdJOVJuw.js +19 -0
  5. package/dashboard/dist/assets/{DevicePage-CZFnVVjk.js → DevicePage-CQMG1bh8.js} +1 -1
  6. package/dashboard/dist/assets/{DialogTitle-BZl-I43S.js → DialogTitle-BM0Hz4Pq.js} +1 -1
  7. package/dashboard/dist/assets/{FadeIn-0EQh6r0x.js → FadeIn-D8xysY3i.js} +1 -1
  8. package/dashboard/dist/assets/{InsforgeUserHeaderControls-BeA5yiNr.js → InsforgeUserHeaderControls-CsAafXyj.js} +1 -1
  9. package/dashboard/dist/assets/{IpCheckPage-BkjSnzmW.js → IpCheckPage-Bbg9erkT.js} +1 -1
  10. package/dashboard/dist/assets/{LandingPage-CCj37Lvh.js → LandingPage-BCMsWOwJ.js} +1 -1
  11. package/dashboard/dist/assets/{LeaderboardAvatar-B4viOzHY.js → LeaderboardAvatar-CkQa4EX2.js} +1 -1
  12. package/dashboard/dist/assets/{LeaderboardPage-CQV2N36e.js → LeaderboardPage-CyDX3tDL.js} +3 -3
  13. package/dashboard/dist/assets/{LeaderboardProfileModal-CNKo1dRR.js → LeaderboardProfileModal-CMctMA-p.js} +1 -1
  14. package/dashboard/dist/assets/{LeaderboardProfilePage-FvRutqM5.js → LeaderboardProfilePage-DTZ_6dBt.js} +1 -1
  15. package/dashboard/dist/assets/LimitsPage-V7939U8b.js +2 -0
  16. package/dashboard/dist/assets/{LocalOnlyNotice-BH_BM61g.js → LocalOnlyNotice-dODOM3SB.js} +1 -1
  17. package/dashboard/dist/assets/{LoginPage-BOs7Vxww.js → LoginPage-CE5GBEI2.js} +1 -1
  18. package/dashboard/dist/assets/{PopoverPopup-Dd2SS-kl.js → PopoverPopup-CRzMMFsC.js} +1 -1
  19. package/dashboard/dist/assets/{Select-DKPyTgtq.js → Select-m6edgfye.js} +1 -1
  20. package/dashboard/dist/assets/{SelectItemText-JqKVOv-o.js → SelectItemText-DIoTPvZM.js} +1 -1
  21. package/dashboard/dist/assets/{SettingsPage-CJfhq1dP.js → SettingsPage-DObaSleW.js} +1 -1
  22. package/dashboard/dist/assets/{SkillsPage-C6tkEm2L.js → SkillsPage-BSi26dZo.js} +1 -1
  23. package/dashboard/dist/assets/{WidgetsPage-CL32K7OS.js → WidgetsPage-CTl7OtvF.js} +1 -1
  24. package/dashboard/dist/assets/{WrappedPage-7AnZnCu_.js → WrappedPage-BXwhD9aq.js} +1 -1
  25. package/dashboard/dist/assets/{arrow-up-right-2_t43gcm.js → arrow-up-right-DxdoYoxg.js} +1 -1
  26. package/dashboard/dist/assets/{download-INj0jPNk.js → download-BZkwGDg8.js} +1 -1
  27. package/dashboard/dist/assets/{info-D7mMY73X.js → info-DRaQWOpM.js} +1 -1
  28. package/dashboard/dist/assets/{main-D2nNo9eK.js → main-CuaPRwHu.js} +5 -2
  29. package/dashboard/dist/assets/main-DAcSUW2t.css +1 -0
  30. package/dashboard/dist/assets/use-limits-display-prefs-5cj2WfP-.js +1 -0
  31. package/dashboard/dist/assets/{use-native-settings-Dacr_YkP.js → use-native-settings-BfydbPtC.js} +1 -1
  32. package/dashboard/dist/assets/{use-spring-CE3dBlxJ.js → use-spring-BxDSGjR_.js} +1 -1
  33. package/dashboard/dist/assets/{use-usage-limits-BOjNomCE.js → use-usage-limits-D_5PMCyF.js} +1 -1
  34. package/dashboard/dist/assets/{useCurrency-V1KRKBNl.js → useCurrency-DQhzQX2k.js} +1 -1
  35. package/dashboard/dist/assets/{useOpenInteractionType-DVyniqcO.js → useOpenInteractionType--grUNSll.js} +1 -1
  36. package/dashboard/dist/index.html +2 -2
  37. package/dashboard/dist/share.html +2 -2
  38. package/package.json +1 -1
  39. package/src/cli.js +3 -3
  40. package/src/commands/doctor.js +5 -0
  41. package/src/commands/serve.js +3 -1
  42. package/src/lib/browser-auth.js +40 -13
  43. package/src/lib/doctor.js +104 -1
  44. package/src/lib/pricing/seed-snapshot.json +1 -1
  45. package/src/lib/usage-limits.js +133 -1
  46. package/dashboard/dist/assets/DashboardPage-CB24v0ry.js +0 -19
  47. package/dashboard/dist/assets/LimitsPage-By5T54_9.js +0 -2
  48. package/dashboard/dist/assets/main-CGmdZkmj.css +0 -1
  49. package/dashboard/dist/assets/use-limits-display-prefs-CbW7JdJz.js +0 -1
@@ -494,6 +494,133 @@ async function fetchKimiLimits({ home, env, fetchImpl = fetch } = {}) {
494
494
  }
495
495
  }
496
496
 
497
+ function resolveZaiAuth({ env = process.env } = {}) {
498
+ const anthropicBaseUrl = typeof env?.ANTHROPIC_BASE_URL === "string" ? env.ANTHROPIC_BASE_URL.trim() : "";
499
+ const anthropicToken = typeof env?.ANTHROPIC_AUTH_TOKEN === "string" ? env.ANTHROPIC_AUTH_TOKEN.trim() : "";
500
+ if (anthropicBaseUrl && anthropicToken) {
501
+ try {
502
+ const host = new URL(anthropicBaseUrl).hostname.toLowerCase();
503
+ if (host === "api.z.ai" || host === "open.bigmodel.cn") {
504
+ return {
505
+ endpoint: `${new URL(anthropicBaseUrl).origin}/api/monitor/usage/quota/limit`,
506
+ authorization: anthropicToken,
507
+ };
508
+ }
509
+ } catch (_error) {}
510
+ }
511
+
512
+ const apiKey = [
513
+ env?.TOKENTRACKER_ZAI_API_KEY,
514
+ env?.ZAI_API_KEY,
515
+ env?.ZHIPU_API_KEY,
516
+ ].find((value) => typeof value === "string" && value.trim());
517
+ if (!apiKey) return null;
518
+ const trimmed = apiKey.trim();
519
+ return {
520
+ endpoint: "https://api.z.ai/api/monitor/usage/quota/limit",
521
+ authorization: /^Bearer\s+/i.test(trimmed) ? trimmed : `Bearer ${trimmed}`,
522
+ };
523
+ }
524
+
525
+ function zaiResetTime(value) {
526
+ if (value === null || value === undefined || value === "") return null;
527
+ const n = Number(value);
528
+ if (Number.isFinite(n) && n > 0) {
529
+ const ms = n > 10_000_000_000 ? n : n * 1000;
530
+ const date = new Date(ms);
531
+ return Number.isFinite(date.getTime()) ? date.toISOString() : null;
532
+ }
533
+ const ts = Date.parse(String(value));
534
+ return Number.isFinite(ts) ? new Date(ts).toISOString() : null;
535
+ }
536
+
537
+ function zaiWindowFromLimit(limit) {
538
+ if (!limit || typeof limit !== "object") return null;
539
+ let usedPercent = clampPercent(limit.percentage);
540
+ if (usedPercent === null) {
541
+ const current = Number(limit.currentValue ?? limit.usage);
542
+ const remaining = Number(limit.remaining);
543
+ if (Number.isFinite(current) && current >= 0 && Number.isFinite(remaining) && remaining >= 0) {
544
+ usedPercent = clampPercent((current / (current + remaining)) * 100);
545
+ }
546
+ }
547
+ return buildWindow({
548
+ usedPercent,
549
+ resetAt: zaiResetTime(limit.nextResetTime),
550
+ });
551
+ }
552
+
553
+ function normalizeZaiUsageResponse(body) {
554
+ const data = body?.data && typeof body.data === "object" ? body.data : {};
555
+ const limits = Array.isArray(data.limits) ? data.limits : [];
556
+ let fiveHour = null;
557
+ let weekly = null;
558
+ let monthly = null;
559
+
560
+ for (const limit of limits) {
561
+ const type = typeof limit?.type === "string" ? limit.type : "";
562
+ const unit = Number(limit?.unit);
563
+ const number = Number(limit?.number);
564
+ if (type === "TOKENS_LIMIT" && unit === 3 && number === 5 && !fiveHour) {
565
+ fiveHour = zaiWindowFromLimit(limit);
566
+ } else if (type === "TOKENS_LIMIT" && unit === 6 && !weekly) {
567
+ weekly = zaiWindowFromLimit(limit);
568
+ } else if (type === "TIME_LIMIT" && !monthly) {
569
+ monthly = zaiWindowFromLimit(limit);
570
+ }
571
+ }
572
+
573
+ return {
574
+ account_plan: typeof data.planName === "string"
575
+ ? data.planName
576
+ : typeof data.plan === "string"
577
+ ? data.plan
578
+ : typeof data.level === "string"
579
+ ? data.level
580
+ : data.level != null
581
+ ? String(data.level)
582
+ : null,
583
+ primary_window: fiveHour,
584
+ secondary_window: weekly,
585
+ tertiary_window: monthly,
586
+ };
587
+ }
588
+
589
+ async function fetchZaiLimits({ env = process.env, fetchImpl = fetch } = {}) {
590
+ const auth = resolveZaiAuth({ env });
591
+ if (!auth) return { configured: false };
592
+
593
+ try {
594
+ const res = await fetchImpl(auth.endpoint, {
595
+ method: "GET",
596
+ headers: {
597
+ Authorization: auth.authorization,
598
+ Accept: "application/json",
599
+ },
600
+ });
601
+ if (res.status === 401 || res.status === 403) {
602
+ throw new Error("Z.AI token rejected. Check ZAI_API_KEY or ZHIPU_API_KEY.");
603
+ }
604
+ if (!res.ok) {
605
+ throw new Error(`Z.AI API returned ${res.status}`);
606
+ }
607
+ const json = await res.json();
608
+ if (json?.success === false) {
609
+ throw new Error(json?.msg || "Z.AI API returned an unsuccessful response.");
610
+ }
611
+ return {
612
+ configured: true,
613
+ error: null,
614
+ ...normalizeZaiUsageResponse(json),
615
+ };
616
+ } catch (error) {
617
+ return {
618
+ configured: true,
619
+ error: error?.message || "Unknown error",
620
+ };
621
+ }
622
+ }
623
+
497
624
  function resolveGeminiHome({ home, env } = {}) {
498
625
  const explicit = typeof env?.GEMINI_HOME === "string" ? env.GEMINI_HOME.trim() : "";
499
626
  return explicit ? path.resolve(explicit) : path.join(home, ".gemini");
@@ -1698,7 +1825,7 @@ async function getUsageLimits({
1698
1825
  const codexPlanType = codexAuthRefreshed?.planType || null;
1699
1826
 
1700
1827
  const providerFetch = withFetchTimeout(fetchImpl, providerTimeoutMs);
1701
- const [claudeResult, codexResult, cursor, kimi, gemini, kiro, antigravity, copilot] = await Promise.all([
1828
+ const [claudeResult, codexResult, cursor, kimi, zai, gemini, kiro, antigravity, copilot] = await Promise.all([
1702
1829
  claudeToken
1703
1830
  ? withProviderTimeout(fetchClaudeUsageLimits(claudeToken, { fetchImpl: providerFetch, maxAttempts: 1 }), "Claude", providerTimeoutMs).then(
1704
1831
  (value) => ({ status: "fulfilled", value }),
@@ -1719,6 +1846,8 @@ async function getUsageLimits({
1719
1846
  .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
1720
1847
  withProviderTimeout(fetchKimiLimits({ home, env, fetchImpl: providerFetch }), "Kimi", providerTimeoutMs)
1721
1848
  .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
1849
+ withProviderTimeout(fetchZaiLimits({ env, fetchImpl: providerFetch }), "Z.AI", providerTimeoutMs)
1850
+ .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
1722
1851
  withProviderTimeout(fetchGeminiLimits({ home, env, fetchImpl: providerFetch, commandRunner }), "Gemini", providerTimeoutMs)
1723
1852
  .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
1724
1853
  Promise.resolve().then(() => fetchKiroLimits({ commandRunner, now })),
@@ -1772,6 +1901,7 @@ async function getUsageLimits({
1772
1901
  codex: withPlanLabel(codex, codex.plan_type, "Codex"),
1773
1902
  cursor: withPlanLabel(cursor, cursor.membership_type, "Cursor"),
1774
1903
  kimi: withPlanLabel(kimi, kimi.subscription_type || kimi.membership_level, "Kimi"),
1904
+ zai: withPlanLabel(zai, zai.account_plan, "Z.AI"),
1775
1905
  gemini: withPlanLabel(gemini, gemini.account_plan, "Gemini"),
1776
1906
  kiro: withPlanLabel(kiro, kiro.plan_name, "Kiro"),
1777
1907
  antigravity: withPlanLabel(antigravity, antigravity.account_plan, "Antigravity"),
@@ -1795,6 +1925,8 @@ module.exports = {
1795
1925
  normalizeCursorUsageSummary,
1796
1926
  normalizeGeminiQuotaResponse,
1797
1927
  normalizeKimiUsageResponse,
1928
+ normalizeZaiUsageResponse,
1929
+ fetchZaiLimits,
1798
1930
  parseKiroUsageOutput,
1799
1931
  normalizeAntigravityResponse,
1800
1932
  parseListeningPorts,