| 18 | #[async_trait] |
| 19 | impl Command for RunCommand { |
| 20 | async fn execute(&self, ctx: &AppContext) -> Result<(), Box<dyn Error>> { |
| 21 | let args = &self.task_args; |
| 22 | let name = args.resolved_name(); |
| 23 | |
| 24 | let agents = args.parse_and_validate_agents()?; |
| 25 | |
| 26 | // Run command only supports single agent (no multi-agent execution) |
| 27 | if agents.len() > 1 { |
| 28 | return Err( |
| 29 | "Run command only supports a single agent. Use 'tsk add' for multi-agent tasks." |
| 30 | .into(), |
| 31 | ); |
| 32 | } |
| 33 | |
| 34 | let prompt = args.resolve_prompt()?; |
| 35 | let repo_root = args.resolve_repo_root()?; |
| 36 | |
| 37 | let task = args |
| 38 | .configure_builder(repo_root, name.clone(), Some(agents[0].clone()), prompt) |
| 39 | .build(ctx) |
| 40 | .await?; |
| 41 | |
| 42 | println!( |
| 43 | "Running {} ({}, {}, {}){}", |
| 44 | task.id, |
| 45 | task.task_type, |
| 46 | task.stack, |
| 47 | task.agent, |
| 48 | args.branch_suffix() |
| 49 | ); |
| 50 | |
| 51 | // Update terminal title for the task |
| 52 | ctx.terminal_operations().set_title(&format!("TSK: {name}")); |
| 53 | |
| 54 | // Execute the task |
| 55 | let docker_client: Arc<dyn crate::context::docker_client::DockerClient> = |
| 56 | match &self.docker_client_override { |
| 57 | Some(client) => Arc::clone(client), |
| 58 | None => Arc::new( |
| 59 | DefaultDockerClient::new(&ctx.tsk_config().container_engine) |
| 60 | .map_err(|e| -> Box<dyn Error> { e.into() })?, |
| 61 | ), |
| 62 | }; |
| 63 | let docker_manager = DockerManager::new(ctx, docker_client.clone(), None); |
| 64 | let task_runner = TaskRunner::new(ctx, docker_manager, None); |
| 65 | |
| 66 | // Set up signal handler for Ctrl+C cancellation |
| 67 | let storage = ctx.task_storage(); |
| 68 | let task_id = task.id.clone(); |
| 69 | let container_name = format!("tsk-{}", task.id); |
| 70 | let cancel_client = docker_client.clone(); |
| 71 | let cancel_storage = storage.clone(); |
| 72 | |
| 73 | tokio::spawn(async move { |
| 74 | let mut sigterm = |
| 75 | signal(SignalKind::terminate()).expect("Failed to listen for SIGTERM"); |
| 76 | tokio::select! { |
| 77 | _ = tokio::signal::ctrl_c() => {}, |