fix(coding-agent): terminate vendored rules findProjectRoot walk at non-cwd drive roots
Summary
On Windows, every read/edit/write tool call targeting a file on a different drive than the session cwd freezes the agent session permanently: the vendored pi-rules findProjectRoot walks parent directories looking for project markers and never terminates, spinning one core at 100% inside the rules extension's tool_result handler.
Root cause
findProjectRoot terminates its walk only when currentDirectory === resolve("/"), but resolve("/") is cwd's drive root (e.g. E:\), while dirname() of another drive's root returns that root itself (e.g. C:\). For cross-drive (or UNC) targets with no marker up-tree, the exit condition never holds and the synchronous loop never ends.
How this was found (evidence)
Reported as repeatedly freezing interactive sessions. Reproduced and dissected on Windows 11 with senpi 2026.7.26, workspace on E::
- Session JSONL audit: 6/6 tool calls targeting
C:paths (temp paste images, files under the user profile) never produced atoolResult; 26/26 same-drive calls succeeded. - A headless
senpi --printrepro burned 53.6s CPU in 60s before producing any output. - V8 inspector stack of the hung process:
#0 findProjectRoot (rules/rules/project-root.js)
#1 fingerprintDynamicTargets (rules/rules/engine.js)
#2 tool_result handler (rules/index.js)
#3 emitToolResult (extension runner)
Because the loop is synchronous, the abort signal is never processed: esc cannot interrupt and users must kill the process.
Fix
Stop the walk when dirname() stops progressing (parentDirectory === currentDirectory). The existing resolve("/") early-exit is preserved; cross-drive and UNC roots are covered uniformly.
packages/coding-agent/src/core/extensions/builtin/rules/rules/project-root.ts— the guard (vendored file; adaptation documented in the extension'schanges.mdper the contract)test/suite/regressions/0000-rules-find-project-root-cross-drive.test.ts— regression test exercising the real cross-drive scenario on multi-drive Windows machines (no-ops where the scenario cannot occur; pre-fix it hangs, post-fix returnsnullinstantly)
Upstream
The same fix was submitted to the vendored source: https://github.com/code-yeongyu/pi-rules/pull/19 — the changes.md entry notes this adaptation can be dropped once a fixed pi-rules release is re-vendored.
Validation
- New regression test passes on Windows 11 (cwd on
E:, temp onC:— real cross-drive), ~5ms. - Root
npm run checkclean (biome + tsgo + lock/import checks). - The identical fix in the pi-rules repo passes its full project-root suite 12/12 with no new failures.
Summary by cubic
Fixes a Windows-only infinite loop in findProjectRoot when accessing files on a different drive than the cwd. The walk now terminates when dirname() stops progressing and returns null for cross-drive and UNC paths without markers.
- Bug Fixes
- Updated
packages/coding-agent/src/core/extensions/builtin/rules/rules/project-root.tsto stop the walk whendirname()no longer changes the path (keeps theresolve("/")early exit). - Added
packages/coding-agent/test/suite/regressions/0000-rules-find-project-root-cross-drive.test.tsto exercise the cross-drive case in CI and assert it returnsnullinstead of hanging. - Documented the vendored change in
packages/coding-agent/src/core/extensions/builtin/rules/changes.md; upstream fix submitted: https://github.com/code-yeongyu/pi-rules/pull/19.
- Updated