fix(coding-agent): Windows platform seams: kernel python path, tilde joins, hidden spawns, handshake budgets, bash and Herdr socket resolution - #2036
Open
snimu wants to merge 14 commits into
Open
Conversation
uv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites joined <venv>/bin/python unconditionally, so first-run kernel bootstrap always failed on native Windows. Mirror the existing win32 uv.exe branch with one kernelVenvPython helper used at both sites.
Tilde expansion concatenated homedir() with the posix remainder at three sites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy), producing mixed-separator paths like C:\Users\u/rest on Windows. Join through the platform path module instead and route PI_PACKAGE_DIR through expandTildePath.
…n PATH findBashOnPath took the first where-match, and System32\bash.exe (the WSL launcher, which executes Linux-side) precedes per-user Git Bash installs on default PATHs. Order matches so %SystemRoot% entries are only a last resort.
…ace on win32 The built-in Herdr reporter connected to the exported unix-style socket path verbatim; on Windows a local-domain connection must target \\.\pipe\, and the reporter swallows connect errors by design, so the mismatch was invisible. Map unmapped paths into the pipe namespace before dialing.
…rt TTL getWindowsProcessStartId spawns a synchronous powershell query that blocks the event loop, and supervisor liveness checks plus daemon-ps poll loops call it repeatedly for the same pid. Memoize successful ids for 5s so hot paths reuse one query.
…adline connectWorker granted every hello/worker_auth attempt a fixed 1s clock, so a handshake that consistently needs longer (slow win32 boxes) failed every retry regardless of the 30s outer budget, and the adopt/recover paths shrank even the outer budget to 1.5-2s. Per-attempt waits now consume the remaining outer deadline, all connectWorker callers use the one 30s constant, and the downward 1s hello/auth overrides in daemon-mode and the routed client fall back to the client defaults.
…pers windowsHide defaults to false, so console-subsystem children of a windowless daemon or detached worker allocate a fresh console and flash or steal focus on every spawn; only one call site in the repo set the flag. Add spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/ execFileSyncHidden to utils/child-process.ts and migrate all 49 non-interactive coding-agent spawn/exec sites; the tui package's two background spawns set windowsHide inline. Interactive spawns (editors, inherit-stdio installers and relaunches) intentionally keep their console.
… with hidden-window wrappers
The per-pid cache could hand a recycled pid the dead process's start id for up to 5s. The start id exists solely to detect pid recycling, and its consumers act on that identity: the orphan-process journal decides taskkill /T from it and daemon-ps shutdown waits poll it for change, so a stale match can kill a replacement process tree or mask an exited owner. No caller is both hot and staleness-tolerant; the handshake latency issue is already addressed by deriving budgets from the outer deadline.
…vely Windows pipe names are case-insensitive, but the pass-through check was case-sensitive, so a valid \\.\PIPE\... target was re-joined into a different pipe name and the error-swallowing reporter failed silently. Lowercase only the prefix check; the returned path keeps its casing.
… into fix/windows-platform-seams # Conflicts: # packages/coding-agent/src/core/kernel/repl-manager.ts
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cc11f4e. Configure here.
… pins Collapse the wrapper doc block to one line, drop test comments that restate assertions, share one recording wrapper in the child-process mock, unwrap single-test describes, and remove one posix assertion already covered by its sibling. No behavior coverage removed; all pins keep their failing assertions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Prime Agent misbehaves on native Windows in six independent places. Each fix below is behind a platform check (or a platform-neutral mechanism), covered by a unit test that exercises the win32 branch via an injected platform, and verified to fail on the pre-fix code.
Fixes
<venv>/bin/python, but uv creates<venv>\Scripts\python.exeon win32 (the same file already branches foruv.exe). OnekernelVenvPythonhelper now owns the layout. Fixes the defect reported in discussions [Bug] Kernel bootstrap fails on native Windows — venv Python resolved as bin/python #1401 and Bug report: Prime Agent on Windows - three reproducible breakages (with ready fixes) #1969 (part 1).~/expansion produced mixed-separator paths (C:\Users\u/rest) at three sites:expandPath,expandTildePath, and an inline copy forPI_PACKAGE_DIR. Expansion now joins through the platform path module, and the inline copy delegates toexpandTildePath. Fixes the defect reported in discussions [Bug] expandTildePath produces mixed path separators on Windows #1442 and [Bug] expandPath in path-utils.ts produces mixed path separators on Windows (same pattern as #1442) #1469.windowsHidedefaults to false and exactly one call site in the repo set it, so console-subsystem children of the windowless daemon and detached workers allocated fresh consoles.utils/child-process.tsnow exportsspawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/execFileSyncHidden, and all 49 non-interactive coding-agent spawn/exec sites route through them (the tui package's two background spawns set the flag inline). The six interactive spawns (editors, inherit-stdio installers/updates/relaunches) intentionally keep their console. No-op off Windows. Fixes the defect reported in discussion [Bug] Background subprocesses flash console windows on native Windows #1461.connectWorkergave every hello/worker_auth attempt a fixed 1s clock inside its retry loop, so a handshake that consistently needs longer (the win32 process-identity probe alone is a 0.2–3s synchronous powershell spawn under AV scanning) failed every retry regardless of the 30s outer budget — and the adopt/recover paths shrank even the outer budget to 1.5–2s. Per-attempt waits now consume the remaining outer deadline (handshakeBudgetMs), everyconnectWorkercaller uses the single 30s constant, and the downward 1s hello/auth overrides in daemon-mode and the routed client are deleted in favor of the clients' 3s defaults. Only failure paths get slower. Fixes the defect reported in discussions [Bug] Windows named-pipe daemon: session worker listens but create times out on hello/worker_auth #1622 and [Bug] Windows: session create always fails — worker handshake budgets cannot accommodate AV-slowed process launches #1678.findBashOnPathpicked WSL'sSystem32\bash.exe(a Linux-side launcher, not a Windows shell) because it took the firstwhere bash.exematch. Matches under%SystemRoot%are now only a last resort, so per-user Git Bash installs (scoop/winget) win. Fixes the defect reported in discussion [Bug] Windows shell resolution picks WSL bash.exe over Git Bash, breaking Windows commands #1437.\\.\pipe\namespace before dialing. Fixes the defect reported in discussion [Bug] Built-in Herdr reporter never connects on Windows, leaving panes stuck on Unknown #1399.An earlier revision of this branch also added a 5s per-pid cache for the win32 process start id. It was reverted here: the start id exists to detect pid recycling, and a cached id could hand a recycled pid the dead process's identity — its consumers decide
taskkill /Tand shutdown-wait completion from that identity. Review flagged it (thread onsession-lease.ts:127) and no caller is both hot and staleness-tolerant; the handshake latency problem is already covered by fix 4.Size and shape
Total src: +221/−121 (net +100); tests: +95/−7 (net +88).
New mechanism is ~95 lines: the five hidden-spawn wrappers plus four small helpers (
kernelVenvPython,handshakeBudgetMs,orderWindowsBashCandidates,herdrSocketTarget). Deletions remove the duplicated tilde-expansion copy, the fixed per-attempt handshake clocks and downward timeout overrides, and the one inlinewindowsHide; the rest of the churn is 1:1 call-site migration to the wrappers.Validation
npm run check(biome, tsgo, installer, browser-smoke) green.test:ci(4648 passed),test:process,test:kernel, and the tui suite (750 passed) green in a clean Linux container; the only failures are the environment's known root/lsof-dependent set, identical before and after this change.CodeQL note
The two "shell command built from environment values" alerts on
utils/child-process.tsare pre-existing flows relocated by the call-site migration: the same rule already flagsmainatcore/kernel/bootstrap.ts:374/:392(alerts #1 and #5), and those exact sinks now live inside the shared wrappers. The wrappers take command + argument arrays; the shell-string form (execSyncHidden) exists only for the pre-existing intentional shell callers (user-configured config-resolution commands, fixed-string clipboard fallbacks). No new shell surface is introduced by this PR.Linear: https://linear.app/primeintellect/issue/RES-1268/discussion-sweep-p5-windows-seam-pack-spawnhidden-venv-path-homedir
Note
Fix Windows platform seams across hidden spawns, kernel paths, tilde joins, handshake budgets, bash and Herdr sockets
spawnHidden,spawnSyncHidden,execSyncHidden,execFileHidden, andexecFileSyncHiddenhelpers in child-process.ts that forcewindowsHide: true; migrates ~20 call sites across daemon, CLI, kernel, git, shell, clipboard, package-manager, and TUI modules to use them instead of directnode:child_processAPIskernelVenvPythonin bootstrap.ts to resolvevenv/Scripts/python.exeon win32 andvenv/bin/pythonelsewhere; updates venv provisioning and kernel readiness checks to use itexpandPath(path-utils.ts) andexpandTildePath(config.ts) to join home-relative paths with platform-specificpath.posix/path.win32instead of string concatenationhandshakeBudgetMsin daemon-supervisor.ts that computes remaining outer-deadline time (clamped to 50ms minimum); replaces fixed 1-second hello/auth timeouts with budget-derived values, and raises worker connect allowances from 1.5–2s toWORKER_CONNECT_TIMEOUT_MS(30s)orderWindowsBashCandidatesin shell.ts to deprioritize SystemRoot bash paths, andherdrSocketTargetin herdr-agent-state.ts to map non-namespaced socket paths into the Windows named-pipe namespaceWORKER_CONNECT_TIMEOUT_MSin daemon-supervisor.ts); supervisor hello waits in daemon-mode.ts and daemon-routed-client.ts now use default/configured timeouts instead of forced 1-second valuesMacroscope summarized 8864109.
Note
Medium Risk
Wide migration of subprocess creation and longer daemon handshake waits on failure paths can affect timing and behavior on all platforms, not only Windows.
Overview
Improves native Windows behavior and centralizes a few cross-cutting fixes.
Child processes: Adds
spawnHidden/spawnSyncHidden/exec*Hiddenwrappers that always setwindowsHide: true, and routes background daemon, kernel, git, clipboard, and tool spawns through them (TUI autocomplete and link-open spawns set the flag inline). Interactive consoles are unchanged.Paths:
kernelVenvPythonpicksScripts\python.exeon win32;expandTildePath/expandPathjoin~/…with the platform path module instead of string concat (fixes mixedC:\…/…paths).Daemon:
handshakeBudgetMsmakes hello/auth waits use the remaining 30s connect budget; worker recovery paths use the full timeout instead of 1–2s caps; hardcoded 1s hello waits in daemon-mode/routed client are removed.Shell / integrations:
orderWindowsBashCandidatesdeprioritizes WSL’s System32bash.exe;herdrSocketTargetmaps unix-style Herdr socket paths into\\.\pipe\before connecting.Reviewed by Cursor Bugbot for commit 8864109. Bugbot is set up for automated code reviews on this repo. Configure here.