intent_engine/cli_handlers/
status_command.rs1use crate::backend::{TaskBackend, WorkspaceBackend};
2use crate::db::models::{NoFocusResponse, StatusResponse, TaskBrief};
3use crate::error::Result;
4
5pub async fn handle_status(
10 task_mgr: &impl TaskBackend,
11 ws_mgr: &impl WorkspaceBackend,
12 task_id: Option<i64>,
13 with_events: bool,
14 format: &str,
15) -> Result<bool> {
16 let target_task_id = if let Some(id) = task_id {
18 Some(id)
19 } else {
20 let current = ws_mgr.get_current_task(None).await?;
21 current.current_task_id
22 };
23
24 match target_task_id {
25 Some(id) => {
26 let status = task_mgr.get_status(id, with_events).await?;
27
28 if format == "json" {
29 println!("{}", serde_json::to_string_pretty(&status)?);
30 } else {
31 print_status_text(&status);
32 }
33 Ok(true)
34 },
35 None => {
36 let root_tasks = task_mgr.get_root_tasks().await?;
37 let root_briefs: Vec<TaskBrief> = root_tasks.iter().map(TaskBrief::from).collect();
38
39 let response = NoFocusResponse {
40 message: "No focused task. Use 'ie plan' with status:'doing' to start a task."
41 .to_string(),
42 root_tasks: root_briefs,
43 };
44
45 if format == "json" {
46 println!("{}", serde_json::to_string_pretty(&response)?);
47 } else {
48 println!(" {}", response.message);
49 if !response.root_tasks.is_empty() {
50 println!("\n Root tasks:");
51 for task in &response.root_tasks {
52 let icon = super::utils::status_icon(&task.status);
53 println!(" {} #{}: {} [{}]", icon, task.id, task.name, task.status);
54 }
55 }
56 }
57 Ok(false)
58 },
59 }
60}
61
62pub fn print_status_text(status: &StatusResponse) {
64 let ft = &status.focused_task;
65 let icon = super::utils::status_icon(&ft.status);
66 println!("{} Task #{}: {}", icon, ft.id, ft.name);
67 println!(" Status: {}", ft.status);
68 if let Some(parent_id) = ft.parent_id {
69 println!(" Parent: #{}", parent_id);
70 }
71 if let Some(priority) = ft.priority {
72 println!(" Priority: {}", priority);
73 }
74 if let Some(spec) = &ft.spec {
75 println!(" Spec: {}", spec);
76 }
77 println!(" Owner: {}", ft.owner);
78 if let Some(ts) = ft.first_todo_at {
79 println!(" First todo: {}", ts.format("%Y-%m-%d %H:%M:%S UTC"));
80 }
81 if let Some(ts) = ft.first_doing_at {
82 println!(" First doing: {}", ts.format("%Y-%m-%d %H:%M:%S UTC"));
83 }
84 if let Some(ts) = ft.first_done_at {
85 println!(" First done: {}", ts.format("%Y-%m-%d %H:%M:%S UTC"));
86 }
87
88 if !status.ancestors.is_empty() {
89 println!("\n Ancestors ({}):", status.ancestors.len());
90 for ancestor in &status.ancestors {
91 let parent_info = ancestor
92 .parent_id
93 .map(|p| format!(" (parent: #{})", p))
94 .unwrap_or_default();
95 let priority_info = ancestor
96 .priority
97 .map(|p| format!(" [P{}]", p))
98 .unwrap_or_default();
99 println!(
100 " #{}: {} [{}]{}{}",
101 ancestor.id, ancestor.name, ancestor.status, parent_info, priority_info
102 );
103 if let Some(spec) = &ancestor.spec {
104 println!(" Spec: {}", spec);
105 }
106 println!(" Owner: {}", ancestor.owner);
107 if let Some(ts) = ancestor.first_todo_at {
108 print!(" todo: {} ", ts.format("%m-%d %H:%M:%S"));
109 }
110 if let Some(ts) = ancestor.first_doing_at {
111 print!("doing: {} ", ts.format("%m-%d %H:%M:%S"));
112 }
113 if let Some(ts) = ancestor.first_done_at {
114 print!("done: {}", ts.format("%m-%d %H:%M:%S"));
115 }
116 if ancestor.first_todo_at.is_some()
117 || ancestor.first_doing_at.is_some()
118 || ancestor.first_done_at.is_some()
119 {
120 println!();
121 }
122 }
123 }
124
125 if !status.siblings.is_empty() {
126 println!("\n Siblings ({}):", status.siblings.len());
127 for sibling in &status.siblings {
128 let parent_info = sibling
129 .parent_id
130 .map(|p| format!(" (parent: #{})", p))
131 .unwrap_or_default();
132 let spec_indicator = if sibling.has_spec { "" } else { " ?" };
133 println!(
134 " #{}: {} [{}]{}{}",
135 sibling.id, sibling.name, sibling.status, parent_info, spec_indicator
136 );
137 }
138 }
139
140 if !status.descendants.is_empty() {
141 println!("\n Descendants ({}):", status.descendants.len());
142 for desc in &status.descendants {
143 let parent_info = desc
144 .parent_id
145 .map(|p| format!(" (parent: #{})", p))
146 .unwrap_or_default();
147 let spec_indicator = if desc.has_spec { "" } else { " ?" };
148 println!(
149 " #{}: {} [{}]{}{}",
150 desc.id, desc.name, desc.status, parent_info, spec_indicator
151 );
152 }
153 }
154
155 if let Some(events) = &status.events {
156 println!("\n Events ({}):", events.len());
157 for event in events.iter().take(10) {
158 println!(
159 " #{} [{}] {}: {}",
160 event.id,
161 event.log_type,
162 event.timestamp.format("%Y-%m-%d %H:%M:%S"),
163 event.discussion_data.chars().take(60).collect::<String>()
164 );
165 }
166 }
167}