tokentracker-cli 0.83.6 → 0.83.8

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 (163) hide show
  1. package/dashboard/dist/assets/{AchievementBadge-EZ_bFGXa.js → AchievementBadge-CVhNHKpb.js} +1 -1
  2. package/dashboard/dist/assets/{AchievementsPage-Y0k0UVcj.js → AchievementsPage-CgbG_gTv.js} +2 -2
  3. package/dashboard/dist/assets/{AchievementsSection-gNn-Sccq.js → AchievementsSection-Bx6vFwQz.js} +1 -1
  4. package/dashboard/dist/assets/{BadgeDetailModal-D75mcwYT.js → BadgeDetailModal-Usvl2n6F.js} +1 -1
  5. package/dashboard/dist/assets/{Card-NUfQ9HNP.js → Card-B53Y04fc.js} +1 -1
  6. package/dashboard/dist/assets/{ClawdAnimated-BRbE8Q8R.js → ClawdAnimated-BmA7XPg6.js} +1 -1
  7. package/dashboard/dist/assets/{CommandPalette-DvXS8gml.js → CommandPalette-DoPxESGz.js} +1 -1
  8. package/dashboard/dist/assets/{CommunityStatsModal-pMLOCFZw.js → CommunityStatsModal-DrpfFt-f.js} +1 -1
  9. package/dashboard/dist/assets/{ConfirmModal-BFMzzw67.js → ConfirmModal-B9PKshe6.js} +1 -1
  10. package/dashboard/dist/assets/DashboardPage-CTMM_hXz.js +1 -0
  11. package/dashboard/dist/assets/DevicePage-vjjYOiKF.js +1 -0
  12. package/dashboard/dist/assets/{DialogClose-3wNhXinx.js → DialogClose-yWdm6qiH.js} +1 -1
  13. package/dashboard/dist/assets/DialogDescription-CWMyz32A.js +1 -0
  14. package/dashboard/dist/assets/{DialogTitle-Ct8fFe0d.js → DialogTitle-DrHXSoKd.js} +1 -1
  15. package/dashboard/dist/assets/{FadeIn-BlTWjEk_.js → FadeIn-CXYsfy0c.js} +1 -1
  16. package/dashboard/dist/assets/HeaderGithubStar-DiJcy3xs.js +1 -0
  17. package/dashboard/dist/assets/{IpCheckPage-azBefsAB.js → IpCheckPage-BThUN_Lb.js} +1 -1
  18. package/dashboard/dist/assets/{LandingPage-AZUMZfFX.js → LandingPage-DtCtWP7i.js} +2 -2
  19. package/dashboard/dist/assets/{LeaderboardAvatar-CIIx7oE_.js → LeaderboardAvatar-CEyIeJIy.js} +1 -1
  20. package/dashboard/dist/assets/LeaderboardPage-SY-luadv.js +2 -0
  21. package/dashboard/dist/assets/{LeaderboardProfileModal-lCl1juGH.js → LeaderboardProfileModal-Cyib57pI.js} +4 -4
  22. package/dashboard/dist/assets/{LeaderboardProfilePage-BP1ice75.js → LeaderboardProfilePage-C95tq95g.js} +3 -3
  23. package/dashboard/dist/assets/{LimitsPage-BHs9KMMV.js → LimitsPage-DBx649o6.js} +2 -2
  24. package/dashboard/dist/assets/{LocalOnlyNotice-BdlY8imq.js → LocalOnlyNotice-Bml2Sr0e.js} +1 -1
  25. package/dashboard/dist/assets/{LoginCard-BRUrEPfx.js → LoginCard-CJ1vSiXs.js} +1 -1
  26. package/dashboard/dist/assets/{LoginModal-OUppx8M-.js → LoginModal-Qt_1EUWq.js} +1 -1
  27. package/dashboard/dist/assets/{LoginPage-BWBunrTf.js → LoginPage-Bqg9kiqv.js} +1 -1
  28. package/dashboard/dist/assets/{PetPage-DXmShiZi.js → PetPage-BMzM_h1d.js} +1 -1
  29. package/dashboard/dist/assets/{PopoverPopup-CXO-dECR.js → PopoverPopup-DnziJqpr.js} +1 -1
  30. package/dashboard/dist/assets/{ProviderIcon-llJHJlM6.js → ProviderIcon-vH5lKjuw.js} +1 -1
  31. package/dashboard/dist/assets/{ResetPasswordPage-0C8wqcDe.js → ResetPasswordPage-CcJ3RIsg.js} +1 -1
  32. package/dashboard/dist/assets/{Select-C6z5XFfG.js → Select-BI5vIdwQ.js} +1 -1
  33. package/dashboard/dist/assets/{SelectItemText-CFFYsm0E.js → SelectItemText-Gugj_y4f.js} +1 -1
  34. package/dashboard/dist/assets/SettingsPage-C9CTs2jw.js +1 -0
  35. package/dashboard/dist/assets/{SkillsPage-Cgm9uSQc.js → SkillsPage-1Z59oZKe.js} +1 -1
  36. package/dashboard/dist/assets/{TokenGalaxy-BHLK8HTa.js → TokenGalaxy-Dwt_uTjM.js} +1 -1
  37. package/dashboard/dist/assets/TrendMonitor-Cv7KTTBy.js +19 -0
  38. package/dashboard/dist/assets/WidgetsPage-C2a6XGsg.js +1 -0
  39. package/dashboard/dist/assets/WrappedPage-BXqj1X1G.js +1 -0
  40. package/dashboard/dist/assets/__vite-browser-external-BEMfOISl.css +1 -0
  41. package/dashboard/dist/assets/__vite-browser-external-ounIWgVD.js +1418 -0
  42. package/dashboard/dist/assets/{agent-logos-CLPc2PPF.js → agent-logos-DQe_ByDz.js} +1 -1
  43. package/dashboard/dist/assets/{arrow-up-right-BpNverQC.js → arrow-up-right-B70Z9_kp.js} +1 -1
  44. package/dashboard/dist/assets/{check-OAwjmqjx.js → check-Bgp9gUc4.js} +1 -1
  45. package/dashboard/dist/assets/{copy-xACp3XPu.js → copy-CmHwZzAf.js} +1 -1
  46. package/dashboard/dist/assets/{download-DBzAAVuE.js → download-SrGb0psg.js} +1 -1
  47. package/dashboard/dist/assets/{flame-CMyLuKcu.js → flame-gzHssvBI.js} +1 -1
  48. package/dashboard/dist/assets/{format-tokens-DQt23c_Z.js → format-tokens-Cx5HiG8j.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-tqCKNfQb.js → icons-BoFcCRaH.js} +1 -1
  82. package/dashboard/dist/assets/{index-B9uF-lT4.js → index-B5Uo5hBB.js} +1 -1
  83. package/dashboard/dist/assets/{index-zFHCmjHF.js → index-CI9mdiaT.js} +1 -1
  84. package/dashboard/dist/assets/{index-DXdISlgV.js → index-Cx3npmOK.js} +1 -1
  85. package/dashboard/dist/assets/{info-Cf9dDVGg.js → info-6oNE7lgr.js} +1 -1
  86. package/dashboard/dist/assets/{limits-providers-DwTD2qRh.js → limits-providers-yNq34Wte.js} +1 -1
  87. package/dashboard/dist/assets/{link-2-DirFa6Qd.js → link-2-0sgGnuV2.js} +1 -1
  88. package/dashboard/dist/assets/{loader-circle-BaqfyUYe.js → loader-circle-CkdwRbHW.js} +1 -1
  89. package/dashboard/dist/assets/module-Bah3ijPg.js +2 -0
  90. package/dashboard/dist/assets/provider-display-D5N-EIGb.js +42 -0
  91. package/dashboard/dist/assets/{react-TQqv_aZv.js → react-06ETQFHg.js} +1 -1
  92. package/dashboard/dist/assets/skills-api-Dc7mvEQb.js +1 -0
  93. package/dashboard/dist/assets/{terminal-BzeeGl5u.js → terminal-Cl4swf72.js} +1 -1
  94. package/dashboard/dist/assets/{trash-2-BpF9HuIx.js → trash-2-CcXLTSbt.js} +1 -1
  95. package/dashboard/dist/assets/{use-community-stats-DYM36tGa.js → use-community-stats-DjcTzPzV.js} +1 -1
  96. package/dashboard/dist/assets/{use-limits-display-prefs-CA9x1hIh.js → use-limits-display-prefs-iOdmyksX.js} +1 -1
  97. package/dashboard/dist/assets/{use-native-settings-DrFmUbb1.js → use-native-settings-DYzvG6BB.js} +1 -1
  98. package/dashboard/dist/assets/{use-ordered-list-DkxsFCa4.js → use-ordered-list-BvvmM-zv.js} +1 -1
  99. package/dashboard/dist/assets/use-reduced-motion-DU9jOpMZ.js +1 -0
  100. package/dashboard/dist/assets/{use-session-efficiency-pref-CH3-yj76.js → use-session-efficiency-pref-Cr2VfduK.js} +1 -1
  101. package/dashboard/dist/assets/{use-transform-Cg_abBxV.js → use-transform-WhWaB_tE.js} +1 -1
  102. package/dashboard/dist/assets/{use-usage-limits-CIWhPB2s.js → use-usage-limits-5c6FAHCw.js} +1 -1
  103. package/dashboard/dist/assets/{useCurrency-CaldvKOC.js → useCurrency-CvyI7Z7t.js} +1 -1
  104. package/dashboard/dist/assets/{useScrollLock-zwTkEijR.js → useScrollLock-IfyzbX-7.js} +1 -1
  105. package/dashboard/dist/assets/{useTokenFormat-DrEbQlO7.js → useTokenFormat-DBOCm5sY.js} +1 -1
  106. package/dashboard/dist/assets/{zap-DZJCXhYl.js → zap-DcdvNotr.js} +1 -1
  107. package/dashboard/dist/index.html +2 -2
  108. package/dashboard/dist/ip-check.html +2 -2
  109. package/dashboard/dist/leaderboard.html +2 -2
  110. package/dashboard/dist/share.html +2 -2
  111. package/package.json +3 -2
  112. package/src/commands/sync.js +1 -0
  113. package/src/lib/pricing/curated-overrides.json +3 -0
  114. package/src/lib/pricing/matcher.js +27 -0
  115. package/src/lib/pricing/seed-snapshot.json +1 -1
  116. package/src/lib/rollout.js +197 -2
  117. package/dashboard/dist/assets/DashboardPage-D6oQfa7t.js +0 -1
  118. package/dashboard/dist/assets/DevicePage-w-XvCjYG.js +0 -1
  119. package/dashboard/dist/assets/DialogDescription-BIcAn3d1.js +0 -1
  120. package/dashboard/dist/assets/HeaderGithubStar-DL00mO9h.js +0 -1
  121. package/dashboard/dist/assets/LeaderboardPage-But3rYJH.js +0 -2
  122. package/dashboard/dist/assets/SettingsPage-D5sdztJO.js +0 -1
  123. package/dashboard/dist/assets/TrendMonitor-CTnaAoRP.js +0 -19
  124. package/dashboard/dist/assets/WidgetsPage-CCAvcnKW.js +0 -1
  125. package/dashboard/dist/assets/WrappedPage-CA3TSAK4.js +0 -1
  126. package/dashboard/dist/assets/__vite-browser-external-ByIYTB6l.css +0 -1
  127. package/dashboard/dist/assets/__vite-browser-external-D6Ldq3Qx.js +0 -1351
  128. package/dashboard/dist/assets/geist-mono-cyrillic-400-normal-CeA7eGSt.woff +0 -0
  129. package/dashboard/dist/assets/geist-mono-cyrillic-400-normal-DoshcOXv.woff2 +0 -0
  130. package/dashboard/dist/assets/geist-mono-cyrillic-500-normal-BgLpzsdg.woff +0 -0
  131. package/dashboard/dist/assets/geist-mono-cyrillic-500-normal-BkE2O7RC.woff2 +0 -0
  132. package/dashboard/dist/assets/geist-mono-cyrillic-700-normal-4t7P5rT3.woff2 +0 -0
  133. package/dashboard/dist/assets/geist-mono-cyrillic-700-normal-DpJKySxv.woff +0 -0
  134. package/dashboard/dist/assets/geist-mono-cyrillic-900-normal-CVPizhN4.woff2 +0 -0
  135. package/dashboard/dist/assets/geist-mono-cyrillic-900-normal-DDpyx8f0.woff +0 -0
  136. package/dashboard/dist/assets/geist-mono-latin-400-normal-BXAprPdR.woff +0 -0
  137. package/dashboard/dist/assets/geist-mono-latin-400-normal-DKaoCDn5.woff2 +0 -0
  138. package/dashboard/dist/assets/geist-mono-latin-500-normal-C3sF8Y1B.woff2 +0 -0
  139. package/dashboard/dist/assets/geist-mono-latin-500-normal-YfPbDI_o.woff +0 -0
  140. package/dashboard/dist/assets/geist-mono-latin-700-normal-CzSaXH83.woff +0 -0
  141. package/dashboard/dist/assets/geist-mono-latin-700-normal-DMoeyBRY.woff2 +0 -0
  142. package/dashboard/dist/assets/geist-mono-latin-900-normal-DAGlevET.woff +0 -0
  143. package/dashboard/dist/assets/geist-mono-latin-900-normal-DVg4HgZN.woff2 +0 -0
  144. package/dashboard/dist/assets/geist-mono-latin-ext-400-normal-C1xxG8eb.woff2 +0 -0
  145. package/dashboard/dist/assets/geist-mono-latin-ext-400-normal-a1APXIwD.woff +0 -0
  146. package/dashboard/dist/assets/geist-mono-latin-ext-500-normal-CDyCFkgU.woff2 +0 -0
  147. package/dashboard/dist/assets/geist-mono-latin-ext-500-normal-CzSM7th5.woff +0 -0
  148. package/dashboard/dist/assets/geist-mono-latin-ext-700-normal-BG1muzu_.woff2 +0 -0
  149. package/dashboard/dist/assets/geist-mono-latin-ext-700-normal-BmQm3zK6.woff +0 -0
  150. package/dashboard/dist/assets/geist-mono-latin-ext-900-normal-DvYIGD1f.woff2 +0 -0
  151. package/dashboard/dist/assets/geist-mono-latin-ext-900-normal-LB8u5xx5.woff +0 -0
  152. package/dashboard/dist/assets/geist-mono-symbols2-400-normal-B5fXMCGq.woff +0 -0
  153. package/dashboard/dist/assets/geist-mono-symbols2-500-normal-BYvOiszX.woff +0 -0
  154. package/dashboard/dist/assets/geist-mono-symbols2-700-normal-nLp0AmIG.woff +0 -0
  155. package/dashboard/dist/assets/geist-mono-symbols2-900-normal-DPuoOkkO.woff +0 -0
  156. package/dashboard/dist/assets/geist-mono-vietnamese-400-normal-CyOwoevh.woff +0 -0
  157. package/dashboard/dist/assets/geist-mono-vietnamese-500-normal-Do_laDd2.woff +0 -0
  158. package/dashboard/dist/assets/geist-mono-vietnamese-700-normal-DKtT8o3X.woff +0 -0
  159. package/dashboard/dist/assets/geist-mono-vietnamese-900-normal-BAZIExb_.woff +0 -0
  160. package/dashboard/dist/assets/module-kH5GsDis.js +0 -2
  161. package/dashboard/dist/assets/provider-display-Cos1eTis.js +0 -42
  162. package/dashboard/dist/assets/skills-api-BE5MJlc3.js +0 -1
  163. package/dashboard/dist/assets/use-reduced-motion-BxOv0kpO.js +0 -1
