botmux 3.10.0 → 3.11.0

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 (539) hide show
  1. package/dist/.runtime-build-id +1 -1
  2. package/dist/adapters/backend/herdr-backend.d.ts +4 -3
  3. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  4. package/dist/adapters/backend/herdr-backend.js +11 -8
  5. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  6. package/dist/adapters/backend/pty-backend.d.ts +1 -1
  7. package/dist/adapters/backend/pty-backend.d.ts.map +1 -1
  8. package/dist/adapters/backend/pty-backend.js +4 -1
  9. package/dist/adapters/backend/pty-backend.js.map +1 -1
  10. package/dist/adapters/backend/riff-backend.d.ts +29 -5
  11. package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
  12. package/dist/adapters/backend/riff-backend.js +302 -31
  13. package/dist/adapters/backend/riff-backend.js.map +1 -1
  14. package/dist/adapters/backend/sandbox.d.ts +6 -0
  15. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  16. package/dist/adapters/backend/sandbox.js +7 -0
  17. package/dist/adapters/backend/sandbox.js.map +1 -1
  18. package/dist/adapters/backend/tmux-backend.d.ts +1 -1
  19. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  20. package/dist/adapters/backend/tmux-backend.js +4 -1
  21. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  22. package/dist/adapters/backend/tmux-pipe-backend.d.ts +1 -1
  23. package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
  24. package/dist/adapters/backend/tmux-pipe-backend.js +1 -1
  25. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  26. package/dist/adapters/backend/types.d.ts +37 -3
  27. package/dist/adapters/backend/types.d.ts.map +1 -1
  28. package/dist/adapters/backend/types.js.map +1 -1
  29. package/dist/adapters/backend/zellij-backend.d.ts +3 -3
  30. package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
  31. package/dist/adapters/backend/zellij-backend.js +9 -3
  32. package/dist/adapters/backend/zellij-backend.js.map +1 -1
  33. package/dist/adapters/backend/zellij-observe-backend.d.ts +3 -3
  34. package/dist/adapters/backend/zellij-observe-backend.d.ts.map +1 -1
  35. package/dist/adapters/backend/zellij-observe-backend.js +12 -7
  36. package/dist/adapters/backend/zellij-observe-backend.js.map +1 -1
  37. package/dist/adapters/cli/codex-app.d.ts.map +1 -1
  38. package/dist/adapters/cli/codex-app.js +11 -2
  39. package/dist/adapters/cli/codex-app.js.map +1 -1
  40. package/dist/adapters/cli/read-isolation.d.ts +35 -2
  41. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  42. package/dist/adapters/cli/read-isolation.js +88 -7
  43. package/dist/adapters/cli/read-isolation.js.map +1 -1
  44. package/dist/adapters/cli/runner-input.d.ts +15 -14
  45. package/dist/adapters/cli/runner-input.d.ts.map +1 -1
  46. package/dist/adapters/cli/runner-input.js +64 -26
  47. package/dist/adapters/cli/runner-input.js.map +1 -1
  48. package/dist/adapters/cli/types.d.ts +20 -5
  49. package/dist/adapters/cli/types.d.ts.map +1 -1
  50. package/dist/bot-registry.d.ts +24 -0
  51. package/dist/bot-registry.d.ts.map +1 -1
  52. package/dist/bot-registry.js +110 -5
  53. package/dist/bot-registry.js.map +1 -1
  54. package/dist/cli/fleet-shutdown.d.ts +47 -0
  55. package/dist/cli/fleet-shutdown.d.ts.map +1 -0
  56. package/dist/cli/fleet-shutdown.js +387 -0
  57. package/dist/cli/fleet-shutdown.js.map +1 -0
  58. package/dist/cli/pm2-descriptor-guard.d.ts +19 -0
  59. package/dist/cli/pm2-descriptor-guard.d.ts.map +1 -0
  60. package/dist/cli/pm2-descriptor-guard.js +122 -0
  61. package/dist/cli/pm2-descriptor-guard.js.map +1 -0
  62. package/dist/cli/pm2-exact-start.d.ts +16 -0
  63. package/dist/cli/pm2-exact-start.d.ts.map +1 -0
  64. package/dist/cli/pm2-exact-start.js +63 -0
  65. package/dist/cli/pm2-exact-start.js.map +1 -0
  66. package/dist/cli/pm2-god-admission.d.ts +8 -0
  67. package/dist/cli/pm2-god-admission.d.ts.map +1 -0
  68. package/dist/cli/pm2-god-admission.js +25 -0
  69. package/dist/cli/pm2-god-admission.js.map +1 -0
  70. package/dist/cli/pm2-jlist.d.ts +13 -0
  71. package/dist/cli/pm2-jlist.d.ts.map +1 -0
  72. package/dist/cli/pm2-jlist.js +108 -0
  73. package/dist/cli/pm2-jlist.js.map +1 -0
  74. package/dist/cli/pm2-preflight.d.ts +10 -0
  75. package/dist/cli/pm2-preflight.d.ts.map +1 -0
  76. package/dist/cli/pm2-preflight.js +23 -0
  77. package/dist/cli/pm2-preflight.js.map +1 -0
  78. package/dist/cli/pm2-shutdown-capability.d.ts +27 -0
  79. package/dist/cli/pm2-shutdown-capability.d.ts.map +1 -0
  80. package/dist/cli/pm2-shutdown-capability.js +161 -0
  81. package/dist/cli/pm2-shutdown-capability.js.map +1 -0
  82. package/dist/cli/pm2-start-transaction.d.ts +55 -0
  83. package/dist/cli/pm2-start-transaction.d.ts.map +1 -0
  84. package/dist/cli/pm2-start-transaction.js +220 -0
  85. package/dist/cli/pm2-start-transaction.js.map +1 -0
  86. package/dist/cli/send-dispatch.d.ts +12 -0
  87. package/dist/cli/send-dispatch.d.ts.map +1 -1
  88. package/dist/cli/send-dispatch.js +31 -4
  89. package/dist/cli/send-dispatch.js.map +1 -1
  90. package/dist/cli/session-list-liveness.d.ts +1 -0
  91. package/dist/cli/session-list-liveness.d.ts.map +1 -1
  92. package/dist/cli/session-list-liveness.js +6 -0
  93. package/dist/cli/session-list-liveness.js.map +1 -1
  94. package/dist/cli/session-picker-layout.d.ts +26 -0
  95. package/dist/cli/session-picker-layout.d.ts.map +1 -0
  96. package/dist/cli/session-picker-layout.js +123 -0
  97. package/dist/cli/session-picker-layout.js.map +1 -0
  98. package/dist/cli/session-picker-viewport.d.ts +49 -0
  99. package/dist/cli/session-picker-viewport.d.ts.map +1 -0
  100. package/dist/cli/session-picker-viewport.js +46 -0
  101. package/dist/cli/session-picker-viewport.js.map +1 -0
  102. package/dist/cli/supervisor-shutdown-client.d.ts +31 -0
  103. package/dist/cli/supervisor-shutdown-client.d.ts.map +1 -0
  104. package/dist/cli/supervisor-shutdown-client.js +146 -0
  105. package/dist/cli/supervisor-shutdown-client.js.map +1 -0
  106. package/dist/cli/terminal-width.d.ts +48 -0
  107. package/dist/cli/terminal-width.d.ts.map +1 -0
  108. package/dist/cli/terminal-width.js +119 -0
  109. package/dist/cli/terminal-width.js.map +1 -0
  110. package/dist/cli/vc-agent.d.ts.map +1 -1
  111. package/dist/cli/vc-agent.js +1 -1
  112. package/dist/cli/vc-agent.js.map +1 -1
  113. package/dist/cli.d.ts.map +1 -1
  114. package/dist/cli.js +2269 -716
  115. package/dist/cli.js.map +1 -1
  116. package/dist/codex-app-runner.js +1630 -125
  117. package/dist/codex-app-runner.js.map +1 -1
  118. package/dist/core/ask-api.d.ts +8 -1
  119. package/dist/core/ask-api.d.ts.map +1 -1
  120. package/dist/core/ask-api.js +18 -0
  121. package/dist/core/ask-api.js.map +1 -1
  122. package/dist/core/ask-broker.d.ts +20 -0
  123. package/dist/core/ask-broker.d.ts.map +1 -1
  124. package/dist/core/ask-broker.js +467 -47
  125. package/dist/core/ask-broker.js.map +1 -1
  126. package/dist/core/ask-persist-store.d.ts +126 -0
  127. package/dist/core/ask-persist-store.d.ts.map +1 -0
  128. package/dist/core/ask-persist-store.js +188 -0
  129. package/dist/core/ask-persist-store.js.map +1 -0
  130. package/dist/core/ask-types.d.ts +80 -0
  131. package/dist/core/ask-types.d.ts.map +1 -1
  132. package/dist/core/ask-types.js +62 -0
  133. package/dist/core/ask-types.js.map +1 -1
  134. package/dist/core/cli-session-id-publisher.d.ts +20 -0
  135. package/dist/core/cli-session-id-publisher.d.ts.map +1 -0
  136. package/dist/core/cli-session-id-publisher.js +21 -0
  137. package/dist/core/cli-session-id-publisher.js.map +1 -0
  138. package/dist/core/command-handler.d.ts.map +1 -1
  139. package/dist/core/command-handler.js +427 -255
  140. package/dist/core/command-handler.js.map +1 -1
  141. package/dist/core/cost-calculator.d.ts +13 -0
  142. package/dist/core/cost-calculator.d.ts.map +1 -1
  143. package/dist/core/cost-calculator.js +385 -26
  144. package/dist/core/cost-calculator.js.map +1 -1
  145. package/dist/core/dashboard-ipc-server.d.ts +9 -0
  146. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  147. package/dist/core/dashboard-ipc-server.js +842 -288
  148. package/dist/core/dashboard-ipc-server.js.map +1 -1
  149. package/dist/core/explicit-session-backing-cleanup.d.ts +49 -0
  150. package/dist/core/explicit-session-backing-cleanup.d.ts.map +1 -0
  151. package/dist/core/explicit-session-backing-cleanup.js +76 -0
  152. package/dist/core/explicit-session-backing-cleanup.js.map +1 -0
  153. package/dist/core/idle-worker-sweeper.d.ts +20 -0
  154. package/dist/core/idle-worker-sweeper.d.ts.map +1 -1
  155. package/dist/core/idle-worker-sweeper.js +18 -0
  156. package/dist/core/idle-worker-sweeper.js.map +1 -1
  157. package/dist/core/inflight-input-tracker.d.ts +10 -0
  158. package/dist/core/inflight-input-tracker.d.ts.map +1 -1
  159. package/dist/core/inflight-input-tracker.js +7 -0
  160. package/dist/core/inflight-input-tracker.js.map +1 -1
  161. package/dist/core/managed-origin-attestation.d.ts +51 -0
  162. package/dist/core/managed-origin-attestation.d.ts.map +1 -0
  163. package/dist/core/managed-origin-attestation.js +208 -0
  164. package/dist/core/managed-origin-attestation.js.map +1 -0
  165. package/dist/core/managed-origin-capability.d.ts +62 -3
  166. package/dist/core/managed-origin-capability.d.ts.map +1 -1
  167. package/dist/core/managed-origin-capability.js +419 -9
  168. package/dist/core/managed-origin-capability.js.map +1 -1
  169. package/dist/core/pending-repo-journal.d.ts +6 -0
  170. package/dist/core/pending-repo-journal.d.ts.map +1 -0
  171. package/dist/core/pending-repo-journal.js +85 -0
  172. package/dist/core/pending-repo-journal.js.map +1 -0
  173. package/dist/core/persistent-backend.d.ts +6 -1
  174. package/dist/core/persistent-backend.d.ts.map +1 -1
  175. package/dist/core/persistent-backend.js +12 -6
  176. package/dist/core/persistent-backend.js.map +1 -1
  177. package/dist/core/process-start-identity.d.ts +3 -0
  178. package/dist/core/process-start-identity.d.ts.map +1 -0
  179. package/dist/core/process-start-identity.js +62 -0
  180. package/dist/core/process-start-identity.js.map +1 -0
  181. package/dist/core/raw-command-writer.d.ts +34 -0
  182. package/dist/core/raw-command-writer.d.ts.map +1 -0
  183. package/dist/core/raw-command-writer.js +48 -0
  184. package/dist/core/raw-command-writer.js.map +1 -0
  185. package/dist/core/reply-target.d.ts +85 -22
  186. package/dist/core/reply-target.d.ts.map +1 -1
  187. package/dist/core/reply-target.js +267 -32
  188. package/dist/core/reply-target.js.map +1 -1
  189. package/dist/core/resource-monitor/runtime.d.ts.map +1 -1
  190. package/dist/core/resource-monitor/runtime.js +4 -1
  191. package/dist/core/resource-monitor/runtime.js.map +1 -1
  192. package/dist/core/restart-report.d.ts +6 -1
  193. package/dist/core/restart-report.d.ts.map +1 -1
  194. package/dist/core/restart-report.js +22 -4
  195. package/dist/core/restart-report.js.map +1 -1
  196. package/dist/core/riff-shutdown-detach.d.ts +164 -0
  197. package/dist/core/riff-shutdown-detach.d.ts.map +1 -0
  198. package/dist/core/riff-shutdown-detach.js +787 -0
  199. package/dist/core/riff-shutdown-detach.js.map +1 -0
  200. package/dist/core/riff-worker-shutdown-readiness.d.ts +17 -0
  201. package/dist/core/riff-worker-shutdown-readiness.d.ts.map +1 -0
  202. package/dist/core/riff-worker-shutdown-readiness.js +21 -0
  203. package/dist/core/riff-worker-shutdown-readiness.js.map +1 -0
  204. package/dist/core/session-manager.d.ts +6 -6
  205. package/dist/core/session-manager.d.ts.map +1 -1
  206. package/dist/core/session-manager.js +1227 -594
  207. package/dist/core/session-manager.js.map +1 -1
  208. package/dist/core/session-marker.d.ts +1 -1
  209. package/dist/core/session-marker.d.ts.map +1 -1
  210. package/dist/core/session-marker.js +2 -2
  211. package/dist/core/session-marker.js.map +1 -1
  212. package/dist/core/session-mutation-guard.d.ts +17 -0
  213. package/dist/core/session-mutation-guard.d.ts.map +1 -0
  214. package/dist/core/session-mutation-guard.js +33 -0
  215. package/dist/core/session-mutation-guard.js.map +1 -0
  216. package/dist/core/shutdown-budgets.d.ts +27 -0
  217. package/dist/core/shutdown-budgets.d.ts.map +1 -0
  218. package/dist/core/shutdown-budgets.js +47 -0
  219. package/dist/core/shutdown-budgets.js.map +1 -0
  220. package/dist/core/supervisor-shutdown-ipc.d.ts +10 -0
  221. package/dist/core/supervisor-shutdown-ipc.d.ts.map +1 -0
  222. package/dist/core/supervisor-shutdown-ipc.js +10 -0
  223. package/dist/core/supervisor-shutdown-ipc.js.map +1 -0
  224. package/dist/core/supervisor-shutdown-protocol.d.ts +16 -0
  225. package/dist/core/supervisor-shutdown-protocol.d.ts.map +1 -0
  226. package/dist/core/supervisor-shutdown-protocol.js +16 -0
  227. package/dist/core/supervisor-shutdown-protocol.js.map +1 -0
  228. package/dist/core/trigger-final-suppression.d.ts +4 -0
  229. package/dist/core/trigger-final-suppression.d.ts.map +1 -1
  230. package/dist/core/trigger-final-suppression.js +6 -11
  231. package/dist/core/trigger-final-suppression.js.map +1 -1
  232. package/dist/core/trigger-session.d.ts +70 -0
  233. package/dist/core/trigger-session.d.ts.map +1 -1
  234. package/dist/core/trigger-session.js +923 -145
  235. package/dist/core/trigger-session.js.map +1 -1
  236. package/dist/core/types.d.ts +94 -1
  237. package/dist/core/types.d.ts.map +1 -1
  238. package/dist/core/types.js +9 -0
  239. package/dist/core/types.js.map +1 -1
  240. package/dist/core/worker-pool.d.ts +194 -13
  241. package/dist/core/worker-pool.d.ts.map +1 -1
  242. package/dist/core/worker-pool.js +2597 -547
  243. package/dist/core/worker-pool.js.map +1 -1
  244. package/dist/daemon.d.ts +76 -2
  245. package/dist/daemon.d.ts.map +1 -1
  246. package/dist/daemon.js +2255 -773
  247. package/dist/daemon.js.map +1 -1
  248. package/dist/dashboard/bot-payload.d.ts +20 -0
  249. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  250. package/dist/dashboard/bot-payload.js +24 -0
  251. package/dist/dashboard/bot-payload.js.map +1 -1
  252. package/dist/dashboard/feed-groups.d.ts +17 -0
  253. package/dist/dashboard/feed-groups.d.ts.map +1 -0
  254. package/dist/dashboard/feed-groups.js +75 -0
  255. package/dist/dashboard/feed-groups.js.map +1 -0
  256. package/dist/dashboard/session-card-model.d.ts +1 -1
  257. package/dist/dashboard/session-card-model.d.ts.map +1 -1
  258. package/dist/dashboard/session-card-model.js +8 -5
  259. package/dist/dashboard/session-card-model.js.map +1 -1
  260. package/dist/dashboard/web/bot-defaults-page.d.ts +4 -0
  261. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  262. package/dist/dashboard/web/bot-defaults-page.js +139 -46
  263. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  264. package/dist/dashboard/web/bot-defaults.d.ts +4 -0
  265. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  266. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  267. package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
  268. package/dist/dashboard/web/connectors-page.js +40 -3
  269. package/dist/dashboard/web/connectors-page.js.map +1 -1
  270. package/dist/dashboard/web/groups-page.d.ts.map +1 -1
  271. package/dist/dashboard/web/groups-page.js +95 -2
  272. package/dist/dashboard/web/groups-page.js.map +1 -1
  273. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  274. package/dist/dashboard/web/i18n.js +86 -40
  275. package/dist/dashboard/web/i18n.js.map +1 -1
  276. package/dist/dashboard/web/kanban-model.js +1 -1
  277. package/dist/dashboard/web/kanban-model.js.map +1 -1
  278. package/dist/dashboard/web/overview-page.d.ts.map +1 -1
  279. package/dist/dashboard/web/overview-page.js +3 -2
  280. package/dist/dashboard/web/overview-page.js.map +1 -1
  281. package/dist/dashboard/web/overview.d.ts +3 -0
  282. package/dist/dashboard/web/overview.d.ts.map +1 -1
  283. package/dist/dashboard/web/overview.js +2 -0
  284. package/dist/dashboard/web/overview.js.map +1 -1
  285. package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -1
  286. package/dist/dashboard/web/sessions-kanban.js +2 -0
  287. package/dist/dashboard/web/sessions-kanban.js.map +1 -1
  288. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  289. package/dist/dashboard/web/sessions-page.js +103 -2
  290. package/dist/dashboard/web/sessions-page.js.map +1 -1
  291. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  292. package/dist/dashboard/web/sessions.js +3 -2
  293. package/dist/dashboard/web/sessions.js.map +1 -1
  294. package/dist/dashboard/web/ui.d.ts +8 -0
  295. package/dist/dashboard/web/ui.d.ts.map +1 -1
  296. package/dist/dashboard/web/ui.js +15 -0
  297. package/dist/dashboard/web/ui.js.map +1 -1
  298. package/dist/dashboard-web/app.js +1 -1
  299. package/dist/dashboard-web/chunks/bot-defaults-page-GED4FEMS.js +10 -0
  300. package/dist/dashboard-web/chunks/chunk-6J5LS5AU.js +51 -0
  301. package/dist/dashboard-web/chunks/{chunk-ZU3UUKAR.js → chunk-HK7NIBJG.js} +1 -1
  302. package/dist/dashboard-web/chunks/{chunk-3UE7S77S.js → chunk-KRHWZEXU.js} +1 -1
  303. package/dist/dashboard-web/chunks/chunk-VBXJOJFH.js +1 -0
  304. package/dist/dashboard-web/chunks/connectors-page-EELM66G3.js +1 -0
  305. package/dist/dashboard-web/chunks/groups-page-WKUV6E42.js +8 -0
  306. package/dist/dashboard-web/chunks/{insights-page-T2ZX2RWL.js → insights-page-54UBPPOC.js} +1 -1
  307. package/dist/dashboard-web/chunks/{monitor-room-YNVBAGR6.js → monitor-room-PORHVKRH.js} +1 -1
  308. package/dist/dashboard-web/chunks/{monitoring-page-LHM55YWN.js → monitoring-page-XGA7AXNL.js} +1 -1
  309. package/dist/dashboard-web/chunks/{office-page-ATXVP7PW.js → office-page-AO3AFG45.js} +1 -1
  310. package/dist/dashboard-web/chunks/overview-page-F5BUTYR6.js +1 -0
  311. package/dist/dashboard-web/chunks/{roles-page-56VWM6CD.js → roles-page-M5GIASJU.js} +1 -1
  312. package/dist/dashboard-web/chunks/{schedules-page-S5K6U4EO.js → schedules-page-O232WQRR.js} +1 -1
  313. package/dist/dashboard-web/chunks/sessions-page-YFRPSTIL.js +6 -0
  314. package/dist/dashboard-web/chunks/{settings-page-QUZDQARR.js → settings-page-OJAZLZQT.js} +1 -1
  315. package/dist/dashboard-web/chunks/{skills-page-IFY7AEND.js → skills-page-EFZQPWV4.js} +1 -1
  316. package/dist/dashboard-web/chunks/{team-federation-page-C7FJQPFZ.js → team-federation-page-ZJVAP7HW.js} +1 -1
  317. package/dist/dashboard-web/chunks/{v3-page-2LMF3WWR.js → v3-page-GYWTRGO2.js} +1 -1
  318. package/dist/dashboard-web/chunks/{whiteboards-page-3XC6QRMY.js → whiteboards-page-MSDAG6P7.js} +1 -1
  319. package/dist/dashboard-web/style.css +255 -0
  320. package/dist/dashboard.js +172 -7
  321. package/dist/dashboard.js.map +1 -1
  322. package/dist/desktop/renderer/app.js +21 -0
  323. package/dist/desktop/renderer/app.js.map +1 -1
  324. package/dist/i18n/en.d.ts.map +1 -1
  325. package/dist/i18n/en.js +35 -9
  326. package/dist/i18n/en.js.map +1 -1
  327. package/dist/i18n/zh.d.ts.map +1 -1
  328. package/dist/i18n/zh.js +35 -9
  329. package/dist/i18n/zh.js.map +1 -1
  330. package/dist/im/lark/ask-card.d.ts +23 -0
  331. package/dist/im/lark/ask-card.d.ts.map +1 -1
  332. package/dist/im/lark/ask-card.js +94 -4
  333. package/dist/im/lark/ask-card.js.map +1 -1
  334. package/dist/im/lark/card-builder.d.ts +6 -1
  335. package/dist/im/lark/card-builder.d.ts.map +1 -1
  336. package/dist/im/lark/card-builder.js +112 -15
  337. package/dist/im/lark/card-builder.js.map +1 -1
  338. package/dist/im/lark/card-handler.d.ts +1 -1
  339. package/dist/im/lark/card-handler.d.ts.map +1 -1
  340. package/dist/im/lark/card-handler.js +496 -310
  341. package/dist/im/lark/card-handler.js.map +1 -1
  342. package/dist/im/lark/client.d.ts +7 -0
  343. package/dist/im/lark/client.d.ts.map +1 -1
  344. package/dist/im/lark/client.js +39 -26
  345. package/dist/im/lark/client.js.map +1 -1
  346. package/dist/im/lark/doc-comment.d.ts +7 -4
  347. package/dist/im/lark/doc-comment.d.ts.map +1 -1
  348. package/dist/im/lark/doc-comment.js +19 -6
  349. package/dist/im/lark/doc-comment.js.map +1 -1
  350. package/dist/im/lark/event-dispatcher.d.ts +16 -0
  351. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  352. package/dist/im/lark/event-dispatcher.js +88 -23
  353. package/dist/im/lark/event-dispatcher.js.map +1 -1
  354. package/dist/im/lark/forward-followup-content.d.ts.map +1 -1
  355. package/dist/im/lark/forward-followup-content.js +9 -1
  356. package/dist/im/lark/forward-followup-content.js.map +1 -1
  357. package/dist/im/lark/grant-command.d.ts.map +1 -1
  358. package/dist/im/lark/grant-command.js +7 -4
  359. package/dist/im/lark/grant-command.js.map +1 -1
  360. package/dist/im/lark/md-card.d.ts +11 -0
  361. package/dist/im/lark/md-card.d.ts.map +1 -1
  362. package/dist/im/lark/md-card.js +46 -0
  363. package/dist/im/lark/md-card.js.map +1 -1
  364. package/dist/im/lark/message-parser.d.ts +23 -2
  365. package/dist/im/lark/message-parser.d.ts.map +1 -1
  366. package/dist/im/lark/message-parser.js +58 -3
  367. package/dist/im/lark/message-parser.js.map +1 -1
  368. package/dist/im/lark/overview-card.d.ts.map +1 -1
  369. package/dist/im/lark/overview-card.js +2 -1
  370. package/dist/im/lark/overview-card.js.map +1 -1
  371. package/dist/services/async-trigger-state.d.ts +6 -1
  372. package/dist/services/async-trigger-state.d.ts.map +1 -1
  373. package/dist/services/async-trigger-state.js +21 -0
  374. package/dist/services/async-trigger-state.js.map +1 -1
  375. package/dist/services/async-trigger-store.d.ts +23 -1
  376. package/dist/services/async-trigger-store.d.ts.map +1 -1
  377. package/dist/services/async-trigger-store.js +96 -13
  378. package/dist/services/async-trigger-store.js.map +1 -1
  379. package/dist/services/bridge-fallback-gate.d.ts +40 -0
  380. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  381. package/dist/services/bridge-fallback-gate.js +124 -24
  382. package/dist/services/bridge-fallback-gate.js.map +1 -1
  383. package/dist/services/codex-app-runner-protocol.d.ts +8 -0
  384. package/dist/services/codex-app-runner-protocol.d.ts.map +1 -1
  385. package/dist/services/codex-app-runner-protocol.js +9 -2
  386. package/dist/services/codex-app-runner-protocol.js.map +1 -1
  387. package/dist/services/codex-bridge-queue.d.ts +1 -0
  388. package/dist/services/codex-bridge-queue.d.ts.map +1 -1
  389. package/dist/services/codex-bridge-queue.js +1 -0
  390. package/dist/services/codex-bridge-queue.js.map +1 -1
  391. package/dist/services/codex-service-tier.d.ts +2 -0
  392. package/dist/services/codex-service-tier.d.ts.map +1 -1
  393. package/dist/services/codex-service-tier.js +1 -0
  394. package/dist/services/codex-service-tier.js.map +1 -1
  395. package/dist/services/codex-transcript.d.ts +27 -0
  396. package/dist/services/codex-transcript.d.ts.map +1 -1
  397. package/dist/services/codex-transcript.js +340 -2
  398. package/dist/services/codex-transcript.js.map +1 -1
  399. package/dist/services/grant-policy.d.ts +3 -0
  400. package/dist/services/grant-policy.d.ts.map +1 -1
  401. package/dist/services/grant-policy.js +5 -0
  402. package/dist/services/grant-policy.js.map +1 -1
  403. package/dist/services/grant-prefs-store.d.ts +6 -3
  404. package/dist/services/grant-prefs-store.d.ts.map +1 -1
  405. package/dist/services/grant-prefs-store.js +42 -12
  406. package/dist/services/grant-prefs-store.js.map +1 -1
  407. package/dist/services/hook-runner.d.ts +20 -1
  408. package/dist/services/hook-runner.d.ts.map +1 -1
  409. package/dist/services/hook-runner.js +17 -13
  410. package/dist/services/hook-runner.js.map +1 -1
  411. package/dist/services/idempotency-store.d.ts +134 -0
  412. package/dist/services/idempotency-store.d.ts.map +1 -0
  413. package/dist/services/idempotency-store.js +299 -0
  414. package/dist/services/idempotency-store.js.map +1 -0
  415. package/dist/services/jsonl-cursor.d.ts +7 -3
  416. package/dist/services/jsonl-cursor.d.ts.map +1 -1
  417. package/dist/services/jsonl-cursor.js +55 -31
  418. package/dist/services/jsonl-cursor.js.map +1 -1
  419. package/dist/services/open-platform-rename.d.ts.map +1 -1
  420. package/dist/services/open-platform-rename.js +1 -108
  421. package/dist/services/open-platform-rename.js.map +1 -1
  422. package/dist/services/restart-intent-store.d.ts +22 -2
  423. package/dist/services/restart-intent-store.d.ts.map +1 -1
  424. package/dist/services/restart-intent-store.js +160 -18
  425. package/dist/services/restart-intent-store.js.map +1 -1
  426. package/dist/services/sandbox-store.d.ts +22 -0
  427. package/dist/services/sandbox-store.d.ts.map +1 -1
  428. package/dist/services/sandbox-store.js +37 -8
  429. package/dist/services/sandbox-store.js.map +1 -1
  430. package/dist/services/send-policy.d.ts +41 -33
  431. package/dist/services/send-policy.d.ts.map +1 -1
  432. package/dist/services/send-policy.js +39 -40
  433. package/dist/services/send-policy.js.map +1 -1
  434. package/dist/services/session-store.d.ts +66 -0
  435. package/dist/services/session-store.d.ts.map +1 -1
  436. package/dist/services/session-store.js +403 -67
  437. package/dist/services/session-store.js.map +1 -1
  438. package/dist/services/submit-notification.d.ts +3 -0
  439. package/dist/services/submit-notification.d.ts.map +1 -0
  440. package/dist/services/submit-notification.js +15 -0
  441. package/dist/services/submit-notification.js.map +1 -0
  442. package/dist/services/traex-transcript.d.ts +25 -2
  443. package/dist/services/traex-transcript.d.ts.map +1 -1
  444. package/dist/services/traex-transcript.js +133 -1
  445. package/dist/services/traex-transcript.js.map +1 -1
  446. package/dist/services/trigger-types.d.ts +13 -1
  447. package/dist/services/trigger-types.d.ts.map +1 -1
  448. package/dist/services/trigger-types.js +39 -0
  449. package/dist/services/trigger-types.js.map +1 -1
  450. package/dist/services/voice/index.d.ts +3 -2
  451. package/dist/services/voice/index.d.ts.map +1 -1
  452. package/dist/services/voice/index.js +5 -5
  453. package/dist/services/voice/index.js.map +1 -1
  454. package/dist/services/voice/openai.d.ts +2 -1
  455. package/dist/services/voice/openai.d.ts.map +1 -1
  456. package/dist/services/voice/openai.js +2 -1
  457. package/dist/services/voice/openai.js.map +1 -1
  458. package/dist/services/voice/sami.d.ts +5 -2
  459. package/dist/services/voice/sami.d.ts.map +1 -1
  460. package/dist/services/voice/sami.js +19 -4
  461. package/dist/services/voice/sami.js.map +1 -1
  462. package/dist/setup/bots-store.d.ts.map +1 -1
  463. package/dist/setup/bots-store.js +10 -4
  464. package/dist/setup/bots-store.js.map +1 -1
  465. package/dist/setup/lark-scopes.json +2 -0
  466. package/dist/setup/open-platform-automation.d.ts +9 -1
  467. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  468. package/dist/setup/open-platform-automation.js +44 -15
  469. package/dist/setup/open-platform-automation.js.map +1 -1
  470. package/dist/setup/open-platform-visibility.d.ts +42 -0
  471. package/dist/setup/open-platform-visibility.d.ts.map +1 -0
  472. package/dist/setup/open-platform-visibility.js +133 -0
  473. package/dist/setup/open-platform-visibility.js.map +1 -0
  474. package/dist/setup/verify-permissions.d.ts.map +1 -1
  475. package/dist/setup/verify-permissions.js +6 -0
  476. package/dist/setup/verify-permissions.js.map +1 -1
  477. package/dist/skills/definitions.js +2 -2
  478. package/dist/types.d.ts +290 -13
  479. package/dist/types.d.ts.map +1 -1
  480. package/dist/utils/bot-routing.d.ts +1 -0
  481. package/dist/utils/bot-routing.d.ts.map +1 -1
  482. package/dist/utils/bot-routing.js +1 -1
  483. package/dist/utils/bot-routing.js.map +1 -1
  484. package/dist/utils/child-env.d.ts +1 -1
  485. package/dist/utils/child-env.d.ts.map +1 -1
  486. package/dist/utils/child-env.js +9 -0
  487. package/dist/utils/child-env.js.map +1 -1
  488. package/dist/utils/codex-app-control.d.ts +438 -0
  489. package/dist/utils/codex-app-control.d.ts.map +1 -0
  490. package/dist/utils/codex-app-control.js +2336 -0
  491. package/dist/utils/codex-app-control.js.map +1 -0
  492. package/dist/utils/codex-app-dispatch-ledger.d.ts +78 -0
  493. package/dist/utils/codex-app-dispatch-ledger.d.ts.map +1 -0
  494. package/dist/utils/codex-app-dispatch-ledger.js +149 -0
  495. package/dist/utils/codex-app-dispatch-ledger.js.map +1 -0
  496. package/dist/utils/codex-app-turn-dispatch.d.ts +77 -0
  497. package/dist/utils/codex-app-turn-dispatch.d.ts.map +1 -0
  498. package/dist/utils/codex-app-turn-dispatch.js +141 -0
  499. package/dist/utils/codex-app-turn-dispatch.js.map +1 -0
  500. package/dist/utils/codex-app-turn-liveness.d.ts +125 -0
  501. package/dist/utils/codex-app-turn-liveness.d.ts.map +1 -0
  502. package/dist/utils/codex-app-turn-liveness.js +301 -0
  503. package/dist/utils/codex-app-turn-liveness.js.map +1 -0
  504. package/dist/utils/idle-detector.d.ts +12 -0
  505. package/dist/utils/idle-detector.d.ts.map +1 -1
  506. package/dist/utils/idle-detector.js +19 -0
  507. package/dist/utils/idle-detector.js.map +1 -1
  508. package/dist/utils/input-gate.d.ts +87 -0
  509. package/dist/utils/input-gate.d.ts.map +1 -1
  510. package/dist/utils/input-gate.js +86 -0
  511. package/dist/utils/input-gate.js.map +1 -1
  512. package/dist/utils/lark-upload.d.ts.map +1 -1
  513. package/dist/utils/lark-upload.js +52 -1
  514. package/dist/utils/lark-upload.js.map +1 -1
  515. package/dist/utils/pending-input-queue.d.ts +15 -0
  516. package/dist/utils/pending-input-queue.d.ts.map +1 -1
  517. package/dist/utils/pending-input-queue.js +5 -1
  518. package/dist/utils/pending-input-queue.js.map +1 -1
  519. package/dist/utils/user-token.d.ts.map +1 -1
  520. package/dist/utils/user-token.js +53 -2
  521. package/dist/utils/user-token.js.map +1 -1
  522. package/dist/worker-ipc-preload.d.ts +12 -0
  523. package/dist/worker-ipc-preload.d.ts.map +1 -0
  524. package/dist/worker-ipc-preload.js +44 -0
  525. package/dist/worker-ipc-preload.js.map +1 -0
  526. package/dist/worker.js +2604 -325
  527. package/dist/worker.js.map +1 -1
  528. package/dist/workflows/v3/session-relay-client.d.ts +1 -0
  529. package/dist/workflows/v3/session-relay-client.d.ts.map +1 -1
  530. package/dist/workflows/v3/session-relay-client.js +12 -3
  531. package/dist/workflows/v3/session-relay-client.js.map +1 -1
  532. package/package.json +1 -1
  533. package/dist/dashboard-web/chunks/bot-defaults-page-LTVOUDIS.js +0 -10
  534. package/dist/dashboard-web/chunks/chunk-DCS35UMD.js +0 -1
  535. package/dist/dashboard-web/chunks/chunk-MFQPCVHY.js +0 -51
  536. package/dist/dashboard-web/chunks/connectors-page-5KWDIMKC.js +0 -1
  537. package/dist/dashboard-web/chunks/groups-page-FHOKYXMW.js +0 -8
  538. package/dist/dashboard-web/chunks/overview-page-QYI3KBDD.js +0 -1
  539. package/dist/dashboard-web/chunks/sessions-page-WBP4N7D2.js +0 -6
