diff --git a/backend/run.sh b/backend/run.sh index ffedede8..cf4c220a 100755 --- a/backend/run.sh +++ b/backend/run.sh @@ -56,7 +56,9 @@ fi # (compared via `dir in path.parents`). So we pass ABSOLUTE paths to # the dirs we want to exclude — those are the only patterns uvicorn's # WatchFilesReload actually honors for "anywhere under this tree". -echo "Starting backend server on http://0.0.0.0:8324 ..." +# Dev only: OPENSWARM_PORT lets a parallel worktree bind its own backend port instead of colliding on 8324. Packaged builds never set it. +BACKEND_PORT="${OPENSWARM_PORT:-8324}" +echo "Starting backend server on http://0.0.0.0:${BACKEND_PORT} ..." cd "$PROJECT_ROOT_ABSPATH" UVICORN_EXCLUDE_ARGS=(--reload-exclude '*.pyc') @@ -79,10 +81,10 @@ done # launcher does). Packaged builds leave it unset → fast, lean, # single-process uvicorn. if [[ "${OPENSWARM_DEV:-}" == "1" ]]; then - echo "OPENSWARM_DEV=1 detected — running uvicorn with --reload." - python3 -m uvicorn backend.main:app --host 0.0.0.0 --port 8324 --reload \ + echo "OPENSWARM_DEV=1 detected, running uvicorn with --reload." + python3 -m uvicorn backend.main:app --host 0.0.0.0 --port "$BACKEND_PORT" --reload \ --reload-dir "$BACKEND_DIR_ABSPATH" \ "${UVICORN_EXCLUDE_ARGS[@]}" else - python3 -m uvicorn backend.main:app --host 0.0.0.0 --port 8324 + python3 -m uvicorn backend.main:app --host 0.0.0.0 --port "$BACKEND_PORT" fi diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 1e051e72..3556793b 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -79,13 +79,14 @@ module.exports = (env, argv) => { devServer: { static: { directory: path.join(__dirname, 'public') }, compress: true, - port: 3000, + // Dev only: OPENSWARM_DEV_PORT / OPENSWARM_PORT let a second worktree run its own stack without colliding on 3000/8324 (electron reads the same var names). + port: Number(process.env.OPENSWARM_DEV_PORT) || 3000, hot: true, open: false, historyApiFallback: true, proxy: { '/api': { - target: 'http://localhost:8324', + target: `http://localhost:${process.env.OPENSWARM_PORT || 8324}`, changeOrigin: true, }, }, diff --git a/run.sh b/run.sh index 1f2c3533..987afa4e 100755 --- a/run.sh +++ b/run.sh @@ -22,6 +22,14 @@ FRONTEND_PID="" ELECTRON_PID="" SHUTTING_DOWN=false +# Dev ports. Override BOTH to run a second worktree in parallel without colliding on 3000/8324 +# (e.g. OPENSWARM_PORT=8425 OPENSWARM_DEV_PORT=3005 bash run.sh). Electron, backend/run.sh, and +# webpack all read these same names, so one export each wires the whole stack. +BACKEND_PORT="${OPENSWARM_PORT:-8324}" +FRONTEND_PORT="${OPENSWARM_DEV_PORT:-3000}" +export OPENSWARM_PORT="$BACKEND_PORT" +export OPENSWARM_DEV_PORT="$FRONTEND_PORT" + kill_tree() { local pid=$1 sig=${2:-TERM} local children @@ -91,9 +99,9 @@ fi # That makes the next `bash run.sh` fail with Errno 48 "Address already # in use" and leaves the user thinking the dev loop is broken. Free the # port up front instead of asking the user to debug. -if lsof -ti :8324 >/dev/null 2>&1; then - echo -e "${YELLOW}${BOLD}[preflight]${RESET} Port 8324 still bound from a prior run — killing stale process..." - lsof -ti :8324 | xargs kill -9 2>/dev/null || true +if lsof -ti :$BACKEND_PORT >/dev/null 2>&1; then + echo -e "${YELLOW}${BOLD}[preflight]${RESET} Port ${BACKEND_PORT} still bound from a prior run, killing stale process..." + lsof -ti :$BACKEND_PORT | xargs kill -9 2>/dev/null || true sleep 0.3 fi @@ -119,11 +127,11 @@ bash "$PROJECT_ROOT/backend/run.sh" > >( BACKEND_PID=$! # --- Wait for backend to become healthy --- -echo -e "${YELLOW}${BOLD}Waiting for backend (http://localhost:8324) to be ready...${RESET}" +echo -e "${YELLOW}${BOLD}Waiting for backend (http://localhost:${BACKEND_PORT}) to be ready...${RESET}" MAX_WAIT=120 elapsed=0 while (( elapsed < MAX_WAIT )); do - if curl -s -o /dev/null --connect-timeout 1 http://localhost:8324/ 2>/dev/null; then + if curl -s -o /dev/null --connect-timeout 1 http://localhost:${BACKEND_PORT}/ 2>/dev/null; then echo -e "${GREEN}${BOLD}Backend is ready!${RESET}" break fi @@ -150,11 +158,11 @@ bash "$PROJECT_ROOT/frontend/run.sh" > >( FRONTEND_PID=$! # --- Wait for frontend dev server to become available --- -echo -e "${YELLOW}${BOLD}Waiting for frontend (http://localhost:3000) to be ready...${RESET}" +echo -e "${YELLOW}${BOLD}Waiting for frontend (http://localhost:${FRONTEND_PORT}) to be ready...${RESET}" FRONTEND_MAX_WAIT=60 frontend_elapsed=0 while (( frontend_elapsed < FRONTEND_MAX_WAIT )); do - if curl -s -o /dev/null --connect-timeout 1 http://localhost:3000/ 2>/dev/null; then + if curl -s -o /dev/null --connect-timeout 1 http://localhost:${FRONTEND_PORT}/ 2>/dev/null; then echo -e "${GREEN}${BOLD}Frontend is ready!${RESET}" break fi @@ -199,8 +207,8 @@ ELECTRON_PID=$! echo "" echo -e "${BOLD}All services are running. Press Ctrl+C to stop.${RESET}" -echo -e " Backend: ${BLUE}http://localhost:8324${RESET}" -echo -e " Frontend: ${GREEN}http://localhost:3000${RESET}" +echo -e " Backend: ${BLUE}http://localhost:${BACKEND_PORT}${RESET}" +echo -e " Frontend: ${GREEN}http://localhost:${FRONTEND_PORT}${RESET}" echo -e " Electron: ${MAGENTA}dev shell (pid $ELECTRON_PID)${RESET}" echo ""