rustchain/core/
executor.rs1use 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 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 fn get_file_path(&self, step: &MissionStep) -> Option<String> {
23 self.get_param(step, "path").or_else(|| step.file_path.clone())
24 }
25
26 fn get_content(&self, step: &MissionStep) -> Option<String> {
28 self.get_param(step, "content").or_else(|| step.content.clone())
29 }
30
31 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}