@jr2/orchestrator 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +142 -29
- package/docs/concepts/architecture.md +60 -34
- package/docs/concepts/callers-and-hooks.md +205 -0
- package/docs/concepts/charts.md +13 -8
- package/docs/concepts/composition.md +10 -1
- package/docs/concepts/converge.md +7 -2
- package/docs/concepts/durable-runs.md +43 -16
- package/docs/concepts/effects.md +133 -50
- package/docs/concepts/gates.md +95 -25
- package/docs/concepts/machines-and-workflows.md +14 -4
- package/docs/concepts/pools-and-sources.md +193 -17
- package/docs/concepts/secrets-and-trust.md +186 -62
- package/docs/concepts/the-menu.md +14 -0
- package/docs/concepts/workspaces.md +135 -56
- package/docs/get-started/a-model-decides.md +14 -13
- package/docs/get-started/an-agent-in-a-sandbox.md +46 -35
- package/docs/get-started/connect-a-model.md +1 -1
- package/docs/get-started/create-an-instance.md +17 -14
- package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
- package/docs/get-started/install.md +4 -0
- package/docs/guides/add-tools-to-the-sandbox.md +72 -15
- 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 +29 -12
- 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/cut-a-worktree.md +560 -0
- package/docs/guides/fix-a-failed-converge.md +19 -7
- 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 +14 -7
- package/docs/guides/look-inside-a-sandbox.md +115 -42
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
- package/docs/guides/open-the-console.md +63 -14
- package/docs/guides/push-and-sign-a-branch.md +67 -21
- package/docs/guides/read-a-conversation.md +225 -0
- package/docs/guides/run-a-chart-by-name.md +17 -16
- package/docs/guides/run-a-command-or-call-a-url.md +84 -41
- package/docs/guides/run-one-worker-per-item.md +34 -27
- package/docs/guides/set-an-agents-access-and-dials.md +69 -22
- package/docs/guides/size-a-workspace.md +19 -6
- 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 +7 -1
- package/docs/guides/watch-a-run.md +146 -117
- 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 +18 -8
- package/docs/llms.txt +110 -23
- package/docs/reference/authoring-surface/agent.md +35 -12
- package/docs/reference/authoring-surface/answer.md +20 -4
- package/docs/reference/authoring-surface/arg.md +28 -6
- 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 +15 -0
- 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 +37 -22
- 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 +18 -5
- package/docs/reference/authoring-surface/file.md +37 -17
- 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 +109 -9
- package/docs/reference/authoring-surface/isfailure.md +1 -1
- package/docs/reference/authoring-surface/isready.md +14 -0
- package/docs/reference/authoring-surface/jr2setup.md +14 -4
- package/docs/reference/authoring-surface/mcp.md +107 -0
- package/docs/reference/authoring-surface/open.md +41 -8
- package/docs/reference/authoring-surface/openbody.md +1 -1
- package/docs/reference/authoring-surface/paramsof.md +23 -5
- package/docs/reference/authoring-surface/pool.md +79 -11
- package/docs/reference/authoring-surface/push.md +31 -13
- package/docs/reference/authoring-surface/readyof.md +21 -0
- package/docs/reference/authoring-surface/reread.md +19 -0
- package/docs/reference/authoring-surface/secret.md +26 -5
- 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 +59 -4
- 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 +16 -3
- package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
- package/docs/reference/authoring-surface/type-agentslots.md +4 -1
- package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
- package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
- package/docs/reference/authoring-surface/type-bindactors.md +14 -0
- package/docs/reference/authoring-surface/type-binding.md +6 -7
- 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-commandinput.md +4 -3
- package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
- package/docs/reference/authoring-surface/type-commandoutput.md +23 -5
- package/docs/reference/authoring-surface/type-customize.md +20 -3
- 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 +9 -2
- package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
- package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
- package/docs/reference/authoring-surface/type-filebody.md +4 -8
- package/docs/reference/authoring-surface/type-framepath.md +14 -0
- 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 +3 -5
- package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
- package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
- package/docs/reference/authoring-surface/type-httpoutput.md +8 -2
- package/docs/reference/authoring-surface/type-jr2config.md +37 -2
- package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
- 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-namestart.md +77 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
- package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
- 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-opencommandinput.md +7 -2
- package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
- package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
- package/docs/reference/authoring-surface/type-poolspec.md +11 -6
- package/docs/reference/authoring-surface/type-pushinput.md +22 -3
- package/docs/reference/authoring-surface/type-pushoutput.md +33 -8
- 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 +6 -6
- 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-sandboxoptions.md +11 -4
- 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-slothandles.md +5 -13
- 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 +26 -17
- 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 +30 -9
- package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
- package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
- package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
- package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
- package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
- package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
- package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
- package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
- package/docs/reference/authoring-surface/workspace.md +66 -38
- package/docs/reference/authoring-surface/worktree.md +71 -0
- package/docs/reference/authoring-surface.md +88 -147
- package/docs/reference/cli.md +413 -74
- package/docs/reference/config.md +248 -6
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +81 -14
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +39 -25
- package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
- 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 +39 -32
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +54 -30
- 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 +26 -16
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -10
- 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 +53 -27
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +16 -2
- 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 +124 -43
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +36 -38
- 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 +16 -7
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +36 -19
- 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 -15
- 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 +22 -22
- 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 +13 -12
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +23 -23
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
- package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
- 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 +31 -24
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +18 -10
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +137 -86
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +165 -91
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +7 -7
- 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 +53 -23
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +221 -153
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +161 -96
- 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 +48 -33
- 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/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
- package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +296 -0
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +347 -0
- package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
- 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 +9 -4
- package/docs/reference/glossary.md +138 -45
- package/docs/reference/hooks.md +1077 -0
- package/docs/reference/http-api.md +988 -123
- package/docs/reference/machines.md +0 -1
- package/docs/why.md +7 -5
- package/package.json +10 -3
- package/src/actor.ts +194 -42
- package/src/agent.ts +56 -6
- package/src/ambient.ts +3 -5
- package/src/assembly-checks.ts +530 -4
- package/src/callers.ts +245 -0
- package/src/chart.ts +238 -26
- package/src/charts.ts +9 -2
- package/src/config.ts +566 -7
- package/src/conversations.ts +453 -0
- package/src/custodian.lua +17 -5
- package/src/custodian.ts +257 -77
- package/src/customize.ts +154 -7
- package/src/dispatch-effect.ts +142 -26
- package/src/durability.ts +2 -0
- package/src/duration.ts +20 -0
- package/src/effect-checks.ts +52 -4
- package/src/effect.ts +401 -132
- package/src/effector-wire.ts +278 -30
- package/src/fail.ts +17 -4
- package/src/gate-brand.ts +16 -0
- package/src/gate.ts +634 -48
- package/src/harness-client.ts +84 -35
- package/src/harness-env.ts +33 -0
- package/src/held-secrets.ts +197 -39
- package/src/holds.ts +5 -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 +164 -70
- package/src/http.ts +933 -99
- package/src/index.ts +30 -5
- package/src/instance.ts +196 -26
- package/src/internal.ts +23 -3
- package/src/kube-client.ts +6 -3
- package/src/machine-doc.ts +29 -5
- package/src/mcp-effect.ts +424 -0
- package/src/model-keys.ts +24 -0
- package/src/mount-digest.ts +41 -7
- package/src/names.ts +82 -7
- package/src/notices.ts +576 -59
- package/src/open-body.ts +110 -30
- package/src/open-effect.ts +17 -4
- package/src/open.ts +40 -7
- package/src/parts.ts +125 -35
- package/src/party.ts +35 -1
- package/src/pick.ts +43 -9
- package/src/pool.ts +1172 -172
- package/src/registration.ts +249 -17
- package/src/repo-identity.ts +7 -3
- package/src/repos.ts +20 -2
- package/src/run-host.ts +1614 -190
- package/src/run-list.ts +191 -0
- package/src/sandbox-effect.ts +217 -66
- package/src/sandbox-kube.ts +116 -21
- package/src/secret-placement.ts +248 -35
- package/src/server.ts +53 -4
- package/src/setup.ts +158 -38
- package/src/snapshot-store.ts +565 -48
- package/src/steer.ts +111 -0
- package/src/stub-harness.ts +6 -2
- package/src/tokens.ts +362 -46
- package/src/vocabulary.ts +23 -4
- package/src/wire.ts +27 -10
- package/src/workspace.ts +314 -259
- package/src/worktree.ts +249 -0
- package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
- package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
- 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/harness-client.ts
CHANGED
|
@@ -83,6 +83,7 @@ import {
|
|
|
83
83
|
MAX_KILLS_BODY,
|
|
84
84
|
MAX_TOLD,
|
|
85
85
|
type Notice,
|
|
86
|
+
type SteeringMessage,
|
|
86
87
|
type Settlement,
|
|
87
88
|
type StreamEvent,
|
|
88
89
|
type SubmissionSettledEvent,
|
|
@@ -107,10 +108,15 @@ export type HarnessClient = {
|
|
|
107
108
|
* `/work` — the stub-Harness run with no Workspace. */
|
|
108
109
|
cwd?: string;
|
|
109
110
|
definition: AgentDefinition;
|
|
111
|
+
/** The Agent's slot (ADR-0076), which the Harness states on each control request for this
|
|
112
|
+
* conversation. Omitted only by a caller that drives no Machine (a test of the wire). */
|
|
113
|
+
slot?: string;
|
|
110
114
|
model?: string;
|
|
111
115
|
thinkingLevel?: ThinkingLevel;
|
|
112
116
|
/** The pending notices in this admission's scope (ADR-0062). Omitted when there are none. */
|
|
113
117
|
notices?: Notice[];
|
|
118
|
+
/** The Steering messages held for this Agent slot (ADR-0002). Omitted when there are none. */
|
|
119
|
+
steering?: SteeringMessage[];
|
|
114
120
|
/** The admission is for a conversation this process was told the Harness keeps (ADR-0062).
|
|
115
121
|
* The Harness that keeps none answers 404 and seats none: this verb throws
|
|
116
122
|
* {@link ConversationNotKept}. */
|
|
@@ -382,12 +388,15 @@ export function createHarnessClient(options: HarnessClientOptions): HarnessClien
|
|
|
382
388
|
// `machine-doc.ts` and the surface read it — and the Harness neither validates nor
|
|
383
389
|
// uses it, so it has no business on the Turn's wire.
|
|
384
390
|
definition: admittedDefinition(sendOptions.definition),
|
|
391
|
+
// Who the conversation is (ADR-0076): the Harness states it on each control request.
|
|
392
|
+
...(sendOptions.slot === undefined ? {} : { slot: sendOptions.slot }),
|
|
385
393
|
// Omitted when unset, so an admission with no dials is byte-identical to before.
|
|
386
394
|
...(sendOptions.model ? { model: sendOptions.model } : {}),
|
|
387
395
|
...(sendOptions.thinkingLevel ? { thinkingLevel: sendOptions.thinkingLevel } : {}),
|
|
388
396
|
// The Briefing's news (ADR-0062): typed data, the Harness writes the words. Omitted
|
|
389
397
|
// when there is none, so an admission without notices is byte-identical to before.
|
|
390
398
|
...(sendOptions.notices?.length ? { notices: sendOptions.notices } : {}),
|
|
399
|
+
...(sendOptions.steering?.length ? { steering: sendOptions.steering } : {}),
|
|
391
400
|
// Omitted when unset, so an admission that is not for a kept conversation is
|
|
392
401
|
// byte-identical to before.
|
|
393
402
|
...(sendOptions.kept ? { kept: true } : {}),
|
|
@@ -608,10 +617,11 @@ export function createHarnessClient(options: HarnessClientOptions): HarnessClien
|
|
|
608
617
|
|
|
609
618
|
/** The definition as the ADMISSION carries it (ADR-0057): identity alone. `description` is
|
|
610
619
|
* Console material the Orchestrator strips before admission — the Harness has no use for it and
|
|
611
|
-
* no longer validates it.
|
|
612
|
-
* the
|
|
613
|
-
|
|
614
|
-
|
|
620
|
+
* no longer validates it. `steerable` is the Orchestrator's own (ADR-0002): it refuses Callers,
|
|
621
|
+
* and the model never reads it. Every other field travels, so a field added to the definition
|
|
622
|
+
* reaches the Harness without a change here. */
|
|
623
|
+
function admittedDefinition(definition: AgentDefinition): Omit<AgentDefinition, "description" | "steerable"> {
|
|
624
|
+
const { description: _description, steerable: _steerable, ...identity } = definition;
|
|
615
625
|
return identity;
|
|
616
626
|
}
|
|
617
627
|
|
|
@@ -629,9 +639,11 @@ export function harnessAgentRunPort(client: HarnessClient): AgentRunPort {
|
|
|
629
639
|
// to the Harness's refusal if it is not a path.
|
|
630
640
|
...(input.cwd === undefined ? {} : { cwd: input.cwd }),
|
|
631
641
|
definition: opts.definition,
|
|
642
|
+
slot: opts.slot,
|
|
632
643
|
model: input.model,
|
|
633
644
|
thinkingLevel: input.thinkingLevel,
|
|
634
645
|
...(opts.notices?.length ? { notices: opts.notices } : {}),
|
|
646
|
+
...(opts.steering?.length ? { steering: opts.steering } : {}),
|
|
635
647
|
...(opts.kept ? { kept: true } : {}),
|
|
636
648
|
signal: opts.signal,
|
|
637
649
|
});
|
|
@@ -751,8 +763,9 @@ export function createLiveSetPush(options: {
|
|
|
751
763
|
* `invoke: { src: "coder", input: { prompt } }`. The key is the Agent's name.
|
|
752
764
|
*
|
|
753
765
|
* The invoke's `input` is the Turn: `prompt` (required), `cwd`, `model`, `thinkingLevel` and
|
|
754
|
-
* `continue`. `cwd` is the absolute directory where the Working tools work.
|
|
755
|
-
*
|
|
766
|
+
* `continue`. `cwd` is the absolute directory where the Working tools work. Under Repo Slots it
|
|
767
|
+
* is required: a Worktree that a cut made, `<slot>/default` to read, or `/work`. An Agent with
|
|
768
|
+
* `workspace: "none"`, and a Workspace with no Repo Slot, need no `cwd`. `continue: true` continues the Agent's conversation
|
|
756
769
|
* in this Machine. Absent, each Turn starts a new conversation. `continue` is the literal `true`,
|
|
757
770
|
* not a `boolean`. A Turn can join only a conversation that an earlier Turn started with
|
|
758
771
|
* `continue: true`. Thus in a retry loop, put `continue: true` on each Turn, also on the first, so
|
|
@@ -778,10 +791,9 @@ export function createLiveSetPush(options: {
|
|
|
778
791
|
* - a key in `input` that a Turn does not have: ``agent "<slot>": the Turn's input carries
|
|
779
792
|
* `<key>`, which a Turn has no use for — its input is its Frame (`prompt`, `cwd`), its Dials
|
|
780
793
|
* (`model`, `thinkingLevel`), and `continue` (ADR-0057)``
|
|
781
|
-
* - no `cwd` under
|
|
782
|
-
*
|
|
783
|
-
*
|
|
784
|
-
* the kit gives no slot a meaning (ADR-0051) and a Turn's Frame is where it works (ADR-0057)``
|
|
794
|
+
* - no `cwd` under Repo Slots: ``turn <id>: agent "<slot>" works under a Workspace with Repo Slots
|
|
795
|
+
* (<slots>) and its Turn framed no `cwd`: say where it works, a Worktree, or `cwd: "/work"` above
|
|
796
|
+
* them (ADR-0057)``
|
|
785
797
|
* - a `cwd` that is not an absolute path: ``agent "<slot>": the Turn's Frame carries a `cwd` that
|
|
786
798
|
* is not an absolute path — the Frame says WHERE this Turn works (ADR-0057), and a Turn rooted
|
|
787
799
|
* anywhere else would work in the wrong directory silently``. The Harness makes this refusal
|
|
@@ -801,7 +813,16 @@ export function createLiveSetPush(options: {
|
|
|
801
813
|
* @example
|
|
802
814
|
* ```ts
|
|
803
815
|
* import { z } from "zod";
|
|
804
|
-
* import {
|
|
816
|
+
* import {
|
|
817
|
+
* agent,
|
|
818
|
+
* defineEvent,
|
|
819
|
+
* fail,
|
|
820
|
+
* isReady,
|
|
821
|
+
* jr2Setup,
|
|
822
|
+
* workspace,
|
|
823
|
+
* worktree,
|
|
824
|
+
* type Workspaced,
|
|
825
|
+
* } from "@jr2/orchestrator";
|
|
805
826
|
*
|
|
806
827
|
* const finish = defineEvent({
|
|
807
828
|
* name: "finish",
|
|
@@ -811,6 +832,8 @@ export function createLiveSetPush(options: {
|
|
|
811
832
|
* const runInput = z.object({ branch: z.string() });
|
|
812
833
|
* type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
|
|
813
834
|
*
|
|
835
|
+
* const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
|
|
836
|
+
*
|
|
814
837
|
* const body = jr2Setup({
|
|
815
838
|
* types: {} as { input: BodyInput; context: BodyInput },
|
|
816
839
|
* events: [finish],
|
|
@@ -819,26 +842,35 @@ export function createLiveSetPush(options: {
|
|
|
819
842
|
* model: "anthropic/claude-haiku-5-5",
|
|
820
843
|
* instructions: "You fix failing tests. You change no test.",
|
|
821
844
|
* }),
|
|
845
|
+
* cut: worktree(),
|
|
822
846
|
* fail: fail(),
|
|
823
847
|
* },
|
|
824
848
|
* }).createMachine({
|
|
825
849
|
* id: "fix",
|
|
826
850
|
* context: ({ input }) => input,
|
|
827
851
|
* on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
|
|
828
|
-
* initial: "
|
|
852
|
+
* initial: "cutting",
|
|
829
853
|
* states: {
|
|
854
|
+
* cutting: {
|
|
855
|
+
* invoke: {
|
|
856
|
+
* src: "cut",
|
|
857
|
+
* input: ({ context }) => ({ path: fixTree(context), branch: context.branch }),
|
|
858
|
+
* onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
|
|
859
|
+
* },
|
|
860
|
+
* },
|
|
830
861
|
* coding: {
|
|
831
862
|
* invoke: {
|
|
832
863
|
* src: "coder",
|
|
833
864
|
* input: ({ context }) => ({
|
|
834
865
|
* prompt: "Make `node --test` pass, then commit.",
|
|
835
|
-
* cwd: context
|
|
866
|
+
* cwd: fixTree(context),
|
|
836
867
|
* thinkingLevel: "high",
|
|
837
868
|
* }),
|
|
838
869
|
* },
|
|
839
870
|
* on: { finish: "done" },
|
|
840
871
|
* },
|
|
841
872
|
* done: { type: "final" },
|
|
873
|
+
* notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
842
874
|
* failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
|
|
843
875
|
* lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
|
|
844
876
|
* },
|
|
@@ -847,7 +879,6 @@ export function createLiveSetPush(options: {
|
|
|
847
879
|
* export const machine = workspace(body, {
|
|
848
880
|
* input: runInput,
|
|
849
881
|
* repos: { app: "https://github.com/you/app.git" },
|
|
850
|
-
* spec: ({ input }) => ({ branch: input.branch }),
|
|
851
882
|
* });
|
|
852
883
|
* ```
|
|
853
884
|
*
|
|
@@ -856,6 +887,9 @@ export function createLiveSetPush(options: {
|
|
|
856
887
|
* @see docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md
|
|
857
888
|
* @see docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md
|
|
858
889
|
*/
|
|
890
|
+
export function agent<const D extends AgentDeclaration>(
|
|
891
|
+
declaration: D,
|
|
892
|
+
): AgentLogic & (D extends { workspace: "none" } ? { readonly definition: { readonly workspace: "none" } } : unknown);
|
|
859
893
|
export function agent(declaration: AgentDeclaration): AgentLogic {
|
|
860
894
|
// THE authoring surface for an Agent (ADR-0049): one definition in, one actor slot out. The
|
|
861
895
|
// slot key is the Agent's name (the Harness route, the minted iid, the markers), so a name the
|
|
@@ -956,8 +990,8 @@ export function createExecPort(options: {
|
|
|
956
990
|
*
|
|
957
991
|
* Where it runs:
|
|
958
992
|
* - With no Effect secret in `env`, in the Harness container of the enclosing Workspace's Sandbox.
|
|
959
|
-
* It runs in the Worktree of
|
|
960
|
-
* Agent's Working tools also run in this container.
|
|
993
|
+
* It runs in the Worktree that `worktree` of the invoke's input names, or in `/work` in a
|
|
994
|
+
* Workspace with no Repo Slot. The Agent's Working tools also run in this container.
|
|
961
995
|
* - With an Effect secret in `env`, in the Sandbox Effector, against a commit of the branch. This
|
|
962
996
|
* is the branch tip when it starts, or with `pin: true` the commit that the invoke's `input.sha`
|
|
963
997
|
* names. The output then says `dirty: true` when the Worktree held edits that the command did
|
|
@@ -994,11 +1028,9 @@ export function createExecPort(options: {
|
|
|
994
1028
|
* And when it starts, with no Effect secret in `env`:
|
|
995
1029
|
* - outside a `workspace()`: `command "<slot>" runs in the Harness container of a Workspace, and
|
|
996
1030
|
* its state is not inside a workspace() — invoke it from a Workspace's body (ADR-0067)`
|
|
997
|
-
* - no `
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
* - a `slot` that the Workspace does not have: `command "<slot>" names Repo Slot "<name>", which
|
|
1001
|
-
* its Workspace does not carry (<slots>)`
|
|
1031
|
+
* - no `worktree` under Repo Slots: `` command "<slot>" runs under a Workspace with Repo Slots
|
|
1032
|
+
* (<slots>) and its input names no `worktree`: say which, a Worktree that a cut gave or
|
|
1033
|
+
* `<slot>/default` ``
|
|
1002
1034
|
* - an `arg()` with no string in `input`: `command "<slot>": argv slot <<name>> has no string
|
|
1003
1035
|
* value in its input (got <type>) — map it in the invoke's input`. The angle brackets around the
|
|
1004
1036
|
* arg's name are in the text: `argv slot <file>`. `<type>` is `nothing` when `input` has no such
|
|
@@ -1007,15 +1039,13 @@ export function createExecPort(options: {
|
|
|
1007
1039
|
* And when it starts, with an Effect secret in `env`:
|
|
1008
1040
|
* - outside a `workspace()`: `command "<slot>" runs in the Sandbox Effector of a Workspace, and its
|
|
1009
1041
|
* state is not inside a workspace() — invoke it from a Workspace's body (ADR-0067)`
|
|
1010
|
-
* - no `slot` under a Workspace with more than one Repo Slot: `command "<slot>" runs under a
|
|
1011
|
-
* Workspace carrying more than one Repo Slot (<slots>) — say which: { slot: "<slot>" }
|
|
1012
|
-
* (ADR-0051)`
|
|
1013
1042
|
* - a Workspace with no Repo Slot: `command "<slot>" runs under a Workspace with no Repo Slot: a
|
|
1014
1043
|
* command with an Effect secret runs against one commit of a Repo Slot's branch, and there is
|
|
1015
1044
|
* none — declare a Repo Slot, or name no secret in its env, and it runs in /work beside the Agent
|
|
1016
1045
|
* (ADR-0051)`. `jr2 up` refuses it first, with the same reason
|
|
1017
|
-
* - a `
|
|
1018
|
-
*
|
|
1046
|
+
* - a `worktree` that no cut made in this Sandbox: the output is `exited` 127, with `no cut made
|
|
1047
|
+
* <path> in this Sandbox: cut it with worktree()` in its tail. A detached Worktree gets the same
|
|
1048
|
+
* form
|
|
1019
1049
|
* - `pin: true` and an `input.sha` that is not a full commit id: `command "<slot>" (pin): its
|
|
1020
1050
|
* input's sha is not a full commit id`
|
|
1021
1051
|
* - an `arg()` with no string in `input`: the same text as above.
|
|
@@ -1023,8 +1053,7 @@ export function createExecPort(options: {
|
|
|
1023
1053
|
* @param argv - The program and its arguments: strings and `arg("name")` entries. Or `open`, in a
|
|
1024
1054
|
* Machine that you publish as a package, for the Instance that registers it to bind with
|
|
1025
1055
|
* `customize()`.
|
|
1026
|
-
* @param options - Optional. `
|
|
1027
|
-
* where the Workspace has more than one. `timeout`: `"90s"`, `"10m"` or `"1h"`, default
|
|
1056
|
+
* @param options - Optional. `timeout`: `"90s"`, `"10m"` or `"1h"`, default
|
|
1028
1057
|
* `"10m"`; when it expires, the output is `timeout`. `tail`: how many characters of the end of
|
|
1029
1058
|
* the output stream to keep, default 4096. `env`: environment variables. Each value is
|
|
1030
1059
|
* `secret("name")` for the value of an Effect secret, or `secret("name").path` for the path of a
|
|
@@ -1035,26 +1064,46 @@ export function createExecPort(options: {
|
|
|
1035
1064
|
* @example
|
|
1036
1065
|
* ```ts
|
|
1037
1066
|
* import { z } from "zod";
|
|
1038
|
-
* import {
|
|
1067
|
+
* import {
|
|
1068
|
+
* arg,
|
|
1069
|
+
* command,
|
|
1070
|
+
* fail,
|
|
1071
|
+
* isReady,
|
|
1072
|
+
* jr2Setup,
|
|
1073
|
+
* workspace,
|
|
1074
|
+
* worktree,
|
|
1075
|
+
* type Workspaced,
|
|
1076
|
+
* } from "@jr2/orchestrator";
|
|
1039
1077
|
*
|
|
1040
1078
|
* const runInput = z.object({ branch: z.string() });
|
|
1041
1079
|
* type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
|
|
1042
1080
|
*
|
|
1081
|
+
* const testTree = (context: BodyInput) => `${context.workspace.repos.app}/test` as const;
|
|
1082
|
+
*
|
|
1043
1083
|
* const body = jr2Setup({
|
|
1044
|
-
* types: {} as { input: BodyInput },
|
|
1084
|
+
* types: {} as { input: BodyInput; context: BodyInput },
|
|
1045
1085
|
* actors: {
|
|
1086
|
+
* cut: worktree(),
|
|
1046
1087
|
* tests: command(["node", "--test", arg("file")], { timeout: "5m" }),
|
|
1047
1088
|
* fail: fail(),
|
|
1048
1089
|
* },
|
|
1049
1090
|
* }).createMachine({
|
|
1050
1091
|
* id: "check",
|
|
1092
|
+
* context: ({ input }) => input,
|
|
1051
1093
|
* on: { "workspace.lost": ".lost" },
|
|
1052
|
-
* initial: "
|
|
1094
|
+
* initial: "cutting",
|
|
1053
1095
|
* states: {
|
|
1096
|
+
* cutting: {
|
|
1097
|
+
* invoke: {
|
|
1098
|
+
* src: "cut",
|
|
1099
|
+
* input: ({ context }) => ({ path: testTree(context), branch: context.branch }),
|
|
1100
|
+
* onDone: [{ guard: ({ event }) => isReady(event.output), target: "testing" }, { target: "notCut" }],
|
|
1101
|
+
* },
|
|
1102
|
+
* },
|
|
1054
1103
|
* testing: {
|
|
1055
1104
|
* invoke: {
|
|
1056
1105
|
* src: "tests",
|
|
1057
|
-
* input: { file: "test/greet.test.js" },
|
|
1106
|
+
* input: ({ context }) => ({ file: "test/greet.test.js", worktree: testTree(context) }),
|
|
1058
1107
|
* onDone: [
|
|
1059
1108
|
* {
|
|
1060
1109
|
* guard: ({ event }) => event.output.outcome === "exited" && event.output.code === 0,
|
|
@@ -1067,6 +1116,7 @@ export function createExecPort(options: {
|
|
|
1067
1116
|
* passed: { type: "final" },
|
|
1068
1117
|
* // Not final states: each one fails the run, and the run ends `failed`.
|
|
1069
1118
|
* failed: { invoke: { src: "fail", input: { reason: "the test did not pass" } } },
|
|
1119
|
+
* notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
1070
1120
|
* lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
|
|
1071
1121
|
* },
|
|
1072
1122
|
* });
|
|
@@ -1074,7 +1124,6 @@ export function createExecPort(options: {
|
|
|
1074
1124
|
* export const machine = workspace(body, {
|
|
1075
1125
|
* input: runInput,
|
|
1076
1126
|
* repos: { app: "https://github.com/you/app.git" },
|
|
1077
|
-
* spec: ({ input }) => ({ branch: input.branch }),
|
|
1078
1127
|
* });
|
|
1079
1128
|
* ```
|
|
1080
1129
|
*
|
|
@@ -1086,7 +1135,7 @@ export function createExecPort(options: {
|
|
|
1086
1135
|
export function command<const A extends readonly (string | Arg)[], const Opt extends CommandOptions = CommandOptions>(
|
|
1087
1136
|
argv: A,
|
|
1088
1137
|
options?: Opt,
|
|
1089
|
-
): EffectLogic<CommandInput<A, Opt["pin"]>, CommandOutput> & OpenOf<EnvOpenParts<Opt>>;
|
|
1138
|
+
): EffectLogic<CommandInput<A, Opt["pin"], Opt>, CommandOutput> & OpenOf<EnvOpenParts<Opt>>;
|
|
1090
1139
|
/**
|
|
1091
1140
|
* Make a `command` Effect whose argv is Open: `command(open, options)`, in a Machine that you
|
|
1092
1141
|
* publish as a package. The Instance that registers the Machine binds the argv one time:
|
|
@@ -1103,7 +1152,7 @@ export function command<const A extends readonly (string | Arg)[], const Opt ext
|
|
|
1103
1152
|
export function command<const Opt extends CommandOptions = CommandOptions>(
|
|
1104
1153
|
argv: typeof open,
|
|
1105
1154
|
options?: Opt,
|
|
1106
|
-
): EffectLogic<OpenCommandInput<Opt["pin"]>, CommandOutput> & OpenEffect<"argv" | EnvOpenParts<Opt>>;
|
|
1155
|
+
): EffectLogic<OpenCommandInput<Opt["pin"], Opt>, CommandOutput> & OpenEffect<"argv" | EnvOpenParts<Opt>>;
|
|
1107
1156
|
export function command(
|
|
1108
1157
|
argv: readonly (string | Arg)[] | typeof open,
|
|
1109
1158
|
options: CommandOptions = {},
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// What a Harness container's env tells its start (ADR-0076): which names jr2 composed. The Harness
|
|
2
|
+
// starts as `effector nocore --harness-env -- node …`, and that gives the Harness PROCESS only the
|
|
3
|
+
// names jr2 composed, less each name that loads code from a path (`NODE_OPTIONS`, `LD_*`,
|
|
4
|
+
// `OPENSSL_CONF` …), because the image's `ENV` can name a file that Workspace code writes. The
|
|
5
|
+
// domain, where the Agent's programs run, still gets the container's whole start env.
|
|
6
|
+
//
|
|
7
|
+
// Two marks make the names jr2 composed visible inside the container:
|
|
8
|
+
// - `JR2_HARNESS_ENV_NAMES`: the names of the container's `env`, comma-separated.
|
|
9
|
+
// - The prefix `JR2_ENVFROM_` before each `envFrom` key (with a source's own prefix after it):
|
|
10
|
+
// its keys are not known here, a user's Secret or ConfigMap among them. The start puts each key
|
|
11
|
+
// back under its own name, below a name of `env`, as Kubernetes orders them.
|
|
12
|
+
|
|
13
|
+
/** The env name that lists the names of the Harness container's `env`. */
|
|
14
|
+
export const HARNESS_ENV_NAMES_ENV = "JR2_HARNESS_ENV_NAMES";
|
|
15
|
+
|
|
16
|
+
/** The prefix before each `envFrom` key of a Harness container. */
|
|
17
|
+
export const HARNESS_ENVFROM_PREFIX = "JR2_ENVFROM_";
|
|
18
|
+
|
|
19
|
+
/** The Harness container's `env` with `JR2_HARNESS_ENV_NAMES` last, and its `envFrom` with the
|
|
20
|
+
* prefix `JR2_ENVFROM_`. Both Harness placements use it: a Sandbox's and the Instance Harness. */
|
|
21
|
+
export function markHarnessEnv<E extends { name: string }, F extends { prefix?: string }>(
|
|
22
|
+
env: readonly E[],
|
|
23
|
+
envFrom: readonly F[],
|
|
24
|
+
): { env: (E | { name: string; value: string })[]; envFrom: F[] } {
|
|
25
|
+
const names = [...new Set(env.map((v) => v.name))].filter((n) => n !== HARNESS_ENV_NAMES_ENV);
|
|
26
|
+
return {
|
|
27
|
+
env: [
|
|
28
|
+
...env.filter((v) => v.name !== HARNESS_ENV_NAMES_ENV),
|
|
29
|
+
{ name: HARNESS_ENV_NAMES_ENV, value: names.join(",") },
|
|
30
|
+
],
|
|
31
|
+
envFrom: envFrom.map((f) => ({ ...f, prefix: `${HARNESS_ENVFROM_PREFIX}${f.prefix ?? ""}` })),
|
|
32
|
+
};
|
|
33
|
+
}
|