1use super::Command;
2use crate::context::AppContext;
3use crate::repo_utils::find_repository_root;
4use crate::task::TaskBuilder;
5use crate::task_manager::TaskManager;
6use async_trait::async_trait;
7use std::error::Error;
8use std::path::{Path, PathBuf};
9
10pub struct QuickCommand {
11 pub name: String,
12 pub r#type: String,
13 pub description: Option<String>,
14 pub instructions: Option<String>,
15 pub edit: bool,
16 pub agent: Option<String>,
17 pub timeout: u32,
18 pub tech_stack: Option<String>,
19 pub project: Option<String>,
20}
21
22#[async_trait]
23impl Command for QuickCommand {
24 async fn execute(&self, ctx: &AppContext) -> Result<(), Box<dyn Error>> {
25 println!("Executing quick task: {}", self.name);
26 println!("Type: {}", self.r#type);
27
28 let repo_root = find_repository_root(Path::new("."))?;
30
31 let task = TaskBuilder::new()
33 .repo_root(repo_root.clone())
34 .name(self.name.clone())
35 .task_type(self.r#type.clone())
36 .description(self.description.clone())
37 .instructions_file(self.instructions.as_ref().map(PathBuf::from))
38 .edit(self.edit)
39 .agent(self.agent.clone())
40 .timeout(self.timeout)
41 .tech_stack(self.tech_stack.clone())
42 .project(self.project.clone())
43 .build(ctx)
44 .await?;
45
46 if let Some(ref agent) = self.agent {
47 println!("Agent: {agent}");
48 }
49 println!("Timeout: {} minutes", self.timeout);
50
51 ctx.terminal_operations()
53 .set_title(&format!("TSK: {}", self.name));
54
55 let task_manager = TaskManager::new(ctx)?;
57 let result = task_manager
58 .execute_queued_task(&task)
59 .await
60 .map_err(|e| e.message);
61
62 ctx.terminal_operations().restore_title();
64
65 result?;
66
67 Ok(())
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::test_utils::{NoOpDockerClient, NoOpTskClient};
75 use std::sync::Arc;
76
77 fn create_test_context() -> AppContext {
78 AppContext::builder()
79 .with_docker_client(Arc::new(NoOpDockerClient))
80 .with_tsk_client(Arc::new(NoOpTskClient))
81 .build()
82 }
83
84 #[tokio::test]
85 async fn test_quick_command_validation_no_input() {
86 let cmd = QuickCommand {
87 name: "test".to_string(),
88 r#type: "generic".to_string(),
89 description: None,
90 instructions: None,
91 edit: false,
92 agent: None,
93 timeout: 30,
94 tech_stack: None,
95 project: None,
96 };
97
98 let ctx = create_test_context();
99 let result = cmd.execute(&ctx).await;
100 assert!(result.is_err());
101 assert!(result.unwrap_err().to_string().contains(
102 "Either description or instructions file must be provided, or use edit mode"
103 ));
104 }
105}