mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-14 22:43:17 +08:00
On Windows, libuv reports a watched folder that is being deleted by the folder's own absolute path (\\?\D:\...) and re-arms the read, which fails the same way at once: about 70,000 events in half a second until the stream is closed. The watcher gives each directory link in a project its own recursive stream, so deleting a link's target outside the project started that storm. handleDirEvent joined the absolute name onto the watched folder, got a path that doesn't exist, scheduled a full sync and nothing else. The stream was never closed, the server held a core until restart, and the storm kept re-arming the debounce, so no sync ever ran: the deleted files stayed in the index and later edits never auto-synced. The project root's stream had the same blind spot. Fix: handleDirEvent, which both stream callbacks use, now treats an absolute name as the watched folder itself reporting it is gone. The first such event on a stream arms one check 200 ms later; the rest of the burst finds it armed. The check closes a link's stream when the link no longer leads to the folder it watched (deleted, or pointed elsewhere) and re-reads the tree, whose full sync drops the link's files; a link that leads somewhere live is watched anew. A project root that is gone degrades the watcher with a "project folder was deleted or moved away" reason, which closes every stream. A normal event pays one path.isAbsolute check. Validation (Windows 11, Node 22.22, libuv 1.51): - Raw probe: fs.watch on a junction whose target is deleted gets 70,009 events named \\?\<the junction> in 500 ms (499 ms CPU), and none after close(). - Real MCP server over a project with a junction libs -> outside, outside deleted: main used 3484, 3406, 3391, 3281 ms of CPU per 3 s window and kept the linked symbol; an edit afterwards never synced. With the fix: 296, 0, 0, 79 ms; the linked symbol left the index; the edit synced. - New watcher tests: a fake fs.watch link storm (10,000 self-named events cost no fs call, the stream closes once, a full sync runs, the project stays watched), a fake root storm (degrades once, closes the stream), and a Windows-gated real junction whose storm must go quiet. All 3 fail on main's watcher.ts; watcher.test.ts passes 61/61. Reported in PR #2487 by @L0garithmic; this reimplements the fix independently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>