chore: fix clippy warnings and run rustfmt

This commit is contained in:
Riz Ashraf committed 2026-10-09 00:39:50 +01:00
1 parent fecd8bf33f
commit 3765e6b05d
20 files changed
+148 -97

No files matched your search

+35 -17
View File
@@ -378,11 +378,14 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
{ {
let conn_lock = NVIM_CONN.lock().await; let conn_lock = NVIM_CONN.lock().await;
if let Some(sender) = conn_lock.as_ref() if let Some(sender) = conn_lock.as_ref()
&& !sender.is_closed() { && !sender.is_closed()
{
let active_lock = ACTIVE_SOCKET.lock().await; let active_lock = ACTIVE_SOCKET.lock().await;
if let Some(ref current_socket) = *active_lock if let Some(ref current_socket) = *active_lock
&& let Ok(target) = read_active_socket_file().await && let Ok(target) = read_active_socket_file().await
&& !target.is_empty() && &target == current_socket { && !target.is_empty()
&& &target == current_socket
{
return Ok(sender.clone()); return Ok(sender.clone());
} }
} }
@@ -671,13 +674,14 @@ async fn call_nvim(req: rmpv::Value) -> Result<rmpv::Value, String> {
}; };
let (reply_tx, reply_rx) = oneshot::channel(); let (reply_tx, reply_rx) = oneshot::channel();
if let Err(_) = tx if tx
.send(NvimRequest { .send(NvimRequest {
msgid, msgid,
req, req,
reply: reply_tx, reply: reply_tx,
}) })
.await .await
.is_err()
{ {
PENDING_REQUESTS.remove(&msgid); PENDING_REQUESTS.remove(&msgid);
let mut conn = NVIM_CONN.lock().await; let mut conn = NVIM_CONN.lock().await;
@@ -1341,21 +1345,31 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
"edit" => { "edit" => {
let mut modified_args = args.clone(); 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() { for edit in edits.iter_mut() {
if let Some(content) = edit.get_mut("replacement_content") { if let Some(content) = edit.get_mut("replacement_content")
if let Some(s) = content.as_str() { && let Some(s) = content.as_str()
let lines: Vec<String> = s.split('\n').map(|l| l.trim_end_matches('\r').to_string()).collect(); {
let lines: Vec<String> = s
.split('\n')
.map(|l| l.trim_end_matches('\r').to_string())
.collect();
*content = serde_json::json!(lines); *content = serde_json::json!(lines);
} }
} }
} } else if let Some(content) =
} else if let Some(content) = modified_args.get_mut("replacement_content") { modified_args.get_mut("replacement_content")
if let Some(s) = content.as_str() { && let Some(s) = content.as_str()
let lines: Vec<String> = s.split('\n').map(|l| l.trim_end_matches('\r').to_string()).collect(); {
let lines: Vec<String> = s
.split('\n')
.map(|l| l.trim_end_matches('\r').to_string())
.collect();
*content = serde_json::json!(lines); *content = serde_json::json!(lines);
} }
}
let args_rmp = json_to_rmpv(&modified_args); let args_rmp = json_to_rmpv(&modified_args);
let code = " let code = "
local args = ... local args = ...
@@ -1475,12 +1489,15 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
"create_scratch" | "open_buffer" => { "create_scratch" | "open_buffer" => {
let mut modified_args = args.clone(); let mut modified_args = args.clone();
if let Some(content) = modified_args.get_mut("content") { if let Some(content) = modified_args.get_mut("content")
if let Some(s) = content.as_str() { && let Some(s) = content.as_str()
let lines: Vec<String> = s.split('\n').map(|l| l.trim_end_matches('\r').to_string()).collect(); {
let lines: Vec<String> = s
.split('\n')
.map(|l| l.trim_end_matches('\r').to_string())
.collect();
*content = serde_json::json!(lines); *content = serde_json::json!(lines);
} }
}
let args_rmp = json_to_rmpv(&modified_args); let args_rmp = json_to_rmpv(&modified_args);
let code = " let code = "
local args = ... local args = ...
@@ -1942,7 +1959,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
"highlight" | "clear_highlight" => { "highlight" | "clear_highlight" => {
let mut modified_args = args.clone(); let mut modified_args = args.clone();
if action == "clear_highlight" if action == "clear_highlight"
&& let Some(obj) = modified_args.as_object_mut() { && let Some(obj) = modified_args.as_object_mut()
{
obj.insert("clear_only".to_string(), json!(true)); obj.insert("clear_only".to_string(), json!(true));
} }
let args_rmp = json_to_rmpv(&modified_args); let args_rmp = json_to_rmpv(&modified_args);
+4 -2
View File
@@ -44,7 +44,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = entry.path(); let path = entry.path();
if path.extension().is_some_and(|ext| ext == "json") if path.extension().is_some_and(|ext| ext == "json")
&& let Some(stem) = path.file_stem().and_then(|s| s.to_str()) && let Some(stem) = path.file_stem().and_then(|s| s.to_str())
&& !active_tools.contains(stem) { && !active_tools.contains(stem)
{
println!(" [STALE REMOVED Win] {}", path.display()); println!(" [STALE REMOVED Win] {}", path.display());
let _ = fs::remove_file(&path); let _ = fs::remove_file(&path);
} }
@@ -57,7 +58,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = entry.path(); let path = entry.path();
if path.extension().is_some_and(|ext| ext == "json") if path.extension().is_some_and(|ext| ext == "json")
&& let Some(stem) = path.file_stem().and_then(|s| s.to_str()) && let Some(stem) = path.file_stem().and_then(|s| s.to_str())
&& !active_tools.contains(stem) { && !active_tools.contains(stem)
{
println!(" [STALE REMOVED WSL] {}", path.display()); println!(" [STALE REMOVED WSL] {}", path.display());
let _ = fs::remove_file(&path); let _ = fs::remove_file(&path);
} }
+2 -1
View File
@@ -31,7 +31,8 @@ pub fn load_mcp_config_env() {
{ {
for (key, val) in env_obj { for (key, val) in env_obj {
if let Some(val_str) = val.as_str() if let Some(val_str) = val.as_str()
&& env::var(key).is_err() { && env::var(key).is_err()
{
unsafe { unsafe {
env::set_var(key, val_str); env::set_var(key, val_str);
} }
+3 -3
View File
@@ -168,7 +168,8 @@ pub fn init_redb(base: &Path) -> Arc<Database> {
} else { } else {
let migrated_path = json_path.with_extension("json.migrated"); let migrated_path = json_path.with_extension("json.migrated");
if std::fs::rename(&json_path, &migrated_path).is_err() if std::fs::rename(&json_path, &migrated_path).is_err()
&& migrated_path.exists() { && migrated_path.exists()
{
let _ = std::fs::remove_file(&migrated_path); let _ = std::fs::remove_file(&migrated_path);
let _ = std::fs::rename(&json_path, &migrated_path); let _ = std::fs::rename(&json_path, &migrated_path);
} }
@@ -178,8 +179,7 @@ pub fn init_redb(base: &Path) -> Arc<Database> {
} }
} }
} }
if opened_ok if opened_ok && let Err(e) = write_txn.commit() {
&& let Err(e) = write_txn.commit() {
tracing::error!("Failed to commit database migration transaction: {}", e); tracing::error!("Failed to commit database migration transaction: {}", e);
} }
} }
+3 -6
View File
@@ -259,13 +259,10 @@ pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
let mut norm_a_sq = 0.0f32; let mut norm_a_sq = 0.0f32;
let mut norm_b_sq = 0.0f32; let mut norm_b_sq = 0.0f32;
let chunks_a = a.chunks_exact(8); let (chunks_a, remainder_a) = a.as_chunks::<8>();
let chunks_b = b.chunks_exact(8); let (chunks_b, remainder_b) = b.as_chunks::<8>();
let remainder_a = chunks_a.remainder(); for (ca, cb) in chunks_a.iter().zip(chunks_b.iter()) {
let remainder_b = chunks_b.remainder();
for (ca, cb) in chunks_a.zip(chunks_b) {
for i in 0..8 { for i in 0..8 {
let x = ca[i]; let x = ca[i];
let y = cb[i]; let y = cb[i];
+4 -2
View File
@@ -120,7 +120,8 @@ impl McpTool for ReadFileSkeletonHandler {
} }
} }
if header.is_empty() if header.is_empty()
&& let Some(first_line) = node_text.lines().next() { && let Some(first_line) = node_text.lines().next()
{
header = first_line.to_string(); header = first_line.to_string();
} }
@@ -425,7 +426,8 @@ fn scan_workspace_for_symbol(
break; break;
} }
if let Ok(meta) = std::fs::metadata(path) if let Ok(meta) = std::fs::metadata(path)
&& meta.len() > 1024 * 1024 { && meta.len() > 1024 * 1024
{
continue; continue;
} }
if let Ok(content) = std::fs::read_to_string(path) { if let Ok(content) = std::fs::read_to_string(path) {
+2 -1
View File
@@ -140,7 +140,8 @@ impl McpTool for QueryGitDiffsHandler {
let mut results = Vec::new(); let mut results = Vec::new();
let cwd = env::current_dir().unwrap_or_default(); let cwd = env::current_dir().unwrap_or_default();
if let Ok(repo) = git2::Repository::discover(&cwd) if let Ok(repo) = git2::Repository::discover(&cwd)
&& let Ok(mut revwalk) = repo.revwalk() { && let Ok(mut revwalk) = repo.revwalk()
{
let _ = revwalk.push_head(); let _ = revwalk.push_head();
let mut count = 0; let mut count = 0;
for oid in revwalk.flatten() { for oid in revwalk.flatten() {
+7 -3
View File
@@ -63,7 +63,8 @@ impl<'a> GraphQueryBuilder<'a> {
} }
nodes_at_current_depth -= 1; nodes_at_current_depth -= 1;
if current_depth < self.max_depth if current_depth < self.max_depth
&& let Some(neighbors) = adj.get(current) { && let Some(neighbors) = adj.get(current)
{
for &(neighbor, rel_type, is_inverse) in neighbors { for &(neighbor, rel_type, is_inverse) in neighbors {
if !visited.contains(neighbor) { if !visited.contains(neighbor) {
visited.insert(neighbor); visited.insert(neighbor);
@@ -997,7 +998,8 @@ impl McpTool for GetSubgraphHandler {
while let Some((curr, d)) = queue.pop_front() { while let Some((curr, d)) = queue.pop_front() {
if d < depth if d < depth
&& let Some(neighbors) = adj.get(curr) { && let Some(neighbors) = adj.get(curr)
{
for &next in neighbors { for &next in neighbors {
if visited.insert(next.to_string()) { if visited.insert(next.to_string()) {
queue.push_back((next, d + 1)); queue.push_back((next, d + 1));
@@ -1176,7 +1178,9 @@ impl McpTool for ResolveStaleSymbolsHandler {
state.modify_graph(|g| { state.modify_graph(|g| {
for name in g.entities.keys() { for name in g.entities.keys() {
if let Some(target) = &req.target if let Some(target) = &req.target
&& name != target && !name.contains(target) { && name != target
&& !name.contains(target)
{
continue; continue;
} }
checked += 1; checked += 1;
+32 -18
View File
@@ -111,7 +111,8 @@ impl McpTool for SearchErrorFixesHandler {
score += 0.5; score += 0.5;
} }
if let Some(emb) = &f.embedding if let Some(emb) = &f.embedding
&& !query_emb.is_empty() { && !query_emb.is_empty()
{
score += crate::embedding::cosine_similarity(&query_emb, emb); score += crate::embedding::cosine_similarity(&query_emb, emb);
} }
(f, score) (f, score)
@@ -198,7 +199,8 @@ impl McpTool for LogCodeChangeHandler {
description = format!("{} [Line Range: {}]", description, range); description = format!("{} [Line Range: {}]", description, range);
} }
if let Some(symbols) = &req.symbol_references if let Some(symbols) = &req.symbol_references
&& !symbols.is_empty() { && !symbols.is_empty()
{
description = format!("{} [Symbols: {}]", description, symbols.join(", ")); description = format!("{} [Symbols: {}]", description, symbols.join(", "));
} }
@@ -244,9 +246,8 @@ impl McpTool for LogCodeChangeHandler {
let detected_vcs = if let Some(vcs) = req.vcs_type.clone() { let detected_vcs = if let Some(vcs) = req.vcs_type.clone() {
Some(vcs) Some(vcs)
} else if let Some(ref rev) = effective_rev { } else if let Some(ref rev) = effective_rev {
if rev.starts_with('r') && rev[1..].chars().all(|c| c.is_ascii_digit()) { if (rev.starts_with('r') && rev[1..].chars().all(|c| c.is_ascii_digit()))
Some("svn".to_string()) || req
} else if req
.repo_url .repo_url
.as_deref() .as_deref()
.map(|u| u.contains("/svn/")) .map(|u| u.contains("/svn/"))
@@ -337,7 +338,8 @@ impl McpTool for QueryRecentChangesHandler {
.rev() .rev()
.filter(|c| { .filter(|c| {
if let Some(ns) = &req.namespace if let Some(ns) = &req.namespace
&& !c.namespace.eq_ignore_ascii_case(ns) { && !c.namespace.eq_ignore_ascii_case(ns)
{
return false; return false;
} }
if let Some(repo) = &req.repo_name if let Some(repo) = &req.repo_name
@@ -349,7 +351,8 @@ impl McpTool for QueryRecentChangesHandler {
return false; return false;
} }
if let Some(vcs) = &req.vcs_type if let Some(vcs) = &req.vcs_type
&& !c.effective_vcs().eq_ignore_ascii_case(vcs) { && !c.effective_vcs().eq_ignore_ascii_case(vcs)
{
return false; return false;
} }
true true
@@ -464,7 +467,8 @@ impl McpTool for DecisionsHandler {
&& let Some(s_pos) = adrs && let Some(s_pos) = adrs
.iter() .iter()
.position(|a| a.id.eq_ignore_ascii_case(superseded_id)) .position(|a| a.id.eq_ignore_ascii_case(superseded_id))
&& s_pos != pos { && s_pos != pos
{
adrs[s_pos].status = "superseded".to_string(); adrs[s_pos].status = "superseded".to_string();
adrs_to_index.push(adrs[s_pos].clone()); adrs_to_index.push(adrs[s_pos].clone());
} }
@@ -1273,18 +1277,21 @@ impl McpTool for ManageCheckpointHandler {
} }
if let Ok(graph_content) = std::fs::read_to_string(target_dir.join("graph.json")) if let Ok(graph_content) = std::fs::read_to_string(target_dir.join("graph.json"))
&& let Ok(graph) = serde_json::from_str(&graph_content) { && let Ok(graph) = serde_json::from_str(&graph_content)
{
state.graph.modify(|g| *g = graph); state.graph.modify(|g| *g = graph);
} }
if let Ok(tasks_content) = std::fs::read_to_string(target_dir.join("tasks.json")) if let Ok(tasks_content) = std::fs::read_to_string(target_dir.join("tasks.json"))
&& let Ok(tasks) = serde_json::from_str(&tasks_content) { && let Ok(tasks) = serde_json::from_str(&tasks_content)
{
state.project.tasks.modify(|t| *t = tasks); state.project.tasks.modify(|t| *t = tasks);
} }
if let Ok(debts_content) = if let Ok(debts_content) =
std::fs::read_to_string(target_dir.join("tech_debts.json")) std::fs::read_to_string(target_dir.join("tech_debts.json"))
&& let Ok(debts) = serde_json::from_str(&debts_content) { && let Ok(debts) = serde_json::from_str(&debts_content)
{
state.code.tech_debts.modify(|d| *d = debts); state.code.tech_debts.modify(|d| *d = debts);
} }
@@ -1296,7 +1303,8 @@ impl McpTool for ManageCheckpointHandler {
if let Ok(entries) = std::fs::read_dir(&checkpoints_dir) { if let Ok(entries) = std::fs::read_dir(&checkpoints_dir) {
for entry in entries.flatten() { for entry in entries.flatten() {
if entry.path().is_dir() if entry.path().is_dir()
&& let Some(n) = entry.file_name().to_str() { && let Some(n) = entry.file_name().to_str()
{
list.push(serde_json::json!({"type": "checkpoint", "name": n})); list.push(serde_json::json!({"type": "checkpoint", "name": n}));
} }
} }
@@ -1467,7 +1475,8 @@ impl McpTool for GetNextActionableTasksHandler {
if let Some(branch) = &req.git_branch if let Some(branch) = &req.git_branch
&& let Some(tb) = &task.git_branch && let Some(tb) = &task.git_branch
&& tb != branch { && tb != branch
{
continue; continue;
} }
@@ -1541,7 +1550,8 @@ impl McpTool for HypothesesHandler {
.into_iter() .into_iter()
.filter(|h| { .filter(|h| {
if let Some(tid) = &req.task_id if let Some(tid) = &req.task_id
&& h.task_id.as_ref() != Some(tid) { && h.task_id.as_ref() != Some(tid)
{
return false; return false;
} }
if let Some(q) = &req.query { if let Some(q) = &req.query {
@@ -1725,20 +1735,24 @@ impl McpTool for AgentSignalsHandler {
.iter() .iter()
.filter(|s| { .filter(|s| {
if let Some(ttl) = s.ttl_seconds if let Some(ttl) = s.ttl_seconds
&& now > s.timestamp + ttl { && now > s.timestamp + ttl
{
return false; return false;
} }
if let Some(sender) = &req.sender if let Some(sender) = &req.sender
&& s.sender.to_lowercase() != sender.to_lowercase() { && s.sender.to_lowercase() != sender.to_lowercase()
{
return false; return false;
} }
if let Some(st) = &req.signal_type if let Some(st) = &req.signal_type
&& s.signal_type.to_lowercase() != st.to_lowercase() { && s.signal_type.to_lowercase() != st.to_lowercase()
{
return false; return false;
} }
true true
}) })
.take(req.limit.unwrap_or(20)).cloned() .take(req.limit.unwrap_or(20))
.cloned()
.collect::<Vec<_>>() .collect::<Vec<_>>()
}); });
+2 -1
View File
@@ -287,7 +287,8 @@ pub async fn reconcile_commit_or_code_change(
return true; return true;
} }
if let (Some(n1), Some(n2)) = (adr_numeric_id(&adr.id), adr_numeric_id(cand)) if let (Some(n1), Some(n2)) = (adr_numeric_id(&adr.id), adr_numeric_id(cand))
&& n1 == n2 { && n1 == n2
{
return true; return true;
} }
false false
+2 -2
View File
@@ -50,7 +50,6 @@ impl McpTool for TasksHandler {
priority: req.priority, priority: req.priority,
assigned_agent: req.assigned_agent, assigned_agent: req.assigned_agent,
verification_command: req.verification_command, verification_command: req.verification_command,
..Default::default()
}; };
let idx = state.get_search_index().await; let idx = state.get_search_index().await;
drop(idx.index_task(&task)); drop(idx.index_task(&task));
@@ -479,7 +478,8 @@ impl McpTool for MilestonesHandler {
m.status = status.clone(); m.status = status.clone();
if (status.eq_ignore_ascii_case("completed") if (status.eq_ignore_ascii_case("completed")
|| status.eq_ignore_ascii_case("done")) || status.eq_ignore_ascii_case("done"))
&& m.completed_at.is_none() { && m.completed_at.is_none()
{
m.completed_at = Some(crate::handlers::utils::now_secs()); m.completed_at = Some(crate::handlers::utils::now_secs());
} }
if let Some(task_ids) = &req.task_ids { if let Some(task_ids) = &req.task_ids {
+9 -12
View File
@@ -191,8 +191,7 @@ pub fn html_to_markdown(html: &str) -> String {
out.push_str("* "); out.push_str("* ");
} }
} }
"/li" "/li" if !in_cell => {
if !in_cell => {
out.push('\n'); out.push('\n');
} }
_ => {} _ => {}
@@ -510,7 +509,8 @@ pub async fn process_clipboard_snapshot(state: Arc<MemoryState>) {
.search_index .search_index
.read() .read()
.await .await
.index_clipboard_image(&doc_id, &path_str, text); .index_clipboard_image(&doc_id, &path_str, text)
.await;
} }
let cached = crate::state::CachedClipboardImage { let cached = crate::state::CachedClipboardImage {
@@ -567,7 +567,8 @@ pub async fn process_clipboard_snapshot(state: Arc<MemoryState>) {
let mut cache = state.clipboard_cache.write().await; let mut cache = state.clipboard_cache.write().await;
if let Some(ref prev) = cache.last_text if let Some(ref prev) = cache.last_text
&& prev.text == cached.text { && prev.text == cached.text
{
return; return;
} }
cache.last_text = Some(cached.clone()); cache.last_text = Some(cached.clone());
@@ -891,11 +892,9 @@ impl McpTool for ClipboardHandler {
} }
if let Some(eng) = engine if let Some(eng) = engine
&& let Some(ocr_text) = perform_ocrs_ocr(eng, &dynamic_img) { && let Some(ocr_text) = perform_ocrs_ocr(eng, &dynamic_img)
out.insert( {
"image_analysis".to_string(), out.insert("image_analysis".to_string(), json!(ocr_text.trim()));
json!(ocr_text.trim()),
);
} }
} }
Ok(out) Ok(out)
@@ -905,9 +904,7 @@ impl McpTool for ClipboardHandler {
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??; .map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
state.record_activity("clipboard", "Read contents from OS clipboard", None); state.record_activity("clipboard", "Read contents from OS clipboard", None);
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&Value::Object( Ok::<String, crate::error::AppError>(serde_yaml::to_string(&Value::Object(out))?)
out,
))?)
} }
ClipboardAction::Write => { ClipboardAction::Write => {
let text_opt = req.text; let text_opt = req.text;
+2 -2
View File
@@ -163,7 +163,7 @@ fn extract_chunks_with_parent(
node: Node, node: Node,
code: &str, code: &str,
chunks: &mut Vec<(String, String, String)>, chunks: &mut Vec<(String, String, String)>,
ext: &str, _ext: &str,
parent_scope: Option<&str>, parent_scope: Option<&str>,
depth: usize, depth: usize,
) { ) {
@@ -229,7 +229,7 @@ fn extract_chunks_with_parent(
} else { } else {
let mut cursor = node.walk(); let mut cursor = node.walk();
for child in node.named_children(&mut cursor) { 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);
} }
} }
} }
+12 -8
View File
@@ -107,7 +107,8 @@ pub async fn ttl_sweeper_worker(state: Arc<MemoryState>) {
state.project.tasks.read_with(|tasks| { state.project.tasks.read_with(|tasks| {
for t in tasks.iter() { for t in tasks.iter() {
if let Some(exp) = t.expires_at if let Some(exp) = t.expires_at
&& t.is_active() { && t.is_active()
{
next_expiry = Some(next_expiry.map_or(exp, |curr| curr.min(exp))); next_expiry = Some(next_expiry.map_or(exp, |curr| curr.min(exp)));
} }
} }
@@ -140,7 +141,7 @@ pub async fn ttl_sweeper_worker(state: Arc<MemoryState>) {
let sleep_duration = match next_expiry { let sleep_duration = match next_expiry {
Some(exp) if exp > now => { Some(exp) if exp > now => {
let diff = 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), Some(_) => std::time::Duration::from_millis(50),
None => std::time::Duration::from_secs(60), None => std::time::Duration::from_secs(60),
@@ -161,7 +162,9 @@ pub async fn ttl_sweeper_worker(state: Arc<MemoryState>) {
state.project.tasks.modify(|tasks| { state.project.tasks.modify(|tasks| {
for t in tasks.iter_mut() { for t in tasks.iter_mut() {
if let Some(exp) = t.expires_at if let Some(exp) = t.expires_at
&& exp <= now && t.is_active() { && exp <= now
&& t.is_active()
{
t.status = "expired".to_string(); t.status = "expired".to_string();
t.updated_at = now; t.updated_at = now;
expired_tasks.push(t.id.clone()); expired_tasks.push(t.id.clone());
@@ -249,7 +252,8 @@ pub async fn condense_graph_worker(state: Arc<MemoryState>) {
}); });
if let Some((content, names)) = snippet_condensation if let Some((content, names)) = snippet_condensation
&& !content.is_empty() { && !content.is_empty()
{
let name = format!("Snippet History {}", now); let name = format!("Snippet History {}", now);
state.modify_graph(|graph| { state.modify_graph(|graph| {
graph.entities.insert( graph.entities.insert(
@@ -319,7 +323,8 @@ pub async fn memory_consolidation_worker(state: Arc<MemoryState>) {
.trim_end_matches("```") .trim_end_matches("```")
.trim(); .trim();
if let Ok(duplicates) = serde_json::from_str::<Vec<String>>(cleaned) if let Ok(duplicates) = serde_json::from_str::<Vec<String>>(cleaned)
&& duplicates.len() == 2 { && duplicates.len() == 2
{
let e1_name = &duplicates[0]; let e1_name = &duplicates[0];
let e2_name = &duplicates[1]; let e2_name = &duplicates[1];
@@ -466,8 +471,8 @@ pub async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::erro
event.payload.get("action").and_then(|a| a.as_str()), event.payload.get("action").and_then(|a| a.as_str()),
event.payload.get("target").and_then(|t| t.as_str()), event.payload.get("target").and_then(|t| t.as_str()),
event.payload.get("status").and_then(|s| s.as_str()), event.payload.get("status").and_then(|s| s.as_str()),
) { )
if (status == "authorized" || status == "blocked") && (status == "authorized" || status == "blocked")
&& let Some(addr) = subscribers.remove(&(action.to_string(), target.to_string())) { && let Some(addr) = subscribers.remove(&(action.to_string(), target.to_string())) {
let response = if status == "authorized" { b"APPROVED" } else { b"REJECTED" }; let response = if status == "authorized" { b"APPROVED" } else { b"REJECTED" };
let _ = socket.send_to(response, addr).await; let _ = socket.send_to(response, addr).await;
@@ -476,7 +481,6 @@ pub async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::erro
} }
} }
} }
}
}); });
let nvim_udp_state = Arc::clone(&app_state); let nvim_udp_state = Arc::clone(&app_state);
+5 -3
View File
@@ -13,7 +13,6 @@ pub enum ChangeKind {
Renamed, Renamed,
} }
#[derive(Debug, Clone, Serialize, Deserialize, Default)] #[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CodeChange { pub struct CodeChange {
pub timestamp: u64, pub timestamp: u64,
@@ -55,7 +54,9 @@ impl CodeChange {
return vcs.as_str(); return vcs.as_str();
} }
if let Some(rev) = self.revision.as_deref().or(self.git_commit.as_deref()) if let Some(rev) = self.revision.as_deref().or(self.git_commit.as_deref())
&& rev.starts_with('r') && rev[1..].chars().all(|c| c.is_ascii_digit()) { && rev.starts_with('r')
&& rev[1..].chars().all(|c| c.is_ascii_digit())
{
return "svn"; return "svn";
} }
if let Some(br) = self.branch.as_deref().or(self.git_branch.as_deref()) if let Some(br) = self.branch.as_deref().or(self.git_branch.as_deref())
@@ -262,7 +263,8 @@ impl KnowledgeGraph {
HashMap::with_capacity(self.relations.len() * 2); HashMap::with_capacity(self.relations.len() * 2);
for rel in &self.relations { for rel in &self.relations {
if let Some(rf) = relation_filter if let Some(rf) = relation_filter
&& rel.relation_type != rf { && rel.relation_type != rf
{
continue; continue;
} }
adj.entry(rel.from.as_str()).or_default().push(( adj.entry(rel.from.as_str()).or_default().push((
+2 -1
View File
@@ -552,7 +552,8 @@ impl SearchService {
self.state.read_graph(|graph| { self.state.read_graph(|graph| {
for entity in graph.entities.values() { for entity in graph.entities.values() {
if let Some(ns) = filter_namespace if let Some(ns) = filter_namespace
&& entity.namespace != ns { && entity.namespace != ns
{
continue; continue;
} }
let obs = entity.observations.join("; "); let obs = entity.observations.join("; ");
+3 -3
View File
@@ -87,7 +87,8 @@ impl ClipboardCacheState {
pub fn push_text(&mut self, text: CachedClipboardText) { pub fn push_text(&mut self, text: CachedClipboardText) {
if let Some(ref prev) = self.last_text if let Some(ref prev) = self.last_text
&& prev.text == text.text { && prev.text == text.text
{
return; return;
} }
self.last_text = Some(text.clone()); self.last_text = Some(text.clone());
@@ -141,8 +142,7 @@ impl MemoryState {
pub fn new(base_dir_str: &str) -> Self { pub fn new(base_dir_str: &str) -> Self {
let is_in_memory = base_dir_str == ":memory:"; let is_in_memory = base_dir_str == ":memory:";
let base = std::path::PathBuf::from(base_dir_str); let base = std::path::PathBuf::from(base_dir_str);
if !is_in_memory if !is_in_memory && let Err(e) = std::fs::create_dir_all(&base) {
&& let Err(e) = std::fs::create_dir_all(&base) {
tracing::error!("Failed to create store directory at {:?}: {}", base, e); tracing::error!("Failed to create store directory at {:?}: {}", base, e);
} }
+4 -1
View File
@@ -34,7 +34,9 @@ static QUEUE_REGISTRY: std::sync::Mutex<Option<(Arc<Database>, DbWriteQueue)>> =
fn get_or_create_queue(db: Arc<Database>) -> DbWriteQueue { fn get_or_create_queue(db: Arc<Database>) -> DbWriteQueue {
let mut reg = QUEUE_REGISTRY.lock().unwrap_or_else(|e| e.into_inner()); let mut reg = QUEUE_REGISTRY.lock().unwrap_or_else(|e| e.into_inner());
if let Some((ref existing_db, ref queue)) = *reg if let Some((ref existing_db, ref queue)) = *reg
&& Arc::ptr_eq(existing_db, &db) && !queue.tx.is_closed() { && Arc::ptr_eq(existing_db, &db)
&& !queue.tx.is_closed()
{
return queue.clone(); return queue.clone();
} }
let new_queue = DbWriteQueue::new(db.clone()); let new_queue = DbWriteQueue::new(db.clone());
@@ -458,6 +460,7 @@ impl<T: DeserializeOwned + Default + Serialize + Send + Sync + 'static> Store<T>
} }
} }
#[allow(clippy::type_complexity)]
fn prepare_batch( fn prepare_batch(
&self, &self,
new_snapshot: &T, new_snapshot: &T,
+7
View File
@@ -612,6 +612,7 @@ pub enum HandoffMemoAction {
/// - 'leave': Post a handoff memo. Required: content. Optional: namespace. /// - 'leave': Post a handoff memo. Required: content. Optional: namespace.
/// - 'read': Inspect active memos. Optional: namespace. /// - 'read': Inspect active memos. Optional: namespace.
/// - 'clear': Clear memos. Optional: namespace, ids. /// - 'clear': Clear memos. Optional: namespace, ids.
///
/// Next steps on error: Check parameter requirements for 'leave' or 'clear' actions. /// Next steps on error: Check parameter requirements for 'leave' or 'clear' actions.
#[derive(Debug, Deserialize, Serialize, JsonSchema)] #[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct HandoffMemosTool { pub struct HandoffMemosTool {
@@ -655,6 +656,7 @@ pub enum TaskAction {
/// - 'list': List active tasks. Optional: git_branch, summary_level ('compact'|'detailed'|'full'), max_tokens. /// - '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). /// - 'set_criteria': Set acceptance criteria. Required: id, criteria (array of strings).
/// - 'verify': Verify criteria met. Required: id. /// - 'verify': Verify criteria met. Required: id.
///
/// Next steps on error: Check required parameters or call list to verify task IDs. /// Next steps on error: Check required parameters or call list to verify task IDs.
#[derive(Debug, Deserialize, Serialize, JsonSchema)] #[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct TasksTool { pub struct TasksTool {
@@ -719,6 +721,7 @@ pub enum MilestoneAction {
/// - 'add': Create milestone. Required: title. Optional: namespace. /// - 'add': Create milestone. Required: title. Optional: namespace.
/// - 'update': Update milestone status. Required: id, status. /// - 'update': Update milestone status. Required: id, status.
/// - 'list': List milestones. Optional: namespace. /// - 'list': List milestones. Optional: namespace.
///
/// Next steps on error: Provide required title for 'add' or id/status for 'update'. /// Next steps on error: Provide required title for 'add' or id/status for 'update'.
#[derive(Debug, Deserialize, Serialize, JsonSchema)] #[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct MilestonesTool { pub struct MilestonesTool {
@@ -765,6 +768,7 @@ pub enum SnippetAction {
/// - 'search': Search snippets. Optional: query, tags, hybrid (boolean for BM25+vector search). /// - 'search': Search snippets. Optional: query, tags, hybrid (boolean for BM25+vector search).
/// - 'delete': Delete snippet. Required: id (or query) as snippet name. /// - 'delete': Delete snippet. Required: id (or query) as snippet name.
/// - 'tag': Tag snippet. Required: id (or query), tags (array of strings). /// - 'tag': Tag snippet. Required: id (or query), tags (array of strings).
///
/// Next steps on error: Ensure snippet name/query or id is provided. /// Next steps on error: Ensure snippet name/query or id is provided.
#[derive(Debug, Deserialize, Serialize, JsonSchema)] #[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct SnippetsTool { pub struct SnippetsTool {
@@ -815,6 +819,7 @@ pub enum DecisionAction {
/// - 'query': Search ADRs. Optional: query, namespace. /// - '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. /// - '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. /// - 'delete': Remove ADR. Required: id.
///
/// Next steps on error: Provide title for 'log' or id for 'update'/'delete'. /// Next steps on error: Provide title for 'log' or id for 'update'/'delete'.
#[derive(Deserialize, Serialize, JsonSchema, Debug, Clone)] #[derive(Deserialize, Serialize, JsonSchema, Debug, Clone)]
pub struct DecisionsTool { 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. /// - '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. /// - 'resolve': Mark tech debt resolved. Required: id.
/// - 'list': List tech debt items. Optional: include_resolved, namespace. /// - 'list': List tech debt items. Optional: include_resolved, namespace.
///
/// Next steps on error: Provide description for 'log' or valid ID for 'resolve'. /// Next steps on error: Provide description for 'log' or valid ID for 'resolve'.
#[derive(Debug, Deserialize, Serialize, JsonSchema)] #[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct TechDebtTool { pub struct TechDebtTool {
@@ -963,6 +969,7 @@ pub enum EnvAction {
/// - 'log_requirement': Log environment variable requirement. Required: key. Optional: description, is_secret, namespace. /// - '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. /// - 'register': Register remote target environment. Required: name. Optional: url, description, requires_vpn, namespace.
/// - 'get_details': Get full environment details. Optional: namespace. /// - 'get_details': Get full environment details. Optional: namespace.
///
/// Next steps on error: Provide key for 'log_requirement' or name for 'register'. /// Next steps on error: Provide key for 'log_requirement' or name for 'register'.
#[derive(Debug, Deserialize, Serialize, JsonSchema)] #[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct EnvironmentTool { pub struct EnvironmentTool {
+8 -11
View File
@@ -105,7 +105,8 @@ async fn trigger_autonomous_review(path: &Path, state: Arc<MemoryState>) {
// ADR-0109: Incremental Background AST Indexing & Differential Graph Updates // ADR-0109: Incremental Background AST Indexing & Differential Graph Updates
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or(""); let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
if matches!(ext, "rs" | "ts" | "js" | "py" | "go" | "java" | "c" | "cpp") if matches!(ext, "rs" | "ts" | "js" | "py" | "go" | "java" | "c" | "cpp")
&& let Ok(content) = std::fs::read_to_string(path) { && let Ok(content) = std::fs::read_to_string(path)
{
let language = match ext { let language = match ext {
"rs" => Some(tree_sitter_rust::LANGUAGE), "rs" => Some(tree_sitter_rust::LANGUAGE),
"ts" | "js" => Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT), "ts" | "js" => Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT),
@@ -120,14 +121,10 @@ async fn trigger_autonomous_review(path: &Path, state: Arc<MemoryState>) {
if let Some(lang) = language { if let Some(lang) = language {
let mut parser = tree_sitter::Parser::new(); let mut parser = tree_sitter::Parser::new();
if parser.set_language(&lang.into()).is_ok() if parser.set_language(&lang.into()).is_ok()
&& let Some(tree) = parser.parse(&content, None) { && let Some(tree) = parser.parse(&content, None)
{
let mut chunks = Vec::new(); let mut chunks = Vec::new();
crate::indexer::extract_chunks( crate::indexer::extract_chunks(tree.root_node(), &content, &mut chunks, ext);
tree.root_node(),
&content,
&mut chunks,
ext,
);
let file_str = path.to_string_lossy().to_string(); let file_str = path.to_string_lossy().to_string();
let now = std::time::SystemTime::now() let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
@@ -138,8 +135,9 @@ async fn trigger_autonomous_review(path: &Path, state: Arc<MemoryState>) {
let file_str_clone = file_str.clone(); let file_str_clone = file_str.clone();
state.modify_graph(|g| { state.modify_graph(|g| {
// Ensure File entity exists // Ensure File entity exists
g.entities.entry(file_str.clone()).or_insert_with(|| { g.entities
crate::models::Entity { .entry(file_str.clone())
.or_insert_with(|| crate::models::Entity {
name: file_str.clone(), name: file_str.clone(),
entity_type: "File".to_string(), entity_type: "File".to_string(),
namespace: "global".to_string(), namespace: "global".to_string(),
@@ -147,7 +145,6 @@ async fn trigger_autonomous_review(path: &Path, state: Arc<MemoryState>) {
created_at: Some(now), created_at: Some(now),
updated_at: Some(now), updated_at: Some(now),
..Default::default() ..Default::default()
}
}); });
for (chunk_name, chunk_code, chunk_desc) in chunks { for (chunk_name, chunk_code, chunk_desc) in chunks {