@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,29 +1,84 @@
1
1
  /**
2
2
  * THE judgment of every tool-name list one prepared task receives — the run's own selector lists (`TaskSpec.allowTools` /
3
- * `TaskSpec.excludeTools`, unless the delegation lane spawned it — its spawning run judged them where they were mounted), the definitions it
4
- * carries (`TaskSpec.agents`), and the definitions and tool-level lists a mounted delegation tool carries (the `authored` faces
5
- * — the engine's built-ins are not judged; only a tool a deployment mounted (depth 0) publishes them). One rule for both sides:
6
- * a value that is not a list, an entry that is not a string and a spelling that can name no tool are REFUSED; an entry whose
7
- * name no tool of the universe answers to (a server this deployment does not declare, a stale or misspelt name) is KEPT as
8
- * written — the selector reads every entry by name, so a denied one hides a tool of that name whenever one is mounted and an
9
- * allowed one admits it — and told to the host, one account per entry. And one contradiction, judged on every leg: a
10
- * denylist (the run's own or one of its ceiling) that reaches a tool the leg's kind relies on (the catalog's protocol column)
11
- * is refused — neither a silently ignored deny nor a silently crippled leg.
3
+ * `TaskSpec.excludeTools`; when the delegation lane spawned it, its spawning run judged them where they were mounted, and the evidence
4
+ * it handed down spares them here), the definitions it carries (`TaskSpec.agents`), and the definitions and tool-level lists a mounted
5
+ * delegation tool carries (the `authored` faces — the engine's built-ins are not judged; only a tool a deployment mounted (depth 0)
6
+ * publishes them). One rule for both sides: a value that is not a list, an entry that is not a string, a spelling that can name no tool
7
+ * and a spelling that is another spelling of a tool the list's universe carries (`BASH` beside `Bash`) are REFUSED; an entry whose
8
+ * name no tool of the universe answers to (a server this deployment does not declare, a misspelt name) is KEPT as written — the
9
+ * selector reads every entry by name, so a denied one hides a tool of that name whenever one is mounted and an allowed one admits
10
+ * it — and told to the host, one account per entry. And one contradiction, judged on every leg: a denylist (the run's own or one
11
+ * of its ceiling) that reaches a tool the leg's kind relies on (the catalog's protocol column) is refused — neither a silently
12
+ * ignored deny nor a silently crippled leg.
12
13
  *
13
- * Universe = the task's assembled roster before the valve, every tool the catalog describes, every mounted delegation tool's
14
- * pool and the caller's own tools (names and aliases), and the protocol peers the task declares (a namespaced spelling under a
15
- * declared peer names a tool of it — the peer's tool list is runtime data, so the peer is what is checked). A delegation tool
16
- * whose factory injects tools per spawn with no declared roster (`extraTools`) lists none of them here; a kept entry reaches
17
- * its products by name like any other later-mounted tool.
14
+ * Two kinds of list, two universes. A ROOT-facing list bounds the tools of the run that holds it: the run's own lists (also the
15
+ * ceiling of every child), the policy name audit and the session-rules write gate ask the same question of it. Its universe is the
16
+ * run's roster before the valve, the caller's own tools, every tool the catalog describes (`rootFacingToolNames`) and the exact
17
+ * names of the pools its reachable delegation tools declare and can list — and another spelling of a carried name is always refused,
18
+ * whatever a delegation tool injects per spawn. A CHILD-facing list bounds a child that does not exist yet: a definition's two
19
+ * lists and a delegation tool's two lists. Its universe is the pool the delegation tool that hands the child declares (names, aliases, the
20
+ * declared `extraToolNames`, and the tool's own name: the child is handed the tool again, rebuilt, while its depth allows) and the catalog — not the
21
+ * spawning run's roster, which the child is not handed; every definition is judged against each reachable delegation tool's own pool; a delegation tool whose factory
22
+ * injects tools per spawn with no declared roster lists none of its pool, so there another spelling is kept and told (it may be one
23
+ * of that pool's own). Only the delegation tools the run's own selector leaves are read, in both: a tool it takes out hands nobody
24
+ * anything. A layer a run inherits (its ceiling) is not asked again: the run that wrote it asked its own universe, and a layer a
25
+ * checkpoint row restored is read for its spelling before the claim. The same goes for the lists a delegation tool hands its child
26
+ * (the child's own): when the spawning run read them against a pool it could list, its evidence spares them in the child. When it
27
+ * could not (the keep above), the child is the run whose roster can answer — it refuses another spelling of a tool of its own
28
+ * universe (its roster, the catalog, the pools it can list, and the delegation tool that spawned it, under its exact mounted name: a name
29
+ * of the child's lineage, mounted at its depth or not — an exact hit of that name is the tool's own, whatever else reads as a twin of it),
30
+ * and the spawning run already told what it kept, so nothing is told a second time.
18
31
  *
19
32
  * Throws `config.tool_face_control` for the run's own lists and the protocol contradiction, `config.agent.unknown_tool` for a
20
- * definition's or a delegation tool's lists — synchronous, like the phase that calls it.
33
+ * definition's or a delegation tool's lists (`detail.reason`: `unknown_name` for a spelling no tool name can have, `near_miss` for
34
+ * another spelling of a tool of the universe) — synchronous, like the phase that calls it.
21
35
  */
22
36
  import type { AgentTool } from "../../internal/harness.js";
37
+ import { valveLeaves } from "../../agents/tool-filter.js";
23
38
  import { type ProtocolId } from "../protocol-table.js";
24
39
  import type { ToolLegKind, ToolSelectorLayer } from "../tool-face.js";
40
+ import { type ConstraintChainEntry } from "../tool-policy.js";
25
41
  import type { TaskSpec } from "../types.js";
