feat: prevent multiple watchers on the same dir#83
Conversation
| process.kill(pid, 0); | ||
| return false; | ||
| } catch { | ||
| fs.unlinkSync(lockFile); |
There was a problem hiding this comment.
Bug: Stale lock cleanup can throw unhandled ENOENT error
When multiple processes detect a stale lock file simultaneously, they may both attempt to call fs.unlinkSync(lockFile). The first process succeeds, but the second throws an ENOENT error because the file no longer exists. This error is not caught by the inner try-catch (which only handles process.kill errors) and propagates to the outer catch which only handles EEXIST. The unhandled ENOENT gets re-thrown, causing the process to crash instead of gracefully failing to acquire the lock.
| } catch { | ||
| fs.unlinkSync(lockFile); | ||
| } | ||
| } |
There was a problem hiding this comment.
Bug: Corrupt lock file permanently blocks lock acquisition
When a lock file exists but contains invalid content (e.g., empty or non-numeric), Number.parseInt returns NaN, causing the !Number.isNaN(pid) condition to be false. The code skips the cleanup block entirely and attempts to create the lock file with the wx flag, which fails with EEXIST. This results in acquireLock returning false even though no valid process holds the lock, permanently blocking lock acquisition until the corrupt file is manually removed.
Real-world issue confirmation: Multiple agents spawning independent mgrep watch processesI've discovered this PR addresses a critical blocker for using mgrep with multiple coding agents simultaneously. Current SituationI installed mgrep on multiple agents (Codex, Claude Code, and OpenCode) and immediately ran into the exact problem this PR solves. Without the PID-based lock mechanism, each agent spawns its own independent System Impact (M1 MacBook Air)
Why This is Critical
Next StepsThis PR's locking mechanism will allow:
|
Note
Introduces a PID-based lock to ensure only one watcher performs initial sync per directory, with proper lock cleanup on exit.
src/commands/watch.ts):isLocked/acquireLockto detect and enforce a single active sync per directory; skip initial sync if locked.exit/SIGINT/SIGTERMtoreleaseLock.src/lib/lock.ts):/tmpwith base64-encoded path key:acquireLock,releaseLock,isLocked.Written by Cursor Bugbot for commit 4ac0c96. This will update automatically on new commits. Configure here.