Skip to main content

sc/cli/commands/
status.rs

1//! Status command implementation.
2
3use crate::config::{current_git_branch, resolve_db_path, resolve_session_id};
4use crate::error::{Error, Result};
5use crate::storage::SqliteStorage;
6use serde::Serialize;
7use std::path::PathBuf;
8
9/// Output for status command.
10#[derive(Serialize)]
11struct StatusOutput {
12    session: Option<SessionInfo>,
13    project_path: Option<String>,
14    git_branch: Option<String>,
15    item_count: usize,
16    high_priority_count: usize,
17    categories: CategoryBreakdown,
18}
19
20#[derive(Serialize)]
21struct SessionInfo {
22    id: String,
23    name: String,
24    status: String,
25    created_at: i64,
26    updated_at: i64,
27}
28
29#[derive(Serialize)]
30struct CategoryBreakdown {
31    reminder: usize,
32    decision: usize,
33    progress: usize,
34    note: usize,
35}
36
37/// Execute status command.
38///
39/// If `session_id` is provided (from MCP bridge), looks up that specific session.
40/// Otherwise falls back to finding an active session for the current project path.
41pub fn execute(db_path: Option<&PathBuf>, session_id: Option<&str>, json: bool) -> Result<()> {
42    let db_path = resolve_db_path(db_path.map(|p| p.as_path()))
43        .ok_or(Error::NotInitialized)?;
44
45    if !db_path.exists() {
46        return Err(Error::NotInitialized);
47    }
48
49    let storage = SqliteStorage::open(&db_path)?;
50    let git_branch = current_git_branch();
51
52    // Resolve session via TTY-keyed status cache (soft — no error if missing)
53    let session = match resolve_session_id(session_id) {
54        Ok(sid) => storage.get_session(&sid)?,
55        Err(_) => None,
56    };
57
58    // Use the session's project_path for the output
59    let project_path = session.as_ref()
60        .and_then(|s| s.project_path.clone());
61
62    let (item_count, high_priority_count, categories) = if let Some(ref s) = session {
63        // Get all items for the session
64        let items = storage.get_context_items(&s.id, None, None, Some(1000))?;
65
66        let high = items.iter().filter(|i| i.priority == "high").count();
67        let reminder = items.iter().filter(|i| i.category == "reminder").count();
68        let decision = items.iter().filter(|i| i.category == "decision").count();
69        let progress = items.iter().filter(|i| i.category == "progress").count();
70        let note = items.iter().filter(|i| i.category == "note").count();
71
72        (
73            items.len(),
74            high,
75            CategoryBreakdown {
76                reminder,
77                decision,
78                progress,
79                note,
80            },
81        )
82    } else {
83        (
84            0,
85            0,
86            CategoryBreakdown {
87                reminder: 0,
88                decision: 0,
89                progress: 0,
90                note: 0,
91            },
92        )
93    };
94
95    if json {
96        let output = StatusOutput {
97            session: session.map(|s| SessionInfo {
98                id: s.id.clone(),
99                name: s.name.clone(),
100                status: s.status.clone(),
101                created_at: s.created_at,
102                updated_at: s.updated_at,
103            }),
104            project_path,
105            git_branch: git_branch.clone(),
106            item_count,
107            high_priority_count,
108            categories,
109        };
110        println!("{}", serde_json::to_string(&output)?);
111    } else {
112        println!("SaveContext Status");
113        println!("==================");
114        println!();
115
116        if let Some(ref path) = project_path {
117            println!("Project: {path}");
118        }
119        if let Some(ref branch) = git_branch {
120            println!("Branch:  {branch}");
121        }
122        println!();
123
124        if let Some(ref s) = session {
125            println!("Active Session: {}", s.name);
126            println!("  ID: {}", s.id);
127            println!("  Status: {}", s.status);
128            println!();
129            println!("Context Items: {item_count}");
130            if high_priority_count > 0 {
131                println!("  High Priority: {high_priority_count}");
132            }
133            println!("  Reminders: {}", categories.reminder);
134            println!("  Decisions: {}", categories.decision);
135            println!("  Progress:  {}", categories.progress);
136            println!("  Notes:     {}", categories.note);
137        } else {
138            println!("No active session.");
139            println!();
140            println!("Start one with: sc session start \"Session Name\"");
141        }
142    }
143
144    Ok(())
145}