@@ -55,6 +55,19 @@ type CachedUsageKind = UsageKind | 'aiden';
55
55
  /** Token usage is advisory. Never let dashboard row rendering synchronously
56
56
  * scan pathological multi-GB transcripts. */
57
57
  export declare const MAX_USAGE_TRANSCRIPT_BYTES: number;
58
+ /** Codex token_count events are cumulative snapshots, so an oversized cold
59
+ * restore starts from a bounded tail window and recovers the latest usage
60
+ * card from it. Real 150MiB+ rollouts almost always carry a token_count
61
+ * snapshot in the last 4MiB, so this window is the common-case fast path. */
62
+ export declare const CODEX_USAGE_TRANSCRIPT_TAIL_BYTES: number;
63
+ /** When the last tail window is missing a metric (a single huge turn can push
64
+ * the newest token_count snapshot — or the model line — out of it), do ONE
65
+ * bounded widen to this size and re-scan that whole window. It is the width of
66
+ * the single widened pass, NOT a cumulative ladder: the worst-case synchronous
67
+ * dashboard read is `tail + this`, and past it we fail closed (yield whatever
68
+ * the widened window found, never inheriting a possibly-stale value across an
69
+ * unverifiable generation boundary). */
70
+ export declare const CODEX_USAGE_MAX_BACKSCAN_BYTES: number;
58
71
  export declare function __resetSessionUsageCachesForTest(): void;
