From 4d1c957f420cd0da534d419890d8e54665cb001c Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Wed, 10 Jun 2026 08:46:41 -0700 Subject: [PATCH] =?UTF-8?q?fix(slice-1):=20dev.sh=20portable=20on=20bash?= =?UTF-8?q?=203.2=20=E2=80=94=20drop=20wait=20-n,=20reap=20process=20subtr?= =?UTF-8?q?ee?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS ships bash 3.2 (no wait -n): poll with kill -0 instead. npm spawns vite as a grandchild, so cleanup now recurses pgrep -P to reap the whole subtree — Ctrl-C frees both :8000 and :5173 cleanly. Verified clean-checkout -> dev.sh -> empty self-migrated Postgres -> /healthz 200, and trap teardown. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/dev.sh | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/scripts/dev.sh b/scripts/dev.sh index 5b76cab..c1adbfd 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -35,13 +35,30 @@ backend_pid=$! ( cd "$repo_root/frontend" && npm run dev ) & frontend_pid=$! +# Kill a process and its whole descendant tree (children first), portably across +# macOS and Linux — npm spawns vite as a grandchild, so killing the captured pid +# alone would orphan it on :5173. `pgrep -P` (list children) exists on both. +kill_tree() { + local pid=$1 child + for child in $(pgrep -P "$pid" 2>/dev/null); do + kill_tree "$child" + done + kill "$pid" 2>/dev/null || true +} + cleanup() { + trap - INT TERM echo echo "==> stopping backend and Vite" - kill "$backend_pid" "$frontend_pid" 2>/dev/null || true + kill_tree "$backend_pid" + kill_tree "$frontend_pid" wait "$backend_pid" "$frontend_pid" 2>/dev/null || true } trap cleanup INT TERM -wait -n "$backend_pid" "$frontend_pid" +# Wait until either process exits, then tear the other down. `wait -n` would be +# tidier but is unsupported on macOS's bundled bash 3.2, so poll portably. +while kill -0 "$backend_pid" 2>/dev/null && kill -0 "$frontend_pid" 2>/dev/null; do + sleep 1 +done cleanup