context-mode 1.0.168 → 2.0.0-next.5

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 (395) hide show
  1. package/.claude-plugin/marketplace.json +4 -22
  2. package/.claude-plugin/plugin.json +9 -24
  3. package/SHA256SUMS +31 -0
  4. package/claude-code/skills/ctx-doctor/SKILL.md +6 -0
  5. package/claude-code/skills/ctx-stats/SKILL.md +6 -0
  6. package/claude-code/skills/ctx-upgrade/SKILL.md +6 -0
  7. package/cli.mjs +6744 -0
  8. package/copilot/plugin.json +14 -0
  9. package/fixtures/hook-roundtrip.json +22 -0
  10. package/gemini-extension.json +14 -0
  11. package/hook.mjs +202 -0
  12. package/hooks/claude-code.json +50 -0
  13. package/hooks/codex.json +50 -0
  14. package/hooks/copilot-cli.json +33 -0
  15. package/hooks/hooks.json +16 -111
  16. package/hooks/kiro.json +69 -0
  17. package/hooks/qwen.json +50 -0
  18. package/hooks/vscode.json +40 -0
  19. package/hooks/zcode.json +53 -0
  20. package/opencode/plugin.js +22456 -0
  21. package/package.json +29 -114
  22. package/pi/index.js +50841 -0
  23. package/pi/skills/ctx-doctor/SKILL.md +6 -0
  24. package/pi/skills/ctx-stats/SKILL.md +6 -0
  25. package/pi/skills/ctx-upgrade/SKILL.md +6 -0
  26. package/qwen-extension.json +15 -0
  27. package/run.mjs +5633 -0
  28. package/search.mjs +5633 -0
  29. package/server.mjs +48198 -0
  30. package/skills/ctx-doctor/SKILL.md +3 -19
  31. package/skills/ctx-stats/SKILL.md +3 -23
  32. package/skills/ctx-upgrade/SKILL.md +3 -28
  33. package/.codex-plugin/hooks.json +0 -65
  34. package/.codex-plugin/mcp.json +0 -13
  35. package/.codex-plugin/plugin.json +0 -31
  36. package/.openclaw-plugin/index.ts +0 -12
  37. package/.openclaw-plugin/openclaw.plugin.json +0 -38
  38. package/.openclaw-plugin/package.json +0 -28
  39. package/LICENSE +0 -94
  40. package/README.md +0 -1619
  41. package/bin/statusline.mjs +0 -378
  42. package/build/adapters/antigravity/index.d.ts +0 -51
  43. package/build/adapters/antigravity/index.js +0 -169
  44. package/build/adapters/antigravity-cli/index.d.ts +0 -51
  45. package/build/adapters/antigravity-cli/index.js +0 -342
  46. package/build/adapters/base.d.ts +0 -92
  47. package/build/adapters/base.js +0 -135
  48. package/build/adapters/claude-code/config.d.ts +0 -8
  49. package/build/adapters/claude-code/config.js +0 -8
  50. package/build/adapters/claude-code/hooks.d.ts +0 -106
  51. package/build/adapters/claude-code/hooks.js +0 -183
  52. package/build/adapters/claude-code/index.d.ts +0 -80
  53. package/build/adapters/claude-code/index.js +0 -569
  54. package/build/adapters/claude-code-base.d.ts +0 -49
  55. package/build/adapters/claude-code-base.js +0 -113
  56. package/build/adapters/client-map.d.ts +0 -10
  57. package/build/adapters/client-map.js +0 -42
  58. package/build/adapters/codex/config.d.ts +0 -8
  59. package/build/adapters/codex/config.js +0 -8
  60. package/build/adapters/codex/hooks.d.ts +0 -55
  61. package/build/adapters/codex/hooks.js +0 -64
  62. package/build/adapters/codex/index.d.ts +0 -87
  63. package/build/adapters/codex/index.js +0 -992
  64. package/build/adapters/codex/paths.d.ts +0 -1
  65. package/build/adapters/codex/paths.js +0 -12
  66. package/build/adapters/codex/usage.d.ts +0 -107
  67. package/build/adapters/codex/usage.js +0 -227
  68. package/build/adapters/copilot-base.d.ts +0 -94
  69. package/build/adapters/copilot-base.js +0 -297
  70. package/build/adapters/copilot-cli/hooks.d.ts +0 -33
  71. package/build/adapters/copilot-cli/hooks.js +0 -64
  72. package/build/adapters/copilot-cli/index.d.ts +0 -48
  73. package/build/adapters/copilot-cli/index.js +0 -341
  74. package/build/adapters/cursor/config.d.ts +0 -4
  75. package/build/adapters/cursor/config.js +0 -4
  76. package/build/adapters/cursor/hooks.d.ts +0 -55
  77. package/build/adapters/cursor/hooks.js +0 -82
  78. package/build/adapters/cursor/index.d.ts +0 -64
  79. package/build/adapters/cursor/index.js +0 -517
  80. package/build/adapters/detect.d.ts +0 -136
  81. package/build/adapters/detect.js +0 -623
  82. package/build/adapters/gemini-cli/config.d.ts +0 -8
  83. package/build/adapters/gemini-cli/config.js +0 -8
  84. package/build/adapters/gemini-cli/hooks.d.ts +0 -83
  85. package/build/adapters/gemini-cli/hooks.js +0 -115
  86. package/build/adapters/gemini-cli/index.d.ts +0 -80
  87. package/build/adapters/gemini-cli/index.js +0 -483
  88. package/build/adapters/jetbrains-copilot/config.d.ts +0 -8
  89. package/build/adapters/jetbrains-copilot/config.js +0 -8
  90. package/build/adapters/jetbrains-copilot/hooks.d.ts +0 -59
  91. package/build/adapters/jetbrains-copilot/hooks.js +0 -87
  92. package/build/adapters/jetbrains-copilot/index.d.ts +0 -31
  93. package/build/adapters/jetbrains-copilot/index.js +0 -131
  94. package/build/adapters/kimi/config.d.ts +0 -8
  95. package/build/adapters/kimi/config.js +0 -8
  96. package/build/adapters/kimi/hooks.d.ts +0 -28
  97. package/build/adapters/kimi/hooks.js +0 -34
  98. package/build/adapters/kimi/index.d.ts +0 -66
  99. package/build/adapters/kimi/index.js +0 -537
  100. package/build/adapters/kimi/paths.d.ts +0 -21
  101. package/build/adapters/kimi/paths.js +0 -52
  102. package/build/adapters/kimi/usage.d.ts +0 -82
  103. package/build/adapters/kimi/usage.js +0 -217
  104. package/build/adapters/kiro/hooks.d.ts +0 -61
  105. package/build/adapters/kiro/hooks.js +0 -94
  106. package/build/adapters/kiro/index.d.ts +0 -61
  107. package/build/adapters/kiro/index.js +0 -301
  108. package/build/adapters/omp/index.d.ts +0 -65
  109. package/build/adapters/omp/index.js +0 -182
  110. package/build/adapters/omp/plugin.d.ts +0 -81
  111. package/build/adapters/omp/plugin.js +0 -331
  112. package/build/adapters/omp/usage.d.ts +0 -49
  113. package/build/adapters/omp/usage.js +0 -110
  114. package/build/adapters/openclaw/config.d.ts +0 -8
  115. package/build/adapters/openclaw/config.js +0 -8
  116. package/build/adapters/openclaw/hooks.d.ts +0 -50
  117. package/build/adapters/openclaw/hooks.js +0 -61
  118. package/build/adapters/openclaw/index.d.ts +0 -74
  119. package/build/adapters/openclaw/index.js +0 -439
  120. package/build/adapters/openclaw/mcp-tools.d.ts +0 -54
  121. package/build/adapters/openclaw/mcp-tools.js +0 -207
  122. package/build/adapters/openclaw/plugin.d.ts +0 -141
  123. package/build/adapters/openclaw/plugin.js +0 -818
  124. package/build/adapters/openclaw/session-db.d.ts +0 -55
  125. package/build/adapters/openclaw/session-db.js +0 -88
  126. package/build/adapters/openclaw/usage.d.ts +0 -34
  127. package/build/adapters/openclaw/usage.js +0 -52
  128. package/build/adapters/openclaw/workspace-router.d.ts +0 -29
  129. package/build/adapters/openclaw/workspace-router.js +0 -64
  130. package/build/adapters/opencode/config.d.ts +0 -8
  131. package/build/adapters/opencode/config.js +0 -8
  132. package/build/adapters/opencode/hooks.d.ts +0 -38
  133. package/build/adapters/opencode/hooks.js +0 -50
  134. package/build/adapters/opencode/index.d.ts +0 -67
  135. package/build/adapters/opencode/index.js +0 -463
  136. package/build/adapters/opencode/plugin.d.ts +0 -184
  137. package/build/adapters/opencode/plugin.js +0 -558
  138. package/build/adapters/opencode/zod3tov4.d.ts +0 -1
  139. package/build/adapters/opencode/zod3tov4.js +0 -132
  140. package/build/adapters/pi/extension.d.ts +0 -81
  141. package/build/adapters/pi/extension.js +0 -861
  142. package/build/adapters/pi/index.d.ts +0 -57
  143. package/build/adapters/pi/index.js +0 -173
  144. package/build/adapters/pi/mcp-bridge.d.ts +0 -268
  145. package/build/adapters/pi/mcp-bridge.js +0 -894
  146. package/build/adapters/qwen-code/hooks.d.ts +0 -26
  147. package/build/adapters/qwen-code/hooks.js +0 -29
  148. package/build/adapters/qwen-code/index.d.ts +0 -40
  149. package/build/adapters/qwen-code/index.js +0 -361
  150. package/build/adapters/qwen-code/usage.d.ts +0 -90
  151. package/build/adapters/qwen-code/usage.js +0 -222
  152. package/build/adapters/types.d.ts +0 -360
  153. package/build/adapters/types.js +0 -118
  154. package/build/adapters/vscode-copilot/config.d.ts +0 -8
  155. package/build/adapters/vscode-copilot/config.js +0 -8
  156. package/build/adapters/vscode-copilot/hooks.d.ts +0 -71
  157. package/build/adapters/vscode-copilot/hooks.js +0 -98
  158. package/build/adapters/vscode-copilot/index.d.ts +0 -32
  159. package/build/adapters/vscode-copilot/index.js +0 -222
  160. package/build/adapters/zed/index.d.ts +0 -40
  161. package/build/adapters/zed/index.js +0 -163
  162. package/build/cache-heal.d.ts +0 -48
  163. package/build/cache-heal.js +0 -150
  164. package/build/cli.d.ts +0 -34
  165. package/build/cli.js +0 -1827
  166. package/build/concurrency/runPool.d.ts +0 -36
  167. package/build/concurrency/runPool.js +0 -51
  168. package/build/db-base.d.ts +0 -179
  169. package/build/db-base.js +0 -569
  170. package/build/executor.d.ts +0 -72
  171. package/build/executor.js +0 -678
  172. package/build/exit-classify.d.ts +0 -19
  173. package/build/exit-classify.js +0 -12
  174. package/build/fetch-cache.d.ts +0 -13
  175. package/build/fetch-cache.js +0 -15
  176. package/build/lifecycle.d.ts +0 -124
  177. package/build/lifecycle.js +0 -278
  178. package/build/openclaw/mcp-tools.d.ts +0 -54
  179. package/build/openclaw/mcp-tools.js +0 -198
  180. package/build/openclaw/workspace-router.d.ts +0 -29
  181. package/build/openclaw/workspace-router.js +0 -64
  182. package/build/openclaw-plugin.d.ts +0 -130
  183. package/build/openclaw-plugin.js +0 -626
  184. package/build/opencode-plugin.d.ts +0 -122
  185. package/build/opencode-plugin.js +0 -375
  186. package/build/pi-extension.d.ts +0 -14
  187. package/build/pi-extension.js +0 -451
  188. package/build/routing-block.d.ts +0 -8
  189. package/build/routing-block.js +0 -86
  190. package/build/runPool.d.ts +0 -36
  191. package/build/runPool.js +0 -51
  192. package/build/runtime.d.ts +0 -71
  193. package/build/runtime.js +0 -659
  194. package/build/search/auto-memory.d.ts +0 -47
  195. package/build/search/auto-memory.js +0 -170
  196. package/build/search/ctx-search-schema.d.ts +0 -90
  197. package/build/search/ctx-search-schema.js +0 -135
  198. package/build/search/flood-guard.d.ts +0 -57
  199. package/build/search/flood-guard.js +0 -80
  200. package/build/search/unified.d.ts +0 -56
  201. package/build/search/unified.js +0 -104
  202. package/build/security.d.ts +0 -206
  203. package/build/security.js +0 -780
  204. package/build/server.d.ts +0 -184
  205. package/build/server.js +0 -4542
  206. package/build/session/analytics.d.ts +0 -745
  207. package/build/session/analytics.js +0 -2369
  208. package/build/session/db.d.ts +0 -468
  209. package/build/session/db.js +0 -1308
  210. package/build/session/error-classifier.d.ts +0 -87
  211. package/build/session/error-classifier.js +0 -303
  212. package/build/session/event-emit.d.ts +0 -48
  213. package/build/session/event-emit.js +0 -101
  214. package/build/session/extract.d.ts +0 -333
  215. package/build/session/extract.js +0 -2688
  216. package/build/session/model-prices.json +0 -429
  217. package/build/session/persist-tool-calls.d.ts +0 -54
  218. package/build/session/persist-tool-calls.js +0 -105
  219. package/build/session/pricing.d.ts +0 -64
  220. package/build/session/pricing.js +0 -151
  221. package/build/session/project-attribution.d.ts +0 -73
  222. package/build/session/project-attribution.js +0 -245
  223. package/build/session/purge.d.ts +0 -138
  224. package/build/session/purge.js +0 -240
  225. package/build/session/snapshot.d.ts +0 -46
  226. package/build/session/snapshot.js +0 -532
  227. package/build/store-directory.d.ts +0 -56
  228. package/build/store-directory.js +0 -254
  229. package/build/store.d.ts +0 -147
  230. package/build/store.js +0 -1714
  231. package/build/tool-naming.d.ts +0 -4
  232. package/build/tool-naming.js +0 -24
  233. package/build/truncate.d.ts +0 -57
  234. package/build/truncate.js +0 -142
  235. package/build/types.d.ts +0 -117
  236. package/build/types.js +0 -20
  237. package/build/util/claude-config.d.ts +0 -32
  238. package/build/util/claude-config.js +0 -84
  239. package/build/util/hook-config.d.ts +0 -27
  240. package/build/util/hook-config.js +0 -76
  241. package/build/util/jsonc.d.ts +0 -14
  242. package/build/util/jsonc.js +0 -104
  243. package/build/util/plugin-cache-integrity.d.ts +0 -51
  244. package/build/util/plugin-cache-integrity.js +0 -146
  245. package/build/util/project-dir.d.ts +0 -149
  246. package/build/util/project-dir.js +0 -340
  247. package/build/util/sibling-mcp.d.ts +0 -79
  248. package/build/util/sibling-mcp.js +0 -181
  249. package/cli.bundle.mjs +0 -1235
  250. package/configs/antigravity/GEMINI.md +0 -68
  251. package/configs/antigravity/mcp_config.json +0 -7
  252. package/configs/antigravity-cli/hooks/hooks.json +0 -37
  253. package/configs/antigravity-cli/hooks.json +0 -37
  254. package/configs/antigravity-cli/mcp_config.json +0 -10
  255. package/configs/antigravity-cli/plugin.json +0 -14
  256. package/configs/antigravity-cli/rules/context-mode.md +0 -77
  257. package/configs/antigravity-cli/skills/context-mode/SKILL.md +0 -77
  258. package/configs/claude-code/CLAUDE.md +0 -91
  259. package/configs/codex/AGENTS.md +0 -99
  260. package/configs/codex/config.toml +0 -8
  261. package/configs/codex/hooks.json +0 -47
  262. package/configs/copilot-cli/.github/plugin/plugin.json +0 -23
  263. package/configs/copilot-cli/.mcp.json +0 -12
  264. package/configs/copilot-cli/README.md +0 -47
  265. package/configs/copilot-cli/hooks.json +0 -41
  266. package/configs/copilot-cli/skills/context-mode/SKILL.md +0 -38
  267. package/configs/cursor/context-mode.mdc +0 -76
  268. package/configs/cursor/hooks.json +0 -21
  269. package/configs/cursor/mcp.json +0 -7
  270. package/configs/gemini-cli/GEMINI.md +0 -88
  271. package/configs/gemini-cli/mcp.json +0 -7
  272. package/configs/gemini-cli/settings.json +0 -60
  273. package/configs/jetbrains-copilot/copilot-instructions.md +0 -80
  274. package/configs/jetbrains-copilot/hooks.json +0 -16
  275. package/configs/jetbrains-copilot/mcp.json +0 -7
  276. package/configs/kilo/AGENTS.md +0 -84
  277. package/configs/kilo/kilo.json +0 -6
  278. package/configs/kimi/hooks.json +0 -54
  279. package/configs/kiro/KIRO.md +0 -84
  280. package/configs/kiro/agent.json +0 -18
  281. package/configs/kiro/mcp.json +0 -7
  282. package/configs/omp/SYSTEM.md +0 -85
  283. package/configs/omp/mcp.json +0 -7
  284. package/configs/openclaw/AGENTS.md +0 -87
  285. package/configs/openclaw/openclaw.json +0 -13
  286. package/configs/opencode/AGENTS.md +0 -84
  287. package/configs/opencode/opencode.json +0 -6
  288. package/configs/pi/AGENTS.md +0 -3
  289. package/configs/qwen-code/QWEN.md +0 -91
  290. package/configs/vscode-copilot/copilot-instructions.md +0 -80
  291. package/configs/vscode-copilot/hooks.json +0 -16
  292. package/configs/vscode-copilot/mcp.json +0 -7
  293. package/configs/zed/AGENTS.md +0 -68
  294. package/hooks/antigravity-cli/payload.mjs +0 -98
  295. package/hooks/antigravity-cli/posttooluse.mjs +0 -138
  296. package/hooks/antigravity-cli/pretooluse.mjs +0 -78
  297. package/hooks/antigravity-cli/stop.mjs +0 -58
  298. package/hooks/auto-injection.mjs +0 -102
  299. package/hooks/cache-heal-utils.mjs +0 -379
  300. package/hooks/codex/platform.mjs +0 -1
  301. package/hooks/codex/posttooluse.mjs +0 -66
  302. package/hooks/codex/precompact.mjs +0 -70
  303. package/hooks/codex/pretooluse.mjs +0 -42
  304. package/hooks/codex/sessionstart.mjs +0 -121
  305. package/hooks/codex/stop.mjs +0 -138
  306. package/hooks/codex/userpromptsubmit.mjs +0 -75
  307. package/hooks/copilot-cli/posttooluse.mjs +0 -79
  308. package/hooks/copilot-cli/precompact.mjs +0 -66
  309. package/hooks/copilot-cli/pretooluse.mjs +0 -41
  310. package/hooks/copilot-cli/sessionstart.mjs +0 -121
  311. package/hooks/copilot-cli/stop.mjs +0 -59
  312. package/hooks/copilot-cli/userpromptsubmit.mjs +0 -77
  313. package/hooks/core/codex-caps.mjs +0 -112
  314. package/hooks/core/formatters.mjs +0 -356
  315. package/hooks/core/mcp-ready.mjs +0 -109
  316. package/hooks/core/platform-detect.mjs +0 -49
  317. package/hooks/core/routing.mjs +0 -1017
  318. package/hooks/core/stdin.mjs +0 -90
  319. package/hooks/core/tool-naming.mjs +0 -57
  320. package/hooks/cursor/afteragentresponse.mjs +0 -74
  321. package/hooks/cursor/hooks.json +0 -31
  322. package/hooks/cursor/posttooluse.mjs +0 -72
  323. package/hooks/cursor/pretooluse.mjs +0 -26
  324. package/hooks/cursor/sessionstart.mjs +0 -97
  325. package/hooks/cursor/stop.mjs +0 -48
  326. package/hooks/ensure-deps.mjs +0 -254
  327. package/hooks/formatters/claude-code.mjs +0 -113
  328. package/hooks/formatters/cursor.mjs +0 -37
  329. package/hooks/formatters/gemini-cli.mjs +0 -55
  330. package/hooks/formatters/vscode-copilot.mjs +0 -55
  331. package/hooks/gemini-cli/aftermodel.mjs +0 -70
  332. package/hooks/gemini-cli/aftertool.mjs +0 -61
  333. package/hooks/gemini-cli/beforeagent.mjs +0 -99
  334. package/hooks/gemini-cli/beforetool.mjs +0 -27
  335. package/hooks/gemini-cli/precompress.mjs +0 -55
  336. package/hooks/gemini-cli/sessionstart.mjs +0 -137
  337. package/hooks/heal-partial-install.mjs +0 -712
  338. package/hooks/jetbrains-copilot/posttooluse.mjs +0 -61
  339. package/hooks/jetbrains-copilot/precompact.mjs +0 -55
  340. package/hooks/jetbrains-copilot/pretooluse.mjs +0 -27
  341. package/hooks/jetbrains-copilot/sessionstart.mjs +0 -124
  342. package/hooks/kimi/platform.mjs +0 -1
  343. package/hooks/kimi/posttooluse.mjs +0 -72
  344. package/hooks/kimi/precompact.mjs +0 -80
  345. package/hooks/kimi/pretooluse.mjs +0 -42
  346. package/hooks/kimi/sessionend.mjs +0 -61
  347. package/hooks/kimi/sessionstart.mjs +0 -113
  348. package/hooks/kimi/stop.mjs +0 -132
  349. package/hooks/kimi/userpromptsubmit.mjs +0 -90
  350. package/hooks/kiro/agentspawn.mjs +0 -97
  351. package/hooks/kiro/posttooluse.mjs +0 -51
  352. package/hooks/kiro/pretooluse.mjs +0 -64
  353. package/hooks/kiro/userpromptsubmit.mjs +0 -88
  354. package/hooks/normalize-hooks.mjs +0 -323
  355. package/hooks/platform-bridge.mjs +0 -340
  356. package/hooks/posttooluse.mjs +0 -187
  357. package/hooks/precompact.mjs +0 -100
  358. package/hooks/pretooluse.mjs +0 -227
  359. package/hooks/qwen-code/platform.mjs +0 -1
  360. package/hooks/qwen-code/stop.mjs +0 -168
  361. package/hooks/routing-block.mjs +0 -105
  362. package/hooks/run-hook.mjs +0 -95
  363. package/hooks/security.bundle.mjs +0 -2
  364. package/hooks/session-attribution.bundle.mjs +0 -1
  365. package/hooks/session-db.bundle.mjs +0 -144
  366. package/hooks/session-directive.mjs +0 -520
  367. package/hooks/session-extract.bundle.mjs +0 -3
  368. package/hooks/session-helpers.mjs +0 -428
  369. package/hooks/session-loaders.mjs +0 -448
  370. package/hooks/session-snapshot.bundle.mjs +0 -32
  371. package/hooks/sessionstart.mjs +0 -464
  372. package/hooks/stop.mjs +0 -82
  373. package/hooks/suppress-stderr.mjs +0 -25
  374. package/hooks/userpromptsubmit.mjs +0 -108
  375. package/hooks/vscode-copilot/posttooluse.mjs +0 -61
  376. package/hooks/vscode-copilot/precompact.mjs +0 -55
  377. package/hooks/vscode-copilot/pretooluse.mjs +0 -27
  378. package/hooks/vscode-copilot/sessionstart.mjs +0 -129
  379. package/openclaw.plugin.json +0 -38
  380. package/scripts/heal-better-sqlite3.mjs +0 -430
  381. package/scripts/heal-installed-plugins.mjs +0 -598
  382. package/scripts/plugin-cache-integrity.mjs +0 -248
  383. package/scripts/postinstall.mjs +0 -384
  384. package/server.bundle.mjs +0 -1161
  385. package/skills/.ignore +0 -7
  386. package/skills/context-mode/SKILL.md +0 -300
  387. package/skills/context-mode/references/anti-patterns.md +0 -283
  388. package/skills/context-mode/references/patterns-javascript.md +0 -298
  389. package/skills/context-mode/references/patterns-python.md +0 -304
  390. package/skills/context-mode/references/patterns-shell.md +0 -277
  391. package/skills/ctx-index/SKILL.md +0 -46
  392. package/skills/ctx-insight/SKILL.md +0 -24
  393. package/skills/ctx-purge/SKILL.md +0 -49
  394. package/skills/ctx-search/SKILL.md +0 -35
  395. package/start.mjs +0 -616
