Files
thedotmack__claude-mem/.github
weiconghe cd5108c1db fix(windows): reclaim ghost listeners left by out-of-band worker deaths (#3900)
When the worker daemon dies out-of-band (crash, taskkill /F without /T), its chroma-mcp sidecar chain (uvx -> uv -> python) survives holding the inherited listening socket. The port stays LISTENING under the dead worker PID and every launcher refuses to start ('Port already in use, refusing to start duplicate' / 'Port in use but worker not responding to health checks') forever — hooks thrash until a human tree-kills the sidecar chain by hand (plan-15 #3603; reproduced 2026-09-07 and again by the probe that shaped this fix).

Changes:
- src/shared/port-reclaim.ts: detect a listener whose owning PID is dead and kill the surviving sidecar chain. Targets are found two ways: walking the parent chain down from the dead PID (Windows preserves parent links after death), plus a full-table scan matching the sidecar's --data-dir argument for the broken-chain case where uvx/uv exited on pipe EOF and only chroma-mcp/python survive one or two links below a dead PID. Every kill carries the start token from the same table read that discovered the target; a live owner is never touched.
- daemon duplicate gate + ensureWorkerStarted: reclaim the ghost before refusing to start, and clear the spawn cooldown when the reclaim succeeded (the cooldown's reason is gone).
- HealthMonitor: bounded (5s) HTTP probes so a ghost listener — which accepts TCP but never responds — cannot hang the liveness checks forever.
- Windows integration gate (worker-ghost-port-recovery): a detached fixture worker with a real chroma chain is killed out-of-band; the production ensureWorkerStarted must reclaim the port and start a replacement. Fails on main, where no reclaim exists.
- Unit tests for the parser, the ownership fingerprint and every reclaim decision branch.
2026-09-10 18:01:56 -07:00
..