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