diff --git a/bin_replace.pdb b/bin_replace.pdb new file mode 100644 index 0000000..5bc2bb2 Binary files /dev/null and b/bin_replace.pdb differ diff --git a/server/src/handlers_v2/env.rs b/server/src/handlers_v2/env.rs index 20e232b..944ca24 100644 --- a/server/src/handlers_v2/env.rs +++ b/server/src/handlers_v2/env.rs @@ -155,9 +155,12 @@ impl McpTool for GetEnvironmentDetailsHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: GetEnvironmentDetailsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut envs = state.environments.read(); - envs.retain(|e| e.namespace == req.namespace); - let data = serde_json::to_string(&envs).unwrap_or_default(); + let data = state.environments.read_with(|envs| { + let filtered: Vec<_> = envs.iter().filter(|e| e.namespace == req.namespace).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } + + diff --git a/server/src/handlers_v2/meta.rs b/server/src/handlers_v2/meta.rs index 91b4606..88135f7 100644 --- a/server/src/handlers_v2/meta.rs +++ b/server/src/handlers_v2/meta.rs @@ -65,16 +65,19 @@ impl McpTool for QueryDecisionsHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: QueryDecisionsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut adrs = state.adrs.read(); - if let Some(q) = req.query { - let q = q.to_lowercase(); - adrs.retain(|a| { - contains_ignore_ascii_case(&a.title, &q) - || contains_ignore_ascii_case(&a.context, &q) - || contains_ignore_ascii_case(&a.decision, &q) - }); - } - let data = serde_json::to_string(&adrs).unwrap_or_default(); + let data = state.adrs.read_with(|adrs| { + let filtered: Vec<_> = adrs.iter().filter(|a| { + if let Some(q) = &req.query { + let q = q.to_lowercase(); + contains_ignore_ascii_case(&a.title, &q) + || contains_ignore_ascii_case(&a.context, &q) + || contains_ignore_ascii_case(&a.decision, &q) + } else { + true + } + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -127,12 +130,13 @@ impl McpTool for SearchErrorFixesHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: SearchErrorFixesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let q = req.query.to_lowercase(); - let mut fixes = state.error_fixes.read(); - fixes.retain(|f| { - contains_ignore_ascii_case(&f.signature, &q) - || contains_ignore_ascii_case(&f.solution, &q) + let data = state.error_fixes.read_with(|fixes| { + let filtered: Vec<_> = fixes.iter().filter(|f| { + contains_ignore_ascii_case(&f.signature, &q) + || contains_ignore_ascii_case(&f.solution, &q) + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() }); - let data = serde_json::to_string(&fixes).unwrap_or_default(); Ok(data.to_string()) } } @@ -183,7 +187,7 @@ impl McpTool for QueryRecentChangesHandler { } async fn execute(&self, _args: Value, state: Arc) -> Result { - let data = serde_json::to_string(&state.ledger.read()).unwrap_or_else(|_| "[]".to_string()); + let data = state.ledger.read_with(|l| serde_json::to_string(l).unwrap_or_else(|_| "[]".to_string())); Ok(data.to_string()) } } @@ -232,8 +236,7 @@ impl McpTool for ReadPreferencesHandler { } async fn execute(&self, _args: Value, state: Arc) -> Result { - let prefs = state.prefs.read(); - let data = serde_json::to_string(&prefs).unwrap_or_default(); + let data = state.prefs.read_with(|prefs| serde_json::to_string(prefs).unwrap_or_default()); Ok(data.to_string()) } } @@ -320,9 +323,12 @@ impl McpTool for ListTechDebtHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: ListTechDebtTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut debts = state.tech_debts.read(); - debts.retain(|d| d.namespace == req.namespace && (req.include_resolved || !d.is_resolved)); - let data = serde_json::to_string(&debts).unwrap_or_default(); + let data = state.tech_debts.read_with(|debts| { + let filtered: Vec<_> = debts.iter().filter(|d| { + d.namespace == req.namespace && (req.include_resolved || !d.is_resolved) + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -490,3 +496,5 @@ impl McpTool for GetProjectHealthHandler { } use crate::handlers_v2::utils::*; + + diff --git a/server/src/handlers_v2/notes.rs b/server/src/handlers_v2/notes.rs index c35764d..ab1d350 100644 --- a/server/src/handlers_v2/notes.rs +++ b/server/src/handlers_v2/notes.rs @@ -51,7 +51,7 @@ impl McpTool for ReadStickyNotesHandler { } async fn execute(&self, _args: Value, state: Arc) -> Result { - let data = serde_json::to_string(&state.sticky.read()).unwrap_or_else(|_| "[]".to_string()); + let data = state.sticky.read_with(|s| serde_json::to_string(s).unwrap_or_else(|_| "[]".to_string())); Ok(data.to_string()) } } @@ -161,11 +161,16 @@ impl McpTool for ReadHandoffMemosHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: ReadHandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut items = state.handoff_memos.read(); - if let Some(ns) = req.namespace { - items.retain(|i| i.namespace == ns); - } - let data = serde_json::to_string(&items).unwrap_or_default(); + let data = state.handoff_memos.read_with(|items| { + let filtered: Vec<_> = items.iter().filter(|i| { + if let Some(ns) = &req.namespace { + &i.namespace == ns + } else { + true + } + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -271,3 +276,4 @@ impl McpTool for GenerateStandupReportHandler { Ok(report.to_string()) } } + diff --git a/server/src/handlers_v2/tasks.rs b/server/src/handlers_v2/tasks.rs index 8f62c6d..eefd884 100644 --- a/server/src/handlers_v2/tasks.rs +++ b/server/src/handlers_v2/tasks.rs @@ -263,15 +263,18 @@ impl McpTool for ListActiveTasksHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: ListActiveTasksTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut tasks = state.tasks.read(); - tasks.retain(|t| t.status != "done"); - if let Some(branch) = req.git_branch { - tasks.retain(|t| { - t.git_branch.is_none() || t.git_branch.as_deref() == Some(branch.as_str()) - }); - } - let data = serde_json::to_string(&tasks).unwrap_or_default(); - Ok(data.to_string()) + let data = state.tasks.read_with(|tasks| { + let filtered: Vec<_> = tasks.iter().filter(|t| { + let status_match = t.status != "done"; + let branch_match = match &req.git_branch { + Some(branch) => t.git_branch.is_none() || t.git_branch.as_deref() == Some(branch.as_str()), + None => true, + }; + status_match && branch_match + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); + Ok(data) } } @@ -313,7 +316,7 @@ impl McpTool for SetAcceptanceCriteriaHandler { } }); if success { - Ok(vec!["Acceptance criteria set successfully.".to_string()][0].clone()) + Ok("Acceptance criteria set successfully.".to_string()) } else { Ok("Task not found.".to_string()) } @@ -360,15 +363,14 @@ impl McpTool for VerifyAcceptanceCriteriaHandler { } }); if success { - Ok(vec![format!( + Ok(format!( "Acceptance criteria verified with proof: {}", req.proof - )][0] - .clone()) + )) } else if already_met { Ok("Acceptance criteria was already met.".to_string()) } else { - Ok(vec!["Acceptance criteria or task not found.".to_string()][0].clone()) + Ok("Acceptance criteria or task not found.".to_string()) } } } @@ -446,11 +448,16 @@ impl McpTool for ListMilestonesHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: ListMilestonesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut items = state.milestones.read(); - if let Some(ns) = req.namespace { - items.retain(|i| i.namespace == ns); - } - let data = serde_json::to_string(&items).unwrap_or_default(); - Ok(data.to_string()) + let data = state.milestones.read_with(|items| { + let filtered: Vec<_> = items.iter().filter(|i| { + if let Some(ns) = &req.namespace { + &i.namespace == ns + } else { + true + } + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); + Ok(data) } } diff --git a/server/src/handlers_v2/workspaces.rs b/server/src/handlers_v2/workspaces.rs index e5976f6..66baf12 100644 --- a/server/src/handlers_v2/workspaces.rs +++ b/server/src/handlers_v2/workspaces.rs @@ -75,16 +75,20 @@ impl McpTool for ListPinnedFilesHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: ListPinnedFilesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut pinned = state.pinned_files.read(); - if let Some(ns) = req.namespace { - pinned.retain(|p| p.namespace == ns); - } - if let Some(branch) = req.git_branch { - pinned.retain(|p| { - p.git_branch.is_none() || p.git_branch.as_deref() == Some(branch.as_str()) - }); - } - let data = serde_json::to_string(&pinned).unwrap_or_default(); + let data = state.pinned_files.read_with(|pinned| { + let filtered: Vec<_> = pinned.iter().filter(|p| { + let ns_match = match &req.namespace { + Some(ns) => &p.namespace == ns, + None => true, + }; + let branch_match = match &req.git_branch { + Some(branch) => p.git_branch.is_none() || p.git_branch.as_deref() == Some(branch.as_str()), + None => true, + }; + ns_match && branch_match + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -239,9 +243,12 @@ impl McpTool for LoadContextWorkspaceHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: LoadContextWorkspaceTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut ws = state.context_workspaces.read(); - ws.retain(|w| w.namespace == req.namespace && w.name == req.name); - let data = serde_json::to_string(&ws.first()).unwrap_or_default(); + let data = state.context_workspaces.read_with(|ws| { + let filtered: Vec<_> = ws.iter().filter(|w| { + w.namespace == req.namespace && w.name == req.name + }).collect(); + serde_json::to_string(&filtered.first()).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -264,9 +271,12 @@ impl McpTool for ListContextWorkspacesHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: ListContextWorkspacesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut ws = state.context_workspaces.read(); - ws.retain(|w| w.namespace == req.namespace); - let data = serde_json::to_string(&ws).unwrap_or_default(); + let data = state.context_workspaces.read_with(|ws| { + let filtered: Vec<_> = ws.iter().filter(|w| { + w.namespace == req.namespace + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -314,9 +324,12 @@ impl McpTool for GetPrChecklistHandler { async fn execute(&self, args: Value, state: Arc) -> Result { let req: GetPrChecklistTool = serde_json::from_value(args).map_err(|e| e.to_string())?; - let mut items = state.pr_checklists.read(); - items.retain(|i| i.namespace == req.namespace); - let data = serde_json::to_string(&items).unwrap_or_default(); + let data = state.pr_checklists.read_with(|items| { + let filtered: Vec<_> = items.iter().filter(|i| { + i.namespace == req.namespace + }).collect(); + serde_json::to_string(&filtered).unwrap_or_default() + }); Ok(data.to_string()) } } @@ -346,3 +359,5 @@ impl McpTool for ClearPrChecklistHandler { } use crate::handlers_v2::utils::*; + +