@sema-agent/core 7.55.0 → 7.56.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 +513 -0
  2. package/dist/agents/cascade.js +1 -1
  3. package/dist/agents/cc-peer-directory.js +1 -0
  4. package/dist/agents/child-model-seat.d.ts +0 -11
  5. package/dist/agents/child-model-seat.js +0 -3
  6. package/dist/agents/list-agents-tool.d.ts +3 -1
  7. package/dist/agents/list-agents-tool.js +7 -7
  8. package/dist/agents/peer-directory.d.ts +22 -4
  9. package/dist/agents/peer-directory.js +24 -2
  10. package/dist/agents/peer-session-drain.js +2 -2
  11. package/dist/agents/repair-loop.js +2 -2
  12. package/dist/agents/send-message-tool.js +4 -4
  13. package/dist/agents/subagent.d.ts +6 -4
  14. package/dist/agents/subagent.js +64 -60
  15. package/dist/agents/tool-filter.d.ts +7 -5
  16. package/dist/agents/tool-filter.js +12 -9
  17. package/dist/agents/verify.d.ts +3 -2
  18. package/dist/agents/verify.js +3 -3
  19. package/dist/brain/anthropic.js +30 -73
  20. package/dist/brain/media-degrade.d.ts +18 -7
  21. package/dist/brain/media-degrade.js +13 -2
  22. package/dist/brain/model-capability.d.ts +37 -0
  23. package/dist/brain/model-capability.js +34 -0
  24. package/dist/brain/model-presets.d.ts +2 -8
  25. package/dist/brain/model-presets.js +1 -6
  26. package/dist/brain/open-responses.js +13 -26
  27. package/dist/brain/openai.js +14 -87
  28. package/dist/brain/reasoning-request.d.ts +96 -0
  29. package/dist/brain/reasoning-request.js +174 -0
  30. package/dist/brain/reasoning.d.ts +11 -11
  31. package/dist/brain/reasoning.js +4 -3
  32. package/dist/brain/request-params.d.ts +7 -4
  33. package/dist/brain/request-params.js +7 -4
  34. package/dist/brain/status-sink.d.ts +20 -0
  35. package/dist/brain/status-sink.js +7 -0
  36. package/dist/core/a2a.d.ts +2 -1
  37. package/dist/core/a2a.js +19 -13
  38. package/dist/core/agent-definition.d.ts +10 -0
  39. package/dist/core/allow-entry.d.ts +20 -13
  40. package/dist/core/allow-entry.js +26 -22
  41. package/dist/core/allow-rule-shadow.d.ts +3 -3
  42. package/dist/core/ask-origin.d.ts +64 -18
  43. package/dist/core/ask-origin.js +63 -23
  44. package/dist/core/ask-question.d.ts +51 -8
  45. package/dist/core/ask-question.js +3 -4
  46. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  47. package/dist/core/ask-unresolvable-notice.js +16 -2
  48. package/dist/core/checkpoint-generation.d.ts +53 -0
  49. package/dist/core/checkpoint-generation.js +35 -0
  50. package/dist/core/checkpoint-queries.d.ts +180 -0
  51. package/dist/core/checkpoint-queries.js +272 -0
  52. package/dist/core/checkpoint-requirements.d.ts +13 -1
  53. package/dist/core/checkpoint-requirements.js +4 -0
  54. package/dist/core/checkpoint-store.d.ts +88 -24
  55. package/dist/core/checkpoint-store.js +24 -9
  56. package/dist/core/cross-boundary-taint.d.ts +6 -5
  57. package/dist/core/cross-boundary-taint.js +1 -3
  58. package/dist/core/decision-receipt.d.ts +37 -3
  59. package/dist/core/decision-receipt.js +17 -17
  60. package/dist/core/delegation-not-started.d.ts +6 -0
  61. package/dist/core/delegation-not-started.js +17 -0
  62. package/dist/core/engine-attestation.d.ts +93 -0
  63. package/dist/core/engine-attestation.js +70 -0
  64. package/dist/core/engine-capabilities.d.ts +4 -1
  65. package/dist/core/engine-capabilities.js +1 -1
  66. package/dist/core/engine-notice.d.ts +30 -11
  67. package/dist/core/file-history-store.d.ts +90 -14
  68. package/dist/core/file-history-store.js +23 -15
  69. package/dist/core/gate-fold.d.ts +1 -1
  70. package/dist/core/gate-fold.js +22 -10
  71. package/dist/core/gate-lanes.js +73 -64
  72. package/dist/core/gate-outcome.d.ts +26 -5
  73. package/dist/core/gate-outcome.js +26 -0
  74. package/dist/core/governance-codes.d.ts +5 -1
  75. package/dist/core/governance-codes.js +6 -0
  76. package/dist/core/hooks.d.ts +17 -16
  77. package/dist/core/hooks.js +3 -1
  78. package/dist/core/host-floor.d.ts +128 -0
  79. package/dist/core/host-floor.js +206 -0
  80. package/dist/core/host-target.d.ts +38 -3
  81. package/dist/core/host-target.js +38 -5
  82. package/dist/core/mcp.d.ts +5 -1
  83. package/dist/core/mcp.js +67 -41
  84. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  85. package/dist/core/memory-engine/engine.js +4 -4
  86. package/dist/core/memory-engine/layout.d.ts +60 -8
  87. package/dist/core/memory-engine/layout.js +65 -6
  88. package/dist/core/model-seat.d.ts +10 -3
  89. package/dist/core/mods/classic-events.d.ts +67 -0
  90. package/dist/core/mods/classic-events.js +1 -0
  91. package/dist/core/mods/dollar.d.ts +13 -0
  92. package/dist/core/mods/extension-call.d.ts +31 -0
  93. package/dist/core/mods/extension-call.js +43 -0
  94. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  95. package/dist/core/mods/kernel/dispatch.js +140 -69
  96. package/dist/core/mods/kernel/events.d.ts +47 -11
  97. package/dist/core/mods/kernel/events.js +66 -42
  98. package/dist/core/mods/kernel/index.d.ts +4 -4
  99. package/dist/core/mods/kernel/index.js +2 -2
  100. package/dist/core/mods/kernel/receive.d.ts +39 -5
  101. package/dist/core/mods/kernel/receive.js +290 -17
  102. package/dist/core/mods/kernel/registration.d.ts +33 -2
  103. package/dist/core/mods/kernel/registration.js +6 -7
  104. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  105. package/dist/core/mods/kernel/site-rules.js +24 -42
  106. package/dist/core/mods/spec-seats.d.ts +69 -0
  107. package/dist/core/mods/spec-seats.js +114 -0
  108. package/dist/core/mods/stations.d.ts +28 -8
  109. package/dist/core/mods/stations.js +29 -13
  110. package/dist/core/mods/tool-call.d.ts +79 -0
  111. package/dist/core/mods/tool-call.js +152 -0
  112. package/dist/core/namespaced-rule-name.d.ts +32 -38
  113. package/dist/core/namespaced-rule-name.js +29 -36
  114. package/dist/core/parent-spec-seat.d.ts +6 -1
  115. package/dist/core/parent-spec-seat.js +2 -0
  116. package/dist/core/park-selfcheck.js +1 -0
  117. package/dist/core/permission-rule-consent.d.ts +19 -0
  118. package/dist/core/permission-rule-consent.js +116 -26
  119. package/dist/core/permission-rule-model.d.ts +14 -3
  120. package/dist/core/permission-rule-model.js +39 -24
  121. package/dist/core/permission-rule-org.d.ts +6 -2
  122. package/dist/core/permission-rule-org.js +7 -3
  123. package/dist/core/permission-rule-provider.d.ts +5 -2
  124. package/dist/core/permission-rule-provider.js +41 -11
  125. package/dist/core/permission-rule-store.d.ts +3 -2
  126. package/dist/core/permission-rule-store.js +11 -2
  127. package/dist/core/permission-rule-sync.js +3 -2
  128. package/dist/core/permission-rule-syntax.d.ts +5 -4
  129. package/dist/core/permission-rule-syntax.js +2 -2
  130. package/dist/core/permission-rules.d.ts +4 -4
  131. package/dist/core/permission-rules.js +11 -20
  132. package/dist/core/persisted-rule-arms.d.ts +2 -2
  133. package/dist/core/persisted-rule-arms.js +10 -12
  134. package/dist/core/principal-name.d.ts +20 -0
  135. package/dist/core/principal-name.js +22 -0
  136. package/dist/core/prompt-section-seat.js +4 -6
  137. package/dist/core/protocol-http-auth.d.ts +26 -5
  138. package/dist/core/protocol-http-auth.js +137 -4
  139. package/dist/core/retired-keys.d.ts +16 -0
  140. package/dist/core/retired-keys.js +16 -4
  141. package/dist/core/rewrite-rejudge.d.ts +60 -0
  142. package/dist/core/rewrite-rejudge.js +36 -0
  143. package/dist/core/roles.d.ts +28 -1
  144. package/dist/core/roles.js +31 -19
  145. package/dist/core/rule-lane-reads.d.ts +20 -15
  146. package/dist/core/rule-lane-reads.js +45 -17
  147. package/dist/core/rule-owner.d.ts +3 -3
  148. package/dist/core/rule-owner.js +3 -2
  149. package/dist/core/runner/announce-once-ledger.d.ts +14 -0
  150. package/dist/core/runner/announce-once-ledger.js +5 -0
  151. package/dist/core/runner/assemble-result.d.ts +1 -0
  152. package/dist/core/runner/assemble-result.js +1 -1
  153. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  154. package/dist/core/runner/caller-roster.d.ts +16 -4
  155. package/dist/core/runner/caller-roster.js +33 -6
  156. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  157. package/dist/core/runner/capability-withheld-seat.js +24 -0
  158. package/dist/core/runner/classifier-ladder.d.ts +7 -9
  159. package/dist/core/runner/classifier-ladder.js +3 -3
  160. package/dist/core/runner/construction-doors.js +3 -0
  161. package/dist/core/runner/contracts.d.ts +28 -25
  162. package/dist/core/runner/cross-boundary-lane.d.ts +17 -13
  163. package/dist/core/runner/cross-boundary-lane.js +40 -27
  164. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  165. package/dist/core/runner/denial-limit-arms.js +1 -1
  166. package/dist/core/runner/file-history-request.d.ts +18 -0
  167. package/dist/core/runner/file-history-request.js +21 -13
  168. package/dist/core/runner/file-history-restore.d.ts +45 -0
  169. package/dist/core/runner/file-history-restore.js +46 -0
  170. package/dist/core/runner/gate-exit.d.ts +3 -3
  171. package/dist/core/runner/gate-exit.js +4 -3
  172. package/dist/core/runner/image.d.ts +7 -17
  173. package/dist/core/runner/image.js +9 -60
  174. package/dist/core/runner/permission-rule-lanes.d.ts +4 -4
  175. package/dist/core/runner/permission-rule-lanes.js +26 -10
  176. package/dist/core/runner/person-path-rows.d.ts +12 -9
  177. package/dist/core/runner/person-path-rows.js +18 -7
  178. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  179. package/dist/core/runner/prepare-ask-lane.js +5 -2
  180. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  181. package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
  182. package/dist/core/runner/prepare-config-doors.d.ts +29 -38
  183. package/dist/core/runner/prepare-config-doors.js +42 -25
  184. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  185. package/dist/core/runner/prepare-defer-classify.js +7 -8
  186. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  187. package/dist/core/runner/prepare-file-history.js +7 -39
  188. package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
  189. package/dist/core/runner/prepare-gate-stations.js +10 -1
  190. package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
  191. package/dist/core/runner/prepare-hands-readface.js +15 -14
  192. package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
  193. package/dist/core/runner/prepare-inherited-gate.js +5 -3
  194. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  195. package/dist/core/runner/prepare-park-ask.js +5 -5
  196. package/dist/core/runner/prepare-policy-chain.d.ts +6 -3
  197. package/dist/core/runner/prepare-policy-chain.js +65 -72
  198. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  199. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  200. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  201. package/dist/core/runner/prepare-prompt-inputs.js +3 -5
  202. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -0
  203. package/dist/core/runner/prepare-protocol-tools.js +3 -3
  204. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  205. package/dist/core/runner/prepare-safety-scan.js +0 -17
  206. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  207. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  208. package/dist/core/runner/prepare-task.d.ts +1 -1
  209. package/dist/core/runner/prepare-task.js +29 -20
  210. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
  211. package/dist/core/runner/prepare-tool-disclosure-mount.js +20 -16
  212. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  213. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  214. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -2
  215. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  216. package/dist/core/runner/resume-admission.js +1 -1
  217. package/dist/core/runner/resume-apply.js +11 -12
  218. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  219. package/dist/core/runner/resume-claim.d.ts +4 -2
  220. package/dist/core/runner/resume-claim.js +15 -8
  221. package/dist/core/runner/retired-runner-deps.js +1 -0
  222. package/dist/core/runner/rewind-files.d.ts +15 -0
  223. package/dist/core/runner/rewind-files.js +132 -0
  224. package/dist/core/runner/run-attachment-seats.js +2 -1
  225. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  226. package/dist/core/runner/run-brain-sinks.js +4 -2
  227. package/dist/core/runner/run-harness-handlers.js +12 -4
  228. package/dist/core/runner/run-leg.d.ts +1 -1
  229. package/dist/core/runner/run-leg.js +30 -18
  230. package/dist/core/runner/run-settle-and-teardown.js +2 -1
  231. package/dist/core/runner/run-turn-boundary.js +1 -10
  232. package/dist/core/runner/runtask.d.ts +3 -0
  233. package/dist/core/runner/runtask.js +8 -9
  234. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  235. package/dist/core/runner/session-read-file-states.js +28 -0
  236. package/dist/core/runner/session-rule-policy.js +4 -3
  237. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  238. package/dist/core/runner/shell-env-withheld.js +51 -0
  239. package/dist/core/runner/skills-seat.js +6 -2
  240. package/dist/core/runner/stream-settle-backstop.js +1 -1
  241. package/dist/core/runner/sub-agent-deny-lists.js +4 -7
  242. package/dist/core/runner/synthetic-tools.d.ts +6 -0
  243. package/dist/core/runner/synthetic-tools.js +4 -1
  244. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  245. package/dist/core/runner/tool-disclosure.js +1 -3
  246. package/dist/core/runner/tool-end-body.d.ts +1 -1
  247. package/dist/core/runner/tool-end-body.js +10 -9
  248. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  249. package/dist/core/runner/tool-not-executed.js +11 -0
  250. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  251. package/dist/core/runner/tool-occurrence.js +7 -0
  252. package/dist/core/runner/turn-attachments.d.ts +33 -15
  253. package/dist/core/runner/turn-attachments.js +62 -37
  254. package/dist/core/runner-deps.d.ts +5 -5
  255. package/dist/core/safety-axis-vocab.d.ts +6 -4
  256. package/dist/core/safety-axis-vocab.js +6 -5
  257. package/dist/core/safety-merge-corpus.js +11 -3
  258. package/dist/core/secret-env.d.ts +26 -3
  259. package/dist/core/secret-env.js +44 -8
  260. package/dist/core/select-model.js +3 -3
  261. package/dist/core/session-policy-store.d.ts +27 -15
  262. package/dist/core/session-policy-store.js +156 -36
  263. package/dist/core/session-store.d.ts +29 -10
  264. package/dist/core/session-store.js +51 -19
  265. package/dist/core/session.d.ts +82 -16
  266. package/dist/core/session.js +53 -0
  267. package/dist/core/shell-read-silence.d.ts +11 -12
  268. package/dist/core/shell-read-silence.js +9 -5
  269. package/dist/core/shell-run-candidates.js +3 -1
  270. package/dist/core/shell-wrapper-projection.js +1 -1
  271. package/dist/core/shell-wrapper-table.d.ts +14 -7
  272. package/dist/core/shell-wrapper-table.js +5 -4
  273. package/dist/core/side-query.js +10 -1
  274. package/dist/core/skill-grant.d.ts +7 -2
  275. package/dist/core/skill-grant.js +5 -0
  276. package/dist/core/skills-directory.js +6 -2
  277. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  278. package/dist/core/store-contracts/checkpoint-store-contract.js +140 -2
  279. package/dist/core/store-contracts/file-history-store-contract.js +31 -1
  280. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  281. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  282. package/dist/core/store-contracts/session-repo-contract.js +51 -0
  283. package/dist/core/store-contracts/session-store-contract.d.ts +2 -1
  284. package/dist/core/store-contracts/session-store-contract.js +150 -14
  285. package/dist/core/stub-env.d.ts +2 -0
  286. package/dist/core/stub-env.js +1 -0
  287. package/dist/core/synthetic-read-verdict.js +3 -3
  288. package/dist/core/task-event.d.ts +32 -4
  289. package/dist/core/task-notification.d.ts +16 -12
  290. package/dist/core/task-registry.d.ts +9 -0
  291. package/dist/core/task-registry.js +11 -1
  292. package/dist/core/task-result.d.ts +18 -0
  293. package/dist/core/task-spec.d.ts +18 -13
  294. package/dist/core/tighten-task-spec.js +2 -1
  295. package/dist/core/tool-catalog-entries.d.ts +17 -0
  296. package/dist/core/tool-catalog-entries.js +13 -2
  297. package/dist/core/tool-check-reading.d.ts +11 -0
  298. package/dist/core/tool-check-reading.js +11 -6
  299. package/dist/core/tool-model-gate.d.ts +2 -2
  300. package/dist/core/tool-name-aliases.d.ts +16 -16
  301. package/dist/core/tool-name-aliases.js +13 -19
  302. package/dist/core/tool-name-readings.d.ts +5 -35
  303. package/dist/core/tool-name-readings.js +1 -9
  304. package/dist/core/tool-policy.d.ts +68 -198
  305. package/dist/core/tool-policy.js +149 -198
  306. package/dist/core/tool-result-store.js +3 -0
  307. package/dist/core/tool-roster.d.ts +14 -19
  308. package/dist/core/tool-roster.js +11 -44
  309. package/dist/core/tool-spec-members.js +7 -2
  310. package/dist/core/tool-spec.d.ts +19 -11
  311. package/dist/core/tools.js +49 -9
  312. package/dist/core/trace.d.ts +2 -2
  313. package/dist/core/types.d.ts +1 -1
  314. package/dist/core/user-attachment.d.ts +8 -1
  315. package/dist/core/user-attachment.js +64 -4
  316. package/dist/core/wiring-manifest.d.ts +9 -0
  317. package/dist/core/wiring-manifest.js +1 -0
  318. package/dist/core/workflow-journal-store.js +1 -1
  319. package/dist/engine/compaction/compaction.js +3 -2
  320. package/dist/engine/execution-env/node-execution-env.d.ts +7 -3
  321. package/dist/engine/execution-env/node-execution-env.js +11 -2
  322. package/dist/engine/harness/agent-harness.d.ts +25 -1
  323. package/dist/engine/harness/agent-harness.js +54 -7
  324. package/dist/engine/harness/types.d.ts +29 -2
  325. package/dist/engine/llm/types.d.ts +28 -11
  326. package/dist/engine/loop/agent-loop.d.ts +22 -0
  327. package/dist/engine/loop/agent-loop.js +16 -26
  328. package/dist/engine/loop/types.d.ts +16 -6
  329. package/dist/engine/session/memory-repo.d.ts +9 -2
  330. package/dist/engine/session/memory-repo.js +11 -1
  331. package/dist/engine/session/repo-utils.d.ts +6 -5
  332. package/dist/engine/session/repo-utils.js +14 -6
  333. package/dist/index.d.ts +22 -10
  334. package/dist/index.js +15 -7
  335. package/dist/internal/harness-types.d.ts +1 -1
  336. package/dist/internal/llm.d.ts +1 -1
  337. package/dist/orchestration/run-workflow-tool.d.ts +6 -4
  338. package/dist/orchestration/run-workflow-tool.js +5 -3
  339. package/dist/orchestration/workflow.d.ts +3 -0
  340. package/dist/orchestration/workflow.js +36 -18
  341. package/dist/prompt-assembly/artifact.d.ts +2 -2
  342. package/dist/prompt-assembly/artifact.js +5 -3
  343. package/dist/prompt-assembly/assemble.d.ts +3 -2
  344. package/dist/prompt-assembly/assemble.js +1 -1
  345. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  346. package/dist/prompt-assembly/catalog/schema.js +34 -2
  347. package/dist/prompt-assembly/catalog/sections.js +0 -1
  348. package/dist/prompt-assembly/composer.d.ts +3 -1
  349. package/dist/prompt-assembly/composer.js +1 -1
  350. package/dist/prompt-assembly/event-registry.js +1 -0
  351. package/dist/prompt-assembly/overlay.js +3 -3
  352. package/dist/prompt-assembly/renderers.d.ts +1 -1
  353. package/dist/prompt-assembly/renderers.js +0 -3
  354. package/dist/prompt-assembly/role-base.d.ts +15 -0
  355. package/dist/prompt-assembly/role-base.js +9 -0
  356. package/dist/prompt-assembly/select.d.ts +39 -14
  357. package/dist/prompt-assembly/select.js +47 -16
  358. package/dist/prompt-assembly/sugar.d.ts +17 -11
  359. package/dist/prompt-assembly/sugar.js +8 -3
  360. package/dist/prompt-assembly/tool-catalog.d.ts +37 -3
  361. package/dist/prompt-assembly/tool-catalog.js +114 -4
  362. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  363. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  364. package/dist/prompt-assembly/types.d.ts +0 -7
  365. package/dist/scenarios/full-body.d.ts +11 -11
  366. package/dist/scenarios/full-body.js +4 -3
  367. package/dist/shell/lex.js +10 -1
  368. package/dist/stores/file/adoption/adopt.js +4 -3
  369. package/dist/stores/file/adoption/marker.js +3 -2
  370. package/dist/stores/file/checkpoint-store.d.ts +21 -0
  371. package/dist/stores/file/checkpoint-store.js +38 -6
  372. package/dist/stores/file/file-history-store.js +6 -7
  373. package/dist/stores/file/index.js +2 -1
  374. package/dist/stores/file/permission-rule-adopt.js +4 -3
  375. package/dist/stores/file/permission-rule-store.js +11 -5
  376. package/dist/stores/file/session-store.d.ts +29 -6
  377. package/dist/stores/file/session-store.js +42 -50
  378. package/dist/tools/artifact/artifact-tool.js +3 -2
  379. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  380. package/dist/tools/fs/bash-program-position.js +56 -9
  381. package/dist/tools/fs/fs-bash.js +5 -5
  382. package/dist/tools/fs/fs-glob.d.ts +86 -0
  383. package/dist/tools/fs/fs-glob.js +226 -0
  384. package/dist/tools/fs/fs-read.js +14 -14
  385. package/dist/tools/fs/fs-search-tools.js +7 -7
  386. package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
  387. package/dist/tools/fs/pattern-kill-guard.js +397 -0
  388. package/dist/tools/fs/pdf.d.ts +9 -6
  389. package/dist/tools/fs/pdf.js +3 -3
  390. package/dist/tools/fs/program-read-model.d.ts +57 -7
  391. package/dist/tools/fs/program-read-model.js +11 -1
  392. package/dist/tools/fs/program-read-model.rows.js +78 -21
  393. package/dist/tools/fs/read-deny-home.js +3 -2
  394. package/dist/tools/fs/removal-targets.d.ts +17 -7
  395. package/dist/tools/fs/removal-targets.js +47 -20
  396. package/dist/tools/fs/search.d.ts +10 -0
  397. package/dist/tools/fs/search.js +20 -26
  398. package/dist/tools/fs/shell-read-argv.js +89 -12
  399. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  400. package/dist/tools/fs/shell-read-bindings.js +41 -0
  401. package/dist/tools/fs/shell-read-check.js +6 -19
  402. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  403. package/dist/tools/fs/shell-read-environment.js +3 -2
  404. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  405. package/dist/tools/fs/shell-read-establish.js +19 -20
  406. package/dist/tools/fs/shell-read-plan.js +24 -16
  407. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  408. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  409. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  410. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  411. package/dist/tools/fs/shell-reentry-text.js +40 -2
  412. package/dist/tools/todo.js +63 -63
  413. package/dist/tools/web.d.ts +19 -14
  414. package/dist/tools/web.js +38 -55
  415. package/package.json +1 -1
  416. package/test/export-surface.snapshot.json +143 -5
  417. package/wire-changes/core@7.56.0.json +3891 -0
  418. package/wire-changes/mods-kernel@7.56.0.json +303 -0
