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,532 +0,0 @@
1
- /**
2
- * Snapshot builder — converts stored SessionEvents into a reference-based
3
- * XML resume snapshot.
4
- *
5
- * Pure functions only. No database access, no file system, no side effects.
6
- *
7
- * The output XML is injected into the LLM's context after a compact event to
8
- * restore session awareness. Instead of truncated inline data, each section
9
- * contains a natural summary plus a runnable search tool call that retrieves
10
- * full details from the indexed knowledge base on demand.
11
- *
12
- * Zero truncation. Zero information loss. Full data lives in SessionDB;
13
- * the snapshot is a table of contents.
14
- */
15
- import { escapeXML } from "../truncate.js";
16
- // ── Helpers ──────────────────────────────────────────────────────────────────
17
- const MAX_ACTIVE_FILES = 10;
18
- /**
19
- * Extract 2-4 keyword phrases from a list of strings for BM25 search queries.
20
- * Takes actual data values and picks representative terms.
21
- */
22
- function buildQueries(items, maxQueries = 4) {
23
- const unique = [...new Set(items.filter(s => s.length > 0))];
24
- const selected = unique.slice(0, maxQueries);
25
- return selected.map(s => {
26
- // Take the first ~80 chars as a query — enough for BM25 matching
27
- const trimmed = s.length > 80 ? s.slice(0, 80) : s;
28
- return trimmed;
29
- });
30
- }
31
- /**
32
- * Format a runnable tool call block for a section.
33
- */
34
- function toolCall(toolName, queries) {
35
- if (queries.length === 0)
36
- return "";
37
- const escaped = queries.map(q => `"${escapeXML(q)}"`).join(", ");
38
- return `\n For full details:\n ${escapeXML(toolName)}(\n queries: [${escaped}],\n source: "session-events"\n )`;
39
- }
40
- // ── Section builders ─────────────────────────────────────────────────────────
41
- function buildFilesSection(fileEvents, searchTool) {
42
- if (fileEvents.length === 0)
43
- return "";
44
- // Build per-file operation counts
45
- const fileMap = new Map();
46
- for (const ev of fileEvents) {
47
- const path = ev.data;
48
- let entry = fileMap.get(path);
49
- if (!entry) {
50
- entry = { ops: new Map() };
51
- fileMap.set(path, entry);
52
- }
53
- let op;
54
- if (ev.type === "file_write")
55
- op = "write";
56
- else if (ev.type === "file_read")
57
- op = "read";
58
- else if (ev.type === "file_edit")
59
- op = "edit";
60
- else
61
- op = ev.type;
62
- entry.ops.set(op, (entry.ops.get(op) ?? 0) + 1);
63
- }
64
- // Limit to last MAX_ACTIVE_FILES files (by insertion order = chronological)
65
- const entries = Array.from(fileMap.entries());
66
- const limited = entries.slice(-MAX_ACTIVE_FILES);
67
- const summaryLines = [];
68
- const queryTerms = [];
69
- for (const [path, { ops }] of limited) {
70
- const opsStr = Array.from(ops.entries())
71
- .map(([k, v]) => `${k}×${v}`)
72
- .join(", ");
73
- // Use just the filename for concise display
74
- const fileName = path.split("/").pop() ?? path;
75
- summaryLines.push(` ${escapeXML(fileName)} (${escapeXML(opsStr)})`);
76
- queryTerms.push(`${fileName} ${Array.from(ops.keys()).join(" ")}`);
77
- }
78
- const queries = buildQueries(queryTerms);
79
- const lines = [
80
- ` <files count="${fileMap.size}">`,
81
- ...summaryLines,
82
- toolCall(searchTool, queries),
83
- ` </files>`,
84
- ];
85
- return lines.join("\n");
86
- }
87
- function buildErrorsSection(errorEvents, searchTool) {
88
- if (errorEvents.length === 0)
89
- return "";
90
- const summaryLines = [];
91
- const queryTerms = [];
92
- for (const ev of errorEvents) {
93
- summaryLines.push(` ${escapeXML(ev.data)}`);
94
- queryTerms.push(ev.data);
95
- }
96
- const queries = buildQueries(queryTerms);
97
- const lines = [
98
- ` <errors count="${errorEvents.length}">`,
99
- ...summaryLines,
100
- toolCall(searchTool, queries),
101
- ` </errors>`,
102
- ];
103
- return lines.join("\n");
104
- }
105
- function buildDecisionsSection(decisionEvents, searchTool) {
106
- if (decisionEvents.length === 0)
107
- return "";
108
- const seen = new Set();
109
- const summaryLines = [];
110
- const queryTerms = [];
111
- for (const ev of decisionEvents) {
112
- if (seen.has(ev.data))
113
- continue;
114
- seen.add(ev.data);
115
- summaryLines.push(` ${escapeXML(ev.data)}`);
116
- queryTerms.push(ev.data);
117
- }
118
- if (summaryLines.length === 0)
119
- return "";
120
- const queries = buildQueries(queryTerms);
121
- const lines = [
122
- ` <decisions count="${summaryLines.length}">`,
123
- ...summaryLines,
124
- toolCall(searchTool, queries),
125
- ` </decisions>`,
126
- ];
127
- return lines.join("\n");
128
- }
129
- function buildRulesSection(ruleEvents, searchTool) {
130
- if (ruleEvents.length === 0)
131
- return "";
132
- const seen = new Set();
133
- const summaryLines = [];
134
- const queryTerms = [];
135
- for (const ev of ruleEvents) {
136
- if (seen.has(ev.data))
137
- continue;
138
- seen.add(ev.data);
139
- if (ev.type === "rule_content") {
140
- summaryLines.push(` ${escapeXML(ev.data)}`);
141
- }
142
- else {
143
- summaryLines.push(` ${escapeXML(ev.data)}`);
144
- }
145
- queryTerms.push(ev.data);
146
- }
147
- if (summaryLines.length === 0)
148
- return "";
149
- const queries = buildQueries(queryTerms);
150
- const lines = [
151
- ` <rules count="${summaryLines.length}">`,
152
- ...summaryLines,
153
- toolCall(searchTool, queries),
154
- ` </rules>`,
155
- ];
156
- return lines.join("\n");
157
- }
158
- function buildGitSection(gitEvents, searchTool) {
159
- if (gitEvents.length === 0)
160
- return "";
161
- const summaryLines = [];
162
- const queryTerms = [];
163
- for (const ev of gitEvents) {
164
- summaryLines.push(` ${escapeXML(ev.data)}`);
165
- queryTerms.push(ev.data);
166
- }
167
- const queries = buildQueries(queryTerms);
168
- const lines = [
169
- ` <git count="${gitEvents.length}">`,
170
- ...summaryLines,
171
- toolCall(searchTool, queries),
172
- ` </git>`,
173
- ];
174
- return lines.join("\n");
175
- }
176
- /**
177
- * Render <task_state> from task events.
178
- * Reconstructs the full task list from create/update events,
179
- * filters out completed tasks, and renders only pending/in-progress work.
180
- *
181
- * TaskCreate events have `{ subject }`, TaskUpdate events have `{ taskId, status }`.
182
- * Match by chronological order: creates[0] -> lowest taskId from updates.
183
- */
184
- export function renderTaskState(taskEvents) {
185
- if (taskEvents.length === 0)
186
- return "";
187
- const creates = [];
188
- const updates = {};
189
- for (const ev of taskEvents) {
190
- try {
191
- const parsed = JSON.parse(ev.data);
192
- if (typeof parsed.subject === "string") {
193
- creates.push(parsed.subject);
194
- }
195
- else if (typeof parsed.taskId === "string" && typeof parsed.status === "string") {
196
- updates[parsed.taskId] = parsed.status;
197
- }
198
- }
199
- catch { /* not JSON */ }
200
- }
201
- if (creates.length === 0)
202
- return "";
203
- const DONE = new Set(["completed", "deleted", "failed"]);
204
- // Match creates to updates positionally (creates[0] -> lowest taskId)
205
- const sortedIds = Object.keys(updates).sort((a, b) => Number(a) - Number(b));
206
- const pending = [];
207
- for (let i = 0; i < creates.length; i++) {
208
- const matchedId = sortedIds[i];
209
- const status = matchedId ? (updates[matchedId] ?? "pending") : "pending";
210
- if (!DONE.has(status)) {
211
- pending.push(creates[i]);
212
- }
213
- }
214
- // All tasks completed — nothing to render
215
- if (pending.length === 0)
216
- return "";
217
- const lines = [];
218
- for (const task of pending) {
219
- lines.push(` [pending] ${escapeXML(task)}`);
220
- }
221
- return lines.join("\n");
222
- }
223
- function buildTaskSection(taskEvents, searchTool) {
224
- const taskContent = renderTaskState(taskEvents);
225
- if (!taskContent)
226
- return "";
227
- const queryTerms = [];
228
- for (const ev of taskEvents) {
229
- try {
230
- const parsed = JSON.parse(ev.data);
231
- if (typeof parsed.subject === "string") {
232
- queryTerms.push(parsed.subject);
233
- }
234
- }
235
- catch { /* not JSON */ }
236
- }
237
- const queries = buildQueries(queryTerms);
238
- const pendingCount = taskContent.split("\n").length;
239
- const lines = [
240
- ` <task_state count="${pendingCount}">`,
241
- taskContent,
242
- toolCall(searchTool, queries),
243
- ` </task_state>`,
244
- ];
245
- return lines.join("\n");
246
- }
247
- function buildEnvironmentSection(cwdEvents, envEvents, searchTool) {
248
- if (cwdEvents.length === 0 && envEvents.length === 0)
249
- return "";
250
- const summaryLines = [];
251
- const queryTerms = [];
252
- if (cwdEvents.length > 0) {
253
- const lastCwd = cwdEvents[cwdEvents.length - 1];
254
- summaryLines.push(` cwd: ${escapeXML(lastCwd.data)}`);
255
- queryTerms.push("working directory");
256
- }
257
- for (const env of envEvents) {
258
- summaryLines.push(` ${escapeXML(env.data)}`);
259
- queryTerms.push(env.data);
260
- }
261
- const queries = buildQueries(queryTerms);
262
- const lines = [
263
- ` <environment>`,
264
- ...summaryLines,
265
- toolCall(searchTool, queries),
266
- ` </environment>`,
267
- ];
268
- return lines.join("\n");
269
- }
270
- function buildSubagentsSection(subagentEvents, searchTool) {
271
- if (subagentEvents.length === 0)
272
- return "";
273
- const summaryLines = [];
274
- const queryTerms = [];
275
- for (const ev of subagentEvents) {
276
- const status = ev.type === "subagent_completed" ? "completed"
277
- : ev.type === "subagent_launched" ? "launched"
278
- : "unknown";
279
- summaryLines.push(` [${status}] ${escapeXML(ev.data)}`);
280
- queryTerms.push(`subagent ${ev.data}`);
281
- }
282
- const queries = buildQueries(queryTerms);
283
- const lines = [
284
- ` <subagents count="${subagentEvents.length}">`,
285
- ...summaryLines,
286
- toolCall(searchTool, queries),
287
- ` </subagents>`,
288
- ];
289
- return lines.join("\n");
290
- }
291
- function buildSkillsSection(skillEvents, searchTool) {
292
- if (skillEvents.length === 0)
293
- return "";
294
- // Count invocations per skill name
295
- const skillCounts = new Map();
296
- for (const ev of skillEvents) {
297
- const name = ev.data.split(":")[0].trim();
298
- skillCounts.set(name, (skillCounts.get(name) ?? 0) + 1);
299
- }
300
- const summaryLines = [];
301
- const queryTerms = [];
302
- for (const [name, count] of skillCounts) {
303
- summaryLines.push(` ${escapeXML(name)} (${count}×)`);
304
- queryTerms.push(`skill ${name} invocation`);
305
- }
306
- const queries = buildQueries(queryTerms);
307
- const lines = [
308
- ` <skills count="${skillEvents.length}">`,
309
- ...summaryLines,
310
- toolCall(searchTool, queries),
311
- ` </skills>`,
312
- ];
313
- return lines.join("\n");
314
- }
315
- function buildRolesSection(roleEvents, searchTool) {
316
- if (roleEvents.length === 0)
317
- return "";
318
- const seen = new Set();
319
- const summaryLines = [];
320
- const queryTerms = [];
321
- for (const ev of roleEvents) {
322
- if (seen.has(ev.data))
323
- continue;
324
- seen.add(ev.data);
325
- summaryLines.push(` ${escapeXML(ev.data)}`);
326
- queryTerms.push(ev.data);
327
- }
328
- if (summaryLines.length === 0)
329
- return "";
330
- const queries = buildQueries(queryTerms);
331
- const lines = [
332
- ` <roles count="${summaryLines.length}">`,
333
- ...summaryLines,
334
- toolCall(searchTool, queries),
335
- ` </roles>`,
336
- ];
337
- return lines.join("\n");
338
- }
339
- function buildIntentSection(intentEvents) {
340
- if (intentEvents.length === 0)
341
- return "";
342
- const lastIntent = intentEvents[intentEvents.length - 1];
343
- return ` <intent mode="${escapeXML(lastIntent.data)}"/>`;
344
- }
345
- /**
346
- * Restore the most recent stated session goal verbatim. Placed at the top of
347
- * the snapshot (right after how_to_search) so the resuming LLM reads the
348
- * active objective before anything else and keeps working toward it.
349
- */
350
- function buildGoalSection(goalEvents) {
351
- if (goalEvents.length === 0)
352
- return "";
353
- const lastGoal = goalEvents[goalEvents.length - 1];
354
- return [
355
- ` <session_goal>`,
356
- ` The active objective for this session. Keep working toward it until it is met; do not ask the user to restate it.`,
357
- ` ${escapeXML(lastGoal.data)}`,
358
- ` </session_goal>`,
359
- ].join("\n");
360
- }
361
- /**
362
- * Raw-prompt safety net (issue #535):
363
- * Always surface the most recent user prompts verbatim so the next LLM
364
- * sees them even if every universal-rule detector misses. Bound per-prompt
365
- * payload to RECENT_MESSAGE_MAX_CHARS Unicode codepoints; bound the total
366
- * count to RECENT_MESSAGES_LIMIT to keep the resume block compact.
367
- */
368
- const RECENT_MESSAGES_LIMIT = 3;
369
- const RECENT_MESSAGE_MAX_CHARS = 400;
370
- function truncateForSnapshot(value, max) {
371
- const codepoints = [...value];
372
- if (codepoints.length <= max)
373
- return value;
374
- return codepoints.slice(0, max).join("");
375
- }
376
- function buildRecentMessagesSection(userPromptEvents) {
377
- if (userPromptEvents.length === 0)
378
- return "";
379
- // Last N in chronological order — newest at the bottom mirrors the
380
- // way the user reads their own scrollback.
381
- const recent = userPromptEvents.slice(-RECENT_MESSAGES_LIMIT);
382
- const items = recent
383
- .map(ev => {
384
- const body = truncateForSnapshot(ev.data ?? "", RECENT_MESSAGE_MAX_CHARS);
385
- if (!body)
386
- return "";
387
- return ` <message>${escapeXML(body)}</message>`;
388
- })
389
- .filter(Boolean);
390
- if (items.length === 0)
391
- return "";
392
- return [
393
- ` <recent_user_messages count="${items.length}">`,
394
- ...items,
395
- ` </recent_user_messages>`,
396
- ].join("\n");
397
- }
398
- // ── Main builder ─────────────────────────────────────────────────────────────
399
- /**
400
- * Build a reference-based resume snapshot XML string from stored session events.
401
- *
402
- * Algorithm:
403
- * 1. Group events by category
404
- * 2. For each non-empty category, build a summary section with a runnable
405
- * search tool call containing exact queries for full details
406
- * 3. Assemble ALL non-empty sections — no priority dropping, no byte budget
407
- */
408
- export function buildResumeSnapshot(events, opts) {
409
- const compactCount = opts?.compactCount ?? 1;
410
- const searchTool = opts?.searchTool ?? "ctx_search";
411
- const now = new Date().toISOString();
412
- // ── Group events by category ──
413
- const fileEvents = [];
414
- const taskEvents = [];
415
- const ruleEvents = [];
416
- const decisionEvents = [];
417
- const cwdEvents = [];
418
- const errorEvents = [];
419
- const envEvents = [];
420
- const gitEvents = [];
421
- const subagentEvents = [];
422
- const intentEvents = [];
423
- const goalEvents = [];
424
- const skillEvents = [];
425
- const roleEvents = [];
426
- const userPromptEvents = [];
427
- for (const ev of events) {
428
- switch (ev.category) {
429
- case "file":
430
- fileEvents.push(ev);
431
- break;
432
- case "task":
433
- taskEvents.push(ev);
434
- break;
435
- case "rule":
436
- ruleEvents.push(ev);
437
- break;
438
- case "decision":
439
- decisionEvents.push(ev);
440
- break;
441
- case "cwd":
442
- cwdEvents.push(ev);
443
- break;
444
- case "error":
445
- errorEvents.push(ev);
446
- break;
447
- case "env":
448
- envEvents.push(ev);
449
- break;
450
- case "git":
451
- gitEvents.push(ev);
452
- break;
453
- case "subagent":
454
- subagentEvents.push(ev);
455
- break;
456
- case "intent":
457
- intentEvents.push(ev);
458
- break;
459
- case "goal":
460
- goalEvents.push(ev);
461
- break;
462
- case "skill":
463
- skillEvents.push(ev);
464
- break;
465
- case "role":
466
- roleEvents.push(ev);
467
- break;
468
- case "user-prompt":
469
- userPromptEvents.push(ev);
470
- break;
471
- }
472
- }
473
- // ── Build all sections ──
474
- const sections = [];
475
- // How-to-search instruction block (always present)
476
- sections.push(` <how_to_search>
477
- Each section below contains a summary of prior work.
478
- For FULL DETAILS, run the exact tool call shown under each section.
479
- Do NOT ask the user to re-explain prior work. Search first.
480
- Do NOT invent your own queries — use the ones provided.
481
- </how_to_search>`);
482
- // Session goal first — the objective the LLM must keep working toward.
483
- const goal = buildGoalSection(goalEvents);
484
- if (goal)
485
- sections.push(goal);
486
- const files = buildFilesSection(fileEvents, searchTool);
487
- if (files)
488
- sections.push(files);
489
- const errors = buildErrorsSection(errorEvents, searchTool);
490
- if (errors)
491
- sections.push(errors);
492
- const decisions = buildDecisionsSection(decisionEvents, searchTool);
493
- if (decisions)
494
- sections.push(decisions);
495
- const rules = buildRulesSection(ruleEvents, searchTool);
496
- if (rules)
497
- sections.push(rules);
498
- const git = buildGitSection(gitEvents, searchTool);
499
- if (git)
500
- sections.push(git);
501
- const tasks = buildTaskSection(taskEvents, searchTool);
502
- if (tasks)
503
- sections.push(tasks);
504
- const environment = buildEnvironmentSection(cwdEvents, envEvents, searchTool);
505
- if (environment)
506
- sections.push(environment);
507
- const subagents = buildSubagentsSection(subagentEvents, searchTool);
508
- if (subagents)
509
- sections.push(subagents);
510
- const skills = buildSkillsSection(skillEvents, searchTool);
511
- if (skills)
512
- sections.push(skills);
513
- const roles = buildRolesSection(roleEvents, searchTool);
514
- if (roles)
515
- sections.push(roles);
516
- const intent = buildIntentSection(intentEvents);
517
- if (intent)
518
- sections.push(intent);
519
- // Raw-prompt safety net — always last so it stays adjacent to the next
520
- // LLM turn and is read after the structured sections.
521
- const recentMessages = buildRecentMessagesSection(userPromptEvents);
522
- if (recentMessages)
523
- sections.push(recentMessages);
524
- // ── Assemble ──
525
- const header = `<session_resume events="${events.length}" compact_count="${compactCount}" generated_at="${now}">`;
526
- const footer = `</session_resume>`;
527
- const body = sections.join("\n\n");
528
- if (body) {
529
- return `${header}\n\n${body}\n\n${footer}`;
530
- }
531
- return `${header}\n${footer}`;
532
- }
@@ -1,56 +0,0 @@
1
- /**
2
- * walkDirectory — bounded recursive directory walker for ctx_index (#687).
3
- *
4
- * Issue: ctx_index refused directory paths via the security gate at
5
- * src/store.ts:845 ("refusing to index <path>: not a regular file"). The gate
6
- * is a TOCTOU defense from #442 round-3 and MUST be preserved — directory
7
- * support is layered as a separate concern here. Each file produced by
8
- * walkDirectory is then read via the existing per-file
9
- * `openSync + fstatSync.isFile()` invariant in `ContentStore.index()`.
10
- *
11
- * Reported by @matiasduartee across 4 clients × Windows 11.
12
- * https://github.com/anthropic-experimental/context-mode/issues/687
13
- *
14
- * Design constraints:
15
- * - No new dependencies (avoid the `ignore` package — issue #687 Diagnose).
16
- * - Cross-OS: path.sep / path.join everywhere, never raw "/" string ops.
17
- * - Symlink cycle detection via a resolved-path Set.
18
- * - Symlink-escape rejection: refuse to follow symlinks that resolve outside
19
- * the rootPath (defense-in-depth alongside per-file checkFilePathDenyPolicy).
20
- * - FTS5-blowup guard: hard cap maxFiles (default 200, per Architect).
21
- */
22
- export interface WalkOptions {
23
- /** Glob-ish include patterns. Empty/undefined means include all (subject to extensions). */
24
- include?: string[];
25
- /** Glob-ish exclude patterns. Merged with sensible defaults. */
26
- exclude?: string[];
27
- /** Max recursion depth from rootPath (0 = root only). Default 5. */
28
- maxDepth?: number;
29
- /** Hard cap on total files. Default 200 — FTS5 blow-up guard. */
30
- maxFiles?: number;
31
- /** Allowed file extensions (with leading dot). Empty/undefined means default set. */
32
- extensions?: string[];
33
- /** Apply nearest .gitignore rules during walk. Default true. */
34
- respectGitignore?: boolean;
35
- /** Follow directory symlinks. Default false (cycle hazard + escape risk). */
36
- followSymlinks?: boolean;
37
- }
38
- export interface WalkResult {
39
- files: string[];
40
- /** True when maxFiles cap was hit and traversal halted early. */
41
- capped: boolean;
42
- /** Total files discovered before cap (for reporting). */
43
- totalSeen: number;
44
- }
45
- /**
46
- * Walk `rootPath` recursively under the given bounds and return absolute file
47
- * paths matching the filters. Pure synchronous traversal — no allocations
48
- * beyond the result array. Symlink cycles are detected via a resolved-path
49
- * Set; symlink escapes (resolving outside rootPath) are silently skipped.
50
- */
51
- export declare function walkDirectory(rootPath: string, opts?: WalkOptions): string[];
52
- /**
53
- * Same as walkDirectory but returns capped + totalSeen so callers can surface
54
- * a "capped at N files" notice in their response.
55
- */
56
- export declare function walkDirectoryDetailed(rootPath: string, opts?: WalkOptions): WalkResult;