#!/usr/bin/env bash # setup.sh — HomeAI root orchestrator # # Usage: # ./setup.sh all # run all phases in order # ./setup.sh p1 # infra only # ./setup.sh p2 # llm only # ./setup.sh p1 p2 # multiple phases # ./setup.sh status # show service health # # Phases: p1=infra p2=llm p3=voice p4=agent p5=character # p6=esp32 p7=visual p8=images set -euo pipefail REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=scripts/common.sh source "${REPO_DIR}/scripts/common.sh" # ─── Phase definitions ───────────────────────────────────────────────────────── declare -A PHASE_NAME=( [p1]="homeai-infra (Docker stack)" [p2]="homeai-llm (Ollama + Open WebUI)" [p3]="homeai-voice (STT / TTS / Wyoming)" [p4]="homeai-agent (OpenClaw + skills + mem0)" [p5]="homeai-character (Character Manager UI)" [p6]="homeai-esp32 (ESPHome firmware)" [p7]="homeai-visual (VTube Studio bridge)" [p8]="homeai-images (ComfyUI workflows)" ) PHASE_ORDER=(p1 p2 p3 p4 p5 p6 p7 p8) run_phase() { local phase="$1" local subdir="${REPO_DIR}/homeai-${phase#p}" # Map phase ID to directory name case "$phase" in p1) subdir="${REPO_DIR}/homeai-infra" ;; p2) subdir="${REPO_DIR}/homeai-llm" ;; p3) subdir="${REPO_DIR}/homeai-voice" ;; p4) subdir="${REPO_DIR}/homeai-agent" ;; p5) subdir="${REPO_DIR}/homeai-character" ;; p6) subdir="${REPO_DIR}/homeai-esp32" ;; p7) subdir="${REPO_DIR}/homeai-visual" ;; p8) subdir="${REPO_DIR}/homeai-images" ;; *) die "Unknown phase: $phase" ;; esac local setup_script="${subdir}/setup.sh" if [[ ! -f "$setup_script" ]]; then die "Setup script not found: $setup_script" fi log_section "Phase ${phase^^}: ${PHASE_NAME[$phase]}" bash "$setup_script" } show_status() { log_section "HomeAI Service Status" load_env_services local services=( "Home Assistant|${HA_URL:-http://localhost:8123}" "Portainer|${PORTAINER_URL:-https://localhost:9443}" "Uptime Kuma|${UPTIME_KUMA_URL:-http://localhost:3001}" "Gitea|${GITEA_URL:-http://localhost:3000}" "code-server|${CODE_SERVER_URL:-http://localhost:8090}" "n8n|${N8N_URL:-http://localhost:5678}" "Ollama|${OLLAMA_URL:-http://localhost:11434}" "Open WebUI|${OPEN_WEBUI_URL:-http://localhost:3030}" ) for entry in "${services[@]}"; do local name="${entry%%|*}" local url="${entry##*|}" if curl -sf --max-time 2 "$url" -o /dev/null 2>/dev/null; then printf " ${GREEN}●${RESET} %-20s %s\n" "$name" "$url" else printf " ${RED}○${RESET} %-20s %s\n" "$name" "$url" fi done echo "" } usage() { echo "" echo " Usage: $0 | all | status" echo "" echo " Phases:" for p in "${PHASE_ORDER[@]}"; do printf " %-6s %s\n" "$p" "${PHASE_NAME[$p]}" done echo "" echo " Examples:" echo " $0 all # setup everything in order" echo " $0 p1 p2 # infra + llm only" echo " $0 status # check service health" echo "" } # ─── Main ────────────────────────────────────────────────────────────────────── main() { if [[ $# -eq 0 ]]; then usage exit 0 fi detect_platform # Bootstrap root .env if missing bootstrap_env "${REPO_DIR}" local phases=() for arg in "$@"; do case "$arg" in all) phases=("${PHASE_ORDER[@]}") ;; status) show_status; exit 0 ;; p[1-8]) phases+=("$arg") ;; help|-h|--help) usage; exit 0 ;; *) die "Unknown argument: $arg. Run '$0 help' for usage." ;; esac done if [[ ${#phases[@]} -eq 0 ]]; then usage; exit 0 fi for phase in "${phases[@]}"; do run_phase "$phase" done log_section "Setup complete" show_status } main "$@"