@namzu/sdk 51.0.0 → 52.0.0

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 (352) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/dist/agents/QueryAgent.d.ts.map +1 -1
  3. package/dist/agents/QueryAgent.js +2 -0
  4. package/dist/agents/QueryAgent.js.map +1 -1
  5. package/dist/agents/SupervisorAgent.d.ts +1 -1
  6. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  7. package/dist/agents/SupervisorAgent.js.map +1 -1
  8. package/dist/agents/examples/SupervisorAgent.d.ts +42 -0
  9. package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
  10. package/dist/agents/examples/SupervisorAgent.js +80 -4
  11. package/dist/agents/examples/SupervisorAgent.js.map +1 -1
  12. package/dist/agents/index.d.ts +1 -1
  13. package/dist/agents/index.d.ts.map +1 -1
  14. package/dist/agents/index.js.map +1 -1
  15. package/dist/authorization/protected-paths.d.ts +36 -0
  16. package/dist/authorization/protected-paths.d.ts.map +1 -0
  17. package/dist/authorization/protected-paths.js +107 -0
  18. package/dist/authorization/protected-paths.js.map +1 -0
  19. package/dist/authorization/readonly-commands.d.ts +39 -0
  20. package/dist/authorization/readonly-commands.d.ts.map +1 -0
  21. package/dist/authorization/readonly-commands.js +797 -0
  22. package/dist/authorization/readonly-commands.js.map +1 -0
  23. package/dist/authorization/readonly-flags.d.ts +19 -0
  24. package/dist/authorization/readonly-flags.d.ts.map +1 -0
  25. package/dist/authorization/readonly-flags.js +178 -0
  26. package/dist/authorization/readonly-flags.js.map +1 -0
  27. package/dist/authorization/removal.d.ts +52 -0
  28. package/dist/authorization/removal.d.ts.map +1 -0
  29. package/dist/authorization/removal.js +283 -0
  30. package/dist/authorization/removal.js.map +1 -0
  31. package/dist/authorization/shell-paths.d.ts +66 -0
  32. package/dist/authorization/shell-paths.d.ts.map +1 -0
  33. package/dist/authorization/shell-paths.js +697 -0
  34. package/dist/authorization/shell-paths.js.map +1 -0
  35. package/dist/bridge/acp/update.d.ts.map +1 -1
  36. package/dist/bridge/acp/update.js +1 -0
  37. package/dist/bridge/acp/update.js.map +1 -1
  38. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  39. package/dist/bridge/sse/mapper.js +1 -0
  40. package/dist/bridge/sse/mapper.js.map +1 -1
  41. package/dist/compaction/context-window.d.ts +24 -0
  42. package/dist/compaction/context-window.d.ts.map +1 -1
  43. package/dist/compaction/context-window.js +34 -0
  44. package/dist/compaction/context-window.js.map +1 -1
  45. package/dist/compaction/manual.d.ts.map +1 -1
  46. package/dist/compaction/manual.js +10 -2
  47. package/dist/compaction/manual.js.map +1 -1
  48. package/dist/compaction/plan.d.ts +4 -0
  49. package/dist/compaction/plan.d.ts.map +1 -1
  50. package/dist/compaction/plan.js +6 -2
  51. package/dist/compaction/plan.js.map +1 -1
  52. package/dist/compaction/verifier.d.ts +11 -1
  53. package/dist/compaction/verifier.d.ts.map +1 -1
  54. package/dist/compaction/verifier.js +19 -7
  55. package/dist/compaction/verifier.js.map +1 -1
  56. package/dist/config/runtime.d.ts +55 -7
  57. package/dist/config/runtime.d.ts.map +1 -1
  58. package/dist/config/runtime.js +23 -2
  59. package/dist/config/runtime.js.map +1 -1
  60. package/dist/connector/web/guarded-fetch.d.ts.map +1 -1
  61. package/dist/connector/web/guarded-fetch.js +24 -0
  62. package/dist/connector/web/guarded-fetch.js.map +1 -1
  63. package/dist/connector/web/index.d.ts +1 -1
  64. package/dist/connector/web/index.d.ts.map +1 -1
  65. package/dist/connector/web/page.d.ts +59 -0
  66. package/dist/connector/web/page.d.ts.map +1 -0
  67. package/dist/connector/web/page.js +112 -0
  68. package/dist/connector/web/page.js.map +1 -0
  69. package/dist/connector/web/types.d.ts +47 -0
  70. package/dist/connector/web/types.d.ts.map +1 -1
  71. package/dist/connector/web/types.js.map +1 -1
  72. package/dist/constants/continuation.d.ts +8 -0
  73. package/dist/constants/continuation.d.ts.map +1 -1
  74. package/dist/constants/continuation.js +8 -0
  75. package/dist/constants/continuation.js.map +1 -1
  76. package/dist/constants/plugin/index.d.ts +1 -1
  77. package/dist/constants/plugin/index.d.ts.map +1 -1
  78. package/dist/constants/plugin/index.js +1 -1
  79. package/dist/constants/plugin/index.js.map +1 -1
  80. package/dist/manager/agent/lifecycle.d.ts +7 -0
  81. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  82. package/dist/manager/agent/lifecycle.js +11 -2
  83. package/dist/manager/agent/lifecycle.js.map +1 -1
  84. package/dist/manager/session/turn-recorder.d.ts.map +1 -1
  85. package/dist/manager/session/turn-recorder.js +4 -2
  86. package/dist/manager/session/turn-recorder.js.map +1 -1
  87. package/dist/plugin/index.d.ts +1 -1
  88. package/dist/plugin/index.d.ts.map +1 -1
  89. package/dist/plugin/index.js +1 -1
  90. package/dist/plugin/index.js.map +1 -1
  91. package/dist/plugin/lifecycle.d.ts +6 -0
  92. package/dist/plugin/lifecycle.d.ts.map +1 -1
  93. package/dist/plugin/lifecycle.js +98 -114
  94. package/dist/plugin/lifecycle.js.map +1 -1
  95. package/dist/plugin/shell-hook.d.ts +90 -22
  96. package/dist/plugin/shell-hook.d.ts.map +1 -1
  97. package/dist/plugin/shell-hook.js +434 -41
  98. package/dist/plugin/shell-hook.js.map +1 -1
  99. package/dist/provider/errors.d.ts +10 -0
  100. package/dist/provider/errors.d.ts.map +1 -1
  101. package/dist/provider/errors.js +16 -0
  102. package/dist/provider/errors.js.map +1 -1
  103. package/dist/provider/retry.d.ts +27 -0
  104. package/dist/provider/retry.d.ts.map +1 -1
  105. package/dist/provider/retry.js +19 -3
  106. package/dist/provider/retry.js.map +1 -1
  107. package/dist/public-runtime.d.ts +4 -1
  108. package/dist/public-runtime.d.ts.map +1 -1
  109. package/dist/public-runtime.js +4 -1
  110. package/dist/public-runtime.js.map +1 -1
  111. package/dist/public-types.d.ts +2 -2
  112. package/dist/public-types.d.ts.map +1 -1
  113. package/dist/runtime/jobs/registry.d.ts +21 -0
  114. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  115. package/dist/runtime/jobs/registry.js +15 -2
  116. package/dist/runtime/jobs/registry.js.map +1 -1
  117. package/dist/runtime/query/executor/tool-call-admission.d.ts +10 -0
  118. package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
  119. package/dist/runtime/query/executor/tool-call-admission.js +74 -13
  120. package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
  121. package/dist/runtime/query/executor.d.ts +41 -2
  122. package/dist/runtime/query/executor.d.ts.map +1 -1
  123. package/dist/runtime/query/executor.js +190 -6
  124. package/dist/runtime/query/executor.js.map +1 -1
  125. package/dist/runtime/query/finalize-turn.d.ts +6 -0
  126. package/dist/runtime/query/finalize-turn.d.ts.map +1 -1
  127. package/dist/runtime/query/finalize-turn.js +1 -1
  128. package/dist/runtime/query/finalize-turn.js.map +1 -1
  129. package/dist/runtime/query/index.d.ts +29 -0
  130. package/dist/runtime/query/index.d.ts.map +1 -1
  131. package/dist/runtime/query/index.js +15 -3
  132. package/dist/runtime/query/index.js.map +1 -1
  133. package/dist/runtime/query/iteration/index.d.ts +31 -0
  134. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  135. package/dist/runtime/query/iteration/index.js +216 -7
  136. package/dist/runtime/query/iteration/index.js.map +1 -1
  137. package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts +58 -0
  138. package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts.map +1 -0
  139. package/dist/runtime/query/iteration/phases/compaction-breaker.js +91 -0
  140. package/dist/runtime/query/iteration/phases/compaction-breaker.js.map +1 -0
  141. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  142. package/dist/runtime/query/iteration/phases/compaction.js +89 -7
  143. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  144. package/dist/runtime/query/iteration/phases/context.d.ts +10 -0
  145. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  146. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  147. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  148. package/dist/runtime/query/iteration/phases/tool-review.js +165 -2
  149. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  150. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  151. package/dist/runtime/query/iteration/stream-turn.js +24 -1
  152. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  153. package/dist/runtime/query/path-escalation.d.ts +36 -0
  154. package/dist/runtime/query/path-escalation.d.ts.map +1 -0
  155. package/dist/runtime/query/path-escalation.js +184 -0
  156. package/dist/runtime/query/path-escalation.js.map +1 -0
  157. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  158. package/dist/runtime/query/plugin-hooks.js +8 -0
  159. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  160. package/dist/runtime/query/reminders.d.ts +35 -0
  161. package/dist/runtime/query/reminders.d.ts.map +1 -0
  162. package/dist/runtime/query/reminders.js +7 -0
  163. package/dist/runtime/query/reminders.js.map +1 -0
  164. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  165. package/dist/runtime/query/resume-pending.js +26 -0
  166. package/dist/runtime/query/resume-pending.js.map +1 -1
  167. package/dist/runtime/query/review-policy.d.ts +26 -0
  168. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  169. package/dist/runtime/query/review-policy.js +79 -5
  170. package/dist/runtime/query/review-policy.js.map +1 -1
  171. package/dist/runtime/query/tool-output-budget.d.ts +46 -0
  172. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  173. package/dist/runtime/query/tool-output-budget.js +85 -1
  174. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  175. package/dist/runtime/query/tooling.d.ts +1 -0
  176. package/dist/runtime/query/tooling.d.ts.map +1 -1
  177. package/dist/runtime/query/tooling.js +5 -0
  178. package/dist/runtime/query/tooling.js.map +1 -1
  179. package/dist/session/paths.d.ts +5 -1
  180. package/dist/session/paths.d.ts.map +1 -1
  181. package/dist/session/paths.js +8 -0
  182. package/dist/session/paths.js.map +1 -1
  183. package/dist/store/memory/disk.d.ts.map +1 -1
  184. package/dist/store/memory/disk.js +2 -2
  185. package/dist/store/memory/disk.js.map +1 -1
  186. package/dist/store/memory/markdown.d.ts.map +1 -1
  187. package/dist/store/memory/markdown.js +2 -2
  188. package/dist/store/memory/markdown.js.map +1 -1
  189. package/dist/store/memory/naming.d.ts +9 -0
  190. package/dist/store/memory/naming.d.ts.map +1 -1
  191. package/dist/store/memory/naming.js +12 -0
  192. package/dist/store/memory/naming.js.map +1 -1
  193. package/dist/tools/builtins/bash.d.ts +30 -1
  194. package/dist/tools/builtins/bash.d.ts.map +1 -1
  195. package/dist/tools/builtins/bash.js +170 -26
  196. package/dist/tools/builtins/bash.js.map +1 -1
  197. package/dist/tools/builtins/content-fingerprint.d.ts +2 -0
  198. package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -1
  199. package/dist/tools/builtins/content-fingerprint.js +4 -0
  200. package/dist/tools/builtins/content-fingerprint.js.map +1 -1
  201. package/dist/tools/builtins/edit.d.ts.map +1 -1
  202. package/dist/tools/builtins/edit.js +60 -18
  203. package/dist/tools/builtins/edit.js.map +1 -1
  204. package/dist/tools/builtins/grep.d.ts +8 -1
  205. package/dist/tools/builtins/grep.d.ts.map +1 -1
  206. package/dist/tools/builtins/grep.js +152 -33
  207. package/dist/tools/builtins/grep.js.map +1 -1
  208. package/dist/tools/builtins/read-file.d.ts +1 -0
  209. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  210. package/dist/tools/builtins/read-file.js +44 -5
  211. package/dist/tools/builtins/read-file.js.map +1 -1
  212. package/dist/tools/builtins/read-render.d.ts +52 -0
  213. package/dist/tools/builtins/read-render.d.ts.map +1 -1
  214. package/dist/tools/builtins/read-render.js +143 -0
  215. package/dist/tools/builtins/read-render.js.map +1 -1
  216. package/dist/tools/builtins/web.d.ts +13 -2
  217. package/dist/tools/builtins/web.d.ts.map +1 -1
  218. package/dist/tools/builtins/web.js +225 -32
  219. package/dist/tools/builtins/web.js.map +1 -1
  220. package/dist/tools/coordinator/ask-user-question.d.ts +2 -0
  221. package/dist/tools/coordinator/ask-user-question.d.ts.map +1 -1
  222. package/dist/tools/coordinator/ask-user-question.js +256 -92
  223. package/dist/tools/coordinator/ask-user-question.js.map +1 -1
  224. package/dist/tools/coordinator/question-options.d.ts +1 -0
  225. package/dist/tools/coordinator/question-options.d.ts.map +1 -1
  226. package/dist/tools/coordinator/question-options.js +6 -1
  227. package/dist/tools/coordinator/question-options.js.map +1 -1
  228. package/dist/tools/defineTool.d.ts +4 -1
  229. package/dist/tools/defineTool.d.ts.map +1 -1
  230. package/dist/tools/defineTool.js +6 -1
  231. package/dist/tools/defineTool.js.map +1 -1
  232. package/dist/tools/paths.d.ts +6 -0
  233. package/dist/tools/paths.d.ts.map +1 -1
  234. package/dist/tools/paths.js +1 -1
  235. package/dist/tools/paths.js.map +1 -1
  236. package/dist/types/agent/query.d.ts +3 -0
  237. package/dist/types/agent/query.d.ts.map +1 -1
  238. package/dist/types/errors/catalog.js +1 -1
  239. package/dist/types/errors/catalog.js.map +1 -1
  240. package/dist/types/hitl/index.d.ts +104 -0
  241. package/dist/types/hitl/index.d.ts.map +1 -1
  242. package/dist/types/hitl/index.js.map +1 -1
  243. package/dist/types/message/index.d.ts +1 -1
  244. package/dist/types/message/index.d.ts.map +1 -1
  245. package/dist/types/message/index.js +2 -0
  246. package/dist/types/message/index.js.map +1 -1
  247. package/dist/types/plugin/index.d.ts +93 -19
  248. package/dist/types/plugin/index.d.ts.map +1 -1
  249. package/dist/types/plugin/index.js +3 -0
  250. package/dist/types/plugin/index.js.map +1 -1
  251. package/dist/types/provider/error.d.ts +6 -0
  252. package/dist/types/provider/error.d.ts.map +1 -1
  253. package/dist/types/provider/errors.d.ts +19 -0
  254. package/dist/types/provider/errors.d.ts.map +1 -1
  255. package/dist/types/provider/errors.js +39 -1
  256. package/dist/types/provider/errors.js.map +1 -1
  257. package/dist/types/provider/stream.d.ts +6 -0
  258. package/dist/types/provider/stream.d.ts.map +1 -1
  259. package/dist/types/session/events.d.ts +15 -2
  260. package/dist/types/session/events.d.ts.map +1 -1
  261. package/dist/types/session/events.js.map +1 -1
  262. package/dist/types/session/records.d.ts +9 -9
  263. package/dist/types/session/records.d.ts.map +1 -1
  264. package/dist/types/session/records.js +1 -0
  265. package/dist/types/session/records.js.map +1 -1
  266. package/dist/types/session/stop-reason.d.ts +5 -0
  267. package/dist/types/session/stop-reason.d.ts.map +1 -1
  268. package/dist/types/tool/index.d.ts +52 -0
  269. package/dist/types/tool/index.d.ts.map +1 -1
  270. package/dist/types/tool/index.js.map +1 -1
  271. package/dist/utils/backoff.d.ts +12 -0
  272. package/dist/utils/backoff.d.ts.map +1 -1
  273. package/dist/utils/backoff.js +15 -0
  274. package/dist/utils/backoff.js.map +1 -1
  275. package/package.json +4 -2
  276. package/src/agents/QueryAgent.ts +5 -1
  277. package/src/agents/SupervisorAgent.ts +1 -1
  278. package/src/agents/examples/SupervisorAgent.ts +217 -106
  279. package/src/agents/index.ts +1 -1
  280. package/src/authorization/protected-paths.ts +110 -0
  281. package/src/authorization/readonly-commands.ts +771 -0
  282. package/src/authorization/readonly-flags.ts +196 -0
  283. package/src/authorization/removal.ts +326 -0
  284. package/src/authorization/shell-paths.ts +927 -0
  285. package/src/bridge/acp/update.ts +1 -0
  286. package/src/bridge/sse/mapper.ts +1 -0
  287. package/src/compaction/context-window.ts +41 -0
  288. package/src/compaction/manual.ts +10 -2
  289. package/src/compaction/plan.ts +11 -2
  290. package/src/compaction/verifier.ts +28 -3
  291. package/src/config/runtime.ts +23 -2
  292. package/src/connector/web/guarded-fetch.ts +26 -0
  293. package/src/connector/web/index.ts +3 -0
  294. package/src/connector/web/page.ts +130 -0
  295. package/src/connector/web/types.ts +47 -0
  296. package/src/constants/continuation.ts +10 -0
  297. package/src/constants/plugin/index.ts +1 -1
  298. package/src/manager/agent/lifecycle.ts +12 -4
  299. package/src/manager/session/turn-recorder.ts +10 -2
  300. package/src/plugin/index.ts +1 -0
  301. package/src/plugin/lifecycle.ts +107 -119
  302. package/src/plugin/shell-hook.ts +477 -43
  303. package/src/provider/errors.ts +18 -0
  304. package/src/provider/retry.ts +53 -3
  305. package/src/public-runtime.ts +8 -0
  306. package/src/public-types.ts +4 -0
  307. package/src/runtime/jobs/registry.ts +39 -2
  308. package/src/runtime/query/executor/tool-call-admission.ts +79 -13
  309. package/src/runtime/query/executor.ts +242 -8
  310. package/src/runtime/query/finalize-turn.ts +7 -1
  311. package/src/runtime/query/index.ts +45 -3
  312. package/src/runtime/query/iteration/index.ts +251 -12
  313. package/src/runtime/query/iteration/phases/compaction-breaker.ts +106 -0
  314. package/src/runtime/query/iteration/phases/compaction.ts +99 -12
  315. package/src/runtime/query/iteration/phases/context.ts +11 -0
  316. package/src/runtime/query/iteration/phases/tool-review.ts +177 -2
  317. package/src/runtime/query/iteration/stream-turn.ts +24 -1
  318. package/src/runtime/query/path-escalation.ts +204 -0
  319. package/src/runtime/query/plugin-hooks.ts +8 -0
  320. package/src/runtime/query/reminders.ts +45 -0
  321. package/src/runtime/query/resume-pending.ts +27 -0
  322. package/src/runtime/query/review-policy.ts +106 -5
  323. package/src/runtime/query/tool-output-budget.ts +115 -1
  324. package/src/runtime/query/tooling.ts +6 -0
  325. package/src/session/paths.ts +11 -1
  326. package/src/store/memory/disk.ts +2 -1
  327. package/src/store/memory/markdown.ts +2 -1
  328. package/src/store/memory/naming.ts +13 -0
  329. package/src/tools/builtins/bash.ts +203 -34
  330. package/src/tools/builtins/content-fingerprint.ts +5 -0
  331. package/src/tools/builtins/edit.ts +69 -19
  332. package/src/tools/builtins/grep.ts +159 -38
  333. package/src/tools/builtins/read-file.ts +48 -5
  334. package/src/tools/builtins/read-render.ts +193 -0
  335. package/src/tools/builtins/web.ts +258 -33
  336. package/src/tools/coordinator/ask-user-question.ts +309 -103
  337. package/src/tools/coordinator/question-options.ts +8 -1
  338. package/src/tools/defineTool.ts +11 -2
  339. package/src/tools/paths.ts +1 -1
  340. package/src/types/agent/query.ts +3 -0
  341. package/src/types/errors/catalog.ts +1 -1
  342. package/src/types/hitl/index.ts +104 -0
  343. package/src/types/message/index.ts +2 -0
  344. package/src/types/plugin/index.ts +101 -18
  345. package/src/types/provider/error.ts +6 -0
  346. package/src/types/provider/errors.ts +49 -1
  347. package/src/types/provider/stream.ts +6 -0
  348. package/src/types/session/events.ts +15 -2
  349. package/src/types/session/records.ts +1 -0
  350. package/src/types/session/stop-reason.ts +5 -0
  351. package/src/types/tool/index.ts +53 -2
  352. package/src/utils/backoff.ts +21 -0
