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