#!/bin/sh set -e SQUADEM_VERSION="${SQUADEM_VERSION:-latest}" SQUADEM_DIR="${SQUADEM_DIR:-$HOME/.squadem}" COMPOSE_URL="https://get.squadem.com/docker-compose.yml" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' info() { printf "${GREEN}[squadem]${NC} %s\n" "$1"; } warn() { printf "${YELLOW}[squadem]${NC} %s\n" "$1"; } error() { printf "${RED}[squadem]${NC} %s\n" "$1"; exit 1; } echo "" echo "${CYAN}${BOLD}" echo " ███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ███████╗███╗ ███╗" echo " ██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔══██╗██╔════╝████╗ ████║" echo " ███████╗██║ ██║██║ ██║███████║██║ ██║█████╗ ██╔████╔██║" echo " ╚════██║██║▄▄ ██║██║ ██║██╔══██║██║ ██║██╔══╝ ██║╚██╔╝██║" echo " ███████║╚██████╔╝╚██████╔╝██║ ██║██████╔╝███████╗██║ ╚═╝ ██║" echo " ╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝" echo "${NC}" echo " AI Command Center" echo "" OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Darwin) OS_NAME="macOS" ;; Linux) OS_NAME="Linux" ;; *) error "Unsupported OS: $OS. Squadem supports macOS and Linux." ;; esac case "$ARCH" in x86_64|amd64) ARCH_NAME="amd64" ;; arm64|aarch64) ARCH_NAME="arm64" ;; *) error "Unsupported architecture: $ARCH" ;; esac info "Detected: $OS_NAME ($ARCH_NAME)" info "Checking prerequisites..." if ! command -v docker >/dev/null 2>&1; then error "Docker is not installed. Install it from https://docker.com/get-started" fi if ! docker compose version >/dev/null 2>&1; then error "Docker Compose v2 is required. Update Docker Desktop or install the compose plugin." fi if ! docker info >/dev/null 2>&1; then error "Docker daemon is not running. Start Docker Desktop and try again." fi DOCKER_VER=$(docker --version | grep -oE '[0-9]+\.[0-9]+' | head -1) info "Docker $DOCKER_VER detected" if [ "$OS" = "Darwin" ]; then TOTAL_MEM_GB=$(sysctl -n hw.memsize 2>/dev/null | awk '{printf "%d", $1/1073741824}') elif [ "$OS" = "Linux" ]; then TOTAL_MEM_GB=$(awk '/MemTotal/ {printf "%d", $2/1048576}' /proc/meminfo 2>/dev/null) fi if [ -n "$TOTAL_MEM_GB" ] && [ "$TOTAL_MEM_GB" -lt 8 ]; then warn "System has ${TOTAL_MEM_GB}GB RAM. Squadem recommends at least 8GB." fi mkdir -p "$SQUADEM_DIR" cd "$SQUADEM_DIR" info "Installing to $SQUADEM_DIR" if [ ! -f .env ]; then info "Generating secure configuration..." gen_password() { openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c "$1"; } PG_PASS=$(gen_password 24) MINIO_PASS=$(gen_password 24) LICENSE_KEY=$(gen_password 32) ADMIN_KEY=$(gen_password 32) N8N_PASS=$(gen_password 16) KC_PASS=$(gen_password 16) cat > .env << ENVEOF # Squadem Configuration (auto-generated) # Edit this file to customize your installation # Version SQUADEM_VERSION=${SQUADEM_VERSION} # Database POSTGRES_USER=eac_user POSTGRES_PASSWORD=${PG_PASS} POSTGRES_DB=eac_db # Object Storage MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=${MINIO_PASS} # Security Keys LICENSE_SECRET_KEY=${LICENSE_KEY} ADMIN_API_KEY=${ADMIN_KEY} # Authentication (set to true to enable Keycloak SSO) AUTH_ENABLED=false KEYCLOAK_ADMIN_PASSWORD=${KC_PASS} # n8n Workflow Engine N8N_BASIC_AUTH_USER=admin N8N_BASIC_AUTH_PASSWORD=${N8N_PASS} # GPU (set to true to force CPU mode) FORCE_CPU=false # External AI Keys (optional) OPENAI_API_KEY= ANTHROPIC_API_KEY= # Diarization (auto/pyannote/nemo) DIARIZATION_BACKEND=auto HF_TOKEN= ENVEOF info "Generated .env with secure random passwords" else warn ".env already exists -- keeping existing configuration" fi info "Downloading Squadem ${SQUADEM_VERSION}..." if command -v curl >/dev/null 2>&1; then curl -fsSL "$COMPOSE_URL" -o docker-compose.yml elif command -v wget >/dev/null 2>&1; then wget -q "$COMPOSE_URL" -O docker-compose.yml else error "curl or wget is required to download Squadem" fi info "Pulling container images... (this may take several minutes on first install)" docker compose pull 2>&1 | grep -E "Pull|pull|Downloaded|Error" || true info "Starting Squadem..." docker compose up -d 2>&1 | grep -v "^$" info "Waiting for services to be ready..." TIMEOUT=180 ELAPSED=0 READY=false while [ $ELAPSED -lt $TIMEOUT ]; do API_OK=$(curl -sf http://localhost:8081/health >/dev/null 2>&1 && echo "1" || echo "0") FRONTEND_OK=$(curl -sf http://localhost:8200/ >/dev/null 2>&1 && echo "1" || echo "0") if [ "$API_OK" = "1" ] && [ "$FRONTEND_OK" = "1" ]; then READY=true break fi sleep 5 ELAPSED=$((ELAPSED + 5)) printf "\r${GREEN}[squadem]${NC} Waiting... %ds / %ds" "$ELAPSED" "$TIMEOUT" done echo "" if [ "$READY" = "true" ]; then info "All core services are healthy!" else warn "Some services are still starting. This is normal for first install." warn "Check status: cd $SQUADEM_DIR && docker compose ps" fi echo "" echo "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" echo " ${GREEN}${BOLD}Squadem is running!${NC}" echo "" echo " ${BOLD}Dashboard${NC} http://localhost:8200" echo " ${BOLD}API${NC} http://localhost:8081" echo " ${BOLD}AI Proxy${NC} http://localhost:8080" echo " ${BOLD}n8n Workflows${NC} http://localhost:5678" echo "" echo " ${BOLD}Config${NC} $SQUADEM_DIR/.env" echo "" echo " ${BOLD}Commands:${NC}" echo " cd $SQUADEM_DIR" echo " docker compose ps # service status" echo " docker compose logs -f # live logs" echo " docker compose down # stop all" echo " docker compose pull # update images" echo " docker compose up -d # restart" echo "" echo "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo ""