@jr2/orchestrator 0.4.1 → 0.6.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.
- package/README.md +20 -2
- package/console/components/app.ts +2 -0
- package/console/components/fleet.ts +14 -1
- package/console/components/machine-pane.ts +41 -2
- package/console/main.ts +13 -1
- package/console/store.ts +102 -6
- package/console/style.css +21 -0
- package/docs/agents-block.md +5 -0
- package/docs/concepts/agents-and-turns.md +478 -0
- package/docs/concepts/architecture.md +243 -0
- package/docs/concepts/charts.md +146 -0
- package/docs/concepts/composition.md +357 -0
- package/docs/concepts/converge.md +257 -0
- package/docs/concepts/durable-runs.md +189 -0
- package/docs/concepts/effects.md +658 -0
- package/docs/concepts/gates.md +208 -0
- package/docs/concepts/machines-and-workflows.md +298 -0
- package/docs/concepts/pools-and-sources.md +230 -0
- package/docs/concepts/secrets-and-trust.md +306 -0
- package/docs/concepts/the-menu.md +381 -0
- package/docs/concepts/workspaces.md +756 -0
- package/docs/get-started/a-model-decides.md +563 -0
- package/docs/get-started/an-agent-in-a-sandbox.md +383 -0
- package/docs/get-started/connect-a-model.md +248 -0
- package/docs/get-started/create-an-instance.md +194 -0
- package/docs/get-started/have-your-assistant-write-a-machine.md +993 -0
- package/docs/get-started/install.md +130 -0
- package/docs/guides/add-tools-to-the-sandbox.md +308 -0
- package/docs/guides/answer-a-gate.md +304 -0
- package/docs/guides/bind-open-parts.md +224 -0
- package/docs/guides/cancel-a-run.md +146 -0
- package/docs/guides/clean-up.md +206 -0
- package/docs/guides/cut-a-worktree.md +560 -0
- package/docs/guides/fix-a-failed-converge.md +361 -0
- package/docs/guides/give-the-cluster-git-credentials.md +222 -0
- package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
- package/docs/guides/let-an-agent-write-a-chart.md +230 -0
- package/docs/guides/look-inside-a-sandbox.md +177 -0
- package/docs/guides/mirror-the-kit-images.md +176 -0
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +318 -0
- package/docs/guides/open-the-console.md +91 -0
- package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
- package/docs/guides/push-and-sign-a-branch.md +532 -0
- package/docs/guides/run-a-chart-by-name.md +270 -0
- package/docs/guides/run-a-command-or-call-a-url.md +587 -0
- package/docs/guides/run-one-worker-per-item.md +322 -0
- package/docs/guides/set-an-agents-access-and-dials.md +420 -0
- package/docs/guides/size-a-workspace.md +217 -0
- package/docs/guides/start-a-run-from-a-run.md +237 -0
- package/docs/guides/start-a-run.md +207 -0
- package/docs/guides/upgrade-the-kit-version.md +240 -0
- package/docs/guides/use-a-hosted-provider.md +214 -0
- package/docs/guides/use-a-local-model.md +313 -0
- package/docs/guides/watch-a-run.md +349 -0
- package/docs/guides/write-a-workflow.md +318 -0
- package/docs/index.md +44 -0
- package/docs/llms.txt +237 -0
- package/docs/reference/authoring-surface/agent.md +151 -0
- package/docs/reference/authoring-surface/answer.md +156 -0
- package/docs/reference/authoring-surface/arg.md +82 -0
- package/docs/reference/authoring-surface/basic.md +62 -0
- package/docs/reference/authoring-surface/bearer.md +53 -0
- package/docs/reference/authoring-surface/branchname.md +15 -0
- package/docs/reference/authoring-surface/chartschema.md +23 -0
- package/docs/reference/authoring-surface/chartschemafor.md +48 -0
- package/docs/reference/authoring-surface/command.md +206 -0
- package/docs/reference/authoring-surface/customize.md +64 -0
- package/docs/reference/authoring-surface/defineconfig.md +41 -0
- package/docs/reference/authoring-surface/defineevent.md +114 -0
- package/docs/reference/authoring-surface/dispatch.md +126 -0
- package/docs/reference/authoring-surface/fail.md +96 -0
- package/docs/reference/authoring-surface/file.md +142 -0
- package/docs/reference/authoring-surface/frompick.md +277 -0
- package/docs/reference/authoring-surface/http.md +259 -0
- package/docs/reference/authoring-surface/isfailure.md +58 -0
- package/docs/reference/authoring-surface/isready.md +14 -0
- package/docs/reference/authoring-surface/jr2setup.md +237 -0
- package/docs/reference/authoring-surface/open.md +105 -0
- package/docs/reference/authoring-surface/openbody.md +86 -0
- package/docs/reference/authoring-surface/paramsof.md +143 -0
- package/docs/reference/authoring-surface/pool.md +186 -0
- package/docs/reference/authoring-surface/push.md +130 -0
- package/docs/reference/authoring-surface/readyof.md +21 -0
- package/docs/reference/authoring-surface/secret.md +139 -0
- package/docs/reference/authoring-surface/sentby.md +83 -0
- package/docs/reference/authoring-surface/source.md +51 -0
- package/docs/reference/authoring-surface/text.md +62 -0
- package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
- package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
- package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
- package/docs/reference/authoring-surface/type-agentslots.md +15 -0
- package/docs/reference/authoring-surface/type-answeraction.md +12 -0
- package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
- package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
- package/docs/reference/authoring-surface/type-arg.md +19 -0
- package/docs/reference/authoring-surface/type-argnames.md +12 -0
- package/docs/reference/authoring-surface/type-bindactors.md +14 -0
- package/docs/reference/authoring-surface/type-binding.md +61 -0
- package/docs/reference/authoring-surface/type-bindingof.md +12 -0
- package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
- package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
- package/docs/reference/authoring-surface/type-ceilings.md +41 -0
- package/docs/reference/authoring-surface/type-chainlink.md +19 -0
- package/docs/reference/authoring-surface/type-chartaction.md +46 -0
- package/docs/reference/authoring-surface/type-chartagent.md +28 -0
- package/docs/reference/authoring-surface/type-chartevent.md +20 -0
- package/docs/reference/authoring-surface/type-chartguard.md +20 -0
- package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
- package/docs/reference/authoring-surface/type-chartjson.md +14 -0
- package/docs/reference/authoring-surface/type-chartstate.md +46 -0
- package/docs/reference/authoring-surface/type-charttext.md +40 -0
- package/docs/reference/authoring-surface/type-charttransition.md +22 -0
- package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
- package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
- package/docs/reference/authoring-surface/type-childat.md +12 -0
- package/docs/reference/authoring-surface/type-childslots.md +12 -0
- package/docs/reference/authoring-surface/type-commandenv.md +15 -0
- package/docs/reference/authoring-surface/type-commandinput.md +20 -0
- package/docs/reference/authoring-surface/type-commandoptions.md +56 -0
- package/docs/reference/authoring-surface/type-commandoutput.md +122 -0
- package/docs/reference/authoring-surface/type-customize.md +111 -0
- package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
- package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
- package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
- package/docs/reference/authoring-surface/type-dispatchoutput.md +72 -0
- package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
- package/docs/reference/authoring-surface/type-duration.md +15 -0
- package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
- package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
- package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
- package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
- package/docs/reference/authoring-surface/type-eventdef.md +45 -0
- package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
- package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
- package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
- package/docs/reference/authoring-surface/type-failslot.md +14 -0
- package/docs/reference/authoring-surface/type-failure.md +19 -0
- package/docs/reference/authoring-surface/type-failureinput.md +20 -0
- package/docs/reference/authoring-surface/type-filebody.md +37 -0
- package/docs/reference/authoring-surface/type-framepath.md +14 -0
- package/docs/reference/authoring-surface/type-frominput.md +14 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +56 -0
- package/docs/reference/authoring-surface/type-httpdefinition.md +104 -0
- package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
- package/docs/reference/authoring-surface/type-httpinput.md +12 -0
- package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
- package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
- package/docs/reference/authoring-surface/type-httpoutput.md +95 -0
- package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
- package/docs/reference/authoring-surface/type-jr2config.md +126 -0
- package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
- package/docs/reference/authoring-surface/type-lends.md +38 -0
- package/docs/reference/authoring-surface/type-logicat.md +12 -0
- package/docs/reference/authoring-surface/type-markedif.md +12 -0
- package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
- package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
- package/docs/reference/authoring-surface/type-namestart.md +77 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +27 -0
- package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
- package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
- package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
- package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
- package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
- package/docs/reference/authoring-surface/type-opencommandinput.md +22 -0
- package/docs/reference/authoring-surface/type-openeffect.md +12 -0
- package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
- package/docs/reference/authoring-surface/type-openof.md +12 -0
- package/docs/reference/authoring-surface/type-opensecret.md +23 -0
- package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
- package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +26 -0
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +27 -0
- package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
- package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
- package/docs/reference/authoring-surface/type-poolspec.md +60 -0
- package/docs/reference/authoring-surface/type-pushinput.md +34 -0
- package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
- package/docs/reference/authoring-surface/type-pushoutput.md +149 -0
- package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
- package/docs/reference/authoring-surface/type-quantity.md +14 -0
- package/docs/reference/authoring-surface/type-reached.md +12 -0
- package/docs/reference/authoring-surface/type-reposlot.md +70 -0
- package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
- package/docs/reference/authoring-surface/type-sandboxoptions.md +84 -0
- package/docs/reference/authoring-surface/type-secret.md +25 -0
- package/docs/reference/authoring-surface/type-sender.md +19 -0
- package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
- package/docs/reference/authoring-surface/type-size.md +85 -0
- package/docs/reference/authoring-surface/type-slothandles.md +24 -0
- package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
- package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
- package/docs/reference/authoring-surface/type-syncstate.md +12 -0
- package/docs/reference/authoring-surface/type-text.md +19 -0
- package/docs/reference/authoring-surface/type-textpart.md +24 -0
- package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
- package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
- package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
- package/docs/reference/authoring-surface/type-unknown.md +21 -0
- package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
- package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
- package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
- package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
- package/docs/reference/authoring-surface/type-workspaced.md +115 -0
- package/docs/reference/authoring-surface/type-workspacehandles.md +22 -0
- package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
- package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
- package/docs/reference/authoring-surface/type-workspaceoptions.md +27 -0
- package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
- package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
- package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
- package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
- package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
- package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
- package/docs/reference/authoring-surface/workspace.md +287 -0
- package/docs/reference/authoring-surface/worktree.md +71 -0
- package/docs/reference/authoring-surface.md +217 -0
- package/docs/reference/cli.md +433 -0
- package/docs/reference/config.md +765 -0
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +114 -0
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +117 -0
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +130 -0
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +240 -0
- package/docs/reference/decisions/0006-agent-control-surface.md +50 -0
- package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
- package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
- package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
- package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
- package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +175 -0
- package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +271 -0
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +126 -0
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +71 -0
- package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +287 -0
- package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +101 -0
- package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +175 -0
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +436 -0
- package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
- package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +245 -0
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +90 -0
- package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
- package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +193 -0
- package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +126 -0
- package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
- package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
- package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
- package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
- package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
- package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
- package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
- package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
- package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
- package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
- package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
- package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
- package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
- package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +238 -0
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +86 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +123 -0
- package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
- package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
- package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +108 -0
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +427 -0
- package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
- package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +239 -0
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +82 -0
- package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
- package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +552 -0
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +458 -0
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +475 -0
- package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +334 -0
- package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
- package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
- package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
- package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
- package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
- package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
- package/docs/reference/decisions.md +86 -0
- package/docs/reference/glossary.md +687 -0
- package/docs/reference/http-api.md +1386 -0
- package/docs/reference/machines.md +189 -0
- package/docs/reference/mechanism-events.md +72 -0
- package/docs/why.md +207 -0
- package/package.json +5 -3
- package/src/actor.ts +694 -106
- package/src/agent.ts +114 -38
- package/src/ambient.ts +3 -4
- package/src/assembly-checks.ts +189 -7
- package/src/cause.ts +234 -0
- package/src/chart.ts +345 -46
- package/src/charts.ts +43 -8
- package/src/config.ts +440 -178
- package/src/custodian.lua +17 -5
- package/src/custodian.ts +325 -99
- package/src/customize.ts +199 -49
- package/src/dispatch-effect.ts +945 -0
- package/src/door-compat.ts +217 -0
- package/src/durability.ts +11 -4
- package/src/effect-checks.ts +50 -3
- package/src/effect.ts +641 -128
- package/src/effector-wire.ts +165 -13
- package/src/fail.ts +222 -0
- package/src/harness-client.ts +587 -50
- package/src/harness-env.ts +33 -0
- package/src/held-secrets.ts +125 -16
- package/src/holds.ts +3 -0
- package/src/http-effect.ts +556 -58
- package/src/http.ts +480 -30
- package/src/index.ts +74 -82
- package/src/instance.ts +68 -8
- package/src/internal.ts +85 -0
- package/src/kube-client.ts +6 -3
- package/src/machine-doc.ts +24 -7
- package/src/mechanism-routes.ts +168 -0
- package/src/model-keys.generated.ts +53 -0
- package/src/model-keys.ts +42 -58
- package/src/names.ts +19 -6
- package/src/notices.ts +483 -41
- package/src/open-body.ts +242 -40
- package/src/open-effect.ts +81 -8
- package/src/open.ts +90 -6
- package/src/parts.ts +213 -30
- package/src/party.ts +101 -2
- package/src/pick.ts +497 -11
- package/src/pool.ts +282 -50
- package/src/registration.ts +133 -12
- package/src/repo-identity.ts +7 -3
- package/src/repos.ts +22 -3
- package/src/run-host.ts +665 -45
- package/src/run-output.ts +38 -0
- package/src/sandbox-effect.ts +457 -71
- package/src/sandbox-kube.ts +66 -17
- package/src/secret-placement.ts +59 -17
- package/src/server.ts +3 -0
- package/src/setup.ts +325 -62
- package/src/size.ts +121 -9
- package/src/snapshot-store.ts +54 -10
- package/src/stub-harness.ts +44 -16
- package/src/timers.ts +14 -1
- package/src/tokens.ts +107 -32
- package/src/vocabulary.ts +88 -14
- package/src/wire.ts +100 -26
- package/src/workspace.ts +771 -238
- package/src/worktree.ts +249 -0
package/src/open.ts
CHANGED
|
@@ -5,13 +5,97 @@
|
|
|
5
5
|
// and a `workspace()`'s Repo Slots (parts.ts, which already imports agent.ts). A module with
|
|
6
6
|
// nothing but the sentinel in it is what lets both import it and neither import the other.
|
|
7
7
|
|
|
8
|
+
// `Symbol.for`, so an Instance's own copy of this module and the CLI's walk agree on it — a
|
|
9
|
+
// packaged Machine may be built against one and walked by the other.
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* package cannot know
|
|
12
|
-
*
|
|
11
|
+
* Leave a part of a Machine Open: for the Instance that registers the Machine to bind with
|
|
12
|
+
* `customize()`. Write it where a value goes, in a Machine that you publish as a package, for a
|
|
13
|
+
* part that the package cannot know or pay for:
|
|
14
|
+
* - a Repo Slot: `repos: { app: open }`, or the whole map: `repos: open`;
|
|
15
|
+
* - an Agent's model: `agent({ model: open, … })`;
|
|
16
|
+
* - an Effect's url or argv: `http({ url: open, … })`, `command(open)`;
|
|
17
|
+
* - the secret of an Effect's auth, of a header, or of a command's `env`: `secret(open)`.
|
|
13
18
|
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
19
|
+
* `jr2 up` refuses a Workflow with an Open part that nobody bound, and prints the `customize()`
|
|
20
|
+
* line that binds it: ``refusing: workflow "<name>" leaves <part> open — bind it where the Machine
|
|
21
|
+
* is registered: export const machine = customize(<import>, …) (<adr>)``. A run never sees an
|
|
22
|
+
* Open part.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { z } from "zod";
|
|
27
|
+
* import {
|
|
28
|
+
* agent,
|
|
29
|
+
* customize,
|
|
30
|
+
* defineEvent,
|
|
31
|
+
* fail,
|
|
32
|
+
* isReady,
|
|
33
|
+
* jr2Setup,
|
|
34
|
+
* open,
|
|
35
|
+
* workspace,
|
|
36
|
+
* worktree,
|
|
37
|
+
* type Workspaced,
|
|
38
|
+
* } from "@jr2/orchestrator";
|
|
39
|
+
*
|
|
40
|
+
* const finish = defineEvent({
|
|
41
|
+
* name: "finish",
|
|
42
|
+
* description: "Call this when `node --test` passes.",
|
|
43
|
+
* input: z.object({}),
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* type Input = Workspaced<{}, "app">;
|
|
47
|
+
*
|
|
48
|
+
* const fixTree = (context: Input) => `${context.workspace.repos.app}/fix` as const;
|
|
49
|
+
*
|
|
50
|
+
* const body = jr2Setup({
|
|
51
|
+
* types: {} as { context: Input; input: Input },
|
|
52
|
+
* events: [finish],
|
|
53
|
+
* actors: {
|
|
54
|
+
* coder: agent({ model: open, instructions: "You fix the failing test." }),
|
|
55
|
+
* cut: worktree(),
|
|
56
|
+
* fail: fail(),
|
|
57
|
+
* },
|
|
58
|
+
* }).createMachine({
|
|
59
|
+
* id: "fix",
|
|
60
|
+
* context: ({ input }) => input,
|
|
61
|
+
* on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
|
|
62
|
+
* initial: "cutting",
|
|
63
|
+
* states: {
|
|
64
|
+
* cutting: {
|
|
65
|
+
* invoke: {
|
|
66
|
+
* src: "cut",
|
|
67
|
+
* input: ({ context }) => ({ path: fixTree(context), branch: "jr2/fix" }),
|
|
68
|
+
* onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
|
|
69
|
+
* },
|
|
70
|
+
* },
|
|
71
|
+
* coding: {
|
|
72
|
+
* invoke: {
|
|
73
|
+
* src: "coder",
|
|
74
|
+
* input: ({ context }) => ({ prompt: "Make `node --test` pass.", cwd: fixTree(context) }),
|
|
75
|
+
* },
|
|
76
|
+
* on: { finish: "done" },
|
|
77
|
+
* },
|
|
78
|
+
* done: { type: "final" },
|
|
79
|
+
* notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
80
|
+
* failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
|
|
81
|
+
* lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
|
|
82
|
+
* },
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* // What a package exports: the repository and the model are Open.
|
|
86
|
+
* export const fix = workspace(body, {
|
|
87
|
+
* repos: { app: open },
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // What an Instance's `workflows/fix.ts` exports: the same Machine, its Open parts bound.
|
|
91
|
+
* export const machine = customize(fix, {
|
|
92
|
+
* repos: { app: { url: "https://github.com/you/app.git" } },
|
|
93
|
+
* agents: { coder: { model: "anthropic/claude-haiku-5-5" } },
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @see docs/guides/bind-open-parts.md
|
|
98
|
+
* @see docs/concepts/composition.md
|
|
99
|
+
* @see docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md
|
|
16
100
|
*/
|
|
17
101
|
export const open: unique symbol = Symbol.for("jr2.open");
|
package/src/parts.ts
CHANGED
|
@@ -51,10 +51,15 @@ import type { AnyActorRef, AnyStateMachine, StateNode, UnknownActorLogic } from
|
|
|
51
51
|
import { isAgent, isOpenAgent, type AgentDeclaration } from "./agent.ts";
|
|
52
52
|
import { argvText, isEffect, placementOf, type EffectParts, type Placement } from "./effect.ts";
|
|
53
53
|
import { effectBindingLine, openPartsOf, type OpenEffectPart } from "./open-effect.ts";
|
|
54
|
+
import { isFailSlot } from "./fail.ts";
|
|
54
55
|
import { isImageContext } from "./images.ts";
|
|
55
56
|
import { isOpenBody, openBodyDeclarationOf, type OpenBodyDeclaration } from "./open-body.ts";
|
|
56
57
|
import { open } from "./open.ts";
|
|
57
58
|
import { repoIdentity } from "./repo-identity.ts";
|
|
59
|
+
import { refuseUnroutedOutcome } from "./effect-checks.ts";
|
|
60
|
+
import { refuseUnroutedAgentFault } from "./mechanism-routes.ts";
|
|
61
|
+
import { refuseSlotActiveTwice } from "./party.ts";
|
|
62
|
+
import { refuseLostOutput } from "./run-output.ts";
|
|
58
63
|
import { userSeatOf, type Size, type UserContainer } from "./size.ts";
|
|
59
64
|
|
|
60
65
|
// --- Repo Slots (ADR-0051) ---------------------------------------------------------------------
|
|
@@ -71,15 +76,102 @@ import { userSeatOf, type Size, type UserContainer } from "./size.ts";
|
|
|
71
76
|
// meets it first, and `import { open } from "@jr2/orchestrator"` is the only spelling anyone writes.
|
|
72
77
|
export { open } from "./open.ts";
|
|
73
78
|
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The repository of a Repo Slot: `{ url, ref }`. `url` is the Repo's git url. `ref` is the branch,
|
|
81
|
+
* the tag or the commit that the clone stays on, and that a new branch starts from; absent, the
|
|
82
|
+
* Repo's default branch. Where only a url is needed, a string is enough.
|
|
83
|
+
*
|
|
84
|
+
* `workspace()` and `customize()` refuse:
|
|
85
|
+
* - an empty `url`: ``<where>: Repo Slot "<slot>" is bound to an empty url (got <value>) — a slot
|
|
86
|
+
* is `open`, a url, `{ url, ref? }`, or a mapper `({ input }) => url | { url, ref? }` over the
|
|
87
|
+
* door (ADR-0051).``
|
|
88
|
+
* - an empty `ref`: the same text, with `bound with an empty ref` in place of `bound to an empty
|
|
89
|
+
* url`.
|
|
90
|
+
* - a url that names no Repo, such as a relative path: ``<where>: Repo Slot "<slot>" binds
|
|
91
|
+
* "<url>", which names no Repo — <reason> (ADR-0051).``
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { jr2Setup, workspace, type Binding } from "@jr2/orchestrator";
|
|
96
|
+
*
|
|
97
|
+
* const app: Binding = { url: "https://github.com/you/app.git", ref: "release-2" };
|
|
98
|
+
*
|
|
99
|
+
* const body = jr2Setup().createMachine({
|
|
100
|
+
* id: "body",
|
|
101
|
+
* initial: "done",
|
|
102
|
+
* states: { done: { type: "final" } },
|
|
103
|
+
* });
|
|
104
|
+
*
|
|
105
|
+
* export const machine = workspace(body, {
|
|
106
|
+
* repos: { app },
|
|
107
|
+
* });
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @see docs/concepts/workspaces.md
|
|
111
|
+
* @see docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md
|
|
112
|
+
*/
|
|
113
|
+
// What a Repo Slot resolves to (GLOSSARY.md "Binding").
|
|
114
|
+
export type Binding = {
|
|
115
|
+
/** The Repo's git url. */
|
|
116
|
+
url: string;
|
|
117
|
+
/** The branch, tag or commit that the clone stays on, and that a new branch starts from. Default:
|
|
118
|
+
* the Repo's default branch. */
|
|
119
|
+
ref?: string;
|
|
120
|
+
};
|
|
77
121
|
|
|
122
|
+
// Bound and open are what `jr2 up` can see; per-run is the run's business, fenced at attach by
|
|
123
|
+
// `git.credentials` (ADR-0051).
|
|
78
124
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
125
|
+
* The value of one Repo Slot in `workspace({ repos })`. One of:
|
|
126
|
+
* - a url, or a {@link Binding} `{ url, ref }`: the Machine names the Repo.
|
|
127
|
+
* - {@link open}: the Instance that registers the Machine binds it with `customize()`. `jr2 up`
|
|
128
|
+
* refuses a Workflow that leaves it open: ``refusing: workflow "<name>" leaves Repo Slot
|
|
129
|
+
* "<slot>" open — bind it where the Machine is registered: export const machine =
|
|
130
|
+
* customize(<import>, …) (ADR-0051)``, with the whole `customize` line to paste.
|
|
131
|
+
* - a function of the run input, `({ input }) => url` or a {@link Binding}: each run chooses. The
|
|
132
|
+
* url must match an entry of `git.credentials` in `jr2.config.ts`, or the run cannot use it.
|
|
133
|
+
*
|
|
134
|
+
* The key of the slot is a directory name under `/work`. It starts with a letter, so never with
|
|
135
|
+
* `.`: `/work/.jr2/` is reserved for jr2. `workspace()` and `customize()` refuse a key that does
|
|
136
|
+
* not: ``<where>: Repo Slot key "<key>" is not a directory name — a slot becomes `/work/<slot>`,
|
|
137
|
+
* `/work/.jr2/` is reserved for jr2, and its order matters, so it starts with a letter and matches
|
|
138
|
+
* /^[A-Za-z][A-Za-z0-9._-]*$/ (ADR-0051, ADR-0075).`` They refuse a value of another
|
|
139
|
+
* shape: ``<where>: Repo Slot "<slot>" is <what> — a slot is `open`, a url, `{ url, ref? }`, or a
|
|
140
|
+
* mapper `({ input }) => url | { url, ref? }` over the door (ADR-0051).``
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* import { z } from "zod";
|
|
145
|
+
* import { jr2Setup, open, workspace, type RepoSlot, type Workspaced } from "@jr2/orchestrator";
|
|
146
|
+
*
|
|
147
|
+
* const runInput = z.object({ service: z.string() });
|
|
148
|
+
* type RunInput = z.infer<typeof runInput>;
|
|
149
|
+
*
|
|
150
|
+
* const service: RepoSlot<RunInput> = ({ input }) => `https://github.com/you/${input.service}.git`;
|
|
151
|
+
*
|
|
152
|
+
* const body = jr2Setup({
|
|
153
|
+
* types: {} as { input: Workspaced<RunInput, "service" | "docs" | "config"> },
|
|
154
|
+
* }).createMachine({
|
|
155
|
+
* id: "body",
|
|
156
|
+
* initial: "done",
|
|
157
|
+
* states: { done: { type: "final" } },
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* // A Machine for a package: the Instance that registers it binds `config`.
|
|
161
|
+
* export const deploy = workspace(body, {
|
|
162
|
+
* input: runInput,
|
|
163
|
+
* repos: {
|
|
164
|
+
* service,
|
|
165
|
+
* docs: "https://github.com/you/docs.git",
|
|
166
|
+
* config: open,
|
|
167
|
+
* },
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @see docs/concepts/workspaces.md
|
|
172
|
+
* @see docs/guides/bind-open-parts.md
|
|
173
|
+
* @see docs/guides/give-the-cluster-git-credentials.md
|
|
174
|
+
* @see docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md
|
|
83
175
|
*/
|
|
84
176
|
export type RepoSlot<TInput = unknown> =
|
|
85
177
|
| typeof open
|
|
@@ -104,12 +196,13 @@ export function repoSlotState(value: RepoSlot<any>): RepoSlotState {
|
|
|
104
196
|
* carry — and to what a prompt can name without quoting. It starts with a LETTER: the handles
|
|
105
197
|
* keep declaration order, which a Machine may give a meaning to (`task`: the first slot is the
|
|
106
198
|
* one the coder edits), and JS puts an integer-like key such as `"1"` ahead of every other key in
|
|
107
|
-
* `Object.keys`, wherever the author wrote it.
|
|
199
|
+
* `Object.keys`, wherever the author wrote it. So a key never starts with `.`, and `/work/.jr2/`
|
|
200
|
+
* stays jr2's (ADR-0075). */
|
|
108
201
|
export const REPO_SLOT_KEY = /^[A-Za-z][A-Za-z0-9._-]*$/;
|
|
109
202
|
|
|
110
203
|
/**
|
|
111
|
-
* Refuse a malformed slot value BY NAME, at build time —
|
|
112
|
-
*
|
|
204
|
+
* Refuse a malformed slot value BY NAME, at build time — a derives-from-a-typo fault, one build
|
|
205
|
+
* earlier. A bound url is also parsed here: an
|
|
113
206
|
* identity the walk cannot derive (a relative path, an unknown scheme) is refused where the
|
|
114
207
|
* author wrote it rather than at the converge that walks it. `where` names the caller
|
|
115
208
|
* (`workspace()`, `customize()`).
|
|
@@ -118,8 +211,8 @@ export function assertRepoSlot(where: string, slot: string, value: unknown): ass
|
|
|
118
211
|
if (!REPO_SLOT_KEY.test(slot)) {
|
|
119
212
|
throw new Error(
|
|
120
213
|
`${where}: Repo Slot key ${JSON.stringify(slot)} is not a directory name — a slot becomes ` +
|
|
121
|
-
"`/work/<slot
|
|
122
|
-
"/^[A-Za-z][A-Za-z0-9._-]*$/ (ADR-0051).",
|
|
214
|
+
"`/work/<slot>`, `/work/.jr2/` is reserved for jr2, and its order matters, so it starts with a letter " +
|
|
215
|
+
"and matches /^[A-Za-z][A-Za-z0-9._-]*$/ (ADR-0051, ADR-0075).",
|
|
123
216
|
);
|
|
124
217
|
}
|
|
125
218
|
if (value === open || typeof value === "function") return;
|
|
@@ -151,9 +244,8 @@ export function assertRepoSlot(where: string, slot: string, value: unknown): ass
|
|
|
151
244
|
* to a concrete ref on the port's side, which is what keeps the Machine cluster-agnostic. The
|
|
152
245
|
* Repos are Slots, each bound, open, or per-run.
|
|
153
246
|
*
|
|
154
|
-
* They are options
|
|
155
|
-
*
|
|
156
|
-
* evaluate.
|
|
247
|
+
* They are static options because `jr2 up` must find them by walking the Machine, and no walk can
|
|
248
|
+
* evaluate a function of run input.
|
|
157
249
|
*/
|
|
158
250
|
export type SandboxParts = {
|
|
159
251
|
/** The Sandbox Image. Absent → the Instance's `images/default`, then the stock Harness. */
|
|
@@ -167,6 +259,8 @@ export type SandboxParts = {
|
|
|
167
259
|
/** The Size the Machine states (ADR-0060) — the `workspace()`'s, with any `customize()` layered
|
|
168
260
|
* over it. Absent → the Instance's `sandbox.resources`, then the kit default. */
|
|
169
261
|
resources?: Size;
|
|
262
|
+
/** The pod's work group (ADR-0005). Absent: the port's default. */
|
|
263
|
+
workGroup?: number;
|
|
170
264
|
/** The Held secrets this Workspace's pod gets beside its Agents' model keys (ADR-0059): names of
|
|
171
265
|
* the `secrets` list. Naming is placement — no other pod gets a name for being listed here. */
|
|
172
266
|
secrets?: string[];
|
|
@@ -199,8 +293,8 @@ export function sandboxPartsOf(machine: AnyStateMachine | undefined): SandboxPar
|
|
|
199
293
|
|
|
200
294
|
/** Does this Machine COMPOSE a Sandbox — i.e. is it a `workspace()` wrapper? Distinct from
|
|
201
295
|
* `sandboxPartsOf(m)` naming no image: a wrapper that names neither image still owns the two
|
|
202
|
-
* seats, which is what `customize({ image })` retunes (ADR-0049) — and it
|
|
203
|
-
*
|
|
296
|
+
* seats, which is what `customize({ image })` retunes (ADR-0049) — and it may carry no Repo Slot
|
|
297
|
+
* at all (ADR-0051). Also the data-plane switch, read off the walk: an Instance needs
|
|
204
298
|
* Sandboxes exactly when a registered Machine composes one. A logic with no `config` (an Effect's,
|
|
205
299
|
* ADR-0067) composes none. */
|
|
206
300
|
export function composesSandbox(machine: AnyStateMachine): boolean {
|
|
@@ -470,14 +564,15 @@ export type CarriedEffect = {
|
|
|
470
564
|
(| {
|
|
471
565
|
kind: "command";
|
|
472
566
|
argv: string[];
|
|
473
|
-
slot?: string;
|
|
474
567
|
secrets?: string[];
|
|
475
568
|
pin?: true;
|
|
476
569
|
open?: Array<"argv" | "secret">;
|
|
570
|
+
/** A `worktree()`: its `expect`. A report prints it in place of the kit program's argv. */
|
|
571
|
+
cut?: { expect?: "new" | "existing" };
|
|
477
572
|
}
|
|
478
573
|
/** An http Effect (ADR-0068): its method, its fixed target, and the secrets it names — what
|
|
479
574
|
* places each secret, and what its Effector's config allows. `file`: its body is a Worktree
|
|
480
|
-
* file (ADR-0067), so it runs in its Workspace's Sandbox Effector
|
|
575
|
+
* file (ADR-0067), so it runs in its Workspace's Sandbox Effector.
|
|
481
576
|
* An Open url has no target, and names only the secrets its headers and auth name. */
|
|
482
577
|
| {
|
|
483
578
|
kind: "http";
|
|
@@ -486,17 +581,39 @@ export type CarriedEffect = {
|
|
|
486
581
|
secrets: string[];
|
|
487
582
|
idempotent: boolean;
|
|
488
583
|
file?: true;
|
|
489
|
-
slot?: string;
|
|
490
584
|
open?: Array<"url" | "secret">;
|
|
491
585
|
}
|
|
492
|
-
/** A push (ADR-0067, ADR-
|
|
586
|
+
/** A push (ADR-0067, ADR-0075): a cut Worktree's branch to its Repo Slot's Binding. It names no
|
|
493
587
|
* secret: `jr2 up` resolves its credential through `git.credentials`. */
|
|
494
588
|
| { kind: "push"; slot?: string; sign: boolean; squash: boolean; force: boolean; pin: boolean; secrets: string[] }
|
|
589
|
+
/** A dispatch (ADR-0071): the Workflow it starts a run of, as `jr2 run` names it, whether it
|
|
590
|
+
* waits, and — toward another Orchestrator — the target's origin as an http target and its
|
|
591
|
+
* token as the one secret (placed in the Instance Effector beside the http Effects). No target:
|
|
592
|
+
* it runs in the Orchestrator's own process and names no secret. `input`: the slot's input
|
|
593
|
+
* schema as JSON Schema, what the walk compares with the callee's door; absent, the door alone
|
|
594
|
+
* checks. An Open target has no target and no secret yet. */
|
|
595
|
+
| {
|
|
596
|
+
kind: "dispatch";
|
|
597
|
+
workflow: string;
|
|
598
|
+
wait: boolean;
|
|
599
|
+
target?: { scheme: "http" | "https"; host: string; port: number };
|
|
600
|
+
secrets: string[];
|
|
601
|
+
input?: Record<string, unknown>;
|
|
602
|
+
open?: Array<"target">;
|
|
603
|
+
}
|
|
495
604
|
);
|
|
496
605
|
|
|
606
|
+
/** One state that can fail the run (ADR-0073): it invokes a `fail()` slot. `state` is the state's
|
|
607
|
+
* id, `machine` the id of its Machine, `slot` the slot key it invokes, and `path` the `customize()`
|
|
608
|
+
* route to its Machine, as an {@link OpenSlot}'s. Static, as a Gate or an Effect is: the walk reads
|
|
609
|
+
* it, and `jr2 up`, `jr2 check` and the Machine doc list it. */
|
|
610
|
+
export type CarriedFailure = { machine: string; state: string; slot: string; path: OpenSlot["path"] };
|
|
611
|
+
|
|
497
612
|
/** Everything the registered Machines carry that a converge or a boot must act on. */
|
|
498
613
|
export type CarriedParts = {
|
|
499
614
|
agents: CarriedAgent[];
|
|
615
|
+
/** Every state that invokes a `fail()` slot (ADR-0073), in walk order, nested Machines too. */
|
|
616
|
+
failures: CarriedFailure[];
|
|
500
617
|
/** Every Effect slot, in walk order — one per Machine and slot key, at the first route the walk
|
|
501
618
|
* reached its Machine by. The placement reads {@link placedEffectsOf}: one per route. */
|
|
502
619
|
effects: CarriedEffect[];
|
|
@@ -556,17 +673,18 @@ function inlineMachines(node: StateNode<any, any>): Array<{ machine: AnyStateMac
|
|
|
556
673
|
}
|
|
557
674
|
|
|
558
675
|
/**
|
|
559
|
-
* Refuse a Part written inline on an `invoke.src` — an `agent()`, an Effect or a `workspace()` that
|
|
676
|
+
* Refuse a Part written inline on an `invoke.src` — an `agent()`, an Effect, a `fail()` or a `workspace()` that
|
|
560
677
|
* is no key of the Machine's `actors` (see the module comment). Thrown at build by
|
|
561
678
|
* `jr2Setup.createMachine` and at load by {@link partsOf}, so a Machine built with xstate's own
|
|
562
|
-
* `createMachine` is refused where `jr2 up` and the Orchestrator read it. A plain
|
|
563
|
-
* written inline is not a Part: it stays walked, with no `customize()` route (its
|
|
564
|
-
* `undefined`).
|
|
679
|
+
* `createMachine` is refused where `jr2 check`, `jr2 up` and the Orchestrator read it. A plain
|
|
680
|
+
* child Machine written inline is not a Part: it stays walked, with no `customize()` route (its
|
|
681
|
+
* `path` is `undefined`).
|
|
565
682
|
*/
|
|
566
683
|
export function refuseInlineParts(machine: AnyStateMachine): void {
|
|
567
684
|
const partOf = (src: unknown): { part: string; written: string } | undefined => {
|
|
568
685
|
if (isAgent(src)) return { part: "an Agent", written: "agent(...)" };
|
|
569
686
|
if (isEffect(src)) return { part: "an Effect", written: `${src.effect.kind}(...)` };
|
|
687
|
+
if (isFailSlot(src)) return { part: "a fail() Part", written: "fail()" };
|
|
570
688
|
const child = asMachine(src);
|
|
571
689
|
if (child && composesSandbox(child)) return { part: "a Workspace", written: "workspace(...)" };
|
|
572
690
|
return undefined;
|
|
@@ -615,6 +733,7 @@ function canonical(value: unknown): string {
|
|
|
615
733
|
*/
|
|
616
734
|
export function partsOf(machines: Iterable<AnyStateMachine>): CarriedParts {
|
|
617
735
|
const agents: CarriedAgent[] = [];
|
|
736
|
+
const failures: CarriedFailure[] = [];
|
|
618
737
|
const effects: CarriedEffect[] = [];
|
|
619
738
|
const images: CarriedImage[] = [];
|
|
620
739
|
const repos: CarriedRepo[] = [];
|
|
@@ -690,6 +809,11 @@ export function partsOf(machines: Iterable<AnyStateMachine>): CarriedParts {
|
|
|
690
809
|
if (walked.has(machine)) return;
|
|
691
810
|
walked.add(machine);
|
|
692
811
|
refuseInlineParts(machine);
|
|
812
|
+
refuseLostOutput(machine);
|
|
813
|
+
refuseUnroutedAgentFault(machine);
|
|
814
|
+
refuseUnroutedOutcome(machine);
|
|
815
|
+
// Here too, for a Machine built with xstate's own setup: the Turns' identity is the runtime's.
|
|
816
|
+
refuseSlotActiveTwice(machine);
|
|
693
817
|
const parts = sandboxPartsOf(machine);
|
|
694
818
|
const user = userSeatOf(parts.user);
|
|
695
819
|
collectImage(parts.image);
|
|
@@ -706,6 +830,7 @@ export function partsOf(machines: Iterable<AnyStateMachine>): CarriedParts {
|
|
|
706
830
|
});
|
|
707
831
|
}
|
|
708
832
|
const body = wrapperBodyOf(machine);
|
|
833
|
+
for (const { state, slot } of failingStatesOf(machine)) failures.push({ machine: machine.id, state, slot, path });
|
|
709
834
|
for (const [name, logic] of Object.entries(machine.implementations.actors as Record<string, unknown>)) {
|
|
710
835
|
if (isAgent(logic)) collectAgent(path, name, logic.definition);
|
|
711
836
|
else if (isOpenBody(logic)) {
|
|
@@ -735,6 +860,7 @@ export function partsOf(machines: Iterable<AnyStateMachine>): CarriedParts {
|
|
|
735
860
|
for (const body of noneBodies) for (const m of body.declaration.allows.models) harnessModels.add(m);
|
|
736
861
|
return {
|
|
737
862
|
agents,
|
|
863
|
+
failures,
|
|
738
864
|
effects,
|
|
739
865
|
images,
|
|
740
866
|
repos,
|
|
@@ -817,6 +943,23 @@ export function carriedEffectOf(
|
|
|
817
943
|
): CarriedEffect {
|
|
818
944
|
const placement = placementOf(parts);
|
|
819
945
|
const openParts = openPartsOf(parts);
|
|
946
|
+
if (parts.kind === "dispatch") {
|
|
947
|
+
const input = (parts as { [DISPATCH_INPUT]?: Record<string, unknown> })[DISPATCH_INPUT];
|
|
948
|
+
return {
|
|
949
|
+
name,
|
|
950
|
+
path,
|
|
951
|
+
route,
|
|
952
|
+
kind: "dispatch",
|
|
953
|
+
placement,
|
|
954
|
+
workflow: parts.workflow,
|
|
955
|
+
wait: parts.wait,
|
|
956
|
+
timeoutMs: parts.timeoutMs,
|
|
957
|
+
...(parts.target === undefined || parts.target === open ? {} : { target: originTarget(parts.target.url) }),
|
|
958
|
+
secrets: [...parts.secrets],
|
|
959
|
+
...(input !== undefined ? { input } : {}),
|
|
960
|
+
...(openParts.length ? { open: openParts as Array<"target"> } : {}),
|
|
961
|
+
};
|
|
962
|
+
}
|
|
820
963
|
if (parts.kind === "http") {
|
|
821
964
|
return {
|
|
822
965
|
name,
|
|
@@ -831,7 +974,6 @@ export function carriedEffectOf(
|
|
|
831
974
|
idempotent: parts.idempotent,
|
|
832
975
|
timeoutMs: parts.timeoutMs,
|
|
833
976
|
...(parts.file ? { file: true as const } : {}),
|
|
834
|
-
...(parts.file?.slot !== undefined ? { slot: parts.file.slot } : {}),
|
|
835
977
|
};
|
|
836
978
|
}
|
|
837
979
|
if (parts.kind === "push") {
|
|
@@ -851,7 +993,7 @@ export function carriedEffectOf(
|
|
|
851
993
|
...(slot !== undefined ? { slot } : {}),
|
|
852
994
|
};
|
|
853
995
|
}
|
|
854
|
-
const { argv, timeoutMs,
|
|
996
|
+
const { argv, timeoutMs, secrets, pin } = parts;
|
|
855
997
|
return {
|
|
856
998
|
name,
|
|
857
999
|
path,
|
|
@@ -860,13 +1002,27 @@ export function carriedEffectOf(
|
|
|
860
1002
|
placement,
|
|
861
1003
|
argv: argvText(argv),
|
|
862
1004
|
timeoutMs,
|
|
863
|
-
...(slot !== undefined ? { slot } : {}),
|
|
864
1005
|
...(secrets?.length ? { secrets: [...secrets] } : {}),
|
|
865
1006
|
...(pin ? { pin } : {}),
|
|
866
1007
|
...(openParts.length ? { open: openParts as Array<"argv" | "secret"> } : {}),
|
|
1008
|
+
...(parts.cut ? { cut: { ...parts.cut } } : {}),
|
|
867
1009
|
};
|
|
868
1010
|
}
|
|
869
1011
|
|
|
1012
|
+
/** The key a dispatch's slot schema rides its parts under (dispatch-effect.ts): `Symbol.for`, so this
|
|
1013
|
+
* walk reads it off a Machine built by another copy of the module (ADR-0071). */
|
|
1014
|
+
const DISPATCH_INPUT = Symbol.for("jr2.dispatch.input");
|
|
1015
|
+
|
|
1016
|
+
/** A dispatch target's origin as the Effector's fence reads an http target: scheme, host, port. The
|
|
1017
|
+
* origin was checked when the slot was built, so it parses. */
|
|
1018
|
+
function originTarget(url: string): { scheme: "http" | "https"; host: string; port: number } {
|
|
1019
|
+
const u = new URL(url);
|
|
1020
|
+
const scheme = u.protocol === "http:" ? "http" : "https";
|
|
1021
|
+
// As an http target's: brackets off an IPv6 literal, lower case (http-effect.ts `targetOf`).
|
|
1022
|
+
const host = u.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
1023
|
+
return { scheme, host, port: u.port ? Number(u.port) : scheme === "http" ? 80 : 443 };
|
|
1024
|
+
}
|
|
1025
|
+
|
|
870
1026
|
/**
|
|
871
1027
|
* One Workspace a Machine composes, as its pod's Held secrets are placed (ADR-0059): what the pod
|
|
872
1028
|
* names. Located like a {@link CarriedSize} — `path` is the `customize()` route to its
|
|
@@ -888,6 +1044,9 @@ export type WorkspacePod = {
|
|
|
888
1044
|
* credentialed `command` slot below the `workspace()`, down to the next `workspace()` — read off
|
|
889
1045
|
* their plain data, statically. Empty → the pod gets no Sandbox Effector and no Secret. */
|
|
890
1046
|
effects: CarriedEffect[];
|
|
1047
|
+
/** The slot of each `worktree()` below the `workspace()`, down to the next `workspace()`. A cut runs
|
|
1048
|
+
* in the Harness container, so `effects` does not hold it. Absent when there is none. */
|
|
1049
|
+
cuts?: string[];
|
|
891
1050
|
/** The `workspace()`'s `effector: { image }`, as written. Absent → the Sandbox Image. */
|
|
892
1051
|
effector?: { image: string };
|
|
893
1052
|
/** The `workspace()`'s own `image`, as written — its Sandbox Image. Absent → `images/default`,
|
|
@@ -896,6 +1055,9 @@ export type WorkspacePod = {
|
|
|
896
1055
|
/** Each Repo Slot's Binding url as the Machine binds it, by slot, in order; undefined for an open
|
|
897
1056
|
* or per-run slot, whose url `jr2 up` cannot read. A push resolves its credential through it. */
|
|
898
1057
|
bindings: Record<string, string | undefined>;
|
|
1058
|
+
/** The `workspace()` declares no Repo Slot (ADR-0051): it has only `/work`, which its steps
|
|
1059
|
+
* share. Absent for one with slots, and for an Open map, whose slots the composer names. */
|
|
1060
|
+
noSlot?: true;
|
|
899
1061
|
};
|
|
900
1062
|
|
|
901
1063
|
/**
|
|
@@ -913,6 +1075,7 @@ export function workspacePodsOf(root: AnyStateMachine): WorkspacePod[] {
|
|
|
913
1075
|
models: Set<string>,
|
|
914
1076
|
on: Set<AnyStateMachine>,
|
|
915
1077
|
effects: Map<string, CarriedEffect>,
|
|
1078
|
+
cuts: Set<string>,
|
|
916
1079
|
path: OpenSlot["path"],
|
|
917
1080
|
route: PlacementRoute,
|
|
918
1081
|
): void => {
|
|
@@ -920,7 +1083,7 @@ export function workspacePodsOf(root: AnyStateMachine): WorkspacePod[] {
|
|
|
920
1083
|
on.add(machine);
|
|
921
1084
|
const body = wrapperBodyOf(machine);
|
|
922
1085
|
const visit = (child: AnyStateMachine, at: OpenSlot["path"], to: PlacementRoute) => {
|
|
923
|
-
if (!composesSandbox(child)) modelsIn(child, models, on, effects, at, to);
|
|
1086
|
+
if (!composesSandbox(child)) modelsIn(child, models, on, effects, cuts, at, to);
|
|
924
1087
|
};
|
|
925
1088
|
for (const [name, logic] of Object.entries(machine.implementations.actors as Record<string, unknown>)) {
|
|
926
1089
|
if (isAgent(logic)) {
|
|
@@ -939,6 +1102,7 @@ export function workspacePodsOf(root: AnyStateMachine): WorkspacePod[] {
|
|
|
939
1102
|
if (isEffect(logic)) {
|
|
940
1103
|
const effect = carriedEffectOf(name, path, route, logic.effect);
|
|
941
1104
|
if (effect.placement === "sandbox") effects.set(JSON.stringify([route, name]), effect);
|
|
1105
|
+
if (logic.effect.kind === "command" && logic.effect.cut) cuts.add(name);
|
|
942
1106
|
continue;
|
|
943
1107
|
}
|
|
944
1108
|
const child = asMachine(logic);
|
|
@@ -958,7 +1122,8 @@ export function workspacePodsOf(root: AnyStateMachine): WorkspacePod[] {
|
|
|
958
1122
|
if (composesSandbox(machine)) {
|
|
959
1123
|
const models = new Set<string>();
|
|
960
1124
|
const effects = new Map<string, CarriedEffect>();
|
|
961
|
-
|
|
1125
|
+
const cuts = new Set<string>();
|
|
1126
|
+
modelsIn(machine, models, new Set(), effects, cuts, path, route);
|
|
962
1127
|
const parts = sandboxPartsOf(machine);
|
|
963
1128
|
const bindings: Record<string, string | undefined> = {};
|
|
964
1129
|
if (parts.repos !== open) {
|
|
@@ -973,9 +1138,11 @@ export function workspacePodsOf(root: AnyStateMachine): WorkspacePod[] {
|
|
|
973
1138
|
secrets: [...(parts.secrets ?? [])],
|
|
974
1139
|
models: [...models].sort(),
|
|
975
1140
|
effects: [...effects.values()],
|
|
1141
|
+
...(cuts.size ? { cuts: [...cuts] } : {}),
|
|
976
1142
|
...(parts.effector ? { effector: { ...parts.effector } } : {}),
|
|
977
1143
|
...(parts.image !== undefined ? { image: parts.image } : {}),
|
|
978
1144
|
bindings,
|
|
1145
|
+
...(parts.repos !== open && Object.keys(parts.repos).length === 0 ? { noSlot: true as const } : {}),
|
|
979
1146
|
});
|
|
980
1147
|
}
|
|
981
1148
|
const body = wrapperBodyOf(machine);
|
|
@@ -990,6 +1157,22 @@ export function workspacePodsOf(root: AnyStateMachine): WorkspacePod[] {
|
|
|
990
1157
|
return pods;
|
|
991
1158
|
}
|
|
992
1159
|
|
|
1160
|
+
/** Every state of `machine`'s own tree that invokes a `fail()` slot (ADR-0073), in document order,
|
|
1161
|
+
* with the slot key: a state that can fail the run. A child Machine's states are its own walk's. */
|
|
1162
|
+
export function failingStatesOf(machine: AnyStateMachine): Array<{ state: string; slot: string }> {
|
|
1163
|
+
const actors = machine.implementations.actors as Record<string, unknown>;
|
|
1164
|
+
const out: Array<{ state: string; slot: string }> = [];
|
|
1165
|
+
const visit = (node: StateNode<any, any>): void => {
|
|
1166
|
+
for (const inv of node.invoke) {
|
|
1167
|
+
if (typeof inv.src === "string" && isFailSlot(actors[inv.src])) out.push({ state: node.id, slot: inv.src });
|
|
1168
|
+
}
|
|
1169
|
+
const children = Object.values(node.states as Record<string, StateNode<any, any>>);
|
|
1170
|
+
for (const child of children.sort((a, b) => a.order - b.order)) visit(child);
|
|
1171
|
+
};
|
|
1172
|
+
visit(machine.root);
|
|
1173
|
+
return out;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
993
1176
|
/** Every machine object written inline below `node`, at any depth of its state tree, with its hop. */
|
|
994
1177
|
function walkStates(node: StateNode<any, any>, visit: (machine: AnyStateMachine, hop: RouteHop) => void): void {
|
|
995
1178
|
for (const { machine, hop } of inlineMachines(node)) visit(machine, hop);
|