@jr2/orchestrator 0.5.1 → 0.7.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 (350) hide show
  1. package/console/components/app.ts +55 -15
  2. package/console/components/bottom-drawer.ts +259 -0
  3. package/console/components/drawer.ts +14 -6
  4. package/console/components/fleet.ts +36 -13
  5. package/console/components/machine-pane.ts +61 -5
  6. package/console/components/nav.ts +54 -8
  7. package/console/conversation.ts +161 -0
  8. package/console/login.ts +123 -0
  9. package/console/main.ts +600 -60
  10. package/console/store.ts +611 -64
  11. package/console/style.css +231 -0
  12. package/docs/agents-block.md +2 -2
  13. package/docs/concepts/agents-and-turns.md +142 -29
  14. package/docs/concepts/architecture.md +60 -34
  15. package/docs/concepts/callers-and-hooks.md +205 -0
  16. package/docs/concepts/charts.md +13 -8
  17. package/docs/concepts/composition.md +10 -1
  18. package/docs/concepts/converge.md +7 -2
  19. package/docs/concepts/durable-runs.md +43 -16
  20. package/docs/concepts/effects.md +133 -50
  21. package/docs/concepts/gates.md +95 -25
  22. package/docs/concepts/machines-and-workflows.md +14 -4
  23. package/docs/concepts/pools-and-sources.md +193 -17
  24. package/docs/concepts/secrets-and-trust.md +186 -62
  25. package/docs/concepts/the-menu.md +14 -0
  26. package/docs/concepts/workspaces.md +135 -56
  27. package/docs/get-started/a-model-decides.md +14 -13
  28. package/docs/get-started/an-agent-in-a-sandbox.md +46 -35
  29. package/docs/get-started/connect-a-model.md +1 -1
  30. package/docs/get-started/create-an-instance.md +17 -14
  31. package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
  32. package/docs/get-started/install.md +4 -0
  33. package/docs/guides/add-tools-to-the-sandbox.md +72 -15
  34. package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
  35. package/docs/guides/answer-a-gate.md +74 -37
  36. package/docs/guides/bind-open-parts.md +29 -12
  37. package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
  38. package/docs/guides/cancel-a-run.md +26 -16
  39. package/docs/guides/cut-a-worktree.md +560 -0
  40. package/docs/guides/fix-a-failed-converge.md +19 -7
  41. package/docs/guides/give-a-caller-a-scope.md +203 -0
  42. package/docs/guides/give-an-agent-mcp-tools.md +422 -0
  43. package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
  44. package/docs/guides/let-an-agent-write-a-chart.md +14 -7
  45. package/docs/guides/look-inside-a-sandbox.md +115 -42
  46. package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
  47. package/docs/guides/open-the-console.md +63 -14
  48. package/docs/guides/push-and-sign-a-branch.md +67 -21
  49. package/docs/guides/read-a-conversation.md +225 -0
  50. package/docs/guides/run-a-chart-by-name.md +17 -16
  51. package/docs/guides/run-a-command-or-call-a-url.md +84 -41
  52. package/docs/guides/run-one-worker-per-item.md +34 -27
  53. package/docs/guides/set-an-agents-access-and-dials.md +69 -22
  54. package/docs/guides/size-a-workspace.md +19 -6
  55. package/docs/guides/start-a-run-for-each-alert.md +290 -0
  56. package/docs/guides/start-a-run-from-a-run.md +18 -16
  57. package/docs/guides/start-a-run.md +24 -18
  58. package/docs/guides/steer-an-agent.md +332 -0
  59. package/docs/guides/use-a-hosted-provider.md +7 -1
  60. package/docs/guides/watch-a-run.md +146 -117
  61. package/docs/guides/write-a-hook-kind.md +238 -0
  62. package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
  63. package/docs/guides/write-a-workflow.md +18 -8
  64. package/docs/llms.txt +110 -23
  65. package/docs/reference/authoring-surface/agent.md +35 -12
  66. package/docs/reference/authoring-surface/answer.md +20 -4
  67. package/docs/reference/authoring-surface/arg.md +28 -6
  68. package/docs/reference/authoring-surface/basic.md +1 -1
  69. package/docs/reference/authoring-surface/bearer.md +1 -1
  70. package/docs/reference/authoring-surface/branchname.md +15 -0
  71. package/docs/reference/authoring-surface/carry.md +23 -0
  72. package/docs/reference/authoring-surface/chartschema.md +1 -1
  73. package/docs/reference/authoring-surface/chartschemafor.md +1 -1
  74. package/docs/reference/authoring-surface/command.md +37 -22
  75. package/docs/reference/authoring-surface/customize.md +4 -1
  76. package/docs/reference/authoring-surface/defineconfig.md +1 -1
  77. package/docs/reference/authoring-surface/defineevent.md +1 -1
  78. package/docs/reference/authoring-surface/dispatch.md +5 -4
  79. package/docs/reference/authoring-surface/fail.md +18 -5
  80. package/docs/reference/authoring-surface/file.md +37 -17
  81. package/docs/reference/authoring-surface/frompick.md +1 -1
  82. package/docs/reference/authoring-surface/gate.md +118 -0
  83. package/docs/reference/authoring-surface/group-agents.md +15 -0
  84. package/docs/reference/authoring-surface/group-charts.md +16 -0
  85. package/docs/reference/authoring-surface/group-composition.md +25 -0
  86. package/docs/reference/authoring-surface/group-config.md +17 -0
  87. package/docs/reference/authoring-surface/group-effects.md +48 -0
  88. package/docs/reference/authoring-surface/group-failure.md +13 -0
  89. package/docs/reference/authoring-surface/group-gates.md +16 -0
  90. package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
  91. package/docs/reference/authoring-surface/group-steering.md +12 -0
  92. package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
  93. package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
  94. package/docs/reference/authoring-surface/http.md +109 -9
  95. package/docs/reference/authoring-surface/isfailure.md +1 -1
  96. package/docs/reference/authoring-surface/isready.md +14 -0
  97. package/docs/reference/authoring-surface/jr2setup.md +14 -4
  98. package/docs/reference/authoring-surface/mcp.md +107 -0
  99. package/docs/reference/authoring-surface/open.md +41 -8
  100. package/docs/reference/authoring-surface/openbody.md +1 -1
  101. package/docs/reference/authoring-surface/paramsof.md +23 -5
  102. package/docs/reference/authoring-surface/pool.md +79 -11
  103. package/docs/reference/authoring-surface/push.md +31 -13
  104. package/docs/reference/authoring-surface/readyof.md +21 -0
  105. package/docs/reference/authoring-surface/reread.md +19 -0
  106. package/docs/reference/authoring-surface/secret.md +26 -5
  107. package/docs/reference/authoring-surface/sentby.md +1 -1
  108. package/docs/reference/authoring-surface/skip.md +22 -0
  109. package/docs/reference/authoring-surface/source.md +59 -4
  110. package/docs/reference/authoring-surface/steer.md +93 -0
  111. package/docs/reference/authoring-surface/text.md +1 -1
  112. package/docs/reference/authoring-surface/type-agentdefinition.md +16 -3
  113. package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
  114. package/docs/reference/authoring-surface/type-agentslots.md +4 -1
  115. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  116. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  117. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  118. package/docs/reference/authoring-surface/type-binding.md +6 -7
  119. package/docs/reference/authoring-surface/type-caller.md +40 -0
  120. package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
  121. package/docs/reference/authoring-surface/type-carry.md +19 -0
  122. package/docs/reference/authoring-surface/type-chainlink.md +3 -3
  123. package/docs/reference/authoring-surface/type-commandinput.md +4 -3
  124. package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
  125. package/docs/reference/authoring-surface/type-commandoutput.md +23 -5
  126. package/docs/reference/authoring-surface/type-customize.md +20 -3
  127. package/docs/reference/authoring-surface/type-delivered.md +17 -0
  128. package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
  129. package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
  130. package/docs/reference/authoring-surface/type-dispatchoutput.md +9 -2
  131. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  132. package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
  133. package/docs/reference/authoring-surface/type-filebody.md +4 -8
  134. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  135. package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
  136. package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
  137. package/docs/reference/authoring-surface/type-gatelook.md +37 -0
  138. package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
  139. package/docs/reference/authoring-surface/type-gatereply.md +19 -0
  140. package/docs/reference/authoring-surface/type-gateslot.md +21 -0
  141. package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
  142. package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
  143. package/docs/reference/authoring-surface/type-gateslots.md +12 -0
  144. package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
  145. package/docs/reference/authoring-surface/type-hostinjectedinput.md +3 -5
  146. package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
  147. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  148. package/docs/reference/authoring-surface/type-httpoutput.md +8 -2
  149. package/docs/reference/authoring-surface/type-jr2config.md +37 -2
  150. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  151. package/docs/reference/authoring-surface/type-lends.md +5 -1
  152. package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
  153. package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
  154. package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
  155. package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
  156. package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
  157. package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
  158. package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
  159. package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
  160. package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
  161. package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
  162. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  163. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
  164. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  165. package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
  166. package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
  167. package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
  168. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
  169. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
  170. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  171. package/docs/reference/authoring-surface/type-poolspec.md +11 -6
  172. package/docs/reference/authoring-surface/type-pushinput.md +22 -3
  173. package/docs/reference/authoring-surface/type-pushoutput.md +33 -8
  174. package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
  175. package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
  176. package/docs/reference/authoring-surface/type-reposlot.md +6 -6
  177. package/docs/reference/authoring-surface/type-reread.md +18 -0
  178. package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
  179. package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
  180. package/docs/reference/authoring-surface/type-sender.md +26 -1
  181. package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
  182. package/docs/reference/authoring-surface/type-size.md +1 -1
  183. package/docs/reference/authoring-surface/type-skip.md +19 -0
  184. package/docs/reference/authoring-surface/type-slothandles.md +5 -13
  185. package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
  186. package/docs/reference/authoring-surface/type-sourcein.md +25 -0
  187. package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
  188. package/docs/reference/authoring-surface/type-sourcespec.md +26 -17
  189. package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
  190. package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
  191. package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
  192. package/docs/reference/authoring-surface/type-steerargs.md +20 -0
  193. package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
  194. package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
  195. package/docs/reference/authoring-surface/type-workspaced.md +30 -9
  196. package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
  197. package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
  198. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  199. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  200. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  201. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  202. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  203. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  204. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  205. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  206. package/docs/reference/authoring-surface/workspace.md +66 -38
  207. package/docs/reference/authoring-surface/worktree.md +71 -0
  208. package/docs/reference/authoring-surface.md +88 -147
  209. package/docs/reference/cli.md +413 -74
  210. package/docs/reference/config.md +248 -6
  211. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
  212. package/docs/reference/decisions/0002-duplex-streaming-actor.md +81 -14
  213. package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
  214. package/docs/reference/decisions/0005-sandbox-pod-composition.md +39 -25
  215. package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
  216. package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
  217. package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
  218. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
  219. package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
  220. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +39 -32
  221. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +54 -30
  222. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
  223. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +26 -16
  224. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
  225. package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -10
  226. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
  227. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +53 -27
  228. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +16 -2
  229. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
  230. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +124 -43
  231. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +36 -38
  232. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
  233. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +16 -7
  234. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +36 -19
  235. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
  236. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
  237. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -15
  238. package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
  239. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +22 -22
  240. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
  241. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +13 -12
  242. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +23 -23
  243. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
  244. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
  245. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
  246. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
  247. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
  248. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
  249. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +31 -24
  250. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +18 -10
  251. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +137 -86
  252. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +165 -91
  253. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +7 -7
  254. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
  255. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
  256. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +53 -23
  257. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +221 -153
  258. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +161 -96
  259. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
  260. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +48 -33
  261. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
  262. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
  263. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
  264. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +296 -0
  265. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +347 -0
  266. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  267. package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
  268. package/docs/reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md +198 -0
  269. package/docs/reference/decisions.md +9 -4
  270. package/docs/reference/glossary.md +138 -45
  271. package/docs/reference/hooks.md +1077 -0
  272. package/docs/reference/http-api.md +988 -123
  273. package/docs/reference/machines.md +0 -1
  274. package/docs/why.md +7 -5
  275. package/package.json +10 -3
  276. package/src/actor.ts +194 -42
  277. package/src/agent.ts +56 -6
  278. package/src/ambient.ts +3 -5
  279. package/src/assembly-checks.ts +530 -4
  280. package/src/callers.ts +245 -0
  281. package/src/chart.ts +238 -26
  282. package/src/charts.ts +9 -2
  283. package/src/config.ts +566 -7
  284. package/src/conversations.ts +453 -0
  285. package/src/custodian.lua +17 -5
  286. package/src/custodian.ts +257 -77
  287. package/src/customize.ts +154 -7
  288. package/src/dispatch-effect.ts +142 -26
  289. package/src/durability.ts +2 -0
  290. package/src/duration.ts +20 -0
  291. package/src/effect-checks.ts +52 -4
  292. package/src/effect.ts +401 -132
  293. package/src/effector-wire.ts +278 -30
  294. package/src/fail.ts +17 -4
  295. package/src/gate-brand.ts +16 -0
  296. package/src/gate.ts +634 -48
  297. package/src/harness-client.ts +84 -35
  298. package/src/harness-env.ts +33 -0
  299. package/src/held-secrets.ts +197 -39
  300. package/src/holds.ts +5 -2
  301. package/src/hook-kinds/discord.ts +92 -0
  302. package/src/hook-kinds/door.ts +107 -0
  303. package/src/hook-kinds/github.ts +89 -0
  304. package/src/hook-kinds/gitlab.ts +72 -0
  305. package/src/hook-kinds/hook.ts +7 -0
  306. package/src/hook-kinds/index.ts +465 -0
  307. package/src/hook-kinds/slack.ts +151 -0
  308. package/src/hook-kinds/webhook.ts +113 -0
  309. package/src/hooks.ts +506 -0
  310. package/src/http-effect.ts +164 -70
  311. package/src/http.ts +933 -99
  312. package/src/index.ts +30 -5
  313. package/src/instance.ts +196 -26
  314. package/src/internal.ts +23 -3
  315. package/src/kube-client.ts +6 -3
  316. package/src/machine-doc.ts +29 -5
  317. package/src/mcp-effect.ts +424 -0
  318. package/src/model-keys.ts +24 -0
  319. package/src/mount-digest.ts +41 -7
  320. package/src/names.ts +82 -7
  321. package/src/notices.ts +576 -59
  322. package/src/open-body.ts +110 -30
  323. package/src/open-effect.ts +17 -4
  324. package/src/open.ts +40 -7
  325. package/src/parts.ts +125 -35
  326. package/src/party.ts +35 -1
  327. package/src/pick.ts +43 -9
  328. package/src/pool.ts +1172 -172
  329. package/src/registration.ts +249 -17
  330. package/src/repo-identity.ts +7 -3
  331. package/src/repos.ts +20 -2
  332. package/src/run-host.ts +1614 -190
  333. package/src/run-list.ts +191 -0
  334. package/src/sandbox-effect.ts +217 -66
  335. package/src/sandbox-kube.ts +116 -21
  336. package/src/secret-placement.ts +248 -35
  337. package/src/server.ts +53 -4
  338. package/src/setup.ts +158 -38
  339. package/src/snapshot-store.ts +565 -48
  340. package/src/steer.ts +111 -0
  341. package/src/stub-harness.ts +6 -2
  342. package/src/tokens.ts +362 -46
  343. package/src/vocabulary.ts +23 -4
  344. package/src/wire.ts +27 -10
  345. package/src/workspace.ts +314 -259
  346. package/src/worktree.ts +249 -0
  347. package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
  348. package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
  349. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
  350. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +0 -65
