hematite/agent/
find_files.rs1use crate::agent::fuzzy::fuzzy_match;
2use serde_json::Value;
3use walkdir::WalkDir;
4
5pub async fn find_files_fuzzy(args: &Value) -> Result<String, String> {
8 let query = args
9 .get("query")
10 .and_then(|v| v.as_str())
11 .ok_or_else(|| "Missing required argument: 'query'".to_string())?;
12
13 let max_results = args.get("limit").and_then(|v| v.as_u64()).unwrap_or(20) as usize;
14 let workspace_root = crate::tools::file_ops::workspace_root();
15
16 let mut matches = Vec::new();
17
18 for entry in WalkDir::new(&workspace_root)
19 .into_iter()
20 .filter_entry(|e| {
21 let name = e.file_name().to_string_lossy();
22 !name.starts_with('.') && name != "target" && name != "node_modules"
23 })
24 .filter_map(|e| e.ok())
25 {
26 if entry.file_type().is_file() {
27 let rel_path = entry
28 .path()
29 .strip_prefix(&workspace_root)
30 .unwrap_or(entry.path());
31 let path_str = rel_path.to_string_lossy();
32
33 if let Some((_, score)) = fuzzy_match(&path_str, query) {
34 matches.push((path_str.into_owned(), score));
35 }
36 }
37 }
38
39 matches.sort_by_key(|m| m.1);
41 matches.truncate(max_results);
42
43 if matches.is_empty() {
44 return Ok(format!("No files found matching '{}'", query));
45 }
46
47 let mut output = format!("Found {} matches for '{}':\n", matches.len(), query);
48 for (path, score) in matches {
49 let confidence = if score <= -100 {
50 "High"
51 } else if score <= 5 {
52 "Moderate"
53 } else {
54 "Low"
55 };
56 output.push_str(&format!("- {} (Confidence: {})\n", path, confidence));
57 }
58
59 Ok(output)
60}