@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/pool.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// The Source port is generalized — `next(active) → item | null`, plus an optional `wake` event
|
|
11
11
|
// def (a webhook / `jr2 send` push seam, served as a standing gate named "source") and
|
|
12
12
|
// `pollEvery` (the set mutates underneath us — re-query). A queue, a generator, or a re-queried
|
|
13
|
-
// set; tk's claim actor is one adapter (
|
|
13
|
+
// set; tk's claim actor is one adapter (GLOSSARY.md: Work Source is the Source adapter for tickets).
|
|
14
14
|
//
|
|
15
15
|
// Terminal triage is three-valued (ADR-0017, forced by parking-is-retention):
|
|
16
16
|
// - drained — source empty and all children settled → final (jr exit 0);
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
// final, distinct status (jr exit 2), never an indistinguishable idle poll;
|
|
19
19
|
// - waiting — children parked (gates, agents) → the run stays open; the gates list is the
|
|
20
20
|
// "what needs me" surface (jr exit 3).
|
|
21
|
+
// With failures and `failures: "fail"` (the default), a drained or deadlocked pool fails the run instead
|
|
22
|
+
// (ADR-0073), and the detail of the Failure carries the status.
|
|
21
23
|
// The pool can make this call because it owns both the source and the children. Distinguishing
|
|
22
24
|
// drained from deadlocked needs one more bit than `null` carries, so a Source's `next` MAY
|
|
23
25
|
// resolve the richer `{ item: null, open: n }` shape; a bare `null` means drained-when-idle.
|
|
@@ -33,67 +35,135 @@ import {
|
|
|
33
35
|
} from "xstate";
|
|
34
36
|
import type { z } from "zod";
|
|
35
37
|
import type { EventDef } from "@jr2/agent-protocol";
|
|
38
|
+
import { fail, failurePayload, isFailure, type FailureInput } from "./fail.ts";
|
|
36
39
|
import { gate } from "./gate.ts";
|
|
37
40
|
import { attachWrapperBody, type JR2Wrapper, type WrapperActors } from "./parts.ts";
|
|
38
41
|
import { attachInputSchema, attachVocabulary } from "./vocabulary.ts";
|
|
39
42
|
|
|
43
|
+
// The rich shape's `open` is the one bit that separates DRAINED from DEADLOCKED when the pool goes
|
|
44
|
+
// idle (ADR-0017); a bare `null` means drained-when-idle.
|
|
40
45
|
/**
|
|
41
|
-
* What `next` resolves
|
|
42
|
-
*
|
|
43
|
-
*
|
|
46
|
+
* What the `next` of a Source resolves to: an item, to claim it; `null`, when no item is ready
|
|
47
|
+
* now; or `{ item, open }`, where `open` is the number of items that exist but are not ready.
|
|
48
|
+
* When no worker runs and `next` gives no item, the Pool ends: `drained` when `open` is 0 or
|
|
49
|
+
* absent, `deadlocked` when `open` is more than 0.
|
|
44
50
|
*/
|
|
45
51
|
export type SourceNextResult<T> = T | null | { item: T | null; open: number };
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
// The Source port (ADR-0017).
|
|
54
|
+
/** Where a Pool gets its work items: the Source. Make one with {@link source}. */
|
|
48
55
|
export type SourceSpec<T> = {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
// A union of the accepted output shapes because xstate's actor-logic type is invariant in its
|
|
57
|
+
// output — a `fromPromise` inferred as `T | null` must still assign.
|
|
58
|
+
/** Claim the next ready item. Write it as an xstate promise actor,
|
|
59
|
+
* `fromPromise(async ({ input }) => …)`. Its input is `{ active }`: the ids of the items that
|
|
60
|
+
* workers have now, which it must not give again. It must also not give again an item that a
|
|
61
|
+
* worker finished. It resolves to a {@link SourceNextResult}. The Pool calls it when the run
|
|
62
|
+
* starts, after each claim, and when a worker settles. While workers run and no item is ready, it
|
|
63
|
+
* also calls it on `wake` and every `pollEvery`. */
|
|
52
64
|
next:
|
|
53
65
|
| PromiseActorLogic<SourceNextResult<T>, { active: string[] }>
|
|
54
66
|
| PromiseActorLogic<{ item: T | null; open: number }, { active: string[] }>
|
|
55
67
|
| PromiseActorLogic<T | null, { active: string[] }>
|
|
56
68
|
| PromiseActorLogic<null, { active: string[] }>;
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
// The webhook / `jr2 send` push seam. The def IS the pool machine's vocabulary (ADR-0011).
|
|
70
|
+
/** An external event, made with `defineEvent`, that tells the Pool that new work is ready, for
|
|
71
|
+
* example from a webhook or `jr2 send`. While workers run and no item is ready, it makes the Pool
|
|
72
|
+
* call `next` at once. The Pool serves it as a Gate named `source` for the whole run
|
|
73
|
+
* (`<path>.source` when the Pool is composed in another Machine). Default: none. */
|
|
59
74
|
wake?: EventDef;
|
|
60
|
-
|
|
75
|
+
// For sets that mutate underneath us.
|
|
76
|
+
/** While workers run and no item is ready, call `next` again after this many milliseconds. Use
|
|
77
|
+
* it for a Source whose items change while the run waits. Default: none, so the Pool calls
|
|
78
|
+
* `next` again only when a worker settles or `wake` comes. */
|
|
61
79
|
pollEvery?: number;
|
|
62
80
|
};
|
|
63
81
|
|
|
64
|
-
|
|
82
|
+
// Identity by design — the value IS the spec; this is the naming/typing seam.
|
|
83
|
+
/**
|
|
84
|
+
* Declare a Source: where a `pool()` gets its work items, one at a time. It gives back the spec
|
|
85
|
+
* that you pass. The item type `T` types what `next` gives. `pool()` does not carry `T` to
|
|
86
|
+
* `itemId` and `itemInput`, so write the item type on their parameter, as the `pool()` example does.
|
|
87
|
+
*
|
|
88
|
+
* @param spec - How to claim the next item, and when to look again. See {@link SourceSpec}.
|
|
89
|
+
* @returns The same spec.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { fromPromise } from "xstate";
|
|
94
|
+
* import { source } from "@jr2/orchestrator";
|
|
95
|
+
*
|
|
96
|
+
* type Issue = { id: string; title: string };
|
|
97
|
+
*
|
|
98
|
+
* const backlog: Issue[] = [
|
|
99
|
+
* { id: "ISSUE-1", title: "Fix the greeting." },
|
|
100
|
+
* { id: "ISSUE-2", title: "Add a --name flag." },
|
|
101
|
+
* ];
|
|
102
|
+
*
|
|
103
|
+
* export const issues = source<Issue>({
|
|
104
|
+
* next: fromPromise(async ({ input }: { input: { active: string[] } }) => {
|
|
105
|
+
* const issue = backlog.find((i) => !input.active.includes(i.id)) ?? null;
|
|
106
|
+
* if (issue) backlog.splice(backlog.indexOf(issue), 1);
|
|
107
|
+
* return issue;
|
|
108
|
+
* }),
|
|
109
|
+
* pollEvery: 60_000,
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @see docs/guides/run-one-worker-per-item.md
|
|
114
|
+
* @see docs/concepts/pools-and-sources.md
|
|
115
|
+
* @see docs/reference/decisions/0017-pool-over-a-source-port.md
|
|
116
|
+
*/
|
|
65
117
|
export function source<T>(spec: SourceSpec<T>): SourceSpec<T> {
|
|
66
118
|
return spec;
|
|
67
119
|
}
|
|
68
120
|
|
|
69
|
-
/** How a pool run ends (its machine output). `items` maps itemId → the worker
|
|
70
|
-
|
|
121
|
+
/** How a pool run ends (its machine output). `items` maps itemId → the output of a worker that got
|
|
122
|
+
* to a final state. `failures` maps itemId → the Failure of a worker that failed (ADR-0073). */
|
|
123
|
+
export type PoolOutput = {
|
|
124
|
+
status: "drained" | "deadlocked";
|
|
125
|
+
items: Record<string, unknown>;
|
|
126
|
+
failures: Record<string, FailureInput>;
|
|
127
|
+
};
|
|
71
128
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
*/
|
|
129
|
+
// How a pool is configured (ADR-0017, ADR-0033). `TInput` is what came through the pool's door:
|
|
130
|
+
// the PARSED schema when `input` declares one, and `unknown` when it does not — absence is
|
|
131
|
+
// permissive, so jr2 knows nothing and says so, exactly as `workspace()`'s door-less path does.
|
|
132
|
+
// A pool that is fed by something other than a caller may state what it is fed by annotating the
|
|
133
|
+
// mapper's parameter; for anything a caller starts, the honest fix is to declare `input`.
|
|
134
|
+
/** What you pass to `pool()`: where the items come from, how many workers run at once, and what
|
|
135
|
+
* each worker gets. */
|
|
79
136
|
export type PoolSpec<T, TInput = unknown> = {
|
|
80
|
-
/** The
|
|
137
|
+
/** The Machine id: the name of the Pool in the Console. Default: `"pool"`. */
|
|
81
138
|
id?: string;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
139
|
+
// The WORKER's schema is deliberately not the door (ADR-0033): workers are fed per-ITEM (the
|
|
140
|
+
// source item, or `itemInput`'s result), never the run body, so it describes nothing a starter
|
|
141
|
+
// sends.
|
|
142
|
+
/** The run input of the Pool, as a zod object: what a caller sends to start a run. `cap` and
|
|
143
|
+
* `itemInput` read it, typed by it. A worker never gets it: each worker gets its item. Default:
|
|
144
|
+
* none, and then their `input` is `unknown`. */
|
|
86
145
|
input?: z.ZodObject;
|
|
146
|
+
/** Where the items come from. Make it with {@link source}. */
|
|
87
147
|
source: SourceSpec<T>;
|
|
88
|
-
|
|
148
|
+
// Stable child identity: the spawn id, the active-set entry, the outcome key.
|
|
149
|
+
/** The id of an item. The Pool uses it as the id of the item's worker and in the `active` list
|
|
150
|
+
* that `next` gets. It is also the key of that worker's output in `items`. Give each item an id
|
|
151
|
+
* of its own, and the same id every time. */
|
|
89
152
|
itemId: (item: T) => string;
|
|
90
|
-
/**
|
|
153
|
+
/** The most workers that run at once: a number, or a function of the run input. Default: `1`. */
|
|
91
154
|
cap?: number | ((args: { input: TInput }) => number);
|
|
92
|
-
/**
|
|
155
|
+
/** Make a worker's input from its item and the run input. Default: the item itself. */
|
|
93
156
|
itemInput?: (item: T, args: { input: TInput }) => unknown;
|
|
94
|
-
|
|
95
|
-
|
|
157
|
+
// jr semantics: runs END; a parking policy can be added when a workflow needs one.
|
|
158
|
+
/** What the Pool does when the Source has no more items and every worker has settled. Only
|
|
159
|
+
* `"final"`: the run ends. Default: `"final"`. */
|
|
96
160
|
onDrained?: "final";
|
|
161
|
+
/** What the Pool does at the end when one or more workers failed. The Pool catches each worker's
|
|
162
|
+
* Failure either way, so one failed item does not stop the other workers. `"fail"`: when the Pool
|
|
163
|
+
* ends with failures, `drained` or `deadlocked`, it fails the run with the reason
|
|
164
|
+
* `"<n> of <m> items failed"` and the detail `{ status, items, failures }`. `"report"`: the Pool
|
|
165
|
+
* ends `done`, with the failures in its output. Default: `"fail"`. */
|
|
166
|
+
failures?: "fail" | "report";
|
|
97
167
|
};
|
|
98
168
|
|
|
99
169
|
/**
|
|
@@ -102,12 +172,14 @@ export type PoolSpec<T, TInput = unknown> = {
|
|
|
102
172
|
* TRANSPARENT to its worker (ADR-0049), so `customize(machine, { agents })` on a pool-rooted
|
|
103
173
|
* workflow offers the WORKER's Agents and the composer never spells `worker`. {@link JR2Wrapper} is
|
|
104
174
|
* what marks it a jr2 wrapper: the transparency follows the marker, not the slot's spelling.
|
|
175
|
+
*
|
|
176
|
+
* @internal
|
|
105
177
|
*/
|
|
106
178
|
export type PoolMachine<TWorker extends AnyStateMachine, TInput> = StateMachine<
|
|
107
179
|
any,
|
|
108
180
|
any,
|
|
109
181
|
any,
|
|
110
|
-
WrapperActors<"worker", TWorker, "next" | "gate">,
|
|
182
|
+
WrapperActors<"worker", TWorker, "next" | "gate" | "fail">,
|
|
111
183
|
any,
|
|
112
184
|
any,
|
|
113
185
|
any,
|
|
@@ -128,6 +200,8 @@ type PoolCtx = {
|
|
|
128
200
|
active: string[];
|
|
129
201
|
/** Settled workers' outputs, by item id — the pool's output collects them. */
|
|
130
202
|
items: Record<string, unknown>;
|
|
203
|
+
/** Failed workers' payloads, by item id (ADR-0073). */
|
|
204
|
+
failures: Record<string, FailureInput>;
|
|
131
205
|
status?: "drained" | "deadlocked";
|
|
132
206
|
};
|
|
133
207
|
|
|
@@ -146,15 +220,90 @@ function normalizeClaim(output: unknown): Claim {
|
|
|
146
220
|
return { item: output, open: 0 };
|
|
147
221
|
}
|
|
148
222
|
|
|
223
|
+
// Build the pool machine (ADR-0017). Returns a plain machine — the usual workflow ROOT, but
|
|
224
|
+
// nestable as a child like any other. Its vocabulary is the wake def alone: the worker keeps its
|
|
225
|
+
// own (ADR-0011, ADR-0049).
|
|
149
226
|
/**
|
|
150
|
-
*
|
|
151
|
-
* (`export const machine = pool(
|
|
152
|
-
*
|
|
227
|
+
* Make a Pool: a Machine that runs one worker Machine for each item that a Source gives, with at
|
|
228
|
+
* most `cap` workers at once. Use it as the root of a Workflow (`export const machine = pool(…)`),
|
|
229
|
+
* or compose it in another Machine.
|
|
230
|
+
*
|
|
231
|
+
* The run ends when the Source has no item ready and no worker runs. Its output is
|
|
232
|
+
* `{ status, items, failures }`: `status` is `"drained"` when no item is left, or `"deadlocked"`
|
|
233
|
+
* when items exist but none can start; `items` holds the output of each worker that got to a final
|
|
234
|
+
* state, by item id; `failures` holds the Failure of each worker that failed, by item id. A worker's
|
|
235
|
+
* Failure stops only that worker: the other workers and their Sandboxes stay. When the Pool ends
|
|
236
|
+
* with one or more failures, `drained` or `deadlocked`, it fails the run by default: the reason is
|
|
237
|
+
* `"<n> of <m> items failed"`, and the detail is `{ status, items, failures }`. With
|
|
238
|
+
* `failures: "report"`, it ends `done` with that output. A worker's defect ends the whole run
|
|
239
|
+
* `error`. While workers wait on Gates, the run stays open.
|
|
240
|
+
*
|
|
241
|
+
* `customize()` reaches through a Pool to its worker: `customize(pool, { agents })` retunes the
|
|
242
|
+
* worker's Agents. The events that the Pool accepts are its `wake` event only; each worker keeps
|
|
243
|
+
* its own.
|
|
244
|
+
*
|
|
245
|
+
* @param worker - The Machine to run for each item. It gets the item, or what `itemInput` makes
|
|
246
|
+
* of it, as its input. It does not get the run input.
|
|
247
|
+
* @param spec - The Source, the item id, the cap, and the worker's input. See {@link PoolSpec}.
|
|
248
|
+
* @returns The Pool, as a Machine.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* import { fromPromise } from "xstate";
|
|
253
|
+
* import { customize, pool, source } from "@jr2/orchestrator";
|
|
254
|
+
* import { task } from "@jr2/machines";
|
|
255
|
+
*
|
|
256
|
+
* type Issue = { id: string; title: string };
|
|
257
|
+
*
|
|
258
|
+
* const backlog: Issue[] = [
|
|
259
|
+
* { id: "ISSUE-1", title: "Fix the greeting." },
|
|
260
|
+
* { id: "ISSUE-2", title: "Add a --name flag." },
|
|
261
|
+
* ];
|
|
262
|
+
*
|
|
263
|
+
* const issues = source<Issue>({
|
|
264
|
+
* next: fromPromise(async ({ input }: { input: { active: string[] } }) => {
|
|
265
|
+
* const issue = backlog.find((i) => !input.active.includes(i.id)) ?? null;
|
|
266
|
+
* if (issue) backlog.splice(backlog.indexOf(issue), 1);
|
|
267
|
+
* return issue;
|
|
268
|
+
* }),
|
|
269
|
+
* });
|
|
270
|
+
*
|
|
271
|
+
* const fixer = customize(task, {
|
|
272
|
+
* repos: { app: { url: "https://github.com/you/app.git" } },
|
|
273
|
+
* agents: { coder: { model: "anthropic/claude-haiku-5-5" } },
|
|
274
|
+
* });
|
|
275
|
+
*
|
|
276
|
+
* export const machine = pool(fixer, {
|
|
277
|
+
* id: "issues",
|
|
278
|
+
* source: issues,
|
|
279
|
+
* itemId: (issue: Issue) => issue.id,
|
|
280
|
+
* cap: 2,
|
|
281
|
+
* itemInput: (issue: Issue) => ({ prompt: issue.title, branch: `fix/${issue.id}` }),
|
|
282
|
+
* });
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @see docs/guides/run-one-worker-per-item.md
|
|
286
|
+
* @see docs/concepts/pools-and-sources.md
|
|
287
|
+
* @see docs/reference/decisions/0017-pool-over-a-source-port.md
|
|
153
288
|
*/
|
|
154
289
|
export function pool<TWorker extends AnyStateMachine, TSchema extends z.ZodObject>(
|
|
155
290
|
worker: TWorker,
|
|
156
291
|
spec: PoolSpec<any, z.infer<TSchema>> & { input: TSchema },
|
|
157
292
|
): PoolMachine<TWorker, z.infer<TSchema>>;
|
|
293
|
+
/**
|
|
294
|
+
* Make a Pool with no `input` schema. A Pool is a Machine that runs one worker Machine for each
|
|
295
|
+
* item that a Source gives, with at most `cap` workers at once. See {@link pool} for the full description and
|
|
296
|
+
* an example.
|
|
297
|
+
*
|
|
298
|
+
* @param worker - The Machine to run for each item. It gets the item, or what `itemInput` makes
|
|
299
|
+
* of it, as its input. It does not get the run input.
|
|
300
|
+
* @param spec - The Source, the item id, the cap, and the worker's input. See {@link PoolSpec}.
|
|
301
|
+
* @returns The Pool, as a Machine.
|
|
302
|
+
*
|
|
303
|
+
* @see docs/guides/run-one-worker-per-item.md
|
|
304
|
+
* @see docs/concepts/pools-and-sources.md
|
|
305
|
+
* @see docs/reference/decisions/0017-pool-over-a-source-port.md
|
|
306
|
+
*/
|
|
158
307
|
export function pool<TWorker extends AnyStateMachine, TInput = unknown>(
|
|
159
308
|
worker: TWorker,
|
|
160
309
|
spec: PoolSpec<any, TInput> & { input?: never },
|
|
@@ -166,9 +315,14 @@ export function pool(worker: AnyStateMachine, spec: PoolSpec<any, any>): AnyStat
|
|
|
166
315
|
/** `xstate.done.actor.<childId>` → the settled worker's item id. */
|
|
167
316
|
const doneChildOf = (event: unknown): string =>
|
|
168
317
|
((event as { type: string }).type.match(/^xstate\.done\.actor\.(.+)$/) as RegExpMatchArray)[1]!;
|
|
318
|
+
/** `xstate.error.actor.<childId>` → the failed worker's item id. */
|
|
319
|
+
const errorChildOf = (event: unknown): string =>
|
|
320
|
+
((event as { type: string }).type.match(/^xstate\.error\.actor\.(.+)$/) as RegExpMatchArray)[1]!;
|
|
169
321
|
|
|
322
|
+
const report = spec.failures === "report";
|
|
323
|
+
const failuresOf = (context: unknown) => (context as PoolCtx).failures;
|
|
170
324
|
const machine = setup({
|
|
171
|
-
actors: { worker, next: spec.source.next, gate },
|
|
325
|
+
actors: { worker, next: spec.source.next, gate, fail: fail() },
|
|
172
326
|
}).createMachine({
|
|
173
327
|
id: spec.id ?? "pool",
|
|
174
328
|
context: ({ input }): PoolCtx => ({
|
|
@@ -176,6 +330,7 @@ export function pool(worker: AnyStateMachine, spec: PoolSpec<any, any>): AnyStat
|
|
|
176
330
|
cap: typeof spec.cap === "function" ? spec.cap({ input }) : (spec.cap ?? 1),
|
|
177
331
|
active: [],
|
|
178
332
|
items: {},
|
|
333
|
+
failures: {},
|
|
179
334
|
}),
|
|
180
335
|
// The wake seam: a standing gate for the whole run's life (root invokes stop only at final).
|
|
181
336
|
// The invoke id IS the gate's name (the id derives from the actor path — ADR-0011):
|
|
@@ -201,6 +356,28 @@ export function pool(worker: AnyStateMachine, spec: PoolSpec<any, any>): AnyStat
|
|
|
201
356
|
stopChild(({ event }) => doneChildOf(event)),
|
|
202
357
|
],
|
|
203
358
|
},
|
|
359
|
+
// A worker failed (ADR-0073): keep its Failure, free its slot, stop the ref, and go look for
|
|
360
|
+
// more work. The Pool is the parent that catches it, so one failed item does not end the run
|
|
361
|
+
// and the host does not delete the Sandboxes of the other workers — a worker parked at a Gate
|
|
362
|
+
// keeps its work (parking is retention, ADR-0012). Only a Failure of a live worker: a defect,
|
|
363
|
+
// or an error of `next`, takes no transition here, so it goes up and ends the run `error`.
|
|
364
|
+
"xstate.error.actor.*": {
|
|
365
|
+
guard: ({ context, event }) =>
|
|
366
|
+
isFailure((event as { error?: unknown }).error) &&
|
|
367
|
+
(context as unknown as PoolCtx).active.includes(errorChildOf(event)),
|
|
368
|
+
target: ".discovering",
|
|
369
|
+
actions: [
|
|
370
|
+
assign({
|
|
371
|
+
failures: ({ context, event }) => ({
|
|
372
|
+
...(context as unknown as PoolCtx).failures,
|
|
373
|
+
[errorChildOf(event)]: failurePayload((event as unknown as { error: never }).error),
|
|
374
|
+
}),
|
|
375
|
+
active: ({ context, event }) =>
|
|
376
|
+
(context as unknown as PoolCtx).active.filter((id) => id !== errorChildOf(event)),
|
|
377
|
+
}),
|
|
378
|
+
stopChild(({ event }) => errorChildOf(event)),
|
|
379
|
+
],
|
|
380
|
+
},
|
|
204
381
|
},
|
|
205
382
|
states: {
|
|
206
383
|
discovering: {
|
|
@@ -234,6 +411,22 @@ export function pool(worker: AnyStateMachine, spec: PoolSpec<any, any>): AnyStat
|
|
|
234
411
|
// Nothing ready, workers live → healthy parking: their settling re-queries, as do
|
|
235
412
|
// the wake gate and the poll timer. This is jr's exit-3 "waiting" as a state.
|
|
236
413
|
{ guard: ({ context }) => (context as PoolCtx).active.length > 0, target: "parked" },
|
|
414
|
+
// Idle with failures: the run fails (ADR-0017, ADR-0073), at a drain and at a deadlock.
|
|
415
|
+
// No worker is live, so the Failure deletes no sibling's Sandbox. `"report"` has no
|
|
416
|
+
// `failing` state and no branch to it, so the walk lists no state that fails the run. The
|
|
417
|
+
// branch is spread in, so xstate cannot infer the actor type of its action: `as never`
|
|
418
|
+
// lets the check pass.
|
|
419
|
+
...(report
|
|
420
|
+
? []
|
|
421
|
+
: [
|
|
422
|
+
{
|
|
423
|
+
guard: ({ context }: { context: unknown }) => Object.keys(failuresOf(context)).length > 0,
|
|
424
|
+
target: "failing",
|
|
425
|
+
actions: assign({
|
|
426
|
+
status: ({ event }) => (claimOf(event).open > 0 ? ("deadlocked" as const) : ("drained" as const)),
|
|
427
|
+
}) as never,
|
|
428
|
+
},
|
|
429
|
+
]),
|
|
237
430
|
// Idle + items exist that will never become ready by themselves → jr's exit 2.
|
|
238
431
|
{
|
|
239
432
|
guard: ({ event }) => claimOf(event).open > 0,
|
|
@@ -246,13 +439,30 @@ export function pool(worker: AnyStateMachine, spec: PoolSpec<any, any>): AnyStat
|
|
|
246
439
|
},
|
|
247
440
|
},
|
|
248
441
|
saturated: {
|
|
249
|
-
// Every slot full: only a settling worker (the root `xstate.done.actor.*`
|
|
442
|
+
// Every slot full: only a settling worker (the root `xstate.done.actor.*` or a caught
|
|
443
|
+
// Failure) moves us.
|
|
250
444
|
},
|
|
251
445
|
parked: {
|
|
252
446
|
// Waiting on the world: wake early on push, or re-query on the poll cadence.
|
|
253
447
|
on: wake ? { [wake.name]: "discovering" } : {},
|
|
254
448
|
after: spec.source.pollEvery ? { [spec.source.pollEvery]: { target: "discovering" } } : {},
|
|
255
449
|
},
|
|
450
|
+
// Not a final state: the run ends `failed`, and the Failure says which items failed.
|
|
451
|
+
...(report
|
|
452
|
+
? {}
|
|
453
|
+
: {
|
|
454
|
+
failing: {
|
|
455
|
+
invoke: {
|
|
456
|
+
src: "fail" as const,
|
|
457
|
+
input: ({ context }: { context: unknown }) => {
|
|
458
|
+
const { status, items, failures } = context as PoolCtx;
|
|
459
|
+
const n = Object.keys(failures).length;
|
|
460
|
+
const m = n + Object.keys(items).length;
|
|
461
|
+
return { reason: `${n} of ${m} items failed`, detail: { status, items, failures } };
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
}),
|
|
256
466
|
drained: { type: "final" },
|
|
257
467
|
deadlocked: { type: "final" },
|
|
258
468
|
},
|
|
@@ -260,6 +470,7 @@ export function pool(worker: AnyStateMachine, spec: PoolSpec<any, any>): AnyStat
|
|
|
260
470
|
output: ({ context }): PoolOutput => ({
|
|
261
471
|
status: (context as unknown as PoolCtx).status ?? "drained",
|
|
262
472
|
items: (context as unknown as PoolCtx).items,
|
|
473
|
+
failures: (context as unknown as PoolCtx).failures,
|
|
263
474
|
}),
|
|
264
475
|
});
|
|
265
476
|
|