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,87 +0,0 @@
1
- /**
2
- * error-classifier — PRD-context-as-a-service §5 ABI parity
3
- *
4
- * Pure classifiers that derive per-event metadata from PostToolUse hook
5
- * stdin, mirroring the seed shape produced by context-mode-platform's
6
- * `seed.ts` so the bridge can ship full seed-shape parity.
7
- *
8
- * The dashboard reads three derived columns that are populated by the
9
- * platform seeder but, per the OSS handoff (ANOMALY #3), are NEVER READ
10
- * by the engine when ingesting live events:
11
- *
12
- * • error_category — one of 10 fixed buckets
13
- * • error_tool — tool name that produced the error
14
- * • command_type — git / test / build / lint / install / format / run / other
15
- * • command_tool — first token of the command (npm, git, pytest, …)
16
- * • duration_bucket — fast / medium / slow / timeout
17
- *
18
- * We populate them anyway, with sane defaults derived from message text
19
- * and tool name, so the dashboard renders symmetrically with seed.
20
- *
21
- * Hard constraints:
22
- * 1. Pure functions — no I/O, no globals, no module state.
23
- * 2. `error_category` MUST match seed's `pickErrorClassification`
24
- * output exactly. The literal union below is the ABI.
25
- * 3. No external dependencies; TypeScript stdlib only.
26
- * 4. Robust to null / undefined / empty / malformed input.
27
- */
28
- export type ErrorCategory = "file_not_found" | "command_not_found" | "edit_match_failed" | "test_failed" | "syntax_error" | "runtime_error" | "permission_denied" | "git_conflict" | "timeout" | "unknown";
29
- export type CommandType = "test" | "build" | "lint" | "git" | "install" | "format" | "run" | "other";
30
- export type DurationBucket = "fast" | "medium" | "slow" | "timeout";
31
- export interface ErrorClassification {
32
- error_category: ErrorCategory;
33
- error_tool: string;
34
- }
35
- export interface CommandClassification {
36
- command_type: CommandType;
37
- command_tool: string;
38
- }
39
- /**
40
- * Classify an error message + tool name into one of seed's 10 categories.
41
- *
42
- * Patterns (ordered most-specific → least-specific so the first match
43
- * wins). Rationale for each pattern is inline.
44
- *
45
- * • file_not_found — Node's ENOENT, Python's FileNotFoundError, and
46
- * Claude's "Cannot find module" all signal a
47
- * missing file/path.
48
- * • command_not_found — POSIX shells emit "command not found" (exit 127)
49
- * and "bash: <bin>: not found"; npx prints similar.
50
- * • edit_match_failed — Claude's Edit tool prints "old_string not found"
51
- * or "matches multiple locations" when the patch
52
- * context is stale.
53
- * • test_failed — vitest/jest/pytest format `FAIL ` prefix; npm
54
- * prints "Test failed".
55
- * • syntax_error — SyntaxError (JS/TS), tsc TS-codes, or Python's
56
- * SyntaxError header.
57
- * • runtime_error — TypeError/ReferenceError/RangeError (uncaught).
58
- * • permission_denied — EACCES / "permission denied" from fs or sudo.
59
- * • git_conflict — git's "CONFLICT" header on rebase/merge, plus
60
- * "Merge conflict in".
61
- * • timeout — explicit "timeout"/"timed out"/"ETIMEDOUT".
62
- * • unknown — fallthrough; never throws.
63
- */
64
- export declare function classifyError(message: unknown, toolName: unknown): ErrorClassification;
65
- /**
66
- * Classify a Bash command into a workflow bucket. The bucket is derived
67
- * from the (tool, sub-verb) pair: `npm test` → test, `npm run build` →
68
- * build, `git commit` → git, `pip install` → install, etc.
69
- *
70
- * Heuristic ordering — most-specific verb checks first; falls through to
71
- * `run` for generic execution and `other` for anything we can't classify.
72
- */
73
- export declare function classifyCommand(command: unknown): CommandClassification;
74
- /**
75
- * Bucketise a latency_ms reading into the four fixed buckets the
76
- * dashboard renders. Bucket edges (in ms):
77
- *
78
- * fast : [0, 1_000)
79
- * medium : [1_000, 10_000)
80
- * slow : [10_000, 60_000)
81
- * timeout : [60_000, ∞)
82
- *
83
- * Defensive: negative and non-numeric inputs collapse to `fast` (the
84
- * neutral bucket) rather than throwing, because hooks have been seen
85
- * to emit `null` for very short calls.
86
- */
87
- export declare function bucketizeDuration(latencyMs: unknown): DurationBucket;
@@ -1,303 +0,0 @@
1
- /**
2
- * error-classifier — PRD-context-as-a-service §5 ABI parity
3
- *
4
- * Pure classifiers that derive per-event metadata from PostToolUse hook
5
- * stdin, mirroring the seed shape produced by context-mode-platform's
6
- * `seed.ts` so the bridge can ship full seed-shape parity.
7
- *
8
- * The dashboard reads three derived columns that are populated by the
9
- * platform seeder but, per the OSS handoff (ANOMALY #3), are NEVER READ
10
- * by the engine when ingesting live events:
11
- *
12
- * • error_category — one of 10 fixed buckets
13
- * • error_tool — tool name that produced the error
14
- * • command_type — git / test / build / lint / install / format / run / other
15
- * • command_tool — first token of the command (npm, git, pytest, …)
16
- * • duration_bucket — fast / medium / slow / timeout
17
- *
18
- * We populate them anyway, with sane defaults derived from message text
19
- * and tool name, so the dashboard renders symmetrically with seed.
20
- *
21
- * Hard constraints:
22
- * 1. Pure functions — no I/O, no globals, no module state.
23
- * 2. `error_category` MUST match seed's `pickErrorClassification`
24
- * output exactly. The literal union below is the ABI.
25
- * 3. No external dependencies; TypeScript stdlib only.
26
- * 4. Robust to null / undefined / empty / malformed input.
27
- */
28
- // ── Internal helpers ────────────────────────────────────────────────────
29
- /**
30
- * Normalise message for case-insensitive substring matching. Coerces
31
- * non-string input (null, undefined, numbers from errno objects) to
32
- * empty string so downstream `.includes()` is always safe.
33
- */
34
- function normalise(s) {
35
- if (typeof s !== "string")
36
- return "";
37
- return s.toLowerCase();
38
- }
39
- /**
40
- * Best-effort `error_tool` derivation. Prefers the PostToolUse-supplied
41
- * `toolName`; falls back to scanning the message for a canonical tool
42
- * name (Read/Edit/Write/Bash/Grep/Glob) so isolated error strings still
43
- * resolve to a useful value rather than the literal "unknown".
44
- */
45
- function deriveErrorTool(toolName, message) {
46
- if (typeof toolName === "string" && toolName.trim().length > 0) {
47
- return toolName.trim();
48
- }
49
- // Canonical Claude Code tool names that may appear in error strings.
50
- const known = ["Edit", "Read", "Write", "Bash", "Grep", "Glob", "MultiEdit"];
51
- for (const t of known) {
52
- if (message.toLowerCase().includes(t.toLowerCase()))
53
- return t;
54
- }
55
- return "unknown";
56
- }
57
- // ── Error classifier ────────────────────────────────────────────────────
58
- /**
59
- * Classify an error message + tool name into one of seed's 10 categories.
60
- *
61
- * Patterns (ordered most-specific → least-specific so the first match
62
- * wins). Rationale for each pattern is inline.
63
- *
64
- * • file_not_found — Node's ENOENT, Python's FileNotFoundError, and
65
- * Claude's "Cannot find module" all signal a
66
- * missing file/path.
67
- * • command_not_found — POSIX shells emit "command not found" (exit 127)
68
- * and "bash: <bin>: not found"; npx prints similar.
69
- * • edit_match_failed — Claude's Edit tool prints "old_string not found"
70
- * or "matches multiple locations" when the patch
71
- * context is stale.
72
- * • test_failed — vitest/jest/pytest format `FAIL ` prefix; npm
73
- * prints "Test failed".
74
- * • syntax_error — SyntaxError (JS/TS), tsc TS-codes, or Python's
75
- * SyntaxError header.
76
- * • runtime_error — TypeError/ReferenceError/RangeError (uncaught).
77
- * • permission_denied — EACCES / "permission denied" from fs or sudo.
78
- * • git_conflict — git's "CONFLICT" header on rebase/merge, plus
79
- * "Merge conflict in".
80
- * • timeout — explicit "timeout"/"timed out"/"ETIMEDOUT".
81
- * • unknown — fallthrough; never throws.
82
- */
83
- export function classifyError(message, toolName) {
84
- const msg = normalise(message);
85
- const tool = typeof toolName === "string" ? toolName : "";
86
- const error_tool = deriveErrorTool(toolName, typeof message === "string" ? message : "");
87
- // Empty / malformed input → unknown bucket but still return a valid tool.
88
- if (msg.length === 0) {
89
- return { error_category: "unknown", error_tool };
90
- }
91
- // ── file_not_found ────────────────────────────────────────────────
92
- // Node's ENOENT carries "no such file or directory"; Claude's Read
93
- // tool surfaces the raw errno line. "cannot find module" is the
94
- // require-resolution variant.
95
- if (msg.includes("enoent") ||
96
- msg.includes("no such file") ||
97
- msg.includes("cannot find module") ||
98
- msg.includes("filenotfounderror")) {
99
- return { error_category: "file_not_found", error_tool };
100
- }
101
- // ── command_not_found ────────────────────────────────────────────
102
- // POSIX shells: "<shell>: <bin>: command not found" → exit 127.
103
- // Some hooks surface the bare exit code without the message.
104
- if (msg.includes("command not found") ||
105
- msg.includes(": not found") ||
106
- /\bexit(?:\s+code)?\s*[:=]?\s*127\b/.test(msg)) {
107
- return { error_category: "command_not_found", error_tool };
108
- }
109
- // ── edit_match_failed ────────────────────────────────────────────
110
- // Claude Code's Edit tool prints these exact phrases when the
111
- // `old_string` parameter no longer matches the file contents.
112
- // Gate on the Edit tool to avoid false positives when a Bash script
113
- // happens to contain the literal text "old_string".
114
- if ((tool === "Edit" || tool === "MultiEdit") &&
115
- (msg.includes("old_string") ||
116
- msg.includes("could not find string") ||
117
- msg.includes("string to replace not found") ||
118
- msg.includes("matches multiple"))) {
119
- return { error_category: "edit_match_failed", error_tool };
120
- }
121
- // Edit-style failure can also leak without tool name — match the
122
- // distinctive Claude phrasing alone.
123
- if (msg.includes("old_string not found") || msg.includes("string to replace not found")) {
124
- return { error_category: "edit_match_failed", error_tool };
125
- }
126
- // ── git_conflict ─────────────────────────────────────────────────
127
- // Check BEFORE test_failed because "CONFLICT" can co-occur with the
128
- // word "fail" in some merge outputs.
129
- if (msg.includes("conflict") &&
130
- (msg.includes("merge") || msg.includes("rebase") || msg.includes("git"))) {
131
- return { error_category: "git_conflict", error_tool };
132
- }
133
- if (msg.startsWith("conflict") || msg.includes("merge conflict")) {
134
- return { error_category: "git_conflict", error_tool };
135
- }
136
- // ── timeout ──────────────────────────────────────────────────────
137
- // Check BEFORE test_failed; "test timed out" should bucket as timeout.
138
- if (msg.includes("etimedout") ||
139
- msg.includes("timed out") ||
140
- msg.includes("timeout") ||
141
- msg.includes("deadline exceeded")) {
142
- return { error_category: "timeout", error_tool };
143
- }
144
- // ── permission_denied ────────────────────────────────────────────
145
- if (msg.includes("eacces") ||
146
- msg.includes("permission denied") ||
147
- msg.includes("operation not permitted") ||
148
- msg.includes("eperm")) {
149
- return { error_category: "permission_denied", error_tool };
150
- }
151
- // ── syntax_error ─────────────────────────────────────────────────
152
- // tsc errors look like "error TS2322"; JS SyntaxError header is exact.
153
- if (msg.includes("syntaxerror") ||
154
- /\berror\s+ts\d{3,5}\b/.test(msg) ||
155
- msg.includes("unexpected token") ||
156
- msg.includes("unexpected end of") ||
157
- msg.includes("parse error")) {
158
- return { error_category: "syntax_error", error_tool };
159
- }
160
- // ── test_failed ──────────────────────────────────────────────────
161
- // vitest/jest print `FAIL `; npm test prints "Test failed".
162
- // pytest prints "FAILED" capital. Bias to Bash tool but accept
163
- // unscoped messages because hooks sometimes drop tool name.
164
- if (msg.includes("test failed") ||
165
- msg.includes("tests failed") ||
166
- /\bfail(?:ed)?\b.*\btest\b/.test(msg) ||
167
- /\b\d+\s+tests?\s+failed\b/.test(msg) ||
168
- msg.includes("assertion") ||
169
- /^fail\s/.test(msg) ||
170
- /\nfail\s/.test(msg)) {
171
- return { error_category: "test_failed", error_tool };
172
- }
173
- // ── runtime_error ────────────────────────────────────────────────
174
- // Catch-all for uncaught JS exceptions and the common Python ones.
175
- // Placed near the end so more specific buckets (syntax_error) win
176
- // when both could match.
177
- if (msg.includes("typeerror") ||
178
- msg.includes("referenceerror") ||
179
- msg.includes("rangeerror") ||
180
- msg.includes("uncaught exception") ||
181
- msg.includes("traceback (most recent call last)") ||
182
- msg.includes("nullpointerexception")) {
183
- return { error_category: "runtime_error", error_tool };
184
- }
185
- // Fallthrough — categorisation is best-effort; the dashboard renders
186
- // "unknown" as a neutral bucket rather than dropping the event.
187
- return { error_category: "unknown", error_tool };
188
- }
189
- // ── Command classifier ──────────────────────────────────────────────────
190
- /**
191
- * Tokenise a shell command, stripping leading env-var prefixes
192
- * (`FOO=bar npm run build`) and `sudo`/`time` wrappers so the first
193
- * meaningful token is returned.
194
- */
195
- function firstToken(command) {
196
- const parts = command.trim().split(/\s+/);
197
- let i = 0;
198
- // Skip env-var assignments: KEY=value
199
- while (i < parts.length && /^[A-Za-z_][A-Za-z0-9_]*=.*/.test(parts[i]))
200
- i++;
201
- // Skip common wrappers that aren't the "real" tool.
202
- while (i < parts.length && (parts[i] === "sudo" || parts[i] === "time" || parts[i] === "nice"))
203
- i++;
204
- return parts[i] ?? "";
205
- }
206
- /**
207
- * Classify a Bash command into a workflow bucket. The bucket is derived
208
- * from the (tool, sub-verb) pair: `npm test` → test, `npm run build` →
209
- * build, `git commit` → git, `pip install` → install, etc.
210
- *
211
- * Heuristic ordering — most-specific verb checks first; falls through to
212
- * `run` for generic execution and `other` for anything we can't classify.
213
- */
214
- export function classifyCommand(command) {
215
- if (typeof command !== "string" || command.trim().length === 0) {
216
- return { command_type: "other", command_tool: "" };
217
- }
218
- const raw = command.trim();
219
- const tool = firstToken(raw).toLowerCase();
220
- const lower = raw.toLowerCase();
221
- // ── git ──────────────────────────────────────────────────────────
222
- if (tool === "git") {
223
- return { command_type: "git", command_tool: "git" };
224
- }
225
- // ── install ──────────────────────────────────────────────────────
226
- // npm/pnpm/yarn/pip install variants come before generic test/build
227
- // because `npm install --save-dev jest` would otherwise match test.
228
- if (/\b(install|add|ci)\b/.test(lower) &&
229
- (tool === "npm" || tool === "pnpm" || tool === "yarn" || tool === "bun" || tool === "pip" || tool === "pip3")) {
230
- return { command_type: "install", command_tool: tool };
231
- }
232
- if (tool === "brew" && /\binstall\b/.test(lower)) {
233
- return { command_type: "install", command_tool: "brew" };
234
- }
235
- // ── test ─────────────────────────────────────────────────────────
236
- // Direct test runners, plus `npm test` / `pnpm test` / `yarn test`.
237
- if (tool === "vitest" || tool === "jest" || tool === "pytest" ||
238
- tool === "mocha" || tool === "playwright" || tool === "cypress") {
239
- return { command_type: "test", command_tool: tool };
240
- }
241
- if ((tool === "npm" || tool === "pnpm" || tool === "yarn" || tool === "bun") &&
242
- /\btest\b/.test(lower)) {
243
- return { command_type: "test", command_tool: tool };
244
- }
245
- // ── lint ─────────────────────────────────────────────────────────
246
- if (tool === "eslint" || tool === "tslint" || tool === "ruff" || tool === "flake8" || tool === "pylint") {
247
- return { command_type: "lint", command_tool: tool };
248
- }
249
- if (/\blint\b/.test(lower) && (tool === "npm" || tool === "pnpm" || tool === "yarn" || tool === "bun")) {
250
- return { command_type: "lint", command_tool: tool };
251
- }
252
- // ── format ───────────────────────────────────────────────────────
253
- if (tool === "prettier" || tool === "black" || tool === "gofmt" || tool === "rustfmt") {
254
- return { command_type: "format", command_tool: tool };
255
- }
256
- if (/\b(format|fmt)\b/.test(lower) && (tool === "npm" || tool === "pnpm" || tool === "yarn" || tool === "bun")) {
257
- return { command_type: "format", command_tool: tool };
258
- }
259
- // ── build ────────────────────────────────────────────────────────
260
- if (tool === "tsc" || tool === "webpack" || tool === "rollup" || tool === "vite" || tool === "esbuild" || tool === "make") {
261
- return { command_type: "build", command_tool: tool };
262
- }
263
- if (/\bbuild\b/.test(lower) && (tool === "npm" || tool === "pnpm" || tool === "yarn" || tool === "bun" || tool === "cargo" || tool === "go")) {
264
- return { command_type: "build", command_tool: tool };
265
- }
266
- // ── run ──────────────────────────────────────────────────────────
267
- // Generic execution — `npm run …` (with no recognised sub-verb),
268
- // `node script.js`, `python -m foo`, etc.
269
- if ((tool === "npm" || tool === "pnpm" || tool === "yarn" || tool === "bun") &&
270
- /\brun\b/.test(lower)) {
271
- return { command_type: "run", command_tool: tool };
272
- }
273
- if (tool === "node" || tool === "python" || tool === "python3" || tool === "deno" || tool === "bun") {
274
- return { command_type: "run", command_tool: tool };
275
- }
276
- // Fallthrough — preserves the tool name so the dashboard can still
277
- // chart "other" commands by their underlying binary.
278
- return { command_type: "other", command_tool: tool || "" };
279
- }
280
- // ── Duration bucketiser ────────────────────────────────────────────────
281
- /**
282
- * Bucketise a latency_ms reading into the four fixed buckets the
283
- * dashboard renders. Bucket edges (in ms):
284
- *
285
- * fast : [0, 1_000)
286
- * medium : [1_000, 10_000)
287
- * slow : [10_000, 60_000)
288
- * timeout : [60_000, ∞)
289
- *
290
- * Defensive: negative and non-numeric inputs collapse to `fast` (the
291
- * neutral bucket) rather than throwing, because hooks have been seen
292
- * to emit `null` for very short calls.
293
- */
294
- export function bucketizeDuration(latencyMs) {
295
- const n = typeof latencyMs === "number" && Number.isFinite(latencyMs) ? latencyMs : 0;
296
- if (n < 1_000)
297
- return "fast";
298
- if (n < 10_000)
299
- return "medium";
300
- if (n < 60_000)
301
- return "slow";
302
- return "timeout";
303
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * event-emit — Phase 5+7 of D2 PRD (stats-event-driven-architecture)
3
- *
4
- * Server-side helpers that record sandbox / index / cache work into
5
- * `session_events` with the new `bytes_avoided` / `bytes_returned`
6
- * columns so the renderer can compute the real $ saved instead of the
7
- * conservative `events × 256` token estimate.
8
- *
9
- * Design notes
10
- * ────────────
11
- * - Uses the public `SessionDB.insertEvent(... , bytes)` API the schema
12
- * engineer extended in this branch — same dedup + FIFO eviction +
13
- * transaction wrapping you'd get from any other event source.
14
- * - Best-effort error swallowing matches `persistToolCallCounter` in
15
- * `persist-tool-calls.ts`. A stats-side failure must NEVER break the
16
- * parent MCP tool call.
17
- * - Resolves the latest `session_id` from `session_meta` so the wiring
18
- * in `server.ts` is `setImmediate(() => emit*({...}))` — no need to
19
- * plumb session ids through every handler.
20
- */
21
- /**
22
- * Record a `ctx_execute` / `ctx_execute_file` / `ctx_batch_execute` run.
23
- * `bytesReturned` is the size of the stdout text the user actually saw —
24
- * the rest of the sandbox output stayed out of context.
25
- */
26
- export declare function emitSandboxExecuteEvent(opts: {
27
- sessionDbPath: string;
28
- toolName: string;
29
- bytesReturned: number;
30
- }): void;
31
- /**
32
- * Record a `ctx_index` / `trackIndexed` write — content kept out of
33
- * context by being chunked into FTS5 instead of returned inline.
34
- */
35
- export declare function emitIndexWriteEvent(opts: {
36
- sessionDbPath: string;
37
- source: string;
38
- bytesAvoided: number;
39
- }): void;
40
- /**
41
- * Record a `ctx_fetch_and_index` TTL cache hit — bytes the user would
42
- * have spent re-fetching the same URL within the 24h cache window.
43
- */
44
- export declare function emitCacheHitEvent(opts: {
45
- sessionDbPath: string;
46
- source: string;
47
- bytesAvoided: number;
48
- }): void;
@@ -1,101 +0,0 @@
1
- /**
2
- * event-emit — Phase 5+7 of D2 PRD (stats-event-driven-architecture)
3
- *
4
- * Server-side helpers that record sandbox / index / cache work into
5
- * `session_events` with the new `bytes_avoided` / `bytes_returned`
6
- * columns so the renderer can compute the real $ saved instead of the
7
- * conservative `events × 256` token estimate.
8
- *
9
- * Design notes
10
- * ────────────
11
- * - Uses the public `SessionDB.insertEvent(... , bytes)` API the schema
12
- * engineer extended in this branch — same dedup + FIFO eviction +
13
- * transaction wrapping you'd get from any other event source.
14
- * - Best-effort error swallowing matches `persistToolCallCounter` in
15
- * `persist-tool-calls.ts`. A stats-side failure must NEVER break the
16
- * parent MCP tool call.
17
- * - Resolves the latest `session_id` from `session_meta` so the wiring
18
- * in `server.ts` is `setImmediate(() => emit*({...}))` — no need to
19
- * plumb session ids through every handler.
20
- */
21
- import { existsSync } from "node:fs";
22
- import { SessionDB } from "./db.js";
23
- /**
24
- * Open the SessionDB at `dbPath`, find the latest session_id, and run
25
- * `fn` with both. Wraps everything in try/catch so callers stay
26
- * fire-and-forget.
27
- */
28
- function withLatestSession(dbPath, fn) {
29
- try {
30
- if (!existsSync(dbPath))
31
- return;
32
- const sdb = new SessionDB({ dbPath });
33
- try {
34
- const sid = sdb.getLatestSessionId();
35
- if (!sid)
36
- return;
37
- fn(sdb, sid);
38
- }
39
- finally {
40
- try {
41
- sdb.close();
42
- }
43
- catch { /* ignore */ }
44
- }
45
- }
46
- catch {
47
- // Best-effort: never break the parent MCP tool call.
48
- }
49
- }
50
- /**
51
- * Record a `ctx_execute` / `ctx_execute_file` / `ctx_batch_execute` run.
52
- * `bytesReturned` is the size of the stdout text the user actually saw —
53
- * the rest of the sandbox output stayed out of context.
54
- */
55
- export function emitSandboxExecuteEvent(opts) {
56
- withLatestSession(opts.sessionDbPath, (sdb, sid) => {
57
- sdb.insertEvent(sid, {
58
- type: "sandbox-execute",
59
- category: "sandbox",
60
- priority: 1,
61
- data: opts.toolName,
62
- project_dir: "",
63
- attribution_source: "server",
64
- attribution_confidence: 1,
65
- }, "ctx-server", undefined, { bytesReturned: opts.bytesReturned });
66
- });
67
- }
68
- /**
69
- * Record a `ctx_index` / `trackIndexed` write — content kept out of
70
- * context by being chunked into FTS5 instead of returned inline.
71
- */
72
- export function emitIndexWriteEvent(opts) {
73
- withLatestSession(opts.sessionDbPath, (sdb, sid) => {
74
- sdb.insertEvent(sid, {
75
- type: "index-write",
76
- category: "sandbox",
77
- priority: 1,
78
- data: opts.source,
79
- project_dir: "",
80
- attribution_source: "server",
81
- attribution_confidence: 1,
82
- }, "ctx-server", undefined, { bytesAvoided: opts.bytesAvoided });
83
- });
84
- }
85
- /**
86
- * Record a `ctx_fetch_and_index` TTL cache hit — bytes the user would
87
- * have spent re-fetching the same URL within the 24h cache window.
88
- */
89
- export function emitCacheHitEvent(opts) {
90
- withLatestSession(opts.sessionDbPath, (sdb, sid) => {
91
- sdb.insertEvent(sid, {
92
- type: "cache-hit",
93
- category: "cache",
94
- priority: 1,
95
- data: opts.source,
96
- project_dir: "",
97
- attribution_source: "server",
98
- attribution_confidence: 1,
99
- }, "ctx-server", undefined, { bytesAvoided: opts.bytesAvoided });
100
- });
101
- }