@@ -262,6 +262,7 @@ export class PluginLifecycleManager {
262
262
  handler: (context: PluginHookContext) => Promise<PluginHookResult>
263
263
  priority: number
264
264
  seq: number
265
+ statusMessage?: string
265
266
  }>
266
267
  > = new Map()
267
268
  private pluginContributions: Map<PluginId, PluginContributionRecord> = new Map()
@@ -417,6 +418,7 @@ export class PluginLifecycleManager {
417
418
  pluginId,
418
419
  handler: hook.handler,
419
420
  priority: hook.priority ?? DEFAULT_HOOK_PRIORITY,
421
+ ...(hook.statusMessage !== undefined ? { statusMessage: hook.statusMessage } : {}),
420
422
  // Registration index, so the sort has something stable to fall
421
423
  // back on when priorities are equal.
422
424
  seq: handlers.length,
@@ -1066,115 +1068,42 @@ export class PluginLifecycleManager {
1066
1068
  return []
1067
1069
  }
1068
1070
 
1069
- const results: PluginHookResult[] = []
1070
- // Interrupt hooks are cleanup/notification observers. One extension's
1071
- // skip, error, retry, or timeout must not suppress the extensions that
1072
- // follow it, and none of those results can change the cancellation that
1073
- // already happened. Other hook events retain their existing flow-control
1074
- // semantics.
1075
- const observationalFanOut = event === 'turn_interrupt'
1076
-
1077
- // Determine execution order: post_* hooks run backward (for cleanup semantics)
1078
- const isPost = event.startsWith('post_')
1079
-
1080
- // For post_* hooks, we need to process in reverse order (last registered runs first)
1081
- const indicesToProcess: number[] = []
1082
- if (isPost) {
1083
- for (let i = handlers.length - 1; i >= 0; i--) {
1084
- indicesToProcess.push(i)
1085
- }
1086
- } else {
1087
- for (let i = 0; i < handlers.length; i++) {
1088
- indicesToProcess.push(i)
1089
- }
1090
- }
1091
-
1092
- // Track input overlay so chained `modify` actions compose: each subsequent
1093
- // hook sees the input produced by the previous hook's modify.
1094
- let toolInputOverlay = context.toolInput
1095
-
1096
- for (const idx of indicesToProcess) {
1097
- const hookEntry = handlers[idx]
1098
- if (!hookEntry) continue
1099
- const { pluginId, handler: handlerFn } = hookEntry
1100
- const hookContext: PluginHookContext = {
1101
- ...context,
1102
- toolInput: toolInputOverlay,
1103
- pluginId,
1104
- event,
1105
- }
1106
-
1107
- if (emitSessionEvent) {
1108
- await emitSessionEvent({
1109
- type: 'plugin_hook_executing',
1110
- sessionId: context.sessionId,
1111
- ...(context.turnId !== undefined ? { turnId: context.turnId } : {}),
1112
- pluginId,
1113
- hookEvent: event,
1114
- })
1115
- callerSignal?.throwIfAborted()
1116
- }
1117
-
1118
- const start = performance.now()
1119
- let result: PluginHookResult
1120
-
1121
- // The deadline timer is captured and cleared in `finally`.
1122
- // Without that it stayed armed after the hook resolved, and an
1123
- // armed timer keeps the Node event loop alive: hooks fire on
1124
- // every tool call and every model call, so a turn of twenty tool
1125
- // calls left twenty live timers and the process could not exit
1126
- // until the last one expired. Nothing failed — it just hung, for
1127
- // up to the timeout, every time.
1128
- const deadline = new AbortController()
1129
- const hookSignal = callerSignal
1130
- ? AbortSignal.any([callerSignal, deadline.signal])
1131
- : deadline.signal
1132
- let timer: ReturnType<typeof setTimeout> | undefined
1133
- let onCallerAbort: (() => void) | undefined
1134
-
1135
- try {
1136
- const races: Promise<PluginHookResult>[] = [
1137
- Promise.resolve().then(() => handlerFn({ ...hookContext, signal: hookSignal })),
1138
- new Promise<PluginHookResult>((_, reject) => {
1139
- timer = setTimeout(() => {
1140
- // Told, not just abandoned: a hook holding a socket
1141
- // open can close it.
1142
- deadline.abort()
1143
- reject(new Error('Hook timeout'))
1144
- }, this.hookTimeoutMs)
1145
- }),
1146
- ]
1147
- if (callerSignal) {
1148
- races.push(
1149
- new Promise<PluginHookResult>((_, reject) => {
1150
- onCallerAbort = () => reject(callerSignal.reason)
1151
- callerSignal.addEventListener('abort', onCallerAbort, {
1152
- once: true,
1153
- })
1154
- if (callerSignal.aborted) onCallerAbort()
1155
- }),
1156
- )
1157
- }
1158
- result = await Promise.race(races)
1159
- callerSignal?.throwIfAborted()
1160
- } catch (err) {
1161
- // Cancellation belongs to the turn, not to the plugin. Turning it
1162
- // into a hook error would let the query continue after its caller
1163
- // withdrew authority and would report Stop as a plugin failure.
1164
- if (callerSignal?.aborted) throw callerSignal.reason
1165
- const message = toErrorMessage(err)
1166
- result = { action: 'error', message }
1167
- } finally {
1168
- if (timer !== undefined) clearTimeout(timer)
1169
- if (onCallerAbort) callerSignal?.removeEventListener('abort', onCallerAbort)
1170
- }
1171
-
1071
+ // Every matching hook starts at once, on the context the event carried,
1072
+ // and the answers come back in registration (priority) order. Nothing
1073
+ // short-circuits: a hook that refuses does not stop its siblings from
1074
+ // running, and the caller decides how the answers combine (a refusal
1075
+ // outranks an `ask`, which outranks an `allow`; of several rewrites the
1076
+ // last in order wins; contexts are joined). The old chain ran them one
1077
+ // by one, `post_*` in reverse, each seeing the previous hook's `modify`.
1078
+ const entries = handlers.map((hookEntry) => ({
1079
+ hookEntry,
1080
+ hookContext: { ...context, pluginId: hookEntry.pluginId, event } as PluginHookContext,
1081
+ }))
1082
+ for (const { hookEntry } of entries) {
1083
+ if (!emitSessionEvent) break
1084
+ await emitSessionEvent({
1085
+ type: 'plugin_hook_executing',
1086
+ sessionId: context.sessionId,
1087
+ ...(context.turnId !== undefined ? { turnId: context.turnId } : {}),
1088
+ pluginId: hookEntry.pluginId,
1089
+ hookEvent: event,
1090
+ ...(hookEntry.statusMessage !== undefined
1091
+ ? { statusMessage: hookEntry.statusMessage }
1092
+ : {}),
1093
+ })
1172
1094
  callerSignal?.throwIfAborted()
1173
- const durationMs = Math.round(performance.now() - start)
1174
-
1095
+ }
1096
+ const settled = await Promise.all(
1097
+ entries.map(({ hookEntry, hookContext }) =>
1098
+ this.runOneHook(hookEntry, hookContext, callerSignal),
1099
+ ),
1100
+ )
1101
+ callerSignal?.throwIfAborted()
1102
+ const results: PluginHookResult[] = []
1103
+ for (const { hookEntry, result, durationMs } of settled) {
1175
1104
  this.emit({
1176
1105
  type: 'plugin_hook_executed',
1177
- pluginId,
1106
+ pluginId: hookEntry.pluginId,
1178
1107
  hookEvent: event,
1179
1108
  durationMs,
1180
1109
  })
@@ -1185,30 +1114,89 @@ export class PluginLifecycleManager {
1185
1114
  type: 'plugin_hook_completed',
1186
1115
  sessionId: context.sessionId,
1187
1116
  ...(context.turnId !== undefined ? { turnId: context.turnId } : {}),
1188
- pluginId,
1117
+ pluginId: hookEntry.pluginId,
1189
1118
  hookEvent: event,
1190
1119
  result,
1191
1120
  })
1192
1121
  callerSignal?.throwIfAborted()
1193
1122
  }
1194
-
1195
1123
  results.push(result)
1124
+ }
1125
+ return results
1126
+ }
1196
1127
 