@@ -255,12 +255,10 @@ export function createTurnBoundary(input) {
255
255
  const pendingTools = tdRef !== undefined && tdRef.pending.length > 0 ? [...tdRef.pending] : undefined;
256
256
  const pendingRemovedTools = tdRef !== undefined && tdRef.pendingRemoved.length > 0 ? [...tdRef.pendingRemoved] : undefined;
257
257
  const pendingReaddedTools = tdRef !== undefined && tdRef.pendingReadded.length > 0 ? [...tdRef.pendingReadded] : undefined;
258
- const pendingFailedMcp = tdRef !== undefined && tdRef.pendingFailed.length > 0 ? tdRef.pendingFailed.map((f) => ({ ...f })) : undefined;
259
- const mcpToolsDelta = pendingRemovedTools !== undefined || pendingReaddedTools !== undefined || pendingFailedMcp !== undefined
258
+ const mcpToolsDelta = pendingRemovedTools !== undefined || pendingReaddedTools !== undefined
260
259
  ? {
261
260
  ...(pendingRemovedTools !== undefined ? { removed: pendingRemovedTools } : {}),
262
261
  ...(pendingReaddedTools !== undefined ? { readded: pendingReaddedTools } : {}),
263
- ...(pendingFailedMcp !== undefined ? { failedServers: pendingFailedMcp } : {}),
264
262
  }
265
263
  : undefined;
266
264
  const mcpInstructionsOn = rs.attach.attachmentsCfg?.mcpInstructions === true;
@@ -359,13 +357,6 @@ export function createTurnBoundary(input) {
359
357
  ref.pendingRemoved.splice(0, pendingRemovedTools.length);
360
358
  if (pendingReaddedTools !== undefined)
361
359
  ref.pendingReadded.splice(0, pendingReaddedTools.length);
362
- if (pendingFailedMcp !== undefined) {
363
- ref.pendingFailed.splice(0, pendingFailedMcp.length);
364
- if (!noNextRequest()) {
365
- prepared.announcedListingsRef.mcpFailed = [...(prepared.announcedListingsRef.mcpFailed ?? []), ...pendingFailedMcp];
366
- announcedOnceDirty = true;
367
- }
368
- }
369
360
  }
370
361
  }