package/src/setup.ts CHANGED
@@ -29,6 +29,7 @@ import { randomUUID } from "node:crypto";
29
29
  import {
30
30
  setup,
31
31
  type ActionFunction,
32
+ type ActorLogic,
32
33
  type AnyActorRef,
33
34
  type AnyStateMachine,
34
35
  type DelayConfig,
@@ -39,6 +40,7 @@ import {
39
40
  type NonReducibleUnknown,
40
41
  type ParameterizedObject,
41
42
  type SetupReturn,
43
+ type Snapshot,
42
44
  type UnknownActorLogic,
43
45
  } from "xstate";
44
46
  import type { z } from "zod";
@@ -46,11 +48,13 @@ import { eventMap, type EventDef, type EventFrom, type Sender } from "@jr2/agent
46
48
  import type { AgentRunInput, AgentTurnInput, FaultTelemetry } from "./actor.ts";
47
49
  import { isAgent } from "./agent.ts";
48
50
  import { isEffect } from "./effect.ts";
49
- import { effectChecks } from "./effect-checks.ts";
50
- import { gate } from "./gate.ts";
51
+ import type { AnyFramePath, FramePath, WorktreePath, WorktreeReady } from "./worktree.ts";
52
+ import { effectChecks, refuseUnroutedOutcome } from "./effect-checks.ts";
53
+ import { isGateInvoke } from "./gate-brand.ts";
54
+ import { isGateSlot, plainGate, settlesOnItsOwn, type PlainGate } from "./gate.ts";
51
55
  import { attachLent, isOpenBody, openBodyDeclarationOf, type LentParts } from "./open-body.ts";
52
56
  import { refuseInlineParts } from "./parts.ts";
53
- import { partyWarnings, refuseUnknownSentBy, SENT_BY, sentByGuard } from "./party.ts";
57
+ import { partyWarnings, refuseSlotActiveTwice, refuseUnknownSentBy, SENT_BY, sentByGuard } from "./party.ts";
54
58
  import { refuseLostOutput } from "./run-output.ts";
55
59
  import { refuseUnroutedAgentFault } from "./mechanism-routes.ts";
56
60
  import { boundEpoch, boundRunId, continuedIid } from "./registration.ts";
@@ -109,7 +113,7 @@ type SentByGuards = { [SENT_BY]: { id: string } };
109
113
  /** The jr2 actor every workflow can invoke by name without listing it (ADR-0015). `gate` is the
110
114
  * whole set: an Agent is not pre-registered, because it is not one logic — it is the slot the
111
115
  * Machine declares, `actors: { coder: agent(def) }` (ADR-0049). */
112
- const jr2Actors = { gate };
116
+ const jr2Actors: { gate: PlainGate } = { gate: plainGate };
113
117
  type JR2Actors = typeof jr2Actors;
114
118
 
115
119
  /**
@@ -130,6 +134,74 @@ type ToProvidedActor<TActors extends Record<string, UnknownActorLogic>> = {
130
134
  [K in keyof TActors & string]: { src: K; logic: TActors[K]; id: string | undefined };
131
135
  }[keyof TActors & string];
132
136
 
137
+ // The types below carry the body's Repo Slots to every Worktree input.
138
+ /** @internal */
139
+ type NoHandles = { readonly noHandles: true };
140
+ /** `S`, the slots of the body, or {@link NoHandles} when its input and context hold no handles.
141
+ * @internal */
142
+ type RepoSlotsOf<TInput, TContext> = TInput extends { workspace: { repos: infer R } }
143
+ ? keyof R & string
144
+ : TContext extends { workspace: { repos: infer R } }
145
+ ? keyof R & string
146
+ : NoHandles;
147
+ /** The Worktrees of the slots `S` that this key takes: a `push({ slot })` keeps to its own slot.
148
+ * @internal */
149
+ type PathIn<W, S> = S extends string ? (`/work/${S}/x` extends NonNullable<W> ? WorktreePath<S> : never) : never;
150
+ /** One arm of an input. A key that names a Worktree or a Frame is REQUIRED under a body with Repo
151
+ * Slots, so that no mix of `cwd`, `worktree` and `path` lands in `/work`. Under a body with none,
152
+ * `worktree` goes: there is no Worktree. A Turn's arm that carries no kit path (the run's own form)
153
+ * and every other key stay.
154
+ * @internal */
155
+ type BindArm<I, S> = I extends object
156
+ ? "worktree" extends keyof I
157
+ ? [S] extends [never]
158
+ ? Omit<I, "worktree"> & { worktree?: never }
159
+ : Omit<I, "worktree"> & { worktree: PathIn<I["worktree"], S> }
160
+ : "cwd" extends keyof I
161
+ ? [NonNullable<I["cwd"]>] extends [AnyFramePath]
162
+ ? [S] extends [never]
163
+ ? I
164
+ : Omit<I, "cwd"> & { cwd: FramePath<S & string> }
165
+ : I
166
+ : "path" extends keyof I
167
+ ? [S] extends [never]
168
+ ? I
169
+ : Omit<I, "path"> & { path: PathIn<I["path"], S> }
170
+ : I
171
+ : I;
172
+ /** Does this input name a Worktree? @internal */
173
+ type NamesWorktree<I> = I extends object ? ("worktree" extends keyof I ? true : never) : never;
174
+ /** @internal */
175
+ type BindInput<I, S> = [NamesWorktree<I>] extends [never]
176
+ ? BindArm<I, S>
177
+ : [S] extends [never]
178
+ ? BindArm<I, S>
179
+ : Exclude<BindArm<I, S>, void | undefined>;
180
+ /** A cut's `ready` output with the body's slots. @internal */
181
+ type BindOutput<O, S> = O extends WorktreeReady ? WorktreeReady<S & string> : O;
182
+ /** @internal */
183
+ type BindSnapshot<Snap, S> = Snap extends { output: infer O }
184
+ ? [O] extends [BindOutput<O, S>]
185
+ ? Snap
186
+ : Omit<Snap, "output"> & { output: BindOutput<O, S> }
187
+ : Snap;
188
+ /** @internal */
189
+ type BindLogic<L extends UnknownActorLogic, S> = L extends AnyStateMachine
190
+ ? L
191
+ : ([S] extends [never] ? false : [S] extends [NoHandles] ? true : false) extends true
192
+ ? L
193
+ : L extends { readonly definition: { readonly workspace: "none" } }
194
+ ? L
195
+ : L extends ActorLogic<infer Snap, infer Ev, infer I, infer Sys, infer Em>
196
+ ? BindSnapshot<Snap, S> extends infer B extends Snapshot<unknown>
197
+ ? Omit<L, keyof ActorLogic<Snap, Ev, I, Sys, Em>> & ActorLogic<B, Ev, BindInput<I, S>, any, Em>
198
+ : never
199
+ : L;
200
+ /** @internal */
201
+ type BindActors<A extends Record<string, UnknownActorLogic>, TInput, TContext> = {
202
+ [K in keyof A]: BindLogic<A[K], RepoSlotsOf<TInput, TContext>>;
203
+ };
204
+
133
205
  /**
134
206
  * Set up a Machine that takes workflow events: the jr2 form of xstate's `setup()`. Write a Machine
135
207
  * with it when an Agent or a Gate sends events into the Machine, or when the Machine declares a
@@ -141,7 +213,9 @@ type ToProvidedActor<TActors extends Record<string, UnknownActorLogic>> = {
141
213
  * `defineEvent` events you list, plus the events jr2 itself sends (`agent.fault`,
142
214
  * `workspace.lost`). An event that a party sent has `event.sender`. A Machine that takes no
143
215
  * workflow event leaves out `events`.
144
- * - The `gate` actor is ready to invoke by name: `invoke: { src: "gate" }`.
216
+ * - The `gate` actor is ready to invoke by name: `invoke: { src: "gate" }`. A Gate slot that hears a
217
+ * Hook (`actors: { review: gate({ … }) }`) is invoked by its key. An event in its `delivers` whose
218
+ * def leaves `audience` unset is `audience: "external"` in this Machine.
145
219
  * - Each Agent slot (`actors: { coder: agent(…) }`) gets its Menu from the states that invoke it.
146
220
  * - The `sentBy(id)` guard is ready to use.
147
221
  * - `createMachine` also takes `input`: a zod object for the input that starts a run. jr2 checks
@@ -198,6 +272,13 @@ type ToProvidedActor<TActors extends Record<string, UnknownActorLogic>> = {
198
272
  * run an Agent`: the body sends it a Chart's unrouted `agent.fault`. When both kinds have no route,
199
273
  * one line names both, joined by `, and`. One route on the root is a route for each state. A
200
274
  * Chart's Machine does not get this refusal: in a Chart the route is optional (ADR-0070).
275
+ * - an event in a Gate slot's `delivers` that `events` does not list: ``machine "<id>": Gate slot
276
+ * "<slot>" delivers "<name>", which no def in jr2Setup({ events }) declares (declared: <names>) —
277
+ * list it in events (ADR-0011)``
278
+ * - an event in a Gate slot's `delivers` that the Gate does not accept at a state that invokes it:
279
+ * ``machine "<id>": state "<state>" invokes Gate slot "<slot>", which delivers "<name>", and its
280
+ * Gate does not accept it (accepts: <names>) — no handler or look could deliver it: handle it on
281
+ * that state, a state above it or a plain child, or drop it from delivers (ADR-0011)``
201
282
  *
202
283
  * It also refuses a `sentBy` that names no party (see `sentBy`). It refuses a pick param that
203
284
  * nothing reads, where the pick enters a state that invokes an Effect (see `fromPick`). Shapes that
@@ -287,7 +368,8 @@ export function jr2Setup<
287
368
  * listed, if it is not a jr2 or xstate event (an event with a `.` in its name). */
288
369
  events?: TDefs;
289
370
  /** The actors the states invoke by name, as in `setup()`: Agent slots (`agent(…)`), Effects
290
- * (`command(…)`, `http(…)`, `push(…)`), child Machines, `workspace(…)` and plain xstate logic.
371
+ * (`command(…)`, `http(…)`, `push(…)`), Gate slots (`gate({ … })`), child Machines, `workspace(…)`
372
+ * and plain xstate logic.
291
373
  * The key is the slot's name. An actor named `gate` replaces jr2's Gate. */
292
374
  actors?: TActors;
293
375
  /** Named actions, as in `setup()`. Their `event` has the type of this Machine's events. */
@@ -321,7 +403,7 @@ export function jr2Setup<
321
403
  ): SetupReturn<
