#!/usr/bin/env bash # Manage the AgenticCode stack: build and (re)deploy ac-code-server + neo4j + ac-ui # via docker-compose, and install the ac-cli launcher to the user's local bin. # # Run without arguments for the command list. # # Note: running this with no argument used to mean "deploy" (when the script was still # called deploy.sh). It now prints help instead — a full deploy bumps the version and # rebuilds everything, which is not something a bare, argument-less invocation should # trigger by accident. Say 'deploy' when you mean it. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" CLI_INSTALL_DIR="$HOME/.local/share/agenticcode" CLI_JAR_DEST="$CLI_INSTALL_DIR/ac-cli.jar" CLI_BIN="$HOME/.local/bin/ac" CLI_MARKER="# agenticcode-ac-cli-launcher" log() { echo "==> $*"; } compose() { if docker compose version >/dev/null 2>&1; then docker compose "$@" else docker-compose "$@" fi } require_docker() { if ! docker info >/dev/null 2>&1; then echo "Docker does not appear to be running (or not reachable). Start Docker and re-run." >&2 exit 1 fi } # Stamps ac-cli's bundled version from ac-code-server's agenticcode.version (the single # source of truth), so 'ac version' can detect a stale CLI against a newer server. # Note: a full build already bumps agenticcode.version and stamps ac-cli via the # ac-mvn-plugins 'bump-version' mojo (bound to ac-code-server's generate-resources phase). # This function is only used by the CLI-only rebuild path, which must NOT bump but must # still sync the CLI to the current server version. stamp_cli_version() { local props="ac-code-server/src/main/resources/application.properties" local cli_props="ac-cli/src/main/resources/agenticcode.properties" local current current="$(grep -m1 '^agenticcode.version=' "$props" | cut -d= -f2)" if [[ -z "$current" ]]; then echo "Could not find agenticcode.version in $props" >&2 exit 1 fi sed -i "s/^version=.*/version=$current/" "$cli_props" log "Stamped ac-cli version: $current" } build_all() { # The version bump + ac-cli stamp happen inside the Maven build (ac-mvn-plugins # 'bump-version' mojo on ac-code-server), since 'install' is a trigger goal. log "Building all modules (mvn clean install -DskipTests)" mvn clean install -DskipTests } build_cli_only() { stamp_cli_version log "Building ac-cli (mvn -pl ac-cli -am package -DskipTests)" mvn -pl ac-cli -am package -DskipTests } install_cli() { local jar jar="$(find ac-cli/target -maxdepth 1 -name 'ac-cli-*.jar' ! -name 'original-*' | head -n1)" if [[ -z "$jar" ]]; then echo "No ac-cli jar found in ac-cli/target — build failed?" >&2 exit 1 fi mkdir -p "$CLI_INSTALL_DIR" "$HOME/.local/bin" cp "$jar" "$CLI_JAR_DEST" if [[ -e "$CLI_BIN" ]] && ! grep -q "$CLI_MARKER" "$CLI_BIN" 2>/dev/null; then echo "Refusing to overwrite $CLI_BIN — it already exists and wasn't installed by this script." >&2 echo "Remove it manually first, or install elsewhere." >&2 exit 1 fi cat > "$CLI_BIN" < $CLI_BIN (jar: $CLI_JAR_DEST)" case ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) echo "Note: $HOME/.local/bin is not on your PATH. Add it, e.g.: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;; esac } cmd_deploy() { build_all require_docker log "Stopping ac-code-server container (neo4j left untouched)" compose stop ac-code-server || true compose rm -f ac-code-server || true log "Building ac-code-server image" compose build ac-code-server log "Starting neo4j + ac-code-server" compose up -d neo4j ac-code-server deploy_ui install_cli } # (Re)builds the ac-ui image (npm build runs inside Docker) and restarts its container. deploy_ui() { log "Building ac-ui image (npm build runs inside Docker)" compose build ac-ui log "Starting ac-ui (http://localhost:5174)" compose up -d ac-ui } cmd_stop() { require_docker log "Stopping ac-code-server container only (neo4j left running)" compose stop ac-code-server } cmd_cli() { build_cli_only install_cli } cmd_ui() { require_docker deploy_ui } cmd_logs() { require_docker if [[ "${1:-}" == "-f" ]]; then docker logs -f --tail 200 agenticcode-server else docker logs --tail 200 agenticcode-server fi } # Restarts the running ac-code-server container without rebuilding anything. Useful to # abort a long server-side job (a deep refresh keeps running after its HTTP client is # killed — the request is not the job) or to pick up a config change. cmd_restart() { require_docker log "Restarting ac-code-server (no build; neo4j untouched)" docker restart agenticcode-server } # Reports what is up and which version answers, without ever failing on a down stack — # that is precisely the case it exists for. Every probe is guarded, since 'set -e' would # otherwise abort this command exactly when it has something to report. cmd_status() { if ! docker info >/dev/null 2>&1; then echo "Docker: not running (or not reachable)" return 0 fi log "Containers" docker ps -a --filter "name=agenticcode-" \ --format ' {{.Names}}\t{{.Status}}' 2>/dev/null || true log "Server" local version version="$(curl -fsS --max-time 3 http://localhost:8787/api/version 2>/dev/null || true)" if [[ -n "$version" ]]; then echo " http://localhost:8787 -> $version" else echo " http://localhost:8787 -> unreachable" fi log "Projects" local projects projects="$(curl -fsS --max-time 3 http://localhost:8787/api/projects 2>/dev/null || true)" if [[ -n "$projects" ]]; then echo "$projects" | grep -o '"name":"[^"]*"' | cut -d'"' -f4 | sed 's/^/ /' || echo " (none)" else echo " (server unreachable)" fi } # Stops the whole stack, neo4j included — 'stop' deliberately leaves neo4j up, so this is # the only scripted way to bring everything down. # # Intentionally NOT 'compose down -v': the neo4j-data volume holds the ingested graph # (hundreds of thousands of nodes, hours of ingest). 'down' means "stack off", never # "graph gone". Do not add -v here. cmd_down() { require_docker log "Stopping the whole stack (neo4j included; the graph volume is kept)" compose down } usage() { cat <<'EOF' manage-ac.sh — manage the AgenticCode stack Usage: ./manage-ac.sh deploy Full deploy: bump version, mvn clean install, rebuild+restart ac-code-server, rebuild+start ac-ui, install ac-cli. (neo4j is left running untouched if already up) restart Restart ac-code-server only — no build. Also aborts a long server-side job such as a running deep refresh. stop Stop ac-code-server only; neo4j and ac-ui keep running. down Stop the whole stack, neo4j included. The graph volume is kept. status Show containers, the server version and the ingested projects. Works (and reports) when the stack is down. cli Build and (re)install ac-cli only — no Docker involved. ui Rebuild and restart ac-ui only (npm build runs inside Docker; no local Node needed). Served at http://localhost:5174. logs [-f] Last 200 lines of ac-code-server logs; -f to follow. Notes: - The server answers on http://localhost:8787, the UI on http://localhost:5174. - The version bump lives in the Maven build (ac-mvn-plugins 'bump-version' mojo): every 'mvn package'/'install'/'deploy' bumps agenticcode.version and stamps ac-cli. 'mvn test'/'compile'/'quarkus:dev' do not. 'deploy' bumps because it runs a full install — which is why a bare, argument-less invocation means help, not deploy. EOF } case "${1:-}" in deploy) cmd_deploy ;; restart) cmd_restart ;; stop) cmd_stop ;; down) cmd_down ;; status) cmd_status ;; cli) cmd_cli ;; ui) cmd_ui ;; logs) shift; cmd_logs "${1:-}" ;; "" | -h | --help | help) usage ;; *) echo "Unknown command: $1" >&2 echo >&2 usage >&2 exit 1 ;; esac