Files
AzerothAI/deploy/pc-lab/remote-dashboard-dev.sh
Richard Clark 5f0fc86cf9
Core tests / core (push) Successful in 9m57s
Full verification / application (push) Failing after 5m16s
Full verification / local-brain (push) Failing after 6m15s
Realm simulation / simulated-live-world (push) Failing after 5m32s
WoW integration lab / real-worldserver (push) Canceled after 17m23s
Import verified AzerothAI snapshot from GitHub
Source branch: feature/ai-brain-router
Source commit: c2a09e0460465201a58aaab56c71424e9a96405e
2026-09-22 13:12:54 -04:00

159 lines
5.6 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
LAB_ROOT="${AZEROTHAI_PLAYABLE_ROOT:-$HOME/azerothai-pc-lab}"
DEV_PORT="${AZEROTHAI_REMOTE_UI_DEV_PORT:-5173}"
PROXY_PORT="${AZEROTHAI_TAILNET_PROXY_PORT:-8788}"
APP_PORT="${AZEROTHAI_APP_PORT:-8787}"
PID_FILE="$LAB_ROOT/azerothai-ui-dev.pid"
LOG_FILE="$LAB_ROOT/azerothai-ui-dev.log"
NGINX_SITE="/etc/nginx/sites-available/azerothai-tailnet"
NGINX_LINK="/etc/nginx/sites-enabled/azerothai-tailnet"
need(){ command -v "$1" >/dev/null 2>&1 || { echo "Missing required command: $1" >&2; exit 1; }; }
need curl
need tailscale
need pnpm
TAILSCALE_IP="$(tailscale ip -4 2>/dev/null | head -n1 || true)"
if [[ -z "$TAILSCALE_IP" ]]; then
echo "No active Tailscale IPv4 address found." >&2
exit 2
fi
DNS_NAME="$(tailscale status --json 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print((d.get("Self",{}).get("DNSName") or "").rstrip("."))' 2>/dev/null || true)"
echo "==> Rebuilding live AzerothAI backend with current source"
cd "$REPO_ROOT"
pnpm build
if [[ -f "$LAB_ROOT/azerothai.pid" ]]; then
OLD_APP_PID="$(cat "$LAB_ROOT/azerothai.pid" 2>/dev/null || true)"
if [[ -n "$OLD_APP_PID" ]]; then kill "$OLD_APP_PID" 2>/dev/null || true; fi
fi
pkill -f "wrangler.*8787" 2>/dev/null || true
pkill -f "pnpm.*start:lan" 2>/dev/null || true
sleep 2
nohup pnpm start:lan >"$LAB_ROOT/azerothai.log" 2>&1 &
echo $! > "$LAB_ROOT/azerothai.pid"
echo "==> Waiting for live AzerothAI backend"
for _ in {1..90}; do
if curl -fsS "http://127.0.0.1:$APP_PORT/api/health" >/dev/null 2>&1; then break; fi
sleep 1
done
curl -fsS "http://127.0.0.1:$APP_PORT/api/health" >/dev/null
echo "==> Restarting autonomous high-level service if this lab is configured"
RUNTIME_ENV="$LAB_ROOT/runtime.env"
if [[ -f "$RUNTIME_ENV" ]] && grep -q '^AUTONOMY_TOKEN=' "$RUNTIME_ENV"; then
bash "$REPO_ROOT/deploy/playable/install-autonomy-service.sh"
fi
echo "==> Ensuring durable ALE database relay is active"
if [[ -f "$RUNTIME_ENV" ]] && grep -q '^ALE_BRIDGE_TOKEN=' "$RUNTIME_ENV" && grep -q '^DOCKER_DB_ROOT_PASSWORD=' "$RUNTIME_ENV"; then
bash "$REPO_ROOT/deploy/playable/install-ale-relay-service.sh"
fi
echo "==> Starting hydration-safe dashboard UI"
mkdir -p "$LAB_ROOT"
if [[ -f "$PID_FILE" ]]; then
OLD_PID="$(cat "$PID_FILE" 2>/dev/null || true)"
if [[ -n "$OLD_PID" ]]; then kill "$OLD_PID" 2>/dev/null || true; fi
fi
pkill -f "vinext.*$DEV_PORT" 2>/dev/null || true
cd "$REPO_ROOT"
nohup pnpm dev >"$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
for _ in {1..90}; do
if curl -fsS "http://127.0.0.1:$DEV_PORT/" >/dev/null 2>&1; then
break
fi
sleep 1
done
if ! curl -fsS "http://127.0.0.1:$DEV_PORT/" >/dev/null 2>&1; then
echo "Dashboard UI dev server did not start." >&2
tail -80 "$LOG_FILE" >&2 || true
exit 3
fi
echo "==> Installing nginx if needed"
if ! command -v nginx >/dev/null 2>&1; then
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y nginx
fi
echo "==> Wiring UI to the live AzerothAI API"
sudo tee "$NGINX_SITE" >/dev/null <<EOF
server {
listen 127.0.0.1:$PROXY_PORT;
server_name _;
location ^~ /api/ {
proxy_http_version 1.1;
proxy_buffering off;
proxy_cache off;
proxy_set_header Host \$http_host;
proxy_set_header X-Forwarded-Host \$http_host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://127.0.0.1:$APP_PORT;
add_header Cache-Control "no-store" always;
}
location / {
proxy_http_version 1.1;
proxy_set_header Host 127.0.0.1:$DEV_PORT;
proxy_set_header X-Forwarded-Host \$http_host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://127.0.0.1:$DEV_PORT;
add_header Cache-Control "no-store" always;
}
}
EOF
sudo ln -sfn "$NGINX_SITE" "$NGINX_LINK"
sudo nginx -t
sudo systemctl enable --now nginx
sudo systemctl reload nginx
echo "==> Verifying dashboard and live API through proxy"
VERIFY_HOST="${DNS_NAME:-$TAILSCALE_IP}"
curl -fsS -H "Host: $VERIFY_HOST" "http://127.0.0.1:$PROXY_PORT/" >/dev/null
curl -fsS -H "Host: $VERIFY_HOST" "http://127.0.0.1:$PROXY_PORT/api/state" >/dev/null
ORIGIN="https://$VERIFY_HOST"
ACTION_BODY="$(mktemp)"
ACTION_CODE="$(curl -sS -o "$ACTION_BODY" -w '%{http_code}' -X POST -H "Host: $VERIFY_HOST" -H "Origin: $ORIGIN" -H "Content-Type: application/json" --data '{}' "http://127.0.0.1:$PROXY_PORT/api/actions" || true)"
if [[ "$ACTION_CODE" == "403" ]] && grep -q "Cross-origin action rejected" "$ACTION_BODY"; then
echo "Remote action origin check is still rejecting the trusted tailnet host." >&2
cat "$ACTION_BODY" >&2
rm -f "$ACTION_BODY"
exit 47
fi
rm -f "$ACTION_BODY"
echo "Remote action origin check: accepted (HTTP $ACTION_CODE expected for empty test action)"
echo "==> Publishing privately with Tailscale Serve"
sudo tailscale serve --bg "$PROXY_PORT"
STAMP="$(date +%s)"
echo
echo "============================================================"
echo " AzerothAI remote dashboard is ready"
echo "============================================================"
if [[ -n "$DNS_NAME" ]]; then
echo "Open this fresh URL:"
echo " https://$DNS_NAME/?v=$STAMP"
else
echo "Run: tailscale serve status"
fi
echo
echo "UI log: $LOG_FILE"
echo "Live API remains on port $APP_PORT."