chore: worktree dev setup (#484)

* chore: auto-assign per-worktree backend port via VS Code folderOpen task

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: remove .conductor dev setup (moved to native git worktrees)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Abhishek 2026-06-30 15:40:29 +05:30 committed by GitHub
parent 6937e01b49
commit 982030d26e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 108 additions and 386 deletions

76
scripts/worktree-assign-port.sh Executable file
View file

@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Assign a unique backend port to this git worktree and rewrite the env files
# that depend on it. Runs automatically as a VS Code "folderOpen" task (see
# .vscode/tasks.json), so it executes once per worktree when you open it.
#
# Scheme:
# - The MAIN worktree is left untouched (backend stays on uvicorn's default 8000).
# - Each linked worktree gets the next free backend port: 8001, 8002, ...
# - api/.env : UVICORN_PORT -> the assigned backend port
# - ui/.env.local : BACKEND_URL -> http://localhost:<port>
# NEXT_PUBLIC_BACKEND_URL -> http://localhost:<port>
#
# CORS is intentionally NOT touched: local dev runs DEPLOYMENT_MODE="oss", where
# the API forces allow_origins=["*"] and ignores CORS_ALLOWED_ORIGINS entirely.
#
# Idempotent: re-running keeps an already-assigned, non-colliding port. The UI
# dev server is left alone — `npm run dev` auto-selects a free port (3000, 3001…).
set -euo pipefail
ROOT="$(git rev-parse --show-toplevel)"
MAIN="$(git worktree list --porcelain | sed -n '1s/^worktree //p')"
[ "$ROOT" = "$MAIN" ] && { echo "[worktree] main worktree -> backend 8000 (untouched)"; exit 0; }
AENV="$ROOT/api/.env"
UENV="$ROOT/ui/.env.local"
[ -f "$AENV" ] || { echo "[worktree] no api/.env yet; skipping"; exit 0; }
# Echo the UVICORN_PORT value from an env file (empty if unset/missing).
port_of() { { grep -E '^[[:space:]]*UVICORN_PORT=' "$1" 2>/dev/null | tail -1 | sed -E 's/^[^=]*=//; s/[[:space:]]//g'; } || true; }
# Ports already in use by OTHER worktrees (main implicitly uses 8000).
used=(8000)
while IFS= read -r line; do
case "$line" in
"worktree "*)
wt="${line#worktree }"
[ "$wt" = "$ROOT" ] && continue
p="$(port_of "$wt/api/.env")"
[ -n "$p" ] && used+=("$p")
;;
esac
done < <(git worktree list --porcelain)
mine="$(port_of "$AENV")"
# Keep my port if it's set and not claimed by another worktree; else take max+1.
reassign=1
if [ -n "$mine" ]; then
reassign=0
for u in "${used[@]}"; do [ "$u" = "$mine" ] && reassign=1; done
fi
if [ "$reassign" -eq 1 ]; then
max=0
for u in "${used[@]}"; do [ "$u" -gt "$max" ] && max="$u"; done
B=$((max + 1))
else
B="$mine"
fi
# Insert or update KEY=VALUE in an env file, preserving everything else.
upsert() {
local key="$1" val="$2" file="$3"
if grep -qE "^[[:space:]]*${key}=" "$file"; then
sed -i.bak -E "s|^[[:space:]]*${key}=.*|${key}=${val}|" "$file" && rm -f "$file.bak"
else
printf '\n%s=%s\n' "$key" "$val" >> "$file"
fi
}
upsert UVICORN_PORT "$B" "$AENV"
if [ -f "$UENV" ]; then
upsert BACKEND_URL "http://localhost:$B" "$UENV"
upsert NEXT_PUBLIC_BACKEND_URL "http://localhost:$B" "$UENV"
fi
echo "[worktree] $(basename "$ROOT"): backend=$B (UI auto-port via 'npm run dev')"