context-mode 1.0.169 → 2.0.0-next.6

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 (382) hide show
  1. package/.claude-plugin/marketplace.json +4 -22
  2. package/.claude-plugin/plugin.json +9 -24
  3. package/.codex-plugin/hooks.json +18 -33
  4. package/.codex-plugin/mcp.json +5 -4
  5. package/.codex-plugin/plugin.json +8 -27
  6. package/SHA256SUMS +37 -0
  7. package/claude-code/skills/ctx-doctor/SKILL.md +6 -0
  8. package/claude-code/skills/ctx-stats/SKILL.md +6 -0
  9. package/claude-code/skills/ctx-upgrade/SKILL.md +6 -0
  10. package/cli.mjs +6859 -0
  11. package/codex/skills/ctx-doctor/SKILL.md +6 -0
  12. package/codex/skills/ctx-stats/SKILL.md +6 -0
  13. package/codex/skills/ctx-upgrade/SKILL.md +6 -0
  14. package/copilot/plugin.json +14 -0
  15. package/fixtures/hook-roundtrip.json +22 -0
  16. package/gemini-extension.json +14 -0
  17. package/hook.mjs +202 -0
  18. package/hooks/claude-code.json +50 -0
  19. package/hooks/codex.json +50 -0
  20. package/hooks/copilot-cli.json +33 -0
  21. package/hooks/hooks.json +16 -111
  22. package/hooks/kiro.json +69 -0
  23. package/hooks/qwen.json +50 -0
  24. package/hooks/vscode.json +40 -0
  25. package/hooks/zcode.json +53 -0
  26. package/opencode/plugin.js +22491 -0
  27. package/package.json +32 -114
  28. package/pi/index.js +50876 -0
  29. package/pi/skills/ctx-doctor/SKILL.md +6 -0
  30. package/pi/skills/ctx-stats/SKILL.md +6 -0
  31. package/pi/skills/ctx-upgrade/SKILL.md +6 -0
  32. package/qwen-extension.json +15 -0
  33. package/run.mjs +5639 -0
  34. package/search.mjs +5639 -0
  35. package/server.mjs +48214 -0
  36. package/skills/ctx-doctor/SKILL.md +3 -19
  37. package/skills/ctx-stats/SKILL.md +3 -23
  38. package/skills/ctx-upgrade/SKILL.md +3 -28
  39. package/.openclaw-plugin/index.ts +0 -12
  40. package/.openclaw-plugin/openclaw.plugin.json +0 -38
  41. package/.openclaw-plugin/package.json +0 -28
  42. package/LICENSE +0 -94
  43. package/README.md +0 -1619
  44. package/bin/statusline.mjs +0 -378
  45. package/build/adapters/antigravity/index.d.ts +0 -51
  46. package/build/adapters/antigravity/index.js +0 -169
  47. package/build/adapters/antigravity-cli/index.d.ts +0 -51
  48. package/build/adapters/antigravity-cli/index.js +0 -342
  49. package/build/adapters/base.d.ts +0 -92
  50. package/build/adapters/base.js +0 -135
  51. package/build/adapters/claude-code/config.d.ts +0 -8
  52. package/build/adapters/claude-code/config.js +0 -8
  53. package/build/adapters/claude-code/hooks.d.ts +0 -106
  54. package/build/adapters/claude-code/hooks.js +0 -183
  55. package/build/adapters/claude-code/index.d.ts +0 -80
  56. package/build/adapters/claude-code/index.js +0 -569
  57. package/build/adapters/claude-code-base.d.ts +0 -49
  58. package/build/adapters/claude-code-base.js +0 -113
  59. package/build/adapters/client-map.d.ts +0 -10
  60. package/build/adapters/client-map.js +0 -42
  61. package/build/adapters/codex/config.d.ts +0 -8
  62. package/build/adapters/codex/config.js +0 -8
  63. package/build/adapters/codex/hooks.d.ts +0 -55
  64. package/build/adapters/codex/hooks.js +0 -64
  65. package/build/adapters/codex/index.d.ts +0 -87
  66. package/build/adapters/codex/index.js +0 -992
  67. package/build/adapters/codex/paths.d.ts +0 -1
  68. package/build/adapters/codex/paths.js +0 -12
  69. package/build/adapters/codex/usage.d.ts +0 -107
  70. package/build/adapters/codex/usage.js +0 -227
  71. package/build/adapters/copilot-base.d.ts +0 -94
  72. package/build/adapters/copilot-base.js +0 -297
  73. package/build/adapters/copilot-cli/hooks.d.ts +0 -33
  74. package/build/adapters/copilot-cli/hooks.js +0 -64
  75. package/build/adapters/copilot-cli/index.d.ts +0 -48
  76. package/build/adapters/copilot-cli/index.js +0 -341
  77. package/build/adapters/cursor/config.d.ts +0 -4
  78. package/build/adapters/cursor/config.js +0 -4
  79. package/build/adapters/cursor/hooks.d.ts +0 -55
  80. package/build/adapters/cursor/hooks.js +0 -82
  81. package/build/adapters/cursor/index.d.ts +0 -64
  82. package/build/adapters/cursor/index.js +0 -517
  83. package/build/adapters/detect.d.ts +0 -136
  84. package/build/adapters/detect.js +0 -623
  85. package/build/adapters/gemini-cli/config.d.ts +0 -8
  86. package/build/adapters/gemini-cli/config.js +0 -8
  87. package/build/adapters/gemini-cli/hooks.d.ts +0 -83
  88. package/build/adapters/gemini-cli/hooks.js +0 -115
  89. package/build/adapters/gemini-cli/index.d.ts +0 -80
  90. package/build/adapters/gemini-cli/index.js +0 -483
  91. package/build/adapters/jetbrains-copilot/config.d.ts +0 -8
  92. package/build/adapters/jetbrains-copilot/config.js +0 -8
  93. package/build/adapters/jetbrains-copilot/hooks.d.ts +0 -59
  94. package/build/adapters/jetbrains-copilot/hooks.js +0 -87
  95. package/build/adapters/jetbrains-copilot/index.d.ts +0 -31
  96. package/build/adapters/jetbrains-copilot/index.js +0 -131
  97. package/build/adapters/kimi/config.d.ts +0 -8
  98. package/build/adapters/kimi/config.js +0 -8
  99. package/build/adapters/kimi/hooks.d.ts +0 -28
  100. package/build/adapters/kimi/hooks.js +0 -34
  101. package/build/adapters/kimi/index.d.ts +0 -66
  102. package/build/adapters/kimi/index.js +0 -537
  103. package/build/adapters/kimi/paths.d.ts +0 -21
  104. package/build/adapters/kimi/paths.js +0 -52
  105. package/build/adapters/kimi/usage.d.ts +0 -82
  106. package/build/adapters/kimi/usage.js +0 -217
  107. package/build/adapters/kiro/hooks.d.ts +0 -61
  108. package/build/adapters/kiro/hooks.js +0 -94
  109. package/build/adapters/kiro/index.d.ts +0 -61
  110. package/build/adapters/kiro/index.js +0 -301
  111. package/build/adapters/omp/index.d.ts +0 -65
  112. package/build/adapters/omp/index.js +0 -182
  113. package/build/adapters/omp/plugin.d.ts +0 -81
  114. package/build/adapters/omp/plugin.js +0 -331
  115. package/build/adapters/omp/usage.d.ts +0 -49
  116. package/build/adapters/omp/usage.js +0 -110
  117. package/build/adapters/openclaw/config.d.ts +0 -8
  118. package/build/adapters/openclaw/config.js +0 -8
  119. package/build/adapters/openclaw/hooks.d.ts +0 -50
  120. package/build/adapters/openclaw/hooks.js +0 -61
  121. package/build/adapters/openclaw/index.d.ts +0 -74
  122. package/build/adapters/openclaw/index.js +0 -439
  123. package/build/adapters/openclaw/mcp-tools.d.ts +0 -54
  124. package/build/adapters/openclaw/mcp-tools.js +0 -207
  125. package/build/adapters/openclaw/plugin.d.ts +0 -141
  126. package/build/adapters/openclaw/plugin.js +0 -818
  127. package/build/adapters/openclaw/session-db.d.ts +0 -55
  128. package/build/adapters/openclaw/session-db.js +0 -88
  129. package/build/adapters/openclaw/usage.d.ts +0 -34
  130. package/build/adapters/openclaw/usage.js +0 -52
  131. package/build/adapters/openclaw/workspace-router.d.ts +0 -29
  132. package/build/adapters/openclaw/workspace-router.js +0 -64
  133. package/build/adapters/opencode/config.d.ts +0 -8
  134. package/build/adapters/opencode/config.js +0 -8
  135. package/build/adapters/opencode/hooks.d.ts +0 -38
  136. package/build/adapters/opencode/hooks.js +0 -50
  137. package/build/adapters/opencode/index.d.ts +0 -67
  138. package/build/adapters/opencode/index.js +0 -463
  139. package/build/adapters/opencode/plugin.d.ts +0 -184
  140. package/build/adapters/opencode/plugin.js +0 -558
  141. package/build/adapters/opencode/zod3tov4.d.ts +0 -1
  142. package/build/adapters/opencode/zod3tov4.js +0 -132
  143. package/build/adapters/pi/extension.d.ts +0 -81
  144. package/build/adapters/pi/extension.js +0 -861
  145. package/build/adapters/pi/index.d.ts +0 -57
  146. package/build/adapters/pi/index.js +0 -173
  147. package/build/adapters/pi/mcp-bridge.d.ts +0 -268
  148. package/build/adapters/pi/mcp-bridge.js +0 -894
  149. package/build/adapters/qwen-code/hooks.d.ts +0 -26
  150. package/build/adapters/qwen-code/hooks.js +0 -29
  151. package/build/adapters/qwen-code/index.d.ts +0 -40
  152. package/build/adapters/qwen-code/index.js +0 -361
  153. package/build/adapters/qwen-code/usage.d.ts +0 -90
  154. package/build/adapters/qwen-code/usage.js +0 -222
  155. package/build/adapters/types.d.ts +0 -360
  156. package/build/adapters/types.js +0 -118
  157. package/build/adapters/vscode-copilot/config.d.ts +0 -8
  158. package/build/adapters/vscode-copilot/config.js +0 -8
  159. package/build/adapters/vscode-copilot/hooks.d.ts +0 -71
  160. package/build/adapters/vscode-copilot/hooks.js +0 -98
  161. package/build/adapters/vscode-copilot/index.d.ts +0 -32
  162. package/build/adapters/vscode-copilot/index.js +0 -222
  163. package/build/adapters/zed/index.d.ts +0 -40
  164. package/build/adapters/zed/index.js +0 -163
  165. package/build/cli.d.ts +0 -34
  166. package/build/cli.js +0 -1827
  167. package/build/db-base.d.ts +0 -179
  168. package/build/db-base.js +0 -569
  169. package/build/executor.d.ts +0 -72
  170. package/build/executor.js +0 -678
  171. package/build/exit-classify.d.ts +0 -19
  172. package/build/exit-classify.js +0 -12
  173. package/build/fetch-cache.d.ts +0 -13
  174. package/build/fetch-cache.js +0 -15
  175. package/build/lifecycle.d.ts +0 -124
  176. package/build/lifecycle.js +0 -278
  177. package/build/runPool.d.ts +0 -36
  178. package/build/runPool.js +0 -51
  179. package/build/runtime.d.ts +0 -71
  180. package/build/runtime.js +0 -659
  181. package/build/search/auto-memory.d.ts +0 -47
  182. package/build/search/auto-memory.js +0 -170
  183. package/build/search/ctx-search-schema.d.ts +0 -90
  184. package/build/search/ctx-search-schema.js +0 -135
  185. package/build/search/flood-guard.d.ts +0 -57
  186. package/build/search/flood-guard.js +0 -80
  187. package/build/search/unified.d.ts +0 -56
  188. package/build/search/unified.js +0 -104
  189. package/build/security.d.ts +0 -206
  190. package/build/security.js +0 -780
  191. package/build/server.d.ts +0 -184
  192. package/build/server.js +0 -4563
  193. package/build/session/analytics.d.ts +0 -773
  194. package/build/session/analytics.js +0 -2420
  195. package/build/session/db.d.ts +0 -468
  196. package/build/session/db.js +0 -1308
  197. package/build/session/error-classifier.d.ts +0 -87
  198. package/build/session/error-classifier.js +0 -303
  199. package/build/session/event-emit.d.ts +0 -48
  200. package/build/session/event-emit.js +0 -101
  201. package/build/session/extract.d.ts +0 -333
  202. package/build/session/extract.js +0 -2688
  203. package/build/session/model-prices.json +0 -429
  204. package/build/session/persist-tool-calls.d.ts +0 -54
  205. package/build/session/persist-tool-calls.js +0 -105
  206. package/build/session/pricing.d.ts +0 -64
  207. package/build/session/pricing.js +0 -151
  208. package/build/session/project-attribution.d.ts +0 -73
  209. package/build/session/project-attribution.js +0 -245
  210. package/build/session/purge.d.ts +0 -138
  211. package/build/session/purge.js +0 -240
  212. package/build/session/retrieval-marker.d.ts +0 -39
  213. package/build/session/retrieval-marker.js +0 -65
  214. package/build/session/snapshot.d.ts +0 -46
  215. package/build/session/snapshot.js +0 -532
  216. package/build/store-directory.d.ts +0 -56
  217. package/build/store-directory.js +0 -254
  218. package/build/store.d.ts +0 -147
  219. package/build/store.js +0 -1714
  220. package/build/truncate.d.ts +0 -57
  221. package/build/truncate.js +0 -142
  222. package/build/types.d.ts +0 -117
  223. package/build/types.js +0 -20
  224. package/build/util/claude-config.d.ts +0 -32
  225. package/build/util/claude-config.js +0 -84
  226. package/build/util/hook-config.d.ts +0 -27
  227. package/build/util/hook-config.js +0 -76
  228. package/build/util/jsonc.d.ts +0 -14
  229. package/build/util/jsonc.js +0 -104
  230. package/build/util/plugin-cache-integrity.d.ts +0 -51
  231. package/build/util/plugin-cache-integrity.js +0 -146
  232. package/build/util/project-dir.d.ts +0 -149
  233. package/build/util/project-dir.js +0 -340
  234. package/build/util/sibling-mcp.d.ts +0 -79
  235. package/build/util/sibling-mcp.js +0 -181
  236. package/cli.bundle.mjs +0 -1236
  237. package/configs/antigravity/GEMINI.md +0 -68
  238. package/configs/antigravity/mcp_config.json +0 -7
  239. package/configs/antigravity-cli/hooks/hooks.json +0 -37
  240. package/configs/antigravity-cli/hooks.json +0 -37
  241. package/configs/antigravity-cli/mcp_config.json +0 -10
  242. package/configs/antigravity-cli/plugin.json +0 -14
  243. package/configs/antigravity-cli/rules/context-mode.md +0 -77
  244. package/configs/antigravity-cli/skills/context-mode/SKILL.md +0 -77
  245. package/configs/claude-code/CLAUDE.md +0 -91
  246. package/configs/codex/AGENTS.md +0 -99
  247. package/configs/codex/config.toml +0 -8
  248. package/configs/codex/hooks.json +0 -47
  249. package/configs/copilot-cli/.github/plugin/plugin.json +0 -23
  250. package/configs/copilot-cli/.mcp.json +0 -12
  251. package/configs/copilot-cli/README.md +0 -47
  252. package/configs/copilot-cli/hooks.json +0 -41
  253. package/configs/copilot-cli/skills/context-mode/SKILL.md +0 -38
  254. package/configs/cursor/context-mode.mdc +0 -76
  255. package/configs/cursor/hooks.json +0 -21
  256. package/configs/cursor/mcp.json +0 -7
  257. package/configs/gemini-cli/GEMINI.md +0 -88
  258. package/configs/gemini-cli/mcp.json +0 -7
  259. package/configs/gemini-cli/settings.json +0 -60
  260. package/configs/jetbrains-copilot/copilot-instructions.md +0 -80
  261. package/configs/jetbrains-copilot/hooks.json +0 -16
  262. package/configs/jetbrains-copilot/mcp.json +0 -7
  263. package/configs/kilo/AGENTS.md +0 -84
  264. package/configs/kilo/kilo.json +0 -6
  265. package/configs/kimi/hooks.json +0 -54
  266. package/configs/kiro/KIRO.md +0 -84
  267. package/configs/kiro/agent.json +0 -18
  268. package/configs/kiro/mcp.json +0 -7
  269. package/configs/omp/SYSTEM.md +0 -85
  270. package/configs/omp/mcp.json +0 -7
  271. package/configs/openclaw/AGENTS.md +0 -87
  272. package/configs/openclaw/openclaw.json +0 -13
  273. package/configs/opencode/AGENTS.md +0 -84
  274. package/configs/opencode/opencode.json +0 -6
  275. package/configs/pi/AGENTS.md +0 -3
  276. package/configs/qwen-code/QWEN.md +0 -91
  277. package/configs/vscode-copilot/copilot-instructions.md +0 -80
  278. package/configs/vscode-copilot/hooks.json +0 -16
  279. package/configs/vscode-copilot/mcp.json +0 -7
  280. package/configs/zed/AGENTS.md +0 -68
  281. package/hooks/antigravity-cli/payload.mjs +0 -98
  282. package/hooks/antigravity-cli/posttooluse.mjs +0 -138
  283. package/hooks/antigravity-cli/pretooluse.mjs +0 -78
  284. package/hooks/antigravity-cli/stop.mjs +0 -58
  285. package/hooks/auto-injection.mjs +0 -102
  286. package/hooks/cache-heal-utils.mjs +0 -379
  287. package/hooks/codex/platform.mjs +0 -1
  288. package/hooks/codex/posttooluse.mjs +0 -66
  289. package/hooks/codex/precompact.mjs +0 -70
  290. package/hooks/codex/pretooluse.mjs +0 -42
  291. package/hooks/codex/sessionstart.mjs +0 -121
  292. package/hooks/codex/stop.mjs +0 -138
  293. package/hooks/codex/userpromptsubmit.mjs +0 -75
  294. package/hooks/copilot-cli/posttooluse.mjs +0 -79
  295. package/hooks/copilot-cli/precompact.mjs +0 -66
  296. package/hooks/copilot-cli/pretooluse.mjs +0 -41
  297. package/hooks/copilot-cli/sessionstart.mjs +0 -121
  298. package/hooks/copilot-cli/stop.mjs +0 -59
  299. package/hooks/copilot-cli/userpromptsubmit.mjs +0 -77
  300. package/hooks/core/codex-caps.mjs +0 -112
  301. package/hooks/core/formatters.mjs +0 -356
  302. package/hooks/core/mcp-ready.mjs +0 -109
  303. package/hooks/core/platform-detect.mjs +0 -49
  304. package/hooks/core/routing.mjs +0 -1017
  305. package/hooks/core/stdin.mjs +0 -90
  306. package/hooks/core/tool-naming.mjs +0 -57
  307. package/hooks/cursor/afteragentresponse.mjs +0 -74
  308. package/hooks/cursor/hooks.json +0 -31
  309. package/hooks/cursor/posttooluse.mjs +0 -72
  310. package/hooks/cursor/pretooluse.mjs +0 -26
  311. package/hooks/cursor/sessionstart.mjs +0 -97
  312. package/hooks/cursor/stop.mjs +0 -48
  313. package/hooks/ensure-deps.mjs +0 -254
  314. package/hooks/formatters/claude-code.mjs +0 -113
  315. package/hooks/formatters/cursor.mjs +0 -37
  316. package/hooks/formatters/gemini-cli.mjs +0 -55
  317. package/hooks/formatters/vscode-copilot.mjs +0 -55
  318. package/hooks/gemini-cli/aftermodel.mjs +0 -70
  319. package/hooks/gemini-cli/aftertool.mjs +0 -61
  320. package/hooks/gemini-cli/beforeagent.mjs +0 -99
  321. package/hooks/gemini-cli/beforetool.mjs +0 -27
  322. package/hooks/gemini-cli/precompress.mjs +0 -55
  323. package/hooks/gemini-cli/sessionstart.mjs +0 -137
  324. package/hooks/heal-partial-install.mjs +0 -712
  325. package/hooks/jetbrains-copilot/posttooluse.mjs +0 -61
  326. package/hooks/jetbrains-copilot/precompact.mjs +0 -55
  327. package/hooks/jetbrains-copilot/pretooluse.mjs +0 -27
  328. package/hooks/jetbrains-copilot/sessionstart.mjs +0 -124
  329. package/hooks/kimi/platform.mjs +0 -1
  330. package/hooks/kimi/posttooluse.mjs +0 -72
  331. package/hooks/kimi/precompact.mjs +0 -80
  332. package/hooks/kimi/pretooluse.mjs +0 -42
  333. package/hooks/kimi/sessionend.mjs +0 -61
  334. package/hooks/kimi/sessionstart.mjs +0 -113
  335. package/hooks/kimi/stop.mjs +0 -132
  336. package/hooks/kimi/userpromptsubmit.mjs +0 -90
  337. package/hooks/kiro/agentspawn.mjs +0 -97
  338. package/hooks/kiro/posttooluse.mjs +0 -51
  339. package/hooks/kiro/pretooluse.mjs +0 -64
  340. package/hooks/kiro/userpromptsubmit.mjs +0 -88
  341. package/hooks/normalize-hooks.mjs +0 -323
  342. package/hooks/platform-bridge.mjs +0 -340
  343. package/hooks/posttooluse.mjs +0 -225
  344. package/hooks/precompact.mjs +0 -100
  345. package/hooks/pretooluse.mjs +0 -227
  346. package/hooks/qwen-code/platform.mjs +0 -1
  347. package/hooks/qwen-code/stop.mjs +0 -168
  348. package/hooks/routing-block.mjs +0 -105
  349. package/hooks/run-hook.mjs +0 -95
  350. package/hooks/security.bundle.mjs +0 -2
  351. package/hooks/session-attribution.bundle.mjs +0 -1
  352. package/hooks/session-db.bundle.mjs +0 -144
  353. package/hooks/session-directive.mjs +0 -520
  354. package/hooks/session-extract.bundle.mjs +0 -3
  355. package/hooks/session-helpers.mjs +0 -428
  356. package/hooks/session-loaders.mjs +0 -448
  357. package/hooks/session-snapshot.bundle.mjs +0 -32
  358. package/hooks/sessionstart.mjs +0 -464
  359. package/hooks/stop.mjs +0 -82
  360. package/hooks/suppress-stderr.mjs +0 -25
  361. package/hooks/userpromptsubmit.mjs +0 -108
  362. package/hooks/vscode-copilot/posttooluse.mjs +0 -61
  363. package/hooks/vscode-copilot/precompact.mjs +0 -55
  364. package/hooks/vscode-copilot/pretooluse.mjs +0 -27
  365. package/hooks/vscode-copilot/sessionstart.mjs +0 -129
  366. package/openclaw.plugin.json +0 -38
  367. package/scripts/heal-better-sqlite3.mjs +0 -430
  368. package/scripts/heal-installed-plugins.mjs +0 -598
  369. package/scripts/plugin-cache-integrity.mjs +0 -248
  370. package/scripts/postinstall.mjs +0 -384
  371. package/server.bundle.mjs +0 -1162
  372. package/skills/.ignore +0 -7
  373. package/skills/context-mode/SKILL.md +0 -300
  374. package/skills/context-mode/references/anti-patterns.md +0 -283
  375. package/skills/context-mode/references/patterns-javascript.md +0 -298
  376. package/skills/context-mode/references/patterns-python.md +0 -304
  377. package/skills/context-mode/references/patterns-shell.md +0 -277
  378. package/skills/ctx-index/SKILL.md +0 -46
  379. package/skills/ctx-insight/SKILL.md +0 -24
  380. package/skills/ctx-purge/SKILL.md +0 -49
  381. package/skills/ctx-search/SKILL.md +0 -35
  382. package/start.mjs +0 -616
