1use crate::commands::Command;
4use crate::error::{ActrCliError, Result};
5use crate::utils::{execute_command_streaming, is_actr_project, warn_if_not_actr_project};
6use actr_config::ConfigParser;
7use async_trait::async_trait;
8use clap::Args;
9use tracing::info;
10
11#[derive(Args)]
12pub struct RunCommand {
13 pub script_name: Option<String>,
15}
16
17#[async_trait]
18impl Command for RunCommand {
19 async fn execute(&self) -> Result<()> {
20 info!("🚀 Running Actor-RTC project");
21
22 warn_if_not_actr_project();
24
25 let _project_root = std::env::current_dir()?;
26
27 let config = if is_actr_project() {
29 Some(ConfigParser::from_file("Actr.toml")?)
30 } else {
31 None
32 };
33
34 let script_name = self.script_name.as_deref().unwrap_or("run");
36
37 let Some(ref config) = config else {
38 return Err(ActrCliError::command_error(
39 "No Actr.toml found. Run 'actr init' to create a project.".to_string(),
40 ));
41 };
42
43 let available_scripts = config.list_scripts();
44
45 let Some(command) = config.get_script(script_name) else {
46 if available_scripts.is_empty() {
47 return Err(ActrCliError::command_error(
48 "No scripts defined in Actr.toml. Add a [scripts] section.".to_string(),
49 ));
50 }
51 return Err(ActrCliError::command_error(format!(
52 "Script '{}' not found. Available scripts: {}",
53 script_name,
54 available_scripts.join(", ")
55 )));
56 };
57
58 info!("📜 Executing script '{}': {}", script_name, command);
59
60 self.run_script_command(command).await?;
62
63 Ok(())
64 }
65}
66
67impl RunCommand {
68 async fn run_script_command(&self, command: &str) -> Result<()> {
69 let parts: Vec<&str> = command.split_whitespace().collect();
71 if parts.is_empty() {
72 return Err(ActrCliError::command_error("Empty command".to_string()));
73 }
74
75 let program = parts[0];
76 let args = parts[1..].to_vec();
77
78 info!("▶️ Executing: {} {}", program, args.join(" "));
79
80 execute_command_streaming(program, &args, None).await
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_script_name_default() {
91 let cmd = RunCommand { script_name: None };
92
93 let script_name = cmd.script_name.as_deref().unwrap_or("run");
94 assert_eq!(script_name, "run");
95 }
96
97 #[test]
98 fn test_script_name_custom() {
99 let cmd = RunCommand {
100 script_name: Some("test".to_string()),
101 };
102
103 let script_name = cmd.script_name.as_deref().unwrap_or("run");
104 assert_eq!(script_name, "test");
105 }
106}