1197
- if (!observationalFanOut && result.action === 'modify') {
1198
- toolInputOverlay = result.input
1199
- }
1128
+ /**
1129
+ * Run one hook to its answer: bounded by the manager's deadline and the
1130
+ * turn's own cancellation. A throw or a timeout is an `error` answer; the
1131
+ * turn's cancellation is rethrown, because it belongs to the turn.
1132
+ */
1133
+ private async runOneHook(
1134
+ hookEntry: {
1135
+ pluginId: PluginId
1136
+ handler: (context: PluginHookContext) => Promise<PluginHookResult>
1137
+ },
1138
+ hookContext: PluginHookContext,
1139
+ callerSignal: AbortSignal | undefined,
1140
+ ): Promise<{ hookEntry: typeof hookEntry; result: PluginHookResult; durationMs: number }> {
1141
+ const { handler: handlerFn } = hookEntry
1142
+ const start = performance.now()
1143
+ let result: PluginHookResult
1144
+
1145
+ // The deadline timer is captured and cleared in `finally`.
1146
+ // Without that it stayed armed after the hook resolved, and an
1147
+ // armed timer keeps the Node event loop alive: hooks fire on
1148
+ // every tool call and every model call, so a turn of twenty tool
1149
+ // calls left twenty live timers and the process could not exit
1150
+ // until the last one expired. Nothing failed — it just hung, for
1151
+ // up to the timeout, every time.
1152
+ const deadline = new AbortController()
1153
+ const hookSignal = callerSignal
1154
+ ? AbortSignal.any([callerSignal, deadline.signal])
1155
+ : deadline.signal
1156
+ let timer: ReturnType<typeof setTimeout> | undefined
1157
+ let onCallerAbort: (() => void) | undefined
1200
1158
 
1201
- // Handle flow control: check priority order: error > skip > retry > resume > modify > continue
1202
- // Short-circuit on error or skip; return immediately on resume or retry
1203
- if (!observationalFanOut && (result.action === 'error' || result.action === 'skip')) {
1204
- break
1205
- }
1206
- if (!observationalFanOut && result.action === 'retry') {
1207
- break
1159
+ try {
1160
+ const races: Promise<PluginHookResult>[] = [
1161
+ Promise.resolve().then(() => handlerFn({ ...hookContext, signal: hookSignal })),
1162
+ new Promise<PluginHookResult>((_, reject) => {
1163
+ timer = setTimeout(() => {
1164
+ // Told, not just abandoned: a hook holding a socket
1165
+ // open can close it.
1166
+ deadline.abort()
1167
+ reject(new Error('Hook timeout'))
1168
+ }, this.hookTimeoutMs)
1169
+ }),
1170
+ ]
1171
+ if (callerSignal) {
1172
+ races.push(
1173
+ new Promise<PluginHookResult>((_, reject) => {
1174
+ onCallerAbort = () => reject(callerSignal.reason)
1175
+ callerSignal.addEventListener('abort', onCallerAbort, {
1176
+ once: true,
1177
+ })
1178
+ if (callerSignal.aborted) onCallerAbort()
1179
+ }),
1180
+ )
1208
1181
  }
1182
+ result = await Promise.race(races)
1183
+ callerSignal?.throwIfAborted()
1184
+ } catch (err) {
1185
+ // Cancellation belongs to the turn, not to the plugin. Turning it
1186
+ // into a hook error would let the query continue after its caller
1187
+ // withdrew authority and would report Stop as a plugin failure.
1188
+ if (callerSignal?.aborted) throw callerSignal.reason
1189
+ const message = toErrorMessage(err)
1190
+ result = { action: 'error', message }
1191
+ } finally {
1192
+ if (timer !== undefined) clearTimeout(timer)
1193
+ if (onCallerAbort) callerSignal?.removeEventListener('abort', onCallerAbort)
1209
1194
  }
1210
1195
 
1211
- return results
1196
+ callerSignal?.throwIfAborted()
1197
+ const durationMs = Math.round(performance.now() - start)
1198
+
1199
+ return { hookEntry, result, durationMs }
1212
1200
  }
1213
1201
 
1214
1202
  private emit(event: PluginLifecycleEvent): void {