@sema-agent/core 7.51.2 → 7.53.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 (446) hide show
  1. package/CHANGELOG.md +698 -2
  2. package/README.md +3 -1
  3. package/dist/agents/agent-transcript-tool.d.ts +1 -1
  4. package/dist/agents/cascade.js +4 -0
  5. package/dist/agents/cross-session-envelope.d.ts +8 -0
  6. package/dist/agents/cross-session-envelope.js +6 -0
  7. package/dist/agents/cross-session-judge.d.ts +21 -1
  8. package/dist/agents/cross-session-judge.js +8 -0
  9. package/dist/agents/cross-session-ref.d.ts +5 -0
  10. package/dist/agents/cross-session-ref.js +1 -0
  11. package/dist/agents/cumulative-stats.d.ts +3 -0
  12. package/dist/agents/cumulative-stats.js +3 -0
  13. package/dist/agents/list-agents-tool.d.ts +1 -1
  14. package/dist/agents/org-delivery-gate.d.ts +122 -0
  15. package/dist/agents/org-delivery-gate.js +69 -0
  16. package/dist/agents/peer-held-queue.d.ts +9 -4
  17. package/dist/agents/peer-held-queue.js +6 -5
  18. package/dist/agents/peer-session-drain.d.ts +35 -5
  19. package/dist/agents/peer-session-drain.js +271 -180
  20. package/dist/agents/read-inbox-tool.d.ts +8 -1
  21. package/dist/agents/read-inbox-tool.js +5 -1
  22. package/dist/agents/repair-loop.js +4 -0
  23. package/dist/agents/send-message-tool.d.ts +11 -16
  24. package/dist/agents/send-message-tool.js +11 -13
  25. package/dist/agents/subagent.d.ts +3 -0
  26. package/dist/agents/subagent.js +105 -76
  27. package/dist/agents/tool-filter.d.ts +58 -13
  28. package/dist/agents/tool-filter.js +34 -14
  29. package/dist/bench/metrics.d.ts +1 -0
  30. package/dist/brain/anthropic.d.ts +6 -1
  31. package/dist/brain/anthropic.js +17 -13
  32. package/dist/brain/model-presets.d.ts +4 -5
  33. package/dist/brain/model-presets.js +6 -5
  34. package/dist/brain/open-responses.js +16 -12
  35. package/dist/brain/openai.js +16 -12
  36. package/dist/brain/request-params.d.ts +12 -33
  37. package/dist/brain/request-params.js +5 -2
  38. package/dist/brain/request-route.d.ts +9 -8
  39. package/dist/brain/request-route.js +1 -0
  40. package/dist/brain/route-adjudicator.d.ts +123 -47
  41. package/dist/brain/route-adjudicator.js +171 -42
  42. package/dist/brain/route-conformance.js +2 -2
  43. package/dist/brain/routing.d.ts +24 -1
  44. package/dist/brain/routing.js +54 -19
  45. package/dist/brain/status-sink.d.ts +18 -0
  46. package/dist/brain/status-sink.js +7 -0
  47. package/dist/brain/timeout.js +5 -4
  48. package/dist/core/a2a.d.ts +5 -2
  49. package/dist/core/a2a.js +30 -13
  50. package/dist/core/allow-entry.d.ts +42 -9
  51. package/dist/core/allow-entry.js +25 -18
  52. package/dist/core/auto-compaction.d.ts +80 -20
  53. package/dist/core/auto-compaction.js +65 -18
  54. package/dist/core/auto-promote.d.ts +2 -1
  55. package/dist/core/auto-promote.js +2 -2
  56. package/dist/core/caller-tool-name.d.ts +9 -0
  57. package/dist/core/caller-tool-name.js +13 -0
  58. package/dist/core/checkpoint-requirements.d.ts +7 -1
  59. package/dist/core/checkpoint-requirements.js +2 -0
  60. package/dist/core/checkpoint-store.d.ts +57 -24
  61. package/dist/core/checkpoint-store.js +3 -3
  62. package/dist/core/child-clamp-seats.d.ts +6 -0
  63. package/dist/core/child-clamp-seats.js +2 -1
  64. package/dist/core/compliance.js +3 -1
  65. package/dist/core/credential-vocabulary.d.ts +33 -8
  66. package/dist/core/credential-vocabulary.js +32 -7
  67. package/dist/core/decision-receipt.d.ts +2 -2
  68. package/dist/core/delegation-frames.d.ts +9 -2
  69. package/dist/core/delegation-name.d.ts +18 -0
  70. package/dist/core/delegation-name.js +47 -0
  71. package/dist/core/effective-path-target.d.ts +25 -6
  72. package/dist/core/effective-path-target.js +24 -2
  73. package/dist/core/engine-capabilities.d.ts +8 -1
  74. package/dist/core/engine-capabilities.js +1 -1
  75. package/dist/core/engine-notice.d.ts +49 -21
  76. package/dist/core/frontmatter-fence.d.ts +10 -0
  77. package/dist/core/frontmatter-fence.js +6 -0
  78. package/dist/core/gate-fold.js +8 -25
  79. package/dist/core/gate-lanes.js +358 -274
  80. package/dist/core/gate-outcome.d.ts +11 -6
  81. package/dist/core/governance-codes.d.ts +11 -4
  82. package/dist/core/governance-codes.js +12 -3
  83. package/dist/core/hands-band-screen.d.ts +7 -0
  84. package/dist/core/hands-band-screen.js +32 -0
  85. package/dist/core/hooks.d.ts +283 -739
  86. package/dist/core/hooks.js +100 -193
  87. package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
  88. package/dist/{tools/fs → core}/image-admission.js +24 -6
  89. package/dist/core/locked-config.d.ts +84 -32
  90. package/dist/core/locked-config.js +128 -42
  91. package/dist/core/mcp-connection-pool.d.ts +4 -1
  92. package/dist/core/mcp-connection-pool.js +7 -2
  93. package/dist/core/mcp-probe.d.ts +12 -9
  94. package/dist/core/mcp-probe.js +3 -3
  95. package/dist/core/mcp-server-spec.d.ts +104 -10
  96. package/dist/core/mcp-server-spec.js +183 -33
  97. package/dist/core/mcp.d.ts +31 -20
  98. package/dist/core/mcp.js +66 -56
  99. package/dist/core/memory-engine/data-plane.js +5 -1
  100. package/dist/core/memory-engine/distiller.js +16 -2
  101. package/dist/core/memory-engine/engine.d.ts +22 -30
  102. package/dist/core/memory-engine/engine.js +16 -10
  103. package/dist/core/memory-engine/frontmatter.d.ts +6 -0
  104. package/dist/core/memory-engine/frontmatter.js +19 -16
  105. package/dist/core/memory.d.ts +2 -2
  106. package/dist/core/mode-policy.d.ts +5 -16
  107. package/dist/core/mode-policy.js +7 -19
  108. package/dist/core/model-seat.d.ts +4 -1
  109. package/dist/core/mods/dollar.d.ts +109 -0
  110. package/dist/core/mods/dollar.js +154 -0
  111. package/dist/core/mods/host.d.ts +23 -0
  112. package/dist/core/mods/host.js +21 -0
  113. package/dist/core/mods/kernel/budget.d.ts +43 -0
  114. package/dist/core/mods/kernel/budget.js +83 -0
  115. package/dist/core/mods/kernel/dispatch.d.ts +100 -0
  116. package/dist/core/mods/kernel/dispatch.js +699 -0
  117. package/dist/core/mods/kernel/events.d.ts +245 -0
  118. package/dist/core/mods/kernel/events.js +210 -0
  119. package/dist/core/mods/kernel/index.d.ts +6 -0
  120. package/dist/core/mods/kernel/index.js +5 -0
  121. package/dist/core/mods/kernel/receive.d.ts +94 -0
  122. package/dist/core/mods/kernel/receive.js +188 -0
  123. package/dist/core/mods/kernel/registration.d.ts +131 -0
  124. package/dist/core/mods/kernel/registration.js +102 -0
  125. package/dist/core/mods/kernel/site-rules.d.ts +149 -0
  126. package/dist/core/mods/kernel/site-rules.js +296 -0
  127. package/dist/core/mods/stations.d.ts +344 -0
  128. package/dist/core/mods/stations.js +437 -0
  129. package/dist/core/mounted-mcp.d.ts +57 -0
  130. package/dist/core/mounted-mcp.js +71 -2
  131. package/dist/core/own-property-receipt.d.ts +13 -0
  132. package/dist/core/own-property-receipt.js +13 -23
  133. package/dist/core/parent-spec-seat.d.ts +18 -7
  134. package/dist/core/parent-spec-seat.js +6 -2
  135. package/dist/core/path-identity.js +2 -1
  136. package/dist/core/permission-rule-model.d.ts +58 -9
  137. package/dist/core/permission-rule-model.js +81 -7
  138. package/dist/core/permission-rule-org.d.ts +163 -33
  139. package/dist/core/permission-rule-org.js +205 -71
  140. package/dist/core/permission-rule-syntax.d.ts +15 -0
  141. package/dist/core/permission-rule-syntax.js +24 -16
  142. package/dist/core/permission-rules.d.ts +14 -2
  143. package/dist/core/permission-rules.js +63 -23
  144. package/dist/core/prompt-section-seat.d.ts +15 -27
  145. package/dist/core/prompt-section-seat.js +73 -40
  146. package/dist/core/protocol-http-auth.d.ts +3 -1
  147. package/dist/core/protocol-http-auth.js +2 -0
  148. package/dist/core/reminder-mint.d.ts +2 -2
  149. package/dist/core/remote-env.d.ts +24 -12
  150. package/dist/core/remote-env.js +1 -0
  151. package/dist/core/resume-startup-cause.d.ts +16 -1
  152. package/dist/core/resume-startup-cause.js +4 -1
  153. package/dist/core/retention.js +7 -2
  154. package/dist/core/retired-keys.d.ts +12 -2
  155. package/dist/core/retired-keys.js +15 -1
  156. package/dist/core/roles.js +60 -10
  157. package/dist/core/rule-lane-reads.js +1 -1
  158. package/dist/core/runner/announce-once-ledger.d.ts +31 -1
  159. package/dist/core/runner/announce-once-ledger.js +22 -0
  160. package/dist/core/runner/assemble-result.d.ts +9 -0
  161. package/dist/core/runner/assemble-result.js +3 -1
  162. package/dist/core/runner/call-hook-stations.d.ts +23 -27
  163. package/dist/core/runner/call-hook-stations.js +58 -42
  164. package/dist/core/runner/caller-stop-gate.d.ts +25 -0
  165. package/dist/core/runner/caller-stop-gate.js +7 -0
  166. package/dist/core/runner/compaction-seams.d.ts +8 -22
  167. package/dist/core/runner/compaction-seams.js +28 -53
  168. package/dist/core/runner/construction-doors.js +11 -1
  169. package/dist/core/runner/contracts.d.ts +86 -83
  170. package/dist/core/runner/credential-origin-seat.d.ts +2 -0
  171. package/dist/core/runner/credential-origin-seat.js +19 -0
  172. package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
  173. package/dist/core/runner/gate-exit.d.ts +47 -36
  174. package/dist/core/runner/gate-exit.js +12 -5
  175. package/dist/core/runner/image.js +1 -2
  176. package/dist/core/runner/inline-image.js +1 -1
  177. package/dist/core/runner/mcp-redial.d.ts +52 -10
  178. package/dist/core/runner/mcp-redial.js +38 -9
  179. package/dist/core/runner/notice-seat-input.d.ts +11 -0
  180. package/dist/core/runner/notice-seat-input.js +1 -0
  181. package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
  182. package/dist/core/runner/permission-rule-lanes.js +22 -10
  183. package/dist/core/runner/person-path-rows.d.ts +3 -1
  184. package/dist/core/runner/person-path-rows.js +3 -2
  185. package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
  186. package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
  187. package/dist/core/runner/prepare-ask-lane.js +6 -15
  188. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
  189. package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
  190. package/dist/core/runner/prepare-config-doors.d.ts +52 -1
  191. package/dist/core/runner/prepare-config-doors.js +168 -143
  192. package/dist/core/runner/prepare-defer-classify.js +7 -11
  193. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  194. package/dist/core/runner/prepare-delegation-surface.js +7 -5
  195. package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
  196. package/dist/core/runner/prepare-gate-stations.js +11 -10
  197. package/dist/core/runner/prepare-hands-readface.d.ts +1 -1
  198. package/dist/core/runner/prepare-hands-readface.js +2 -1
  199. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
  200. package/dist/core/runner/prepare-inherited-gate.js +10 -23
  201. package/dist/core/runner/prepare-listings.d.ts +1 -1
  202. package/dist/core/runner/prepare-listings.js +4 -2
  203. package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
  204. package/dist/core/runner/prepare-memory-engine-session.js +20 -7
  205. package/dist/core/runner/prepare-memory.d.ts +3 -2
  206. package/dist/core/runner/prepare-memory.js +6 -2
  207. package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
  208. package/dist/core/runner/prepare-offload-wrappers.js +2 -1
  209. package/dist/core/runner/prepare-park-ask.js +10 -14
  210. package/dist/core/runner/prepare-policy-chain.d.ts +17 -15
  211. package/dist/core/runner/prepare-policy-chain.js +104 -109
  212. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  213. package/dist/core/runner/prepare-project-context.js +11 -12
  214. package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
  215. package/dist/core/runner/prepare-prompt-assembly.js +138 -101
  216. package/dist/core/runner/prepare-prompt-inputs.d.ts +28 -23
  217. package/dist/core/runner/prepare-prompt-inputs.js +11 -10
  218. package/dist/core/runner/prepare-protocol-tools.d.ts +11 -7
  219. package/dist/core/runner/prepare-protocol-tools.js +20 -13
  220. package/dist/core/runner/prepare-question-face.d.ts +4 -2
  221. package/dist/core/runner/prepare-question-face.js +4 -3
  222. package/dist/core/runner/prepare-safety-scan.js +6 -10
  223. package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
  224. package/dist/core/runner/prepare-suspend-saga.js +7 -5
  225. package/dist/core/runner/prepare-task.js +41 -23
  226. package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
  227. package/dist/core/runner/prepare-turn-wiring.js +29 -27
  228. package/dist/core/runner/prepare-wiring-manifest.d.ts +13 -9
  229. package/dist/core/runner/prepare-wiring-manifest.js +14 -11
  230. package/dist/core/runner/resume-admission.d.ts +4 -1
  231. package/dist/core/runner/resume-admission.js +7 -5
  232. package/dist/core/runner/resume-apply.d.ts +5 -2
  233. package/dist/core/runner/resume-apply.js +24 -42
  234. package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
  235. package/dist/core/runner/resume-checkpoint-screen.js +9 -1
  236. package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
  237. package/dist/core/runner/resume-internals-and-config.js +3 -8
  238. package/dist/core/runner/resume-preflight.js +38 -16
  239. package/dist/core/runner/retired-runner-deps.d.ts +5 -6
  240. package/dist/core/runner/retired-runner-deps.js +4 -5
  241. package/dist/core/runner/run-brain-sinks.d.ts +3 -2
  242. package/dist/core/runner/run-brain-sinks.js +5 -1
  243. package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
  244. package/dist/core/runner/run-compaction-machinery.js +7 -33
  245. package/dist/core/runner/run-harness-handlers.js +4 -2
  246. package/dist/core/runner/run-identity-wiring.d.ts +3 -1
  247. package/dist/core/runner/run-identity-wiring.js +3 -2
  248. package/dist/core/runner/run-leg.js +103 -95
  249. package/dist/core/runner/run-notification-lane.js +1 -0
  250. package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
  251. package/dist/core/runner/run-recovery-lanes.js +14 -11
  252. package/dist/core/runner/run-settle-and-teardown.js +9 -28
  253. package/dist/core/runner/run-stop-and-final-verify.js +18 -25
  254. package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
  255. package/dist/core/runner/run-terminal-adoption.js +34 -22
  256. package/dist/core/runner/run-tool-mount-facts.js +5 -3
  257. package/dist/core/runner/run-turn-boundary.js +32 -37
  258. package/dist/core/runner/runtask.d.ts +6 -7
  259. package/dist/core/runner/runtask.js +15 -73
  260. package/dist/core/runner/session-rule-policy.d.ts +5 -5
  261. package/dist/core/runner/session-rule-policy.js +13 -8
  262. package/dist/core/runner/side-call-account.d.ts +68 -0
  263. package/dist/core/runner/side-call-account.js +61 -0
  264. package/dist/core/runner/skills-seat.d.ts +15 -0
  265. package/dist/core/runner/skills-seat.js +57 -0
  266. package/dist/core/runner/stream-halt-verbs.js +12 -17
  267. package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
  268. package/dist/core/runner/stream-steer-verb.d.ts +1 -1
  269. package/dist/core/runner/stream-steer-verb.js +20 -38
  270. package/dist/core/runner/sub-agent-deny-lists.d.ts +124 -23
  271. package/dist/core/runner/sub-agent-deny-lists.js +230 -71
  272. package/dist/core/runner/synthetic-tools.d.ts +5 -2
  273. package/dist/core/runner/synthetic-tools.js +2 -12
  274. package/dist/core/runner/tool-end-body.d.ts +5 -6
  275. package/dist/core/runner/tool-end-body.js +6 -4
  276. package/dist/core/runner/tool-not-executed.d.ts +15 -0
  277. package/dist/core/runner/tool-not-executed.js +30 -0
  278. package/dist/core/runner/tool-occurrence.d.ts +8 -7
  279. package/dist/core/runner/tool-occurrence.js +5 -5
  280. package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
  281. package/dist/core/runner-deps.d.ts +43 -36
  282. package/dist/core/safety-merge-corpus.js +18 -2
  283. package/dist/core/secret-env.d.ts +88 -20
  284. package/dist/core/secret-env.js +192 -38
  285. package/dist/core/session-policy-store.d.ts +71 -16
  286. package/dist/core/session-policy-store.js +138 -28
  287. package/dist/core/session-reconcile.d.ts +4 -0
  288. package/dist/core/session-reconcile.js +2 -1
  289. package/dist/core/shell-read-silence.js +3 -32
  290. package/dist/core/side-query.d.ts +5 -3
  291. package/dist/core/skill-grant.d.ts +3 -2
  292. package/dist/core/skill-grant.js +17 -9
  293. package/dist/core/skills-directory.d.ts +31 -11
  294. package/dist/core/skills-directory.js +655 -104
  295. package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
  296. package/dist/core/task-event.d.ts +49 -3
  297. package/dist/core/task-notification.js +2 -2
  298. package/dist/core/task-result.d.ts +8 -0
  299. package/dist/core/task-spec.d.ts +20 -19
  300. package/dist/core/task-stream.d.ts +14 -4
  301. package/dist/core/tighten-task-spec.d.ts +4 -3
  302. package/dist/core/tighten-task-spec.js +2 -4
  303. package/dist/core/tool-check-reading.d.ts +74 -0
  304. package/dist/core/tool-check-reading.js +80 -0
  305. package/dist/core/tool-policy.d.ts +62 -18
  306. package/dist/core/tool-policy.js +86 -15
  307. package/dist/core/tool-registry.d.ts +20 -0
  308. package/dist/core/tool-registry.js +4 -0
  309. package/dist/core/tool-spec.d.ts +10 -6
  310. package/dist/core/tools.js +2 -0
  311. package/dist/core/trace.d.ts +51 -32
  312. package/dist/core/types.d.ts +2 -2
  313. package/dist/core/types.js +1 -1
  314. package/dist/core/unc-spelling.d.ts +10 -0
  315. package/dist/core/unc-spelling.js +3 -0
  316. package/dist/core/untrusted-egress.d.ts +8 -0
  317. package/dist/core/untrusted-egress.js +4 -1
  318. package/dist/core/untrusted-text.d.ts +16 -0
  319. package/dist/core/untrusted-text.js +7 -2
  320. package/dist/core/user-attachment.d.ts +25 -4
  321. package/dist/core/user-attachment.js +63 -42
  322. package/dist/core/wiring-manifest.d.ts +18 -15
  323. package/dist/core/wiring-manifest.js +2 -2
  324. package/dist/engine/compaction/utils.js +1 -2
  325. package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
  326. package/dist/engine/execution-env/symlink-chain.js +1 -1
  327. package/dist/engine/harness/agent-harness.d.ts +1 -1
  328. package/dist/engine/harness/agent-harness.js +5 -4
  329. package/dist/engine/harness/types.d.ts +20 -16
  330. package/dist/engine/harness/types.js +7 -1
  331. package/dist/engine/llm/types.d.ts +12 -7
  332. package/dist/engine/loop/agent-loop.d.ts +12 -1
  333. package/dist/engine/loop/agent-loop.js +18 -6
  334. package/dist/engine/loop/types.d.ts +8 -2
  335. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  336. package/dist/engine/session/import-validate.js +3 -10
  337. package/dist/engine/session/session.d.ts +4 -4
  338. package/dist/engine/session/session.js +4 -4
  339. package/dist/index.d.ts +33 -23
  340. package/dist/index.js +23 -15
  341. package/dist/internal/harness.d.ts +2 -1
  342. package/dist/internal/harness.js +2 -1
  343. package/dist/orchestration/goal.d.ts +24 -1
  344. package/dist/orchestration/goal.js +3 -2
  345. package/dist/orchestration/run-spec.d.ts +4 -6
  346. package/dist/orchestration/run-spec.js +39 -63
  347. package/dist/orchestration/run-workflow-tool.js +1 -2
  348. package/dist/orchestration/workflow.d.ts +11 -3
  349. package/dist/orchestration/workflow.js +11 -2
  350. package/dist/prompt-assembly/artifact-store.d.ts +72 -56
  351. package/dist/prompt-assembly/artifact-store.js +60 -52
  352. package/dist/prompt-assembly/artifact.d.ts +90 -76
  353. package/dist/prompt-assembly/artifact.js +197 -145
  354. package/dist/prompt-assembly/assemble.d.ts +36 -29
  355. package/dist/prompt-assembly/assemble.js +34 -220
  356. package/dist/prompt-assembly/bands.d.ts +20 -0
  357. package/dist/prompt-assembly/bands.js +18 -0
  358. package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
  359. package/dist/prompt-assembly/catalog/constitution.js +69 -0
  360. package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
  361. package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
  362. package/dist/prompt-assembly/catalog/index.d.ts +11 -0
  363. package/dist/prompt-assembly/catalog/index.js +60 -0
  364. package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
  365. package/dist/prompt-assembly/catalog/memory.js +6 -0
  366. package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
  367. package/dist/prompt-assembly/catalog/modes.js +137 -0
  368. package/dist/prompt-assembly/catalog/role.d.ts +10 -0
  369. package/dist/prompt-assembly/catalog/role.js +157 -0
  370. package/dist/prompt-assembly/catalog/schema.d.ts +138 -0
  371. package/dist/prompt-assembly/catalog/schema.js +25 -0
  372. package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
  373. package/dist/prompt-assembly/catalog/sections.js +98 -0
  374. package/dist/prompt-assembly/catalog/team.d.ts +4 -0
  375. package/dist/prompt-assembly/catalog/team.js +258 -0
  376. package/dist/prompt-assembly/composer.d.ts +26 -28
  377. package/dist/prompt-assembly/composer.js +124 -46
  378. package/dist/prompt-assembly/epoch.d.ts +89 -79
  379. package/dist/prompt-assembly/epoch.js +115 -142
  380. package/dist/prompt-assembly/explain.d.ts +58 -34
  381. package/dist/prompt-assembly/explain.js +21 -24
  382. package/dist/prompt-assembly/overlay.d.ts +137 -0
  383. package/dist/prompt-assembly/overlay.js +339 -0
  384. package/dist/prompt-assembly/renderers.d.ts +21 -0
  385. package/dist/prompt-assembly/renderers.js +39 -0
  386. package/dist/prompt-assembly/section-usage.d.ts +3 -3
  387. package/dist/prompt-assembly/section-usage.js +1 -1
  388. package/dist/prompt-assembly/select.d.ts +71 -0
  389. package/dist/prompt-assembly/select.js +106 -0
  390. package/dist/prompt-assembly/sugar.d.ts +31 -0
  391. package/dist/prompt-assembly/sugar.js +20 -0
  392. package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
  393. package/dist/prompt-assembly/types.d.ts +45 -148
  394. package/dist/prompts/coordinator.d.ts +2 -21
  395. package/dist/prompts/coordinator.js +3 -255
  396. package/dist/prompts/cowork.d.ts +27 -16
  397. package/dist/prompts/cowork.js +2 -23
  398. package/dist/prompts/default.d.ts +38 -511
  399. package/dist/prompts/default.js +20 -288
  400. package/dist/prompts/supervisor.d.ts +6 -71
  401. package/dist/prompts/supervisor.js +6 -117
  402. package/dist/stores/file/permission-rule-store.d.ts +1 -1
  403. package/dist/stores/file/permission-rule-store.js +2 -1
  404. package/dist/tools/artifact/artifact-tool.js +4 -3
  405. package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
  406. package/dist/tools/fs/dir-entries.d.ts +4 -2
  407. package/dist/tools/fs/dir-entries.js +16 -4
  408. package/dist/tools/fs/fs-bash.d.ts +1 -1
  409. package/dist/tools/fs/fs-bash.js +22 -11
  410. package/dist/tools/fs/fs-pdf.js +17 -13
  411. package/dist/tools/fs/fs-read.js +4 -3
  412. package/dist/tools/fs/fs-shared.d.ts +1 -10
  413. package/dist/tools/fs/fs-shared.js +3 -4
  414. package/dist/tools/fs/fs-write.js +2 -1
  415. package/dist/tools/fs/notebook.js +1 -1
  416. package/dist/tools/fs/pdf.d.ts +20 -10
  417. package/dist/tools/fs/pdf.js +19 -10
  418. package/dist/tools/fs/program-read-model.d.ts +68 -8
  419. package/dist/tools/fs/program-read-model.js +112 -33
  420. package/dist/tools/fs/program-read-model.rows.js +30 -10
  421. package/dist/tools/fs/read-deny-home.d.ts +25 -9
  422. package/dist/tools/fs/read-deny-home.js +28 -27
  423. package/dist/tools/fs/read-deny.d.ts +41 -11
  424. package/dist/tools/fs/read-deny.js +51 -5
  425. package/dist/tools/fs/safety.d.ts +4 -26
  426. package/dist/tools/fs/safety.js +10 -32
  427. package/dist/tools/fs/search.js +15 -10
  428. package/dist/tools/fs/shell-read-argv.d.ts +3 -2
  429. package/dist/tools/fs/shell-read-argv.js +118 -38
  430. package/dist/tools/fs/shell-read-establish.d.ts +5 -5
  431. package/dist/tools/fs/shell-read-establish.js +11 -61
  432. package/dist/tools/fs/shell-read-identity.js +6 -3
  433. package/dist/tools/fs/shell-read-judge.d.ts +13 -15
  434. package/dist/tools/fs/shell-read-judge.js +18 -4
  435. package/dist/tools/fs/shell-read-plan.d.ts +2 -2
  436. package/dist/tools/web.js +1 -1
  437. package/package.json +13 -1
  438. package/test/export-surface.snapshot.json +306 -103
  439. package/wire-changes/core@7.52.0.json +5859 -0
  440. package/wire-changes/core@7.53.0.json +1946 -0
  441. package/dist/core/hook-seats.d.ts +0 -66
  442. package/dist/core/hook-seats.js +0 -37
  443. package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
  444. package/dist/prompt-assembly/packs/sema-default.js +0 -147
  445. package/dist/prompts/simple-sections.d.ts +0 -58
  446. package/dist/prompts/simple-sections.js +0 -43
