#!/usr/bin/env bash # proxyctl — manage the antigravity proxy daemon set -euo pipefail SERVICE="antigravity-proxy" SCRIPT_PATH="$(readlink -f "$0")" PROJECT_DIR="$(cd "$(dirname "$SCRIPT_PATH")/.." && pwd)" PORT="${PROXY_PORT:-8741}" BASE_URL="http://localhost:${PORT}" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' DIM='\033[2m' BOLD='\033[1m' NC='\033[0m' usage() { echo -e "${BOLD}proxyctl${NC} — antigravity proxy daemon manager" echo "" echo -e " ${CYAN}start${NC} Start the proxy daemon" echo -e " ${CYAN}stop${NC} Stop the proxy daemon" echo -e " ${CYAN}restart${NC} Rebuild + restart" echo -e " ${CYAN}rebuild${NC} Build release binary only" echo -e " ${CYAN}status${NC} Service status + quota + usage" echo -e " ${CYAN}logs${NC} [N] Show last N lines (default 30)" echo -e " ${CYAN}logs-follow${NC} [N] Tail last N lines + follow" echo -e " ${CYAN}logs-all${NC} Full log dump" echo -e " ${CYAN}test${NC} [msg] Quick test request (gemini-3-flash)" echo -e " ${CYAN}health${NC} Health check" echo "" } do_build() { echo -e "${YELLOW}Building release binary...${NC}" cd "$PROJECT_DIR" cargo build --release 2>&1 echo -e "${GREEN}Build complete.${NC}" } do_start() { systemctl --user daemon-reload systemctl --user start "$SERVICE" echo -e "${GREEN}Started.${NC} Waiting for ready..." # Wait up to 10s for health for i in $(seq 1 20); do if curl -sf "${BASE_URL}/health" >/dev/null 2>&1; then echo -e "${GREEN}Proxy is up on port ${PORT}.${NC}" return 0 fi sleep 0.5 done echo -e "${RED}Proxy didn't become healthy in 10s. Check logs:${NC}" journalctl --user -u "$SERVICE" --no-pager -n 20 return 1 } do_stop() { systemctl --user stop "$SERVICE" 2>/dev/null || true echo -e "${YELLOW}Stopped.${NC}" } do_restart() { echo -e "${YELLOW}Stopping...${NC}" do_stop do_build do_start } do_status() { echo -e "${BOLD}── Service ──${NC}" systemctl --user status "$SERVICE" --no-pager 2>/dev/null | head -6 || echo -e "${RED}Not running${NC}" echo "" # Health check if ! curl -sf "${BASE_URL}/health" >/dev/null 2>&1; then echo -e "${RED}Proxy is not responding on port ${PORT}.${NC}" return 1 fi echo -e "${BOLD}── Quota ──${NC}" curl -sf "${BASE_URL}/v1/quota" 2>/dev/null | jq '.' 2>/dev/null || echo -e "${DIM}(no quota data)${NC}" echo "" echo -e "${BOLD}── Usage ──${NC}" curl -sf "${BASE_URL}/v1/usage" 2>/dev/null | jq '.' 2>/dev/null || echo -e "${DIM}(no usage data)${NC}" echo "" echo -e "${BOLD}── Sessions ──${NC}" curl -sf "${BASE_URL}/v1/sessions" 2>/dev/null | jq '.' 2>/dev/null || echo -e "${DIM}(no sessions)${NC}" } do_logs() { local lines="${1:-30}" journalctl --user -u "$SERVICE" --no-pager -n "$lines" } do_logs_follow() { local lines="${1:-30}" journalctl --user -u "$SERVICE" --no-pager -n "$lines" -f } do_logs_all() { journalctl --user -u "$SERVICE" --no-pager } do_test() { local msg="${1:-Say hello in exactly 3 words}" echo -e "${CYAN}Testing:${NC} ${msg}" curl -sf "${BASE_URL}/v1/responses" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"gemini-3-flash\", \"input\": \"${msg}\", \"stream\": false, \"timeout\": 30 }" | jq '.' } do_health() { curl -sf "${BASE_URL}/health" | jq '.' 2>/dev/null && echo -e "${GREEN}Healthy${NC}" || echo -e "${RED}Not responding${NC}" } # ── Main ── case "${1:-}" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; rebuild) do_build ;; status) do_status ;; logs) do_logs "${2:-30}" ;; logs-follow) do_logs_follow "${2:-30}" ;; logs-all) do_logs_all ;; test) do_test "${2:-}" ;; health) do_health ;; *) usage ;; esac