feat(ops): R720 WS-rollout deploy/update script (G)
Idempotent attended update of the live coordinator to WS0-WS5: rsync repo + handbook, install fastapi/uvicorn, append AGENT_TEAM_API_TOKEN/SEA_HAVEN_HANDBOOK_DIR to secrev.env if absent, restart the daemon, smoke tests. HTTP API is an opt-in separate step; P3 dispatch stays inert. Snapshot-first + confirm before restart.
This commit is contained in:
parent
a96a5b487a
commit
0689d1696c
1 changed files with 104 additions and 0 deletions
104
agent-team/scripts/deploy-r720-ws-rollout.sh
Executable file
104
agent-team/scripts/deploy-r720-ws-rollout.sh
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env bash
|
||||
# deploy-r720-ws-rollout.sh — attended UPDATE of the live R720 agent-team
|
||||
# coordinator to the WS0–WS5 rollout (PRs #43–#46 + the activation wiring).
|
||||
#
|
||||
# This is an UPDATE, not a first-time provision: P1 is already deployed per
|
||||
# agent-team/DEPLOY-R720.md (repo rsynced to ~/orchestrator, venv at
|
||||
# agent-team/.venv, systemd unit agent-team-coordinator.service running).
|
||||
# Run this from the MAC, after the WS branches have merged to main. It rsyncs
|
||||
# the new code, installs the new deps, appends the new secrets if absent, syncs
|
||||
# the engineering handbook, restarts the coordinator, and smoke-tests.
|
||||
#
|
||||
# It is idempotent and FAILS LOUDLY. It changes a live box, so:
|
||||
# 1) SNAPSHOT FIRST (Hyper-V checkpoint of sh-secrev on the R720 host).
|
||||
# 2) It prompts before the restart.
|
||||
#
|
||||
# What goes LIVE after this (the safe, ungated seams):
|
||||
# * WS1 in-process multi-model invokers (bind_multi_invoker, already wired)
|
||||
# * WS5 handbook context_provider injected into the planner prompt
|
||||
# * WS2 Slack /new-task -> start a task (AUTHZ-01 owner allowlist gated)
|
||||
# The HTTP API (WS1) + the /delegate hook are OPTIONAL and started separately
|
||||
# (see step 6). The P3 dispatch/build-verify path stays INERT (gated).
|
||||
set -euo pipefail
|
||||
|
||||
# ── Config (override via env) ────────────────────────────────────────────────
|
||||
BOX="${BOX:-adam@10.10.60.120}"
|
||||
SSH_KEY="${SSH_KEY:-$HOME/.ssh/r720_seahaven}"
|
||||
REPO_LOCAL="${REPO_LOCAL:-$HOME/Documents/repositories/orchestrator}"
|
||||
HANDBOOK_LOCAL="${HANDBOOK_LOCAL:-$HOME/Documents/repositories/engineering-handbook}"
|
||||
# Where the handbook lands on the box; must match SEA_HAVEN_HANDBOOK_DIR below.
|
||||
HANDBOOK_REMOTE="${HANDBOOK_REMOTE:-/home/adam/.sea-haven/engineering-handbook}"
|
||||
SSH="ssh -i ${SSH_KEY} ${BOX}"
|
||||
|
||||
say() { printf '\n\033[1;36m== %s\033[0m\n' "$*"; }
|
||||
confirm() { read -r -p "$1 [y/N] " a; [ "$a" = "y" ] || [ "$a" = "Y" ]; }
|
||||
|
||||
say "Preflight"
|
||||
[ -f "${SSH_KEY}" ] || { echo "missing SSH key ${SSH_KEY}"; exit 1; }
|
||||
$SSH true || { echo "cannot reach ${BOX}"; exit 1; }
|
||||
echo "SNAPSHOT REMINDER: take a Hyper-V checkpoint of sh-secrev on the R720 host now."
|
||||
confirm "Snapshot taken and ready to update the LIVE coordinator?" || { echo "aborted"; exit 1; }
|
||||
|
||||
say "1. rsync repo (Mac -> box; same excludes as the P1 runbook)"
|
||||
rsync -av --exclude .env --exclude .venv --exclude .git --exclude '__pycache__' \
|
||||
"${REPO_LOCAL}/" "${BOX}:orchestrator/"
|
||||
|
||||
say "2. rsync engineering handbook -> ${HANDBOOK_REMOTE} (WS5 context_provider source)"
|
||||
if [ -d "${HANDBOOK_LOCAL}" ]; then
|
||||
$SSH "mkdir -p ${HANDBOOK_REMOTE}"
|
||||
rsync -av --delete --exclude .git "${HANDBOOK_LOCAL}/" "${BOX}:${HANDBOOK_REMOTE}/"
|
||||
else
|
||||
echo "WARN: ${HANDBOOK_LOCAL} not found; context_provider will return '' (fail-safe). Skipping."
|
||||
fi
|
||||
|
||||
say "3. Install new venv deps (fastapi/uvicorn for the WS1 HTTP API)"
|
||||
# requirements.txt now pins fastapi==0.136.1 / uvicorn==0.46.0. The coordinator
|
||||
# itself does not need them, but the optional HTTP API (step 6) does.
|
||||
$SSH 'cd ~/orchestrator/agent-team && . .venv/bin/activate && pip install --upgrade "fastapi==0.136.1" "uvicorn==0.46.0"'
|
||||
|
||||
say "4. Append new secrets to ~/secrev.env if absent (mode 600, never committed)"
|
||||
# AGENT_TEAM_API_TOKEN: required only if you run the HTTP API / /delegate hook.
|
||||
# SEA_HAVEN_HANDBOOK_DIR: where load_handbook_conventions() reads from.
|
||||
$SSH "bash -s" <<REMOTE
|
||||
set -euo pipefail
|
||||
touch ~/secrev.env && chmod 600 ~/secrev.env
|
||||
grep -q '^SEA_HAVEN_HANDBOOK_DIR=' ~/secrev.env || \
|
||||
echo 'SEA_HAVEN_HANDBOOK_DIR=${HANDBOOK_REMOTE}' >> ~/secrev.env
|
||||
if grep -q '^AGENT_TEAM_API_TOKEN=' ~/secrev.env; then
|
||||
echo 'AGENT_TEAM_API_TOKEN already set; leaving as-is.'
|
||||
else
|
||||
echo 'AGENT_TEAM_API_TOKEN NOT set. Add it now (generated on the Mac):'
|
||||
echo ' echo "AGENT_TEAM_API_TOKEN=<token>" >> ~/secrev.env && chmod 600 ~/secrev.env'
|
||||
echo '(only needed for the HTTP API / auto-delegate hook; the coordinator runs without it.)'
|
||||
fi
|
||||
REMOTE
|
||||
|
||||
say "5. Restart the coordinator daemon"
|
||||
confirm "Restart agent-team-coordinator.service now?" || { echo "skipped restart"; exit 0; }
|
||||
$SSH 'sudo systemctl restart agent-team-coordinator.service && sleep 2 && systemctl is-active agent-team-coordinator.service'
|
||||
$SSH 'journalctl -u agent-team-coordinator.service -n 30 --no-pager'
|
||||
|
||||
say "6. (OPTIONAL) HTTP API + /delegate hook — start only if you want them"
|
||||
cat <<'NOTE'
|
||||
The coordinator now serves WS5 context + WS2 /new-task. The WS1 HTTP API is a
|
||||
SEPARATE process (api.serve(), 127.0.0.1:8765, bearer auth). To run it:
|
||||
- ensure AGENT_TEAM_API_TOKEN is set in ~/secrev.env
|
||||
- run: cd ~/orchestrator/agent-team && . .venv/bin/activate && \
|
||||
python3 -c "from agent_team.api import serve; serve()"
|
||||
- (for persistence, add a second systemd unit; not auto-installed here.)
|
||||
Then set AGENT_TEAM_API_TOKEN + AGENT_TEAM_API_URL in the Mac Claude Code env
|
||||
to enable the /delegate hook (sea-haven-claude-plugin).
|
||||
NOTE
|
||||
|
||||
say "7. SMOKE TESTS (manual)"
|
||||
cat <<'SMOKE'
|
||||
a) Coordinator up: systemctl is-active agent-team-coordinator.service -> active
|
||||
b) Handbook visible: cd ~/orchestrator/agent-team && . .venv/bin/activate && \
|
||||
python3 -c "from agent_team.nodes.handbook import load_handbook_conventions as h; print(bool(h()))" -> True
|
||||
c) Slack /new-task: post "/new-task add a smoke-test file" in #agent-team as an
|
||||
allowlisted owner -> the bot replies with a clarifying question.
|
||||
d) (if API running) auth: curl -s -o /dev/null -w '%{http_code}' \
|
||||
-H "Authorization: Bearer $AGENT_TEAM_API_TOKEN" http://127.0.0.1:8765/tasks -> 405 (GET not allowed = API up + authed)
|
||||
ROLLBACK: restore the pre-update Hyper-V checkpoint (one-command revert).
|
||||
SMOKE
|
||||
say "Done."
|
||||
Reference in a new issue