322
404
  TContext,
323
405
  WorkflowEvent<TDefs>,
324
- MergedActors<TActors>,
406
+ MergedActors<BindActors<TActors, TInput, TContext>>,
325
407
  {},
326
408
  TActions,
327
409
  TGuards & SentByGuards,
@@ -358,6 +440,10 @@ export function jr2Setup<
358
440
  // Resolve the defs first (duplicates and reserved semantics fail HERE, naming the machine —
359
441
  // the same loud failure `eventMap` gave the manifest, moved to machine-build time)…
360
442
  const defs = eventMap((machineConfig as { id?: string }).id ?? "(machine)", def.events ?? []);
443
+ // A Gate slot's `delivers` (ADR-0011, ADR-0015): each name is one of this Machine's events, and
444
+ // one whose def leaves the audience unset reads as `external`, so no Agent has a Hook's event on
445
+ // its Menu. Before the Menus derive, so the walk, the Menu and the runtime read one vocabulary.
446
+ externalDelivers((machineConfig as { id?: string }).id ?? "(machine)", defs, def.actors ?? {});
361
447
 
362
448
  // Every Open body slot (ADR-0070), found by its brand: each name it lends resolves against THIS
363
449
  // setup's own parts, or the Machine is refused naming it. The resolved set is stamped on the slot,
