@sema-agent/server 7.146.0 → 7.148.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 (850) hide show
  1. package/MIGRATION.md +1423 -24
  2. package/README.md +21 -8
  3. package/README.zh-CN.md +15 -9
  4. package/USAGE.md +537 -216
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +18 -7
  7. package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +42 -4
  9. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  10. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  11. package/deploy/sema-up/chart/values.yaml +4 -3
  12. package/deploy/sema-up/cluster-up.sh +75 -176
  13. package/deploy/sema-up/kube-up.sh +29 -49
  14. package/deploy/sema-up/lib/chart-run.sh +23 -0
  15. package/deploy/sema-up/lib/dataroot.sh +3 -3
  16. package/deploy/sema-up/lib/flagshape.sh +4 -0
  17. package/deploy/sema-up/lib/health.sh +62 -13
  18. package/deploy/sema-up/lib/helm-values-cluster.py +18 -0
  19. package/deploy/sema-up/lib/helm-values-kube.py +35 -0
  20. package/deploy/sema-up/lib/lanes.json +2 -5
  21. package/deploy/sema-up/lib/regcred.py +8 -0
  22. package/deploy/sema-up/lib/remote/helm-install.sh +3 -0
  23. package/deploy/sema-up/lib/remote/image-import.sh +6 -0
  24. package/deploy/sema-up/lib/remote/machine-precheck.sh +11 -0
  25. package/deploy/sema-up/lib/remote/region-probe.sh +3 -0
  26. package/deploy/sema-up/lib/remote/stack-ready.sh +26 -0
  27. package/deploy/sema-up/lib/remote/vxlan-guard.sh +8 -0
  28. package/deploy/sema-up/lib/render-stack.py +17 -0
  29. package/deploy/sema-up/lib/shell-text.sh +87 -0
  30. package/deploy/sema-up/lib/usage-flags.txt +10 -0
  31. package/deploy/sema-up/lib/usage-head.txt +1 -0
  32. package/deploy/sema-up/lib/usage-tail.txt +13 -0
  33. package/deploy/sema-up/preflight.sh +10 -8
  34. package/deploy/sema-up/sema-up.sh +26 -48
  35. package/deploy/sema-up/smoke.sh +7 -6
  36. package/deploy/sema-up/stack/compose.dataroot.yaml +3 -0
  37. package/deploy/sema-up/stack/compose.yaml +18 -5
  38. package/deploy/sema-up/stack/sema-stack-cluster.yaml +25 -3
  39. package/dist/adoption/plan.d.ts +24 -0
  40. package/dist/adoption/plan.js +53 -1
  41. package/dist/adoption/runner.d.ts +10 -1
  42. package/dist/adoption/runner.js +36 -16
  43. package/dist/adoption/wire.d.ts +3 -3
  44. package/dist/approval-card.d.ts +32 -34
  45. package/dist/approval-gate-currency.js +3 -2
  46. package/dist/approval-reconciler.d.ts +4 -13
  47. package/dist/approval-reconciler.js +2 -2
  48. package/dist/approval.d.ts +16 -14
  49. package/dist/approval.js +3 -3
  50. package/dist/audit.d.ts +10 -3
  51. package/dist/audit.js +17 -9
  52. package/dist/auth-bridge.d.ts +0 -14
  53. package/dist/auth-bridge.js +0 -7
  54. package/dist/auto-mode-face.d.ts +10 -7
  55. package/dist/auto-mode-face.js +7 -4
  56. package/dist/background-agent-name.d.ts +19 -1
  57. package/dist/background-agent-name.js +12 -2
  58. package/dist/background-session-reap.d.ts +1 -1
  59. package/dist/bake-runner/main.js +9 -6
  60. package/dist/bench/s1/arms.js +6 -5
  61. package/dist/bench/s1/live-deps.js +8 -3
  62. package/dist/bench/s1/run-firm.js +6 -5
  63. package/dist/bind-host.d.ts +25 -0
  64. package/dist/bind-host.js +25 -0
  65. package/dist/boot/adoption.d.ts +3 -0
  66. package/dist/boot/adoption.js +1 -0
  67. package/dist/boot/crash-last.js +2 -1
  68. package/dist/boot/deployment-mods.d.ts +1 -1
  69. package/dist/boot/device-lane.js +5 -5
  70. package/dist/boot/engine-lease.d.ts +12 -11
  71. package/dist/boot/execution-env.d.ts +19 -8
  72. package/dist/boot/execution-env.js +80 -62
  73. package/dist/boot/execution-lane.d.ts +37 -9
  74. package/dist/boot/execution-lane.js +74 -20
  75. package/dist/boot/exit-boundary.d.ts +3 -3
  76. package/dist/boot/exit-boundary.js +6 -5
  77. package/dist/boot/exit-last.js +2 -1
  78. package/dist/boot/fatal-exit.d.ts +3 -5
  79. package/dist/boot/fatal-exit.js +2 -2
  80. package/dist/boot/governance-seams.d.ts +2 -2
  81. package/dist/boot/leader.d.ts +15 -0
  82. package/dist/boot/leader.js +18 -16
  83. package/dist/boot/memory-boundary.d.ts +11 -11
  84. package/dist/boot/memory-boundary.js +3 -3
  85. package/dist/boot/memory-consolidation.d.ts +50 -53
  86. package/dist/boot/memory-consolidation.js +11 -18
  87. package/dist/boot/org-memory.js +4 -3
  88. package/dist/boot/parked-revive-gate.d.ts +1 -1
  89. package/dist/boot/parked-revive-gate.js +3 -3
  90. package/dist/boot/reapers.d.ts +4 -3
  91. package/dist/boot/reapers.js +20 -17
  92. package/dist/boot/resolve-spec.d.ts +5 -3
  93. package/dist/boot/resolve-spec.js +133 -165
  94. package/dist/boot/retention-lane.d.ts +7 -45
  95. package/dist/boot/retention-lane.js +2 -2
  96. package/dist/boot/runner-deps.d.ts +28 -7
  97. package/dist/boot/runner-deps.js +11 -4
  98. package/dist/boot/runtime-caps.d.ts +2 -2
  99. package/dist/boot/runtime-caps.js +16 -2
  100. package/dist/boot/session-faces.d.ts +17 -7
  101. package/dist/boot/session-faces.js +122 -96
  102. package/dist/boot/shutdown.d.ts +5 -4
  103. package/dist/boot/shutdown.js +6 -4
  104. package/dist/boot/stage-01-config.d.ts +1 -1
  105. package/dist/boot/stage-01-config.js +14 -2
  106. package/dist/boot/stage-02-web-admin-pull.d.ts +2 -1
  107. package/dist/boot/stage-02-web-admin-pull.js +15 -8
  108. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  109. package/dist/boot/stage-03-store-backend.js +4 -3
  110. package/dist/boot/stage-04-stores.d.ts +3 -1
  111. package/dist/boot/stage-04-stores.js +2 -2
  112. package/dist/boot/stage-05-execution-env.d.ts +9 -5
  113. package/dist/boot/stage-05-execution-env.js +5 -5
  114. package/dist/boot/stage-06-runners.d.ts +13 -15
  115. package/dist/boot/stage-06-runners.js +24 -18
  116. package/dist/boot/stage-07-capability-layer.d.ts +14 -11
  117. package/dist/boot/stage-07-capability-layer.js +9 -12
  118. package/dist/boot/stage-08-reapers.d.ts +14 -11
  119. package/dist/boot/stage-08-reapers.js +3 -3
  120. package/dist/boot/stage-09-leader.d.ts +16 -18
  121. package/dist/boot/stage-09-leader.js +12 -4
  122. package/dist/boot/stage-10-http-server.d.ts +16 -18
  123. package/dist/boot/stage-10-http-server.js +9 -5
  124. package/dist/boot/store-evidence.d.ts +20 -0
  125. package/dist/boot/store-evidence.js +13 -0
  126. package/dist/boot/stores.d.ts +12 -0
  127. package/dist/boot/stores.js +39 -17
  128. package/dist/boot/task-list-lane.d.ts +4 -4
  129. package/dist/boot/web-admin.d.ts +4 -2
  130. package/dist/boot/web-admin.js +58 -38
  131. package/dist/boot/webfetch-summarize-lane.d.ts +1 -1
  132. package/dist/boot-reclaim.d.ts +3 -1
  133. package/dist/boot-reclaim.js +1 -1
  134. package/dist/brain.d.ts +7 -18
  135. package/dist/brain.js +5 -17
  136. package/dist/budget.js +6 -6
  137. package/dist/capabilities/center-plugins.d.ts +9 -1
  138. package/dist/capabilities/center-plugins.js +37 -11
  139. package/dist/capabilities/center-wiring.js +1 -1
  140. package/dist/capabilities/composite-members.d.ts +3 -2
  141. package/dist/capabilities/composite-members.js +3 -2
  142. package/dist/capabilities/execution-lane.d.ts +7 -7
  143. package/dist/capabilities/execution-lane.js +2 -2
  144. package/dist/capabilities/hands-lane.d.ts +1 -1
  145. package/dist/capabilities/repo-tools.d.ts +2 -0
  146. package/dist/capabilities/repo-tools.js +14 -12
  147. package/dist/capabilities/scenarios.d.ts +38 -33
  148. package/dist/capabilities/scenarios.js +24 -25
  149. package/dist/capabilities/settings-contract.d.ts +29 -0
  150. package/dist/capabilities/settings-contract.js +14 -0
  151. package/dist/capabilities/skills.d.ts +6 -6
  152. package/dist/capabilities/tool-defer.d.ts +1 -1
  153. package/dist/capability-facts.d.ts +69 -4
  154. package/dist/capability-facts.js +77 -5
  155. package/dist/card-void.d.ts +4 -4
  156. package/dist/card-void.js +1 -1
  157. package/dist/center-credential-renewer.d.ts +6 -2
  158. package/dist/center-credential-renewer.js +10 -5
  159. package/dist/config-catalog.d.ts +16 -1
  160. package/dist/config-catalog.js +68 -61
  161. package/dist/config-dir-trust.d.ts +37 -4
  162. package/dist/config-dir-trust.js +88 -44
  163. package/dist/config-invariants.d.ts +58 -4
  164. package/dist/config-invariants.js +104 -23
  165. package/dist/config-lkg.d.ts +24 -2
  166. package/dist/config-lkg.js +22 -9
  167. package/dist/config-provider.d.ts +9 -9
  168. package/dist/config-provider.js +25 -108
  169. package/dist/config-pull-failure.d.ts +50 -0
  170. package/dist/config-pull-failure.js +48 -0
  171. package/dist/config-types.d.ts +215 -202
  172. package/dist/config.d.ts +69 -14
  173. package/dist/config.js +188 -96
  174. package/dist/degenerate-instrument.js +1 -1
  175. package/dist/delegated-session-owner.d.ts +1 -1
  176. package/dist/deleted-session-ids.d.ts +3 -2
  177. package/dist/deploy-facts.js +3 -2
  178. package/dist/deployment-governance.d.ts +3 -3
  179. package/dist/deployment-shape.d.ts +51 -16
  180. package/dist/deployment-shape.js +31 -6
  181. package/dist/egress-redirect.d.ts +25 -7
  182. package/dist/egress-redirect.js +20 -2
  183. package/dist/elicitation.d.ts +6 -5
  184. package/dist/elicitation.js +23 -22
  185. package/dist/engine-identity.d.ts +28 -0
  186. package/dist/engine-identity.js +10 -0
  187. package/dist/entry-problems.d.ts +5 -7
  188. package/dist/entry-problems.js +1 -1
  189. package/dist/env-facts.d.ts +7 -5
  190. package/dist/env-facts.js +12 -7
  191. package/dist/env-witness.d.ts +7 -0
  192. package/dist/env-witness.js +16 -0
  193. package/dist/execution-config-root.d.ts +5 -5
  194. package/dist/execution-config-root.js +5 -5
  195. package/dist/execution-env-purpose.d.ts +14 -0
  196. package/dist/execution-env-purpose.js +29 -0
  197. package/dist/execution-lane-caps.d.ts +53 -103
  198. package/dist/execution-lane-caps.js +51 -83
  199. package/dist/execution-placement.d.ts +65 -9
  200. package/dist/execution-placement.js +58 -0
  201. package/dist/field-conflict.d.ts +7 -11
  202. package/dist/field-conflict.js +3 -3
  203. package/dist/file-history-capture.d.ts +3 -3
  204. package/dist/file-history-disclosure.d.ts +2 -2
  205. package/dist/file-history-disclosure.js +1 -0
  206. package/dist/fleet/drain-entry.d.ts +17 -10
  207. package/dist/fleet/drain-entry.js +1 -1
  208. package/dist/fleet/fleet-bus.d.ts +21 -3
  209. package/dist/fleet/fleet-bus.js +35 -25
  210. package/dist/fleet/fleet-reconciler.js +2 -2
  211. package/dist/fleet/serving-lease.js +6 -7
  212. package/dist/fleet-client.js +3 -3
  213. package/dist/fleet-lease.d.ts +0 -1
  214. package/dist/fleet-lease.js +4 -5
  215. package/dist/history-anchor.d.ts +42 -0
  216. package/dist/history-anchor.js +34 -0
  217. package/dist/hitl-delivery.d.ts +90 -0
  218. package/dist/hitl-delivery.js +98 -0
  219. package/dist/hooks/classic-stations.d.ts +8 -11
  220. package/dist/hooks/classic-stations.js +0 -7
  221. package/dist/hooks/command-spawn.d.ts +1 -4
  222. package/dist/hooks/command-spawn.js +0 -11
  223. package/dist/hooks/hook-llm.d.ts +5 -1
  224. package/dist/hooks/hook-llm.js +24 -15
  225. package/dist/hooks/hook-runner.d.ts +119 -65
  226. package/dist/hooks/hook-runner.js +415 -217
  227. package/dist/host-lsp-manager.d.ts +22 -8
  228. package/dist/host-lsp-manager.js +4 -1
  229. package/dist/http/active-run-conflict.d.ts +2 -43
  230. package/dist/http/active-run-conflict.js +3 -7
  231. package/dist/http/admission.d.ts +4 -18
  232. package/dist/http/admission.js +75 -78
  233. package/dist/http/approval-sweeps.d.ts +5 -8
  234. package/dist/http/approval-sweeps.js +55 -30
  235. package/dist/http/caller-trust.d.ts +8 -10
  236. package/dist/http/caller-trust.js +1 -2
  237. package/dist/http/checkpoint-ctx.d.ts +17 -0
  238. package/dist/http/checkpoint-ctx.js +6 -0
  239. package/dist/http/claim-heartbeat.d.ts +49 -0
  240. package/dist/http/claim-heartbeat.js +46 -0
  241. package/dist/http/claim-latency.d.ts +10 -0
  242. package/dist/http/claim-latency.js +12 -0
  243. package/dist/http/claimed-run.d.ts +4 -3
  244. package/dist/http/dispatch.d.ts +8 -1
  245. package/dist/http/dispatch.js +77 -31
  246. package/dist/http/durable-run-leg.d.ts +3 -3
  247. package/dist/http/durable-run-leg.js +18 -12
  248. package/dist/http/execution-context.d.ts +18 -42
  249. package/dist/http/execution-context.js +11 -5
  250. package/dist/http/health-reader.d.ts +36 -0
  251. package/dist/http/health-reader.js +21 -0
  252. package/dist/http/health-self-report.d.ts +9 -9
  253. package/dist/http/health-self-report.js +4 -4
  254. package/dist/http/idempotency.d.ts +9 -5
  255. package/dist/http/idempotency.js +4 -4
  256. package/dist/http/memory-compliance-failure-reply.d.ts +15 -16
  257. package/dist/http/memory-compliance-failure-reply.js +7 -2
  258. package/dist/http/memory-face-fault-reply.d.ts +67 -0
  259. package/dist/http/memory-face-fault-reply.js +71 -0
  260. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  261. package/dist/http/memory-store-refusal-reply.js +6 -0
  262. package/dist/http/owner-access.d.ts +391 -56
  263. package/dist/http/owner-access.js +372 -33
  264. package/dist/http/principal-gate.d.ts +26 -94
  265. package/dist/http/principal-gate.js +24 -81
  266. package/dist/http/refusal-body.d.ts +35 -2
  267. package/dist/http/refusal-body.js +34 -0
  268. package/dist/http/request-guards.d.ts +10 -14
  269. package/dist/http/request-guards.js +34 -68
  270. package/dist/http/resume-composition.d.ts +37 -0
  271. package/dist/http/resume-composition.js +18 -0
  272. package/dist/http/resume-ctx-read.d.ts +35 -12
  273. package/dist/http/resume-ctx-read.js +25 -6
  274. package/dist/http/resume-legs.d.ts +24 -24
  275. package/dist/http/resume-legs.js +260 -171
  276. package/dist/http/retired-skill-manifest.d.ts +1 -1
  277. package/dist/http/rewind-files-reply.d.ts +34 -0
  278. package/dist/http/rewind-files-reply.js +36 -0
  279. package/dist/http/route-ctx.d.ts +56 -47
  280. package/dist/http/route-table.js +2 -0
  281. package/dist/http/routes/a2a-serve.d.ts +43 -5
  282. package/dist/http/routes/a2a-serve.js +58 -37
  283. package/dist/http/routes/admin-config-refresh.js +2 -2
  284. package/dist/http/routes/admin-drain.js +2 -2
  285. package/dist/http/routes/admin-memory-optout.js +4 -3
  286. package/dist/http/routes/adoption.d.ts +3 -0
  287. package/dist/http/routes/adoption.js +17 -10
  288. package/dist/http/routes/agents-roster.js +13 -7
  289. package/dist/http/routes/approvals-assistant.js +73 -88
  290. package/dist/http/routes/attachments.js +2 -2
  291. package/dist/http/routes/background.d.ts +3 -3
  292. package/dist/http/routes/background.js +9 -17
  293. package/dist/http/routes/capabilities.js +23 -20
  294. package/dist/http/routes/config-catalog.js +2 -2
  295. package/dist/http/routes/devices.d.ts +3 -3
  296. package/dist/http/routes/devices.js +5 -5
  297. package/dist/http/routes/diagnostics.d.ts +27 -3
  298. package/dist/http/routes/diagnostics.js +27 -21
  299. package/dist/http/routes/engine.js +2 -2
  300. package/dist/http/routes/fleet.js +5 -3
  301. package/dist/http/routes/images.js +10 -6
  302. package/dist/http/routes/leader.d.ts +7 -2
  303. package/dist/http/routes/leader.js +12 -3
  304. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  305. package/dist/http/routes/mcp-reconnect.js +7 -15
  306. package/dist/http/routes/memory-bundle.js +4 -7
  307. package/dist/http/routes/memory-compliance.js +4 -4
  308. package/dist/http/routes/memory-consolidation.js +6 -9
  309. package/dist/http/routes/memory-origin.d.ts +3 -1
  310. package/dist/http/routes/memory-origin.js +7 -8
  311. package/dist/http/routes/memory-policy.js +17 -12
  312. package/dist/http/routes/notify-wake.js +12 -20
  313. package/dist/http/routes/observability.js +3 -3
  314. package/dist/http/routes/principal-inbox.d.ts +1 -1
  315. package/dist/http/routes/principal-inbox.js +2 -2
  316. package/dist/http/routes/projects.d.ts +70 -0
  317. package/dist/http/routes/projects.js +87 -0
  318. package/dist/http/routes/retention-ops.js +6 -9
  319. package/dist/http/routes/rules.js +50 -7
  320. package/dist/http/routes/run-memory-capture.d.ts +2 -2
  321. package/dist/http/routes/run-memory-capture.js +6 -12
  322. package/dist/http/routes/run-permission-mode.d.ts +2 -2
  323. package/dist/http/routes/run-permission-mode.js +10 -17
  324. package/dist/http/routes/runs.js +148 -233
  325. package/dist/http/routes/session-memory-sync.d.ts +2 -2
  326. package/dist/http/routes/session-memory-sync.js +7 -13
  327. package/dist/http/routes/session-sync.d.ts +4 -2
  328. package/dist/http/routes/session-sync.js +48 -30
  329. package/dist/http/routes/sessions-list.d.ts +3 -3
  330. package/dist/http/routes/sessions-list.js +9 -9
  331. package/dist/http/routes/sessions.d.ts +7 -1
  332. package/dist/http/routes/sessions.js +177 -112
  333. package/dist/http/routes/shared-memory.js +6 -6
  334. package/dist/http/routes/side-query.js +2 -2
  335. package/dist/http/routes/tasks.js +144 -122
  336. package/dist/http/routes/trace-usage.d.ts +0 -12
  337. package/dist/http/routes/trace-usage.js +40 -46
  338. package/dist/http/routes/workflows.d.ts +39 -4
  339. package/dist/http/routes/workflows.js +42 -14
  340. package/dist/http/run-concurrency-cap.d.ts +20 -12
  341. package/dist/http/run-concurrency-cap.js +39 -26
  342. package/dist/http/run-read-face.d.ts +3 -5
  343. package/dist/http/run-read-face.js +8 -13
  344. package/dist/http/send.d.ts +12 -3
  345. package/dist/http/send.js +42 -6
  346. package/dist/http/server.d.ts +63 -50
  347. package/dist/http/server.js +52 -16
  348. package/dist/http/sse-log.d.ts +17 -10
  349. package/dist/http/sse-log.js +7 -7
  350. package/dist/http/stored-body-replay.d.ts +17 -3
  351. package/dist/http/stored-body-replay.js +11 -2
  352. package/dist/http/submit-ctx.d.ts +16 -8
  353. package/dist/http/submit-ctx.js +6 -2
  354. package/dist/http/submit-replay.d.ts +19 -6
  355. package/dist/http/submit-replay.js +18 -6
  356. package/dist/http/sync-submit-body.d.ts +3 -4
  357. package/dist/http/sync-submit-body.js +4 -5
  358. package/dist/http/wire-types.d.ts +23 -13
  359. package/dist/identity-source.d.ts +36 -5
  360. package/dist/identity-source.js +27 -0
  361. package/dist/index.d.ts +3 -2
  362. package/dist/index.js +2 -1
  363. package/dist/instruction-source-notice.d.ts +1 -1
  364. package/dist/key-resolver.d.ts +32 -0
  365. package/dist/key-resolver.js +23 -9
  366. package/dist/leader/diffup.js +2 -1
  367. package/dist/leader/endpoint.d.ts +26 -5
  368. package/dist/leader/endpoint.js +154 -14
  369. package/dist/leader/fanout.d.ts +3 -0
  370. package/dist/leader/fanout.js +78 -63
  371. package/dist/leader/leader.d.ts +16 -0
  372. package/dist/leader/leader.js +43 -3
  373. package/dist/leader/merge.d.ts +9 -1
  374. package/dist/leader/merge.js +16 -1
  375. package/dist/leader/repair-wire.js +1 -1
  376. package/dist/leader/wire.d.ts +36 -3
  377. package/dist/leader/wire.js +59 -18
  378. package/dist/lsp-evict.d.ts +6 -4
  379. package/dist/lsp-evict.js +2 -3
  380. package/dist/memory-embedder-reembed.d.ts +38 -0
  381. package/dist/memory-embedder-reembed.js +20 -0
  382. package/dist/memory-incident-sink.d.ts +0 -28
  383. package/dist/memory-incident-sink.js +5 -0
  384. package/dist/memory-operator-faces.d.ts +5 -4
  385. package/dist/memory-operator-faces.js +1 -1
  386. package/dist/memory-scope.d.ts +31 -4
  387. package/dist/memory-scope.js +65 -16
  388. package/dist/memory-store-refusal.d.ts +20 -4
  389. package/dist/memory-store-refusal.js +1 -1
  390. package/dist/memory-sync-client.d.ts +5 -2
  391. package/dist/memory-sync-client.js +19 -14
  392. package/dist/memory-sync.js +1 -1
  393. package/dist/model-compat.d.ts +51 -28
  394. package/dist/model-compat.js +55 -23
  395. package/dist/model-context-window.d.ts +18 -0
  396. package/dist/model-context-window.js +2 -0
  397. package/dist/model-entry-headers.d.ts +46 -4
  398. package/dist/model-entry-headers.js +2 -2
  399. package/dist/model-entry-refusal.d.ts +46 -17
  400. package/dist/model-entry-refusal.js +47 -27
  401. package/dist/model-plane-face.d.ts +19 -11
  402. package/dist/model-plane-face.js +9 -1
  403. package/dist/model-plane-probe.d.ts +2 -0
  404. package/dist/model-plane-probe.js +17 -0
  405. package/dist/model-provider.d.ts +3 -3
  406. package/dist/model-route-endpoint.d.ts +9 -5
  407. package/dist/model-route-endpoint.js +29 -7
  408. package/dist/model-select.d.ts +16 -0
  409. package/dist/model-select.js +4 -0
  410. package/dist/mountinfo.d.ts +37 -0
  411. package/dist/mountinfo.js +47 -0
  412. package/dist/namespaced-rule-name.d.ts +28 -2
  413. package/dist/namespaced-rule-name.js +10 -1
  414. package/dist/net-address.d.ts +1 -1
  415. package/dist/observability/corrupt-read-seat.d.ts +4 -4
  416. package/dist/observability/corrupt-read-seat.js +5 -3
  417. package/dist/observability/fail-open.d.ts +75 -47
  418. package/dist/observability/fail-open.js +77 -47
  419. package/dist/observability/logger.d.ts +22 -1
  420. package/dist/observability/logger.js +89 -12
  421. package/dist/observability/metrics.d.ts +2 -0
  422. package/dist/observability/metrics.js +5 -4
  423. package/dist/observability/otel-exporter.js +2 -1
  424. package/dist/observability/principal-context.d.ts +14 -7
  425. package/dist/observability/principal-context.js +8 -3
  426. package/dist/observability/run-terminal.d.ts +7 -1
  427. package/dist/observability/run-terminal.js +5 -2
  428. package/dist/observability/secret-env-scrub.d.ts +30 -4
  429. package/dist/observability/secret-env-scrub.js +15 -3
  430. package/dist/orchestration/hardened-vm-runner.d.ts +1 -0
  431. package/dist/orchestration/hardened-vm-runner.js +11 -5
  432. package/dist/orchestration/hardened-vm-worker-runner.d.ts +0 -14
  433. package/dist/orchestration/hardened-vm-worker-runner.js +5 -0
  434. package/dist/orchestration/hardened-vm-worker.js +2 -1
  435. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  436. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  437. package/dist/orchestration/workflow-completion-inbox.d.ts +29 -9
  438. package/dist/orchestration/workflow-completion-inbox.js +65 -46
  439. package/dist/org-delivery-gate.d.ts +5 -4
  440. package/dist/org-delivery-gate.js +7 -6
  441. package/dist/org-memory-admission.d.ts +5 -2
  442. package/dist/org-memory-admission.js +25 -10
  443. package/dist/outbound-dispatcher.d.ts +1 -1
  444. package/dist/outbound-dispatcher.js +6 -12
  445. package/dist/owner-brands.d.ts +81 -0
  446. package/dist/owner-brands.js +42 -0
  447. package/dist/owner-faces.d.ts +531 -0
  448. package/dist/owner-faces.js +126 -0
  449. package/dist/parked-decide.d.ts +100 -31
  450. package/dist/parked-decide.js +162 -48
  451. package/dist/parked-revive-surface.d.ts +14 -4
  452. package/dist/parked-revive-surface.js +5 -4
  453. package/dist/peer-directory.d.ts +6 -8
  454. package/dist/peer-directory.js +3 -2
  455. package/dist/permission-rule-vocab.d.ts +53 -8
  456. package/dist/permission-rule-vocab.js +30 -2
  457. package/dist/plugins/adoption-log-sql.d.ts +0 -22
  458. package/dist/plugins/adoption-log-sql.js +5 -3
  459. package/dist/plugins/approval-ask-retired-delete-by-task-m50.d.ts +7 -0
  460. package/dist/plugins/approval-ask-retired-delete-by-task-m50.js +17 -0
  461. package/dist/plugins/approval-ask-store-file.d.ts +28 -9
  462. package/dist/plugins/approval-ask-store-file.js +74 -18
  463. package/dist/plugins/approval-ask-store-memory.d.ts +17 -7
  464. package/dist/plugins/approval-ask-store-memory.js +35 -12
  465. package/dist/plugins/approval-ask-store-sql.d.ts +42 -20
  466. package/dist/plugins/approval-ask-store-sql.js +44 -11
  467. package/dist/plugins/approval-exemption-skill-m46.d.ts +20 -0
  468. package/dist/plugins/approval-exemption-skill-m46.js +25 -0
  469. package/dist/plugins/approval-exemption-store.d.ts +6 -1
  470. package/dist/plugins/approval-exemption-store.js +14 -0
  471. package/dist/plugins/approval-nonce-store.d.ts +39 -12
  472. package/dist/plugins/approval-nonce-store.js +72 -23
  473. package/dist/plugins/blob-backend.d.ts +40 -195
  474. package/dist/plugins/blob-backend.js +41 -234
  475. package/dist/plugins/caching-session-store.d.ts +22 -5
  476. package/dist/plugins/caching-session-store.js +43 -4
  477. package/dist/plugins/checkpoint-index-columns.d.ts +33 -6
  478. package/dist/plugins/checkpoint-index-columns.js +39 -3
  479. package/dist/plugins/checkpoint-store-face.d.ts +84 -11
  480. package/dist/plugins/checkpoint-store-face.js +18 -1
  481. package/dist/plugins/device-store-sql.d.ts +2 -2
  482. package/dist/plugins/device-store-sql.js +6 -10
  483. package/dist/plugins/ensure-index.d.ts +13 -1
  484. package/dist/plugins/ensure-index.js +154 -21
  485. package/dist/plugins/ensure-schema-lock-policy.d.ts +0 -15
  486. package/dist/plugins/ensure-schema-lock-policy.js +3 -2
  487. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  488. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  489. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  490. package/dist/plugins/execution-placement-sql.js +94 -54
  491. package/dist/plugins/file-run-store.d.ts +89 -35
  492. package/dist/plugins/file-run-store.js +197 -142
  493. package/dist/plugins/host-platform.d.ts +24 -3
  494. package/dist/plugins/host-platform.js +15 -1
  495. package/dist/plugins/image-bake-store-sql.js +2 -0
  496. package/dist/plugins/imported-layer-root-retirement.d.ts +19 -10
  497. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  498. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  499. package/dist/plugins/inbox-payload-column.js +13 -0
  500. package/dist/plugins/k8s-pod-reaper.d.ts +1 -3
  501. package/dist/plugins/k8s-pod-reaper.js +0 -1
  502. package/dist/plugins/leader-run-store-sql.d.ts +22 -0
  503. package/dist/plugins/leader-run-store-sql.js +34 -4
  504. package/dist/plugins/local-checkpoint-store.d.ts +63 -23
  505. package/dist/plugins/local-checkpoint-store.js +204 -81
  506. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  507. package/dist/plugins/local-data-dir-modes-m39.js +183 -0
  508. package/dist/plugins/local-docker-capacity.d.ts +93 -0
  509. package/dist/plugins/local-docker-capacity.js +194 -0
  510. package/dist/plugins/local-docker-reaper.d.ts +92 -0
  511. package/dist/plugins/local-docker-reaper.js +102 -0
  512. package/dist/plugins/local-engine-high-water.d.ts +13 -0
  513. package/dist/plugins/local-engine-high-water.js +62 -0
  514. package/dist/plugins/local-session-store.d.ts +442 -143
  515. package/dist/plugins/local-session-store.js +941 -289
  516. package/dist/plugins/local-session-window.d.ts +3 -2
  517. package/dist/plugins/local-session-window.js +3 -2
  518. package/dist/plugins/local-sidecar-quarantine.js +3 -2
  519. package/dist/plugins/local-task-attachment-store.d.ts +20 -1
  520. package/dist/plugins/local-task-attachment-store.js +32 -12
  521. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  522. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  523. package/dist/plugins/memory-embedder.d.ts +1 -1
  524. package/dist/plugins/memory-embedder.js +11 -9
  525. package/dist/plugins/memory-engine-pg.d.ts +7 -5
  526. package/dist/plugins/memory-engine-pg.js +18 -9
  527. package/dist/plugins/memory-engine-sql-apply.d.ts +21 -8
  528. package/dist/plugins/memory-engine-sql-apply.js +7 -9
  529. package/dist/plugins/memory-engine-tidb.d.ts +12 -7
  530. package/dist/plugins/memory-engine-tidb.js +18 -10
  531. package/dist/plugins/memory-optout-grant-store-sql.d.ts +1 -1
  532. package/dist/plugins/memory-optout-grant-store-sql.js +3 -3
  533. package/dist/plugins/memory-run-store.d.ts +39 -27
  534. package/dist/plugins/memory-run-store.js +72 -70
  535. package/dist/plugins/one-time-migration-marker.d.ts +10 -0
  536. package/dist/plugins/one-time-migration-marker.js +7 -0
  537. package/dist/plugins/one-time-migrations.d.ts +325 -74
  538. package/dist/plugins/one-time-migrations.js +705 -230
  539. package/dist/plugins/org-delivery-quota-store.js +2 -1
  540. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  541. package/dist/plugins/owner-only-file-mode.js +141 -0
  542. package/dist/plugins/permission-rule-store-file.d.ts +11 -11
  543. package/dist/plugins/permission-rule-store-file.js +14 -2
  544. package/dist/plugins/permission-rule-store-sql.d.ts +4 -63
  545. package/dist/plugins/permission-rule-store-sql.js +6 -86
  546. package/dist/plugins/pg-pool.d.ts +3 -32
  547. package/dist/plugins/pg-pool.js +27 -11
  548. package/dist/plugins/release-version.d.ts +20 -0
  549. package/dist/plugins/release-version.js +28 -0
  550. package/dist/plugins/remote-env-adb.d.ts +20 -4
  551. package/dist/plugins/remote-env-adb.js +39 -11
  552. package/dist/plugins/remote-env-e2b.d.ts +19 -28
  553. package/dist/plugins/remote-env-e2b.js +40 -29
  554. package/dist/plugins/remote-env-host.d.ts +11 -10
  555. package/dist/plugins/remote-env-host.js +40 -27
  556. package/dist/plugins/remote-env-k8s.d.ts +45 -47
  557. package/dist/plugins/remote-env-k8s.js +122 -62
  558. package/dist/plugins/remote-env-local-docker.d.ts +152 -15
  559. package/dist/plugins/remote-env-local-docker.js +370 -75
  560. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  561. package/dist/plugins/remote-env-ssh.js +26 -24
  562. package/dist/plugins/remote-scratchpad.js +4 -0
  563. package/dist/plugins/remote-shell.d.ts +59 -30
  564. package/dist/plugins/remote-shell.js +175 -62
  565. package/dist/plugins/retention-declaration.d.ts +37 -0
  566. package/dist/plugins/retention-declaration.js +9 -0
  567. package/dist/plugins/retention-deployment.d.ts +158 -0
  568. package/dist/plugins/retention-deployment.js +119 -0
  569. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  570. package/dist/plugins/retention-lane-store-sql.js +103 -1
  571. package/dist/plugins/retention-sql.d.ts +29 -0
  572. package/dist/plugins/retention-sql.js +8 -0
  573. package/dist/plugins/run-preview-m45.d.ts +11 -0
  574. package/dist/plugins/run-preview-m45.js +19 -0
  575. package/dist/plugins/run-store-sql.d.ts +56 -68
  576. package/dist/plugins/run-store-sql.js +127 -116
  577. package/dist/plugins/s3-answer.d.ts +2 -1
  578. package/dist/plugins/sandbox-reaper.d.ts +26 -0
  579. package/dist/plugins/sandbox-reaper.js +2 -0
  580. package/dist/plugins/scenario-prefix-switch-m42.d.ts +54 -0
  581. package/dist/plugins/scenario-prefix-switch-m42.js +55 -0
  582. package/dist/plugins/scheduler-support.d.ts +16 -1
  583. package/dist/plugins/scheduler-support.js +22 -2
  584. package/dist/plugins/schema-consistency.d.ts +42 -15
  585. package/dist/plugins/schema-consistency.js +213 -13
  586. package/dist/plugins/schema-drift-sentence.d.ts +4 -1
  587. package/dist/plugins/schema-drift-sentence.js +4 -4
  588. package/dist/plugins/schema-ensure-legs.d.ts +10 -1
  589. package/dist/plugins/schema-ensure-legs.js +12 -2
  590. package/dist/plugins/schema-indexes.js +3 -0
  591. package/dist/plugins/schema-live-columns.d.ts +14 -5
  592. package/dist/plugins/schema-live-columns.js +10 -10
  593. package/dist/plugins/send-user-file.js +2 -1
  594. package/dist/plugins/session-birth.d.ts +37 -0
  595. package/dist/plugins/session-birth.js +38 -0
  596. package/dist/plugins/session-epoch-anchor.d.ts +40 -12
  597. package/dist/plugins/session-epoch-anchor.js +33 -11
  598. package/dist/plugins/session-ext-table.d.ts +98 -0
  599. package/dist/plugins/session-ext-table.js +134 -0
  600. package/dist/plugins/session-fork.d.ts +16 -2
  601. package/dist/plugins/session-fork.js +3 -0
  602. package/dist/plugins/session-ownership.d.ts +1 -1
  603. package/dist/plugins/session-placement.d.ts +22 -16
  604. package/dist/plugins/session-placement.js +15 -12
  605. package/dist/plugins/session-row-sql.d.ts +20 -7
  606. package/dist/plugins/session-row-sql.js +16 -8
  607. package/dist/plugins/session-run-rollup.d.ts +29 -0
  608. package/dist/plugins/session-run-rollup.js +40 -0
  609. package/dist/plugins/session-store-sql.d.ts +157 -0
  610. package/dist/plugins/session-store-sql.js +398 -0
  611. package/dist/plugins/session-withdraw-sql.d.ts +36 -0
  612. package/dist/plugins/session-withdraw-sql.js +42 -0
  613. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  614. package/dist/plugins/session-workspace-cell.js +2 -2
  615. package/dist/plugins/shared-memory-store-sql.d.ts +10 -69
  616. package/dist/plugins/shared-memory-store-sql.js +15 -14
  617. package/dist/plugins/shell-sentinel-owner-m48.d.ts +20 -0
  618. package/dist/plugins/shell-sentinel-owner-m48.js +3 -0
  619. package/dist/plugins/snapshot-bucket-presence.d.ts +2 -1
  620. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  621. package/dist/plugins/sql-driver.d.ts +24 -8
  622. package/dist/plugins/sql-driver.js +43 -9
  623. package/dist/plugins/sql-errors.d.ts +35 -5
  624. package/dist/plugins/sql-errors.js +55 -3
  625. package/dist/plugins/sql-json-column.d.ts +8 -7
  626. package/dist/plugins/sql-json-column.js +10 -6
  627. package/dist/plugins/store-backend.d.ts +114 -18
  628. package/dist/plugins/store-backend.js +340 -87
  629. package/dist/plugins/store-contracts.d.ts +97 -30
  630. package/dist/plugins/store-contracts.js +23 -1
  631. package/dist/plugins/store-fault.d.ts +28 -2
  632. package/dist/plugins/store-fault.js +20 -2
  633. package/dist/plugins/task-attachment-store.d.ts +21 -11
  634. package/dist/plugins/task-attachment-store.js +37 -19
  635. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  636. package/dist/plugins/text-column-capacity.d.ts +21 -0
  637. package/dist/plugins/text-column-capacity.js +5 -0
  638. package/dist/plugins/tidb-pool.d.ts +3 -2
  639. package/dist/plugins/tidb-pool.js +42 -39
  640. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  641. package/dist/plugins/web-search.js +5 -3
  642. package/dist/plugins/workflow-run-store-sql.d.ts +6 -1
  643. package/dist/plugins/workflow-run-store-sql.js +11 -5
  644. package/dist/principal-jwt.d.ts +4 -4
  645. package/dist/principal-jwt.js +20 -5
  646. package/dist/principal-shape.d.ts +41 -0
  647. package/dist/principal-shape.js +19 -0
  648. package/dist/question.d.ts +13 -23
  649. package/dist/question.js +21 -39
  650. package/dist/read-face-posture.d.ts +6 -6
  651. package/dist/read-face-posture.js +2 -2
  652. package/dist/request-declaration-refusal.d.ts +35 -12
  653. package/dist/request-declaration-refusal.js +21 -9
  654. package/dist/request-form.d.ts +58 -0
  655. package/dist/request-form.js +72 -0
  656. package/dist/request-image-urls.d.ts +8 -2
  657. package/dist/request-image-urls.js +2 -1
  658. package/dist/request-images.d.ts +20 -0
  659. package/dist/request-images.js +59 -0
  660. package/dist/request-key-closure.d.ts +6 -7
  661. package/dist/request-key-closure.js +15 -2
  662. package/dist/request-value-closure.d.ts +5 -5
  663. package/dist/request-value-closure.js +1 -1
  664. package/dist/resource-suspend.d.ts +7 -16
  665. package/dist/resource-suspend.js +1 -1
  666. package/dist/retired-name-host-notice.d.ts +21 -0
  667. package/dist/retired-name-host-notice.js +12 -0
  668. package/dist/rule-entry-list.d.ts +2 -2
  669. package/dist/rule-entry-list.js +3 -4
  670. package/dist/rule-issue-reading.d.ts +58 -0
  671. package/dist/rule-issue-reading.js +14 -0
  672. package/dist/rules-consent.d.ts +46 -16
  673. package/dist/rules-consent.js +102 -53
  674. package/dist/run-acceptance.d.ts +3 -1
  675. package/dist/run-acceptance.js +3 -0
  676. package/dist/run-local.d.ts +14 -6
  677. package/dist/run-local.js +109 -93
  678. package/dist/run-stale-default.d.ts +7 -0
  679. package/dist/run-stale-default.js +2 -0
  680. package/dist/runs.d.ts +73 -44
  681. package/dist/runs.js +65 -43
  682. package/dist/runtime-caps-resolver.d.ts +36 -14
  683. package/dist/runtime-caps-resolver.js +31 -14
  684. package/dist/runtime-governance.d.ts +2 -2
  685. package/dist/runtime-governance.js +5 -3
  686. package/dist/sealed-key-layout.d.ts +12 -6
  687. package/dist/sealed-key-layout.js +5 -1
  688. package/dist/sealed-key.d.ts +12 -2
  689. package/dist/sealed-key.js +116 -26
  690. package/dist/security.d.ts +133 -161
  691. package/dist/security.js +163 -59
  692. package/dist/sema-config-dir.d.ts +20 -0
  693. package/dist/sema-config-dir.js +27 -2
  694. package/dist/server-secret-env.d.ts +23 -5
  695. package/dist/server-secret-env.js +14 -4
  696. package/dist/service-version.d.ts +2 -1
  697. package/dist/service-version.js +2 -2
  698. package/dist/session-children-retire.d.ts +7 -5
  699. package/dist/session-children-retire.js +7 -2
  700. package/dist/session-deletion.d.ts +88 -0
  701. package/dist/session-deletion.js +8 -0
  702. package/dist/session-erase.d.ts +145 -0
  703. package/dist/session-erase.js +115 -0
  704. package/dist/session-error-wire.d.ts +6 -6
  705. package/dist/session-error-wire.js +1 -1
  706. package/dist/session-incarnation.d.ts +60 -10
  707. package/dist/session-incarnation.js +19 -2
  708. package/dist/session-policy-wire.d.ts +6 -3
  709. package/dist/session-policy-wire.js +11 -1
  710. package/dist/session-resident-background.d.ts +29 -47
  711. package/dist/session-resident-background.js +77 -8
  712. package/dist/session-row.d.ts +3 -2
  713. package/dist/session-rules-seat.d.ts +12 -0
  714. package/dist/session-rules-seat.js +19 -0
  715. package/dist/session-sync-kernel.d.ts +1 -1
  716. package/dist/session-titler.d.ts +7 -15
  717. package/dist/session-titler.js +1 -1
  718. package/dist/session-workspace.d.ts +11 -2
  719. package/dist/session-workspace.js +5 -0
  720. package/dist/sighup-idle.d.ts +1 -1
  721. package/dist/spec-fields.d.ts +57 -3
  722. package/dist/spec-fields.js +72 -51
  723. package/dist/store-posture.d.ts +138 -21
  724. package/dist/store-posture.js +188 -3
  725. package/dist/stored-request-hooks-m20.d.ts +3 -2
  726. package/dist/stored-request-hooks-m20.js +21 -16
  727. package/dist/stores-sql/background-agent-store-sql.d.ts +11 -2
  728. package/dist/stores-sql/background-agent-store-sql.js +73 -20
  729. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  730. package/dist/stores-sql/blob-index-sql.js +154 -0
  731. package/dist/stores-sql/checkpoint-store-sql.d.ts +34 -29
  732. package/dist/stores-sql/checkpoint-store-sql.js +86 -71
  733. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  734. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  735. package/dist/stores-sql/mailbox-store-sql.d.ts +7 -4
  736. package/dist/stores-sql/mailbox-store-sql.js +31 -32
  737. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +30 -81
  738. package/dist/{plugins → stores-sql}/pg-session-storage.js +123 -244
  739. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +197 -223
  740. package/dist/{plugins → stores-sql}/retention-store-sql.js +148 -207
  741. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  742. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  743. package/dist/stores-sql/session-policy-store-sql.d.ts +33 -11
  744. package/dist/stores-sql/session-policy-store-sql.js +44 -36
  745. package/dist/stores-sql/session-write-hooks.d.ts +65 -0
  746. package/dist/stores-sql/session-write-hooks.js +2 -0
  747. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +14 -15
  748. package/dist/{plugins → stores-sql}/tidb-session-storage.js +22 -28
  749. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +67 -138
  750. package/dist/{plugins → stores-sql}/tidb-session-store.js +130 -200
  751. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  752. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  753. package/dist/stores-sql/windowed-session-storage.d.ts +61 -0
  754. package/dist/stores-sql/windowed-session-storage.js +70 -0
  755. package/dist/submission-exit.d.ts +50 -0
  756. package/dist/submission-exit.js +108 -0
  757. package/dist/task-a2a.d.ts +7 -1
  758. package/dist/task-a2a.js +18 -17
  759. package/dist/task-cwd.d.ts +31 -3
  760. package/dist/task-cwd.js +25 -1
  761. package/dist/task-mcp.d.ts +11 -3
  762. package/dist/task-mcp.js +16 -19
  763. package/dist/task-settings.d.ts +23 -14
  764. package/dist/task-settings.js +35 -13
  765. package/dist/terminal.d.ts +25 -43
  766. package/dist/terminal.js +31 -11
  767. package/dist/tool-approval.d.ts +152 -137
  768. package/dist/tool-approval.js +199 -199
  769. package/dist/trace/core-keyset-guard.d.ts +22 -9
  770. package/dist/trace/core-vocab-wire.d.ts +95 -0
  771. package/dist/trace/core-vocab-wire.js +15 -0
  772. package/dist/trace/engine-notice-wire.d.ts +1 -1
  773. package/dist/trace/engine-notice-wire.js +2 -0
  774. package/dist/trace/exit-seat.d.ts +52 -4
  775. package/dist/trace/exit-seat.js +43 -36
  776. package/dist/trace/extension-call-face.d.ts +3 -2
  777. package/dist/trace/extension-call-face.js +3 -1
  778. package/dist/trace/ledger-events.d.ts +4 -7
  779. package/dist/trace/ledger-sink.d.ts +1 -30
  780. package/dist/trace/ledger-sink.js +0 -11
  781. package/dist/trace/model-segment.d.ts +5 -5
  782. package/dist/trace/model-segment.js +5 -5
  783. package/dist/trace/project.d.ts +88 -58
  784. package/dist/trace/project.js +64 -28
  785. package/dist/trace/redact.d.ts +124 -28
  786. package/dist/trace/redact.js +936 -328
  787. package/dist/trace/self-minted-wire.d.ts +750 -29
  788. package/dist/trace/self-minted-wire.js +262 -25
  789. package/dist/trace/sema-provenance.d.ts +45 -41
  790. package/dist/trace/sema-provenance.js +81 -10
  791. package/dist/trace/task-notification-facets.d.ts +70 -2
  792. package/dist/trace/task-notification-facets.js +71 -1
  793. package/dist/trace/wire-projection-faces.d.ts +43 -8
  794. package/dist/trace/wire-projection-faces.js +28 -3
  795. package/dist/unread-request-members.d.ts +66 -0
  796. package/dist/unread-request-members.js +41 -0
  797. package/dist/upstream-body.d.ts +23 -0
  798. package/dist/upstream-body.js +16 -0
  799. package/dist/url-refusal.d.ts +3 -3
  800. package/dist/url-refusal.js +11 -4
  801. package/dist/user-authored-text.d.ts +1 -1
  802. package/dist/user-input-ledger.d.ts +7 -8
  803. package/dist/user-input-ledger.js +1 -1
  804. package/dist/web-admin-client/apply-effective.d.ts +6 -3
  805. package/dist/web-admin-client/apply-effective.js +33 -40
  806. package/dist/web-admin-client/apply-ledger.d.ts +16 -7
  807. package/dist/web-admin-client/apply-ledger.js +5 -2
  808. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  809. package/dist/web-admin-client/candidate-gate.js +53 -5
  810. package/dist/web-admin-client/center-request.d.ts +6 -3
  811. package/dist/web-admin-client/center-request.js +17 -16
  812. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  813. package/dist/web-admin-client/effective-keys.js +1 -2
  814. package/dist/web-admin-client/entry-metadata.d.ts +8 -0
  815. package/dist/web-admin-client/entry-metadata.js +13 -0
  816. package/dist/web-admin-client/facade.d.ts +1 -1
  817. package/dist/web-admin-client/http-client.d.ts +2 -1
  818. package/dist/web-admin-client/http-client.js +40 -13
  819. package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
  820. package/dist/web-admin-client/mcp-revocation.js +2 -1
  821. package/dist/web-admin-client/read-warnings.d.ts +1 -0
  822. package/dist/web-admin-client/read-warnings.js +1 -0
  823. package/dist/web-admin-client/restart-signal.js +13 -6
  824. package/dist/web-admin-client/skills-mcp.d.ts +22 -8
  825. package/dist/web-admin-client/skills-mcp.js +26 -21
  826. package/dist/web-admin-client/types.d.ts +35 -51
  827. package/dist/workspace-space.d.ts +3 -2
  828. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +4 -4
  829. package/package.json +16 -12
  830. package/scripts/drain-check-local.mjs +118 -173
  831. package/scripts/drain-check.mysql.sql +20 -16
  832. package/scripts/drain-check.pg.sql +20 -16
  833. package/wire-changes/server@7.147.0.json +813 -0
  834. package/wire-changes/server@7.148.0.json +1517 -0
  835. package/dist/http/memory-control-plane-corrupt-reply.d.ts +0 -25
  836. package/dist/http/memory-control-plane-corrupt-reply.js +0 -19
  837. package/dist/http/memory-layer-reply.d.ts +0 -30
  838. package/dist/http/memory-layer-reply.js +0 -24
  839. package/dist/lsp/e2b-bridge.d.ts +0 -57
  840. package/dist/lsp/e2b-bridge.js +0 -139
  841. package/dist/lsp/e2b-manager.d.ts +0 -93
  842. package/dist/lsp/e2b-manager.js +0 -178
  843. package/dist/lsp/lsp-frames.d.ts +0 -14
  844. package/dist/lsp/lsp-frames.js +0 -25
  845. package/dist/lsp/manager.d.ts +0 -129
  846. package/dist/lsp/manager.js +0 -127
  847. package/dist/lsp/types.d.ts +0 -12
  848. package/dist/lsp/types.js +0 -2
  849. package/dist/lsp/ws-transport.d.ts +0 -40
  850. package/dist/lsp/ws-transport.js +0 -210
