refactor: drop Manage prefix from consolidated smart MCP tools
This commit is contained in:
1 parent
e45db33297
commit
961abb01e7
8 files changed
+885
-71
No files matched your search
@@ -162,6 +162,56 @@ impl McpTool for GetEnvironmentDetailsHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EnvironmentHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for EnvironmentHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"environment"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<EnvironmentTool>(
|
||||||
|
"environment",
|
||||||
|
"Consolidated environment & infrastructure management",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: EnvironmentTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
|
match req.action {
|
||||||
|
EnvAction::UpdateFingerprint => {
|
||||||
|
let tool_versions = req.tool_versions.unwrap_or_default();
|
||||||
|
UpdateEnvFingerprintHandler.execute(serde_json::json!({"namespace": ns, "tool_versions": tool_versions}), state).await
|
||||||
|
}
|
||||||
|
EnvAction::ReadFingerprint => {
|
||||||
|
ReadEnvFingerprintHandler.execute(serde_json::json!({"namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
EnvAction::LogRequirement => {
|
||||||
|
let key = req.key.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("key is required for 'log_requirement' action".to_string())
|
||||||
|
})?;
|
||||||
|
let desc = req.description.unwrap_or_default();
|
||||||
|
let secret = req.is_secret.unwrap_or(false);
|
||||||
|
LogEnvRequirementHandler.execute(serde_json::json!({"key": key, "description": desc, "is_secret": secret, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
EnvAction::Register => {
|
||||||
|
let name = req.name.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("name is required for 'register' action".to_string())
|
||||||
|
})?;
|
||||||
|
let url = req.url.unwrap_or_default();
|
||||||
|
let desc = req.description.unwrap_or_default();
|
||||||
|
let vpn = req.requires_vpn.unwrap_or(false);
|
||||||
|
RegisterEnvironmentHandler.execute(serde_json::json!({"name": name, "url": url, "description": desc, "requires_vpn": vpn, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
EnvAction::GetDetails => {
|
||||||
|
GetEnvironmentDetailsHandler.execute(serde_json::json!({"namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -524,6 +524,109 @@ impl McpTool for ListTechDebtHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DecisionsHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for DecisionsHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"decisions"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<DecisionsTool>(
|
||||||
|
"decisions",
|
||||||
|
"Consolidated Architectural Decision Records (ADRs) management (log, query, delete)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: DecisionsTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
|
match req.action {
|
||||||
|
DecisionAction::Log => {
|
||||||
|
let title = req.title.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("title is required for 'log' action".to_string())
|
||||||
|
})?;
|
||||||
|
let status = req.status.unwrap_or_else(|| "accepted".to_string());
|
||||||
|
let context = req.context.unwrap_or_default();
|
||||||
|
let decision = req.decision.unwrap_or_default();
|
||||||
|
let consequences = req.consequences.unwrap_or_default();
|
||||||
|
LogDecisionHandler.execute(
|
||||||
|
serde_json::json!({
|
||||||
|
"title": title,
|
||||||
|
"status": status,
|
||||||
|
"context": context,
|
||||||
|
"decision": decision,
|
||||||
|
"consequences": consequences,
|
||||||
|
"namespace": ns
|
||||||
|
}),
|
||||||
|
state,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
DecisionAction::Query => {
|
||||||
|
QueryDecisionsHandler.execute(serde_json::json!({"query": req.query, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
DecisionAction::Delete => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'delete' action".to_string())
|
||||||
|
})?;
|
||||||
|
DeleteDecisionHandler.execute(serde_json::json!({"id": id}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TechDebtHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for TechDebtHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"tech_debt"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<TechDebtTool>(
|
||||||
|
"tech_debt",
|
||||||
|
"Consolidated technical debt management (log, resolve, list)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: TechDebtTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
|
match req.action {
|
||||||
|
TechDebtAction::Log => {
|
||||||
|
let desc = req.description.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("description is required for 'log' action".to_string())
|
||||||
|
})?;
|
||||||
|
let ideal = req.ideal_solution.unwrap_or_default();
|
||||||
|
LogTechDebtHandler.execute(
|
||||||
|
serde_json::json!({
|
||||||
|
"description": desc,
|
||||||
|
"ideal_solution": ideal,
|
||||||
|
"git_commit": req.git_commit,
|
||||||
|
"git_branch": req.git_branch,
|
||||||
|
"symbol_references": req.symbol_references,
|
||||||
|
"line_range": req.line_range,
|
||||||
|
"namespace": ns
|
||||||
|
}),
|
||||||
|
state,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
TechDebtAction::Resolve => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'resolve' action".to_string())
|
||||||
|
})?;
|
||||||
|
ResolveTechDebtHandler.execute(serde_json::json!({"id": id}), state).await
|
||||||
|
}
|
||||||
|
TechDebtAction::List => {
|
||||||
|
let inc = req.include_resolved.unwrap_or(false);
|
||||||
|
ListTechDebtHandler.execute(serde_json::json!({"include_resolved": inc, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct OmniSearchHandler;
|
pub struct OmniSearchHandler;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -7,23 +7,23 @@ use serde_json::Value;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct ManageStickyNotesHandler;
|
pub struct StickyNotesHandler;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl McpTool for ManageStickyNotesHandler {
|
impl McpTool for StickyNotesHandler {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"manage_sticky_notes"
|
"sticky_notes"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema(&self) -> Value {
|
fn schema(&self) -> Value {
|
||||||
crate::mcp::tool_def::<ManageStickyNotesTool>(
|
crate::mcp::tool_def::<StickyNotesTool>(
|
||||||
"manage_sticky_notes",
|
"sticky_notes",
|
||||||
"Manage ephemeral sticky notes with TTL (add, read, delete, clear)",
|
"Ephemeral sticky notes with TTL (add, read, delete, clear)",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
let req: ManageStickyNotesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
let req: StickyNotesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
match req.action {
|
match req.action {
|
||||||
StickyNoteAction::Add => {
|
StickyNoteAction::Add => {
|
||||||
let content = req.content.ok_or_else(|| {
|
let content = req.content.ok_or_else(|| {
|
||||||
@@ -216,29 +216,35 @@ impl McpTool for ClearStickyNotesHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LeaveHandoffMemoHandler;
|
pub struct HandoffMemosHandler;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl McpTool for LeaveHandoffMemoHandler {
|
impl McpTool for HandoffMemosHandler {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"leave_handoff_memo"
|
"handoff_memos"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema(&self) -> Value {
|
fn schema(&self) -> Value {
|
||||||
crate::mcp::tool_def::<LeaveHandoffMemoTool>(
|
crate::mcp::tool_def::<HandoffMemosTool>(
|
||||||
"leave_handoff_memo",
|
"handoff_memos",
|
||||||
"Execute leave_handoff_memo",
|
"Handoff memos across sessions (leave, read, clear)",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
let req: LeaveHandoffMemoTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
let req: HandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
match req.action {
|
||||||
|
HandoffMemoAction::Leave => {
|
||||||
|
let content = req.content.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("content is required for 'leave' action".to_string())
|
||||||
|
})?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
state.telemetry.handoff_memos.modify(|memos| {
|
state.telemetry.handoff_memos.modify(|memos| {
|
||||||
memos.push(crate::models::HandoffMemo {
|
memos.push(crate::models::HandoffMemo {
|
||||||
id: uuid::Uuid::new_v4().to_string(),
|
id: uuid::Uuid::new_v4().to_string(),
|
||||||
author: "agy".to_string(),
|
author: "agy".to_string(),
|
||||||
content: req.content,
|
content,
|
||||||
namespace: req.namespace,
|
namespace: ns,
|
||||||
timestamp: crate::handlers::utils::now_secs(),
|
timestamp: crate::handlers::utils::now_secs(),
|
||||||
expires_at: None,
|
expires_at: None,
|
||||||
});
|
});
|
||||||
@@ -246,27 +252,9 @@ impl McpTool for LeaveHandoffMemoHandler {
|
|||||||
memos.remove(0);
|
memos.remove(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Ok("Handoff memo left".to_string())
|
Ok("Handoff memo left.".to_string())
|
||||||
}
|
}
|
||||||
}
|
HandoffMemoAction::Read => {
|
||||||
|
|
||||||
pub struct ReadHandoffMemosHandler;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl McpTool for ReadHandoffMemosHandler {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"read_handoff_memos"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn schema(&self) -> Value {
|
|
||||||
crate::mcp::tool_def::<ReadHandoffMemosTool>(
|
|
||||||
"read_handoff_memos",
|
|
||||||
"Execute read_handoff_memos",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
|
||||||
let req: ReadHandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
|
||||||
let data = state.telemetry.handoff_memos.read_with(|items| {
|
let data = state.telemetry.handoff_memos.read_with(|items| {
|
||||||
let filtered: Vec<_> = items
|
let filtered: Vec<_> = items
|
||||||
.iter()
|
.iter()
|
||||||
@@ -282,31 +270,18 @@ impl McpTool for ReadHandoffMemosHandler {
|
|||||||
})?;
|
})?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
HandoffMemoAction::Clear => {
|
||||||
|
let ids: HashSet<_> = req.ids.unwrap_or_default().into_iter().collect();
|
||||||
|
state.telemetry.handoff_memos.modify(|memos| {
|
||||||
|
if ids.is_empty() {
|
||||||
|
memos.clear();
|
||||||
|
} else {
|
||||||
|
memos.retain(|m| !ids.contains(&m.id));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
pub struct ClearHandoffMemosHandler;
|
Ok("Handoff memos cleared.".to_string())
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl McpTool for ClearHandoffMemosHandler {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"clear_handoff_memos"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema(&self) -> Value {
|
|
||||||
crate::mcp::tool_def::<ClearHandoffMemosTool>(
|
|
||||||
"clear_handoff_memos",
|
|
||||||
"Execute clear_handoff_memos",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
|
||||||
let req: ClearHandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
|
||||||
let ids: HashSet<_> = req.ids.into_iter().collect();
|
|
||||||
state
|
|
||||||
.telemetry
|
|
||||||
.handoff_memos
|
|
||||||
.modify(|memos| memos.retain(|m| !ids.contains(&m.id)));
|
|
||||||
Ok("Handoff memos cleared".to_string())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,10 +456,10 @@ mod tests {
|
|||||||
let dir = tempdir().unwrap();
|
let dir = tempdir().unwrap();
|
||||||
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
||||||
|
|
||||||
let handoff_handler = LeaveHandoffMemoHandler;
|
let handoff_handler = HandoffMemosHandler;
|
||||||
let args = json!({
|
let args = json!({
|
||||||
|
"action": "leave",
|
||||||
"content": "Finished implementing graph tests",
|
"content": "Finished implementing graph tests",
|
||||||
"author": "Antigravity",
|
|
||||||
"namespace": "global"
|
"namespace": "global"
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -493,11 +468,10 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(res, "Handoff memo left");
|
assert_eq!(res, "Handoff memo left.");
|
||||||
|
|
||||||
let read_handoff = ReadHandoffMemosHandler;
|
let res2 = handoff_handler
|
||||||
let res2 = read_handoff
|
.execute(json!({"action": "read", "namespace": "global"}), state.clone())
|
||||||
.execute(json!({"namespace": "global"}), state.clone())
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
.map_err(|e| crate::error::AppError::Internal(e.to_string()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -532,7 +506,7 @@ mod tests {
|
|||||||
let dir = tempfile::tempdir().unwrap();
|
let dir = tempfile::tempdir().unwrap();
|
||||||
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
|
||||||
|
|
||||||
let handler = ManageStickyNotesHandler;
|
let handler = StickyNotesHandler;
|
||||||
let invalid_args = serde_json::json!({
|
let invalid_args = serde_json::json!({
|
||||||
"action": "invalid_action"
|
"action": "invalid_action"
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -512,6 +512,145 @@ impl McpTool for ListMilestonesHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TasksHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for TasksHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"tasks"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<TasksTool>(
|
||||||
|
"tasks",
|
||||||
|
"Consolidated task management (add, update, delete, list, set_criteria, verify)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: TasksTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
match req.action {
|
||||||
|
TaskAction::Add => {
|
||||||
|
let title = req.title.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("title is required for 'add' action".to_string())
|
||||||
|
})?;
|
||||||
|
let description = req.description.unwrap_or_default();
|
||||||
|
let add_args = serde_json::json!({
|
||||||
|
"title": title,
|
||||||
|
"description": description,
|
||||||
|
"git_branch": req.git_branch,
|
||||||
|
"parent_id": req.parent_id,
|
||||||
|
"dependencies": req.dependencies,
|
||||||
|
});
|
||||||
|
AddTaskHandler.execute(add_args, state).await
|
||||||
|
}
|
||||||
|
TaskAction::Update => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'update' action".to_string())
|
||||||
|
})?;
|
||||||
|
let status = req.status.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("status is required for 'update' action".to_string())
|
||||||
|
})?;
|
||||||
|
let update_args = serde_json::json!({
|
||||||
|
"id": id,
|
||||||
|
"status": status,
|
||||||
|
});
|
||||||
|
UpdateTaskStatusHandler.execute(update_args, state).await
|
||||||
|
}
|
||||||
|
TaskAction::Delete => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'delete' action".to_string())
|
||||||
|
})?;
|
||||||
|
let del_args = serde_json::json!({
|
||||||
|
"id": id,
|
||||||
|
});
|
||||||
|
DeleteTaskHandler.execute(del_args, state).await
|
||||||
|
}
|
||||||
|
TaskAction::List => {
|
||||||
|
let list_args = serde_json::json!({
|
||||||
|
"git_branch": req.git_branch,
|
||||||
|
"summary_level": req.summary_level,
|
||||||
|
"max_tokens": req.max_tokens,
|
||||||
|
});
|
||||||
|
ListActiveTasksHandler.execute(list_args, state).await
|
||||||
|
}
|
||||||
|
TaskAction::SetCriteria => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'set_criteria' action".to_string())
|
||||||
|
})?;
|
||||||
|
let criteria = req.criteria.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("criteria array is required for 'set_criteria' action".to_string())
|
||||||
|
})?;
|
||||||
|
let set_args = serde_json::json!({
|
||||||
|
"id": id,
|
||||||
|
"acceptance_criteria": criteria,
|
||||||
|
});
|
||||||
|
SetAcceptanceCriteriaHandler.execute(set_args, state).await
|
||||||
|
}
|
||||||
|
TaskAction::Verify => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'verify' action".to_string())
|
||||||
|
})?;
|
||||||
|
let verify_args = serde_json::json!({
|
||||||
|
"id": id,
|
||||||
|
});
|
||||||
|
VerifyAcceptanceCriteriaHandler.execute(verify_args, state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MilestonesHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for MilestonesHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"milestones"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<MilestonesTool>(
|
||||||
|
"milestones",
|
||||||
|
"Consolidated milestone management (add, update, list)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: MilestonesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
match req.action {
|
||||||
|
MilestoneAction::Add => {
|
||||||
|
let title = req.title.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("title is required for 'add' action".to_string())
|
||||||
|
})?;
|
||||||
|
let add_args = serde_json::json!({
|
||||||
|
"title": title,
|
||||||
|
"namespace": req.namespace.unwrap_or_else(|| crate::models::default_namespace()),
|
||||||
|
});
|
||||||
|
AddMilestoneHandler.execute(add_args, state).await
|
||||||
|
}
|
||||||
|
MilestoneAction::Update => {
|
||||||
|
let id = req.id.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id is required for 'update' action".to_string())
|
||||||
|
})?;
|
||||||
|
let status = req.status.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("status is required for 'update' action".to_string())
|
||||||
|
})?;
|
||||||
|
let update_args = serde_json::json!({
|
||||||
|
"id": id,
|
||||||
|
"status": status,
|
||||||
|
});
|
||||||
|
UpdateMilestoneHandler.execute(update_args, state).await
|
||||||
|
}
|
||||||
|
MilestoneAction::List => {
|
||||||
|
let list_args = serde_json::json!({
|
||||||
|
"namespace": req.namespace,
|
||||||
|
});
|
||||||
|
ListMilestonesHandler.execute(list_args, state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -218,6 +218,48 @@ impl McpTool for ToggleClipboardWatchModeHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::tools::{ClipboardAction, ClipboardTool};
|
||||||
|
|
||||||
|
pub struct ClipboardHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for ClipboardHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"clipboard"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<ClipboardTool>(
|
||||||
|
"clipboard",
|
||||||
|
"Consolidated OS clipboard management (read, write, toggle_watch)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: ClipboardTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
match req.action {
|
||||||
|
ClipboardAction::Read => {
|
||||||
|
ReadClipboardHandler.execute(serde_json::json!({}), state).await
|
||||||
|
}
|
||||||
|
ClipboardAction::Write => {
|
||||||
|
WriteClipboardHandler.execute(
|
||||||
|
serde_json::json!({
|
||||||
|
"text": req.text,
|
||||||
|
"html": req.html,
|
||||||
|
"files": req.files,
|
||||||
|
"image_path": req.image_path
|
||||||
|
}),
|
||||||
|
state,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
ClipboardAction::ToggleWatch => {
|
||||||
|
let enable = req.enabled.unwrap_or(true);
|
||||||
|
ToggleClipboardWatchModeHandler.execute(serde_json::json!({"enable": enable}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -475,6 +475,203 @@ impl McpTool for ClearPrChecklistHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PinnedFilesHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for PinnedFilesHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"pinned_files"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<PinnedFilesTool>(
|
||||||
|
"pinned_files",
|
||||||
|
"Consolidated pinned files focus management (pin, unpin, list)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: PinnedFilesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
|
match req.action {
|
||||||
|
PinnedFileAction::Pin => {
|
||||||
|
let path = req.path.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("path is required for 'pin' action".to_string())
|
||||||
|
})?;
|
||||||
|
PinFileHandler.execute(serde_json::json!({"file_path": path, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
PinnedFileAction::Unpin => {
|
||||||
|
let path = req.path.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("path is required for 'unpin' action".to_string())
|
||||||
|
})?;
|
||||||
|
UnpinFileHandler.execute(serde_json::json!({"file_path": path, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
PinnedFileAction::List => {
|
||||||
|
ListPinnedFilesHandler.execute(serde_json::json!({"namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ContextWorkspacesHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for ContextWorkspacesHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"context_workspaces"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<ContextWorkspacesTool>(
|
||||||
|
"context_workspaces",
|
||||||
|
"Consolidated context workspace state management (save, load, list, delete, diff)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: ContextWorkspacesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
|
match req.action {
|
||||||
|
ContextWorkspaceAction::Save => {
|
||||||
|
let name = req.name.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("name is required for 'save' action".to_string())
|
||||||
|
})?;
|
||||||
|
let pinned_files = req.pinned_files.unwrap_or_default();
|
||||||
|
let active_task_ids = req.active_task_ids.unwrap_or_default();
|
||||||
|
SaveContextWorkspaceHandler.execute(
|
||||||
|
serde_json::json!({
|
||||||
|
"name": name,
|
||||||
|
"namespace": ns,
|
||||||
|
"pinned_files": pinned_files,
|
||||||
|
"active_task_ids": active_task_ids
|
||||||
|
}),
|
||||||
|
state,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
ContextWorkspaceAction::Load => {
|
||||||
|
let name = req.name.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("name is required for 'load' action".to_string())
|
||||||
|
})?;
|
||||||
|
LoadContextWorkspaceHandler.execute(serde_json::json!({"name": name, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
ContextWorkspaceAction::List => {
|
||||||
|
ListContextWorkspacesHandler.execute(serde_json::json!({"namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
ContextWorkspaceAction::Delete => {
|
||||||
|
let name = req.name.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("name is required for 'delete' action".to_string())
|
||||||
|
})?;
|
||||||
|
DeleteContextWorkspaceHandler.execute(serde_json::json!({"name": name, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
ContextWorkspaceAction::Diff => {
|
||||||
|
let name = req.name.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("name is required for 'diff' action".to_string())
|
||||||
|
})?;
|
||||||
|
let other = req.other_name.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("other_name is required for 'diff' action".to_string())
|
||||||
|
})?;
|
||||||
|
DiffContextWorkspacesHandler.execute(serde_json::json!({"workspace_a": name, "workspace_b": other, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PrChecklistHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for PrChecklistHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"pr_checklist"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<PrChecklistTool>(
|
||||||
|
"pr_checklist",
|
||||||
|
"Consolidated PR checklist management (add, get, clear)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: PrChecklistTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
let ns = req.namespace.unwrap_or_else(|| crate::models::default_namespace());
|
||||||
|
match req.action {
|
||||||
|
PrChecklistAction::Add => {
|
||||||
|
let desc = req.description.ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("description is required for 'add' action".to_string())
|
||||||
|
})?;
|
||||||
|
AddPrChecklistItemHandler.execute(serde_json::json!({"description": desc, "namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
PrChecklistAction::Get => {
|
||||||
|
GetPrChecklistHandler.execute(serde_json::json!({"namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
PrChecklistAction::Clear => {
|
||||||
|
ClearPrChecklistHandler.execute(serde_json::json!({"namespace": ns}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SnippetsHandler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McpTool for SnippetsHandler {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"snippets"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema(&self) -> Value {
|
||||||
|
crate::mcp::tool_def::<SnippetsTool>(
|
||||||
|
"snippets",
|
||||||
|
"Consolidated reusable code snippets management (store, search, delete, tag)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||||
|
let req: SnippetsTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||||
|
match req.action {
|
||||||
|
SnippetAction::Store => {
|
||||||
|
let name = req.query.or(req.id).ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("name is required for 'store' action".to_string())
|
||||||
|
})?;
|
||||||
|
let lang = req.language.unwrap_or_else(|| "text".to_string());
|
||||||
|
let code = req.code.unwrap_or_default();
|
||||||
|
let desc = req.description.unwrap_or_default();
|
||||||
|
StoreSnippetHandler.execute(
|
||||||
|
serde_json::json!({
|
||||||
|
"name": name,
|
||||||
|
"language": lang,
|
||||||
|
"code": code,
|
||||||
|
"description": desc,
|
||||||
|
"tags": req.tags
|
||||||
|
}),
|
||||||
|
state,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
SnippetAction::Search => {
|
||||||
|
let q = req.query.unwrap_or_default();
|
||||||
|
if req.hybrid.unwrap_or(false) {
|
||||||
|
crate::handlers::meta::SearchSnippetsHybridHandler.execute(serde_json::json!({"query": q, "tags": req.tags}), state).await
|
||||||
|
} else {
|
||||||
|
SearchSnippetsHandler.execute(serde_json::json!({"query": q, "tags": req.tags}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SnippetAction::Delete => {
|
||||||
|
let id = req.id.or(req.query).ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id/name is required for 'delete' action".to_string())
|
||||||
|
})?;
|
||||||
|
DeleteSnippetHandler.execute(serde_json::json!({"name": id}), state).await
|
||||||
|
}
|
||||||
|
SnippetAction::Tag => {
|
||||||
|
let id = req.id.or(req.query).ok_or_else(|| {
|
||||||
|
crate::error::AppError::Internal("id/name is required for 'tag' action".to_string())
|
||||||
|
})?;
|
||||||
|
let tags = req.tags.unwrap_or_default();
|
||||||
|
TagSnippetHandler.execute(serde_json::json!({"name": id, "tags": tags}), state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use crate::handlers::utils::*;
|
use crate::handlers::utils::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
+12
-4
@@ -493,6 +493,8 @@ impl MemoryHandler {
|
|||||||
register!(graph::MergeEntitiesHandler);
|
register!(graph::MergeEntitiesHandler);
|
||||||
register!(graph::FindOrphansHandler);
|
register!(graph::FindOrphansHandler);
|
||||||
|
|
||||||
|
register!(tasks::TasksHandler);
|
||||||
|
register!(tasks::MilestonesHandler);
|
||||||
register!(tasks::AddTaskHandler);
|
register!(tasks::AddTaskHandler);
|
||||||
register!(tasks::DeleteTaskHandler);
|
register!(tasks::DeleteTaskHandler);
|
||||||
register!(tasks::UpdateTaskStatusHandler);
|
register!(tasks::UpdateTaskStatusHandler);
|
||||||
@@ -503,18 +505,18 @@ impl MemoryHandler {
|
|||||||
register!(tasks::UpdateMilestoneHandler);
|
register!(tasks::UpdateMilestoneHandler);
|
||||||
register!(tasks::ListMilestonesHandler);
|
register!(tasks::ListMilestonesHandler);
|
||||||
|
|
||||||
register!(notes::ManageStickyNotesHandler);
|
register!(notes::StickyNotesHandler);
|
||||||
|
register!(notes::HandoffMemosHandler);
|
||||||
register!(notes::AddStickyNoteHandler);
|
register!(notes::AddStickyNoteHandler);
|
||||||
register!(notes::ReadStickyNotesHandler);
|
register!(notes::ReadStickyNotesHandler);
|
||||||
register!(notes::DeleteStickyNoteHandler);
|
register!(notes::DeleteStickyNoteHandler);
|
||||||
register!(notes::ClearStickyNotesHandler);
|
register!(notes::ClearStickyNotesHandler);
|
||||||
register!(notes::LeaveHandoffMemoHandler);
|
|
||||||
register!(notes::ReadHandoffMemosHandler);
|
|
||||||
register!(notes::ClearHandoffMemosHandler);
|
|
||||||
register!(notes::AddSessionSummaryHandler);
|
register!(notes::AddSessionSummaryHandler);
|
||||||
register!(notes::GenerateStandupReportHandler);
|
register!(notes::GenerateStandupReportHandler);
|
||||||
register!(notes::PromoteToEntityHandler);
|
register!(notes::PromoteToEntityHandler);
|
||||||
|
|
||||||
|
register!(meta::DecisionsHandler);
|
||||||
|
register!(meta::TechDebtHandler);
|
||||||
register!(meta::LogDecisionHandler);
|
register!(meta::LogDecisionHandler);
|
||||||
register!(meta::QueryDecisionsHandler);
|
register!(meta::QueryDecisionsHandler);
|
||||||
register!(meta::DeleteDecisionHandler);
|
register!(meta::DeleteDecisionHandler);
|
||||||
@@ -530,12 +532,17 @@ impl MemoryHandler {
|
|||||||
register!(meta::OmniSearchHandler);
|
register!(meta::OmniSearchHandler);
|
||||||
register!(meta::GetProjectHealthHandler);
|
register!(meta::GetProjectHealthHandler);
|
||||||
|
|
||||||
|
register!(env::EnvironmentHandler);
|
||||||
register!(env::UpdateEnvFingerprintHandler);
|
register!(env::UpdateEnvFingerprintHandler);
|
||||||
register!(env::ReadEnvFingerprintHandler);
|
register!(env::ReadEnvFingerprintHandler);
|
||||||
register!(env::LogEnvRequirementHandler);
|
register!(env::LogEnvRequirementHandler);
|
||||||
register!(env::RegisterEnvironmentHandler);
|
register!(env::RegisterEnvironmentHandler);
|
||||||
register!(env::GetEnvironmentDetailsHandler);
|
register!(env::GetEnvironmentDetailsHandler);
|
||||||
|
|
||||||
|
register!(workspaces::PinnedFilesHandler);
|
||||||
|
register!(workspaces::ContextWorkspacesHandler);
|
||||||
|
register!(workspaces::PrChecklistHandler);
|
||||||
|
register!(workspaces::SnippetsHandler);
|
||||||
register!(workspaces::PinFileHandler);
|
register!(workspaces::PinFileHandler);
|
||||||
register!(workspaces::UnpinFileHandler);
|
register!(workspaces::UnpinFileHandler);
|
||||||
register!(workspaces::ListPinnedFilesHandler);
|
register!(workspaces::ListPinnedFilesHandler);
|
||||||
@@ -549,6 +556,7 @@ impl MemoryHandler {
|
|||||||
register!(workspaces::AddPrChecklistItemHandler);
|
register!(workspaces::AddPrChecklistItemHandler);
|
||||||
register!(workspaces::GetPrChecklistHandler);
|
register!(workspaces::GetPrChecklistHandler);
|
||||||
register!(workspaces::ClearPrChecklistHandler);
|
register!(workspaces::ClearPrChecklistHandler);
|
||||||
|
register!(vision::ClipboardHandler);
|
||||||
register!(vision::ReadClipboardHandler);
|
register!(vision::ReadClipboardHandler);
|
||||||
register!(vision::WriteClipboardHandler);
|
register!(vision::WriteClipboardHandler);
|
||||||
register!(git::GetActiveWorktreeContextHandler);
|
register!(git::GetActiveWorktreeContextHandler);
|
||||||
|
|||||||
+303
-2
@@ -140,9 +140,9 @@ pub enum StickyNoteAction {
|
|||||||
Clear,
|
Clear,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manage ephemeral sticky notes with TTL (add, read, delete, clear).
|
/// Ephemeral sticky notes with TTL (add, read, delete, clear).
|
||||||
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
pub struct ManageStickyNotesTool {
|
pub struct StickyNotesTool {
|
||||||
/// Action to perform: 'add', 'read', 'delete', or 'clear'.
|
/// Action to perform: 'add', 'read', 'delete', or 'clear'.
|
||||||
pub action: StickyNoteAction,
|
pub action: StickyNoteAction,
|
||||||
/// Content of the sticky note (required for 'add').
|
/// Content of the sticky note (required for 'add').
|
||||||
@@ -1083,3 +1083,304 @@ pub struct SearchSnippetsHybridTool {
|
|||||||
pub limit: Option<usize>,
|
pub limit: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consolidated Smart Management Tools
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum HandoffMemoAction {
|
||||||
|
Leave,
|
||||||
|
Read,
|
||||||
|
Clear,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Manage handoff memos across sessions (leave, read, clear).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct HandoffMemosTool {
|
||||||
|
/// Action to perform: 'leave', 'read', or 'clear'.
|
||||||
|
pub action: HandoffMemoAction,
|
||||||
|
/// Content of the handoff memo (required for 'leave').
|
||||||
|
pub content: Option<String>,
|
||||||
|
/// Optional namespace filter or assignment.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
/// Array of memo IDs to clear (required for 'clear').
|
||||||
|
pub ids: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum TaskAction {
|
||||||
|
Add,
|
||||||
|
Update,
|
||||||
|
Delete,
|
||||||
|
List,
|
||||||
|
SetCriteria,
|
||||||
|
Verify,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated task management (add, update, delete, list, set_criteria, verify).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct TasksTool {
|
||||||
|
/// Action to perform: 'add', 'update', 'delete', 'list', 'set_criteria', or 'verify'.
|
||||||
|
pub action: TaskAction,
|
||||||
|
/// Task ID (required for 'update', 'delete', 'set_criteria', 'verify').
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// Task title (required for 'add').
|
||||||
|
pub title: Option<String>,
|
||||||
|
/// Task description (required for 'add').
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// New status: 'pending', 'completed', or 'cancelled' (for 'update').
|
||||||
|
pub status: Option<String>,
|
||||||
|
/// Parent task ID (optional for 'add').
|
||||||
|
pub parent_id: Option<String>,
|
||||||
|
/// List of dependency task IDs (optional for 'add').
|
||||||
|
pub dependencies: Option<Vec<String>>,
|
||||||
|
/// Git branch filter or assignment.
|
||||||
|
pub git_branch: Option<String>,
|
||||||
|
/// Acceptance criteria (required for 'set_criteria').
|
||||||
|
pub criteria: Option<Vec<String>>,
|
||||||
|
/// Summary level: 'compact', 'detailed', or 'full' (for 'list').
|
||||||
|
pub summary_level: Option<String>,
|
||||||
|
/// Maximum tokens budget cap (for 'list').
|
||||||
|
pub max_tokens: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum MilestoneAction {
|
||||||
|
Add,
|
||||||
|
Update,
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated milestone management (add, update, list).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct MilestonesTool {
|
||||||
|
/// Action to perform: 'add', 'update', or 'list'.
|
||||||
|
pub action: MilestoneAction,
|
||||||
|
/// Milestone ID (required for 'update').
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// Milestone title (required for 'add').
|
||||||
|
pub title: Option<String>,
|
||||||
|
/// New status (for 'update').
|
||||||
|
pub status: Option<String>,
|
||||||
|
/// Optional namespace filter or assignment.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum PinnedFileAction {
|
||||||
|
Pin,
|
||||||
|
Unpin,
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated pinned files focus management (pin, unpin, list).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct PinnedFilesTool {
|
||||||
|
/// Action to perform: 'pin', 'unpin', or 'list'.
|
||||||
|
pub action: PinnedFileAction,
|
||||||
|
/// Absolute or workspace relative file path (required for 'pin' and 'unpin').
|
||||||
|
pub path: Option<String>,
|
||||||
|
/// Optional namespace.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ContextWorkspaceAction {
|
||||||
|
Save,
|
||||||
|
Load,
|
||||||
|
List,
|
||||||
|
Delete,
|
||||||
|
Diff,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated context workspace state management (save, load, list, delete, diff).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct ContextWorkspacesTool {
|
||||||
|
/// Action to perform: 'save', 'load', 'list', 'delete', or 'diff'.
|
||||||
|
pub action: ContextWorkspaceAction,
|
||||||
|
/// Workspace name.
|
||||||
|
pub name: Option<String>,
|
||||||
|
/// Second workspace name (for 'diff').
|
||||||
|
pub other_name: Option<String>,
|
||||||
|
/// Pinned file paths (for 'save').
|
||||||
|
pub pinned_files: Option<Vec<String>>,
|
||||||
|
/// Active task IDs (for 'save').
|
||||||
|
pub active_task_ids: Option<Vec<String>>,
|
||||||
|
/// Optional namespace.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum PrChecklistAction {
|
||||||
|
Add,
|
||||||
|
Get,
|
||||||
|
Clear,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated PR checklist management (add, get, clear).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct PrChecklistTool {
|
||||||
|
/// Action to perform: 'add', 'get', or 'clear'.
|
||||||
|
pub action: PrChecklistAction,
|
||||||
|
/// Checklist item description (required for 'add').
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// Optional namespace.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum SnippetAction {
|
||||||
|
Store,
|
||||||
|
Search,
|
||||||
|
Delete,
|
||||||
|
Tag,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated reusable code snippets management (store, search, delete, tag).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct SnippetsTool {
|
||||||
|
/// Action to perform: 'store', 'search', 'delete', or 'tag'.
|
||||||
|
pub action: SnippetAction,
|
||||||
|
/// Snippet ID (required for 'delete', 'tag').
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// Search query or snippet name.
|
||||||
|
pub query: Option<String>,
|
||||||
|
/// Snippet language (for 'store').
|
||||||
|
pub language: Option<String>,
|
||||||
|
/// Code content (for 'store').
|
||||||
|
pub code: Option<String>,
|
||||||
|
/// Snippet description (for 'store').
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// Classification tags (for 'store', 'search', 'tag').
|
||||||
|
pub tags: Option<Vec<String>>,
|
||||||
|
/// Enable hybrid lexical + semantic vector ranking (for 'search').
|
||||||
|
pub hybrid: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum DecisionAction {
|
||||||
|
Log,
|
||||||
|
Query,
|
||||||
|
Delete,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated Architectural Decision Records (ADRs) management (log, query, delete).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct DecisionsTool {
|
||||||
|
/// Action to perform: 'log', 'query', or 'delete'.
|
||||||
|
pub action: DecisionAction,
|
||||||
|
/// ADR ID (required for 'delete').
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// ADR title (required for 'log').
|
||||||
|
pub title: Option<String>,
|
||||||
|
/// ADR status (required for 'log').
|
||||||
|
pub status: Option<String>,
|
||||||
|
/// Context & problem statement (required for 'log').
|
||||||
|
pub context: Option<String>,
|
||||||
|
/// Decision made (required for 'log').
|
||||||
|
pub decision: Option<String>,
|
||||||
|
/// Consequences & tradeoffs (required for 'log').
|
||||||
|
pub consequences: Option<String>,
|
||||||
|
/// Search query string (for 'query').
|
||||||
|
pub query: Option<String>,
|
||||||
|
/// Optional namespace.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum TechDebtAction {
|
||||||
|
Log,
|
||||||
|
Resolve,
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated technical debt management (log, resolve, list).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct TechDebtTool {
|
||||||
|
/// Action to perform: 'log', 'resolve', or 'list'.
|
||||||
|
pub action: TechDebtAction,
|
||||||
|
/// Tech debt ID (required for 'resolve').
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// Tech debt description (required for 'log').
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// Ideal solution (required for 'log').
|
||||||
|
pub ideal_solution: Option<String>,
|
||||||
|
/// Include resolved tech debt items (for 'list').
|
||||||
|
pub include_resolved: Option<bool>,
|
||||||
|
/// Associated git commit hash.
|
||||||
|
pub git_commit: Option<String>,
|
||||||
|
/// Associated git branch.
|
||||||
|
pub git_branch: Option<String>,
|
||||||
|
/// Symbol references associated with the tech debt.
|
||||||
|
pub symbol_references: Option<Vec<String>>,
|
||||||
|
/// Line range associated with the tech debt.
|
||||||
|
pub line_range: Option<String>,
|
||||||
|
/// Optional namespace.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum EnvAction {
|
||||||
|
UpdateFingerprint,
|
||||||
|
ReadFingerprint,
|
||||||
|
LogRequirement,
|
||||||
|
Register,
|
||||||
|
GetDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated environment & infrastructure management (update_fingerprint, read_fingerprint, log_requirement, register, get_details).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct EnvironmentTool {
|
||||||
|
/// Action to perform.
|
||||||
|
pub action: EnvAction,
|
||||||
|
/// Map of tool names to versions (for 'update_fingerprint').
|
||||||
|
pub tool_versions: Option<std::collections::HashMap<String, String>>,
|
||||||
|
/// Env variable key (for 'log_requirement').
|
||||||
|
pub key: Option<String>,
|
||||||
|
/// Description (for 'log_requirement', 'register').
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// Secret flag (for 'log_requirement').
|
||||||
|
pub is_secret: Option<bool>,
|
||||||
|
/// Environment name (for 'register').
|
||||||
|
pub name: Option<String>,
|
||||||
|
/// Environment URL (for 'register').
|
||||||
|
pub url: Option<String>,
|
||||||
|
/// VPN required flag (for 'register').
|
||||||
|
pub requires_vpn: Option<bool>,
|
||||||
|
/// Optional namespace.
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ClipboardAction {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
ToggleWatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consolidated OS clipboard management (read, write, toggle_watch).
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct ClipboardTool {
|
||||||
|
/// Action to perform: 'read', 'write', or 'toggle_watch'.
|
||||||
|
pub action: ClipboardAction,
|
||||||
|
/// Plain text content (for 'write').
|
||||||
|
pub text: Option<String>,
|
||||||
|
/// HTML content (for 'write').
|
||||||
|
pub html: Option<String>,
|
||||||
|
/// File paths for Windows File Drop (for 'write').
|
||||||
|
pub files: Option<Vec<String>>,
|
||||||
|
/// Image path (for 'write').
|
||||||
|
pub image_path: Option<String>,
|
||||||
|
/// Enable watch mode flag (for 'toggle_watch').
|
||||||
|
pub enabled: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user