Agents can now provision their sandbox on a connected fleet node instead of the gateway host. Local stays the strict default, so existing agents are byte-for- byte unaffected until explicitly placed elsewhere. Security parity: the daemon links the REAL cm-sandbox DockerDriver and runs the typed container ops (sb_provision/sb_exec/sb_destroy/sb_health/sb_list) through it — identical hardening (cap-drop ALL, seccomp, no-net, read-only, non-root) to local sandboxes. cm-sandbox spec types are now Serialize/Deserialize so the spec crosses the channel. - cm-api: RemoteDriver (impl SandboxDriver over the node channel) + HubDriverProvider (impl cm_runtime::NodeDriverProvider, hands out a driver only for connected nodes via a sync online set) + NodeHub.call/is_connected. AppState.with_node_hub so the hub is shared with the placement provider. - cm-runtime SandboxManager: driver_for(node_id) routes by the recorded agent_containers.node_id (local default = existing driver, identical path); placement_node() reads the workspace setting and falls back to local if the node is offline; exec/release route accordingly. NodeDriverProvider trait. - DB: 0020_workspace_placement + repo (for_agent/get/set/clear). - main.rs: build the NodeHub first; inject HubDriverProvider into the agent manager + share the hub with AppState. - API+UI: GET/PUT /api/fleet/placement + a "Run agents on: Local / <node>" selector in the Fleet overview. Note: a node must be able to pull the agent image (the daemon docker-pulls it); interactive PTY for agent containers on remote nodes is not wired (Terminal app stays local) — the in-dashboard node shell already covers host access. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
64 lines
2.4 KiB
Bash
64 lines
2.4 KiB
Bash
#!/usr/bin/env bash
|
||
# Clawmates Visualization Layer — installer (idempotent, safe to re-run)
|
||
set -euo pipefail
|
||
cd "$(dirname "$0")"
|
||
|
||
say() { printf '\033[1;38;5;209m›\033[0m %s\n' "$*"; }
|
||
ok() { printf '\033[1;32m✓\033[0m %s\n' "$*"; }
|
||
warn() { printf '\033[1;33m!\033[0m %s\n' "$*"; }
|
||
|
||
echo
|
||
say "Clawmates visualization layer — install"
|
||
echo
|
||
|
||
# 1) Node >= 20 -------------------------------------------------------------
|
||
if command -v node >/dev/null 2>&1; then
|
||
NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]')"
|
||
if [ "$NODE_MAJOR" -ge 20 ]; then ok "Node $(node -v)"; else
|
||
warn "Node $(node -v) found but >= 20 is required."
|
||
echo " Install Node 20 LTS: https://nodejs.org or 'sudo apt install nodejs' from NodeSource."
|
||
exit 1
|
||
fi
|
||
else
|
||
warn "Node not found. Install Node 20 LTS, then re-run:"
|
||
echo " curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs"
|
||
exit 1
|
||
fi
|
||
|
||
# 2) Bridge deps (intentionally none beyond Node built-ins) -----------------
|
||
if [ -f realtime/package.json ]; then
|
||
( cd realtime && npm ci --omit=dev 2>/dev/null || npm install --omit=dev 2>/dev/null || true )
|
||
ok "Bridge ready (dependency-free)"
|
||
fi
|
||
|
||
# 3) Static file server ------------------------------------------------------
|
||
if command -v caddy >/dev/null 2>&1; then
|
||
ok "Caddy present — will serve screens/"
|
||
elif command -v npx >/dev/null 2>&1; then
|
||
warn "Caddy not found; will fall back to 'npx serve'."
|
||
else
|
||
warn "No static server found. Install Caddy: https://caddyserver.com/docs/install"
|
||
fi
|
||
|
||
# 4) .env --------------------------------------------------------------------
|
||
if [ ! -f .env ]; then
|
||
cp .env.example .env
|
||
ok "Wrote .env from .env.example — edit it before running live mode."
|
||
else
|
||
ok ".env already exists (left untouched)"
|
||
fi
|
||
|
||
echo
|
||
ok "Install complete."
|
||
echo
|
||
say "Next — DEMO mode (no backend):"
|
||
echo " (cd realtime && CLAWMATES_MODE=demo node server.mjs)"
|
||
echo " caddy file-server --root ./screens --listen :8080 # or: npx serve ./screens -l 8080"
|
||
echo " open http://localhost:8080/Clawmates%20World.dc.html?live=http://localhost:8420/live"
|
||
echo
|
||
say "Next — LIVE mode (wire to cm-api): edit .env, then"
|
||
echo " (cd realtime && CLAWMATES_MODE=live node server.mjs)"
|
||
echo
|
||
say "See IMPLEMENTATION.md for per-screen wiring, the event taxonomy, Infrastructure (Tailscale/daemon/cloud), and the systemd unit."
|
||
echo
|