@jr2/orchestrator 0.3.0 → 0.5.1
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/bin/server.ts +7 -4
- package/console/canvas.ts +27 -14
- package/console/components/app.ts +12 -1
- package/console/components/fleet.ts +52 -6
- package/console/components/machine-pane.ts +128 -2
- package/console/components/nav.ts +1 -1
- package/console/components/schema-form.ts +12 -4
- package/console/json-field.ts +23 -0
- package/console/main.ts +122 -39
- package/console/store.ts +321 -21
- package/console/style.css +111 -0
- package/docs/agents-block.md +5 -0
- package/docs/concepts/agents-and-turns.md +442 -0
- package/docs/concepts/architecture.md +230 -0
- package/docs/concepts/charts.md +143 -0
- package/docs/concepts/composition.md +357 -0
- package/docs/concepts/converge.md +254 -0
- package/docs/concepts/durable-runs.md +189 -0
- package/docs/concepts/effects.md +603 -0
- package/docs/concepts/gates.md +208 -0
- package/docs/concepts/machines-and-workflows.md +289 -0
- package/docs/concepts/pools-and-sources.md +230 -0
- package/docs/concepts/secrets-and-trust.md +222 -0
- package/docs/concepts/the-menu.md +378 -0
- package/docs/concepts/workspaces.md +678 -0
- package/docs/get-started/a-model-decides.md +563 -0
- package/docs/get-started/an-agent-in-a-sandbox.md +381 -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 +922 -0
- package/docs/get-started/install.md +126 -0
- package/docs/guides/add-tools-to-the-sandbox.md +295 -0
- package/docs/guides/answer-a-gate.md +304 -0
- package/docs/guides/bind-open-parts.md +223 -0
- package/docs/guides/cancel-a-run.md +146 -0
- package/docs/guides/clean-up.md +206 -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 +226 -0
- package/docs/guides/look-inside-a-sandbox.md +174 -0
- package/docs/guides/mirror-the-kit-images.md +176 -0
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +302 -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 +486 -0
- package/docs/guides/run-a-chart-by-name.md +270 -0
- package/docs/guides/run-a-command-or-call-a-url.md +544 -0
- package/docs/guides/run-one-worker-per-item.md +321 -0
- package/docs/guides/set-an-agents-access-and-dials.md +375 -0
- package/docs/guides/size-a-workspace.md +204 -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 +208 -0
- package/docs/guides/use-a-local-model.md +313 -0
- package/docs/guides/watch-a-run.md +326 -0
- package/docs/guides/write-a-workflow.md +318 -0
- package/docs/index.md +44 -0
- package/docs/llms.txt +216 -0
- package/docs/reference/authoring-surface/agent.md +128 -0
- package/docs/reference/authoring-surface/answer.md +140 -0
- package/docs/reference/authoring-surface/arg.md +60 -0
- package/docs/reference/authoring-surface/basic.md +62 -0
- package/docs/reference/authoring-surface/bearer.md +53 -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 +191 -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 +83 -0
- package/docs/reference/authoring-surface/file.md +122 -0
- package/docs/reference/authoring-surface/frompick.md +277 -0
- package/docs/reference/authoring-surface/http.md +159 -0
- package/docs/reference/authoring-surface/isfailure.md +58 -0
- package/docs/reference/authoring-surface/jr2setup.md +237 -0
- package/docs/reference/authoring-surface/open.md +74 -0
- package/docs/reference/authoring-surface/openbody.md +86 -0
- package/docs/reference/authoring-surface/paramsof.md +125 -0
- package/docs/reference/authoring-surface/pool.md +186 -0
- package/docs/reference/authoring-surface/push.md +112 -0
- package/docs/reference/authoring-surface/secret.md +118 -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 +12 -0
- package/docs/reference/authoring-surface/type-answeraction.md +12 -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-binding.md +62 -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 +19 -0
- package/docs/reference/authoring-surface/type-commandoptions.md +78 -0
- package/docs/reference/authoring-surface/type-commandoutput.md +104 -0
- package/docs/reference/authoring-surface/type-customize.md +109 -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 +65 -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 +41 -0
- package/docs/reference/authoring-surface/type-frominput.md +14 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +58 -0
- package/docs/reference/authoring-surface/type-httpdefinition.md +101 -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 +89 -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-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-noslotspec.md +26 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +32 -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 +17 -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 +31 -0
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +32 -0
- package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
- package/docs/reference/authoring-surface/type-poolspec.md +60 -0
- package/docs/reference/authoring-surface/type-pushinput.md +15 -0
- package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
- package/docs/reference/authoring-surface/type-pushoutput.md +124 -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 +77 -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 +32 -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 +94 -0
- package/docs/reference/authoring-surface/type-workspacehandles.md +23 -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 +39 -0
- package/docs/reference/authoring-surface/type-workspacespec.md +37 -0
- package/docs/reference/authoring-surface/workspace.md +259 -0
- package/docs/reference/authoring-surface.md +197 -0
- package/docs/reference/cli.md +433 -0
- package/docs/reference/config.md +756 -0
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +113 -0
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +110 -0
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +124 -0
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +230 -0
- package/docs/reference/decisions/0006-agent-control-surface.md +47 -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 +157 -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 +265 -0
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +124 -0
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +69 -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 +275 -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 +100 -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 +176 -0
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +439 -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 +237 -0
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +89 -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 +190 -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 +127 -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 +227 -0
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +81 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +111 -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 +106 -0
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +384 -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 +212 -0
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +83 -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 +550 -0
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +430 -0
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +464 -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 +323 -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.md +83 -0
- package/docs/reference/glossary.md +648 -0
- package/docs/reference/http-api.md +1348 -0
- package/docs/reference/machines.md +190 -0
- package/docs/reference/mechanism-events.md +72 -0
- package/docs/why.md +206 -0
- package/package.json +6 -4
- package/src/actor.ts +976 -61
- package/src/agent.ts +114 -38
- package/src/ambient.ts +4 -1
- package/src/assembly-checks.ts +347 -0
- package/src/assembly-tar.ts +494 -0
- package/src/assembly.ts +721 -0
- package/src/cause.ts +234 -0
- package/src/chart.ts +2182 -0
- package/src/charts.ts +748 -0
- package/src/config.ts +520 -162
- package/src/content-hash.ts +105 -0
- package/src/custodian.lua +6 -5
- package/src/custodian.ts +143 -39
- package/src/customize.ts +388 -55
- 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 +557 -0
- package/src/effect.ts +1202 -0
- package/src/effector-wire.ts +674 -0
- package/src/fail.ts +209 -0
- package/src/fingerprint.ts +4 -3
- package/src/gate.ts +8 -0
- package/src/git-clone.ts +65 -0
- package/src/git-push.ts +336 -0
- package/src/harness-client.ts +764 -48
- package/src/held-secrets.ts +82 -26
- package/src/holds.ts +156 -0
- package/src/http-effect.ts +1423 -0
- package/src/http.ts +916 -113
- package/src/images.ts +47 -21
- package/src/index.ts +62 -43
- package/src/instance.ts +505 -59
- package/src/internal.ts +84 -0
- package/src/kube-client.ts +333 -0
- package/src/machine-doc.ts +106 -6
- package/src/mechanism-routes.ts +168 -0
- package/src/model-keys.generated.ts +53 -0
- package/src/model-keys.ts +18 -58
- package/src/mount-digest.ts +53 -0
- package/src/names.ts +66 -8
- package/src/notices.ts +141 -0
- package/src/open-body.ts +1580 -0
- package/src/open-effect.ts +217 -0
- package/src/open.ts +59 -6
- package/src/parts.ts +709 -41
- package/src/party.ts +534 -0
- package/src/pick.ts +761 -0
- package/src/pool.ts +248 -37
- package/src/registration.ts +382 -19
- package/src/repo-fetch.ts +60 -85
- package/src/repos.ts +65 -75
- package/src/rest.ts +133 -0
- package/src/run-host.ts +2383 -115
- package/src/run-output.ts +38 -0
- package/src/sandbox-effect.ts +1126 -0
- package/src/sandbox-effector.ts +111 -0
- package/src/sandbox-kube.ts +1721 -0
- package/src/sandbox-watch.ts +260 -0
- package/src/secret-placement.ts +529 -0
- package/src/server.ts +284 -84
- package/src/setup.ts +819 -117
- package/src/size.ts +454 -0
- package/src/snapshot-store.ts +115 -20
- package/src/stub-harness.ts +49 -16
- package/src/sync-client.ts +54 -0
- package/src/timers.ts +191 -0
- package/src/tokens.ts +35 -4
- package/src/vocabulary.ts +135 -15
- package/src/wire.ts +238 -10
- package/src/workspace.ts +1195 -338
- package/src/sandbox-kubectl.ts +0 -1108
package/src/agent.ts
CHANGED
|
@@ -22,57 +22,133 @@
|
|
|
22
22
|
|
|
23
23
|
import { open } from "./open.ts";
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// jr2's reasoning-effort scale (ADR-0027) — a strict subset of the runtime's, so every value
|
|
26
|
+
// passes through unmapped; mirrored by `@jr2/harness`'s spec contract.
|
|
27
|
+
/**
|
|
28
|
+
* How hard the model thinks before it answers: `"off"`, `"minimal"`, `"low"`, `"medium"`,
|
|
29
|
+
* `"high"` or `"xhigh"`. Set it on an Agent's definition (`thinkingLevel`), or for one Turn in the
|
|
30
|
+
* invoke's `input`.
|
|
31
|
+
*
|
|
32
|
+
* A model can lack a level. Claude Sonnet 5.5 has no `"off"`, and at `"off"` the Harness's request
|
|
33
|
+
* then sends effort `"high"`. The Harness does not refuse such a level: it runs the Turn, and the
|
|
34
|
+
* printed conversation names the level that the model ran at.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { agent, type ThinkingLevel } from "@jr2/orchestrator";
|
|
39
|
+
*
|
|
40
|
+
* const effort: ThinkingLevel = "high";
|
|
41
|
+
*
|
|
42
|
+
* export const reviewer = agent({
|
|
43
|
+
* model: "anthropic/claude-haiku-5-5",
|
|
44
|
+
* instructions: "You review diffs for correctness.",
|
|
45
|
+
* thinkingLevel: effort,
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @see docs/guides/set-an-agents-access-and-dials.md
|
|
50
|
+
* @see docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md
|
|
51
|
+
*/
|
|
27
52
|
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
28
53
|
|
|
29
|
-
|
|
30
|
-
|
|
54
|
+
// The value the Agent actor reads off its own slot's definition to place the Turn (ADR-0028,
|
|
55
|
+
// ADR-0031).
|
|
56
|
+
/** What an Agent may do to the Workspace: `"write"`, `"read"` or `"none"`. With `"none"`, its Turn
|
|
57
|
+
* runs on the Instance Harness, not in a Sandbox. The `workspace` field of {@link AgentDefinition}
|
|
58
|
+
* tells what each value gives. */
|
|
31
59
|
export type WorkspaceAccess = "write" | "read" | "none";
|
|
32
60
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
61
|
+
// The plain-data Agent definition (ADR-0018): IDENTITY plus one default. A Turn's Frame — what it
|
|
62
|
+
// is about and where it works — is not here and cannot be (ADR-0057): a Worktree path exists only
|
|
63
|
+
// once a run has a branch, so no definition written before the run could name one.
|
|
64
|
+
//
|
|
65
|
+
// Must stay JSON-serializable: the definition rides the Turn to the Harness (ADR-0049), so
|
|
66
|
+
// anything non-serializable would be silently lost — grow this contract deliberately. ADR-0028
|
|
67
|
+
// added a restriction vocabulary (`workspace`), not an extension one: custom tool implementations
|
|
68
|
+
// stay out of the contract.
|
|
69
|
+
/**
|
|
70
|
+
* An Agent's definition: which model it runs, its instructions, and what it may do to the
|
|
71
|
+
* Workspace. Give it to `agent()` to get the Agent's actor slot. It is plain data that can be
|
|
72
|
+
* written as JSON.
|
|
73
|
+
*
|
|
74
|
+
* It holds who the Agent is, not what one Turn does. The prompt of a Turn and the directory it
|
|
75
|
+
* works in are the Frame. The state that invokes the Agent sets the Frame in the invoke's
|
|
76
|
+
* `input`. That `input` can also set `model` and `thinkingLevel` for one Turn: the Dials. It
|
|
77
|
+
* cannot change `instructions` or `workspace`.
|
|
36
78
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { agent, type AgentDefinition } from "@jr2/orchestrator";
|
|
82
|
+
*
|
|
83
|
+
* const definition: AgentDefinition = {
|
|
84
|
+
* model: "anthropic/claude-haiku-5-5",
|
|
85
|
+
* instructions: "You fix the failing test, and you change nothing else.",
|
|
86
|
+
* description: "Fixes one failing test",
|
|
87
|
+
* thinkingLevel: "medium",
|
|
88
|
+
* workspace: "write",
|
|
89
|
+
* };
|
|
90
|
+
*
|
|
91
|
+
* export const coder = agent(definition);
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @see docs/concepts/agents-and-turns.md
|
|
95
|
+
* @see docs/guides/set-an-agents-access-and-dials.md
|
|
96
|
+
* @see docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md
|
|
97
|
+
* @see docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md
|
|
98
|
+
*/
|
|
41
99
|
export type AgentDefinition = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
100
|
+
// REQUIRED, with no instance-wide default (ADR-0018): `jr2.config.ts`'s `harness` section
|
|
101
|
+
// declares which providers are REACHABLE, and the definition makes the choice. This is also the
|
|
102
|
+
// only model `jr2 up` can preflight, since a workflow's is not statically recoverable. An
|
|
103
|
+
// invocation may override it for one Turn (`AgentTurnInput.model`).
|
|
104
|
+
/** The model, as `<provider>/<modelId>`: for example `anthropic/claude-haiku-5-5`. The
|
|
105
|
+
* provider must be one that `jr2.config.ts` can reach. Here it is always a string: an `open`
|
|
106
|
+
* model of `agent()` must be bound before a Turn starts. One Turn may set another model in the
|
|
107
|
+
* invoke's `input`. */
|
|
47
108
|
model: string;
|
|
48
|
-
/** The Agent's
|
|
109
|
+
/** The Agent's instructions: the text that tells the model who it is and how to work. The same
|
|
110
|
+
* on every Turn. */
|
|
49
111
|
instructions: string;
|
|
50
|
-
/**
|
|
112
|
+
/** A short description, for people who read the Machine. The model never reads it. */
|
|
51
113
|
description?: string;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
114
|
+
// Effort is a property of the task's difficulty, so the same persona legitimately runs at
|
|
115
|
+
// different settings in different Machines; an invocation may override it for one Turn
|
|
116
|
+
// (`AgentTurnInput.thinkingLevel`).
|
|
117
|
+
/** How hard the model thinks: one of {@link ThinkingLevel}. Absent: `"off"`. A model with no
|
|
118
|
+
* `"off"` runs at another level, and the printed conversation names it. One Turn may set another
|
|
119
|
+
* level in the invoke's `input`. */
|
|
55
120
|
thinkingLevel?: ThinkingLevel;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
*
|
|
62
|
-
*
|
|
121
|
+
// The persona in one word (ADR-0028), deliberately not `tools` (that names the control-plane
|
|
122
|
+
// Menu, what it may SAY). `"read"` states intent and stops the honest path: bash stays, and the
|
|
123
|
+
// detached review worktree is the containment. `"none"` frames no directory — only Working tools
|
|
124
|
+
// consume one — and places the Turn on the Instance Harness (ADR-0031).
|
|
125
|
+
/** What the Agent may do to the Workspace. Default: `"write"`.
|
|
126
|
+
* - `"write"`: all the Working tools (read, write, edit, bash, grep, glob).
|
|
127
|
+
* - `"read"`: no write or edit tool. The Agent keeps bash, so `"read"` does not stop a command
|
|
128
|
+
* that writes. To keep the Agent from changing the branch, frame its Turn in the review
|
|
129
|
+
* Worktree: `reviewSha` in the spec, then `cwd: context.workspace.review?.<slot>`.
|
|
130
|
+
* - `"none"`: no Working tools. The Agent only reads its prompt and picks from its Menu. Its Turn
|
|
131
|
+
* runs on the Instance Harness, not in a Sandbox, so it needs no `workspace()` around it. */
|
|
63
132
|
workspace?: WorkspaceAccess;
|
|
64
133
|
};
|
|
65
134
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
135
|
+
// The Agent as an author DECLARES it (ADR-0054): the definition, except that `model` may be Open —
|
|
136
|
+
// the one part a packaged Machine cannot honestly fill, since the package cannot pay for it. Every
|
|
137
|
+
// other field is the wire's, because every other field a package CAN state.
|
|
138
|
+
//
|
|
139
|
+
// This is what `agent()` takes and what the slot's brand carries, so the walk and `customize()`
|
|
140
|
+
// read the author's own answer, Open included. Nothing sends this: the wire takes an
|
|
141
|
+
// AgentDefinition, and `requireBoundAgent` is the one door between the two.
|
|
142
|
+
/** What `agent()` takes: an {@link AgentDefinition}, except that `model` can also be `open`. */
|
|
143
|
+
export type AgentDeclaration = Omit<AgentDefinition, "model"> & {
|
|
144
|
+
/** The model, as `<provider>/<modelId>`: for example `anthropic/claude-haiku-5-5`. Required:
|
|
145
|
+
* there is no default model. The provider must be one that `jr2.config.ts` can reach.
|
|
146
|
+
*
|
|
147
|
+
* Or `open`, in a Machine that you publish as a package. Then the Instance that registers the
|
|
148
|
+
* Machine binds the model with `customize()`. One Turn may set another model in the invoke's
|
|
149
|
+
* `input`. */
|
|
150
|
+
model: string | typeof open;
|
|
151
|
+
};
|
|
76
152
|
|
|
77
153
|
/** The brand `agent(declaration)` stamps on its logic (ADR-0049): the declaration itself, readable
|
|
78
154
|
* off the logic object. Everything that must recognize an Agent slot reads THIS — never a name
|
package/src/ambient.ts
CHANGED
|
@@ -23,7 +23,10 @@ export type AmbientHandles = {
|
|
|
23
23
|
sandbox: string;
|
|
24
24
|
/** Every Repo Slot's branch-worktree path, by slot (ADR-0051). */
|
|
25
25
|
repos: Record<string, string>;
|
|
26
|
-
|
|
26
|
+
/** Every Repo Slot's Binding url, by slot (ADR-0051): where a push goes. */
|
|
27
|
+
bindings?: Record<string, string>;
|
|
28
|
+
/** The branch the Worktrees are on. Absent for a Workspace with no Repo Slot (ADR-0051). */
|
|
29
|
+
branch?: string;
|
|
27
30
|
/** Detached review-worktree paths, when the spec carried `reviewSha` (ADR-0028). */
|
|
28
31
|
review?: Record<string, string>;
|
|
29
32
|
};
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
// The walk's refusals, as a LISTING (ADR-0069). The walk runs twice: `jr2 up` runs it on the host
|
|
2
|
+
// before any cluster work, and the door runs it again over the unpacked Assembly before the
|
|
3
|
+
// publish lands. Both ends call these functions, so the two walks cannot drift. They return the
|
|
4
|
+
// lines and print nothing: `jr2 up` prints them after `refusing: `, and the door returns them in
|
|
5
|
+
// its `422` report.
|
|
6
|
+
|
|
7
|
+
import { isAbsolute, relative, sep } from "node:path";
|
|
8
|
+
import type { AnyStateMachine } from "xstate";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import type { JR2Config } from "./config.ts";
|
|
11
|
+
import { imageContextDigest, type ImageRefs } from "./images.ts";
|
|
12
|
+
import { openPartsText } from "./open-effect.ts";
|
|
13
|
+
import { customizeLine, partsOf, placedEffectsOf, workspacePodsOf } from "./parts.ts";
|
|
14
|
+
import { refuseEffectSecrets, type PlacementWalk } from "./secret-placement.ts";
|
|
15
|
+
import {
|
|
16
|
+
chartFileRefusals,
|
|
17
|
+
chartName,
|
|
18
|
+
chartWrapperOf,
|
|
19
|
+
splitChartName,
|
|
20
|
+
wrapperFault,
|
|
21
|
+
type ChartFile,
|
|
22
|
+
} from "./charts.ts";
|
|
23
|
+
import { doorCompat } from "./door-compat.ts";
|
|
24
|
+
|
|
25
|
+
// The comparison is the same one `jr2 up`'s foreign preflight makes, so it is exported beside the
|
|
26
|
+
// walk the CLI already imports (ADR-0071).
|
|
27
|
+
export { doorCompat, type DoorCompat } from "./door-compat.ts";
|
|
28
|
+
import { inputSchemaOf, isZodSchema } from "./vocabulary.ts";
|
|
29
|
+
|
|
30
|
+
/** One registered Workflow, as `loadWorkflows` gives it. */
|
|
31
|
+
export type LoadedWorkflow = { name: string; machine: AnyStateMachine };
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Every registered Machine that has a zod `input` on its `createMachine` config and that `jr2Setup`
|
|
35
|
+
* did not make (ADR-0033). The `setup()` of xstate keeps that `input` in the config but does not read it,
|
|
36
|
+
* so the Machine has no door: a start with any input passes, and the Console start form is only a
|
|
37
|
+
* field for JSON. TypeScript accepts the config, so only this walk finds it. One line per Workflow,
|
|
38
|
+
* naming the fix.
|
|
39
|
+
* A Machine with no `input`, or with an `input` that is not zod, can still use `setup()`.
|
|
40
|
+
*
|
|
41
|
+
* The line text follows `refusing: ` in `jr2 up`'s output; the prefix is the caller's.
|
|
42
|
+
*/
|
|
43
|
+
export function doorRefusals(workflows: readonly LoadedWorkflow[]): string[] {
|
|
44
|
+
const lines: string[] = [];
|
|
45
|
+
for (const w of workflows) {
|
|
46
|
+
const declared = (w.machine.config as { input?: unknown }).input;
|
|
47
|
+
if (!isZodSchema(declared) || inputSchemaOf(w.machine)) continue;
|
|
48
|
+
lines.push(
|
|
49
|
+
`workflow "${w.name}": machine "${w.machine.id}" has a zod \`input\` on createMachine, but jr2Setup did not ` +
|
|
50
|
+
"make this Machine, so no door reads that input: a run starts with any input, and the Console start form " +
|
|
51
|
+
"is only a field for JSON — make the Machine with jr2Setup in place of setup() or createMachine() (leave " +
|
|
52
|
+
"out `events` if it takes no workflow event) (ADR-0033)",
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return lines;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Every part a registered Machine leaves Open (ADR-0051, ADR-0054): a Repo Slot with no url, an
|
|
60
|
+
* Agent with no model, an Effect's url, argv or secret. One line per part, in walk order within
|
|
61
|
+
* each kind, so a composer fixes all of them in one edit. Each line names the Workflow and the
|
|
62
|
+
* `customize()` line that binds the part. A part on a Machine invoked inline has no fix line,
|
|
63
|
+
* because no `customize()` reaches an actor without a slot key.
|
|
64
|
+
*
|
|
65
|
+
* The line text follows `refusing: ` in `jr2 up`'s output; the prefix is the caller's.
|
|
66
|
+
*/
|
|
67
|
+
export function openPartRefusals(workflows: readonly LoadedWorkflow[]): string[] {
|
|
68
|
+
const lines: string[] = [];
|
|
69
|
+
for (const w of workflows) {
|
|
70
|
+
const walked = partsOf([w.machine]);
|
|
71
|
+
const opened: Array<{
|
|
72
|
+
slot: string | undefined;
|
|
73
|
+
path: readonly string[] | undefined;
|
|
74
|
+
part: Parameters<typeof customizeLine>[3];
|
|
75
|
+
what: string;
|
|
76
|
+
adr: string;
|
|
77
|
+
}> = [
|
|
78
|
+
...walked.openSlots.map((o) => ({
|
|
79
|
+
...o,
|
|
80
|
+
part: "repo" as const,
|
|
81
|
+
// An Open MAP names no slot (the composer does), so it is refused as "the Repo Slots".
|
|
82
|
+
what: o.slot === undefined ? "its Repo Slots" : `Repo Slot "${o.slot}"`,
|
|
83
|
+
adr: "ADR-0051",
|
|
84
|
+
})),
|
|
85
|
+
...walked.openAgents.map((o) => ({ ...o, part: "agent" as const, what: `Agent "${o.slot}"`, adr: "ADR-0054" })),
|
|
86
|
+
// An Effect's Open url, argv or secret (ADR-0054): one binding object for an Effect with two.
|
|
87
|
+
...walked.openEffects.map(({ parts, ...o }) => ({
|
|
88
|
+
...o,
|
|
89
|
+
part: parts,
|
|
90
|
+
what: `the ${openPartsText(parts)} of Effect "${o.slot}"`,
|
|
91
|
+
adr: "ADR-0054",
|
|
92
|
+
})),
|
|
93
|
+
];
|
|
94
|
+
for (const { slot, path, part, what, adr } of opened) {
|
|
95
|
+
if (path === undefined) {
|
|
96
|
+
lines.push(
|
|
97
|
+
`workflow "${w.name}" leaves ${what} open on a Machine invoked inline — no ` +
|
|
98
|
+
"customize() reaches an actor without a slot key; declare that Machine under setup({ actors }) and " +
|
|
99
|
+
`bind it there (ADR-0049, ${adr})`,
|
|
100
|
+
);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const where = path.length ? ` (on the Machine composed as ${path.map((k) => `"${k}"`).join(" → ")})` : "";
|
|
104
|
+
lines.push(
|
|
105
|
+
`workflow "${w.name}" leaves ${what} open${where} — bind it where the Machine is ` +
|
|
106
|
+
`registered: export const machine = ${customizeLine("<import>", path, slot, part)} (${adr})`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return lines;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* What the registered Machines name for secret placement (ADR-0059, ADR-0068): every Effect and
|
|
115
|
+
* every Workspace's pod, per route, and the models the Instance Harness hosts: those of the `"none"`
|
|
116
|
+
* Agents and of every Open body that allows `"none"` (ADR-0070). `jr2 up` and the door build the same walk from the same Workflows.
|
|
117
|
+
*/
|
|
118
|
+
export function placementWalkOf(workflows: readonly LoadedWorkflow[]): PlacementWalk {
|
|
119
|
+
// The walk's own `instanceHarness` (ADR-0068, ADR-0070): the models of the "none" Agents and of
|
|
120
|
+
// every Open body that allows "none", so a Chart's minted "none" Agent has its key placed, or the
|
|
121
|
+
// publish is refused, never a 401 mid-run.
|
|
122
|
+
const { instanceHarness } = partsOf(workflows.map((w) => w.machine));
|
|
123
|
+
return {
|
|
124
|
+
// Per route, not per Machine object: a Machine placed twice is checked where each copy runs.
|
|
125
|
+
effects: workflows.flatMap((w) => placedEffectsOf(w.machine).map((effect) => ({ workflow: w.name, effect }))),
|
|
126
|
+
workspaces: workflows.flatMap((w) => workspacePodsOf(w.machine).map((pod) => ({ workflow: w.name, pod }))),
|
|
127
|
+
...(instanceHarness ? { instanceHarness: { models: [...instanceHarness.models] } } : {}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* What a `dispatch` names, checked against what the walk can see (ADR-0071). Each dispatch with no
|
|
133
|
+
* target — a same-Instance one; a foreign target is `jr2 up`'s preflight, a warning — must name a
|
|
134
|
+
* Workflow the Assembly has: a Machine (`workflows/<name>.ts`), or `<wrapper>/<name>`, a named Chart
|
|
135
|
+
* under a Chart wrapper the Assembly registers, from a Chart file or (when `runtime` is given) a
|
|
136
|
+
* runtime Chart. A miss is an error. Without `runtime` — on the host, which cannot see the
|
|
137
|
+
* Orchestrator's volume — a slashed name under a known wrapper with no Chart file is a warning.
|
|
138
|
+
* Then the slot's input schema, when it has one, is compared with the callee's door
|
|
139
|
+
* (`doorCompat`): a fault is an error, naming the field; a schema outside the compared subset is a
|
|
140
|
+
* warning, "not compared".
|
|
141
|
+
*
|
|
142
|
+
* A dispatch resolves at RUN time against the current Assembly (ADR-0069); this check is of the
|
|
143
|
+
* Assembly being published, so a later publish that drops the callee answers `refused` with the
|
|
144
|
+
* door's 404 then, and is not refused for it here.
|
|
145
|
+
*/
|
|
146
|
+
export function dispatchRefusals(
|
|
147
|
+
workflows: readonly LoadedWorkflow[],
|
|
148
|
+
charts: readonly ChartFile[],
|
|
149
|
+
runtime?: readonly { name: string }[],
|
|
150
|
+
): { errors: string[]; warnings: string[] } {
|
|
151
|
+
const errors: string[] = [];
|
|
152
|
+
const warnings: string[] = [];
|
|
153
|
+
const seen = new Set<string>();
|
|
154
|
+
for (const w of workflows) {
|
|
155
|
+
for (const effect of partsOf([w.machine]).effects) {
|
|
156
|
+
// A target, bound or Open, is another Orchestrator's: its door is not in this Assembly.
|
|
157
|
+
if (effect.kind !== "dispatch" || effect.target !== undefined || effect.open !== undefined) continue;
|
|
158
|
+
const name = effect.workflow;
|
|
159
|
+
const at = `workflow "${w.name}" dispatches "${name}"`;
|
|
160
|
+
const once = JSON.stringify([w.name, effect.name, name]);
|
|
161
|
+
if (seen.has(once)) continue;
|
|
162
|
+
seen.add(once);
|
|
163
|
+
const callee = calleeOf(workflows, charts, runtime, name);
|
|
164
|
+
if ("error" in callee) {
|
|
165
|
+
errors.push(`${at} ${callee.error} (ADR-0071)`);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
// A slashed name with no Chart the host can see still has a known door: the wrapper's minus
|
|
169
|
+
// its Chart fields, the same for every Chart under it. So it is warned AND compared.
|
|
170
|
+
if (callee.warning) warnings.push(`${at}: ${callee.warning} (ADR-0071)`);
|
|
171
|
+
if (effect.input === undefined) continue;
|
|
172
|
+
if ("notDrawn" in callee.door) {
|
|
173
|
+
warnings.push(`${at}: its input schema and the door are not compared — ${callee.door.notDrawn} (ADR-0071)`);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const compared = doorCompat(effect.input, callee.door.schema);
|
|
177
|
+
if (compared.ok === "not-compared") {
|
|
178
|
+
warnings.push(`${at}: its input schema and the door are not compared — ${compared.why} (ADR-0071)`);
|
|
179
|
+
} else if (compared.ok === false) {
|
|
180
|
+
for (const fault of compared.faults) {
|
|
181
|
+
errors.push(
|
|
182
|
+
`${at} with input its door does not take: ${fault} — align the slot's \`input\` with the door ` +
|
|
183
|
+
"(derive it from the door's schema, `door.pick({ ... })`) (ADR-0071)",
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { errors, warnings };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** The door a dispatch's name resolves to in these Workflows, or why it does not. */
|
|
193
|
+
function calleeOf(
|
|
194
|
+
workflows: readonly LoadedWorkflow[],
|
|
195
|
+
charts: readonly ChartFile[],
|
|
196
|
+
runtime: readonly { name: string }[] | undefined,
|
|
197
|
+
name: string,
|
|
198
|
+
): { door: Door; warning?: string } | { error: string } {
|
|
199
|
+
const split = splitChartName(name);
|
|
200
|
+
if (!split) {
|
|
201
|
+
const found = workflows.find((w) => w.name === name);
|
|
202
|
+
if (!found) {
|
|
203
|
+
return {
|
|
204
|
+
error:
|
|
205
|
+
`which no Workflow in the Assembly has — add workflows/${name}.ts, or name one it registers` +
|
|
206
|
+
(workflows.length ? `: ${workflows.map((w) => `"${w.name}"`).join(", ")}` : ""),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return { door: doorOf(found.machine, []) };
|
|
210
|
+
}
|
|
211
|
+
const { wrapper, name: short } = split;
|
|
212
|
+
const fault = wrapperFault(workflows, wrapper);
|
|
213
|
+
if (fault) {
|
|
214
|
+
return {
|
|
215
|
+
error:
|
|
216
|
+
fault.status === 404
|
|
217
|
+
? `which no Workflow in the Assembly has — no workflows/${wrapper}.ts registers the Chart wrapper "${wrapper}"`
|
|
218
|
+
: `which no Workflow in the Assembly can be: ${fault.error}`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const machine = workflows.find((w) => w.name === wrapper)!.machine;
|
|
222
|
+
const door = doorOf(machine, chartWrapperOf(machine)?.chartFields ?? []);
|
|
223
|
+
const file = `workflows/${wrapper}/${short}.chart.json`;
|
|
224
|
+
if (charts.some((c) => chartName(c.wrapper, c.name) === name)) return { door };
|
|
225
|
+
if (runtime === undefined) {
|
|
226
|
+
return {
|
|
227
|
+
door,
|
|
228
|
+
warning:
|
|
229
|
+
`the Assembly has no Chart file ${file}, and a runtime Chart lives on the Orchestrator's volume alone, ` +
|
|
230
|
+
"which jr2 up cannot see — the publish door checks it, and a run of the dispatch is refused with the door's " +
|
|
231
|
+
"404 if it is not there",
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (runtime.some((c) => c.name === name)) return { door };
|
|
235
|
+
return {
|
|
236
|
+
error:
|
|
237
|
+
`which no Workflow in the Assembly has — add the Chart file ${file}; or, for a runtime Chart, PUT ` +
|
|
238
|
+
`/workflows/${wrapper}/charts/${short} before this publish (a PUT needs "${wrapper}" in the current ` +
|
|
239
|
+
`Assembly: when this publish adds it, publish "${wrapper}" first, then PUT the Chart, then publish the dispatch)`,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** A door as the comparison reads it: its JSON Schema (null: it declares no input), or why zod
|
|
244
|
+
* could not draw one. */
|
|
245
|
+
type Door = { schema: Record<string, unknown> | null } | { notDrawn: string };
|
|
246
|
+
|
|
247
|
+
/** A Workflow's door as JSON Schema, exactly as `GET /workflows/<name>` serves it (run-host.ts
|
|
248
|
+
* `inputSchema`): null for a Machine that declares none; for a named Chart the wrapper's minus its
|
|
249
|
+
* Chart fields, which the Chart supplies (ADR-0070). A door zod cannot draw (`z.date()`,
|
|
250
|
+
* `z.custom()`) is not drawn as "any", which would guess "compatible": it is not compared. */
|
|
251
|
+
function doorOf(machine: AnyStateMachine, chartFields: readonly string[]): Door {
|
|
252
|
+
let schema = inputSchemaOf(machine);
|
|
253
|
+
if (!schema) return { schema: null };
|
|
254
|
+
if (chartFields.length) schema = schema.omit(Object.fromEntries(chartFields.map((f) => [f, true])) as never);
|
|
255
|
+
try {
|
|
256
|
+
return { schema: z.toJSONSchema(schema, { io: "input" }) as Record<string, unknown> };
|
|
257
|
+
} catch (err) {
|
|
258
|
+
return {
|
|
259
|
+
notDrawn: `the door has a part JSON Schema cannot state (${err instanceof Error ? err.message : String(err)})`,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export type AssemblyRefusalInput = {
|
|
265
|
+
/** The Assembly's `jr2.config.ts`, loaded; `undefined` when it ships none. */
|
|
266
|
+
config: JR2Config | undefined;
|
|
267
|
+
/** Every Workflow the Assembly registers, loaded. */
|
|
268
|
+
workflows: readonly LoadedWorkflow[];
|
|
269
|
+
/**
|
|
270
|
+
* The Assembly's Chart files (ADR-0070), read: `workflows/<wrapper>/<name>.chart.json`. Each is
|
|
271
|
+
* admitted against its wrapper's Open body by the same door a run's Chart passes. Absent, none.
|
|
272
|
+
*/
|
|
273
|
+
charts?: readonly ChartFile[];
|
|
274
|
+
/**
|
|
275
|
+
* The runtime Charts on the Orchestrator's volume (ADR-0070), by Workflow name
|
|
276
|
+
* (`<wrapper>/<name>`): what a dispatch of a named Chart may resolve to beside the Chart files
|
|
277
|
+
* (ADR-0071). The door can see them; absent, none.
|
|
278
|
+
*/
|
|
279
|
+
runtimeCharts?: readonly { name: string }[];
|
|
280
|
+
/**
|
|
281
|
+
* The image map the Orchestrator reads per provision (ADR-0038), or a reader of it. Present
|
|
282
|
+
* only when deployed: a host-booted process has no map, and no Sandbox to provision. When
|
|
283
|
+
* present, every `file:` context a Machine names must have its digest in the map.
|
|
284
|
+
*/
|
|
285
|
+
images?: () => Promise<ImageRefs>;
|
|
286
|
+
/**
|
|
287
|
+
* The directory the Assembly was imported from. A refusal names a `file:` context relative to
|
|
288
|
+
* it (`images/box`), as the composer's own folder holds it: at the door that directory is a
|
|
289
|
+
* staging path, which is gone when the refusal arrives.
|
|
290
|
+
*/
|
|
291
|
+
root?: string;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* The door's walk (ADR-0069): the refusals the Orchestrator can see in an Assembly it has already
|
|
296
|
+
* imported. An import error, a missing `export const machine` and a Vocabulary error are the
|
|
297
|
+
* caller's: they throw at import, before this runs. Here: a zod `input` that no door reads, every
|
|
298
|
+
* Open part, a secret the config does not declare (or a literal one too short to scrub), a `file:`
|
|
299
|
+
* image context whose digest the mounted image map does not hold, and a Chart file that does not
|
|
300
|
+
* admit under its wrapper (ADR-0070), each line naming the file. The door runs this after `jr2 up`
|
|
301
|
+
* did its cluster work, so each check is true when the Assembly lands.
|
|
302
|
+
*/
|
|
303
|
+
export async function assemblyRefusals(input: AssemblyRefusalInput): Promise<string[]> {
|
|
304
|
+
const lines = [...doorRefusals(input.workflows), ...openPartRefusals(input.workflows)];
|
|
305
|
+
// A Chart file is the Instance's own (ADR-0070): one that fails refuses the publish.
|
|
306
|
+
if (input.charts?.length) lines.push(...chartFileRefusals(input.charts, input.workflows));
|
|
307
|
+
// A same-Instance dispatch names a Workflow this Assembly has (ADR-0071). The door sees the
|
|
308
|
+
// runtime Charts, so a miss is an error here. Its warnings (a schema "not compared") have no
|
|
309
|
+
// channel in the publish's answer, and are dropped: `jr2 up` printed them before the publish.
|
|
310
|
+
lines.push(...dispatchRefusals(input.workflows, input.charts ?? [], input.runtimeCharts ?? []).errors);
|
|
311
|
+
try {
|
|
312
|
+
refuseEffectSecrets(input.config ?? {}, placementWalkOf(input.workflows));
|
|
313
|
+
} catch (err) {
|
|
314
|
+
lines.push(err instanceof Error ? err.message : String(err));
|
|
315
|
+
}
|
|
316
|
+
const images = partsOf(input.workflows.map((w) => w.machine)).images;
|
|
317
|
+
const where = (dir: string): string => {
|
|
318
|
+
const rel = input.root === undefined ? undefined : relative(input.root, dir);
|
|
319
|
+
return rel !== undefined && rel !== "" && !rel.startsWith("..") && !isAbsolute(rel)
|
|
320
|
+
? rel.split(sep).join("/")
|
|
321
|
+
: dir;
|
|
322
|
+
};
|
|
323
|
+
if (input.images && images.length) {
|
|
324
|
+
let refs: ImageRefs | undefined;
|
|
325
|
+
try {
|
|
326
|
+
refs = await input.images();
|
|
327
|
+
} catch (err) {
|
|
328
|
+
lines.push(err instanceof Error ? err.message : String(err));
|
|
329
|
+
}
|
|
330
|
+
if (refs) {
|
|
331
|
+
for (const image of images) {
|
|
332
|
+
const digest = await imageContextDigest(image.dir);
|
|
333
|
+
if (refs.sandbox[digest] === undefined) {
|
|
334
|
+
const named = input.workflows
|
|
335
|
+
.filter((w) => partsOf([w.machine]).images.some((i) => i.dir === image.dir))
|
|
336
|
+
.map((w) => `"${w.name}"`);
|
|
337
|
+
const by = named.length ? ` that workflow ${named.join(", ")} names` : "";
|
|
338
|
+
lines.push(
|
|
339
|
+
`the Sandbox Image context ${where(image.dir)}${by} (digest ${digest}) is not in the image map — ` +
|
|
340
|
+
"`jr2 up` builds every `file:` context and writes the map before it publishes (ADR-0038, ADR-0069)",
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return lines;
|
|
347
|
+
}
|