@@ -370,6 +456,12 @@ export function jr2Setup<
370
456
  // ADR-0007 restore path and invoke-time `resolveAccepts` validation are unchanged.
371
457
  const derived = deriveMenus(machineConfig, defs, def.actors ?? {});
372
458
  const machine = (inner.createMachine as unknown as (c: never) => AnyStateMachine)(derived.config as never);
459
+ // A Gate slot's event that its state's Gate does not accept (ADR-0011): no handler or look could
460
+ // ever deliver it.
461
+ if (derived.refused.length) {
462
+ const idOf = (path: readonly string[]): string => stateAt(machine, path).id;
463
+ throw new Error(`machine "${machine.id}": ${derived.refused.map((r) => r(idOf)).join("; ")}`);
464
+ }
373
465
 
374
466
  // Close the nested-`on` typo hole (ADR-0015): with the manifest dead, a typo'd key would
375
467
  // silently become vocabulary — so every non-dotted key the machine handles anywhere must map
@@ -411,13 +503,20 @@ export function jr2Setup<
411
503
  // (ADR-0074): the run would wait for ever. Not in a compiled Chart: there the route is optional,
412
504
  // and the Open body sends the event that no transition takes to the Machine that invoked it (ADR-0070).
413
505
  if (compiledChart !== true) refuseUnroutedAgentFault(machine);
