@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
@@ -1,5 +1,5 @@
1
1
  import { withArgsReading } from "./effective-path-target.js";
2
- import { attestClassifierDenyCause, classifierDenyCauseOf, decisionText, refuseOutOfContractDecision } from "./tool-policy.js";
2
+ import { attest, attestationOf, decisionText, refuseOutOfContractDecision } from "./tool-policy.js";
3
3
  import { arbitrateByMode, classifyAsk, fileCommandOptionsSentence, persistedRuleMandateOf, ruleClearanceOf, safetyAxisOf, stampAskOrigin } from "./ask-origin.js";
4
4
  import { classifierParseFailureDenyMessage, denialLimitFallbackMessage, rungDidNotRule, unarmedWindow } from "./auto-mode.js";
5
5
  import { classifierNoRulingArm, settleNoRulingAsk } from "./classifier-unavailable-arm.js";
@@ -39,7 +39,7 @@ export async function runGateLanes(pass) {
39
39
  requiresUserInteraction: input.requiresUserInteraction,
40
40
  probeUnanswered: pass.probeUnanswered === true,
41
41
  writeProtected: pass.writeProtected === true,
42
- writeProtectionUnresolved: pass.writeProtectionUnresolved === true,
42
+ targetUnresolved: pass.targetUnresolved === true,
43
43
  });
44
44
  const readFaceNow = input.readFace?.();
45
45
  const askOriginFacts = (org, ruleCallUnreadable) => ({
@@ -307,13 +307,13 @@ export async function runGateLanes(pass) {
307
307
  message: verdict.kind === "block" ? `auto-mode classifier blocked this call${reason ? `: ${reason}` : category ? `: [${category}]` : ""}` : reason,
308
308
  decisionReason: "classifier",
309
309
  };
310
- pass.decision = verdict.kind === "parse_error" ? attestClassifierDenyCause(denied, "parse_error", pass.req) : denied;
310
+ pass.decision = verdict.kind === "parse_error" ? attest(denied, pass.req, { classifierCause: "parse_error" }) : denied;
311
311
  }
312
312
  }
313
313
  }
314
314
  if (pass.decision.action === "deny") {
315
315
  pass.deniedBy = "classifier";
316
- pass.denyCause = classifierDenyCauseOf(pass.decision, pass.req);
316
+ pass.denyCause = attestationOf(pass.decision, pass.req)?.classifierCause;
317
317
  }
318
318
  }
