sqry_cli/commands/
watch.rs1use crate::args::Cli;
4use crate::commands::index::{create_build_config, create_progress_reporter};
5use anyhow::{Context, Result};
6use sqry_core::graph::unified::persistence::GraphStorage;
7use sqry_core::watch::FileWatcher;
8use std::path::PathBuf;
9use std::time::Duration;
10
11pub fn execute(
16 cli: &Cli,
17 path: Option<String>,
18 threads: Option<usize>,
19 debounce: Option<u64>,
20 _show_stats: bool, build_if_missing: bool,
22) -> Result<()> {
23 let root_path = resolve_path(path)?;
24 let build_config = create_build_config(cli, &root_path, threads)?;
25 let plugins = sqry_plugin_registry::create_plugin_manager();
26
27 let storage = GraphStorage::new(&root_path);
29 if !storage.exists() {
30 if build_if_missing {
31 println!("🔨 Building initial graph...");
32 let (_, progress) = create_progress_reporter(cli);
33 sqry_core::graph::unified::build::build_and_persist_graph_with_progress(
34 &root_path,
35 &plugins,
36 &build_config,
37 "cli:watch",
38 progress,
39 )?;
40 } else {
41 anyhow::bail!(
42 "No index found at {}. Use --build to create one, or run 'sqry index' first.",
43 root_path.display()
44 );
45 }
46 }
47
48 let watcher = FileWatcher::new(&root_path)?;
50 let debounce_duration = debounce.map_or(Duration::from_millis(500), Duration::from_millis);
51
52 println!("🔍 Watch mode started");
53 println!("📂 Monitoring: {}", root_path.display());
54 println!("⏱️ Debounce: {}ms", debounce_duration.as_millis());
55 println!();
56 println!("Press Ctrl+C to stop...");
57 println!();
58
59 let (_, progress) = create_progress_reporter(cli);
60
61 loop {
62 let changes = watcher.wait_with_debounce(debounce_duration)?;
64
65 if changes.is_empty() {
66 continue;
67 }
68
69 println!(
70 "📝 Detected {} file changes, updating graph...",
71 changes.len()
72 );
73 let start = std::time::Instant::now();
74
75 match sqry_core::graph::unified::build::build_and_persist_graph_with_progress(
77 &root_path,
78 &plugins,
79 &build_config,
80 "cli:watch",
81 progress.clone(),
82 ) {
83 Ok((_graph, _build_result)) => {
84 println!("✓ Graph updated in {:.2}s", start.elapsed().as_secs_f64());
85 }
86 Err(e) => {
87 eprintln!("❌ Error updating graph: {e}");
88 }
89 }
90 println!();
91 }
92}
93
94fn resolve_path(path: Option<String>) -> Result<PathBuf> {
96 let path_str = path.unwrap_or_else(|| ".".to_string());
97 let path = PathBuf::from(path_str);
98
99 if path.exists() {
100 path.canonicalize().context("Failed to resolve path")
101 } else {
102 anyhow::bail!("Path does not exist: {}", path.display());
103 }
104}