#!/usr/bin/env bash set -euo pipefail source "$(dirname "${BASH_SOURCE[0]}")/worktree-common.sh" port_in_use() { lsof -nP -iTCP:"$1" -sTCP:LISTEN &>/dev/null } if [[ -z "${WM_SLOT:-}" ]]; then # Scan .env.local files of existing worktrees to find which slots are claimed, # then pick the lowest free slot. This avoids collisions when worktrees are # removed and new ones created (position-based indexing would re-use slots # still held by surviving worktrees). used_slots=() current_dir="$(pwd)" while IFS= read -r wt_path; do [[ "$wt_path" == "$current_dir" ]] && continue if [[ -f "$wt_path/.env.local" ]]; then bp=$(grep '^BACKEND_PORT=' "$wt_path/.env.local" | cut -d= -f2 || true) if [[ -n "$bp" && "$bp" -gt 8000 ]]; then used_slots+=("$(( (bp - 8000) / 10 ))") fi fi done < <(git worktree list --porcelain | sed -n 's/^worktree //p') # Find lowest available slot (slot 0 = 8000/3000 is reserved for main) WM_SLOT=1 while [[ " ${used_slots[*]:-} " == *" $WM_SLOT "* ]]; do ((WM_SLOT++)) done echo "Auto-assigned slot $WM_SLOT (used: ${used_slots[*]:-none})" fi # Slot-based: predictable ports for SSH forwarding # Slot 0 = 8000/3000, slot 1 = 8010/3010, slot 2 = 8020/3020, etc. backend_port=$((8000 + WM_SLOT * 10)) frontend_port=$((3000 + WM_SLOT * 10)) if port_in_use "$backend_port" || port_in_use "$frontend_port"; then echo "WARNING: Slot $WM_SLOT ports ($backend_port/$frontend_port) already in use" >&2 fi # Generate .env.local with port overrides cat > .env.local <> .env.local fi echo "Created .env.local with ports: backend=$backend_port, frontend=$frontend_port" wm_shared_post_create "$(pwd)"