@moondeck/station 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +149 -2
- package/bin/uai-host.mjs +130 -0
- package/db/migrations/0000_host_tasks.sql +12 -0
- package/db/migrations/0001_host_ui.sql +11 -0
- package/db/migrations/0002_host_github_tokens.sql +8 -0
- package/db/migrations/0003_host_ssh_keys.sql +8 -0
- package/db/migrations/0004_host_owner_name.sql +1 -0
- package/db/migrations/0005_host_env_vars.sql +5 -0
- package/db/migrations/0006_host_project_env.sql +9 -0
- package/db/migrations/0007_host_github_token_kind.sql +7 -0
- package/db/migrations/0008_host_mcp_connections.sql +18 -0
- package/db/migrations/0009_host_agent_sessions.sql +15 -0
- package/db/migrations/0010_host_engine_accounts.sql +13 -0
- package/db/migrations/0011_codex_thread_id.sql +5 -0
- package/db/migrations/0012_agent_session_attach_key.sql +4 -0
- package/db/migrations/0013_github_credential_generations.sql +11 -0
- package/db/migrations/0014_host_inventory_event_index.sql +1 -0
- package/db/migrations/0015_host_settings.sql +9 -0
- package/db/migrations/0016_task_environment.sql +2 -0
- package/db/migrations/0017_engine_account_scope.sql +7 -0
- package/db/migrations/0018_engine_account_position.sql +3 -0
- package/db/migrations/0019_engine_account_store_ref.sql +3 -0
- package/db/migrations/0020_user_credential_store_ref.sql +6 -0
- package/db/migrations/0021_project_env_store_ref.sql +3 -0
- package/db/migrations/0022_task_project_ids.sql +5 -0
- package/db/migrations/0023_project_env_org.sql +4 -0
- package/db/migrations/0024_task_env_mode.sql +9 -0
- package/db/migrations/0025_project_env_authority.sql +147 -0
- package/db/migrations/0026_project_env_replica.sql +150 -0
- package/db/migrations/0027_cloud_credential_foundation.sql +51 -0
- package/db/migrations/0028_leased_engine_runtimes.sql +11 -0
- package/db/migrations/0029_task_shared_files_mode.sql +5 -0
- package/db/migrations/0030_credential_cleanup_restops.sql +12 -0
- package/db/migrations/0031_first_turn_receipts.sql +9 -0
- package/db/migrations/meta/_journal.json +230 -0
- package/db/schema.ts +871 -0
- package/images/standard/Dockerfile +347 -0
- package/images/standard/README.md +167 -0
- package/images/standard/container/code-server-settings.json +63 -0
- package/images/standard/container/corepack-version +1 -0
- package/images/standard/container/uai-init +704 -0
- package/images/standard/container/uai-materialize-runtimes +1527 -0
- package/images/standard/container/uai-task-forwarder.mjs +303 -0
- package/images/standard/tool-versions +2 -0
- package/lib/__fixtures__/skill-index/SKILL.md +10 -0
- package/lib/__fixtures__/skill-index/skills/accessibility-checklist.md +7 -0
- package/lib/__fixtures__/skill-index/skills/brand-voice.md +9 -0
- package/lib/__fixtures__/skill-index/skills/design-tokens.md +9 -0
- package/lib/agent-cli.ts +1507 -0
- package/lib/agent-errors.ts +22 -0
- package/lib/agent.ts +672 -0
- package/lib/agents/attach-compatibility.ts +51 -0
- package/lib/agents/claude.ts +918 -0
- package/lib/agents/codex-token-usage.fixture.json +130 -0
- package/lib/agents/codex.ts +1392 -0
- package/lib/agents/cursor-period-usage.ts +253 -0
- package/lib/agents/cursor.ts +562 -0
- package/lib/agents/dispatch.ts +78 -0
- package/lib/agents/durable-proc.ts +334 -0
- package/lib/agents/factory.ts +57 -0
- package/lib/agents/grok.ts +381 -0
- package/lib/agents/kimi.ts +329 -0
- package/lib/agents/machine-durable.ts +604 -0
- package/lib/agents/mock.ts +133 -0
- package/lib/agents/mode.ts +64 -0
- package/lib/agents/opencode.ts +508 -0
- package/lib/agents/output-source.ts +3 -0
- package/lib/agents/proc.ts +221 -0
- package/lib/agents/rate-limit.ts +337 -0
- package/lib/agents/registry.ts +182 -0
- package/lib/agents/session-state.ts +197 -0
- package/lib/agents/skill-index-preamble.fixture.ts +26 -0
- package/lib/agents/transport.ts +741 -0
- package/lib/agents/types.ts +254 -0
- package/lib/agents/uai.ts +106 -0
- package/lib/agents/usage.ts +44 -0
- package/lib/apple-one-off.ts +277 -0
- package/lib/apple-runtime-recycle.ts +237 -0
- package/lib/apple-uninstall-teardown.ts +224 -0
- package/lib/assignment-evidence.ts +94 -0
- package/lib/attachments.ts +48 -0
- package/lib/browser-testing.ts +1537 -0
- package/lib/capture-flow.ts +332 -0
- package/lib/cloud-credential-cleanup-adapter.ts +123 -0
- package/lib/cloud-credential-host.ts +512 -0
- package/lib/cloud-credential-leases.ts +2587 -0
- package/lib/cloud-credential-runtime.ts +1357 -0
- package/lib/cloud-state.ts +56 -0
- package/lib/codex-auth.ts +456 -0
- package/lib/command-db.ts +310 -0
- package/lib/compose-network-recovery.ts +283 -0
- package/lib/connection-secret-redaction.ts +25 -0
- package/lib/container-runtime.ts +1470 -0
- package/lib/credential-cleanup-inventory.ts +490 -0
- package/lib/credential-consumers/engine-anchor.ts +1880 -0
- package/lib/credential-consumers/engines.ts +797 -0
- package/lib/credential-consumers/files.ts +934 -0
- package/lib/credential-consumers/github.ts +702 -0
- package/lib/credential-consumers/mcp.ts +389 -0
- package/lib/credential-consumers/task-files.ts +127 -0
- package/lib/credential-consumers/task-secrets.ts +10 -0
- package/lib/credential-store-pickup.ts +149 -0
- package/lib/credential-store-scope.ts +112 -0
- package/lib/credential-store.ts +932 -0
- package/lib/credentials-activation-authority.ts +709 -0
- package/lib/credentials-purge.ts +1006 -0
- package/lib/custom-connection-capture.ts +395 -0
- package/lib/custom-connection-launch.ts +384 -0
- package/lib/custom-connection-runtime.ts +141 -0
- package/lib/db.ts +80 -0
- package/lib/disk-pressure.ts +42 -0
- package/lib/docker-exec.ts +156 -0
- package/lib/engine-accounts.ts +1970 -0
- package/lib/engine-connect.ts +321 -0
- package/lib/engine-credential-env.ts +52 -0
- package/lib/engine-login.ts +2933 -0
- package/lib/engines.ts +1342 -0
- package/lib/enrollment-state.ts +251 -0
- package/lib/env-file.ts +246 -0
- package/lib/env-schema.ts +937 -0
- package/lib/env.ts +195 -0
- package/lib/first-turn-receipts.ts +62 -0
- package/lib/fs-aliases.ts +49 -0
- package/lib/git-clone-credentials.ts +334 -0
- package/lib/git-diff.ts +530 -0
- package/lib/git-identity.ts +715 -0
- package/lib/github-git-auth.ts +207 -0
- package/lib/github-origin.ts +28 -0
- package/lib/github-tokens.ts +2439 -0
- package/lib/host-cloud-url.ts +62 -0
- package/lib/host-config.ts +279 -0
- package/lib/host-env.ts +424 -0
- package/lib/host-logs.ts +965 -0
- package/lib/internal-connections.ts +5 -0
- package/lib/keyed-promise-tail.ts +23 -0
- package/lib/launch-mode.ts +25 -0
- package/lib/lease.ts +239 -0
- package/lib/legacy-host.ts +769 -0
- package/lib/legacy-runtime-retirement.ts +424 -0
- package/lib/legacy-runtime-v1.fixture.ts +627 -0
- package/lib/machine-exec.ts +238 -0
- package/lib/machine-gateway-tunnel.ts +344 -0
- package/lib/machine-keys.ts +65 -0
- package/lib/machine-project-env-loader.ts +152 -0
- package/lib/machine-provider-aws.ts +923 -0
- package/lib/machine-provider-local.ts +338 -0
- package/lib/machine-provider.ts +90 -0
- package/lib/managed-activation-watcher.ts +72 -0
- package/lib/managed-install-owner-watcher.ts +55 -0
- package/lib/managed-operation-drain.ts +57 -0
- package/lib/managed-runtime.ts +4296 -0
- package/lib/managed-update-scheduler.ts +125 -0
- package/lib/mcp-capture.ts +865 -0
- package/lib/mcp-config-lock.ts +2 -0
- package/lib/mcp-connections.ts +959 -0
- package/lib/mcp-gateway.ts +2594 -0
- package/lib/obs.ts +512 -0
- package/lib/openrouter-budget.ts +247 -0
- package/lib/orchestrator.ts +11409 -0
- package/lib/person-capture.ts +327 -0
- package/lib/preview-ports.ts +85 -0
- package/lib/preview-sidecar.ts +331 -0
- package/lib/project-env-authority.ts +1319 -0
- package/lib/project-env-feature.ts +74 -0
- package/lib/project-env-legacy-tags.ts +130 -0
- package/lib/project-env-loader.ts +242 -0
- package/lib/project-env-replica.ts +2094 -0
- package/lib/project-env-schema-capture.ts +342 -0
- package/lib/project-env-staging.ts +148 -0
- package/lib/project-env-task-policy.ts +176 -0
- package/lib/project-env-task-replica.ts +1752 -0
- package/lib/release-feed.ts +61 -0
- package/lib/release-manifest.ts +710 -0
- package/lib/release-trust.ts +46 -0
- package/lib/repo-clone.ts +38 -0
- package/lib/routing/shadow.ts +261 -0
- package/lib/runner-boot.ts +10 -0
- package/lib/runtime-activation-tail.ts +279 -0
- package/lib/runtime-archive.ts +1216 -0
- package/lib/runtime-authority.ts +166 -0
- package/lib/runtime-guard.ts +36 -0
- package/lib/runtime-provider-state.ts +169 -0
- package/lib/runtime-reconnect.ts +86 -0
- package/lib/runtime-state.ts +1033 -0
- package/lib/safe-http.ts +364 -0
- package/lib/secrets-proxy/address.ts +95 -0
- package/lib/secrets-proxy/audit.ts +30 -0
- package/lib/secrets-proxy/ca-store.ts +200 -0
- package/lib/secrets-proxy/ca.ts +470 -0
- package/lib/secrets-proxy/container-steps.ts +138 -0
- package/lib/secrets-proxy/der.ts +273 -0
- package/lib/secrets-proxy/engine.ts +1633 -0
- package/lib/secrets-proxy/host.ts +93 -0
- package/lib/secrets-proxy/hostname.ts +57 -0
- package/lib/secrets-proxy/placeholders.ts +196 -0
- package/lib/secrets-proxy/policy.ts +150 -0
- package/lib/secrets-proxy/readiness.ts +148 -0
- package/lib/secrets-proxy/runtime.ts +582 -0
- package/lib/secrets-proxy/scrub.ts +559 -0
- package/lib/secrets-proxy/sidecar-view.ts +139 -0
- package/lib/secrets-proxy/task-scripts.ts +262 -0
- package/lib/secrets-proxy/task-trust.ts +605 -0
- package/lib/secrets-proxy/trust-watch.ts +80 -0
- package/lib/secrets.ts +71 -0
- package/lib/shared-files-s3.ts +976 -0
- package/lib/shared-files.ts +156 -0
- package/lib/sidecar-assign.ts +49 -0
- package/lib/sidecar-guard.ts +58 -0
- package/lib/sidecar-resume.ts +178 -0
- package/lib/sidecar.ts +69 -0
- package/lib/signin-box-credentials.ts +465 -0
- package/lib/signin-box.ts +114 -0
- package/lib/skill-index-example.fixture.ts +56 -0
- package/lib/skill-layout.ts +417 -0
- package/lib/skills.ts +489 -0
- package/lib/ssh.ts +401 -0
- package/lib/standard-image-cleanup.ts +117 -0
- package/lib/standard-image-pin.ts +207 -0
- package/lib/standard-image.ts +1697 -0
- package/lib/stopped-task-status-queue.ts +120 -0
- package/lib/task-container-cli.ts +269 -0
- package/lib/task-credential-cleanup.ts +752 -0
- package/lib/task-diff-sandbox.ts +464 -0
- package/lib/task-diff.ts +91 -0
- package/lib/task-env-forwarder.ts +228 -0
- package/lib/task-env-source.ts +249 -0
- package/lib/task-environment/anchor.ts +31 -0
- package/lib/task-environment/apple-container.ts +860 -0
- package/lib/task-environment/docker.ts +1344 -0
- package/lib/task-environment/index.ts +466 -0
- package/lib/task-environment/legacy-adoption.ts +467 -0
- package/lib/task-environment/machine-environment.ts +61 -0
- package/lib/task-environment/machine-task-up.ts +1227 -0
- package/lib/task-environment/machine.ts +974 -0
- package/lib/task-environment/registry.ts +59 -0
- package/lib/task-environment/self-identity.ts +20 -0
- package/lib/task-environment/self.ts +566 -0
- package/lib/task-environment/types.ts +642 -0
- package/lib/task-environment/workspace-files.ts +685 -0
- package/lib/task-environment/workspace-runtime.fixture.ts +50 -0
- package/lib/task-files-machine-retirement-outbox.ts +592 -0
- package/lib/task-files-machine-retirement.ts +116 -0
- package/lib/task-files-readiness.ts +127 -0
- package/lib/task-gateway-port.ts +22 -0
- package/lib/task-gateway-protocol.ts +190 -0
- package/lib/task-gateway-recovery.ts +47 -0
- package/lib/task-gateway-state.ts +512 -0
- package/lib/task-identity.ts +19 -0
- package/lib/task-inventory.ts +682 -0
- package/lib/task-machine-credentials-activation.ts +95 -0
- package/lib/task-machine-swap-safety.ts +729 -0
- package/lib/task-person-credentials.ts +76 -0
- package/lib/task-project-ops-host.ts +147 -0
- package/lib/task-project-ops.ts +1062 -0
- package/lib/task-secret-staging.ts +16 -0
- package/lib/task-status.ts +46 -0
- package/lib/task-token.ts +46 -0
- package/lib/token-broker-adopt.ts +344 -0
- package/lib/token-broker-lambda.ts +105 -0
- package/lib/token-broker-local.ts +392 -0
- package/lib/token-broker-revision.ts +310 -0
- package/lib/token-broker-ssm.ts +525 -0
- package/lib/token-broker.ts +218 -0
- package/lib/token-lanes/openai-oauth.ts +123 -0
- package/lib/token-lanes/registry.ts +45 -0
- package/lib/token-lanes/types.ts +163 -0
- package/lib/token-lanes/xai-oauth.ts +165 -0
- package/lib/transcript.ts +128 -0
- package/lib/tunnel-registry.ts +220 -0
- package/lib/tunnel-runtime.ts +235 -0
- package/lib/ulid.ts +16 -0
- package/lib/user-bus-env.ts +116 -0
- package/lib/user-credentials-store.ts +435 -0
- package/lib/vnode-pressure.ts +142 -0
- package/package.json +115 -8
- package/runner/runner.mjs +442 -0
- package/scripts/agent/_common.sh +633 -0
- package/scripts/agent/env-hook.sh +626 -0
- package/scripts/agent/moondeck-cli.sh +5 -0
- package/scripts/agent/task-down.sh +291 -0
- package/scripts/agent/task-status.sh +70 -0
- package/scripts/agent/task-up.sh +3761 -0
- package/scripts/agent/uai-env-exec.sh +26 -0
- package/scripts/install/darwin.ts +1048 -0
- package/scripts/install/linux.ts +958 -0
- package/scripts/install/types.ts +78 -0
- package/scripts/install/util.ts +254 -0
- package/scripts/install/win.ts +143 -0
- package/src/activation-respawn.ts +155 -0
- package/src/apple-tunnel-route.ts +104 -0
- package/src/bridge-diagnostics.ts +39 -0
- package/src/capture-wire.ts +102 -0
- package/src/cli.ts +2585 -0
- package/src/cloud-credentials.ts +2144 -0
- package/src/cloud-origins.ts +23 -0
- package/src/credential-location.ts +248 -0
- package/src/credential-wire-validation.ts +25 -0
- package/src/custom-connections.ts +237 -0
- package/src/engine-account-paths.ts +11 -0
- package/src/engine-models.ts +39 -0
- package/src/engine-usage.ts +104 -0
- package/src/enrollment-next-steps.ts +24 -0
- package/src/event-outbox.ts +185 -0
- package/src/index.ts +2907 -0
- package/src/load-env.ts +97 -0
- package/src/machine-tunnel-route.ts +156 -0
- package/src/main.ts +6363 -0
- package/src/never-proxied-domains.ts +31 -0
- package/src/outbound-frame.ts +31 -0
- package/src/paths.ts +81 -0
- package/src/project-env-latest.ts +130 -0
- package/src/project-env-policy.ts +396 -0
- package/src/project-env-wording.ts +53 -0
- package/src/protocol.ts +5550 -0
- package/src/runtime-bootstrap.ts +165 -0
- package/src/station-identity.ts +96 -0
- package/src/task-env-names.ts +28 -0
- package/src/task-secrets.ts +75 -0
- package/src/tunnel-dial.ts +102 -0
- package/src/ui/server.ts +852 -0
- package/src/ui/types.ts +173 -0
- package/src/workspace-path-policy.ts +41 -0
- package/ui/app.js +1102 -0
- package/ui/index.html +90 -0
- package/ui/style.css +685 -0
- package/ui/uai-favicon.svg +21 -0
- package/ui/uai-logo-black.svg +9 -0
- package/ui/uai-wheel.svg +9 -0
- package/bin/moondeck-station.mjs +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Diogo Perillo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,150 @@
|
|
|
1
1
|
# @moondeck/station
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
**Moondeck Station**, the host for [Moondeck](https://moondeck.io) — a self-hosted service
|
|
4
|
+
that runs parallel AI coding tasks in ephemeral Docker containers on a machine
|
|
5
|
+
**you** control. This package is the long-running per-user daemon that connects
|
|
6
|
+
your machine to the Moondeck cloud and runs the task containers locally. It also
|
|
7
|
+
serves a small read-only monitor UI on `127.0.0.1` (ADR-028).
|
|
8
|
+
|
|
9
|
+
One process does three things:
|
|
10
|
+
|
|
11
|
+
- **Cloud bridge** — a host-initiated *outbound* WSS to
|
|
12
|
+
`wss://app.moondeck.io/host` carrying every command/tunnel. The cloud never
|
|
13
|
+
connects in; nothing inbound is exposed.
|
|
14
|
+
- **Local UI** — an HTTP server on `127.0.0.1:5876` (next free port if taken):
|
|
15
|
+
connection badge, service info, active tasks, recent events. Localhost only,
|
|
16
|
+
no auth, read-only — mutations come from the cloud, not here.
|
|
17
|
+
- **MCP gateway** — a credential-injecting HTTP proxy for task containers,
|
|
18
|
+
bound to `127.0.0.1:5877` by default. Listener failures retry with capped
|
|
19
|
+
backoff and are advertised to the cloud as bounded health state.
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- **Docker** (running) — tasks are containers.
|
|
24
|
+
- **Node 22, 24, 25 or 26; Node 24 LTS recommended.** Those are the majors the
|
|
25
|
+
pinned SQLite dependency ships a prebuilt binary for. Tested release majors
|
|
26
|
+
are 22, 24 and 26; Node 25 warns and continues when the binding loads.
|
|
27
|
+
Anything else — including Node 20, 21 and 23 — has to compile from source
|
|
28
|
+
and fails on a machine without a C++ toolchain.
|
|
29
|
+
|
|
30
|
+
## Install & enroll
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm i -g @moondeck/station
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then, in the Moondeck web app, open an organization and choose **“Add a host.”** It
|
|
37
|
+
mints a one-time enrollment token and shows the exact command to run on this
|
|
38
|
+
machine (ADR-031):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
moondeck-station setup --cloud wss://app.moondeck.io/host --enroll uaienroll_…
|
|
42
|
+
moondeck-station install # per-user service: launchd (macOS) / systemd --user (Linux)
|
|
43
|
+
moondeck-station start
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The host generates its **own** bridge credential locally. The cloud persists
|
|
47
|
+
only its hash; the raw credential transits authenticated TLS for bridge auth
|
|
48
|
+
and existing-host attachment but is not stored there (ADR-015). Once started
|
|
49
|
+
it appears in your org and can run tasks. Data + config live under `~/.moondeck`
|
|
50
|
+
(`~/.moondeck/.env.local`, `~/.moondeck/data/`); from a repo checkout they stay under the
|
|
51
|
+
repo instead. The monitor UI is at `http://127.0.0.1:5876` (exact port in
|
|
52
|
+
`moondeck-station status`).
|
|
53
|
+
|
|
54
|
+
## CLI (`moondeck-station`)
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
setup --cloud <wss-url> --enroll <token>
|
|
58
|
+
claim this machine, or enroll its existing identity in
|
|
59
|
+
the token's workspace
|
|
60
|
+
enroll <token> [--cloud <wss-url>]
|
|
61
|
+
first-time setup, or attach this machine to another
|
|
62
|
+
workspace; uses the stored cloud URL when available
|
|
63
|
+
install [--dry-run] install as a per-user service for this OS
|
|
64
|
+
uninstall remove the service
|
|
65
|
+
start | stop control the installed service
|
|
66
|
+
restart stop + start
|
|
67
|
+
status connection, service info, active tasks (same data as the UI)
|
|
68
|
+
logs [--follow] tail the service log
|
|
69
|
+
run run in the foreground (debug)
|
|
70
|
+
pair <token> store a host token directly (manual fallback for setup)
|
|
71
|
+
open open the local UI in your browser
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`enroll` is available in host version 0.9.15 and newer. Its compatible cloud
|
|
75
|
+
endpoint is intentionally deployed before that host release.
|
|
76
|
+
|
|
77
|
+
`--dry-run` on `install` (and start/stop/…) prints the unit file + load
|
|
78
|
+
commands without touching launchd/systemd.
|
|
79
|
+
|
|
80
|
+
## Headless
|
|
81
|
+
|
|
82
|
+
Runs identically with no display: install via the same flow, skip `moondeck-station
|
|
83
|
+
open`, and use `moondeck-station status` for everything the UI shows. The UI stays
|
|
84
|
+
reachable over an SSH port-forward to `127.0.0.1:5876` if you want it.
|
|
85
|
+
|
|
86
|
+
At boot, task and channel starts wait for the initial agent-CLI maintenance
|
|
87
|
+
pass to settle before any in-container writer or station executes. The cloud
|
|
88
|
+
host page shows this short preparation state. It also shows MCP gateway
|
|
89
|
+
listener failures while the host retries them; gateway health is independent
|
|
90
|
+
of ordinary task admission.
|
|
91
|
+
|
|
92
|
+
## Security
|
|
93
|
+
|
|
94
|
+
Tasks run in ephemeral containers and **do not** mount your live AI session
|
|
95
|
+
dirs. Per-task credentials (GitHub tokens, SSH keys) are decrypted only on the
|
|
96
|
+
host, using a host-resident master key; the cloud stores only hashes and public
|
|
97
|
+
keys. See [ADR-015](https://github.com/moondeckio/uai/blob/main/docs/decisions.md)
|
|
98
|
+
for the secret-blind model.
|
|
99
|
+
|
|
100
|
+
## Dev (from a repo checkout)
|
|
101
|
+
|
|
102
|
+
`pnpm host-agent` (from the repo root) = `moondeck-station run` — the service in the
|
|
103
|
+
foreground, no install, logs to stdout. The packaged binary runs the same
|
|
104
|
+
TypeScript source through [tsx](https://github.com/privatenumber/tsx); there is
|
|
105
|
+
no build step (ADR-032).
|
|
106
|
+
|
|
107
|
+
## More
|
|
108
|
+
|
|
109
|
+
- [Moondeck on GitHub](https://github.com/moondeckio/uai)
|
|
110
|
+
- [docs/host-ui.md](https://github.com/moondeckio/uai/blob/main/docs/host-ui.md) — the local UI surface.
|
|
111
|
+
- [docs/host-packaging.md](https://github.com/moondeckio/uai/blob/main/docs/host-packaging.md) — how this package is built and published.
|
|
112
|
+
</content>
|
|
113
|
+
|
|
114
|
+
## Telemetry
|
|
115
|
+
|
|
116
|
+
Installed hosts report **crashes only** to Sentry by default. Sent on a
|
|
117
|
+
crash: the error and stack trace (paths and secret-shaped strings
|
|
118
|
+
redacted), recent bridge-connection breadcrumbs, OS/runtime versions, the
|
|
119
|
+
package version, and a pseudonymous host id. No sessions, no usage pings,
|
|
120
|
+
and no request data — nothing is sent until something actually crashes.
|
|
121
|
+
Telemetry is designed to exclude chat, prompts, env values, and repo
|
|
122
|
+
content; error text is scrubbed for secret shapes, but redaction is
|
|
123
|
+
pattern-based, not perfect. Repo checkouts and dev/test runs never report,
|
|
124
|
+
and reporting only activates after this notice has been shown once (the
|
|
125
|
+
`install`/`pair`/`setup`/`start`/`restart` commands print it — a silently
|
|
126
|
+
upgraded service stays off until one of them runs).
|
|
127
|
+
|
|
128
|
+
Opt out any time — add to `$UAI_HOME/.env.local` (default
|
|
129
|
+
`~/.moondeck/.env.local`), then `moondeck-station restart`:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
UAI_TELEMETRY_DISABLED=1
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`UAI_SENTRY_DSN=<dsn>` redirects reports to your own Sentry instead.
|
|
136
|
+
|
|
137
|
+
## Moving from the old Uai host (`@runuai/host`)
|
|
138
|
+
|
|
139
|
+
A station never runs beside the old host. Remove the old one first: its
|
|
140
|
+
service, runtime, `uai-host` commands and leftover task containers. `~/.uai`
|
|
141
|
+
is kept unless you pass `--purge`; it refuses while the old host runs tasks
|
|
142
|
+
unless you pass `--force` (their work is lost):
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
npx @moondeck/station uninstall-legacy # or: moondeck-station uninstall-legacy
|
|
146
|
+
npx @moondeck/station install
|
|
147
|
+
moondeck-station enroll <token from app.moondeck.io>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
With the one-line installer: `curl -fsSL https://app.moondeck.io/install | sh -s -- --uninstall-legacy --enroll <token>`.
|
package/bin/uai-host.mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Published entrypoint for `@moondeck/station`, its `moondeck-station` bin (ADR-032). The file keeps its
|
|
4
|
+
* pre-rename name: the runtime archive layout pins `agent/bin/uai-host.mjs`.
|
|
5
|
+
*
|
|
6
|
+
* The host ships TypeScript source and runs it through tsx — no build step —
|
|
7
|
+
* so every runtime path (drizzle migrations, scripts/agent/*.sh, the
|
|
8
|
+
* images/standard build context) resolves off its source file exactly as in
|
|
9
|
+
* dev. This shim verifies that the native SQLite dependency can load,
|
|
10
|
+
* registers tsx's ESM loader, then hands off to src/cli.ts. argv passes
|
|
11
|
+
* straight through: src/cli.ts reads process.argv.slice(2).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// A builtin — importing it here loads nothing of the app and no tsx.
|
|
15
|
+
import { stripVTControlCharacters } from "node:util";
|
|
16
|
+
|
|
17
|
+
const minimumNodeMajor = 20;
|
|
18
|
+
const testedNodeMajors = new Set([22, 24, 26]);
|
|
19
|
+
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "", 10);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The commands that BOOT the agent, and so genuinely need the native module.
|
|
23
|
+
*
|
|
24
|
+
* Everything else — `logs`, `status`, `open`, `stop`, `uninstall`, `setup`,
|
|
25
|
+
* `--help` — only inspects or dismantles an install, and all of them were
|
|
26
|
+
* verified to run with the module unloadable. Failing them on a broken probe
|
|
27
|
+
* takes away the diagnostic path (`logs`) and the recovery path (`stop`,
|
|
28
|
+
* `uninstall`) from precisely the user the probe exists to help: they are told
|
|
29
|
+
* to reinstall, and cannot remove the wedged service first.
|
|
30
|
+
*
|
|
31
|
+
* `start`/`restart`/`install` don't open the database in THIS process — they
|
|
32
|
+
* hand off to launchd/systemd — but they all end in a running agent, so
|
|
33
|
+
* failing fast here beats a crash-looping service the user then has to chase
|
|
34
|
+
* through the log.
|
|
35
|
+
*/
|
|
36
|
+
const commandsNeedingNativeSqlite = new Set([
|
|
37
|
+
"run",
|
|
38
|
+
"start",
|
|
39
|
+
"restart",
|
|
40
|
+
"install",
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Of those, the ones whose `--dry-run` prints a plan and boots nothing.
|
|
45
|
+
*
|
|
46
|
+
* `run` is deliberately absent: it ignores the flag and boots regardless, so
|
|
47
|
+
* exempting on the flag alone would wave through the one command that really
|
|
48
|
+
* does need the module.
|
|
49
|
+
*/
|
|
50
|
+
const dryRunnableCommands = new Set(["start", "restart", "install"]);
|
|
51
|
+
|
|
52
|
+
/** Whether this invocation will actually end in a running agent. */
|
|
53
|
+
function needsNativeSqlite(argv) {
|
|
54
|
+
const command = argv[2] ?? "";
|
|
55
|
+
if (!commandsNeedingNativeSqlite.has(command)) return false;
|
|
56
|
+
return !(dryRunnableCommands.has(command) && argv.includes("--dry-run"));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function errorSummary(error) {
|
|
60
|
+
// Native loader errors can carry ANSI colour, which lands as escape noise in
|
|
61
|
+
// a log file or a non-TTY pipe. Strip it before picking the line to show.
|
|
62
|
+
const message = stripVTControlCharacters(
|
|
63
|
+
error instanceof Error ? error.message : String(error),
|
|
64
|
+
);
|
|
65
|
+
const firstLine = message
|
|
66
|
+
.split(/\r?\n/)
|
|
67
|
+
.map((line) => line.trim())
|
|
68
|
+
.find(Boolean);
|
|
69
|
+
if (!firstLine) return "unknown error";
|
|
70
|
+
return firstLine.length > 240 ? `${firstLine.slice(0, 237)}...` : firstLine;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function nativeRecoveryAdvice() {
|
|
74
|
+
return process.versions.electron
|
|
75
|
+
? "Update or reinstall the Uai Host desktop app and retry."
|
|
76
|
+
: "Reinstall @moondeck/station; if that still fails, switch to Node.js 24 LTS and reinstall.";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function probeNativeSqlite() {
|
|
80
|
+
try {
|
|
81
|
+
const { default: Database } = await import("better-sqlite3");
|
|
82
|
+
const database = new Database(":memory:");
|
|
83
|
+
database.close();
|
|
84
|
+
return { ok: true };
|
|
85
|
+
} catch (error) {
|
|
86
|
+
return { ok: false, error };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function main() {
|
|
91
|
+
if (!Number.isInteger(nodeMajor) || nodeMajor < minimumNodeMajor) {
|
|
92
|
+
console.error(
|
|
93
|
+
`moondeck-station requires Node.js 20 or newer; found v${process.versions.node}. Install Node.js 24 LTS and retry.`,
|
|
94
|
+
);
|
|
95
|
+
process.exitCode = 1;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const sqliteProbe = await probeNativeSqlite();
|
|
100
|
+
if (!sqliteProbe.ok) {
|
|
101
|
+
const detail =
|
|
102
|
+
`moondeck-station could not load its native SQLite module on Node.js v${process.versions.node}. ` +
|
|
103
|
+
`${nativeRecoveryAdvice()} Cause: ${errorSummary(sqliteProbe.error)}`;
|
|
104
|
+
if (needsNativeSqlite(process.argv)) {
|
|
105
|
+
console.error(detail);
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Still say it — a broken module IS why their service is down — but let
|
|
110
|
+
// the command through so they can read the log and uninstall.
|
|
111
|
+
console.warn(`${detail} Continuing — this command does not need it.`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Only when the probe actually succeeded — otherwise this contradicts the
|
|
115
|
+
// warning just printed, telling the user SQLite loaded right after saying it
|
|
116
|
+
// could not.
|
|
117
|
+
if (sqliteProbe.ok && !testedNodeMajors.has(nodeMajor)) {
|
|
118
|
+
console.warn(
|
|
119
|
+
`moondeck-station has not been tested on Node.js v${process.versions.node}; continuing because native SQLite loaded. Node.js 24 LTS is recommended.`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Keep this import behind the native probe: the preflight must run in plain
|
|
124
|
+
// Node before tsx (and the TypeScript application graph) is loaded.
|
|
125
|
+
const { register } = await import("tsx/esm/api");
|
|
126
|
+
register();
|
|
127
|
+
await import(new URL("../src/cli.ts", import.meta.url).href);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await main();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
CREATE TABLE `uai_host_tasks` (
|
|
2
|
+
`task_id` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`code_server_port` integer,
|
|
4
|
+
`preview_ports` text DEFAULT '[]' NOT NULL,
|
|
5
|
+
`compose_project` text,
|
|
6
|
+
`worktree_path` text,
|
|
7
|
+
`status_mirror` text,
|
|
8
|
+
`locked_at` integer,
|
|
9
|
+
`started_at` integer,
|
|
10
|
+
`ended_at` integer,
|
|
11
|
+
`updated_at` integer DEFAULT (unixepoch() * 1000) NOT NULL
|
|
12
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ALTER TABLE `uai_host_tasks` ADD `owner_user_id` text;--> statement-breakpoint
|
|
2
|
+
ALTER TABLE `uai_host_tasks` ADD `owner_email` text;--> statement-breakpoint
|
|
3
|
+
ALTER TABLE `uai_host_tasks` ADD `project_slugs` text DEFAULT '[]' NOT NULL;--> statement-breakpoint
|
|
4
|
+
CREATE TABLE `uai_host_events` (
|
|
5
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
6
|
+
`task_id` text NOT NULL,
|
|
7
|
+
`kind` text NOT NULL,
|
|
8
|
+
`ts` integer DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
9
|
+
`detail` text
|
|
10
|
+
);--> statement-breakpoint
|
|
11
|
+
CREATE INDEX `uai_host_events_ts_idx` ON `uai_host_events` (`ts`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE `uai_host_tasks` ADD `owner_name` text;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
DROP TABLE IF EXISTS `host_env_vars`;
|
|
2
|
+
--> statement-breakpoint
|
|
3
|
+
CREATE TABLE `host_project_env` (
|
|
4
|
+
`project_id` text NOT NULL,
|
|
5
|
+
`key` text NOT NULL,
|
|
6
|
+
`value_enc` text NOT NULL,
|
|
7
|
+
`updated_at` integer NOT NULL DEFAULT (unixepoch() * 1000),
|
|
8
|
+
PRIMARY KEY (`project_id`, `key`)
|
|
9
|
+
);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- ADR-033: non-expiring per-host tokens. `kind` distinguishes the stored token:
|
|
2
|
+
-- 'refresh' (legacy, ADR-027) → refresh_token_ct holds a refresh token; the
|
|
3
|
+
-- host exchanges it for short-lived access tokens.
|
|
4
|
+
-- 'access' (ADR-033) → refresh_token_ct holds a long-lived, non-
|
|
5
|
+
-- expiring access token; injected directly, no exchange/refresh.
|
|
6
|
+
-- Existing rows default to 'refresh' (their current semantics).
|
|
7
|
+
ALTER TABLE `host_github_tokens` ADD `kind` text DEFAULT 'refresh' NOT NULL;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- ADR-057: user-authed MCP connections. Secrets sealed with the host master
|
|
2
|
+
-- key (ct.nonce base64, like host_project_env.value_enc); the cloud holds only
|
|
3
|
+
-- non-secret metadata.
|
|
4
|
+
CREATE TABLE `host_mcp_connections` (
|
|
5
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
6
|
+
`user_id` text NOT NULL,
|
|
7
|
+
`url` text NOT NULL,
|
|
8
|
+
`auth_kind` text NOT NULL,
|
|
9
|
+
`token_endpoint` text,
|
|
10
|
+
`redirect_uri` text,
|
|
11
|
+
`client_id` text,
|
|
12
|
+
`client_secret_enc` text,
|
|
13
|
+
`pkce_verifier_enc` text,
|
|
14
|
+
`secret_enc` text,
|
|
15
|
+
`status` text DEFAULT 'pending' NOT NULL,
|
|
16
|
+
`scopes` text,
|
|
17
|
+
`updated_at` integer NOT NULL
|
|
18
|
+
);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- ADR-061: durable agent sessions. One row per (task, agent) tracking the
|
|
2
|
+
-- live in-container runner and how far the host has consumed its outbox —
|
|
3
|
+
-- the byte offset is what makes a host restart resume instead of respawn.
|
|
4
|
+
CREATE TABLE `host_agent_sessions` (
|
|
5
|
+
`task_id` text NOT NULL,
|
|
6
|
+
`agent_id` text NOT NULL,
|
|
7
|
+
`session_dir` text NOT NULL,
|
|
8
|
+
`container_name` text NOT NULL,
|
|
9
|
+
`kind` text NOT NULL,
|
|
10
|
+
`outbox_offset` integer DEFAULT 0 NOT NULL,
|
|
11
|
+
`status` text DEFAULT 'running' NOT NULL,
|
|
12
|
+
`created_at` integer NOT NULL,
|
|
13
|
+
`updated_at` integer NOT NULL,
|
|
14
|
+
PRIMARY KEY(`task_id`, `agent_id`)
|
|
15
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- ADR-076: multiple accounts per engine. One row per EXTRA (non-default)
|
|
2
|
+
-- credential for an engine kind; the legacy single slot is synthesized as the
|
|
3
|
+
-- "default" account and is NOT stored here. Secret material is sealed with the
|
|
4
|
+
-- host master key (env kind) or lives in an isolated host dir (config-dir kind).
|
|
5
|
+
CREATE TABLE `host_engine_accounts` (
|
|
6
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
7
|
+
`kind` text NOT NULL,
|
|
8
|
+
`label` text NOT NULL,
|
|
9
|
+
`auth_kind` text NOT NULL,
|
|
10
|
+
`secret_enc` text,
|
|
11
|
+
`config_dir` text,
|
|
12
|
+
`created_at` integer NOT NULL
|
|
13
|
+
);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- ADR-078: Codex restart-survival. Persist the app-server thread id so a
|
|
2
|
+
-- respawned Codex (allowAttach:false → kill+respawn on host restart) can
|
|
3
|
+
-- `thread/resume` the SAME durable thread from its on-disk rollout instead of
|
|
4
|
+
-- starting a fresh one and losing the conversation. Null for non-codex kinds.
|
|
5
|
+
ALTER TABLE `host_agent_sessions` ADD `codex_thread_id` text;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
-- Durable runners otherwise attach by task + agent alone. Persist the
|
|
2
|
+
-- host-owned launch-policy generation so a rolling policy/tool transition can
|
|
3
|
+
-- replace an incompatible live runner instead of silently inheriting it.
|
|
4
|
+
ALTER TABLE `host_agent_sessions` ADD `attach_compatibility_key` text;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ALTER TABLE `host_github_tokens` ADD `generation` integer DEFAULT 0 NOT NULL;
|
|
2
|
+
--> statement-breakpoint
|
|
3
|
+
CREATE TABLE `host_github_credential_generations` (
|
|
4
|
+
`user_id` text PRIMARY KEY NOT NULL,
|
|
5
|
+
`generation` integer DEFAULT 0 NOT NULL,
|
|
6
|
+
`mutation` text DEFAULT 'set' NOT NULL,
|
|
7
|
+
`updated_at` integer NOT NULL
|
|
8
|
+
);
|
|
9
|
+
--> statement-breakpoint
|
|
10
|
+
INSERT INTO `host_github_credential_generations` (`user_id`, `generation`, `mutation`, `updated_at`)
|
|
11
|
+
SELECT `user_id`, 0, 'set', `updated_at` FROM `host_github_tokens`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CREATE INDEX `uai_host_events_task_id_idx` ON `uai_host_events` (`task_id`);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CREATE TABLE `host_settings` (
|
|
2
|
+
`id` text PRIMARY KEY DEFAULT 'host' NOT NULL,
|
|
3
|
+
`retain_terminal_history` integer DEFAULT true NOT NULL,
|
|
4
|
+
`updated_at` integer DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
5
|
+
CONSTRAINT "host_settings_singleton" CHECK (`host_settings`.`id` = 'host'),
|
|
6
|
+
CONSTRAINT "host_settings_retention_boolean" CHECK (`host_settings`.`retain_terminal_history` IN (0, 1))
|
|
7
|
+
);
|
|
8
|
+
--> statement-breakpoint
|
|
9
|
+
INSERT INTO `host_settings` (`id`, `retain_terminal_history`) VALUES ('host', true);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- ADR-131 Decision 3: engine accounts carry a scope — 'host' (the owner's,
|
|
2
|
+
-- today's rows) or 'org:<orgId>' (a workspace's account on a shared host).
|
|
3
|
+
-- Tasks resolve accounts by their scope; org scopes never see the default
|
|
4
|
+
-- slot or the host's rows.
|
|
5
|
+
ALTER TABLE `host_engine_accounts` ADD `scope` text NOT NULL DEFAULT 'host';--> statement-breakpoint
|
|
6
|
+
CREATE INDEX `host_engine_accounts_scope_kind_idx` ON `host_engine_accounts` (`scope`,`kind`);--> statement-breakpoint
|
|
7
|
+
ALTER TABLE `uai_host_tasks` ADD `engine_account_scope` text;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- ADR-134 slice 2 (host 0.9.113): per-user credentials mirror to the
|
|
2
|
+
-- credential store on Uai-operated hosts. Null on owned hosts and before the
|
|
3
|
+
-- first successful mirror.
|
|
4
|
+
ALTER TABLE `host_github_tokens` ADD `store_ref` text;--> statement-breakpoint
|
|
5
|
+
ALTER TABLE `host_ssh_keys` ADD `store_ref` text;--> statement-breakpoint
|
|
6
|
+
ALTER TABLE `host_mcp_connections` ADD `store_ref` text;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Machine tasks (ADR-121) have no compose env, so per-project env values
|
|
2
|
+
-- (ADR-015) must ride each agent session's env instead — and the host only
|
|
3
|
+
-- knew a task's project SLUGS while env is keyed by project id. Lead project
|
|
4
|
+
-- first. Older rows stay '[]' (Docker tasks never read it).
|
|
5
|
+
ALTER TABLE `uai_host_tasks` ADD `project_ids` text NOT NULL DEFAULT '[]';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
-- ADR-133: the project's org, so the mirrored parameter can carry the `org`
|
|
2
|
+
-- tag the task-machine lease policy conditions on. Null until the cloud sends
|
|
3
|
+
-- it (env.var.set / env.var.list with orgId) or a stored value carries it.
|
|
4
|
+
ALTER TABLE `host_project_env` ADD `org_id` text;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- ADR-153: durable rollout fence for per-command project env delivery.
|
|
2
|
+
-- Existing/null rows are interpreted as `baked`; new task-up writes `loader`
|
|
3
|
+
-- before creating runtime resources, so recovery never launches a binary that
|
|
4
|
+
-- is absent from an older container image.
|
|
5
|
+
ALTER TABLE `uai_host_tasks` ADD `env_mode` text;
|
|
6
|
+
--> statement-breakpoint
|
|
7
|
+
-- Value-free declaration/literal metadata needed to rebuild the resolver
|
|
8
|
+
-- after runner restart, before the cloud re-sends task-up.
|
|
9
|
+
ALTER TABLE `uai_host_tasks` ADD `project_env_spec` text;
|