@@ -1,558 +0,0 @@
1
- /**
2
- * OpenCode / KiloCode TypeScript plugin entry point for context-mode.
3
- *
4
- * Provides five hooks (v1.0.107 — Mickey OC-1..OC-4 follow-up):
5
- * - tool.execute.before — Routing enforcement (deny/modify/passthrough)
6
- * - tool.execute.after — Session event capture + first-fire AGENTS.md scan (OC-4)
7
- * - experimental.session.compacting — Compaction snapshot + budget-capped auto-injection (OC-3)
8
- * - experimental.chat.system.transform — ROUTING_BLOCK + resume snapshot injection (OC-1)
9
- * - chat.message — User-prompt capture w/ CCv2 inline filter (OC-2) + AGENTS.md scan (OC-4)
10
- *
11
- * KiloCode loads this via: import("context-mode") → expects default export
12
- * with shape { server: (input) => Promise<Hooks> } (PluginModule).
13
- *
14
- * OpenCode loads this via: import("context-mode/plugin") → also supports
15
- * the named export ContextModePlugin for backward compat.
16
- *
17
- * Constraints:
18
- * - No SessionStart hook (OpenCode doesn't support it — #14808, #5409)
19
- * - context injection now via chat.system.transform surrogate (OC-1)
20
- * - No routing file auto-write (avoid dirtying project trees)
21
- * - Session cleanup happens at plugin init (no SessionStart)
22
- */
23
- import { dirname, resolve, join } from "node:path";
24
- import { fileURLToPath, pathToFileURL } from "node:url";
25
- import { existsSync, readFileSync } from "node:fs";
26
- import { resolveSessionDbPath, SessionDB } from "../../session/db.js";
27
- import { extractEvents, extractUserEvents, parseOpencodeUsage, buildAgentUsageEvent } from "../../session/extract.js";
28
- import { buildResumeSnapshot } from "../../session/snapshot.js";
29
- import { OpenCodeAdapter } from "./index.js";
30
- import { PLATFORM_ENV_VARS } from "../detect.js";
31
- import { zod3ShapeToV4 } from "./zod3tov4.js";
32
- // Synthetic message tags emitted by harnesses (CCv2 inline filter). When the
33
- // user "message" is actually a system-generated nudge (e.g. tool-result, system
34
- // reminder), capturing it as user_prompt would flood the DB with noise.
35
- const SYNTHETIC_MESSAGE_PREFIXES = [
36
- "<task-notification>",
37
- "<system-reminder>",
38
- "<context_guidance>",
39
- "<tool-result>",
40
- ];
41
- function isSyntheticMessage(text) {
42
- const trimmed = text.trim();
43
- return SYNTHETIC_MESSAGE_PREFIXES.some((p) => trimmed.startsWith(p));
44
- }
45
- // ── Helpers ───────────────────────────────────────────────
46
- // Quorum markers — must NOT be substrings of each other (#487).
47
- // Each token uniquely identifies the routing block / context-mode rules
48
- // without overlapping any other marker. The XML tag is the primary signal;
49
- // the two distinctive bare tool names are the secondary signals. Together
50
- // any 2 of 3 confirm the system prompt already carries routing instructions.
51
- const ROUTING_MARKERS = [
52
- "<context_window_protection>",
53
- "ctx_search",
54
- "ctx_index",
55
- ];
56
- function systemHasRoutingInstructions(system) {
57
- const text = system.join("\n");
58
- // Word-boundary check guards against unrelated identifiers that happen to
59
- // share a prefix/suffix (e.g. a hypothetical `ctx_search_v2`).
60
- const wordBoundary = (m) => {
61
- if (m.startsWith("<"))
62
- return text.includes(m);
63
- const re = new RegExp(`(?:^|\\W)${m.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}(?:\\W|$)`);
64
- return re.test(text);
65
- };
66
- return ROUTING_MARKERS.filter(wordBoundary).length >= 2;
67
- }
68
- /**
69
- * Detect whether the plugin is running under KiloCode or OpenCode.
70
- *
71
- * Reuses the canonical PLATFORM_ENV_VARS list (src/adapters/detect.ts) instead
72
- * of hardcoding env var names — single source of truth, future-proof if Kilo
73
- * or OpenCode add/rename env vars upstream.
74
- *
75
- * Order matters: KiloCode is an OpenCode fork and sets `OPENCODE=1` in
76
- * addition to `KILO_PID`. PLATFORM_ENV_VARS lists `kilo` BEFORE `opencode`
77
- * so KILO_PID wins the iteration.
78
- *
79
- * Pre-fix version was `return process.env.KILO_PID ? "kilo" : "opencode";` —
80
- * surfaced by github.com/mksglu/context-mode/pull/376 (mikij). Full symmetric
81
- * fix: also actively check opencode env vars instead of blind fallback.
82
- */
83
- function getPlatform() {
84
- for (const [platform, vars] of PLATFORM_ENV_VARS) {
85
- if (platform !== "kilo" && platform !== "opencode")
86
- continue;
87
- if (vars.some((v) => process.env[v.name])) {
88
- return platform;
89
- }
90
- }
91
- // Plugin host should always set one of the env vars. Fallback to opencode
92
- // (the wider ecosystem) when neither is set, for predictable behavior.
93
- return "opencode";
94
- }
95
- // ── Plugin Factory ────────────────────────────────────────
96
- /**
97
- * Plugin factory. Called once when KiloCode/OpenCode loads the plugin.
98
- * Returns an object mapping hook event names to async handler functions.
99
- *
100
- * KiloCode expects: export default { id: string, server: (input) => Promise<Hooks> }
101
- * OpenCode expects: export const ContextModePlugin = (ctx) => Promise<Hooks>
102
- */
103
- async function createContextModePlugin(ctx) {
104
- // Resolve build dir from compiled JS location
105
- const platform = getPlatform();
106
- const adapter = new OpenCodeAdapter(platform);
107
- const buildDir = dirname(fileURLToPath(import.meta.url));
108
- // initSecurity() looks for `<dir>/security.js`, which lives at the
109
- // top of build/ — two levels up from this adapter directory.
110
- const buildRoot = resolve(buildDir, "..", "..");
111
- // Load routing module (ESM .mjs, lives outside build/ in hooks/)
112
- const routingPath = resolve(buildDir, "..", "..", "..", "hooks", "core", "routing.mjs");
113
- const routing = await import(pathToFileURL(routingPath).href);
114
- await routing.initSecurity(buildRoot);
115
- // OC-1 / OC-3: Load hook helpers once at plugin init. Dynamic import keeps
116
- // the .mjs ESM islands isolated from the .ts compile graph.
117
- const routingBlockPath = resolve(buildDir, "..", "..", "..", "hooks", "routing-block.mjs");
118
- const routingBlockMod = await import(pathToFileURL(routingBlockPath).href);
119
- const toolNamingPath = resolve(buildDir, "..", "..", "..", "hooks", "core", "tool-naming.mjs");
120
- const toolNamingMod = await import(pathToFileURL(toolNamingPath).href);
121
- const autoInjectionPath = resolve(buildDir, "..", "..", "..", "hooks", "auto-injection.mjs");
122
- const autoInjectionMod = await import(pathToFileURL(autoInjectionPath).href);
123
- // Pre-build the routing block once per process — it is platform-specific
124
- // (tool naming differs between opencode and kilo) but does NOT depend on
125
- // sessionID, so we cache it. createToolNamer accepts both "opencode" and
126
- // "kilo" per hooks/core/tool-naming.mjs:25-26.
127
- const toolNamer = toolNamingMod.createToolNamer(platform);
128
- const routingBlock = routingBlockMod.createRoutingBlock(toolNamer);
129
- // Initialize per-process state. We do NOT fabricate a sessionId here —
130
- // OpenCode/Kilo provide the real `input.sessionID` on every hook, and a
131
- // process-global UUID would (a) never match prior-session resume rows and
132
- // (b) collide across multi-session reuse (Mickey / PR #376 root cause).
133
- const projectDir = ctx?.directory ?? process.cwd();
134
- // C2 narrowing: resolve DB path through the canonical helper directly.
135
- // BaseAdapter no longer exposes getSessionDBPath; the adapter only owns
136
- // the sessions DIR (per-platform), the helper owns the per-project FILE
137
- // (case-fold + worktree-suffix + one-shot legacy migration).
138
- const db = new SessionDB({
139
- dbPath: resolveSessionDbPath({ projectDir, sessionsDir: adapter.getSessionDir() }),
140
- });
141
- // Clean up old sessions on startup (no SessionStart hook to do this).
142
- db.cleanupOldSessions(7);
143
- // OC-4 (#487 follow-up): per-session capture gate. PR #487 trusted the host
144
- // to deliver AGENTS.md events, but OpenCode only fires `rule_content` events
145
- // when the user explicitly reads the file. snapshot.ts:172 + analytics.ts:152
146
- // CONSUME `rule_content` to render rules into the resume snapshot — without
147
- // this capture path, AGENTS.md is silently absent from continuity output.
148
- // Keyed by sessionId (NOT projectDir) so multi-session reuse within a long-
149
- // lived plugin process still gets per-session capture exactly once.
150
- const agentsMdCaptured = new Set();
151
- /**
152
- * OC-4: Read AGENTS.md (with CLAUDE.md / CONTEXT.md fallbacks) from the
153
- * project directory and persist as `rule` + `rule_content` events. Mirrors
154
- * the CC SessionStart pattern at hooks/sessionstart.mjs:121-132 and the
155
- * OpenCode instruction.ts FILES order. Idempotent via `agentsMdCaptured`
156
- * Set keyed by sessionId. Fail-soft: missing/unreadable files do not throw.
157
- */
158
- function captureAgentsMd(sessionId) {
159
- if (agentsMdCaptured.has(sessionId))
160
- return;
161
- agentsMdCaptured.add(sessionId);
162
- const candidates = ["AGENTS.md", "CLAUDE.md", "CONTEXT.md"];
163
- for (const name of candidates) {
164
- try {
165
- const p = join(projectDir, name);
166
- if (!existsSync(p))
167
- continue;
168
- const content = readFileSync(p, "utf-8");
169
- if (!content.trim())
170
- continue;
171
- db.insertEvent(sessionId, {
172
- type: "rule",
173
- category: "rule",
174
- data: p,
175
- priority: 1,
176
- }, "PluginInit");
177
- db.insertEvent(sessionId, {
178
- type: "rule_content",
179
- category: "rule",
180
- data: content,
181
- priority: 1,
182
- }, "PluginInit");
183
- }
184
- catch {
185
- // file missing or unreadable — skip silently
186
- }
187
- }
188
- }
189
- function logger(message = "context-mode debug log", extra) {
190
- return ctx.client.app.log({
191
- body: {
192
- service: "context-mode-logger",
193
- level: "info",
194
- message,
195
- extra,
196
- },
197
- });
198
- }
199
- /**
200
- * Drop-in wrapper for `logger` that NEVER rejects (#448).
201
- *
202
- * The OPENCODE_DEBUG branch awaits `logger(...)` from inside the chat-turn
203
- * hot path (chat.system.transform). If `ctx.client.app.log` rejects —
204
- * transport error, closed stream, oversized payload — the promise rejection
205
- * propagates back to OpenCode core and can break the turn. Debug logging
206
- * is best-effort; swallow errors silently and let the turn proceed.
207
- */
208
- async function safeLog(message, extra) {
209
- try {
210
- await logger(message, extra);
211
- }
212
- catch {
213
- // Never break the turn on debug-log failure.
214
- }
215
- }
216
- async function buildNativeTools() {
217
- // Import the existing MCP server registry without starting its stdio
218
- // transport. This is the plugin-only bridge for #574: OpenCode/Kilo
219
- // call ctx_* tools in-process through Hooks.tool instead of spawning
220
- // a separate MCP child per session.
221
- const prevEmbedded = process.env.CONTEXT_MODE_EMBEDDED_PLUGIN_TOOLS;
222
- process.env.CONTEXT_MODE_EMBEDDED_PLUGIN_TOOLS = "1";
223
- let mod;
224
- try {
225
- mod = await import("../../server.js");
226
- }
227
- finally {
228
- if (prevEmbedded === undefined)
229
- delete process.env.CONTEXT_MODE_EMBEDDED_PLUGIN_TOOLS;
230
- else
231
- process.env.CONTEXT_MODE_EMBEDDED_PLUGIN_TOOLS = prevEmbedded;
232
- }
233
- const tools = {};
234
- for (const registered of mod.REGISTERED_CTX_TOOLS) {
235
- const config = registered.config;
236
- // Zod schema object that the MCP framework normally calls
237
- // safeParseAsync() on before invoking the handler. The native
238
- // OpenCode plugin path bypasses MCP's transport layer entirely
239
- // (refs/platforms/opencode/packages/opencode/src/tool/registry.ts:127),
240
- // so we must parse args here too — otherwise z.preprocess() coercions
241
- // (coerceCommandsArray / coerceJsonArray in server.ts) and defaults
242
- // never fire. Fixes #621.
243
- const inputSchema = config.inputSchema;
244
- const shape = typeof inputSchema?.shape === "object" && inputSchema.shape !== null
245
- ? inputSchema.shape
246
- : typeof inputSchema?._def?.shape === "function"
247
- ? inputSchema._def.shape()
248
- : {};
249
- // Both KiloCode and recent OpenCode bundle Zod v4 in-host; v3 schemas
250
- // crash with `n._zod.def` undefined. Gate widened from kilo-only (#632)
251
- // because every consumer of this file is an OpenCode-family host.
252
- const argsForHost = zod3ShapeToV4(shape);
253
- tools[registered.name] = {
254
- description: String(config.description ?? ""),
255
- args: argsForHost,
256
- async execute(args, toolCtx) {
257
- toolCtx.metadata?.({ title: String(config.title ?? registered.name) });
258
- const project = toolCtx.directory || projectDir;
259
- // Run the registered Zod schema BEFORE the handler — same contract
260
- // as the MCP SDK (server/mcp.js safeParseAsync at line 174). This
261
- // applies z.preprocess() coercions, populates .default() values,
262
- // and produces the validation error the handler expects (#621).
263
- let parsedArgs = args ?? {};
264
- if (typeof inputSchema?.parse === "function") {
265
- try {
266
- parsedArgs = inputSchema.parse(args ?? {});
267
- }
268
- catch (err) {
269
- // Surface validation failures with a clear, actionable message
270
- // (mirrors MCP SDK error format) instead of a downstream
271
- // "x.map is not a function" crash.
272
- const message = err instanceof Error ? err.message : String(err);
273
- throw new Error(`Invalid arguments for ${registered.name}: ${message}`);
274
- }
275
- }
276
- const result = await mod.withProjectDirOverride({ projectDir: project, sessionId: toolCtx.sessionID }, async () => registered.handler(parsedArgs));
277
- const r = result;
278
- const text = Array.isArray(r?.content)
279
- ? r.content
280
- .filter((c) => c?.type === "text" && typeof c.text === "string")
281
- .map((c) => c.text)
282
- .join("\n")
283
- : typeof result === "string"
284
- ? result
285
- : JSON.stringify(result ?? "");
286
- if (r?.isError)
287
- throw new Error(text || `${registered.name} returned an error`);
288
- return { title: String(config.title ?? registered.name), output: text };
289
- },
290
- };
291
- }
292
- return tools;
293
- }
294
- const nativeTools = await buildNativeTools();
295
- return {
296
- tool: nativeTools,
297
- // ── PreToolUse: Routing enforcement ─────────────────
298
- "tool.execute.before": async (input, output) => {
299
- const toolName = input.tool ?? "";
300
- const toolInput = output.args ?? {};
301
- let decision;
302
- try {
303
- decision = routing.routePreToolUse(toolName, toolInput, projectDir, platform);
304
- }
305
- catch {
306
- return; // Routing failure → allow passthrough
307
- }
308
- if (!decision)
309
- return; // No routing match → passthrough
310
- if (decision.action === "deny" || decision.action === "ask") {
311
- // Throw to block — OpenCode catches this and denies the tool call
312
- throw new Error(decision.reason ?? "Blocked by context-mode");
313
- }
314
- if (decision.action === "modify" && decision.updatedInput) {
315
- // Mutate output.args — OpenCode reads the mutated output object
316
- Object.assign(output.args, decision.updatedInput);
317
- }
318
- if (decision.action === "context" && decision.additionalContext) {
319
- // Mutate output.args — OpenCode reads the mutated output object
320
- output.args.additionalContext = decision.additionalContext;
321
- }
322
- },
323
- // ── PostToolUse: Session event capture ──────────────
324
- "tool.execute.after": async (input, output) => {
325
- const sessionId = input.sessionID;
326
- if (!sessionId)
327
- return;
328
- try {
329
- db.ensureSession(sessionId, projectDir);
330
- // OC-4 (#487 follow-up): AGENTS.md → rule_content capture for snapshot
331
- // and auto-memory parity. Idempotent per-session via Set guard.
332
- captureAgentsMd(sessionId);
333
- const hookInput = {
334
- tool_name: input.tool ?? "",
335
- tool_input: input.args ?? {},
336
- tool_response: output.output,
337
- tool_output: undefined, // OpenCode doesn't provide isError
338
- };
339
- const events = extractEvents(hookInput);
340
- for (const event of events) {
341
- // Cast: extract.ts SessionEvent lacks data_hash (computed by insertEvent)
342
- db.insertEvent(sessionId, event, "PostToolUse");
343
- }
344
- }
345
- catch {
346
- // Silent — session capture must never break the tool call
347
- }
348
- },
349
- // ── event: per-turn token + cost capture (paid-observability) ───
350
- // The generic bus `event` hook (refs/platforms/opencode/packages/plugin/
351
- // src/index.ts:224) delivers every Event; we filter `message.updated`
352
- // (published on each assistant-message update incl. step-finish —
353
- // session.ts:673) and read tokens/cost/modelID off properties.info
354
- // (assistant filter via role; refs stream.transport.ts:214-216).
355
- //
356
- // CAVEAT (refs processor.ts:717-718): message-level `.tokens` is the LAST
357
- // step's snapshot (overwritten per step-finish), while `.cost` is
358
- // cumulative for the turn. parseOpencodeUsage passes `.cost` through as
359
- // native_cost_usd so the billed $ stays exact despite the token snapshot
360
- // being last-step only. `message.updated` fires multiple times per turn;
361
- // because tokens are a terminal snapshot and cost is cumulative, the last
362
- // event for a message carries the final figures — re-emitting on each
363
- // update is idempotent at the cost column and merely refreshes the
364
- // last-step token telemetry. db.insertEvent both persists locally AND
365
- // forwards to the platform (the TS-plugin equivalent of the .mjs
366
- // attributeAndInsertEvents path).
367
- event: async (input) => {
368
- try {
369
- const ev = input?.event;
370
- if (!ev || ev.type !== "message.updated")
371
- return;
372
- const sessionId = ev.properties?.info?.sessionID;
373
- if (!sessionId || typeof sessionId !== "string")
374
- return;
375
- const counts = parseOpencodeUsage(ev);
376
- if (!counts)
377
- return;
378
- const usageEvent = buildAgentUsageEvent(counts);
379
- if (!usageEvent)
380
- return;
381
- db.ensureSession(sessionId, projectDir);
382
- db.insertEvent(sessionId, usageEvent, "MessageUpdated");
383
- }
384
- catch {
385
- // Silent — usage capture must never break the session.
386
- }
387
- },
388
- // ── chat.message: User-prompt capture (OC-2 / Z2) ───
389
- // SDK signature verified at refs/platforms/opencode/packages/plugin/src/
390
- // index.ts:233. Orchestrator reference at refs/plugin-examples/opencode/
391
- // opencode-orchestrator/src/plugin-handlers/chat-message-handler.ts:41-65.
392
- // CCv2 inline filter: skip synthetic harness messages (system reminders,
393
- // tool results, etc.) so we don't pollute the user-prompt event stream.
394
- "chat.message": async (input, output) => {
395
- const sessionId = input?.sessionID;
396
- if (!sessionId)
397
- return;
398
- try {
399
- const parts = Array.isArray(output?.parts) ? output.parts : [];
400
- const textPart = parts.find((p) => p && p.type === "text" && typeof p.text === "string" && p.text.length > 0);
401
- if (!textPart || !textPart.text)
402
- return;
403
- const message = textPart.text;
404
- if (isSyntheticMessage(message))
405
- return;
406
- db.ensureSession(sessionId, projectDir);
407
- // OC-4 (#487 follow-up): also capture on chat.message so sessions that
408
- // never invoke a tool still seed rule_content events for continuity.
409
- captureAgentsMd(sessionId);
410
- // 1. Always save the raw prompt
411
- db.insertEvent(sessionId, {
412
- type: "user_prompt",
413
- category: "user-prompt",
414
- data: message,
415
- priority: 1,
416
- }, "UserPromptSubmit");
417
- // 2. Extract role/decision/intent/skill events from the prompt body
418
- const userEvents = extractUserEvents(message);
419
- for (const ev of userEvents) {
420
- db.insertEvent(sessionId, ev, "UserPromptSubmit");
421
- }
422
- }
423
- catch {
424
- // Silent — chat.message must never break the turn
425
- }
426
- },
427
- // ── PreCompact: Snapshot generation ─────────────────
428
- "experimental.session.compacting": async (input, output) => {
429
- const sessionId = input.sessionID;
430
- if (!sessionId)
431
- return "";
432
- try {
433
- db.ensureSession(sessionId, projectDir);
434
- const events = db.getEvents(sessionId);
435
- if (events.length === 0)
436
- return "";
437
- const stats = db.getSessionStats(sessionId);
438
- const snapshot = buildResumeSnapshot(events, {
439
- compactCount: (stats?.compact_count ?? 0) + 1,
440
- });
441
- db.upsertResume(sessionId, snapshot, events.length);
442
- db.incrementCompactCount(sessionId);
443
- // Mutate output.context to inject the snapshot
444
- output.context.push(snapshot);
445
- if (process.env.OPENCODE_DEBUG) {
446
- await safeLog(snapshot, {
447
- sessionId,
448
- source: "on compaction - snapshot",
449
- });
450
- }
451
- // OC-3 / Z3: Add budget-capped auto-injection (P1 role / P2 rules /
452
- // P3 skills / P4 intent — ≤500 tokens / ~2000 chars per
453
- // hooks/auto-injection.mjs). Pushed as a separate context entry so
454
- // OpenCode can fold it independently from the verbose snapshot.
455
- try {
456
- const autoBlock = autoInjectionMod.buildAutoInjection(events);
457
- if (autoBlock && autoBlock.length > 0) {
458
- output.context.push(autoBlock);
459
- }
460
- if (process.env.OPENCODE_DEBUG) {
461
- await safeLog(autoBlock, {
462
- sessionId,
463
- source: "on compaction - autoBlock",
464
- });
465
- }
466
- }
467
- catch {
468
- // Auto-injection failure must NOT break the snapshot path.
469
- }
470
- return snapshot;
471
- }
472
- catch {
473
- return "";
474
- }
475
- },
476
- // ── SessionStart equivalent (PR #376) ───────────────
477
- // OpenCode lacks a real SessionStart hook (#14808, #5409). The closest
478
- // surrogate is `experimental.chat.system.transform` — verified shape:
479
- // input: { sessionID?: string; model: Model }
480
- // output: { system: string[] }
481
- // We claim the most-recent unconsumed resume snapshot atomically (race-
482
- // safe across concurrent processes) and prepend it to the system prompt.
483
- "experimental.chat.system.transform": async (input, output) => {
484
- const sessionId = input?.sessionID;
485
- if (!sessionId)
486
- return;
487
- // ── OC-1 / CCv1: ROUTING_BLOCK injection ──────────────
488
- // Inject the <context_window_protection> XML block on the first
489
- // chat.system.transform per session. This is INDEPENDENT of the
490
- // resume snapshot path below — routing block must fire even when
491
- // no prior session row exists. Splice at index 1 (NOT unshift) for
492
- // the same OpenCode llm.ts:117-128 cache-fold reason as resume.
493
- //
494
- // Skip injection when system prompt already contains context-mode
495
- // routing rules (e.g. via AGENTS.md / CLAUDE.md loaded by the host).
496
- // Detect by checking for a quorum of distinctive tool names — any two
497
- // of ctx_execute, ctx_batch_execute, ctx_fetch_and_index confirms the
498
- // instructions are present and avoids ~2K chars of duplication.
499
- if (Array.isArray(output?.system)) {
500
- if (!systemHasRoutingInstructions(output.system)) {
501
- try {
502
- output.system.splice(1, 0, routingBlock);
503
- }
504
- catch {
505
- // Never break the chat turn on routing-block injection failure.
506
- }
507
- if (process.env.OPENCODE_DEBUG) {
508
- await safeLog(output.system[1], { sessionId, source: 'on routing block injection' });
509
- }
510
- }
511
- else if (process.env.OPENCODE_DEBUG) {
512
- await safeLog(`routing block skipped — system prompt already contains context-mode instructions`, { sessionId, source: 'on routing block injection' });
513
- }
514
- }
515
- try {
516
- // Pass current sessionId so SQL excludes self-injection (v1.0.106 — Mickey #376
517
- // follow-up): if Session B compacts mid-flight and produces its own row,
518
- // B's next system.transform must NOT claim that row back into B's prompt.
519
- const row = db.claimLatestUnconsumedResume(sessionId);
520
- if (!row || !row.snapshot)
521
- return; // no row → retry on next turn
522
- if (process.env.OPENCODE_DEBUG) {
523
- await safeLog(row.snapshot, {
524
- sessionId,
525
- source: "on resume - snapshot",
526
- });
527
- }
528
- if (Array.isArray(output?.system)) {
529
- // Insert at index 1 (after the header) — NOT unshift.
530
- // OpenCode's llm.ts:117-128 saves `header = system[0]` BEFORE this
531
- // hook runs and then folds the rest into a 2-part structure
532
- // `[header, body]` only if `system[0] === header` after the hook.
533
- // Prepending via unshift replaces system[0] with the snapshot,
534
- // making the equality check fail → cache-fold is skipped → every
535
- // system block is sent as a separate `role: "system"` message →
536
- // provider prompt cache is invalidated on every resume injection.
537
- // Inserting at index 1 keeps the header invariant and lets the
538
- // snapshot ride along inside the cached body block.
539
- output.system.splice(1, 0, row.snapshot);
540
- // Mark consumed only AFTER successful splice so failed paths can retry
541
- if (process.env.OPENCODE_DEBUG) {
542
- await safeLog(output.system[1], { sessionId, source: "on resume" });
543
- }
544
- }
545
- }
546
- catch {
547
- // Silent — never break the chat turn
548
- }
549
- },
550
- };
551
- }
552
- // ── Exports ──────────────────────────────────────────────
553
- // KiloCode PluginModule: default export with { server } shape
554
- // OpenCode compat: named export for direct import("context-mode/plugin")
555
- export default { id: "context-mode", server: createContextModePlugin };
556
- export { createContextModePlugin as ContextModePlugin };
557
- // Test surface — exported for unit testing the quorum substring fix (#487).
558
- export { systemHasRoutingInstructions, ROUTING_MARKERS };
@@ -1 +0,0 @@
1
- export declare function zod3ShapeToV4(shape: Record<string, unknown>, depth?: number): Record<string, unknown>;