@@ -1,745 +0,0 @@
1
- /**
2
- * AnalyticsEngine — Runtime savings + session continuity reporting.
3
- *
4
- * Computes context-window savings from runtime stats and queries
5
- * session continuity data from SessionDB.
6
- *
7
- * Usage:
8
- * const engine = new AnalyticsEngine(sessionDb);
9
- * const report = engine.queryAll(runtimeStats);
10
- */
11
- /** Database adapter — anything with a prepare() method (better-sqlite3, bun:sqlite, etc.) */
12
- export interface DatabaseAdapter {
13
- prepare(sql: string): {
14
- run(...params: unknown[]): unknown;
15
- get(...params: unknown[]): unknown;
16
- all(...params: unknown[]): unknown[];
17
- };
18
- }
19
- /** Context savings result (#1) */
20
- export interface ContextSavings {
21
- rawBytes: number;
22
- contextBytes: number;
23
- savedBytes: number;
24
- savedPercent: number;
25
- }
26
- /** Think in code comparison result (#2) */
27
- export interface ThinkInCodeComparison {
28
- fileBytes: number;
29
- outputBytes: number;
30
- ratio: number;
31
- }
32
- /** Tool-level savings result (#3) */
33
- export interface ToolSavingsRow {
34
- tool: string;
35
- rawBytes: number;
36
- contextBytes: number;
37
- savedBytes: number;
38
- }
39
- /** Sandbox I/O result (#19) */
40
- export interface SandboxIO {
41
- inputBytes: number;
42
- outputBytes: number;
43
- }
44
- /** MCP tool usage row — concurrency stats for batch-style tools. */
45
- export interface McpToolUsageRow {
46
- tool_name: string;
47
- calls: number;
48
- median_concurrency: number | null;
49
- max_concurrency: number | null;
50
- }
51
- /**
52
- * Conversation-scoped stats — aggregated from `session_events` for a single
53
- * `session_id` across every worktree DB plus the compact-rescue snapshot from
54
- * `session_resume`. Replaces the broken in-memory `tool_call_counter` that
55
- * only saw `ctx_*` MCP calls and reset to 0 every time the MCP server PID
56
- * changed (which is what made hours-of-work conversations show "1 call · 5 KB").
57
- */
58
- export interface ConversationStats {
59
- /** session_id this aggregate covers (the current Claude Code conversation). */
60
- sessionId: string;
61
- /** Total event count for this session_id, summed across all DBs. */
62
- events: number;
63
- /** Distinct DB files this session_id appeared in (a rotation indicator). */
64
- dbCount: number;
65
- /** Wall-clock days from first to last event. Captures real activity length. */
66
- daysAlive: number;
67
- /** Bytes restored from the compact snapshot for this session_id. 0 if no compact. */
68
- snapshotBytes: number;
69
- /** Number of compact snapshots consumed for this session_id. */
70
- snapshotsConsumed: number;
71
- /** Category breakdown for this session_id. */
72
- byCategory: Array<{
73
- category: string;
74
- count: number;
75
- label: string;
76
- }>;
77
- /**
78
- * Earliest event timestamp (ms epoch) for this session_id across every DB.
79
- * Used by the section-1 "started X" line in the narrative renderer. 0 when
80
- * the session has no events yet. Optional for back-compat with older
81
- * callers / fixtures that pre-date the narrative layout.
82
- */
83
- firstEventMs?: number;
84
- /** Latest event timestamp (ms epoch) — pairs with firstEventMs. */
85
- lastEventMs?: number;
86
- /**
87
- * Wall-clock timestamp of the most recent /compact rescue for this session.
88
- * Drives the "On <datetime>, /compact fired" line in section 1. Undefined
89
- * when the conversation has never been compacted.
90
- */
91
- lastRescueMs?: number;
92
- /**
93
- * Per-day capture breakdown for the section-1 horizontal timeline. Each
94
- * entry is one calendar day (UTC midnight ms) with that day's event count
95
- * + optional rescueBytes when /compact fired on that day. Empty array
96
- * when no events recorded yet.
97
- */
98
- byDay?: Array<{
99
- ms: number;
100
- count: number;
101
- rescueBytes?: number;
102
- }>;
103
- }
104
- /** Runtime stats tracked by server.ts during a live session. */
105
- export interface RuntimeStats {
106
- bytesReturned: Record<string, number>;
107
- bytesIndexed: number;
108
- bytesSandboxed: number;
109
- calls: Record<string, number>;
110
- sessionStart: number;
111
- cacheHits: number;
112
- cacheMisses?: number;
113
- cacheBytesSaved: number;
114
- }
115
- /**
116
- * Index observability snapshot — point-in-time view of the persistent
117
- * content store. Optional input to `formatReport` so callers that don't
118
- * have store access (or don't want the extra DB hit) can omit it.
119
- */
120
- export interface IndexState {
121
- totalChunks: number;
122
- totalSources: number;
123
- lastIndexedAt?: string;
124
- }
125
- /** Unified report combining runtime stats, DB analytics, and continuity data. */
126
- export interface FullReport {
127
- /** Runtime context savings (passed in, not from DB) */
128
- savings: {
129
- processed_kb: number;
130
- entered_kb: number;
131
- saved_kb: number;
132
- pct: number;
133
- savings_ratio: number;
134
- by_tool: Array<{
135
- tool: string;
136
- calls: number;
137
- context_kb: number;
138
- tokens: number;
139
- }>;
140
- total_calls: number;
141
- total_bytes_returned: number;
142
- kept_out: number;
143
- total_processed: number;
144
- };
145
- cache?: {
146
- hits: number;
147
- misses: number;
148
- hit_rate: number;
149
- bytes_saved: number;
150
- ttl_hours_left: number;
151
- total_with_cache: number;
152
- total_savings_ratio: number;
153
- };
154
- /** Session metadata from SessionDB */
155
- session: {
156
- id: string;
157
- uptime_min: string;
158
- };
159
- /** Session continuity data */
160
- continuity: {
161
- total_events: number;
162
- by_category: Array<{
163
- category: string;
164
- count: number;
165
- label: string;
166
- preview: string;
167
- why: string;
168
- }>;
169
- compact_count: number;
170
- resume_ready: boolean;
171
- };
172
- /** Persistent project memory — all events across all sessions */
173
- projectMemory: {
174
- total_events: number;
175
- session_count: number;
176
- by_category: Array<{
177
- category: string;
178
- count: number;
179
- label: string;
180
- }>;
181
- };
182
- }
183
- /**
184
- * Human-readable labels for event categories.
185
- *
186
- * Each label is a sentence-case phrase that reads like a benefit, not a
187
- * column name. The user shouldn't see raw schema words like "external-ref"
188
- * or "agent-finding" — those leak the database into the UX. When a new
189
- * category lands without an entry here, the renderer falls through to the
190
- * raw category id; that's a copy-debt signal, fix it here.
191
- */
192
- export declare const categoryLabels: Record<string, string>;
193
- /** Explains why each category matters for continuity. */
194
- export declare const categoryHints: Record<string, string>;
195
- export declare class AnalyticsEngine {
196
- private readonly db;
197
- /**
198
- * Create an AnalyticsEngine.
199
- *
200
- * Accepts either a SessionDB instance (extracts internal db via
201
- * the protected getter — use the static fromDB helper for raw adapters)
202
- * or any object with a prepare() method for direct usage.
203
- */
204
- constructor(db: DatabaseAdapter);
205
- /**
206
- * #1 Context Savings Total — bytes kept out of context window.
207
- *
208
- * Stub: requires server.ts to accumulate rawBytes and contextBytes
209
- * during a live session. Call with tracked values.
210
- */
211
- static contextSavingsTotal(rawBytes: number, contextBytes: number): ContextSavings;
212
- /**
213
- * #2 Think in Code Comparison — ratio of file size to sandbox output size.
214
- *
215
- * Stub: requires server.ts tracking of execute/execute_file calls.
216
- */
217
- static thinkInCodeComparison(fileBytes: number, outputBytes: number): ThinkInCodeComparison;
218
- /**
219
- * #3 Tool Savings — per-tool breakdown of context savings.
220
- *
221
- * Stub: requires per-tool accumulators in server.ts.
222
- */
223
- static toolSavings(tools: Array<{
224
- tool: string;
225
- rawBytes: number;
226
- contextBytes: number;
227
- }>): ToolSavingsRow[];
228
- /**
229
- * #19 Sandbox I/O — total input/output bytes processed by the sandbox.
230
- *
231
- * Stub: requires PolyglotExecutor byte counters.
232
- */
233
- static sandboxIO(inputBytes: number, outputBytes: number): SandboxIO;
234
- /**
235
- * MCP tool usage — call counts and concurrency stats per MCP tool.
236
- *
237
- * Reads `mcp_tool_call` events, parses the JSON payload, and aggregates:
238
- * - call count per tool_name
239
- * - median + max of `params.concurrency` (only for tools that take it,
240
- * e.g. ctx_batch_execute, ctx_fetch_and_index). Returns null when the
241
- * tool doesn't carry a concurrency param so callers can render N/A.
242
- *
243
- * Best-effort: malformed rows or truncated payloads are skipped silently.
244
- */
245
- getMcpToolUsage(): McpToolUsageRow[];
246
- /**
247
- * Build a FullReport by merging runtime stats (passed in)
248
- * with continuity data from the DB.
249
- *
250
- * This is the ONE call that ctx_stats should use.
251
- */
252
- queryAll(runtimeStats: RuntimeStats): FullReport;
253
- }
254
- /**
255
- * Where one adapter stores its context-mode sidecars on disk. Mirrors the
256
- * map in `src/adapters/detect.ts:92-111` (`getSessionDirSegments`) so we
257
- * never go out of sync as a single source of truth.
258
- *
259
- * `sessionsDir` = `<home>/<segments>/context-mode/sessions`
260
- * `contentDir` = `<home>/<segments>/context-mode/content`
261
- *
262
- * Why duplicated here: `getSessionDirSegments` returns segments relative to
263
- * `homedir()`; analytics needs the absolute joined paths for both `sessions`
264
- * and `content` siblings. Keeping a parallel hard-coded list avoids importing
265
- * detect.ts (which pulls in adapter loaders) into the stats path.
266
- */
267
- export interface AdapterDirEntry {
268
- /** Adapter id matching `src/adapters/detect.ts` PlatformId. */
269
- name: string;
270
- /** Absolute path to `<home>/<segments>/context-mode/sessions`. */
271
- sessionsDir: string;
272
- /** Absolute path to `<home>/<segments>/context-mode/content`. */
273
- contentDir: string;
274
- }
275
- /**
276
- * Enumerate every known adapter's sessions + content dirs under `home`.
277
- * Used by `getMultiAdapterLifetimeStats` and `getMultiAdapterRealBytesStats`
278
- * so a single call surfaces "your work everywhere on this machine across
279
- * all AI tools" (the marketing line).
280
- *
281
- * Returns ALL 17 adapters even when the dir doesn't exist on disk — the
282
- * scanner functions filter to existing dirs. That keeps the enumeration
283
- * pure / testable without filesystem dependencies.
284
- */
285
- export declare function enumerateAdapterDirs(opts?: {
286
- home?: string;
287
- }): AdapterDirEntry[];
288
- /** Aggregated stats spanning every SessionDB + auto-memory under the user's profile. */
289
- export interface LifetimeStats {
290
- totalEvents: number;
291
- totalSessions: number;
292
- autoMemoryCount: number;
293
- autoMemoryProjects: number;
294
- /** Per-prefix breakdown of auto-memory files (user/feedback/project/...). */
295
- autoMemoryByPrefix: Record<string, number>;
296
- /**
297
- * Per-category event counts aggregated across every SessionDB on disk.
298
- * Keys are the raw category strings (file/cwd/rule/...) — the renderer
299
- * looks them up against `categoryLabels` for display. Empty `{}` when no
300
- * sidecar has any events. Optional for back-compat with older fixtures.
301
- */
302
- categoryCounts: Record<string, number>;
303
- /**
304
- * Total bytes restored from compact-rescue snapshots across every DB on
305
- * disk. Adds the rescue benefit to lifetime $ so the headline isn't
306
- * silently undercounting the killer feature. 0 when no compact has fired
307
- * or older fixtures don't pass this. Optional for back-compat with tests.
308
- */
309
- rescueBytes?: number;
310
- /**
311
- * Earliest event timestamp (ms epoch) across every DB. Used for the
312
- * "since 2026-04-14" lifetime narrative. 0 when unknown. Optional.
313
- */
314
- firstEventMs?: number;
315
- /**
316
- * Distinct project_dir count across every DB. Different from
317
- * `autoMemoryProjects` (which only counts dirs with auto-memory files).
318
- * Captures every cwd context-mode has ever seen events for. Optional.
319
- */
320
- distinctProjects?: number;
321
- }
322
- /**
323
- * Aggregate lifetime stats from all SessionDB files in `sessionsDir` and
324
- * all auto-memory markdown files under `memoryRoot/<project>/memory/`.
325
- *
326
- * Best-effort: silently ignores missing/unreadable files so ctx_stats
327
- * can never be broken by a corrupt sidecar.
328
- */
329
- export declare function getLifetimeStats(opts?: {
330
- sessionsDir?: string;
331
- memoryRoot?: string;
332
- /** Override for tests — defaults to db-base loadDatabase(). */
333
- loadDatabase?: () => unknown;
334
- }): LifetimeStats;
335
- /**
336
- * Aggregate every event for one `session_id` across all SessionDB files in
337
- * `sessionsDir` plus the compact-rescue snapshot bytes from `session_resume`.
338
- *
339
- * Why this exists: the Claude Code session_id can persist across days while
340
- * the underlying DB file rotates (size cap), and a compact-rescue snapshot
341
- * carries hundreds of KB of context that would otherwise have been lost. The
342
- * old in-memory `tool_call_counter` saw none of this — it counted only `ctx_*`
343
- * MCP calls against the current MCP server PID and reset on every restart.
344
- * Reading from `session_events` + `session_resume` is the source-of-truth
345
- * version that matches what users actually experienced.
346
- */
347
- export declare function getConversationStats(opts: {
348
- sessionId: string;
349
- sessionsDir?: string;
350
- /** Optional worktree filename prefix (sha256(cwd)[:16]). When omitted, scans every DB. */
351
- worktreeHash?: string;
352
- loadDatabase?: () => unknown;
353
- }): ConversationStats;
354
- /**
355
- * Real-bytes counter the renderer uses to replace the conservative
356
- * `events × 256` token estimate. Reads four sources from disk and
357
- * returns the sum the renderer divides by 4 to get tokens.
358
- *
359
- * - `eventDataBytes` = SUM(LENGTH(data)) FROM session_events
360
- * - `bytesAvoided` = SUM(bytes_avoided) FROM session_events
361
- * - `bytesReturned` = SUM(bytes_returned) FROM session_events
362
- * - `snapshotBytes` = SUM(LENGTH(snapshot)) FROM session_resume
363
- * - `totalSavedTokens` = (eventDataBytes + bytesAvoided + snapshotBytes) / 4
364
- *
365
- * `bytesReturned` is reported but NOT folded into `totalSavedTokens`
366
- * because it represents bytes the model already paid for — adding it
367
- * would double-count what's already on the user's invoice.
368
- */
369
- export interface RealBytesStats {
370
- eventDataBytes: number;
371
- bytesAvoided: number;
372
- bytesReturned: number;
373
- snapshotBytes: number;
374
- /**
375
- * v1.0.133 Slice 3: bytes attributed to this session in the FTS5 content
376
- * DB — `SUM(LENGTH(title) + LENGTH(content)) FROM chunks WHERE session_id = ?`.
377
- *
378
- * Read-only, render-time computation. Populated only when
379
- * `getRealBytesStats` is called with both `sessionId` AND `contentDbPath`
380
- * (i.e. the conversation tier from ctx_stats). Lifetime / project tiers
381
- * leave this at 0 — aggregating across every adapter's content DB is a
382
- * separate concern.
383
- *
384
- * Legacy chunks with empty `session_id` (pre-Slice-1) are NOT backfilled:
385
- * the architect rejected the time-window join as unsafe. Old conversations
386
- * stay low; new conversations populate honestly.
387
- */
388
- contentBytes: number;
389
- totalSavedTokens: number;
390
- }
391
- /**
392
- * v1.0.133 Slice 3: Sum the bytes attributed to one session in the FTS5
393
- * content DB.
394
- *
395
- * Returns `LENGTH(title) + LENGTH(content)` summed across every chunk
396
- * whose `session_id` column matches `sessionId`. Best-effort — returns 0
397
- * when the DB file is missing, the schema lacks the `session_id` column
398
- * (pre-Slice-1 content DBs), or the query fails. Never throws.
399
- *
400
- * Render-time only. Does NOT mutate the content DB. Architect-approved
401
- * because the read-only join carries no risk of cross-session attribution
402
- * (the FK was set at chunk insert time by Slice 1).
403
- */
404
- export declare function getContentBytesForSession(sessionId: string, contentDbPath: string, opts?: {
405
- loadDatabase?: () => unknown;
406
- }): number;
407
- /**
408
- * v1.0.134 SLICE C — lifetime tier all-chunks aggregate.
409
- *
410
- * Sibling of {@link getContentBytesForSession} that omits the session_id
411
- * filter so the lifetime tier sees every chunk in the content store —
412
- * including legacy unattributed rows (sessionId === '') and chunks
413
- * attributed to other adapters' sessions. Without this, the lifetime
414
- * "kept out" headline only counts session_events.bytes_avoided and
415
- * misses the bulk of indexed payload.
416
- *
417
- * Best-effort: returns 0 when the DB file is missing, the schema lacks
418
- * the `chunks` table, or the query fails. Never throws — same contract
419
- * as the rest of the analytics module so a corrupt content DB cannot
420
- * crash ctx_stats.
421
- */
422
- export declare function getContentBytesAllSessions(contentDbPath: string, opts?: {
423
- loadDatabase?: () => unknown;
424
- }): number;
425
- /**
426
- * Compute real-bytes stats across one session, one project (worktree
427
- * filter), or every session on disk (lifetime).
428
- *
429
- * - Pass `sessionId` for the conversation tier.
430
- * - Pass `worktreeHash` to filter `*.db` files by name prefix
431
- * (per-project lifetime — `sha256(cwd).slice(0, 16)`).
432
- * - Pass neither — full lifetime aggregate.
433
- *
434
- * Best-effort: returns zeroes when the dir is missing, the DB is
435
- * corrupt, or the session has no events. Never throws — same
436
- * contract as `getConversationStats` / `getLifetimeStats` so the
437
- * stats-render path can never crash on a bad sidecar.
438
- */
439
- export declare function getRealBytesStats(opts: {
440
- sessionId?: string;
441
- sessionsDir?: string;
442
- worktreeHash?: string;
443
- /**
444
- * v1.0.148 follow-up (Bug E+F): when set, the function aggregates across
445
- * EVERY session whose `session_meta.project_dir` matches this value, not
446
- * just one session_id. Resolves the per-conversation under-attribution:
447
- * one Claude Code conversation typically spans many session_ids (resume
448
- * cycles, /compact rebirths, PID sub-process sessions spawned by
449
- * ctx_execute), so a single-session_id filter loses the sandbox-burst
450
- * bytes_avoided that all live under the conversation's cwd.
451
- *
452
- * Uses a META subquery (`session_id IN (SELECT session_id FROM
453
- * session_meta WHERE project_dir = ?)`), then sums ALL events for
454
- * matching sessions regardless of their event-level project_dir
455
- * (sandbox-burst events write `project_dir = ''` even when the
456
- * META row carries the parent cwd — see Bug F).
457
- *
458
- * Mutually exclusive with `sessionId`. When both are set, `sessionId`
459
- * wins for back-compat.
460
- */
461
- projectDir?: string;
462
- /**
463
- * v1.0.133 Slice 3: when set alongside `sessionId`, the function joins
464
- * the FTS5 content DB at this path and folds chunk bytes into
465
- * `bytesAvoided` + `totalSavedTokens` + `contentBytes`. Render-time
466
- * only — no DB writes.
467
- */
468
- contentDbPath?: string;
469
- loadDatabase?: () => unknown;
470
- }): RealBytesStats;
471
- /**
472
- * Real-usage filter thresholds. Decided in the B3a /diagnose conversation
473
- * to suppress fixture-noise dirs (test runs that touched ~/.X but never
474
- * carried real user work).
475
- *
476
- * An adapter is `isReal=true` iff ALL four hold:
477
- * eventCount >= 100
478
- * distinctProjects >= 5
479
- * lastActivity within 30 days
480
- * avgEventBytes >= 50
481
- *
482
- * Tuneable via `getMultiAdapterLifetimeStats({ filter })` for testing.
483
- */
484
- export interface RealUsageFilter {
485
- minEvents?: number;
486
- minProjects?: number;
487
- recencyMs?: number;
488
- minAvgBytes?: number;
489
- /** Fixed "now" timestamp for deterministic testing. Defaults to Date.now(). */
490
- nowMs?: number;
491
- }
492
- /** Per-adapter scan result returned by {@link scanOneAdapter}. */
493
- export interface AdapterScanResult {
494
- /** Adapter id (matches `enumerateAdapterDirs().name`). */
495
- name: string;
496
- /** Total event rows across every `*.db` in this adapter's sessions dir. */
497
- eventCount: number;
498
- /** Total distinct session_meta rows across every db. */
499
- sessionCount: number;
500
- /** Sum of LENGTH(data) across every session_event row. */
501
- dataBytes: number;
502
- /** Sum of LENGTH(snapshot) across consumed compact-rescue snapshots. */
503
- rescueBytes: number;
504
- /** Reserved for future content/ scan (B3b). 0 today. */
505
- contentBytes: number;
506
- /** Distinct session_id count across all dbs (alias of sessionCount). */
507
- uuidConvs: number;
508
- /** Distinct project_dir values across all session_events. */
509
- projectDirs: string[];
510
- /** Earliest event ms epoch (Number.POSITIVE_INFINITY when no events). */
511
- firstMs: number;
512
- /** Latest event ms epoch (0 when no events). */
513
- lastMs: number;
514
- /** Real-usage flag — see {@link RealUsageFilter}. */
515
- isReal: boolean;
516
- }
517
- /** Aggregated multi-adapter lifetime stats. */
518
- export interface MultiAdapterLifetimeStats {
519
- /** Sum of eventCount across every adapter that exists on disk. */
520
- totalEvents: number;
521
- /** Sum of sessionCount across every adapter. */
522
- totalSessions: number;
523
- /** Sum of dataBytes + rescueBytes across every adapter. */
524
- totalBytes: number;
525
- /** Per-adapter rows for adapters that have >= one .db file. */
526
- perAdapter: AdapterScanResult[];
527
- }
528
- /**
529
- * Aggregate lifetime stats across every adapter dir under `home`.
530
- * The marketing line — "your work everywhere on this machine across all
531
- * AI tools" — depends on this. Existing `getLifetimeStats` (single dir)
532
- * is untouched; this is purely additive.
533
- */
534
- export declare function getMultiAdapterLifetimeStats(opts?: {
535
- home?: string;
536
- loadDatabase?: () => unknown;
537
- filter?: RealUsageFilter;
538
- }): MultiAdapterLifetimeStats;
539
- /** Aggregated multi-adapter real-bytes stats. */
540
- export interface MultiAdapterRealBytesStats extends RealBytesStats {
541
- /** Per-adapter row in the same shape as {@link RealBytesStats}, keyed by name. */
542
- perAdapter: Array<RealBytesStats & {
543
- name: string;
544
- }>;
545
- }
546
- /**
547
- * Aggregate real-bytes stats across every adapter dir under `home`.
548
- * Mirrors `getRealBytesStats` (single dir, analytics.ts:887-989) but
549
- * iterates {@link enumerateAdapterDirs}. Optional `sessionId` /
550
- * `worktreeHash` filters apply uniformly to every dir.
551
- */
552
- export declare function getMultiAdapterRealBytesStats(opts?: {
553
- home?: string;
554
- sessionId?: string;
555
- worktreeHash?: string;
556
- loadDatabase?: () => unknown;
557
- }): MultiAdapterRealBytesStats;
558
- /**
559
- * Marketing-grade labels for auto-memory file prefixes. The renderer sees raw
560
- * filename prefixes (`project_codex_hooks.md` → `project`) — without this map
561
- * the user gets schema words in the UI, which leaks the database into UX.
562
- */
563
- export declare const autoMemoryLabels: Record<string, string>;
564
- /**
565
- * Marketing-grade labels for adapter ids surfaced by
566
- * {@link enumerateAdapterDirs} / {@link getMultiAdapterLifetimeStats}.
567
- * The renderer never shows raw IDs — UX uses the names users see in
568
- * each tool's own surface area.
569
- */
570
- export declare const adapterLabels: Record<string, string>;
571
- /**
572
- * Format a byte count for the narrative dashboard.
573
- *
574
- * Single-unit auto-scale (Grafana / CloudWatch / Datadog convention).
575
- * Decimals shrink as the integer part grows so the number stays readable
576
- * at every magnitude. Max output width is 8 characters which fits the
577
- * existing `padStart(8)` callsites in Sections 1, 3, 4.
578
- *
579
- * < 1 KB → "X B" e.g. "100 B"
580
- * 1 KB – < 100 KB → "X.Y KB" e.g. "4.7 KB", "92.8 KB"
581
- * 100 KB – < 1 MB → "X KB" e.g. "227 KB", "976 KB"
582
- * 1 MB – < 100 MB → "X.Y MB" e.g. "4.5 MB", "11.6 MB"
583
- * 100 MB – < 1 GB → "X MB" e.g. "178 MB", "906 MB"
584
- * 1 GB – < 100 GB → "X.YY GB" e.g. "1.00 GB", "11.36 GB"
585
- * ≥ 100 GB → "X.Y GB" e.g. "216.6 GB"
586
- *
587
- * Replaced the dual-unit "X KB (0.YY MB)" form because the parenthetical
588
- * rounded to 0.00 / 0.01 in the common range and added noise without
589
- * information. Scale awareness comes from the unit jump between rows.
590
- */
591
- export declare function kb(b: number): string;
592
- export declare function detectLocaleAndTz(): {
593
- locale: string;
594
- tz: string;
595
- };
596
- /**
597
- * Render the section-4 "For example: what would that cost?" block.
598
- *
599
- * Translates a lifetime token total into a relatable Opus-4 dollar figure
600
- * + 3 tangible comparisons (Cursor Pro / Claude Max / weekends of API
601
- * coding) + 10-dev team scale projection + alternate-model scale row,
602
- * capped with an EXAMPLES disclaimer. The renderer is intentionally
603
- * liberal with rounding (whole-month Cursor counts, integer weekends)
604
- * because this section is illustrative — the EXAMPLES line tells users
605
- * not to confuse it for a bill.
606
- *
607
- * Returns [] when there's nothing to scale (lifetimeTokens === 0) so
608
- * the section disappears cleanly on a fresh install.
609
- *
610
- * Math constants:
611
- * Opus 4.7/4.8 = $5.00 per 1M input tokens (fallback when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN not set)
612
- * Sonnet 4.6 = $3.00 per 1M input tokens
613
- * GPT-4o = $2.50 per 1M input tokens
614
- * Gemini 2 = $1.25 per 1M input tokens
615
- * Haiku 4.5 = $1.00 per 1M input tokens
616
- * Cursor Pro = $20 / month → "X months of Cursor Pro"
617
- * Claude Max = $200 / month → "X.X months of Claude Max"
618
- * Weekend coding ≈ $73.67 → "X weekends of nonstop API coding"
619
- * Team multiplier = 10× → "At a 10-dev team scale: ~$X over Y days, or ~$Z/year"
620
- */
621
- export declare function renderCostExample(lifetimeBytes: number, lifetimeTokens: number, lifetimeDays: number): string[];
622
- /**
623
- * One day on the horizontal narrative timeline. `ms` is midnight-UTC of
624
- * the day (caller is responsible for normalising); `count` is captures
625
- * for that day; `rescueBytes` (when >0) overlays the ◆ /compact glyph.
626
- */
627
- export interface TimelineDay {
628
- ms: number;
629
- count: number;
630
- rescueBytes?: number;
631
- }
632
- /**
633
- * Render the proportional-spacing horizontal day strip used in section 1
634
- * of the 5-section narrative. Returns the lines verbatim ready to splice
635
- * into the formatReport line buffer:
636
- *
637
- * apr 28 ●──────────────────────●────█──────────────────────◆────● may 10
638
- *
639
- * apr 28 277 captures
640
- * may 4 438 captures ← peak
641
- * may 9 261 captures ◆ /compact rescued 1552 KB
642
- * may 10 100 captures
643
- *
644
- * ● active day █ peak day ◆ /compact rescue
645
- *
646
- * The strip body is exactly 56 chars wide. Day positions are computed as
647
- * `round((day - first) / (last - first) * 55)`. Glyph priority for a
648
- * column: rescue (◆) > peak (█) > active (●). Filler is the box-drawing
649
- * `─` character so the strip reads cleanly in monospace terminals.
650
- */
651
- export declare function renderHorizontalTimeline(days: TimelineDay[], locale: string, tz: string): string[];
652
- /**
653
- * Render a UTC ms timestamp as a human-readable local datetime string in
654
- * the canonical Mert-approved format:
655
- *
656
- * "28 Apr 2026 at 12:16 (Europe/Istanbul)"
657
- *
658
- * Used by the 5-section narrative renderer (formatReport) so users see
659
- * exactly when their conversation started + when /compact rescues fired
660
- * in their wall-clock timezone — never UTC, never ambiguous.
661
- *
662
- * - 24-hour clock with zero-padded minutes ("20:54", not "8:54 PM").
663
- * - Day is NOT zero-padded ("9 May", not "09 May") to match the target.
664
- * - IANA timezone is appended verbatim in parentheses regardless of
665
- * locale so users never misread Istanbul-time as UTC.
666
- * - Returns "" for ms === 0 or NaN so callers can guard the rendered
667
- * line ("started …") without an extra timestamp-validity check.
668
- */
669
- export declare function formatLocalDateTime(ms: number, locale: string, tz: string): string;
670
- /**
671
- * Per-token USD rate — resolves on every call.
672
- * Dynamic when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN is set, Opus 4.7/4.8 input
673
- * ($5 per 1M tokens) otherwise.
674
- */
675
- export declare function pricePerToken(): number;
676
- /**
677
- * Back-compat alias for the original Opus-rate const (PR #401 architect
678
- * P1.1 — single source of truth). Kept as a literal so any third-party
679
- * consumer importing the named constant still resolves to the same
680
- * fallback rate. New code should call pricePerToken() to pick up the
681
- * dynamic Pi env override.
682
- *
683
- * @deprecated Use pricePerToken() to honor PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN.
684
- */
685
- export declare const OPUS_INPUT_PRICE_PER_TOKEN: number;
686
- /** Convert a token count to a USD string at the current per-token rate. */
687
- export declare function tokensToUsd(tokens: number): string;
688
- /**
689
- * Render a FullReport as a visual savings dashboard designed for screenshotting.
690
- *
691
- * Design principles:
692
- * - Before/After comparison bar is the HERO — one glance = "wow"
693
- * - "tokens saved" is the number people share
694
- * - Per-tool breakdown shows what each tool SAVED, sorted by impact
695
- * - Project memory: category bars showing persistent data across sessions
696
- * - No: Pct column, category tables, tips, jargon
697
- */
698
- export declare function formatReport(report: FullReport, version?: string, latestVersion?: string | null, opts?: {
699
- lifetime?: LifetimeStats;
700
- mcpUsage?: McpToolUsageRow[];
701
- conversation?: ConversationStats;
702
- /**
703
- * Phase 8 of D2 PRD — pass realBytes pre-aggregated from
704
- * `getRealBytesStats(...)` and the renderer will use those numbers
705
- * for the $ math instead of the conservative `events × 256` estimate.
706
- *
707
- * - `realBytes.lifetime` overrides `lifetimeTokensWithout`.
708
- * - `realBytes.conversation` overrides `conversationTokens`.
709
- * - Either may be omitted independently — missing values fall back
710
- * to the legacy estimate so this feature can never produce
711
- * a smaller number than before (Mert: stats only go up).
712
- * - When the new value is SMALLER than the legacy estimate (fresh
713
- * sessions before any sandbox events emit), we keep the larger
714
- * number to honour the same monotonic-growth invariant.
715
- */
716
- realBytes?: {
717
- lifetime?: RealBytesStats;
718
- conversation?: RealBytesStats;
719
- };
720
- /**
721
- * B3b — multi-adapter aggregation surfaced by
722
- * `getMultiAdapterLifetimeStats(...)` (analytics.ts:1248). When present,
723
- * the renderer adds a "Where it came from" sub-block under the receipt,
724
- * promotes the headline to "across N AI tools" when >= 2 real adapters
725
- * are detected, and renames the all-work block to "All your work
726
- * everywhere". Backward compat: omitting this opt preserves the legacy
727
- * single-adapter renderer output unchanged.
728
- */
729
- multiAdapter?: MultiAdapterLifetimeStats;
730
- /**
731
- * Point-in-time snapshot of the persistent content store. Optional —
732
- * callers that don't have store access can omit it and the renderer
733
- * skips the observability section gracefully.
734
- */
735
- indexState?: IndexState;
736
- /**
737
- * 5-section narrative renderer overrides. Defaults to ambient
738
- * `process.cwd()` + `Date.now()` + `detectLocaleAndTz()` for production
739
- * use; tests inject deterministic values so output is byte-stable.
740
- */
741
- cwd?: string;
742
- now?: number;
743
- locale?: string;
744
- tz?: string;
745
- }): string;