319
319
  if (input.sandboxAdmission !== undefined &&
@@ -456,12 +456,12 @@ export async function runGateLanes(pass) {
456
456
  let askBeforeResolve = pass.decision;
457
457
  const resolveOnce = (d) => (callSignal !== undefined ? resolveAsk(d, pass.req, callSignal) : resolveAsk(d, pass.req));
458
458
  let resolved = await resolveOnce(askBeforeResolve);
459
- const refallback = settleNoRulingAsk({ ask: askBeforeResolve, mintedHere: noRulingMinted, resolved, tracker: input.autoMode?.denialTracking });
459
+ const refallback = settleNoRulingAsk({ ask: askBeforeResolve, mintedHere: noRulingMinted, resolved: { action: resolved.action, settlement: attestationOf(resolved, pass.req)?.settlement }, tracker: input.autoMode?.denialTracking });
460
460
  if (refallback !== undefined && askBeforeResolve.action === "ask") {
461
461
  askBeforeResolve = fallbackAskOf(askBeforeResolve, refallback, toolName);
462
462
  resolved = await resolveOnce(askBeforeResolve);
463
463
  }
464
- ledger.fromResolved(resolved, askBeforeResolve, toolName);
464
+ resolved = ledger.fromResolved(resolved, askBeforeResolve, pass.req);
465
465
  if (resolved.action === "deny")
466
466
  pass.deniedBy = "ask_resolution";
467
467
  pass.decision = resolved;
@@ -480,7 +480,8 @@ export async function runGateLanes(pass) {
480
480
  input.autoMode?.denialTracking?.recordAllow();
481
481
  }
482
482
  else if ((resolved.action === "deny" &&
483
- (SETTLEMENT_NOBODY_JUDGED[resolved.settlement.kind] || resolved.settlement.kind === "approver_unavailable")) ||
483
+ ledger.settled !== undefined &&
484
+ (SETTLEMENT_NOBODY_JUDGED[ledger.settled.settlement.kind] || ledger.settled.settlement.kind === "approver_unavailable")) ||
484
485
  resolved.approverUnavailable === true) {
485
486
  try {
486
487
  input.onHeadlessDenialLimit?.({ toolName, toolCallId, fallback: unarmedWindow(askBeforeResolve.denialLimitFallback) });
@@ -562,10 +563,11 @@ export async function runGateLanes(pass) {
562
563
  const attributed = ledger.classifierRoundOf(recheck);
563
564
  if (attributed !== undefined)
564
565
  pass.classifierRound = attributed;
565
- const refusedBy = ledger.fromDecision(recheck);
566
- if (recheck.action === "deny" && refusedBy !== undefined) {
566
+ const read = ledger.fromDecision(recheck);
567
+ recheck = read.decision;
568
+ if (recheck.action === "deny" && read.deniedBy !== undefined) {
567
569
  editDenied = recheck;
568
- pass.deniedBy = refusedBy;
570
+ pass.deniedBy = read.deniedBy;
569
571
  pass.denyCause = ledger.causeOf(recheck);
570
572
  break;
571
573
  }
@@ -636,8 +638,7 @@ export async function runGateLanes(pass) {
636
638
  }
637
639
  }
638
640
  const editAskReq = { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) };
639
- const rr = await (callSignal !== undefined ? resolveAsk(editAskDecision, editAskReq, callSignal) : resolveAsk(editAskDecision, editAskReq));
640
- ledger.fromResolved(rr, editAskDecision, toolName);
641
+ const rr = ledger.fromResolved(await (callSignal !== undefined ? resolveAsk(editAskDecision, editAskReq, callSignal) : resolveAsk(editAskDecision, editAskReq)), editAskDecision, editAskReq);
641
642
  if (rr.action !== "allow") {
642
643
  editDenied = rr;
643
644
  pass.deniedBy = "ask_resolution";
@@ -653,14 +654,14 @@ export async function runGateLanes(pass) {
653
654
  editRewrittenSinceHuman = false;
654
655
  }
655
656
  if (editDenied === undefined && editRewrittenSinceHuman && input.writeProtectionCheck !== undefined) {
656
- const judged = input.writeProtectionCheck(toolName, editArgs, pass.req.face, input.trackedCwd?.(), callSignal ?? input.abortSignal);
657
- const verdict = judged === null ? undefined : await awaitWriteProtectionJudgment(judged, boundedAwaitDeadlineMs(), callSignal ?? input.abortSignal);
657
+ const check = input.writeProtectionCheck;
658
+ const verdict = await awaitWriteProtectionJudgment((deadline) => check(toolName, editArgs, pass.req.face, input.trackedCwd?.(), deadline), boundedAwaitDeadlineMs, callSignal ?? input.abortSignal);
658
659
  if (verdict !== undefined && verdict.kind !== "clear") {
659
660
  editDenied = {
660
661
  action: "deny",
661
662
  message: verdict.kind === "hit"
662
663
  ? `the approved edit for "${toolName}" was rewritten by the restriction chain onto a write-protected path (table entry "${verdict.hit.name}") that no approval covers — denied fail-closed; re-submit the edited action directly`
663
- : `the approved edit for "${toolName}" was rewritten by the restriction chain onto a target whose real location could not be resolved (${verdict.cause}) — denied fail-closed; re-submit the edited action directly`,
664
+ : `the approved edit for "${toolName}" was rewritten by the restriction chain onto a target whose destination could not be determined (target_unresolved: ${verdict.cause}) — denied fail-closed; re-submit the edited action directly`,
664
665
  };
665
666
  pass.deniedBy = "write_protection";
666
667
  }
@@ -62,9 +62,9 @@ export declare function isSettlementKind(v: unknown): v is SettlementKind;
62
62
  * ended (the ask resolver's arms, the approval factory's arms, the decide lane over a host's decision
63
63
  * FACTS), and the four DECIDER words by one composer ({@link settledByDecider}). A host never mints a kind: a synchronous approver reports `"human"`/`"timeout"`/`"policy"` on its
64
64
  * outcome and a durable decide reports `hostDecision.decidedBy` (`"person"`/`"sla_timeout"`/`"policy"`) — facts
65
- * core turns into the word. Nothing on the caller-composable policy face (`PermissionResult`) carries a settlement,
66
- * so a policy cannot self-declare one; the engine's own settlement sites that hand a settled decision
67
- * back through a policy fold attest it through {@link engineSettlementOf}.
65
+ * core turns into the word. A settlement reaches the gate's exit only inside an engine-minted record on the decision
66
+ * (`PermissionResult.attestation`, {@link import("./tool-policy.js").EngineAttestation}), which a policy cannot compose:
67
+ * the receipt refuses a record the engine did not mint.
68
68
  */
69
69
  export type Settlement = {
70
70
  kind: "human_allowed" | "human_refused";
@@ -130,6 +130,13 @@ export declare function isSettlementParty(v: unknown): v is SettlementParty;
130
130
  export declare const HOST_DECIDERS: readonly ["person", "sla_timeout", "policy"];
131
131
  export type HostDecider = (typeof HOST_DECIDERS)[number];
132
132
  export declare const isHostDecider: (word: unknown) => word is HostDecider;
133
+ /** The host's DECISION FACTS on a durable decide — who ended the wait, and the attribution the approval channel
134
+ * reported for that party. ONE shape for every decide that records its decider (a tool approval's and a plan
135
+ * pause's); core mints the settlement word from it ({@link settlementOfHostDecision}), the host never supplies one. */
136
+ export interface HostDecisionFacts {
137
+ decidedBy: HostDecider;
138
+ approver?: string;
139
+ }
133
140
  /** The DECIDER arms of {@link Settlement} — a person's and the deployment policy's, the two parties that
134
141
  * answer an ask either way. Named so a site that both composes one and quotes its note can read the seat
135
142
  * off the record instead of re-deriving it. */
@@ -162,6 +169,14 @@ export declare function decidersNote(text: string | undefined): string | undefin
162
169
  * refusal is never a control-flow boundary — so a note handed with the policy party is not filed here.
163
170
  */
164
171
  export declare function settledByDecider(party: DeciderSettlement["who"]["party"], verdict: "allowed" | "refused", approver: string | undefined, note?: string): DeciderSettlement;
172
+ /**
173
+ * THE mint for a durable decide's settlement, from the host's decision FACTS: the SLA sweep's word is the host's own
174
+ * record (`park_sla_expired`, whatever the verdict — the capture refuses a sweep that allows), a person's and the
175
+ * deployment policy's go through {@link settledByDecider}. Every durable decide that records its decider — a tool
176
+ * approval's and a plan pause's — composes its record here, so one answer cannot end as two records depending on
177
+ * which kind of row it resolved. `note` is the decider's own text on a refusal (filed on the person's refusal only).
178
+ */
179
+ export declare function settlementOfHostDecision(facts: HostDecisionFacts, verdict: "allowed" | "refused", note?: string): Settlement;
165
180
  /** Which settlement kinds are REFUSALS (the ask ended as a deny). Total over the closed set — the fence
166
181
  * below refuses a member without a row — so invariant I2 is a table lookup, not a list in a condition. */
167
182
  export declare const SETTLEMENT_IS_REFUSAL: {
@@ -345,8 +360,8 @@ export type GateDisposition = {
345
360
  * to anyone: the mode, the disclosed class word (`askClass`, the first member of the folded set in `ASK_CLASSES`
346
361
  * order — one of {@link releasableAskClassesFor} on the call's face), the whole set, and the origin / mandate words the card would
347
362
  * have shown. `reason` is a member of {@link import("./ask-origin.js").MODE_RELEASE_REASONS} (`isModeReleaseReason`):
348
- * `"rule_unreadable"` marks a release over a rule the call could not be read against, `"write_protection_unresolved"` a release (the
349
- * shell face) over a write target the judge could not resolve; absent, the release names none. The record carries no face, so the
363
+ * `"rule_unreadable"` marks a release over a rule the call could not be read against, `"target_unresolved"` a release (the
364
+ * shell face) over a write target whose reading could not say where it leads; absent, the release names none. The record carries no face, so the
350
365
  * screen asks that SOME face releases the class.
351
366
  */
352
367
  export interface ModeRelease {
@@ -37,6 +37,11 @@ export function settledByDecider(party, verdict, approver, note) {
37
37
  const given = decidersNote(note);
38
38
  return { kind: verdict === "allowed" ? "human_allowed" : "human_refused", who: { party: "person", ...attributed }, when: Date.now(), ...(given !== undefined ? { note: given } : {}) };
39
39
  }
40
+ export function settlementOfHostDecision(facts, verdict, note) {
41
+ if (facts.decidedBy === "sla_timeout")
42
+ return { kind: "park_sla_expired", who: { party: "host", ...(facts.approver !== undefined ? { approver: facts.approver } : {}) }, when: Date.now() };
43
+ return settledByDecider(facts.decidedBy, verdict, facts.approver, verdict === "refused" ? note : undefined);
44
+ }
40
45
  export const SETTLEMENT_IS_REFUSAL = {
41
46
  human_allowed: false,
42
47
  human_refused: true,
@@ -44,7 +44,8 @@ export declare const NON_GOVERNANCE_MEMORY_CODES: ReadonlySet<string>;
44
44
  export declare function governanceRetryClass(code: string): GovernanceRetryClass | undefined;
45
45
  /**
46
46
  * The CLOSED set of codes the `spec.tools` DECLARATION door refuses a caller's tool entry with, at prepare,
47
- * before anything mounts: the entry cannot be built from its own members (`config.tool_mount_denied`), a
47
+ * before anything mounts: the entry cannot be built from its own members, or the caller changed its array after the run
48
+ * fixed the roster (`config.tool_mount_denied`), a
48
49
  * member over a roster row's wire bound (`config.tool_roster_bound` / `config.tool_name_too_long` /
49
50
  * `config.tool_contract_too_long`), a schema over the row's key bounds (`config.tool_schema_bound`), a
50
51
  * declared face or result card the schema / namespace cannot carry (`config.tool_face_invalid`), a name or
@@ -136,7 +137,7 @@ export type NoticeAudience = "user" | "operator";
136
137
  * the union's catalog ({@link EngineNotice.code}). The groups below say only which family a row joins,
137
138
  * so the catalog is not written a second time here and the two cannot drift.
138
139
  */
139
- export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.write_protection_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "permission.allowed_tool_not_granted", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.base_url_changed_key_unchanged", "route.response_model_mismatch", "route.tool_call_id_folded", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable"];
140
+ export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.path_view_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "permission.allowed_tool_not_granted", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.base_url_changed_key_unchanged", "route.response_model_mismatch", "route.tool_call_id_folded", "route.finish_reason_unknown", "route.stream_end_ignored", "route.extra_body_reserved_dropped", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable"];
140
141
  /** A catalogued code (see {@link ENGINE_NOTICE_CODES}); {@link NOTICE_MINTER} says who mints it. NOT the type of
141
142
  * `EngineNotice.code`, which stays `string` — a host forwarding its own notices through the same
142
143
  * sink is a supported shape, and narrowing that field would break it. */
@@ -174,6 +175,8 @@ declare const NOTICE_AUDIENCE_TABLE: {
174
175
  readonly "task.late_approval": "user";
175
176
  readonly "task.interrupt_unconsumed": "user";
176
177
  readonly "task.tool_turn_incomplete": "user";
178
+ readonly "route.finish_reason_unknown": "user";
179
+ readonly "route.stream_end_ignored": "user";
177
180
  readonly "approval.read_root_granted": "user";
178
181
  readonly "approval.read_root_grant_rejected": "user";
179
182
  readonly "config.durable_gate_unavailable": "user";
@@ -202,7 +205,7 @@ declare const NOTICE_AUDIENCE_TABLE: {
202
205
  readonly "config.artifact_host_invalid": "operator";
203
206
  readonly "config.task_root_not_canonical": "operator";
204
207
  readonly "config.write_protection_target_view_absent": "operator";
205
- readonly "config.write_protection_unresolved": "operator";
208
+ readonly "config.path_view_unresolved": "operator";
206
209
  readonly "config.execution_env_capability_invalid": "operator";
207
210
  readonly "config.tool_card_undeclared": "operator";
208
211
  readonly "config.tool_face_undeclared": "operator";
@@ -233,6 +236,7 @@ declare const NOTICE_AUDIENCE_TABLE: {
233
236
  readonly "route.base_url_changed_key_unchanged": "operator";
234
237
  readonly "route.response_model_mismatch": "operator";
235
238
  readonly "route.tool_call_id_folded": "operator";
239
+ readonly "route.extra_body_reserved_dropped": "operator";
236
240
  readonly "context.tool_turn_repaired": "operator";
237
241
  readonly "skills.listing_truncated": "operator";
238
242
  readonly "agents.listing_truncated": "operator";
@@ -282,7 +286,7 @@ declare const NOTICE_MINTER_TABLE: {
282
286
  readonly "config.artifact_host_invalid": "engine";
283
287
  readonly "config.task_root_not_canonical": "engine";
284
288
  readonly "config.write_protection_target_view_absent": "engine";
285
- readonly "config.write_protection_unresolved": "engine";
289
+ readonly "config.path_view_unresolved": "engine";
286
290
  readonly "config.execution_env_capability_invalid": "engine";
287
291
  readonly "config.tool_card_undeclared": "engine";
288
292
  readonly "config.tool_face_undeclared": "engine";
@@ -334,6 +338,9 @@ declare const NOTICE_MINTER_TABLE: {
334
338
  readonly "route.base_url_changed_key_unchanged": "engine";
335
339
  readonly "route.response_model_mismatch": "engine";
336
340
  readonly "route.tool_call_id_folded": "engine";
341
+ readonly "route.finish_reason_unknown": "engine";
342
+ readonly "route.stream_end_ignored": "engine";
343
+ readonly "route.extra_body_reserved_dropped": "engine";
337
344
  readonly "context.tool_turn_repaired": "engine";
338
345
  readonly "task.user_steer_undrained": "engine";
339
346
  readonly "task.user_followup_undrained": "engine";
@@ -85,6 +85,8 @@ export const NON_GOVERNANCE_MEMORY_CODES = new Set([
85
85
  "memory.capture_optout_sweep_failed",
86
86
  "memory.target_outside_store",
87
87
  "memory.scope_home_not_directory",
88
+ "memory.root_anchor_backfilled",
89
+ "memory.root_reanchored",
88
90
  ]);
89
91
  export function governanceRetryClass(code) {
90
92
  if (Object.prototype.hasOwnProperty.call(GOVERNANCE_CODES, code)) {
@@ -130,7 +132,7 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
130
132
  "config.artifact_host_invalid",
131
133
  "config.task_root_not_canonical",
132
134
  "config.write_protection_target_view_absent",
133
- "config.write_protection_unresolved",
135
+ "config.path_view_unresolved",
134
136
  "config.execution_env_capability_invalid",
135
137
  "config.tool_card_undeclared",
136
138
  "config.tool_face_undeclared",
@@ -182,6 +184,9 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
182
184
  "route.base_url_changed_key_unchanged",
183
185
  "route.response_model_mismatch",
184
186
  "route.tool_call_id_folded",
187
+ "route.finish_reason_unknown",
188
+ "route.stream_end_ignored",
189
+ "route.extra_body_reserved_dropped",
185
190
  "context.tool_turn_repaired",
186
191
  "task.user_steer_undrained",
187
192
  "task.user_followup_undrained",
@@ -223,6 +228,8 @@ const NOTICE_AUDIENCE_TABLE = {
223
228
  "task.late_approval": "user",
224
229
  "task.interrupt_unconsumed": "user",
225
230
  "task.tool_turn_incomplete": "user",
231
+ "route.finish_reason_unknown": "user",
232
+ "route.stream_end_ignored": "user",
226
233
  "approval.read_root_granted": "user",
227
234
  "approval.read_root_grant_rejected": "user",
228
235
  "config.durable_gate_unavailable": "user",
@@ -251,7 +258,7 @@ const NOTICE_AUDIENCE_TABLE = {
251
258
  "config.artifact_host_invalid": "operator",
252
259
  "config.task_root_not_canonical": "operator",
253
260
  "config.write_protection_target_view_absent": "operator",
254
- "config.write_protection_unresolved": "operator",
261
+ "config.path_view_unresolved": "operator",
255
262
  "config.execution_env_capability_invalid": "operator",
256
263
  "config.tool_card_undeclared": "operator",
257
264
  "config.tool_face_undeclared": "operator",
@@ -282,6 +289,7 @@ const NOTICE_AUDIENCE_TABLE = {
282
289
  "route.base_url_changed_key_unchanged": "operator",
283
290
  "route.response_model_mismatch": "operator",
284
291
  "route.tool_call_id_folded": "operator",
292
+ "route.extra_body_reserved_dropped": "operator",
285
293
  "context.tool_turn_repaired": "operator",
286
294
  "skills.listing_truncated": "operator",
287
295
  "agents.listing_truncated": "operator",
@@ -312,7 +320,7 @@ const NOTICE_MINTER_TABLE = {
312
320
  "config.artifact_host_invalid": "engine",
313
321
  "config.task_root_not_canonical": "engine",
314
322
  "config.write_protection_target_view_absent": "engine",
315
- "config.write_protection_unresolved": "engine",
323
+ "config.path_view_unresolved": "engine",
316
324
  "config.execution_env_capability_invalid": "engine",
317
325
  "config.tool_card_undeclared": "engine",
318
326
  "config.tool_face_undeclared": "engine",
@@ -364,6 +372,9 @@ const NOTICE_MINTER_TABLE = {
364
372
  "route.base_url_changed_key_unchanged": "engine",
365
373
  "route.response_model_mismatch": "engine",
366
374
  "route.tool_call_id_folded": "engine",
375
+ "route.finish_reason_unknown": "engine",
376
+ "route.stream_end_ignored": "engine",
377
+ "route.extra_body_reserved_dropped": "engine",
367
378
  "context.tool_turn_repaired": "engine",
368
379
  "task.user_steer_undrained": "engine",
369
380
  "task.user_followup_undrained": "engine",
@@ -957,6 +957,10 @@ export interface ToolGateResult {
957
957
  gate?: GateOutcome;
958
958
  /** Rewritten args to execute with (re-validated by the loop); omitted when nothing rewrote. */
959
959
  updatedInput?: unknown;
960
+ /** The input this pass decided on (what a refusal refused, what an allowed call runs with) as a deep, FROZEN copy taken
961
+ * at the exit — never the live args. Beside {@link gate} on both terminal exits; absent on the suspend exit. The deny
962
+ * observer gets a detached, writable copy of it. */
963
+ finalInput?: unknown;
960
964
  /** A blocking refusal's structured details, when the refusing station minted any (the shell read station's
961
965
  * `read_path_denied` / `readonly_out_of_root` cards): the loop attaches them to the error result it mints
962
966
  * from `reason`, so the refusal reaches `tool_end.structured` / `errorCode` exactly as the tool's own
@@ -100,3 +100,11 @@ export declare function snapshotMcpEntries(entries: readonly McpServerSpec[]): M
100
100
  * Runs BEFORE any side effect of task preparation.
101
101
  */
102
102
  export declare function preflightLockedConfig(spec: TaskSpec, deps: RunnerDeps): LockedPreflight;
103
+ /**
104
+ * The two caller policies a prepare resolves to: the task's own seat over the deployment's, or the deployment's alone
105
+ * under a `toolPolicy` lock. One resolution for the preflight above and for the resume ladder's pre-claim door.
106
+ */
107
+ export declare function callerPolicySeats(spec: Pick<TaskSpec, "toolPolicy" | "basePolicyForResumeEdit">, deps: Pick<RunnerDeps, "toolPolicy" | "basePolicyForResumeEdit">, toolPolicyLocked: boolean): Pick<LockedPreflight, "toolPolicy" | "basePolicyForResumeEdit">;
108
+ /** The retired-member door over the resolved caller policies: a member the engine no longer reads is refused by name
109
+ * (`config.deps_retired_key`), never dropped in silence. */
110
+ export declare function assertCallerPoliciesCurrent(policies: Pick<LockedPreflight, "toolPolicy" | "basePolicyForResumeEdit">): void;
@@ -1,5 +1,6 @@
1
1
  import { isToolContentOrigin, TOOL_CONTENT_ORIGINS } from "./memory-engine/content-origin.js";
2
2
  import { inlineUntrusted } from "./untrusted-text.js";
3
+ import { assertNoRetiredToolPolicyKeys } from "./retired-keys.js";
3
4
  export const LOCKED_KEY_REGISTRY = {
4
5
  mcp: { specFields: ["mcp"] },
5
6
  toolPolicy: { specFields: ["toolPolicy", "basePolicyForResumeEdit"] },
@@ -67,10 +68,21 @@ export function preflightLockedConfig(spec, deps) {
67
68
  }
68
69
  }
69
70
  }
71
+ const policies = callerPolicySeats(spec, deps, lockedKeys.has("toolPolicy"));
72
+ assertCallerPoliciesCurrent(policies);
70
73
  return {
71
74
  lockedKeys,
72
75
  mcp: lockedKeys.has("mcp") || spec.mcp === undefined ? undefined : snapshotAndValidateMcpEntries(spec.mcp),
73
- toolPolicy: lockedKeys.has("toolPolicy") ? deps.toolPolicy : (spec.toolPolicy ?? deps.toolPolicy),
74
- basePolicyForResumeEdit: lockedKeys.has("toolPolicy") ? deps.basePolicyForResumeEdit : (spec.basePolicyForResumeEdit ?? deps.basePolicyForResumeEdit),
76
+ ...policies,
75
77
  };
76
78
  }
79
+ export function callerPolicySeats(spec, deps, toolPolicyLocked) {
80
+ return {
81
+ toolPolicy: toolPolicyLocked ? deps.toolPolicy : (spec.toolPolicy ?? deps.toolPolicy),
82
+ basePolicyForResumeEdit: toolPolicyLocked ? deps.basePolicyForResumeEdit : (spec.basePolicyForResumeEdit ?? deps.basePolicyForResumeEdit),
83
+ };
84
+ }
85
+ export function assertCallerPoliciesCurrent(policies) {
86
+ assertNoRetiredToolPolicyKeys(policies.toolPolicy);
87
+ assertNoRetiredToolPolicyKeys(policies.basePolicyForResumeEdit);
88
+ }
package/dist/core/lsp.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { uriToPath } from "./lsp-protocol.js";
2
- import { foldRedundantPathSegments, isAbsoluteForFamily, joinForFamily, pathFamilyOf } from "../tools/fs/safety.js";
2
+ import { anchorSpelling, foldRedundantPathSegments, pathFamilyOf } from "../tools/fs/safety.js";
3
3
  import { Type } from "typebox";
4
4
  import { defineTool, errorResult } from "./tools.js";
5
5
  import { toolFace } from "./tool-catalog-entries.js";
@@ -69,11 +69,9 @@ export function settleOnAbort(job, signal, onAbort) {
69
69
  });
70
70
  }
71
71
  export function resolveLspPath(filePath, cwd) {
72
- const family = cwd === undefined ? undefined : pathFamilyOf({ root: cwd });
73
- const isAbsForm = family !== undefined && isAbsoluteForFamily(family, filePath);
74
- if (isAbsForm || !cwd || family === undefined)
72
+ if (!cwd)
75
73
  return foldRedundantPathSegments(filePath);
76
- return foldRedundantPathSegments(joinForFamily(family, cwd, filePath));
74
+ return foldRedundantPathSegments(anchorSpelling(pathFamilyOf({ root: cwd }), cwd, filePath));
77
75
  }
78
76
  export const MAX_LSP_FILE_BYTES = 10 * 1000 * 1000;
79
77
  function fmt(result, ctx) {
@@ -266,10 +266,9 @@ export declare function mailboxCrossProcessMountVerdict(store: MailboxStore): Ma
266
266
  /** RB-250② (2026-07-28) class fix — the box age for `reap` is the MAX `sentAt`, not the
267
267
  * last array element: `sentAt` is caller-supplied, so append order need not be time order, and taking
268
268
  * the tail let a box whose freshest message was mid-array be swept — both bundled backends discarded
269
- * a brand-new message while the CC adapter (stores/cc/mailbox-store.ts, the in-package reference)
270
- * already reduces over MAX. Non-finite `sentAt` ⇒ undefined ("unknown age ⇒ never reaped", the CC
271
- * adapter's documented posture — treating it as very old would let a malformed row delete a live
272
- * box). Module-level export only; NOT re-exported from src/index.ts. */
269
+ * a brand-new message. Non-finite `sentAt` ⇒ undefined ("unknown age ⇒ never reaped" — treating it as
270
+ * very old would let a malformed row delete a live box). Module-level export only; NOT re-exported
271
+ * from src/index.ts. */
273
272
  export declare function newestSentAt(messages: readonly MailboxMessage[]): number | undefined;
274
273
  /** A lease-facing copy of a stored record: every mutable member (hopChain, peerMeta) detached, so a
275
274
  * consumer's mutation can never reach the record a redelivery serves. Shared by the bundled backends. */
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The MCP connection pool of ONE run tree: the legs of a tree — the root run and every delegated child it spawns, background
3
+ * and kept ones included — that declare the same server lease ONE connection (one client, one stdio process, one authorization,
4
+ * one lock holder) instead of dialling a copy each.
5
+ *
6
+ * WHAT IS SHARED AND WHAT IS NOT. Only the connection is: the SDK client over its transport. Everything a leg binds to
7
+ * itself stays the leg's own — the tool objects it mints around the client (their reminder-disclosure counters, their
8
+ * revocation probe, their runId), its liveness record, its close announcer. A shared tool object would write into the account of a
9
+ * parent leg that ended; a shared connection cannot.
10
+ *
11
+ * LIFETIME. A lease is released when its leg's materialization is disposed (the leg ended, failed, was cancelled or parked); the
12
+ * last holder's release closes the connection. The pool itself holds no connection between leases and dies with the run that
13
+ * created it: after `close()` a tree member that asks for a connection dials one of its own (a kept child resumed hours later,
14
+ * a revived one), so the DECLARATION stays the one source of truth — no handle is ever recorded anywhere.
15
+ *
16
+ * THE KEY is the server's declaration as the dial reads it (name and transport) and the principal the task runs under: a
17
+ * different principal is a different identity at the server. A server that opted in to elicitation never enters the pool — the
18
+ * answer to its questions belongs to the leg that is waiting on it.
19
+ */
20
+ import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
21
+ import type { McpServerSpec } from "./mcp-server-spec.js";
22
+ /** The slice of a listed tool the SDK client caches per connection (its output validator, its task-support flags). */
23
+ export interface McpToolMeta {
24
+ readonly name: string;
25
+ readonly outputSchema?: unknown;
26
+ readonly execution?: unknown;
27
+ }
28
+ /** Records one `tools/list` result on a pooled connection (see {@link McpLease.openListing}): the tools the leg mounted from it, of which
29
+ * `retained` names the ones the listing did not return (an incomplete walk keeps them mounted) — those join the membership only. */
30
+ export type McpListingWriter = (tools: ReadonlyArray<McpToolMeta>, apply: (all: McpToolMeta[]) => void, retained?: ReadonlySet<string>) => void;
31
+ /** One leg's hold on a pooled connection. */
32
+ export interface McpLease {
33
+ readonly client: Client;
34
+ /**
35
+ * Open a `tools/list` round trip on the connection — call it BEFORE the request. The returned writer records the result twice over:
36
+ * as the connection's metadata for each listed tool, at this listing's version (its place in the order listings were opened on the
37
+ * connection: a listing opened earlier never overwrites what a later one wrote, whichever answer arrives first; an entry the listing
38
+ * did not return — `retained` — writes no record), and as THIS leg's membership (the names it mounted). It then rewrites the client's per-connection tool cache with the current metadata of every name
39
+ * some holder mounted: the SDK clears and refills that cache on each write, so a leg that mounted a subset must not erase what its
40
+ * siblings' tools need. A release changes the membership only and rewrites the cache from the same metadata.
41
+ */
42
+ openListing(): McpListingWriter;
43
+ /** Run `fn` when the connection closes under the lease (the server died, the transport dropped). Never called for this lease's own release. */
44
+ onClose(fn: () => void): void;
45
+ /** Give the hold back; the last holder's release closes the connection. Idempotent. */
46
+ release(): Promise<void>;
47
+ }
48
+ export declare class McpConnectionPool {
49
+ private readonly entries;
50
+ private readonly dialing;
51
+ /** Bumped by each {@link detach}: a dial that finishes after its key was detached serves the legs already waiting on it and publishes nothing. */
52
+ private readonly generation;
53
+ private shut;
54
+ /**
55
+ * The key a declaration leases under. `kind` is the dial's own single reading of the transport kind (the dial reads it once and threads it, so a
56
+ * transport object that answers differently to two readers cannot split the dial from its key); every other transport member is read here.
57
+ */
58
+ static keyOf(spec: McpServerSpec, principal: string | undefined, kind: string | undefined): string;
59
+ /**
60
+ * Lease the connection for `key`, dialling it with `dial` when none is live. `fresh` replaces the pool's current connection with a new
61
+ * dial (a re-dial): the connection it replaces lives on until its other holders release it. Resolves `undefined` once the pool is
62
+ * closed — the caller dials for itself. A dial that rejects rejects every waiter of that dial, and the pool keeps nothing of it.
63
+ */
64
+ acquire(key: string, dial: () => Promise<Client>, opts?: {
65
+ fresh?: boolean;
66
+ }): Promise<McpLease | undefined>;
67
+ /** Make the next lease of `key` dial a new connection. */
68
+ detach(key: string): void;
69
+ /** No lease is granted after this; the connections still held stay open until their holders release them. */
70
+ close(): void;
71
+ /** How many connections the pool holds open right now (for the lifecycle pins). */
72
+ get live(): number;
73
+ private dialNew;
74
+ private lease;
75
+ }
@@ -0,0 +1,128 @@
1
+ import { canonicalize } from "./canonical-json.js";
2
+ export class McpConnectionPool {
3
+ entries = new Map();
4
+ dialing = new Map();
5
+ generation = new Map();
6
+ shut = false;
7
+ static keyOf(spec, principal, kind) {
8
+ const rest = Object.fromEntries(Object.keys(spec.transport).filter((k) => k !== "kind").map((k) => [k, Reflect.get(spec.transport, k)]));
9
+ return canonicalize([spec.name, kind ?? null, rest, principal ?? null]);
10
+ }
11
+ async acquire(key, dial, opts) {
12
+ if (this.shut)
13
+ return undefined;
14
+ if (opts?.fresh === true)
15
+ this.detach(key);
16
+ let entry = this.entries.get(key);
17
+ if (entry === undefined || entry.closed) {
18
+ let pending = this.dialing.get(key);
19
+ if (pending === undefined) {
20
+ const started = this.dialNew(key, this.generation.get(key) ?? 0, dial);
21
+ pending = started;
22
+ this.dialing.set(key, started);
23
+ const settled = () => {
24
+ if (this.dialing.get(key) === started)
25
+ this.dialing.delete(key);
26
+ };
27
+ void started.then(settled, settled);
28
+ }
29
+ entry = await pending;
30
+ }
31
+ return this.lease(entry);
32
+ }
33
+ detach(key) {
34
+ this.generation.set(key, (this.generation.get(key) ?? 0) + 1);
35
+ const e = this.entries.get(key);
36
+ if (e !== undefined) {
37
+ e.current = false;
38
+ this.entries.delete(key);
39
+ }
40
+ this.dialing.delete(key);
41
+ }
42
+ close() {
43
+ this.shut = true;
44
+ }
45
+ get live() {
46
+ let n = 0;
47
+ for (const e of this.entries.values())
48
+ if (!e.closed)
49
+ n++;
50
+ return n;
51
+ }
52
+ async dialNew(key, generation, dial) {
53
+ const client = await dial();
54
+ const entry = { client, refs: 0, listeners: new Set(), holders: new Map(), meta: new Map(), nextVersion: 0, current: true, closed: false };
55
+ client.onclose = () => {
56
+ entry.closed = true;
57
+ if (this.entries.get(key) === entry)
58
+ this.entries.delete(key);
59
+ for (const fn of [...entry.listeners]) {
60
+ try {
61
+ fn();
62
+ }
63
+ catch {
64
+ }
65
+ }
66
+ };
67
+ if ((this.generation.get(key) ?? 0) === generation)
68
+ this.entries.set(key, entry);
69
+ else
70
+ entry.current = false;
71
+ return entry;
72
+ }
73
+ lease(entry) {
74
+ entry.refs++;
75
+ const mine = new Set();
76
+ let released = false;
77
+ const cached = () => {
78
+ const held = new Set([...entry.holders.values()].flat());
79
+ return [...entry.meta].filter(([name]) => held.has(name)).map(([, r]) => r.tool);
80
+ };
81
+ const lease = {
82
+ client: entry.client,
83
+ onClose: (fn) => {
84
+ mine.add(fn);
85
+ entry.listeners.add(fn);
86
+ },
87
+ openListing: () => {
88
+ const version = entry.nextVersion++;
89
+ return (tools, apply, retained) => {
90
+ for (const tool of tools) {
91
+ const prior = entry.meta.get(tool.name);
92
+ if (retained?.has(tool.name) === true) {
93
+ if (prior === undefined)
94
+ entry.meta.set(tool.name, { tool, version: -1 });
95
+ continue;
96
+ }
97
+ if (prior !== undefined && prior.version > version)
98
+ continue;
99
+ entry.meta.delete(tool.name);
100
+ entry.meta.set(tool.name, { tool, version });
101
+ }
102
+ if (!released)
103
+ entry.holders.set(lease, tools.map((t) => t.name));
104
+ entry.apply = apply;
105
+ apply(cached());
106
+ };
107
+ },
108
+ release: async () => {
109
+ if (released)
110
+ return;
111
+ released = true;
112
+ for (const fn of mine)
113
+ entry.listeners.delete(fn);
114
+ entry.refs--;
115
+ if (entry.holders.delete(lease) && entry.refs > 0)
116
+ entry.apply?.(cached());
117
+ if (entry.refs > 0)
118
+ return;
119
+ entry.current = false;
120
+ for (const [k, v] of this.entries)
121
+ if (v === entry)
122
+ this.entries.delete(k);
123
+ await entry.client.close().catch(() => undefined);
124
+ },
125
+ };
126
+ return lease;
127
+ }
128
+ }
@@ -2,7 +2,8 @@ import type { AssertAllKeysHandled } from "./ask-origin.js";
2
2
  /**
3
3
  * The closed set of failure classes ({@link McpFailure.kind}):
4
4
  * · `connect_refused` — a connect-phase errno (ECONNREFUSED / ENOTFOUND / EAI_AGAIN / EHOSTUNREACH /
5
- * ENETUNREACH / UND_ERR_CONNECT_TIMEOUT): the request provably never left;
5
+ * ENETUNREACH / UND_ERR_CONNECT_TIMEOUT), or a proxy's refusal of the tunnel
6
+ * request: the request provably never left;
6
7
  * · `connection_failed` — any other errno / undici code on the cause chain (a reset or a timeout
7
8
  * mid-exchange): the request may have run;
8
9
  * · `connection_closed` — the SDK reported the transport closed (`McpError` `ConnectionClosed`): in