506
+ // An Effect's `onDone` with no last arm that always matches (ADR-0075): the run would stay in the
507
+ // state and show no fault. A compiled Chart comes here too, so the door refuses it.
508
+ refuseUnroutedOutcome(machine);
414
509
  refuseParallelBelowAgents(machine, def.actors ?? {});
510
+ // One slot, two Turns at once (ADR-0015): one sender and one conversation cannot hold both.
511
+ refuseSlotActiveTwice(machine);
415
512
  refuseUnknownSentBy(machine);
416
513
  // Before the Effect checks: they ask who may send a writing (`mayTake`), which reads its audience.
417
514
  attachVocabulary(machine, defs);
418
515
  // The Effect checks (ADR-0067): a pick param nothing reads, a `fill` that overwrites one, a
419
516
  // `fromPick` of another pick — refused; a mapper the probe cannot run — warned.
420
- const effects = effectChecks(machine, def.actors ?? {}, defs);
517
+ // A Chart's door reads each reference itself (rule 7), and it refuses every load warning: the
518
+ // walk's "I could not run this" says nothing of a Chart's `{{...}}` mapper or its `set`.
519
+ const effects = effectChecks(machine, def.actors ?? {}, defs, compiledChart === true);
421
520
  if (effects.errors.length) throw new Error(`machine "${machine.id}": ${effects.errors.join("; ")}`);
