use super::WatchArgs;
use anyhow::Result;
use colored::*;
use std::path::PathBuf;
use std::time::{Duration, Instant};
pub fn run(args: &WatchArgs) -> Result<()> {
eprintln!("{}", "👁️ Forge Guard — Watch Mode".bold());
eprintln!(" Watching: {}", args.dirs);
eprintln!(" Debounce: {}ms", args.debounce_ms);
let watch_dirs: Vec<PathBuf> = args
.dirs
.split(',')
.map(|s| {
let p = PathBuf::from(s.trim());
if p.is_relative() {
args.shared.project.join(p)
} else {
p
}
})
.collect();
for dir in &watch_dirs {
if !dir.exists() {
anyhow::bail!("Directory does not exist: {}", dir.display());
}
}
eprintln!(
"\n{}",
" Watching for changes... (Ctrl+C to stop)".dimmed()
);
let debounce = Duration::from_millis(args.debounce_ms);
let poll_interval = Duration::from_millis(200);
let mut last_mod = get_last_modification(&watch_dirs)?;
let mut last_trigger = Instant::now();
loop {
std::thread::sleep(poll_interval);
let current_mod = get_last_modification(&watch_dirs)?;
if current_mod > last_mod && last_trigger.elapsed() >= debounce {
eprintln!("\n{}", "🔄 Change detected, re-auditing...".bold());
let audit_args = super::AuditArgs {
shared: super::SharedFlags {
chain: args.shared.chain.clone(),
project: args.shared.project.clone(),
json: args.shared.json,
markdown: args.shared.markdown,
strict: args.shared.strict,
offline: args.shared.offline,
production: args.shared.production,
report: args.shared.report,
parallelism: args.shared.parallelism,
},
full: args.full,
quick: false,
summary: false,
exploit: args.full,
gas: args.full,
all_chains: false,
sources: args.dirs.clone(),
exclude: args.exclude.clone(),
ai: false,
ai_provider: "openai".into(),
ai_model: "gpt-4".into(),
ai_api_key: None,
ollama_endpoint: None,
ai_full: false,
};
if let Err(e) = super::audit::run(&audit_args) {
eprintln!("{} Audit error: {}", "⚠️".yellow(), e);
}
last_mod = current_mod;
last_trigger = Instant::now();
eprintln!(
"\n{}",
" Waiting for changes... (Ctrl+C to stop)".dimmed()
);
}
}
}
fn get_last_modification(dirs: &[PathBuf]) -> Result<std::time::SystemTime> {
let mut latest = std::time::UNIX_EPOCH;
for dir in dirs {
for entry in walkdir::WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
{
if entry.file_type().is_file() {
if let Ok(metadata) = entry.metadata() {
if let Ok(modified) = metadata.modified() {
if modified > latest {
latest = modified;
}
}
}
}
}
}
Ok(latest)
}