tokentracker-cli 0.87.5 → 0.87.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 (109) hide show
  1. package/LICENSE +1 -1
  2. package/README.de.md +32 -32
  3. package/README.ja.md +31 -31
  4. package/README.ko.md +31 -31
  5. package/README.md +34 -34
  6. package/README.zh-CN.md +31 -31
  7. package/dashboard/dist/assets/{AchievementBadge-_BbqyV4s.js → AchievementBadge-4SSFyzNE.js} +1 -1
  8. package/dashboard/dist/assets/{AchievementsPage-DlXdQMuk.js → AchievementsPage-4ASCXja2.js} +2 -2
  9. package/dashboard/dist/assets/{AchievementsSection-BAL23Qum.js → AchievementsSection-CyaMYMol.js} +1 -1
  10. package/dashboard/dist/assets/{BadgeDetailModal-D5VYBn1e.js → BadgeDetailModal-CUWTCEru.js} +1 -1
  11. package/dashboard/dist/assets/{Card-BCAAH2Tv.js → Card-C79yXijL.js} +1 -1
  12. package/dashboard/dist/assets/{ClawdAnimated-BaeJ4goq.js → ClawdAnimated-Cw6J-x_d.js} +1 -1
  13. package/dashboard/dist/assets/{CommandPalette-DaBo0N_t.js → CommandPalette-C1RQ58De.js} +1 -1
  14. package/dashboard/dist/assets/{CommunityStatsModal-DtnbqllK.js → CommunityStatsModal-CycaCGsd.js} +1 -1
  15. package/dashboard/dist/assets/{ConfirmModal-BdIbatZd.js → ConfirmModal-hPuA2aup.js} +1 -1
  16. package/dashboard/dist/assets/{Controls-CtlnwG2h.js → Controls-DjunxsRS.js} +1 -1
  17. package/dashboard/dist/assets/{DashboardPage-B7YSxJXW.js → DashboardPage-C5H5_EZN.js} +1 -1
  18. package/dashboard/dist/assets/{DevicePage-Y1QufKqx.js → DevicePage-a1TT-0Bd.js} +1 -1
  19. package/dashboard/dist/assets/{DialogClose-BA6Fr6X7.js → DialogClose-CCRfnIbO.js} +1 -1
  20. package/dashboard/dist/assets/DialogDescription-C99d5K4r.js +1 -0
  21. package/dashboard/dist/assets/{DialogTitle-CQlYwz-I.js → DialogTitle-2Qa5pApU.js} +1 -1
  22. package/dashboard/dist/assets/{FadeIn-C7oxsfI-.js → FadeIn-C3mpVy83.js} +1 -1
  23. package/dashboard/dist/assets/HeaderGithubStar-Dn_F7ByX.js +1 -0
  24. package/dashboard/dist/assets/{HoverTooltip-Tf9XsZ6G.js → HoverTooltip-DaywO0Zz.js} +1 -1
  25. package/dashboard/dist/assets/{IpCheckPage-DEK7d2P9.js → IpCheckPage-oqGfnWb7.js} +1 -1
  26. package/dashboard/dist/assets/{LandingPage-Cev8vQ3V.js → LandingPage-CX7dYsEX.js} +2 -2
  27. package/dashboard/dist/assets/{LeaderboardAvatar-BP8r8s_o.js → LeaderboardAvatar-Bl-OMQ2x.js} +1 -1
  28. package/dashboard/dist/assets/{LeaderboardPage-CFinKL9O.js → LeaderboardPage-yeWcgiVo.js} +2 -2
  29. package/dashboard/dist/assets/{LeaderboardProfileModal-DKSPH2_U.js → LeaderboardProfileModal-CDmZtQ_m.js} +4 -4
  30. package/dashboard/dist/assets/{LeaderboardProfilePage-DNSIoOdU.js → LeaderboardProfilePage-BqJYxoN1.js} +2 -2
  31. package/dashboard/dist/assets/LimitsPage-D8NFgXbZ.js +4 -0
  32. package/dashboard/dist/assets/LocalOnlyNotice-DjdhDEiq.js +1 -0
  33. package/dashboard/dist/assets/{LoginCard-Dq5-__UO.js → LoginCard-jQXAmSQb.js} +1 -1
  34. package/dashboard/dist/assets/{LoginModal-BWuDhVTL.js → LoginModal-q4G6EN7b.js} +1 -1
  35. package/dashboard/dist/assets/{LoginPage-Dwb39YqH.js → LoginPage-BklWSXzs.js} +1 -1
  36. package/dashboard/dist/assets/{PetPage-BcvAOVH2.js → PetPage-DyWuMUTA.js} +1 -1
  37. package/dashboard/dist/assets/{PopoverPopup-CnywL4jN.js → PopoverPopup-Dbxed_FL.js} +1 -1
  38. package/dashboard/dist/assets/{ProviderIcon-DAn58wfZ.js → ProviderIcon-ChYuSSfj.js} +1 -1
  39. package/dashboard/dist/assets/{ResetPasswordPage-B-iZ9m8Z.js → ResetPasswordPage-DJww1dxo.js} +1 -1
  40. package/dashboard/dist/assets/{SegmentedControl-DUlvUP02.js → SegmentedControl-Dr73_QVm.js} +1 -1
  41. package/dashboard/dist/assets/{Select-BbVO0yyC.js → Select-BMCy_8oY.js} +1 -1
  42. package/dashboard/dist/assets/{SelectItemText-BCo4iRHj.js → SelectItemText-BRU7mlBI.js} +1 -1
  43. package/dashboard/dist/assets/{ServiceStatusPage-Bf65rMHS.js → ServiceStatusPage-DDao-oTH.js} +1 -1
  44. package/dashboard/dist/assets/{SessionsPage-D2QWuLy9.js → SessionsPage-BjngkrsY.js} +1 -1
  45. package/dashboard/dist/assets/{SettingsPage-BtlZ7v0t.js → SettingsPage-Dsftjg5j.js} +1 -1
  46. package/dashboard/dist/assets/{SkillsPage-D7CXkuxF.js → SkillsPage-igML0DOZ.js} +1 -1
  47. package/dashboard/dist/assets/{TokenGalaxy-B1VqfzOB.js → TokenGalaxy-BBETSYe7.js} +1 -1
  48. package/dashboard/dist/assets/{ToolbarRootContext-DlRA_RFX.js → ToolbarRootContext-CzEAxfqj.js} +1 -1
  49. package/dashboard/dist/assets/{TrendMonitor-D945Vzv_.js → TrendMonitor-JV6lkw-s.js} +1 -1
  50. package/dashboard/dist/assets/{WidgetsPage-CZLhBVQL.js → WidgetsPage-GpUmv0hI.js} +1 -1
  51. package/dashboard/dist/assets/{WrappedPage-Gf15Ax3y.js → WrappedPage-SP2r4wf1.js} +1 -1
  52. package/dashboard/dist/assets/{__vite-browser-external-_-wIz90P.js → __vite-browser-external-AQgdBxou.js} +14 -13
  53. package/dashboard/dist/assets/{agent-logos-Ccd-gCmY.js → agent-logos-DxwSc05k.js} +1 -1
  54. package/dashboard/dist/assets/{arrow-up-right-DksoZ7Fm.js → arrow-up-right-CDW5zn0Q.js} +1 -1
  55. package/dashboard/dist/assets/{check-CFyujViz.js → check-CQfDkdqM.js} +1 -1
  56. package/dashboard/dist/assets/{chevron-right-D2Y9ycoK.js → chevron-right-DDFSY4w-.js} +1 -1
  57. package/dashboard/dist/assets/{copy-CvzVu4Jv.js → copy-hxnyMdBa.js} +1 -1
  58. package/dashboard/dist/assets/{download-M9hdGe0X.js → download-DOUBKxcf.js} +1 -1
  59. package/dashboard/dist/assets/{external-link-BrvgYr3H.js → external-link-CVipCZOa.js} +1 -1
  60. package/dashboard/dist/assets/{flame-CanCCWfM.js → flame-C-QU6mPf.js} +1 -1
  61. package/dashboard/dist/assets/{format-tokens-D-x5NM5s.js → format-tokens-DRX15id1.js} +1 -1
  62. package/dashboard/dist/assets/{icons-iDxUXUbD.js → icons-ajxtn_0O.js} +1 -1
  63. package/dashboard/dist/assets/{index-CDK-qlvv.js → index-Bq5VZMkS.js} +1 -1
  64. package/dashboard/dist/assets/{index-BPe3pmGu.js → index-DnVXRsqb.js} +1 -1
  65. package/dashboard/dist/assets/{index-DhgQVkQR.js → index-OJC-yROZ.js} +1 -1
  66. package/dashboard/dist/assets/{info-CS19GYkG.js → info-eITfPd17.js} +1 -1
  67. package/dashboard/dist/assets/{limits-providers-Cep8gK1J.js → limits-providers-TMq74bRy.js} +1 -1
  68. package/dashboard/dist/assets/{link-2-_GqbzcZy.js → link-2-D778MOmL.js} +1 -1
  69. package/dashboard/dist/assets/{loader-circle-DQlJKeCp.js → loader-circle-uN5rBNIF.js} +1 -1
  70. package/dashboard/dist/assets/{maximize-2-AaA61WoH.js → maximize-2-C4FBbMpN.js} +1 -1
  71. package/dashboard/dist/assets/{modifiers.esm-DgAD_X3C.js → modifiers.esm-DLeiQDTT.js} +1 -1
  72. package/dashboard/dist/assets/{monitor-smartphone-C-KIKlP-.js → monitor-smartphone-C-obu2-u.js} +1 -1
  73. package/dashboard/dist/assets/{provider-display-BWK3HqpN.js → provider-display-Bjl8tmYu.js} +1 -1
  74. package/dashboard/dist/assets/{react-BGB0fHad.js → react-Diah7uAT.js} +1 -1
  75. package/dashboard/dist/assets/{search-BhQx4B4T.js → search-B0bPOquo.js} +1 -1
  76. package/dashboard/dist/assets/{skills-api-BtsImOWQ.js → skills-api-6otf2Sdl.js} +1 -1
  77. package/dashboard/dist/assets/{sortable.esm-ew4S8Y1L.js → sortable.esm-DcrJaOfF.js} +1 -1
  78. package/dashboard/dist/assets/{store-OBiS6gfr.js → store-DOs4omJM.js} +1 -1
  79. package/dashboard/dist/assets/{terminal-GvWRPCY9.js → terminal-CpMZjaGk.js} +1 -1
  80. package/dashboard/dist/assets/{trash-2-COv_kp05.js → trash-2-BQYnn3zf.js} +1 -1
  81. package/dashboard/dist/assets/{use-community-stats-COxOg9PE.js → use-community-stats-CdL4zXXV.js} +1 -1
  82. package/dashboard/dist/assets/{use-limits-display-prefs-wf8pf1cF.js → use-limits-display-prefs-DUh4f8f4.js} +1 -1
  83. package/dashboard/dist/assets/{use-ordered-list-Dw-kLFB1.js → use-ordered-list-DVs0Ik3O.js} +1 -1
  84. package/dashboard/dist/assets/use-reduced-motion--_Yc7AWk.js +1 -0
  85. package/dashboard/dist/assets/{use-session-efficiency-pref-D9X2CzAz.js → use-session-efficiency-pref-CGggPI6Y.js} +1 -1
  86. package/dashboard/dist/assets/{use-transform-BgfBM2dC.js → use-transform-DMj91FEL.js} +1 -1
  87. package/dashboard/dist/assets/{use-usage-limits-CrHu9ZJi.js → use-usage-limits-xJOXzuZG.js} +1 -1
  88. package/dashboard/dist/assets/{useCurrency-CmI0tWeH.js → useCurrency-BQRBx-KO.js} +1 -1
  89. package/dashboard/dist/assets/{useScrollLock-BtUfInbu.js → useScrollLock-DuTPOBl8.js} +1 -1
  90. package/dashboard/dist/assets/{useTokenFormat-DAHyFBMr.js → useTokenFormat-Dd95ph6d.js} +1 -1
  91. package/dashboard/dist/assets/{zap-C9NzWrn0.js → zap-DJMdRI6y.js} +1 -1
  92. package/dashboard/dist/index.html +7 -7
  93. package/dashboard/dist/ip-check.html +1 -1
  94. package/dashboard/dist/leaderboard.html +1 -1
  95. package/dashboard/dist/llms.txt +4 -4
  96. package/dashboard/dist/share.html +2 -2
  97. package/package.json +3 -3
  98. package/src/commands/sync.js +1 -0
  99. package/src/lib/grok-hook.js +11 -2
  100. package/src/lib/opencode-go-limits.js +59 -30
  101. package/src/lib/pricing/seed-snapshot.json +1 -1
  102. package/src/lib/rollout.js +283 -68
  103. package/src/lib/star-cta.js +1 -1
  104. package/src/lib/usage-limits.js +3 -3
  105. package/dashboard/dist/assets/DialogDescription-JjVfYyrp.js +0 -1
  106. package/dashboard/dist/assets/HeaderGithubStar-5eKhC60J.js +0 -1
  107. package/dashboard/dist/assets/LimitsPage-DDljQnW7.js +0 -4
  108. package/dashboard/dist/assets/LocalOnlyNotice-BuNHRmPw.js +0 -1
  109. package/dashboard/dist/assets/use-reduced-motion-B3wPPJY8.js +0 -1
