mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 18:55:37 -04:00
78c245b905
Before starting daemon, now: 1. Calls daemon-stop command to cleanly stop any running daemon 2. Force kills any process on the daemon port as final measure This handles cases where a daemon auto-starts during the build process
383 lines
12 KiB
Bash
Executable File
383 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# agent-core reload script
|
|
# Usage: ./scripts/reload.sh [OPTIONS]
|
|
#
|
|
# This script:
|
|
# 1. Kills all agent-core processes
|
|
# 2. Optionally cleans build artifacts (--clean or --fresh)
|
|
# 3. Rebuilds from source (unless --no-build)
|
|
# 4. Copies binary to ~/bin/agent-core
|
|
# 5. Starts daemon (unless --no-daemon)
|
|
# 6. Verifies everything is working
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
PKG_DIR="$REPO_ROOT/packages/agent-core"
|
|
BINARY_SRC="$PKG_DIR/dist/agent-core-linux-x64/bin/agent-core"
|
|
BINARY_DST="$HOME/bin/agent-core"
|
|
DAEMON_PORT="${AGENT_CORE_PORT:-3210}"
|
|
DAEMON_HOST="${AGENT_CORE_HOST:-127.0.0.1}"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
log() { echo -e "${BLUE}[reload]${NC} $*"; }
|
|
ok() { echo -e "${GREEN}[ OK ]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[ WARN ]${NC} $*"; }
|
|
err() { echo -e "${RED}[ERROR]${NC} $*"; }
|
|
|
|
# Parse args
|
|
NO_BUILD=false
|
|
NO_DAEMON=false
|
|
STATUS_ONLY=false
|
|
CLEAN_BUILD=false
|
|
FRESH_BUILD=false
|
|
|
|
for arg in "$@"; do
|
|
case $arg in
|
|
--no-build) NO_BUILD=true ;;
|
|
--no-daemon) NO_DAEMON=true ;;
|
|
--status) STATUS_ONLY=true ;;
|
|
--clean) CLEAN_BUILD=true ;;
|
|
--fresh) FRESH_BUILD=true ;;
|
|
--help|-h)
|
|
echo "Usage: $0 [OPTIONS]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --no-build Skip rebuilding (just restart)"
|
|
echo " --no-daemon Don't start daemon after reload"
|
|
echo " --status Show status and diagnostics only"
|
|
echo " --clean Clean build artifacts before rebuilding"
|
|
echo " --fresh Full fresh build: clean + clear turbo cache + reinstall deps"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 # Normal rebuild and restart"
|
|
echo " $0 --status # Just show current status"
|
|
echo " $0 --clean # Clean dist/, rebuild, restart"
|
|
echo " $0 --fresh # Nuclear option: purge everything, rebuild from scratch"
|
|
echo " $0 --no-daemon # Rebuild but don't start daemon"
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Clean function
|
|
do_clean() {
|
|
log "Cleaning build artifacts..."
|
|
|
|
# Clean dist directory
|
|
if [[ -d "$PKG_DIR/dist" ]]; then
|
|
rm -rf "$PKG_DIR/dist"
|
|
ok "Removed $PKG_DIR/dist"
|
|
else
|
|
warn "No dist directory to clean"
|
|
fi
|
|
}
|
|
|
|
# Fresh/full clean function
|
|
do_fresh_clean() {
|
|
log "Performing FULL fresh clean..."
|
|
|
|
# Clean dist
|
|
if [[ -d "$PKG_DIR/dist" ]]; then
|
|
rm -rf "$PKG_DIR/dist"
|
|
ok "Removed dist/"
|
|
fi
|
|
|
|
# Clean turbo cache
|
|
if [[ -d "$REPO_ROOT/.turbo" ]]; then
|
|
rm -rf "$REPO_ROOT/.turbo"
|
|
ok "Removed .turbo/ cache"
|
|
fi
|
|
|
|
# Clean node_modules/.cache
|
|
if [[ -d "$REPO_ROOT/node_modules/.cache" ]]; then
|
|
rm -rf "$REPO_ROOT/node_modules/.cache"
|
|
ok "Removed node_modules/.cache"
|
|
fi
|
|
|
|
# Clean bun cache for the package
|
|
if [[ -d "$PKG_DIR/node_modules/.cache" ]]; then
|
|
rm -rf "$PKG_DIR/node_modules/.cache"
|
|
ok "Removed package node_modules/.cache"
|
|
fi
|
|
|
|
# Optionally reinstall deps
|
|
log "Reinstalling dependencies..."
|
|
cd "$REPO_ROOT"
|
|
if bun install 2>&1 | tail -3; then
|
|
ok "Dependencies reinstalled"
|
|
else
|
|
warn "bun install had warnings (may be ok)"
|
|
fi
|
|
}
|
|
|
|
# Status/diagnostics function
|
|
show_status() {
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo " AGENT-CORE STATUS"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# Binary info
|
|
echo "Binary: $BINARY_DST"
|
|
if [[ -f "$BINARY_DST" ]]; then
|
|
local mod_time=$(stat -c "%Y" "$BINARY_DST" 2>/dev/null || stat -f "%m" "$BINARY_DST" 2>/dev/null)
|
|
local mod_date=$(date -d "@$mod_time" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || date -r "$mod_time" "+%Y-%m-%d %H:%M:%S" 2>/dev/null)
|
|
ok "Exists (modified: $mod_date)"
|
|
else
|
|
err "Not found"
|
|
fi
|
|
echo ""
|
|
|
|
# Running processes
|
|
echo "Processes:"
|
|
local procs=$(pgrep -af "agent-core|bun.*print-logs" 2>/dev/null | grep -v "reload.sh" | grep -v "pgrep" || true)
|
|
if [[ -n "$procs" ]]; then
|
|
echo "$procs" | while read -r line; do
|
|
local pid=$(echo "$line" | awk '{print $1}')
|
|
local cmd=$(echo "$line" | cut -d' ' -f2-)
|
|
if [[ "$cmd" == *"daemon"* ]]; then
|
|
ok "Daemon: PID $pid"
|
|
elif [[ "$cmd" == *"bun"*"print-logs"* ]]; then
|
|
ok "TUI (dev): PID $pid"
|
|
elif [[ "$cmd" == *"print-logs"* ]] || [[ "$cmd" == *"/bin/agent-core" ]]; then
|
|
ok "TUI: PID $pid"
|
|
else
|
|
echo " Other: PID $pid - $cmd"
|
|
fi
|
|
done
|
|
else
|
|
warn "No agent-core processes running"
|
|
fi
|
|
echo ""
|
|
|
|
# Daemon health
|
|
echo "Daemon API: http://$DAEMON_HOST:$DAEMON_PORT"
|
|
local health=$(curl -sf "http://$DAEMON_HOST:$DAEMON_PORT/global/health" 2>/dev/null || echo "")
|
|
if [[ -n "$health" ]]; then
|
|
local version=$(echo "$health" | grep -o '"version":"[^"]*"' | cut -d'"' -f4)
|
|
ok "Healthy (version: $version)"
|
|
else
|
|
warn "Not responding"
|
|
fi
|
|
echo ""
|
|
|
|
# Tool directories
|
|
echo "Tool directories:"
|
|
for dir in "$HOME/.config/agent-core/tool" "$REPO_ROOT/.agent-core/tool"; do
|
|
if [[ -d "$dir" ]]; then
|
|
local count=$(ls -1 "$dir"/*.ts 2>/dev/null | wc -l || echo 0)
|
|
ok "$dir ($count tools)"
|
|
ls -1 "$dir"/*.ts 2>/dev/null | while read -r f; do
|
|
echo " - $(basename "$f")"
|
|
done
|
|
else
|
|
echo " $dir (not found)"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Source vs binary timestamps
|
|
echo "Source timestamps:"
|
|
local src_files=(
|
|
"$PKG_DIR/src/provider/transform.ts"
|
|
"$PKG_DIR/src/provider/provider.ts"
|
|
"$PKG_DIR/src/server/server.ts"
|
|
"$PKG_DIR/src/session/llm.ts"
|
|
)
|
|
local binary_time=$(stat -c "%Y" "$BINARY_DST" 2>/dev/null || echo 0)
|
|
for src in "${src_files[@]}"; do
|
|
if [[ -f "$src" ]]; then
|
|
local src_time=$(stat -c "%Y" "$src" 2>/dev/null || echo 0)
|
|
local src_date=$(date -d "@$src_time" "+%H:%M:%S" 2>/dev/null || date -r "$src_time" "+%H:%M:%S" 2>/dev/null)
|
|
local name=$(basename "$src")
|
|
if [[ $src_time -gt $binary_time ]]; then
|
|
warn "$name ($src_date) - NEWER than binary, rebuild needed!"
|
|
else
|
|
ok "$name ($src_date)"
|
|
fi
|
|
fi
|
|
done
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
}
|
|
|
|
if $STATUS_ONLY; then
|
|
show_status
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo " AGENT-CORE RELOAD"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# Step 1: Kill ALL agent-core related processes (be aggressive!)
|
|
log "Stopping ALL agent-core processes..."
|
|
|
|
kill_procs() {
|
|
local pattern="$1"
|
|
local name="$2"
|
|
local pids=$(pgrep -f "$pattern" 2>/dev/null | grep -v $$ | grep -v "reload" || true)
|
|
if [[ -n "$pids" ]]; then
|
|
echo "$pids" | xargs -r kill -9 2>/dev/null || true
|
|
ok "Killed $name (PIDs: $(echo $pids | tr '\n' ' '))"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# Kill in order of dependency
|
|
kill_procs "agent-core daemon" "daemon" || warn "No daemon to kill"
|
|
kill_procs "agent-core.*gateway" "gateway" || true
|
|
kill_procs "agent-core.*print-logs" "TUI (binary)" || true
|
|
kill_procs "bun.*print-logs" "TUI (dev)" || true
|
|
kill_procs "bun.*agent-core" "bun agent-core" || true
|
|
kill_procs "/bin/agent-core" "agent-core binary" || true
|
|
|
|
# Wait for processes to die
|
|
sleep 1
|
|
|
|
# Nuclear option: kill ANYTHING with agent-core in the command
|
|
remaining=$(pgrep -af "agent-core" 2>/dev/null | grep -v $$ | grep -v "reload.sh" | grep -v "grep" || true)
|
|
if [[ -n "$remaining" ]]; then
|
|
warn "Lingering processes found:"
|
|
echo "$remaining"
|
|
echo ""
|
|
log "Force killing ALL remaining..."
|
|
pgrep -f "agent-core" 2>/dev/null | grep -v $$ | grep -v "reload" | xargs -r kill -9 2>/dev/null || true
|
|
sleep 1
|
|
fi
|
|
|
|
# Also kill any process listening on the daemon port
|
|
port_pid=$(lsof -ti:$DAEMON_PORT 2>/dev/null || true)
|
|
if [[ -n "$port_pid" ]]; then
|
|
kill -9 $port_pid 2>/dev/null || true
|
|
ok "Killed process on port $DAEMON_PORT (PID: $port_pid)"
|
|
fi
|
|
|
|
# Final verification
|
|
final_check=$(pgrep -af "agent-core" 2>/dev/null | grep -v $$ | grep -v "reload" || true)
|
|
if [[ -n "$final_check" ]]; then
|
|
err "WARNING: Some processes may still be running:"
|
|
echo "$final_check"
|
|
else
|
|
ok "All processes stopped"
|
|
fi
|
|
|
|
# Extra wait to ensure file handles are released
|
|
sleep 2
|
|
|
|
# Step 2: Clean if requested
|
|
if $FRESH_BUILD; then
|
|
do_fresh_clean
|
|
elif $CLEAN_BUILD; then
|
|
do_clean
|
|
fi
|
|
|
|
# Step 3: Rebuild
|
|
if ! $NO_BUILD; then
|
|
log "Rebuilding agent-core..."
|
|
cd "$PKG_DIR"
|
|
if bun run build 2>&1 | tail -10; then
|
|
ok "Build complete"
|
|
else
|
|
err "Build failed!"
|
|
exit 1
|
|
fi
|
|
else
|
|
warn "Skipping build (--no-build)"
|
|
fi
|
|
|
|
# Step 4: Copy binary (with retry for "Text file busy")
|
|
log "Installing binary..."
|
|
if [[ -f "$BINARY_SRC" ]]; then
|
|
# Remove old binary first to avoid "Text file busy"
|
|
if [[ -f "$BINARY_DST" ]]; then
|
|
rm -f "$BINARY_DST" 2>/dev/null || true
|
|
sleep 0.5
|
|
fi
|
|
|
|
# Retry copy with increasing delays
|
|
for attempt in 1 2 3 4 5; do
|
|
if cp "$BINARY_SRC" "$BINARY_DST" 2>/dev/null; then
|
|
chmod +x "$BINARY_DST"
|
|
ok "Installed to $BINARY_DST"
|
|
break
|
|
else
|
|
if [[ $attempt -eq 5 ]]; then
|
|
err "Failed to copy binary after 5 attempts (Text file busy?)"
|
|
err "Try: rm -f $BINARY_DST && then re-run this script"
|
|
exit 1
|
|
fi
|
|
warn "Copy attempt $attempt failed, retrying in ${attempt}s..."
|
|
sleep $attempt
|
|
fi
|
|
done
|
|
else
|
|
err "Binary not found at $BINARY_SRC"
|
|
exit 1
|
|
fi
|
|
|
|
# Step 5: Start daemon
|
|
if ! $NO_DAEMON; then
|
|
# Kill any daemon that may have started during build
|
|
log "Ensuring no daemon is running..."
|
|
"$BINARY_DST" daemon-stop 2>/dev/null || true
|
|
sleep 1
|
|
|
|
# Kill by port as final measure
|
|
port_pid=$(lsof -ti:$DAEMON_PORT 2>/dev/null || true)
|
|
if [[ -n "$port_pid" ]]; then
|
|
kill -9 $port_pid 2>/dev/null || true
|
|
ok "Killed process on port $DAEMON_PORT"
|
|
sleep 1
|
|
fi
|
|
|
|
log "Starting daemon..."
|
|
nohup "$BINARY_DST" daemon --hostname "$DAEMON_HOST" --port "$DAEMON_PORT" --gateway > /tmp/agent-core-daemon.log 2>&1 &
|
|
DAEMON_PID=$!
|
|
sleep 2
|
|
|
|
# Verify daemon started
|
|
if kill -0 "$DAEMON_PID" 2>/dev/null; then
|
|
# Check health endpoint
|
|
for i in {1..5}; do
|
|
health=$(curl -sf "http://$DAEMON_HOST:$DAEMON_PORT/global/health" 2>/dev/null || echo "")
|
|
if [[ -n "$health" ]]; then
|
|
version=$(echo "$health" | grep -o '"version":"[^"]*"' | cut -d'"' -f4)
|
|
ok "Daemon started (PID: $DAEMON_PID, version: $version)"
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
if [[ -z "$health" ]]; then
|
|
warn "Daemon started but health check failed"
|
|
fi
|
|
else
|
|
err "Daemon failed to start! Check /tmp/agent-core-daemon.log"
|
|
tail -20 /tmp/agent-core-daemon.log
|
|
exit 1
|
|
fi
|
|
else
|
|
warn "Skipping daemon start (--no-daemon)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo " RELOAD COMPLETE"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
show_status
|