The host never started on Windows: `setsid: command not found`, after
which the script wrote the dead setsid pid to .dev-host.pid and counted
out its full timeout printing dots. setsid is Linux-only, so this would
have hit macOS too.
Four Linux assumptions, replaced with probed alternatives:
setsid used when present; otherwise plain nohup, and stop
walks the process tree instead of killing the group
ss falls back to lsof (macOS), then netstat (Windows)
node -p require reads the version with sed instead: bash hands Node
/c/Users/..., which Node resolves as C:\c\Users\...
and throws MODULE_NOT_FOUND
--show-current falls back to `describe`, empty on the detached HEAD
a fresh submodule checkout leaves behind
Also, so the next failure is legible rather than a wall of dots:
the readiness loop now stops the moment the host process dies, and the
timeout prints the log's error lines instead of `tail -5`, which the
per-file session-sync chatter had made useless. Timeout raised to 120s
for cold first starts (tsx compile + vite optimizeDeps), overridable
with READY_TIMEOUT_SECONDS.
Unrelated bug found while there: stop_host used `exit 0` when nothing was
running, so `restart` on a stopped host never reached start_host.
Verified on Linux: the three port backends agree, and the no-setsid path
was exercised in isolation — group kill fails as expected and kill_tree
reaps parent and children. The netstat and ps branches are written to
documented behaviour but untested for lack of a Windows or macOS host.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>