intent_engine/cli_handlers/
task.rs1use crate::cli::TaskCommands;
2use crate::cli_handlers::read_stdin;
3use crate::cli_handlers::utils::print_task_context;
4use crate::error::{IntentError, Result};
5use crate::project::ProjectContext;
6use crate::tasks::TaskManager;
7use crate::workspace::WorkspaceManager;
8
9pub async fn handle_task_command(cmd: TaskCommands) -> Result<()> {
10 match cmd {
11 TaskCommands::Add {
12 name,
13 parent,
14 spec_stdin,
15 } => {
16 let ctx = ProjectContext::load_or_init().await?;
17 let task_mgr = TaskManager::new(&ctx.pool);
18
19 let spec = if spec_stdin {
20 Some(read_stdin()?)
21 } else {
22 None
23 };
24
25 let task = task_mgr.add_task(&name, spec.as_deref(), parent).await?;
26 println!("{}", serde_json::to_string_pretty(&task)?);
27 },
28
29 TaskCommands::Get { id, with_events } => {
30 let ctx = ProjectContext::load().await?;
31 let task_mgr = TaskManager::new(&ctx.pool);
32
33 if with_events {
34 let task = task_mgr.get_task_with_events(id).await?;
35 println!("{}", serde_json::to_string_pretty(&task)?);
36 } else {
37 let task = task_mgr.get_task(id).await?;
38 println!("{}", serde_json::to_string_pretty(&task)?);
39 }
40 },
41
42 TaskCommands::Update {
43 id,
44 name,
45 parent,
46 status,
47 complexity,
48 priority,
49 spec_stdin,
50 } => {
51 let ctx = ProjectContext::load_or_init().await?;
52 let task_mgr = TaskManager::new(&ctx.pool);
53
54 let spec = if spec_stdin {
55 Some(read_stdin()?)
56 } else {
57 None
58 };
59
60 let priority_int = match &priority {
62 Some(p) => Some(crate::priority::PriorityLevel::parse_to_int(p)?),
63 None => None,
64 };
65
66 let parent_opt = parent.map(Some);
67 let task = task_mgr
68 .update_task(
69 id,
70 name.as_deref(),
71 spec.as_deref(),
72 parent_opt,
73 status.as_deref(),
74 complexity,
75 priority_int,
76 )
77 .await?;
78 println!("{}", serde_json::to_string_pretty(&task)?);
79 },
80
81 TaskCommands::Del { id } => {
82 let ctx = ProjectContext::load_or_init().await?;
83 let task_mgr = TaskManager::new(&ctx.pool);
84
85 task_mgr.delete_task(id).await?;
86 println!(
87 "{}",
88 serde_json::to_string_pretty(&serde_json::json!({
89 "success": true,
90 "message": format!("Task {} deleted", id)
91 }))?
92 );
93 },
94
95 TaskCommands::List {
96 status,
97 parent,
98 sort_by,
99 limit,
100 offset,
101 } => {
102 let ctx = ProjectContext::load().await?;
103 let task_mgr = TaskManager::new(&ctx.pool);
104
105 let parent_opt = parent.map(|p| {
106 if p == "null" {
107 None
108 } else {
109 p.parse::<i64>().ok()
110 }
111 });
112
113 use crate::db::models::TaskSortBy;
115 let sort_by_parsed = match sort_by.as_deref() {
116 Some("id") => Some(TaskSortBy::Id),
117 Some("priority") => Some(TaskSortBy::Priority),
118 Some("time") => Some(TaskSortBy::Time),
119 Some("focus") => Some(TaskSortBy::FocusAware),
120 None => None, Some(other) => {
122 return Err(IntentError::InvalidInput(format!(
123 "Invalid sort_by value '{}'. Valid values: id, priority, time, focus",
124 other
125 )));
126 },
127 };
128
129 let result = task_mgr
130 .find_tasks(status.as_deref(), parent_opt, sort_by_parsed, limit, offset)
131 .await?;
132 println!("{}", serde_json::to_string_pretty(&result)?);
133 },
134
135 TaskCommands::Start { id, with_events } => {
136 let ctx = ProjectContext::load_or_init().await?;
137 let task_mgr = TaskManager::new(&ctx.pool);
138
139 let task = task_mgr.start_task(id, with_events).await?;
140 println!("{}", serde_json::to_string_pretty(&task)?);
141 },
142
143 TaskCommands::Done => {
144 let ctx = ProjectContext::load_or_init().await?;
145 let task_mgr = TaskManager::new(&ctx.pool);
146
147 let task = task_mgr.done_task().await?;
148 println!("{}", serde_json::to_string_pretty(&task)?);
149 },
150
151 TaskCommands::PickNext { format } => {
152 let ctx = ProjectContext::load_or_init().await?;
153 let task_mgr = TaskManager::new(&ctx.pool);
154
155 let response = task_mgr.pick_next().await?;
156
157 match format.as_str() {
159 "json" => {
160 println!("{}", serde_json::to_string_pretty(&response)?);
161 },
162 _ => {
163 println!("{}", response.format_as_text());
165 },
166 }
167 },
168
169 TaskCommands::SpawnSubtask { name, spec_stdin } => {
170 let ctx = ProjectContext::load_or_init().await?;
171 let task_mgr = TaskManager::new(&ctx.pool);
172
173 let spec = if spec_stdin {
174 Some(read_stdin()?)
175 } else {
176 None
177 };
178
179 let subtask = task_mgr.spawn_subtask(&name, spec.as_deref()).await?;
180 println!("{}", serde_json::to_string_pretty(&subtask)?);
181 },
182
183 TaskCommands::DependsOn {
184 blocked_task_id,
185 blocking_task_id,
186 } => {
187 let ctx = ProjectContext::load().await?;
188
189 let dependency =
190 crate::dependencies::add_dependency(&ctx.pool, blocking_task_id, blocked_task_id)
191 .await?;
192
193 let response = serde_json::json!({
194 "dependency_id": dependency.id,
195 "blocking_task_id": dependency.blocking_task_id,
196 "blocked_task_id": dependency.blocked_task_id,
197 "created_at": dependency.created_at,
198 "message": format!(
199 "Dependency added: Task {} now depends on Task {}",
200 blocked_task_id, blocking_task_id
201 )
202 });
203
204 println!("{}", serde_json::to_string_pretty(&response)?);
205 },
206
207 TaskCommands::Context { task_id } => {
208 let ctx = ProjectContext::load().await?;
209 let task_mgr = TaskManager::new(&ctx.pool);
210 let workspace_mgr = WorkspaceManager::new(&ctx.pool);
211
212 let target_id = if let Some(id) = task_id {
214 id
215 } else {
216 let current = workspace_mgr.get_current_task().await?;
217 current.current_task_id.ok_or_else(|| {
218 IntentError::InvalidInput(
219 "No task currently focused. Use 'ie task start <ID>' or provide task_id"
220 .to_string(),
221 )
222 })?
223 };
224
225 let context = task_mgr.get_task_context(target_id).await?;
226
227 print_task_context(&context)?;
229 },
230 }
231
232 Ok(())
233}