#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BACKEND_PORT="${BACKEND_PORT:-8010}" FRONTEND_PORT="${FRONTEND_PORT:-5173}" port_pid() { lsof -tiTCP:"$1" -sTCP:LISTEN 2>/dev/null | head -n 1 || true } port_cmd() { local pid pid="$(port_pid "$1")" if [[ -z "$pid" ]]; then return 0 fi ps -p "$pid" -o command= 2>/dev/null || true } print_port_conflict() { local port="$1" local pid local cmd pid="$(port_pid "$port")" cmd="$(port_cmd "$port")" echo "Port $port is already in use." >&2 if [[ -n "$pid" ]]; then echo " PID: $pid" >&2 fi if [[ -n "$cmd" ]]; then echo " CMD: $cmd" >&2 fi } cleanup() { if [[ -n "${BACKEND_PID:-}" ]]; then kill "$BACKEND_PID" 2>/dev/null || true fi if [[ -n "${FRONTEND_PID:-}" ]]; then kill "$FRONTEND_PID" 2>/dev/null || true fi } trap cleanup EXIT INT TERM if [[ -n "$(port_pid "$BACKEND_PORT")" ]]; then print_port_conflict "$BACKEND_PORT" echo "Set BACKEND_PORT to another port or stop the existing process first." >&2 exit 1 fi if [[ -n "$(port_pid "$FRONTEND_PORT")" ]]; then print_port_conflict "$FRONTEND_PORT" echo "Set FRONTEND_PORT to another port or stop the existing process first." >&2 exit 1 fi cd "$ROOT_DIR" # Prefer miniconda Python (has all project deps); fall back to conda/system python3 PYTHON="${CONDA_PREFIX:-}/bin/python" if [[ ! -x "$PYTHON" ]]; then PYTHON="$(command -v /Users/icemilk/miniconda3/bin/python 2>/dev/null || command -v python3)" fi "$PYTHON" -m uvicorn backend.app.main:app --host 127.0.0.1 --port "$BACKEND_PORT" --reload \ > >(sed 's/^/[backend] /') \ 2> >(sed 's/^/[backend] /' >&2) & BACKEND_PID=$! cd "$ROOT_DIR/frontend" npm run dev -- --host 127.0.0.1 --port "$FRONTEND_PORT" \ > >(sed 's/^/[frontend] /') \ 2> >(sed 's/^/[frontend] /' >&2) & FRONTEND_PID=$! echo "Backend: http://127.0.0.1:${BACKEND_PORT}" echo "Frontend: http://127.0.0.1:${FRONTEND_PORT}" echo "Press Ctrl+C to stop both services." wait "$BACKEND_PID" "$FRONTEND_PID"