feat(server): refactor handlers, router, state management, and memory tools
This commit is contained in:
1 parent
87ddb01063
commit
a083719cf1
36 files changed
+1899
-597
No files matched your search
+56
-45
@@ -2,9 +2,9 @@ use crate::router::McpTool;
|
||||
use crate::state::MemoryState;
|
||||
use crate::tools::GetActiveWorktreeContextTool;
|
||||
use async_trait::async_trait;
|
||||
use serde_json::{json, Value};
|
||||
use std::sync::Arc;
|
||||
use serde_json::{Value, json};
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct GetActiveWorktreeContextHandler;
|
||||
|
||||
@@ -21,56 +21,66 @@ impl McpTool for GetActiveWorktreeContextHandler {
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, _args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let result = tokio::task::spawn_blocking(move || -> crate::error::Result<serde_json::Value> {
|
||||
let cwd = env::current_dir().map_err(|e| e.to_string())?;
|
||||
let repo = git2::Repository::discover(&cwd).map_err(|e| crate::error::AppError::Internal(format!("Not in a git repository: {}", e)))?;
|
||||
|
||||
let mut branch_name = String::new();
|
||||
if let Ok(head) = repo.head()
|
||||
&& let Some(name) = head.shorthand() {
|
||||
async fn execute(
|
||||
&self,
|
||||
_args: Value,
|
||||
_state: Arc<MemoryState>,
|
||||
) -> crate::error::Result<String> {
|
||||
let result =
|
||||
tokio::task::spawn_blocking(move || -> crate::error::Result<serde_json::Value> {
|
||||
let cwd = env::current_dir().map_err(|e| e.to_string())?;
|
||||
let repo = git2::Repository::discover(&cwd).map_err(|e| {
|
||||
crate::error::AppError::Internal(format!("Not in a git repository: {}", e))
|
||||
})?;
|
||||
|
||||
let mut branch_name = String::new();
|
||||
if let Ok(head) = repo.head()
|
||||
&& let Some(name) = head.shorthand()
|
||||
{
|
||||
branch_name = name.to_string();
|
||||
}
|
||||
|
||||
let mut opts = git2::DiffOptions::new();
|
||||
let mut diff = None;
|
||||
|
||||
// Try to diff against HEAD
|
||||
if let Ok(tree) = repo.head().and_then(|h| h.peel_to_tree()) {
|
||||
diff = repo.diff_tree_to_workdir_with_index(Some(&tree), Some(&mut opts)).ok();
|
||||
}
|
||||
let mut opts = git2::DiffOptions::new();
|
||||
let mut diff = None;
|
||||
|
||||
let mut files = Vec::new();
|
||||
let mut diff_output = String::new();
|
||||
// Try to diff against HEAD
|
||||
if let Ok(tree) = repo.head().and_then(|h| h.peel_to_tree()) {
|
||||
diff = repo
|
||||
.diff_tree_to_workdir_with_index(Some(&tree), Some(&mut opts))
|
||||
.ok();
|
||||
}
|
||||
|
||||
if let Some(diff) = diff {
|
||||
let _ = diff.print(git2::DiffFormat::Patch, |_delta, _hunk, line| {
|
||||
let content = std::str::from_utf8(line.content()).unwrap_or("");
|
||||
diff_output.push_str(content);
|
||||
true
|
||||
});
|
||||
let mut files = Vec::new();
|
||||
let mut diff_output = String::new();
|
||||
|
||||
for delta in diff.deltas() {
|
||||
if let Some(path) = delta.new_file().path() {
|
||||
files.push(path.to_string_lossy().into_owned());
|
||||
if let Some(diff) = diff {
|
||||
let _ = diff.print(git2::DiffFormat::Patch, |_delta, _hunk, line| {
|
||||
let content = std::str::from_utf8(line.content()).unwrap_or("");
|
||||
diff_output.push_str(content);
|
||||
true
|
||||
});
|
||||
|
||||
for delta in diff.deltas() {
|
||||
if let Some(path) = delta.new_file().path() {
|
||||
files.push(path.to_string_lossy().into_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate diff output if it's too large to save tokens
|
||||
if diff_output.len() > 10000 {
|
||||
diff_output.truncate(10000);
|
||||
diff_output.push_str("\n... [Diff truncated due to size]");
|
||||
}
|
||||
// Truncate diff output if it's too large to save tokens
|
||||
if diff_output.len() > 10000 {
|
||||
diff_output.truncate(10000);
|
||||
diff_output.push_str("\n... [Diff truncated due to size]");
|
||||
}
|
||||
|
||||
Ok(json!({
|
||||
"branch": branch_name,
|
||||
"modified_files": files,
|
||||
"diff": diff_output
|
||||
}))
|
||||
})
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
|
||||
Ok(json!({
|
||||
"branch": branch_name,
|
||||
"modified_files": files,
|
||||
"diff": diff_output
|
||||
}))
|
||||
})
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
|
||||
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&result)?)
|
||||
}
|
||||
@@ -79,9 +89,9 @@ impl McpTool for GetActiveWorktreeContextHandler {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempfile::tempdir;
|
||||
use std::sync::Arc;
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_active_worktree_context() {
|
||||
@@ -89,7 +99,8 @@ mod tests {
|
||||
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
||||
let handler = GetActiveWorktreeContextHandler;
|
||||
|
||||
let result = handler.execute(json!({}), state)
|
||||
let result = handler
|
||||
.execute(json!({}), state)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to get worktree context: {}", e))
|
||||
.unwrap();
|
||||
|
||||
Reference in new issue
Block a user