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