1use crate::config::constants::tools;
4use crate::config::types::AgentConfig;
5use crate::tools::ToolRegistry;
6use crate::utils::colors::style;
7use anyhow::{Result, anyhow};
8use serde_json::json;
9
10fn print_result(action: &str, result: &Result<serde_json::Value>) {
12 match result {
13 Ok(_) => println!(" {} {}", style("[+]").green(), action),
14 Err(e) => println!(" {} {}: {}", style("[X]").red(), action, e),
15 }
16}
17
18pub async fn handle_create_project_command(
20 config: AgentConfig,
21 name: String,
22 features: String,
23) -> Result<()> {
24 println!(
25 "{}",
26 style(format!(
27 "Creating Rust project '{}' with features: {}",
28 name, features
29 ))
30 .cyan()
31 .bold()
32 );
33
34 let features: Vec<String> = if features.is_empty() {
35 vec![]
36 } else {
37 features.split(',').map(|s| s.trim().to_owned()).collect()
38 };
39
40 let registry = ToolRegistry::new(config.workspace.clone()).await;
41
42 println!(
44 "{}",
45 style("Step 1: Creating project directory structure...").cyan()
46 );
47 let create_dir_result = registry
48 .execute_tool(
49 tools::WRITE_FILE,
50 json!({
51 "path": format!("{}/.gitkeep", name),
52 "content": "",
53 "overwrite": true,
54 "create_dirs": true
55 }),
56 )
57 .await;
58
59 if let Err(e) = &create_dir_result {
60 println!(" {} Failed to create directory: {}", style("✗").red(), e);
61 return Err(anyhow!("Failed to create project directory: {}", e));
62 }
63 print_result("Created project directory", &create_dir_result);
64
65 println!("{}", style("Step 2: Generating Cargo.toml...").cyan());
67 let cargo_toml_content = format!(
68 r#"[package]
69name = "{}"
70version = "0.1.0"
71edition = "2021"
72
73[dependencies]
74{}"#,
75 name,
76 if features.iter().any(|s| s == "serde") {
77 "serde = { version = \"1.0\", features = [\"derive\"] }"
78 } else {
79 ""
80 }
81 );
82
83 let cargo_result = registry
84 .execute_tool(
85 tools::WRITE_FILE,
86 json!({
87 "path": format!("{}/Cargo.toml", name),
88 "content": cargo_toml_content,
89 "overwrite": true,
90 "create_dirs": true
91 }),
92 )
93 .await;
94
95 print_result("Created Cargo.toml", &cargo_result);
96
97 println!(
99 "{}",
100 style("Step 3: Creating source code structure...").cyan()
101 );
102
103 let main_rs_content = if features.iter().any(|s| s == "serde") {
104 r#"use serde::{Deserialize, Serialize};
105
106#[derive(Serialize, Deserialize, Debug)]
107struct Person {
108 name: String,
109 age: u32,
110}
111
112fn main() {
113 println!("Hello, {}!", env!("CARGO_PKG_NAME"));
114
115 let person = Person {
116 name: "Alice".to_owned(),
117 age: 30,
118 };
119
120 println!("Created person: {:?}", person);
121}"#
122 } else {
123 &format!(
124 r#"fn main() {{
125 println!("Hello, {}!", env!("CARGO_PKG_NAME"));
126}}"#,
127 name
128 )
129 };
130
131 let main_rs_result = registry
132 .execute_tool(
133 tools::WRITE_FILE,
134 json!({
135 "path": format!("{}/src/main.rs", name),
136 "content": main_rs_content,
137 "overwrite": true,
138 "create_dirs": true
139 }),
140 )
141 .await;
142
143 print_result("Created src/main.rs", &main_rs_result);
144
145 println!("{}", style("Step 4: Generating documentation...").cyan());
147 let readme_content = format!(
148 r#"# {}
149
150A Rust project with the following features: {}
151
152## Building
153
154```bash
155cargo build
156```
157
158## Running
159
160```bash
161cargo run
162```
163
164## Testing
165
166```bash
167cargo test
168```
169"#,
170 name,
171 features.join(", ")
172 );
173
174 let readme_result = registry
175 .execute_tool(
176 tools::WRITE_FILE,
177 json!({
178 "path": format!("{}/README.md", name),
179 "content": readme_content,
180 "overwrite": true,
181 "create_dirs": true
182 }),
183 )
184 .await;
185
186 print_result("Created README.md", &readme_result);
187
188 println!("{}", style("Step 5: Adding .gitignore...").cyan());
190 let gitignore_content = r#"/target/
191Cargo.lock
192.DS_Store
193*.log
194.env
195"#;
196
197 let gitignore_result = registry
198 .execute_tool(
199 tools::WRITE_FILE,
200 json!({
201 "path": format!("{}/.gitignore", name),
202 "content": gitignore_content,
203 "overwrite": true,
204 "create_dirs": true
205 }),
206 )
207 .await;
208
209 print_result("Created .gitignore", &gitignore_result);
210
211 println!("{}", style("Step 6: Testing project build...").cyan());
213 let test_build_result = registry
214 .execute_tool(
215 tools::UNIFIED_SEARCH,
216 json!({
217 "action": "list",
218 "path": format!("{}/src", name),
219 "include_hidden": false
220 }),
221 )
222 .await;
223
224 match test_build_result {
225 Ok(result) => {
226 if let Some(files) = result.get("files")
227 && let Some(files_array) = files.as_array()
228 && !files_array.is_empty()
229 {
230 println!(" {} Project structure verified", style("[+]").green());
231 }
232 }
233 Err(e) => println!(
234 " {} Failed to verify project structure: {}",
235 style("✗").red(),
236 e
237 ),
238 }
239
240 println!("{}", style("Project creation complete!").green().bold());
241 println!(
242 "{}",
243 style(format!(
244 " Project '{}' created with {} features",
245 name,
246 features.len()
247 ))
248 .cyan()
249 );
250 println!(
251 "{}",
252 style(format!(
253 " Run 'cd {} && cargo run' to test your new project",
254 name
255 ))
256 .dim()
257 );
258
259 Ok(())
260}