| 210 | |
| 211 | impl ReasoningGenerator for ClaudeCliGenerator { |
| 212 | fn generate(&self, condensed_text: &str, _files: &[String]) -> AgentResult<TurnReasoning> { |
| 213 | let prompt = self.build_prompt(condensed_text); |
| 214 | let claude_path = self.claude_path(); |
| 215 | let model = self.model(); |
| 216 | |
| 217 | // Build the command |
| 218 | // --print: output to stdout instead of interactive mode |
| 219 | // --output-format json: wrap response in {"result": "..."} JSON |
| 220 | // --model: which model to use |
| 221 | // --setting-sources "": skip all settings (hooks, MCP, etc.) |
| 222 | let mut cmd = Command::new(claude_path); |
| 223 | cmd.args([ |
| 224 | "--print", |
| 225 | "--output-format", |
| 226 | "json", |
| 227 | "--model", |
| 228 | model, |
| 229 | "--setting-sources", |
| 230 | "", |
| 231 | ]); |
| 232 | |
| 233 | // Isolate the subprocess from the user's repository |
| 234 | cmd.current_dir(std::env::temp_dir()); |
| 235 | cmd.env_clear(); |
| 236 | for (key, value) in Self::clean_env() { |
| 237 | cmd.env(&key, &value); |
| 238 | } |
| 239 | |
| 240 | // Pass prompt via stdin |
| 241 | cmd.stdin(std::process::Stdio::piped()); |
| 242 | cmd.stdout(std::process::Stdio::piped()); |
| 243 | cmd.stderr(std::process::Stdio::piped()); |
| 244 | |
| 245 | // Spawn the process |
| 246 | let mut child = cmd.spawn().map_err(|e| { |
| 247 | if e.kind() == std::io::ErrorKind::NotFound { |
| 248 | AgentError::Internal(format!( |
| 249 | "Claude CLI not found at '{}'. Install from https://docs.anthropic.com/en/docs/claude-code", |
| 250 | claude_path |
| 251 | )) |
| 252 | } else { |
| 253 | AgentError::Internal(format!("Failed to spawn Claude CLI: {}", e)) |
| 254 | } |
| 255 | })?; |
| 256 | |
| 257 | // Write prompt to stdin |
| 258 | if let Some(mut stdin) = child.stdin.take() { |
| 259 | let _ = stdin.write_all(prompt.as_bytes()); |
| 260 | // stdin is dropped here, closing the pipe |
| 261 | } |
| 262 | |
| 263 | // Wait for the process with timeout |
| 264 | let output = child |
| 265 | .wait_with_output() |
| 266 | .map_err(|e| AgentError::Internal(format!("Claude CLI process failed: {}", e)))?; |
| 267 | |
| 268 | if !output.status.success() { |
| 269 | let stderr = String::from_utf8_lossy(&output.stderr); |