#!/bin/bash # Agent Evolution Dashboard - Docker Management Script # Mount-driven: no rebuild required after file changes. # # Quick-ref: # bash agent-evolution/docker-run.sh run # start (no rebuild needed later) # bash agent-evolution/docker-run.sh reload # restart container to pick up new mounts # bash agent-evolution/docker-run.sh restart # rebuild image + restart container set -e IMAGE_NAME="apaw-evolution" CONTAINER_NAME="apaw-evolution-dashboard" PORT=3003 # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Build Docker image (rarely needed — only on Dockerfile / base-image changes) build() { log_info "Building Docker image..." docker build \ -t "$IMAGE_NAME:latest" \ -f agent-evolution/Dockerfile \ . log_info "Build complete: $IMAGE_NAME:latest" } # Run container with directory mounts (no file copies) run() { # Check if container already running if docker ps -q --filter "name=$CONTAINER_NAME" | grep -q .; then log_warn "Container $CONTAINER_NAME is already running" log_info "Use '$0 reload' to restart with latest host files" log_info "Use '$0 restart' to rebuild image and restart" exit 0 fi # Remove stopped container if exists if docker ps -aq --filter "name=$CONTAINER_NAME" | grep -q .; then log_info "Removing stopped container..." docker rm "$CONTAINER_NAME" >/dev/null || true fi log_info "Starting container with mount-driven volumes..." docker run -d \ --name "$CONTAINER_NAME" \ -p "$PORT:3001" \ -v "$(pwd)/agent-evolution/index.standalone.html:/app/index.html:ro" \ -v "$(pwd)/agent-evolution/data:/app/data:ro" \ -v "$(pwd)/.kilo:/app/kilo:ro" \ --restart unless-stopped \ --health-cmd "wget --no-verbose --tries=1 --spider http://localhost:3001/ || exit 1" \ --health-interval "30s" \ --health-timeout "10s" \ --health-retries "3" \ "$IMAGE_NAME:latest" log_info "Container started: $CONTAINER_NAME" log_info "Dashboard available at: http://localhost:$PORT" log_info "Mounted: ./agent-evolution/index.standalone.html → /app/index.html" log_info " ./agent-evolution/data → /app/data" log_info " ./.kilo → /app/kilo" log_info "Tip: edit host files, run bun run sync:evolution, then reload page or use '$0 reload'" } # Stop and remove container stop() { log_info "Stopping container..." docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true log_info "Container stopped" } # Restart container WITHOUT rebuilding image (picks up new host files) reload() { log_info "Reloading container to reflect host file changes..." stop run } # Rebuild image AND restart container (only when Dockerfile changes) restart() { log_info "Full restart: rebuild image + restart container..." stop build run } # View logs logs() { docker logs -f "$CONTAINER_NAME" } # Open dashboard in browser open() { URL="http://localhost:$PORT" log_info "Opening dashboard: $URL" if command -v xdg-open &> /dev/null; then xdg-open "$URL" elif command -v open &> /dev/null; then open "$URL" elif command -v start &> /dev/null; then start "$URL" else log_warn "Could not open browser. Navigate to: $URL" fi } # Sync evolution data on host (generates index.standalone.html from latest data) sync() { log_info "Syncing evolution data..." if command -v bun &> /dev/null; then bun run agent-evolution/scripts/sync-agent-history.ts elif command -v node &> /dev/null; then npx tsx agent-evolution/scripts/sync-agent-history.ts else log_error "Node.js or Bun required for sync" exit 1 fi log_info "Sync complete — run '$0 reload' to pick up changes" } # Status check status() { if docker ps -q --filter "name=$CONTAINER_NAME" | grep -q .; then log_info "Container status: ${GREEN}RUNNING${NC}" log_info "URL: http://localhost:$PORT" # Health check HEALTH=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "unknown") log_info "Health: $HEALTH" # Uptime STARTED=$(docker inspect --format='{{.State.StartedAt}}' "$CONTAINER_NAME" 2>/dev/null) if [ -n "$STARTED" ] && [ "$STARTED" != "" ]; then log_info "Started: $STARTED" fi else if docker ps -aq --filter "name=$CONTAINER_NAME" | grep -q .; then log_info "Container status: ${YELLOW}STOPPED${NC}" else log_info "Container status: ${RED}NOT CREATED${NC}" fi fi } # Clean up clean() { log_info "Cleaning up..." stop docker rmi "$IMAGE_NAME:latest" >/dev/null 2>&1 || true log_info "Cleanup complete" } # Show help show_help() { echo "Agent Evolution Dashboard - Docker Management (mount-driven, no-rebuild)" echo "" echo "Quick start:" echo " 1. bash $0 run # Start container once" echo " 2. edit files + bun run sync:evolution" echo " 3. bash $0 reload # Container picks up changes immediately" echo "" echo "Commands:" echo " build Build Docker image (rare — only Dockerfile changes)" echo " run Start container for the first time" echo " stop Stop and remove container" echo " reload Restart container to pick up latest host files (no rebuild)" echo " restart Rebuild image AND restart container" echo " logs View container logs" echo " open Open dashboard in browser" echo " sync Run sync-agent-history.ts on host" echo " status Show container status" echo " clean Remove container AND image" echo " help Show this help message" } # Main case "${1:-help}" in build) build ;; run) run ;; stop) stop ;; reload) reload ;; restart) restart ;; logs) logs ;; open) open ;; sync) sync ;; status) status ;; clean) clean ;; dev) log_warn "'dev' mode deprecated — use 'run' + volume mounts instead." log_info "Run: bash $0 run" ;; help) show_help ;; *) log_error "Unknown command: $1" show_help exit 1 ;; esac