rustchain/core/
executor.rs

1use crate::core::{Mission, MissionStep, Result, RustChainError, ToolError};
2use std::path::Path;
3use std::process::Command;
4
5pub struct MissionExecutor;
6
7impl MissionExecutor {
8    pub fn new() -> Self {
9        Self
10    }
11    
12    // Helper function to get parameter as string
13    fn get_param(&self, step: &MissionStep, key: &str) -> Option<String> {
14        if let Some(params) = &step.parameters {
15            params.get(key)?.as_str().map(String::from)
16        } else {
17            None
18        }
19    }
20    
21    // Helper function to get file path from parameters or legacy field  
22    fn get_file_path(&self, step: &MissionStep) -> Option<String> {
23        self.get_param(step, "path").or_else(|| step.file_path.clone())
24    }
25    
26    // Helper function to get content from parameters or legacy field
27    fn get_content(&self, step: &MissionStep) -> Option<String> {
28        self.get_param(step, "content").or_else(|| step.content.clone())
29    }
30    
31    // Helper function to get command from parameters or legacy field
32    fn get_command(&self, step: &MissionStep) -> Option<String> {
33        self.get_param(step, "command").or_else(|| step.command.clone())
34    }
35    
36    pub async fn execute_mission(&self, mission: Mission) -> Result<()> {
37        println!("๐Ÿš€ Executing mission: {}", mission.name);
38        
39        for (i, step) in mission.steps.iter().enumerate() {
40            println!("๐Ÿ“‹ Step {}/{}: {}", i + 1, mission.steps.len(), step.id);
41            self.execute_step(step).await?;
42        }
43        
44        println!("โœ… Mission completed: {}", mission.name);
45        Ok(())
46    }
47    
48    async fn execute_step(&self, step: &MissionStep) -> Result<()> {
49        match step.step_type.as_str() {
50            "create" | "create_file" => self.execute_create_step(step),
51            "edit" => self.execute_edit_step(step),
52            "command" => self.execute_command_step(step),
53            "test" => self.execute_test_step(step),
54            _ => Err(RustChainError::Tool(ToolError::NotFound { 
55                tool_name: format!("step_type_{}", step.step_type) 
56            })),
57        }
58    }
59    
60    fn execute_create_step(&self, step: &MissionStep) -> Result<()> {
61        if let (Some(file_path), Some(content)) = (self.get_file_path(step), self.get_content(step)) {
62            let path = Path::new(&file_path);
63            if let Some(parent) = path.parent() {
64                std::fs::create_dir_all(parent)?;
65            }
66            std::fs::write(path, &content)?;
67            println!("๐Ÿ“ Created: {}", file_path);
68        } else {
69            return Err(RustChainError::Tool(ToolError::InvalidParameters { 
70                tool_name: "create_file".to_string(),
71                details: "Missing file_path or content parameters".to_string()
72            }));
73        }
74        Ok(())
75    }
76    
77    fn execute_edit_step(&self, step: &MissionStep) -> Result<()> {
78        if let (Some(file_path), Some(content)) = (self.get_file_path(step), self.get_content(step)) {
79            let existing = std::fs::read_to_string(&file_path).unwrap_or_default();
80            let new_content = format!("{}\n{}", existing.trim(), content.trim());
81            std::fs::write(&file_path, new_content)?;
82            println!("โœ๏ธ Edited: {}", file_path);
83        } else {
84            return Err(RustChainError::Tool(ToolError::InvalidParameters { 
85                tool_name: "edit_file".to_string(),
86                details: "Missing file_path or content parameters".to_string()
87            }));
88        }
89        Ok(())
90    }
91    
92    fn execute_command_step(&self, step: &MissionStep) -> Result<()> {
93        if let Some(command) = self.get_command(step) {
94            let output = Command::new("sh")
95                .arg("-c")
96                .arg(&command)
97                .output()?;
98            
99            if output.status.success() {
100                println!("๐Ÿ”ง Command succeeded: {}", command);
101            } else {
102                let stderr = String::from_utf8_lossy(&output.stderr);
103                return Err(RustChainError::Tool(ToolError::ExecutionFailed { 
104                    tool_name: "command".to_string(),
105                    reason: format!("Command failed: {}", stderr)
106                }));
107            }
108        } else {
109            return Err(RustChainError::Tool(ToolError::InvalidParameters { 
110                tool_name: "command".to_string(),
111                details: "Missing command parameter".to_string()
112            }));
113        }
114        Ok(())
115    }
116    
117    fn execute_test_step(&self, step: &MissionStep) -> Result<()> {
118        let default_lang = "rust".to_string();
119        let language = step.language.as_ref().unwrap_or(&default_lang);
120        
121        match language.as_str() {
122            "rust" => {
123                let output = Command::new("cargo")
124                    .args(&["test"])
125                    .output()?;
126                
127                if output.status.success() {
128                    println!("โœ… Tests passed");
129                } else {
130                    let stderr = String::from_utf8_lossy(&output.stderr);
131                    println!("โš ๏ธ Test output: {}", stderr);
132                }
133            }
134            _ => println!("๐Ÿงช Test step for {} (not implemented)", language),
135        }
136        
137        Ok(())
138    }
139}