@@ -7351,6 +7351,35 @@ function resolveOmpDefaultModel() {
7351
7351
  return "omp-unknown";
7352
7352
  }
7353
7353
 
7354
+ const OMP_HEADER_SCAN_MAX_BYTES = 65536;
7355
+
7356
+ async function resolveOmpFileCwd(filePath) {
7357
+ let stream;
7358
+ try {
7359
+ stream = fssync.createReadStream(filePath, {
7360
+ encoding: "utf8",
7361
+ start: 0,
7362
+ end: OMP_HEADER_SCAN_MAX_BYTES,
7363
+ });
7364
+ } catch {
7365
+ return null;
7366
+ }
7367
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
7368
+ try {
7369
+ for await (const line of rl) {
7370
+ if (!line || !line.includes('"session"')) continue;
7371
+ let entry;
7372
+ try { entry = JSON.parse(line); } catch { continue; }
7373
+ if (entry?.type !== "session") continue;
7374
+ return typeof entry.cwd === "string" && entry.cwd.trim() ? entry.cwd.trim() : null;
7375
+ }
7376
+ } finally {
7377
+ rl.close();
7378
+ stream.close?.();
7379
+ }
7380
+ return null;
7381
+ }
7382
+
7354
7383
  // ─────────────────────────────────────────────────────────────────────────────
