#![allow(dead_code)]
use std::path::Path;
use std::time::Duration;
use crate::commands::run::PhaseType;
use crate::contracts::{ClaudePermissionMode, Model, ReasoningEffort};
use crate::runner::{OutputHandler, OutputStream, ResolvedRunnerCliOptions, RunnerError};
#[derive(Debug, Clone)]
pub struct RunnerMetadata {
pub id: String,
pub name: String,
pub supports_resume: bool,
pub default_model: Option<String>,
}
#[derive(Clone)]
pub struct RunContext<'a> {
pub work_dir: &'a Path,
pub bin: &'a str,
pub model: Model,
pub prompt: &'a str,
pub timeout: Option<Duration>,
pub output_handler: Option<OutputHandler>,
pub output_stream: OutputStream,
pub runner_cli: ResolvedRunnerCliOptions,
pub reasoning_effort: Option<ReasoningEffort>,
pub permission_mode: Option<ClaudePermissionMode>,
pub phase_type: Option<PhaseType>,
pub session_id: Option<String>,
}
impl std::fmt::Debug for RunContext<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RunContext")
.field("work_dir", &self.work_dir)
.field("bin", &self.bin)
.field("model", &self.model)
.field("prompt", &self.prompt)
.field("timeout", &self.timeout)
.field("output_stream", &self.output_stream)
.field("runner_cli", &self.runner_cli)
.field("reasoning_effort", &self.reasoning_effort)
.field("permission_mode", &self.permission_mode)
.field("phase_type", &self.phase_type)
.field("session_id", &self.session_id)
.finish_non_exhaustive()
}
}
#[derive(Clone)]
pub struct ResumeContext<'a> {
pub work_dir: &'a Path,
pub bin: &'a str,
pub model: Model,
pub session_id: &'a str,
pub message: &'a str,
pub timeout: Option<Duration>,
pub output_handler: Option<OutputHandler>,
pub output_stream: OutputStream,
pub runner_cli: ResolvedRunnerCliOptions,
pub reasoning_effort: Option<ReasoningEffort>,
pub permission_mode: Option<ClaudePermissionMode>,
pub phase_type: Option<PhaseType>,
}
impl std::fmt::Debug for ResumeContext<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ResumeContext")
.field("work_dir", &self.work_dir)
.field("bin", &self.bin)
.field("model", &self.model)
.field("session_id", &self.session_id)
.field("message", &self.message)
.field("timeout", &self.timeout)
.field("output_stream", &self.output_stream)
.field("runner_cli", &self.runner_cli)
.field("reasoning_effort", &self.reasoning_effort)
.field("permission_mode", &self.permission_mode)
.field("phase_type", &self.phase_type)
.finish_non_exhaustive()
}
}
pub type PluginCommandParts = (
std::process::Command,
Option<Vec<u8>>,
Vec<Box<dyn std::any::Any + Send + Sync>>,
);
pub trait RunnerPlugin: Send + Sync {
fn metadata(&self) -> RunnerMetadata;
fn build_run_command(&self, ctx: RunContext<'_>) -> Result<PluginCommandParts, RunnerError>;
fn build_resume_command(
&self,
ctx: ResumeContext<'_>,
) -> Result<PluginCommandParts, RunnerError>;
fn parse_response_line(&self, line: &str, buffer: &mut String) -> Option<String>;
fn requires_managed_session_id(&self) -> bool {
false
}
}
pub trait ResponseParser: Send + Sync {
fn parse(&self, json: &serde_json::Value, buffer: &mut String) -> Option<String>;
fn runner_id(&self) -> &str;
}