#!/usr/bin/env bash # Author: Simon-Pierre Boucher # Contact: contact@spboucher.ai # # Déploie ka4 (version agressive/concurrente) sur un node macOS du cluster (défaut : M4M36). # Cohabite avec ka2 sur le même node : port + services + domaine + web-addr ngrok distincts. # - venv + dépendances # - 3 services launchd résilients : com.ka4.web / com.ka4.bot / com.ka4.ngrok # - ngrok --url=https://www.ka4.bot -> uvicorn 127.0.0.1:8899 (inspection sur :4041) # # Usage : bash deploy/deploy.sh [NODE] [PORT] [DOMAIN] set -euo pipefail NODE="${1:-M4M36}" PORT="${2:-8899}" DOMAIN="${3:-www.ka4.bot}" REMOTE_DIR="~/cluster-projects/ka4" NGROK="/opt/homebrew/bin/ngrok" echo "==> Déploiement de ka4 sur ${NODE} (port ${PORT}, domaine ${DOMAIN})" rsync -az --delete \ --exclude '.venv' --exclude '.git' --exclude '*.db' --exclude '*.db-*' \ --exclude '__pycache__' --exclude 'exports' --exclude 'logs' \ ./ "${NODE}:${REMOTE_DIR}/" ssh "${NODE}" DOMAIN="${DOMAIN}" PORT="${PORT}" NGROK="${NGROK}" 'bash -s' <<'REMOTE' set -euo pipefail DIR="$HOME/cluster-projects/ka4" cd "$DIR" echo "--> venv + dépendances" python3 -m venv .venv ./.venv/bin/python -m pip install -q --upgrade pip ./.venv/bin/python -m pip install -q -r requirements.txt PY="$DIR/.venv/bin/python" UVICORN="$DIR/.venv/bin/uvicorn" LOGS="$DIR/logs"; mkdir -p "$LOGS" LA="$HOME/Library/LaunchAgents"; mkdir -p "$LA" write_plist () { local label="$1" ; shift local plist="$LA/${label}.plist" { echo '' echo '' echo '' echo " Label${label}" echo ' ProgramArguments' for a in "$@"; do echo " ${a}"; done echo ' ' echo " WorkingDirectory${DIR}" echo ' RunAtLoad' echo ' KeepAlive' echo " StandardOutPath${LOGS}/${label}.out.log" echo " StandardErrorPath${LOGS}/${label}.err.log" echo ' EnvironmentVariables' echo " PATH/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin" echo ' ' echo '' } > "$plist" launchctl unload "$plist" 2>/dev/null || true launchctl load "$plist" echo " launchd chargé: ${label}" } # config ngrok dédiée : inspection sur :4041 (KA2 occupe déjà :4040 sur ce node) NGCONF="$DIR/ngrok-ka4.yml" printf 'version: "3"\nagent:\n web_addr: localhost:4041\n' > "$NGCONF" DEFCONF="$HOME/Library/Application Support/ngrok/ngrok.yml" echo "--> services launchd (com.ka4.*)" write_plist "com.ka4.web" "$UVICORN" "web.app:app" "--host" "127.0.0.1" "--port" "${PORT}" write_plist "com.ka4.bot" "$PY" "main.py" "run" "--daily-budget" "3000" "--cycle-delay" "8" "--queue-batch" "24" "--session-minutes" "15" write_plist "com.ka4.ngrok" "$NGROK" "http" "--url=https://${DOMAIN}" "--config" "$DEFCONF" "--config" "$NGCONF" "${PORT}" echo "--> session : 15 min dès le déploiement (bouton « Continuer » pour +15 min)" "$PY" - <<'PYSET' import time from src.config import config from src.storage import Store s = Store(config.db_path) s.set_setting("run_until", str(time.time() + 15 * 60)) s.set_setting("paused", "0") s.close() print("run_until = maintenant + 15 min") PYSET sleep 6 echo "--> healthcheck local" curl -s "http://127.0.0.1:${PORT}/health" || echo "(web pas encore prêt)" echo echo "--> tunnel ngrok (inspection :4041)" curl -s http://127.0.0.1:4041/api/tunnels 2>/dev/null | head -c 400 || echo "(api ngrok non prête)" echo REMOTE echo echo "==> Déploiement terminé. Dashboard ka4 : https://${DOMAIN}"