#!/usr/bin/env bash # Author: Simon-Pierre Boucher # Contact: contact@spboucher.ai # # Déploie ka2 sur un node macOS du cluster (défaut : M4M36) : # - venv + dépendances # - 3 services launchd résilients (KeepAlive) : web, bot long terme, tunnel ngrok # - tunnel ngrok --url=https://www.ka2.bot -> uvicorn 127.0.0.1:8799 # # Usage (depuis le laptop) : bash deploy/deploy.sh [NODE] [PORT] [DOMAIN] set -euo pipefail NODE="${1:-M4M36}" PORT="${2:-8799}" DOMAIN="${3:-www.ka2.bot}" REMOTE_DIR="~/cluster-projects/ka2" NGROK="/opt/homebrew/bin/ngrok" echo "==> Déploiement de ka2 sur ${NODE} (port ${PORT}, domaine ${DOMAIN})" # 1) Synchro du code (sans venv/db/git) rsync -az --delete \ --exclude '.venv' --exclude '.git' --exclude '*.db' --exclude '*.db-*' \ --exclude '__pycache__' --exclude 'exports' \ ./ "${NODE}:${REMOTE_DIR}/" # 2) Configuration distante (venv, deps, launchd) ssh "${NODE}" DOMAIN="${DOMAIN}" PORT="${PORT}" NGROK="${NGROK}" 'bash -s' <<'REMOTE' set -euo pipefail DIR="$HOME/cluster-projects/ka2" 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}" } echo "--> services launchd" write_plist "com.ka2.web" "$UVICORN" "web.app:app" "--host" "127.0.0.1" "--port" "${PORT}" write_plist "com.ka2.bot" "$PY" "main.py" "run" "--daily-budget" "800" "--cycle-delay" "20" write_plist "com.ka2.ngrok" "$NGROK" "http" "--url=https://${DOMAIN}" "${PORT}" echo "--> session : 15 min à partir de maintenant (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 5 echo "--> healthcheck local" curl -s "http://127.0.0.1:${PORT}/health" || echo "(web pas encore prêt)" echo echo "--> tunnel ngrok" curl -s http://127.0.0.1:4040/api/tunnels 2>/dev/null | head -c 400 || echo "(api ngrok non prête)" echo REMOTE echo echo "==> Déploiement terminé. Dashboard : https://${DOMAIN}"