59
72
  /** Read a transcript's token usage through the stat/incremental cache.
60
73
  * This is the reusable entry point for dashboard rows and, later, the
@@ -1 +1 @@
1
- {"version":3,"file":"cost-calculator.d.ts","sourceRoot":"","sources":["../../src/core/cost-calculator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAgBtD,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;SAIS;AACT,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;gFAIgF;AAChF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;kEAC8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;sFACkF;IAClF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEjF;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAOjF;AAqID;+EAC+E;AAC/E,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AA6OhE,KAAK,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAoB3C;8CAC8C;AAC9C,eAAO,MAAM,0BAA0B,QAAmB,CAAC;AAO3D,wBAAgB,gCAAgC,IAAI,IAAI,CAIvD;AAiJD;;+BAE+B;AAC/B,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,iBAAiB,GAAG,IAAI,CAEnI;AA4ED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,sBAAsB,GAAG,iBAAiB,GAAG,IAAI,CAExF;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,sBAAsB,GAAG,oBAAoB,CAevF;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C"}
1
+ {"version":3,"file":"cost-calculator.d.ts","sourceRoot":"","sources":["../../src/core/cost-calculator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAgBtD,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;SAIS;AACT,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;gFAIgF;AAChF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;kEAC8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;sFACkF;IAClF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEjF;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAOjF;AAwID;+EAC+E;AAC/E,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAmRhE,KAAK,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAwB3C;8CAC8C;AAC9C,eAAO,MAAM,0BAA0B,QAAmB,CAAC;AAC3D;;;8EAG8E;AAC9E,eAAO,MAAM,iCAAiC,QAAkB,CAAC;AAEjE;;;;;;yCAMyC;AACzC,eAAO,MAAM,8BAA8B,QAAmB,CAAC;AAO/D,wBAAgB,gCAAgC,IAAI,IAAI,CAIvD;AA0fD;;+BAE+B;AAC/B,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,iBAAiB,GAAG,IAAI,CAEnI;AA4ED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,sBAAsB,GAAG,iBAAiB,GAAG,IAAI,CAExF;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,sBAAsB,GAAG,oBAAoB,CAevF;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C"}
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Session cost calculator — computes token usage from JSONL logs.
3
3
  */
4
- import { existsSync, readFileSync, statSync } from 'node:fs';
4
+ import { closeSync, constants, existsSync, fstatSync, openSync, readFileSync, readSync, statSync } from 'node:fs';
5
5
  import { logger } from '../utils/logger.js';
6
6
  import { findAidenLatestCheckpointByBotmuxSessionId, findAidenLatestCheckpointBySessionId } from '../services/aiden-checkpoints.js';
7
7
  import { __resetTranscriptResolverCacheForTest, cachedTranscriptPathLookup, resolveSessionTranscriptPath, } from '../services/transcript-resolver.js';
8
- import { scanJsonlFromOffset } from '../services/jsonl-cursor.js';
8
+ import { scanJsonlFromFd, scanJsonlFromOffset } from '../services/jsonl-cursor.js';
9
9
  import { isMeaningfulQueuedCommand, isMeaningfulUserEvent, } from '../services/claude-transcript.js';
10
10
  // ─── Helpers ─────────────────────────────────────────────────────────────────
11
11
  export function getSessionJsonlPath(sessionId, cwd) {
@@ -123,6 +123,16 @@ function extractCodexContextUsage(entry) {
123
123
  ...(percentUsed !== undefined ? { percentUsed } : {}),
124
124
  };
125
125
  }
126
+ const CODEX_USAGE_SOURCE_RECORD_MAX_BYTES = 64 * 1024;
127
+ function sourceRecordForLine(line, lineStart) {
128
+ if (lineStart === undefined || lineStart < 0)
129
+ return null;
130
+ if (Buffer.byteLength(line, 'utf8') > CODEX_USAGE_SOURCE_RECORD_MAX_BYTES)
131
+ return null;
132
+ return {
133
+ offset: lineStart,
134
+ };
135
+ }
126
136
  function usageKindForCli(cliId) {
127
137
  switch (cliId) {
128
138
  case 'claude-code':
@@ -155,6 +165,9 @@ function newTokenUsageAggregate() {
155
165
  turns: 0,
156
166
  latestCodexUsage: null,
157
167
  latestContextUsage: null,
168
+ latestCodexUsageSource: null,
169
+ latestContextUsageSource: null,
170
+ modelSource: null,
158
171
  turnInputTokens: 0,
159
172
  turnOutputTokens: 0,
160
173
  };
@@ -217,18 +230,28 @@ function foldClaudeLine(agg, seenMessageIds, entry) {
217
230
  /** Codex rollouts report cumulative totals via event_msg/token_count; only
218
231
  * the latest snapshot counts. The active model rides on turn_context /
219
232
  * session_meta payloads (latest wins — sessions can switch models). */
220
- function foldCodexLine(agg, entry) {
233
+ function foldCodexLine(agg, entry, getSource) {
221
234
  const contextUsage = extractCodexContextUsage(entry);
222
- if (contextUsage)
235
+ let source;
236
+ const sourceForTrackedMetric = () => {
237
+ source ??= getSource();
238
+ return source;
239
+ };
240
+ if (contextUsage) {
223
241
  agg.latestContextUsage = contextUsage;
242
+ agg.latestContextUsageSource = sourceForTrackedMetric();
243
+ }
224
244
  const codexUsage = extractCodexTokenCountUsage(entry);
225
245
  if (codexUsage) {
226
246
  agg.latestCodexUsage = codexUsage;
247
+ agg.latestCodexUsageSource = sourceForTrackedMetric();
227
248
  return;
228
249
  }
229
250
  const m = entry?.payload?.model ?? entry?.payload?.collaboration_mode?.settings?.model;
230
- if (typeof m === 'string' && m)
251
+ if (typeof m === 'string' && m) {
231
252
  agg.model = m;
253
+ agg.modelSource = sourceForTrackedMetric();
254
+ }
232
255
  }
233
256
  /** CoCo events: only assistant messages with response_meta.usage count; the
234
257
  * agent_end summary repeats the last turn's usage and must not be counted. */
@@ -300,12 +323,12 @@ function foldGenericLine(agg, seenMessageIds, entry) {
300
323
  agg.model = native.model;
301
324
  agg.turns++;
302
325
  }
303
- function foldUsageLine(kind, agg, seenMessageIds, entry) {
326
+ function foldUsageLine(kind, agg, seenMessageIds, entry, getSource) {
304
327
  switch (kind) {
305
328
  case 'claude':
306
329
  return foldClaudeLine(agg, seenMessageIds, entry);
307
330
  case 'codex':
308
- return foldCodexLine(agg, entry);
331
+ return foldCodexLine(agg, entry, getSource ?? (() => null));
309
332
  case 'coco':
310
333
  return foldCocoLine(agg, entry);
311
334
  case 'pi':
@@ -322,7 +345,7 @@ function readTokenUsageAggregate(path, kind) {
322
345
  try {
323
346
  let scanError = null;
324
347
  const scanned = scanJsonlFromOffset(path, 0, {
325
- onLine: (line) => foldUsageJsonLine(kind, agg, seenMessageIds, line),
348
+ onLine: (line, lineStart) => foldUsageJsonLine(kind, agg, seenMessageIds, line, lineStart),
326
349
  onError: (error) => { scanError = error; },
327
350
  });
328
351
  if (!scanned)
@@ -362,6 +385,20 @@ const USAGE_REPARSE_MIN_INTERVAL_MS = 15_000;
362
385
  /** Token usage is advisory. Never let dashboard row rendering synchronously
363
386
  * scan pathological multi-GB transcripts. */
364
387
  export const MAX_USAGE_TRANSCRIPT_BYTES = 64 * 1024 * 1024;
388
+ /** Codex token_count events are cumulative snapshots, so an oversized cold
389
+ * restore starts from a bounded tail window and recovers the latest usage
390
+ * card from it. Real 150MiB+ rollouts almost always carry a token_count
391
+ * snapshot in the last 4MiB, so this window is the common-case fast path. */
392
+ export const CODEX_USAGE_TRANSCRIPT_TAIL_BYTES = 4 * 1024 * 1024;
393
+ const CODEX_USAGE_REPLAY_BYTES = 4 * 1024 * 1024;
394
+ /** When the last tail window is missing a metric (a single huge turn can push
395
+ * the newest token_count snapshot — or the model line — out of it), do ONE
396
+ * bounded widen to this size and re-scan that whole window. It is the width of
397
+ * the single widened pass, NOT a cumulative ladder: the worst-case synchronous
398
+ * dashboard read is `tail + this`, and past it we fail closed (yield whatever
399
+ * the widened window found, never inheriting a possibly-stale value across an
400
+ * unverifiable generation boundary). */
401
+ export const CODEX_USAGE_MAX_BACKSCAN_BYTES = 32 * 1024 * 1024;
365
402
  /** Aiden checkpoint paths move as the session progresses (latest.json points
366
403
  * at a new checkpoint id per turn), so positive hits expire quickly too. */
367
404
  const AIDEN_PATH_HIT_TTL_MS = 15_000;
@@ -384,14 +421,337 @@ function foldUsageText(kind, agg, seenMessageIds, text) {
384
421
  catch { /* skip malformed lines */ }
385
422
  }
386
423
  }
387
- function foldUsageJsonLine(kind, agg, seenMessageIds, line) {
424
+ function foldUsageJsonLine(kind, agg, seenMessageIds, line, lineStart) {
388
425
  if (!line.trim())
389
426
  return;
390
427
  try {
391
- foldUsageLine(kind, agg, seenMessageIds, JSON.parse(line));
428
+ const entry = JSON.parse(line);
429
+ if (kind !== 'codex') {
430
+ foldUsageLine(kind, agg, seenMessageIds, entry);
431
+ return;
432
+ }
433
+ let sourceCalculated = false;
434
+ let source = null;
435
+ foldUsageLine(kind, agg, seenMessageIds, entry, () => {
436
+ if (!sourceCalculated) {
437
+ source = sourceRecordForLine(line, lineStart);
438
+ sourceCalculated = true;
439
+ }
440
+ return source;
441
+ });
392
442
  }
393
443
  catch { /* skip malformed lines */ }
394
444
  }
445
+ function readFdProbe(fd, offset, length) {
446
+ if (length <= 0)
447
+ return Buffer.alloc(0);
448
+ try {
449
+ const buf = Buffer.alloc(length);
450
+ const read = readSync(fd, buf, 0, length, offset);
451
+ return buf.subarray(0, read);
452
+ }
453
+ catch {
454
+ return null;
455
+ }
456
+ }
457
+ function isJsonlLineBoundaryFd(fd, offset) {
458
+ if (offset <= 0)
459
+ return true;
460
+ const probe = readFdProbe(fd, offset - 1, 1);
461
+ return !!probe && probe.length === 1 && probe[0] === 0x0a;
462
+ }
463
+ function aggregateHasCodexUsage(agg) {
464
+ return !!agg.latestCodexUsage || !!agg.latestContextUsage;
465
+ }
466
+ /** The two cumulative-usage metrics recovered. Used to decide when the bounded
467
+ * widen can stop: cumulative and context can sit on different lines, so a
468
+ * window that caught only one is not complete. Model is handled separately
469
+ * (see the model back-fill below) — it is a stable session-level attribute, so
470
+ * gating the (bounded) widen on it would force a re-scan for every rollout that
471
+ * simply never re-emits a model line inside the tail window. */
472
+ function aggregateHasAllCodexMetrics(agg) {
473
+ return !!agg.latestCodexUsage && !!agg.latestContextUsage;
474
+ }
475
+ function ensureUsageFileCacheCapacity(key) {
476
+ if (usageFileCache.size >= USAGE_FILE_CACHE_MAX_ENTRIES && !usageFileCache.has(key)) {
477
+ const oldest = usageFileCache.keys().next().value;
478
+ if (oldest !== undefined)
479
+ usageFileCache.delete(oldest);
480
+ }
481
+ }
482
+ function canReuseUsageCache(cached, st) {
483
+ if (!cached.canReadIncrementally)
484
+ return false;
485
+ if (st.size < cached.offset)
486
+ return false;
487
+ return cached.dev === st.dev && cached.ino === st.ino;
488
+ }
489
+ function earliestCodexReplaySourceOffset(previous) {
490
+ if (!previous)
491
+ return null;
492
+ const offsets = [];
493
+ if (previous.latestCodexUsage) {
494
+ if (!previous.latestCodexUsageSource)
495
+ return null;
496
+ offsets.push(previous.latestCodexUsageSource.offset);
497
+ }
498
+ if (previous.latestContextUsage) {
499
+ if (!previous.latestContextUsageSource)
500
+ return null;
501
+ offsets.push(previous.latestContextUsageSource.offset);
502
+ }
503
+ if (previous.model) {
504
+ if (!previous.modelSource)
505
+ return null;
506
+ offsets.push(previous.modelSource.offset);
507
+ }
508
+ return offsets.length > 0 ? Math.min(...offsets) : null;
509
+ }
510
+ function cacheUsageRead(key, st, entry) {
511
+ ensureUsageFileCacheCapacity(key);
512
+ usageFileCache.set(key, {
513
+ ...entry,
514
+ mtimeMs: st.mtimeMs,
515
+ ctimeMs: st.ctimeMs,
516
+ size: st.size,
517
+ dev: st.dev,
518
+ ino: st.ino,
519
+ });
520
+ }
521
+ function readCodexTokenAggregateCached(key, path, st, cached, now, retryOnRace = true) {
522
+ let fd = null;
523
+ let fdStat;
524
+ try {
525
+ fd = openSync(path, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
526
+ fdStat = fstatSync(fd);
527
+ if (!fdStat.isFile()) {
528
+ closeSync(fd);
529
+ usageFileCache.delete(key);
530
+ return { agg: newTokenUsageAggregate(), result: null };
531
+ }
532
+ }
533
+ catch (error) {
534
+ if (fd !== null)
535
+ closeSync(fd);
536
+ logger.error(`Failed to open Codex transcript ${path}: ${error instanceof Error ? error.message : String(error)}`);
537
+ usageFileCache.delete(key);
538
+ return null;
539
+ }
540
+ if (fdStat.dev !== st.dev || fdStat.ino !== st.ino || fdStat.size !== st.size) {
541
+ closeSync(fd);
542
+ usageFileCache.delete(key);
543
+ if (retryOnRace) {
544
+ return readCodexTokenAggregateCached(key, path, fdStat, undefined, now, false);
545
+ }
546
+ return { agg: newTokenUsageAggregate(), result: null };
547
+ }
548
+ let state;
549
+ let seenMessageIds;
550
+ let baseOffset = 0;
551
+ const previousAgg = cached?.previewAgg ? cloneAggregate(cached.previewAgg) : undefined;
552
+ const sameOpenFileAsCache = !!cached
553
+ && cached.dev === fdStat.dev
554
+ && cached.ino === fdStat.ino;
555
+ const canConsiderReplay = !!cached
556
+ && sameOpenFileAsCache
557
+ && cached.canReadIncrementally
558
+ && cached.offset > 0
559
+ && fdStat.size >= cached.offset;
560
+ const oversized = fdStat.size > MAX_USAGE_TRANSCRIPT_BYTES;
561
+ const candidateReplayBaseOffset = canConsiderReplay
562
+ ? earliestCodexReplaySourceOffset(previousAgg)
563
+ : null;
564
+ const candidateReplaySpan = candidateReplayBaseOffset === null
565
+ ? Number.POSITIVE_INFINITY
566
+ : fdStat.size - candidateReplayBaseOffset;
567
+ const replayBaseOffset = candidateReplaySpan <= CODEX_USAGE_REPLAY_BYTES
568
+ && candidateReplayBaseOffset !== null
569
+ && isJsonlLineBoundaryFd(fd, candidateReplayBaseOffset)
570
+ ? candidateReplayBaseOffset
571
+ : null;
572
+ const replaySpan = replayBaseOffset === null ? Number.POSITIVE_INFINITY : fdStat.size - replayBaseOffset;
573
+ const reuseTrackedReplay = replayBaseOffset !== null && replaySpan <= CODEX_USAGE_REPLAY_BYTES;
574
+ const scanFromWindow = (from, knownLineBoundary) => {
575
+ const windowState = newTokenUsageAggregate();
576
+ const windowSeen = new Set();
577
+ // Replay/full-file reads start on a proven line boundary (offset 0, or an
578
+ // offset already validated by isJsonlLineBoundaryFd), so they need no extra
579
+ // probe. Only a widened bounded-tail window lands at an arbitrary byte and
580
+ // must drop the partial leading record.
581
+ let dropResidual = !knownLineBoundary && from > 0 && !isJsonlLineBoundaryFd(fd, from);
582
+ let droppedResidual = false;
583
+ let windowScanError = null;
584
+ const windowScanned = scanJsonlFromFd(fd, from, {
585
+ endOffset: fdStat.size,
586
+ onLine: (line, lineStart) => {
587
+ if (dropResidual) {
588
+ dropResidual = false;
589
+ droppedResidual = true;
590
+ return;
591
+ }
592
+ foldUsageJsonLine('codex', windowState, windowSeen, line, lineStart);
593
+ },
594
+ onError: (error) => { windowScanError = error; },
595
+ });
596
+ if (!windowScanned) {
597
+ logger.error(`Failed to read Codex transcript slice ${path}: ${windowScanError instanceof Error ? windowScanError.message : String(windowScanError)}`);
598
+ return null;
599
+ }
600
+ let windowPreview = windowState;
601
+ const windowTail = windowScanned.pendingTail.trim();
602
+ const residualTailPending = dropResidual && !droppedResidual;
603
+ if (windowTail && !residualTailPending) {
604
+ windowPreview = cloneAggregate(windowState);
605
+ foldUsageText('codex', windowPreview, new Set(windowSeen), windowTail);
606
+ }
607
+ return {
608
+ state: windowState,
609
+ seenMessageIds: windowSeen,
610
+ scanned: windowScanned,
611
+ completeBytes: windowScanned.newOffset - from,
612
+ previewAgg: windowPreview,
613
+ pendingTailIsInitialResidualLine: residualTailPending,
614
+ };
615
+ };
616
+ let scanned;
617
+ let completeBytes;
618
+ let previewAgg;
619
+ let pendingTailIsInitialResidualLine;
620
+ if (reuseTrackedReplay) {
621
+ baseOffset = replayBaseOffset;
622
+ const win = scanFromWindow(baseOffset, true);
623
+ if (!win) {
624
+ closeSync(fd);
625
+ usageFileCache.delete(key);
626
+ return null;
627
+ }
628
+ ({ state, seenMessageIds, scanned, completeBytes, previewAgg, pendingTailIsInitialResidualLine } = win);
629
+ }
630
+ else if (!oversized) {
631
+ baseOffset = 0;
632
+ const win = scanFromWindow(baseOffset, true);
633
+ if (!win) {
634
+ closeSync(fd);
635
+ usageFileCache.delete(key);
636
+ return null;
637
+ }
638
+ ({ state, seenMessageIds, scanned, completeBytes, previewAgg, pendingTailIsInitialResidualLine } = win);
639
+ }
640
+ else {
641
+ // Oversized cold/bounded read. Fast path: scan the last tail window. Widen
642
+ // ONCE to the back-scan budget and re-scan that whole window when the fast
643
+ // path is incomplete — either the two usage metrics (cumulative/context)
644
+ // are not both present, or this session is KNOWN to carry a model (the
645
+ // cached read had one) but the fast window has none. A single >4MiB turn can
646
+ // push the newest token_count — or a just-switched model line — out of the
647
+ // tail window; the widen recovers the true latest of all of them. A single
648
+ // widened pass (not a 4/8/.../32 ladder) keeps the worst-case synchronous
649
+ // read at tail + budget, not their sum. Each pass scans from a fresh state;
650
+ // Codex token_count/model are latest-wins, so re-folding older lines first
651
+ // and letting the newest overwrite last is exact. Model is NOT inherited
652
+ // from cache: a widen that still finds none fails closed to empty rather
653
+ // than risk shipping a stale model (which mis-prices the ledger) after an
654
+ // append-only model switch.
655
+ const cachedHadModel = sameOpenFileAsCache && !!previousAgg?.model;
656
+ baseOffset = Math.max(0, fdStat.size - CODEX_USAGE_TRANSCRIPT_TAIL_BYTES);
657
+ let win = scanFromWindow(baseOffset, false);
658
+ if (!win) {
659
+ closeSync(fd);
660
+ usageFileCache.delete(key);
661
+ return null;
662
+ }
663
+ const fastPathIncomplete = !aggregateHasAllCodexMetrics(win.previewAgg)
664
+ || (cachedHadModel && !win.previewAgg.model);
665
+ if (fastPathIncomplete && baseOffset > 0) {
666
+ const widenedBaseOffset = Math.max(0, fdStat.size - CODEX_USAGE_MAX_BACKSCAN_BYTES);
667
+ if (widenedBaseOffset < baseOffset) {
668
+ const widened = scanFromWindow(widenedBaseOffset, false);
669
+ if (!widened) {
670
+ closeSync(fd);
671
+ usageFileCache.delete(key);
672
+ return null;
673
+ }
674
+ baseOffset = widenedBaseOffset;
675
+ win = widened;
676
+ }
677
+ }
678
+ ({ state, seenMessageIds, scanned, completeBytes, previewAgg, pendingTailIsInitialResidualLine } = win);
679
+ }
680
+ const nextOffset = pendingTailIsInitialResidualLine ? baseOffset : baseOffset + completeBytes;
681
+ let endStat;
682
+ try {
683
+ endStat = fstatSync(fd);
684
+ }
685
+ catch {
686
+ closeSync(fd);
687
+ usageFileCache.delete(key);
688
+ return { agg: newTokenUsageAggregate(), result: null };
689
+ }
690
+ if (endStat.dev !== fdStat.dev
691
+ || endStat.ino !== fdStat.ino
692
+ || endStat.size !== fdStat.size
693
+ || endStat.mtimeMs !== fdStat.mtimeMs
694
+ || endStat.ctimeMs !== fdStat.ctimeMs) {
695
+ closeSync(fd);
696
+ usageFileCache.delete(key);
697
+ if (retryOnRace) {
698
+ return readCodexTokenAggregateCached(key, path, endStat, undefined, now, false);
699
+ }
700
+ return { agg: newTokenUsageAggregate(), result: null };
701
+ }
702
+ let pathStat;
703
+ try {
704
+ pathStat = statSync(path);
705
+ }
706
+ catch {
707
+ closeSync(fd);
708
+ usageFileCache.delete(key);
709
+ return { agg: newTokenUsageAggregate(), result: null };
710
+ }
711
+ if (pathStat.dev !== fdStat.dev
712
+ || pathStat.ino !== fdStat.ino
713
+ || pathStat.size !== fdStat.size
714
+ || pathStat.mtimeMs !== fdStat.mtimeMs
715
+ || pathStat.ctimeMs !== fdStat.ctimeMs) {
716
+ closeSync(fd);
717
+ usageFileCache.delete(key);
718
+ if (retryOnRace) {
719
+ return readCodexTokenAggregateCached(key, path, pathStat, undefined, now, false);
720
+ }
721
+ return { agg: newTokenUsageAggregate(), result: null };
722
+ }
723
+ if (pendingTailIsInitialResidualLine) {
724
+ // The bounded window starts in the middle of a JSONL record and no newline
725
+ // has arrived yet. Cache safe stat/throttle metadata only; the stored
726
+ // offset is not a reusable durable cursor, so any later change reboots from
727
+ // a bounded tail instead of turning that suffix into a fake complete line.
728
+ const result = finalizeTokenUsage(previewAgg);
729
+ cacheUsageRead(key, fdStat, {
730
+ offset: nextOffset,
731
+ state,
732
+ seenMessageIds,
733
+ previewAgg,
734
+ result,
735
+ parsedAtMs: now,
736
+ canReadIncrementally: false,
737
+ });
738
+ closeSync(fd);
739
+ return { agg: previewAgg, result };
740
+ }
741
+ const result = finalizeTokenUsage(previewAgg);
742
+ const canReadIncrementally = aggregateHasCodexUsage(previewAgg);
743
+ cacheUsageRead(key, fdStat, {
744
+ offset: nextOffset,
745
+ state,
746
+ seenMessageIds,
747
+ previewAgg,
748
+ result,
749
+ parsedAtMs: now,
750
+ canReadIncrementally,
751
+ });
752
+ closeSync(fd);
753
+ return { agg: previewAgg, result };
754
+ }
395
755
  function readSessionTokenAggregateCached(path, kind, opts) {
396
756
  const key = `${kind}:${path}`;
397
757
  let st = null;
@@ -402,8 +762,11 @@ function readSessionTokenAggregateCached(path, kind, opts) {
402
762
  st = null;
403
763
  }
404
764
  if (!st) {
405
- // Unstat-able (file gone, or mocked fs in unit tests): parse directly, uncached.
406
765
  usageFileCache.delete(key);
766
+ if (kind === 'codex') {
767
+ return { agg: newTokenUsageAggregate(), result: null };
768
+ }
769
+ // Unstat-able (file gone, or mocked fs in unit tests): parse directly, uncached.
407
770
  if (kind === 'aiden') {
408
771
  const result = readTokenUsageFromAidenCheckpoint(path);
409
772
  return result ? { agg: newTokenUsageAggregate(), result } : null;
@@ -413,13 +776,16 @@ function readSessionTokenAggregateCached(path, kind, opts) {
413
776
  }
414
777
  const now = Date.now();
415
778
  const cached = usageFileCache.get(key);
416
- if (cached) {
417
- const unchanged = cached.mtimeMs === st.mtimeMs && cached.size === st.size;
779
+ if (cached && cached.dev === st.dev && cached.ino === st.ino) {
780
+ const unchanged = cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && cached.size === st.size;
418
781
  const throttled = !opts?.fresh && now - cached.parsedAtMs < USAGE_REPARSE_MIN_INTERVAL_MS;
419
782
  if (unchanged || throttled) {
420
783
  return { agg: cached.previewAgg, result: cached.result };
421
784
  }
422
785
  }
786
+ if (kind === 'codex') {
787
+ return readCodexTokenAggregateCached(key, path, st, cached, now);
788
+ }
423
789
  if (st.size > MAX_USAGE_TRANSCRIPT_BYTES) {
424
790
  // Warn once per transcript, not per observed size: an actively-growing
425
791
  // oversized file would otherwise re-warn and leak a Set entry every reparse.
@@ -432,31 +798,25 @@ function readSessionTokenAggregateCached(path, kind, opts) {
432
798
  return { agg: cached.previewAgg, result: cached.result };
433
799
  return { agg: newTokenUsageAggregate(), result: null };
434
800
  }
435
- if (usageFileCache.size >= USAGE_FILE_CACHE_MAX_ENTRIES && !usageFileCache.has(key)) {
436
- const oldest = usageFileCache.keys().next().value;
437
- if (oldest !== undefined)
438
- usageFileCache.delete(oldest);
439
- }
440
801
  if (kind === 'aiden') {
441
802
  // Checkpoints are rewritten whole — nothing incremental to exploit.
442
803
  const result = readTokenUsageFromAidenCheckpoint(path);
443
804
  const blank = newTokenUsageAggregate();
444
- usageFileCache.set(key, {
445
- mtimeMs: st.mtimeMs,
446
- size: st.size,
805
+ cacheUsageRead(key, st, {
447
806
  offset: -1,
448
807
  state: blank,
449
808
  seenMessageIds: new Set(),
450
809
  previewAgg: blank,
451
810
  result,
452
811
  parsedAtMs: now,
812
+ canReadIncrementally: false,
453
813
  });
454
814
  return { agg: blank, result };
455
815
  }
456
816
  let state;
457
817
  let seenMessageIds;
458
818
  let baseOffset;
459
- if (cached && cached.offset > 0 && st.size >= cached.offset) {
819
+ if (cached && cached.offset > 0 && canReuseUsageCache(cached, st)) {
460
820
  // Append-only growth: continue folding from the durable frontier.
461
821
  state = cached.state;
462
822
  seenMessageIds = cached.seenMessageIds;
@@ -470,7 +830,7 @@ function readSessionTokenAggregateCached(path, kind, opts) {
470
830
  let scanError = null;
471
831
  const scanned = scanJsonlFromOffset(path, baseOffset, {
472
832
  endOffset: st.size,
473
- onLine: (line) => foldUsageJsonLine(kind, state, seenMessageIds, line),
833
+ onLine: (line, lineStart) => foldUsageJsonLine(kind, state, seenMessageIds, line, lineStart),
474
834
  onError: (error) => { scanError = error; },
475
835
  });
476
836
  if (!scanned) {
@@ -490,15 +850,14 @@ function readSessionTokenAggregateCached(path, kind, opts) {
490
850
  foldUsageText(kind, previewAgg, new Set(seenMessageIds), tailText);
491
851
  }
492
852
  const result = finalizeTokenUsage(previewAgg);
493
- usageFileCache.set(key, {
494
- mtimeMs: st.mtimeMs,
495
- size: st.size,
853
+ cacheUsageRead(key, st, {
496
854
  offset: baseOffset + completeBytes,
497
855
  state,
498
856
  seenMessageIds,
499
857
  previewAgg,
500
858
  result,
501
859
  parsedAtMs: now,
860
+ canReadIncrementally: true,
502
861
  });
503
862
  return { agg: previewAgg, result };
504
863
  }