@sema-agent/core 7.54.1 → 7.55.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 (399) hide show
  1. package/CHANGELOG.md +437 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/builtin-agents.d.ts +12 -14
  4. package/dist/agents/cc-peer-directory.d.ts +36 -0
  5. package/dist/agents/cc-peer-directory.js +138 -0
  6. package/dist/agents/cc-peer-wire.d.ts +105 -0
  7. package/dist/agents/cc-peer-wire.js +98 -0
  8. package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
  9. package/dist/agents/cc-uds-peer-channel.js +457 -0
  10. package/dist/agents/cross-session-envelope.d.ts +4 -1
  11. package/dist/agents/cross-session-envelope.js +8 -1
  12. package/dist/agents/cross-session-judge.d.ts +2 -2
  13. package/dist/agents/list-agents-tool.js +2 -1
  14. package/dist/agents/observer.d.ts +4 -5
  15. package/dist/agents/observer.js +2 -1
  16. package/dist/agents/peer-admission.d.ts +6 -0
  17. package/dist/agents/peer-admission.js +4 -1
  18. package/dist/agents/peer-directory.d.ts +43 -9
  19. package/dist/agents/peer-directory.js +66 -23
  20. package/dist/agents/peer-notices.d.ts +1 -1
  21. package/dist/agents/peer-session-drain.d.ts +3 -1
  22. package/dist/agents/peer-session-drain.js +1 -0
  23. package/dist/agents/read-inbox-tool.js +2 -1
  24. package/dist/agents/retain-ledger.d.ts +1 -1
  25. package/dist/agents/roster-store.d.ts +1 -1
  26. package/dist/agents/send-message-tool.d.ts +10 -0
  27. package/dist/agents/send-message-tool.js +34 -5
  28. package/dist/agents/subagent.d.ts +34 -79
  29. package/dist/agents/subagent.js +45 -46
  30. package/dist/agents/tool-filter.d.ts +29 -46
  31. package/dist/agents/tool-filter.js +8 -31
  32. package/dist/agents/verify.d.ts +3 -3
  33. package/dist/brain/anthropic.js +14 -9
  34. package/dist/brain/errors.d.ts +15 -0
  35. package/dist/brain/errors.js +10 -0
  36. package/dist/brain/model-presets.d.ts +4 -4
  37. package/dist/brain/open-responses.js +15 -10
  38. package/dist/brain/openai.js +17 -12
  39. package/dist/brain/provider-dialect.d.ts +39 -3
  40. package/dist/brain/provider-dialect.js +28 -0
  41. package/dist/brain/reasoning.d.ts +1 -1
  42. package/dist/brain/request-params.d.ts +55 -5
  43. package/dist/brain/request-params.js +35 -3
  44. package/dist/brain/retry.d.ts +1 -1
  45. package/dist/brain/route-adjudicator.d.ts +15 -0
  46. package/dist/brain/route-adjudicator.js +15 -0
  47. package/dist/brain/stream-engine.js +6 -5
  48. package/dist/brain/stream-shared.d.ts +1 -1
  49. package/dist/core/advisor-verdict.d.ts +120 -0
  50. package/dist/core/advisor-verdict.js +92 -0
  51. package/dist/core/agent-definition.d.ts +7 -8
  52. package/dist/core/allow-entry.d.ts +49 -23
  53. package/dist/core/allow-entry.js +57 -32
  54. package/dist/core/allow-rule-shadow.d.ts +7 -0
  55. package/dist/core/approval-object.d.ts +2 -1
  56. package/dist/core/approval-object.js +6 -6
  57. package/dist/core/ask-origin.d.ts +63 -11
  58. package/dist/core/ask-origin.js +27 -5
  59. package/dist/core/ask-question.js +10 -4
  60. package/dist/core/auto-compaction.d.ts +11 -8
  61. package/dist/core/auto-compaction.js +4 -2
  62. package/dist/core/auto-mode-arming.d.ts +2 -2
  63. package/dist/core/auto-mode-defaults.d.ts +8 -8
  64. package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
  65. package/dist/core/auto-mode-prompt.d.ts +1 -1
  66. package/dist/core/auto-mode.d.ts +17 -9
  67. package/dist/core/auto-mode.js +9 -6
  68. package/dist/core/background-agent-store.d.ts +3 -3
  69. package/dist/core/canonical-json.d.ts +1 -1
  70. package/dist/core/canonical-json.js +2 -2
  71. package/dist/core/checkpoint-requirements.d.ts +6 -3
  72. package/dist/core/checkpoint-requirements.js +4 -14
  73. package/dist/core/checkpoint-store.d.ts +80 -51
  74. package/dist/core/checkpoint-store.js +56 -74
  75. package/dist/core/child-clamp-seats.d.ts +6 -0
  76. package/dist/core/child-clamp-seats.js +3 -16
  77. package/dist/core/compliance.d.ts +2 -2
  78. package/dist/core/context-edit.d.ts +6 -7
  79. package/dist/core/cross-boundary-taint.d.ts +9 -3
  80. package/dist/core/cross-boundary-taint.js +5 -3
  81. package/dist/core/decision-receipt.js +2 -2
  82. package/dist/core/effective-path-target.d.ts +1 -1
  83. package/dist/core/engine-notice.d.ts +19 -5
  84. package/dist/core/exec-output-tail.d.ts +1 -1
  85. package/dist/core/file-history-retention.d.ts +1 -1
  86. package/dist/core/file-history-store.d.ts +59 -9
  87. package/dist/core/file-history-store.js +35 -17
  88. package/dist/core/gate-fold.js +3 -2
  89. package/dist/core/gate-lanes.js +12 -8
  90. package/dist/core/gate-outcome.d.ts +17 -4
  91. package/dist/core/gate-outcome.js +30 -0
  92. package/dist/core/governance-codes.d.ts +13 -3
  93. package/dist/core/governance-codes.js +10 -0
  94. package/dist/core/hands-band.d.ts +1 -1
  95. package/dist/core/hooks.d.ts +4 -4
  96. package/dist/core/host-target.d.ts +49 -0
  97. package/dist/core/host-target.js +59 -0
  98. package/dist/core/image-downsample.d.ts +1 -1
  99. package/dist/core/lsp-diagnostics.d.ts +4 -4
  100. package/dist/core/lsp.d.ts +3 -3
  101. package/dist/core/mailbox-store.d.ts +4 -0
  102. package/dist/core/mcp-connection-pool.d.ts +18 -2
  103. package/dist/core/mcp-connection-pool.js +53 -6
  104. package/dist/core/mcp-failure.d.ts +23 -4
  105. package/dist/core/mcp-failure.js +26 -11
  106. package/dist/core/mcp-listing-drift.d.ts +10 -0
  107. package/dist/core/mcp-listing-drift.js +6 -0
  108. package/dist/core/mcp-server-link.d.ts +173 -0
  109. package/dist/core/mcp-server-link.js +127 -0
  110. package/dist/core/mcp-server-spec.d.ts +4 -2
  111. package/dist/core/mcp-session-end.d.ts +26 -0
  112. package/dist/core/mcp-session-end.js +29 -0
  113. package/dist/core/mcp-startup-request.d.ts +17 -0
  114. package/dist/core/mcp-startup-request.js +17 -0
  115. package/dist/core/mcp.d.ts +13 -13
  116. package/dist/core/mcp.js +187 -162
  117. package/dist/core/media-byte-cap.d.ts +1 -1
  118. package/dist/core/memory-engine/engine.d.ts +9 -9
  119. package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
  120. package/dist/core/memory-engine/tools.js +4 -1
  121. package/dist/core/mode-policy.d.ts +1 -1
  122. package/dist/core/namespaced-rule-name.d.ts +33 -7
  123. package/dist/core/namespaced-rule-name.js +39 -25
  124. package/dist/core/output-style.d.ts +1 -1
  125. package/dist/core/param-rule-reach.d.ts +15 -0
  126. package/dist/core/param-rule-reach.js +30 -0
  127. package/dist/core/parent-spec-seat.d.ts +8 -1
  128. package/dist/core/parent-spec-seat.js +4 -0
  129. package/dist/core/pause-registry.d.ts +16 -5
  130. package/dist/core/pause-registry.js +6 -2
  131. package/dist/core/peer-channel.d.ts +70 -0
  132. package/dist/core/peer-channel.js +1 -0
  133. package/dist/core/permission-rule-consent.d.ts +11 -5
  134. package/dist/core/permission-rule-consent.js +37 -30
  135. package/dist/core/permission-rule-model.d.ts +233 -64
  136. package/dist/core/permission-rule-model.js +384 -85
  137. package/dist/core/permission-rule-provider.d.ts +2 -1
  138. package/dist/core/permission-rule-store.d.ts +20 -25
  139. package/dist/core/permission-rule-store.js +1 -4
  140. package/dist/core/permission-rule-sync.d.ts +11 -2
  141. package/dist/core/permission-rule-sync.js +8 -1
  142. package/dist/core/permission-rules.d.ts +49 -11
  143. package/dist/core/permission-rules.js +123 -89
  144. package/dist/core/persisted-rule-arms.d.ts +4 -2
  145. package/dist/core/present-plan-tool.js +3 -1
  146. package/dist/core/protocol-naming.d.ts +2 -2
  147. package/dist/core/read-only-shell-table.d.ts +1 -1
  148. package/dist/core/read-only-shell.d.ts +1 -1
  149. package/dist/core/roles.d.ts +6 -2
  150. package/dist/core/roles.js +45 -44
  151. package/dist/core/rule-offer-read.d.ts +53 -0
  152. package/dist/core/rule-offer-read.js +146 -0
  153. package/dist/core/rule-owner.d.ts +46 -0
  154. package/dist/core/rule-owner.js +28 -0
  155. package/dist/core/runner/advisor-instructions.d.ts +70 -0
  156. package/dist/core/runner/advisor-instructions.js +61 -0
  157. package/dist/core/runner/advisor-tool.d.ts +33 -0
  158. package/dist/core/runner/advisor-tool.js +112 -0
  159. package/dist/core/runner/announce-once-ledger.d.ts +4 -26
  160. package/dist/core/runner/announce-once-ledger.js +14 -46
  161. package/dist/core/runner/approval-feedback.js +6 -3
  162. package/dist/core/runner/assemble-result.d.ts +1 -1
  163. package/dist/core/runner/caller-roster.d.ts +7 -0
  164. package/dist/core/runner/caller-roster.js +11 -0
  165. package/dist/core/runner/classifier-ladder.d.ts +27 -5
  166. package/dist/core/runner/classifier-ladder.js +12 -11
  167. package/dist/core/runner/compaction-restate.d.ts +10 -6
  168. package/dist/core/runner/compaction-restate.js +9 -3
  169. package/dist/core/runner/contracts.d.ts +13 -9
  170. package/dist/core/runner/conversation-segment.d.ts +28 -0
  171. package/dist/core/runner/conversation-segment.js +42 -0
  172. package/dist/core/runner/cross-boundary-lane.d.ts +6 -5
  173. package/dist/core/runner/cross-boundary-lane.js +26 -15
  174. package/dist/core/runner/decide-continuation.d.ts +7 -4
  175. package/dist/core/runner/decide-continuation.js +2 -2
  176. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  177. package/dist/core/runner/derived-route-fallback.d.ts +24 -24
  178. package/dist/core/runner/derived-route-fallback.js +9 -7
  179. package/dist/core/runner/gate-exit.d.ts +6 -0
  180. package/dist/core/runner/gate-exit.js +7 -2
  181. package/dist/core/runner/initial-run-state.js +1 -1
  182. package/dist/core/runner/permission-rule-lanes.d.ts +2 -2
  183. package/dist/core/runner/permission-rule-lanes.js +14 -7
  184. package/dist/core/runner/person-path-rows.js +1 -1
  185. package/dist/core/runner/prepare-advisor.d.ts +63 -0
  186. package/dist/core/runner/prepare-advisor.js +77 -0
  187. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  188. package/dist/core/runner/prepare-config-doors.d.ts +6 -4
  189. package/dist/core/runner/prepare-config-doors.js +18 -12
  190. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  191. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  192. package/dist/core/runner/prepare-file-history.js +39 -39
  193. package/dist/core/runner/prepare-gate-stations.d.ts +1 -4
  194. package/dist/core/runner/prepare-gate-stations.js +2 -7
  195. package/dist/core/runner/prepare-inherited-gate.d.ts +5 -4
  196. package/dist/core/runner/prepare-inherited-gate.js +3 -3
  197. package/dist/core/runner/prepare-park-ask.js +7 -7
  198. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  199. package/dist/core/runner/prepare-policy-chain.js +4 -10
  200. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  201. package/dist/core/runner/prepare-project-context.js +6 -3
  202. package/dist/core/runner/prepare-prompt-inputs.js +1 -1
  203. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -2
  204. package/dist/core/runner/prepare-protocol-tools.js +3 -2
  205. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  206. package/dist/core/runner/prepare-safety-scan.js +8 -6
  207. package/dist/core/runner/prepare-task.js +15 -18
  208. package/dist/core/runner/prepare-tool-disclosure-mount.js +6 -4
  209. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -3
  210. package/dist/core/runner/prepare-wiring-manifest.js +2 -2
  211. package/dist/core/runner/resume-policy-outcome.js +1 -1
  212. package/dist/core/runner/retired-runner-deps.js +1 -1
  213. package/dist/core/runner/run-attachment-seats.js +0 -1
  214. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  215. package/dist/core/runner/run-compaction-machinery.js +2 -12
  216. package/dist/core/runner/run-git-lane.d.ts +1 -0
  217. package/dist/core/runner/run-harness-handlers.js +2 -3
  218. package/dist/core/runner/run-leg.js +13 -0
  219. package/dist/core/runner/run-settle-and-teardown.js +1 -1
  220. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  221. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  222. package/dist/core/runner/run-turn-boundary.js +14 -12
  223. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  224. package/dist/core/runner/session-rule-policy.js +13 -28
  225. package/dist/core/runner/side-call-account.d.ts +32 -8
  226. package/dist/core/runner/side-call-account.js +23 -1
  227. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  228. package/dist/core/runner/sub-agent-deny-lists.js +4 -3
  229. package/dist/core/runner/synthetic-tools.d.ts +10 -13
  230. package/dist/core/runner/synthetic-tools.js +4 -2
  231. package/dist/core/runner/tool-disclosure.js +2 -1
  232. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  233. package/dist/core/runner/tool-face-overlay.js +17 -1
  234. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  235. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  236. package/dist/core/runner/turn-attachments.d.ts +60 -67
  237. package/dist/core/runner-deps.d.ts +37 -37
  238. package/dist/core/runtime-caps.d.ts +4 -4
  239. package/dist/core/safety-merge-corpus.js +17 -1
  240. package/dist/core/same-plain-value.d.ts +40 -0
  241. package/dist/core/same-plain-value.js +49 -0
  242. package/dist/core/scheduler.d.ts +1 -1
  243. package/dist/core/sensitive-path-policy.d.ts +1 -1
  244. package/dist/core/sensitive-path-policy.js +1 -1
  245. package/dist/core/session-policy-store.d.ts +77 -22
  246. package/dist/core/session-policy-store.js +56 -14
  247. package/dist/core/session-reconcile.d.ts +2 -2
  248. package/dist/core/session-store.d.ts +80 -30
  249. package/dist/core/session-store.js +118 -76
  250. package/dist/core/session.d.ts +24 -46
  251. package/dist/core/shared-memory/tools.js +3 -1
  252. package/dist/core/shared-memory/types.d.ts +1 -1
  253. package/dist/core/side-query.d.ts +10 -0
  254. package/dist/core/side-query.js +5 -0
  255. package/dist/core/store-contracts/checkpoint-store-contract.js +29 -2
  256. package/dist/core/store-contracts/file-history-store-contract.js +43 -3
  257. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  258. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  259. package/dist/core/store-contracts/session-repo-contract.js +125 -0
  260. package/dist/core/store-contracts/session-store-contract.d.ts +4 -7
  261. package/dist/core/store-contracts/session-store-contract.js +215 -41
  262. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  263. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  264. package/dist/core/task-event.d.ts +10 -4
  265. package/dist/core/task-notification.d.ts +3 -3
  266. package/dist/core/task-registry-agent.d.ts +4 -4
  267. package/dist/core/task-registry-shared.d.ts +4 -4
  268. package/dist/core/task-registry-shared.js +1 -0
  269. package/dist/core/task-registry.d.ts +4 -4
  270. package/dist/core/task-registry.js +3 -1
  271. package/dist/core/task-result.d.ts +3 -3
  272. package/dist/core/task-spec.d.ts +52 -52
  273. package/dist/core/task-stream.d.ts +6 -6
  274. package/dist/core/task-tool-shape.d.ts +4 -4
  275. package/dist/core/tighten-task-spec.d.ts +1 -1
  276. package/dist/core/tool-catalog-entries.d.ts +19 -2
  277. package/dist/core/tool-catalog-entries.js +57 -42
  278. package/dist/core/tool-conformance.js +1 -0
  279. package/dist/core/tool-errors.d.ts +2 -2
  280. package/dist/core/tool-face-reader.js +5 -3
  281. package/dist/core/tool-face.d.ts +21 -2
  282. package/dist/core/tool-face.js +1 -1
  283. package/dist/core/tool-model-gate.d.ts +3 -3
  284. package/dist/core/tool-name-aliases.d.ts +29 -8
  285. package/dist/core/tool-name-aliases.js +27 -3
  286. package/dist/core/tool-name-readings.d.ts +5 -8
  287. package/dist/core/tool-name-readings.js +1 -2
  288. package/dist/core/tool-policy.d.ts +24 -5
  289. package/dist/core/tool-policy.js +34 -10
  290. package/dist/core/tool-registry.d.ts +14 -7
  291. package/dist/core/tool-registry.js +17 -7
  292. package/dist/core/tool-result-store.js +2 -1
  293. package/dist/core/tool-roster.d.ts +47 -18
  294. package/dist/core/tool-roster.js +53 -32
  295. package/dist/core/tool-spec-members.js +1 -1
  296. package/dist/core/tool-spec.d.ts +35 -21
  297. package/dist/core/tools.js +3 -2
  298. package/dist/core/trace.d.ts +4 -0
  299. package/dist/core/untrusted-egress.d.ts +1 -1
  300. package/dist/core/untrusted-text.d.ts +1 -1
  301. package/dist/core/warm-resume.d.ts +1 -1
  302. package/dist/core/wiring-manifest.d.ts +49 -0
  303. package/dist/core/wiring-manifest.js +13 -5
  304. package/dist/core/workflow-journal-store.d.ts +62 -0
  305. package/dist/core/workflow-journal-store.js +77 -1
  306. package/dist/core/workflow-run-store.d.ts +6 -0
  307. package/dist/core/workflow-run-store.js +2 -0
  308. package/dist/engine/compaction/compaction.d.ts +9 -9
  309. package/dist/engine/execution-env/node-execution-env.d.ts +19 -5
  310. package/dist/engine/execution-env/node-execution-env.js +43 -22
  311. package/dist/engine/harness/agent-harness.d.ts +14 -8
  312. package/dist/engine/harness/agent-harness.js +33 -26
  313. package/dist/engine/harness/types.d.ts +29 -7
  314. package/dist/engine/harness/types.js +12 -1
  315. package/dist/engine/llm/types.d.ts +9 -9
  316. package/dist/engine/llm/validation.d.ts +4 -1
  317. package/dist/engine/llm/validation.js +13 -1
  318. package/dist/engine/loop/agent-loop.d.ts +1 -1
  319. package/dist/engine/loop/agent-loop.js +10 -8
  320. package/dist/engine/loop/types.d.ts +15 -13
  321. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  322. package/dist/engine/session/memory-repo.d.ts +10 -11
  323. package/dist/engine/session/memory-repo.js +13 -8
  324. package/dist/engine/session/parent-chain-guard.d.ts +3 -2
  325. package/dist/engine/session/parent-chain-guard.js +1 -1
  326. package/dist/engine/session/repo-utils.d.ts +31 -3
  327. package/dist/engine/session/repo-utils.js +42 -5
  328. package/dist/index.d.ts +27 -15
  329. package/dist/index.js +21 -11
  330. package/dist/internal/harness-types.d.ts +1 -1
  331. package/dist/internal/harness.d.ts +3 -3
  332. package/dist/internal/harness.js +2 -2
  333. package/dist/internal/llm.d.ts +1 -1
  334. package/dist/internal/llm.js +1 -1
  335. package/dist/orchestration/goal.js +2 -2
  336. package/dist/orchestration/run-workflow-tool.d.ts +2 -2
  337. package/dist/orchestration/run-workflow-tool.js +5 -3
  338. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  339. package/dist/orchestration/workflow-types.d.ts +18 -0
  340. package/dist/orchestration/workflow-types.js +6 -0
  341. package/dist/orchestration/workflow.d.ts +2 -13
  342. package/dist/orchestration/workflow.js +21 -31
  343. package/dist/prompt-assembly/event-registry.js +1 -0
  344. package/dist/prompt-assembly/tool-catalog.d.ts +3 -0
  345. package/dist/prompt-assembly/tool-catalog.js +3 -0
  346. package/dist/prompts/default.d.ts +14 -14
  347. package/dist/scenarios/full-body.d.ts +4 -4
  348. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  349. package/dist/stores/file/adoption/adopt.js +24 -31
  350. package/dist/stores/file/adoption/marker.d.ts +6 -13
  351. package/dist/stores/file/adoption/marker.js +6 -15
  352. package/dist/stores/file/checkpoint-store.d.ts +3 -0
  353. package/dist/stores/file/checkpoint-store.js +9 -3
  354. package/dist/stores/file/file-history-store.d.ts +20 -19
  355. package/dist/stores/file/file-history-store.js +152 -135
  356. package/dist/stores/file/fs-atomic.d.ts +15 -0
  357. package/dist/stores/file/fs-atomic.js +89 -14
  358. package/dist/stores/file/index.d.ts +1 -1
  359. package/dist/stores/file/mailbox-store.d.ts +3 -0
  360. package/dist/stores/file/mailbox-store.js +3 -1
  361. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  362. package/dist/stores/file/permission-rule-adopt.js +15 -16
  363. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  364. package/dist/stores/file/permission-rule-store.js +21 -14
  365. package/dist/stores/file/session-policy-store.d.ts +3 -3
  366. package/dist/stores/file/session-store.d.ts +26 -11
  367. package/dist/stores/file/session-store.js +77 -40
  368. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  369. package/dist/stores/file/workflow-journal-store.js +28 -13
  370. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  371. package/dist/tools/artifact/artifact-tool.js +2 -1
  372. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  373. package/dist/tools/fs/fs-bash.d.ts +2 -2
  374. package/dist/tools/fs/fs-bash.js +3 -1
  375. package/dist/tools/fs/fs-shared.d.ts +8 -8
  376. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  377. package/dist/tools/fs/notebook.d.ts +2 -2
  378. package/dist/tools/fs/read-deny.d.ts +29 -7
  379. package/dist/tools/fs/read-deny.js +63 -22
  380. package/dist/tools/fs/removal-targets.d.ts +1 -1
  381. package/dist/tools/fs/safety.d.ts +9 -9
  382. package/dist/tools/fs/search.d.ts +6 -6
  383. package/dist/tools/fs/shell-read-check.js +6 -1
  384. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  385. package/dist/tools/fs/shell-read-judge.js +5 -2
  386. package/dist/tools/loop-tick.d.ts +2 -2
  387. package/dist/tools/scheduler-tools.js +5 -1
  388. package/dist/tools/task-list.d.ts +7 -7
  389. package/dist/tools/task-list.js +5 -1
  390. package/dist/tools/todo.js +2 -1
  391. package/dist/tools/web.d.ts +1 -1
  392. package/dist/tools/web.js +40 -37
  393. package/dist/tools/worktree.d.ts +3 -3
  394. package/dist/tools/worktree.js +3 -1
  395. package/package.json +1 -1
  396. package/test/export-surface.snapshot.json +5756 -5638
  397. package/wire-changes/core@7.55.0.json +3318 -0
  398. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  399. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -4,7 +4,6 @@ import { hasSessionFork, isSessionConflict } from "../session.js";