26
- import type { AnnounceOnceSink } from "./contracts.js";
42
+ import type { CheckpointErrorReason } from "../checkpoint-store.js";
43
+ import type { AnnounceOnceSink, RunInternals } from "./contracts.js";
44
+ /** What the delegation tools a run mounts hand their children (the pools of {@link delegationPoolReading}). */
45
+ interface DelegationPoolReading {
46
+ readonly tools: NonNullable<TaskSpec["tools"]>;
47
+ readonly names: Set<string>;
48
+ readonly complete: boolean;
49
+ }
50
+ /**
51
+ * THE judgment of the name a delegation tool is mounted under: the name it declares for itself (`createSubagentTool({ name })`, the default
52
+ * name when none is given), which the factory binds to the `execute` that carries the delegation out ({@link declaredDelegationNameOf}) —
53
+ * so a copy of the tool, a product of it, a stripped or shell copy all still say it. A delegation tool is ONE tool with ONE name: the lists
54
+ * of its agent definitions, the copy of it a child is handed, the rebuilt copy a run's own definitions produce and the prompt text it speaks
55
+ * all say the declared name, while the roster, the pool reading and the model's call say the mounted one. A mount whose `name` differs from
56
+ * the declared one makes the tool answer to two names — a denied list that names one of them is read against the other — so it is REFUSED,
57
+ * naming both names and the two ways to one name. This is the sentence of that refusal for the first such entry of the rosters given — or
58
+ * `undefined`; it never throws (an entry whose members cannot be read is not judged here: the roster snapshot refuses it). A tool the
59
+ * factory did not make, and a roster that is no list (the doors' to judge), are not read.
60
+ */
61
+ export declare function renamedDelegationMountSentence(...rosters: unknown[]): string | undefined;
62
+ /**
63
+ * The refusal of a renamed delegation mount at prepare (`config.tool_face_control`, `detail.reason: "renamed_mount"`), asked of every roster
64
+ * the run holds: the one the caller mounted and the one the per-task rebuild (a function the caller's tool supplies) handed back. A resume
65
+ * asks the roster it is handed once more before the claim (this same function, through the resume screen's config-refusal channel), so the row stays pending.
66
+ */
67
+ export declare function refuseRenamedDelegationMounts(...rosters: unknown[]): void;
68
+ /**
69
+ * THE reading of what the delegation tools a run mounts hand their children, read after the run's own tool valve: only a delegation
70
+ * tool the valve leaves (`leaves`, the valve's one reading — `valveLeaves`) counts — one it takes out hands nobody anything, and neither
71
+ * its pool names nor an unlistable pool of it belong to any universe. The tools themselves, every pool tool's name and alias (a declared
72
+ * `extraToolNames` roster included), and whether every one of those pools can be listed: a delegation tool whose factory injects tools
73
+ * per spawn with no declared roster has no listable pool (the static `tools` it was given included), so a name outside the listed ones
74
+ * may be one of its own. This is the one place the pool side of both universes is defined; the list judgment below and the policy name
75
+ * audit ask it.
76
+ */
77
+ export declare function delegationPoolReading(callerTools: NonNullable<TaskSpec["tools"]>, leaves: ReturnType<typeof valveLeaves>): DelegationPoolReading;
78
+ /** The arms of this module's `config.tool_face_control` refusal that a resume carries before the claim as `detail.reason` of a `checkpoint.config_refused` — the same words
79
+ * ({@link CheckpointErrorReason}): a list the row recorded that is not a list / has a member that is not a string / has a spelling no tool name can have / is not in the
80
+ * spelling a row records, a record that is not one, a renamed delegation mount, an occupied table of declared names. */
81
+ export type PersistedToolFaceReason = Extract<CheckpointErrorReason, "not_a_list" | "not_a_string" | "unknown_name" | "unsupported_pattern" | "invalid_record" | "renamed_mount" | "registry_occupied">;
27
82
  /**
28
83
  * The names a definition's denied-tools entries stand for, for a lane that has neither a roster nor a notice sink at the point
29
84
  * it builds its own policy (a workflow leg's agentType): each entry is read by the one reading, so `Tool(content)` denies the
@@ -32,6 +87,22 @@ import type { AnnounceOnceSink } from "./contracts.js";
32
87
  * leg's roster and a sink; the leg's own policy-name audit is what reads them.
33
88
  */
34
89
  export declare function deniedToolNamesOf(where: string, value: unknown): string[];
