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
@@ -41,8 +41,9 @@ impl McpTool for AddTaskHandler {
|
||||
let idx = state.get_search_index();
|
||||
drop(idx.index_task(&task));
|
||||
state.project.tasks.modify(|tasks| {
|
||||
tasks.push(task);
|
||||
tasks.push(task.clone());
|
||||
});
|
||||
state.record_activity("task_create", &format!("Created task: {}", task.title), Some(&task.description));
|
||||
Ok(format!("Task added with ID: {}", task_id).to_string())
|
||||
}
|
||||
}
|
||||
@@ -255,6 +256,7 @@ impl McpTool for UpdateTaskStatusHandler {
|
||||
blocker_details
|
||||
)))
|
||||
} else if found {
|
||||
state.record_activity("task_update", &format!("Task {} status -> {}", req.id, req.status), None);
|
||||
Ok("Task status updated.".to_string())
|
||||
} else {
|
||||
Err(crate::error::AppError::Internal("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string()))
|
||||
@@ -386,7 +388,9 @@ impl McpTool for VerifyAcceptanceCriteriaHandler {
|
||||
} else if already_met {
|
||||
Ok("Acceptance criteria was already met.".to_string())
|
||||
} else {
|
||||
Err(crate::error::AppError::Internal("Acceptance criteria or task not found.".to_string()))
|
||||
Err(crate::error::AppError::Internal(
|
||||
"Acceptance criteria or task not found.".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,7 +449,10 @@ impl McpTool for UpdateMilestoneHandler {
|
||||
if found {
|
||||
Ok("Milestone updated".to_string())
|
||||
} else {
|
||||
Err(crate::error::AppError::Internal("Milestone not found. Please verify the milestone ID using list_milestones.".to_string()))
|
||||
Err(crate::error::AppError::Internal(
|
||||
"Milestone not found. Please verify the milestone ID using list_milestones."
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -499,13 +506,19 @@ mod tests {
|
||||
"acceptance_criteria": ["Stop the noise", "Reach lightspeed"],
|
||||
});
|
||||
|
||||
let res = add_handler.execute(args, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
let res = add_handler
|
||||
.execute(args, state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(res.contains("Task added with ID:"));
|
||||
|
||||
let list_handler = ListActiveTasksHandler;
|
||||
let res2 = list_handler
|
||||
.execute(json!({}), state.clone())
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(res2.contains("Fix the hyperdrive"));
|
||||
}
|
||||
|
||||
@@ -520,7 +533,9 @@ mod tests {
|
||||
json!({"title": "Test", "description": "test"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
|
||||
let id_start = res.find("ID: ").unwrap() + 4;
|
||||
let task_id = res[id_start..].trim();
|
||||
@@ -530,13 +545,19 @@ mod tests {
|
||||
"id": task_id,
|
||||
"status": "done"
|
||||
});
|
||||
let res3 = update_handler.execute(args, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
let res3 = update_handler
|
||||
.execute(args, state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert_eq!(res3, "Task status updated.");
|
||||
|
||||
let list_handler = ListActiveTasksHandler;
|
||||
let res4 = list_handler
|
||||
.execute(json!({}), state.clone())
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(!res4.contains(task_id));
|
||||
}
|
||||
|
||||
@@ -555,7 +576,11 @@ mod tests {
|
||||
"end_date": 1700000000,
|
||||
"namespace": "global"
|
||||
});
|
||||
let res1 = add_milestone.execute(args_ms, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
let res1 = add_milestone
|
||||
.execute(args_ms, state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(res1.contains("Milestone added"));
|
||||
|
||||
// Fetch milestone ID from state directly to update
|
||||
@@ -567,14 +592,20 @@ mod tests {
|
||||
"id": ms_id,
|
||||
"status": "completed"
|
||||
});
|
||||
let res2 = update_ms.execute(args_ums, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
let res2 = update_ms
|
||||
.execute(args_ums, state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert_eq!(res2, "Milestone updated");
|
||||
|
||||
// List Milestones
|
||||
let list_ms = ListMilestonesHandler;
|
||||
let res3 = list_ms
|
||||
.execute(json!({"namespace": "global"}), state.clone())
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(res3.contains("completed"));
|
||||
assert!(res3.contains("Release 1.0"));
|
||||
|
||||
@@ -585,7 +616,9 @@ mod tests {
|
||||
json!({"title": "Test", "description": "desc"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
let task_id = res_task[res_task.find("ID: ").unwrap() + 4..].trim();
|
||||
|
||||
let set_ac = SetAcceptanceCriteriaHandler;
|
||||
@@ -594,7 +627,11 @@ mod tests {
|
||||
"task_title": "Test",
|
||||
"criteria": ["Do X", "Do Y"]
|
||||
});
|
||||
let res4 = set_ac.execute(args_ac, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
let res4 = set_ac
|
||||
.execute(args_ac, state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert_eq!(res4, "Acceptance criteria set successfully.");
|
||||
|
||||
let verify_ac = VerifyAcceptanceCriteriaHandler;
|
||||
@@ -603,7 +640,11 @@ mod tests {
|
||||
"criteria": "Do X",
|
||||
"proof": "I did X"
|
||||
});
|
||||
let res5 = verify_ac.execute(args_vac, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
let res5 = verify_ac
|
||||
.execute(args_vac, state.clone())
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(res5.contains("Acceptance criteria verified"));
|
||||
}
|
||||
|
||||
@@ -618,7 +659,9 @@ mod tests {
|
||||
json!({"title": "Parent", "description": "p"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
let parent_id = parent[parent.find("ID: ").unwrap() + 4..]
|
||||
.trim()
|
||||
.to_string();
|
||||
@@ -628,13 +671,17 @@ mod tests {
|
||||
json!({"title": "Child", "description": "c", "parent_id": parent_id}),
|
||||
state.clone(),
|
||||
)
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
let _child_id = child[child.find("ID: ").unwrap() + 4..].trim().to_string();
|
||||
|
||||
let del_task = DeleteTaskHandler;
|
||||
let res_del = del_task
|
||||
.execute(json!({"id": parent_id}), state.clone())
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string())).unwrap();
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||
.unwrap();
|
||||
assert!(res_del.contains("Deleted task and its children (2 total)."));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user