@sema-agent/core 7.48.0 → 7.49.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 (418) hide show
  1. package/CHANGELOG.md +418 -0
  2. package/README.md +2 -2
  3. package/dist/agents/cascade.d.ts +2 -5
  4. package/dist/agents/child-failure.d.ts +20 -0
  5. package/dist/agents/child-failure.js +28 -0
  6. package/dist/agents/cross-session-ref.d.ts +11 -3
  7. package/dist/agents/cross-session-ref.js +6 -0
  8. package/dist/agents/cumulative-stats.d.ts +12 -15
  9. package/dist/agents/cumulative-stats.js +1 -1
  10. package/dist/agents/extra-tool-names.js +1 -1
  11. package/dist/agents/inherited-tool-pool.d.ts +17 -13
  12. package/dist/agents/inherited-tool-pool.js +4 -3
  13. package/dist/agents/peer-session-drain.d.ts +3 -2
  14. package/dist/agents/peer-session-drain.js +5 -4
  15. package/dist/agents/send-message-tool.js +2 -9
  16. package/dist/agents/subagent.d.ts +10 -29
  17. package/dist/agents/subagent.js +65 -53
  18. package/dist/agents/suspend-guard.d.ts +1 -1
  19. package/dist/agents/tool-filter.d.ts +76 -65
  20. package/dist/agents/tool-filter.js +122 -92
  21. package/dist/agents/verify.d.ts +4 -7
  22. package/dist/agents/verify.js +6 -7
  23. package/dist/bench/metrics.d.ts +1 -2
  24. package/dist/brain/anthropic.js +133 -79
  25. package/dist/brain/errors.d.ts +53 -6
  26. package/dist/brain/errors.js +22 -2
  27. package/dist/brain/input-too-long.d.ts +40 -19
  28. package/dist/brain/input-too-long.js +3 -16
  29. package/dist/brain/open-responses.js +19 -10
  30. package/dist/brain/openai.js +123 -32
  31. package/dist/brain/provider-dialect.d.ts +214 -0
  32. package/dist/brain/provider-dialect.js +186 -0
  33. package/dist/brain/request-params.d.ts +27 -8
  34. package/dist/brain/request-params.js +7 -12
  35. package/dist/brain/request-route.d.ts +84 -0
  36. package/dist/brain/request-route.js +41 -0
  37. package/dist/brain/retry.d.ts +8 -0
  38. package/dist/brain/retry.js +10 -4
  39. package/dist/brain/route-adjudicator.d.ts +7 -0
  40. package/dist/brain/route-adjudicator.js +5 -1
  41. package/dist/brain/status-sink.d.ts +20 -0
  42. package/dist/brain/status-sink.js +11 -0
  43. package/dist/brain/stream-engine.d.ts +52 -1
  44. package/dist/brain/stream-engine.js +81 -24
  45. package/dist/brain/stream-shared.d.ts +57 -11
  46. package/dist/brain/stream-shared.js +28 -2
  47. package/dist/core/a2a.d.ts +1 -0
  48. package/dist/core/agent-config-dir.js +3 -2
  49. package/dist/core/allow-entry.d.ts +21 -12
  50. package/dist/core/allow-entry.js +38 -31
  51. package/dist/core/arg-summary.d.ts +17 -24
  52. package/dist/core/arg-summary.js +169 -68
  53. package/dist/core/ask-origin.d.ts +42 -24
  54. package/dist/core/ask-origin.js +18 -13
  55. package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
  56. package/dist/core/auto-mode-prompt-assets.js +1 -1
  57. package/dist/core/auto-mode-prompt.d.ts +11 -1
  58. package/dist/core/auto-mode-prompt.js +13 -10
  59. package/dist/core/auto-mode-rebuild.d.ts +7 -0
  60. package/dist/core/auto-mode-rebuild.js +4 -1
  61. package/dist/core/canonical-json.d.ts +3 -0
  62. package/dist/core/canonical-json.js +2 -1
  63. package/dist/core/checkpoint-requirements.d.ts +892 -0
  64. package/dist/core/checkpoint-requirements.js +333 -0
  65. package/dist/core/checkpoint-store.d.ts +94 -65
  66. package/dist/core/checkpoint-store.js +14 -26
  67. package/dist/core/child-clamp-seats.d.ts +228 -69
  68. package/dist/core/child-clamp-seats.js +211 -17
  69. package/dist/core/classifier-unavailable-arm.d.ts +5 -1
  70. package/dist/core/classifier-unavailable-arm.js +3 -3
  71. package/dist/core/compliance.d.ts +3 -0
  72. package/dist/core/compliance.js +9 -4
  73. package/dist/core/credential-vocabulary.d.ts +140 -0
  74. package/dist/core/credential-vocabulary.js +131 -0
  75. package/dist/core/decision-receipt.js +1 -1
  76. package/dist/core/effective-path-target.d.ts +73 -16
  77. package/dist/core/effective-path-target.js +63 -33
  78. package/dist/core/engine-notice.d.ts +32 -7
  79. package/dist/core/file-history-store.js +2 -2
  80. package/dist/core/fs-write-gate-policy.d.ts +4 -0
  81. package/dist/core/fs-write-gate-policy.js +22 -5
  82. package/dist/core/gate-bounded-await.d.ts +28 -13
  83. package/dist/core/gate-bounded-await.js +41 -4
  84. package/dist/core/gate-fold.d.ts +1 -1
  85. package/dist/core/gate-fold.js +24 -25
  86. package/dist/core/gate-lanes.js +16 -15
  87. package/dist/core/gate-outcome.d.ts +20 -5
  88. package/dist/core/gate-outcome.js +5 -0
  89. package/dist/core/governance-codes.d.ts +11 -4
  90. package/dist/core/governance-codes.js +14 -3
  91. package/dist/core/hooks.d.ts +4 -0
  92. package/dist/core/locked-config.d.ts +8 -0
  93. package/dist/core/locked-config.js +14 -2
  94. package/dist/core/lsp.js +3 -5
  95. package/dist/core/mailbox-store.d.ts +3 -4
  96. package/dist/core/mcp-connection-pool.d.ts +75 -0
  97. package/dist/core/mcp-connection-pool.js +128 -0
  98. package/dist/core/mcp-failure.d.ts +2 -1
  99. package/dist/core/mcp-failure.js +13 -2
  100. package/dist/core/mcp.d.ts +4 -0
  101. package/dist/core/mcp.js +70 -43
  102. package/dist/core/memory-engine/content-origin.js +2 -14
  103. package/dist/core/memory-engine/engine.d.ts +32 -22
  104. package/dist/core/memory-engine/engine.js +103 -55
  105. package/dist/core/memory-engine/file-backend.d.ts +13 -30
  106. package/dist/core/memory-engine/file-backend.js +37 -252
  107. package/dist/core/memory-engine/index.d.ts +1 -1
  108. package/dist/core/memory-engine/index.js +1 -1
  109. package/dist/core/memory-engine/layout.d.ts +139 -9
  110. package/dist/core/memory-engine/layout.js +350 -7
  111. package/dist/core/memory-engine/scope-contract.d.ts +10 -0
  112. package/dist/core/memory-engine/scope-contract.js +8 -0
  113. package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
  114. package/dist/core/memory-engine/session-incarnation.js +5 -2
  115. package/dist/core/memory-engine/types.d.ts +10 -1
  116. package/dist/core/memory.js +5 -17
  117. package/dist/core/model-seat.d.ts +4 -4
  118. package/dist/core/model-seat.js +1 -1
  119. package/dist/core/mounted-mcp.d.ts +57 -0
  120. package/dist/core/mounted-mcp.js +19 -0
  121. package/dist/core/namespaced-rule-name.d.ts +29 -0
  122. package/dist/core/namespaced-rule-name.js +52 -0
  123. package/dist/core/park-selfcheck.d.ts +1 -1
  124. package/dist/core/park-selfcheck.js +16 -6
  125. package/dist/core/path-guard-rows.d.ts +99 -0
  126. package/dist/core/path-guard-rows.js +45 -0
  127. package/dist/core/path-identity.d.ts +22 -16
  128. package/dist/core/path-identity.js +10 -10
  129. package/dist/core/path-rule-binding.d.ts +2 -1
  130. package/dist/core/path-rule-binding.js +3 -1
  131. package/dist/core/pause-registry.d.ts +16 -2
  132. package/dist/core/pause-registry.js +6 -0
  133. package/dist/core/permission-rule-consent.js +0 -7
  134. package/dist/core/permission-rule-model.d.ts +68 -24
  135. package/dist/core/permission-rule-model.js +105 -24
  136. package/dist/core/permission-rule-store.js +2 -2
  137. package/dist/core/permission-rules.d.ts +3 -30
  138. package/dist/core/permission-rules.js +4 -54
  139. package/dist/core/read-root-candidate.d.ts +1 -3
  140. package/dist/core/read-root-candidate.js +4 -15
  141. package/dist/core/real-approval.d.ts +4 -3
  142. package/dist/core/retired-keys.d.ts +13 -0
  143. package/dist/core/retired-keys.js +14 -0
  144. package/dist/core/roles.d.ts +2 -3
  145. package/dist/core/roles.js +15 -6
  146. package/dist/core/runner/assemble-result.d.ts +0 -7
  147. package/dist/core/runner/assemble-result.js +19 -31
  148. package/dist/core/runner/caller-roster.d.ts +78 -0
  149. package/dist/core/runner/caller-roster.js +219 -0
  150. package/dist/core/runner/checkpoint-scope.d.ts +16 -16
  151. package/dist/core/runner/checkpoint-scope.js +2 -2
  152. package/dist/core/runner/child-tree.js +2 -2
  153. package/dist/core/runner/contracts.d.ts +68 -35
  154. package/dist/core/runner/decide-continuation.d.ts +51 -3
  155. package/dist/core/runner/decide-continuation.js +76 -21
  156. package/dist/core/runner/denial-limit-arms.d.ts +17 -5
  157. package/dist/core/runner/denial-limit-arms.js +11 -9
  158. package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
  159. package/dist/core/runner/extra-body-dropped-seat.js +22 -0
  160. package/dist/core/runner/finish-reason-seat.d.ts +9 -0
  161. package/dist/core/runner/finish-reason-seat.js +40 -0
  162. package/dist/core/runner/gate-exit.d.ts +44 -32
  163. package/dist/core/runner/gate-exit.js +112 -25
  164. package/dist/core/runner/inherited-ask-grants.js +6 -4
  165. package/dist/core/runner/mcp-redial.d.ts +3 -3
  166. package/dist/core/runner/mcp-redial.js +3 -4
  167. package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
  168. package/dist/core/runner/permission-rule-lanes.js +5 -4
  169. package/dist/core/runner/prepare-artifact.d.ts +4 -0
  170. package/dist/core/runner/prepare-artifact.js +2 -1
  171. package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
  172. package/dist/core/runner/prepare-ask-lane.js +12 -6
  173. package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
  174. package/dist/core/runner/prepare-boundary-parks.js +4 -7
  175. package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
  176. package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
  177. package/dist/core/runner/prepare-config-doors.d.ts +9 -9
  178. package/dist/core/runner/prepare-config-doors.js +10 -5
  179. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  180. package/dist/core/runner/prepare-defer-classify.js +5 -3
  181. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  182. package/dist/core/runner/prepare-delegation-surface.js +3 -3
  183. package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
  184. package/dist/core/runner/prepare-gate-stations.js +9 -7
  185. package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
  186. package/dist/core/runner/prepare-hands-readface.js +7 -7
  187. package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
  188. package/dist/core/runner/prepare-inherited-gate.js +14 -15
  189. package/dist/core/runner/prepare-listings.d.ts +7 -24
  190. package/dist/core/runner/prepare-listings.js +4 -5
  191. package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
  192. package/dist/core/runner/prepare-memory-engine-session.js +4 -3
  193. package/dist/core/runner/prepare-memory.d.ts +6 -0
  194. package/dist/core/runner/prepare-memory.js +13 -13
  195. package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
  196. package/dist/core/runner/prepare-offload-wrappers.js +3 -3
  197. package/dist/core/runner/prepare-park-ask.d.ts +7 -8
  198. package/dist/core/runner/prepare-park-ask.js +17 -10
  199. package/dist/core/runner/prepare-policy-chain.js +24 -44
  200. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  201. package/dist/core/runner/prepare-project-context.js +3 -4
  202. package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
  203. package/dist/core/runner/prepare-protocol-tools.js +3 -4
  204. package/dist/core/runner/prepare-run-refs.d.ts +3 -0
  205. package/dist/core/runner/prepare-run-refs.js +2 -1
  206. package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
  207. package/dist/core/runner/prepare-safety-scan.js +1 -2
  208. package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
  209. package/dist/core/runner/prepare-suspend-saga.js +28 -12
  210. package/dist/core/runner/prepare-task.d.ts +1 -1
  211. package/dist/core/runner/prepare-task.js +67 -56
  212. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
  213. package/dist/core/runner/prepare-wiring-manifest.js +5 -8
  214. package/dist/core/runner/resume-apply.js +7 -14
  215. package/dist/core/runner/resume-checkpoint-screen.js +11 -4
  216. package/dist/core/runner/resume-internals-and-config.js +2 -2
  217. package/dist/core/runner/resume-policy-outcome.js +5 -32
  218. package/dist/core/runner/resume-review-outcome.js +4 -1
  219. package/dist/core/runner/retired-runner-deps.d.ts +6 -0
  220. package/dist/core/runner/retired-runner-deps.js +10 -1
  221. package/dist/core/runner/run-brain-sinks.d.ts +4 -0
  222. package/dist/core/runner/run-brain-sinks.js +5 -2
  223. package/dist/core/runner/run-harness-handlers.js +27 -34
  224. package/dist/core/runner/run-leg.d.ts +0 -2
  225. package/dist/core/runner/run-leg.js +32 -33
  226. package/dist/core/runner/run-terminal-adoption.js +4 -3
  227. package/dist/core/runner/runtask.js +8 -8
  228. package/dist/core/runner/session-rule-policy.js +5 -5
  229. package/dist/core/runner/stream-settle-backstop.js +7 -4
  230. package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
  231. package/dist/core/runner/sub-agent-deny-lists.js +111 -80
  232. package/dist/core/runner/terminal-account.d.ts +48 -0
  233. package/dist/core/runner/terminal-account.js +186 -0
  234. package/dist/core/runner/tool-end-body.d.ts +54 -17
  235. package/dist/core/runner/tool-end-body.js +27 -2
  236. package/dist/core/runner/tool-face-overlay.d.ts +3 -1
  237. package/dist/core/runner/tool-face-overlay.js +6 -4
  238. package/dist/core/runner/tool-occurrence.d.ts +106 -0
  239. package/dist/core/runner/tool-occurrence.js +123 -0
  240. package/dist/core/runner/tool-progress-lane.d.ts +16 -8
  241. package/dist/core/runner/tool-progress-lane.js +25 -34
  242. package/dist/core/runner/turn-attachments.d.ts +1 -1
  243. package/dist/core/runner/write-protection-station.d.ts +21 -9
  244. package/dist/core/runner/write-protection-station.js +20 -17
  245. package/dist/core/runner-deps.d.ts +12 -22
  246. package/dist/core/secret-env.d.ts +16 -5
  247. package/dist/core/secret-env.js +23 -63
  248. package/dist/core/sensitive-path-policy.d.ts +19 -18
  249. package/dist/core/sensitive-path-policy.js +73 -49
  250. package/dist/core/session-reconcile.d.ts +3 -0
  251. package/dist/core/session-reconcile.js +5 -4
  252. package/dist/core/session-store.d.ts +5 -0
  253. package/dist/core/session-store.js +12 -0
  254. package/dist/core/session.d.ts +13 -0
  255. package/dist/core/shared-memory/normalize.d.ts +17 -4
  256. package/dist/core/shared-memory/normalize.js +7 -7
  257. package/dist/core/shell-lexer.js +5 -4
  258. package/dist/core/skill-grant.js +1 -1
  259. package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
  260. package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
  261. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
  262. package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
  263. package/dist/core/stub-env.d.ts +2 -0
  264. package/dist/core/stub-env.js +1 -0
  265. package/dist/core/synthetic-read-verdict.js +2 -2
  266. package/dist/core/task-event.d.ts +59 -5
  267. package/dist/core/task-result.d.ts +1 -1
  268. package/dist/core/task-spec.d.ts +42 -9
  269. package/dist/core/terminal-cause.d.ts +94 -11
  270. package/dist/core/tighten-task-spec.d.ts +5 -4
  271. package/dist/core/tighten-task-spec.js +20 -25
  272. package/dist/core/tool-catalog-entries.d.ts +5 -7
  273. package/dist/core/tool-catalog-entries.js +14 -15
  274. package/dist/core/tool-face.d.ts +47 -0
  275. package/dist/core/tool-face.js +5 -0
  276. package/dist/core/tool-model-gate.d.ts +5 -5
  277. package/dist/core/tool-name-aliases.d.ts +26 -2
  278. package/dist/core/tool-name-aliases.js +13 -0
  279. package/dist/core/tool-name-list.d.ts +30 -0
  280. package/dist/core/tool-name-list.js +55 -0
  281. package/dist/core/tool-name-readings.d.ts +1 -9
  282. package/dist/core/tool-name-readings.js +1 -3
  283. package/dist/core/tool-policy.d.ts +195 -85
  284. package/dist/core/tool-policy.js +165 -380
  285. package/dist/core/tool-registry.d.ts +44 -1
  286. package/dist/core/tool-registry.js +26 -0
  287. package/dist/core/tool-roster.d.ts +19 -1
  288. package/dist/core/tool-roster.js +21 -2
  289. package/dist/core/tool-spec-members.d.ts +45 -0
  290. package/dist/core/tool-spec-members.js +169 -0
  291. package/dist/core/tool-spec.d.ts +46 -8
  292. package/dist/core/tools.d.ts +6 -2
  293. package/dist/core/tools.js +8 -4
  294. package/dist/core/untrusted-egress.js +29 -26
  295. package/dist/core/untrusted-text.d.ts +13 -10
  296. package/dist/core/untrusted-text.js +6 -44
  297. package/dist/core/workflow-journal-store.d.ts +4 -1
  298. package/dist/core/write-protect.d.ts +65 -29
  299. package/dist/core/write-protect.js +235 -177
  300. package/dist/engine/compaction/compaction.d.ts +2 -2
  301. package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
  302. package/dist/engine/execution-env/node-execution-env.js +16 -38
  303. package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
  304. package/dist/engine/execution-env/symlink-chain.js +32 -0
  305. package/dist/engine/harness/types.d.ts +7 -0
  306. package/dist/engine/llm/tool-turns.d.ts +3 -0
  307. package/dist/engine/llm/tool-turns.js +1 -0
  308. package/dist/engine/llm/types.d.ts +59 -23
  309. package/dist/engine/loop/agent-loop.js +16 -2
  310. package/dist/engine/session/memory-repo.js +11 -3
  311. package/dist/engine/session/repo-utils.d.ts +8 -0
  312. package/dist/engine/session/repo-utils.js +13 -0
  313. package/dist/index.d.ts +20 -23
  314. package/dist/index.js +17 -20
  315. package/dist/internal/harness.d.ts +1 -1
  316. package/dist/internal/harness.js +1 -1
  317. package/dist/internal/llm.d.ts +2 -2
  318. package/dist/internal/llm.js +1 -1
  319. package/dist/orchestration/governance-baseline-validity.js +1 -1
  320. package/dist/orchestration/run-spec.js +3 -3
  321. package/dist/orchestration/run-workflow-tool.d.ts +16 -35
  322. package/dist/orchestration/run-workflow-tool.js +38 -78
  323. package/dist/orchestration/workflow-governance.d.ts +21 -25
  324. package/dist/orchestration/workflow-governance.js +38 -78
  325. package/dist/orchestration/workflow-primitives.d.ts +7 -22
  326. package/dist/orchestration/workflow-primitives.js +5 -12
  327. package/dist/orchestration/workflow-types.d.ts +1 -1
  328. package/dist/orchestration/workflow.d.ts +61 -11
  329. package/dist/orchestration/workflow.js +189 -117
  330. package/dist/scenarios/full-body.d.ts +1 -1
  331. package/dist/shell/lex.d.ts +0 -21
  332. package/dist/shell/lex.js +250 -68
  333. package/dist/shell/shell-words.d.ts +35 -0
  334. package/dist/shell/shell-words.js +65 -0
  335. package/dist/stores/file/checkpoint-store.d.ts +5 -5
  336. package/dist/stores/file/checkpoint-store.js +5 -2
  337. package/dist/stores/file/index.d.ts +0 -8
  338. package/dist/stores/file/index.js +0 -12
  339. package/dist/stores/file/session-store.d.ts +3 -0
  340. package/dist/stores/file/session-store.js +44 -19
  341. package/dist/tools/artifact/artifact-tool.js +2 -0
  342. package/dist/tools/fs/bash-program-position.d.ts +10 -3
  343. package/dist/tools/fs/bash-program-position.js +21 -9
  344. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  345. package/dist/tools/fs/bash-readonly-classifier.js +8 -7
  346. package/dist/tools/fs/containment-face.d.ts +4 -0
  347. package/dist/tools/fs/containment-face.js +3 -0
  348. package/dist/tools/fs/fs-shared.d.ts +10 -0
  349. package/dist/tools/fs/fs-shared.js +18 -0
  350. package/dist/tools/fs/fs-write.js +4 -2
  351. package/dist/tools/fs/index.d.ts +1 -1
  352. package/dist/tools/fs/program-read-model.d.ts +39 -18
  353. package/dist/tools/fs/program-read-model.js +29 -19
  354. package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
  355. package/dist/tools/fs/program-read-model.rows.js +5 -5
  356. package/dist/tools/fs/read-deny-home.d.ts +33 -47
  357. package/dist/tools/fs/read-deny-home.js +35 -49
  358. package/dist/tools/fs/read-deny.d.ts +23 -22
  359. package/dist/tools/fs/read-deny.js +114 -89
  360. package/dist/tools/fs/removal-targets.d.ts +56 -23
  361. package/dist/tools/fs/removal-targets.js +65 -87
  362. package/dist/tools/fs/safety.d.ts +29 -22
  363. package/dist/tools/fs/safety.js +17 -11
  364. package/dist/tools/fs/search.js +10 -8
  365. package/dist/tools/fs/shell-read-argv.js +1 -1
  366. package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
  367. package/dist/tools/fs/shell-read-bindings.js +324 -86
  368. package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
  369. package/dist/tools/fs/shell-read-builtins.js +43 -0
  370. package/dist/tools/fs/shell-read-check.d.ts +15 -1
  371. package/dist/tools/fs/shell-read-check.js +51 -42
  372. package/dist/tools/fs/shell-read-establish.js +6 -6
  373. package/dist/tools/fs/shell-read-functions.d.ts +22 -0
  374. package/dist/tools/fs/shell-read-functions.js +29 -0
  375. package/dist/tools/fs/shell-read-judge.d.ts +48 -18
  376. package/dist/tools/fs/shell-read-judge.js +33 -4
  377. package/dist/tools/fs/shell-read-plan.d.ts +12 -6
  378. package/dist/tools/fs/shell-read-plan.js +118 -113
  379. package/dist/tools/fs/shell-read-start.d.ts +29 -6
  380. package/dist/tools/fs/shell-read-start.js +16 -9
  381. package/dist/tools/fs/shell-read-word.js +4 -0
  382. package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
  383. package/dist/tools/fs/shell-read-workdir.js +281 -0
  384. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
  385. package/dist/tools/fs/shell-read-write-targets.js +14 -5
  386. package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
  387. package/dist/tools/fs/shell-reentry-text.js +3 -11
  388. package/dist/tools/task-list.d.ts +1 -2
  389. package/dist/tools/web.js +1 -1
  390. package/package.json +4 -1
  391. package/test/export-surface.snapshot.json +107 -143
  392. package/wire-changes/core@7.49.0.json +4765 -0
  393. package/dist/agents/teacher.d.ts +0 -159
  394. package/dist/agents/teacher.js +0 -577
  395. package/dist/agents/team.d.ts +0 -226
  396. package/dist/agents/team.js +0 -257
  397. package/dist/core/strategy-store.d.ts +0 -238
  398. package/dist/core/strategy-store.js +0 -253
  399. package/dist/orchestration/builtin-workflows.d.ts +0 -133
  400. package/dist/orchestration/builtin-workflows.js +0 -159
  401. package/dist/scenarios/env.d.ts +0 -40
  402. package/dist/scenarios/env.js +0 -39
  403. package/dist/scenarios/scenario-registry.d.ts +0 -110
  404. package/dist/scenarios/scenario-registry.js +0 -140
  405. package/dist/scenarios/teacher-quickstart.d.ts +0 -40
  406. package/dist/scenarios/teacher-quickstart.js +0 -12
  407. package/dist/stores/cc/lockfile.d.ts +0 -10
  408. package/dist/stores/cc/lockfile.js +0 -98
  409. package/dist/stores/cc/mailbox-store.d.ts +0 -20
  410. package/dist/stores/cc/mailbox-store.js +0 -255
  411. package/dist/stores/cc/roster-adapter.d.ts +0 -12
  412. package/dist/stores/cc/roster-adapter.js +0 -117
  413. package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
  414. package/dist/stores/cc/sidecar-transcript.js +0 -264
  415. package/dist/stores/cc/task-list-store.d.ts +0 -2
  416. package/dist/stores/cc/task-list-store.js +0 -125
  417. package/dist/stores/file/strategy-store.d.ts +0 -97
  418. package/dist/stores/file/strategy-store.js +0 -341