@@ -1,6 +1,8 @@
1
1
  import { strict as assert } from "node:assert";
2
2
  import { MAILBOX_INVALID_PEER_META_CODE, MAILBOX_TOMBSTONED_RECIPIENT_CODE } from "../mailbox-store.js";
3
3
  import { beginContract } from "./contract-harness.js";
4
+ import { PRINCIPAL_INBOX_HANDLE } from "../../agents/cross-session-ref.js";
5
+ import { mintCrossPrincipalRecord } from "../../agents/org-delivery-gate.js";
4
6
  export const MAILBOX_CONTRACT_SCOPE = "default";
5
7
  const msg = (content, sentAt = 1000) => ({ content, sentAt });
6
8
  async function withStores(mk, fn) {
@@ -259,6 +261,17 @@ export async function mailboxBundledOnlyContract(mk, runAssertion) {
259
261
  await s.drop("tenant-b", "shared-handle");
260
262
  assert.equal(await s.peekCount("tenant-b", "shared-handle"), 0);
261
263
  });
264
+ run("第四条消费链(principal 收件箱):投递门铸的信落收件人 scope 的 principal.inbox,两只信任锚逐字节回读,发信方 scope 零残留", async (make) => {
265
+ const s = make();
266
+ const letter = mintCrossPrincipalRecord({ from: { scope: "principal-a", name: "alice" }, body: { content: "letter" }, receiptId: "gr-1", sentAt: 10_000, consumer: { kind: "terminals" } });
267
+ assert.equal(await s.append("principal-b", PRINCIPAL_INBOX_HANDLE, letter), 1);
268
+ assert.equal(await s.peekCount("principal-a", PRINCIPAL_INBOX_HANDLE), 0, "发信方 scope 的同名箱不得出现这封信");
269
+ const lease = await s.claimLease("principal-b", PRINCIPAL_INBOX_HANDLE, "drain:r1", 60_000, 10_000);
270
+ assert.deepEqual(lease.messages.map((m) => m.peerMeta), [{ kind: "peer_message", fromScope: "principal-a", gateReceiptId: "gr-1" }]);
271
+ assert.equal(lease.messages[0].from, "alice");
272
+ assert.deepEqual(await s.ack("principal-b", PRINCIPAL_INBOX_HANDLE, "drain:r1", lease.maxSeq), { acked: true });
273
+ assert.equal(await s.peekCount("principal-b", PRINCIPAL_INBOX_HANDLE), 0);
274
+ });
262
275
  await settle();