371
362
  if ((mcpAdds !== undefined || mcpRemovals !== undefined) &&
@@ -8,6 +8,7 @@ import type { AgentDefinition, ModelRef, ModelRoles, RunnerDeps, TaskEvent, Task
8
8
  import { type ContextSettings, type ContextWindowOverlay } from "../context-settings.js";
9
9
  import type { ResumeRun, ResumeTaskConfig, RunInternals, RunnerSelfSeat } from "./contracts.js";
10
10
  export type { ResumeTaskConfig } from "./contracts.js";
11
+ import type { RewindFilesRequest, RewindFilesResult } from "../file-history-store.js";
11
12
  /**
12
13
  * A stateless task runner. Holds shared deps (the external brain, model catalog) and an
13
14
  * in-memory session store so that passing a `sessionId` continues a prior conversation.
@@ -133,6 +134,8 @@ export declare class Runner implements RunnerSelfSeat {
133
134
  * the same model resolution as tasks, returns real usage/model. No session, no tool execution, no
134
135
  * policy gate, no accounting — caller-trusted. */
135
136
  sideQuery(spec: SideQuerySpec): Promise<SideQueryResult>;
137
+ /** The out-of-run code-only rewind, no model call and no session entry — the contract is {@link rewindSessionFiles}'s (refused while a leg of this Runner holds or awaits the session's lock). */
138
+ rewindFiles(request: RewindFilesRequest): Promise<RewindFilesResult>;
136
139
  /** Run a task and stream live events; await `.result()` for the final TaskResult. `resume` (internal)
137
140
  * drives a durable resume through the same loop instead of a fresh objective prompt.
138
141
  * `internals` (internal) is a TRUSTED run-scoped channel for live per-task state the
@@ -7,7 +7,7 @@ import { createRapidRefillState } from "../auto-compaction.js";
7
7
  import { boundInputHashOf } from "../canonical-json.js";
8
8
  import { emitTrace } from "../trace.js";
9
9
  import { emitTaskOutcome } from "../task-outcome.js";
10
- import { runWithReasoningWireFacts } from "../../brain/status-sink.js";
10
+ import { runWithCapabilityWithheld, runWithReasoningWireFacts } from "../../brain/status-sink.js";
11
11
  import { expandTiers } from "../roles.js";
12
12
  import { announceReadDenySwap, screenSwappableDeps } from "../swappable-deps.js";
13
13
  import { runSideQuery } from "../side-query.js";
@@ -62,6 +62,7 @@ import { runStopAndFinalVerify } from "./run-stop-and-final-verify.js";
62
62
  import { runRecoveryLanes } from "./run-recovery-lanes.js";
63
63
  import { runGitLane } from "./run-git-lane.js";
64
64
  import { deploymentCanRerootChild } from "./child-tree.js";
65
+ import { rewindSessionFiles } from "./rewind-files.js";
65
66
  import { thrownText } from "../thrown-value.js";
66
67
  export class Runner {
67
68
  deps;
@@ -160,11 +161,8 @@ export class Runner {
160
161
  await prev.catch(() => { });
161
162
  return () => {
162
163
  release();
163
- void chain.then(() => {
164
- if (this.sessionLocks.get(sessionId) === chain) {
165
- this.sessionLocks.delete(sessionId);
166
- }
167
- });
164
+ if (this.sessionLocks.get(sessionId) === chain)
165
+ this.sessionLocks.delete(sessionId);
168
166
  };
169
167
  }
170
168
  swapDeps(next) {
@@ -233,8 +231,9 @@ export class Runner {
233
231
  announceReadDenySwap(this.deps.onNotice, seats, this.deps);
234
232
  }
235
233
  sideQuery(spec) {
236
- return runWithReasoningWireFacts(() => { }, () => runSideQuery(spec, { brain: this.deps.brain, models: this.deps.models, roles: this.deps.roles }));
234
+ return runWithReasoningWireFacts(() => { }, () => runWithCapabilityWithheld(() => { }, () => runSideQuery(spec, { brain: this.deps.brain, models: this.deps.models, roles: this.deps.roles })));
237
235
  }
236
+ rewindFiles(request) { return rewindSessionFiles({ deps: this.deps, sessions: this.sessions, readStates: this.sessionReadStates, sessionBusy: (id) => this.sessionLocks.has(id), takeSessionLock: (id) => this.acquireSessionLock(id) }, request); }
238
237
  runTaskStream(spec, resume, internals) {
239
238
  if (resume !== undefined && (typeof resume !== "object" || resume.outcome === undefined)) {
240
239
  throw new TypeError("runTaskStream: `resume` must be a ResumeRun carrying `outcome` — got a value without one. " +
@@ -403,7 +402,7 @@ export class Runner {
403
402
  const { effectiveTimeoutMs, walltimeMonotonicDeadline, timeout, pushContent, ownCommittedTailRef, emitCommitted } = runClockAndContent({ spec, prepared, queue, internals, rs, ident, parentToolCallId, startedToolCallIds });
404
403
  const toolProgress = createToolProgressLane(pushContent, ident, prepared.toolOccurrences);
405
404
  prepared.toolProgressRef.current = toolProgress;
406
- const { withBrainSinks, withLegRequestSinks } = runBrainSinks({ queue, internals, rs, ident, observeReasoningWireFacts, notice: { onNotice: this.deps.onNotice, sessionId: prepared.sessionId, runId: prepared.runId } });
405
+ const { withBrainSinks, withLegRequestSinks } = runBrainSinks({ queue, internals, rs, ident, observeReasoningWireFacts, notice: { onNotice: this.deps.onNotice, sessionId: prepared.sessionId, runId: prepared.runId }, announced: prepared });
407
406
  const toolLabels = new Map(prepared.tools.flatMap((t) => (t.label !== undefined && t.label !== t.name ? [[t.name, t.label]] : [])));
408
407
  for (const orphan of prepared.wakeRecovered) {
409
408
  emitSettled(prepared.toolOccurrences, { toolCallId: orphan.toolCallId, spelledName: orphan.toolName, ...(toolLabels.has(orphan.toolName) ? { label: toolLabels.get(orphan.toolName) } : {}), args: orphan.args }, reconciledEnd(orphan), { push: (f) => queue.push({ ...f, ...ident() }), structured: prepared.structuredProjector, mediaByteCapBytes: this.deps.mediaByteCapBytes });
@@ -502,7 +501,7 @@ export class Runner {
502
501
  token, cp, resumeSignal, recheckGovernanceWindow, store, runner: this.depsSeat,
503
502
  locallyClaimedTokens: this.locallyClaimedTokens, parentConstraintRegistry: this.parentConstraintRegistry, suspendedEnvReaps: this.suspendedEnvReaps,
504
503
  next: () => resumeClaim({
505
- token, cp, store, outcomeForStore,
504
+ token, cp, store, outcomeForStore, holder: internals?.holder,
506
505
  locallyClaimedTokens: this.locallyClaimedTokens, parentConstraintRegistry: this.parentConstraintRegistry,
507
506
  next: () => this.resumeHandoff({ token, cp, store, config, internals, resumeInternals, plainPolicyOutcome, redeemedAnswer, outcomeForStore, wakeMessage, wakeHookContext, legMods, resumeSignal }),
508
507
  }),
@@ -39,7 +39,22 @@ import type { ReadFileState } from "../../tools/fs/safety.js";
39
39
  */
40
40
  export declare class SessionReadFileStates {
41
41
  private readonly seats;
42
+ /**
43
+ * The ONE handoff of "which files did a file-history restore of this session move" to the read state that
44
+ * must stop vouching for their old bytes — written by every restore (the run's restore seat and the
45
+ * out-of-run `Runner.rewindFiles`), read by the next leg's read face, which checks each path against the disk
46
+ * after every seeding rung and settles the batch only once its own map is adopted as the seat. A leg that
47
+ * throws before adopting, or skips the adoption, leaves the batch for the next one. Bounded like the seats
48
+ * (LRU over session ids): a dropped batch costs a refusal whose wording blames an outside edit, never an admission.
49
+ */
50
+ private readonly restored;
42
51
  private static readonly CAP;
52
+ /** Record the ABSOLUTE paths a restore of `sessionId`'s history wrote, deleted or failed to write. */
53
+ noteRestored(sessionId: string, absPaths: readonly string[]): void;
54
+ /** The paths still owed a read-state check on `sessionId` — a copy; nothing is cleared by reading. */
55
+ pendingRestored(sessionId: string): readonly string[];
56
+ /** Clear exactly the paths a leg checked and then adopted over; a path noted since stays owed. */
57
+ settleRestored(sessionId: string, checked: readonly string[]): void;
43
58
  /** The session's seat row, or undefined (cross-process / evicted / first turn) ⇒ caller replays.
44
59
  * The caller must verify the anchor against the session's CURRENT branch before using `state`. */
45
60
  get(sessionId: string): {
@@ -1,6 +1,34 @@
1
1
  export class SessionReadFileStates {
2
2
  seats = new Map();
3
+ restored = new Map();
3
4
  static CAP = 1024;
5
+ noteRestored(sessionId, absPaths) {
6
+ if (absPaths.length === 0)
7
+ return;
8
+ const batch = this.restored.get(sessionId) ?? new Set();
9
+ for (const p of absPaths)
10
+ batch.add(p);
11
+ this.restored.delete(sessionId);
12
+ this.restored.set(sessionId, batch);
13
+ while (this.restored.size > SessionReadFileStates.CAP) {
14
+ const oldest = this.restored.keys().next().value;
15
+ if (oldest === undefined)
16
+ break;
17
+ this.restored.delete(oldest);
18
+ }
19
+ }
20
+ pendingRestored(sessionId) {
21
+ return [...(this.restored.get(sessionId) ?? [])];
22
+ }
23
+ settleRestored(sessionId, checked) {
24
+ const batch = this.restored.get(sessionId);
25
+ if (batch === undefined)
26
+ return;
27
+ for (const p of checked)
28
+ batch.delete(p);
29
+ if (batch.size === 0)
30
+ this.restored.delete(sessionId);
31
+ }
4
32
  get(sessionId) {
5
33
  const seat = this.seats.get(sessionId);
6
34
  if (seat !== undefined) {
@@ -1,5 +1,5 @@
1
1
  import { canonicalizeTarget, isWinFormPath, pathFamilyOf, writeTargetPath } from "../../tools/fs/safety.js";
2
- import { SESSION_RULES_GRAMMAR, compileSessionRuleBucket, continuesLineage, earlierGrammarAnnouncer, earlierGrammarRefusalClause, readSessionRulesShape, unreadableDenyEntries } from "../session-policy-store.js";
2
+ import { SESSION_RULES_GRAMMAR, compileSessionRuleBucket, continuesLineage, earlierGrammarAnnouncer, earlierGrammarEntries, earlierGrammarRefusalClause, readSessionRulesShape, unreadableDenyEntries } from "../session-policy-store.js";
3
3
  import { compiledEntryName, judgeAllowEntries, uncoveredCommandSegment } from "../allow-entry.js";
4
4
  import { inlineUntrusted } from "../untrusted-text.js";
5
5
  import { callTargetReadingOf, pathTargetBaseOf, readCallTarget } from "../effective-path-target.js";
@@ -95,7 +95,7 @@ function compileSessionRules(rules) {
95
95
  if ("fault" in shaped) {
96
96
  const { field, got } = shaped.fault;
97
97
  const what = got === "not a rule bucket" ? "a key that is no rule bucket" : field === "" ? `a value that is ${got}, not an object of rule buckets` : `${field} holding ${got}`;
98
- return { deny: [], allow: undefined, earlier: { grammar: SESSION_RULES_GRAMMAR, toolAllow: [], toolDeny: [] }, allowDirs: undefined, pathRows: false, names: { deny: [], allow: [] }, unreadable: refuseEvery(what) };
98
+ return { deny: [], allow: undefined, earlier: { grammar: SESSION_RULES_GRAMMAR, toolAllow: [], toolDeny: [] }, announced: { toolAllow: [], toolDeny: [] }, allowDirs: undefined, pathRows: false, names: { deny: [], allow: [] }, unreadable: refuseEvery(what) };
99
99
  }
100
100
  const { toolAllow, allowDirs, grammar } = shaped.rules;
101
101
  const unreadDeny = unreadableDenyEntries(shaped.rules).length;
@@ -109,6 +109,7 @@ function compileSessionRules(rules) {
109
109
  deny,
110
110
  allow,
111
111
  earlier: { grammar, toolAllow: named(allowList, true), toolDeny: named(denyList, true) },
112
+ announced: { toolAllow: earlierGrammarEntries(shaped.rules, "toolAllow"), toolDeny: earlierGrammarEntries(shaped.rules, "toolDeny") },
112
113
  allowDirs: allowDirs !== undefined && allowDirs.length > 0 ? allowDirs : undefined,
113
114
  pathRows: [...deny, ...(allow ?? [])].some((r) => r.compiled.kind === "path"),
114
115
  names: { deny: [...deny.map((r) => compiledEntryName(r.compiled)), ...named(denyList, false)], allow: [...(allow ?? []).map((r) => compiledEntryName(r.compiled)), ...named(allowList, false)] },
@@ -128,7 +129,7 @@ export function createSessionRulePolicy(rules, opts) {
128
129
  if (compiled === undefined || compiledFor !== r) {
129
130
  compiled = compileSessionRules(r);
130
131
  for (const field of ["toolAllow", "toolDeny"])
131
- announceEarlier(compiled.earlier[field], field, compiled.earlier.grammar);
132
+ announceEarlier(compiled.announced[field], field, compiled.earlier.grammar);
132
133
  compiledFor = r;
133
134
  }
134
135
  return compiled;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The run's seat for `inherit_env.names_withheld`: the person whose run drives the engine's shell tool is told which
3
+ * variables of the engine's environment that shell does not receive.
4
+ *
5
+ * ONE FACT, ONE MINT. Which entries a shell child loses is decided by the execution environment's one composition
6
+ * (`inheritedHostEnv(policy, findings)` and the adapter's explicit grants), and the environment hands the result over as
7
+ * the read `ExecutionEnv.withheldEnv`. This seat reads that answer and tells it; it never recomputes it (the policy and
8
+ * the grants are the adapter's, not the run's). The split into the scrub's half and the deployment's own credentials is
9
+ * the one the operator notice uses (`withheldEnvNames`).
10
+ *
11
+ * WHEN. At the start of every call to the engine's own shell tool (its mount, judged by the catalog's mount judge), on a
12
+ * root leg (the person reads the root; the delegation fact is the hook identity's, the leg's one derivation). The answer
13
+ * is read at each such call because it can grow during a run — a credential the engine takes in when it first routes a
14
+ * model, dials a peer or builds a seat is withheld from the next child — and a call follows at least one model request.
15
+ * Told once per SESSION per answer: the digest rides the session's announced record (`advisories`), and a run-time record
16
+ * write is parked for the leg's flush like every other run-time arm of that record.
17
+ *
18
+ * An answer of `"unknown"` is told as unknown, never as silence. A value that is neither a list of findings nor
19
+ * `"unknown"` (or a read that throws) is a wiring fault: it is announced to the operator under the existing
20
+ * capability-shape code, once per run, and the person is told nothing — no reading defaults to `"unknown"`.
21
+ */
22
+ import { type EngineNotice } from "../engine-notice.js";
23
+ import type { ExecutionEnv } from "../../internal/harness.js";
24
+ import type { Prepared } from "./contracts.js";
25
+ export type WithheldShellEnvSeatInput = Pick<Prepared, "sessionId" | "runId" | "hookIdentity" | "toolRosterDeltas" | "announcedListingsRef" | "frameReceipts"> & {
26
+ readonly harness: {
27
+ readonly env: Pick<ExecutionEnv, "withheldEnv">;
28
+ };
29
+ };
30
+ /** The seat, per run. `onToolStart` never throws: a diagnostic may not be what fails a call. */
31
+ export declare function createWithheldShellEnvSeat(prepared: WithheldShellEnvSeatInput, onNotice: ((notice: EngineNotice) => void) | undefined): {
32
+ onToolStart(toolName: string): void;
33
+ };
@@ -0,0 +1,51 @@
1
+ import { deliverEngineNotice } from "../engine-notice.js";
2
+ import { withheldEnvUserNotice } from "../secret-env.js";
3
+ import { isEngineShellFace } from "../tool-catalog-entries.js";
4
+ import { toolCallFaceOf } from "../tool-roster.js";
5
+ import { announceDigest, withAnnounceDigests } from "./announce-once-ledger.js";
6
+ const isFinding = (f) => typeof f === "object" && f !== null && typeof Reflect.get(f, "key") === "string" && typeof Reflect.get(f, "kind") === "string";
7
+ function readWithheldEnv(env) {
8
+ try {
9
+ const value = env.withheldEnv;
10
+ if (value === "unknown")
11
+ return "unknown";
12
+ if (!Array.isArray(value))
13
+ return { malformed: value === null ? "null" : typeof value };
14
+ return value.every(isFinding) ? value : { malformed: "array holding a non-finding" };
15
+ }
16
+ catch {
17
+ return { malformed: "unreadable" };
18
+ }
19
+ }
20
+ export function createWithheldShellEnvSeat(prepared, onNotice) {
21
+ let shapeFaultTold = false;
22
+ return {
23
+ onToolStart(toolName) {
24
+ if (prepared.hookIdentity.isDelegatedChild || !isEngineShellFace(toolCallFaceOf(prepared.toolRosterDeltas.current, toolName)))
25
+ return;
26
+ const answer = readWithheldEnv(prepared.harness.env);
27
+ if (typeof answer === "object" && "malformed" in answer) {
28
+ if (shapeFaultTold)
29
+ return;
30
+ shapeFaultTold = true;
31
+ deliverEngineNotice(onNotice, {
32
+ code: "config.execution_env_capability_invalid",
33
+ message: `The execution environment declares withheldEnv as (${answer.malformed}), not a list of findings or "unknown". The person whose run drives its shell is told nothing about the variables that shell does not receive. Fix the adapter — this is a wiring fault, not a supported way to leave the member unanswered.`,
34
+ detail: { key: "withheldEnv", valueType: answer.malformed },
35
+ });
36
+ return;
37
+ }
38
+ const notice = withheldEnvUserNotice(answer, { sessionId: prepared.sessionId, runId: prepared.runId });
39
+ if (notice === undefined)
40
+ return;
41
+ const d = notice.detail;
42
+ const digest = announceDigest(notice.code, `${d.state}\n${[...(d.names ?? [])].sort().join("\n")}\n\n${[...(d.ownCredentials ?? [])].sort().join("\n")}`);
43
+ const record = prepared.announcedListingsRef;
44
+ if (record.advisories?.includes(digest) === true)
45
+ return;
46
+ deliverEngineNotice(onNotice, notice);
47
+ record.advisories = withAnnounceDigests(record.advisories, [digest]);
48
+ prepared.frameReceipts.listingSnapshotOwed = true;
49
+ },
50
+ };
51
+ }
@@ -39,7 +39,7 @@ export function readSkillsSeat(skills) {
39
39
  const at = `${SKILLS_SEAT}[${i}]`;
40
40
  if (typeof raw !== "object" || raw === null || Array.isArray(raw))
41
41
  throw skillsSeatRefusal(at, `must be an object { name, description, content } (got ${kindOf(raw)})`);
42
- const { name, description, content, allowedTools, disallowedTools, files: rawFiles, baseDir, ...rest } = raw;
42
+ const { name, description, content, allowedTools, disallowedTools, files: rawFiles, baseDir, mods: rawMods, ...rest } = raw;
43
43
  void rest;
44
44
  for (const [member, value] of [["name", name], ["description", description], ["content", content]]) {
45
45
  if (typeof value !== "string")
@@ -47,11 +47,15 @@ export function readSkillsSeat(skills) {
47
47
  }
48
48
  const files = readSkillFiles(rawFiles, `${at}.files`);
49
49
  skillBaseDirOf(baseDir);
50
+ if (rawMods !== undefined && !Array.isArray(rawMods))
51
+ throw skillsSeatRefusal(`${at}.mods`, `must be a list of mods registrations (got ${kindOf(rawMods)})`);
50
52
  if (seen.has(name))
51
53
  continue;
52
54
  seen.add(name);
53
55
  const [allowed, denied] = [readSkillTable(allowedTools), readSkillTable(disallowedTools)];
54
- out.push({ name, description, content, ...(allowed !== undefined ? { allowedTools: allowed } : {}), ...(denied !== undefined ? { disallowedTools: denied } : {}), ...(files !== undefined ? { files } : {}), ...(baseDir !== undefined ? { baseDir } : {}) });
56
+ const list = rawMods;
57
+ const mods = list === undefined ? undefined : Object.freeze(Array.from({ length: list.length }, (_, j) => list[j]));
58
+ out.push({ name, description, content, ...(allowed !== undefined ? { allowedTools: allowed } : {}), ...(denied !== undefined ? { disallowedTools: denied } : {}), ...(files !== undefined ? { files } : {}), ...(baseDir !== undefined ? { baseDir } : {}), ...(mods !== undefined ? { mods } : {}) });
55
59
  }
56
60
  return out;
57
61
  }
@@ -74,7 +74,7 @@ export function streamSettleBackstop(input) {
74
74
  sessionId: taskIdRef.sessionId ?? "unknown",
75
75
  ...(taskIdRef.runId !== undefined ? { runId: taskIdRef.runId } : {}),
76
76
  terminal: { kind: "failed", ...(code !== undefined ? { code } : {}), message, ...(detail !== undefined ? { detail } : {}) },
77
- result: "",
77
+ result: "", resultEntryIds: [],
78
78
  ...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
79
79
  ...(taskIdRef.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: taskIdRef.effectiveMemoryScopes } : {}),
80
80
  ...(taskIdRef.effectiveReasoning !== undefined ? { effectiveReasoning: taskIdRef.effectiveReasoning } : {}),
@@ -6,7 +6,7 @@ import { ENGINE_TOOLS } from "../tool-catalog-entries.js";
6
6
  import { callerToolNameProblem } from "../caller-tool-name.js";
7
7
  import { mintNamespacePrefix } from "../protocol-naming.js";
8
8
  import { PROTOCOL_TABLE, protocolOf } from "../protocol-table.js";
9
- import { mountedToolNames, splitNamespacedName, wholeProtocolOf } from "../tool-name-aliases.js";
9
+ import { grantWildcardRefusalOf, mountedToolNames, splitNamespacedName } from "../tool-name-aliases.js";
10
10
  import { projectionToolNames } from "../tool-policy.js";
11
11
  import { declaredDelegationNameOf } from "../delegation-name.js";
12
12
  export function renamedDelegationMountSentence(...rosters) {
@@ -97,9 +97,6 @@ function readableToolNameList(where, side, value, code) {
97
97
  throw refused(notAStringSentence(where, side, index, read.type), code, "not_a_string");
98
98
  if (read.kind === "unreadable")
99
99
  throw grammarRefusal(where, side, { entry: read.entry, reason: "grammar" }, code);
100
- if (side === "denied" && read.name === "*") {
101
- throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: a denied list has no wildcard — the entry would hide nothing. To give the agent no tools, write an empty allowed list.`, code, "unsupported_pattern");
102
- }
103
100
  return { entry: entry, name: read.name, content: read.content };
104
101
  });
105
102
  }
@@ -117,11 +114,11 @@ function judgeToolNameList(where, side, value, universe, advise, code) {
117
114
  const content = side === "denied" && written;
118
115
  const reach = side === "denied" ? readDeniedToolList([entry]) : (readAllowedToolList([entry]) ?? readDeniedToolList([]));
119
116
  const split = splitNamespacedName(name);
120
- const whole = wholeProtocolOf(name);
121
- if (whole !== undefined) {
117
+ const toolSplit = splitNamespacedName(toolName);
118
+ if (toolName.includes("*") && (toolSplit === undefined || toolSplit.peer.includes("*"))) {
122
119
  if (side === "denied")
123
120
  continue;
124
- throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: an allowed list has no protocol-wide form — name a peer (\`${whole.prefix}<peer>\`) or one of its tools (\`${whole.prefix}<peer>__<tool>\`).`, code, "unsupported_pattern");
121
+ throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: ${grantWildcardRefusalOf(name)}.`, code, "unsupported_pattern");
125
122
  }
126
123
  const { inert } = compileAllowList([toolName], "deny", universe.known);
127
124
  const flaw = inert[0] === undefined ? undefined : { ...inert[0], entry, ...(inert[0].reason === "near_miss" && inert[0].currentName !== undefined ? { carriedBy: universe.carrierOf(inert[0].currentName) } : {}) };
@@ -58,6 +58,12 @@ export declare const SKILL_TOOL_NAME = "Skill";
58
58
  * an oversized skill is excluded from the disclosure block and the tool, with an operator-visible config error. The compaction-time retention caps are a
59
59
  * different door, deliberately. */
60
60
  export declare const SKILL_CONTENT_MAX_CHARS: number;
61
+ /** The skills a leg LOADS — those the load gate above passes ({@link skillLoadReading}, the one predicate): the skills whose
62
+ * hooks the leg's mods admission takes, as the roster's filter (which also reports each one it excludes) takes the same. */
63
+ export declare function skillsThatLoad<T extends {
64
+ readonly content: string;
65
+ readonly baseDir?: unknown;
66
+ }>(skills: readonly T[] | undefined): T[];
61
67
  /** Total per-invoke cap for a skill's inlined attachments (`SkillSpec.files`) — an ATTACHMENT-face budget, distinct from the (gone) body truncation door:
62
68
  * the body is delivered untruncated at invoke time (CC parity), while attachments ride along bounded and truncation-disclosed. */
63
69
  export declare const SKILL_ATTACHMENTS_MAX_CHARS = 50000;
@@ -4,7 +4,7 @@ import { sanitizeUntrustedText, SHELLED_BODY_ENVELOPE_TAGS } from "../untrusted-
4
4
  import { SKILL_LISTING_DEFAULT_BUDGET, SKILL_LISTING_DESC_MAX_CHARS_DEFAULT } from "../skill-listing-budget.js";
5
5
  import { readSkillTable, skillNamedBy } from "../skill-grant.js";
6
6
  import { OUTPUT_TOOL_NAME, mountRuleFace, toolFace } from "../tool-catalog-entries.js";
7
- import { substituteSkillRoot, substituteSkillRootBounded } from "./skill-base-dir.js";
7
+ import { skillLoadReading, substituteSkillRoot, substituteSkillRootBounded } from "./skill-base-dir.js";
8
8
  import { readSkillsSeat } from "./skills-seat.js";
9
9
  import { foldListingWithin } from "./listing-fold.js";
10
10
  export const REPORT_BLOCKED_TOOL_NAME = "ReportBlocked";
@@ -90,6 +90,9 @@ export function createReportFindingsTool() {
90
90
  }
91
91
  export const SKILL_TOOL_NAME = "Skill";
92
92
  export const SKILL_CONTENT_MAX_CHARS = 1024 * 1024;
93
+ export function skillsThatLoad(skills) {
94
+ return (skills ?? []).filter((s) => skillLoadReading(s, SKILL_CONTENT_MAX_CHARS).loads);
95
+ }
93
96
  export const SKILL_ATTACHMENTS_MAX_CHARS = 50_000;
94
97
  export const SKILL_ATTACHMENT_PATH_MAX_CHARS = 512;
95
98
  const SKILL_FILES_LIST_MAX_CHARS = 200;
@@ -64,20 +64,18 @@ export declare function buildDeferredRegistry(deferred: ReadonlySet<string>, too
64
64
  * validation, not activation state: a call whose arguments validate against the REAL tool's
65
65
  * declared schema runs the real tool directly (activation is only about whether the model has
66
66
  * been SHOWN the schema, never an execution gate). Governance cannot be laundered through this
67
- * lane: policy/effect/irreversibility gates key on the tool NAME maps built from the real
68
- * declarations, and the engine's approval pipeline runs before any execute — the placeholder
69
- * object on the harness list plays no part in adjudication.
67
+ * lane: the gate judges the call before any execute, and the call runs the one mounted instance its
68
+ * placeholder stands for — the harness resolves a call to its placeholder before the gate, as it
69
+ * resolves any call to its tool, so what runs is fixed before anything is judged.
70
70
  */
71
71
  export interface PlaceholderDirectCall {
72
72
  /**
73
- * Resolve the real tool AT CALL TIME, never from a prepare-time snapshot. The mounted
74
- * roster is a LIVE array: an MCP refresh splices a server's name domain out and pushes freshly
75
- * materialized tool objects back in, so a Map captured when the placeholder was built would hand
76
- * this lane the WITHDRAWN object (stale schema shape gate, stale transport client) long after the
77
- * roster moved on. Returns `undefined` when the name no longer resolves — a withdrawn name has no
78
- * direct lane, and the caller falls back to the teaching rejection.
73
+ * The mounted instance this placeholder stands for, bound when the placeholder is minted for it (one
74
+ * placeholder per instance; a refresh that replaces the instance mints a new placeholder for the new
75
+ * one). Never re-resolved by name: a call the gate judged while a refresh landed runs the instance it
76
+ * was resolved to, whose own checks answer a declaration that changed meanwhile.
79
77
  */
80
- resolveReal: () => PlaceholderDirectTarget | undefined;
78
+ real: PlaceholderDirectTarget;
81
79
  /**
82
80
  * The scheduling declaration this placeholder carries while it stands in for the real
83
81
  * tool. Mirrors the REAL tool's own `executionMode` (see the mirror rationale in
@@ -91,7 +89,7 @@ export interface PlaceholderDirectCall {
91
89
  * schema it hands back actually lives (this result only, versus this result AND every later
92
90
  * request's tools block). Absent ⇒ the swap posture.
93
91
  *
94
- * A FUNCTION, evaluated per call, for the same reason `resolveReal` is: the answer is not
92
+ * A FUNCTION, evaluated per call: the answer is not
95
93
  * a prepare-time constant. The run-wide strategy is, but the per-tool exemption on top of it reads
96
94
  * the LIVE roster — an MCP refresh can replace a tool with a declaration that no longer fits the
97
95
  * result-text carrier (or one that now does), and a boolean captured when the placeholder was built
@@ -113,7 +111,7 @@ export interface PlaceholderDirectCall {
113
111
  */
114
112
  activate: () => Promise<string | undefined>;
115
113
  }
116
- /** The live view of the real tool behind a placeholder, resolved per call (see {@link PlaceholderDirectCall.resolveReal}). */
114
+ /** The real tool behind a placeholder (see {@link PlaceholderDirectCall.real}). */
117
115
  export interface PlaceholderDirectTarget {
118
116
  /** The REAL tool's declared parameter schema — the shape gate for a direct call. */
119
117
  parameters: TSchema;
@@ -93,9 +93,7 @@ export function createPlaceholderTool(info, direct) {
93
93
  parameters: EMPTY_PARAMS,
94
94
  ...(direct.executionMode !== undefined ? { executionMode: direct.executionMode } : {}),
95
95
  execute: async (toolCallId, params, signal, onUpdate) => {
96
- const real = direct.resolveReal();
97
- if (real === undefined)
98
- return teachingRejection();
96
+ const { real } = direct;
99
97
  if (Value.Check(real.parameters, params)) {
100
98
  lastFailureShape = undefined;
101
99
  repeats = 0;
@@ -95,7 +95,7 @@ export interface SettledOccurrence extends Pick<OccurrenceEnd, "notExecuted"> {
95
95
  * The END projection — the ONE mint of `tool_end`, for every station that closes a call: the live loop's
96
96
  * `tool_execution_end`, the resumed leg's resolution, an interrupted run's reconcile and the reconcile replayed at
97
97
  * the next process start. It reads the occurrence and nothing else: `gate` is its latest gate record, `isError` is
98
- * the tool's bit or the refusal that record names, and `notExecuted` rides on positive evidence only: the station's own or `refusedBeforeRelease` (returned for the rows).
98
+ * the tool's bit or the refusal that record names, and `notExecuted` rides on positive evidence only: the station's own or `neverExecuted` (returned for the rows).
99
99
  *
100
100
  * A call whose start never went out on this stream (a call the loop never reached, a call announced by a dead
101
101
  * process) gets its start minted here first, marked `recovered` and carrying the input the closing station holds —
@@ -1,6 +1,6 @@
1
1
  import {} from "../../internal/harness.js";
2
- import { readMember } from "../thrown-value.js";
3
- import { refusedBeforeRelease } from "./tool-not-executed.js";
2
+ import { isPlainRecord } from "../mods/kernel/receive.js";
3
+ import { neverExecuted } from "./tool-not-executed.js";
4
4
  import { MCP_DELIVERY_VERDICTS } from "../mcp-failure.js";
5
5
  import { closeNeverExecuted } from "../session-reconcile.js";
6
6
  import { TOOL_SEARCH_NAME } from "./tool-disclosure.js";
@@ -38,11 +38,12 @@ export function batchResponseDigest(result) {
38
38
  export function toolEndBodyFrom(result, isError, leg, gate, gatedCallIdOfRun) {
39
39
  const o = toolOutputFrom(result, leg.mediaByteCapBytes);
40
40
  const st = leg.structured(result);
41
- const det = isError ? readMember(result, "details") : undefined;
42
- const codeRaw = readMember(det, "code");
43
- const kindRaw = readMember(det, "errorKind");
41
+ const det = isError ? result?.details : undefined;
42
+ const card = isPlainRecord(det) ? det : undefined;
43
+ const codeRaw = card?.code;
44
+ const kindRaw = card?.errorKind;
44
45
  const code = typeof codeRaw === "string" ? codeRaw : typeof kindRaw === "string" ? kindRaw : undefined;
45
- const deliveredRaw = readMember(det, "delivered");
46
+ const deliveredRaw = card?.delivered;
46
47
  const delivered = typeof deliveredRaw === "string" && MCP_DELIVERY_VERDICTS.includes(deliveredRaw) ? deliveredRaw : undefined;
47
48
  const gatedCallId = code === "gate.parked" ? gatedCallIdOfRun : undefined;
48
49
  return {
@@ -54,7 +55,7 @@ export function toolEndBodyFrom(result, isError, leg, gate, gatedCallIdOfRun) {
54
55
  ...(gate !== undefined ? { gate } : {}),
55
56
  };
56
57
  }
57
- const startFrameOf = (o, recovered) => ({ type: "tool_start", toolCallId: o.toolCallId, toolName: o.spelledName, ...(o.label !== undefined ? { label: o.label } : {}), args: o.args, ...(recovered ? { recovered: true } : {}) });
58
+ const startFrameOf = (o, recovered) => ({ type: "tool_start", toolCallId: o.toolCallId, toolName: o.spelledName, ...(o.label !== undefined ? { label: o.label } : {}), args: o.args, ...(recovered ? { recovered: true } : {}), ...(o.requestedBy !== undefined ? { requestedBy: o.requestedBy } : {}) });
58
59
  export function announceToolCall(table, start, frames) {
59
60
  table.open(start);
60
61
  frames.push(startFrameOf(start, false));
@@ -65,7 +66,7 @@ export function emitSettled(table, start, end, frames) {
65
66
  if (!occ.startEmitted)
66
67
  frames.push(startFrameOf(occ, true));
67
68
  const gate = occ.gateRounds.at(-1);
68
- const isError = end.isError || gate?.disposition.kind === "denied", notExecuted = end.notExecuted === true || refusedBeforeRelease(occ);
69
+ const isError = end.isError || gate?.disposition.kind === "denied", notExecuted = end.notExecuted === true || neverExecuted(occ);
69
70
  table.close(occ.toolCallId, end.interrupted === true ? "interrupted" : "settled");
70
71
  frames.push({
71
72
  type: "tool_end",
@@ -75,7 +76,7 @@ export function emitSettled(table, start, end, frames) {
75
76
  isError,
76
77
  ...toolEndBodyFrom(end.result, isError, frames, gate, end.gatedCallIdOfRun),
77
78
  ...(gate?.disposition.kind === "denied" && occ.wireName !== undefined ? { wireName: occ.wireName } : {}),
78
- ...(notExecuted ? { notExecuted: true } : {}),
79
+ ...(notExecuted ? { notExecuted: true } : {}), ...(occ.answeredInPlaceBy !== undefined ? { answeredBy: occ.answeredInPlaceBy } : {}), ...(occ.requestedBy !== undefined ? { requestedBy: occ.requestedBy } : {}),
79
80
  });
80
81
  return { ...(gate !== undefined ? { gate } : {}), isError, ...(notExecuted ? { notExecuted: true } : {}) };
81
82
  }
@@ -4,9 +4,14 @@ import type { ToolOccurrence } from "./tool-occurrence.js";
4
4
  * release, by a station inside the execution, is not). A call whose start this stream never carried (a recovered
5
5
  * one, closed by a station that knows only its own class) is not read here. */
6
6
  export declare function refusedBeforeRelease(occ: Pick<ToolOccurrence, "life" | "gateRounds" | "startEmitted">): boolean;
7
+ /** The one reading of the engine's positive evidence that a call never ran: refused before it was let go
8
+ * ({@link refusedBeforeRelease}), or answered in place of its body by an extension at `tool.call` (the body was never called). */
9
+ export declare function neverExecuted(occ: Pick<ToolOccurrence, "life" | "gateRounds" | "startEmitted" | "answeredInPlaceBy">): boolean;
7
10
  /** `details` as a persisted `toolResult` row carries it: `notExecuted` is the ENGINE's key — the settlement's fact when it holds,
8
11
  * absent otherwise, whatever a tool wrote under that name. Returns `details` itself unless the key has to move; never mutates it. */
9
12
  export declare function rowDetailsOf(details: unknown, notExecuted: boolean): unknown;
13
+ /** The persisted row's mark: the call this `toolResult` row closes never ran (the key {@link rowDetailsOf} writes). */
14
+ export declare function rowNotExecuted(details: unknown): boolean;
10
15
  /** A row the resumed leg mints (`toolResultMsg`) with the settlement's fact on it. */
11
16
  export declare function withRowNotExecuted<T extends object>(row: T, notExecuted: boolean): T;
12
17
  /** Write the end projection's one `notExecuted` onto the result the live loop persists as the call's row: the loop builds that message
@@ -2,6 +2,9 @@ import { readOwnMembers } from "../thrown-value.js";
2
2
  export function refusedBeforeRelease(occ) {
3
3
  return occ.life === "announced" && occ.startEmitted && occ.gateRounds.at(-1)?.disposition.kind === "denied";
4
4
  }
5
+ export function neverExecuted(occ) {
6
+ return refusedBeforeRelease(occ) || occ.answeredInPlaceBy !== undefined;
7
+ }
5
8
  export function rowDetailsOf(details, notExecuted) {
6
9
  const carries = (() => { try {
7
10
  return details !== null && typeof details === "object" && !Array.isArray(details) && Object.keys(details).includes("notExecuted");
@@ -18,6 +21,14 @@ export function rowDetailsOf(details, notExecuted) {
18
21
  delete bag["notExecuted"];
19
22
  return bag;
20
23
  }
24
+ export function rowNotExecuted(details) {
25
+ try {
26
+ return details !== null && typeof details === "object" && details.notExecuted === true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
21
32
  export function withRowNotExecuted(row, notExecuted) {
22
33
  return notExecuted ? { ...row, details: rowDetailsOf(undefined, true) } : row;
23
34
  }
@@ -42,6 +42,8 @@ export interface OccurrenceStart {
42
42
  readonly label?: string;
43
43
  /** The arguments the start frame carries (for a recovered start: the call's own input as the transcript holds it). */
44
44
  readonly args: unknown;
45
+ /** An extension's own call (`$.tool.call`): who asked for it — the frames carry it. Absent for a call a model message carried. */
46
+ readonly requestedBy?: import("../task-event.js").ExtensionRequester;
45
47
  }
46
48
  /** The record, as its readers see it. Written only through {@link ToolOccurrenceTable}. */
47
49
  export interface ToolOccurrence extends OccurrenceStart {
@@ -63,6 +65,9 @@ export interface ToolOccurrence extends OccurrenceStart {
63
65
  /** The heartbeat covers it. Cleared when the loop leaves the call behind at a turn end with no end of its own:
64
66
  * the record stays (a later settlement must still know its start frame went out) but no beat describes it. */
65
67
  readonly beating: boolean;
68
+ /** An extension at `tool.call` answered for the call in place of its body — its result, or its refusal — and named here:
69
+ * the body was never called (positive evidence the call did not run). Absent: no station answered in its place. */
70
+ readonly answeredInPlaceBy?: string;
66
71
  }
67
72
  /** The table of one leg's occurrences — the record's only writer. */
68
73
  export interface ToolOccurrenceTable {
@@ -86,6 +91,9 @@ export interface ToolOccurrenceTable {
86
91
  /** A station after the gate refused the call: one more gate record, minted as a veto of whatever the latest one
87
92
  * settled (a person's yes stays on the settlement; the refusing layer is the disposition). Returns the record. */
88
93
  refuse(toolCallId: string, layer: DeniedBy): GateOutcome;
94
+ /** An extension at `tool.call` answered for the call before its body was called (the kernel's record says the body had
95
+ * not started): the body is never called for this attempt. Once per attempt; a second is an engine defect. */
96
+ answeredInPlace(toolCallId: string, by: string): void;
89
97
  /** An ask for this call is put to the person: the count rises, and the returned `resumeFromUser` lowers it once
90
98
  * (a second call is a no-op). The pair is bound to THIS attempt — a return after the call ended, or after a
91
99
  * reused id re-opened, touches nothing — and an ask for a call this leg does not hold counts nothing: the wait
@@ -21,6 +21,7 @@ export function createToolOccurrenceTable() {
21
21
  ...(start.wireName !== undefined ? { wireName: start.wireName } : {}),
22
22
  ...(start.label !== undefined ? { label: start.label } : {}),
23
23
  args: start.args,
24
+ ...(start.requestedBy !== undefined ? { requestedBy: start.requestedBy } : {}),
24
25
  attempt,
25
26
  life: "announced",
26
27
  awaitingUser: 0,
@@ -96,6 +97,12 @@ export function createToolOccurrenceTable() {
96
97
  occ.gateRounds.push(round);
97
98
  return round;
98
99
  },
100
+ answeredInPlace(toolCallId, by) {
101
+ const occ = held(toolCallId, "an answer in place of the body");
102
+ if (occ.answeredInPlaceBy !== undefined)
103
+ throw new Error(`tool occurrence: call "${toolCallId}" (attempt ${occ.attempt}) was already answered in place`);
104
+ occ.answeredInPlaceBy = by;
105
+ },
99
106
  heard(toolCallId) {
100
107
  const occ = byId.get(toolCallId);
101
108
  if (occ !== undefined)