#!/usr/bin/env bash # Start a files-first local dev-hub: postgres, migrate, seed, API, optional edge relay. set -euo pipefail STATE_HUB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$STATE_HUB_DIR" PROFILE="${1:-dev}" WITH_EDGE="${WITH_EDGE:-0}" WITH_MCP="${WITH_MCP:-0}" REPO_ROOT="${REPO_ROOT:-$HOME}" usage() { cat <<'USAGE' Usage: scripts/dev_hub_up.sh [dev|fleet] dev — local ephemeral hub on :8000 (default) fleet — prefer fleet tunnel API on :18000 when reachable Environment: WITH_EDGE=1 Start edge relay on :18080 after API is up WITH_MCP=1 Register dev-hub MCP after API is up REPO_ROOT= Parent directory for register-from-classification-all (default: $HOME) USAGE } if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then usage exit 0 fi api_healthy() { curl -fsS --max-time 2 "${1%/}/state/health" >/dev/null 2>&1 } pick_api_base() { if [[ "$PROFILE" == "fleet" ]]; then if api_healthy "http://127.0.0.1:18000"; then echo "http://127.0.0.1:18000" return fi echo "WARN: fleet profile requested but :18000 unreachable; falling back to local :8000" >&2 fi echo "http://127.0.0.1:8000" } API_BASE="$(pick_api_base)" export API_BASE echo "==> Dev hub profile: ${PROFILE}" echo "==> API_BASE: ${API_BASE}" if [[ "$API_BASE" == "http://127.0.0.1:8000" ]]; then echo "==> Starting local postgres + migrations" make db make migrate make seed if api_healthy "$API_BASE"; then echo "==> API already running on :8000" else echo "==> Starting API on :8000 (background)" fuser -k 8000/tcp 2>/dev/null || true nohup "$(command -v uv || echo uv)" run uvicorn api.main:app \ --host 127.0.0.1 --port 8000 \ >"${STATE_HUB_DIR}/.dev-hub-api.log" 2>&1 & for _ in $(seq 1 30); do api_healthy "$API_BASE" && break sleep 1 done api_healthy "$API_BASE" || { echo "ERROR: API failed to start; see .dev-hub-api.log" >&2 exit 1 } echo "==> API healthy" fi echo "==> Registering local repos from classification files under ${REPO_ROOT}" API_BASE="$API_BASE" make register-from-classification-all || { echo "WARN: register-from-classification-all had errors (continuing)" >&2 } else echo "==> Fleet profile: using remote hub; skipping local postgres/migrate/seed" fi if [[ "$WITH_EDGE" == "1" && "$API_BASE" == "http://127.0.0.1:8000" ]]; then echo "==> Starting edge relay on :18080" fuser -k 18080/tcp 2>/dev/null || true STATEHUB_UPSTREAM_URL="$API_BASE" nohup "$(command -v uv || echo uv)" run uvicorn api.edge.relay:app \ --host 127.0.0.1 --port 18080 \ >"${STATE_HUB_DIR}/.dev-hub-edge.log" 2>&1 & echo " Edge relay: http://127.0.0.1:18080 (set API_BASE to this for offline buffering)" fi if [[ "$WITH_MCP" == "1" ]]; then make register-mcp API_BASE="$API_BASE" || echo "WARN: MCP registration skipped" >&2 fi echo "" echo "Dev hub ready." echo " API: ${API_BASE}" echo " Profile: ${PROFILE}" echo " Replay: statehub outbox replay --upstream-url ${API_BASE}" echo " Consistency: statehub fix-consistency --repo --api-base ${API_BASE}"