feat(mcp): enhance MCP server registration with error handling and improve transport process management
refactor: update various tools for better error handling and path resolution fix: improve markdown rendering and input display in TUI
This commit is contained in:
@@ -70,7 +70,8 @@ impl Tool for PlanReady {
|
||||
if std::fs::create_dir_all(&plan_dir).is_ok() {
|
||||
let filename = format!("plan-{}.md", chrono::Utc::now().format("%Y%m%d_%H%M%S"));
|
||||
let path = plan_dir.join(&filename);
|
||||
let _ = std::fs::write(&path, &plan_content);
|
||||
std::fs::write(&path, &plan_content)
|
||||
.map_err(|e| anyhow::anyhow!("failed to save plan: {e}"))?;
|
||||
Ok(format!("Plan saved to {filename}. Starting execution."))
|
||||
} else {
|
||||
Ok("Plan is ready. Starting execution.".to_string())
|
||||
|
||||
@@ -55,7 +55,14 @@ impl Tool for Grep {
|
||||
}
|
||||
if let Ok(content) = fs::read_to_string(file_path) {
|
||||
for (i, line) in content.lines().enumerate() {
|
||||
if line.contains(&pattern) {
|
||||
let is_match = if let Ok(re) = regex::Regex::new(&pattern) {
|
||||
re.is_match(line)
|
||||
} else {
|
||||
// Fall back to literal substring search when the
|
||||
// pattern is not a valid regex.
|
||||
line.contains(&pattern)
|
||||
};
|
||||
if is_match {
|
||||
let rel_path = file_path
|
||||
.strip_prefix(&path)
|
||||
.unwrap_or(file_path)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Change the working directory for subsequent commands.
|
||||
|
||||
use crate::tools::{Tool, ToolCtx};
|
||||
use crate::tools::{resolve_path, Tool, ToolCtx};
|
||||
use anyhow::Result;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
@@ -28,9 +28,10 @@ impl Tool for Cd {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||||
fn run(&self, ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||||
let dir = crate::tools::arg_str(args, "directory")?;
|
||||
std::env::set_current_dir(&dir)?;
|
||||
Ok(format!("Changed directory to '{dir}'"))
|
||||
let resolved = resolve_path(&ctx.workspaces, &dir)?;
|
||||
std::env::set_current_dir(&resolved)?;
|
||||
Ok(format!("Changed directory to '{}'", resolved.display()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//! Update the shared directory cache.
|
||||
//! Update the shared directory cache by resolving each path against
|
||||
//! workspaces and storing the resolved paths in `ctx.dir_cache`.
|
||||
|
||||
use crate::tools::ToolCtx;
|
||||
use crate::tools::{resolve_path, ToolCtx};
|
||||
use anyhow::Result;
|
||||
use serde_json::{json, Value};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct DirCacheUpdate;
|
||||
|
||||
@@ -28,7 +30,7 @@ impl crate::tools::Tool for DirCacheUpdate {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||||
fn run(&self, ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||||
let paths: Vec<String> = args
|
||||
.get("paths")
|
||||
.and_then(|v| v.as_array())
|
||||
@@ -39,7 +41,19 @@ impl crate::tools::Tool for DirCacheUpdate {
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let count = paths.len();
|
||||
let resolved: Vec<PathBuf> = paths
|
||||
.iter()
|
||||
.map(|p| resolve_path(&ctx.workspaces, p))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let count = resolved.len();
|
||||
|
||||
// Persist the resolved paths into the shared DirCache so the TUI
|
||||
// and other tools can read the cached listing without re-scanning.
|
||||
let dc = ctx.dir_cache.clone();
|
||||
let rt = tokio::runtime::Runtime::new()?;
|
||||
rt.block_on(async { dc.write().await.set(resolved).await });
|
||||
|
||||
Ok(format!("Directory cache updated with {} entries", count))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ use crate::tools::{arg_str, Tool, ToolCtx};
|
||||
use crate::workflow::engine::execution::execute_workflow;
|
||||
use crate::workflow::hive_mind::cycle::execute_cycle;
|
||||
use crate::workflow::hive_mind::synthesis::synthesize_consensus;
|
||||
use crate::workflow::hive_mind::types::{CognitiveCycle, NodeOutput};
|
||||
use crate::workflow::hive_mind::types::{
|
||||
CognitiveCycle, NodeDirective, NodeOutput,
|
||||
};
|
||||
use crate::workflow::script::WorkflowScript;
|
||||
|
||||
/// Execute a multi-step workflow defined in YAML.
|
||||
@@ -102,10 +104,16 @@ impl Tool for NoteFinding {
|
||||
|
||||
fn run(&self, ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||||
let finding = crate::tools::arg_str(args, "finding")?;
|
||||
let category = args
|
||||
.get("category")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("general");
|
||||
|
||||
let tagged = format!("[{category}] {finding}");
|
||||
|
||||
if let Some(ref findings) = ctx.workflow_findings {
|
||||
if let Ok(mut guard) = findings.lock() {
|
||||
guard.push(finding.clone());
|
||||
guard.push(tagged);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,13 +213,24 @@ impl Tool for HiveMind {
|
||||
let mut all_node_outputs = Vec::new();
|
||||
|
||||
for (cycle_idx, cycle_val) in cycles_val.iter().enumerate() {
|
||||
let directives: Vec<String> = cycle_val
|
||||
let directives: Vec<NodeDirective> = cycle_val
|
||||
.get("directives")
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|arr| {
|
||||
arr.iter()
|
||||
.filter_map(|d| d.get("directive").and_then(|v| v.as_str()))
|
||||
.map(String::from)
|
||||
.filter_map(|d| {
|
||||
let directive = d
|
||||
.get("directive")
|
||||
.and_then(|v| v.as_str())?;
|
||||
let access = d
|
||||
.get("access")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("read");
|
||||
Some(NodeDirective {
|
||||
directive: directive.to_string(),
|
||||
access_tier: access.to_string(),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
Reference in New Issue
Block a user