@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/sandbox-kube.ts
CHANGED
|
@@ -43,8 +43,10 @@
|
|
|
43
43
|
// containers:
|
|
44
44
|
//
|
|
45
45
|
// volume runtime the kit's Harness image, as an `image` volume → /opt/jr2
|
|
46
|
-
// volume conversations an emptyDir → /conversations, the Harness container's alone
|
|
46
|
+
// volume conversations an emptyDir → /run/jr2/conversations, the Harness container's alone
|
|
47
47
|
// (ADR-0031: a Harness restart inside the pod keeps its conversations)
|
|
48
|
+
// volume shell an emptyDir → /run/jr2/shell, the Harness container's alone: the
|
|
49
|
+
// socket of a person's shell (`jr2 workspace shell`, ADR-0076)
|
|
48
50
|
// initContainer preflight the USER'S image + that volume → ADR-0037's probe, the thing that
|
|
49
51
|
// proves a registry ref, whose first appearance is this provision
|
|
50
52
|
// container harness the Sandbox Image, command overridden, /work + /opt/jr2 mounted
|
|
@@ -83,11 +85,14 @@ import {
|
|
|
83
85
|
custodianBootstrap,
|
|
84
86
|
custodianComposition,
|
|
85
87
|
custodianScript,
|
|
88
|
+
CREDENTIAL_KEYS,
|
|
89
|
+
heldStandInKey,
|
|
86
90
|
CUSTODIAN_BOOTSTRAP_KEY,
|
|
87
91
|
CUSTODIAN_SCRIPT_KEY,
|
|
88
92
|
type CustodianComposition,
|
|
89
93
|
} from "./custodian.ts";
|
|
90
|
-
import { readHeldManifest, workspaceHeldPod, type HeldManifest } from "./held-secrets.ts";
|
|
94
|
+
import { heldStandIn, readHeldManifest, workspaceHeldPod, type HeldManifest } from "./held-secrets.ts";
|
|
95
|
+
import { markHarnessEnv } from "./harness-env.ts";
|
|
91
96
|
import {
|
|
92
97
|
effectorManifestKey,
|
|
93
98
|
readSandboxEffectorManifest,
|
|
@@ -102,6 +107,8 @@ import {
|
|
|
102
107
|
CONVERSATIONS_DIR,
|
|
103
108
|
CONVERSATIONS_DIR_ENV,
|
|
104
109
|
CONVERSATIONS_VOLUME,
|
|
110
|
+
SHELL_DIR,
|
|
111
|
+
SHELL_VOLUME,
|
|
105
112
|
HELD_MOUNT,
|
|
106
113
|
CA_CONFIGMAP,
|
|
107
114
|
heldManifestKey,
|
|
@@ -112,6 +119,15 @@ import {
|
|
|
112
119
|
PRIORITY_CLASS_SANDBOX,
|
|
113
120
|
REPOS_MOUNT,
|
|
114
121
|
sandboxCustodianConfigMap,
|
|
122
|
+
ANNOTATION_HOLD,
|
|
123
|
+
ANNOTATION_KEEPALIVE,
|
|
124
|
+
ANNOTATION_WORKSPACE_PATH,
|
|
125
|
+
HOLD_HELD,
|
|
126
|
+
HOLD_RELEASED,
|
|
127
|
+
LABEL_SANDBOX_RUN,
|
|
128
|
+
LABEL_SANDBOX_WORKFLOW,
|
|
129
|
+
LABEL_SANDBOX_WORKSPACE,
|
|
130
|
+
workspaceLabel,
|
|
115
131
|
} from "./names.ts";
|
|
116
132
|
import {
|
|
117
133
|
CONFIGMAPS,
|
|
@@ -133,10 +149,14 @@ import {
|
|
|
133
149
|
type SandboxObject,
|
|
134
150
|
type SandboxWatch,
|
|
135
151
|
} from "./sandbox-watch.ts";
|
|
136
|
-
import { effectorKey, harnessToken, harnessTokenDigest, sandboxToken } from "./tokens.ts";
|
|
152
|
+
import { controlStandIn, controlToken, effectorKey, harnessToken, harnessTokenDigest, sandboxToken } from "./tokens.ts";
|
|
137
153
|
import type { AttachError, AttachRequest, AttachResponse } from "./wire.ts";
|
|
138
154
|
import type { Continuity, MemoryKill, PlacingWait, ProvisionedRepo, SandboxLoss, SandboxPort } from "./workspace.ts";
|
|
139
155
|
|
|
156
|
+
/** A Secret's `data`: each value base64'd. */
|
|
157
|
+
const base64Values = (values: Record<string, string>): Record<string, string> =>
|
|
158
|
+
Object.fromEntries(Object.entries(values).map(([k, v]) => [k, Buffer.from(v).toString("base64")]));
|
|
159
|
+
|
|
140
160
|
/** Where jr2's runtime lands in every container that gets it (ADR-0037). `/opt/jr2` and not `/app`
|
|
141
161
|
* because a stranger's base may already use `/app`, and one layout must serve both the stock
|
|
142
162
|
* Harness image and an arbitrary Sandbox Image. It is a PUBLISHED surface: `bin/` beside `lib/`
|
|
@@ -156,11 +176,21 @@ const RUNTIME_VOLUME_MOUNT = { name: RUNTIME_VOLUME, mountPath: RUNTIME_MOUNT, s
|
|
|
156
176
|
/** The primary container's command (ADR-0037). Absolute, so it never depends on the image's
|
|
157
177
|
* `WORKDIR`, and identical to the stock Harness image's own `CMD` — one runtime, two placements.
|
|
158
178
|
* `tini` is PID 1 (ADR-0061): the Agent's processes are the Harness's children, and a tree the
|
|
159
|
-
* memory guard kills must leave no zombies behind.
|
|
179
|
+
* memory guard kills must leave no zombies behind. The Harness holds the Stand-ins in its memory,
|
|
180
|
+
* and below Landlock ABI 6 a confined child can still signal it (ADR-0076): `effector nocore`
|
|
181
|
+
* starts it with no core file, so a dumping signal writes nothing a child reads, and
|
|
182
|
+
* `--disable-sigusr1` keeps SIGUSR1 from opening Node's inspector, which would run a child's code
|
|
183
|
+
* in the Harness. `--harness-env` gives the Harness process only the names jr2 composed, less each
|
|
184
|
+
* name that loads code from a path, and the domain the whole start env (`harness-env.ts`). */
|
|
160
185
|
const HARNESS_COMMAND = [
|
|
161
186
|
`${RUNTIME_MOUNT}/bin/tini`,
|
|
162
187
|
"--",
|
|
188
|
+
`${RUNTIME_MOUNT}/bin/effector`,
|
|
189
|
+
"nocore",
|
|
190
|
+
"--harness-env",
|
|
191
|
+
"--",
|
|
163
192
|
`${RUNTIME_MOUNT}/bin/node`,
|
|
193
|
+
"--disable-sigusr1",
|
|
164
194
|
`${RUNTIME_MOUNT}/src/main.ts`,
|
|
165
195
|
];
|
|
166
196
|
|
|
@@ -753,6 +783,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
753
783
|
name: string;
|
|
754
784
|
runId: string;
|
|
755
785
|
workflow: string;
|
|
786
|
+
path: string;
|
|
756
787
|
image?: string;
|
|
757
788
|
user?: string;
|
|
758
789
|
workGroup?: number;
|
|
@@ -785,8 +816,16 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
785
816
|
metadata: {
|
|
786
817
|
name: req.name,
|
|
787
818
|
namespace: ns,
|
|
788
|
-
// The run↔workspace link `jr2
|
|
789
|
-
|
|
819
|
+
// The run↔workspace link the `jr2 workspace` verbs read (ADR-0009/0012), without the host:
|
|
820
|
+
// the run, the Workflow and a selector form of the path as labels, the exact path as an
|
|
821
|
+
// annotation. The hold mark is `held` from this first write (ADR-0021); the Lease writes it
|
|
822
|
+
// again with each renewal, and `released` when it stops for good.
|
|
823
|
+
labels: {
|
|
824
|
+
[LABEL_SANDBOX_RUN]: req.runId,
|
|
825
|
+
[LABEL_SANDBOX_WORKFLOW]: req.workflow,
|
|
826
|
+
...(req.path ? { [LABEL_SANDBOX_WORKSPACE]: workspaceLabel(req.path) } : {}),
|
|
827
|
+
},
|
|
828
|
+
annotations: { ...(req.path ? { [ANNOTATION_WORKSPACE_PATH]: req.path } : {}), [ANNOTATION_HOLD]: HOLD_HELD },
|
|
790
829
|
},
|
|
791
830
|
spec: {
|
|
792
831
|
// The Sandbox Image, unmodified (ADR-0037) — the user's tools, its own USER and HOME, and
|
|
@@ -834,8 +873,14 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
834
873
|
// Never empty: the Custodian's address is unconditional. The seat's own vars (the fallback
|
|
835
874
|
// `HOME`) come FIRST, so the instance's `harness.env` can still override them the way it
|
|
836
875
|
// overrides anything the image set.
|
|
837
|
-
|
|
838
|
-
...(
|
|
876
|
+
// Marked (`harness-env.ts`, ADR-0076): the Harness's start tells jr2's names from the image's.
|
|
877
|
+
...(() => {
|
|
878
|
+
const marked = markHarnessEnv(
|
|
879
|
+
[...seat.env, ...harnessEnv(req.name, custodian, cpuHintEnv())],
|
|
880
|
+
cfg().envFrom ?? [],
|
|
881
|
+
);
|
|
882
|
+
return { env: marked.env, ...(marked.envFrom.length ? { envFrom: marked.envFrom } : {}) };
|
|
883
|
+
})(),
|
|
839
884
|
// What the AGENT gets: an address on its own loopback and a Stand-in for every credential,
|
|
840
885
|
// and no credential anywhere. The Custodian beside it holds them (ADR-0013, ADR-0059).
|
|
841
886
|
sidecars,
|
|
@@ -865,6 +910,9 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
865
910
|
// that Workspace is `Lost` (ADR-0021) — and mounted below into the Harness container
|
|
866
911
|
// ALONE: the User Container must not read an Agent's history.
|
|
867
912
|
{ name: CONVERSATIONS_VOLUME, emptyDir: {} },
|
|
913
|
+
// The shell socket's folder (ADR-0076): the Harness listens there for `jr2 workspace
|
|
914
|
+
// shell`, in the Harness container ALONE, where no process that it confines makes a file.
|
|
915
|
+
{ name: SHELL_VOLUME, emptyDir: {} },
|
|
868
916
|
// Only for ADR-0037's fallback seat: uid 1000 on a stranger's base has no home at all.
|
|
869
917
|
...seat.homeVolume,
|
|
870
918
|
// The Custodian's (its values, leaves and config), and the trust ConfigMap (ADR-0020).
|
|
@@ -879,6 +927,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
879
927
|
{ name: "work", mountPath: WORK_ROOT },
|
|
880
928
|
RUNTIME_VOLUME_MOUNT,
|
|
881
929
|
{ name: CONVERSATIONS_VOLUME, mountPath: CONVERSATIONS_DIR },
|
|
930
|
+
{ name: SHELL_VOLUME, mountPath: SHELL_DIR },
|
|
882
931
|
...seat.homeMount,
|
|
883
932
|
...custodian.harnessMounts,
|
|
884
933
|
],
|
|
@@ -902,7 +951,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
902
951
|
* `data`, not `stringData`: a server-side apply owns the fields it names, and `stringData` is
|
|
903
952
|
* write-only — it never reads back as the field applied.
|
|
904
953
|
*/
|
|
905
|
-
const applyTokenSecret = async (name: string, owner: KubeObject): Promise<void> => {
|
|
954
|
+
const applyTokenSecret = async (name: string, owner: KubeObject, manifest: HeldManifest): Promise<void> => {
|
|
906
955
|
if (!opts.signingKey) throw new Error("kubeSandbox: a Custodian needs a signingKey to mint its Sandbox token");
|
|
907
956
|
const uid = owner.metadata?.uid;
|
|
908
957
|
if (!uid) throw new Error(`Sandbox "${name}": the CR's apply answered with no uid to own its token Secret`);
|
|
@@ -925,7 +974,19 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
925
974
|
],
|
|
926
975
|
},
|
|
927
976
|
type: "Opaque",
|
|
928
|
-
|
|
977
|
+
// The pod's credentials (ADR-0076, C1, C1b): its fetch token and its control token, which the
|
|
978
|
+
// Custodian alone mounts; its secret control Stand-in; and one secret Stand-in per held secret
|
|
979
|
+
// the pod's manifest names, which the Custodian (for its swap) and the Harness container (as
|
|
980
|
+
// files under `/run/jr2/`) mount. Every one a signed name, so a re-provision re-applies the
|
|
981
|
+
// same values. Never a ConfigMap, the CR, an env, an event or a log line.
|
|
982
|
+
data: base64Values({
|
|
983
|
+
[CREDENTIAL_KEYS.fetchToken]: sandboxToken(opts.signingKey, name),
|
|
984
|
+
[CREDENTIAL_KEYS.controlToken]: controlToken(opts.signingKey, name),
|
|
985
|
+
[CREDENTIAL_KEYS.controlStandIn]: controlStandIn(opts.signingKey, name),
|
|
986
|
+
...Object.fromEntries(
|
|
987
|
+
manifest.secrets.map((s) => [heldStandInKey(s.name), heldStandIn(opts.signingKey!, name, s.name)]),
|
|
988
|
+
),
|
|
989
|
+
}),
|
|
929
990
|
});
|
|
930
991
|
};
|
|
931
992
|
|
|
@@ -1030,7 +1091,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
1030
1091
|
},
|
|
1031
1092
|
data: {
|
|
1032
1093
|
[CUSTODIAN_BOOTSTRAP_KEY]: JSON.stringify(custodianBootstrap(manifest, orchestrator)),
|
|
1033
|
-
[CUSTODIAN_SCRIPT_KEY]: custodianScript(manifest),
|
|
1094
|
+
[CUSTODIAN_SCRIPT_KEY]: custodianScript(manifest, { fetch: true }),
|
|
1034
1095
|
},
|
|
1035
1096
|
});
|
|
1036
1097
|
};
|
|
@@ -1257,8 +1318,9 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
1257
1318
|
image: refs.custodian,
|
|
1258
1319
|
pod,
|
|
1259
1320
|
config: sandboxCustodianConfigMap(req.name),
|
|
1260
|
-
|
|
1321
|
+
credentials: { secret: secretName(req.name) },
|
|
1261
1322
|
sandbox: req.name,
|
|
1323
|
+
...(req.secrets?.length ? { granted: req.secrets } : {}),
|
|
1262
1324
|
caBundle: cfg().caBundle === true,
|
|
1263
1325
|
resources: split.custodian,
|
|
1264
1326
|
});
|
|
@@ -1287,7 +1349,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
1287
1349
|
sandboxes();
|
|
1288
1350
|
const applied = await kube().apply(SANDBOXES, ns, cr).catch(noOperator(req.name, "Sandbox"));
|
|
1289
1351
|
// After the CR: its uid owns both, so they go when it goes.
|
|
1290
|
-
await applyTokenSecret(req.name, applied);
|
|
1352
|
+
await applyTokenSecret(req.name, applied, manifest);
|
|
1291
1353
|
await applyCustodianConfig(req.name, applied, manifest);
|
|
1292
1354
|
if (effectorManifest) {
|
|
1293
1355
|
await applyEffectorKey(req.name, applied);
|
|
@@ -1403,24 +1465,44 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
1403
1465
|
const { identity, key } = repoIdentity(r.url);
|
|
1404
1466
|
return { slot: r.slot, url: r.url, identity, key, ...(r.ref !== undefined ? { ref: r.ref } : {}) };
|
|
1405
1467
|
}),
|
|
1406
|
-
branch: req.spec.branch,
|
|
1407
|
-
...(req.spec.reviewSha ? { reviewSha: req.spec.reviewSha } : {}),
|
|
1408
1468
|
};
|
|
1409
|
-
const { repos,
|
|
1469
|
+
const { repos, bases } = await postAttach(req.name, endpoint, body);
|
|
1410
1470
|
const stale = staleSlots(req.repos, staleByName.get(req.name));
|
|
1411
|
-
return { repos,
|
|
1471
|
+
return { repos, bases, ...(stale ? { stale } : {}) };
|
|
1412
1472
|
},
|
|
1413
1473
|
|
|
1414
1474
|
leaseIntervalMs,
|
|
1415
1475
|
|
|
1416
1476
|
async renew(name) {
|
|
1417
|
-
// A write, and only that (ADR-0021): the stamp the operator's idle GC reads
|
|
1418
|
-
//
|
|
1477
|
+
// A write, and only that (ADR-0021): the stamp the operator's idle GC reads, and the hold
|
|
1478
|
+
// mark, written again so a restored run's Lease marks the Sandbox `held`. What the workspace
|
|
1479
|
+
// IS comes from the watch, never from this answer.
|
|
1419
1480
|
await kube().patch(SANDBOXES, ns, name, {
|
|
1420
|
-
metadata: { annotations: {
|
|
1481
|
+
metadata: { annotations: { [ANNOTATION_KEEPALIVE]: new Date().toISOString(), [ANNOTATION_HOLD]: HOLD_HELD } },
|
|
1421
1482
|
});
|
|
1422
1483
|
},
|
|
1423
1484
|
|
|
1485
|
+
async releaseHold(name) {
|
|
1486
|
+
// The Lease stopped for good (ADR-0021): no run holds this Sandbox now, and `jr2 workspace rm`
|
|
1487
|
+
// may remove it. A write, and only that.
|
|
1488
|
+
await kube().patch(SANDBOXES, ns, name, { metadata: { annotations: { [ANNOTATION_HOLD]: HOLD_RELEASED } } });
|
|
1489
|
+
},
|
|
1490
|
+
|
|
1491
|
+
async releaseRun(runId) {
|
|
1492
|
+
// A restore ended this run without hosting it (ADR-0021): no Lease runs, so each of its
|
|
1493
|
+
// Sandboxes gets the mark here. The list is the cluster's, not the watch's cache, which may
|
|
1494
|
+
// not have listed yet at boot.
|
|
1495
|
+
const list = await kube().list<SandboxObject>(SANDBOXES, ns, { labelSelector: `${LABEL_SANDBOX_RUN}=${runId}` });
|
|
1496
|
+
await Promise.all(
|
|
1497
|
+
list.items.flatMap((sb) => {
|
|
1498
|
+
const name = sb.metadata?.name;
|
|
1499
|
+
return name
|
|
1500
|
+
? [kube().patch(SANDBOXES, ns, name, { metadata: { annotations: { [ANNOTATION_HOLD]: HOLD_RELEASED } } })]
|
|
1501
|
+
: [];
|
|
1502
|
+
}),
|
|
1503
|
+
);
|
|
1504
|
+
},
|
|
1505
|
+
|
|
1424
1506
|
continuity(name, listener) {
|
|
1425
1507
|
// The watch's word on this name (ADR-0063): the first list, then every event. A dropped
|
|
1426
1508
|
// watch says nothing, so this says nothing either — unknown is never loss.
|
|
@@ -1458,7 +1540,20 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
|
|
|
1458
1540
|
async destroy(name) {
|
|
1459
1541
|
staleByName.delete(name);
|
|
1460
1542
|
// The token Secret is the CR's child from birth, so deleting the CR reaps it (ADR-0001).
|
|
1461
|
-
await kube().delete(SANDBOXES, ns, name);
|
|
1543
|
+
await kube().delete(SANDBOXES, ns, name, { foreground: true });
|
|
1544
|
+
// A retry of the same invoke id takes the same name, and the pod takes it too: a new Sandbox
|
|
1545
|
+
// must not find the old pod on its way out, and read `Lost` (ADR-0075). So the wait is
|
|
1546
|
+
// for the pod as well: foreground keeps the CR until the pod is gone. Bounded: a stuck finalizer
|
|
1547
|
+
// is the operator's to report, and the run does not wait on it for ever.
|
|
1548
|
+
for (let i = 0; i < 120; i++) {
|
|
1549
|
+
if (
|
|
1550
|
+
(await kube()
|
|
1551
|
+
.get<SandboxObject>(SANDBOXES, ns, name)
|
|
1552
|
+
.catch(() => undefined)) === undefined
|
|
1553
|
+
)
|
|
1554
|
+
return;
|
|
1555
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1556
|
+
}
|
|
1462
1557
|
},
|
|
1463
1558
|
};
|
|
1464
1559
|
}
|