7355
7384
  // Kilo Code VS Code extension — passive reader for VS Code-family
7356
7385
  // globalStorage/kilocode.kilo-code/tasks/<uuid>/ui_messages.json files.
@@ -9384,17 +9413,27 @@ async function parseOmpIncremental({
9384
9413
  subagentFiles,
9385
9414
  cursors,
9386
9415
  queuePath,
9416
+ projectQueuePath,
9417
+ publicRepoResolver,
9387
9418
  onProgress,
9388
9419
  env,
9389
9420
  defaultModel,
9390
9421
  } = {}) {
9391
9422
  await ensureDir(path.dirname(queuePath));
9423
+ const projectEnabled = typeof projectQueuePath === "string" && projectQueuePath.length > 0;
9392
9424
  const ompState = cursors.omp && typeof cursors.omp === "object" ? cursors.omp : {};
9393
9425
  const seenIds = new Set(Array.isArray(ompState.seenIds) ? ompState.seenIds : []);
9426
+ const projectSeenIds = new Set(
9427
+ Array.isArray(ompState.projectSeenIds) ? ompState.projectSeenIds : [],
9428
+ );
9394
9429
  const fileOffsets =
9395
9430
  ompState.fileOffsets && typeof ompState.fileOffsets === "object"
9396
9431
  ? { ...ompState.fileOffsets }
9397
9432
  : {};
9433
+ const projectFileOffsets =
9434
+ ompState.projectFileOffsets && typeof ompState.projectFileOffsets === "object"
9435
+ ? { ...ompState.projectFileOffsets }
9436
+ : {};
9398
9437
 
9399
9438
  const mainFiles = Array.isArray(sessionFiles)
9400
9439
  ? sessionFiles
@@ -9416,13 +9455,28 @@ async function parseOmpIncremental({
9416
9455
  ...ompState,
9417
9456
  seenIds: Array.from(seenIds),
9418
9457
  fileOffsets,
9458
+ ...(projectEnabled
9459
+ ? {
9460
+ projectSeenIds: Array.from(projectSeenIds),
9461
+ projectFileOffsets,
9462
+ }
9463
+ : {}),
9419
9464
  updatedAt: new Date().toISOString(),
9420
9465
  };
9421
- return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
9466
+ return {
9467
+ recordsProcessed: 0,
9468
+ eventsAggregated: 0,
9469
+ bucketsQueued: 0,
9470
+ projectBucketsQueued: 0,
9471
+ };
9422
9472
  }
9423
9473
 
9424
9474
  const hourlyState = normalizeHourlyState(cursors?.hourly);
9425
9475
  const touchedBuckets = new Set();
9476
+ const projectState = projectEnabled ? normalizeProjectState(cursors?.projectHourly) : null;
9477
+ const projectTouchedBuckets = projectEnabled ? new Set() : null;
9478
+ const projectMetaCache = projectEnabled ? new Map() : null;
9479
+ const publicRepoCache = projectEnabled ? new Map() : null;
9426
9480
  const cb = typeof onProgress === "function" ? onProgress : null;
9427
9481
  let recordsProcessed = 0;
9428
9482
  let eventsAggregated = 0;
@@ -9552,28 +9606,169 @@ async function parseOmpIncremental({
9552
9606
  };
9553
9607
  }
9554
9608
 
9609
+ // Project attribution has an independent cursor so upgrading an existing
9610
+ // installation can backfill already-consumed OMP sessions without adding
9611
+ // those messages to the total-usage buckets a second time. Current OMP
9612
+ // session headers persist the real cwd; unlike the encoded session folder,
9613
+ // it is lossless even when path components contain dashes.
9614
+ if (projectEnabled) {
9615
+ for (const filePath of files) {
9616
+ let stat;
9617
+ try { stat = fssync.statSync(filePath); } catch { continue; }
9618
+
9619
+ const prevEntry = projectFileOffsets[filePath] || {};
9620
+ const prevSize = Number(prevEntry.size) || 0;
9621
+ const prevIno = prevEntry.ino;
9622
+ const inodeChanged = typeof prevIno === "number" && prevIno !== stat.ino;
9623
+ const startOffset = stat.size < prevSize || inodeChanged ? 0 : prevSize;
9624
+ if (stat.size <= startOffset) continue;
9625
+
9626
+ const cwd = await resolveOmpFileCwd(filePath);
9627
+ const projectContext = cwd
9628
+ ? await resolveProjectContextForPath({
9629
+ startDir: cwd,
9630
+ projectMetaCache,
9631
+ publicRepoCache,
9632
+ publicRepoResolver,
9633
+ projectState,
9634
+ })
9635
+ : null;
9636
+ const projectRef = projectContext?.projectRef || null;
9637
+ const projectKey = projectContext?.projectKey || null;
9638
+
9639
+ if (projectKey && projectRef) {
9640
+ let stream;
9641
+ try {
9642
+ stream = fssync.createReadStream(filePath, {
9643
+ encoding: "utf8",
9644
+ start: startOffset,
9645
+ });
9646
+ } catch {
9647
+ continue;
9648
+ }
9649
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
9650
+ for await (const line of rl) {
9651
+ if (!line || !line.trim()) continue;
9652
+ let entry;
9653
+ try { entry = JSON.parse(line); } catch { continue; }
9654
+ const msg = entry?.type === "message" ? entry.message : null;
9655
+ const usage = msg?.role === "assistant" ? msg.usage : null;
9656
+ if (!usage || typeof usage !== "object") continue;
9657
+
9658
+ const entryId = typeof entry.id === "string" && entry.id ? entry.id : null;
9659
+ if (!entryId || projectSeenIds.has(entryId)) continue;
9660
+
9661
+ const input = toNonNegativeInt(usage.input);
9662
+ const output = toNonNegativeInt(usage.output);
9663
+ const cacheRead = toNonNegativeInt(usage.cacheRead);
9664
+ const cacheWrite = toNonNegativeInt(usage.cacheWrite);
9665
+ const reasoningTokens = toNonNegativeInt(usage.reasoningTokens);
9666
+ if (
9667
+ input === 0 &&
9668
+ output === 0 &&
9669
+ cacheRead === 0 &&
9670
+ cacheWrite === 0 &&
9671
+ reasoningTokens === 0
9672
+ ) {
9673
+ projectSeenIds.add(entryId);
9674
+ continue;
9675
+ }
9676
+
9677
+ let tsMs = null;
9678
+ if (Number.isFinite(Number(msg.timestamp)) && Number(msg.timestamp) > 0) {
9679
+ tsMs = Number(msg.timestamp);
9680
+ } else if (typeof entry.timestamp === "string" && entry.timestamp) {
9681
+ const parsed = Date.parse(entry.timestamp);
9682
+ if (Number.isFinite(parsed) && parsed > 0) tsMs = parsed;
9683
+ }
9684
+ const bucketStart = tsMs == null
9685
+ ? null
9686
+ : toUtcHalfHourStart(new Date(tsMs).toISOString());
9687
+ if (!bucketStart) {
9688
+ projectSeenIds.add(entryId);
9689
+ continue;
9690
+ }
9691
+
9692
+ const totalTokens =
9693
+ Number.isFinite(Number(usage.totalTokens)) && Number(usage.totalTokens) > 0
9694
+ ? toNonNegativeInt(usage.totalTokens)
9695
+ : input + output + cacheRead + cacheWrite + reasoningTokens;
9696
+ const delta = {
9697
+ input_tokens: input,
9698
+ cached_input_tokens: cacheRead,
9699
+ cache_creation_input_tokens: cacheWrite,
9700
+ output_tokens: output,
9701
+ reasoning_output_tokens: reasoningTokens,
9702
+ total_tokens: totalTokens,
9703
+ conversation_count: 1,
9704
+ };
9705
+ const projectBucket = getProjectBucket(
9706
+ projectState,
9707
+ projectKey,
9708
+ "omp",
9709
+ bucketStart,
9710
+ projectRef,
9711
+ );
9712
+ addTotals(projectBucket.totals, delta);
9713
+ projectTouchedBuckets.add(projectBucketKey(projectKey, "omp", bucketStart));
9714
+ projectSeenIds.add(entryId);
9715
+ }
9716
+ }
9717
+
9718
+ let postStat = stat;
9719
+ try { postStat = fssync.statSync(filePath); } catch {}
9720
+ projectFileOffsets[filePath] = {
9721
+ size: postStat.size,
9722
+ mtimeMs: postStat.mtimeMs,
9723
+ ino: postStat.ino,
9724
+ };
9725
+ }
9726
+ }
9727
+
9555
9728
  // Cap dedup set to last 10k IDs to bound cursor state size — same convention
9556
9729
  // as Kimi/CodeBuddy/Copilot so cursors.json doesn't grow unbounded.
9557
9730
  const seenArr = Array.from(seenIds);
9558
9731
  const cappedSeen =
9559
9732
  seenArr.length > 10_000 ? seenArr.slice(seenArr.length - 10_000) : seenArr;
9733
+ const projectSeenArr = Array.from(projectSeenIds);
9734
+ const cappedProjectSeen =
9735
+ projectSeenArr.length > 10_000
9736
+ ? projectSeenArr.slice(projectSeenArr.length - 10_000)
9737
+ : projectSeenArr;
9560
9738
 
9561
9739
  const bucketsQueued = await enqueueTouchedBuckets({
9562
9740
  queuePath,
9563
9741
  hourlyState,
9564
9742
  touchedBuckets,
9565
9743
  });
9744
+ const projectBucketsQueued = projectEnabled
9745
+ ? await enqueueTouchedProjectBuckets({
9746
+ projectQueuePath,
9747
+ projectState,
9748
+ projectTouchedBuckets,
9749
+ })
9750
+ : 0;
9566
9751
  const updatedAt = new Date().toISOString();
9567
9752
  hourlyState.updatedAt = updatedAt;
9568
9753
  cursors.hourly = hourlyState;
9754
+ if (projectState) {
9755
+ projectState.updatedAt = updatedAt;
9756
+ cursors.projectHourly = projectState;
9757
+ }
9569
9758
  cursors.omp = {
9570
9759
  ...ompState,
9571
9760
  seenIds: cappedSeen,
9572
9761
  fileOffsets,
9762
+ ...(projectEnabled
9763
+ ? {
9764
+ projectSeenIds: cappedProjectSeen,
9765
+ projectFileOffsets,
9766
+ }
9767
+ : {}),
9573
9768
  updatedAt,
9574
9769
  };
9575
9770
 
9576
- return { recordsProcessed, eventsAggregated, bucketsQueued };
9771
+ return { recordsProcessed, eventsAggregated, bucketsQueued, projectBucketsQueued };
9577
9772
  }
9578
9773
 
9579
9774
  // ─────────────────────────────────────────────────────────────────────────────