263
276
  }
264
277
  export async function mailboxCrossProcessContract(hooks) {
@@ -547,7 +547,14 @@ export type TaskEvent = ({
547
547
  /**
548
548
  * @contract tool_end.notExecuted — `true` when the engine has POSITIVE evidence this call never executed:
549
549
  * the loop closed it without running it (a sibling settled by a halted batch, a call a turn interrupt
550
- * reached before it started) or an interrupted run's reconcile closed a call this run never started.
550
+ * reached before it started), an interrupted run's reconcile closed a call this run never started, or the
551
+ * engine's own judgment REFUSED the call and never let it go to its executor (a person's refusal, the host's
552
+ * SLA sweep, a policy or hook or plan-mode deny, a post-approval veto before the run — read off the call's
553
+ * occurrence: the latest {@link gate} record is `denied` and the life never reached the release). A refusal
554
+ * recorded AFTER the release (a station inside the execution, such as the shell read admission) is not
555
+ * evidence. The persisted `toolResult` row repeats the frame's mark as `details.notExecuted: true` (a live
556
+ * leg's rows, the resumed leg's and the reconcile's appended close) — the engine's key alone: a tool's own
557
+ * value under that name is dropped from the row.
551
558
  * ABSENT means only that no such evidence exists — never "it ran": a call closed with its outcome unknown
552
559
  * (a reconcile at the next process start, a call interrupted mid-execution) carries no mark, because
553
560
  * telling a consumer it did not run could invite a replay of a write that already took effect.
@@ -670,6 +677,10 @@ export type TaskEvent = ({
670
677
  * pre-compaction context size. CC parity = `SDKCompactBoundary{trigger, pre_tokens, preserved_segment}`. */
671
678
  type: "compacted";
672
679
  trigger: "auto" | "manual" | "forced";
680
+ /** The pass this frame CONCLUDES — the value the pass's `compaction_started` frame carried. A landing is
681
+ * always preceded by its start, so the engine sets it on every `compacted` frame; it is optional in the
682
+ * type only so a literal a host builds by hand stays valid. */
683
+ pass?: string;
673
684
  tokensBefore: number;
674
685
  /** How much context this compaction FREED, as the engine measured it: one structural sum over
675
686
  * the pre-messages minus the same sum over the post-messages, inside the pass. **The only
@@ -753,8 +764,12 @@ export type TaskEvent = ({
753
764
  * or the rapid-refill breaker disabled compaction mid-task (`reason` says which). A spec
754
765
  * that statically disables compaction does NOT produce one of these per boundary (that
755
766
  * would be per-boundary noise about a static configuration, not a state change).
756
- * - `"mooted"` — a manual request was processed but no boundary could serve it (dying loop /
757
- * caller cancel).
767
+ * - `"mooted"` — the pass did not run to its end: a manual request no boundary could serve
768
+ * (`trigger:"manual"`, `reason:"task_ending"`), or a request withdrawn / a pass cut in flight by its
769
+ * caller — a `compact({ signal })` withdrawal, `halt()`, `interrupt()`, `destroy()` or the task's own
770
+ * `signal` (`reason:"cancelled"`), on any trigger: `"auto"`, `"manual"` or `"forced"`, or a turn-boundary
771
+ * pass in flight that the task's own end cut — a limit, a timeout (`reason:"task_ending"`, with the
772
+ * `pass` the start announced). Read `"mooted"` with its `trigger` — it is not a manual-only outcome.
758
773
  */
759
774
  type: "compaction_outcome";
760
775
  outcome: Exclude<CompactOutcome, "compacted"> | "suppressed";
@@ -762,6 +777,37 @@ export type TaskEvent = ({
762
777
  trigger: "auto" | "manual" | "forced";
763
778
  /** Optional human-readable detail (mirrors the trace frame's reason where one exists). */
764
779
  reason?: string;
780
+ /** The pass this frame CONCLUDES — the value its `compaction_started` frame carried. Present exactly when a
781
+ * start was announced for the pass this frame ends, which makes it `failed` or `mooted` (a pass that ran its
782
+ * summary call and did not land, or was cut while it ran). Absent on every outcome of a pass that never
783
+ * started — `blocked`, `suppressed`, `disabled`, `noop`, a `mooted` request no boundary served — and on the
784
+ * rapid-refill `disabled` frame, which reports a state the landing before it caused, not that pass's end. */
785
+ pass?: string;
786
+ } & TaskEventIdentity) | ({
787
+ /**
788
+ * A compaction pass is under way: the engine has committed to it and is about to produce its summary.
789
+ * Until now compaction was announced only when it ended (`compacted`, or `compaction_outcome` for a pass
790
+ * that did not land), so a consumer watching a summary call wait out a provider's retries had nothing to
791
+ * show for the minutes in between.
792
+ *
793
+ * Minted at the one place a pass commits — after the trigger gate, a valid cut point and the
794
+ * `preCompact` hook (a blocking hook ends the pass before it starts), before the summary provider is
795
+ * consulted or the model is called — by every lane that compacts: the turn boundary (`"auto"`, `"manual"`,
796
+ * and `"forced"` under trim pressure), the prompt-too-long recovery and guard-chain arm B (`"forced"`), and
797
+ * the end-of-task summary (`"auto"`). Retries inside the pass's model call never mint a second one.
798
+ *
799
+ * Pairing: exactly one frame concludes each started pass, carrying the same `pass` — `compacted` when it
800
+ * lands, `compaction_outcome{failed | mooted}` when it does not. A pass that never reaches this point
801
+ * (`blocked`, `suppressed`, `disabled`, `noop`) announces nothing here and its outcome carries no `pass`.
802
+ * `pass` is unique across runs, so a consumer multiplexing several tasks on one stream pairs on `pass` alone.
803
+ */
804
+ type: "compaction_started";
805
+ /** Same three-state vocabulary (and the same value) the pass hands the `preCompact` hook and its concluding frame. */
806
+ trigger: "auto" | "manual" | "forced";
807
+ /** The pass's identity: an opaque engine-minted id (uuidv7), carried by the frame that concludes the pass. */
808
+ pass: string;
809
+ /** The engine clock (epoch ms) at the moment the pass committed. */
810
+ startedAt: number;
765
811
  } & TaskEventIdentity) | ({
766
812
  /**
767
813
  * TB telemetry B3: the engine injected a SYSTEM steering message (a deadline nudge
@@ -2,7 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { escapeEnvelopeTag, inlineUntrusted, sanitizeUntrustedText } from "./untrusted-text.js";
3
3
  import { egressText } from "./untrusted-egress.js";
4
4
  import { PEER_MESSAGE_NOTICE } from "../agents/peer-admission.js";
5
- import { buildCrossSessionEnvelope, CROSS_SESSION_MESSAGE_NOTICE, neutralizePeerBody } from "../agents/cross-session-envelope.js";
5
+ import { buildCrossSessionEnvelope, CROSS_PRINCIPAL_MESSAGE_NOTICE, CROSS_SESSION_MESSAGE_NOTICE, neutralizePeerBody } from "../agents/cross-session-envelope.js";
6
6
  export const TASK_NOTIFICATION_TERMINAL_STATUSES = Object.freeze(["completed", "failed", "killed", "cancelled"]);
7
7
  export const NOTIFICATION_INJECTION_OUTCOMES = Object.freeze(["queued", "parked", "parked_durably", "dropped_duplicate"]);
8
8
  export function isNotificationInjectionOutcome(value) {
@@ -88,7 +88,7 @@ export function renderAgentMessageFrame(frame) {
88
88
  }
89
89
  export function renderCrossSessionMessageFrame(frame) {
90
90
  const { body, ...fields } = frame;
91
- return `${buildCrossSessionEnvelope(fields, body)}\n\n${CROSS_SESSION_MESSAGE_NOTICE}`;
91
+ return `${buildCrossSessionEnvelope(fields, body)}\n\n${fields.fromScope !== undefined ? CROSS_PRINCIPAL_MESSAGE_NOTICE : CROSS_SESSION_MESSAGE_NOTICE}`;
92
92
  }
93
93
  export function renderCrossSessionNoticeLine(notice) {
94
94
  return sanitizeUntrustedText(notice.text);
@@ -881,6 +881,14 @@ export interface TaskResult {
881
881
  /** Within-task compaction LLM cost (micro-USD) — part of `costMicroUsd`, so subtracted from root.
882
882
  * ⚠️ See {@link llmRootMicroUsd}: under-reports prior slices' compaction on a multi-slice resource resume. */
883
883
  compactionMicroUsd: number;
884
+ /** The model calls made beside the main loop — the permission classifier's and mods' `$.model.complete` — in
885
+ * micro-USD. An **"of which" line**, not a partition member: this cost is part of `costMicroUsd` and stays INSIDE
886
+ * {@link llmRootMicroUsd}, so `llmRootMicroUsd + compactionMicroUsd === costMicroUsd` keeps holding. Present once
887
+ * at least one such call was booked this leg (absent ⇒ none; a result with no such call is unchanged). A call
888
+ * whose reply carried no usage marks `stats.usageMissing` instead of adding here.
889
+ * ⚠️ Like {@link compactionMicroUsd}, per-leg on a multi-slice `resource_limit` RESUME: the prior slices' side-call
890
+ * spend is inside the exact `costMicroUsd` and `llmRootMicroUsd` but not in this line. */
891
+ sideCallMicroUsd?: number;
884
892
  };
885
893
  };
886
894
  }
@@ -296,11 +296,22 @@ export interface TaskSpec {
296
296
  compactionModel?: ModelRef;
297
297
  /** Thinking level. If omitted, a default from the resolved role's `RoleSpec.thinking` applies. */
298
298
  thinking?: ThinkingLevel;
299
- /** Preset system prompt for this task. */
299
+ /** This task's role text: it replaces the selected role base (`promptRole`). Text carrying a locked section verbatim
300
+ * (an already-assembled prompt) is refused by name (`prompt.assembled_role_refused`). */
300
301
  systemPrompt?: string;
302
+ /** The role base `core/role.base` selects: `"general"` (absent), `"code"`, `"coordinator"`, `"cowork"` (rendered from the
303
+ * mounted tools and the working directory); `systemPrompt` replaces whichever is selected. Not inherited (a child gets
304
+ * the sub-agent persona). A value outside the closed set is refused at prepare. */
305
+ promptRole?: "general" | "code" | "coordinator" | "cowork";
306
+ /** `"minimal"` leaves the core-behavior band out; the locked sections (mode sections in play among them) and
307
+ * `appendSystemPrompt` stay. Absent ⇒ standard. Rides the parent spec seat to every engine-built child (a clamp-table
308
+ * row: no child authors the standard form back). A value outside the closed set is refused at prepare. */
309
+ promptForm?: "minimal";
310
+ /** The deployment's binding (a scenario name): a prompt selector value, read by every overlay's `when.binding` (center, deploy and task alike); rides the parent spec seat; out of grammar (non-blank, ≤ 128 Unicode code points — `PROMPT_BINDING_MAX_CHARS`, counted `[...s].length`, not UTF-16 units) ⇒ `config.prompt_selector_invalid`. */
311
+ promptBinding?: string;
301
312
  /**
302
313
  * APPEND a caller block to the assembled system prompt, keeping the engine's base + harness/safety blocks
303
- * (unlike `systemPrompt`, which REPLACES the base, and `promptProvider`, which rewrites the whole assembly).
314
+ * (unlike `systemPrompt`, which REPLACES the role base).
304
315
  * The lightweight user/scenario-extension seam (≈ CC `--append-system-prompt`): add task-specific rules,
305
316
  * domain context, or a persona tweak without losing the neutral base, cyber/url safety, harness context, or
306
317
  * memory discipline. CALLER-TRUSTED (same trust level as `systemPrompt`/`skills` — NOT user input). Composed
@@ -330,17 +341,6 @@ export interface TaskSpec {
330
341
  name: string;
331
342
  turnReminder?: string;
332
343
  };
333
- /**
334
- * Per-task ROLE-LAYER prompt provider (overrides `RunnerDeps.promptProvider`). Lets one Runner serve
335
- * different scenarios with different role prompts. 提示词主权批: `stableSystem` supplies the role base
336
- * only — core appends the constitution (harness/safety/mode/memory blocks) structurally, so a provider
337
- * cannot drop it by accident; `replaceAll: true` is the explicit full-replacement escape hatch.
338
- * TRUST BOUNDARY: a provider is function-valued and therefore CODE — it can only be set by in-process
339
- * deployment code, never by a wire-level (JSON) task submission; untrusted self-orchestration specs
340
- * additionally have this field stripped by workflow governance. The `prompt.assembled` trace records
341
- * which mode ran, so a `replaceAll` is always observable.
342
- */
343
- promptProvider?: import("../prompts/default.js").PromptProvider;
344
344
  /**
345
345
  * Enable long-term memory for this task. **design/138 S4 (BREAKING): requires `RunnerDeps.memoryBackend`**
346
346
  * (the injection-first memory engine — materialize → file ops → harvest). With a backend configured the
@@ -614,8 +614,8 @@ export interface TaskSpec {
614
614
  * and a name nothing answers never fails the run): both lists are judged once, here and for the
615
615
  * delegation tool's own lists alike; a `denyTools` entry is read as the reference reads it
616
616
  * (`Tool(content)` hides the whole `Tool`, with a host notice); an entry whose spelling no tool name
617
- * can have is REJECTED at task start (`config.agent.unknown_tool`); an entry naming a tool that does
618
- * not exist (a server this deployment does not declare, a stale or misspelt name) is kept as written
617
+ * can have, or is another spelling of a tool the child is handed (a tool of the pool the delegation tool declares, or the engine's catalog: a case twin, a retired name with a successor: `"near_miss"`, while that pool can be listed), is REJECTED at task start (`config.agent.unknown_tool`); an entry naming a tool that does
618
+ * not exist (a server this deployment does not declare, a misspelt name) is kept as written
619
619
  * — it denies, or admits, a tool of that name if one is mounted later — and told to the host once
620
620
  * via `RunnerDeps.onError` phase `"config"` (zero model-facing warning); and
621
621
  * providing this field with NO delegation tool mounted is rejected too
@@ -656,10 +656,11 @@ export interface TaskSpec {
656
656
  * write-capable fs tools (CC's same gate); zero cost/behavior change otherwise. `false` opts out.
657
657
  */
658
658
  lspDiagnostics?: boolean;
659
- /** In-process hooks for this task — the full `Hooks` lifecycle seam (tool pre/post/failure/batch
660
- * interception, prompt gating, stop pushback, compaction taps, permission-denied observation; each
661
- * member's contract is on the interface). Overrides `RunnerDeps.hooks`. */
662
- hooks?: import("./hooks.js").Hooks;
659
+ /** The task seat of the mods bus — `user` tier only, beside `RunnerDeps.mods` (never instead); INTEGRATION §10. Its
660
+ * registrations hang handlers on the `classic.*` events the engine's stations raise (tool pre/post/failure/batch,
661
+ * prompt submit, stop, compaction, permission denied). A delegated child dispatches its parent's task seat as its own
662
+ * (the parent spec seat fills an unset one). */
663
+ mods?: readonly import("./mods/kernel/index.js").ModRegistration<import("./mods/dollar.js").EngineDollar>[];
663
664
  /**
664
665
  * The session's SELF-REPORTED presence for the peer directory (`agent` = what it is, `intent` = what
665
666
  * it is doing; each ≤ 120 chars). The engine never writes a directory row: the same object goes out
@@ -326,8 +326,12 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
326
326
  /**
327
327
  * Hard-**interrupt** the running task — a real abort (not a best-effort hint), equivalent to firing the
328
328
  * task's `signal` (design/47). Refused typed (`steering.not_running`, the steer-family liveness code —
329
- * `cannot interrupt: …`) once the task has finished (the loop's end included: the teardown window
330
- * refuses like `halt`/`steer` do), never silently dropped. **A run that has already given its answer
329
+ * `cannot interrupt: …`) once the task's result is out, never silently dropped. Until then it is
330
+ * answered — the teardown window after the loop's end included, where the consumer still sees a running
331
+ * task: the run's ONE caller-stop gate (this verb, {@link halt}, {@link destroy}, the task's `signal`)
332
+ * cuts any compaction pass still in flight — end-of-task, turn-boundary or prompt-too-long recovery,
333
+ * reported `compaction_outcome{outcome:"mooted", reason:"cancelled"}` with that pass's own `trigger` — and
334
+ * no further pass starts; a stop after the loop's end changes nothing else. **A run that has already given its answer
331
335
  * is not cancellable**: once its last turn ended `stopReason:"stop"` with no queued steer / follow-up
332
336
  * left to serve (a continuation the person had already asked for makes that "stop" work in progress,
333
337
  * not an answer), a stop landing on the run's
@@ -402,8 +406,12 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
402
406
  * naturally — nothing is cut and no boundary stops for it, so the result reports the natural
403
407
  * completion WITHOUT the `haltedByUser` seat and the engine mints `task.halt_unconsumed` (the
404
408
  * verb receipt and that notice are the halt's whole trace; the seat is signed from consumption,
405
- * never from acceptance — see {@link TaskResult.haltedByUser}). Typed refusals: the
406
- * steer-family `steering.not_running` once the task has finished (teardown included); a halt
409
+ * never from acceptance — see {@link TaskResult.haltedByUser}). A halt after the loop's end but before
410
+ * the result is out finds nothing to cut or stop and is answered the same way (`{turnCut:false}` +
411
+ * `task.halt_unconsumed`). Every answered halt trips the run's caller-stop gate: no compaction pass
412
+ * starts after it (the halted boundary's and the end-of-task pass included — the session's next run
413
+ * compacts at its own boundary) and a pass in flight is cut (see {@link interrupt}). Typed refusals: the
414
+ * steer-family `steering.not_running` once the task's result is out; a halt
407
415
  * issued BEFORE the run's first prompt polls the same bounded birth window as {@link steer} and
408
416
  * then stops the run before its first model turn (an empty, cleanly-halted completed run).
409
417
  *
@@ -428,6 +436,8 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
428
436
  * `AbortController.abort()` then `Promise.all(streams.map((s) => s.destroy()))`.
429
437
  *
430
438
  * - **still running** → hard-interrupts it; the run's own `finish()` tears down its execution env.
439
+ * It is a caller stop like {@link interrupt}: a compaction pass in flight (the run's tail included)
440
+ * is cut, so the reap never waits out a summary call's retry schedule.
431
441
  * - **suspended** (`status:"suspended"`) → `finish()` SKIPPED env teardown (the remote env was
432
442
  * `suspendVM`-paused for a durable resume) and the checkpoint is committed → `destroy()` reaps BOTH:
433
443
  * it CAS-**expires** the checkpoint (`CheckpointStore.expire`, fencing any concurrent resume) and —
@@ -12,7 +12,7 @@ export declare class TaskSpecTightenError extends Error {
12
12
  * the override can only ADD denials/asks). Either alone ⇒ that one. This is the central fix: a blind spread
13
13
  * would drop the base policy entirely.
14
14
  * - **every row of the clamp table** (`CLAMP_SET`: `handsReadOnly`, `interactiveTools`, `approvalReach`, the two
15
- * containment faces, `readDenyPatterns`, `oneShot`, `memoryPersistenceCapable`, `fileHistory`) — a base carrying the
15
+ * containment faces, `readDenyPatterns`, `oneShot`, `memoryPersistenceCapable`, `fileHistory`, `promptForm`) — a base carrying the
16
16
  * row's restricting value meeting an override that states a different one ⇒ **throw** (loosening); otherwise the
17
17
  * restricting value wins if either side carries it, an add-only list unions, and an override writing `undefined`
18
18
  * erases nothing.
@@ -20,8 +20,9 @@ export declare class TaskSpecTightenError extends Error {
20
20
  * be loosened because absence is the only other state and an override cannot unset a base value.
21
21
  * - **`onAsk`** — no safe automatic merge (the approver and the policy must be coordinated). Both set to
22
22
  * DIFFERENT values ⇒ **throw**; equal ⇒ keep; one set ⇒ that one.
23
- * - **`hooks`** — no standard composition (stacking hook results is caller-specific). Both set ⇒ **throw**;
24
- * one set ⇒ that one.
23
+ * - **`mods`** — both set ⇒ both ride, base first then override (the task seat is a list and the bus composes it:
24
+ * a registration only ever adds a handler to the chain; names stay unique, refused at admission otherwise).
25
+ * One set ⇒ that one.
25
26
  *
26
27
  * @throws {TaskSpecTightenError} when an override would loosen a stricter base safety field, or when two
27
28
  * incompatible safety values are both set and cannot be merged automatically.
@@ -63,10 +63,8 @@ export function tightenTaskSpec(base, overrides) {
63
63
  "(the approver must be coordinated with the policy); set it in exactly one of base/overrides");
64
64
  }
65
65
  merged.onAsk = base.onAsk ?? overrides.onAsk;
66
- if (base.hooks !== undefined && overrides.hooks !== undefined) {
67
- throw new TaskSpecTightenError("tightenTaskSpec: hooks set on both base and overrides cannot be merged automatically " +
68
- "(hook stacking is caller-specific); set hooks in exactly one of base/overrides, or compose them yourself");
66
+ if (base.mods !== undefined || overrides.mods !== undefined) {
67
+ merged.mods = [...(base.mods ?? []), ...(overrides.mods ?? [])];
69
68
  }
70
- merged.hooks = base.hooks ?? overrides.hooks;
71
69
  return merged;
72
70
  }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The gate's reading of `tool.check`: the ONE comparison of an answer with the verdict standing where it was raised, and the
3
+ * raise over every chain a leg's gate is constrained by (its own bus, then each inherited installation), read by that one
4
+ * comparison. The lanes own the raise points and what each reading does to the pass; this module owns what an answer means.
5
+ */
6
+ import type { PermissionResult, ToolCallRequest } from "./tool-policy.js";
7
+ import type { AllowRuleShadow } from "./allow-rule-shadow.js";
8
+ import { type InstallationAskSettlement, type ToolCheckOutcome, type ToolCheckProjection } from "./mods/stations.js";
9
+ /** A verdict `tool.check` is raised over — never a deny (a standing refusal raises nothing). */
10
+ export type ToolCheckStanding = Exclude<PermissionResult, {
11
+ action: "deny";
12
+ }>;
13
+ /** What a reading came to. `minted` on an ask: the reading minted it over an allow (the ask carries no stamp of the round yet).
14
+ * `approved`: a person an inherited installation's question went to approved an edit of the call — the gate's approved-edit
15
+ * pass takes it, as it takes an edit approved at this leg's own question. */
16
+ export type ToolCheckReading = {
17
+ readonly kind: "stands";
18
+ } | {
19
+ readonly kind: "denied";
20
+ readonly deny: PermissionResult;
21
+ } | {
22
+ readonly kind: "asked";
23
+ readonly ask: Extract<PermissionResult, {
24
+ action: "ask";
25
+ }>;
26
+ readonly minted: boolean;
27
+ readonly marked?: true;
28
+ } | {
29
+ readonly kind: "cleared";
30
+ readonly allow: Extract<PermissionResult, {
31
+ action: "allow";
32
+ }>;
33
+ } | {
34
+ readonly kind: "shadowed";
35
+ readonly shadows: readonly AllowRuleShadow[];
36
+ } | {
37
+ readonly kind: "approved";
38
+ readonly allow: Extract<PermissionResult, {
39
+ action: "allow";
40
+ }> & {
41
+ readonly updatedInput: unknown;
42
+ };
43
+ readonly outstanding?: Extract<PermissionResult, {
44
+ action: "ask";
45
+ }>;
46
+ };
47
+ /** The call a reading is about: its wire name, the args the check judged, the policy's rewrite riding a minted verdict, and the
48
+ * request an inherited installation's question is settled over (the judged args). */
49
+ export interface ToolCheckCall {
50
+ readonly toolName: string;
51
+ readonly judged: unknown;
52
+ readonly rewrite: unknown;
53
+ readonly request: ToolCallRequest;
54
+ readonly signal: AbortSignal | undefined;
55
+ }
56
+ /** One chain a gate raises `tool.check` on: its raise over a projection; for the leg's own bus only, the allow layer's
57
+ * predicate under which its `allow` may clear an ask; for an inherited installation only, the settlement its question takes. */
58
+ export interface ToolCheckChain {
59
+ readonly raise: (projection: ToolCheckProjection) => Promise<ToolCheckOutcome | undefined>;
60
+ readonly mayClear?: () => boolean;
61
+ readonly settle?: InstallationAskSettlement;
62
+ }
63
+ /**
64
+ * The raise over every chain the leg's gate is constrained by, read by the one comparison: the leg's own bus first (its `allow`
65
+ * may clear an ask where the allow layer may), then each inherited installation in order (its `allow` clears nothing — a
66
+ * constraint only tightens). Each chain is raised over the verdict the previous left standing (`project`); a refusal ends it.
67
+ * An inherited installation's `ask` is its own question, settled where its installation froze (`settle`, the settlement its
68
+ * `classic.PreToolUse` ask takes in the fold): refused ⇒ refused; approved ⇒ the verdict standing before it stands (this leg's
69
+ * own question, if any, is still this leg's); approved with an edit ⇒ `approved`, for the gate's approved-edit pass; floated
70
+ * (the call marked for the park) ⇒ asked. The reading of the whole is the last verdict the chains moved the call to — an ask
71
+ * keeps the disclosures any later `allow` made over it — else the disclosures alone, else it stands. Undefined when no chain
72
+ * raised (nothing hangs on the event).
73
+ */
74
+ export declare function readToolChecks(chains: readonly ToolCheckChain[], standing: ToolCheckStanding, call: ToolCheckCall, project: (current: ToolCheckStanding, mayClear: (() => boolean) | undefined) => ToolCheckProjection): Promise<ToolCheckReading | undefined>;
@@ -0,0 +1,80 @@
1
+ import { refusalOf } from "./tool-policy.js";
2
+ import { allowRuleShadowOf } from "./allow-entry.js";
3
+ import { inlineUntrusted } from "./untrusted-text.js";
4
+ import { failedHandlerClause } from "./mods/stations.js";
5
+ const STANDS = Object.freeze({ kind: "stands" });
6
+ function readToolCheck(heard, standing, call, mayClear) {
7
+ const { toolName } = call;
8
+ const refused = (message) => ({ kind: "denied", deny: refusalOf({ action: "deny", message, decisionReason: "hook" }, call.judged) });
9
+ if (heard.kind === "aborted")
10
+ return refused(`the task was cancelled while a tool.check handler was still checking this call to "${toolName}"; the call was NOT executed (fail-closed)`);
11
+ if (heard.kind === "failed")
12
+ return refused(`a tool.check handler ${failedHandlerClause(heard)} while checking this call to "${toolName}"; the call was NOT executed (fail-closed)`);
13
+ if (heard.by === undefined && heard.decision === standing.action)
14
+ return STANDS;
15
+ const { who, why } = speakerOf(heard);
16
+ const rewritten = call.rewrite !== undefined ? { updatedInput: call.rewrite } : {};
17
+ if (heard.decision === "deny")
18
+ return refused(`tool "${toolName}" denied by ${who}${why}`);
19
+ if (heard.decision === "ask") {
20
+ return standing.action === "ask"
21
+ ? { kind: "asked", ask: { ...standing, decisionReason: "hook", ...(heard.reason !== undefined ? { message: heard.reason } : {}) }, minted: false }
22
+ : { kind: "asked", ask: { ...questionOf(heard, toolName), ...rewritten }, minted: true };
23
+ }
24
+ if (standing.action === "allow")
25
+ return STANDS;
26
+ if (mayClear?.() === true)
27
+ return { kind: "cleared", allow: { action: "allow", message: `${who} allowed this call`, decisionReason: "hook", ...rewritten } };
28
+ return { kind: "shadowed", shadows: [allowRuleShadowOf("hook", heard.by !== undefined ? [heard.by] : [])] };
29
+ }
30
+ function speakerOf(heard) {
31
+ return { who: heard.by !== undefined ? `extension "${inlineUntrusted(heard.by, 80)}"` : "an extension", why: heard.reason !== undefined ? `: ${inlineUntrusted(heard.reason, 500)}` : "" };
32
+ }
33
+ function questionOf(heard, toolName) {
34
+ const { who, why } = speakerOf(heard);
35
+ return { action: "ask", message: `tool "${toolName}" needs approval (asked by ${who}${why})`, decisionReason: "hook" };
36
+ }
37
+ export async function readToolChecks(chains, standing, call, project) {
38
+ let raised = false;
39
+ let current = standing;
40
+ let moved;
41
+ const shadows = [];
42
+ for (const chain of chains) {
43
+ const heard = await chain.raise(project(current, chain.mayClear));
44
+ if (heard === undefined)
45
+ continue;
46
+ raised = true;
47
+ const reading = readToolCheck(heard, current, call, chain.mayClear);
48
+ if (reading.kind === "denied")
49
+ return reading;
50
+ if (reading.kind === "asked" && chain.settle !== undefined && heard.kind === "answered") {
51
+ const settled = await chain.settle(questionOf(heard, call.toolName), call.request, call.signal);
52
+ if (settled.action === "deny")
53
+ return { kind: "denied", deny: refusalOf(settled, call.judged) };
54
+ if (settled.action === "allow") {
55
+ if (settled.updatedInput !== undefined)
56
+ return { kind: "approved", allow: { ...settled, updatedInput: settled.updatedInput }, ...(moved?.kind === "asked" ? { outstanding: moved.ask } : {}) };
57
+ continue;
58
+ }
59
+ const ask = current.action === "ask" ? current : settled;
60
+ moved = { kind: "asked", ask, minted: current.action !== "ask" || (moved?.kind === "asked" && moved.minted), marked: true };
61
+ current = ask;
62
+ continue;
63
+ }
64
+ if (reading.kind === "shadowed")
65
+ shadows.push(...reading.shadows);
66
+ if (reading.kind === "asked") {
67
+ moved = { ...reading, minted: reading.minted || (moved?.kind === "asked" && moved.minted), ...(moved?.kind === "asked" && moved.marked === true ? { marked: true } : {}) };
68
+ current = reading.ask;
69
+ }
70
+ if (reading.kind === "cleared") {
71
+ moved = reading;
72
+ current = reading.allow;
73
+ }
74
+ }
75
+ if (!raised)
76
+ return undefined;
77
+ if (moved?.kind === "asked" && shadows.length > 0)
78
+ return { ...moved, ask: { ...moved.ask, allowRuleShadowed: [...(moved.ask.allowRuleShadowed ?? []), ...shadows] } };
79
+ return moved ?? (shadows.length > 0 ? { kind: "shadowed", shadows } : STANDS);
80
+ }
@@ -340,7 +340,7 @@ export type AskGuard = "dangerous_delete" | "unverifiable_delete" | "unverifiabl
340
340
  * REPLACE the model's args before execution (re-validated against the tool schema first).
341
341
  * `deny` may ALSO carry `updatedInput` (1.256 复审 MED-2): it never executes anything, but a
342
342
  * combined-policy deny reports the ACCUMULATED pre-deny rewrite (policy A redacted → policy B
343
- * denied) so a deny OBSERVER (`Hooks.permissionDenied`) sees the final post-rewrite args, not the
343
+ * denied) so a deny OBSERVER (`classic.PermissionDenied`) sees the final post-rewrite args, not the
344
344
  * stale un-redacted ones.
345
345
  * - `ask` requests human confirmation; with no approver wired it resolves deterministically to deny
346
346
  * (headless auto-deny, see `RunnerDeps.onAsk`). `requiresRealApproval: true` (RB-203
@@ -755,12 +755,23 @@ export declare function namespacedCoveringEntries(entries: readonly string[] | u
755
755
  * `nameListHolds` (a covering entry and an exact entry in one list are one rule: it reaches the call iff its name is on the
756
756
  * list)? See {@link namespacedCoveringEntries}. */
757
757
  export declare function namespacedCoveringHit(covering: readonly string[], call: Pick<ToolCallRequest, "toolName" | "face">): boolean;
758
+ /**
759
+ * The tool names a projection component is keyed on, and the member that holds them: a `tool_deny` / `tool_allowlist`'s
760
+ * `names`, a `shell_command`'s `tools` (its `deny` / `allow` are command names, not tool names). A frozen chain holds them only
761
+ * in the one spelling a checkpoint row records a tool name in; the resume screen reads them back by it before anything replays.
762
+ */
763
+ export declare function projectionToolNames(c: ToolPolicyProjectionComponent): {
764
+ readonly member: "names" | "tools";
765
+ readonly list: unknown;
766
+ };
758
767
  /**
759
768
  * Execute a persisted {@link ToolPolicyProjection} against a call (F-012 L1): returns the first
760
769
  * component's deny, or `undefined` when the projection has no opinion (it is deny-only by
761
770
  * construction — never an allow, never an ask). This is what a durable RESUME runs instead of
762
771
  * trusting a re-supplied policy's execution half for the frozen deny data: the projection persisted
763
772
  * at suspend is the authority for what the chain refused, whatever a re-supplied closure claims.
773
+ * A tool name is matched as recorded, which is the rule syntax's reading only for a name in its canonical spelling: the resume
774
+ * screen refuses a frozen chain holding any other ({@link projectionToolNames}) before this runs on it.
764
775
  */
765
776
  export declare function checkToolPolicyProjection(projection: Pick<ToolPolicyProjection, "components">, req: Pick<ToolCallRequest, "toolName" | "args" | "face">): Extract<PermissionResult, {
766
777
  action: "deny";
@@ -920,20 +931,6 @@ export declare const DECISION_MEMBERS: readonly DecisionMember[];
920
931
  export declare function refuseOutOfContractDecision(d: PermissionResult, opts?: {
921
932
  reasonIsNonInput?: boolean;
922
933
  }): PermissionResult;
923
- /**
924
- * The PreToolUse hook seat's receipt under its public name — what a host that composes several hooks into the one the
925
- * engine takes runs on EACH slot's result before folding it, so it reads the result the way the engine will. It is
926
- * {@link refuseOutOfContractDecision} at the hook seam (`reasonIsNonInput`), the same function the engine's seat calls (hooks.ts
927
- * `screenPreToolUseResult`): no second statement of the contract.
928
- *
929
- * What comes back, for an object: the engine's own refusal (a `deny` for which {@link isEngineRefusal} is true — return it as the
930
- * composed hook's answer and the engine takes it as its own fail-closed deny), or the engine's frozen, detached copy of the
931
- * result (fold the copy, never the original). `undefined`, `null` and `false` are no opinion and come back as themselves. The
932
- * caller's object is not changed and none of its code runs; an answer handed back to this function returns as itself.
933
- */
934
- export declare function receiveHookResult(result: unknown): (PermissionResult & {
935
- additionalContext?: string;
936
- }) | null | undefined | false;
937
934
  /** The raw tool-name lists a name-keyed policy was built from (audit feed, see block note above). */
938
935
  export interface ToolPolicyNameSets {
939
936
  readonly allow?: readonly string[];
@@ -953,15 +950,20 @@ export type NamedToolPolicy = ToolPolicy & {
953
950
  export declare function toolPolicyNameSets(p: ToolPolicy | undefined): readonly ToolPolicyNameSets[];
954
951
  /**
955
952
  * Name-based allow/deny. `deny` always wins. If `allow` is provided, only those tools are permitted
956
- * (everything else denied). Without `allow`, everything not in `deny` is permitted.
957
- * Carries {@link NamedToolPolicy.nameSets} so the host can audit the raw lists against the mounted
953
+ * (everything else denied). Without `allow`, everything not in `deny` is permitted. Each entry is read by the rule
954
+ * syntax (`ruleSpellingOf`): a name, or `Tool()` / `Tool(*)` — the bare `Tool`, as every list reader reads them, once however
955
+ * many spellings write it; any other spelling is not a tool name (`onInvalidName`), and neither is the wildcard `*` (`*`,
956
+ * `*()`, `*(*)`) in `deny`: it names no tool, and the entry would be kept and never match. In `allow` it is one entry no tool
957
+ * carries — the list admits what else it names, and nothing for it.
958
+ * Carries {@link NamedToolPolicy.nameSets} (the names as read) so the host can audit the lists against the mounted
958
959
  * pool ([c209-E] advisory); enforcement semantics are unchanged.
959
960
  */
960
961
  export declare function createAllowDenyPolicy(opts: {
961
962
  allow?: string[];
962
963
  deny?: string[];
963
964
  /**
964
- * What to do with an entry that is not a tool NAME but a rule CONTENT form (`Bash(ps:*)`, `Edit(src/**)`).
965
+ * What to do with an entry that is not a tool NAME: a rule CONTENT form (`Bash(ps:*)`, `Edit(src/**)`), a spelling
966
+ * the rule syntax reads no tool name in (`" Bash"`, `Bash\t(*)`, `-deploy`), or the wildcard `*` in the deny list.
965
967
  * `"throw"` (default, matching {@link createPermissionRulePolicy}'s posture toward a rule it cannot
966
968
  * compile) refuses at construction; `"skip"` drops the entry and reports it. Under BOTH, the entry never
967
969
  * silently narrows the allowlist.
@@ -1838,6 +1840,48 @@ export declare function tryCloneArgs<T>(v: T): {
1838
1840
  reason: string;
1839
1841
  cause?: unknown;
1840
1842
  };
1843
+ /** The ONE mint of a refusal's reported args: the deny carrying the args its refusing station or layer JUDGED, which the gate's
1844
+ * exit reports (`finalInput`, the deny observer's `input`); a deny already carrying the args its own layers judged (a composed
1845
+ * chain's, nested ones included) keeps them. Read by the gate's lanes and by {@link combinePolicies}. Only a deny is changed. */
1846
+ export declare function refusalOf<D extends PermissionResult>(deny: D, judged: unknown): D;
1847
+ /**
1848
+ * A PreToolUse hook's `ask` folded over a verdict by `deny > ask > allow` — the ONE law for the gate's first screening and for
1849
+ * an approved edit's re-screen. A deny stands. Over an allow, the hook's own ask, RECONSTRUCTED rather than spread (its message,
1850
+ * its real-approval demand, its rewrite) under the hook provenance the engine stamps. Over an ask, that ask keeps every member,
1851
+ * takes the hook provenance and the hook's real-approval demand, and its message carries the hook's beside its own — a person
1852
+ * clearing one ask that stands for two gates sees both reasons.
1853
+ */
1854
+ export declare function foldHookAsk(verdict: Exclude<PermissionResult, {
1855
+ action: "deny";
1856
+ }>, hookAsk: Extract<PermissionResult, {
1857
+ action: "ask";
1858
+ }>): Extract<PermissionResult, {
1859
+ action: "ask";
1860
+ }>;
1861
+ export declare function foldHookAsk(verdict: PermissionResult, hookAsk: Extract<PermissionResult, {
1862
+ action: "ask";
1863
+ }>): PermissionResult;
1864
+ /**
1865
+ * THE args of one tool-gate pass — what every judge of the call reads and what the call runs with: ONE engine-owned
1866
+ * value, the {@link tryCloneArgs} snapshot of what was handed in, deep-frozen. The gate mints it at its entry from the
1867
+ * model's args, and every value that replaces it comes through here too (a hook's or a policy's rewrite at the decision
1868
+ * receipt, a person's edit at the approver's answer), so the args of a pass are always such a value. Because it cannot
1869
+ * change, it is handed to every judge as it is — a policy, the org and stored-rule lanes, the classifier, an extension's
1870
+ * check, the person's card — and none of them can make what runs differ from what was judged: an in-place write throws
1871
+ * (a rewrite is an answer's `updatedInput`). An owned value handed back is itself; a primitive is immutable as it is.
1872
+ * A value the snapshot refuses is refused the same way (exotic args are a refusal, never a shared reference).
1873
+ */
1874
+ export declare function ownArgs<T>(v: T, root?: string): {
1875
+ ok: true;
1876
+ value: T;
1877
+ } | {
1878
+ ok: false;
1879
+ reason: string;
1880
+ cause?: unknown;
1881
+ };
1882
+ /** A call's argument reading (the loop's: the tool's preparation, the schema's coercions) whose every value is engine-owned
1883
+ * like a pass's args ({@link ownArgs}) — the gate's face seat and the resumed call's belt seat read through this one. */
1884
+ export declare function ownedReading(read: (args: unknown) => unknown): (args: unknown) => unknown;
1841
1885
  /**
1842
1886
  * A label for a value that was THROWN at us, safe to put in a fail-closed refusal. Never coerces: `String(x)`
1843
1887
  * throws on a null-prototype object or a untrusted `toString`/`Symbol.toPrimitive`, and the thrower here is