From 67056d1f0fa3d1225d9da6e9995f3e4851e7dd52 Mon Sep 17 00:00:00 2001 From: Santhosh Janardhanan Date: Mon, 13 Apr 2026 14:36:02 -0400 Subject: [PATCH] feat: add vault file system watcher with debounced sync --- src/companion/indexer_daemon/watcher.py | 55 +++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/companion/indexer_daemon/watcher.py diff --git a/src/companion/indexer_daemon/watcher.py b/src/companion/indexer_daemon/watcher.py new file mode 100644 index 0000000..bfd0516 --- /dev/null +++ b/src/companion/indexer_daemon/watcher.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +import time +from pathlib import Path + +from watchdog.events import FileSystemEventHandler +from watchdog.observers import Observer + +from companion.config import load_config +from companion.rag.indexer import Indexer +from companion.rag.vector_store import VectorStore + + +class VaultEventHandler(FileSystemEventHandler): + def __init__(self, indexer: Indexer, debounce_seconds: float = 5.0): + self.indexer = indexer + self.debounce_seconds = debounce_seconds + self._last_sync = 0.0 + + def on_any_event(self, event): + if event.is_directory: + return + if not event.src_path.endswith(".md"): + return + now = time.time() + if now - self._last_sync < self.debounce_seconds: + return + self._last_sync = now + try: + self.indexer.sync() + except Exception as exc: + print(f"Sync failed: {exc}") + + +def start_watcher(config_path: str = "config.json") -> None: + config = load_config(config_path) + store = VectorStore( + uri=config.rag.vector_store.path, dimensions=config.rag.embedding.dimensions + ) + indexer = Indexer(config, store) + handler = VaultEventHandler(indexer) + observer = Observer() + observer.schedule(handler, str(config.vault.path), recursive=True) + observer.start() + print(f"Watching {config.vault.path} for changes...") + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + observer.stop() + observer.join() + + +if __name__ == "__main__": + start_watcher()