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
21 files changed
+420 -369

No files matched your search

+12 -12
View File
@@ -68,18 +68,18 @@ pub async fn handle_socket(socket: WebSocket, state: Arc<AppState>, _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::<serde_json::Value>(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::<serde_json::Value>(details_str)
{
return Some(
serde_json::json!({
"jsonrpc": "2.0",
"method": "notifications/task/completed",
"params": event_val
})
.to_string(),
);
}
None
})
.take(5)
+10 -8
View File
@@ -44,10 +44,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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);
}
}
}
+6 -5
View File
@@ -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);
}
}
}
}
+8 -8
View File
@@ -168,20 +168,20 @@ pub fn init_redb(base: &Path) -> Arc<Database> {
} 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!(
+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_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];
+8 -6
View File
@@ -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 {
+19 -18
View File
@@ -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
+20 -16
View File
@@ -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<String, crate::models::Entity> = 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('.'))
+68 -54
View File
@@ -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::<Vec<_>>()
});
+9 -8
View File
@@ -245,11 +245,11 @@ pub fn recalculate_milestones(state: &MemoryState) -> Vec<String> {
&& (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
});
+4 -4
View File
@@ -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 {
+14 -17
View File
@@ -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<MemoryState>) {
.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<MemoryState>) {
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::<String, crate::error::AppError>(serde_yaml::to_string(&Value::Object(
out,
))?)
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&Value::Object(out))?)
}
ClipboardAction::Write => {
let text_opt = req.text;
+2 -2
View File
@@ -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);
}
}
}
+62 -58
View File
@@ -107,9 +107,10 @@ pub async fn ttl_sweeper_worker(state: Arc<MemoryState>) {
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<MemoryState>) {
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<MemoryState>) {
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<MemoryState>) {
});
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<String> = 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<String> = 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<MemoryState>) {
.trim_end_matches("```")
.trim();
if let Ok(duplicates) = serde_json::from_str::<Vec<String>>(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<MemoryState>) -> Result<(), Box<dyn std::erro
event.payload.get("action").and_then(|a| a.as_str()),
event.payload.get("target").and_then(|t| t.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 response = if status == "authorized" { b"APPROVED" } else { b"REJECTED" };
let _ = socket.send_to(response, addr).await;
}
}
}
}
}
+12 -10
View File
@@ -13,7 +13,6 @@ pub enum ChangeKind {
Renamed,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CodeChange {
pub timestamp: u64,
@@ -55,16 +54,18 @@ impl CodeChange {
return vcs.as_str();
}
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()) {
return "svn";
}
&& rev.starts_with('r')
&& rev[1..].chars().all(|c| c.is_ascii_digit())
{
return "svn";
}
if let Some(br) = self.branch.as_deref().or(self.git_branch.as_deref())
&& (br.eq_ignore_ascii_case("trunk")
|| br.starts_with("branches/")
|| br.starts_with("tags/"))
{
return "svn";
}
{
return "svn";
}
"git"
}
@@ -262,9 +263,10 @@ impl KnowledgeGraph {
HashMap::with_capacity(self.relations.len() * 2);
for rel in &self.relations {
if let Some(rf) = relation_filter
&& rel.relation_type != rf {
continue;
}
&& rel.relation_type != rf
{
continue;
}
adj.entry(rel.from.as_str()).or_default().push((
rel.to.as_str(),
rel.relation_type.as_str(),
+4 -3
View File
@@ -552,9 +552,10 @@ impl SearchService {
self.state.read_graph(|graph| {
for entity in graph.entities.values() {
if let Some(ns) = filter_namespace
&& entity.namespace != ns {
continue;
}
&& entity.namespace != ns
{
continue;
}
let obs = entity.observations.join("; ");
let desc = format!("{}: {}", entity.entity_type, obs);
if let Some(ref emb) = entity.embedding {
+7 -7
View File
@@ -87,9 +87,10 @@ impl ClipboardCacheState {
pub fn push_text(&mut self, text: CachedClipboardText) {
if let Some(ref prev) = self.last_text
&& prev.text == text.text {
return;
}
&& prev.text == text.text
{
return;
}
self.last_text = Some(text.clone());
self.history.push_front(ClipboardHistoryItem::Text(text));
if self.history.len() > 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);
+6 -3
View File
@@ -34,9 +34,11 @@ static QUEUE_REGISTRY: std::sync::Mutex<Option<(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());
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<T: DeserializeOwned + Default + Serialize + Send + Sync + 'static> Store<T>
}
}
#[allow(clippy::type_complexity)]
fn prepare_batch(
&self,
new_snapshot: &T,
+7
View File
@@ -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 {
+94 -97
View File
@@ -105,109 +105,106 @@ async fn trigger_autonomous_review(path: &Path, state: Arc<MemoryState>) {
// 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 {:?}",