#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BACKEND_DIR="${ROOT_DIR}/offline-backend-20260512/backend" FRONTEND_DIR="${ROOT_DIR}/frontend-web" RUNTIME_DIR="${ROOT_DIR}/.runtime" LOG_DIR="${RUNTIME_DIR}/logs" PID_DIR="${RUNTIME_DIR}/pids" BACKEND_HOST="${BACKEND_HOST:-0.0.0.0}" BACKEND_PORT="${BACKEND_PORT:-8001}" FRONTEND_HOST="${FRONTEND_HOST:-0.0.0.0}" FRONTEND_PORT="${FRONTEND_PORT:-5174}" detect_host_ip() { if command -v hostname >/dev/null 2>&1; then # `hostname -I` is unsupported on Windows Git Bash; `|| true` keeps the # pipefail-safe fallback (HOST_IP then defaults to 127.0.0.1 below). hostname -I 2>/dev/null | awk '{print $1}' || true fi } HOST_IP="${HOST_IP:-$(detect_host_ip)}" HOST_IP="${HOST_IP:-127.0.0.1}" BACKEND_PUBLIC_BASE_URL="${BACKEND_PUBLIC_BASE_URL:-http://${HOST_IP}:${BACKEND_PORT}}" FRONTEND_PUBLIC_BASE_URL="${FRONTEND_PUBLIC_BASE_URL:-http://${HOST_IP}:${FRONTEND_PORT}}" # The standalone legacy TaskCOP UI runs on Vite :8080 and calls the Gateway # directly through its configured b1ConsumerUrl. Keep its local origins in the # backend CORS allow-list instead of relying on a frontend reverse proxy. GATEWAY_CORS_ORIGINS="${GATEWAY_CORS_ORIGINS:-http://localhost:${FRONTEND_PORT},http://127.0.0.1:${FRONTEND_PORT},http://${HOST_IP}:${FRONTEND_PORT},http://localhost:8080,http://127.0.0.1:8080}" mkdir -p "${LOG_DIR}" "${PID_DIR}" is_running() { local pid_file="$1" [[ -f "${pid_file}" ]] || return 1 local pid pid="$(cat "${pid_file}" 2>/dev/null || true)" [[ -n "${pid}" ]] || return 1 kill -0 "${pid}" >/dev/null 2>&1 } stop_by_pid_file() { local name="$1" local pid_file="$2" if ! [[ -f "${pid_file}" ]]; then echo "${name} is not running (no pid file)." return 0 fi local pid pid="$(cat "${pid_file}" 2>/dev/null || true)" if [[ -z "${pid}" ]] || ! kill -0 "${pid}" >/dev/null 2>&1; then echo "${name} is not running (stale pid file removed)." rm -f "${pid_file}" return 0 fi echo "Stopping ${name} (pid ${pid})..." # Services are started with setsid, so the pid is also the process group id. # Stop the whole group to avoid leaving Vite/esbuild/uvicorn child processes. kill "-${pid}" >/dev/null 2>&1 || true kill "${pid}" >/dev/null 2>&1 || true for _ in {1..30}; do if ! kill -0 "${pid}" >/dev/null 2>&1; then rm -f "${pid_file}" echo "${name} stopped." return 0 fi sleep 0.2 done echo "${name} did not stop gracefully; killing..." kill -9 "-${pid}" >/dev/null 2>&1 || true kill -9 "${pid}" >/dev/null 2>&1 || true rm -f "${pid_file}" echo "${name} stopped." } stop_by_pattern() { local name="$1" local pattern="$2" if ! command -v pgrep >/dev/null 2>&1; then return 0 fi local pids pids="$(pgrep -f "${pattern}" || true)" if [[ -z "${pids}" ]]; then return 0 fi echo "Stopping ${name} processes matching: ${pattern}" while IFS= read -r pid; do [[ -n "${pid}" ]] || continue [[ "${pid}" != "$$" ]] || continue kill "${pid}" >/dev/null 2>&1 || true done <<<"${pids}" }