@@ -1,26 +1,28 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { composeHostSubprocessEnv, hostSubprocessEnv } from "../server-secret-env.js";
3
3
  import vm from "node:vm";
4
- import { hostShell, resolveHostShell, adoptHostForegroundChild, killTreeSoft, killTreeHard } from "../plugins/host-platform.js";
4
+ import { hostShell, resolveHostShell, adoptHostForegroundChild, killTreeSoft, killTreeHard, signalProcessTree, reapedLeaderGroupAlive } from "../plugins/host-platform.js";
5
5
  import { classifyHooksConfig, DEFAULT_HOOK_TIMEOUT_SECONDS, HOOK_ENTRY_TYPES, HOOK_EVENTS, HOOK_EVENT_OWNER, HOOK_EVENT_MATCHER_FIELD, hookMatcherForm, hookMatcherSelects, interpolateHookEnvVars, } from "@sema-agent/settings-schema/hooks";
6
- import { findUrlCredential, formatConfigPath, outgoingPath } from "@sema-agent/settings-schema";
6
+ import { findUrlCredential, outgoingPath } from "@sema-agent/settings-schema";
7
7
  import { httpHookEnvVarsAllowed, httpHookUrlVerdict } from "@sema-agent/settings-schema";
8
8
  import { ENGINE_OWNED_HOOK_EVENTS } from "@sema-agent/settings-schema/hooks";