4
4
  import { readMember } from "../thrown-value.js";
5
5
  import { receiptRefusal, receiveOwnProperties } from "../own-property-receipt.js";
6
6
  import { beginContract } from "./contract-harness.js";
7
- import { registerSessionIncarnationCases } from "./session-store-incarnation-contract.js";
8
7
  const AT = "2026-10-18T00:00:00.000Z";
9
8
  const AT_MS = Date.parse(AT);
10
9
  const STAMP = { api: "openai-completions", provider: "contract-kit", model: "contract-kit-model" };
@@ -12,9 +11,9 @@ const ZERO_USAGE = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalToke
12
11
  function userEntry(id, parentId, text = `t-${id}`) {
13
12
  return { id, parentId, type: "message", timestamp: AT, message: { role: "user", content: [{ type: "text", text }], timestamp: AT_MS } };
14
13
  }
15
- function assistantEntry(id, parentId, toolCall) {
16
- const content = toolCall !== undefined ? [{ type: "toolCall", id: toolCall, name: "Read", arguments: { file_path: "/kit/x" } }] : [{ type: "text", text: `a-${id}` }];
17
- return { id, parentId, type: "message", timestamp: AT, message: { role: "assistant", content, ...STAMP, usage: ZERO_USAGE, stopReason: toolCall !== undefined ? "toolUse" : "stop", timestamp: AT_MS } };
14
+ function assistantEntry(id, parentId, ...toolCalls) {
15
+ const content = toolCalls.length > 0 ? toolCalls.map((call) => ({ type: "toolCall", id: call, name: "Read", arguments: { file_path: "/kit/x" } })) : [{ type: "text", text: `a-${id}` }];
16
+ return { id, parentId, type: "message", timestamp: AT, message: { role: "assistant", content, ...STAMP, usage: ZERO_USAGE, stopReason: toolCalls.length > 0 ? "toolUse" : "stop", timestamp: AT_MS } };
18
17
  }
19
18
  function toolResultEntry(id, parentId, toolCallId) {
20
19
  return { id, parentId, type: "message", timestamp: AT, message: { role: "toolResult", toolCallId, toolName: "Read", content: [{ type: "text", text: "ok" }], isError: false, timestamp: AT_MS } };
@@ -89,8 +88,22 @@ function assertNewestFirst(rows) {
89
88
  function registerUntyped(store, sessionId, owner) {
90
89
  return Reflect.apply(store.register, store, [sessionId, owner]);
91
90
  }
92
- const hasOwnership = (s) => typeof s.ownerOf === "function" && typeof s.register === "function";
91
+ const hasHead = (s) => typeof s.headOf === "function";
92
+ const hasOwnership = (s) => hasHead(s) && typeof s.register === "function";
93
93
  const declaresPlacements = (s) => s.placements?.subagent !== undefined;
94
+ const headOf = (store, sessionId) => store.headOf(sessionId);
95
+ async function ownerOf(store, sessionId, what) {
96
+ const head = await headOf(store, sessionId);
97
+ assert.ok(head !== undefined, `${what}: the row exists, so headOf must answer it`);
98
+ return head.owner;
99
+ }
100
+ async function tokenOf(store, sessionId, what) {
101
+ const head = await headOf(store, sessionId);
102
+ assert.ok(head !== undefined, `${what}: the row exists, so headOf must answer it`);
103
+ assert.equal(typeof head.incarnation, "string", `${what}: a session row created through this store must carry an incarnation`);
104
+ assert.notEqual(head.incarnation, "", `${what}: an empty token names nobody`);
105
+ return head.incarnation;
106
+ }
94
107
  async function honorsRequireExisting(store) {
95
108
  const probe = freshId();
96
109
  await store.acquire(probe);
@@ -165,8 +178,8 @@ async function runSessionStoreContract(make, hooks) {
165
178
  noteTaskRun: (s) => typeof s.noteTaskRun === "function",
166
179
  listPlaced: (s) => declaresPlacements(s) && typeof s.listPlaced === "function",
167
180
  placements: declaresPlacements,
181
+ headOf: hasHead,
168
182
  ownership: hasOwnership,
169
- incarnationOf: (s) => typeof s.incarnationOf === "function",
170
183
  replica: () => hooks.replica !== undefined,
171
184
  };
172
185
  const faceRun = (name, needs, fn) => run(name, async (store, open) => {
@@ -214,8 +227,8 @@ async function runSessionStoreContract(make, hooks) {
214
227
  }
215
228
  if (typeof store.list === "function")
216
229
  assert.equal(rowOf(await store.list(), id), undefined, "the refused acquire must not surface on the session list");
217
- if (typeof store.incarnationOf === "function")
218
- assert.equal(await store.incarnationOf(id), undefined, "nor have a row");
230
+ if (hasHead(store))
231
+ assert.equal(await headOf(store, id), undefined, "nor have a row");
219
232
  report("requireExisting", honored ? "verified" : "absent");
220
233
  });
221
234
  run("[acquire] two concurrent acquires of one id are one session: one log, and the second write on the same parent loses the CAS", async (store) => {
@@ -438,10 +451,10 @@ async function runSessionStoreContract(make, hooks) {
438
451
  assert.equal(await store.fork(missing), null);
439
452
  if (await honorsRequireExisting(store))
440
453
  await rejectsWithCode(() => store.acquire(missing, { requireExisting: true }), "not_found", "a fork of a missing source must not create it");
441
- if (typeof store.incarnationOf === "function")
442
- assert.equal(await store.incarnationOf(missing), undefined, "a fork of a missing source must not create it");
454
+ if (hasHead(store))
455
+ assert.equal(await headOf(store, missing), undefined, "a fork of a missing source must not create it");
443
456
  });
444
- faceRun("[fork] a fork never inherits an in-flight assistant turn: a leaf turn whose tool call has no result yet (with or without sibling results already in) is left out", ["fork"], async (store) => {
457
+ faceRun("[fork] a fork never inherits an in-flight assistant turn: a turn with a tool call no result answers yet (with or without sibling results already in) is left out; a turn every call of which is answered is kept", ["fork"], async (store) => {
445
458
  const parallel = freshId();
446
459
  const p = (await store.acquire(parallel)).session;
447
460
  await append(p, userEntry("u1", null));
@@ -451,10 +464,18 @@ async function runSessionStoreContract(make, hooks) {
451
464
  const sequential = freshId();
452
465
  const q = (await store.acquire(sequential)).session;
453
466
  await append(q, userEntry("u1", null));
454
- await append(q, assistantEntry("a1", "u1", "call-1"));
467
+ await append(q, assistantEntry("a1", "u1", "call-1", "call-2"));
455
468
  await append(q, toolResultEntry("r1", "a1", "call-1"));
456
469
  const qf = await store.fork(sequential);
457
- assert.deepEqual(await pathIds((await readBack(store, qf))), ["u1"], "a sibling call's committed result does not settle the turn");
470
+ assert.deepEqual(await pathIds((await readBack(store, qf))), ["u1"], "a sibling call's committed result does not settle the turn: call-2 has none");
471
+ const answered = freshId();
472
+ const t = (await store.acquire(answered)).session;
473
+ await append(t, userEntry("u1", null));
474
+ await append(t, assistantEntry("a1", "u1", "call-1", "call-2"));
475
+ await append(t, toolResultEntry("r1", "a1", "call-2"));
476
+ await append(t, toolResultEntry("r2", "r1", "call-1"));
477
+ const tf = await store.fork(answered);
478
+ assert.deepEqual(await pathIds((await readBack(store, tf))), ["u1", "a1", "r1", "r2"], "a tool turn every call of which has its result is settled: a fork keeps it");
458
479
  const settled = freshId();
459
480
  const s = (await store.acquire(settled)).session;
460
481
  await append(s, userEntry("u1", null));
@@ -620,64 +641,217 @@ async function runSessionStoreContract(make, hooks) {
620
641
  assert.ok(scoped.includes(complete) && scoped.includes(incomplete) && !scoped.includes(elsewhere), "scope narrows to one tenant");
621
642
  assert.ok(!(await store.listPlaced("subagent", { olderThanMs: 60 * 60 * 1000 })).some((r) => r.sessionId === complete), "a session placed just now is not an hour old");
622
643
  });
623
- faceRun("[ownership] ownerOf answers three states that never collapse: an id never registered ⇒ undefined, anonymous ⇒ null, owned ⇒ the owner", ["ownership"], async (store) => {
624
- const [unknown, owned, anonymous] = [freshId(), freshId(), freshId()];
625
- assert.equal(await store.ownerOf(unknown), undefined, "no ownership row ⇒ undefined, never null");
644
+ faceRun("[head] headOf answers undefined for an id with no row; for a row, its owner, its occupant and its active leaf — the leaf follows appends and a branch switch", ["headOf"], async (store) => {
645
+ const id = freshId();
646
+ assert.equal(await headOf(store, id), undefined, "no row ⇒ undefined");
647
+ const { session } = await store.acquire(id);
648
+ assert.deepEqual(await headOf(store, id), { owner: null, incarnation: (await session.getMetadata()).incarnation, leafId: null }, "a row acquire created: no owner, its occupant, no leaf");
649
+ await append(session, userEntry("e1", null));
650
+ await append(session, assistantEntry("e2", "e1"));
651
+ assert.equal((await headOf(store, id))?.leafId, "e2", "an append moves the head's leaf");
652
+ await session.getStorage().setLeafId("e1");
653
+ assert.equal((await headOf(store, id))?.leafId, "e1", "a branch switch moves it back");
654
+ await session.getStorage().setLeafId(null);
655
+ assert.equal((await headOf(store, id))?.leafId, null);
656
+ });
657
+ faceRun("[head] the head lives in the row: a store reopened over the same rows (a restart) answers the same owner, occupant and leaf", ["headOf"], async (store, open) => {
658
+ const id = freshId();
659
+ const { session } = await store.acquire(id);
660
+ await append(session, userEntry("e1", null));
661
+ await append(session, assistantEntry("e2", "e1"));
662
+ await session.getStorage().setLeafId("e1");
663
+ const before = await headOf(store, id);
664
+ const second = await open(hooks.reopen(store));
665
+ assert.deepEqual(await headOf(second, id), before, "a head an instance kept for itself would answer differently after every restart");
666
+ });
667
+ faceRun("[head] one read, one generation: while an id is deleted and created again under other owners, no head pairs one generation's owner with another's occupant", ["ownership"], async (store) => {
668
+ const id = freshId();
669
+ const generations = [];
670
+ const reads = [];
671
+ const probe = () => {
672
+ for (let k = 0; k < 3; k++)
673
+ reads.push(headOf(store, id));
674
+ };
675
+ for (let i = 0; i < 12; i++) {
676
+ if (i > 0) {
677
+ probe();
678
+ await hooks.deleteSession(store, id);
679
+ }
680
+ probe();
681
+ await store.register(id, `kit-gen-${i}`);
682
+ probe();
683
+ await store.acquire(id);
684
+ generations.push((await headOf(store, id)));
685
+ }
686
+ const whole = new Set(generations.map((g) => `${g.owner}|${g.incarnation}`));
687
+ assert.equal(whole.size, generations.length, "each generation is its own owner and occupant");
688
+ for (const head of await Promise.all(reads)) {
689
+ if (head === undefined)
690
+ continue;
691
+ assert.ok(whole.has(`${head.owner}|${head.incarnation}`), `a head read ${head.owner} with occupant ${head.incarnation}, a pair no generation of the row ever held`);
692
+ }
693
+ });
694
+ faceRun("[ownership] register on an id with no row creates its row recording the owner — a string, or null for anonymous; a row acquire created records null", ["ownership"], async (store) => {
695
+ const [owned, anonymous, acquired] = [freshId(), freshId(), freshId()];
626
696
  await store.register(owned, "kit-alice");
627
697
  await store.register(anonymous, null);
628
- assert.equal(await store.ownerOf(owned), "kit-alice");
629
- assert.equal(await store.ownerOf(anonymous), null, "an anonymous row ⇒ null, never undefined");
630
- });
631
- faceRun("[ownership] register is first-write-wins: later calls neither overwrite nor throw, whatever they carry", ["ownership"], async (store) => {
632
- const [owned, anonymous] = [freshId(), freshId()];
698
+ await store.acquire(acquired);
699
+ assert.equal(await ownerOf(store, owned, "a registered id"), "kit-alice");
700
+ assert.equal(await ownerOf(store, anonymous, "an anonymous registration"), null);
701
+ assert.equal(await ownerOf(store, acquired, "a row acquire created"), null, "acquire names no owner");
702
+ const token = await tokenOf(store, owned, "a registered row");
703
+ assert.equal((await (await readBack(store, owned)).getMetadata()).incarnation, token, "the registered row is the session acquire then hands out");
704
+ });
705
+ faceRun("[ownership] register on a row that exists does nothing, whatever it carries — an owned row, an anonymous row, a row acquire created, a placed row", ["ownership"], async (store) => {
706
+ const [owned, anonymous, acquired] = [freshId(), freshId(), freshId()];
633
707
  await store.register(owned, "kit-alice");
634
708
  await store.register(owned, "kit-bob");
635
709
  await store.register(owned, null);
636
710
  await registerUntyped(store, owned, undefined);
637
- assert.equal(await store.ownerOf(owned), "kit-alice");
711
+ assert.equal(await ownerOf(store, owned, "an owned row"), "kit-alice");
638
712
  await store.register(anonymous, null);
639
713
  await store.register(anonymous, "kit-bob");
640
- assert.equal(await store.ownerOf(anonymous), null, "an anonymous row is not claimable by a later register");
714
+ assert.equal(await ownerOf(store, anonymous, "an anonymous row"), null, "an anonymous row is not claimable by a later register");
715
+ await store.acquire(acquired);
716
+ await store.register(acquired, "kit-carol");
717
+ assert.equal(await ownerOf(store, acquired, "a row acquire created"), null, "there is no claiming of a row that exists");
718
+ if (declaresPlacements(store)) {
719
+ const placed = freshId();
720
+ await store.acquire(placed, { placement: placementFor() });
721
+ await store.register(placed, "kit-dave");
722
+ assert.equal(await ownerOf(store, placed, "a placed row"), null, "a placed row records no owner");
723
+ }
641
724
  });
642
725
  faceRun("[ownership] a FIRST register whose owner is neither a string nor null is refused loudly and leaves no row behind", ["ownership"], async (store) => {
643
726
  const id = freshId();
644
727
  await thrownBy(() => registerUntyped(store, id, undefined), "a first register with owner undefined");
645
728
  await thrownBy(() => registerUntyped(store, id, 42), "a first register with a numeric owner");
646
- assert.equal(await store.ownerOf(id), undefined, "the refused writes stored nothing");
729
+ assert.equal(await headOf(store, id), undefined, "the refused writes stored nothing");
647
730
  await store.register(id, "kit-carol");
648
- assert.equal(await store.ownerOf(id), "kit-carol", "the id is still ownable — no row that reads as 'no row' was minted");
731
+ assert.equal(await ownerOf(store, id, "the first well-formed register"), "kit-carol", "the id is still ownable");
649
732
  });
650
733
  faceRun("[ownership] two concurrent first registers: each caller's own re-read sees the same winner, one of the two", ["ownership"], async (store) => {
651
734
  const id = freshId();
652
735
  const caller = async (owner) => {
653
736
  await store.register(id, owner);
654
- return store.ownerOf(id);
737
+ return ownerOf(store, id, "after a register");
655
738
  };
656
739
  const [x, y] = await Promise.all([caller("kit-x"), caller("kit-y")]);
657
740
  assert.equal(x, y, "the loser must see the winner on its own re-read, or both callers attach to one session");
658
741
  assert.ok(x === "kit-x" || x === "kit-y");
659
- assert.equal(await store.ownerOf(id), x, "and the row keeps that winner");
742
+ assert.equal(await ownerOf(store, id, "the settled row"), x, "and the row keeps that winner");
660
743
  });
661
- faceRun("[ownership] the ownership row outlives the cached view: a registered session that is forgotten still reads its owner", ["ownership", "forget"], async (store) => {
662
- const id = freshId();
663
- await store.register(id, "kit-alice");
664
- await append((await store.acquire(id)).session, userEntry("e1", null));
665
- await store.forget(id);
666
- assert.equal(await store.ownerOf(id), "kit-alice", "a live session reading undefined would be re-claimable by anyone");
744
+ faceRun("[ownership] the owner is a cell of the row: it reads back after the cached view is dropped and on a store reopened over the same rows (a restart)", ["ownership"], async (store, open) => {
745
+ const [owned, acquired] = [freshId(), freshId()];
746
+ await store.register(owned, "kit-alice");
747
+ await append((await store.acquire(owned)).session, userEntry("e1", null));
748
+ await store.acquire(acquired);
749
+ if (typeof store.forget === "function") {
750
+ await store.forget(owned);
751
+ assert.equal(await ownerOf(store, owned, "a forgotten session"), "kit-alice", "a live session must never lose its owner with the cached view");
752
+ }
753
+ const second = await open(hooks.reopen(store));
754
+ assert.equal(await ownerOf(second, owned, "after a restart"), "kit-alice", "an owner an instance kept for itself is lost on every restart, and the session is then anyone's");
755
+ assert.equal(await ownerOf(second, acquired, "after a restart"), null);
756
+ await second.register(owned, "kit-bob");
757
+ assert.equal(await ownerOf(second, owned, "a register after a restart"), "kit-alice", "a restart opens no claiming window");
667
758
  });
668
- faceRun("[ownership] a fork's ownership agrees with its source: no owner or null ⇒ the source's (an owned copy is never downgraded), an explicit owner ⇒ that owner, an anonymous source ⇒ anonymous", ["ownership", "fork"], async (store) => {
759
+ faceRun("[ownership] a fork records its owner in its own row: no owner or null ⇒ the source's (an owned copy is never downgraded), an explicit owner ⇒ that owner, an anonymous source ⇒ anonymous", ["ownership", "fork"], async (store) => {
669
760
  const owned = freshId();
670
761
  await store.register(owned, "kit-alice");
671
762
  await append((await store.acquire(owned)).session, userEntry("e1", null));
672
- assert.equal(await store.ownerOf((await store.fork(owned))), "kit-alice", "no owner argument ⇒ the source's owner");
673
- assert.equal(await store.ownerOf((await store.fork(owned, null))), "kit-alice", "an explicit null never downgrades a copy of an owned history to anonymous");
674
- assert.equal(await store.ownerOf((await store.fork(owned, "kit-bob"))), "kit-bob", "an explicit owner scopes the fork");
763
+ assert.equal(await ownerOf(store, (await store.fork(owned)), "a fork"), "kit-alice", "no owner argument ⇒ the source's owner");
764
+ assert.equal(await ownerOf(store, (await store.fork(owned, null)), "a fork"), "kit-alice", "an explicit null never downgrades a copy of an owned history to anonymous");
765
+ assert.equal(await ownerOf(store, (await store.fork(owned, "kit-bob")), "a fork"), "kit-bob", "an explicit owner scopes the fork");
675
766
  const anonymous = freshId();
676
- await store.register(anonymous, null);
677
767
  await append((await store.acquire(anonymous)).session, userEntry("e1", null));
678
- assert.equal(await store.ownerOf((await store.fork(anonymous))), null);
679
- assert.equal(await store.ownerOf((await store.fork(anonymous, null))), null);
768
+ assert.equal(await ownerOf(store, (await store.fork(anonymous)), "a fork"), null);
769
+ assert.equal(await ownerOf(store, (await store.fork(anonymous, null)), "a fork"), null);
770
+ });
771
+ faceRun("[ownership] an id registered first is an ordinary row: a placement-carrying acquire of it is refused placement_refused", ["ownership", "placements"], async (store) => {
772
+ const id = freshId();
773
+ await store.register(id, "kit-alice");
774
+ await rejectsWithCode(() => store.acquire(id, { placement: placementFor() }), "placement_refused", "a placed creation onto an id a register already created");
775
+ assert.equal(await ownerOf(store, id, "the registered row"), "kit-alice", "the refused acquire rewrote nothing");
776
+ });
777
+ faceRun("[ownership] acquire serves only the occupant the row holds: after another instance deleted the row and registered the id to another owner, this instance's next acquire serves the new occupant, never its cached view of the old one", ["ownership", "replica"], async (store, open) => {
778
+ const id = freshId();
779
+ const other = await open(hooks.replica(store));
780
+ await store.register(id, "kit-alice");
781
+ await append((await store.acquire(id)).session, userEntry("alice-only", null));
782
+ await other.acquire(id);
783
+ await hooks.deleteSession(other, id);
784
+ await other.register(id, "kit-bob");
785
+ const head = await headOf(store, id);
786
+ assert.equal(head?.owner, "kit-bob", "this instance's head reads the row");
787
+ const served = (await store.acquire(id)).session;
788
+ assert.equal((await served.getMetadata()).incarnation, head?.incarnation, "the session handed out is the row the owner was read from");
789
+ assert.deepEqual(await entryIds(served), [], "the previous occupant's transcript is not served under the new owner");
790
+ });
791
+ faceRun("[ownership] the metadata a session hands out is not the row: writing to it changes no owner or occupant the head answers", ["ownership"], async (store) => {
792
+ const id = freshId();
793
+ await store.register(id, "kit-alice");
794
+ const before = await headOf(store, id);
795
+ try {
796
+ Object.assign(await (await store.acquire(id)).session.getMetadata(), { owner: null, incarnation: "kit-forged" });
797
+ }
798
+ catch {
799
+ }
800
+ assert.deepEqual(await headOf(store, id), before, "admission changes only through a write of the row");
801
+ });
802
+ faceRun("[incarnation] a session created through acquire carries a token, and every later read of the row answers the same one", ["headOf", "requireExisting"], async (store) => {
803
+ const id = freshId();
804
+ await store.acquire(id);
805
+ const first = await tokenOf(store, id, "after acquire");
806
+ await store.acquire(id);
807
+ assert.equal(await tokenOf(store, id, "a re-acquire"), first, "a re-acquire reopens the same occupant");
808
+ await store.forget?.(id);
809
+ assert.equal(await tokenOf(store, id, "after forget"), first, "the token is the row's, not the cache's: forgetting the cached view must not change it");
810
+ await store.acquire(id, { requireExisting: true });
811
+ assert.equal(await tokenOf(store, id, "a require-existing reopen"), first, "a require-existing reopen after the cache forgot it is still the same occupant");
812
+ });
813
+ faceRun("[incarnation] the session acquire hands back carries the token headOf answers — a run's memory seat reads the former", ["headOf", "requireExisting"], async (store) => {
814
+ const id = freshId();
815
+ const acquired = await store.acquire(id);
816
+ const byId = await tokenOf(store, id, "by-id read");
817
+ assert.equal((await acquired.session.getMetadata()).incarnation, byId, "two faces of one row cell must agree, or the seat and the by-id read name two occupants");
818
+ });
819
+ faceRun("[incarnation] a second store over the same rows (a restart, a replica) answers the same token — the token lives in the row, not in an instance", ["headOf", "requireExisting"], async (store, open) => {
820
+ const id = freshId();
821
+ await store.acquire(id);
822
+ const first = await tokenOf(store, id, "first instance");
823
+ const second = await open(hooks.reopen(store));
824
+ assert.equal(await tokenOf(second, id, "second instance"), first, "an instance-local token would name a different occupant after every restart");
825
+ await second.acquire(id, { requireExisting: true });
826
+ assert.equal(await tokenOf(second, id, "reopened on the second instance"), first, "reopening the session on the second instance is still the same occupant");
827
+ });
828
+ faceRun("[incarnation] two sessions never share a token, and an id with no session has no head (unknown — not an error, not a token)", ["headOf", "requireExisting"], async (store) => {
829
+ const id = freshId();
830
+ await store.acquire(id);
831
+ const generated = await store.acquire();
832
+ const a = await tokenOf(store, id, "explicit id");
833
+ const g = await tokenOf(store, generated.sessionId, "generated id");
834
+ assert.notEqual(a, g, "two sessions are two occupants");
835
+ assert.equal(await headOf(store, freshId()), undefined, "no row ⇒ unknown");
836
+ });
837
+ faceRun("[incarnation] a deleted id handed out again is a NEW occupant: a fresh token, never the previous occupant's", ["headOf", "requireExisting"], async (store) => {
838
+ const id = freshId();
839
+ await store.acquire(id);
840
+ const before = await tokenOf(store, id, "first occupant");
841
+ await hooks.deleteSession(store, id);
842
+ assert.equal(await headOf(store, id), undefined, "a deleted row has no occupant");
843
+ await store.acquire(id);
844
+ const after = await tokenOf(store, id, "second occupant");
845
+ assert.notEqual(after, before, "the id was recycled — the previous occupant's records must not bind this one");
846
+ });
847
+ faceRun("[incarnation] a fork is a new occupant: a fresh token, and the source keeps its own", ["headOf", "requireExisting", "fork"], async (store) => {
848
+ const src = freshId();
849
+ await store.acquire(src);
850
+ const source = await tokenOf(store, src, "fork source");
851
+ const forkedId = await store.fork(src);
852
+ assert.ok(forkedId !== null, "forking an existing session returns the fork's id");
853
+ assert.notEqual(await tokenOf(store, forkedId, "fork"), source, "a fork copies the history, never the occupant");
854
+ assert.equal(await tokenOf(store, src, "fork source after"), source, "forking does not touch the source's occupant");
680
855
  });
681
- registerSessionIncarnationCases((name, fn) => faceRun(`[incarnation] ${name}`, ["incarnationOf", "requireExisting"], (store) => fn(store)), hooks);
682
856
  await settle();
683
857
  }
@@ -1,5 +1,5 @@
1
1
  import { strict as assert } from "node:assert";
2
- import { JOURNAL_OVERSIZE_ERROR_CODE, MAX_JOURNAL_RESULT_BYTES, } from "../workflow-journal-store.js";
2
+ import { JOURNAL_INCOMPATIBLE_ERROR_CODE, JOURNAL_OVERSIZE_ERROR_CODE, MAX_JOURNAL_RESULT_BYTES, } from "../workflow-journal-store.js";
3
3
  import { beginContract } from "./contract-harness.js";
4
4
  const key = (ordinal) => `${ordinal}:h`;
5
5
  const completed = (ordinal, over = {}) => ({
@@ -22,6 +22,7 @@ const parked = (ordinal, over = {}) => ({
22
22
  });
23
23
  const OVER_CAP = "x".repeat(MAX_JOURNAL_RESULT_BYTES + 1024);
24
24
  const isOversizeRefusal = (e) => e instanceof Error && e.code === JOURNAL_OVERSIZE_ERROR_CODE;
25
+ const isIncompatibleRefusal = (e) => e instanceof Error && e.code === JOURNAL_INCOMPATIBLE_ERROR_CODE;
25
26
  export async function workflowJournalStoreContract(make, runAssertion) {
26
27
  const { run, settle } = beginContract(runAssertion);
27
28
  run("append → load returns entries ASCENDING by ordinal, both arms verbatim; a re-append per ordinal OVERWRITES", async () => {
@@ -64,6 +65,30 @@ export async function workflowJournalStoreContract(make, runAssertion) {
64
65
  await store.append("run-1", "tenant-a", { callKey: key(1), parked: parked(1) });
65
66
  assert.equal((await store.load("run-1", "tenant-a"))[1].parked?.terminal.kind, "paused");
66
67
  });
68
+ run("a PARKED row whose payload is not a paused result is refused — at append, or by the whole load — never read back as an entry, never dropped", async () => {
69
+ const bad = [
70
+ ["terminal completed", { ...parked(1), terminal: { kind: "completed" } }],
71
+ ["paused terminal without a checkpoint token", { ...parked(1), terminal: { kind: "paused", gate: { kind: "human", reason: "approve", toolName: "Write" } } }],
72
+ ["parked arm a string", "paused"],
73
+ ];
74
+ for (const [what, payload] of bad) {
75
+ const store = make();
76
+ await store.append("run-1", "tenant-a", { callKey: key(0), result: completed(0) });
77
+ let appended = true;
78
+ try {
79
+ await store.append("run-1", "tenant-a", { callKey: key(1), parked: payload });
80
+ }
81
+ catch {
82
+ appended = false;
83
+ }
84
+ if (appended) {
85
+ await assert.rejects(store.load("run-1", "tenant-a"), isIncompatibleRefusal, `${what}: the row was journaled, so the load must refuse — with code "${JOURNAL_INCOMPATIBLE_ERROR_CODE}" — rather than answer around it`);
86
+ }
87
+ else {
88
+ assert.deepEqual((await store.load("run-1", "tenant-a")).map((e) => e.callKey), [key(0)], `${what}: an append that refused must have journaled nothing`);
89
+ }
90
+ }
91
+ });
67
92
  run("the cap is inclusive: a payload of EXACTLY the cap's byte count is accepted on both arms", async () => {
68
93
  const store = make();
69
94
  const fit = (payload) => {
@@ -9,7 +9,7 @@
9
9
  * same defect has been found and fixed one site at a time (RB-122 in `clipWithFilePointer`, then
10
10
  * `truncateError`, then the three siblings above), which is exactly the shape a shared primitive prevents.
11
11
  *
12
- * Anchored on CC 2.1.220 `A7e`'s helpers `ma` (head) / `_W` (tail): drop the straddling code point WHOLE
12
+ * Head / tail helpers: drop the straddling code point WHOLE
13
13
  * rather than emit half of it. Zero imports, so any module in the repo may depend on it without risking an
14
14
  * import cycle.
15
15
  *
@@ -25,7 +25,7 @@ export declare const isHighSurrogate: (c: number) => boolean;
25
25
  export declare const isLowSurrogate: (c: number) => boolean;
26
26
  /**
27
27
  * Head-keep of at most `keep` code UNITS that never ends on a lone high surrogate — a code point straddling
28
- * the cut is dropped whole (CC 2.1.220 `ma`).
28
+ * the cut is dropped whole.
29
29
  *
30
30
  * Callers must derive any "how much was dropped" count from the RETURNED length, never from `keep`: when
31
31
  * the rollback fires the result is one unit SHORTER than the budget, and a count computed from `keep`
@@ -33,7 +33,7 @@ export declare const isLowSurrogate: (c: number) => boolean;
33
33
  */
34
34
  export declare function sliceHeadSafe(s: string, keep: number): string;
35
35
  /**
36
- * Tail-keep counterpart: at most `keep` code units, never STARTING on a lone low surrogate (CC 2.1.220
36
+ * Tail-keep counterpart: at most `keep` code units, never STARTING on a lone low surrogate (the reference's
37
37
  * `_W`). Same rule for the caller's dropped-count arithmetic — read it off the returned length.
38
38
  */
39
39
  export declare function sliceTailSafe(s: string, keep: number): string;
@@ -322,7 +322,7 @@ export type TaskEvent = ({
322
322
  * forwarded to a parent's display sink under the SAME opt-in as those two
323
323
  * (`TaskSpec.forwardSubagentEvents`).
324
324
  *
325
- * ONE FRAME, not two: CC 2.1.259 splits this into a per-tool `tool_heartbeat` plus Bash's own
325
+ * ONE FRAME, not two: the reference splits this into a per-tool `tool_heartbeat` plus Bash's own
326
326
  * `bash_progress`; this engine mints the single shape and lets the OUTPUT KEYS be what is conditional.
327
327
  * Registered divergence.
328
328
  *
@@ -413,7 +413,7 @@ export type TaskEvent = ({
413
413
  * document/worktree/todo/task/task-list/task-output/task-stop/agent/fork/workflow-run/web-fetch/
414
414
  * web-search/cron-create/cron-delete/cron-list/tool-search/repo-map/monitor-start/
415
415
  * enter-plan-mode/exit-plan-mode/report-findings/schedule-wakeup/send-message/agent-transcript/
416
- * a2a/path_not_in_root/readonly_out_of_root/read_unestablished), surfaced on the live wire so a CC-faithful shell
416
+ * a2a/path_not_in_root/readonly_out_of_root/read_unestablished/advisor), surfaced on the live wire so a CC-faithful shell
417
417
  * renders rich cards (red/green diff, stdout panes, file cards) without re-parsing the
418
418
  * model-facing string. Absent when the tool carries no card shape or when the serialized card
419
419
  * exceeds the size bound (omitted whole; a consumer falls back to `output`).
@@ -427,13 +427,19 @@ export type TaskEvent = ({
427
427
  * memory-saved / memory-recall, three words with no producer anywhere in core (a batch MultiEdit
428
428
  * replay mints `type:"edit"` with an `edits[]` array; core mounts no memory tool at all).
429
429
  *
430
+ * The **advisor** card (`type:"advisor"`, the advisor tool's every call) carries closed words, numbers and catalog ids
431
+ * only — `outcome` (`reviewed` / `declined` / `unavailable`, and `isError` ⇔ `unavailable`), `model`, `servedModel?`,
432
+ * `stopReason?`, `code?` / `errorKind?` (the failure's own words), `hold?: true` (this failure's cause switches the
433
+ * advisor off for the conversation until it is compacted — a classification, not a promise: the transcript says so once
434
+ * the result is recorded) and `usage?`. The guidance, a refusal's reason and an error's message ride {@link output}.
435
+ *
430
436
  * **Leak boundary**: the allowlist gates by `type`, so what rides is whatever the minting tool put
431
437
  * in the object — which makes each mint site responsible for its own field set. The Agent family's
432
438
  * completed card is therefore built from an EXPLICIT whitelist rather than a child-`TaskResult`
433
439
  * spread: a `TaskResult` can carry `checkpointToken` (the resume CAPABILITY) on the
434
440
  * `unexpected.suspended` terminal, and that field, with `checkpointGate`, never leaves the process.
435
441
  *
436
- * **双面契约(CC 2.1.207 @765495 成文,`tool_use_result` describe;CC207-CORE-SWEEP P2-3)** — a tool
442
+ * **双面契约(`tool_use_result` describe;P2-3)** — a tool
437
443
  * result has TWO faces that never substitute for each other:
438
444
  * - **模型面** = {@link output} / the tool_result text: the string the MODEL reads. It may carry
439
445
  * model-directed framing — e.g. a delegation tool's trailer (agentId / usage lines the model uses to
@@ -841,7 +847,7 @@ export type TaskEvent = ({
841
847
  preview: string;
842
848
  } & TaskEventIdentity) | ({
843
849
  /**
844
- * design/121 (CC 198 `<new-diagnostics>` parity): NEW LSP diagnostics that appeared after the
850
+ * design/121 (`<new-diagnostics>`): NEW LSP diagnostics that appeared after the
845
851
  * agent's edits, drained at a turn boundary. The SAME data was injected into the model as a
846
852
  * `<new-diagnostics>` context message; this frame is the shell's render source (CC's collapsed
847
853
  * `Found N new diagnostic issues in M files (ctrl+o to expand)` row). UNTRUSTED RAW (language-
@@ -26,7 +26,7 @@ export declare function isNotificationInjectionOutcome(value: unknown): value is
26
26
  export type NotificationDisposition = Exclude<NotificationInjectionOutcome, "dropped_duplicate">;
27
27
  /** The closed value set of {@link SystemInjectionPriority}, as data — the wire-facing entries validate
28
28
  * against THIS rather than against three inline string literals, so widening the type widens the guard.
29
- * (Names taken verbatim from CC 2.1.223's `UYo` @ `CC:644918`; see the semantics note on
29
+ * (Names taken from the reference; see the semantics note on
30
30
  * {@link SystemInjection.priority} for which of CC's behaviors this engine implements.) */
31
31
  export declare const SYSTEM_INJECTION_PRIORITIES: readonly SystemInjectionPriority[];
32
32
  /** backlog #389 伴生 (D-3, bad-value loudness) — is this a priority this engine knows at all? A value
@@ -327,8 +327,8 @@ export interface ExternalNotificationInput {
327
327
  export interface SystemInjection<TPayload = unknown> {
328
328
  kind: "task_notification";
329
329
  /**
330
- * design/373 — the injection ladder is LIVE (all three values carry delivery semantics, the CC
331
- * 2.1.223 form; the flat "every priority delivers at the next boundary" era ended with this
330
+ * design/373 — the injection ladder is LIVE (all three values carry delivery semantics, the reference's
331
+ * form; the flat "every priority delivers at the next boundary" era ended with this
332
332
  * design — its H-1 anchor-correction note is preserved in the design archive, and the ruled
333
333
  * changes it named are exactly what landed here):
334
334
  *
@@ -282,12 +282,12 @@ export declare function abortBackgroundAgentsForOwnerLane(core: DurableAgentCore
282
282
  skipSessionScoped?: boolean;
283
283
  sessionScopedOnly?: boolean;
284
284
  }): number;
285
- /** CC206-B name resolution over the caller-visible background_agent rows (CC `cgo`/`gvy`, 206:575142-575178
286
- * and 206:575199-575210 — sema's single-lane subset: no teammate/name-registry branches).
285
+ /** Name resolution over the caller-visible background_agent rows
286
+ * (sema's single-lane subset: no teammate/name-registry branches).
287
287
  *
288
288
  * [c209-D] PUBLIC + explicit-name layer 0: the single resolver both TaskStop (:1839 leg) and
289
289
  * SendMessage consume, so the two verbs can never drift. Ladder:
290
- * 0a. verbatim `handle.name` match — LATEST-WINS (CC SendMessage.md: "a newer agent took the name
290
+ * 0a. exact `handle.name` match — LATEST-WINS (the reference's SendMessage doc: "a newer agent took the name
291
291
  * (latest wins)"; older rows stay task_id-addressable), any status (names keep working after
292
292
  * completion — the resume face is the CC "resumes it from its transcript" counterpart).
293
293
  * **Latest-wins is RESOLUTION, not permission to redirect a conversation**: CC pairs the same
@@ -446,7 +446,7 @@ export declare function deliverToRunningAgentLane(core: DurableAgentCore, id: st
446
446
  * very rows a retry needs. The task faces' split lives in `runningAgentFooterLane` (RB-332). */
447
447
  export declare function runningBackgroundAgentLabelsLane(core: DurableAgentCore, access: TaskAccess): string[];
448
448
  /**
449
- * The not-found FOOTER's two rows, split the way CC 220 assembles them:
449
+ * The not-found FOOTER's two rows, split the way the reference assembles them:
450
450
  * - `named` = CC `uG_` (220:467941-467953): the agentNameRegistry's KEYS whose task is a running local
451
451
  * agent, listed as BARE NAMES — the string a retry should pass verbatim. sema's counterpart
452
452
  * of "has a registry entry" is the handle carrying an explicit `name` (spawn-time label),
@@ -590,10 +590,10 @@ export declare const MONITOR_DEFAULT_TIMEOUT_MS = 300000;
590
590
  export declare const MONITOR_MAX_TIMEOUT_MS = 3600000;
591
591
  export declare const MONITOR_MAX_BATCHES_PER_MINUTE = 50;
592
592
  /** Burst capacity of the storm token bucket — how many batches may fire
593
- * back-to-back before the SUPPRESSION level engages. CC value, adopted verbatim. */
593
+ * back-to-back before the SUPPRESSION level engages. Adopted from the reference. */
594
594
  export declare const MONITOR_STORM_BURST = 10;
595
595
  /** How long a monitor must stay CONTINUOUSLY over budget before the
596
- * second level (kill) fires. CC value, adopted verbatim. */
596
+ * second level (kill) fires. Adopted from the reference. */
597
597
  export declare const MONITOR_STORM_KILL_AFTER_MS = 30000;
598
598
  /** The partial-line accumulator bound. sema's `lineBuf` had NO bound —
599
599
  * a monitored process emitting megabytes without a single newline grew it without limit (the spool's
@@ -789,7 +789,7 @@ export declare function firstDropNote(spool: {
789
789
  /** ONE wording for "you stopped nothing" across every already-terminal stop face —
790
790
  * the in-process bash/monitor/agent arms and the durable-row fallback previously split: the durable
791
791
  * arm answered honestly while the in-process arms claimed `Terminated <id>.` over work that finished
792
- * (or was killed) on its own. CC 220 refuses the call outright (`Task X is not running (status: …)`,
792
+ * (or was killed) on its own. The reference refuses the call outright (`Task X is not running (status: …)`,
793
793
  * 220:468231-468236); sema keeps the idempotent no-op posture (stopWorkflow / durable-arm precedent,
794
794
  * no isError) but the receipt must tell the truth. */
795
795
  export declare function alreadyTerminalStopNote(id: string, status: string): string;
@@ -840,7 +840,7 @@ export declare const DURABLE_AGENT_HANDLE_RE: RegExp;
840
840
  * real child error — settleBackgroundAgent never stores it (status "killed" + stoppedBy already say
841
841
  * it); exported so the subagent call sites and the registry agree on the exact sentinel. */
842
842
  export declare const BG_AGENT_REAP_STOP_ERROR = "stopped (parent task ended or TaskStop)";
843
- /** CC206-B 欠账 — TaskStop name addressing, CC `XN` verbatim (206:574955-574962): NFKC-normalize, strip
843
+ /** TaskStop name addressing: NFKC-normalize, strip
844
844
  * control/format chars (whitespace-class ones survive), trim, lowercase, whitespace runs → hyphens. Both
845
845
  * the query and the candidate label go through this, so "Fix Tests" addresses "fix tests".
846
846
  * [c209-D]: EXPORTED — SendMessage's "main" reserved lane must use the SAME canonicalization
@@ -217,6 +217,7 @@ export function formatWorkflowRun(run) {
217
217
  runId: run.id,
218
218
  type: "workflow",
219
219
  status: run.status,
220
+ ...(summary.parked ? { parked: true } : {}),
220
221
  ...(summary.name ? { name: summary.name } : {}),
221
222
  ...(summary.currentPhase ? { currentPhase: summary.currentPhase } : {}),
222
223
  agents: { done, total: run.agents.length, failed },
@@ -33,7 +33,7 @@ export interface RegisterBackgroundBashInput extends TaskAccess {
33
33
  * rolling bound) and fires ONE completion task-notification at the terminal state — the background-bash
34
34
  * half of CC's LocalShellTask completion notify. Also flips TaskOutput to re-readable spool reads. */
35
35
  onTerminal?: (notification: TaskNotificationPayload) => void;
36
- /** CC 2.1.209 对齐批A A5: the task's OUTPUT FILE — the launch receipt advertises it and the watcher
36
+ /** The task's OUTPUT FILE — the launch receipt advertises it and the watcher
37
37
  * mirrors every polled increment into it (append-only, unbounded — unlike the rolling in-memory
38
38
  * spool), so "Read the output file path" is a real alternative to TaskOutput. Terminal
39
39
  * task-notifications carry the same path (`output_file`). Primarily meaningful with `onTerminal`
@@ -66,9 +66,9 @@ export interface TaskPollOptions {
66
66
  filter?: string;
67
67
  /** design/116 W3 (CC TaskOutput `block`): wait until the task reaches a terminal state (or `timeoutMs`)
68
68
  * instead of returning the instantaneous snapshot — saves the model blind re-poll turns. The TOOL layer
69
- * defaults this to TRUE (CC 187 `block: default(!0)`, 裁定 2026-07-02); registry callers pass it explicitly. */
69
+ * defaults this to TRUE (裁定 2026-07-02); registry callers pass it explicitly. */
70
70
  block?: boolean;
71
- /** Max wait for `block` (ms). Default 30s, capped at 600s (CC 187). */
71
+ /** Max wait for `block` (ms). Default 30s, capped at 600s. */
72
72
  timeoutMs?: number;
73
73
  /** Abort signal — a blocked wait must stop when the tool call is cancelled. */
74
74
  signal?: AbortSignal;
@@ -101,7 +101,7 @@ export interface TaskToolOptions extends TaskAccess {
101
101
  * foreground clamp (design/130 P2b). When present, a BLOCKING TaskOutput wait is clamped so it
102
102
  * cannot eat the write-out window: the model gets an honest, visible clamp note instead of a
103
103
  * silent 10-minute blind wait into the finalize wall (TB rs**: 9.1min poll = the exact tax).
104
- * CC posture note (anchors/2.1.212/print-mode-drain.md): CC classifies WIND-DOWN waits, and its
104
+ * CC posture note: CC classifies WIND-DOWN waits, and its
105
105
  * block cap rides per-query budgets — a deadline-aware wait is the sema equivalent on the tool face. */
106
106
  deadlineMs?: () => number | undefined;
107
107
  /** design/157 B17 S2 (fable 终判 D4) — whether a terminal <task-notification> is actually wired for
@@ -12,7 +12,7 @@ import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutp
12
12
  export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
13
13
  import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
14
14
  import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, activeDelegationHandlesLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
15
- import { toolFace } from "./tool-catalog-entries.js";
15
+ import { mountRuleFace, toolFace } from "./tool-catalog-entries.js";
16
16
  import { thrownText } from "./thrown-value.js";
17
17
  import { agentStateSourceOfHandle, agentStateSourceOfRecord, agentStateSummary, readAgentState } from "./agent-state.js";
18
18
  export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
@@ -1307,6 +1307,7 @@ export function createTaskOutputTool(opts) {
1307
1307
  return defineTool({
1308
1308
  name: TASK_OUTPUT_TOOL_NAME,
1309
1309
  ...toolFace("task-output"),
1310
+ ruleFace: mountRuleFace("task-output"),
1310
1311
  description: composeTaskOutputDescription(caps),
1311
1312
  parameters: composeTaskOutputParams(caps),
1312
1313
  boundaryLegsFor: (rawArgs, at) => {
@@ -1360,6 +1361,7 @@ export function createTaskStopTool(opts) {
1360
1361
  return defineTool({
1361
1362
  name: TASK_STOP_TOOL_NAME,
1362
1363
  ...toolFace("task-stop"),
1364
+ ruleFace: mountRuleFace("task-stop"),
1363
1365
  description: composeTaskStopDescription(REGISTRY_TASK_TOOL_CAPS),
1364
1366
  parameters: TASK_STOP_PARAMS,
1365
1367
  boundaryLegsFor: (rawArgs, at) => {