Migrate 203 test files (356 call sites) from fs.rm/fs.rmSync to
removeWithRetries/removeSyncWithRetries to reduce EBUSY test failures
on Windows. removeWithRetries is now exported from @oh-my-pi/pi-utils.
The migration uses a regex-based approach that:
- Replaces fs.rm(path, { recursive, force }) → removeWithRetries(path)
- Replaces fs.rmSync(path, { recursive, force }) → removeSyncWithRetries(path)
- Replaces fs.rm(path) → removeWithRetries(path) (no options)
- Skips fs.rm/fs.rmSync inside template literals (bun --eval scripts)
- Adds imports to existing @oh-my-pi/pi-utils import or creates new one
- Removes unused fs imports where fs.rm was the only fs usage (4 files)
LspFileSystem.write received the already-resolved absolute path, so
isInternalUrlPath could never see the original scheme ('/Users/theo/.omp/agent/sessions/-Projects-oh-my-pi/2026-06-10T09-11-41-506Z_019eb0cd-3ec2-7000-92aa-1b82aa4d78f0/local/,' vault://)
and the bridge guard only caught the active plan file via the secondary
absolutePath comparison.
Fix: store the original user-provided path in LspFileSystem as
requestedPath and pass it as the first arg to routeWriteThroughBridge.
This matches replace.ts and hashline/filesystem.ts which already pass
the unresolved path correctly.
Also remove the ReturnType<typeof spyOn> annotation from makeBridge()
per the AGENTS.md "NEVER use ReturnType<>" rule.
Addresses all three review concerns from @roboomp and @chatgpt-codex-connector:
1. **Contract regression fixed**: guard
(extracted from ) is now called by all four write sites.
Internal-URL paths (e.g. ) and the active plan file
in plan mode are never routed to the editor bridge.
2. **Bridge call hygiene**: bridge calls are now wrapped in ,
is called, and
is bumped — matching the contract already had.
3. **Tests**: adds 6 parity tests
(2 per write site) mirroring :
- routes plain workspace writes through the bridge, skips writethrough
- writes local plan artifacts to disk instead of the ACP bridge
**Shared module**: exports
and (guard +
bridge call + ToolError wrap + invalidateFsScanAfterWrite +
bumpFileMutationVersion). All four write sites call it; the duplicated
6-line pattern is gone. is simplified to use the same helper
instead of its private method.