422
521
 
423
522
  const idOf = (path: readonly string[]): string => stateAt(machine, path).id;
@@ -441,7 +540,7 @@ export function jr2Setup<
441
540
  return { ...inner, createMachine } as unknown as SetupReturn<
442
541
  TContext,
443
542
  WorkflowEvent<TDefs>,
444
- MergedActors<TActors>,
543
+ MergedActors<BindActors<TActors, TInput, TContext>>,
445
544
  {},
446
545
  TActions,
447
546
  TGuards & SentByGuards,
@@ -525,7 +624,7 @@ function deriveMenus(
525
624
  config: unknown,
526
625
  defs: Map<string, EventDef>,
527
626
  actors: Record<string, UnknownActorLogic>,
528
- ): { config: unknown; seats: Seat[]; warnings: Warning[]; derivedGateIds: Set<string> } {
627
+ ): { config: unknown; seats: Seat[]; warnings: Warning[]; derivedGateIds: Set<string>; refused: Warning[] } {
529
628
  const pick = (reach: Reach, kind: "agent" | "external", self: string): string[] =>
530
629
  [...reach]
531
630
  .filter(([name, owners]) => {
@@ -545,6 +644,8 @@ function deriveMenus(
545
644
  const parties = new Map<string, { agents: string[]; gate: boolean }>();
546
645
  // The Gate invoke ids this walk names: a party warning says how to name one instead.
547
646
  const derivedGateIds = new Set<string>();
647
+ // A Gate slot's `delivers` that its state's Gate does not accept (ADR-0011): refusals.
648
+ const refused: Warning[] = [];
548
649
 
549
650
  const walk = (
550
651
  node: LooseState,
@@ -567,7 +668,7 @@ function deriveMenus(
567
668
  const invokes = Array.isArray(node.invoke) ? node.invoke : [node.invoke];
568
669
  // >1 unnamed gate in one state would collide on the state-key id; suffix ONLY then, so
569
670
  // the common case (one gate per state) keeps the clean name.
570
- const unnamedGates = invokes.filter((inv) => inv?.src === "gate" && inv.id == null).length;
671
+ const unnamedGates = invokes.filter((inv) => isGateInvoke(inv, actors) && inv.id == null).length;
571
672
  let ordinal = 0;
572
673
  const wrapOne = (inv: LooseInvoke): LooseInvoke => {
573
674
  // The slot key IS the Agent name (ADR-0049) — read off the declaration, never authored.
@@ -600,7 +701,7 @@ function deriveMenus(
600
701
  seats.push({ path, party: "agent", agent: inv.src, names: [...derived].sort() });
601
702
  return { ...inv, input: wrapAgentInput(inv.input, derived, inv.src, menuOf) };
602
703
  }
603
- if (inv?.src === "gate") {
704
+ if (isGateInvoke(inv, actors)) {
604
705
  // A Gate's plain children — below it, with no party-invoking state between — are its own
605
706
  // by position, as an Agent's modes are its (ADR-0015).
606
707
  const reach: Reach = new Map([...names].map(([name, owners]) => [name, new Set(owners)]));
@@ -608,6 +709,20 @@ function deriveMenus(
608
709
  reach.set(name, (reach.get(name) ?? new Set<string>()).add(owner));
609
710
  const accepts = pick(reach, "external", owner);
610
711
  seats.push({ path, party: "gate", names: [...accepts].sort() });
712
+ const slot = typeof inv.src === "string" ? actors[inv.src] : undefined;
713
+ if (isGateSlot(slot)) {
714
+ const outside = slot.gateSlot.delivers.map((d) => d.name).filter((name) => !accepts.includes(name));
715
+ if (outside.length) {
716
+ const name = inv.src as string;
717
+ refused.push(
718
+ (idOf) =>
719
+ `state "${idOf(path)}" invokes Gate slot "${name}", which delivers ${outside.map((n) => `"${n}"`).join(", ")}, ` +
720
+ `and its Gate does not accept ${outside.length > 1 ? "them" : "it"} (accepts: ${accepts.join(", ") || "nothing"}) — ` +
721
+ "no handler or look could deliver it: handle it on that state, a state above it or a plain child, " +
722
+ "or drop it from delivers (ADR-0011)",
723
+ );
724
+ }
725
+ }
611
726
  const wrapped: LooseInvoke = { ...inv, input: wrapGateInput(inv.input, accepts) };
612
727
  // A machine-root gate (empty path) is left to xstate's default id: a `""` id would be
613
728
  // worse than a noisy one, and the derived gate id still works.
@@ -632,7 +747,7 @@ function deriveMenus(
632
747
  };
633
748
 
634
749
  const out = walk(config as LooseState, new Map(), new Map(), [], NOBODY);
635
- return { config: out, seats, warnings: [...warnings.values()], derivedGateIds };
750
+ return { config: out, seats, warnings: [...warnings.values()], derivedGateIds, refused };
636
751
  }
637
752
 
638
753
  /**
@@ -767,7 +882,7 @@ function unenteredModes(machine: AnyStateMachine, actors: Record<string, Unknown
767
882
  continue;
768
883
  }
769
884
  const party = child.invoke.some(
770
- (inv) => inv.src === "gate" || (typeof inv.src === "string" && isAgent(actors[inv.src])),
885
+ (inv) => isGateInvoke(inv, actors) || (typeof inv.src === "string" && isAgent(actors[inv.src])),
771
886
  );
772
887
  if (!party) descend(child);
773
888
  continue;
@@ -790,27 +905,6 @@ function unenteredModes(machine: AnyStateMachine, actors: Record<string, Unknown
790
905
  return out;
791
906
  }
792
907
 
793
- /**
794
- * Does this logic settle on its own — a promise, the one plain xstate actor that ends without being
795
- * stopped? Asked of its own transition: a promise logic's initial snapshot, sent xstate's resolve
796
- * event, is `done`. That event name is an xstate internal (5.32.2); a bump that renamed it would
797
- * make every promise read long-lived, and setup.test.ts pins it against the real constructors.
798
- */
799
- function settlesOnItsOwn(logic: unknown): boolean {
800
- const l = logic as {
801
- getInitialSnapshot?: (scope: unknown, input: unknown) => unknown;
802
- transition?: (snapshot: unknown, event: unknown, scope: unknown) => { status?: string } | undefined;
803
- };
804
- if (typeof l?.getInitialSnapshot !== "function" || typeof l.transition !== "function") return false;
805
- try {
806
- const scope = { self: {}, defer: () => {}, emit: () => {} };
807
- const snapshot = l.getInitialSnapshot(scope, undefined);
808
- return l.transition(snapshot, { type: "xstate.promise.resolve", data: undefined }, scope)?.status === "done";
809
- } catch {
810
- return false;
811
- }
812
- }
813
-
814
908
  /**
815
909
  * The load walk's Rest warnings (ADR-0024): shapes below an Agent's state that keep it from Rest, so
816
910
  * every pick of the Agent is refused for longer than the author likely meant. Warnings, never
@@ -840,7 +934,7 @@ function restWarnings(machine: AnyStateMachine, actors: Record<string, UnknownAc
840
934
  for (const inv of child.invoke) {
841
935
  const logic = logicOf(inv.src);
842
936
  const name = typeof inv.src === "string" ? inv.src : inv.id;
843
- if (inv.src === "gate") {
937
+ if (isGateInvoke(inv, actors)) {
844
938
  for (const [event, candidates] of child.transitions) {
845
939
  if (event.includes(".") || event === "*") continue;
846
940
  if (candidates.some((t) => (t.target ?? []).length > 0)) continue;
@@ -904,6 +998,7 @@ function stampOpenBodies(
904
998
  ["agents", "an Agent slot (agent(...))", isAgent],
905
999
  ["effects", "an Effect slot", isEffect],
906
1000
  ["machines", "a Machine", (l: unknown) => (l as { root?: unknown } | undefined)?.root !== undefined],
1001
+ ["gates", "a Gate slot (gate({ … }))", isGateSlot],
907
1002
  ] as const;
908
1003
  for (const [kind, what, test] of actorKinds) {
909
1004
  for (const name of decl.lends[kind] ?? []) {
@@ -974,6 +1069,29 @@ function stateAt(machine: AnyStateMachine, path: readonly string[]): AnyStateMac
974
1069
  return node;
975
1070
  }
976
1071
 
1072
+ /**
1073
+ * The `delivers` of each Gate slot this setup declares (ADR-0011, ADR-0015). Each name must be an
1074
+ * event of the Machine: a handler or a look gives a plain event, which the Machine's own def parses.
1075
+ * An event whose def leaves the audience unset reads as `audience: "external"` in this Machine's
1076
+ * vocabulary, so no Agent of the Machine has it on its Menu, and the author does not have to know
1077
+ * this. An explicit audience stays.
1078
+ */
1079
+ function externalDelivers(machineId: string, defs: Map<string, EventDef>, actors: Record<string, unknown>): void {
1080
+ for (const [slot, logic] of Object.entries(actors)) {
1081
+ if (!isGateSlot(logic)) continue;
1082
+ for (const d of logic.gateSlot.delivers) {
1083
+ const own = defs.get(d.name);
1084
+ if (!own) {
1085
+ throw new Error(
1086
+ `machine "${machineId}": Gate slot "${slot}" delivers "${d.name}", which no def in jr2Setup({ events }) ` +
1087
+ `declares (declared: ${[...defs.keys()].join(", ") || "none"}) — list it in events (ADR-0011)`,
1088
+ );
1089
+ }
1090
+ if (own.audience === undefined) defs.set(d.name, Object.freeze({ ...own, audience: "external" as const }));
1091
+ }
1092
+ }
1093
+ }
1094
+
977
1095
  /** A state's own workflow-event keys: dotted names are jr2's or xstate's, `*` is the wildcard. */
978
1096
  function ownPicks(node: LooseState): string[] {
979
1097
  return Object.keys(node.on ?? {}).filter((key) => !key.includes(".") && key !== "*");
@@ -984,7 +1102,7 @@ function partiesOf(node: LooseState, actors: Record<string, UnknownActorLogic>):
984
1102
  const invokes = node.invoke ? (Array.isArray(node.invoke) ? node.invoke : [node.invoke]) : [];
985
1103
  return {
986
1104
  agents: invokes.flatMap((inv) => (typeof inv?.src === "string" && isAgent(actors[inv.src]) ? [inv.src] : [])),
987
- gate: invokes.some((inv) => inv?.src === "gate"),
1105
+ gate: invokes.some((inv) => isGateInvoke(inv, actors)),
988
1106
  };
989
1107
  }
990
1108
 
@@ -1066,7 +1184,7 @@ function refuseUnknownKeys(consumer: object, agentName: string): void {
1066
1184
  /** Wrap an Agent slot's invoke input: name the Agent (the slot key), append the state's derived set
1067
1185
  * and the Agent's Menu, and finalize the mechanism fields. */
1068
1186
  function wrapAgentInput(orig: unknown, derived: string[], agentName: string, menuOf: (agentName: string) => string[]) {
1069
- return (args: InputArgs): AgentRunInput => {
1187
+ const wrapped = (args: InputArgs): AgentRunInput => {
1070
1188
  const consumer = resolveInput(orig, args) as Partial<AgentTurnInput & AgentRunInput>;
1071
1189
  refuseUnknownKeys(consumer, agentName);
1072
1190
  return {
@@ -1097,6 +1215,8 @@ function wrapAgentInput(orig: unknown, derived: string[], agentName: string, men
1097
1215
  menu: menuOf(agentName),
1098
1216
  };
1099
1217
  };
1218
+ // The walk reads what the author wrote: `workspace()`, for a literal `cwd`.
1219
+ return Object.assign(wrapped, { consumerInput: orig });
1100
1220
  }
1101
1221
 
1102
1222
  /** Wrap a gate invoke input: append the derived accepted set. */