From 3765e6b05de684ef93bee2242af6db760edb9836 Mon Sep 17 00:00:00 2001 From: Riz Ashraf Date: Fri, 9 Oct 2026 00:39:50 +0100 Subject: [PATCH] chore: fix clippy warnings and run rustfmt --- nvim-core/src/lib.rs | 72 ++++++---- server/src/api/ws.rs | 24 ++-- server/src/bin/export_schemas.rs | 18 +-- server/src/config.rs | 11 +- server/src/db.rs | 16 +-- server/src/embedding.rs | 9 +- server/src/handlers/ast.rs | 14 +- server/src/handlers/git.rs | 37 ++--- server/src/handlers/graph.rs | 36 ++--- server/src/handlers/meta.rs | 122 ++++++++-------- server/src/handlers/reconciliation.rs | 17 +-- server/src/handlers/tasks.rs | 8 +- server/src/handlers/vision.rs | 31 ++--- server/src/indexer.rs | 4 +- server/src/lib.rs | 120 ++++++++-------- server/src/models.rs | 22 +-- server/src/search.rs | 7 +- server/src/state.rs | 14 +- server/src/store.rs | 9 +- server/src/tools.rs | 7 + server/src/watcher.rs | 191 +++++++++++++------------- 21 files changed, 420 insertions(+), 369 deletions(-) diff --git a/nvim-core/src/lib.rs b/nvim-core/src/lib.rs index 52af157..cc99a5e 100644 --- a/nvim-core/src/lib.rs +++ b/nvim-core/src/lib.rs @@ -378,14 +378,17 @@ async fn get_nvim_connection() -> Result, String> { { let conn_lock = NVIM_CONN.lock().await; if let Some(sender) = conn_lock.as_ref() - && !sender.is_closed() { - let active_lock = ACTIVE_SOCKET.lock().await; - if let Some(ref current_socket) = *active_lock - && let Ok(target) = read_active_socket_file().await - && !target.is_empty() && &target == current_socket { - return Ok(sender.clone()); - } + && !sender.is_closed() + { + let active_lock = ACTIVE_SOCKET.lock().await; + if let Some(ref current_socket) = *active_lock + && let Ok(target) = read_active_socket_file().await + && !target.is_empty() + && &target == current_socket + { + return Ok(sender.clone()); } + } } let interactive_socket = get_socket_path().await.ok(); @@ -671,13 +674,14 @@ async fn call_nvim(req: rmpv::Value) -> Result { }; let (reply_tx, reply_rx) = oneshot::channel(); - if let Err(_) = tx + if tx .send(NvimRequest { msgid, req, reply: reply_tx, }) .await + .is_err() { PENDING_REQUESTS.remove(&msgid); let mut conn = NVIM_CONN.lock().await; @@ -1341,20 +1345,30 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) { } "edit" => { let mut modified_args = args.clone(); - if let Some(edits) = modified_args.get_mut("edits").and_then(|v| v.as_array_mut()) { + if let Some(edits) = modified_args + .get_mut("edits") + .and_then(|v| v.as_array_mut()) + { for edit in edits.iter_mut() { - if let Some(content) = edit.get_mut("replacement_content") { - if let Some(s) = content.as_str() { - let lines: Vec = s.split('\n').map(|l| l.trim_end_matches('\r').to_string()).collect(); - *content = serde_json::json!(lines); - } + if let Some(content) = edit.get_mut("replacement_content") + && let Some(s) = content.as_str() + { + let lines: Vec = s + .split('\n') + .map(|l| l.trim_end_matches('\r').to_string()) + .collect(); + *content = serde_json::json!(lines); } } - } else if let Some(content) = modified_args.get_mut("replacement_content") { - if let Some(s) = content.as_str() { - let lines: Vec = s.split('\n').map(|l| l.trim_end_matches('\r').to_string()).collect(); - *content = serde_json::json!(lines); - } + } else if let Some(content) = + modified_args.get_mut("replacement_content") + && let Some(s) = content.as_str() + { + let lines: Vec = s + .split('\n') + .map(|l| l.trim_end_matches('\r').to_string()) + .collect(); + *content = serde_json::json!(lines); } let args_rmp = json_to_rmpv(&modified_args); let code = " @@ -1475,11 +1489,14 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) { } "create_scratch" | "open_buffer" => { let mut modified_args = args.clone(); - if let Some(content) = modified_args.get_mut("content") { - if let Some(s) = content.as_str() { - let lines: Vec = s.split('\n').map(|l| l.trim_end_matches('\r').to_string()).collect(); - *content = serde_json::json!(lines); - } + if let Some(content) = modified_args.get_mut("content") + && let Some(s) = content.as_str() + { + let lines: Vec = s + .split('\n') + .map(|l| l.trim_end_matches('\r').to_string()) + .collect(); + *content = serde_json::json!(lines); } let args_rmp = json_to_rmpv(&modified_args); let code = " @@ -1942,9 +1959,10 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) { "highlight" | "clear_highlight" => { let mut modified_args = args.clone(); if action == "clear_highlight" - && let Some(obj) = modified_args.as_object_mut() { - obj.insert("clear_only".to_string(), json!(true)); - } + && let Some(obj) = modified_args.as_object_mut() + { + obj.insert("clear_only".to_string(), json!(true)); + } let args_rmp = json_to_rmpv(&modified_args); let code = " local args = ... diff --git a/server/src/api/ws.rs b/server/src/api/ws.rs index 54aee27..1f8f986 100644 --- a/server/src/api/ws.rs +++ b/server/src/api/ws.rs @@ -68,18 +68,18 @@ pub async fn handle_socket(socket: WebSocket, state: Arc, _client_type .filter_map(|act_val| { if act_val["category"] == "TASK_EVENT" && let Some(details_str) = act_val["details"].as_str() - && let Ok(event_val) = - serde_json::from_str::(details_str) - { - return Some( - serde_json::json!({ - "jsonrpc": "2.0", - "method": "notifications/task/completed", - "params": event_val - }) - .to_string(), - ); - } + && let Ok(event_val) = + serde_json::from_str::(details_str) + { + return Some( + serde_json::json!({ + "jsonrpc": "2.0", + "method": "notifications/task/completed", + "params": event_val + }) + .to_string(), + ); + } None }) .take(5) diff --git a/server/src/bin/export_schemas.rs b/server/src/bin/export_schemas.rs index 1a00c46..e567dbe 100644 --- a/server/src/bin/export_schemas.rs +++ b/server/src/bin/export_schemas.rs @@ -44,10 +44,11 @@ async fn main() -> Result<(), Box> { let path = entry.path(); if path.extension().is_some_and(|ext| ext == "json") && let Some(stem) = path.file_stem().and_then(|s| s.to_str()) - && !active_tools.contains(stem) { - println!(" [STALE REMOVED Win] {}", path.display()); - let _ = fs::remove_file(&path); - } + && !active_tools.contains(stem) + { + println!(" [STALE REMOVED Win] {}", path.display()); + let _ = fs::remove_file(&path); + } } } @@ -57,10 +58,11 @@ async fn main() -> Result<(), Box> { let path = entry.path(); if path.extension().is_some_and(|ext| ext == "json") && let Some(stem) = path.file_stem().and_then(|s| s.to_str()) - && !active_tools.contains(stem) { - println!(" [STALE REMOVED WSL] {}", path.display()); - let _ = fs::remove_file(&path); - } + && !active_tools.contains(stem) + { + println!(" [STALE REMOVED WSL] {}", path.display()); + let _ = fs::remove_file(&path); + } } } diff --git a/server/src/config.rs b/server/src/config.rs index fc521df..c9ad99f 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -31,12 +31,13 @@ pub fn load_mcp_config_env() { { for (key, val) in env_obj { if let Some(val_str) = val.as_str() - && env::var(key).is_err() { - unsafe { - env::set_var(key, val_str); - } - info!("Loaded env var {} from mcp_config.json", key); + && env::var(key).is_err() + { + unsafe { + env::set_var(key, val_str); } + info!("Loaded env var {} from mcp_config.json", key); + } } } } diff --git a/server/src/db.rs b/server/src/db.rs index 32af155..718d887 100644 --- a/server/src/db.rs +++ b/server/src/db.rs @@ -168,20 +168,20 @@ pub fn init_redb(base: &Path) -> Arc { } else { let migrated_path = json_path.with_extension("json.migrated"); if std::fs::rename(&json_path, &migrated_path).is_err() - && migrated_path.exists() { - let _ = std::fs::remove_file(&migrated_path); - let _ = std::fs::rename(&json_path, &migrated_path); - } + && migrated_path.exists() + { + let _ = std::fs::remove_file(&migrated_path); + let _ = std::fs::rename(&json_path, &migrated_path); + } } } } } } } - if opened_ok - && let Err(e) = write_txn.commit() { - tracing::error!("Failed to commit database migration transaction: {}", e); - } + if opened_ok && let Err(e) = write_txn.commit() { + tracing::error!("Failed to commit database migration transaction: {}", e); + } } Err(e) => { tracing::error!( diff --git a/server/src/embedding.rs b/server/src/embedding.rs index 317cc1a..3b899cd 100644 --- a/server/src/embedding.rs +++ b/server/src/embedding.rs @@ -259,13 +259,10 @@ pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 { let mut norm_a_sq = 0.0f32; let mut norm_b_sq = 0.0f32; - let chunks_a = a.chunks_exact(8); - let chunks_b = b.chunks_exact(8); + let (chunks_a, remainder_a) = a.as_chunks::<8>(); + let (chunks_b, remainder_b) = b.as_chunks::<8>(); - let remainder_a = chunks_a.remainder(); - let remainder_b = chunks_b.remainder(); - - for (ca, cb) in chunks_a.zip(chunks_b) { + for (ca, cb) in chunks_a.iter().zip(chunks_b.iter()) { for i in 0..8 { let x = ca[i]; let y = cb[i]; diff --git a/server/src/handlers/ast.rs b/server/src/handlers/ast.rs index ae1e649..8f082f6 100644 --- a/server/src/handlers/ast.rs +++ b/server/src/handlers/ast.rs @@ -120,9 +120,10 @@ impl McpTool for ReadFileSkeletonHandler { } } if header.is_empty() - && let Some(first_line) = node_text.lines().next() { - header = first_line.to_string(); - } + && let Some(first_line) = node_text.lines().next() + { + header = first_line.to_string(); + } out.push_str(&indent); out.push_str(header.trim()); @@ -425,9 +426,10 @@ fn scan_workspace_for_symbol( break; } if let Ok(meta) = std::fs::metadata(path) - && meta.len() > 1024 * 1024 { - continue; - } + && meta.len() > 1024 * 1024 + { + continue; + } if let Ok(content) = std::fs::read_to_string(path) { for (line_num, line) in content.lines().enumerate() { let is_match = if filter_fn_call { diff --git a/server/src/handlers/git.rs b/server/src/handlers/git.rs index e42ffab..afb3a36 100644 --- a/server/src/handlers/git.rs +++ b/server/src/handlers/git.rs @@ -140,27 +140,28 @@ impl McpTool for QueryGitDiffsHandler { let mut results = Vec::new(); let cwd = env::current_dir().unwrap_or_default(); if let Ok(repo) = git2::Repository::discover(&cwd) - && let Ok(mut revwalk) = repo.revwalk() { - let _ = revwalk.push_head(); - let mut count = 0; - for oid in revwalk.flatten() { - if count >= remaining { - break; - } - if let Ok(commit) = repo.find_commit(oid) { - let summary = commit.summary().unwrap_or(""); - if summary.to_lowercase().contains(&q) { - count += 1; - results.push(json!({ - "commit_id": oid.to_string(), - "author": commit.author().name().unwrap_or("unknown"), - "message": summary, - "timestamp": commit.time().seconds(), - })); - } + && let Ok(mut revwalk) = repo.revwalk() + { + let _ = revwalk.push_head(); + let mut count = 0; + for oid in revwalk.flatten() { + if count >= remaining { + break; + } + if let Ok(commit) = repo.find_commit(oid) { + let summary = commit.summary().unwrap_or(""); + if summary.to_lowercase().contains(&q) { + count += 1; + results.push(json!({ + "commit_id": oid.to_string(), + "author": commit.author().name().unwrap_or("unknown"), + "message": summary, + "timestamp": commit.time().seconds(), + })); } } } + } results }) .await diff --git a/server/src/handlers/graph.rs b/server/src/handlers/graph.rs index bb08d06..1b71e1b 100644 --- a/server/src/handlers/graph.rs +++ b/server/src/handlers/graph.rs @@ -63,16 +63,17 @@ impl<'a> GraphQueryBuilder<'a> { } nodes_at_current_depth -= 1; if current_depth < self.max_depth - && let Some(neighbors) = adj.get(current) { - for &(neighbor, rel_type, is_inverse) in neighbors { - if !visited.contains(neighbor) { - visited.insert(neighbor); - parents.insert(neighbor, (current, rel_type, is_inverse)); - queue.push_back(neighbor); - nodes_at_next_depth += 1; - } + && let Some(neighbors) = adj.get(current) + { + for &(neighbor, rel_type, is_inverse) in neighbors { + if !visited.contains(neighbor) { + visited.insert(neighbor); + parents.insert(neighbor, (current, rel_type, is_inverse)); + queue.push_back(neighbor); + nodes_at_next_depth += 1; } } + } if nodes_at_current_depth == 0 { current_depth += 1; nodes_at_current_depth = nodes_at_next_depth; @@ -997,13 +998,14 @@ impl McpTool for GetSubgraphHandler { while let Some((curr, d)) = queue.pop_front() { if d < depth - && let Some(neighbors) = adj.get(curr) { - for &next in neighbors { - if visited.insert(next.to_string()) { - queue.push_back((next, d + 1)); - } + && let Some(neighbors) = adj.get(curr) + { + for &next in neighbors { + if visited.insert(next.to_string()) { + queue.push_back((next, d + 1)); } } + } } let ent: std::collections::HashMap = visited @@ -1176,9 +1178,11 @@ impl McpTool for ResolveStaleSymbolsHandler { state.modify_graph(|g| { for name in g.entities.keys() { if let Some(target) = &req.target - && name != target && !name.contains(target) { - continue; - } + && name != target + && !name.contains(target) + { + continue; + } checked += 1; let path = std::path::Path::new(name); if (name.contains('/') || name.contains('\\') || name.contains('.')) diff --git a/server/src/handlers/meta.rs b/server/src/handlers/meta.rs index 50f76b4..f8f47a1 100644 --- a/server/src/handlers/meta.rs +++ b/server/src/handlers/meta.rs @@ -111,9 +111,10 @@ impl McpTool for SearchErrorFixesHandler { score += 0.5; } if let Some(emb) = &f.embedding - && !query_emb.is_empty() { - score += crate::embedding::cosine_similarity(&query_emb, emb); - } + && !query_emb.is_empty() + { + score += crate::embedding::cosine_similarity(&query_emb, emb); + } (f, score) }) .filter(|(_, score)| *score > 0.1) @@ -198,9 +199,10 @@ impl McpTool for LogCodeChangeHandler { description = format!("{} [Line Range: {}]", description, range); } if let Some(symbols) = &req.symbol_references - && !symbols.is_empty() { - description = format!("{} [Symbols: {}]", description, symbols.join(", ")); - } + && !symbols.is_empty() + { + description = format!("{} [Symbols: {}]", description, symbols.join(", ")); + } if state.ollama.is_available().await { let prompt = format!( @@ -244,13 +246,12 @@ impl McpTool for LogCodeChangeHandler { let detected_vcs = if let Some(vcs) = req.vcs_type.clone() { Some(vcs) } else if let Some(ref rev) = effective_rev { - if rev.starts_with('r') && rev[1..].chars().all(|c| c.is_ascii_digit()) { - Some("svn".to_string()) - } else if req - .repo_url - .as_deref() - .map(|u| u.contains("/svn/")) - .unwrap_or(false) + if (rev.starts_with('r') && rev[1..].chars().all(|c| c.is_ascii_digit())) + || req + .repo_url + .as_deref() + .map(|u| u.contains("/svn/")) + .unwrap_or(false) { Some("svn".to_string()) } else { @@ -337,21 +338,23 @@ impl McpTool for QueryRecentChangesHandler { .rev() .filter(|c| { if let Some(ns) = &req.namespace - && !c.namespace.eq_ignore_ascii_case(ns) { - return false; - } + && !c.namespace.eq_ignore_ascii_case(ns) + { + return false; + } if let Some(repo) = &req.repo_name && c.repo_name .as_ref() .map(|rn| !rn.eq_ignore_ascii_case(repo)) .unwrap_or(true) - { - return false; - } + { + return false; + } if let Some(vcs) = &req.vcs_type - && !c.effective_vcs().eq_ignore_ascii_case(vcs) { - return false; - } + && !c.effective_vcs().eq_ignore_ascii_case(vcs) + { + return false; + } true }) .skip(offset) @@ -464,10 +467,11 @@ impl McpTool for DecisionsHandler { && let Some(s_pos) = adrs .iter() .position(|a| a.id.eq_ignore_ascii_case(superseded_id)) - && s_pos != pos { - adrs[s_pos].status = "superseded".to_string(); - adrs_to_index.push(adrs[s_pos].clone()); - } + && s_pos != pos + { + adrs[s_pos].status = "superseded".to_string(); + adrs_to_index.push(adrs[s_pos].clone()); + } let a = &mut adrs[pos]; if let Some(t) = req.title { @@ -1273,20 +1277,23 @@ impl McpTool for ManageCheckpointHandler { } if let Ok(graph_content) = std::fs::read_to_string(target_dir.join("graph.json")) - && let Ok(graph) = serde_json::from_str(&graph_content) { - state.graph.modify(|g| *g = graph); - } + && let Ok(graph) = serde_json::from_str(&graph_content) + { + state.graph.modify(|g| *g = graph); + } if let Ok(tasks_content) = std::fs::read_to_string(target_dir.join("tasks.json")) - && let Ok(tasks) = serde_json::from_str(&tasks_content) { - state.project.tasks.modify(|t| *t = tasks); - } + && let Ok(tasks) = serde_json::from_str(&tasks_content) + { + state.project.tasks.modify(|t| *t = tasks); + } if let Ok(debts_content) = std::fs::read_to_string(target_dir.join("tech_debts.json")) - && let Ok(debts) = serde_json::from_str(&debts_content) { - state.code.tech_debts.modify(|d| *d = debts); - } + && let Ok(debts) = serde_json::from_str(&debts_content) + { + state.code.tech_debts.modify(|d| *d = debts); + } Ok(format!("Checkpoint '{}' restored successfully.", name)) } @@ -1296,9 +1303,10 @@ impl McpTool for ManageCheckpointHandler { if let Ok(entries) = std::fs::read_dir(&checkpoints_dir) { for entry in entries.flatten() { if entry.path().is_dir() - && let Some(n) = entry.file_name().to_str() { - list.push(serde_json::json!({"type": "checkpoint", "name": n})); - } + && let Some(n) = entry.file_name().to_str() + { + list.push(serde_json::json!({"type": "checkpoint", "name": n})); + } } } let snaps = state.project.snapshots.read_with(|snaps| snaps.clone()); @@ -1467,9 +1475,10 @@ impl McpTool for GetNextActionableTasksHandler { if let Some(branch) = &req.git_branch && let Some(tb) = &task.git_branch - && tb != branch { - continue; - } + && tb != branch + { + continue; + } let unblocked = task.dependencies.is_empty() || task.dependencies.iter().all(|d| completed_ids.contains(d)); @@ -1541,9 +1550,10 @@ impl McpTool for HypothesesHandler { .into_iter() .filter(|h| { if let Some(tid) = &req.task_id - && h.task_id.as_ref() != Some(tid) { - return false; - } + && h.task_id.as_ref() != Some(tid) + { + return false; + } if let Some(q) = &req.query { let lq = q.to_lowercase(); return h.hypothesis.to_lowercase().contains(&lq) @@ -1725,20 +1735,24 @@ impl McpTool for AgentSignalsHandler { .iter() .filter(|s| { if let Some(ttl) = s.ttl_seconds - && now > s.timestamp + ttl { - return false; - } + && now > s.timestamp + ttl + { + return false; + } if let Some(sender) = &req.sender - && s.sender.to_lowercase() != sender.to_lowercase() { - return false; - } + && s.sender.to_lowercase() != sender.to_lowercase() + { + return false; + } if let Some(st) = &req.signal_type - && s.signal_type.to_lowercase() != st.to_lowercase() { - return false; - } + && s.signal_type.to_lowercase() != st.to_lowercase() + { + return false; + } true }) - .take(req.limit.unwrap_or(20)).cloned() + .take(req.limit.unwrap_or(20)) + .cloned() .collect::>() }); diff --git a/server/src/handlers/reconciliation.rs b/server/src/handlers/reconciliation.rs index 625776d..6b790e8 100644 --- a/server/src/handlers/reconciliation.rs +++ b/server/src/handlers/reconciliation.rs @@ -245,11 +245,11 @@ pub fn recalculate_milestones(state: &MemoryState) -> Vec { && (t.status == "in_progress" || t.status == "active") })) && !m.status.eq_ignore_ascii_case("in_progress") - && !m.status.eq_ignore_ascii_case("completed") - { - m.status = "in_progress".to_string(); - updated.push(m.id.clone()); - } + && !m.status.eq_ignore_ascii_case("completed") + { + m.status = "in_progress".to_string(); + updated.push(m.id.clone()); + } } }); @@ -287,9 +287,10 @@ pub async fn reconcile_commit_or_code_change( return true; } if let (Some(n1), Some(n2)) = (adr_numeric_id(&adr.id), adr_numeric_id(cand)) - && n1 == n2 { - return true; - } + && n1 == n2 + { + return true; + } false }); diff --git a/server/src/handlers/tasks.rs b/server/src/handlers/tasks.rs index 001765a..167af4e 100644 --- a/server/src/handlers/tasks.rs +++ b/server/src/handlers/tasks.rs @@ -50,7 +50,6 @@ impl McpTool for TasksHandler { priority: req.priority, assigned_agent: req.assigned_agent, verification_command: req.verification_command, - ..Default::default() }; let idx = state.get_search_index().await; drop(idx.index_task(&task)); @@ -479,9 +478,10 @@ impl McpTool for MilestonesHandler { m.status = status.clone(); if (status.eq_ignore_ascii_case("completed") || status.eq_ignore_ascii_case("done")) - && m.completed_at.is_none() { - m.completed_at = Some(crate::handlers::utils::now_secs()); - } + && m.completed_at.is_none() + { + m.completed_at = Some(crate::handlers::utils::now_secs()); + } if let Some(task_ids) = &req.task_ids { m.task_ids = task_ids.clone(); if let Some(deliverables) = &req.deliverables { diff --git a/server/src/handlers/vision.rs b/server/src/handlers/vision.rs index 76bdfa9..8ed9cbb 100644 --- a/server/src/handlers/vision.rs +++ b/server/src/handlers/vision.rs @@ -191,10 +191,9 @@ pub fn html_to_markdown(html: &str) -> String { out.push_str("* "); } } - "/li" - if !in_cell => { - out.push('\n'); - } + "/li" if !in_cell => { + out.push('\n'); + } _ => {} } } else if c == '&' { @@ -510,7 +509,8 @@ pub async fn process_clipboard_snapshot(state: Arc) { .search_index .read() .await - .index_clipboard_image(&doc_id, &path_str, text); + .index_clipboard_image(&doc_id, &path_str, text) + .await; } let cached = crate::state::CachedClipboardImage { @@ -567,9 +567,10 @@ pub async fn process_clipboard_snapshot(state: Arc) { let mut cache = state.clipboard_cache.write().await; if let Some(ref prev) = cache.last_text - && prev.text == cached.text { - return; - } + && prev.text == cached.text + { + return; + } cache.last_text = Some(cached.clone()); cache .history @@ -891,12 +892,10 @@ impl McpTool for ClipboardHandler { } if let Some(eng) = engine - && let Some(ocr_text) = perform_ocrs_ocr(eng, &dynamic_img) { - out.insert( - "image_analysis".to_string(), - json!(ocr_text.trim()), - ); - } + && let Some(ocr_text) = perform_ocrs_ocr(eng, &dynamic_img) + { + out.insert("image_analysis".to_string(), json!(ocr_text.trim())); + } } Ok(out) }, @@ -905,9 +904,7 @@ impl McpTool for ClipboardHandler { .map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??; state.record_activity("clipboard", "Read contents from OS clipboard", None); - Ok::(serde_yaml::to_string(&Value::Object( - out, - ))?) + Ok::(serde_yaml::to_string(&Value::Object(out))?) } ClipboardAction::Write => { let text_opt = req.text; diff --git a/server/src/indexer.rs b/server/src/indexer.rs index a49d4c9..5e803ff 100644 --- a/server/src/indexer.rs +++ b/server/src/indexer.rs @@ -163,7 +163,7 @@ fn extract_chunks_with_parent( node: Node, code: &str, chunks: &mut Vec<(String, String, String)>, - ext: &str, + _ext: &str, parent_scope: Option<&str>, depth: usize, ) { @@ -229,7 +229,7 @@ fn extract_chunks_with_parent( } else { let mut cursor = node.walk(); for child in node.named_children(&mut cursor) { - extract_chunks_with_parent(child, code, chunks, ext, current_scope, depth + 1); + extract_chunks_with_parent(child, code, chunks, _ext, current_scope, depth + 1); } } } diff --git a/server/src/lib.rs b/server/src/lib.rs index daaab5d..4b25c3d 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -107,9 +107,10 @@ pub async fn ttl_sweeper_worker(state: Arc) { state.project.tasks.read_with(|tasks| { for t in tasks.iter() { if let Some(exp) = t.expires_at - && t.is_active() { - next_expiry = Some(next_expiry.map_or(exp, |curr| curr.min(exp))); - } + && t.is_active() + { + next_expiry = Some(next_expiry.map_or(exp, |curr| curr.min(exp))); + } } }); @@ -140,7 +141,7 @@ pub async fn ttl_sweeper_worker(state: Arc) { let sleep_duration = match next_expiry { Some(exp) if exp > now => { let diff = exp - now; - std::time::Duration::from_secs(diff.min(60).max(1)) + std::time::Duration::from_secs(diff.clamp(1, 60)) } Some(_) => std::time::Duration::from_millis(50), None => std::time::Duration::from_secs(60), @@ -161,11 +162,13 @@ pub async fn ttl_sweeper_worker(state: Arc) { state.project.tasks.modify(|tasks| { for t in tasks.iter_mut() { if let Some(exp) = t.expires_at - && exp <= now && t.is_active() { - t.status = "expired".to_string(); - t.updated_at = now; - expired_tasks.push(t.id.clone()); - } + && exp <= now + && t.is_active() + { + t.status = "expired".to_string(); + t.updated_at = now; + expired_tasks.push(t.id.clone()); + } } }); @@ -249,27 +252,28 @@ pub async fn condense_graph_worker(state: Arc) { }); if let Some((content, names)) = snippet_condensation - && !content.is_empty() { - let name = format!("Snippet History {}", now); - state.modify_graph(|graph| { - graph.entities.insert( - name.clone(), - crate::models::Entity { - name: name.clone(), - entity_type: "Historical Summary".to_string(), - observations: vec![content], - namespace: crate::models::default_namespace(), - git_branch: None, - ..Default::default() - }, - ); - }); - let name_set: std::collections::HashSet = names.into_iter().collect(); - state.code.snippets.modify(|snippets| { - snippets.retain(|s| !name_set.contains(&s.name)); - }); - tracing::info!("Condensed snippets into Historical Summary."); - } + && !content.is_empty() + { + let name = format!("Snippet History {}", now); + state.modify_graph(|graph| { + graph.entities.insert( + name.clone(), + crate::models::Entity { + name: name.clone(), + entity_type: "Historical Summary".to_string(), + observations: vec![content], + namespace: crate::models::default_namespace(), + git_branch: None, + ..Default::default() + }, + ); + }); + let name_set: std::collections::HashSet = names.into_iter().collect(); + state.code.snippets.modify(|snippets| { + snippets.retain(|s| !name_set.contains(&s.name)); + }); + tracing::info!("Condensed snippets into Historical Summary."); + } } } @@ -319,36 +323,37 @@ pub async fn memory_consolidation_worker(state: Arc) { .trim_end_matches("```") .trim(); if let Ok(duplicates) = serde_json::from_str::>(cleaned) - && duplicates.len() == 2 { - let e1_name = &duplicates[0]; - let e2_name = &duplicates[1]; + && duplicates.len() == 2 + { + let e1_name = &duplicates[0]; + let e2_name = &duplicates[1]; - if e1_name != e2_name { - tracing::info!( - "Memory Consolidation Daemon: Merging '{}' into '{}'", - e2_name, - e1_name - ); - state.modify_graph(|g| { - if let Some(mut e2) = g.entities.remove(e2_name) { - if let Some(e1) = g.entities.get_mut(e1_name) { - e1.observations.append(&mut e2.observations); - } else { - g.entities.insert(e2_name.clone(), e2); - } + if e1_name != e2_name { + tracing::info!( + "Memory Consolidation Daemon: Merging '{}' into '{}'", + e2_name, + e1_name + ); + state.modify_graph(|g| { + if let Some(mut e2) = g.entities.remove(e2_name) { + if let Some(e1) = g.entities.get_mut(e1_name) { + e1.observations.append(&mut e2.observations); + } else { + g.entities.insert(e2_name.clone(), e2); } + } - for rel in g.relations.iter_mut() { - if rel.from == *e2_name { - rel.from = e1_name.clone(); - } - if rel.to == *e2_name { - rel.to = e1_name.clone(); - } + for rel in g.relations.iter_mut() { + if rel.from == *e2_name { + rel.from = e1_name.clone(); } - }); - } + if rel.to == *e2_name { + rel.to = e1_name.clone(); + } + } + }); } + } } } } @@ -466,13 +471,12 @@ pub async fn run_server(state: Arc) -> Result<(), Box 20 { @@ -141,10 +142,9 @@ impl MemoryState { pub fn new(base_dir_str: &str) -> Self { let is_in_memory = base_dir_str == ":memory:"; let base = std::path::PathBuf::from(base_dir_str); - if !is_in_memory - && let Err(e) = std::fs::create_dir_all(&base) { - tracing::error!("Failed to create store directory at {:?}: {}", base, e); - } + if !is_in_memory && let Err(e) = std::fs::create_dir_all(&base) { + tracing::error!("Failed to create store directory at {:?}: {}", base, e); + } let db = crate::db::init_redb(&base); diff --git a/server/src/store.rs b/server/src/store.rs index 5a74f60..ab28a23 100644 --- a/server/src/store.rs +++ b/server/src/store.rs @@ -34,9 +34,11 @@ static QUEUE_REGISTRY: std::sync::Mutex, DbWriteQueue)>> = fn get_or_create_queue(db: Arc) -> DbWriteQueue { let mut reg = QUEUE_REGISTRY.lock().unwrap_or_else(|e| e.into_inner()); if let Some((ref existing_db, ref queue)) = *reg - && Arc::ptr_eq(existing_db, &db) && !queue.tx.is_closed() { - return queue.clone(); - } + && Arc::ptr_eq(existing_db, &db) + && !queue.tx.is_closed() + { + return queue.clone(); + } let new_queue = DbWriteQueue::new(db.clone()); *reg = Some((db, new_queue.clone())); new_queue @@ -458,6 +460,7 @@ impl Store } } + #[allow(clippy::type_complexity)] fn prepare_batch( &self, new_snapshot: &T, diff --git a/server/src/tools.rs b/server/src/tools.rs index 11b3e9b..88e2960 100644 --- a/server/src/tools.rs +++ b/server/src/tools.rs @@ -612,6 +612,7 @@ pub enum HandoffMemoAction { /// - 'leave': Post a handoff memo. Required: content. Optional: namespace. /// - 'read': Inspect active memos. Optional: namespace. /// - 'clear': Clear memos. Optional: namespace, ids. +/// /// Next steps on error: Check parameter requirements for 'leave' or 'clear' actions. #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct HandoffMemosTool { @@ -655,6 +656,7 @@ pub enum TaskAction { /// - 'list': List active tasks. Optional: git_branch, summary_level ('compact'|'detailed'|'full'), max_tokens. /// - 'set_criteria': Set acceptance criteria. Required: id, criteria (array of strings). /// - 'verify': Verify criteria met. Required: id. +/// /// Next steps on error: Check required parameters or call list to verify task IDs. #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct TasksTool { @@ -719,6 +721,7 @@ pub enum MilestoneAction { /// - 'add': Create milestone. Required: title. Optional: namespace. /// - 'update': Update milestone status. Required: id, status. /// - 'list': List milestones. Optional: namespace. +/// /// Next steps on error: Provide required title for 'add' or id/status for 'update'. #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct MilestonesTool { @@ -765,6 +768,7 @@ pub enum SnippetAction { /// - 'search': Search snippets. Optional: query, tags, hybrid (boolean for BM25+vector search). /// - 'delete': Delete snippet. Required: id (or query) as snippet name. /// - 'tag': Tag snippet. Required: id (or query), tags (array of strings). +/// /// Next steps on error: Ensure snippet name/query or id is provided. #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct SnippetsTool { @@ -815,6 +819,7 @@ pub enum DecisionAction { /// - 'query': Search ADRs. Optional: query, namespace. /// - 'update': Update ADR status or implementation info. Required: id. Optional: status, git_commit, git_branch, task_id, context, decision, consequences, title. /// - 'delete': Remove ADR. Required: id. +/// /// Next steps on error: Provide title for 'log' or id for 'update'/'delete'. #[derive(Deserialize, Serialize, JsonSchema, Debug, Clone)] pub struct DecisionsTool { @@ -875,6 +880,7 @@ pub enum TechDebtAction { /// - 'log': Record technical debt. Required: description. Optional: ideal_solution, git_commit, git_branch, symbol_references, line_range, namespace. /// - 'resolve': Mark tech debt resolved. Required: id. /// - 'list': List tech debt items. Optional: include_resolved, namespace. +/// /// Next steps on error: Provide description for 'log' or valid ID for 'resolve'. #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct TechDebtTool { @@ -963,6 +969,7 @@ pub enum EnvAction { /// - 'log_requirement': Log environment variable requirement. Required: key. Optional: description, is_secret, namespace. /// - 'register': Register remote target environment. Required: name. Optional: url, description, requires_vpn, namespace. /// - 'get_details': Get full environment details. Optional: namespace. +/// /// Next steps on error: Provide key for 'log_requirement' or name for 'register'. #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct EnvironmentTool { diff --git a/server/src/watcher.rs b/server/src/watcher.rs index 8c8b01e..c542f11 100644 --- a/server/src/watcher.rs +++ b/server/src/watcher.rs @@ -105,109 +105,106 @@ async fn trigger_autonomous_review(path: &Path, state: Arc) { // ADR-0109: Incremental Background AST Indexing & Differential Graph Updates let ext = path.extension().and_then(|e| e.to_str()).unwrap_or(""); if matches!(ext, "rs" | "ts" | "js" | "py" | "go" | "java" | "c" | "cpp") - && let Ok(content) = std::fs::read_to_string(path) { - let language = match ext { - "rs" => Some(tree_sitter_rust::LANGUAGE), - "ts" | "js" => Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT), - "py" => Some(tree_sitter_python::LANGUAGE), - "java" => Some(tree_sitter_java::LANGUAGE), - "c" => Some(tree_sitter_c::LANGUAGE), - "cpp" => Some(tree_sitter_cpp::LANGUAGE), - "go" => Some(tree_sitter_go::LANGUAGE), - _ => None, - }; + && let Ok(content) = std::fs::read_to_string(path) + { + let language = match ext { + "rs" => Some(tree_sitter_rust::LANGUAGE), + "ts" | "js" => Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT), + "py" => Some(tree_sitter_python::LANGUAGE), + "java" => Some(tree_sitter_java::LANGUAGE), + "c" => Some(tree_sitter_c::LANGUAGE), + "cpp" => Some(tree_sitter_cpp::LANGUAGE), + "go" => Some(tree_sitter_go::LANGUAGE), + _ => None, + }; - if let Some(lang) = language { - let mut parser = tree_sitter::Parser::new(); - if parser.set_language(&lang.into()).is_ok() - && let Some(tree) = parser.parse(&content, None) { - let mut chunks = Vec::new(); - crate::indexer::extract_chunks( - tree.root_node(), - &content, - &mut chunks, - ext, + if let Some(lang) = language { + let mut parser = tree_sitter::Parser::new(); + if parser.set_language(&lang.into()).is_ok() + && let Some(tree) = parser.parse(&content, None) + { + let mut chunks = Vec::new(); + crate::indexer::extract_chunks(tree.root_node(), &content, &mut chunks, ext); + let file_str = path.to_string_lossy().to_string(); + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_secs(); + + let chunks_count = chunks.len(); + let file_str_clone = file_str.clone(); + state.modify_graph(|g| { + // Ensure File entity exists + g.entities + .entry(file_str.clone()) + .or_insert_with(|| crate::models::Entity { + name: file_str.clone(), + entity_type: "File".to_string(), + namespace: "global".to_string(), + file_path: Some(file_str.clone()), + created_at: Some(now), + updated_at: Some(now), + ..Default::default() + }); + + for (chunk_name, chunk_code, chunk_desc) in chunks { + let symbol_name = format!("{}::{}", file_str, chunk_name); + let symbol_type = if chunk_desc.contains("struct") { + "DataStructure".to_string() + } else { + "McpTool".to_string() + }; + + g.entities.insert( + symbol_name.clone(), + crate::models::Entity { + name: symbol_name.clone(), + entity_type: symbol_type, + observations: vec![format!( + "AST definition: {} chars", + chunk_code.len() + )], + namespace: "global".to_string(), + file_path: Some(file_str.clone()), + created_at: Some(now), + updated_at: Some(now), + ..Default::default() + }, ); - let file_str = path.to_string_lossy().to_string(); - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_secs(); - let chunks_count = chunks.len(); - let file_str_clone = file_str.clone(); - state.modify_graph(|g| { - // Ensure File entity exists - g.entities.entry(file_str.clone()).or_insert_with(|| { - crate::models::Entity { - name: file_str.clone(), - entity_type: "File".to_string(), - namespace: "global".to_string(), - file_path: Some(file_str.clone()), - created_at: Some(now), - updated_at: Some(now), - ..Default::default() - } - }); - - for (chunk_name, chunk_code, chunk_desc) in chunks { - let symbol_name = format!("{}::{}", file_str, chunk_name); - let symbol_type = if chunk_desc.contains("struct") { - "DataStructure".to_string() - } else { - "McpTool".to_string() - }; - - g.entities.insert( - symbol_name.clone(), - crate::models::Entity { - name: symbol_name.clone(), - entity_type: symbol_type, - observations: vec![format!( - "AST definition: {} chars", - chunk_code.len() - )], - namespace: "global".to_string(), - file_path: Some(file_str.clone()), - created_at: Some(now), - updated_at: Some(now), - ..Default::default() - }, - ); - - let rel = crate::models::Relation { - from: file_str.clone(), - to: symbol_name, - relation_type: "declares".to_string(), - namespace: "global".to_string(), - ..Default::default() - }; - if !g.relations.contains(&rel) { - g.relations.push(rel); - } - } - }); - - let _ = state.event_bus_tx.send(crate::state::GenericEvent { - topic: "ast:symbol_updated".to_string(), - session_id: None, - payload: serde_json::json!({ - "file": file_str_clone, - "extension": ext, - "symbols_count": chunks_count, - }), - }); - - let _ = state.event_bus_tx.send(crate::state::GenericEvent { - topic: "resource:updated".to_string(), - session_id: None, - payload: serde_json::json!({ - "uri": "memory://graph" - }), - }); + let rel = crate::models::Relation { + from: file_str.clone(), + to: symbol_name, + relation_type: "declares".to_string(), + namespace: "global".to_string(), + ..Default::default() + }; + if !g.relations.contains(&rel) { + g.relations.push(rel); + } } + }); + + let _ = state.event_bus_tx.send(crate::state::GenericEvent { + topic: "ast:symbol_updated".to_string(), + session_id: None, + payload: serde_json::json!({ + "file": file_str_clone, + "extension": ext, + "symbols_count": chunks_count, + }), + }); + + let _ = state.event_bus_tx.send(crate::state::GenericEvent { + topic: "resource:updated".to_string(), + session_id: None, + payload: serde_json::json!({ + "uri": "memory://graph" + }), + }); } } + } info!( "Autonomous review & incremental AST index complete for {:?}",