use std::collections::HashMap; use std::sync::{Arc, Mutex}; use portable_pty::ChildKiller; use tokio::sync::broadcast; use crate::agent_log::AgentLogWriter; use super::{AgentEvent, AgentRuntime, RuntimeContext, RuntimeResult, RuntimeStatus}; /// Agent runtime that spawns the `claude` CLI in a PTY and streams JSON events. /// /// This is the default runtime (`runtime = "claude-code"` in project.toml). /// It wraps the existing PTY-based execution logic, preserving all streaming, /// token tracking, and inactivity timeout behaviour. pub struct ClaudeCodeRuntime { child_killers: Arc>>>, } impl ClaudeCodeRuntime { pub fn new( child_killers: Arc>>>, ) -> Self { Self { child_killers } } } impl AgentRuntime for ClaudeCodeRuntime { async fn start( &self, ctx: RuntimeContext, tx: broadcast::Sender, event_log: Arc>>, log_writer: Option>>, ) -> Result { let pty_result = super::super::pty::run_agent_pty_streaming( &ctx.story_id, &ctx.agent_name, &ctx.command, &ctx.args, &ctx.prompt, &ctx.cwd, &tx, &event_log, log_writer, ctx.inactivity_timeout_secs, Arc::clone(&self.child_killers), ) .await?; Ok(RuntimeResult { session_id: pty_result.session_id, token_usage: pty_result.token_usage, }) } fn stop(&self) { // Stopping is handled externally by the pool via kill_child_for_key(). // The ChildKillerGuard in pty.rs deregisters automatically on process exit. } fn get_status(&self) -> RuntimeStatus { // Lifecycle status is tracked by the pool; the runtime itself is stateless. RuntimeStatus::Idle } }