- markdown-validator: deepseek-v4-pro-max → nemotron-3-nano (90% cost cut) - release-manager: glm-5.1 → kimi-k2.6 (+2 matrix, 1M context for diffs) - capability-analyst: glm-5.1 → deepseek-v4-pro-max (+4 matrix, 1M ctx) - browser-automation: qwen3-coder → deepseek-v4-flash (3× faster inference) - history-miner: nemotron-3-super → qwen3.5-122b (+14 IF, 12.4M pulls)
209 lines
6.5 KiB
Bash
209 lines
6.5 KiB
Bash
#!/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 |