90
+ /**
91
+ * THE read-back of the tool names a checkpoint row carries, before the claim: the ceiling the resumed leg will run under when it is
92
+ * the row's (`ceiling`: absent when a live seat hands one) — each layer read by {@link readSelectorLayer} as a recorded layer — and
93
+ * the frozen policy chain (`inheritedGate.constraintChain`; each component's members {@link projectionToolNames} names), whose
94
+ * replay matches a name as recorded, which is the rule syntax's reading only for a name in its canonical spelling. The refusal
95
+ * sentence of the first entry neither reading may be applied to, naming it and where it sits, or `undefined`; a member that is not
96
+ * a list, or an entry that is not a string, is named by its type only. And the delegation tool the row records as having written the
97
+ * leg's own lists (`ownLists`, absent when a live seat hands one): it joins the universe those lists are asked of, so it must be a name.
98
+ * The refusal is its sentence and the arm it is ({@link CheckpointErrorReason}); {@link refusePersistedToolNames} throws it as prepare's own refusal.
99
+ */
100
+ export declare function persistedToolNamesRefusal(ceiling: unknown, chain: readonly ConstraintChainEntry[] | undefined, ownLists?: unknown): {
101
+ readonly message: string;
102
+ readonly reason: PersistedToolFaceReason;
103
+ } | undefined;
104
+ /** {@link persistedToolNamesRefusal} as prepare's own refusal (`config.tool_face_control`, the arm as `detail.reason`): what a resume's pre-claim screen throws through the resume's one refusal channel. */
105
+ export declare function refusePersistedToolNames(ceiling: unknown, chain: readonly ConstraintChainEntry[] | undefined, ownLists?: unknown): void;
35
106
  /**
36
107
  * The upstream judgment of a run's own lists, when it holds: the evidence digest the spawning run handed down (live) or the resumed row
37
108
  * recorded, returned only when it equals the digest of the lists this prepare read — the evidence is bound to the lists it was minted
@@ -41,9 +112,21 @@ export declare function boundToolListsJudgment(evidence: string | undefined, own
41
112
  readonly allow: readonly string[] | undefined;
42
113
  readonly exclude: readonly string[] | undefined;
43
114
  }): string | undefined;
115
+ /**
116
+ * The record of the delegation tool that wrote a leg's own lists, held only for the lists it wrote: the live seat's (the delegation lane
117
+ * mints it with the digest of exactly the lists it handed the child) or, with none, the resumed row's. A prepare whose own lists digest to
118
+ * the record's `lists` keeps it — they are the lists that tool wrote, so their refusals name it and its name is a name of the leg's
119
+ * lineage; any other lists (a resume whose host handed another table) are the host's own `TaskSpec` seats, and the leg asks them as such
120
+ * with no lineage name cleared. A record that is not one (a host that set the live seat itself) refuses the leg, as a row's does before the
121
+ * claim: `config.tool_face_control`, `detail.reason: "invalid_record"`.
122
+ */
123
+ export declare function boundOwnToolLists(record: unknown, own: {
124
+ readonly allow: readonly string[] | undefined;
125
+ readonly exclude: readonly string[] | undefined;
126
+ }): RunInternals["ownToolLists"];
44
127
  export interface RunToolListsInput {
45
- /** borrowed-readonly — the REBOUND spec: `agents` (the task's definitions) and `tools` (the caller's tools and the mounted delegation tools). */
46
- spec: Pick<TaskSpec, "agents" | "tools">;
128
+ /** borrowed-readonly — the REBOUND spec: `agents` (the task's definitions), `tools` (the caller's tools and the mounted delegation tools) and `excludeAllTools` (the valve's whole-face switch, which takes the delegation tools out too). */
129
+ spec: Pick<TaskSpec, "agents" | "tools" | "excludeAllTools">;
47
130
  /** borrowed-readonly — the assembled mount array BEFORE the selector's valve (names + aliases = the roster half of the universe). */
48
131
  tools: ReadonlyArray<AgentTool>;
49
132
  /** borrowed-readonly — the peers the task declares, per protocol of the protocol table (its MCP servers, its A2A peers): a namespaced
@@ -61,15 +144,33 @@ export interface RunToolListsInput {
61
144
  /** borrowed-readonly — every layer of the run's selector (the ceiling, then its own) and the kinds of leg it is. */
62
145
  layers: readonly ToolSelectorLayer[];
63
146
  legs: readonly ToolLegKind[];
64
- /** True ⇔ the spawning run's prepare judged exactly these own lists where they were mounted — the evidence digest it handed down
65
- * (live, or recorded on the resumed row) equals the digest of the lists this prepare read ({@link boundToolListsJudgment}). */
147
+ /** True ⇔ the spawning run's prepare judged exactly these own lists where they were mounted, against a pool it could list (as the
148
+ * child-facing lists of the delegation tool or definition that wrote them) — the evidence digest it handed down (live, or recorded
149
+ * on the resumed row) equals the digest of the lists this prepare read ({@link boundToolListsJudgment}). They are then not judged
150
+ * again: neither told nor refused. */
66
151
  judgedUpstream: boolean;
67
- /** Whose lists the run's own are, when the run that spawned it wrote them ({@link delegationListWhere}); absent ⇒ the run's own
68
- * `TaskSpec` seats. */
69
- ownWhere: string | undefined;
152
+ /** True ⇔ a delegation lane spawned this leg inside a prepared run, which read these own lists against a pool it could not list: it
153
+ * kept what it could not judge and told it (no evidence digest was handed down). They are judged here, against this leg's roster,
154
+ * and refused as any own list is — but nothing is told a second time. Absent ⇒ nobody told. */
155
+ toldUpstream?: boolean;
156
+ /** The delegation tool (and the agent definition) whose lists the run's own are, when the run that spawned it wrote them
157
+ * (`RunInternals.ownToolLists`); absent ⇒ the run's own `TaskSpec` seats. Its sentence is {@link delegationListWhere}; its tool name is
158
+ * a name of the leg's lineage, so the run's own lists are asked of a universe that carries it. */
159
+ ownBy: RunInternals["ownToolLists"];
70
160
  /** borrowed-readonly — the once-per-session ledger whose operator sink carries the notices. */
71
161
  onceLedger: Pick<AnnounceOnceSink, "onError">;
72
162
  /** borrowed-readonly — the acquired session's id (operator-line context). */
73
163
  sessionId: string;
74
164
  }
75
165
  export declare function judgeRunToolLists(input: RunToolListsInput): void;
166
+ /**
167
+ * THE judgment of a tool ceiling a HOST wrote (`RunWorkflowOptions.toolCeiling`), asked of one workflow agent's spec before it launches.
168
+ * A ceiling a prepared run hands down was judged where it was written and is not asked again; one a host wrote was judged nowhere, and
169
+ * it bounds the tools of every agent that holds it — a root-facing list: it is read against the catalog, the agent's caller tools and the
170
+ * listable pools of the delegation tools the agent's own selector leaves (the layers above the host's — a launching run's —, the host's
171
+ * and the agent's own lists together: a tool they take out hands nobody anything), and another spelling of one of those is refused (`config.tool_face_control`,
172
+ * `detail.reason: "near_miss"`) rather than kept as a deny that hides nothing. A name no tool answers to stays kept (a tool of that
173
+ * name may be mounted later), unannounced: the host wrote no spec this leg could name the list of.
174
+ */
175
+ export declare function judgeHostToolCeiling(layers: readonly ToolSelectorLayer[], agent: Pick<TaskSpec, "tools" | "allowTools" | "excludeTools" | "excludeAllTools">, above?: readonly ToolSelectorLayer[]): void;
176
+ export {};
@@ -1,11 +1,63 @@
1
- import { deniedProtocolTools, delegationListWhere, listReaches, notAListSentence, toolListsDigest, notAStringSentence, readAllowedToolList, readDeniedEntry, readDeniedToolList } from "../../agents/tool-filter.js";
1
+ import { compileToolSelector, valveLeaves, deniedProtocolTools, delegationListWhere, isCanonicalToolName, isToolSelectorLayer, listReaches, notAListSentence, toolListsDigest, notAStringSentence, readAllowedToolList, readDeniedEntry, readDeniedToolList } from "../../agents/tool-filter.js";
2
2
  import { readToolNameList, valueTypeLabel } from "../tool-name-list.js";
3
- import { compileAllowList, inertEntryPhrase, renderListEntry } from "../allow-entry.js";
3
+ import { compileAllowList, inertEntryPhrase, renderListEntry, rootFacingToolNames } from "../allow-entry.js";
4
4
  import { inlineUntrusted } from "../untrusted-text.js";
5
5
  import { ENGINE_TOOLS } from "../tool-catalog-entries.js";
6
+ import { callerToolNameProblem } from "../caller-tool-name.js";
6
7
  import { mintNamespacePrefix } from "../protocol-naming.js";
7
8
  import { PROTOCOL_TABLE, protocolOf } from "../protocol-table.js";
8
- import { splitNamespacedName } from "../tool-name-aliases.js";
9
+ import { mountedToolNames, splitNamespacedName } from "../tool-name-aliases.js";
10
+ import { projectionToolNames } from "../tool-policy.js";
11
+ import { declaredDelegationNameOf } from "../delegation-name.js";
12
+ export function renamedDelegationMountSentence(...rosters) {
13
+ for (const tools of rosters) {
14
+ if (!Array.isArray(tools))
15
+ continue;
16
+ for (const t of tools) {
17
+ const declared = declaredDelegationNameOf(t);
18
+ if (declared === undefined)
19
+ continue;
20
+ try {
21
+ const mounted = t.name;
22
+ if (declared === mounted)
23
+ continue;
24
+ return `The delegation tool declared as "${inlineUntrusted(declared, 80)}" is mounted under the name "${inlineUntrusted(String(mounted), 80)}": one tool would answer to two names (the agent definitions' tool lists, the copy a child is handed and the tool's prompt text speak the declared one; the roster and the model's call speak the mounted one). Mount it under its declared name, or declare the name you mount it under (\`createSubagentTool({ name })\`).`;
25
+ }
26
+ catch {
27
+ }
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+ export function refuseRenamedDelegationMounts(...rosters) {
33
+ const sentence = renamedDelegationMountSentence(...rosters);
34
+ if (sentence !== undefined)
35
+ throw refused(sentence, "config.tool_face_control", "renamed_mount");
36
+ }
37
+ function poolOf(tools) {
38
+ return { tools, names: mountedToolNames([...tools.map((t) => ({ name: t.name })), ...tools.flatMap((t) => t.agentToolPool ?? [])]), complete: tools.every((t) => t.agentToolPool !== undefined) };
39
+ }
40
+ export function delegationPoolReading(callerTools, leaves) {
41
+ return poolOf(callerTools.filter((t) => t.agentToolFaces !== undefined && leaves(t)));
42
+ }
43
+ function peersOf(known, declaredPeers) {
44
+ const peers = new Set(PROTOCOL_TABLE.flatMap((ns) => (declaredPeers[ns.id] ?? []).map((p) => mintNamespacePrefix(ns, p.name))));
45
+ for (const name of known) {
46
+ const ns = protocolOf(name);
47
+ const split = ns !== undefined ? splitNamespacedName(name) : undefined;
48
+ if (split !== undefined && split.peer !== "")
49
+ peers.add(mintNamespacePrefix(split.ns, split.peer));
50
+ }
51
+ return peers;
52
+ }
53
+ function rootFacingUniverse(mounted, pool, declaredPeers) {
54
+ const known = rootFacingToolNames([...mounted, ...pool.names]);
55
+ return { known, peers: peersOf(known, declaredPeers), complete: true, carrierOf: (name) => (mounted.has(name) ? "run" : pool.names.has(name) ? "pool" : "catalog") };
56
+ }
57
+ function childFacingUniverse(pool, declaredPeers) {
58
+ const known = new Set([...mountedToolNames(ENGINE_TOOLS), ...pool.names]);
59
+ return { known, peers: peersOf(known, declaredPeers), complete: pool.complete, carrierOf: (name) => (pool.names.has(name) ? "pool" : "catalog") };
60
+ }
9
61
  const DENY_LIST_NAMES_ONLY = "To block by path or command, write a deny rule in the caller's permission policy: a tool-name list only takes tool names (it narrows which tools are mounted).";
10
62
  function universeCarries(reach, entry, universe) {
11
63
  for (const name of universe.known)
@@ -23,34 +75,46 @@ function refused(message, code, reason) {
23
75
  return e;
24
76
  }
25
77
  const LIST_WORD = { allowed: "allowed tools", denied: "denied tools" };
78
+ const NEAR_MISS_EFFECT = {
79
+ allowed: "it admits nothing, so the tool it was written for is not granted",
80
+ denied: "it hides nothing, so the tool it was written for stays available to the agent",
81
+ };
82
+ function nearMissRefusal(where, side, flaw, code) {
83
+ return refused(`${where} declares tool ${inertEntryPhrase(flaw)} in its ${LIST_WORD[side]}, a spelling that reaches no tool a run mounts — ${NEAR_MISS_EFFECT[side]}. Write the name as the tool is mounted.`, code, "near_miss");
84
+ }
26
85
  function grammarRefusal(where, side, flaw, code) {
27
86
  return refused(`${where} declares tool ${inertEntryPhrase(flaw)} in its ${LIST_WORD[side]}, a spelling no tool name can have — fix the entry. ${DENY_LIST_NAMES_ONLY}`, code, "unknown_name");
28
87
  }
88
+ function readableToolNameList(where, side, value, code) {
89
+ if (value === undefined || value === null)
90
+ return [];
91
+ const list = readToolNameList(value);
92
+ if (list.kind !== "entries")
93
+ throw refused(notAListSentence(where, side, list), code, "not_a_list");
94
+ return list.entries.map((entry, index) => {
95
+ const read = readDeniedEntry(entry);
96
+ if (read.kind === "not_a_string")
97
+ throw refused(notAStringSentence(where, side, index, read.type), code, "not_a_string");
98
+ if (read.kind === "unreadable")
99
+ throw grammarRefusal(where, side, { entry: read.entry, reason: "grammar" }, code);
100
+ if (side === "denied" && read.name === "*") {
101
+ throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: a denied list has no wildcard — the entry would hide nothing. To give the agent no tools, write an empty allowed list.`, code, "unsupported_pattern");
102
+ }
103
+ return { entry: entry, name: read.name, content: read.content };
104
+ });
105
+ }
29
106
  const KEPT_ENTRY = {
30
107
  allowed: "it grants nothing today and stays in force for a tool of that name mounted later",
31
108
  denied: "it denies nothing today and stays in force for a tool of that name mounted later",
32
109
  };
110
+ const KEPT_ENTRY_UNLISTED_POOL = "so it is kept here: the pool this delegation tool hands its child cannot be listed, and the spawned child judges the entry against its own roster (another spelling of a tool it carries refuses the child before it starts; an exact name takes effect; a name nothing answers to there stays in force for a tool of that name mounted later)";
33
111
  const PEER_WORD = { mcp: "MCP server", a2a: "A2A peer" };
34
112
  function judgeToolNameList(where, side, value, universe, advise, code) {
35
- if (value === undefined || value === null)
36
- return;
37
- const list = readToolNameList(value);
38
- if (list.kind !== "entries")
39
- throw refused(notAListSentence(where, side, list), code, "not_a_list");
40
- let index = -1;
41
- for (const entry of list.entries) {
42
- index += 1;
43
- if (typeof entry !== "string")
44
- throw refused(notAStringSentence(where, side, index, valueTypeLabel(entry)), code, "not_a_string");
45
- if (entry === "*") {
46
- if (side === "allowed")
47
- continue;
48
- throw refused(`${where} declares "*" in its ${LIST_WORD[side]}: a denied list has no wildcard — the entry would hide nothing. To give the agent no tools, write an empty allowed list.`, code, "unsupported_pattern");
49
- }
50
- const read = readDeniedEntry(entry);
51
- const toolName = read.kind === "name" ? read.name : entry;
52
- const name = side === "denied" ? toolName : entry;
53
- const content = side === "denied" && read.kind === "name" && read.content;
113
+ for (const { entry, name: toolName, content: written } of readableToolNameList(where, side, value, code)) {
114
+ if (toolName === "*" && !written)
115
+ continue;
116
+ const name = side === "denied" || !written ? toolName : entry;
117
+ const content = side === "denied" && written;
54
118
  const reach = side === "denied" ? readDeniedToolList([entry]) : (readAllowedToolList([entry]) ?? readDeniedToolList([]));
55
119
  const split = splitNamespacedName(name);
56
120
  if (split !== undefined && split.peer === "*" && split.tool === undefined) {
@@ -59,9 +123,9 @@ function judgeToolNameList(where, side, value, universe, advise, code) {
59
123
  throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: an allowed list has no protocol-wide form — name a peer (\`${split.ns.prefix}<peer>\`) or its tools.`, code, "unsupported_pattern");
60
124
  }
61
125
  const { inert } = compileAllowList([toolName], "deny", universe.known);
62
- const flaw = inert[0] === undefined ? undefined : { ...inert[0], entry };
63
- if (flaw !== undefined && flaw.reason === "grammar")
64
- throw grammarRefusal(where, side, flaw, code);
126
+ const flaw = inert[0] === undefined ? undefined : { ...inert[0], entry, ...(inert[0].reason === "near_miss" && inert[0].currentName !== undefined ? { carriedBy: universe.carrierOf(inert[0].currentName) } : {}) };
127
+ if (universe.complete && flaw?.currentName !== undefined)
128
+ throw nearMissRefusal(where, side, flaw, code);
65
129
  if (toolName !== name) {
66
130
  advise(new Error(`${where} declares ${renderListEntry(entry)} in its allowed tools: an allowed list names tools, not content, so this entry grants nothing — name the tool "${inlineUntrusted(toolName, 80)}" to grant it, or move the content rule to a denied list or a permission rule.`));
67
131
  continue;
@@ -73,29 +137,117 @@ function judgeToolNameList(where, side, value, universe, advise, code) {
73
137
  }
74
138
  const phrase = flaw !== undefined ? inertEntryPhrase(flaw) : renderListEntry(entry);
75
139
  const undeclared = split !== undefined && split.peer !== "" && !split.peer.includes("*") && !universe.peers.has(mintNamespacePrefix(split.ns, split.peer));
76
- const why = undeclared ? `no ${PEER_WORD[split.ns.id]} named "${inlineUntrusted(split.peer, 80)}" is declared for this task` : "no tool of this task answers to that name";
77
- advise(new Error(`${where} declares tool ${phrase} in its ${LIST_WORD[side]}: ${why}, so ${KEPT_ENTRY[side]}. If the name is misspelt, fix the entry.`));
140
+ const why = undeclared ? `no ${PEER_WORD[split.ns.id]} named "${inlineUntrusted(split.peer, 80)}" is declared for this task` : universe.complete ? "no tool of this task answers to that name" : "no tool this run can list answers to that name";
141
+ advise(new Error(`${where} declares tool ${phrase} in its ${LIST_WORD[side]}: ${why}, ${universe.complete ? `so ${KEPT_ENTRY[side]}` : KEPT_ENTRY_UNLISTED_POOL}. If the name is misspelt, fix the entry.`));
78
142
  }
79
143
  }
80
144
  export function deniedToolNamesOf(where, value) {
81
- const list = readToolNameList(value);
82
- if (list.kind !== "entries")
83
- throw refused(notAListSentence(where, "denied", list), "config.agent.unknown_tool", "not_a_list");
84
- return list.entries.map((entry, index) => {
85
- if (entry === "*")
86
- return entry;
87
- const read = readDeniedEntry(entry);
88
- if (read.kind === "not_a_string")
89
- throw refused(notAStringSentence(where, "denied", index, read.type), "config.agent.unknown_tool", "not_a_string");
90
- const flaw = compileAllowList([read.name], "deny").inert[0];
91
- if (flaw !== undefined && flaw.reason === "grammar")
92
- throw grammarRefusal(where, "denied", { ...flaw, entry: read.name }, "config.agent.unknown_tool");
93
- return read.name;
94
- });
145
+ return readableToolNameList(where, "denied", value, "config.agent.unknown_tool").map((read) => read.name);
146
+ }
147
+ function inheritedListsWhere(ceilings, i) {
148
+ const up = ceilings - 1 - i;
149
+ return up === 0 ? "the lists of the run this leg was spawned under" : `the lists of the run ${up} spawn${up === 1 ? "" : "s"} above the run this leg was spawned under`;
150
+ }
151
+ function readSelectorLayer(layer, layerWhere, listWhere, recorded) {
152
+ if (!isToolSelectorLayer(layer)) {
153
+ throw refused(`${layerWhere} are a value that is ${valueTypeLabel(layer)}, not a pair of tool-name lists (an allowed and a denied list) — the leg does not start. Fix the layer.`, "config.tool_face_control", "not_a_list");
154
+ }
155
+ for (const side of ["allowed", "denied"]) {
156
+ const where = listWhere(side);
157
+ const entries = readableToolNameList(where, side, side === "allowed" ? layer.allow : layer.deny, "config.tool_face_control");
158
+ const written = recorded ? entries.find((read) => !isCanonicalToolName(read.entry)) : undefined;
159
+ if (written !== undefined) {
160
+ throw refused(`${where} declares ${renderListEntry(written.entry)} in its ${LIST_WORD[side]}: a row records each tool name in its bare spelling (\`Read\`, never \`Read()\`, \`Read(*)\` or \`Read(…)\`), and this entry was recorded by an engine that read the list otherwise — it is read here neither as that engine read it nor as this one would`, "config.tool_face_control", "unsupported_pattern");
161
+ }
162
+ }
163
+ }
164
+ function ownToolListsFlaw(value) {
165
+ try {
166
+ if (typeof value !== "object" || value === null || Array.isArray(value))
167
+ return `a value that is ${valueTypeLabel(value)}, not a tool name with an agent definition name and the digest of the lists it wrote`;
168
+ const { toolName, definition, lists } = value;
169
+ if (typeof toolName !== "string" || toolName.length === 0)
170
+ return `a tool whose name is ${typeof toolName === "string" ? "empty" : `a value that is ${valueTypeLabel(toolName)}`}, not a tool name`;
171
+ const problem = callerToolNameProblem(toolName);
172
+ if (problem !== undefined)
173
+ return `a tool whose name is not one a caller tool can carry (${problem})`;
174
+ if (definition !== undefined && typeof definition !== "string")
175
+ return `an agent definition whose name is a value that is ${valueTypeLabel(definition)}, not a name`;
176
+ if (definition === "")
177
+ return "an agent definition whose name is empty, not a name";
178
+ if (lists === undefined)
179
+ return "a record with no digest of the lists it wrote";
180
+ if (typeof lists !== "string")
181
+ return `a digest of the lists it wrote that is a value that is ${valueTypeLabel(lists)}, not a digest`;
182
+ if (lists.length === 0)
183
+ return "a digest of the lists it wrote that is empty, not a digest";
184
+ return undefined;
185
+ }
186
+ catch {
187
+ return "a value that cannot be read";
188
+ }
189
+ }
190
+ export function persistedToolNamesRefusal(ceiling, chain, ownLists) {
191
+ const pending = "refused before the claim (the checkpoint stays pending): finish it on a worker of the engine that parked it, or expire it and run the work again";
192
+ const ownFlaw = ownLists === undefined ? undefined : ownToolListsFlaw(ownLists);
193
+ if (ownFlaw !== undefined)
194
+ return { message: `this leg's checkpoint row records the delegation tool that wrote its own lists as ${ownFlaw} — ${pending}`, reason: "invalid_record" };
195
+ if (ceiling !== undefined) {
196
+ const layers = readToolNameList(ceiling);
197
+ if (layers.kind !== "entries")
198
+ return { message: `the ceiling this leg's checkpoint row recorded is a value that is ${layers.kind === "not_a_list" ? layers.type : "a list that cannot be read"}, not a list of layers — ${pending}`, reason: "not_a_list" };
199
+ try {
200
+ layers.entries.forEach((layer, i) => readSelectorLayer(layer, inheritedListsWhere(layers.entries.length, i), () => inheritedListsWhere(layers.entries.length, i), true));
201
+ }
202
+ catch (e) {
203
+ return { message: `${e.message} — as this leg's checkpoint row recorded it; ${pending}`, reason: e.detail.reason };
204
+ }
205
+ }
206
+ if (!Array.isArray(chain))
207
+ return undefined;
208
+ const flaw = (() => {
209
+ for (const [layer, entry] of chain.entries()) {
210
+ if (typeof entry !== "object" || entry === null || "opaque" in entry || !Array.isArray(entry.components))
211
+ continue;
212
+ for (const c of entry.components) {
213
+ if (typeof c !== "object" || c === null)
214
+ continue;
215
+ const { member, list } = projectionToolNames(c);
216
+ const where = `layer ${layer + 1}'s ${c.kind === "tool_deny" || c.kind === "tool_allowlist" || c.kind === "shell_command" ? `\`${c.kind}\`` : "component"} ${member}`;
217
+ const read = readToolNameList(list);
218
+ if (read.kind !== "entries")
219
+ return { what: `${where} as a value that is ${read.kind === "not_a_list" ? read.type : "a list that cannot be read"}, not a list of tool names`, reason: "not_a_list" };
220
+ const at = read.entries.findIndex((name) => !isCanonicalToolName(name));
221
+ if (at < 0)
222
+ continue;
223
+ const name = read.entries[at];
224
+ return typeof name === "string" ? { what: `${renderListEntry(name)} in ${where}`, reason: "unsupported_pattern" } : { what: `in ${where}, as entry ${at + 1}, a value that is ${valueTypeLabel(name)}`, reason: "not_a_string" };
225
+ }
226
+ }
227
+ return undefined;
228
+ })();
229
+ return flaw === undefined
230
+ ? undefined
231
+ : { reason: flaw.reason, message: `the checkpoint's frozen inherited constraint chain holds ${flaw.what}: a row records each tool name in its bare spelling (\`Read\`, never \`Read()\`, \`Read(*)\` or \`Read(…)\`), and this entry was recorded by a reading that is not the rule syntax's (an earlier engine's name set, or a policy that reads its lists as written) — it is replayed neither as that reading nor as this engine's; ${pending} (with the policy naming the tool itself)` };
232
+ }
233
+ export function refusePersistedToolNames(ceiling, chain, ownLists) {
234
+ const refusal = persistedToolNamesRefusal(ceiling, chain, ownLists);
235
+ if (refusal !== undefined)
236
+ throw refused(refusal.message, "config.tool_face_control", refusal.reason);
95
237
  }
96
238
  export function boundToolListsJudgment(evidence, own) {
97
239
  return evidence !== undefined && evidence === toolListsDigest(own.allow, own.exclude) ? evidence : undefined;
98
240
  }
241
+ export function boundOwnToolLists(record, own) {
242
+ if (record === undefined)
243
+ return undefined;
244
+ const flaw = ownToolListsFlaw(record);
245
+ if (flaw !== undefined) {
246
+ throw refused(`this leg's internals (RunInternals.ownToolLists) record the delegation tool that wrote its own lists as ${flaw} — the leg does not start. Only the delegation lane writes that record: leave it out.`, "config.tool_face_control", "invalid_record");
247
+ }
248
+ const held = record;
249
+ return held.lists === toolListsDigest(own.allow, own.exclude) ? held : undefined;
250
+ }
99
251
  export function judgeRunToolLists(input) {
100
252
  const { spec, tools, onceLedger, sessionId } = input;
101
253
  const advise = (err) => {
@@ -105,6 +257,13 @@ export function judgeRunToolLists(input) {
105
257
  catch {
106
258
  }
107
259
  };
260
+ const ownWhere = input.ownBy !== undefined ? delegationListWhere(input.ownBy.toolName, input.ownBy.definition) : undefined;
261
+ const ceilings = input.layers.length - 1;
262
+ input.layers.forEach((layer, i) => {
263
+ const own = i === ceilings;
264
+ const inherited = own ? undefined : inheritedListsWhere(ceilings, i);
265
+ readSelectorLayer(layer, inherited ?? "this run's own tool lists", (side) => inherited ?? ownWhere ?? (side === "allowed" ? "TaskSpec.allowTools" : "TaskSpec.excludeTools"), false);
266
+ });
108
267
  const denied = deniedProtocolTools(input.layers, input.legs);
109
268
  if (denied.length > 0) {
110
269
  const names = [...new Set(denied.map((h) => `"${h.name}"`))];
@@ -113,43 +272,29 @@ export function judgeRunToolLists(input) {
113
272
  const hits = denied.filter((h) => h.own === own).map((h) => `"${h.name}"`);
114
273
  return hits.length > 0 ? [`${whose} denies ${one ? "it" : hits.join(", ")}`] : [];
115
274
  };
116
- const by = [...deniedBy(true, input.ownWhere ?? "this run's own excludeTools"), ...deniedBy(false, "an inherited list (the spawning run's excludeTools, or one it inherits)")];
275
+ const by = [...deniedBy(true, ownWhere ?? "this run's own excludeTools"), ...deniedBy(false, "an inherited list (the spawning run's excludeTools, or one it inherits)")];
117
276
  throw refused(`This kind of leg (${input.legs.join(", ")}) relies on ${names.join(", ")}, but ${by.join(" and ")} — the leg cannot work without ${one ? "it" : "them"}. Remove the entry from the list that names it.`, "config.tool_face_control", "protocol_denied");
118
277
  }
119
- const delegationTools = (spec.tools ?? []).filter((t) => t.agentToolFaces !== undefined);
120
- const known = new Set();
121
- const add = (t) => {
122
- known.add(t.name);
123
- for (const a of t.aliases ?? [])
124
- known.add(a);
125
- };
126
- for (const t of tools)
127
- add(t);
128
- for (const t of ENGINE_TOOLS)
129
- add(t);
130
- for (const t of spec.tools ?? [])
131
- add(t);
132
- for (const t of delegationTools)
133
- for (const p of t.agentToolPool ?? [])
134
- add(p);
135
- const peers = new Set(PROTOCOL_TABLE.flatMap((ns) => (input.declaredPeers[ns.id] ?? []).map((p) => mintNamespacePrefix(ns, p.name))));
136
- for (const name of known) {
137
- const ns = protocolOf(name);
138
- const split = ns !== undefined ? splitNamespacedName(name) : undefined;
139
- if (split !== undefined && split.peer !== "")
140
- peers.add(mintNamespacePrefix(split.ns, split.peer));
141
- }
142
- const universe = { known, peers };
278
+ const selector = compileToolSelector(input.layers, input.legs);
279
+ const pool = delegationPoolReading(spec.tools ?? [], valveLeaves(spec, selector));
280
+ const mounted = mountedToolNames([...tools, ...(spec.tools ?? [])]);
143
281
  if (!input.judgedUpstream) {
144
- judgeToolNameList(input.ownWhere ?? "TaskSpec.allowTools", "allowed", input.own.allow, universe, advise, "config.tool_face_control");
145
- judgeToolNameList(input.ownWhere ?? "TaskSpec.excludeTools", "denied", input.own.exclude, universe, advise, "config.tool_face_control");
282
+ const root = rootFacingUniverse(input.ownBy !== undefined ? new Set([...mounted, input.ownBy.toolName]) : mounted, pool, input.declaredPeers);
283
+ const own = [["allowed", input.own.allow], ["denied", input.own.exclude]];
284
+ const tell = input.toldUpstream === true ? () => undefined : advise;
285
+ for (const [side, value] of own)
286
+ judgeToolNameList(ownWhere ?? (side === "allowed" ? "TaskSpec.allowTools" : "TaskSpec.excludeTools"), side, value, root, tell, "config.tool_face_control");
146
287
  }
288
+ const children = new Map(pool.tools.map((t) => [t, childFacingUniverse(poolOf([t]), input.declaredPeers)]));
289
+ const taskTargets = pool.tools.length > 0 ? [...children.values()] : [childFacingUniverse(poolOf([]), input.declaredPeers)];
147
290
  for (const def of spec.agents ?? []) {
148
- judgeToolNameList(`TaskSpec.agents: agent "${def.name}"`, "allowed", def.allowTools, universe, advise, "config.agent.unknown_tool");
149
- judgeToolNameList(`TaskSpec.agents: agent "${def.name}"`, "denied", def.denyTools, universe, advise, "config.agent.unknown_tool");
291
+ for (const universe of taskTargets) {
292
+ judgeToolNameList(`TaskSpec.agents: agent "${def.name}"`, "allowed", def.allowTools, universe, advise, "config.agent.unknown_tool");
293
+ judgeToolNameList(`TaskSpec.agents: agent "${def.name}"`, "denied", def.denyTools, universe, advise, "config.agent.unknown_tool");
294
+ }
150
295
  }
151
296
  const replaced = new Set((spec.agents ?? []).map((d) => d.name));
152
- for (const t of delegationTools) {
297
+ for (const [t, universe] of children) {
153
298
  for (const face of t.agentToolFaces ?? []) {
154
299
  if (face.authored === true && !replaced.has(face.name)) {
155
300
  const faceWhere = delegationListWhere(t.name, face.name);
@@ -161,3 +306,17 @@ export function judgeRunToolLists(input) {
161
306
  judgeToolNameList(delegationListWhere(t.name, undefined), "denied", t.agentToolLevelDenyTools, universe, advise, "config.agent.unknown_tool");
162
307
  }
163
308
  }
309
+ export function judgeHostToolCeiling(layers, agent, above = []) {
310
+ const where = (i) => `RunWorkflowOptions.toolCeiling, layer ${i + 1}`;
311
+ layers.forEach((layer, i) => readSelectorLayer(layer, where(i), () => where(i), false));
312
+ const callerTools = agent.tools ?? [];
313
+ const own = { ...(agent.allowTools != null ? { allow: agent.allowTools } : {}), deny: agent.excludeTools ?? [] };
314
+ const selector = compileToolSelector([...above, ...layers, own], ["delegated"]);
315
+ const pool = delegationPoolReading(callerTools, valveLeaves(agent, selector));
316
+ const universe = rootFacingUniverse(mountedToolNames(callerTools), pool, { mcp: undefined, a2a: undefined });
317
+ const unannounced = () => undefined;
318
+ layers.forEach((layer, i) => {
319
+ judgeToolNameList(where(i), "allowed", layer.allow, universe, unannounced, "config.tool_face_control");
320
+ judgeToolNameList(where(i), "denied", layer.deny, universe, unannounced, "config.tool_face_control");
321
+ });
322
+ }
@@ -110,8 +110,11 @@ export interface SkillListingEntry {
110
110
  * and the tool, so what the prompt promises is exactly what the tool serves. Each field is READ ONCE, BY NAME, and
111
111
  * both consumers see the copy: the gate screens this list while the invoke substitutes from it, so a `get baseDir()`
112
112
  * answering those two reads differently passed a screen that measured a value the model never received — and a rest
113
- * copy would silently drop an INHERITED or non-enumerable list. The two tables are read by {@link readSkillTable}. */
114
- export declare function normalizeSkills(skills: SkillLike[] | undefined): SkillLike[];
113
+ * copy would silently drop an INHERITED or non-enumerable list. The two tables are read by {@link readSkillTable}.
114
+ *
115
+ * The sorted view of {@link readSkillsSeat} (skills-seat.ts), which holds the seat's one reading — total over what a caller can
116
+ * hand it, and once. */
117
+ export declare function normalizeSkills(skills: unknown): SkillLike[];
115
118
  /** [c209-C] The skills listing's lead line — single-sourced so the run loop's durable-resume
116
119
  * transcript probe (MED-3② skills arm, runtask) matches EXACTLY what the initial frame carries
117
120
  * (probing the bare `<skills>` fence would be more collision-prone in model-quoted text). */
@@ -5,6 +5,7 @@ import { SKILL_LISTING_DEFAULT_BUDGET, SKILL_LISTING_DESC_MAX_CHARS_DEFAULT } fr
5
5
  import { readSkillTable, skillNamedBy } from "../skill-grant.js";
6
6
  import { toolFace } from "../tool-catalog-entries.js";
7
7
  import { substituteSkillRoot, substituteSkillRootBounded } from "./skill-base-dir.js";
8
+ import { readSkillsSeat } from "./skills-seat.js";
8
9
  import { foldListingWithin } from "./listing-fold.js";
9
10
  export const OUTPUT_TOOL_NAME = "StructuredOutput";
10
11
  export const REPORT_BLOCKED_TOOL_NAME = "ReportBlocked";
@@ -109,18 +110,7 @@ function skillFilesSuffix(files) {
109
110
  return ` [files: ${shown.join(", ")}${more > 0 ? `, +${more} more` : ""}]`;
110
111
  }
111
112
  export function normalizeSkills(skills) {
112
- const seen = new Set();
113
- const out = [];
114
- for (const s of skills ?? []) {
115
- if (!seen.has(s.name)) {
116
- seen.add(s.name);
117
- const { name, description, content, allowedTools, disallowedTools, files, baseDir, ...rest } = s;
118
- void rest;
119
- const [allowed, denied] = [readSkillTable(allowedTools), readSkillTable(disallowedTools)];
120
- out.push({ name, description, content, ...(allowed !== undefined ? { allowedTools: allowed } : {}), ...(denied !== undefined ? { disallowedTools: denied } : {}), ...(files !== undefined ? { files } : {}), ...(baseDir !== undefined ? { baseDir } : {}) });
121
- }
122
- }
123
- return out.toSorted((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
113
+ return readSkillsSeat(skills).toSorted((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
124
114
  }
125
115
  export const SKILLS_LISTING_PROBE_HEADER = "The following skills are available for this task.";
126
116
  export function skillListingLine(s, descMaxChars = SKILL_LISTING_DESC_MAX_CHARS_DEFAULT) {