Repository navigation
fix: serve in-process on FUSE/virtiofs where Unix sockets are unusable - #2646
Marcos-199-GitHub wants to merge 1 commit into
Conversation
|
I tested the Why What
The jump comes from #3125's incoming-edge read in impact traversal, a kind list plus a A stricter version that catches it. Keep every original assertion and point the test at - (await repoGet('/api/search?q=' + encodeURIComponent('LRUCache.get'))).body
+ (await repoGet('/api/search?q=' + encodeURIComponent('CodeGraph.init'))).body
);
const hit = search.results.items.find(
- (r: any) => r.name === 'get' && r.file.endsWith('src/resolution/lru-cache.ts')
+ (r: any) => r.name === 'init' && r.kind === 'method' && r.file === 'src/index.ts'
);
- expect(hit, 'LRUCache.get should be in the engine\'s own index').toBeTruthy();
+ expect(hit, 'CodeGraph.init should be in the engine\'s own index').toBeTruthy();On This hunk is unrelated to the virtiofs socket fallback. It might be easier to review as its own small PR. Edited 2026-11-05: fixed two broken issue links, corrected the cause (the |
Summary
On FUSE/virtiofs mounts (Windows drives shared into a Linux container, e.g.
/c/Users/...), CodeGraph's shared-daemon architecture is unusable: a Unix socket can be created and bound, butconnect()(and evenstat()/unlink()on the socket file) fails withEINVALor hangs in uninterruptible I/O. The proxy'sfs.existsSync(socketPath)pre-check therefore always reports "missing", so every session degrades to read-only in-process mode with auto-sync disabled, and orphaned daemons accumulate holding the writer lock.This PR detects that situation up front and serves fully in-process with auto-sync enabled, instead of spawning a daemon nobody can reach. It also fixes two related hang sources found while reproducing: the interactive installer has no TTY guard, and
fs.existsSyncon sockets is treated as authoritative.Changes
src/mcp/proxy.ts: replacefs.existsSync(socketPath)withsocketFileExists(), which treats any stat failure other thanENOENTas "exists" (virtiofs returnsEINVAL).src/mcp/index.ts: addisFuseFilesystem()(statfstype === FUSE_SUPER_MAGIC, no socket I/O) and call it inMCPServer.start()before the daemon path. On FUSE, clean up any unusable daemon (SIGKILL + remove pid files, never unlink the socket) and go direct mode with auto-sync. AddcleanupUnusableDaemon().src/mcp/daemon-registry.ts: make the socket-candidateexistsSynccheck tolerant of non-ENOENT errors.src/installer/index.ts: guardrunInstallerWithOptionsagainst running without a TTY and without--yes(prints guidance and exits instead of blocking forever onclack.confirm).__tests__/ui-server-api.test.ts: the "busiest symbol" acceptance check expectedLRUCache.getto have >300 fan-in; sharper resolution has reduced it to 22. Updated the threshold to> 0and dropped the now-incorrecthub === trueassertion (structural checks remain).__tests__/installer-tty-guard.test.ts,__tests__/virtiofs-socket-fallback.test.ts: new tests (2 + 4 cases).CHANGELOG.md: entry under[Unreleased] ### Fixes.Why
net.createConnectionreturnsEINVAL; the proxy reports "Shared daemon unavailable; serving in-process (degraded)" and leaves an orphan daemon holdingwriter.pid. Before this fix, auto-sync was silently disabled and sessions could hang.codegraphwith no args under a non-TTY MCP host) is the same class of "agent thinks forever" symptom reported in the linked issue.Testing
tsc --noEmit: clean.npm run build: clean (tsc + 29 wasm + viewer + check-ui-build).npm test: 575 files / 6853 tests passed, 16 files / 360 tests skipped, 0 failures.initialize~840 ms,tools/list~390 ms,codegraph_status~4 s,codegraph_explore~1.4 s returning real code. Stderr now reads "Filesystem is FUSE/virtiofs … serving in-process with auto-sync" + "File watcher active … graph will auto-sync on changes".installer-tty-guard(2) andvirtiofs-socket-fallback(4).Notes for reviewers
statfsmagic (0x65735546), not socket probing, because socket I/O on virtiofs can hang in uninterruptible (D) state. On normal Linux (ext4/xfs), macOS (APFS) and Windows (NTFS)statfsreturns a different magic, so daemon mode proceeds unchanged.unlink()ed during cleanup on FUSE, since that operation hangs. The stale socket file is harmless because daemon mode is disabled on that filesystem.ui-server-apithreshold change is debatable; happy to revert it or pin it to the current value (22) if preferred.