peregrine/manage.sh
pyr0ball 657f9c4060 fix: install make in setup.sh; guard manage.sh against missing make
setup.sh now installs make (via apt/dnf/pacman/brew) before git and
Docker so that manage.sh commands work out of the box on minimal server
installs. manage.sh adds a preflight guard that catches a missing make
early and redirects the user to ./manage.sh setup. Also fixes the
post-setup next-steps hint to use ./manage.sh instead of bare make.
2026-02-26 20:51:34 -08:00

178 lines
6.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# manage.sh — Peregrine CLI wrapper
# A single entry point for all common operations.
# Usage: ./manage.sh <command> [options]
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
info() { echo -e "${BLUE}[peregrine]${NC} $*"; }
success() { echo -e "${GREEN}[peregrine]${NC} $*"; }
warn() { echo -e "${YELLOW}[peregrine]${NC} $*"; }
error() { echo -e "${RED}[peregrine]${NC} $*" >&2; exit 1; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
PROFILE="${PROFILE:-remote}"
# ── Usage ────────────────────────────────────────────────────────────────────
usage() {
echo ""
echo -e " ${BLUE}Peregrine by Circuit Forge LLC${NC}"
echo -e " ${YELLOW}\"Don't be evil, for real and forever.\"${NC}"
echo ""
echo " Usage: ./manage.sh <command> [--profile PROFILE]"
echo ""
echo " Commands:"
echo -e " ${GREEN}setup${NC} Install Docker/Podman + NVIDIA toolkit"
echo -e " ${GREEN}start${NC} Start Peregrine (preflight → up)"
echo -e " ${GREEN}stop${NC} Stop all services"
echo -e " ${GREEN}restart${NC} Restart all services"
echo -e " ${GREEN}status${NC} Show running containers"
echo -e " ${GREEN}logs [service]${NC} Tail logs (default: app)"
echo -e " ${GREEN}update${NC} Pull latest images + rebuild app"
echo -e " ${GREEN}preflight${NC} Check ports + resources; write .env"
echo -e " ${GREEN}test${NC} Run test suite"
echo -e " ${GREEN}prepare-training${NC} Extract cover letters → training JSONL"
echo -e " ${GREEN}finetune${NC} Run LoRA fine-tune (needs GPU profile)"
echo -e " ${GREEN}clean${NC} Remove containers, images, volumes (DESTRUCTIVE)"
echo -e " ${GREEN}open${NC} Open the web UI in your browser"
echo ""
echo " Profiles (set via --profile or PROFILE env var):"
echo " remote API-only, no local inference (default)"
echo " cpu Local Ollama inference on CPU"
echo " single-gpu Ollama + Vision on GPU 0"
echo " dual-gpu Ollama + Vision + vLLM on GPU 0+1"
echo ""
echo " Examples:"
echo " ./manage.sh start"
echo " ./manage.sh start --profile cpu"
echo " ./manage.sh logs ollama"
echo " PROFILE=single-gpu ./manage.sh restart"
echo ""
}
# ── Parse args ───────────────────────────────────────────────────────────────
CMD="${1:-help}"
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--profile|-p) PROFILE="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) break ;;
esac
done
SERVICE="${1:-app}" # used by `logs` command
# ── Dependency guard ──────────────────────────────────────────────────────────
# Commands that delegate to make; others (status, logs, update, open, setup) run fine without it.
_MAKE_CMDS="start stop restart preflight test prepare-training finetune clean"
if [[ " $_MAKE_CMDS " == *" $CMD "* ]] && ! command -v make &>/dev/null; then
error "'make' is not installed. Run: ./manage.sh setup then retry: ./manage.sh ${CMD}"
fi
# ── Commands ─────────────────────────────────────────────────────────────────
case "$CMD" in
setup)
info "Running dependency installer..."
bash setup.sh
;;
preflight)
info "Running preflight checks (PROFILE=${PROFILE})..."
make preflight PROFILE="$PROFILE"
;;
start)
info "Starting Peregrine (PROFILE=${PROFILE})..."
make start PROFILE="$PROFILE"
PORT="$(grep -m1 '^STREAMLIT_PORT=' .env 2>/dev/null | cut -d= -f2 || echo 8501)"
success "Peregrine is up → http://localhost:${PORT}"
;;
stop)
info "Stopping all services..."
make stop
success "Stopped."
;;
restart)
info "Restarting (PROFILE=${PROFILE})..."
make restart PROFILE="$PROFILE"
PORT="$(grep -m1 '^STREAMLIT_PORT=' .env 2>/dev/null | cut -d= -f2 || echo 8501)"
success "Peregrine restarted → http://localhost:${PORT}"
;;
status)
# Auto-detect compose engine same way Makefile does
COMPOSE="$(command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 \
&& echo "docker compose" \
|| (command -v podman >/dev/null 2>&1 && echo "podman compose" || echo "podman-compose"))"
$COMPOSE ps
;;
logs)
COMPOSE="$(command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 \
&& echo "docker compose" \
|| (command -v podman >/dev/null 2>&1 && echo "podman compose" || echo "podman-compose"))"
info "Tailing logs for: ${SERVICE}"
$COMPOSE logs -f "$SERVICE"
;;
update)
info "Pulling latest images and rebuilding app..."
COMPOSE="$(command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 \
&& echo "docker compose" \
|| (command -v podman >/dev/null 2>&1 && echo "podman compose" || echo "podman-compose"))"
$COMPOSE pull searxng ollama 2>/dev/null || true
$COMPOSE build app
success "Update complete. Run './manage.sh restart' to apply."
;;
test)
info "Running test suite..."
make test
;;
prepare-training)
info "Extracting training data from cover letter corpus..."
make prepare-training
;;
finetune)
info "Starting fine-tune (PROFILE=${PROFILE})..."
make finetune PROFILE="$PROFILE"
;;
clean)
warn "This will remove ALL Peregrine containers, images, and volumes."
read -rp "Type 'yes' to confirm: " confirm
[[ "$confirm" == "yes" ]] || { info "Cancelled."; exit 0; }
make clean
;;
open)
PORT="$(grep -m1 '^STREAMLIT_PORT=' .env 2>/dev/null | cut -d= -f2 || echo 8501)"
URL="http://localhost:${PORT}"
info "Opening ${URL}"
if command -v xdg-open &>/dev/null; then
xdg-open "$URL"
elif command -v open &>/dev/null; then
open "$URL"
else
echo "$URL"
fi
;;
help|--help|-h)
usage
;;
*)
error "Unknown command: ${CMD}. Run './manage.sh help' for usage."
;;
esac