9
9
  import { describeToolCatalog } from "@sema-agent/core";
10
- import { hangClassic, wrapClassic } from "./classic-stations.js";
10
+ import { hangClassic } from "./classic-stations.js";
11
11
  import { MAX_HOOK_NOTICE_TEXT_CHARS, boundedNoticeText } from "../fleet/fleet-bus.js";
12
12
  import { recordFailOpen } from "../observability/fail-open.js";
13
- import { LIMIT_REASONS } from "../limit-refusal.js";
13
+ import { LIMIT_REASONS, limitFacts } from "../limit-refusal.js";
14
+ import { fieldCoordinate } from "../http/refusal-body.js";
14
15
  import { clipDataText, echoCallerText } from "../caller-text-echo.js";
15
16
  import { seatText } from "../trace/exit-seat.js";
16
17
  import { redactSecrets, buildDisplaySafeUrl } from "../trace/redact.js";
17
18
  import { canonicalJsonStringify } from "@sema-agent/core";
18
19
  import { ccPromptSystemFor, wrapCondition, parseCcVerdict, CC_EVALUATOR_MAX_OUTPUT_TOKENS } from "./cc-stop-prompt.js";
19
20
  import { ccAgentHookSystemFor } from "./cc-agent-hook-prompt.js";
21
+ import { createEgressFetch } from "../egress-redirect.js";
20
22
  import { renderBranchTranscript } from "./branch-transcript.js";
