Skip to main content

task_graph_mcp/resources/
stats.rs

1//! Stats and plan resource handlers.
2
3use crate::config::StatesConfig;
4use crate::db::Database;
5use anyhow::Result;
6use serde_json::{Value, json};
7
8pub fn get_stats_summary(db: &Database, states_config: &StatesConfig) -> Result<Value> {
9    let stats = db.get_stats(None, None, states_config)?;
10
11    Ok(json!({
12        "total_tasks": stats.total_tasks,
13        "by_status": stats.tasks_by_status,
14        "points": {
15            "total": stats.total_points,
16            "completed": stats.completed_points,
17            "remaining": stats.total_points - stats.completed_points
18        },
19        "time": {
20            "estimated_ms": stats.total_time_estimate_ms,
21            "actual_ms": stats.total_time_actual_ms
22        },
23        "cost_usd": stats.total_cost_usd,
24        "metrics": stats.total_metrics
25    }))
26}
27
28/// Export tasks in ACP (Agent Coordination Protocol) compatible format.
29pub fn get_acp_plan(db: &Database) -> Result<Value> {
30    let tasks = db.get_all_tasks()?;
31    let deps = db.get_all_dependencies()?;
32
33    // Build dependency map
34    let mut blockers_map: std::collections::HashMap<String, Vec<String>> =
35        std::collections::HashMap::new();
36    for dep in &deps {
37        blockers_map
38            .entry(dep.to_task_id.to_string())
39            .or_default()
40            .push(dep.from_task_id.to_string());
41    }
42
43    // Convert tasks to ACP format
44    let acp_tasks: Vec<Value> = tasks
45        .iter()
46        .map(|t| {
47            let blockers = blockers_map
48                .get(&t.id.to_string())
49                .cloned()
50                .unwrap_or_default();
51
52            // Map status to ACP format
53            let status = match t.status.as_str() {
54                "pending" => "todo",
55                "working" => "working",
56                "completed" => "done",
57                _ => &t.status, // Pass through other states
58            };
59
60            json!({
61                "id": t.id.to_string(),
62                "title": t.title,
63                "description": t.description,
64                "status": status,
65                "priority": t.priority,
66                "blockedBy": blockers,
67                "assignee": &t.worker_id,
68                "metadata": {
69                    "points": t.points,
70                    "timeEstimateMs": t.time_estimate_ms,
71                    "timeActualMs": t.time_actual_ms,
72                    "cost": {
73                        "metrics": t.metrics,
74                        "usd": t.cost_usd
75                    }
76                }
77            })
78        })
79        .collect();
80
81    Ok(json!({
82        "version": "1.0",
83        "tasks": acp_tasks
84    }))
85}