context-mode 1.0.169 → 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 (379) 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/cli.d.ts +0 -34
  163. package/build/cli.js +0 -1827
  164. package/build/db-base.d.ts +0 -179
  165. package/build/db-base.js +0 -569
  166. package/build/executor.d.ts +0 -72
  167. package/build/executor.js +0 -678
  168. package/build/exit-classify.d.ts +0 -19
  169. package/build/exit-classify.js +0 -12
  170. package/build/fetch-cache.d.ts +0 -13
  171. package/build/fetch-cache.js +0 -15
  172. package/build/lifecycle.d.ts +0 -124
  173. package/build/lifecycle.js +0 -278
  174. package/build/runPool.d.ts +0 -36
  175. package/build/runPool.js +0 -51
  176. package/build/runtime.d.ts +0 -71
  177. package/build/runtime.js +0 -659
  178. package/build/search/auto-memory.d.ts +0 -47
  179. package/build/search/auto-memory.js +0 -170
  180. package/build/search/ctx-search-schema.d.ts +0 -90
  181. package/build/search/ctx-search-schema.js +0 -135
  182. package/build/search/flood-guard.d.ts +0 -57
  183. package/build/search/flood-guard.js +0 -80
  184. package/build/search/unified.d.ts +0 -56
  185. package/build/search/unified.js +0 -104
  186. package/build/security.d.ts +0 -206
  187. package/build/security.js +0 -780
  188. package/build/server.d.ts +0 -184
  189. package/build/server.js +0 -4563
  190. package/build/session/analytics.d.ts +0 -773
  191. package/build/session/analytics.js +0 -2420
  192. package/build/session/db.d.ts +0 -468
  193. package/build/session/db.js +0 -1308
  194. package/build/session/error-classifier.d.ts +0 -87
  195. package/build/session/error-classifier.js +0 -303
  196. package/build/session/event-emit.d.ts +0 -48
  197. package/build/session/event-emit.js +0 -101
  198. package/build/session/extract.d.ts +0 -333
  199. package/build/session/extract.js +0 -2688
  200. package/build/session/model-prices.json +0 -429
  201. package/build/session/persist-tool-calls.d.ts +0 -54
  202. package/build/session/persist-tool-calls.js +0 -105
  203. package/build/session/pricing.d.ts +0 -64
  204. package/build/session/pricing.js +0 -151
  205. package/build/session/project-attribution.d.ts +0 -73
  206. package/build/session/project-attribution.js +0 -245
  207. package/build/session/purge.d.ts +0 -138
  208. package/build/session/purge.js +0 -240
  209. package/build/session/retrieval-marker.d.ts +0 -39
  210. package/build/session/retrieval-marker.js +0 -65
  211. package/build/session/snapshot.d.ts +0 -46
  212. package/build/session/snapshot.js +0 -532
  213. package/build/store-directory.d.ts +0 -56
  214. package/build/store-directory.js +0 -254
  215. package/build/store.d.ts +0 -147
  216. package/build/store.js +0 -1714
  217. package/build/truncate.d.ts +0 -57
  218. package/build/truncate.js +0 -142
  219. package/build/types.d.ts +0 -117
  220. package/build/types.js +0 -20
  221. package/build/util/claude-config.d.ts +0 -32
  222. package/build/util/claude-config.js +0 -84
  223. package/build/util/hook-config.d.ts +0 -27
  224. package/build/util/hook-config.js +0 -76
  225. package/build/util/jsonc.d.ts +0 -14
  226. package/build/util/jsonc.js +0 -104
  227. package/build/util/plugin-cache-integrity.d.ts +0 -51
  228. package/build/util/plugin-cache-integrity.js +0 -146
  229. package/build/util/project-dir.d.ts +0 -149
  230. package/build/util/project-dir.js +0 -340
  231. package/build/util/sibling-mcp.d.ts +0 -79
  232. package/build/util/sibling-mcp.js +0 -181
  233. package/cli.bundle.mjs +0 -1236
  234. package/configs/antigravity/GEMINI.md +0 -68
  235. package/configs/antigravity/mcp_config.json +0 -7
  236. package/configs/antigravity-cli/hooks/hooks.json +0 -37
  237. package/configs/antigravity-cli/hooks.json +0 -37
  238. package/configs/antigravity-cli/mcp_config.json +0 -10
  239. package/configs/antigravity-cli/plugin.json +0 -14
  240. package/configs/antigravity-cli/rules/context-mode.md +0 -77
  241. package/configs/antigravity-cli/skills/context-mode/SKILL.md +0 -77
  242. package/configs/claude-code/CLAUDE.md +0 -91
  243. package/configs/codex/AGENTS.md +0 -99
  244. package/configs/codex/config.toml +0 -8
  245. package/configs/codex/hooks.json +0 -47
  246. package/configs/copilot-cli/.github/plugin/plugin.json +0 -23
  247. package/configs/copilot-cli/.mcp.json +0 -12
  248. package/configs/copilot-cli/README.md +0 -47
  249. package/configs/copilot-cli/hooks.json +0 -41
  250. package/configs/copilot-cli/skills/context-mode/SKILL.md +0 -38
  251. package/configs/cursor/context-mode.mdc +0 -76
  252. package/configs/cursor/hooks.json +0 -21
  253. package/configs/cursor/mcp.json +0 -7
  254. package/configs/gemini-cli/GEMINI.md +0 -88
  255. package/configs/gemini-cli/mcp.json +0 -7
  256. package/configs/gemini-cli/settings.json +0 -60
  257. package/configs/jetbrains-copilot/copilot-instructions.md +0 -80
  258. package/configs/jetbrains-copilot/hooks.json +0 -16
  259. package/configs/jetbrains-copilot/mcp.json +0 -7
  260. package/configs/kilo/AGENTS.md +0 -84
  261. package/configs/kilo/kilo.json +0 -6
  262. package/configs/kimi/hooks.json +0 -54
  263. package/configs/kiro/KIRO.md +0 -84
  264. package/configs/kiro/agent.json +0 -18
  265. package/configs/kiro/mcp.json +0 -7
  266. package/configs/omp/SYSTEM.md +0 -85
  267. package/configs/omp/mcp.json +0 -7
  268. package/configs/openclaw/AGENTS.md +0 -87
  269. package/configs/openclaw/openclaw.json +0 -13
  270. package/configs/opencode/AGENTS.md +0 -84
  271. package/configs/opencode/opencode.json +0 -6
  272. package/configs/pi/AGENTS.md +0 -3
  273. package/configs/qwen-code/QWEN.md +0 -91
  274. package/configs/vscode-copilot/copilot-instructions.md +0 -80
  275. package/configs/vscode-copilot/hooks.json +0 -16
  276. package/configs/vscode-copilot/mcp.json +0 -7
  277. package/configs/zed/AGENTS.md +0 -68
  278. package/hooks/antigravity-cli/payload.mjs +0 -98
  279. package/hooks/antigravity-cli/posttooluse.mjs +0 -138
  280. package/hooks/antigravity-cli/pretooluse.mjs +0 -78
  281. package/hooks/antigravity-cli/stop.mjs +0 -58
  282. package/hooks/auto-injection.mjs +0 -102
  283. package/hooks/cache-heal-utils.mjs +0 -379
  284. package/hooks/codex/platform.mjs +0 -1
  285. package/hooks/codex/posttooluse.mjs +0 -66
  286. package/hooks/codex/precompact.mjs +0 -70
  287. package/hooks/codex/pretooluse.mjs +0 -42
  288. package/hooks/codex/sessionstart.mjs +0 -121
  289. package/hooks/codex/stop.mjs +0 -138
  290. package/hooks/codex/userpromptsubmit.mjs +0 -75
  291. package/hooks/copilot-cli/posttooluse.mjs +0 -79
  292. package/hooks/copilot-cli/precompact.mjs +0 -66
  293. package/hooks/copilot-cli/pretooluse.mjs +0 -41
  294. package/hooks/copilot-cli/sessionstart.mjs +0 -121
  295. package/hooks/copilot-cli/stop.mjs +0 -59
  296. package/hooks/copilot-cli/userpromptsubmit.mjs +0 -77
  297. package/hooks/core/codex-caps.mjs +0 -112
  298. package/hooks/core/formatters.mjs +0 -356
  299. package/hooks/core/mcp-ready.mjs +0 -109
  300. package/hooks/core/platform-detect.mjs +0 -49
  301. package/hooks/core/routing.mjs +0 -1017
  302. package/hooks/core/stdin.mjs +0 -90
  303. package/hooks/core/tool-naming.mjs +0 -57
  304. package/hooks/cursor/afteragentresponse.mjs +0 -74
  305. package/hooks/cursor/hooks.json +0 -31
  306. package/hooks/cursor/posttooluse.mjs +0 -72
  307. package/hooks/cursor/pretooluse.mjs +0 -26
  308. package/hooks/cursor/sessionstart.mjs +0 -97
  309. package/hooks/cursor/stop.mjs +0 -48
  310. package/hooks/ensure-deps.mjs +0 -254
  311. package/hooks/formatters/claude-code.mjs +0 -113
  312. package/hooks/formatters/cursor.mjs +0 -37
  313. package/hooks/formatters/gemini-cli.mjs +0 -55
  314. package/hooks/formatters/vscode-copilot.mjs +0 -55
  315. package/hooks/gemini-cli/aftermodel.mjs +0 -70
  316. package/hooks/gemini-cli/aftertool.mjs +0 -61
  317. package/hooks/gemini-cli/beforeagent.mjs +0 -99
  318. package/hooks/gemini-cli/beforetool.mjs +0 -27
  319. package/hooks/gemini-cli/precompress.mjs +0 -55
  320. package/hooks/gemini-cli/sessionstart.mjs +0 -137
  321. package/hooks/heal-partial-install.mjs +0 -712
  322. package/hooks/jetbrains-copilot/posttooluse.mjs +0 -61
  323. package/hooks/jetbrains-copilot/precompact.mjs +0 -55
  324. package/hooks/jetbrains-copilot/pretooluse.mjs +0 -27
  325. package/hooks/jetbrains-copilot/sessionstart.mjs +0 -124
  326. package/hooks/kimi/platform.mjs +0 -1
  327. package/hooks/kimi/posttooluse.mjs +0 -72
  328. package/hooks/kimi/precompact.mjs +0 -80
  329. package/hooks/kimi/pretooluse.mjs +0 -42
  330. package/hooks/kimi/sessionend.mjs +0 -61
  331. package/hooks/kimi/sessionstart.mjs +0 -113
  332. package/hooks/kimi/stop.mjs +0 -132
  333. package/hooks/kimi/userpromptsubmit.mjs +0 -90
  334. package/hooks/kiro/agentspawn.mjs +0 -97
  335. package/hooks/kiro/posttooluse.mjs +0 -51
  336. package/hooks/kiro/pretooluse.mjs +0 -64
  337. package/hooks/kiro/userpromptsubmit.mjs +0 -88
  338. package/hooks/normalize-hooks.mjs +0 -323
  339. package/hooks/platform-bridge.mjs +0 -340
  340. package/hooks/posttooluse.mjs +0 -225
  341. package/hooks/precompact.mjs +0 -100
  342. package/hooks/pretooluse.mjs +0 -227
  343. package/hooks/qwen-code/platform.mjs +0 -1
  344. package/hooks/qwen-code/stop.mjs +0 -168
  345. package/hooks/routing-block.mjs +0 -105
  346. package/hooks/run-hook.mjs +0 -95
  347. package/hooks/security.bundle.mjs +0 -2
  348. package/hooks/session-attribution.bundle.mjs +0 -1
  349. package/hooks/session-db.bundle.mjs +0 -144
  350. package/hooks/session-directive.mjs +0 -520
  351. package/hooks/session-extract.bundle.mjs +0 -3
  352. package/hooks/session-helpers.mjs +0 -428
  353. package/hooks/session-loaders.mjs +0 -448
  354. package/hooks/session-snapshot.bundle.mjs +0 -32
  355. package/hooks/sessionstart.mjs +0 -464
  356. package/hooks/stop.mjs +0 -82
  357. package/hooks/suppress-stderr.mjs +0 -25
  358. package/hooks/userpromptsubmit.mjs +0 -108
  359. package/hooks/vscode-copilot/posttooluse.mjs +0 -61
  360. package/hooks/vscode-copilot/precompact.mjs +0 -55
  361. package/hooks/vscode-copilot/pretooluse.mjs +0 -27
  362. package/hooks/vscode-copilot/sessionstart.mjs +0 -129
  363. package/openclaw.plugin.json +0 -38
  364. package/scripts/heal-better-sqlite3.mjs +0 -430
  365. package/scripts/heal-installed-plugins.mjs +0 -598
  366. package/scripts/plugin-cache-integrity.mjs +0 -248
  367. package/scripts/postinstall.mjs +0 -384
  368. package/server.bundle.mjs +0 -1162
  369. package/skills/.ignore +0 -7
  370. package/skills/context-mode/SKILL.md +0 -300
  371. package/skills/context-mode/references/anti-patterns.md +0 -283
  372. package/skills/context-mode/references/patterns-javascript.md +0 -298
  373. package/skills/context-mode/references/patterns-python.md +0 -304
  374. package/skills/context-mode/references/patterns-shell.md +0 -277
  375. package/skills/ctx-index/SKILL.md +0 -46
  376. package/skills/ctx-insight/SKILL.md +0 -24
  377. package/skills/ctx-purge/SKILL.md +0 -49
  378. package/skills/ctx-search/SKILL.md +0 -35
  379. 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;