refactor: reduce kiro_cli complexity by extracting helper functions
Split run_agent_stream into focused helpers: - spawn_kiro_process: command setup and spawn - write_prompt_async: threaded stdin write - generate_session_id: unique ID generation - stream_stdout: line-by-line output processing - collect_stderr: stderr collection Reduces per-function cyclomatic complexity from ~18 to ~6.
This commit is contained in:
@@ -20,67 +20,17 @@ where
|
||||
request.system_prompt.as_deref(),
|
||||
);
|
||||
|
||||
let mut command = crate::hidden_command(&binary);
|
||||
crate::cli_agent_runtime::configure_agent_command_environment(&mut command, &binary);
|
||||
command
|
||||
.arg("chat")
|
||||
.arg("--no-interactive")
|
||||
.arg("--trust-all-tools")
|
||||
.current_dir(&request.vault_path)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
let mut child = spawn_kiro_process(&binary, &request.vault_path)?;
|
||||
let prompt_handle = write_prompt_async(child.stdin.take().ok_or("No stdin handle")?, prompt);
|
||||
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|e| format!("Failed to spawn kiro-cli: {e}"))?;
|
||||
|
||||
// Write prompt from a separate thread to avoid deadlock when prompt > pipe buffer (64KB)
|
||||
let stdin = child.stdin.take().ok_or("No stdin handle")?;
|
||||
let prompt_handle = std::thread::spawn(move || {
|
||||
use std::io::Write;
|
||||
let mut stdin = stdin;
|
||||
let _ = stdin.write_all(prompt.as_bytes());
|
||||
});
|
||||
|
||||
let session_id = format!("kiro-{}-{}", std::process::id(), std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH).map(|d| d.as_millis()).unwrap_or(0));
|
||||
let session_id = generate_session_id();
|
||||
emit(AiAgentStreamEvent::Init {
|
||||
session_id: session_id.clone(),
|
||||
});
|
||||
|
||||
let stdout = child.stdout.take().ok_or("No stdout handle")?;
|
||||
let reader = std::io::BufReader::new(stdout);
|
||||
|
||||
for line in reader.lines() {
|
||||
let line = match line {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
emit(AiAgentStreamEvent::Error {
|
||||
message: format!("Read error: {e}"),
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if !line.is_empty() {
|
||||
let clean = strip_ansi_codes(&line);
|
||||
emit(AiAgentStreamEvent::TextDelta {
|
||||
text: format!("{clean}\n"),
|
||||
});
|
||||
} else {
|
||||
emit(AiAgentStreamEvent::TextDelta {
|
||||
text: "\n".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let stderr_output = child
|
||||
.stderr
|
||||
.take()
|
||||
.and_then(|stderr| std::io::read_to_string(stderr).ok())
|
||||
.unwrap_or_default();
|
||||
stream_stdout(&mut child, &mut emit);
|
||||
|
||||
let stderr_output = collect_stderr(&mut child);
|
||||
let _ = prompt_handle.join();
|
||||
let status = child.wait().map_err(|e| format!("Wait failed: {e}"))?;
|
||||
if !status.success() {
|
||||
@@ -93,6 +43,73 @@ where
|
||||
Ok(session_id)
|
||||
}
|
||||
|
||||
fn spawn_kiro_process(binary: &Path, vault_path: &str) -> Result<std::process::Child, String> {
|
||||
let mut command = crate::hidden_command(binary);
|
||||
crate::cli_agent_runtime::configure_agent_command_environment(&mut command, binary);
|
||||
command
|
||||
.arg("chat")
|
||||
.arg("--no-interactive")
|
||||
.arg("--trust-all-tools")
|
||||
.current_dir(vault_path)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
command.spawn().map_err(|e| format!("Failed to spawn kiro-cli: {e}"))
|
||||
}
|
||||
|
||||
fn write_prompt_async(stdin: std::process::ChildStdin, prompt: String) -> std::thread::JoinHandle<()> {
|
||||
std::thread::spawn(move || {
|
||||
use std::io::Write;
|
||||
let mut stdin = stdin;
|
||||
let _ = stdin.write_all(prompt.as_bytes());
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_session_id() -> String {
|
||||
let ts = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_millis())
|
||||
.unwrap_or(0);
|
||||
format!("kiro-{}-{}", std::process::id(), ts)
|
||||
}
|
||||
|
||||
fn stream_stdout<F>(child: &mut std::process::Child, emit: &mut F)
|
||||
where
|
||||
F: FnMut(AiAgentStreamEvent),
|
||||
{
|
||||
let Some(stdout) = child.stdout.take() else { return };
|
||||
let reader = std::io::BufReader::new(stdout);
|
||||
|
||||
for line in reader.lines() {
|
||||
match line {
|
||||
Ok(l) if !l.is_empty() => {
|
||||
emit(AiAgentStreamEvent::TextDelta {
|
||||
text: format!("{}\n", strip_ansi_codes(&l)),
|
||||
});
|
||||
}
|
||||
Ok(_) => {
|
||||
emit(AiAgentStreamEvent::TextDelta {
|
||||
text: "\n".to_string(),
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
emit(AiAgentStreamEvent::Error {
|
||||
message: format!("Read error: {e}"),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_stderr(child: &mut std::process::Child) -> String {
|
||||
child
|
||||
.stderr
|
||||
.take()
|
||||
.and_then(|stderr| std::io::read_to_string(stderr).ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ensure_mcp_config(vault_path: &str) -> Result<(), String> {
|
||||
let mcp_server_path = crate::cli_agent_runtime::mcp_server_path_string()?;
|
||||
write_mcp_json(vault_path, &mcp_server_path)
|
||||
|
||||
Reference in New Issue
Block a user