@@ -10519,6 +10519,54 @@ function droidSessionIdFromPath(filePath) {
10519
10519
  return base.slice(0, -".settings.json".length);
10520
10520
  }
10521
10521
 
10522
+ // Droid's workspace directory slug is lossy: path separators become `-`, which
10523
+ // collides with literal dashes in directory names. The sibling transcript keeps
10524
+ // the launch cwd losslessly in its session_start record, so project attribution
10525
+ // must read that value instead of trying to decode the directory name.
10526
+ const DROID_CWD_SCAN_MAX_BYTES = 65536;
10527
+
10528
+ async function resolveDroidFileCwd(settingsPath) {
10529
+ if (typeof settingsPath !== "string" || !settingsPath.endsWith(".settings.json")) {
10530
+ return null;
10531
+ }
10532
+ const sidecarPath = settingsPath.slice(0, -".settings.json".length) + ".jsonl";
10533
+ let stream;
10534
+ try {
10535
+ stream = fssync.createReadStream(sidecarPath, {
10536
+ encoding: "utf8",
10537
+ start: 0,
10538
+ end: DROID_CWD_SCAN_MAX_BYTES,
10539
+ });
10540
+ } catch {
10541
+ return null;
10542
+ }
10543
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
10544
+ try {
10545
+ for await (const line of rl) {
10546
+ if (!line || !line.includes('"cwd"')) continue;
10547
+ let entry;
10548
+ try {
10549
+ entry = JSON.parse(line);
10550
+ } catch {
10551
+ continue;
10552
+ }
10553
+ if (
10554
+ (entry?.type === "session_start" || entry?.type === "session") &&
10555
+ typeof entry.cwd === "string" &&
10556
+ entry.cwd.trim()
10557
+ ) {
10558
+ return entry.cwd.trim();
10559
+ }
10560
+ }
10561
+ } catch {
10562
+ return null;
10563
+ } finally {
10564
+ rl.close();
10565
+ stream.close?.();
10566
+ }
10567
+ return null;
10568
+ }
10569
+
10522
10570
  // Resolve a Droid bucket model id. ccusage's chain: settings.model → sidecar
10523
10571
  // <id>.jsonl scrape → `<provider>-unknown` derived from providerLock or inferred
10524
10572
  // from the model fragment. Extracted so the dup-session repair migration can
