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:
oksusucha
2026-05-07 17:13:16 +09:00
parent 16ce8b105c
commit 596d2b93bb

View File

@@ -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)