context-mode 1.0.169 → 2.0.0-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/.claude-plugin/marketplace.json +4 -22
  2. package/.claude-plugin/plugin.json +9 -24
  3. package/SHA256SUMS +31 -0
  4. package/claude-code/skills/ctx-doctor/SKILL.md +6 -0
  5. package/claude-code/skills/ctx-stats/SKILL.md +6 -0
  6. package/claude-code/skills/ctx-upgrade/SKILL.md +6 -0
  7. package/cli.mjs +6744 -0
  8. package/copilot/plugin.json +14 -0
  9. package/fixtures/hook-roundtrip.json +22 -0
  10. package/gemini-extension.json +14 -0
  11. package/hook.mjs +202 -0
  12. package/hooks/claude-code.json +50 -0
  13. package/hooks/codex.json +50 -0
  14. package/hooks/copilot-cli.json +33 -0
  15. package/hooks/hooks.json +16 -111
  16. package/hooks/kiro.json +69 -0
  17. package/hooks/qwen.json +50 -0
  18. package/hooks/vscode.json +40 -0
  19. package/hooks/zcode.json +53 -0
  20. package/opencode/plugin.js +22456 -0
  21. package/package.json +29 -114
  22. package/pi/index.js +50841 -0
  23. package/pi/skills/ctx-doctor/SKILL.md +6 -0
  24. package/pi/skills/ctx-stats/SKILL.md +6 -0
  25. package/pi/skills/ctx-upgrade/SKILL.md +6 -0
  26. package/qwen-extension.json +15 -0
  27. package/run.mjs +5633 -0
  28. package/search.mjs +5633 -0
  29. package/server.mjs +48198 -0
  30. package/skills/ctx-doctor/SKILL.md +3 -19
  31. package/skills/ctx-stats/SKILL.md +3 -23
  32. package/skills/ctx-upgrade/SKILL.md +3 -28
  33. package/.codex-plugin/hooks.json +0 -65
  34. package/.codex-plugin/mcp.json +0 -13
  35. package/.codex-plugin/plugin.json +0 -31
  36. package/.openclaw-plugin/index.ts +0 -12
  37. package/.openclaw-plugin/openclaw.plugin.json +0 -38
  38. package/.openclaw-plugin/package.json +0 -28
  39. package/LICENSE +0 -94
  40. package/README.md +0 -1619
  41. package/bin/statusline.mjs +0 -378
  42. package/build/adapters/antigravity/index.d.ts +0 -51
  43. package/build/adapters/antigravity/index.js +0 -169
  44. package/build/adapters/antigravity-cli/index.d.ts +0 -51
  45. package/build/adapters/antigravity-cli/index.js +0 -342
  46. package/build/adapters/base.d.ts +0 -92
  47. package/build/adapters/base.js +0 -135
  48. package/build/adapters/claude-code/config.d.ts +0 -8
  49. package/build/adapters/claude-code/config.js +0 -8
  50. package/build/adapters/claude-code/hooks.d.ts +0 -106
  51. package/build/adapters/claude-code/hooks.js +0 -183
  52. package/build/adapters/claude-code/index.d.ts +0 -80
  53. package/build/adapters/claude-code/index.js +0 -569
  54. package/build/adapters/claude-code-base.d.ts +0 -49
  55. package/build/adapters/claude-code-base.js +0 -113
  56. package/build/adapters/client-map.d.ts +0 -10
  57. package/build/adapters/client-map.js +0 -42
  58. package/build/adapters/codex/config.d.ts +0 -8
  59. package/build/adapters/codex/config.js +0 -8
  60. package/build/adapters/codex/hooks.d.ts +0 -55
  61. package/build/adapters/codex/hooks.js +0 -64
  62. package/build/adapters/codex/index.d.ts +0 -87
  63. package/build/adapters/codex/index.js +0 -992
  64. package/build/adapters/codex/paths.d.ts +0 -1
  65. package/build/adapters/codex/paths.js +0 -12
  66. package/build/adapters/codex/usage.d.ts +0 -107
  67. package/build/adapters/codex/usage.js +0 -227
  68. package/build/adapters/copilot-base.d.ts +0 -94
  69. package/build/adapters/copilot-base.js +0 -297
  70. package/build/adapters/copilot-cli/hooks.d.ts +0 -33
  71. package/build/adapters/copilot-cli/hooks.js +0 -64
  72. package/build/adapters/copilot-cli/index.d.ts +0 -48
  73. package/build/adapters/copilot-cli/index.js +0 -341
  74. package/build/adapters/cursor/config.d.ts +0 -4
  75. package/build/adapters/cursor/config.js +0 -4
  76. package/build/adapters/cursor/hooks.d.ts +0 -55
  77. package/build/adapters/cursor/hooks.js +0 -82
  78. package/build/adapters/cursor/index.d.ts +0 -64
  79. package/build/adapters/cursor/index.js +0 -517
  80. package/build/adapters/detect.d.ts +0 -136
  81. package/build/adapters/detect.js +0 -623
  82. package/build/adapters/gemini-cli/config.d.ts +0 -8
  83. package/build/adapters/gemini-cli/config.js +0 -8
  84. package/build/adapters/gemini-cli/hooks.d.ts +0 -83
  85. package/build/adapters/gemini-cli/hooks.js +0 -115
  86. package/build/adapters/gemini-cli/index.d.ts +0 -80
  87. package/build/adapters/gemini-cli/index.js +0 -483
  88. package/build/adapters/jetbrains-copilot/config.d.ts +0 -8
  89. package/build/adapters/jetbrains-copilot/config.js +0 -8
  90. package/build/adapters/jetbrains-copilot/hooks.d.ts +0 -59
  91. package/build/adapters/jetbrains-copilot/hooks.js +0 -87
  92. package/build/adapters/jetbrains-copilot/index.d.ts +0 -31
  93. package/build/adapters/jetbrains-copilot/index.js +0 -131
  94. package/build/adapters/kimi/config.d.ts +0 -8
  95. package/build/adapters/kimi/config.js +0 -8
  96. package/build/adapters/kimi/hooks.d.ts +0 -28
  97. package/build/adapters/kimi/hooks.js +0 -34
  98. package/build/adapters/kimi/index.d.ts +0 -66
  99. package/build/adapters/kimi/index.js +0 -537
  100. package/build/adapters/kimi/paths.d.ts +0 -21
  101. package/build/adapters/kimi/paths.js +0 -52
  102. package/build/adapters/kimi/usage.d.ts +0 -82
  103. package/build/adapters/kimi/usage.js +0 -217
  104. package/build/adapters/kiro/hooks.d.ts +0 -61
  105. package/build/adapters/kiro/hooks.js +0 -94
  106. package/build/adapters/kiro/index.d.ts +0 -61
  107. package/build/adapters/kiro/index.js +0 -301
  108. package/build/adapters/omp/index.d.ts +0 -65
  109. package/build/adapters/omp/index.js +0 -182
  110. package/build/adapters/omp/plugin.d.ts +0 -81
  111. package/build/adapters/omp/plugin.js +0 -331
  112. package/build/adapters/omp/usage.d.ts +0 -49
  113. package/build/adapters/omp/usage.js +0 -110
  114. package/build/adapters/openclaw/config.d.ts +0 -8
  115. package/build/adapters/openclaw/config.js +0 -8
  116. package/build/adapters/openclaw/hooks.d.ts +0 -50
  117. package/build/adapters/openclaw/hooks.js +0 -61
  118. package/build/adapters/openclaw/index.d.ts +0 -74
  119. package/build/adapters/openclaw/index.js +0 -439
  120. package/build/adapters/openclaw/mcp-tools.d.ts +0 -54
  121. package/build/adapters/openclaw/mcp-tools.js +0 -207
  122. package/build/adapters/openclaw/plugin.d.ts +0 -141
  123. package/build/adapters/openclaw/plugin.js +0 -818
  124. package/build/adapters/openclaw/session-db.d.ts +0 -55
  125. package/build/adapters/openclaw/session-db.js +0 -88
  126. package/build/adapters/openclaw/usage.d.ts +0 -34
  127. package/build/adapters/openclaw/usage.js +0 -52
  128. package/build/adapters/openclaw/workspace-router.d.ts +0 -29
  129. package/build/adapters/openclaw/workspace-router.js +0 -64
  130. package/build/adapters/opencode/config.d.ts +0 -8
  131. package/build/adapters/opencode/config.js +0 -8
  132. package/build/adapters/opencode/hooks.d.ts +0 -38
  133. package/build/adapters/opencode/hooks.js +0 -50
  134. package/build/adapters/opencode/index.d.ts +0 -67
  135. package/build/adapters/opencode/index.js +0 -463
  136. package/build/adapters/opencode/plugin.d.ts +0 -184
  137. package/build/adapters/opencode/plugin.js +0 -558
  138. package/build/adapters/opencode/zod3tov4.d.ts +0 -1
  139. package/build/adapters/opencode/zod3tov4.js +0 -132
  140. package/build/adapters/pi/extension.d.ts +0 -81
  141. package/build/adapters/pi/extension.js +0 -861
  142. package/build/adapters/pi/index.d.ts +0 -57
  143. package/build/adapters/pi/index.js +0 -173
  144. package/build/adapters/pi/mcp-bridge.d.ts +0 -268
  145. package/build/adapters/pi/mcp-bridge.js +0 -894
  146. package/build/adapters/qwen-code/hooks.d.ts +0 -26
  147. package/build/adapters/qwen-code/hooks.js +0 -29
  148. package/build/adapters/qwen-code/index.d.ts +0 -40
  149. package/build/adapters/qwen-code/index.js +0 -361
  150. package/build/adapters/qwen-code/usage.d.ts +0 -90
  151. package/build/adapters/qwen-code/usage.js +0 -222
  152. package/build/adapters/types.d.ts +0 -360
  153. package/build/adapters/types.js +0 -118
  154. package/build/adapters/vscode-copilot/config.d.ts +0 -8
  155. package/build/adapters/vscode-copilot/config.js +0 -8
  156. package/build/adapters/vscode-copilot/hooks.d.ts +0 -71
  157. package/build/adapters/vscode-copilot/hooks.js +0 -98
  158. package/build/adapters/vscode-copilot/index.d.ts +0 -32
  159. package/build/adapters/vscode-copilot/index.js +0 -222
  160. package/build/adapters/zed/index.d.ts +0 -40
  161. package/build/adapters/zed/index.js +0 -163
  162. package/build/cli.d.ts +0 -34
  163. package/build/cli.js +0 -1827
  164. package/build/db-base.d.ts +0 -179
  165. package/build/db-base.js +0 -569
  166. package/build/executor.d.ts +0 -72
  167. package/build/executor.js +0 -678
  168. package/build/exit-classify.d.ts +0 -19
  169. package/build/exit-classify.js +0 -12
  170. package/build/fetch-cache.d.ts +0 -13
  171. package/build/fetch-cache.js +0 -15
  172. package/build/lifecycle.d.ts +0 -124
  173. package/build/lifecycle.js +0 -278
  174. package/build/runPool.d.ts +0 -36
  175. package/build/runPool.js +0 -51
  176. package/build/runtime.d.ts +0 -71
  177. package/build/runtime.js +0 -659
  178. package/build/search/auto-memory.d.ts +0 -47
  179. package/build/search/auto-memory.js +0 -170
  180. package/build/search/ctx-search-schema.d.ts +0 -90
  181. package/build/search/ctx-search-schema.js +0 -135
  182. package/build/search/flood-guard.d.ts +0 -57
  183. package/build/search/flood-guard.js +0 -80
  184. package/build/search/unified.d.ts +0 -56
  185. package/build/search/unified.js +0 -104
  186. package/build/security.d.ts +0 -206
  187. package/build/security.js +0 -780
  188. package/build/server.d.ts +0 -184
  189. package/build/server.js +0 -4563
  190. package/build/session/analytics.d.ts +0 -773
  191. package/build/session/analytics.js +0 -2420
  192. package/build/session/db.d.ts +0 -468
  193. package/build/session/db.js +0 -1308
  194. package/build/session/error-classifier.d.ts +0 -87
  195. package/build/session/error-classifier.js +0 -303
  196. package/build/session/event-emit.d.ts +0 -48
  197. package/build/session/event-emit.js +0 -101
  198. package/build/session/extract.d.ts +0 -333
  199. package/build/session/extract.js +0 -2688
  200. package/build/session/model-prices.json +0 -429
  201. package/build/session/persist-tool-calls.d.ts +0 -54
  202. package/build/session/persist-tool-calls.js +0 -105
  203. package/build/session/pricing.d.ts +0 -64
  204. package/build/session/pricing.js +0 -151
  205. package/build/session/project-attribution.d.ts +0 -73
  206. package/build/session/project-attribution.js +0 -245
  207. package/build/session/purge.d.ts +0 -138
  208. package/build/session/purge.js +0 -240
  209. package/build/session/retrieval-marker.d.ts +0 -39
  210. package/build/session/retrieval-marker.js +0 -65
  211. package/build/session/snapshot.d.ts +0 -46
  212. package/build/session/snapshot.js +0 -532
  213. package/build/store-directory.d.ts +0 -56
  214. package/build/store-directory.js +0 -254
  215. package/build/store.d.ts +0 -147
  216. package/build/store.js +0 -1714
  217. package/build/truncate.d.ts +0 -57
  218. package/build/truncate.js +0 -142
  219. package/build/types.d.ts +0 -117
  220. package/build/types.js +0 -20
  221. package/build/util/claude-config.d.ts +0 -32
  222. package/build/util/claude-config.js +0 -84
  223. package/build/util/hook-config.d.ts +0 -27
  224. package/build/util/hook-config.js +0 -76
  225. package/build/util/jsonc.d.ts +0 -14
  226. package/build/util/jsonc.js +0 -104
  227. package/build/util/plugin-cache-integrity.d.ts +0 -51
  228. package/build/util/plugin-cache-integrity.js +0 -146
  229. package/build/util/project-dir.d.ts +0 -149
  230. package/build/util/project-dir.js +0 -340
  231. package/build/util/sibling-mcp.d.ts +0 -79
  232. package/build/util/sibling-mcp.js +0 -181
  233. package/cli.bundle.mjs +0 -1236
  234. package/configs/antigravity/GEMINI.md +0 -68
  235. package/configs/antigravity/mcp_config.json +0 -7
  236. package/configs/antigravity-cli/hooks/hooks.json +0 -37
  237. package/configs/antigravity-cli/hooks.json +0 -37
  238. package/configs/antigravity-cli/mcp_config.json +0 -10
  239. package/configs/antigravity-cli/plugin.json +0 -14
  240. package/configs/antigravity-cli/rules/context-mode.md +0 -77
  241. package/configs/antigravity-cli/skills/context-mode/SKILL.md +0 -77
  242. package/configs/claude-code/CLAUDE.md +0 -91
  243. package/configs/codex/AGENTS.md +0 -99
  244. package/configs/codex/config.toml +0 -8
  245. package/configs/codex/hooks.json +0 -47
  246. package/configs/copilot-cli/.github/plugin/plugin.json +0 -23
  247. package/configs/copilot-cli/.mcp.json +0 -12
  248. package/configs/copilot-cli/README.md +0 -47
  249. package/configs/copilot-cli/hooks.json +0 -41
  250. package/configs/copilot-cli/skills/context-mode/SKILL.md +0 -38
  251. package/configs/cursor/context-mode.mdc +0 -76
  252. package/configs/cursor/hooks.json +0 -21
  253. package/configs/cursor/mcp.json +0 -7
  254. package/configs/gemini-cli/GEMINI.md +0 -88
  255. package/configs/gemini-cli/mcp.json +0 -7
  256. package/configs/gemini-cli/settings.json +0 -60
  257. package/configs/jetbrains-copilot/copilot-instructions.md +0 -80
  258. package/configs/jetbrains-copilot/hooks.json +0 -16
  259. package/configs/jetbrains-copilot/mcp.json +0 -7
  260. package/configs/kilo/AGENTS.md +0 -84
  261. package/configs/kilo/kilo.json +0 -6
  262. package/configs/kimi/hooks.json +0 -54
  263. package/configs/kiro/KIRO.md +0 -84
  264. package/configs/kiro/agent.json +0 -18
  265. package/configs/kiro/mcp.json +0 -7
  266. package/configs/omp/SYSTEM.md +0 -85
  267. package/configs/omp/mcp.json +0 -7
  268. package/configs/openclaw/AGENTS.md +0 -87
  269. package/configs/openclaw/openclaw.json +0 -13
  270. package/configs/opencode/AGENTS.md +0 -84
  271. package/configs/opencode/opencode.json +0 -6
  272. package/configs/pi/AGENTS.md +0 -3
  273. package/configs/qwen-code/QWEN.md +0 -91
  274. package/configs/vscode-copilot/copilot-instructions.md +0 -80
  275. package/configs/vscode-copilot/hooks.json +0 -16
  276. package/configs/vscode-copilot/mcp.json +0 -7
  277. package/configs/zed/AGENTS.md +0 -68
  278. package/hooks/antigravity-cli/payload.mjs +0 -98
  279. package/hooks/antigravity-cli/posttooluse.mjs +0 -138
  280. package/hooks/antigravity-cli/pretooluse.mjs +0 -78
  281. package/hooks/antigravity-cli/stop.mjs +0 -58
  282. package/hooks/auto-injection.mjs +0 -102
  283. package/hooks/cache-heal-utils.mjs +0 -379
  284. package/hooks/codex/platform.mjs +0 -1
  285. package/hooks/codex/posttooluse.mjs +0 -66
  286. package/hooks/codex/precompact.mjs +0 -70
  287. package/hooks/codex/pretooluse.mjs +0 -42
  288. package/hooks/codex/sessionstart.mjs +0 -121
  289. package/hooks/codex/stop.mjs +0 -138
  290. package/hooks/codex/userpromptsubmit.mjs +0 -75
  291. package/hooks/copilot-cli/posttooluse.mjs +0 -79
  292. package/hooks/copilot-cli/precompact.mjs +0 -66
  293. package/hooks/copilot-cli/pretooluse.mjs +0 -41
  294. package/hooks/copilot-cli/sessionstart.mjs +0 -121
  295. package/hooks/copilot-cli/stop.mjs +0 -59
  296. package/hooks/copilot-cli/userpromptsubmit.mjs +0 -77
  297. package/hooks/core/codex-caps.mjs +0 -112
  298. package/hooks/core/formatters.mjs +0 -356
  299. package/hooks/core/mcp-ready.mjs +0 -109
  300. package/hooks/core/platform-detect.mjs +0 -49
  301. package/hooks/core/routing.mjs +0 -1017
  302. package/hooks/core/stdin.mjs +0 -90
  303. package/hooks/core/tool-naming.mjs +0 -57
  304. package/hooks/cursor/afteragentresponse.mjs +0 -74
  305. package/hooks/cursor/hooks.json +0 -31
  306. package/hooks/cursor/posttooluse.mjs +0 -72
  307. package/hooks/cursor/pretooluse.mjs +0 -26
  308. package/hooks/cursor/sessionstart.mjs +0 -97
  309. package/hooks/cursor/stop.mjs +0 -48
  310. package/hooks/ensure-deps.mjs +0 -254
  311. package/hooks/formatters/claude-code.mjs +0 -113
  312. package/hooks/formatters/cursor.mjs +0 -37
  313. package/hooks/formatters/gemini-cli.mjs +0 -55
  314. package/hooks/formatters/vscode-copilot.mjs +0 -55
  315. package/hooks/gemini-cli/aftermodel.mjs +0 -70
  316. package/hooks/gemini-cli/aftertool.mjs +0 -61
  317. package/hooks/gemini-cli/beforeagent.mjs +0 -99
  318. package/hooks/gemini-cli/beforetool.mjs +0 -27
  319. package/hooks/gemini-cli/precompress.mjs +0 -55
  320. package/hooks/gemini-cli/sessionstart.mjs +0 -137
  321. package/hooks/heal-partial-install.mjs +0 -712
  322. package/hooks/jetbrains-copilot/posttooluse.mjs +0 -61
  323. package/hooks/jetbrains-copilot/precompact.mjs +0 -55
  324. package/hooks/jetbrains-copilot/pretooluse.mjs +0 -27
  325. package/hooks/jetbrains-copilot/sessionstart.mjs +0 -124
  326. package/hooks/kimi/platform.mjs +0 -1
  327. package/hooks/kimi/posttooluse.mjs +0 -72
  328. package/hooks/kimi/precompact.mjs +0 -80
  329. package/hooks/kimi/pretooluse.mjs +0 -42
  330. package/hooks/kimi/sessionend.mjs +0 -61
  331. package/hooks/kimi/sessionstart.mjs +0 -113
  332. package/hooks/kimi/stop.mjs +0 -132
  333. package/hooks/kimi/userpromptsubmit.mjs +0 -90
  334. package/hooks/kiro/agentspawn.mjs +0 -97
  335. package/hooks/kiro/posttooluse.mjs +0 -51
  336. package/hooks/kiro/pretooluse.mjs +0 -64
  337. package/hooks/kiro/userpromptsubmit.mjs +0 -88
  338. package/hooks/normalize-hooks.mjs +0 -323
  339. package/hooks/platform-bridge.mjs +0 -340
  340. package/hooks/posttooluse.mjs +0 -225
  341. package/hooks/precompact.mjs +0 -100
  342. package/hooks/pretooluse.mjs +0 -227
  343. package/hooks/qwen-code/platform.mjs +0 -1
  344. package/hooks/qwen-code/stop.mjs +0 -168
  345. package/hooks/routing-block.mjs +0 -105
  346. package/hooks/run-hook.mjs +0 -95
  347. package/hooks/security.bundle.mjs +0 -2
  348. package/hooks/session-attribution.bundle.mjs +0 -1
  349. package/hooks/session-db.bundle.mjs +0 -144
  350. package/hooks/session-directive.mjs +0 -520
  351. package/hooks/session-extract.bundle.mjs +0 -3
  352. package/hooks/session-helpers.mjs +0 -428
  353. package/hooks/session-loaders.mjs +0 -448
  354. package/hooks/session-snapshot.bundle.mjs +0 -32
  355. package/hooks/sessionstart.mjs +0 -464
  356. package/hooks/stop.mjs +0 -82
  357. package/hooks/suppress-stderr.mjs +0 -25
  358. package/hooks/userpromptsubmit.mjs +0 -108
  359. package/hooks/vscode-copilot/posttooluse.mjs +0 -61
  360. package/hooks/vscode-copilot/precompact.mjs +0 -55
  361. package/hooks/vscode-copilot/pretooluse.mjs +0 -27
  362. package/hooks/vscode-copilot/sessionstart.mjs +0 -129
  363. package/openclaw.plugin.json +0 -38
  364. package/scripts/heal-better-sqlite3.mjs +0 -430
  365. package/scripts/heal-installed-plugins.mjs +0 -598
  366. package/scripts/plugin-cache-integrity.mjs +0 -248
  367. package/scripts/postinstall.mjs +0 -384
  368. package/server.bundle.mjs +0 -1162
  369. package/skills/.ignore +0 -7
  370. package/skills/context-mode/SKILL.md +0 -300
  371. package/skills/context-mode/references/anti-patterns.md +0 -283
  372. package/skills/context-mode/references/patterns-javascript.md +0 -298
  373. package/skills/context-mode/references/patterns-python.md +0 -304
  374. package/skills/context-mode/references/patterns-shell.md +0 -277
  375. package/skills/ctx-index/SKILL.md +0 -46
  376. package/skills/ctx-insight/SKILL.md +0 -24
  377. package/skills/ctx-purge/SKILL.md +0 -49
  378. package/skills/ctx-search/SKILL.md +0 -35
  379. package/start.mjs +0 -616
