use std::path::Path;
use tokio::sync::broadcast;
use crate::cli::openclaw::default_daemon_probe;
use crate::error::AgentError;
use crate::transport::daemon_runner::run_daemon;
use crate::transport::pipe_runner::{run_pipe, PipeRunnerHandle};
use crate::transport::SpawnOptions;
use crate::types::{AgentEvent, CliTool};
enum TransportHandle {
Pipe(PipeRunnerHandle),
#[allow(dead_code)]
Pty,
Daemon(PipeRunnerHandle),
}
pub struct TransportSession {
pub session_id: String,
pub tool: CliTool,
handle: TransportHandle,
}
impl TransportSession {
pub async fn spawn(
tool: CliTool,
working_dir: &Path,
prompt: &str,
mut options: SpawnOptions,
) -> Result<Self, AgentError> {
options.working_dir = working_dir.to_path_buf();
options.prompt = prompt.to_string();
let (handle, session_id) = match tool {
CliTool::ClaudeCode
| CliTool::Codex
| CliTool::Gemini
| CliTool::Cursor
| CliTool::OpenCode => {
let handle = run_pipe(tool, options)?;
let sid = handle.session_id().to_string();
(TransportHandle::Pipe(handle), sid)
}
CliTool::OpenClaw => {
let probe = default_daemon_probe();
let handle = run_daemon(tool, options, &probe)?;
let sid = handle.session_id().to_string();
(TransportHandle::Daemon(handle), sid)
}
};
Ok(Self {
session_id,
tool,
handle,
})
}
pub fn subscribe(&self) -> broadcast::Receiver<AgentEvent> {
match &self.handle {
TransportHandle::Pipe(h) => h.subscribe(),
TransportHandle::Pty => {
let (tx, rx) = broadcast::channel(1);
drop(tx);
rx
}
TransportHandle::Daemon(h) => h.subscribe(),
}
}
pub fn session_id(&self) -> &str {
&self.session_id
}
pub async fn send_prompt(&self, prompt: &str) -> Result<(), AgentError> {
match &self.handle {
TransportHandle::Pipe(h) => h.send_prompt(prompt).await,
TransportHandle::Pty => Ok(()),
TransportHandle::Daemon(h) => h.send_prompt(prompt).await,
}
}
pub async fn kill(&self) -> Result<(), AgentError> {
match &self.handle {
TransportHandle::Pipe(h) => h.kill().await,
TransportHandle::Pty => Ok(()),
TransportHandle::Daemon(h) => h.kill().await,
}
}
}