bytelyst-devops-tools/scripts/deploy-gigafactory.sh
saravanakumardb1 f7999fb11b feat(scripts): deploy-gigafactory --full/--with-tracker + tracker-web launch
Extends deploy-gigafactory.sh to optionally start the web tracker (tracker-web)
alongside platform-service and registered factories: adds --full (backend +
register + tracker), --with-tracker, --tracker-only, a per-process pid file with
child-aware --stop, and waits for both to be healthy. Gitignore the new runtime
tracker pid.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-06-01 00:25:16 -07:00

209 lines
8.2 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# deploy-gigafactory.sh — one-shot local deploy of the Agent Gigafactory
# (platform-service fleet module) against the configured backend, then register
# the ecosystem products so live /api/fleet/* calls return data.
#
# Prereqs:
# - learning_ai_common_plat checked out as a sibling of this repo
# - services/platform-service/.env filled (Cosmos endpoint/key, JWT_SECRET, ...)
# e.g. populated from Azure: COSMOS_ENDPOINT/COSMOS_KEY/AZURE_BLOB_CONNECTION_STRING
# - pnpm deps installed in common_plat; Node 18+
#
# Usage:
# ./deploy-gigafactory.sh # start service, wait for health, register products, smoke
# ./deploy-gigafactory.sh --full # full local stack: backend + register factories + web tracker
# ./deploy-gigafactory.sh --with-tracker # also start the web tracker (tracker-web) on $TRACKER_PORT
# ./deploy-gigafactory.sh --tracker-only # backend already running; just start the web tracker
# ./deploy-gigafactory.sh --register-only # service already running on $PORT; just register products
# ./deploy-gigafactory.sh --stop # stop the service + tracker started by this script
# ./deploy-gigafactory.sh --no-register # start + health only, skip product registration
#
# Env overrides:
# COMMON_PLAT path to learning_ai_common_plat (default: ../learning_ai_common_plat)
# PORT platform-service port (default: 4003)
# TRACKER_PORT tracker-web (web tracker) port (default: 3003)
# DEFAULT_PRODUCT_ID product the tracker logs in / scopes to (default: first of $PRODUCTS)
# PRODUCTS space-separated "id|DisplayName|PREFIX" tuples (default: ecosystem set)
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMMON_PLAT="${COMMON_PLAT:-$(cd "$HERE/../../learning_ai_common_plat" 2>/dev/null && pwd || true)}"
PORT="${PORT:-4003}"
TRACKER_PORT="${TRACKER_PORT:-3003}"
PS_DIR="$COMMON_PLAT/services/platform-service"
TRACKER_DIR="$COMMON_PLAT/dashboards/tracker-web"
ENV_FILE="$PS_DIR/.env"
PID_FILE="$HERE/.gigafactory-platform-service.pid"
TRACKER_PID_FILE="$HERE/.gigafactory-tracker-web.pid"
LOG_FILE="${TMPDIR:-/tmp}/gigafactory-platform-service.log"
TRACKER_LOG="${TMPDIR:-/tmp}/gigafactory-tracker-web.log"
BASE="http://localhost:$PORT"
TRACKER_URL="http://localhost:$TRACKER_PORT"
PRODUCTS="${PRODUCTS:-\
lysnrai|LysnrAI|LYS \
mindlyst|MindLyst|MIND \
chronomind|ChronoMind|CHR \
jarvisjr|JarvisJr|JAR \
nomgap|NomGap|NOM \
peakpulse|PeakPulse|PEAK \
flowmonk|FlowMonk|FLOW \
notelett|NoteLett|NOTE \
actiontrail|ActionTrail|ACT \
localmemgpt|LocalMemGPT|LMG \
efforise|EffoRise|EFF}"
die() { echo "error: $*" >&2; exit 1; }
# Stop a process recorded in a pid file, plus any children it spawned
# (next dev / pnpm fork worker processes). Returns 0 if it stopped something.
stop_pidfile() {
local pidfile="$1" label="$2"
[ -f "$pidfile" ] || return 1
local pid; pid="$(cat "$pidfile")"
if kill -0 "$pid" 2>/dev/null; then
pkill -P "$pid" 2>/dev/null || true
kill "$pid" 2>/dev/null && echo "stopped $label (pid $pid)"
fi
rm -f "$pidfile"
return 0
}
stop_service() {
local stopped=1
stop_pidfile "$TRACKER_PID_FILE" "tracker-web" && stopped=0
stop_pidfile "$PID_FILE" "platform-service" && stopped=0
[ "$stopped" = 0 ] || echo "no pid files; nothing started by this script"
}
mint_token() {
node -e '
const c=require("crypto");const s=process.env.JWT_SECRET;
if(!s){console.error("JWT_SECRET not set");process.exit(1);}
const b=o=>Buffer.from(JSON.stringify(o)).toString("base64url");
const h=b({alg:"HS256",typ:"JWT"});const n=Math.floor(Date.now()/1e3);
const p=b({sub:"gigafactory-deploy",email:"deploy@bytelyst.local",role:"admin",type:"access",iat:n,exp:n+3600});
console.log(`${h}.${p}.`+c.createHmac("sha256",s).update(`${h}.${p}`).digest("base64url"));
'
}
# wait_for_url <url> <label> <attempts> <logfile>
wait_for_url() {
local url="$1" label="$2" attempts="${3:-60}" log="${4:-}"
echo -n "waiting for $url "
for _ in $(seq 1 "$attempts"); do
if curl -fsS "$url" >/dev/null 2>&1; then echo "— ok"; return 0; fi
echo -n "."; sleep 1
done
echo; die "$label did not become ready${log:+ (see $log)}"
}
wait_for_health() { wait_for_url "$BASE/health" "platform-service" 60 "$LOG_FILE"; }
# Start the web tracker (tracker-web) wired to the local fleet backend.
start_tracker() {
[ -d "$TRACKER_DIR" ] || die "tracker-web not found at $TRACKER_DIR (set COMMON_PLAT)"
local first; first="$(echo "$PRODUCTS" | awk '{print $1}' | cut -d'|' -f1)"
local product="${DEFAULT_PRODUCT_ID:-$first}"
if curl -fsS "$TRACKER_URL" >/dev/null 2>&1; then
echo "tracker-web already responding on :$TRACKER_PORT — reusing it"
return 0
fi
echo "starting tracker-web (web tracker) on :$TRACKER_PORT (log: $TRACKER_LOG)"
( cd "$TRACKER_DIR" && \
PLATFORM_API_URL="$BASE" \
PLATFORM_SERVICE_URL="$BASE" \
JWT_SECRET="${JWT_SECRET:-}" \
DEFAULT_PRODUCT_ID="$product" \
PRODUCT_ID="$product" \
pnpm dev >"$TRACKER_LOG" 2>&1 ) &
echo $! >"$TRACKER_PID_FILE"
# next dev needs a first compile; give it longer than the API health wait.
wait_for_url "$TRACKER_URL" "tracker-web" 120 "$TRACKER_LOG"
}
register_products() {
local token; token="$(mint_token)"
local created=0 existed=0 failed=0
for tuple in $PRODUCTS; do
IFS='|' read -r id name prefix <<<"$tuple"
local code; code="$(curl -s -o /dev/null -w '%{http_code}' -X POST "$BASE/api/products" \
-H "Authorization: Bearer $token" -H "content-type: application/json" \
-H "x-product-id: $id" \
-d "{\"productId\":\"$id\",\"displayName\":\"$name\",\"licensePrefix\":\"$prefix\"}")"
case "$code" in
200|201) echo " created $id"; created=$((created+1));;
409) echo " exists $id"; existed=$((existed+1));;
*) echo " FAILED $id (HTTP $code)"; failed=$((failed+1));;
esac
done
echo "products: created=$created existed=$existed failed=$failed"
# live smoke: fleet metrics for the first product
local first; first="$(echo "$PRODUCTS" | awk '{print $1}' | cut -d'|' -f1)"
echo -n "smoke GET /api/fleet/metrics ($first): "
curl -s -H "Authorization: Bearer $(mint_token)" -H "x-product-id: $first" \
"$BASE/api/fleet/metrics" | head -c 200; echo
}
# ── main ─────────────────────────────────────────────────────────
MODE_STOP=0; DO_BACKEND=1; DO_REGISTER=1; WITH_TRACKER=0
for arg in "$@"; do
case "$arg" in
--stop) MODE_STOP=1;;
--register-only) DO_BACKEND=0;;
--no-register) DO_REGISTER=0;;
--no-backend) DO_BACKEND=0;;
--with-tracker) WITH_TRACKER=1;;
--full) DO_BACKEND=1; DO_REGISTER=1; WITH_TRACKER=1;;
--tracker-only) DO_BACKEND=0; DO_REGISTER=0; WITH_TRACKER=1;;
-h|--help) sed -n '13,27p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0;;
*) die "unknown argument: $arg (try --help)";;
esac
done
if [ "$MODE_STOP" = 1 ]; then stop_service; exit 0; fi
[ -n "$COMMON_PLAT" ] && [ -d "$PS_DIR" ] || die "platform-service not found (set COMMON_PLAT). Looked in: $PS_DIR"
[ -f "$ENV_FILE" ] || die "$ENV_FILE missing — fill it (Cosmos endpoint/key, JWT_SECRET, blob CS)"
set -a; . "$ENV_FILE"; set +a
if [ "$DO_BACKEND" = 1 ]; then
if curl -fsS "$BASE/health" >/dev/null 2>&1; then
echo "platform-service already healthy on :$PORT — reusing it"
else
echo "starting platform-service on :$PORT (log: $LOG_FILE)"
( cd "$PS_DIR" && pnpm exec tsx src/server.ts >"$LOG_FILE" 2>&1 ) &
echo $! >"$PID_FILE"
wait_for_health
fi
fi
if [ "$DO_REGISTER" = 1 ]; then
register_products
fi
if [ "$WITH_TRACKER" = 1 ]; then
start_tracker
fi
cat <<EOF
Gigafactory is up on $BASE (health: $BASE/health)
EOF
if [ "$WITH_TRACKER" = 1 ]; then
cat <<EOF
Web tracker is up on $TRACKER_URL (proxies fleet API -> $BASE)
Next:
- Open: $TRACKER_URL
- Stop all: $HERE/$(basename "$0") --stop
EOF
else
cat <<EOF
Next:
- Web UI: $HERE/$(basename "$0") --with-tracker (start tracker-web on :$TRACKER_PORT)
- Run e2e: (cd "$TRACKER_DIR" && pnpm exec playwright test)
- Stop: $HERE/$(basename "$0") --stop
EOF
fi