21
23
  import { buildRequestUrlCredentialRefusal, urlCredentialHeaderExit } from "../url-credential-refusal.js";
22
24
  import { HOOK_PHASES, HOOK_SOURCE_VOCABULARY_SENTENCE, hookLaneOf, hookPhaseOf, readHookGroupSource } from "./hook-source.js";
23
- import { commandLineChars, composeHookEnvLayer, hookPluginChars, planCommandSpawn, readHookArgs, readHookPlugin } from "./command-spawn.js";
25
+ import { commandLineChars, composeHookEnvLayer, hookPluginChars, planCommandSpawn, readHookPlugin } from "./command-spawn.js";
24
26
  export const MAX_HOOK_ENTRIES_PER_EVENT = 32;
25
27
  export const MAX_HOOK_COMMAND_CHARS = 8_192;
26
28
  export const MAX_HOOK_TIMEOUT_SECONDS = 600;
@@ -42,31 +44,26 @@ function hookEnv(ctx) {
42
44
  return hookChildEnv(composeHookEnvLayer(ctx.shellEnv, ctx.cwd, undefined), false);
43
45
  }
44
46
  export const SETTINGS_HOOK_STATIONS = {
45
- PreToolUse: ["classic.PreToolUse"],
46
- PostToolUse: ["classic.PostToolUse"],
47
- PostToolUseFailure: ["classic.PostToolUseFailure"],
48
- PostToolBatch: ["classic.PostToolBatch"],
49
- UserPromptSubmit: ["classic.UserPromptSubmit"],
50
- Stop: ["classic.Stop", "classic.SubagentStop"],
51
- StopFailure: ["classic.StopFailure"],
52
- PreCompact: ["classic.PreCompact"],
53
- PostCompact: ["classic.PostCompact"],
47
+ PreToolUse: "classic.PreToolUse",
48
+ PostToolUse: "classic.PostToolUse",
49
+ PostToolUseFailure: "classic.PostToolUseFailure",
50
+ PostToolBatch: "classic.PostToolBatch",
51
+ UserPromptSubmit: "classic.UserPromptSubmit",
52
+ Stop: "classic.Stop",
53
+ StopFailure: "classic.StopFailure",
54
+ PreCompact: "classic.PreCompact",
55
+ PostCompact: "classic.PostCompact",
54
56
  };
55
57
  function chainsBelowTaskOn(patterns, station) {
56
58
  return patterns.some((p) => p === station || (p.endsWith(".*") && station.startsWith(p.slice(0, -1))));
57
59
  }
