@jr2/orchestrator 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/console/components/app.ts +55 -15
- package/console/components/bottom-drawer.ts +259 -0
- package/console/components/drawer.ts +14 -6
- package/console/components/fleet.ts +36 -13
- package/console/components/machine-pane.ts +61 -5
- package/console/components/nav.ts +54 -8
- package/console/conversation.ts +161 -0
- package/console/login.ts +123 -0
- package/console/main.ts +600 -60
- package/console/store.ts +611 -64
- package/console/style.css +231 -0
- package/docs/agents-block.md +2 -2
- package/docs/concepts/agents-and-turns.md +86 -9
- package/docs/concepts/architecture.md +41 -28
- package/docs/concepts/callers-and-hooks.md +205 -0
- package/docs/concepts/charts.md +7 -5
- package/docs/concepts/composition.md +10 -1
- package/docs/concepts/converge.md +4 -2
- package/docs/concepts/durable-runs.md +43 -16
- package/docs/concepts/effects.md +50 -22
- package/docs/concepts/gates.md +95 -25
- package/docs/concepts/machines-and-workflows.md +5 -4
- package/docs/concepts/pools-and-sources.md +187 -11
- package/docs/concepts/secrets-and-trust.md +73 -33
- package/docs/concepts/the-menu.md +11 -0
- package/docs/concepts/workspaces.md +6 -5
- package/docs/get-started/a-model-decides.md +14 -13
- package/docs/get-started/an-agent-in-a-sandbox.md +43 -34
- package/docs/get-started/connect-a-model.md +1 -1
- package/docs/get-started/create-an-instance.md +17 -14
- package/docs/guides/add-tools-to-the-sandbox.md +55 -11
- package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
- package/docs/guides/answer-a-gate.md +74 -37
- package/docs/guides/bind-open-parts.md +24 -8
- package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
- package/docs/guides/cancel-a-run.md +26 -16
- package/docs/guides/fix-a-failed-converge.md +18 -6
- package/docs/guides/give-a-caller-a-scope.md +203 -0
- package/docs/guides/give-an-agent-mcp-tools.md +422 -0
- package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
- package/docs/guides/let-an-agent-write-a-chart.md +9 -6
- package/docs/guides/look-inside-a-sandbox.md +101 -31
- package/docs/guides/open-the-console.md +63 -14
- package/docs/guides/read-a-conversation.md +225 -0
- package/docs/guides/run-a-chart-by-name.md +17 -16
- package/docs/guides/run-one-worker-per-item.md +15 -9
- package/docs/guides/set-an-agents-access-and-dials.md +2 -0
- package/docs/guides/start-a-run-for-each-alert.md +290 -0
- package/docs/guides/start-a-run-from-a-run.md +18 -16
- package/docs/guides/start-a-run.md +24 -18
- package/docs/guides/steer-an-agent.md +332 -0
- package/docs/guides/use-a-hosted-provider.md +1 -1
- package/docs/guides/watch-a-run.md +127 -121
- package/docs/guides/write-a-hook-kind.md +238 -0
- package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
- package/docs/guides/write-a-workflow.md +17 -7
- package/docs/llms.txt +81 -15
- package/docs/reference/authoring-surface/agent.md +1 -1
- package/docs/reference/authoring-surface/answer.md +1 -1
- package/docs/reference/authoring-surface/arg.md +1 -1
- package/docs/reference/authoring-surface/basic.md +1 -1
- package/docs/reference/authoring-surface/bearer.md +1 -1
- package/docs/reference/authoring-surface/branchname.md +1 -1
- package/docs/reference/authoring-surface/carry.md +23 -0
- package/docs/reference/authoring-surface/chartschema.md +1 -1
- package/docs/reference/authoring-surface/chartschemafor.md +1 -1
- package/docs/reference/authoring-surface/command.md +1 -1
- package/docs/reference/authoring-surface/customize.md +4 -1
- package/docs/reference/authoring-surface/defineconfig.md +1 -1
- package/docs/reference/authoring-surface/defineevent.md +1 -1
- package/docs/reference/authoring-surface/dispatch.md +5 -4
- package/docs/reference/authoring-surface/fail.md +1 -1
- package/docs/reference/authoring-surface/file.md +1 -1
- package/docs/reference/authoring-surface/frompick.md +1 -1
- package/docs/reference/authoring-surface/gate.md +118 -0
- package/docs/reference/authoring-surface/group-agents.md +15 -0
- package/docs/reference/authoring-surface/group-charts.md +16 -0
- package/docs/reference/authoring-surface/group-composition.md +25 -0
- package/docs/reference/authoring-surface/group-config.md +17 -0
- package/docs/reference/authoring-surface/group-effects.md +48 -0
- package/docs/reference/authoring-surface/group-failure.md +13 -0
- package/docs/reference/authoring-surface/group-gates.md +16 -0
- package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
- package/docs/reference/authoring-surface/group-steering.md +12 -0
- package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
- package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
- package/docs/reference/authoring-surface/http.md +1 -1
- package/docs/reference/authoring-surface/isfailure.md +1 -1
- package/docs/reference/authoring-surface/isready.md +1 -1
- package/docs/reference/authoring-surface/jr2setup.md +13 -3
- package/docs/reference/authoring-surface/mcp.md +107 -0
- package/docs/reference/authoring-surface/open.md +5 -3
- package/docs/reference/authoring-surface/openbody.md +1 -1
- package/docs/reference/authoring-surface/paramsof.md +1 -1
- package/docs/reference/authoring-surface/pool.md +77 -9
- package/docs/reference/authoring-surface/push.md +1 -1
- package/docs/reference/authoring-surface/readyof.md +1 -1
- package/docs/reference/authoring-surface/reread.md +19 -0
- package/docs/reference/authoring-surface/secret.md +1 -1
- package/docs/reference/authoring-surface/sentby.md +1 -1
- package/docs/reference/authoring-surface/skip.md +22 -0
- package/docs/reference/authoring-surface/source.md +56 -1
- package/docs/reference/authoring-surface/steer.md +93 -0
- package/docs/reference/authoring-surface/text.md +1 -1
- package/docs/reference/authoring-surface/type-agentdefinition.md +14 -1
- package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
- package/docs/reference/authoring-surface/type-anyframepath.md +1 -1
- package/docs/reference/authoring-surface/type-anyworktreepath.md +1 -1
- package/docs/reference/authoring-surface/type-binding.md +1 -1
- package/docs/reference/authoring-surface/type-caller.md +40 -0
- package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
- package/docs/reference/authoring-surface/type-carry.md +19 -0
- package/docs/reference/authoring-surface/type-chainlink.md +3 -3
- package/docs/reference/authoring-surface/type-commandoutput.md +1 -1
- package/docs/reference/authoring-surface/type-customize.md +16 -1
- package/docs/reference/authoring-surface/type-delivered.md +17 -0
- package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
- package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
- package/docs/reference/authoring-surface/type-dispatchoutput.md +1 -1
- package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
- package/docs/reference/authoring-surface/type-framepath.md +1 -1
- package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
- package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
- package/docs/reference/authoring-surface/type-gatelook.md +37 -0
- package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
- package/docs/reference/authoring-surface/type-gatereply.md +19 -0
- package/docs/reference/authoring-surface/type-gateslot.md +21 -0
- package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
- package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
- package/docs/reference/authoring-surface/type-gateslots.md +12 -0
- package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +1 -1
- package/docs/reference/authoring-surface/type-httpoutput.md +1 -1
- package/docs/reference/authoring-surface/type-jr2config.md +37 -2
- package/docs/reference/authoring-surface/type-lateroutcome.md +1 -1
- package/docs/reference/authoring-surface/type-lends.md +5 -1
- package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
- package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
- package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
- package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
- package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
- package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
- package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
- package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
- package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
- package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
- package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
- package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
- package/docs/reference/authoring-surface/type-poolnextinput.md +1 -1
- package/docs/reference/authoring-surface/type-poolspec.md +11 -6
- package/docs/reference/authoring-surface/type-pushoutput.md +1 -1
- package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
- package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
- package/docs/reference/authoring-surface/type-reposlot.md +1 -1
- package/docs/reference/authoring-surface/type-reread.md +18 -0
- package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
- package/docs/reference/authoring-surface/type-sender.md +26 -1
- package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
- package/docs/reference/authoring-surface/type-size.md +1 -1
- package/docs/reference/authoring-surface/type-skip.md +19 -0
- package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
- package/docs/reference/authoring-surface/type-sourcein.md +25 -0
- package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
- package/docs/reference/authoring-surface/type-sourcespec.md +16 -7
- package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
- package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
- package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
- package/docs/reference/authoring-surface/type-steerargs.md +20 -0
- package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
- package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
- package/docs/reference/authoring-surface/type-workspaced.md +1 -1
- package/docs/reference/authoring-surface/type-worktreefound.md +3 -3
- package/docs/reference/authoring-surface/type-worktreeinput.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeoptions.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeoutput.md +1 -1
- package/docs/reference/authoring-surface/type-worktreepath.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeready.md +1 -1
- package/docs/reference/authoring-surface/type-worktreerefused.md +4 -4
- package/docs/reference/authoring-surface/workspace.md +1 -1
- package/docs/reference/authoring-surface/worktree.md +1 -1
- package/docs/reference/authoring-surface.md +88 -167
- package/docs/reference/cli.md +413 -74
- package/docs/reference/config.md +235 -2
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +71 -11
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +14 -10
- package/docs/reference/decisions/0006-agent-control-surface.md +4 -4
- package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
- package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
- package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
- package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +9 -2
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +20 -14
- package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +18 -14
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -12
- package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +32 -18
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +14 -1
- package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +116 -34
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +38 -37
- package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +7 -6
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +23 -7
- package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
- package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -18
- package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +4 -3
- package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +5 -4
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +19 -19
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
- package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
- package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +7 -0
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +13 -7
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +38 -30
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +64 -17
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +2 -1
- package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
- package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +51 -23
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +94 -54
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +101 -47
- package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +17 -13
- package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
- package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
- package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +4 -3
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +37 -10
- package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
- package/docs/reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md +198 -0
- package/docs/reference/decisions.md +6 -4
- package/docs/reference/glossary.md +96 -42
- package/docs/reference/hooks.md +1077 -0
- package/docs/reference/http-api.md +976 -149
- package/docs/why.md +2 -1
- package/package.json +10 -3
- package/src/actor.ts +36 -10
- package/src/agent.ts +50 -0
- package/src/assembly-checks.ts +530 -4
- package/src/callers.ts +245 -0
- package/src/chart.ts +52 -7
- package/src/config.ts +550 -1
- package/src/conversations.ts +453 -0
- package/src/custodian.ts +8 -2
- package/src/customize.ts +143 -4
- package/src/dispatch-effect.ts +142 -26
- package/src/durability.ts +2 -0
- package/src/duration.ts +20 -0
- package/src/effect-checks.ts +2 -1
- package/src/effect.ts +60 -7
- package/src/effector-wire.ts +272 -27
- package/src/gate-brand.ts +16 -0
- package/src/gate.ts +634 -48
- package/src/harness-client.ts +10 -4
- package/src/held-secrets.ts +72 -23
- package/src/holds.ts +2 -2
- package/src/hook-kinds/discord.ts +92 -0
- package/src/hook-kinds/door.ts +107 -0
- package/src/hook-kinds/github.ts +89 -0
- package/src/hook-kinds/gitlab.ts +72 -0
- package/src/hook-kinds/hook.ts +7 -0
- package/src/hook-kinds/index.ts +465 -0
- package/src/hook-kinds/slack.ts +151 -0
- package/src/hook-kinds/webhook.ts +113 -0
- package/src/hooks.ts +506 -0
- package/src/http-effect.ts +76 -38
- package/src/http.ts +889 -94
- package/src/index.ts +16 -5
- package/src/instance.ts +196 -26
- package/src/internal.ts +22 -3
- package/src/machine-doc.ts +26 -1
- package/src/mcp-effect.ts +424 -0
- package/src/mount-digest.ts +41 -7
- package/src/names.ts +64 -2
- package/src/notices.ts +138 -10
- package/src/open-body.ts +25 -11
- package/src/open-effect.ts +17 -4
- package/src/open.ts +4 -2
- package/src/parts.ts +87 -9
- package/src/party.ts +2 -1
- package/src/pick.ts +2 -2
- package/src/pool.ts +1142 -163
- package/src/registration.ts +203 -13
- package/src/run-host.ts +1509 -171
- package/src/run-list.ts +191 -0
- package/src/sandbox-kube.ts +53 -5
- package/src/secret-placement.ts +239 -33
- package/src/server.ts +53 -4
- package/src/setup.ts +72 -32
- package/src/snapshot-store.ts +565 -48
- package/src/steer.ts +111 -0
- package/src/stub-harness.ts +6 -2
- package/src/tokens.ts +263 -22
- package/src/wire.ts +17 -0
- package/src/workspace.ts +50 -6
- package/src/worktree.ts +3 -3
- package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +0 -65
package/src/setup.ts
CHANGED
|
@@ -50,7 +50,8 @@ import { isAgent } from "./agent.ts";
|
|
|
50
50
|
import { isEffect } from "./effect.ts";
|
|
51
51
|
import type { AnyFramePath, FramePath, WorktreePath, WorktreeReady } from "./worktree.ts";
|
|
52
52
|
import { effectChecks, refuseUnroutedOutcome } from "./effect-checks.ts";
|
|
53
|
-
import {
|
|
53
|
+
import { isGateInvoke } from "./gate-brand.ts";
|
|
54
|
+
import { isGateSlot, plainGate, settlesOnItsOwn, type PlainGate } from "./gate.ts";
|
|
54
55
|
import { attachLent, isOpenBody, openBodyDeclarationOf, type LentParts } from "./open-body.ts";
|
|
55
56
|
import { refuseInlineParts } from "./parts.ts";
|
|
56
57
|
import { partyWarnings, refuseSlotActiveTwice, refuseUnknownSentBy, SENT_BY, sentByGuard } from "./party.ts";
|
|
@@ -112,7 +113,7 @@ type SentByGuards = { [SENT_BY]: { id: string } };
|
|
|
112
113
|
/** The jr2 actor every workflow can invoke by name without listing it (ADR-0015). `gate` is the
|
|
113
114
|
* whole set: an Agent is not pre-registered, because it is not one logic — it is the slot the
|
|
114
115
|
* Machine declares, `actors: { coder: agent(def) }` (ADR-0049). */
|
|
115
|
-
const jr2Actors = { gate };
|
|
116
|
+
const jr2Actors: { gate: PlainGate } = { gate: plainGate };
|
|
116
117
|
type JR2Actors = typeof jr2Actors;
|
|
117
118
|
|
|
118
119
|
/**
|
|
@@ -212,7 +213,9 @@ type BindActors<A extends Record<string, UnknownActorLogic>, TInput, TContext> =
|
|
|
212
213
|
* `defineEvent` events you list, plus the events jr2 itself sends (`agent.fault`,
|
|
213
214
|
* `workspace.lost`). An event that a party sent has `event.sender`. A Machine that takes no
|
|
214
215
|
* workflow event leaves out `events`.
|
|
215
|
-
* - The `gate` actor is ready to invoke by name: `invoke: { src: "gate" }`.
|
|
216
|
+
* - The `gate` actor is ready to invoke by name: `invoke: { src: "gate" }`. A Gate slot that hears a
|
|
217
|
+
* Hook (`actors: { review: gate({ … }) }`) is invoked by its key. An event in its `delivers` whose
|
|
218
|
+
* def leaves `audience` unset is `audience: "external"` in this Machine.
|
|
216
219
|
* - Each Agent slot (`actors: { coder: agent(…) }`) gets its Menu from the states that invoke it.
|
|
217
220
|
* - The `sentBy(id)` guard is ready to use.
|
|
218
221
|
* - `createMachine` also takes `input`: a zod object for the input that starts a run. jr2 checks
|
|
@@ -269,6 +272,13 @@ type BindActors<A extends Record<string, UnknownActorLogic>, TInput, TContext> =
|
|
|
269
272
|
* run an Agent`: the body sends it a Chart's unrouted `agent.fault`. When both kinds have no route,
|
|
270
273
|
* one line names both, joined by `, and`. One route on the root is a route for each state. A
|
|
271
274
|
* Chart's Machine does not get this refusal: in a Chart the route is optional (ADR-0070).
|
|
275
|
+
* - an event in a Gate slot's `delivers` that `events` does not list: ``machine "<id>": Gate slot
|
|
276
|
+
* "<slot>" delivers "<name>", which no def in jr2Setup({ events }) declares (declared: <names>) —
|
|
277
|
+
* list it in events (ADR-0011)``
|
|
278
|
+
* - an event in a Gate slot's `delivers` that the Gate does not accept at a state that invokes it:
|
|
279
|
+
* ``machine "<id>": state "<state>" invokes Gate slot "<slot>", which delivers "<name>", and its
|
|
280
|
+
* Gate does not accept it (accepts: <names>) — no handler or look could deliver it: handle it on
|
|
281
|
+
* that state, a state above it or a plain child, or drop it from delivers (ADR-0011)``
|
|
272
282
|
*
|
|
273
283
|
* It also refuses a `sentBy` that names no party (see `sentBy`). It refuses a pick param that
|
|
274
284
|
* nothing reads, where the pick enters a state that invokes an Effect (see `fromPick`). Shapes that
|
|
@@ -358,7 +368,8 @@ export function jr2Setup<
|
|
|
358
368
|
* listed, if it is not a jr2 or xstate event (an event with a `.` in its name). */
|
|
359
369
|
events?: TDefs;
|
|
360
370
|
/** The actors the states invoke by name, as in `setup()`: Agent slots (`agent(…)`), Effects
|
|
361
|
-
* (`command(…)`, `http(…)`, `push(…)`), child Machines, `workspace(…)`
|
|
371
|
+
* (`command(…)`, `http(…)`, `push(…)`), Gate slots (`gate({ … })`), child Machines, `workspace(…)`
|
|
372
|
+
* and plain xstate logic.
|
|
362
373
|
* The key is the slot's name. An actor named `gate` replaces jr2's Gate. */
|
|
363
374
|
actors?: TActors;
|
|
364
375
|
/** Named actions, as in `setup()`. Their `event` has the type of this Machine's events. */
|
|
@@ -429,6 +440,10 @@ export function jr2Setup<
|
|
|
429
440
|
// Resolve the defs first (duplicates and reserved semantics fail HERE, naming the machine —
|
|
430
441
|
// the same loud failure `eventMap` gave the manifest, moved to machine-build time)…
|
|
431
442
|
const defs = eventMap((machineConfig as { id?: string }).id ?? "(machine)", def.events ?? []);
|
|
443
|
+
// A Gate slot's `delivers` (ADR-0011, ADR-0015): each name is one of this Machine's events, and
|
|
444
|
+
// one whose def leaves the audience unset reads as `external`, so no Agent has a Hook's event on
|
|
445
|
+
// its Menu. Before the Menus derive, so the walk, the Menu and the runtime read one vocabulary.
|
|
446
|
+
externalDelivers((machineConfig as { id?: string }).id ?? "(machine)", defs, def.actors ?? {});
|
|
432
447
|
|
|
433
448
|
// Every Open body slot (ADR-0070), found by its brand: each name it lends resolves against THIS
|
|
434
449
|
// setup's own parts, or the Machine is refused naming it. The resolved set is stamped on the slot,
|
|
@@ -441,6 +456,12 @@ export function jr2Setup<
|
|
|
441
456
|
// ADR-0007 restore path and invoke-time `resolveAccepts` validation are unchanged.
|
|
442
457
|
const derived = deriveMenus(machineConfig, defs, def.actors ?? {});
|
|
443
458
|
const machine = (inner.createMachine as unknown as (c: never) => AnyStateMachine)(derived.config as never);
|
|
459
|
+
// A Gate slot's event that its state's Gate does not accept (ADR-0011): no handler or look could
|
|
460
|
+
// ever deliver it.
|
|
461
|
+
if (derived.refused.length) {
|
|
462
|
+
const idOf = (path: readonly string[]): string => stateAt(machine, path).id;
|
|
463
|
+
throw new Error(`machine "${machine.id}": ${derived.refused.map((r) => r(idOf)).join("; ")}`);
|
|
464
|
+
}
|
|
444
465
|
|
|
445
466
|
// Close the nested-`on` typo hole (ADR-0015): with the manifest dead, a typo'd key would
|
|
446
467
|
// silently become vocabulary — so every non-dotted key the machine handles anywhere must map
|
|
@@ -603,7 +624,7 @@ function deriveMenus(
|
|
|
603
624
|
config: unknown,
|
|
604
625
|
defs: Map<string, EventDef>,
|
|
605
626
|
actors: Record<string, UnknownActorLogic>,
|
|
606
|
-
): { config: unknown; seats: Seat[]; warnings: Warning[]; derivedGateIds: Set<string
|
|
627
|
+
): { config: unknown; seats: Seat[]; warnings: Warning[]; derivedGateIds: Set<string>; refused: Warning[] } {
|
|
607
628
|
const pick = (reach: Reach, kind: "agent" | "external", self: string): string[] =>
|
|
608
629
|
[...reach]
|
|
609
630
|
.filter(([name, owners]) => {
|
|
@@ -623,6 +644,8 @@ function deriveMenus(
|
|
|
623
644
|
const parties = new Map<string, { agents: string[]; gate: boolean }>();
|
|
624
645
|
// The Gate invoke ids this walk names: a party warning says how to name one instead.
|
|
625
646
|
const derivedGateIds = new Set<string>();
|
|
647
|
+
// A Gate slot's `delivers` that its state's Gate does not accept (ADR-0011): refusals.
|
|
648
|
+
const refused: Warning[] = [];
|
|
626
649
|
|
|
627
650
|
const walk = (
|
|
628
651
|
node: LooseState,
|
|
@@ -645,7 +668,7 @@ function deriveMenus(
|
|
|
645
668
|
const invokes = Array.isArray(node.invoke) ? node.invoke : [node.invoke];
|
|
646
669
|
// >1 unnamed gate in one state would collide on the state-key id; suffix ONLY then, so
|
|
647
670
|
// the common case (one gate per state) keeps the clean name.
|
|
648
|
-
const unnamedGates = invokes.filter((inv) => inv
|
|
671
|
+
const unnamedGates = invokes.filter((inv) => isGateInvoke(inv, actors) && inv.id == null).length;
|
|
649
672
|
let ordinal = 0;
|
|
650
673
|
const wrapOne = (inv: LooseInvoke): LooseInvoke => {
|
|
651
674
|
// The slot key IS the Agent name (ADR-0049) — read off the declaration, never authored.
|
|
@@ -678,7 +701,7 @@ function deriveMenus(
|
|
|
678
701
|
seats.push({ path, party: "agent", agent: inv.src, names: [...derived].sort() });
|
|
679
702
|
return { ...inv, input: wrapAgentInput(inv.input, derived, inv.src, menuOf) };
|
|
680
703
|
}
|
|
681
|
-
if (inv
|
|
704
|
+
if (isGateInvoke(inv, actors)) {
|
|
682
705
|
// A Gate's plain children — below it, with no party-invoking state between — are its own
|
|
683
706
|
// by position, as an Agent's modes are its (ADR-0015).
|
|
684
707
|
const reach: Reach = new Map([...names].map(([name, owners]) => [name, new Set(owners)]));
|
|
@@ -686,6 +709,20 @@ function deriveMenus(
|
|
|
686
709
|
reach.set(name, (reach.get(name) ?? new Set<string>()).add(owner));
|
|
687
710
|
const accepts = pick(reach, "external", owner);
|
|
688
711
|
seats.push({ path, party: "gate", names: [...accepts].sort() });
|
|
712
|
+
const slot = typeof inv.src === "string" ? actors[inv.src] : undefined;
|
|
713
|
+
if (isGateSlot(slot)) {
|
|
714
|
+
const outside = slot.gateSlot.delivers.map((d) => d.name).filter((name) => !accepts.includes(name));
|
|
715
|
+
if (outside.length) {
|
|
716
|
+
const name = inv.src as string;
|
|
717
|
+
refused.push(
|
|
718
|
+
(idOf) =>
|
|
719
|
+
`state "${idOf(path)}" invokes Gate slot "${name}", which delivers ${outside.map((n) => `"${n}"`).join(", ")}, ` +
|
|
720
|
+
`and its Gate does not accept ${outside.length > 1 ? "them" : "it"} (accepts: ${accepts.join(", ") || "nothing"}) — ` +
|
|
721
|
+
"no handler or look could deliver it: handle it on that state, a state above it or a plain child, " +
|
|
722
|
+
"or drop it from delivers (ADR-0011)",
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
689
726
|
const wrapped: LooseInvoke = { ...inv, input: wrapGateInput(inv.input, accepts) };
|
|
690
727
|
// A machine-root gate (empty path) is left to xstate's default id: a `""` id would be
|
|
691
728
|
// worse than a noisy one, and the derived gate id still works.
|
|
@@ -710,7 +747,7 @@ function deriveMenus(
|
|
|
710
747
|
};
|
|
711
748
|
|
|
712
749
|
const out = walk(config as LooseState, new Map(), new Map(), [], NOBODY);
|
|
713
|
-
return { config: out, seats, warnings: [...warnings.values()], derivedGateIds };
|
|
750
|
+
return { config: out, seats, warnings: [...warnings.values()], derivedGateIds, refused };
|
|
714
751
|
}
|
|
715
752
|
|
|
716
753
|
/**
|
|
@@ -845,7 +882,7 @@ function unenteredModes(machine: AnyStateMachine, actors: Record<string, Unknown
|
|
|
845
882
|
continue;
|
|
846
883
|
}
|
|
847
884
|
const party = child.invoke.some(
|
|
848
|
-
(inv) => inv
|
|
885
|
+
(inv) => isGateInvoke(inv, actors) || (typeof inv.src === "string" && isAgent(actors[inv.src])),
|
|
849
886
|
);
|
|
850
887
|
if (!party) descend(child);
|
|
851
888
|
continue;
|
|
@@ -868,27 +905,6 @@ function unenteredModes(machine: AnyStateMachine, actors: Record<string, Unknown
|
|
|
868
905
|
return out;
|
|
869
906
|
}
|
|
870
907
|
|
|
871
|
-
/**
|
|
872
|
-
* Does this logic settle on its own — a promise, the one plain xstate actor that ends without being
|
|
873
|
-
* stopped? Asked of its own transition: a promise logic's initial snapshot, sent xstate's resolve
|
|
874
|
-
* event, is `done`. That event name is an xstate internal (5.32.2); a bump that renamed it would
|
|
875
|
-
* make every promise read long-lived, and setup.test.ts pins it against the real constructors.
|
|
876
|
-
*/
|
|
877
|
-
function settlesOnItsOwn(logic: unknown): boolean {
|
|
878
|
-
const l = logic as {
|
|
879
|
-
getInitialSnapshot?: (scope: unknown, input: unknown) => unknown;
|
|
880
|
-
transition?: (snapshot: unknown, event: unknown, scope: unknown) => { status?: string } | undefined;
|
|
881
|
-
};
|
|
882
|
-
if (typeof l?.getInitialSnapshot !== "function" || typeof l.transition !== "function") return false;
|
|
883
|
-
try {
|
|
884
|
-
const scope = { self: {}, defer: () => {}, emit: () => {} };
|
|
885
|
-
const snapshot = l.getInitialSnapshot(scope, undefined);
|
|
886
|
-
return l.transition(snapshot, { type: "xstate.promise.resolve", data: undefined }, scope)?.status === "done";
|
|
887
|
-
} catch {
|
|
888
|
-
return false;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
|
|
892
908
|
/**
|
|
893
909
|
* The load walk's Rest warnings (ADR-0024): shapes below an Agent's state that keep it from Rest, so
|
|
894
910
|
* every pick of the Agent is refused for longer than the author likely meant. Warnings, never
|
|
@@ -918,7 +934,7 @@ function restWarnings(machine: AnyStateMachine, actors: Record<string, UnknownAc
|
|
|
918
934
|
for (const inv of child.invoke) {
|
|
919
935
|
const logic = logicOf(inv.src);
|
|
920
936
|
const name = typeof inv.src === "string" ? inv.src : inv.id;
|
|
921
|
-
if (inv
|
|
937
|
+
if (isGateInvoke(inv, actors)) {
|
|
922
938
|
for (const [event, candidates] of child.transitions) {
|
|
923
939
|
if (event.includes(".") || event === "*") continue;
|
|
924
940
|
if (candidates.some((t) => (t.target ?? []).length > 0)) continue;
|
|
@@ -982,6 +998,7 @@ function stampOpenBodies(
|
|
|
982
998
|
["agents", "an Agent slot (agent(...))", isAgent],
|
|
983
999
|
["effects", "an Effect slot", isEffect],
|
|
984
1000
|
["machines", "a Machine", (l: unknown) => (l as { root?: unknown } | undefined)?.root !== undefined],
|
|
1001
|
+
["gates", "a Gate slot (gate({ … }))", isGateSlot],
|
|
985
1002
|
] as const;
|
|
986
1003
|
for (const [kind, what, test] of actorKinds) {
|
|
987
1004
|
for (const name of decl.lends[kind] ?? []) {
|
|
@@ -1052,6 +1069,29 @@ function stateAt(machine: AnyStateMachine, path: readonly string[]): AnyStateMac
|
|
|
1052
1069
|
return node;
|
|
1053
1070
|
}
|
|
1054
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* The `delivers` of each Gate slot this setup declares (ADR-0011, ADR-0015). Each name must be an
|
|
1074
|
+
* event of the Machine: a handler or a look gives a plain event, which the Machine's own def parses.
|
|
1075
|
+
* An event whose def leaves the audience unset reads as `audience: "external"` in this Machine's
|
|
1076
|
+
* vocabulary, so no Agent of the Machine has it on its Menu, and the author does not have to know
|
|
1077
|
+
* this. An explicit audience stays.
|
|
1078
|
+
*/
|
|
1079
|
+
function externalDelivers(machineId: string, defs: Map<string, EventDef>, actors: Record<string, unknown>): void {
|
|
1080
|
+
for (const [slot, logic] of Object.entries(actors)) {
|
|
1081
|
+
if (!isGateSlot(logic)) continue;
|
|
1082
|
+
for (const d of logic.gateSlot.delivers) {
|
|
1083
|
+
const own = defs.get(d.name);
|
|
1084
|
+
if (!own) {
|
|
1085
|
+
throw new Error(
|
|
1086
|
+
`machine "${machineId}": Gate slot "${slot}" delivers "${d.name}", which no def in jr2Setup({ events }) ` +
|
|
1087
|
+
`declares (declared: ${[...defs.keys()].join(", ") || "none"}) — list it in events (ADR-0011)`,
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
if (own.audience === undefined) defs.set(d.name, Object.freeze({ ...own, audience: "external" as const }));
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1055
1095
|
/** A state's own workflow-event keys: dotted names are jr2's or xstate's, `*` is the wildcard. */
|
|
1056
1096
|
function ownPicks(node: LooseState): string[] {
|
|
1057
1097
|
return Object.keys(node.on ?? {}).filter((key) => !key.includes(".") && key !== "*");
|
|
@@ -1062,7 +1102,7 @@ function partiesOf(node: LooseState, actors: Record<string, UnknownActorLogic>):
|
|
|
1062
1102
|
const invokes = node.invoke ? (Array.isArray(node.invoke) ? node.invoke : [node.invoke]) : [];
|
|
1063
1103
|
return {
|
|
1064
1104
|
agents: invokes.flatMap((inv) => (typeof inv?.src === "string" && isAgent(actors[inv.src]) ? [inv.src] : [])),
|
|
1065
|
-
gate: invokes.some((inv) => inv
|
|
1105
|
+
gate: invokes.some((inv) => isGateInvoke(inv, actors)),
|
|
1066
1106
|
};
|
|
1067
1107
|
}
|
|
1068
1108
|
|