@@ -1,19 +0,0 @@
1
- /**
2
- * Classify non-zero exit codes for ctx_execute / ctx_execute_file.
3
- *
4
- * Shell commands like `grep` exit 1 for "no matches" — not a real error.
5
- * We treat exit code 1 as a soft failure when:
6
- * - language is "shell"
7
- * - exit code is exactly 1
8
- * - stdout has non-whitespace content
9
- */
10
- export interface ExitClassification {
11
- isError: boolean;
12
- output: string;
13
- }
14
- export declare function classifyNonZeroExit(params: {
15
- language: string;
16
- exitCode: number;
17
- stdout: string;
18
- stderr: string;
19
- }): ExitClassification;
@@ -1,12 +0,0 @@
1
- export function classifyNonZeroExit(params) {
2
- const { language, exitCode, stdout, stderr } = params;
3
- const isSoftFail = language === "shell" &&
4
- exitCode === 1 &&
5
- stdout.trim().length > 0;
6
- return {
7
- isError: !isSoftFail,
8
- output: isSoftFail
9
- ? stdout
10
- : `Exit code: ${exitCode}\n\nstdout:\n${stdout}\n\nstderr:\n${stderr}`,
11
- };
12
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Cache-key / storage-label composition for ctx_fetch_and_index.
3
- *
4
- * Two distinct URLs that share a user-supplied `source` label MUST NOT collide
5
- * in the cache (or in FTS5 storage, since indexing dedups by label). Compose
6
- * `${source}::${url}` whenever a `source` is explicitly provided so cache
7
- * lookup, dedup, and re-indexing are all per-(source,url). When no `source`
8
- * is provided the URL itself is the unique key — no composition needed.
9
- *
10
- * `ctx_search(source: "Docs")` continues to work because LIKE-mode source
11
- * filtering matches on the substring "Docs" inside "Docs::https://…".
12
- */
13
- export declare function composeFetchCacheKey(source: string | undefined, url: string): string;
@@ -1,15 +0,0 @@
1
- /**
2
- * Cache-key / storage-label composition for ctx_fetch_and_index.
3
- *
4
- * Two distinct URLs that share a user-supplied `source` label MUST NOT collide
5
- * in the cache (or in FTS5 storage, since indexing dedups by label). Compose
6
- * `${source}::${url}` whenever a `source` is explicitly provided so cache
7
- * lookup, dedup, and re-indexing are all per-(source,url). When no `source`
8
- * is provided the URL itself is the unique key — no composition needed.
9
- *
10
- * `ctx_search(source: "Docs")` continues to work because LIKE-mode source
11
- * filtering matches on the substring "Docs" inside "Docs::https://…".
12
- */
13
- export function composeFetchCacheKey(source, url) {
14
- return source === undefined ? url : `${source}::${url}`;
15
- }
@@ -1,124 +0,0 @@
1
- /**
2
- * lifecycle — Process lifecycle guard for MCP server.
3
- *
4
- * Detects parent process death (ppid polling) and OS signals to prevent
5
- * orphaned MCP server processes consuming 100% CPU (issue #103).
6
- *
7
- * Stdin close is NOT used as a *standalone* shutdown signal — the MCP stdio
8
- * transport owns stdin and transient pipe events cause spurious -32000
9
- * errors (#236). We do, however, treat stdin EOF as a hint to re-run the
10
- * parent-liveness probe immediately (instead of waiting up to 30 s for the
11
- * next poll tick), which closes the multi-day CPU-spin window seen in
12
- * #311/#388 without reintroducing the false-positive shutdowns of #236.
13
- *
14
- * Additionally, for MCP BRIDGE CHILDREN only (CONTEXT_MODE_BRIDGE_DEPTH>0), a
15
- * request-idle self-shutdown reaps a child that a pi/omp sub-context abandoned
16
- * while its long-lived parent keeps running (#854) — gated so the depth-0
17
- * keep-alive servers #602 restored are never reaped, never via stdin EOF, and
18
- * never while a tool call is in flight (#643).
19
- *
20
- * Cross-platform: macOS, Linux, Windows.
21
- */
22
- export interface LifecycleGuardOptions {
23
- /** Interval in ms to check parent liveness. Default: 30_000 */
24
- checkIntervalMs?: number;
25
- /** Called when parent death or OS signal is detected. */
26
- onShutdown: () => void;
27
- /** Injectable parent-alive check (for testing). Default: ppid-based check. */
28
- isParentAlive?: () => boolean;
29
- /**
30
- * #854: request-idle shutdown timeout (ms) for MCP bridge children. Default:
31
- * {@link bridgeChildIdleTimeoutMs}() — 0 (disabled) unless CONTEXT_MODE_BRIDGE_DEPTH>0.
32
- * Exposed for testing.
33
- */
34
- bridgeIdleMs?: number;
35
- }
36
- /** Injectable dependencies for {@link makeDefaultIsParentAlive}. */
37
- export interface IsParentAliveDeps {
38
- /** Read the current ppid. Default: `() => process.ppid`. */
39
- getPpid?: () => number;
40
- /** Read the grandparent ppid. Default: ps-based POSIX probe, NaN on Windows. */
41
- readGrandparentPpid?: () => number;
42
- }
43
- /**
44
- * Build a parent-liveness check that handles the npm-exec wrapper case (#311).
45
- *
46
- * A plain ppid comparison misses Claude Code sessions launched via
47
- * `start.mjs → npm exec → context-mode server`: when Claude Code dies,
48
- * `start.mjs` reparents to init but `npm exec` stays alive, so the server's
49
- * direct ppid never changes. We additionally check whether the grandparent
50
- * process has been reparented to init (PID 1). When the original grandparent
51
- * was already 1 (daemonized startup) the check is skipped, and on Windows
52
- * where there's no cheap `ps` equivalent we also skip — so this change is
53
- * strictly additive to the previous behavior.
54
- *
55
- * Exported for unit-testing with injected readers. Production code uses
56
- * {@link defaultIsParentAlive} (captured once at module load).
57
- */
58
- export declare function makeDefaultIsParentAlive(deps?: IsParentAliveDeps): () => boolean;
59
- /**
60
- * Resolve the parent-liveness poll interval based on context (#534).
61
- *
62
- * When this process is the MCP bridge child spawned by the Pi adapter
63
- * (`bootstrapMCPTools` in `src/adapters/pi/mcp-bridge.ts` sets
64
- * `CONTEXT_MODE_BRIDGE_DEPTH=1` in the child env), we tighten the poll to
65
- * 1 s. The Pi parent can disappear in under 50 ms (`pi --help` prints
66
- * usage and returns), so the default 30 s window leaves a long-lived
67
- * CPU-spinning orphan. For top-level MCP servers (depth 0 / absent) we
68
- * keep the original 30 s cadence — the existing #311/#388 ppid + stdin
69
- * recovery paths already cover Claude Code style hosts.
70
- *
71
- * Exported for unit-testing.
72
- */
73
- export declare function lifecycleGuardIntervalForEnv(env?: NodeJS.ProcessEnv): number;
74
- /**
75
- * #854: idle-shutdown timeout (ms) for an MCP BRIDGE CHILD. Returns 0 (disabled)
76
- * unless this process is a bridge child (CONTEXT_MODE_BRIDGE_DEPTH>0). depth-0 /
77
- * absent always returns 0, so the long-lived keep-alive servers that #602
78
- * restored are NEVER reaped on idle. Default for bridge children is 3 min;
79
- * override with CONTEXT_MODE_BRIDGE_IDLE_MS (a non-positive value disables it).
80
- * The reaper additionally never fires while a tool call is in flight (see
81
- * {@link noteRequestStart}), so the window only bounds how fast *abandoned*
82
- * children drain — it does not cap legitimate long-running calls.
83
- *
84
- * Exported for unit-testing.
85
- */
86
- export declare function bridgeChildIdleTimeoutMs(env?: NodeJS.ProcessEnv): number;
87
- /**
88
- * #854 / #868: human-readable notice emitted when an idle bridge child is
89
- * released. DX-tuned — human units (seconds, not raw ms), reassures that the
90
- * helper reconnects automatically (it respawns on the next ctx_* call, #583),
91
- * and drops the alarming "self-shutdown" jargon. Pure + exported so the wording
92
- * is pinned by a test and stays grep-friendly via the #854 tag. Note: after the
93
- * #868 fix this fires ONLY for sub-context / non-interactive children — the
94
- * foreground interactive session's child runs with the reaper disabled.
95
- */
96
- export declare function idleReapMessage(idleMs: number): string;
97
- /**
98
- * #854: record MCP activity (inbound message or response). The server calls this
99
- * so the bridge-child idle reaper in {@link startLifecycleGuard} can distinguish
100
- * an actively-used child from an abandoned one. Cheap; safe on the hot path.
101
- */
102
- export declare function noteMcpActivity(): void;
103
- /**
104
- * #854: mark a tool call as started. Suppresses the bridge-child idle reaper so a
105
- * single long-running ctx_execute / ctx_batch_execute (which sends one inbound
106
- * frame then runs unbounded, #643) is never reaped mid-execution.
107
- */
108
- export declare function noteRequestStart(): void;
109
- /** #854: mark a tool call as finished (success or error). */
110
- export declare function noteRequestEnd(): void;
111
- /**
112
- * #854: wrap an MCP stdio transport's `onmessage` so each inbound message
113
- * refreshes the idle clock. Best-effort: call after `connect()` (onmessage set);
114
- * a no-op if it isn't a function, and a throw in noteMcpActivity never breaks
115
- * dispatch. No stdin touch (preserves the #236 contract). Exported for testing.
116
- */
117
- export declare function attachMcpActivityTap(transport: {
118
- onmessage?: (message: unknown, extra?: unknown) => unknown;
119
- } | null | undefined): void;
120
- /**
121
- * Start the lifecycle guard. Returns a cleanup function.
122
- * Skipped automatically when stdin is a TTY (e.g. OpenCode ts-plugin).
123
- */
124
- export declare function startLifecycleGuard(opts: LifecycleGuardOptions): () => void;
@@ -1,278 +0,0 @@
1
- /**
2
- * lifecycle — Process lifecycle guard for MCP server.
3
- *
4
- * Detects parent process death (ppid polling) and OS signals to prevent
5
- * orphaned MCP server processes consuming 100% CPU (issue #103).
6
- *
7
- * Stdin close is NOT used as a *standalone* shutdown signal — the MCP stdio
8
- * transport owns stdin and transient pipe events cause spurious -32000
9
- * errors (#236). We do, however, treat stdin EOF as a hint to re-run the
10
- * parent-liveness probe immediately (instead of waiting up to 30 s for the
11
- * next poll tick), which closes the multi-day CPU-spin window seen in
12
- * #311/#388 without reintroducing the false-positive shutdowns of #236.
13
- *
14
- * Additionally, for MCP BRIDGE CHILDREN only (CONTEXT_MODE_BRIDGE_DEPTH>0), a
15
- * request-idle self-shutdown reaps a child that a pi/omp sub-context abandoned
16
- * while its long-lived parent keeps running (#854) — gated so the depth-0
17
- * keep-alive servers #602 restored are never reaped, never via stdin EOF, and
18
- * never while a tool call is in flight (#643).
19
- *
20
- * Cross-platform: macOS, Linux, Windows.
21
- */
22
- import { execFileSync } from "node:child_process";
23
- /** Read grandparent PID via `ps -o ppid= -p $PPID`. Returns NaN on failure or Windows. */
24
- function readGrandparentPpidImpl() {
25
- if (process.platform === "win32")
26
- return NaN;
27
- const ppid = process.ppid;
28
- if (!ppid || ppid <= 1)
29
- return NaN;
30
- try {
31
- const out = execFileSync("ps", ["-o", "ppid=", "-p", String(ppid)], {
32
- encoding: "utf-8",
33
- timeout: 2000,
34
- stdio: ["ignore", "pipe", "ignore"],
35
- }).trim();
36
- const n = parseInt(out, 10);
37
- return Number.isFinite(n) ? n : NaN;
38
- }
39
- catch {
40
- return NaN;
41
- }
42
- }
43
- /**
44
- * Build a parent-liveness check that handles the npm-exec wrapper case (#311).
45
- *
46
- * A plain ppid comparison misses Claude Code sessions launched via
47
- * `start.mjs → npm exec → context-mode server`: when Claude Code dies,
48
- * `start.mjs` reparents to init but `npm exec` stays alive, so the server's
49
- * direct ppid never changes. We additionally check whether the grandparent
50
- * process has been reparented to init (PID 1). When the original grandparent
51
- * was already 1 (daemonized startup) the check is skipped, and on Windows
52
- * where there's no cheap `ps` equivalent we also skip — so this change is
53
- * strictly additive to the previous behavior.
54
- *
55
- * Exported for unit-testing with injected readers. Production code uses
56
- * {@link defaultIsParentAlive} (captured once at module load).
57
- */
58
- export function makeDefaultIsParentAlive(deps = {}) {
59
- const getPpid = deps.getPpid ?? (() => process.ppid);
60
- const readGp = deps.readGrandparentPpid ?? readGrandparentPpidImpl;
61
- const originalPpid = getPpid();
62
- const originalGrandparentPpid = readGp();
63
- return () => {
64
- const ppid = getPpid();
65
- if (ppid !== originalPpid)
66
- return false;
67
- if (ppid === 0 || ppid === 1)
68
- return false;
69
- // Grandparent orphan check (#311): npm-exec wrappers stay alive past the
70
- // session owner. If our grandparent is now PID 1 but wasn't at startup,
71
- // the wrapping chain is orphaned and we should shut down.
72
- if (!Number.isNaN(originalGrandparentPpid) && originalGrandparentPpid > 1) {
73
- if (readGp() === 1)
74
- return false;
75
- }
76
- return true;
77
- };
78
- }
79
- const defaultIsParentAlive = makeDefaultIsParentAlive();
80
- /**
81
- * Resolve the parent-liveness poll interval based on context (#534).
82
- *
83
- * When this process is the MCP bridge child spawned by the Pi adapter
84
- * (`bootstrapMCPTools` in `src/adapters/pi/mcp-bridge.ts` sets
85
- * `CONTEXT_MODE_BRIDGE_DEPTH=1` in the child env), we tighten the poll to
86
- * 1 s. The Pi parent can disappear in under 50 ms (`pi --help` prints
87
- * usage and returns), so the default 30 s window leaves a long-lived
88
- * CPU-spinning orphan. For top-level MCP servers (depth 0 / absent) we
89
- * keep the original 30 s cadence — the existing #311/#388 ppid + stdin
90
- * recovery paths already cover Claude Code style hosts.
91
- *
92
- * Exported for unit-testing.
93
- */
94
- export function lifecycleGuardIntervalForEnv(env = process.env) {
95
- const raw = env.CONTEXT_MODE_BRIDGE_DEPTH;
96
- if (raw === undefined)
97
- return 30_000;
98
- const depth = Number.parseInt(raw, 10);
99
- if (!Number.isFinite(depth) || depth <= 0)
100
- return 30_000;
101
- return 1000;
102
- }
103
- /**
104
- * #854: idle-shutdown timeout (ms) for an MCP BRIDGE CHILD. Returns 0 (disabled)
105
- * unless this process is a bridge child (CONTEXT_MODE_BRIDGE_DEPTH>0). depth-0 /
106
- * absent always returns 0, so the long-lived keep-alive servers that #602
107
- * restored are NEVER reaped on idle. Default for bridge children is 3 min;
108
- * override with CONTEXT_MODE_BRIDGE_IDLE_MS (a non-positive value disables it).
109
- * The reaper additionally never fires while a tool call is in flight (see
110
- * {@link noteRequestStart}), so the window only bounds how fast *abandoned*
111
- * children drain — it does not cap legitimate long-running calls.
112
- *
113
- * Exported for unit-testing.
114
- */
115
- export function bridgeChildIdleTimeoutMs(env = process.env) {
116
- const depth = Number.parseInt(env.CONTEXT_MODE_BRIDGE_DEPTH ?? "", 10);
117
- if (!Number.isFinite(depth) || depth <= 0)
118
- return 0;
119
- const raw = env.CONTEXT_MODE_BRIDGE_IDLE_MS;
120
- if (raw !== undefined) {
121
- const v = Number.parseInt(raw, 10);
122
- return Number.isFinite(v) && v > 0 ? v : 0;
123
- }
124
- return 180_000;
125
- }
126
- /**
127
- * #854 / #868: human-readable notice emitted when an idle bridge child is
128
- * released. DX-tuned — human units (seconds, not raw ms), reassures that the
129
- * helper reconnects automatically (it respawns on the next ctx_* call, #583),
130
- * and drops the alarming "self-shutdown" jargon. Pure + exported so the wording
131
- * is pinned by a test and stays grep-friendly via the #854 tag. Note: after the
132
- * #868 fix this fires ONLY for sub-context / non-interactive children — the
133
- * foreground interactive session's child runs with the reaper disabled.
134
- */
135
- export function idleReapMessage(idleMs) {
136
- const seconds = Math.round(idleMs / 1000);
137
- return `[context-mode] Released an idle MCP helper after ${seconds}s of inactivity to free memory; it reconnects automatically on next use. (#854)`;
138
- }
139
- // #854 idle-reaper state, module-level by design: an MCP server is exactly one
140
- // process (one StdioServerTransport + one lifecycle guard), so these are never
141
- // shared across concurrent servers in production. Multiple startLifecycleGuard()
142
- // instances arise only in tests, which pair/reset these explicitly.
143
- /** Last MCP activity timestamp (inbound message, tool-call start/end, or response). */
144
- let _lastMcpActivity = Date.now();
145
- /** In-flight tool-call count — the reaper never fires while this is > 0. */
146
- let _inFlight = 0;
147
- /**
148
- * #854: record MCP activity (inbound message or response). The server calls this
149
- * so the bridge-child idle reaper in {@link startLifecycleGuard} can distinguish
150
- * an actively-used child from an abandoned one. Cheap; safe on the hot path.
151
- */
152
- export function noteMcpActivity() {
153
- _lastMcpActivity = Date.now();
154
- }
155
- /**
156
- * #854: mark a tool call as started. Suppresses the bridge-child idle reaper so a
157
- * single long-running ctx_execute / ctx_batch_execute (which sends one inbound
158
- * frame then runs unbounded, #643) is never reaped mid-execution.
159
- */
160
- export function noteRequestStart() {
161
- _inFlight++;
162
- _lastMcpActivity = Date.now();
163
- }
164
- /** #854: mark a tool call as finished (success or error). */
165
- export function noteRequestEnd() {
166
- if (_inFlight > 0)
167
- _inFlight--;
168
- _lastMcpActivity = Date.now();
169
- }
170
- /**
171
- * #854: wrap an MCP stdio transport's `onmessage` so each inbound message
172
- * refreshes the idle clock. Best-effort: call after `connect()` (onmessage set);
173
- * a no-op if it isn't a function, and a throw in noteMcpActivity never breaks
174
- * dispatch. No stdin touch (preserves the #236 contract). Exported for testing.
175
- */
176
- export function attachMcpActivityTap(transport) {
177
- if (!transport)
178
- return;
179
- const prev = typeof transport.onmessage === "function" ? transport.onmessage.bind(transport) : null;
180
- if (!prev)
181
- return;
182
- transport.onmessage = (message, extra) => {
183
- try {
184
- noteMcpActivity();
185
- }
186
- catch { /* never break message dispatch */ }
187
- return prev(message, extra);
188
- };
189
- }
190
- /**
191
- * Start the lifecycle guard. Returns a cleanup function.
192
- * Skipped automatically when stdin is a TTY (e.g. OpenCode ts-plugin).
193
- */
194
- export function startLifecycleGuard(opts) {
195
- const interval = opts.checkIntervalMs ?? lifecycleGuardIntervalForEnv();
196
- const check = opts.isParentAlive ?? defaultIsParentAlive;
197
- let stopped = false;
198
- const shutdown = () => {
199
- if (stopped)
200
- return;
201
- stopped = true;
202
- opts.onShutdown();
203
- };
204
- // P0: Periodic parent liveness check
205
- const timer = setInterval(() => {
206
- if (!check())
207
- shutdown();
208
- }, interval);
209
- timer.unref();
210
- // P0: OS signals — terminal close, kill, ctrl+c
211
- const signals = ["SIGTERM", "SIGINT"];
212
- if (process.platform !== "win32")
213
- signals.push("SIGHUP");
214
- for (const sig of signals)
215
- process.on(sig, shutdown);
216
- // P0: Stdin-EOF assist (#311/#388). The vendored MCP SDK's
217
- // StdioServerTransport only registers 'data' / 'error' listeners — not
218
- // 'end' — so when the parent (e.g. Claude Code) dies abruptly without
219
- // sending SIGTERM, the server keeps reading from a half-closed pipe and
220
- // CPU-spins until the 30 s ppid poll catches up. Observed in #388 with
221
- // single processes accumulating ~80 h of CPU time before SIGKILL.
222
- //
223
- // We deliberately DO NOT call shutdown() unconditionally on 'end' — that
224
- // is exactly the false-positive behavior #236 tore out. Instead we run
225
- // the same isParentAlive() check the periodic timer uses, just earlier.
226
- // If the parent is alive, this is a no-op and the existing #236
227
- // regression test still passes; if the parent is gone, we collapse the
228
- // 30 s detection window to ~0.
229
- //
230
- // Skipped on TTY (OpenCode ts-plugin) where stdin is not the MCP channel.
231
- const onStdinEnd = () => {
232
- if (!check())
233
- shutdown();
234
- };
235
- if (!process.stdin.isTTY) {
236
- process.stdin.on("end", onStdinEnd);
237
- }
238
- // #854: request-idle self-shutdown for MCP BRIDGE CHILDREN only
239
- // (CONTEXT_MODE_BRIDGE_DEPTH>0). Pi/omp loads the extension once per
240
- // sub-context and spawns one bridge child each, tearing them down only at
241
- // session_shutdown — which never fires for sub-contexts while the long-lived
242
- // parent stays alive, so idle children accumulate (#854, same class as #565).
243
- // A bridge child that receives no inbound MCP message for `idleMs` exits
244
- // itself; the extension's single-flight path respawns one on the next call.
245
- //
246
- // Scoped strictly to depth>0 so the depth-0 keep-alive servers that #602
247
- // restored are never reaped on idle. The trigger is idle TIME via
248
- // noteMcpActivity() (NOT stdin EOF), so the #236 contract — and lifecycle's
249
- // hands-off-stdin invariant — are untouched.
250
- const idleMs = opts.bridgeIdleMs ?? bridgeChildIdleTimeoutMs();
251
- let idleTimer;
252
- if (idleMs > 0) {
253
- _lastMcpActivity = Date.now();
254
- idleTimer = setInterval(() => {
255
- // Reap only when truly quiescent: NO tool call in flight AND no MCP
256
- // activity for `idleMs`. The in-flight guard prevents reaping a child
257
- // mid-execution during a long single ctx_execute/batch that sends no
258
- // further messages (#643 unbounded calls) — the false-reap regression the
259
- // adversarial review flagged.
260
- if (_inFlight === 0 && Date.now() - _lastMcpActivity >= idleMs) {
261
- // Child's own stderr — the pi bridge forwards it to pi.logger, never the
262
- // TUI terminal (#868). DX-tuned wording via idleReapMessage.
263
- process.stderr.write(idleReapMessage(idleMs) + "\n");
264
- shutdown();
265
- }
266
- }, Math.max(1000, Math.min(Math.floor(idleMs / 4), 30_000)));
267
- idleTimer.unref();
268
- }
269
- return () => {
270
- stopped = true;
271
- clearInterval(timer);
272
- if (idleTimer)
273
- clearInterval(idleTimer);
274
- for (const sig of signals)
275
- process.removeListener(sig, shutdown);
276
- process.stdin.removeListener("end", onStdinEnd);
277
- };
278
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * Generic in-flight-capped worker pool.
3
- *
4
- * Used by:
5
- * - runBatchCommands (ctx_batch_execute parallel branch)
6
- * - runBatchFetch (ctx_fetch_and_index batch path)
7
- *
8
- * Returns Promise.allSettled-style results so one job's throw cannot
9
- * strand siblings. Caller maps fulfilled/rejected per index. Output
10
- * order is preserved by input index (not completion order).
11
- *
12
- * Designed to be the SINGLE concurrency primitive for the project —
13
- * all "run N independent operations with at most M in flight" needs
14
- * route here. Avoids the worker-pool copy-paste flagged in the
15
- * concurrency PRD architectural review (finding G).
16
- */
17
- export interface PoolJob<T> {
18
- run(): Promise<T>;
19
- }
20
- export interface RunPoolOptions {
21
- /** Hard concurrency cap (1-N). Auto-clamped to job count. */
22
- concurrency: number;
23
- /** Optional: also clamp by `os.cpus().length` (memory-pressure safety). Default false. */
24
- capByCpuCount?: boolean;
25
- /** Optional: per-settled callback (e.g. for progress reporting / metrics). */
26
- onSettled?: (idx: number, result: PromiseSettledResult<unknown>) => void;
27
- }
28
- export interface RunPoolResult<T> {
29
- /** Per-index settled result, ordered by input index. */
30
- settled: PromiseSettledResult<T>[];
31
- /** Concurrency actually used after all caps applied. */
32
- effectiveConcurrency: number;
33
- /** True when effectiveConcurrency < requested concurrency. */
34
- capped: boolean;
35
- }
36
- export declare function runPool<T>(jobs: PoolJob<T>[], opts: RunPoolOptions): Promise<RunPoolResult<T>>;
package/build/runPool.js DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * Generic in-flight-capped worker pool.
3
- *
4
- * Used by:
5
- * - runBatchCommands (ctx_batch_execute parallel branch)
6
- * - runBatchFetch (ctx_fetch_and_index batch path)
7
- *
8
- * Returns Promise.allSettled-style results so one job's throw cannot
9
- * strand siblings. Caller maps fulfilled/rejected per index. Output
10
- * order is preserved by input index (not completion order).
11
- *
12
- * Designed to be the SINGLE concurrency primitive for the project —
13
- * all "run N independent operations with at most M in flight" needs
14
- * route here. Avoids the worker-pool copy-paste flagged in the
15
- * concurrency PRD architectural review (finding G).
16
- */
17
- import { cpus } from "node:os";
18
- export async function runPool(jobs, opts) {
19
- const { concurrency, capByCpuCount = false, onSettled } = opts;
20
- if (jobs.length === 0) {
21
- return { settled: [], effectiveConcurrency: 0, capped: false };
22
- }
23
- const requested = Math.max(1, concurrency);
24
- const cpuCap = capByCpuCount ? Math.max(1, cpus().length) : requested;
25
- const effectiveConcurrency = Math.min(requested, cpuCap, jobs.length);
26
- const capped = effectiveConcurrency < requested;
27
- const settled = new Array(jobs.length);
28
- let nextIdx = 0;
29
- async function worker() {
30
- while (true) {
31
- const idx = nextIdx++;
32
- if (idx >= jobs.length)
33
- return;
34
- try {
35
- const value = await jobs[idx].run();
36
- settled[idx] = { status: "fulfilled", value };
37
- }
38
- catch (err) {
39
- settled[idx] = { status: "rejected", reason: err };
40
- }
41
- onSettled?.(idx, settled[idx]);
42
- }
43
- }
44
- const workers = [];
45
- for (let w = 0; w < effectiveConcurrency; w++)
46
- workers.push(worker());
47
- // allSettled defends against any promise rejection escaping a worker
48
- // (the worker already swallows its own errors, but this is belt-and-braces).
49
- await Promise.allSettled(workers);
50
- return { settled, effectiveConcurrency, capped };
51
- }
@@ -1,71 +0,0 @@
1
- export declare function isAllowlistedShell(shellPath: string): boolean;
2
- export type Language = "javascript" | "typescript" | "python" | "shell" | "ruby" | "go" | "rust" | "php" | "perl" | "r" | "elixir" | "csharp";
3
- export interface RuntimeInfo {
4
- command: string;
5
- available: boolean;
6
- version: string;
7
- preferred: boolean;
8
- }
9
- export interface RuntimeMap {
10
- javascript: string | null;
11
- typescript: string | null;
12
- python: string | null;
13
- shell: string;
14
- ruby: string | null;
15
- go: string | null;
16
- rust: string | null;
17
- php: string | null;
18
- perl: string | null;
19
- r: string | null;
20
- elixir: string | null;
21
- csharp: string | null;
22
- }
23
- /**
24
- * Resolve the JavaScript runtime used by PolyglotExecutor.
25
- *
26
- * PR #190 (f69b0d2) made `process.execPath` the default so snap-Node
27
- * envs would not re-invoke the snap wrapper via PATH. That assumed
28
- * `process.execPath` always points at a JS runtime — true on Node,
29
- * tsx, and snap-Node, but FALSE when context-mode runs in-process
30
- * inside a bun-compiled self-contained binary (OpenCode, Kilo, …).
31
- * In those hosts, `process.execPath` resolves to `opencode.exe` /
32
- * `opencode` (NOT node), and spawning that with a `.js` argument
33
- * triggers the yargs "Failed to change directory" error (#731).
34
- *
35
- * Fix: gate `process.execPath` on the existing `JS_RUNTIMES`
36
- * allowlist (single source of truth — same set used by
37
- * `buildNodeCommand()` in src/adapters/types.ts since PR #708). When
38
- * the execPath basename is not a known JS runtime, fall back to a
39
- * PATH-resolved `node`. If neither is reachable, return `null` and
40
- * let ctx_doctor surface an actionable error.
41
- *
42
- * The cross-OS guard is the allowlist itself — NOT a `win32` check.
43
- * OpenCode ships self-contained binaries on macOS and Linux too,
44
- * and the bug reproduces identically there.
45
- */
46
- export declare function resolveJavascriptRuntime(bun: string | null, deps?: {
47
- execPath?: string;
48
- commandExists?: (cmd: string) => boolean;
49
- }): string | null;
50
- export declare function detectRuntimes(): RuntimeMap;
51
- export declare function hasBunRuntime(): boolean;
52
- /**
53
- * Resolved JS runtime for hook spawn commands. `path` is the absolute (or
54
- * bare-name on POSIX where PATH resolution is reliable) binary path.
55
- * `isBun` is true only when we successfully probed a Bun ≥1.0 install.
56
- */
57
- export interface HookRuntime {
58
- readonly path: string;
59
- readonly isBun: boolean;
60
- }
61
- /**
62
- * Reset the hook-runtime resolution cache. Test-only — production code
63
- * should never call this. Vitest mocks `node:child_process`/`node:fs`
64
- * per-test, so the per-process cache from a previous test would otherwise
65
- * mask the mock and yield the host's real bun/node detection result.
66
- */
67
- export declare function resetHookRuntimeCache(): void;
68
- export declare function resolveHookRuntime(): HookRuntime;
69
- export declare function getRuntimeSummary(runtimes: RuntimeMap): string;
70
- export declare function getAvailableLanguages(runtimes: RuntimeMap): Language[];
71
- export declare function buildCommand(runtimes: RuntimeMap, language: Language, filePath: string): string[];