58
- function managedTightenOnlyOn(lane, station, belowTaskChainPatterns) {
59
- return lane === "managed" && chainsBelowTaskOn(belowTaskChainPatterns, station);
60
- }
61
- const MANAGED_REWRITE_UNSHOWN_REASON = "a managed PreToolUse hook rewrote this call's input, but this deployment runs its own handler for this call after the request's hooks and that handler never sees a rewrite made above it, so the rewrite cannot be honored and the call was not executed";
62
- const MANAGED_ALLOW_UNJUDGED_REASON = "a managed PreToolUse hook allowed this call, but this deployment runs its own handler for this call after the request's hooks, and a request hook's allow does not stand in for that handler's judgment, so the call was not executed (the same outcome as the same hook without a managed source)";
63
- function hangTranslator(on, event, translators, lane) {
60
+ const REQUEST_HOOK_REWRITE_UNSHOWN_REASON = "a request PreToolUse hook rewrote this call's input, but this deployment runs its own handler for this call after the request's hooks and that handler never sees a rewrite made above it, so the rewrite cannot be honored and the call was not executed";
61
+ const REQUEST_HOOK_ALLOW_UNJUDGED_REASON = "a request PreToolUse hook allowed this call, but this deployment runs its own handler for this call after the request's hooks, and a request hook's allow does not stand in for that handler's judgment, so the call was not executed";
62
+ function hangTranslator(on, event, translators) {
64
63
  const translate = translators[event];
65
64
  if (translate === undefined)
66
65
  return;
67
- const hang = lane === "managed" ? wrapClassic : hangClassic;
68
- for (const station of SETTINGS_HOOK_STATIONS[event])
69
- hang(on, station, translate);
66
+ hangClassic(on, SETTINGS_HOOK_STATIONS[event], translate);
70
67
  }
71
68
  export const SETTINGS_HOOKS_REGISTRATIONS = {
72
69
  managed: "settings.hooks.managed",
@@ -235,7 +232,6 @@ const HOOKS_WIRE_KEY_SHAPE = {
235
232
  source: `source must be one of ${HOOK_SOURCE_VOCABULARY_SENTENCE}`,
236
233
  plugin: "plugin must be { name, root, dataDir?, options? } — name a non-empty string, root and dataDir absolute paths with no \"..\" segment and no NUL byte, " +
237
234
  "options an object of string values whose keys are identifiers ([A-Za-z_][A-Za-z0-9_]*); nothing else",
238
- args: "args must be an array of strings without NUL bytes (exec form: command is the executable, args its arguments)",
239
235
  };
240
236
  function hooksCapIssue(limit, event, path, count) {
241
237
  const c = HOOKS_CAPS[limit];
@@ -243,54 +239,61 @@ function hooksCapIssue(limit, event, path, count) {
243
239
  }
244
240
  const matcherPath = (event, groupIndex) => ["hooks", event, groupIndex, "matcher"];
245
241
  export function buildHooksRefusal(issue) {
246
- const field = "settings.hooks";
247
242
  switch (issue.reason) {
248
- case "dead_alias":
243
+ case "dead_alias": {
244
+ const field = hooksFieldCoordinate(matcherPath(issue.event, issue.groupIndex));
249
245
  return {
250
246
  message: `settings.hooks.${issue.event}: matcher "${issue.alias}" is an alias; tool-event matchers match the tool's wire name (PostToolUse / PostToolUseFailure since 7.107.0) — use "${issue.canonical}"`,
251
- field,
252
- detail: { reason: issue.reason, event: issue.event, alias: issue.alias, canonical: issue.canonical, path: matcherPath(issue.event, issue.groupIndex) },
247
+ facts: { field, reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex, alias: issue.alias, canonical: issue.canonical },
253
248
  };
254
- case "over_budget":
249
+ }
250
+ case "over_budget": {
251
+ const field = hooksFieldCoordinate(matcherPath(issue.event, issue.groupIndex));
255
252
  return {
256
- message: `settings.hooks.${issue.event}[${issue.groupIndex}].matcher: evaluating the pattern did not finish within ${issue.budgetMs} ms (catastrophic regex backtracking) — rewrite it as a tool-name list or a pattern without nested repetition`,
257
- field,
258
- detail: { reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex, budgetMs: issue.budgetMs, path: matcherPath(issue.event, issue.groupIndex) },
253
+ message: `${field}: evaluating the pattern did not finish within ${issue.budgetMs} ms (catastrophic regex backtracking) — rewrite it as a tool-name list or a pattern without nested repetition`,
254
+ facts: { field, reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex, budgetMs: issue.budgetMs },
259
255
  };
260
- case "budget_exceeded":
256
+ }
257
+ case "budget_exceeded": {
258
+ const field = hooksFieldCoordinate(matcherPath(issue.event, issue.groupIndex));
261
259
  return {
262
- message: `settings.hooks.${issue.event}[${issue.groupIndex}].matcher: evaluating this configuration's regular-expression matchers took longer than ${issue.totalMs} ms in total (very slow patterns) — write tool names as a list such as "Read|Edit", or simplify the patterns`,
263
- field,
264
- detail: { reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex, totalMs: issue.totalMs, path: matcherPath(issue.event, issue.groupIndex) },
260
+ message: `${field}: evaluating this configuration's regular-expression matchers took longer than ${issue.totalMs} ms in total (very slow patterns) — write tool names as a list such as "Read|Edit", or simplify the patterns`,
261
+ facts: { field, reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex, totalMs: issue.totalMs },
265
262
  };
266
- case "invalid_regex":
263
+ }
264
+ case "invalid_regex": {
265
+ const field = hooksFieldCoordinate(matcherPath(issue.event, issue.groupIndex));
267
266
  return {
268
- message: `settings.hooks.${issue.event}[${issue.groupIndex}].matcher: ${JSON.stringify(issue.matcher)} is not a valid regular expression (${issue.compileError}) — fix the pattern, or write the tool names as a list such as "Read|Edit"`,
269
- field,
270
- detail: { reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex, path: matcherPath(issue.event, issue.groupIndex) },
267
+ message: `${field}: ${JSON.stringify(issue.matcher)} is not a valid regular expression (${issue.compileError}) — fix the pattern, or write the tool names as a list such as "Read|Edit"`,
268
+ facts: { field, reason: issue.reason, event: issue.event, groupIndex: issue.groupIndex },
271
269
  };
272
- case "unsupported_entry_type":
270
+ }
271
+ case "unsupported_entry_type": {
272
+ const field = hooksFieldCoordinate(issue.path);
273
273
  return {
274
- message: `${hooksCoordinate(issue.path)}: this server does not run hook entries of type ${issue.type}; supported: ${SUPPORTED_HOOK_ENTRY_TYPES.join(" / ")}`,
275
- field,
276
- detail: { reason: issue.reason, path: hooksOutgoingPath(issue.path), type: issue.type },
274
+ message: `${field}: this server does not run hook entries of type ${issue.type}; supported: ${SUPPORTED_HOOK_ENTRY_TYPES.join(" / ")}`,
275
+ facts: { field, reason: issue.reason, type: issue.type },
277
276
  };
277
+ }
278
278
  case "over_cap":
279
279
  case "too_long": {
280
280
  const cap = issue;
281
- return { message: HOOKS_CAPS[cap.limit].sentence(cap.event, cap.count), field, detail: { reason: cap.reason, path: hooksOutgoingPath(cap.path), count: cap.count, cap: cap.cap } };
281
+ return { message: HOOKS_CAPS[cap.limit].sentence(cap.event, cap.count), facts: { ...limitFacts(hooksFieldCoordinate(cap.path), HOOKS_CAPS[cap.limit].measure, cap.count, cap.cap), reason: cap.reason } };
282
+ }
283
+ case "unnamed_refusal": {
284
+ const field = hooksFieldCoordinate(issue.path);
285
+ return { message: `${field}: the hooks reader refused this configuration without naming a piece`, facts: { field, reason: issue.reason } };
286
+ }
287
+ case "wire_key_invalid": {
288
+ const field = hooksFieldCoordinate(issue.path);
289
+ return { message: `${field}: ${HOOKS_WIRE_KEY_SHAPE[issue.key]}`, facts: { field, reason: issue.reason, key: issue.key } };
282
290
  }
283
- case "unnamed_refusal":
284
- return { message: `${hooksCoordinate(issue.path)}: the hooks reader refused this configuration without naming a piece`, field, detail: { reason: issue.reason, path: hooksOutgoingPath(issue.path) } };
285
- case "wire_key_invalid":
286
- return { message: `${hooksCoordinate(issue.path)}: ${HOOKS_WIRE_KEY_SHAPE[issue.key]}`, field, detail: { reason: issue.reason, path: hooksOutgoingPath(issue.path), key: issue.key } };
287
291
  default: {
288
292
  const piece = issue;
289
293
  const key = piece.key !== undefined ? hooksOutgoingKey(piece.key) : undefined;
290
294
  return {
291
295
  message: hooksPieceRefusal(piece),
292
- field,
293
- detail: { reason: piece.reason, path: hooksOutgoingPath(piece.path), ...(key !== undefined ? { key } : {}) },
296
+ facts: { field: hooksFieldCoordinate(piece.path), reason: piece.reason, ...(key !== undefined ? { key } : {}) },
294
297
  };
295
298
  }
296
299
  }
@@ -353,8 +356,8 @@ export function hooksUrlCredentialIssue(config) {
353
356
  return undefined;
354
357
  }
355
358
  export function buildHooksUrlCredentialRefusal(issue) {
356
- const entry = `settings.hooks.${issue.event}[${issue.groupIndex}].hooks[${issue.entryIndex}]`;
357
- return buildRequestUrlCredentialRefusal(`${entry}.url`, issue.credential, urlCredentialHeaderExit(`${entry}.headers`));
359
+ const entry = ["hooks", issue.event, issue.groupIndex, "hooks", issue.entryIndex];
360
+ return buildRequestUrlCredentialRefusal(hooksFieldCoordinate([...entry, "url"]), issue.credential, urlCredentialHeaderExit(hooksFieldCoordinate([...entry, "headers"])));
358
361
  }
359
362
  const HOOKS_PIECE_MEANING = {
360
363
  "hooks-not-object": "`hooks` must be an object keyed by hook event name",
@@ -372,8 +375,8 @@ const HOOKS_PIECE_MEANING = {
372
375
  export function hooksOutgoingPath(path) {
373
376
  return outgoingPath(path).map((seg) => (typeof seg === "string" ? echoCallerText(seg) : seg));
374
377
  }
375
- export function hooksCoordinate(path) {
376
- return `settings.${formatConfigPath(hooksOutgoingPath(path))}`;
378
+ export function hooksFieldCoordinate(path) {
379
+ return fieldCoordinate("settings", hooksOutgoingPath(path));
377
380
  }
378
381
  function hooksOutgoingKey(key) {
379
382
  return echoCallerText(String(outgoingPath([key])[0] ?? ""));
@@ -383,7 +386,7 @@ function hooksPieceIssue(piece) {
383
386
  }
384
387
  function hooksPieceRefusal(piece) {
385
388
  const field = piece.key !== undefined ? ` (field: ${hooksOutgoingKey(piece.key)})` : "";
386
- return `${hooksCoordinate(piece.path)}: ${piece.reason} — ${HOOKS_PIECE_MEANING[piece.reason]}${field}`;
389
+ return `${hooksFieldCoordinate(piece.path)}: ${piece.reason} — ${HOOKS_PIECE_MEANING[piece.reason]}${field}`;
387
390
  }
388
391
  function hooksRefused(issue, pieces) {
389
392
  const error = buildHooksRefusal(issue).message;
@@ -432,16 +435,12 @@ export function parseHooksConfig(raw) {
432
435
  return hooksRefused({ reason: "unsupported_entry_type", path: [...at, "type"], type: contractEntry.type });
433
436
  let entry = contractEntry;
434
437
  if (entry.type === "command") {
435
- const rawEntry = rawMember(rawMember(rawGroup, "hooks"), entryIndex);
436
- const rawArgs = rawMember(rawEntry, "args");
437
- const rawPlugin = rawMember(rawEntry, "plugin");
438
- const args = rawArgs === undefined ? undefined : readHookArgs(rawArgs);
439
- if (rawArgs !== undefined && args === undefined)
440
- return hooksRefused({ reason: "wire_key_invalid", path: [...at, "args"], key: "args" });
438
+ const rawPlugin = rawMember(rawMember(rawMember(rawGroup, "hooks"), entryIndex), "plugin");
441
439
  const plugin = rawPlugin === undefined ? undefined : readHookPlugin(rawPlugin);
442
440
  if (rawPlugin !== undefined && plugin === undefined)
443
441
  return hooksRefused({ reason: "wire_key_invalid", path: [...at, "plugin"], key: "plugin" });
444
- entry = { ...entry, ...(args !== undefined ? { args } : {}), ...(plugin !== undefined ? { plugin } : {}) };
442
+ if (plugin !== undefined)
443
+ entry = { ...entry, plugin };
445
444
  const line = commandLineChars(entry);
446
445
  if (line > MAX_HOOK_COMMAND_CHARS)
447
446
  return hooksRefused(hooksCapIssue("command", event, [...at, "command"], line));
@@ -600,7 +599,7 @@ function noteMatcherOverBudget(ctx, args) {
600
599
  detail: `${what} \`${expression}\` did not finish within ${budgetMs} ms on \`${value}\`; treated as selected (${count} ${count === 1 ? "entry" : "entries"})`,
601
600
  });
602
601
  }
603
- function matcherGroupSelected(ctx, event, group, value, toolName) {
602
+ function matcherGroupSelected(ctx, event, group, value, toolName, entries) {
604
603
  const answer = hookMatcherMatches(group.matcher, value);
605
604
  switch (answer) {
606
605
  case true:
@@ -611,7 +610,7 @@ function matcherGroupSelected(ctx, event, group, value, toolName) {
611
610
  ctx.logger.warn("hook_matcher_invalid", { event, matcher: echoCallerText(group.matcher ?? "", { maxChars: MATCHER_ECHO_CHARS }) });
612
611
  return "invalid";
613
612
  case "over_budget":
614
- noteMatcherOverBudget(ctx, { event, scope: "matcher", expression: group.matcher ?? "", value, entries: group.hooks, ...(toolName !== undefined ? { toolName } : {}) });
613
+ noteMatcherOverBudget(ctx, { event, scope: "matcher", expression: group.matcher ?? "", value, entries, ...(toolName !== undefined ? { toolName } : {}) });
615
614
  return "over_budget";
616
615
  default: {
617
616
  const unreachable = answer;
@@ -654,6 +653,41 @@ export const PERMISSIVE_VERDICT_EVENTS = {
654
653
  PreModelSwitch: false,
655
654
  PostModelSwitch: false,
656
655
  };
656
+ export const ON_FAILURE_BLOCK_EVENTS = {
657
+ PreToolUse: true,
658
+ PostToolUse: true,
659
+ PostToolUseFailure: true,
660
+ PostToolBatch: true,
661
+ Notification: true,
662
+ UserPromptSubmit: true,
663
+ UserPromptExpansion: true,
664
+ SessionStart: true,
665
+ SessionEnd: true,
666
+ Stop: false,
667
+ StopFailure: false,
668
+ SubagentStart: true,
669
+ SubagentStop: false,
670
+ PreCompact: true,
671
+ PostCompact: false,
672
+ PermissionRequest: true,
673
+ PermissionDenied: true,
674
+ Setup: true,
675
+ TeammateIdle: false,
676
+ TaskCreated: true,
677
+ TaskCompleted: false,
678
+ Elicitation: true,
679
+ ElicitationResult: true,
680
+ ConfigChange: true,
681
+ WorktreeCreate: true,
682
+ WorktreeRemove: true,
683
+ InstructionsLoaded: true,
684
+ CwdChanged: true,
685
+ FileChanged: true,
686
+ MessageDisplay: true,
687
+ DirectoryAdded: true,
688
+ PreModelSwitch: true,
689
+ PostModelSwitch: true,
690
+ };
657
691
  const DISTRUST_DETAIL = {
658
692
  input_truncated: `the hook did not receive the whole payload (tool_input over ${MAX_TOOL_INPUT_CHARS} characters was replaced by a truncation marker, or a prompt / agent entry's payload text was clipped at that size); its allow / updatedInput are not honored`,
659
693
  matcher_over_budget: "the matcher (or the if condition's tool-name part) did not finish within its budget; the entry ran as selected, so its allow / updatedInput are not honored",
@@ -703,24 +737,26 @@ const VERDICT_GAP_CAUSE = {
703
737
  input_truncated: "verdict_unreadable",
704
738
  matcher_over_budget: "verdict_unreadable",
705
739
  };
706
- function createUnrunLedger(ctx, event, toolName) {
740
+ function createUnrunLedger(ctx, event, toolName, once) {
707
741
  let managedVerdictGap;
708
742
  let haltNoted = false;
709
743
  const ledger = {
710
744
  halted(source, entry) {
711
- if (haltNoted)
745
+ if (haltNoted || !isSyncEntry(entry))
712
746
  return;
713
747
  haltNoted = true;
714
748
  ledger.unrun(source, entry, "budget_exhausted", ENGINE_BUDGET_SPENT_DETAIL);
715
749
  },
716
750
  untrusted(source, entry, reason) {
751
+ once.unsettled(entry);
717
752
  if (hookLaneOf(source) === "unmanaged")
718
753
  return;
719
754
  managedVerdictGap ??= VERDICT_GAP_CAUSE[reason];
720
755
  noteVerdictUntrusted(ctx, { event, reason, entry, source, toolName });
721
756
  },
722
757
  unrun(source, entry, reason, detail) {
723
- if (source === undefined || hookLaneOf(source) === "unmanaged")
758
+ once.unsettled(entry);
759
+ if (source === undefined || hookLaneOf(source) === "unmanaged" || !isSyncEntry(entry))
724
760
  return;
725
761
  managedVerdictGap ??= VERDICT_GAP_CAUSE[reason];
726
762
  ctx.logger.warn("hook_managed_unrun", { event, reason, source: echoCallerText(source), type: entry.type, ...(toolName !== undefined ? { tool: toolName } : {}) });
@@ -800,6 +836,13 @@ function withBelowContext(parts, below) {
800
836
  const tail = belowString(below, "additionalContext");
801
837
  return tail === undefined ? [...parts] : [...parts, tail];
802
838
  }
839
+ const ALSO_ASKS_SPEAKER = {
840
+ managed: "a managed PreToolUse hook",
841
+ unmanaged: "a PreToolUse hook",
842
+ };
843
+ function alsoAsks(lane, below, own) {
844
+ return below === undefined || below === own ? own : `${below} (${ALSO_ASKS_SPEAKER[lane]} also asks: ${own})`;
845
+ }
803
846
  function readBelowPreToolUse(below) {
804
847
  const action = belowString(below, "action");
805
848
  const message = belowString(below, "message") ?? "a PreToolUse hook requires approval";
@@ -812,7 +855,7 @@ function readBelowPreToolUse(below) {
812
855
  allowed: action === "allow",
813
856
  ...(action === "ask" && (cause === undefined || cause === "asked") ? { asked: message } : {}),
814
857
  ...(action === "ask" && cause !== undefined && cause !== "asked" ? { unreadable: { message, cause: unreadableCause } } : {}),
815
- realApproval: action === "ask" && typeof below === "object" && below !== null && Reflect.get(below, "requiresRealApproval") === true,
858
+ ...(action === "ask" && typeof below === "object" && below !== null && Object.hasOwn(below, "requiresRealApproval") && Reflect.get(below, "requiresRealApproval") === true ? { realApproval: true } : {}),
816
859
  ...(rewrite !== null && typeof rewrite === "object" ? { updatedInput: rewrite } : {}),
817
860
  ...(additionalContext !== undefined ? { additionalContext } : {}),
818
861
  };
@@ -824,7 +867,65 @@ function spawnPlannedCommand(plan, ctx, stdio) {
824
867
  const sh = hostShell();
825
868
  return spawn(sh.shell, [...sh.args, plan.command], { cwd: ctx.cwd, env, stdio, detached: true });
826
869
  }
827
- async function runCommandHook(entry, payload, ctx, halt) {
870
+ function createHookTreeLadder(child, ctx, event) {
871
+ const leaderOurs = () => child.pid !== undefined && child.exitCode === null && child.signalCode === null;
872
+ const alive = () => leaderOurs() || (child.pid !== undefined && reapedLeaderGroupAlive(child.pid));
873
+ const shoot = (sig) => {
874
+ const pid = child.pid;
875
+ if (pid === undefined) {
876
+ child.kill(sig);
877
+ return;
878
+ }
879
+ if (leaderOurs()) {
880
+ signalProcessTree(pid, sig);
881
+ return;
882
+ }
883
+ if (!reapedLeaderGroupAlive(pid))
884
+ return;
885
+ try {
886
+ (sig === "SIGTERM" ? killTreeSoft : killTreeHard)(pid);
887
+ }
888
+ catch {
889
+ child.kill(sig);
890
+ }
891
+ };
892
+ let hardFired = false;
893
+ const hard = (end) => {
894
+ if (hardFired)
895
+ return;
896
+ hardFired = true;
897
+ shoot("SIGKILL");
898
+ const recheck = setTimeout(() => {
899
+ const clean = !alive();
900
+ if (!clean)
901
+ shoot("SIGKILL");
902
+ const fields = { event, type: "command", end, shots: clean ? 1 : 2, clean };
903
+ if (clean)
904
+ ctx.logger.info("hook_command_tree_swept", fields);
905
+ else
906
+ ctx.logger.warn("hook_command_tree_swept", fields);
907
+ }, HOOK_KILL_GRACE_MS);
908
+ recheck.unref();
909
+ };
910
+ return {
911
+ halt(onEscalate) {
912
+ shoot("SIGTERM");
913
+ const escalate = setTimeout(() => {
914
+ if (hardFired || !alive())
915
+ return;
916
+ onEscalate();
917
+ hard("halt");
918
+ }, HOOK_KILL_GRACE_MS);
919
+ escalate.unref();
920
+ },
921
+ kill: hard,
922
+ ended() {
923
+ if (alive())
924
+ hard("exit");
925
+ },
926
+ };
927
+ }
928
+ async function runCommandHook(entry, payload, ctx, halt, event) {
828
929
  const plan = await planCommandSpawn(entry, ctx.cwd, ctx.shellEnv);
829
930
  if (plan.kind === "refused")
830
931
  return { code: null, stdout: "", stderr: "", timedOut: false, spawnError: plan.error };
@@ -849,6 +950,7 @@ async function runCommandHook(entry, payload, ctx, halt) {
849
950
  return;
850
951
  }
851
952
  const ticket = adoptHostForegroundChild(child);
953
+ const tree = createHookTreeLadder(child, ctx, event);
852
954
  let stdout = "";
853
955
  let stderr = "";
854
956
  let timedOut = false;
@@ -867,40 +969,16 @@ async function runCommandHook(entry, payload, ctx, halt) {
867
969
  timedOut = true;
868
970
  if (sent !== undefined)
869
971
  sent = "SIGKILL";
870
- try {
871
- if (child.pid)
872
- process.kill(-child.pid, "SIGKILL");
873
- else
874
- child.kill("SIGKILL");
875
- }
876
- catch {
877
- child.kill("SIGKILL");
878
- }
879
972
  settle(null);
973
+ tree.kill("timeout");
880
974
  }, timeoutMs);
881
- const signalGroup = (sig) => {
882
- try {
883
- if (child.pid)
884
- (sig === "SIGTERM" ? killTreeSoft : killTreeHard)(child.pid);
885
- else
886
- child.kill(sig);
887
- }
888
- catch {
889
- child.kill(sig);
890
- }
891
- };
892
975
  const onHalt = () => {
893
976
  if (settled)
894
977
  return;
895
978
  sent = "SIGTERM";
896
- signalGroup("SIGTERM");
897
- const escalate = setTimeout(() => {
898
- if (child.exitCode !== null || child.signalCode !== null)
899
- return;
979
+ tree.halt(() => {
900
980
  sent = "SIGKILL";
901
- signalGroup("SIGKILL");
902
- }, HOOK_KILL_GRACE_MS);
903
- escalate.unref();
981
+ });
904
982
  };
905
983
  halt.addEventListener("abort", onHalt, { once: true });
906
984
  child.stdout?.on("data", (d) => {
@@ -919,7 +997,12 @@ async function runCommandHook(entry, payload, ctx, halt) {
919
997
  resolve({ code: null, stdout, stderr, timedOut, spawnError: String(e) });
920
998
  }
921
999
  });
922
- child.on("close", (code) => settle(code));
1000
+ child.on("close", (code) => {
1001
+ const natural = !settled && sent === undefined;
1002
+ settle(code);
1003
+ if (natural)
1004
+ tree.ended();
1005
+ });
923
1006
  child.stdin?.on("error", () => { });
924
1007
  child.stdin?.end(`${JSON.stringify(boundedToolInputPayload(payload))}\n`);
925
1008
  });
@@ -937,18 +1020,11 @@ async function fireAsyncCommandHook(entry, payload, ctx, event, halt) {
937
1020
  return;
938
1021
  const child = spawnPlannedCommand(plan, ctx, ["pipe", "ignore", rewake ? "pipe" : "ignore"]);
939
1022
  const ticket = adoptHostForegroundChild(child);
1023
+ const tree = createHookTreeLadder(child, ctx, event);
940
1024
  let killedByTimeout = false;
941
1025
  const timer = setTimeout(() => {
942
1026
  killedByTimeout = true;
943
- try {
944
- if (child.pid)
945
- process.kill(-child.pid, "SIGKILL");
946
- else
947
- child.kill("SIGKILL");
948
- }
949
- catch {
950
- child.kill("SIGKILL");
951
- }
1027
+ tree.kill("timeout");
952
1028
  }, timeoutMs);
953
1029
  timer.unref?.();
954
1030
  let stderr = "";
@@ -967,6 +1043,8 @@ async function fireAsyncCommandHook(entry, payload, ctx, event, halt) {
967
1043
  child.on("close", (code) => {
968
1044
  clearTimeout(timer);
969
1045
  ticket?.release();
1046
+ if (!killedByTimeout)
1047
+ tree.ended();
970
1048
  noteAsyncOutcome(entry, ctx, event, payload, { code, rewake, killedByTimeout });
971
1049
  if (!rewake || code !== 2)
972
1050
  return;
@@ -1086,6 +1164,7 @@ function httpHookWithheldSentence(event, block) {
1086
1164
  return `settings.hooks.${event}: http hook not sent — ${why} (rule: ${block.rule}); ${exit}`;
1087
1165
  }
1088
1166
  const MAX_BLANKED_REFERENCES_LOGGED = 16;
1167
+ const httpHookFetch = createEgressFetch("declare the final address as this hook entry's url");
1089
1168
  async function runHttpHook(entry, payload, ctx, event) {
1090
1169
  const block = httpHookUrlVerdict(entry.url, ctx.httpHookAllowlistLayers, SERVER_WORKSPACE_TRUST);
1091
1170
  if (block !== undefined)
@@ -1113,12 +1192,11 @@ async function runHttpHook(entry, payload, ctx, event) {
1113
1192
  const ac = new AbortController();
1114
1193
  const timer = setTimeout(() => ac.abort(), timeoutMs);
1115
1194
  try {
1116
- const res = await fetch(entry.url, {
1195
+ const res = await httpHookFetch(entry.url, {
1117
1196
  method: "POST",
1118
1197
  headers,
1119
1198
  body: `${JSON.stringify(boundedToolInputPayload(payload))}\n`,
1120
1199
  signal: ac.signal,
1121
- redirect: "error",
1122
1200
  });
1123
1201
  let body = "";
1124
1202
  const reader = res.body?.getReader();
@@ -1190,18 +1268,39 @@ function boundedToolInputPayload(payload) {
1190
1268
  return bounded === p.tool_input ? payload : { ...p, tool_input: bounded };
1191
1269
  }
1192
1270
  function readHookStdout(ran, event, ctx, payload, ledger) {
1193
- const { run, entry } = ran;
1194
- const out = parseHookStdout(run.stdout);
1271
+ const out = parseHookStdout(ran.run.stdout);
1195
1272
  if (out !== undefined)
1196
1273
  return out;
1197
- const t = run.stdout.trim();
1198
- if (t.startsWith("{") || t.startsWith("[")) {
1199
- ctx.logger.warn("hook_bad_json_output", { event, type: entry.type, preview: seatText("operator-log-text", t) });
1200
- noteHookFailure(ctx, { event, entry, reason: "bad_json", exitCode: run.code, stderr: run.stderr, toolName: toolNameOf(payload) });
1201
- ledger.unrun(ran.source, entry, "bad_json");
1202
- }
1274
+ if (stdoutVerdictUnreadable(ran.run.stdout))
1275
+ noteBadJson(ctx, ledger, event, ran, toolNameOf(payload));
1203
1276
  return undefined;
1204
1277
  }
1278
+ function stdoutVerdictUnreadable(stdout) {
1279
+ if (parseHookStdout(stdout) !== undefined)
1280
+ return false;
1281
+ const t = stdout.trim();
1282
+ return t.startsWith("{") || t.startsWith("[");
1283
+ }
1284
+ function noteBadJson(ctx, ledger, event, ran, toolName) {
1285
+ const { run, entry } = ran;
1286
+ ctx.logger.warn("hook_bad_json_output", { event, type: entry.type, preview: seatText("operator-log-text", run.stdout.trim()) });
1287
+ noteHookFailure(ctx, { event, entry, reason: "bad_json", exitCode: run.code, stderr: run.stderr, toolName });
1288
+ ledger.unrun(ran.source, entry, "bad_json");
1289
+ }
1290
+ const PERMISSION_DECISION_WORDS = new Set(["allow", "deny", "ask"]);
1291
+ function preToolUseDecisionOf(out) {
1292
+ const hso = out?.hookSpecificOutput;
1293
+ return hso !== null && typeof hso === "object" && hso.hookEventName === "PreToolUse" ? hso.permissionDecision : undefined;
1294
+ }
1295
+ function noteDecisionOutOfSet(ctx, ledger, ran, decision, toolName, effect) {
1296
+ ctx.logger.warn("hook_permission_decision_unknown", {
1297
+ event: "PreToolUse",
1298
+ decision: seatText("operator-log-text", typeof decision === "string" ? decision : typeof decision),
1299
+ tool: toolName,
1300
+ effect,
1301
+ });
1302
+ ledger.unrun(ran.source, ran.entry, "decision_out_of_set");
1303
+ }
1205
1304
  function parseHookStdout(stdout) {
1206
1305
  const t = stdout.trim();
1207
1306
  if (!t.startsWith("{"))
@@ -1223,7 +1322,7 @@ function runRunnableEntry(entry, payload, ctx, event, llmExtra, halt) {
1223
1322
  case "agent":
1224
1323
  return runLlmHook(entry, payload, ctx, { system: ccAgentHookSystemFor(event), event });
1225
1324
  case "command":
1226
- return runCommandHook(entry, payload, ctx, halt);
1325
+ return runCommandHook(entry, payload, ctx, halt, event);
1227
1326
  default: {
1228
1327
  const unreachable = entry;
1229
1328
  void unreachable;
@@ -1231,19 +1330,110 @@ function runRunnableEntry(entry, payload, ctx, event, llmExtra, halt) {
1231
1330
  }
1232
1331
  }
1233
1332
  }
1333
+ async function settleOnce(spentOf, body) {
1334
+ const candidates = new Set();
1335
+ let refused = false;
1336
+ const once = {
1337
+ spent: (entry) => spentOf.has(entry),
1338
+ ran: (entry) => {
1339
+ if (entry.once)
1340
+ candidates.add(entry);
1341
+ },
1342
+ handedOff: (entry) => {
1343
+ if (entry.once)
1344
+ spentOf.add(entry);
1345
+ },
1346
+ unsettled: (entry) => {
1347
+ candidates.delete(entry);
1348
+ },
1349
+ refused: (answer) => {
1350
+ refused = true;
1351
+ return answer;
1352
+ },
1353
+ mark: () => {
1354
+ const at = new Set(candidates);
1355
+ return () => {
1356
+ candidates.clear();
1357
+ for (const entry of at)
1358
+ candidates.add(entry);
1359
+ };
1360
+ },
1361
+ };
1362
+ const answer = await body(once);
1363
+ if (!refused)
1364
+ for (const entry of candidates)
1365
+ spentOf.add(entry);
1366
+ return answer;
1367
+ }
1234
1368
  function isSyncEntry(entry) {
1235
1369
  return !(entry.type === "command" && (entry.async === true || entry.asyncRewake === true));
1236
1370
  }
1237
- async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceFired, halt, deadlineAt, ledger, llmExtra) {
1371
+ function blocksOnFailure(entry, event) {
1372
+ if (!ON_FAILURE_BLOCK_EVENTS[event] || !isSyncEntry(entry))
1373
+ return false;
1374
+ if (entry.type !== "command" && entry.type !== "http")
1375
+ return false;
1376
+ const word = entry.onFailure;
1377
+ switch (word) {
1378
+ case "block":
1379
+ return true;
1380
+ case "continue":
1381
+ case undefined:
1382
+ return false;
1383
+ default: {
1384
+ const unreachable = word;
1385
+ void unreachable;
1386
+ return true;
1387
+ }
1388
+ }
1389
+ }
1390
+ function blockingFailureRun(event, cause) {
1391
+ return { code: 2, stdout: "", stderr: `${event} hook did not reach a verdict (${cause}); blocking because onFailure is "block"`, timedOut: false };
1392
+ }
1393
+ function ranVerdictFlaw(event, run) {
1394
+ if (run.code === 2)
1395
+ return undefined;
1396
+ if (run.code !== 0)
1397
+ return { reason: "exit_nonzero" };
1398
+ if (stdoutVerdictUnreadable(run.stdout))
1399
+ return { reason: "bad_json" };
1400
+ if (event !== "PreToolUse")
1401
+ return undefined;
1402
+ const out = parseHookStdout(run.stdout);
1403
+ if (out?.continue === false || out?.decision === "block")
1404
+ return undefined;
1405
+ const decision = preToolUseDecisionOf(out);
1406
+ return decision !== undefined && !PERMISSION_DECISION_WORDS.has(decision) ? { reason: "decision_out_of_set", decision } : undefined;
1407
+ }
1408
+ function noteRanVerdictFlaw(ctx, ledger, event, ran, flaw, toolName) {
1409
+ switch (flaw.reason) {
1410
+ case "exit_nonzero":
1411
+ noteExitNonzero(ctx, ledger, event, ran, toolName);
1412
+ return;
1413
+ case "bad_json":
1414
+ noteBadJson(ctx, ledger, event, ran, toolName);
1415
+ return;
1416
+ case "decision_out_of_set":
1417
+ noteDecisionOutOfSet(ctx, ledger, ran, flaw.decision, toolName, 'hook ruling not honored (closed word set is allow|deny|ask); the entry\'s onFailure is "block", so this call is denied');
1418
+ return;
1419
+ default: {
1420
+ const unreachable = flaw;
1421
+ void unreachable;
1422
+ }
1423
+ }
1424
+ }
1425
+ async function runMatchingEntries(event, groups, matchValue, payload, ctx, once, halt, deadlineAt, ledger, llmExtra) {
1238
1426
  const results = [];
1239
1427
  let llmEntries = 0;
1240
1428
  const toolName = toolNameOf(payload);
1241
1429
  const inputTruncated = boundedToolInputPayload(payload) !== payload;
1242
1430
  const truncatedFor = (entry) => (entry.type === "prompt" || entry.type === "agent" ? llmHookArguments(payload).truncated : inputTruncated);
1243
- const settle = async (entry, onceKey) => {
1431
+ const blockedBy = (entry, source, cause) => ({ entry, run: blockingFailureRun(event, cause), source });
1432
+ let laneSpent = false;
1433
+ const settle = async (entry) => {
1244
1434
  if (halt.signal.aborted)
1245
1435
  return { kind: "halted" };
1246
- if (entry.once && onceFired.has(onceKey))
1436
+ if (entry.once && once.spent(entry))
1247
1437
  return { kind: "passed" };
1248
1438
  let ifOverBudget = false;
1249
1439
  if (entry.if !== undefined) {
@@ -1269,7 +1459,7 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1269
1459
  }
1270
1460
  if (entry.type === "command" && entry.shell === "powershell") {
1271
1461
  ctx.logger.warn("hook_entries_skipped", { event, type: entry.type, reason: "powershell_not_supported" });
1272
- return isSyncEntry(entry) ? { kind: "unrun", reason: "powershell_unsupported" } : { kind: "passed" };
1462
+ return { kind: "unrun", reason: "powershell_unsupported" };
1273
1463
  }
1274
1464
  if (entry.type === "prompt" || entry.type === "agent") {
1275
1465
  const carrier = entry.type === "prompt" ? ctx.hookLlm : ctx.hookAgent;
@@ -1283,17 +1473,15 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1283
1473
  }
1284
1474
  }
1285
1475
  if (entry.type === "command" && (entry.async || entry.asyncRewake)) {
1286
- if (entry.once)
1287
- onceFired.add(onceKey);
1476
+ once.handedOff(entry);
1288
1477
  void fireAsyncCommandHook(entry, payload, ctx, event, halt.signal);
1289
1478
  return { kind: "passed" };
1290
1479
  }
1291
- if (Date.now() > deadlineAt) {
1292
- ctx.logger.warn("hook_event_deadline_exceeded", { event, budgetSec: MAX_HOOK_EVENT_TOTAL_SECONDS });
1480
+ if (laneSpent || Date.now() > deadlineAt) {
1481
+ if (!laneSpent)
1482
+ ctx.logger.warn("hook_event_deadline_exceeded", { event, budgetSec: MAX_HOOK_EVENT_TOTAL_SECONDS });
1293
1483
  return { kind: "unrun", reason: "budget_exhausted" };
1294
1484
  }
1295
- if (entry.once)
1296
- onceFired.add(onceKey);
1297
1485
  if (entry.type === "prompt" || entry.type === "agent")
1298
1486
  llmEntries++;
1299
1487
  const run = await runRunnableEntry(entry, payload, ctx, event, llmExtra, halt.signal);
@@ -1326,20 +1514,35 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1326
1514
  return { kind: "unrun", reason: "bad_json" };
1327
1515
  return ifOverBudget ? { kind: "ran", run, overBudget: true } : { kind: "ran", run };
1328
1516
  };
1329
- for (const { group, index } of groups) {
1330
- const selected = matcherGroupSelected(ctx, event, group, matchValue, toolName);
1517
+ for (const group of groups) {
1518
+ const pending = laneSpent ? group.hooks.filter((entry) => blocksOnFailure(entry, event)) : group.hooks;
1519
+ if (laneSpent && pending.length === 0)
1520
+ continue;
1521
+ const selected = matcherGroupSelected(ctx, event, group, matchValue, toolName, pending);
1331
1522
  if (selected === "invalid") {
1332
- for (const entry of group.hooks)
1333
- if (isSyncEntry(entry))
1523
+ for (const entry of pending) {
1524
+ if (!laneSpent)
1334
1525
  ledger.unrun(group.source, entry, "matcher_invalid");
1526
+ if (blocksOnFailure(entry, event))
1527
+ results.push(blockedBy(entry, group.source, "matcher_invalid"));
1528
+ }
1335
1529
  continue;
1336
1530
  }
1337
1531
  if (selected === false)
1338
1532
  continue;
1339
- for (const [ei, entry] of group.hooks.entries()) {
1340
- const fate = await settle(entry, `${event}:${index}:${ei}`);
1533
+ for (const entry of group.hooks) {
1534
+ if (laneSpent && !blocksOnFailure(entry, event))
1535
+ continue;
1536
+ const fate = await settle(entry);
1341
1537
  switch (fate.kind) {
1342
1538
  case "ran": {
1539
+ once.ran(entry);
1540
+ const flaw = blocksOnFailure(entry, event) ? ranVerdictFlaw(event, fate.run) : undefined;
1541
+ if (flaw !== undefined) {
1542
+ noteRanVerdictFlaw(ctx, ledger, event, { entry, run: fate.run, source: group.source }, flaw, toolName);
1543
+ results.push(blockedBy(entry, group.source, flaw.reason));
1544
+ break;
1545
+ }
1343
1546
  const distrust = !PERMISSIVE_VERDICT_EVENTS[event]
1344
1547
  ? undefined
1345
1548
  : truncatedFor(entry)
@@ -1353,14 +1556,17 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1353
1556
  break;
1354
1557
  }
1355
1558
  case "unrun":
1356
- ledger.unrun(group.source, entry, fate.reason);
1559
+ if (!laneSpent)
1560
+ ledger.unrun(group.source, entry, fate.reason);
1561
+ if (blocksOnFailure(entry, event))
1562
+ results.push(blockedBy(entry, group.source, fate.reason));
1357
1563
  if (fate.reason === "budget_exhausted")
1358
- return results;
1564
+ laneSpent = true;
1359
1565
  break;
1360
1566
  case "passed":
1361
1567
  break;
1362
1568
  case "halted":
1363
- if (isSyncEntry(entry) && halt.budgetSpent())
1569
+ if (halt.budgetSpent())
1364
1570
  ledger.halted(group.source, entry);
1365
1571
  return results;
1366
1572
  default: {
@@ -1378,17 +1584,16 @@ function createEventClock() {
1378
1584
  }
1379
1585
  const ENGINE_BUDGET_SPENT_DETAIL = "the managed lane's handler ran past its engine budget (HOOKS_TIMEOUT_MS); the managed entries after this one did not run on this event";
1380
1586
  function hookPhasesOf(groups) {
1381
- const indexed = groups.map((group, index) => ({ group, index, phase: hookPhaseOf(group.source) }));
1382
- return HOOK_PHASES.map((phase) => ({ phase, groups: indexed.filter((g) => g.phase === phase).map(({ group, index }) => ({ group, index })) })).filter((l) => l.groups.length > 0);
1587
+ return HOOK_PHASES.map((phase) => ({ phase, groups: groups.filter((g) => hookPhaseOf(g.source) === phase) })).filter((l) => l.groups.length > 0);
1383
1588
  }
1384
1589
  function trustRank(phase) {
1385
1590
  return HOOK_PHASES.length - 1 - HOOK_PHASES.indexOf(phase);
1386
1591
  }
1387
- async function runEventLanes(event, groups, matchValue, payload, ctx, onceFired, halt, ledger, llmExtra) {
1592
+ async function runEventLanes(event, groups, matchValue, payload, ctx, once, halt, ledger, llmExtra) {
1388
1593
  const deadline = createEventClock();
1389
1594
  const ran = [];
1390
1595
  for (const lane of hookPhasesOf(groups)) {
1391
- for (const r of await runMatchingEntries(event, lane.groups, matchValue, payload, ctx, onceFired, halt, deadline(), ledger, llmExtra))
1596
+ for (const r of await runMatchingEntries(event, lane.groups, matchValue, payload, ctx, once, halt, deadline(), ledger, llmExtra))
1392
1597
  ran.push({ ...r, phase: lane.phase });
1393
1598
  }
1394
1599
  return ran.sort((a, b) => trustRank(a.phase) - trustRank(b.phase)).map(({ entry, run, source }) => ({ entry, run, source }));
@@ -1404,9 +1609,9 @@ function basePayload(ctx, permissionMode) {
1404
1609
  function ignoreMatchers(groups) {
1405
1610
  return groups.map((g) => (g.matcher === undefined ? g : { ...g, matcher: undefined }));
1406
1611
  }
1407
- async function runObserveOnlyEvent(event, groups, matchValue, payload, ctx, onceFired, halt) {
1408
- const ledger = createUnrunLedger(ctx, event, toolNameOf(payload));
1409
- const singles = await runEventLanes(event, groups, matchValue, payload, ctx, onceFired, halt, ledger);
1612
+ async function runObserveOnlyEvent(event, groups, matchValue, payload, ctx, once, halt) {
1613
+ const ledger = createUnrunLedger(ctx, event, toolNameOf(payload), once);
1614
+ const singles = await runEventLanes(event, groups, matchValue, payload, ctx, once, halt, ledger);
1410
1615
  for (const ran of singles) {
1411
1616
  const { run } = ran;
1412
1617
  if (run.code !== 0) {
@@ -1459,17 +1664,16 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1459
1664
  if (!pre && !post && !postFailure && !postBatch && !promptSubmit && !stopEntries && !stopFailureEntries && !preCompactEntries && !postCompactEntries) {
1460
1665
  return undefined;
1461
1666
  }
1462
- const onceFired = new Set();
1667
+ const onceSpent = new Set();
1463
1668
  const translators = {};
1464
1669
  if (pre) {
1465
- const tightenOnly = managedTightenOnlyOn(lane, "classic.PreToolUse", ctx.belowTaskChainPatterns);
1466
- translators.PreToolUse = async (e, halt, below) => {
1670
+ const tightenOnly = chainsBelowTaskOn(ctx.belowTaskChainPatterns, "classic.PreToolUse");
1671
+ translators.PreToolUse = (e, halt, below) => settleOnce(onceSpent, async (once) => {
1467
1672
  const prior = readBelowPreToolUse(below);
1468
- const realApproval = prior.realApproval ? { requiresRealApproval: true } : {};
1469
1673
  if (prior.denied)
1470
1674
  return undefined;
1471
1675
  const toolName = e.tool;
1472
- const ledger = createUnrunLedger(ctx, "PreToolUse", toolName);
1676
+ const ledger = createUnrunLedger(ctx, "PreToolUse", toolName, once);
1473
1677
  const deadline = createEventClock();
1474
1678
  let currentInput = prior.updatedInput ?? e.input;
1475
1679
  let rewritten = prior.updatedInput !== undefined;
@@ -1479,9 +1683,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1479
1683
  let unknownDecision = false;
1480
1684
  const contexts = { unmanaged: [], managedPlugin: [], managedPolicy: [] };
1481
1685
  const contextField = () => buildHookContextField([...[...HOOK_PHASES].sort((a, b) => trustRank(a) - trustRank(b)).flatMap((p) => contexts[p]), ...(prior.additionalContext !== undefined ? [prior.additionalContext] : [])]);
1482
- const runPass = async (phase, groups, once) => {
1686
+ const strictness = prior.realApproval === true ? { requiresRealApproval: true } : {};
1687
+ const runPass = async (phase, groups) => {
1483
1688
  let rewroteBy;
1484
- for (const laneGroup of groups) {
1689
+ for (const group of groups) {
1485
1690
  const groupInput = currentInput;
1486
1691
  const payload = {
1487
1692
  ...basePayload(ctx, e.permissionMode),
@@ -1490,7 +1695,7 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1490
1695
  tool_input: groupInput,
1491
1696
  tool_use_id: e.tool_use_id,
1492
1697
  };
1493
- const singles = await runMatchingEntries("PreToolUse", [laneGroup], toolName, payload, ctx, once, halt, deadline(), ledger);
1698
+ const singles = await runMatchingEntries("PreToolUse", [group], toolName, payload, ctx, once, halt, deadline(), ledger);
1494
1699
  for (const ran of singles) {
1495
1700
  const { entry, run } = ran;
1496
1701
  if (run.code === 2) {
@@ -1521,7 +1726,7 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1521
1726
  contexts[phase].push(clipDataText(h.additionalContext, MAX_HOOK_FEEDBACK_CHARS));
1522
1727
  spoke = true;
1523
1728
  }
1524
- const decision = h.permissionDecision;
1729
+ const decision = preToolUseDecisionOf(out);
1525
1730
  if (decision === "deny") {
1526
1731
  const reason = clipDataText(typeof h.permissionDecisionReason === "string" ? h.permissionDecisionReason : "denied by a PreToolUse hook", MAX_HOOK_FEEDBACK_CHARS);
1527
1732
  return { deny: { action: "deny", message: reason, ...contextField() } };
@@ -1529,10 +1734,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1529
1734
  const proposed = h.updatedInput !== null && typeof h.updatedInput === "object" ? h.updatedInput : undefined;
1530
1735
  const proposesRewrite = proposed !== undefined && canonicalJsonStringify(proposed) !== canonicalJsonStringify(groupInput);
1531
1736
  if (tightenOnly && ran.distrust === undefined && (decision === "allow" || (proposesRewrite && (decision === "ask" || decision === undefined)))) {
1532
- return { deny: { action: "deny", message: proposesRewrite ? MANAGED_REWRITE_UNSHOWN_REASON : MANAGED_ALLOW_UNJUDGED_REASON, ...contextField() } };
1737
+ return { deny: { action: "deny", message: proposesRewrite ? REQUEST_HOOK_REWRITE_UNSHOWN_REASON : REQUEST_HOOK_ALLOW_UNJUDGED_REASON, ...contextField() } };
1533
1738
  }
1534
1739
  if (decision === "ask") {
1535
- asked = clipDataText(typeof h.permissionDecisionReason === "string" ? h.permissionDecisionReason : "a PreToolUse hook requires approval", MAX_HOOK_FEEDBACK_CHARS);
1740
+ asked = alsoAsks(lane, prior.asked ?? prior.unreadable?.message, clipDataText(typeof h.permissionDecisionReason === "string" ? h.permissionDecisionReason : "a PreToolUse hook requires approval", MAX_HOOK_FEEDBACK_CHARS));
1536
1741
  spoke = true;
1537
1742
  }
1538
1743
  if (decision === "allow" || decision === undefined) {
@@ -1552,16 +1757,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1552
1757
  spoke = true;
1553
1758
  }
1554
1759
  }
1555
- else if (decision !== "deny" && decision !== "ask") {
1760
+ else if (!PERMISSION_DECISION_WORDS.has(decision)) {
1556
1761
  unknownDecision = true;
1557
1762
  spoke = true;
1558
- ctx.logger.warn("hook_permission_decision_unknown", {
1559
- event: "PreToolUse",
1560
- decision: seatText("operator-log-text", typeof decision === "string" ? decision : typeof decision),
1561
- tool: toolName,
1562
- effect: "hook ruling not honored (closed word set is allow|deny|ask); this call falls back to the engine gate",
1563
- });
1564
- ledger.unrun(ran.source, entry, "decision_out_of_set");
1763
+ noteDecisionOutOfSet(ctx, ledger, ran, decision, toolName, "hook ruling not honored (closed word set is allow|deny|ask); this call falls back to the engine gate");
1565
1764
  }
1566
1765
  }
1567
1766
  }
@@ -1570,54 +1769,52 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1570
1769
  };
1571
1770
  for (const lane of hookPhasesOf(pre)) {
1572
1771
  if (lane.phase === "unmanaged") {
1573
- const pass = await runPass(lane.phase, lane.groups, onceFired);
1772
+ const pass = await runPass(lane.phase, lane.groups);
1574
1773
  if (pass.deny !== undefined)
1575
- return pass.deny;
1774
+ return once.refused(pass.deny);
1576
1775
  continue;
1577
1776
  }
1578
- const onceBefore = new Set(onceFired);
1579
- const first = await runPass(lane.phase, lane.groups, onceFired);
1777
+ const rollback = once.mark();
1778
+ const first = await runPass(lane.phase, lane.groups);
1580
1779
  if (first.deny !== undefined)
1581
- return first.deny;
1780
+ return once.refused(first.deny);
1582
1781
  if (first.rewroteBy === undefined)
1583
1782
  continue;
1584
1783
  contexts[lane.phase].length = 0;
1585
- const rejudgeOnce = new Set(onceBefore);
1586
- const second = await runPass(lane.phase, lane.groups, rejudgeOnce);
1587
- for (const key of rejudgeOnce)
1588
- onceFired.add(key);
1784
+ rollback();
1785
+ const second = await runPass(lane.phase, lane.groups);
1589
1786
  if (second.deny !== undefined)
1590
- return second.deny;
1787
+ return once.refused(second.deny);
1591
1788
  if (second.rewroteBy !== undefined) {
1592
1789
  ledger.unrun(second.rewroteBy.source, second.rewroteBy.entry, "rewrite_unsettled", "the managed hooks of this phase rewrote the tool input again after being re-run on their own rewrite; approval required");
1593
1790
  }
1594
1791
  }
1595
1792
  const managedGap = ledger.managedVerdictGap;
1596
- if (below !== undefined && !spoke && managedGap === undefined)
1793
+ if (!spoke && managedGap === undefined)
1597
1794
  return undefined;
1598
1795
  if (asked !== undefined) {
1599
- return { action: "ask", message: asked, questionCause: "asked", ...(rewritten ? { updatedInput: currentInput } : {}), ...realApproval, ...contextField() };
1796
+ return { action: "ask", message: asked, questionCause: "asked", ...strictness, ...(rewritten ? { updatedInput: currentInput } : {}), ...contextField() };
1600
1797
  }
1601
1798
  if (managedGap !== undefined) {
1602
1799
  return {
1603
1800
  action: "ask",
1604
1801
  message: "a managed PreToolUse hook did not run to a verdict — approval required",
1605
1802
  questionCause: managedGap,
1803
+ ...strictness,
1606
1804
  ...(rewritten ? { updatedInput: currentInput } : {}),
1607
- ...realApproval,
1608
1805
  ...contextField(),
1609
1806
  };
1610
1807
  }
1611
1808
  if (prior.unreadable !== undefined) {
1612
- return { action: "ask", message: prior.unreadable.message, questionCause: prior.unreadable.cause, ...(rewritten ? { updatedInput: currentInput } : {}), ...realApproval, ...contextField() };
1809
+ return { action: "ask", message: prior.unreadable.message, questionCause: prior.unreadable.cause, ...strictness, ...(rewritten ? { updatedInput: currentInput } : {}), ...contextField() };
1613
1810
  }
1614
1811
  if (unknownDecision) {
1615
1812
  return {
1616
1813
  action: "ask",
1617
1814
  message: "a PreToolUse hook returned an unrecognized permissionDecision — approval required",
1618
1815
  questionCause: "verdict_unreadable",
1816
+ ...strictness,
1619
1817
  ...(rewritten ? { updatedInput: currentInput } : {}),
1620
- ...realApproval,
1621
1818
  ...contextField(),
1622
1819
  };
1623
1820
  }
@@ -1627,10 +1824,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1627
1824
  if (rewritten || HOOK_PHASES.some((p) => contexts[p].length > 0) || prior.additionalContext !== undefined)
1628
1825
  return carried;
1629
1826
  return undefined;
1630
- };
1827
+ });
1631
1828
  }
1632
1829
  if (post) {
1633
- translators.PostToolUse = async (e, halt, below) => {
1830
+ translators.PostToolUse = (e, halt, below) => settleOnce(onceSpent, async (once) => {
1634
1831
  const toolName = e.tool;
1635
1832
  const input = e.input;
1636
1833
  const output = e.output;
@@ -1646,8 +1843,8 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1646
1843
  tool_response: { isError: output.isError, text: clipDataText(responseText, MAX_TOOL_RESPONSE_CHARS) },
1647
1844
  tool_use_id: e.tool_use_id,
1648
1845
  };
1649
- const ledger = createUnrunLedger(ctx, "PostToolUse", toolName);
1650
- const singles = await runEventLanes("PostToolUse", post, toolName, payload, ctx, onceFired, halt, ledger);
1846
+ const ledger = createUnrunLedger(ctx, "PostToolUse", toolName, once);
1847
+ const singles = await runEventLanes("PostToolUse", post, toolName, payload, ctx, once, halt, ledger);
1651
1848
  for (const ran of singles) {
1652
1849
  const { entry, run } = ran;
1653
1850
  if (run.code === 2) {
@@ -1683,10 +1880,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1683
1880
  if (contexts.length === 0)
1684
1881
  return undefined;
1685
1882
  return { ...belowMembers(below), ...buildHookContextField(withBelowContext(contexts, below)) };
1686
- };
1883
+ });
1687
1884
  }
1688
1885
  if (postFailure) {
1689
- translators.PostToolUseFailure = async (e, halt, below) => {
1886
+ translators.PostToolUseFailure = (e, halt, below) => settleOnce(onceSpent, async (once) => {
1690
1887
  const toolName = e.tool;
1691
1888
  const f = e.failure;
1692
1889
  const contexts = [];
@@ -1699,8 +1896,8 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1699
1896
  error: clipDataText(f.error, MAX_TOOL_RESPONSE_CHARS),
1700
1897
  is_interrupt: f.isInterrupt,
1701
1898
  };
1702
- const ledger = createUnrunLedger(ctx, "PostToolUseFailure", toolName);
1703
- const singles = await runEventLanes("PostToolUseFailure", postFailure, toolName, payload, ctx, onceFired, halt, ledger);
1899
+ const ledger = createUnrunLedger(ctx, "PostToolUseFailure", toolName, once);
1900
+ const singles = await runEventLanes("PostToolUseFailure", postFailure, toolName, payload, ctx, once, halt, ledger);
1704
1901
  for (const ran of singles) {
1705
1902
  const { entry, run } = ran;
1706
1903
  if (run.code === 2) {
@@ -1732,10 +1929,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1732
1929
  if (contexts.length === 0)
1733
1930
  return undefined;
1734
1931
  return { ...belowMembers(below), ...buildHookContextField(withBelowContext(contexts, below)) };
1735
- };
1932
+ });
1736
1933
  }
1737
1934
  if (postBatch) {
1738
- translators.PostToolBatch = async (e, halt, below) => {
1935
+ translators.PostToolBatch = (e, halt, below) => settleOnce(onceSpent, async (once) => {
1739
1936
  const contexts = [];
1740
1937
  const payload = {
1741
1938
  ...basePayload(ctx, e.permissionMode),
@@ -1747,8 +1944,8 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1747
1944
  tool_response: { isError: c.isError, ...(c.response !== undefined ? { text: clipDataText(c.response, MAX_TOOL_RESPONSE_CHARS) } : {}) },
1748
1945
  })),
1749
1946
  };
1750
- const ledger = createUnrunLedger(ctx, "PostToolBatch", undefined);
1751
- const singles = await runEventLanes("PostToolBatch", ignoreMatchers(postBatch), "", payload, ctx, onceFired, halt, ledger);
1947
+ const ledger = createUnrunLedger(ctx, "PostToolBatch", undefined, once);
1948
+ const singles = await runEventLanes("PostToolBatch", ignoreMatchers(postBatch), "", payload, ctx, once, halt, ledger);
1752
1949
  for (const ran of singles) {
1753
1950
  const { entry, run } = ran;
1754
1951
  if (run.code === 2) {
@@ -1776,19 +1973,19 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1776
1973
  if (contexts.length === 0)
1777
1974
  return undefined;
1778
1975
  return { ...belowMembers(below), ...buildHookContextField(withBelowContext(contexts, below)) };
1779
- };
1976
+ });
1780
1977
  }
1781
1978
  if (promptSubmit) {
1782
- translators.UserPromptSubmit = async (e, halt, below) => {
1979
+ translators.UserPromptSubmit = (e, halt, below) => settleOnce(onceSpent, async (once) => {
1783
1980
  const contexts = [];
1784
1981
  const payload = { ...basePayload(ctx, e.permissionMode), hook_event_name: "UserPromptSubmit", prompt: clipDataText(e.prompt, MAX_TOOL_INPUT_CHARS) };
1785
- const ledger = createUnrunLedger(ctx, "UserPromptSubmit", undefined);
1786
- const singles = await runEventLanes("UserPromptSubmit", ignoreMatchers(promptSubmit), "", payload, ctx, onceFired, halt, ledger);
1982
+ const ledger = createUnrunLedger(ctx, "UserPromptSubmit", undefined, once);
1983
+ const singles = await runEventLanes("UserPromptSubmit", ignoreMatchers(promptSubmit), "", payload, ctx, once, halt, ledger);
1787
1984
  for (const ran of singles) {
1788
1985
  const { entry, run } = ran;
1789
1986
  if (run.code === 2) {
1790
1987
  const reason = clipDataText(run.stderr.trim(), MAX_HOOK_FEEDBACK_CHARS) || "blocked by a UserPromptSubmit hook";
1791
- return { block: reason, ...buildHookContextField(contexts) };
1988
+ return once.refused({ block: reason, ...buildHookContextField(contexts) });
1792
1989
  }
1793
1990
  if (run.code !== 0) {
1794
1991
  noteExitNonzero(ctx, ledger, "UserPromptSubmit", ran);
@@ -1801,11 +1998,11 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1801
1998
  logHookSystemMessage(ctx, "UserPromptSubmit", out.systemMessage);
1802
1999
  if (out.continue === false) {
1803
2000
  const reason = clipDataText(typeof out.stopReason === "string" ? out.stopReason : "hook requested stop", MAX_HOOK_FEEDBACK_CHARS);
1804
- return { block: reason, ...buildHookContextField(contexts) };
2001
+ return once.refused({ block: reason, ...buildHookContextField(contexts) });
1805
2002
  }
1806
2003
  if (out.decision === "block") {
1807
2004
  const reason = clipDataText(typeof out.reason === "string" ? out.reason : "blocked by a UserPromptSubmit hook", MAX_HOOK_FEEDBACK_CHARS);
1808
- return { block: reason, ...buildHookContextField(contexts) };
2005
+ return once.refused({ block: reason, ...buildHookContextField(contexts) });
1809
2006
  }
1810
2007
  const hso = out.hookSpecificOutput;
1811
2008
  if (hso !== null && typeof hso === "object" && hso.hookEventName === "UserPromptSubmit") {
@@ -1817,10 +2014,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1817
2014
  if (contexts.length === 0)
1818
2015
  return undefined;
1819
2016
  return { ...belowMembers(below), ...buildHookContextField(withBelowContext(contexts, below)) };
1820
- };
2017
+ });
1821
2018
  }
1822
2019
  if (stopEntries) {
1823
- translators.Stop = async (sctx, halt, below) => {
2020
+ translators.Stop = (sctx, halt, below) => settleOnce(onceSpent, async (once) => {
1824
2021
  const payload = { ...basePayload(ctx, sctx.permissionMode), hook_event_name: "Stop", stop_hook_active: sctx.stopHookActive };
1825
2022
  let llmExtra;
1826
2023
  const wantsPrompt = stopEntries.some((g) => g.hooks.some((h) => h.type === "prompt"));
@@ -1848,7 +2045,7 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1848
2045
  }
1849
2046
  }
1850
2047
  const stopGroups = ignoreMatchers(stopEntries);
1851
- const ledger = createUnrunLedger(ctx, "Stop", undefined);
2048
+ const ledger = createUnrunLedger(ctx, "Stop", undefined, once);
1852
2049
  if (!llmExtra && wantsPrompt) {
1853
2050
  for (const g of stopGroups)
1854
2051
  for (const h of g.hooks)
@@ -1858,7 +2055,7 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1858
2055
  const effectiveGroups = llmExtra || !wantsPrompt
1859
2056
  ? stopGroups
1860
2057
  : stopGroups.map((g) => ({ ...g, hooks: g.hooks.filter((h) => h.type !== "prompt") })).filter((g) => g.hooks.length > 0);
1861
- const singles = await runEventLanes("Stop", effectiveGroups, "", payload, ctx, onceFired, halt, ledger, llmExtra);
2058
+ const singles = await runEventLanes("Stop", effectiveGroups, "", payload, ctx, once, halt, ledger, llmExtra);
1862
2059
  let block;
1863
2060
  let sawContinueFalse = false;
1864
2061
  const contexts = [];
@@ -1912,15 +2109,16 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1912
2109
  return undefined;
1913
2110
  if (block === undefined && contexts.length === 0)
1914
2111
  return undefined;
1915
- return {
2112
+ const answer = {
1916
2113
  ...belowMembers(below),
1917
2114
  ...(block !== undefined ? { block } : {}),
1918
2115
  ...buildHookContextField(withBelowContext(contexts, below)),
1919
2116
  };
1920
- };
2117
+ return block !== undefined ? once.refused(answer) : answer;
2118
+ });
1921
2119
  }
1922
2120
  if (stopFailureEntries) {
1923
- translators.StopFailure = async (fctx, halt) => {
2121
+ translators.StopFailure = (fctx, halt) => settleOnce(onceSpent, async (once) => {
1924
2122
  const turnError = toAssistantTurnError(fctx.errorKind);
1925
2123
  const payload = {
1926
2124
  ...basePayload(ctx, undefined),
@@ -1928,23 +2126,23 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1928
2126
  error: turnError,
1929
2127
  ...(fctx.error ? { error_details: clipDataText(redactSecrets(fctx.error), MAX_HOOK_FEEDBACK_CHARS) } : {}),
1930
2128
  };
1931
- await runObserveOnlyEvent("StopFailure", stopFailureEntries, turnError, payload, ctx, onceFired, halt);
1932
- };
2129
+ await runObserveOnlyEvent("StopFailure", stopFailureEntries, turnError, payload, ctx, once, halt);
2130
+ });
1933
2131
  }
1934
2132
  if (preCompactEntries) {
1935
- translators.PreCompact = async (pctx, halt, below) => {
2133
+ translators.PreCompact = (pctx, halt, below) => settleOnce(onceSpent, async (once) => {
1936
2134
  const payload = {
1937
2135
  ...basePayload(ctx, undefined),
1938
2136
  hook_event_name: "PreCompact",
1939
2137
  trigger: pctx.trigger,
1940
2138
  custom_instructions: pctx.customInstructions ?? null,
1941
2139
  };
1942
- const ledger = createUnrunLedger(ctx, "PreCompact", undefined);
1943
- const singles = await runEventLanes("PreCompact", preCompactEntries, pctx.trigger, payload, ctx, onceFired, halt, ledger);
2140
+ const ledger = createUnrunLedger(ctx, "PreCompact", undefined, once);
2141
+ const singles = await runEventLanes("PreCompact", preCompactEntries, pctx.trigger, payload, ctx, once, halt, ledger);
1944
2142
  for (const ran of singles) {
1945
2143
  const { entry, run } = ran;
1946
2144
  if (run.code === 2) {
1947
- return { ...belowMembers(below), block: clipDataText(run.stderr.trim(), MAX_HOOK_FEEDBACK_CHARS) || "blocked by a PreCompact hook" };
2145
+ return once.refused({ ...belowMembers(below), block: clipDataText(run.stderr.trim(), MAX_HOOK_FEEDBACK_CHARS) || "blocked by a PreCompact hook" });
1948
2146
  }
1949
2147
  if (run.code !== 0) {
1950
2148
  noteExitNonzero(ctx, ledger, "PreCompact", ran);
@@ -1959,31 +2157,31 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1959
2157
  ctx.logger.warn("hook_continue_false_unsupported", { event: "PreCompact" });
1960
2158
  }
1961
2159
  if (out.decision === "block") {
1962
- return { ...belowMembers(below), block: clipDataText(typeof out.reason === "string" ? out.reason : "blocked by a PreCompact hook", MAX_HOOK_FEEDBACK_CHARS) };
2160
+ return once.refused({ ...belowMembers(below), block: clipDataText(typeof out.reason === "string" ? out.reason : "blocked by a PreCompact hook", MAX_HOOK_FEEDBACK_CHARS) });
1963
2161
  }
1964
2162
  }
1965
2163
  return undefined;
1966
- };
2164
+ });
1967
2165
  }
1968
2166
  if (postCompactEntries) {
1969
- translators.PostCompact = async (cctx, halt) => {
2167
+ translators.PostCompact = (cctx, halt) => settleOnce(onceSpent, async (once) => {
1970
2168
  const payload = {
1971
2169
  ...basePayload(ctx, undefined),
1972
2170
  hook_event_name: "PostCompact",
1973
2171
  trigger: cctx.trigger,
1974
2172
  compact_summary: clipDataText(cctx.summary, MAX_TOOL_RESPONSE_CHARS),
1975
2173
  };
1976
- await runObserveOnlyEvent("PostCompact", postCompactEntries, cctx.trigger, payload, ctx, onceFired, halt);
1977
- };
2174
+ await runObserveOnlyEvent("PostCompact", postCompactEntries, cctx.trigger, payload, ctx, once, halt);
2175
+ });
1978
2176
  }
1979
2177
  const events = Object.keys(translators);
1980
2178
  return {
1981
2179
  name: SETTINGS_HOOKS_REGISTRATIONS[lane],
1982
- uses: { events: events.flatMap((event) => SETTINGS_HOOK_STATIONS[event]), calls: [] },
2180
+ uses: { events: events.map((event) => SETTINGS_HOOK_STATIONS[event]), calls: [] },
1983
2181
  budgetMs,
1984
2182
  register(on) {
1985
2183
  for (const event of events)
1986
- hangTranslator(on, event, translators, lane);
2184
+ hangTranslator(on, event, translators);
1987
2185
  },
1988
2186
  };
1989
2187
  }