v2.10.2
First-launch input race fix + helper-orphan cleanup
Two prod-only bugs surfaced during fresh-PC dogfood of v2.10.1. Neither
reproduced under dev (npm start) because the vite dev-server load delay
hides the underlying daemon-bootstrap timing.
Fixed
-
First-launch keystroke loss on fresh installs. v2.10.1's
DaemonRespawnControllerintroduced a race between renderer mount and the LOCAL→DAEMON IPC handler swap. On cold-start PCs the daemon spawn stretches into hundreds of ms (Defender realtime scan + ASAR cold cache- ConPTY cold start), wide enough for the renderer to mount and reach
handler-swap mid-startup. Any
pty.writethat carried a LOCAL-prefix id (pty-N) into the DAEMON handler was silently dropped becausesessionPipes.get('pty-N')is undefined — manifesting as "the first keystroke does not register" or "only the first keystroke registers" on the very first session. Fix splits renderer navigation out ofcreateWindow()into a standaloneloadMainRenderer()export and defers the call until afterbootstrap()returns andmarkDaemonReady()has unblockeddaemon.whenReady(). Everypty.createfrom the renderer now hits a stable handler topology and produces a correctly-prefixed id. The macOSapp.on('activate')re-open path keeps the immediate-load default because the daemon is already healthy by then.
- ConPTY cold start), wide enough for the renderer to mount and reach
handler-swap mid-startup. Any
-
Helper-orphan zombies on quit.
before-quithas five awaits (renderer save, sleep, daemon shutdown race up to 8s, disconnect, cleanup) beforeapp.quit(). Any hang (stuckpipeServer.stop(), detached webview blockingwill-quit, ConPTY/OSC 7 finalization stall) leaves Electron's renderer / GPU / utility helpers as orphans. On Windows the devnpm startCtrl+C path also leaks helpers because SIGINT only reachesnpm.exe, not the electron tree. Reproduced locally as 20-helper orphan buildup spanning days. Add a 1.5ssetTimeoutafterapp.quit()that callsapp.exit(0)if the graceful path has not finalized;unref()keeps the timer non-blocking so a normal sub-second quit isn't held open. The graceful path is unchanged — this only fires on hang.
Internal
.team/added to.gitignoreso worktree coordination metadata cannot leak into future commits — matches the existing.claude//.gstack/exclusions (Codex/codex reviewP2 finding).