@@ -2,7 +2,8 @@ import { screenGateOutcome, SETTLEMENT_IS_REFUSAL } from "../gate-outcome.js";
2
2
  import { askFaceOf, classifyAsk, headlessApprovalRemedy } from "../ask-origin.js";
3
3
  import { wireOf } from "../tool-name-readings.js";
4
4
  import { isProtectedWrite } from "../tool-registry.js";
5
- import { askUnresolvableCauseOf, classifierDenyCauseOf, classifierRoundOf, decisionText, engineSettlementOf } from "../tool-policy.js";
5
+ import { attestationOf, decisionText } from "../tool-policy.js";
6
+ import { boundInputHashOf } from "../canonical-json.js";
6
7
  import { askUnresolvableRemedySeat } from "../ask-unresolvable-notice.js";
7
8
  import { inlineUntrusted } from "../untrusted-text.js";
8
9
  import { formatHookFeedback } from "../reminder-mint.js";
@@ -33,8 +34,27 @@ function releaseRecordOf(a) {
33
34
  export function directDeny(deniedBy) {
34
35
  return mintGateOutcome({ deniedBy });
35
36
  }
37
+ const SETTLEMENT_IS_HUMAN = {
38
+ human_allowed: true,
39
+ human_refused: true,
40
+ approval_window_expired: false,
41
+ denial_limit_window_expired: false,
42
+ park_sla_expired: false,
43
+ no_approver: false,
44
+ approver_unavailable: false,
45
+ approver_error: false,
46
+ approver_contract: false,
47
+ presentation_failed: false,
48
+ blanket_allow_refused: false,
49
+ policy_allowed: false,
50
+ policy_refused: false,
51
+ task_aborted: false,
52
+ };
53
+ const licensedOf = (r) => (r.inputDigest !== undefined ? { licensed: r.inputDigest } : {});
54
+ const sameClasses = (a, b) => a === undefined || b === undefined ? a === b : a.length === b.length && a.every((c, i) => c === b[i]);
36
55
  export function createSettlementLedger(call) {
37
56
  let settled;
57
+ const contractRefusal = (origin) => ({ settlement: { kind: "approver_contract", who: { party: "none" }, when: Date.now() }, origin });
38
58
  return {
39
59
  get settled() {
40
60
  return settled;
@@ -42,36 +62,78 @@ export function createSettlementLedger(call) {
42
62
  set(next) {
43
63
  settled = next;
44
64
  },
45
- fromResolved(resolved, asked, toolName) {
65
+ fromResolved(resolved, asked, req) {
66
+ const record = attestationOf(resolved, call);
67
+ const retired = typeof resolved === "object" && resolved !== null && Object.hasOwn(resolved, "settlement");
46
68
  if (asked.action !== "ask" || asked.origin === undefined) {
47
- if (resolved.settlement === undefined)
48
- return;
49
- throw new Error(`an ask for "${toolName}" was resolved without an origin word — the origin stamp precedes every resolution`);
69
+ if (resolved.action === "allow" && record?.settlement === undefined && !retired)
70
+ return resolved;
71
+ throw new Error(`an ask for "${call.toolName}" was resolved without an origin word — the origin stamp precedes every resolution`);
50
72
  }
51
- const attested = engineSettlementOf(resolved, call);
52
- if (attested !== undefined) {
53
- settled = { settlement: attested.settlement, origin: asked.origin };
54
- return;
73
+ const origin = asked.origin;
74
+ const refused = (message, by) => {
75
+ settled = by;
76
+ return { action: "deny", message, decisionReason: "mode" };
77
+ };
78
+ if (retired) {
79
+ return refused(`the resolution for "${call.toolName}" carries the retired "settlement" member — what ended a wait is an engine-minted record ` +
80
+ `(\`attestation\`), never a resolver's member; denied fail-closed rather than recording a settlement nobody can attribute`, contractRefusal(origin));
55
81
  }
56
- if (resolved.settlement === undefined)
57
- return;
58
- settled = { settlement: resolved.settlement, origin: asked.origin };
82
+ const edited = resolved.action === "allow" && resolved.updatedInput !== undefined;
83
+ const licensed = () => {
84
+ if (edited)
85
+ return record.inputDigest === boundInputHashOf(resolved.updatedInput);
86
+ const askedDigest = boundInputHashOf(req.args);
87
+ return record.inputDigest === askedDigest && (resolved.presentedInput === undefined || boundInputHashOf(resolved.presentedInput) === askedDigest);
88
+ };
89
+ const bound = record?.settlement !== undefined && record.origin === origin && sameClasses(record.classes, asked.classes) ? record.settlement : undefined;
90
+ const refusal = bound !== undefined && SETTLEMENT_IS_REFUSAL[bound.kind] ? bound : undefined;
91
+ if (resolved.action === "allow") {
92
+ if (refusal !== undefined)
93
+ return refused(`the resolution for "${call.toolName}" answered allow but its engine record names a refusal ("${refusal.kind}") — denied fail-closed`, { settlement: refusal, origin });
94
+ const answer = bound !== undefined && licensed() ? bound : undefined;
95
+ if (answer !== undefined) {
96
+ if (asked.requiresRealApproval === true && !SETTLEMENT_IS_HUMAN[answer.kind]) {
97
+ return refused(`approval required for "${call.toolName}" — this ask requires real approval; the resolution's engine record names an answer that is not a person's ("${answer.kind}") — denied fail-closed: ${asked.message ?? ""}`, contractRefusal(origin));
98
+ }
99
+ settled = { settlement: answer, origin, ...licensedOf(record) };
100
+ return resolved;
101
+ }
102
+ if (asked.requiresRealApproval === true) {
103
+ return refused(`approval required for "${call.toolName}" — this ask requires real approval and the resolution's allow carries no engine ` +
104
+ `settlement record for it (an answer the engine cannot attribute to anyone); denied fail-closed: ${asked.message ?? ""}`, contractRefusal(origin));
105
+ }
106
+ return resolved;
107
+ }
108
+ if (resolved.action !== "deny")
109
+ return resolved;
110
+ settled = refusal !== undefined ? { settlement: refusal, origin } : contractRefusal(origin);
111
+ return resolved;
59
112
  },
60
113
  fromDecision(decision) {
61
114
  if (decision.action === "ask")
62
- return undefined;
63
- const attested = engineSettlementOf(decision, call);
64
- if (attested !== undefined)
65
- settled = { settlement: attested.settlement, origin: attested.origin };
66
- if (decision.action !== "deny")
67
- return undefined;
68
- return attested !== undefined && SETTLEMENT_IS_REFUSAL[attested.settlement.kind] ? "ask_resolution" : "policy";
115
+ return { decision };
116
+ const record = attestationOf(decision, call);
117
+ const answer = record?.settlement !== undefined && record.origin !== undefined ? { settlement: record.settlement, origin: record.origin, ...licensedOf(record) } : undefined;
118
+ if (answer !== undefined)
119
+ settled = answer;
120
+ const refusal = answer !== undefined && SETTLEMENT_IS_REFUSAL[answer.settlement.kind];
121
+ if (decision.action === "allow") {
122
+ if (!refusal)
123
+ return { decision };
124
+ return { decision: { action: "deny", message: `the decision for "${call.toolName}" says allow but its engine record names a refusal ("${answer.settlement.kind}") — denied fail-closed`, decisionReason: "rule" }, deniedBy: "ask_resolution" };
125
+ }
126
+ return { decision, deniedBy: refusal ? "ask_resolution" : "policy" };
127
+ },
128
+ keepForBytes(runs) {
129
+ if (settled !== undefined && settled.licensed !== boundInputHashOf(runs))
130
+ settled = undefined;
69
131
  },
70
132
  causeOf(decision) {
71
- return decision.action === "deny" ? classifierDenyCauseOf(decision, call) : undefined;
133
+ return decision.action === "deny" ? attestationOf(decision, call)?.classifierCause : undefined;
72
134
  },
73
135
  classifierRoundOf(decision) {
74
- return classifierRoundOf(decision, call);
136
+ return attestationOf(decision, call)?.classifierRound;
75
137
  },
76
138
  supersede() {
77
139
  settled = undefined;
@@ -90,6 +152,25 @@ export function cloneObserverInput(input) {
90
152
  return input;
91
153
  }
92
154
  }
155
+ export function frozenInputSnapshot(input) {
156
+ try {
157
+ return deepFreeze(structuredClone(input));
158
+ }
159
+ catch {
160
+ return Object.freeze(Array.isArray(input) ? [...input] : input !== null && typeof input === "object" ? { ...input } : input);
161
+ }
162
+ }
163
+ function deepFreeze(value) {
164
+ if (value === null || typeof value !== "object" || Object.isFrozen(value))
165
+ return value;
166
+ Object.freeze(value);
167
+ for (const key of Reflect.ownKeys(value)) {
168
+ const d = Object.getOwnPropertyDescriptor(value, key);
169
+ if (d !== undefined && "value" in d)
170
+ deepFreeze(d.value);
171
+ }
172
+ return value;
173
+ }
93
174
  const PARK_FAILURE_CAUSE_MAX = 600;
94
175
  function withParkFailureCause(reason, parkFailed) {
95
176
  if (parkFailed === undefined)
@@ -104,8 +185,9 @@ export function passAskFace(pass) {
104
185
  export async function engineFailClosedExit(pass, reason) {
105
186
  const { input, toolName, toolCallId, notifyPermissionDenied } = pass;
106
187
  const gate = directDeny("hook");
107
- await notifyPermissionDenied({ toolName, input: cloneObserverInput(pass.currentInput), toolCallId, reason, gate, ...(input.identity !== undefined ? { identity: input.identity } : {}) });
108
- return { block: true, reason: formatHookFeedback(reason, input.reminderMark), gate, preToolContext: pass.preToolContext };
188
+ const finalInput = frozenInputSnapshot(pass.currentInput);
189
+ await notifyPermissionDenied({ toolName, input: cloneObserverInput(finalInput), toolCallId, reason, gate, ...(input.identity !== undefined ? { identity: input.identity } : {}) });
190
+ return { block: true, reason: formatHookFeedback(reason, input.reminderMark), gate, finalInput, preToolContext: pass.preToolContext };
109
191
  }
110
192
  export function hookDenyExit(pass, deniedReason) {
111
193
  const { input } = pass;
@@ -113,6 +195,7 @@ export function hookDenyExit(pass, deniedReason) {
113
195
  block: true,
114
196
  reason: formatHookFeedback(deniedReason, input.reminderMark),
115
197
  gate: directDeny("hook"),
198
+ finalInput: frozenInputSnapshot(pass.currentInput),
116
199
  preToolContext: pass.preToolContext,
117
200
  };
118
201
  }
@@ -141,7 +224,7 @@ export async function exitGate(pass) {
141
224
  ledger.supersede();
142
225
  }
143
226
  const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(pass.denyCause !== undefined ? { cause: pass.denyCause } : {}), ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}), ...(pass.classifierRound !== undefined ? { classifier: pass.classifierRound } : {}), ...(modeRefusal !== undefined ? { modeRefusal: { mode: modeRefusal.mode, askClass: modeRefusal.askClass, classes: modeRefusal.classes } } : {}) });
144
- const foldCause = askUnresolvableCauseOf(pass.decision, { toolCallId, toolName });
227
+ const foldCause = attestationOf(pass.decision, { toolCallId, toolName })?.unresolvableCause;
145
228
  const unresolvable = foldCause ?? unresolvableCauseOfSettlement(gate);
146
229
  const tableSeat = unresolvable !== undefined ? askUnresolvableRemedySeat(unresolvable) : undefined;
147
230
  const remedySeat = tableSeat === "absent" && input.askSeatForm === "declared_none" && pass.askClassification?.classes.has("content_question") !== true ? "declared_none" : tableSeat;
@@ -151,9 +234,10 @@ export async function exitGate(pass) {
151
234
  const cause = unresolvable;
152
235
  pass.notifier.notify(() => input.onAskUnresolvable?.({ toolName, toolCallId, cause, parkLaneExisted: pass.suspendAsk !== undefined, ...(remedy !== undefined ? { remedy } : {}) }), "toolGate.onAskUnresolvable");
153
236
  }
237
+ const finalInput = frozenInputSnapshot(pass.currentInput);
154
238
  await notifyPermissionDenied({
155
239
  toolName,
156
- input: cloneObserverInput(pass.currentInput),
240
+ input: cloneObserverInput(finalInput),
157
241
  toolCallId,
158
242
  reason: denyReason,
159
243
  gate,
@@ -163,6 +247,7 @@ export async function exitGate(pass) {
163
247
  block: true,
164
248
  reason: formatHookFeedback(denyReason, input.reminderMark),
165
249
  gate,
250
+ finalInput,
166
251
  ...(() => {
167
252
  const details = pass.denyDetails ?? (modeRefusal !== undefined ? undefined : pass.shellReadDetails);
168
253
  return details !== undefined ? { details } : {};
@@ -175,11 +260,13 @@ export async function exitGate(pass) {
175
260
  if (rw !== undefined)
176
261
  pass.currentInput = rw;
177
262
  }
263
+ ledger.keepForBytes(pass.currentInput);
178
264
  const release = pass.arbitration?.kind === "released" ? pass.arbitration : (() => { if (ledger.settled !== undefined)
179
265
  return undefined; const a = pass.arbitration === undefined ? input.ancestorArbitrationOf?.(toolCallId) : undefined; return a?.kind === "released" ? a : undefined; })();
180
266
  return {
181
267
  updatedInput: pass.currentInput === event.input ? undefined : pass.currentInput,
182
268
  gate: mintGateOutcome({ ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}), ...(pass.classifierRound !== undefined ? { classifier: pass.classifierRound } : {}), ...(release !== undefined ? { released: releaseRecordOf(release) } : {}) }),
269
+ finalInput: frozenInputSnapshot(pass.currentInput),
183
270
  preToolContext: pass.preToolContext,
184
271
  };
185
272
  }
@@ -1,5 +1,6 @@
1
1
  import { primaryActivityArg } from "../arg-summary.js";
2
- import { askApproverIdentity, carryEngineAttestations } from "../tool-policy.js";
2
+ import { askApproverIdentity, attest, attestationOf } from "../tool-policy.js";
3
+ import { boundInputHashOf } from "../canonical-json.js";
3
4
  export function askGrantCovers(granted, asked) {
4
5
  return asked !== undefined && asked.length > 0 && granted.length > 0 && asked.every((c) => c === "ordinary" || granted.includes(c));
5
6
  }
@@ -30,7 +31,8 @@ export function consumeInheritedAskGrant(grants, onAsk, humanReviewRef, decision
30
31
  ...(toolArg !== undefined ? { toolArg } : {}),
31
32
  });
32
33
  const reused = { action: "allow", presentedInput: grant.presented };
33
- if (grant.settled !== undefined)
34
- carryEngineAttestations(grant.settled, reused);
35
- return reused;
34
+ const settlement = attestationOf(grant.settled, req)?.settlement;
35
+ if (settlement === undefined || decision.action !== "ask")
36
+ return reused;
37
+ return attest(reused, req, { settlement, ...(decision.origin !== undefined ? { origin: decision.origin } : {}), ...(decision.classes !== undefined ? { classes: decision.classes } : {}), inputDigest: boundInputHashOf(grant.presented) });
36
38
  }
@@ -31,9 +31,9 @@ export interface McpRosterDelta {
31
31
  /** The seats a roster application writes through. Every one of them is borrowed from the phase that
32
32
  * minted it — this module owns nothing. */
33
33
  export interface McpRosterApplyInput {
34
- /** borrowed-readonly — the frozen tool face; `exclude` keeps a deployment-excluded tool from ever
35
- * being re-mounted by a face the model or a host can trigger. */
36
- toolFaceSnapshot: Pick<ToolFaceSnapshot, "exclude">;
34
+ /** borrowed-readonly — the frozen tool face; its selector keeps a tool the leg may not use from ever
35
+ * being mounted by a face the model or a host can trigger. */
36
+ toolFaceSnapshot: Pick<ToolFaceSnapshot, "selector">;
37
37
  /** borrowed-readonly — the per-server face overlay (the phase's `withFaces`). */
38
38
  withFaces: (tools: AgentTool[], server: string) => AgentTool[];
39
39
  /** borrowed-readonly — the large-result wrapper every protocol tool is mounted through. */
@@ -2,9 +2,8 @@ import { deliverEngineNotice } from "../types.js";
2
2
  import { thrownText } from "../thrown-value.js";
3
3
  export function applyMcpRosterDelta(input, delta) {
4
4
  const { toolFaceSnapshot, withFaces, remoteToolOffload, foldProtocolAxes, toolEffects, axisExplicitNegatives, roster } = input;
5
- const excludedSet = new Set(toolFaceSnapshot.exclude ?? []);
6
- const pushable = delta.tools.filter((t) => !excludedSet.has(t.name));
7
- const excluded = delta.tools.filter((t) => excludedSet.has(t.name)).map((t) => t.name);
5
+ const pushable = delta.tools.filter((t) => toolFaceSnapshot.selector.admits(t));
6
+ const excluded = delta.tools.filter((t) => !toolFaceSnapshot.selector.admits(t)).map((t) => t.name);
8
7
  const domainSnapshot = (m) => new Map([...m].filter(([name]) => name.startsWith(delta.prefix)));
9
8
  const restoreDomain = (m, snap) => {
10
9
  for (const name of [...m.keys()])
@@ -20,7 +19,7 @@ export function applyMcpRosterDelta(input, delta) {
20
19
  for (const name of priorDomainNegatives.keys())
21
20
  axisExplicitNegatives.delete(name);
22
21
  try {
23
- foldProtocolAxes(delta.axes.filter((a) => !excludedSet.has(a.name)), "MCP");
22
+ foldProtocolAxes(delta.axes.filter((a) => !excluded.includes(a.name)), "MCP");
24
23
  }
25
24
  catch (foldErr) {
26
25
  restoreDomain(toolEffects, priorDomainEffects);
@@ -34,8 +34,7 @@ import { type HeadLeads } from "../path-rule-binding.js";
34
34
  import type { ToolCallLike } from "../tool-registry.js";
35
35
  import { type OrgRuleResolution } from "../permission-rule-org.js";
36
36
  import { type EffectivePermissionRules, type PermissionRuleStoreProvider } from "../permission-rule-provider.js";
37
- /** The one SHELL tool the persisted-rule lane's COMMAND grammar speaks for (the rule-offer face mints for it and the
38
- * name tools). The PATH and NAME grammars' tools are derived (`ruleToolGrammarOf`). */
37
+ /** The one SHELL tool the persisted-rule lane's COMMAND grammar speaks for (the rule-offer face mints for it and the name tools); the other grammars' tools are derived (`ruleToolGrammarOf`). */
39
38
  export declare const PERSISTED_RULE_TOOL = "Bash";
40
39
  /**
41
40
  * The evidence an INHERITED-lane ask carries.
@@ -1,8 +1,7 @@
1
1
  import { persistedRuleMandateOf, ruleClearanceOf } from "../ask-origin.js";
2
2
  import {} from "../hooks.js";
3
- import { adjudicatePersistedNameRules, adjudicatePersistedPathRules, adjudicatePersistedRules, callPathFaceOf, faceAskSpeaksFor, laneToolNamesOf, nameRuleSubjectOf, ruleToolGrammarOf, segmentCoverageOf, suggestRuleForName, suggestRulesForCommand } from "../permission-rule-model.js";
4
- import { isAbsolutePathForm } from "../../tools/fs/safety.js";
5
- import { callTargetViewsOf } from "../effective-path-target.js";
3
+ import { adjudicatePersistedDomainRules, adjudicatePersistedNameRules, adjudicatePersistedPathRules, adjudicatePersistedRules, callPathFaceOf, domainRuleSubjectOf, faceAskSpeaksFor, laneToolNamesOf, nameRuleSubjectOf, ruleToolGrammarOf, segmentCoverageOf, suggestRuleForName, suggestRulesForCommand } from "../permission-rule-model.js";
4
+ import { callTargetViewsOf, validatePath } from "../effective-path-target.js";
6
5
  import { bindPathRules, persistedRowAnchors, projectScopeIdentity } from "../path-rule-binding.js";
7
6
  import { heldBy, seatOf, wireOf } from "../tool-name-readings.js";
8
7
  import { orgRuleVerdictFor, settleOrgVerdictWithin } from "../permission-rule-org.js";
@@ -81,7 +80,7 @@ export function orgVerdictBeforeClaim(cfg, req) {
81
80
  }
82
81
  export function createPermissionRuleLanes(cfg) {
83
82
  const provider = cfg.provider;
84
- if (cfg.home !== undefined && !isAbsolutePathForm(cfg.home)) {
83
+ if (cfg.home !== undefined && validatePath(cfg.home, { intent: "validate-coordinate" }) === undefined) {
85
84
  const e = new Error(`the execution environment declares homeDir ${JSON.stringify(cfg.home)}, which is not an absolute path — a \`~/\` permission rule could not be resolved against it; declare an absolute home directory or none`);
86
85
  e.code = "config.execution_env_home_dir_invalid";
87
86
  throw e;
@@ -163,6 +162,8 @@ export function createPermissionRuleLanes(cfg) {
163
162
  return pathRuleLaneAnswer(table, req, { root: cfg.root, sessionId: cfg.sessionId, anchorsOf, leads, ...scope });
164
163
  if (grammar === "name")
165
164
  return persistedRuleAnswerOf(adjudicatePersistedNameRules(table, { tool: req.toolName, name: nameRuleSubjectOf(req.toolName, req.args), cwd: cfg.root, sessionId: cfg.sessionId, ...scope }));
165
+ if (grammar === "domain")
166
+ return persistedRuleAnswerOf(adjudicatePersistedDomainRules(table, { tool: req.toolName, host: domainRuleSubjectOf(req.toolName, req.args), cwd: cfg.root, sessionId: cfg.sessionId, ...scope }));
166
167
  const command = req.args?.command;
167
168
  if (typeof command !== "string")
168
169
  return undefined;
@@ -22,6 +22,7 @@ import type { ContainmentFace } from "../../tools/fs/index.js";
22
22
  import type { PlacedReadDenyMatcher } from "../../tools/fs/read-deny-home.js";
23
23
  import { type ArtifactStoreRef } from "./read-root-grant.js";
24
24
  import type { Prepared } from "./contracts.js";
25
+ import type { ToolOccurrenceTable } from "./tool-occurrence.js";
25
26
  export interface PrepareArtifactInput {
26
27
  /** borrowed-readonly — the deployment's hosting seat and the notice sink the refusal arm announces on. */
27
28
  deps: Pick<RunnerDeps, "artifactHost" | "onNotice" | "tracer">;
@@ -36,6 +37,9 @@ export interface PrepareArtifactInput {
36
37
  /** borrowed-readonly — the run's effective approver (`spec.onAsk ?? deps.onAsk`, the seat the tool gate resolves at):
37
38
  * the tool's shared-read consent gate rides it as a mount dep (a core mount's execute ctx is minimal). */
38
39
  onAsk: OnAsk | undefined;
40
+ /** borrowed-mutable — the leg's occurrence table: a consent the tool asks DURING its execution is a wait on the person
41
+ * for that call, counted through the table's one bracket (each confirmation one entry and one exit). */
42
+ toolOccurrences: ToolOccurrenceTable;
39
43
  /** borrowed-readonly — the leg's live permission-mode seat; the tool's shared-read consent gate arbitrates at it before
40
44
  * the approver is consulted (a released read is delivered, undisclosed to nobody: the gate records it). */
41
45
  permissionMode: PermissionModeController;
@@ -11,7 +11,7 @@ import { emitTrace } from "../trace.js";
11
11
  import { createArtifactTool } from "../../tools/artifact/artifact-tool.js";
12
12
  import { thrownText } from "../thrown-value.js";
13
13
  export function prepareArtifact(input) {
14
- const { deps, runId, taskId, sessionId, agentName, onAsk, permissionMode, executionEnv, rootCanonical, additionalRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames, artifactStoreRef } = input;
14
+ const { deps, runId, taskId, sessionId, agentName, onAsk: approver, toolOccurrences, permissionMode, executionEnv, rootCanonical, additionalRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames, artifactStoreRef } = input;
15
15
  const host = deps.artifactHost;
16
16
  if (host === undefined)
17
17
  return { artifactPlane: undefined };
@@ -66,6 +66,7 @@ export function prepareArtifact(input) {
66
66
  return { ok: false, reason: "too_large", size: r.value.byteLength, limit: maxBytes, judgedOn: "bytes" };
67
67
  return { ok: true, key: rk.key, bytes: r.value };
68
68
  };
69
+ const onAsk = typeof approver === "function" ? (req, signal) => toolOccurrences.whileAwaitingUser(req.toolCallId, () => approver(req, signal)) : approver;
69
70
  const artifactSpec = createArtifactTool({ host, capabilities: verdict.capabilities, runId, taskId, sessionId, ...(agentName !== undefined ? { agentName } : {}), readLocalFile, ...(onAsk !== undefined ? { onAsk } : {}), permissionMode: () => permissionMode.current, ...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}) });
70
71
  roster.mount(firstPartyOffload(defineTool(artifactSpec)), { source: "builtin", mountedBy: "optional" });
71
72
  envHandToolNames.add(ARTIFACT_TOOL_NAME);
@@ -36,6 +36,8 @@ export interface PrepareAskLaneInput {
36
36
  stampCallTarget: CallTargetStamp | undefined;
37
37
  /** borrowed-readonly — the run's advertised-writable-directory seat, or undefined (hands-less / nothing advertised). `roots` is read at RUN time, never captured: it is the fence's own admitted list and the write gate's exemption domain must be that same list. Not written here. */
38
38
  advertisedWritableDirs: Pick<AdvertisedWritableDirs, "roots"> | undefined;
39
+ /** borrowed-readonly — the leg's ONE exempt root, stamped on every request a policy judges (`ToolCallRequest.exemptRoots`). */
40
+ exemptRoots: readonly string[];
39
41
  /** borrowed-readonly — the shared mount roster; read at RUN time by the approval-preview projection (alias-aware
40
42
  * lookup over whatever the roster holds when the ask is minted). Never mutated here. */
41
43
  tools: readonly AgentTool[];
@@ -1,9 +1,11 @@
1
1
  import { cardDisclosureOf } from "../allow-entry.js";
2
2
  import { primaryActivityArg } from "../arg-summary.js";
3
3
  import { hookSeatExpiredError, runHookSeat } from "../hooks.js";
4
- import { advertisedWritableRootsSeat, isLiveApproverSeat, resolveAsk } from "../tool-policy.js";
4
+ import { advertisedWritableRootsSeat, exemptRootsSeat, attest, attestationOf, isLiveApproverSeat, resolveAsk } from "../tool-policy.js";
5
+ import { boundInputHashOf } from "../canonical-json.js";
5
6
  import { composeCallSignal, raceAbort } from "./abort-race.js";
6
7
  import { askMandateMember } from "../ask-origin.js";
8
+ import { approvalCardMemberOf } from "../tool-roster.js";
7
9
  import { gateAskCarry, lateAskSettlementObserver } from "./denial-limit-arms.js";
8
10
  import { consumeInheritedAskGrant } from "./inherited-ask-grants.js";
9
11
  import { settleReadRootGrant } from "./read-root-grant.js";
@@ -59,14 +61,14 @@ function resolveApprovalPreview(tools, toolName, args) {
59
61
  }
60
62
  }
61
63
  export function prepareAskLane(input) {
62
- const { gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, handsRoot, stampCallTarget, advertisedWritableDirs, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash, grantReadRoot } = input;
64
+ const { gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, handsRoot, stampCallTarget, advertisedWritableDirs, exemptRoots, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash, grantReadRoot } = input;
63
65
  if (!gateMachineryActive)
64
66
  return { askLane: undefined };
65
67
  const composedCallSignal = (callSignal) => composeCallSignal(abortController.signal, callSignal);
66
68
  const adjudicate = effectivePolicy
67
69
  ? (req, callSignal) => {
68
70
  const signal = composedCallSignal(callSignal);
69
- const stampedReq = () => ({ ...req, budget: budgetSnapshot, ...(handsCwdRef !== undefined ? { cwd: handsCwdRef.current } : {}), ...(handsRoot !== undefined ? { root: handsRoot } : {}), ...advertisedWritableRootsSeat(advertisedWritableDirs) });
71
+ const stampedReq = () => ({ ...req, budget: budgetSnapshot, ...(handsCwdRef !== undefined ? { cwd: handsCwdRef.current } : {}), ...(handsRoot !== undefined ? { root: handsRoot } : {}), ...advertisedWritableRootsSeat(advertisedWritableDirs), ...exemptRootsSeat(exemptRoots) });
70
72
  const withReading = stampCallTarget?.(stampedReq(), signal);
71
73
  return raceAbort(withReading === undefined ? Promise.resolve(effectivePolicy.check(stampedReq(), signal)) : withReading.then((r) => effectivePolicy.check(r, signal)), signal, () => ({
72
74
  action: "deny",
@@ -77,15 +79,18 @@ export function prepareAskLane(input) {
77
79
  const approvalPreviewOf = (toolName, args) => resolveApprovalPreview(tools, toolName, args);
78
80
  const resolveAskBound = async (decision, req, callSignal) => {
79
81
  if (inheritedUnavailableAsks.delete(req.toolCallId)) {
80
- return {
82
+ const intercepted = {
81
83
  action: "deny",
82
84
  message: `approval for "${req.toolName}" requires an ancestor task's approval that cannot be resolved here ` +
83
85
  `(no live approver reachable, or a durable-park mandate applies), and no durable approval park is ` +
84
86
  `available — denied fail-closed (the inherited constraint stands).`,
85
87
  decisionReason: "mode",
86
- settlement: { kind: "approver_unavailable", who: { party: "none" }, when: now() },
87
88
  approverUnavailable: true,
88
89
  };
90
+ const settlement = { kind: "approver_unavailable", who: { party: "none" }, when: now() };
91
+ return decision.action === "ask"
92
+ ? attest(intercepted, req, { settlement, ...(decision.origin !== undefined ? { origin: decision.origin } : {}), ...(decision.classes !== undefined ? { classes: decision.classes } : {}), inputDigest: boundInputHashOf(req.args) })
93
+ : attest(intercepted, req, { settlement, inputDigest: boundInputHashOf(req.args) });
89
94
  }
90
95
  const grantReuse = consumeInheritedAskGrant(inheritedAskGrants, onAsk, humanReviewRef, decision, req);
91
96
  if (grantReuse !== undefined)
@@ -104,6 +109,7 @@ export function prepareAskLane(input) {
104
109
  ...cardDisclosureOf(decision, `approval required for "${req.toolName}"`),
105
110
  ...askSourceIdentity(),
106
111
  ...riskAxesOf(req),
112
+ ...approvalCardMemberOf(req),
107
113
  ...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
108
114
  ...(decision.action === "ask" ? askMandateMember(decision) : {}),
109
115
  ...(decision.action === "ask" ? gateAskCarry(decision, isLiveApproverSeat(onAsk), autoModeDenialTracking.current) : {}),
@@ -116,7 +122,7 @@ export function prepareAskLane(input) {
116
122
  const granting = settleReadRootGrant(resolved.readRootGrant, grantReadRoot, { toolName: req.toolName, toolCallId: req.toolCallId, sessionId, runId, ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}), onNotice: deps.onNotice, signal: composedCallSignal(callSignal) });
117
123
  if (granting !== undefined)
118
124
  await granting;
119
- if (resolved.approverUnavailable !== true && resolved.settlement?.kind !== "task_aborted") {
125
+ if (resolved.approverUnavailable !== true && attestationOf(resolved, req)?.settlement?.kind !== "task_aborted") {
120
126
  humanReviewRef.count += 1;
121
127
  humanReviewRef.totalWaitMs += waitMs;
122
128
  const toolArg = primaryActivityArg(req.args);
@@ -26,12 +26,15 @@ export interface PrepareBoundaryParksInput {
26
26
  * absent). Called at park time; never rebuilt here. */
27
27
  saga: SuspendSaga | undefined;
28
28
  /** borrowed-readonly — the REBOUND spec. Read: `resourceSuspend` (the slice scope/ttl/maxSlices), `retainBackgroundProcesses`
29
- * (the park-only sweep gate), `durableApproval` (the review pause's ttl), `principal` (the rows' identity record and
30
- * the review scope). Never mutated. */
29
+ * (the park-only sweep gate), `durableApproval` (the review pause's ttl), `principal` (the rows' identity record).
30
+ * Never mutated. */
31
31
  spec: Pick<TaskSpec, "resourceSuspend" | "retainBackgroundProcesses" | "durableApproval" | "principal">;
32
32
  /** borrowed-readonly — the leg's checkpoint store, or undefined (then the review lane is absent and the resource mint
33
33
  * answers false). */
34
34
  checkpointStore: CheckpointStore | undefined;
35
+ /** borrowed-readonly — this leg's checkpoint scope (the driver's one `checkpointScopeOf` derivation): the `plan_review`
36
+ * row's scope, and the resource row's when the caller declared no slice scope of its own. */
37
+ checkpointScope: string;
35
38
  /** borrowed-mutable — prepare's abort seat. `.signal` is read (a cancelling run mints nothing); `abort()` is called on
36
39
  * the review lane's commit (the review pause stops the run the human gate's way). */
37
40
  abortController: {
@@ -72,12 +75,6 @@ export interface PrepareBoundaryParksInput {
72
75
  liveSpendRef: Prepared["liveSpendRef"];
73
76
  /** borrowed-readonly — the injectable wall clock (the review pause's `suspendedAt`). */
74
77
  now: () => number;
75
- /** borrowed-readonly — the inherited-gate phase's three version-stamp predicates (face / F-012 / org admission). */
76
- faceCheckpointState: () => boolean;
77
- /** borrowed-readonly — see `faceCheckpointState`. */
78
- f012CheckpointState: () => boolean;
79
- /** borrowed-readonly — see `faceCheckpointState`. */
80
- orgAdmissionCheckpointState: () => boolean;
81
78
  /** borrowed-mutable — the run's committed-pause holder (`Prepared.pausedRef`). Writer here: the commit-side publication
82
79
  * of a committed resource / platform / plan-review checkpoint. */
83
80
  pausedRef: Prepared["pausedRef"];
@@ -1,11 +1,10 @@
1
1
  import { hasBackgroundShell, sweepBackgroundShells, sweepRunBoundaryBackgroundShells } from "../background-shell.js";
2
- import { checkpointVersionFor, debitLedger, mintCheckpointId, mintCheckpointToken, } from "../checkpoint-store.js";
2
+ import { debitLedger, mintCheckpointId, mintCheckpointToken, } from "../checkpoint-store.js";
3
3
  import { defaultTaskRegistry } from "../task-registry.js";
4
- import { checkpointScopeOf } from "./checkpoint-scope.js";
5
4
  import { DEFAULT_RESOURCE_TTL_MS, publishCommittedSuspend, sanitizedTtlMs, USAGE_WINDOW_REAP_MARGIN_MS } from "./park-commit.js";
6
5
  import { remoteEnvFailureNote } from "./remote-env-retry.js";
7
6
  export function prepareBoundaryParks(input) {
8
- const { saga, spec, checkpointStore, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter } = input;
7
+ const { saga, spec, checkpointStore, checkpointScope, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter } = input;
9
8
  if (saga === undefined)
10
9
  return { suspendForResource: undefined, suspendForPlatformLimit: undefined, suspendForReview: undefined };
11
10
  const { inFlightSpendMicroUsd, serializeCheckpointState, commitSuspendSaga, suspendLoopCapHit, suspendableEnv, parkOnlyRemoteEnv, parkOnlyHandle } = saga;
@@ -13,7 +12,7 @@ export function prepareBoundaryParks(input) {
13
12
  const rs = spec.resourceSuspend;
14
13
  if (!checkpointStore)
15
14
  return false;
16
- const scope = rs?.scope ?? checkpointScopeOf(spec);
15
+ const scope = rs?.scope ?? checkpointScope;
17
16
  if (abortController.signal.aborted)
18
17
  return false;
19
18
  if (suspendLoopCapHit(priorLedger?.sliceCount ?? 0, maxSlices, " (resource slice limit)"))
@@ -47,7 +46,6 @@ export function prepareBoundaryParks(input) {
47
46
  const cp = {
48
47
  token,
49
48
  checkpointId: mintCheckpointId(),
50
- version: checkpointVersionFor({ resource: true, binding: false, token: resourceLedgerOut.totalTokens !== undefined, orgAdmission: orgAdmissionCheckpointState(), f012: f012CheckpointState(), realApproval: false, face: faceCheckpointState() }),
51
49
  scope,
52
50
  sessionId,
53
51
  leafId,
@@ -124,14 +122,13 @@ export function prepareBoundaryParks(input) {
124
122
  remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
125
123
  }
126
124
  const token = mintCheckpointToken();
127
- const scope = checkpointScopeOf(spec);
125
+ const scope = checkpointScope;
128
126
  const gate = { kind: "plan_review", reason: reason ?? `plan review requested` };
129
127
  const reviewLedger = debitLedger(priorLedger, liveSpendRef.get?.() ?? { costMicroUsd: 0, tokens: 0, turns: 0, walltimeMs: 0 }, resourceTotal, { countSlice: false });
130
128
  const mintedAt = Date.now();
131
129
  const cp = {
132
130
  token,
133
131
  checkpointId: mintCheckpointId(),
134
- version: checkpointVersionFor({ resource: false, binding: true, token: reviewLedger.totalTokens !== undefined, orgAdmission: orgAdmissionCheckpointState(), f012: f012CheckpointState(), realApproval: false, face: faceCheckpointState() }),
135
132
  scope,
136
133
  sessionId,
137
134
  leafId,
@@ -30,23 +30,24 @@ import { type CheckpointSeat } from "../checkpoint-seat.js";
30
30
  import { type ComplianceCapability } from "../compliance.js";
31
31
  import type { LockedPreflight } from "../locked-config.js";
32
32
  import type { StoredSession } from "../session.js";
33
- import type { RunnerDeps, RuntimeCaps, TaskEvent, TaskSpec, ToolExecuteContext } from "../types.js";
33
+ import type { RunnerDeps, RuntimeCaps, TaskEvent, ToolExecuteContext } from "../types.js";
34
34
  import type { AutoModeArmFact } from "../wiring-manifest.js";
35
35
  import type { AssertAllKeysHandled } from "../ask-origin.js";
36
- import type { ContainmentFace } from "../../tools/fs/index.js";
36
+ import { type ChildClampSource } from "../child-clamp-seats.js";
37
37
  import type { InheritedGate, Prepared, RunInternals, RunnerSelfSeat, ToolFaceSnapshot } from "./contracts.js";
38
38
  import { type BlockedRef } from "./synthetic-tools.js";
39
39
  import { RosterBuilder } from "../tool-roster.js";
40
40
  import type { ParentSpecSeat } from "../parent-spec-seat.js";
41
+ import { type RosterSpec } from "./caller-roster.js";
41
42
  export interface PrepareCapsAndWorkflowInput {
42
43
  /** borrowed-readonly — the REBOUND spec, whole: the roster map reads `tools`; the mounts read `enableBlockedReport`,
43
44
  * `enablePlanMode`, `interactiveTools`; the caps/compliance stations read `principal`, `selfOrchestration`,
44
45
  * `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `handsReadOnly`, `interactiveTools`. The
45
- * self-orchestration predicate takes the whole spec. Never mutated. */
46
- spec: TaskSpec;
46
+ * self-orchestration predicate takes the whole spec. Never mutated. Typed as a spec whose roster is snapshot faces. */
47
+ spec: RosterSpec;
47
48
  /** borrowed-readonly — the deployment seats, whole: `runtimeCapsResolver`, `compliancePostureResolver`, `onError`, `onNotice`,
48
49
  * `autoMode`, `brain`, `models`, and the Workflow mount's dozen deps (`workflowScriptRunner`,
49
- * `workflowGovernanceBaseline`, `workflowRunStore`, `workflowJournalStore`, `workflowScriptStore`, `builtinWorkflows`,
50
+ * `workflowGovernanceBaseline`, `workflowRunStore`, `workflowJournalStore`, `workflowScriptStore`,
50
51
  * `onWorkflowAgentSpawn`, `workflowCompletionNotifier`, `workflowLimits`, `agents`, `builtinAgents`, `onBackgroundChildEvent`).
51
52
  * The self-orchestration predicate takes the whole record. */
52
53
  deps: RunnerDeps;
@@ -87,13 +88,11 @@ export interface PrepareCapsAndWorkflowInput {
87
88
  harnessRef: {
88
89
  current?: AgentHarness;
89
90
  };
90
- /** borrowed-readonly — the run's approval seat as the config doors froze it (the Workflow mount's parentOnAsk / parentApprovalReach). */
91
+ /** borrowed-readonly — the run's approval seat as the config doors froze it (the Workflow mount's parentOnAsk). */
91
92
  askSeat: import("../wiring-manifest.js").AskSeat;
92
93
  /** borrowed-readonly — the parent SPEC seat the children inherit (minted once by the inherited-gate phase; the Workflow mount's dep, the same value the delegation ctx carries). */ parentSpecSeat: ParentSpecSeat;
93
- /** borrowed-readonly — the ONE read-face carrier expression (the Workflow mount's parentReadFace getter calls it). */
94
- carrierReadFace: () => ContainmentFace | undefined;
95
- /** borrowed-readonly — the same carrier expression on the WRITE seat. */
96
- carrierWriteFace: () => ContainmentFace | undefined;
94
+ /** borrowed-readonly — the run's clamp source (minted once by the inherited-gate phase; the Workflow mount's `parentClamps`, the same source the delegation ctx carries). */
95
+ runClampSource: () => ChildClampSource;
97
96
  /** borrowed-readonly — the filtered display-forwarding wrapper (the Workflow mount's forwardEvent; absent ⇒ no key). */
98
97
  forwardEvent: ((e: TaskEvent) => void) | undefined;
99
98
  /** borrowed-readonly — the child-chain assembly (the Workflow mount's inheritedGateForChildren). */
@@ -128,6 +127,8 @@ export interface PrepareCapsAndWorkflowInput {
128
127
  };
129
128
  /** borrowed-readonly — the peer lane's mount verdict (the classifier's cross-session rule fills only while mounted). */
130
129
  peerLaneActive: boolean;
130
+ /** borrowed-readonly — the leg's effective delegation fact (`effectiveDelegationFacts`): the classifier window shows its user lane as the launching agent's. */
131
+ delegated: boolean;
131
132
  /** borrowed-readonly — whether the BUILT-IN SendMessage is on this face (the lane rule's second term). */
132
133
  peerSendMessageBuiltIn: boolean;
133
134
  /** borrowed-readonly — the trusted Runner self-reference the Workflow mount executes children through; undefined when
@@ -140,11 +141,6 @@ export interface PrepareCapsAndWorkflowInput {
140
141
  artifact: PromptEpochArtifact;
141
142
  sourceRevision?: string;
142
143
  } | undefined;
143
- /** borrowed-readonly — LATE-BOUND: the normalized deny additions; the Workflow mount's parentReadDenyPatterns getter reads it at call time. */
144
- readDenyAdditionsNormalized: () => ReadonlyArray<{
145
- pattern: string;
146
- caseSensitive: boolean;
147
- }>;
148
144
  }
149
145
  export interface PrepareCapsAndWorkflowResult {
150
146
  /** owned — THE run's roster BUILDER (the mount array is private to it; `Prepared.tools` is its read face,