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,626 +0,0 @@
1
- /**
2
- * OpenClaw TypeScript plugin entry point for context-mode.
3
- *
4
- * Exports an object with { id, name, configSchema, register(api) } for
5
- * declarative metadata and config validation before code execution.
6
- *
7
- * register(api) registers:
8
- * - before_tool_call hook — Routing enforcement (deny/modify/passthrough)
9
- * - after_tool_call hook — Session event capture
10
- * - command:new hook — Session initialization and cleanup
11
- * - session_start hook — Re-key DB session to OpenClaw's session ID
12
- * - before_compaction hook — Flush events to resume snapshot
13
- * - after_compaction hook — Increment compact count
14
- * - before_prompt_build (p=10) — Resume snapshot injection into system context
15
- * - before_prompt_build (p=5) — Routing instruction injection into system context
16
- * - context-mode engine — Context engine with compaction management
17
- * - /ctx-stats command — Auto-reply command for session statistics
18
- * - /ctx-doctor command — Auto-reply command for diagnostics
19
- * - /ctx-upgrade command — Auto-reply command for upgrade
20
- *
21
- * Loaded by OpenClaw via: openclaw.extensions entry in package.json
22
- *
23
- * OpenClaw plugin paradigm:
24
- * - Plugins export { id, name, configSchema, register(api) } for metadata
25
- * - api.registerHook() for event-driven hooks
26
- * - api.on() for typed lifecycle hooks
27
- * - api.registerContextEngine() for compaction ownership
28
- * - api.registerCommand() for auto-reply slash commands
29
- * - Plugins run in-process with the Gateway (trusted code)
30
- */
31
- import { createHash, randomUUID } from "node:crypto";
32
- import { existsSync, mkdirSync, readFileSync } from "node:fs";
33
- import { homedir } from "node:os";
34
- import { dirname, join, resolve } from "node:path";
35
- import { fileURLToPath, pathToFileURL } from "node:url";
36
- import { OpenClawSessionDB } from "./adapters/openclaw/session-db.js";
37
- import { extractEvents, extractUserEvents } from "./session/extract.js";
38
- import { buildResumeSnapshot } from "./session/snapshot.js";
39
- import { WorkspaceRouter } from "./openclaw/workspace-router.js";
40
- import { buildNodeCommand } from "./adapters/types.js";
41
- import { OPENCLAW_TOOL_DEFS } from "./openclaw/mcp-tools.js";
42
- // ── System-reminder filter (CCv2 — SLICE OClaw-3) ─────────
43
- // Mirror hooks/userpromptsubmit.mjs:30-33: skip system-generated wrappers
44
- // so before_model_resolve never inserts spurious user-prompt events.
45
- const SYSTEM_REMINDER_PREFIXES = [
46
- "<system-reminder>",
47
- "<task-notification>",
48
- "<context_guidance>",
49
- "<tool-result>",
50
- ];
51
- function isSystemReminderMessage(msg) {
52
- const trimmed = msg.trimStart();
53
- for (const prefix of SYSTEM_REMINDER_PREFIXES) {
54
- if (trimmed.startsWith(prefix))
55
- return true;
56
- }
57
- return false;
58
- }
59
- /** Plugin config schema for OpenClaw validation. */
60
- const configSchema = {
61
- type: "object",
62
- properties: {
63
- enabled: {
64
- type: "boolean",
65
- default: true,
66
- description: "Enable or disable the context-mode plugin.",
67
- },
68
- },
69
- additionalProperties: false,
70
- };
71
- // ── Helpers ───────────────────────────────────────────────
72
- function getSessionDir() {
73
- const dir = join(homedir(), ".openclaw", "context-mode", "sessions");
74
- mkdirSync(dir, { recursive: true });
75
- return dir;
76
- }
77
- function getDBPath(projectDir) {
78
- const hash = createHash("sha256")
79
- .update(projectDir)
80
- .digest("hex")
81
- .slice(0, 16);
82
- return join(getSessionDir(), `${hash}.db`);
83
- }
84
- // ── Module-level DB singleton ─────────────────────────────
85
- // Shared across all register() calls (one per agent session).
86
- // Lazy-initialized on first register() using the first projectDir seen.
87
- // Uses OpenClawSessionDB for session_key mapping and rename support.
88
- let _dbSingleton = null;
89
- function getOrCreateDB(projectDir) {
90
- if (!_dbSingleton) {
91
- const dbPath = getDBPath(projectDir);
92
- _dbSingleton = new OpenClawSessionDB({ dbPath });
93
- _dbSingleton.cleanupOldSessions(7);
94
- }
95
- return _dbSingleton;
96
- }
97
- // ── Module-level state for command handlers ───────────────
98
- // Commands are re-registered on each register() call (OpenClaw's registerCommand
99
- // is idempotent). These refs give handlers access to the current session's state.
100
- let _latestDb = null;
101
- let _latestSessionId = "";
102
- let _latestPluginRoot = "";
103
- // ── Plugin Definition (object export) ─────────────────────
104
- /**
105
- * OpenClaw plugin definition. The object form provides declarative metadata
106
- * (id, name, configSchema) that OpenClaw can read without executing code.
107
- * register() is called once per agent session with a fresh api object.
108
- * Each call creates isolated closures (db, sessionId, hooks) — no shared state.
109
- */
110
- export default {
111
- id: "context-mode",
112
- name: "Context Mode",
113
- configSchema,
114
- // OpenClaw calls register() synchronously — returning a Promise causes hooks
115
- // to be silently ignored. Async init runs eagerly; hooks await it on first use.
116
- register(api) {
117
- // Resolve build dir from compiled JS location
118
- const buildDir = dirname(fileURLToPath(import.meta.url));
119
- const projectDir = process.cwd();
120
- const pluginRoot = resolve(buildDir, "..");
121
- // Structured logger — wraps api.logger, falls back to no-op.
122
- // info/error always emit; debug only when api.logger.debug is present
123
- // (i.e. OpenClaw running with --log-level debug or lower).
124
- const log = {
125
- info: (...args) => api.logger?.info("[context-mode]", ...args),
126
- error: (...args) => api.logger?.error("[context-mode]", ...args),
127
- debug: (...args) => api.logger?.debug?.("[context-mode]", ...args),
128
- warn: (...args) => api.logger?.warn?.("[context-mode]", ...args),
129
- };
130
- // Get shared DB singleton (lazy-init on first register() call)
131
- const db = getOrCreateDB(projectDir);
132
- // Start with temp UUID — session_start will assign the real ID + sessionKey
133
- let sessionId = randomUUID();
134
- log.info("register() called, sessionId:", sessionId.slice(0, 8));
135
- // SLICE OClaw-6 (F6 retraction): `resumeInjected` is correctly scoped
136
- // per-register() singleton — Phase 7 confirmed F6 fabrication-as-tech-debt.
137
- // Each OpenClaw agent session calls register() once and gets its own
138
- // closure; the flag prevents double-injection of the resume snapshot in
139
- // back-to-back before_prompt_build calls within the same session. Do not
140
- // promote to module scope.
141
- let resumeInjected = false;
142
- let sessionKey;
143
- // Create temp session so after_tool_call events before session_start have a valid row
144
- db.ensureSession(sessionId, projectDir);
145
- const workspaceRouter = new WorkspaceRouter();
146
- // Async init: load routing module + dynamic routing-block factory.
147
- // SLICE OClaw-2: replaced static readFileSync(configs/openclaw/AGENTS.md)
148
- // with createRoutingBlock(createToolNamer("openclaw")) so OpenClaw-specific
149
- // MCP-prefix substitution stays in lockstep with hooks/routing-block.mjs.
150
- let routingInstructions = "";
151
- const initPromise = (async () => {
152
- const routingPath = resolve(buildDir, "..", "hooks", "core", "routing.mjs");
153
- const routing = await import(pathToFileURL(routingPath).href);
154
- await routing.initSecurity(buildDir);
155
- try {
156
- const blockMod = await import(pathToFileURL(resolve(buildDir, "..", "hooks", "routing-block.mjs")).href);
157
- const namingMod = await import(pathToFileURL(resolve(buildDir, "..", "hooks", "core", "tool-naming.mjs")).href);
158
- const toolNamer = namingMod.createToolNamer("openclaw");
159
- routingInstructions = blockMod.createRoutingBlock(toolNamer);
160
- }
161
- catch (err) {
162
- log.warn?.("failed to build dynamic routing block", err);
163
- // Fallback: legacy disk-read of AGENTS.md (kept for resilience only —
164
- // primary path is the dynamic factory above).
165
- try {
166
- const instructionsPath = resolve(buildDir, "..", "configs", "openclaw", "AGENTS.md");
167
- if (existsSync(instructionsPath)) {
168
- routingInstructions = readFileSync(instructionsPath, "utf-8");
169
- }
170
- }
171
- catch {
172
- // best effort
173
- }
174
- }
175
- return { routing };
176
- })();
177
- // ── 1. tool_call:before — Routing enforcement ──────────
178
- // NOTE: api.on() was broken in OpenClaw ≤2026.1.29 (fixed in PR #9761, issue #5513).
179
- // api.on() is the correct API for typed lifecycle hooks (session_start, before_tool_call, etc.).
180
- // api.registerHook() is for generic/command hooks (command:new, command:reset, command:stop).
181
- api.on("before_tool_call", async (event) => {
182
- const { routing } = await initPromise;
183
- const e = event;
184
- const toolName = e.toolName ?? "";
185
- const toolInput = e.params ?? {};
186
- let decision;
187
- try {
188
- decision = routing.routePreToolUse(toolName, toolInput, projectDir, "openclaw");
189
- }
190
- catch {
191
- return; // Routing failure → allow passthrough
192
- }
193
- if (!decision)
194
- return; // No routing match → passthrough
195
- log.debug("before_tool_call", { tool: toolName, action: decision.action });
196
- if (decision.action === "deny" || decision.action === "ask") {
197
- return {
198
- block: true,
199
- blockReason: decision.reason ?? "Blocked by context-mode",
200
- };
201
- }
202
- if (decision.action === "modify" && decision.updatedInput) {
203
- // In-place mutation — OpenClaw reads the mutated params object.
204
- Object.assign(toolInput, decision.updatedInput);
205
- }
206
- // "context" action → handled by before_prompt_build, not inline
207
- });
208
- // ── 2. after_tool_call — Session event capture ─────────
209
- // Map OpenClaw tool names → Claude Code equivalents so extractEvents
210
- // can recognize them. OpenClaw uses lowercase names; CC uses PascalCase.
211
- const OPENCLAW_TOOL_MAP = {
212
- exec: "Bash",
213
- read: "Read",
214
- write: "Write",
215
- edit: "Edit",
216
- apply_patch: "Edit",
217
- glob: "Glob",
218
- grep: "Grep",
219
- search: "Grep",
220
- };
221
- api.on("after_tool_call", async (event) => {
222
- try {
223
- const e = event;
224
- const rawToolName = e.toolName ?? "";
225
- const mappedToolName = OPENCLAW_TOOL_MAP[rawToolName] ?? rawToolName;
226
- // Accept both result (v2+) and output (older builds)
227
- const rawResult = e.result ?? e.output;
228
- const resultStr = typeof rawResult === "string"
229
- ? rawResult
230
- : rawResult != null
231
- ? JSON.stringify(rawResult)
232
- : undefined;
233
- // Accept both error (string, v2+) and isError (boolean, older builds)
234
- const hasError = Boolean(e.error || e.isError);
235
- const hookInput = {
236
- tool_name: mappedToolName,
237
- tool_input: e.params ?? {},
238
- tool_response: resultStr,
239
- tool_output: hasError ? { isError: true } : undefined,
240
- };
241
- const events = extractEvents(hookInput);
242
- // Resolve agent-specific sessionId from workspace paths in params
243
- const routedSessionId = workspaceRouter.resolveSessionId(e.params ?? {}) ?? sessionId;
244
- if (events.length > 0) {
245
- for (const ev of events) {
246
- db.insertEvent(routedSessionId, ev, "PostToolUse");
247
- }
248
- log.debug("after_tool_call", { tool: rawToolName, mapped: mappedToolName, sessionId: routedSessionId.slice(0, 8), events: events.length, durationMs: e.durationMs });
249
- }
250
- else if (rawToolName) {
251
- // Fallback: record any unrecognized tool call as a generic event
252
- const data = JSON.stringify({
253
- tool: rawToolName,
254
- params: e.params,
255
- durationMs: e.durationMs,
256
- });
257
- db.insertEvent(routedSessionId, {
258
- type: "tool_call",
259
- category: "openclaw",
260
- data,
261
- priority: 1,
262
- data_hash: createHash("sha256")
263
- .update(data)
264
- .digest("hex")
265
- .slice(0, 16),
266
- }, "PostToolUse");
267
- log.debug("after_tool_call", { tool: rawToolName, mapped: rawToolName, sessionId: routedSessionId.slice(0, 8), events: 1, durationMs: e.durationMs });
268
- }
269
- }
270
- catch {
271
- // Silent — session capture must never break the tool call
272
- }
273
- });
274
- // ── 3. command:new — Session initialization ────────────
275
- api.registerHook("command:new", async () => {
276
- try {
277
- log.debug("command:new", { sessionId: sessionId.slice(0, 8) });
278
- db.cleanupOldSessions(7);
279
- }
280
- catch {
281
- // best effort
282
- }
283
- }, {
284
- name: "context-mode.session-new",
285
- description: "Session initialization — cleans up old sessions on /new command",
286
- });
287
- // ── 3b. command:reset / command:stop — Session cleanup ────
288
- api.registerHook("command:reset", async () => {
289
- try {
290
- log.debug("command:reset", { sessionId: sessionId.slice(0, 8) });
291
- db.cleanupOldSessions(7);
292
- }
293
- catch {
294
- // best effort
295
- }
296
- }, {
297
- name: "context-mode.session-reset",
298
- description: "Session cleanup on /reset command",
299
- });
300
- api.registerHook("command:stop", async () => {
301
- try {
302
- log.debug("command:stop", { sessionId: sessionId.slice(0, 8), sessionKey });
303
- if (sessionKey) {
304
- workspaceRouter.removeSession(sessionKey);
305
- }
306
- db.cleanupOldSessions(7);
307
- }
308
- catch {
309
- // best effort
310
- }
311
- }, {
312
- name: "context-mode.session-stop",
313
- description: "Session cleanup on /stop command",
314
- });
315
- // ── 4. session_start — Re-key DB session to OpenClaw's session ID ─
316
- api.on("session_start", async (event) => {
317
- try {
318
- const e = event;
319
- const sid = e?.sessionId;
320
- if (!sid)
321
- return;
322
- const key = e?.sessionKey;
323
- const resumedFrom = e?.resumedFrom;
324
- log.debug("session_start", { sessionId: sid.slice(0, 8), sessionKey: key, resumedFrom });
325
- if (key) {
326
- // Per-agent session lookup via sessionKey
327
- const prevId = db.getMostRecentSession(key);
328
- if (prevId && prevId !== sid) {
329
- db.renameSession(prevId, sid);
330
- log.info(`session re-keyed ${prevId.slice(0, 8)}… → ${sid.slice(0, 8)}… (key=${key})`);
331
- }
332
- else if (!prevId) {
333
- db.ensureSessionWithKey(sid, projectDir, key);
334
- log.info(`new session ${sid.slice(0, 8)}… (key=${key})`);
335
- }
336
- }
337
- else {
338
- // Fallback: no sessionKey → fresh session (Option A)
339
- db.ensureSession(sid, projectDir);
340
- log.info(`session ${sid.slice(0, 8)}… (no sessionKey — fallback)`);
341
- }
342
- sessionId = sid;
343
- _latestSessionId = sessionId;
344
- sessionKey = key;
345
- if (key) {
346
- workspaceRouter.registerSession(key, sessionId);
347
- }
348
- resumeInjected = false;
349
- // Write routing instructions (AGENTS.md) now that we know the real
350
- // workspace. Derive the workspace directory from the sessionKey so we
351
- // only write into recognised /.openclaw/workspace* paths, never into
352
- // the gateway's cwd or any other arbitrary directory.
353
- }
354
- catch {
355
- // best effort — never break session start
356
- }
357
- });
358
- // ── 5. before_compaction — Flush events to snapshot before compaction ─
359
- // NOTE: OpenClaw compaction hooks were broken until #4967/#3728 fix.
360
- // Adapter gracefully degrades — session recovery falls back to DB snapshot
361
- // reconstruction when compaction events don't fire.
362
- api.on("before_compaction", async () => {
363
- try {
364
- const sid = sessionId; // snapshot to avoid race with concurrent session_start
365
- const allEvents = db.getEvents(sid);
366
- log.debug("before_compaction", { sessionId: sid.slice(0, 8), events: allEvents.length });
367
- if (allEvents.length === 0)
368
- return;
369
- const freshStats = db.getSessionStats(sid);
370
- const snapshot = buildResumeSnapshot(allEvents, {
371
- compactCount: (freshStats?.compact_count ?? 0) + 1,
372
- });
373
- db.upsertResume(sid, snapshot, allEvents.length);
374
- }
375
- catch {
376
- // best effort — never break compaction
377
- }
378
- });
379
- // ── 6. after_compaction — Increment compact count ─────
380
- api.on("after_compaction", async () => {
381
- try {
382
- const sid = sessionId;
383
- log.debug("after_compaction", { sessionId: sid.slice(0, 8) });
384
- db.incrementCompactCount(sid); // sessionId consistent with before_compaction within same sync cycle
385
- }
386
- catch {
387
- // best effort
388
- }
389
- });
390
- // ── 7. before_model_resolve — User message capture ────────
391
- api.on("before_model_resolve", async (event) => {
392
- try {
393
- const sid = sessionId; // snapshot to avoid race with concurrent session_start
394
- const e = event;
395
- const messageText = e?.userMessage ?? e?.message ?? e?.content ?? "";
396
- log.debug("before_model_resolve", { hasMessage: !!messageText });
397
- if (!messageText)
398
- return;
399
- // SLICE OClaw-3: skip system-generated wrappers so we never
400
- // misclassify them as user prompts. Mirrors hooks/userpromptsubmit.mjs:30-33.
401
- if (isSystemReminderMessage(messageText)) {
402
- log.debug("before_model_resolve[skip-system-reminder]");
403
- return;
404
- }
405
- const events = extractUserEvents(messageText);
406
- for (const ev of events) {
407
- db.insertEvent(sid, ev, "PostToolUse");
408
- }
409
- }
410
- catch {
411
- // best effort — never break model resolution
412
- }
413
- });
414
- // ── 8. before_prompt_build — Resume snapshot injection ────
415
- api.on("before_prompt_build", () => {
416
- try {
417
- const sid = sessionId; // snapshot to avoid race with concurrent session_start
418
- const resume = db.getResume(sid);
419
- log.debug("before_prompt_build[resume]", { sessionId: sid.slice(0, 8), hasResume: !!resume, injected: !resumeInjected });
420
- if (resumeInjected)
421
- return undefined;
422
- if (!resume)
423
- return undefined;
424
- const freshStats = db.getSessionStats(sid);
425
- if ((freshStats?.compact_count ?? 0) === 0)
426
- return undefined;
427
- resumeInjected = true;
428
- return { prependSystemContext: resume.snapshot };
429
- }
430
- catch {
431
- return undefined;
432
- }
433
- }, { priority: 10 });
434
- // ── 8. before_prompt_build — Routing instruction injection ──
435
- // SLICE OClaw-2: register unconditionally; routingInstructions is populated
436
- // asynchronously by initPromise. The closure resolves the latest value at
437
- // call-time, so the first prompt-build firing after dynamic-import resolution
438
- // sees the dynamic ROUTING_BLOCK XML (matching hooks/routing-block.mjs).
439
- api.on("before_prompt_build", () => {
440
- if (!routingInstructions)
441
- return undefined;
442
- log.debug("before_prompt_build[routing]", { hasInstructions: !!routingInstructions });
443
- // v1.0.107 — visible marker so OpenClaw users can verify the routing
444
- // block reached the model (Mickey-class verification path; mirrors
445
- // OpenCode + Pi adapters).
446
- const marker = `<!-- context-mode: routing block injected (sessionID=${String(sessionId).slice(0, 8)}) -->`;
447
- return { appendSystemContext: marker + "\n" + routingInstructions };
448
- }, { priority: 5 });
449
- // ── 8b. registerTool — Expose 11 ctx_* tools (SLICE OClaw-1) ────
450
- // Phase 7 audit (v1.0.107-adapter-openclaw.json) flagged severity=CRITICAL:
451
- // routing block tells agents to call ctx_execute / ctx_search / etc. but
452
- // nothing called api.registerTool, so the tools didn't exist in the
453
- // OpenClaw session. This loop fixes that — mirrors swarmvault MCP pattern
454
- // (refs/plugin-examples/openclaw/swarmvault/packages/engine/src/mcp.ts:46-51).
455
- if (api.registerTool) {
456
- for (const def of OPENCLAW_TOOL_DEFS) {
457
- try {
458
- api.registerTool(def);
459
- }
460
- catch (err) {
461
- log.warn?.("registerTool failed", { name: def.name }, err);
462
- }
463
- }
464
- log.debug("registerTool[ctx_*]", { count: OPENCLAW_TOOL_DEFS.length });
465
- }
466
- else {
467
- log.warn?.("api.registerTool unavailable — ctx_* tools not exposed in this OpenClaw build");
468
- }
469
- // ── 8c. session_end — Finalize resume snapshot (SLICE OClaw-4) ───
470
- // OpenClaw fires session_end at session lifecycle boundaries (per
471
- // refs/platforms/openclaw/docs/plugins/hooks.md:110). We persist a final
472
- // resume snapshot so a future session_start with resumedFrom can re-attach.
473
- api.on("session_end", async () => {
474
- try {
475
- const sid = sessionId;
476
- const allEvents = db.getEvents(sid);
477
- log.debug("session_end", { sessionId: sid.slice(0, 8), events: allEvents.length });
478
- if (allEvents.length === 0)
479
- return;
480
- const freshStats = db.getSessionStats(sid);
481
- const snapshot = buildResumeSnapshot(allEvents, {
482
- compactCount: freshStats?.compact_count ?? 0,
483
- });
484
- db.upsertResume(sid, snapshot, allEvents.length);
485
- }
486
- catch {
487
- // best effort — never break session shutdown
488
- }
489
- });
490
- // ── 8d. subagent_spawning — Inject routing block (SLICE OClaw-5) ─
491
- // OpenClaw's subagent lifecycle (hooks.md:116) gives us a chance to seed
492
- // every spawned subagent with the same routing block the parent agent
493
- // sees. Without this, subagents have no MCP-routing guidance and degrade
494
- // back to flooding the context with raw tool output.
495
- api.on("subagent_spawning", (event) => {
496
- try {
497
- const e = (event ?? {});
498
- const basePrompt = e?.input?.prompt ?? "";
499
- if (!routingInstructions)
500
- return undefined;
501
- const newPrompt = basePrompt
502
- ? `${basePrompt}\n\n${routingInstructions}`
503
- : routingInstructions;
504
- log.debug("subagent_spawning[inject-routing]", {
505
- basePromptLen: basePrompt.length,
506
- blockLen: routingInstructions.length,
507
- });
508
- return { inputOverride: { ...(e.input ?? {}), prompt: newPrompt } };
509
- }
510
- catch {
511
- return undefined;
512
- }
513
- });
514
- // ── 9. Context engine — Compaction management ──────────
515
- api.registerContextEngine("context-mode", () => ({
516
- info: {
517
- id: "context-mode",
518
- name: "Context Mode",
519
- ownsCompaction: false,
520
- },
521
- async ingest() {
522
- return { ingested: true };
523
- },
524
- async assemble({ messages }) {
525
- return { messages, estimatedTokens: 0 };
526
- },
527
- async compact() {
528
- // No-op: session continuity is handled by before_compaction / after_compaction hooks.
529
- // Returning ownsCompaction: false + compacted: false lets the host platform (OpenClaw)
530
- // manage conversation truncation, preserving Anthropic thinking/redacted_thinking blocks.
531
- // See: https://github.com/mksglu/context-mode/issues/191
532
- return { ok: true, compacted: false };
533
- },
534
- }));
535
- // ── 10. Auto-reply commands — ctx slash commands ──────
536
- // Update module-level refs so command handlers (registered once) always
537
- // read the latest session's db/sessionId/pluginRoot.
538
- _latestDb = db;
539
- _latestSessionId = sessionId;
540
- _latestPluginRoot = pluginRoot;
541
- if (api.registerCommand) {
542
- api.registerCommand({
543
- name: "ctx-stats",
544
- description: "Show context-mode session statistics",
545
- handler: () => {
546
- const text = buildStatsText(_latestDb, _latestSessionId);
547
- return { text };
548
- },
549
- });
550
- api.registerCommand({
551
- name: "ctx-doctor",
552
- description: "Run context-mode diagnostics",
553
- handler: () => {
554
- const bundlePath = resolve(_latestPluginRoot, "cli.bundle.mjs");
555
- const fallbackPath = resolve(_latestPluginRoot, "build", "cli.js");
556
- const cliPath = existsSync(bundlePath) ? bundlePath : fallbackPath;
557
- const cmd = `${buildNodeCommand(cliPath)} doctor`;
558
- return {
559
- text: [
560
- "## ctx-doctor",
561
- "",
562
- "Run this command to diagnose context-mode:",
563
- "",
564
- "```",
565
- cmd,
566
- "```",
567
- ].join("\n"),
568
- };
569
- },
570
- });
571
- api.registerCommand({
572
- name: "ctx-upgrade",
573
- description: "Upgrade context-mode to the latest version",
574
- handler: () => {
575
- const bundlePath = resolve(_latestPluginRoot, "cli.bundle.mjs");
576
- const fallbackPath = resolve(_latestPluginRoot, "build", "cli.js");
577
- const cliPath = existsSync(bundlePath) ? bundlePath : fallbackPath;
578
- const cmd = `${buildNodeCommand(cliPath)} upgrade`;
579
- return {
580
- text: [
581
- "## ctx-upgrade",
582
- "",
583
- "Run this command to upgrade context-mode:",
584
- "",
585
- "```",
586
- cmd,
587
- "```",
588
- "",
589
- "Restart your session after upgrade.",
590
- ].join("\n"),
591
- };
592
- },
593
- });
594
- }
595
- },
596
- };
597
- // ── Stats helper ──────────────────────────────────────────
598
- function buildStatsText(db, sessionId) {
599
- try {
600
- const events = db.getEvents(sessionId);
601
- const stats = db.getSessionStats(sessionId);
602
- const lines = [
603
- "## context-mode stats",
604
- "",
605
- `- Session: \`${sessionId.slice(0, 8)}…\``,
606
- `- Events captured: ${events.length}`,
607
- `- Compactions: ${stats?.compact_count ?? 0}`,
608
- ];
609
- // Summarize events by type
610
- const byType = {};
611
- for (const ev of events) {
612
- const key = ev.type ?? "unknown";
613
- byType[key] = (byType[key] ?? 0) + 1;
614
- }
615
- if (Object.keys(byType).length > 0) {
616
- lines.push("- Event breakdown:");
617
- for (const [type, count] of Object.entries(byType)) {
618
- lines.push(` - ${type}: ${count}`);
619
- }
620
- }
621
- return lines.join("\n");
622
- }
623
- catch {
624
- return "context-mode stats unavailable (session DB error)";
625
- }
626
- }