Skip to content

fix(dev): enumerate and free held ports on Windows - #643

Draft
invisibletype wants to merge 1 commit into
CoreBunch:mainfrom
invisibletype:fix/windows-port-preflight
Draft

invisibletype wants to merge 1 commit into
CoreBunch:mainfrom
invisibletype:fix/windows-port-preflight

Conversation

@invisibletype

@invisibletype invisibletype commented Oct 13, 2026 •

Copy link
Copy Markdown

Summary

Builds on #170. That PR stopped bun run dev / bun run start from crashing on Windows — the port preflight shelled out to lsof, which doesn't exist there — by returning no holders on Windows and waiting ~30s in case a previous dev server is shutting down. But an orphaned dev server never frees the socket, so that path just waits and then exits with a (Unix-only) error the user can't act on.

This implements real holder lookup on Windows via netstat -ano + tasklist, so ensurePortFree identifies the process holding the port and offers to kill it and take over — the same experience the Unix lsof / ps path already gives. It also:

  • replaces the Unix-only sleep subprocess in the kill / re-probe loops with the portable Bun.sleepSync,
  • makes the "couldn't identify holder" hint platform-aware (netstat … | findstr on Windows), and
  • removes the Windows wait-and-give-up fallback this supersedes (no two code paths left side by side).

No behavior change on macOS/Linux. Rebased onto current main (includes #170).

Verification

  • bun run build — passed (tsc -b && vite build), after bun install picked up the new yjs/lib0 deps from main
  • bun test — runs in CI on this PR; freePort.ts is a standalone dev script imported only by scripts/dev.ts / scripts/start.ts, outside the tested module graph, so it can't affect suite results
  • bun run lint — passed
  • Windows path verified live: netstat / tasklist parsing correctly identified the PIDs + names holding :5174 and :3001, and returned empty for a free port

Checklist

  • Tests cover behavior changes. — Dev tooling; platform shell-out with no existing unit test for the module. Verified manually on Windows; the Unix path is unchanged.
  • Docs were updated when behavior, config, deployment, or public surfaces changed. — Module header comment updated; no other docs reference this preflight.
  • No compatibility shim was added for old pre-release behavior. — Supersedes fix(scripts): Windows dev server port probing with cmd timeout fallback #170's Windows fallback rather than keeping both.
  • No secrets, local databases, uploads, or generated artifacts are included.

🤖 Generated with Claude Code

PR CoreBunch#170 stopped `bun run dev` / `bun run start` from crashing on Windows
by having the port preflight return no holders there. But that means a
held port can't be reclaimed: an orphaned dev server (common after an
unclean shutdown) never frees the socket, so the preflight waits ~30s and
then exits with an error the user can't act on.

Implement real holder lookup on Windows via `netstat -ano` + `tasklist`,
so `ensurePortFree` identifies the holding process and offers to kill it
and take over — the same experience the Unix `lsof`/`ps` path gives.
Replace the Unix-only `sleep` subprocess in the kill/re-probe loops with
the portable `Bun.sleepSync`, and drop the Windows wait-and-give-up
fallback this supersedes. No behavior change on macOS/Linux.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@invisibletype
invisibletype force-pushed the fix/windows-port-preflight branch from cd60566 to e32e33e Compare October 14, 2026 15:48
@invisibletype invisibletype changed the title fix(dev): make port preflight cross-platform for Windows fix(dev): enumerate and free held ports on Windows Oct 14, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant