Files
opencode/scripts/reload.sh
T
Artur Do Lago 78c245b905 fix: kill any daemon that started during build
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
2026-01-20 13:12:10 +01:00

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