@@ -10618,6 +10666,8 @@ async function parseDroidIncremental({
10618
10666
  settingsFiles,
10619
10667
  cursors,
10620
10668
  queuePath,
10669
+ projectQueuePath,
10670
+ publicRepoResolver,
10621
10671
  onProgress,
10622
10672
  env,
10623
10673
  // `prune: true` (the production default) drops cursor entries whose session
@@ -10628,12 +10678,17 @@ async function parseDroidIncremental({
10628
10678
  prune = true,
10629
10679
  } = {}) {
10630
10680
  await ensureDir(path.dirname(queuePath));
10681
+ const projectEnabled = typeof projectQueuePath === "string" && projectQueuePath.length > 0;
10631
10682
  const droidState =
10632
10683
  cursors.droid && typeof cursors.droid === "object" ? cursors.droid : {};
10633
10684
  const sessionTotals =
10634
10685
  droidState.sessionTotals && typeof droidState.sessionTotals === "object"
10635
10686
  ? { ...droidState.sessionTotals }
10636
10687
  : {};
10688
+ const projectSessionTotals =
10689
+ droidState.projectSessionTotals && typeof droidState.projectSessionTotals === "object"
10690
+ ? { ...droidState.projectSessionTotals }
10691
+ : {};
10637
10692
 
10638
10693
  const files = dedupeDroidSettingsFilesBySession(
10639
10694
  Array.isArray(settingsFiles)
@@ -10645,13 +10700,24 @@ async function parseDroidIncremental({
10645
10700
  cursors.droid = {
10646
10701
  ...droidState,
10647
10702
  sessionTotals,
10703
+ ...(projectEnabled ? { projectSessionTotals } : {}),
10648
10704
  updatedAt: new Date().toISOString(),
10649
10705
  };
10650
- return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
10706
+ return {
10707
+ recordsProcessed: 0,
10708
+ eventsAggregated: 0,
10709
+ bucketsQueued: 0,
10710
+ projectBucketsQueued: 0,
10711
+ };
10651
10712
  }
10652
10713
 
10653
10714
  const hourlyState = normalizeHourlyState(cursors?.hourly);
10654
10715
  const touchedBuckets = new Set();
10716
+ const projectState = projectEnabled ? normalizeProjectState(cursors?.projectHourly) : null;
10717
+ const projectTouchedBuckets = projectEnabled ? new Set() : null;
10718
+ const projectMetaCache = projectEnabled ? new Map() : null;
10719
+ const publicRepoCache = projectEnabled ? new Map() : null;
10720
+ const projectFreshnessCache = projectEnabled ? new Map() : null;
10655
10721
  const cb = typeof onProgress === "function" ? onProgress : null;
10656
10722
  let recordsProcessed = 0;
10657
10723
  let eventsAggregated = 0;
@@ -10690,8 +10756,33 @@ async function parseDroidIncremental({
10690
10756
  thinking: 0,
10691
10757
  mtimeMs: 0,
10692
10758
  };
10759
+ const projectPrev = projectSessionTotals[sessionId] || {
10760
+ input: 0,
10761
+ output: 0,
10762
+ cacheCreation: 0,
10763
+ cacheRead: 0,
10764
+ thinking: 0,
10765
+ mtimeMs: 0,
10766
+ filePath: null,
10767
+ attributed: false,
10768
+ projectFileContext: null,
10769
+ };
10693
10770
  const isFirstSeenSession = !sessionTotals[sessionId];
10694
- if (mtimeMs && mtimeMs === prev.mtimeMs) continue;
10771
+ const globalNeedsUpdate = !(mtimeMs && mtimeMs === prev.mtimeMs);
10772
+ let projectNeedsUpdate = false;
10773
+ if (projectEnabled) {
10774
+ const projectFileChanged =
10775
+ !mtimeMs || mtimeMs !== projectPrev.mtimeMs || projectPrev.filePath !== filePath;
10776
+ if (!projectSessionTotals[sessionId] || projectFileChanged) {
10777
+ projectNeedsUpdate = true;
10778
+ } else if (projectPrev.attributed !== true) {
10779
+ projectNeedsUpdate = !(await isProjectFileContextFresh(
10780
+ projectPrev.projectFileContext,
10781
+ { freshnessCache: projectFreshnessCache },
10782
+ ));
10783
+ }
10784
+ }
10785
+ if (!globalNeedsUpdate && !projectNeedsUpdate) continue;
10695
10786
 
10696
10787
  let raw;
10697
10788
  try {
@@ -10726,6 +10817,12 @@ async function parseDroidIncremental({
10726
10817
  inputNow + outputNow + cacheCreationNow + cacheReadNow + thinkingNow;
10727
10818
  const sumPrev =
10728
10819
  prev.input + prev.output + prev.cacheCreation + prev.cacheRead + prev.thinking;
10820
+ const projectSumPrev =
10821
+ projectPrev.input +
10822
+ projectPrev.output +
10823
+ projectPrev.cacheCreation +
10824
+ projectPrev.cacheRead +
10825
+ projectPrev.thinking;
10729
10826
 
10730
10827
  // Transient empty: settings.json was observed with zero tokens (mid-write
10731
10828
  // or a brief wipe before the next turn restores totals). Do NOT clobber
@@ -10733,48 +10830,36 @@ async function parseDroidIncremental({
10733
10830
  // the same empty payload next sync. If we overwrote prev with zeros, a
10734
10831
  // later non-empty read would emit the full cumulative as a fresh delta.
10735
10832
  if (sumNow === 0) {
10736
- if (sumPrev > 0) {
10737
- sessionTotals[sessionId] = { ...prev, mtimeMs };
10738
- } else {
10739
- sessionTotals[sessionId] = {
10740
- input: 0,
10741
- output: 0,
10742
- cacheCreation: 0,
10743
- cacheRead: 0,
10744
- thinking: 0,
10745
- mtimeMs,
10746
- };
10833
+ if (globalNeedsUpdate) {
10834
+ if (sumPrev > 0) {
10835
+ sessionTotals[sessionId] = { ...prev, mtimeMs };
10836
+ } else {
10837
+ sessionTotals[sessionId] = {
10838
+ input: 0,
10839
+ output: 0,
10840
+ cacheCreation: 0,
10841
+ cacheRead: 0,
10842
+ thinking: 0,
10843
+ mtimeMs,
10844
+ };
10845
+ }
10846
+ }
10847
+ if (projectNeedsUpdate) {
10848
+ projectSessionTotals[sessionId] =
10849
+ projectSumPrev > 0
10850
+ ? { ...projectPrev, mtimeMs, filePath }
10851
+ : {
10852
+ input: 0,
10853
+ output: 0,
10854
+ cacheCreation: 0,
10855
+ cacheRead: 0,
10856
+ thinking: 0,
10857
+ mtimeMs,
10858
+ filePath,
10859
+ attributed: false,
10860
+ projectFileContext: buildProjectFileContext(null),
10861
+ };
10747
10862
  }
10748
- continue;
10749
- }
10750
-
10751
- // Reset only when the TOTAL shrinks — a real session reuse (Droid wiped
10752
- // tokenUsage and started over). A single field dropping while the sum
10753
- // grows is a schema change or cache eviction; clamping per-field deltas
10754
- // to >=0 is the right behavior for those.
10755
- const isReset = sumNow < sumPrev;
10756
-
10757
- const dInput = isReset ? inputNow : Math.max(0, inputNow - prev.input);
10758
- const dOutput = isReset ? outputNow : Math.max(0, outputNow - prev.output);
10759
- const dCacheCreation = isReset
10760
- ? cacheCreationNow
10761
- : Math.max(0, cacheCreationNow - prev.cacheCreation);
10762
- const dCacheRead = isReset
10763
- ? cacheReadNow
10764
- : Math.max(0, cacheReadNow - prev.cacheRead);
10765
- const dThinking = isReset
10766
- ? thinkingNow
10767
- : Math.max(0, thinkingNow - prev.thinking);
10768
-
10769
- if (dInput + dOutput + dCacheCreation + dCacheRead + dThinking === 0) {
10770
- sessionTotals[sessionId] = {
10771
- input: inputNow,
10772
- output: outputNow,
10773
- cacheCreation: cacheCreationNow,
10774
- cacheRead: cacheReadNow,
10775
- thinking: thinkingNow,
10776
- mtimeMs,
10777
- };
10778
10863
  continue;
10779
10864
  }
10780
10865
 
@@ -10790,31 +10875,146 @@ async function parseDroidIncremental({
10790
10875
  // empty-model sessions bucket identically across both tools.
10791
10876
  const model = resolveDroidModel(settings, filePath);
10792
10877
 
10793
- // Token normalization: inputTokens already excludes cache reads (matches
10794
- // Anthropic API convention), so cache columns slot in directly. Thinking
10795
- // is reasoning_output_tokens folded into cost via existing pricing path.
10796
- const bucketDelta = {
10797
- input_tokens: dInput,
10798
- cached_input_tokens: dCacheRead,
10799
- cache_creation_input_tokens: dCacheCreation,
10800
- output_tokens: dOutput,
10801
- reasoning_output_tokens: dThinking,
10802
- total_tokens: dInput + dOutput + dCacheCreation + dCacheRead + dThinking,
10803
- conversation_count: isFirstSeenSession || isReset ? 1 : 0,
10804
- };
10805
- const bucket = getHourlyBucket(hourlyState, "droid", model, bucketStart);
10806
- addTotals(bucket.totals, bucketDelta);
10807
- touchedBuckets.add(bucketKey("droid", model, bucketStart));
10878
+ if (globalNeedsUpdate) {
10879
+ // Reset only when the TOTAL shrinks a real session reuse (Droid wiped
10880
+ // tokenUsage and started over). A single field dropping while the sum
10881
+ // grows is a schema change or cache eviction; clamping per-field deltas
10882
+ // to >=0 is the right behavior for those.
10883
+ const isReset = sumNow < sumPrev;
10884
+ const dInput = isReset ? inputNow : Math.max(0, inputNow - prev.input);
10885
+ const dOutput = isReset ? outputNow : Math.max(0, outputNow - prev.output);
10886
+ const dCacheCreation = isReset
10887
+ ? cacheCreationNow
10888
+ : Math.max(0, cacheCreationNow - prev.cacheCreation);
10889
+ const dCacheRead = isReset
10890
+ ? cacheReadNow
10891
+ : Math.max(0, cacheReadNow - prev.cacheRead);
10892
+ const dThinking = isReset
10893
+ ? thinkingNow
10894
+ : Math.max(0, thinkingNow - prev.thinking);
10895
+
10896
+ if (dInput + dOutput + dCacheCreation + dCacheRead + dThinking > 0) {
10897
+ // Token normalization: inputTokens already excludes cache reads (matches
10898
+ // Anthropic API convention), so cache columns slot in directly. Thinking
10899
+ // is reasoning_output_tokens — folded into cost via existing pricing path.
10900
+ const bucketDelta = {
10901
+ input_tokens: dInput,
10902
+ cached_input_tokens: dCacheRead,
10903
+ cache_creation_input_tokens: dCacheCreation,
10904
+ output_tokens: dOutput,
10905
+ reasoning_output_tokens: dThinking,
10906
+ total_tokens: dInput + dOutput + dCacheCreation + dCacheRead + dThinking,
10907
+ conversation_count: isFirstSeenSession || isReset ? 1 : 0,
10908
+ };
10909
+ const bucket = getHourlyBucket(hourlyState, "droid", model, bucketStart);
10910
+ addTotals(bucket.totals, bucketDelta);
10911
+ touchedBuckets.add(bucketKey("droid", model, bucketStart));
10912
+ eventsAggregated++;
10913
+ }
10808
10914
 
10809
- sessionTotals[sessionId] = {
10810
- input: inputNow,
10811
- output: outputNow,
10812
- cacheCreation: cacheCreationNow,
10813
- cacheRead: cacheReadNow,
10814
- thinking: thinkingNow,
10815
- mtimeMs,
10816
- };
10817
- eventsAggregated++;
10915
+ sessionTotals[sessionId] = {
10916
+ input: inputNow,
10917
+ output: outputNow,
10918
+ cacheCreation: cacheCreationNow,
10919
+ cacheRead: cacheReadNow,
10920
+ thinking: thinkingNow,
10921
+ mtimeMs,
10922
+ };
10923
+ }
10924
+
10925
+ if (projectNeedsUpdate) {
10926
+ const cwd = await resolveDroidFileCwd(filePath);
10927
+ const projectContext = cwd
10928
+ ? await resolveProjectContextForPath({
10929
+ startDir: wsl.mapWslCwdToUnc(cwd, filePath),
10930
+ projectMetaCache,
10931
+ publicRepoCache,
10932
+ publicRepoResolver,
10933
+ projectState,
10934
+ })
10935
+ : null;
10936
+ const projectRef = projectContext?.projectRef || null;
10937
+ const projectKey = projectContext?.projectKey || null;
10938
+ const projectFileContext = buildProjectFileContext(projectContext);
10939
+
10940
+ // Keep this baseline independent from the global cursor so project
10941
+ // attribution can be backfilled once without replaying global usage.
10942
+ // If the repo is not public/verified yet, leave it unadvanced so a later
10943
+ // sync can retry after project metadata or network availability changes.
10944
+ if (projectKey && projectRef) {
10945
+ const projectReset = sumNow < projectSumPrev;
10946
+ const projectDInput = projectReset
10947
+ ? inputNow
10948
+ : Math.max(0, inputNow - projectPrev.input);
10949
+ const projectDOutput = projectReset
10950
+ ? outputNow
10951
+ : Math.max(0, outputNow - projectPrev.output);
10952
+ const projectDCacheCreation = projectReset
10953
+ ? cacheCreationNow
10954
+ : Math.max(0, cacheCreationNow - projectPrev.cacheCreation);
10955
+ const projectDCacheRead = projectReset
10956
+ ? cacheReadNow
10957
+ : Math.max(0, cacheReadNow - projectPrev.cacheRead);
10958
+ const projectDThinking = projectReset
10959
+ ? thinkingNow
10960
+ : Math.max(0, thinkingNow - projectPrev.thinking);
10961
+ const projectTotal =
10962
+ projectDInput +
10963
+ projectDOutput +
10964
+ projectDCacheCreation +
10965
+ projectDCacheRead +
10966
+ projectDThinking;
10967
+ if (projectTotal > 0) {
10968
+ const projectDelta = {
10969
+ input_tokens: projectDInput,
10970
+ cached_input_tokens: projectDCacheRead,
10971
+ cache_creation_input_tokens: projectDCacheCreation,
10972
+ output_tokens: projectDOutput,
10973
+ reasoning_output_tokens: projectDThinking,
10974
+ total_tokens: projectTotal,
10975
+ conversation_count: !projectSessionTotals[sessionId] || projectReset ? 1 : 0,
10976
+ };
10977
+ const projectBucket = getProjectBucket(
10978
+ projectState,
10979
+ projectKey,
10980
+ "droid",
10981
+ bucketStart,
10982
+ projectRef,
10983
+ );
10984
+ addTotals(projectBucket.totals, projectDelta);
10985
+ projectTouchedBuckets.add(
10986
+ projectBucketKey(projectKey, "droid", bucketStart),
10987
+ );
10988
+ }
10989
+ projectSessionTotals[sessionId] = {
10990
+ input: inputNow,
10991
+ output: outputNow,
10992
+ cacheCreation: cacheCreationNow,
10993
+ cacheRead: cacheReadNow,
10994
+ thinking: thinkingNow,
10995
+ mtimeMs,
10996
+ filePath,
10997
+ projectKey,
10998
+ projectRef,
10999
+ attributed: true,
11000
+ projectFileContext,
11001
+ };
11002
+ } else {
11003
+ projectSessionTotals[sessionId] = {
11004
+ input: 0,
11005
+ output: 0,
11006
+ cacheCreation: 0,
11007
+ cacheRead: 0,
11008
+ thinking: 0,
11009
+ mtimeMs,
11010
+ filePath,
11011
+ projectKey: null,
11012
+ projectRef,
11013
+ attributed: false,
11014
+ projectFileContext,
11015
+ };
11016
+ }
11017
+ }
10818
11018
 
10819
11019
  if (cb) {
10820
11020
  cb({
@@ -10836,6 +11036,9 @@ async function parseDroidIncremental({
10836
11036
  for (const id of Object.keys(sessionTotals)) {
10837
11037
  if (!seenSessionIds.has(id)) delete sessionTotals[id];
10838
11038
  }
11039
+ for (const id of Object.keys(projectSessionTotals)) {
11040
+ if (!seenSessionIds.has(id)) delete projectSessionTotals[id];
11041
+ }
10839
11042
  }
10840
11043
 
10841
11044
  const bucketsQueued = await enqueueTouchedBuckets({
@@ -10843,16 +11046,28 @@ async function parseDroidIncremental({
10843
11046
  hourlyState,
10844
11047
  touchedBuckets,
10845
11048
  });
11049
+ const projectBucketsQueued = projectEnabled
11050
+ ? await enqueueTouchedProjectBuckets({
11051
+ projectQueuePath,
11052
+ projectState,
11053
+ projectTouchedBuckets,
11054
+ })
11055
+ : 0;
10846
11056
  const updatedAt = new Date().toISOString();
10847
11057
  hourlyState.updatedAt = updatedAt;
10848
11058
  cursors.hourly = hourlyState;
11059
+ if (projectState) {
11060
+ projectState.updatedAt = updatedAt;
11061
+ cursors.projectHourly = projectState;
11062
+ }
10849
11063
  cursors.droid = {
10850
11064
  ...droidState,
10851
11065
  sessionTotals,
11066
+ ...(projectEnabled ? { projectSessionTotals } : {}),
10852
11067
  updatedAt,
10853
11068
  };
10854
11069
 
10855
- return { recordsProcessed, eventsAggregated, bucketsQueued };
11070
+ return { recordsProcessed, eventsAggregated, bucketsQueued, projectBucketsQueued };
10856
11071
  }
10857
11072
 
10858
11073
  async function parseKilocodeIncremental({
@@ -5,7 +5,7 @@ const path = require("node:path");
5
5
  const pkg = require("../../package.json");
6
6
  const { readJson, writeJson } = require("./fs");
7
7
 
8
- const STAR_CTA_URL = "https://github.com/mm7894215/TokenTracker";
8
+ const STAR_CTA_URL = "https://github.com/xiufengsun/TokenTracker";
9
9
  const STAR_CTA_STATE_FILE = "star-cta.json";
10
10
 
11
11
  function isTruthyFlag(value) {
@@ -3131,9 +3131,9 @@ async function fetchUsageLimitsUncached({
3131
3131
  .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
3132
3132
  withProviderTimeout(fetchZcodeLimits({ home, env, fetchImpl: providerFetch }), "ZCode", providerTimeoutMs)
3133
3133
  .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
3134
- // OpenCode Go: local opencode.db cost-vs-dollar-cap estimate by default
3135
- // (auth-free, zero-config), upgraded to the exact server-side scrape when an
3136
- // OPENCODE_GO_AUTH_COOKIE is set. See src/lib/opencode-go-limits.js.
3134
+ // OpenCode Go: authoritative subscription windows come from the dashboard
3135
+ // scrape; local opencode.db cost is available only as an explicit estimate.
3136
+ // See src/lib/opencode-go-limits.js.
3137
3137
  withProviderTimeout(fetchOpencodeGoLimits({ home, env, fetchImpl: providerFetch }), "OpenCode Go", providerTimeoutMs)
3138
3138
  .catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
3139
3139
  withProviderTimeout(
@@ -1 +0,0 @@
1
- import{r as n,z as a}from"./__vite-browser-external-_-wIz90P.js";import{u as p}from"./DialogTitle-CQlYwz-I.js";import{u as c}from"./useScrollLock-BtUfInbu.js";const x=n.forwardRef(function(e,r){const{render:l,className:u,style:m,id:s,...t}=e,{store:i}=p(),o=c(s);return i.useSyncedValueWithCleanup("descriptionElementId",o),a("p",e,{ref:r,props:[{id:o},t]})});export{x as D};
@@ -1 +0,0 @@
1
- import{r as s,s as c,j as t,c as d}from"./__vite-browser-external-_-wIz90P.js";function u({repo:r="mm7894215/TokenTracker"}){const[a,o]=s.useState(null);return s.useEffect(()=>{if(typeof window>"u")return;const n=typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,i=typeof document<"u"&&(document.documentElement?.classList.contains("screenshot-capture")||document.body?.classList.contains("screenshot-capture"));c({prefersReducedMotion:n,screenshotCapture:i})&&fetch(`https://api.github.com/repos/${r}`).then(e=>e.json()).then(e=>{e&&typeof e.stargazers_count=="number"&&o(e.stargazers_count)}).catch(()=>{})},[r]),t.jsxs("a",{href:`https://github.com/${r}`,target:"_blank",rel:"noopener noreferrer",className:"inline-flex shrink-0 items-center gap-2 px-3 py-1.5 rounded-md border border-oai-gray-200 dark:border-oai-gray-700 bg-oai-gray-50 dark:bg-oai-gray-800 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-700 transition-colors no-underline",children:[t.jsx("svg",{height:"16",viewBox:"0 0 16 16",width:"16",className:"shrink-0 fill-oai-gray-700 dark:fill-oai-gray-300",children:t.jsx("path",{d:"M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"})}),t.jsx("span",{className:"text-xs font-medium text-oai-gray-700 dark:text-oai-gray-300 whitespace-nowrap",children:d("shared.github.star")}),a!==null&&t.jsx("span",{className:"text-xs font-semibold text-oai-gray-900 dark:text-oai-white tabular-nums whitespace-nowrap",children:a})]})}export{u as H};
@@ -1,4 +0,0 @@
1
- import{m as $,j as a,e as B,c as r,k as W,r as h,ae,d as ie,J as re,L as ne,af as oe,q as se,ag as le}from"./__vite-browser-external-_-wIz90P.js";import{m as D}from"./react-BGB0fHad.js";import{P as L,c as ce,r as N,a as de,u as ue,b as me,s as xe}from"./use-usage-limits-CrHu9ZJi.js";import{L as m,u as pe}from"./use-limits-display-prefs-wf8pf1cF.js";import{C as U}from"./Card-BCAAH2Tv.js";import{F as ge}from"./FadeIn-C7oxsfI-.js";import{L as fe,l as M,a as he}from"./limits-providers-Cep8gK1J.js";import{P as be}from"./ProviderIcon-DAn58wfZ.js";import{H as ye}from"./HoverTooltip-Tf9XsZ6G.js";import{L as ke}from"./LocalOnlyNotice-BuNHRmPw.js";import{u as ve}from"./use-reduced-motion-B3wPPJY8.js";import"./arrow-up-right-DksoZ7Fm.js";import"./download-M9hdGe0X.js";const je=[["path",{d:"M10.268 21a2 2 0 0 0 3.464 0",key:"vwvbt9"}],["path",{d:"M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742",key:"178tsu"}],["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05",key:"1hqiys"}]],_e=$("bell-off",je);const Ne=[["path",{d:"M10.268 21a2 2 0 0 0 3.464 0",key:"vwvbt9"}],["path",{d:"M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326",key:"11g9vi"}]],we=$("bell",Ne),Me=[3,2,3,3,2,2,3];function f({className:e}){return a.jsx("div",{className:B("rounded bg-oai-gray-200/70 dark:bg-oai-gray-800/70 animate-pulse",e)})}function Ee(){return a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(f,{className:"h-3 w-12 shrink-0"}),a.jsx(f,{className:"flex-1 h-1.5 rounded-full min-w-0"}),a.jsx(f,{className:"h-3 w-[30px] shrink-0"}),a.jsx(f,{className:"h-3 w-6 shrink-0"})]})}function Ie({bars:e,index:t}){const i=t%3===0?"w-24":t%3===1?"w-20":"w-[4.5rem]";return a.jsxs("div",{className:"flex flex-col gap-1.5",children:[a.jsxs("div",{className:"flex items-center gap-1.5",children:[a.jsx(f,{className:"h-[14px] w-[14px] rounded shrink-0"}),a.jsx(f,{className:B("h-4",i)})]}),Array.from({length:e},(o,n)=>a.jsx(Ee,{},n))]})}function Le(){return a.jsx(U,{children:a.jsxs("div",{className:"flex flex-col gap-3",children:[a.jsx(f,{className:"h-3.5 w-28"}),Me.map((e,t)=>a.jsx(Ie,{bars:e,index:t},t))]})})}const P=100;function F(e){const t=Date.parse(e);return Number.isFinite(t)?t:null}function Pe(e){return Math.max(0,Math.min(P,Math.round(e)))}function Oe(e){return new Intl.DateTimeFormat(W(),{month:"numeric",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}).format(new Date(e))}function Se(e,t,i){if(e==null||e>=t)return P;const o=t-e,n=t-i;return Pe(n/o*P)}function Re(e){const t=e.available_count;return t===null?null:Number.isInteger(t)&&t>=0?t:void 0}function Ce(e,{now:t}={}){if(!e||typeof e!="object")return null;const i=Re(e);if(i===void 0)return null;const o=Array.isArray(e.credits)?e.credits:[],n=t instanceof Date?t.getTime():Number(t??Date.now()),s=[];for(const d of o){const c=F(d?.expires_at);if(c==null)continue;const l=s.length+1;s.push({key:`reset-${l}`,label:r("limits.codex_reset_bank.row_label",{index:l}),expiresAt:Oe(c),expiresMs:c,percent:Se(F(d?.granted_at),c,n)})}return i===0?null:s.length>0?{kind:"rows",availableCount:i??s.length,rows:s}:i>0?{kind:"count_only",availableCount:i,rows:[]}:null}const Te="shrink-0 text-oai-black dark:text-oai-white";function Ae(e){const t=N(e);if(!Number.isFinite(t))return null;const i=t-Date.now();if(i<=0)return r("shared.time.now");const o=Math.floor(i/6e4);if(o<60)return`${o}m`;const n=Math.floor(o/60);return n<24?`${n}h`:`${Math.floor(n/24)}d`}function De(e,t){const i=t===m.REMAINING?100-e:e;return i>=90?"bg-red-500":i>=70?"bg-amber-500":"bg-emerald-500"}function _(e,t="used_percent"){return e?t==="utilization"?e.utilization:e.used_percent:null}function w(e,t="reset_at"){return e?t==="resets_at"?e.resets_at:e.reset_at:null}function E(e){const t=Math.max(0,Math.min(100,Number(e)||0)),i=Math.round(t);return t>0&&i===0?r("limits.bar.sub_one_percent"):String(i)}function j(e,{useGrouping:t=!0,maximumFractionDigits:i}={}){const o=Number(e);return Number.isFinite(o)?new Intl.NumberFormat(void 0,{minimumFractionDigits:0,maximumFractionDigits:i??(o>=100?0:2),useGrouping:t}).format(o):null}function Fe(e){if(!e||typeof e!="object"||!(Number(e.limit_credits)>0))return null;const t={useGrouping:e.unit!=="calls"},i=j(e.used_credits,t),o=j(e.limit_credits,t),n=j(e.remaining_credits,t);if(!i||!o||!n)return null;const s=e.unit==="calls"?"limits.qoder_calls.detail":"limits.codex_credits.detail";return r(s,{used:i,limit:o,remaining:n})}function Ge(e,t){return ce({usedPercent:_(e.window,e.pctField),windowSeconds:de(e,e.window),resetMs:N(w(e.window,e.resetField)),mode:t})}function q(e){return Number.isFinite(e)?new Intl.DateTimeFormat(W(),{month:"numeric",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}).format(new Date(e)):null}function He(e,t,i){const o=[z(e,t,i)],n=N(w(e.window,e.resetField)),s=q(n);s&&o.push(r(e.timeKind==="expiry"?"limits.hover.expires_at":"limits.hover.resets_at",{time:s}));const d=Fe(e.window);return d&&o.push(d),o.join(`
2
- `)}const K=ye;function $e({label:e,pct:t,reset:i,mode:o=m.USED,pacePercent:n=null,paceOver:s=!1,title:d=null}){const c=Math.max(0,Math.min(100,Number(t)||0)),l=o===m.REMAINING?100-c:c,u=Math.round(l),x=l>0&&u===0?Math.max(l,.35):l;let k=String(u);l>0&&u===0&&(k=r("limits.bar.sub_one_percent"));const p=n==null?null:Math.max(0,Math.min(100,n));return a.jsxs("div",{className:"group relative flex items-center gap-2",children:[a.jsx(K,{text:d}),a.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}),a.jsxs("div",{className:"relative flex-1 bg-oai-gray-100 dark:bg-oai-gray-700/50 rounded-full h-1.5 overflow-hidden",children:[a.jsx("div",{className:`${De(l,o)} rounded-full h-full transition-[width] duration-500 ease-out`,style:{width:`${x}%`,minWidth:l>0?"3px":0}}),p!=null&&a.jsxs(a.Fragment,{children:[a.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"}}),a.jsx("div",{className:`absolute top-0 h-full ${s?"bg-red-500":"bg-emerald-500"}`,style:{left:`calc(${p}% - 1px)`,width:"2px"}})]})]}),a.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:[k,"%"]}),i&&a.jsx("span",{className:"text-[10px] text-oai-gray-400 dark:text-oai-gray-500 w-6 text-right shrink-0",children:i})]})}function z(e,t,i){const o=e.label??r(e.labelKey),n=i===m.REMAINING,s=l=>n?100-l:l;if(t.expectedPercent==null){const l=Math.max(0,Math.min(100,Number(_(e.window,e.pctField))||0)),u=E(s(l));return n?r("limits.explain.remaining",{label:o,used:u}):r("limits.explain.used",{label:o,used:u})}if(t.paceOver){if(t.runsOutEta)return r("limits.explain.ahead_eta",{label:o,eta:t.runsOutEta});const l=E(s(t.projectedEnd??100));return r(n?"limits.explain.ahead_pct_remaining":"limits.explain.ahead_pct",{label:o,pct:l})}const d=Math.max(0,Math.min(100,Number(_(e.window,e.pctField))||0)),c=E(s(t.projectedEnd??d));return r(n?"limits.explain.on_track_remaining":"limits.explain.on_track",{label:o,pct:c})}function Be({rows:e,mode:t}){if(e.length===0)return null;const i=t===m.REMAINING;return a.jsxs("div",{className:"mt-1 flex flex-col gap-1",children:[e.map(({spec:o,pace:n})=>{const s=q(N(w(o.window,o.resetField)));return a.jsxs("div",{className:"text-[11px] leading-snug text-oai-gray-600 dark:text-oai-gray-300",children:[z(o,n,t),s?a.jsxs("span",{className:"text-oai-gray-400 dark:text-oai-gray-500",children:[" · ",r(o.timeKind==="expiry"?"limits.hover.expires_at":"limits.hover.resets_at",{time:s})]}):null]},o.key)}),a.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:r(i?"limits.explain.body_remaining":"limits.explain.body")})]})}function v(e){if(!e)return null;const t=Date.now()-new Date(e).getTime();if(t<0)return null;const i=Math.floor(t/6e4);if(i<1)return r("shared.time.now");if(i<60)return r("shared.time.m_ago",{n:i});const o=Math.floor(i/60);if(o<24)return r("shared.time.h_ago",{n:o});const n=Math.floor(o/24);return r("shared.time.d_ago",{n})}const G={live:{surface:"bg-oai-gray-50 dark:bg-oai-gray-800 border-oai-gray-200/60 dark:border-oai-gray-700/60 text-oai-gray-500 dark:text-oai-gray-400",dot:"bg-emerald-500",pulse:"bg-emerald-400"},stale:{surface:"bg-oai-gray-50 dark:bg-oai-gray-800 border-oai-gray-200/60 dark:border-oai-gray-700/60 text-oai-gray-500 dark:text-oai-gray-400",dot:"bg-amber-500",pulse:"bg-amber-400"},cached:{surface:"bg-oai-gray-50 dark:bg-oai-gray-800 border-oai-gray-200/60 dark:border-oai-gray-700/60 text-oai-gray-500 dark:text-oai-gray-400",dot:"bg-amber-500",pulse:"bg-amber-400"}},We={claude:"claude",codex:"codex"};function y({label:e,age:t=null,tone:i="live",tooltip:o=null}){const n=G[i]||G.live,s=i==="live";return a.jsxs("div",{className:"relative inline-flex items-center group cursor-help ml-1",onClick:d=>d.stopPropagation(),children:[a.jsxs("span",{className:`inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[9px] font-semibold uppercase tracking-wider border leading-normal ${n.surface}`,children:[s?a.jsxs("span",{className:"relative flex h-1.5 w-1.5",children:[a.jsx("span",{className:`animate-ping absolute inline-flex h-full w-full rounded-full ${n.pulse} opacity-75`}),a.jsx("span",{className:`relative inline-flex rounded-full h-1.5 w-1.5 ${n.dot}`})]}):a.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${n.dot}`}),e,t?a.jsxs(a.Fragment,{children:[" · ",t]}):null]}),o?a.jsxs("span",{className:"pointer-events-none absolute left-1/2 bottom-full z-20 mb-2 -translate-x-1/2 w-48 rounded-md bg-oai-gray-900 dark:bg-oai-gray-800 px-2.5 py-1.5 text-[10px] font-normal text-white text-center opacity-0 scale-95 translate-y-1 group-hover:opacity-100 group-hover:scale-100 group-hover:translate-y-0 transition-all duration-200 cubic-bezier(0.16, 1, 0.3, 1) leading-normal shadow-lg origin-bottom border border-oai-gray-800 dark:border-oai-gray-700",children:[o,a.jsx("span",{className:"absolute left-1/2 top-full -translate-x-1/2 border-4 border-transparent border-t-oai-gray-900 dark:border-t-oai-gray-800"})]}):null]})}function O({name:e,providerId:t,children:i,expandable:o=!1,expanded:n=!1,onToggle:s,badge:d=null}){const c=he(t),l=a.jsxs("div",{className:"flex items-center gap-1.5",children:[c?a.jsx(be,{provider:c,size:14,className:Te}):null,a.jsx("span",{className:"text-sm font-medium text-oai-black dark:text-oai-white",children:e}),d]});return o?a.jsxs("div",{role:"button",tabIndex:0,"aria-expanded":n,onClick:s,onKeyDown:u=>{(u.key==="Enter"||u.key===" ")&&(u.preventDefault(),s?.())},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:[l,i]}):a.jsxs("div",{className:"flex flex-col gap-1.5",children:[l,i]})}const Ue=fe;function b({children:e,tone:t="neutral"}){const i=t==="error"?"text-red-600 dark:text-red-400":"text-oai-gray-500 dark:text-oai-gray-400";return a.jsx("div",{className:`text-[11px] leading-snug ${i}`,children:e})}function qe({rows:e,mode:t,extra:i=null}){const o=e.length===0&&!i;return a.jsxs(a.Fragment,{children:[e.map(({spec:n,pace:s})=>a.jsx($e,{label:n.label??r(n.labelKey),pct:_(n.window,n.pctField),reset:Ae(w(n.window,n.resetField)),mode:t,pacePercent:s.pacePercent,paceOver:s.paceOver,title:He(n,s,t)},n.key)),o?a.jsx(b,{children:r("limits.status.no_data")}):null,i]})}function Ke(e){if(!Number.isFinite(e.expiresMs))return null;const t=Math.floor((e.expiresMs-Date.now())/864e5);return t<0?null:t===0?r("limits.reset_bank.hover_detail_today",{date:e.expiresAt}):r("limits.reset_bank.hover_detail",{date:e.expiresAt,days:t})}function ze({row:e}){const t=Math.max(0,Math.min(100,Number(e.percent)||0));return a.jsxs("div",{className:"group relative flex items-center gap-2","data-reset-bank-row":"",children:[a.jsx(K,{text:Ke(e)}),a.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.label}),a.jsx("div",{className:"relative flex-1 bg-oai-gray-100 dark:bg-oai-gray-700/50 rounded-full h-1.5 overflow-hidden",children:a.jsx("div",{className:"bg-oai-gray-400 dark:bg-oai-gray-500 rounded-full h-full transition-[width] duration-500 ease-out",style:{width:`${t}%`,minWidth:t>0?"3px":0}})}),a.jsx("span",{className:"text-[10px] tabular-nums text-oai-gray-400 dark:text-oai-gray-500 w-[4.25rem] text-right shrink-0 whitespace-nowrap",children:e.expiresAt})]})}function Ve({model:e}){const t=e.kind==="count_only"?r("limits.codex_reset_bank.count_only",{count:e.availableCount}):null;return a.jsxs("div",{className:"mt-1 flex flex-col gap-1","data-reset-bank-section":e.kind,children:[a.jsx("div",{className:"text-[10.5px] font-medium uppercase tracking-wide text-oai-gray-400 dark:text-oai-gray-500",children:r("limits.codex_reset_bank.title")}),t?a.jsx("div",{className:"text-[11px] leading-snug text-oai-gray-500 dark:text-oai-gray-400",children:t}):e.rows.map(i=>a.jsx(ze,{row:i},i.key))]})}function V(e,t){if(e==="codex_meta"){const i=Ce(t.reset_credits);return i?a.jsx(Ve,{model:i}):null}if(e==="kimi_parallel"&&t.parallel_limit)return a.jsx(b,{children:r("limits.label.kimi_parallel",{count:t.parallel_limit})});if(e==="kiro_credits"&&Number.isFinite(Number(t.tracked_credits))&&Number(t.tracked_credit_records)>0){const i=j(t.tracked_credits,{maximumFractionDigits:2});return a.jsx(b,{children:r("limits.label.kiro_tracked_credits",{credits:i,count:Number(t.tracked_credit_records)})})}return e==="copilot_otel"&&!t.otel_has_files&&!t.otel_enabled?a.jsx(Je,{defaultDir:t.otel_default_dir}):null}function Xe(e,t,i,o,n,s,d=null){const c=L[e];if(!c)return null;const l=c.windows(t).filter(x=>x.window).map(x=>({spec:x,pace:Ge(x,o)})),u=V(c.extra,t);return a.jsxs(O,{name:i,providerId:e,expandable:l.length>0,expanded:n,onToggle:s,badge:d,children:[a.jsx(qe,{mode:o,rows:l,extra:u}),n?a.jsx(Be,{rows:l,mode:o}):null]},e)}function Ye(e,t,i,o,n){if(!L[e])return null;if(!t?.configured)return a.jsxs(O,{name:M(e),providerId:e,children:[a.jsx(b,{children:r("limits.status.not_connected")}),e==="opencodeGo"?a.jsx(H,{}):null]},e);if(t.error)return a.jsxs(O,{name:M(e),providerId:e,children:[a.jsx(b,{tone:"error",children:r("shared.error.prefix",{error:t.error})}),e==="kiro"?V(L.kiro.extra,t):null,e==="opencodeGo"?a.jsx(H,{}):null]},e);const s=M(e),d=t.plan_label?`${s} ${t.plan_label}`:s;let c=null;if(e==="antigravity")if(t.cached){const u=v(t.cached_at);c=a.jsx(y,{label:r("limits.label.antigravity_cached"),age:u,tone:"cached",tooltip:r("limits.tooltip.antigravity_cached")})}else c=a.jsx(y,{label:r("limits.label.antigravity_live"),tone:"live",tooltip:r("limits.tooltip.antigravity_live")});if(e==="qoder"&&t.cached&&(c=a.jsx(y,{label:r("limits.label.antigravity_cached"),age:v(t.cached_at),tone:"cached",tooltip:r("limits.tooltip.qoder_cached")})),!c&&t.auth_action_required==="reauth"){const u=We[e];c=a.jsx(y,{label:r("limits.reauth.badge"),age:v(t.cached_at),tone:"stale",tooltip:u?r("limits.reauth.tooltip",{command:u}):null})}const l=t.provenance;return l?.stale&&!c&&(c=a.jsx(y,{label:r("limits.provenance.stale"),age:v(l.captured_at),tone:"stale",tooltip:r("limits.provenance.tooltip",{source:l.source,confidence:l.confidence})})),Xe(e,t,d,i,o,n,c)}function Je({defaultDir:e}){const[t,i]=h.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(`
3
- `),s=async d=>{d.stopPropagation();try{await navigator.clipboard.writeText(n),i(!0),setTimeout(()=>i(!1),1600)}catch{}};return a.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:[a.jsx("div",{className:"font-medium text-oai-gray-700 dark:text-oai-gray-200",children:r("limits.copilot.otelHint.title")}),a.jsx("div",{className:"mt-0.5 leading-snug",children:r("limits.copilot.otelHint.body")}),a.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}),a.jsx("button",{type:"button",onClick:s,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?r("limits.copilot.otelHint.copied"):r("limits.copilot.otelHint.copy")})]})}function I({n:e,children:t}){return a.jsxs("li",{className:"flex gap-2.5",children:[a.jsx("span",{className:"mt-[1px] flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-oai-brand/15 text-[9px] font-semibold text-oai-brand",children:e}),a.jsx("div",{className:"min-w-0 flex-1 leading-snug",children:t})]})}function Qe(){return a.jsx("svg",{viewBox:"0 0 12 12","aria-hidden":"true",className:"h-2.5 w-2.5",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:a.jsx("path",{d:"M4.5 2.75h4.75V7.5M9.25 2.75 3 9"})})}function H(){const[e,t]=h.useState(!1),i=['export OPENCODE_GO_AUTH_COOKIE="..."','# Optional: export OPENCODE_GO_WORKSPACE_ID="wrk_..." (Only if auto-discovery fails)'].join(`
4
- `),o=async n=>{n.stopPropagation();try{await navigator.clipboard.writeText(i),t(!0),setTimeout(()=>t(!1),1600)}catch{}};return a.jsxs("div",{className:"mt-1.5 rounded-lg border border-oai-gray-200 dark:border-oai-gray-700/60 bg-oai-gray-50/50 dark:bg-oai-gray-900/20 p-3 text-[11px] text-oai-gray-600 dark:text-oai-gray-300",children:[a.jsx("div",{className:"text-[12px] font-semibold text-oai-gray-800 dark:text-oai-gray-100",children:r("limits.opencodeGo.setupHint.title")}),a.jsx("div",{className:"mt-0.5 leading-snug text-oai-gray-500 dark:text-oai-gray-400",children:r("limits.opencodeGo.setupHint.subtitle")}),a.jsxs("ol",{className:"mt-2.5 space-y-2.5",children:[a.jsxs(I,{n:"1",children:[a.jsx("div",{children:r("limits.opencodeGo.setupHint.step1")}),a.jsxs("a",{href:"https://opencode.ai",target:"_blank",rel:"noreferrer",onClick:n=>n.stopPropagation(),className:"mt-1 inline-flex items-center gap-1 rounded-md bg-oai-brand/10 px-2 py-1 font-medium text-oai-brand hover:bg-oai-brand/15 transition-colors",children:[r("limits.opencodeGo.setupHint.cta"),a.jsx(Qe,{})]})]}),a.jsxs(I,{n:"2",children:[a.jsx("div",{children:r("limits.opencodeGo.setupHint.step2")}),a.jsxs("ul",{className:"mt-1 space-y-0.5 text-oai-gray-500 dark:text-oai-gray-400",children:[a.jsx("li",{children:r("limits.opencodeGo.setupHint.step2_workspace")}),a.jsx("li",{children:r("limits.opencodeGo.setupHint.step2_cookie")})]})]}),a.jsxs(I,{n:"3",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("span",{children:r("limits.opencodeGo.setupHint.step3")}),a.jsx("button",{type:"button",onClick:o,className:"shrink-0 rounded-md border border-oai-gray-300 dark:border-oai-gray-700 px-2 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:e?r("limits.opencodeGo.setupHint.copied"):r("limits.opencodeGo.setupHint.copy")})]}),a.jsx("pre",{className:"mt-1.5 overflow-x-auto rounded-md bg-oai-gray-100 dark:bg-oai-gray-900/60 px-2 py-1.5 font-mono text-[10.5px] leading-relaxed whitespace-pre",children:i}),a.jsx("div",{className:"mt-1 text-[10px] text-oai-gray-400 dark:text-oai-gray-500",children:r("limits.opencodeGo.setupHint.note_app")})]})]})]})}function Ze(e){const[t,i]=h.useState(0);return h.useLayoutEffect(()=>{const o=e.current;if(!o)return;const n=o.querySelectorAll("[data-limit-label]");let s=0,d=null;if(n.length>0)try{d=document.createElement("canvas").getContext("2d")}catch{d=null}if(d){const l=window.getComputedStyle(n[0]);d.font=`${l.fontStyle} ${l.fontWeight} ${l.fontSize} ${l.fontFamily}`;for(const u of n)s=Math.max(s,d.measureText(u.textContent).width)}const c=Math.ceil(s);i(l=>l===c?l:c)}),t}function et({claude:e,codex:t,cursor:i,gemini:o,kimi:n,kiro:s,grok:d,antigravity:c,copilot:l,zcode:u,opencodeGo:x,qoder:k,order:p,visibility:S,displayMode:X}){const Y={claude:e,codex:t,cursor:i,gemini:o,kimi:n,kiro:s,grok:d,antigravity:c,copilot:l,zcode:u,opencodeGo:x,qoder:k},R=h.useRef(null),C=Ze(R),[J,Q]=h.useState(null),Z=Array.isArray(p)&&p.length>0?p:Ue,T=X===m.REMAINING?m.REMAINING:m.USED,ee=T===m.REMAINING?r("limits.settings.display_mode_remaining"):r("limits.settings.display_mode_used"),A=Z.filter(g=>!S||S[g]!==!1).map(g=>Ye(g,Y[g],T,J===g,()=>Q(te=>te===g?null:g))).filter(Boolean);return a.jsx(ge,{delay:.15,children:a.jsx(U,{children:a.jsxs("div",{ref:R,className:"flex flex-col gap-3",style:C>0?{"--tt-limits-label-w":`${C}px`}:void 0,children:[a.jsxs("h3",{className:"text-sm font-medium text-oai-gray-500 dark:text-oai-gray-300 uppercase tracking-wide",children:[r("limits.panel.title"),r("limits.panel.mode_separator"),ee]}),A.length>0?A:a.jsx(b,{children:r("limits.status.all_hidden")})]})})})}const tt=typeof window<"u"&&(window.location.hostname==="localhost"||window.location.hostname==="127.0.0.1"),at="x-apple.systempreferences:com.apple.preference.notifications";function it(){const e=ve(),t=se(),i=r("limits.alert.blocked"),o=t?D.button:D.div;return a.jsxs(o,{type:t?"button":void 0,onClick:t?()=>le({type:"action",name:"openURL",value:at}):void 0,initial:e?!1:{opacity:0,x:14,scale:.9},animate:{opacity:1,x:0,scale:1},transition:{type:"spring",stiffness:320,damping:18},title:i,className:`relative hidden sm:inline-flex min-w-0 max-w-[360px] items-center gap-1.5 rounded-full border border-amber-300/70 bg-amber-50 px-3 py-1.5 text-xs text-amber-700 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-300 ${t?"cursor-pointer transition-colors hover:bg-amber-100 dark:hover:bg-amber-500/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-500/60":""}`,children:[a.jsxs("span",{className:"relative flex h-1.5 w-1.5 shrink-0",children:[a.jsx("span",{className:"absolute inline-flex h-full w-full animate-ping rounded-full bg-amber-400 opacity-75"}),a.jsx("span",{className:"relative inline-flex h-1.5 w-1.5 rounded-full bg-amber-500"})]}),a.jsx("span",{className:"truncate",children:i}),a.jsx("span",{"aria-hidden":!0,className:"absolute left-full top-1/2 -translate-y-1/2 border-[5px] border-transparent border-l-amber-300/80 dark:border-l-amber-500/40"})]})}function ht(){const e=ae(),{data:t,error:i,isLoading:o}=ue(e?{initialRefresh:!0,initialState:e,publishToPreloadCache:!0}:{initialRefresh:!0,publishToPreloadCache:!0}),n=pe(),s=me();return ie.useEffect(()=>{s.enabled&&t&&xe(t)},[s.enabled,t]),!tt&&!re()?a.jsx("div",{className:"flex flex-col flex-1 text-oai-black dark:text-oai-white font-oai antialiased",children:a.jsx(ke,{})}):a.jsx("div",{className:"flex flex-col flex-1 text-oai-black dark:text-oai-white font-oai antialiased",children:a.jsx("main",{className:"flex-1 pt-8 sm:pt-10 pb-12 sm:pb-16",children:a.jsxs("div",{className:"mx-auto max-w-6xl px-4 sm:px-6",children:[a.jsxs("div",{className:"flex flex-row items-start justify-between gap-4 mb-8",children:[a.jsxs("div",{className:"min-w-0",children:[a.jsx("h1",{className:"text-3xl sm:text-4xl font-semibold tracking-tight text-oai-black dark:text-white mb-3",children:r("nav.limits")}),a.jsx("p",{className:"text-oai-gray-500 dark:text-oai-gray-400 text-sm sm:text-base",children:r("limits.page.subtitle")})]}),a.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[s.enabled&&s.permissionBlocked?a.jsx(it,{}):null,a.jsx("button",{type:"button",onClick:()=>{s.setEnabled(!s.enabled)},"aria-label":s.enabled?r("limits.alert.disable"):r("limits.alert.enable"),title:s.enabled?r("limits.alert.disable"):r("limits.alert.enable"),className:`inline-flex h-9 w-9 items-center justify-center rounded-lg border border-oai-gray-200 dark:border-oai-gray-800 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-800 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-oai-brand-500 ${s.enabled&&s.permissionBlocked?"text-amber-600 dark:text-amber-400":"text-oai-gray-600 dark:text-oai-gray-400 hover:text-oai-black dark:hover:text-white"}`,children:s.enabled?a.jsx(we,{className:"h-4 w-4","aria-hidden":!0}):a.jsx(_e,{className:"h-4 w-4","aria-hidden":!0})}),a.jsx(ne,{to:"/settings?section=limits","aria-label":r("limits.page.openSettings"),title:r("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:a.jsx(oe,{className:"h-4 w-4","aria-hidden":!0})})]})]}),o?a.jsx(Le,{}):a.jsxs(a.Fragment,{children:[i?a.jsx("p",{className:"mb-4 text-sm text-red-500 dark:text-red-400",children:r("shared.error.prefix",{error:i})}):null,a.jsx(et,{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,zcode:t?.zcode,opencodeGo:t?.opencodeGo,qoder:t?.qoder,order:n.order,visibility:n.visibility,displayMode:n.displayMode})]})]})})})}export{ht as LimitsPage};
@@ -1 +0,0 @@
1
- import{j as e,c as t}from"./__vite-browser-external-_-wIz90P.js";import{A as r}from"./arrow-up-right-DksoZ7Fm.js";import{D as o}from"./download-M9hdGe0X.js";const i="https://github.com/mm7894215/TokenTracker/releases/latest";function c(){const a=()=>{try{window.location.href="tokentracker://open"}catch{}};return e.jsx("div",{className:"flex flex-1 flex-col items-center justify-center px-6 py-20 text-center",children:e.jsxs("div",{className:"max-w-md",children:[e.jsx("h2",{className:"text-lg font-semibold text-oai-black dark:text-white",children:t("local_only.title")}),e.jsx("p",{className:"mt-2 text-sm leading-relaxed text-oai-gray-500 dark:text-oai-gray-400",children:t("local_only.body")}),e.jsxs("div",{className:"mt-6 flex flex-wrap items-center justify-center gap-3",children:[e.jsxs("button",{type:"button",onClick:a,className:"inline-flex h-9 items-center gap-1.5 rounded-full px-4 text-sm font-medium bg-oai-gray-900 text-white hover:bg-oai-gray-800 dark:bg-white dark:text-oai-gray-900 dark:hover:bg-oai-gray-100 transition-colors",children:[e.jsx("span",{children:t("local_only.open_app")}),e.jsx(r,{size:14,strokeWidth:2,"aria-hidden":!0})]}),e.jsxs("a",{href:i,target:"_blank",rel:"noopener noreferrer",className:"inline-flex h-9 items-center gap-1.5 rounded-full px-4 text-sm font-medium ring-1 ring-oai-gray-200 dark:ring-oai-gray-800 text-oai-gray-700 dark:text-oai-gray-300 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-900 transition-colors",children:[e.jsx(o,{size:14,strokeWidth:2,"aria-hidden":!0}),e.jsx("span",{children:t("local_only.download")})]})]})]})})}export{c as L};
@@ -1 +0,0 @@
1
- import{r as o}from"./__vite-browser-external-_-wIz90P.js";import{h as r,i as t,p as s}from"./react-BGB0fHad.js";function i(){!r.current&&t();const[e]=o.useState(s.current);return e}export{i as u};