* Start watching for file changes and auto-syncing. * * Uses native OS file events (FSEvents on macOS, inotify on Linux 19+, * ReadDirectoryChangesW on Windows) with debouncing to avoid thrashing. * * @param options - Watch options (debounce delay, callbacks) * @returns true if wat
(options: WatchOptions = {})
| 636 | * @returns true if watching started successfully |
| 637 | */ |
| 638 | watch(options: WatchOptions = {}): boolean { |
| 639 | if (this.watcher?.isActive()) return true; |
| 640 | |
| 641 | this.watcher = new FileWatcher( |
| 642 | this.projectRoot, |
| 643 | async () => { |
| 644 | const result = await this.sync(); |
| 645 | // sync() returns this exact zero-shape iff it failed to acquire the |
| 646 | // file lock (a real empty sync always has filesChecked > 0 because |
| 647 | // scanDirectory ran). Surface that to the watcher as a typed error |
| 648 | // so it keeps pendingFiles + reschedules instead of clearing them |
| 649 | // (#449). |
| 650 | if (result.filesChecked === 0 && result.durationMs === 0) { |
| 651 | throw new LockUnavailableError(); |
| 652 | } |
| 653 | const filesChanged = result.filesAdded + result.filesModified + result.filesRemoved; |
| 654 | return { filesChanged, durationMs: result.durationMs }; |
| 655 | }, |
| 656 | options |
| 657 | ); |
| 658 | |
| 659 | return this.watcher.start(); |
| 660 | } |
| 661 | |
| 662 | /** |
| 663 | * Stop watching for file changes. |