Watch a directory for changes and auto-update the graph (blocking mode).
(
path: str,
context: Optional[str] = None,
use_polling: Optional[bool] = None,
sync_on_start: bool = False,
)
| 1086 | |
| 1087 | |
| 1088 | def watch_helper( |
| 1089 | path: str, |
| 1090 | context: Optional[str] = None, |
| 1091 | use_polling: Optional[bool] = None, |
| 1092 | sync_on_start: bool = False, |
| 1093 | ): |
| 1094 | """Watch a directory for changes and auto-update the graph (blocking mode).""" |
| 1095 | import logging |
| 1096 | from ..core.watcher import CodeWatcher |
| 1097 | |
| 1098 | # Suppress verbose watchdog DEBUG logs |
| 1099 | logging.getLogger('watchdog').setLevel(logging.WARNING) |
| 1100 | logging.getLogger('watchdog.observers').setLevel(logging.WARNING) |
| 1101 | logging.getLogger('watchdog.observers.inotify_buffer').setLevel(logging.WARNING) |
| 1102 | |
| 1103 | services = _initialize_services(context) |
| 1104 | if not all(services[:3]): |
| 1105 | _fail_services_init() |
| 1106 | |
| 1107 | db_manager, graph_builder, code_finder, ctx = services |
| 1108 | path_obj = Path(path).resolve() |
| 1109 | |
| 1110 | if not path_obj.exists(): |
| 1111 | console.print(f"[red]Error: Path does not exist: {path_obj}[/red]") |
| 1112 | db_manager.close_driver() |
| 1113 | raise typer.Exit(code=1) |
| 1114 | |
| 1115 | if not path_obj.is_dir(): |
| 1116 | console.print(f"[red]Error: Path must be a directory: {path_obj}[/red]") |
| 1117 | db_manager.close_driver() |
| 1118 | raise typer.Exit(code=1) |
| 1119 | |
| 1120 | console.print(f"[bold cyan]🔍 Watching {path_obj} for changes...[/bold cyan]") |
| 1121 | |
| 1122 | # Check if already indexed — use File node count as a robust fallback so a |
| 1123 | # transient empty result from list_indexed_repositories never triggers a |
| 1124 | # destructive full rescan of an already-populated graph. |
| 1125 | indexed_repos = code_finder.list_indexed_repositories() |
| 1126 | is_indexed = any_repo_matches_path(indexed_repos, path_obj) |
| 1127 | if not is_indexed: |
| 1128 | # Fallback: count File nodes whose path starts with this repo's path. |
| 1129 | # If > 100 exist, the repo is clearly already indexed — skip the scan. |
| 1130 | try: |
| 1131 | with code_finder.driver.session() as _s: |
| 1132 | _r = _s.run( |
| 1133 | "MATCH (n:File) WHERE n.path STARTS WITH $p RETURN count(n) AS c", |
| 1134 | p=path_obj.as_posix() + "/" |
| 1135 | ) |
| 1136 | _count = _r.single()["c"] |
| 1137 | if _count > 100: |
| 1138 | info_logger( |
| 1139 | f"[watch] list_indexed_repositories returned no match for {path_obj} " |
| 1140 | f"but {_count} File nodes exist — treating as already indexed." |
| 1141 | ) |
| 1142 | is_indexed = True |
| 1143 | except Exception as _e: |
| 1144 | warning_logger(f"[watch] Fallback indexed check failed: {_e}") |
| 1145 |
no test coverage detected