use crate::compact::Summary;
use crate::message::{Context, ConversationMessage, Entry};
use crate::{Client, emit, format, import};
pub(crate) trait ClientBehavior {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String;
fn print_summary(&self, summary: &Summary) -> String;
fn render_context(
&self,
entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
cwd: Option<&str>,
) -> String;
fn import_context(&self, ctx: &Context) -> anyhow::Result<String>;
}
pub(crate) struct Claude;
impl ClientBehavior for Claude {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String {
emit::render_claude(summary, context_id, cwd)
}
fn print_summary(&self, summary: &Summary) -> String {
emit::print_claude(summary)
}
fn render_context(
&self,
entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
cwd: Option<&str>,
) -> String {
format::render_claude(entries, messages, context_id, cwd)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_claude(ctx)
}
}
pub(crate) struct Codex;
impl ClientBehavior for Codex {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String {
emit::render_codex(summary, context_id, cwd)
}
fn print_summary(&self, _summary: &Summary) -> String {
emit::print_codex()
}
fn render_context(
&self,
_entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
cwd: Option<&str>,
) -> String {
format::render_codex(messages, context_id, cwd)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_codex(ctx)
}
}
pub(crate) struct Crush;
impl ClientBehavior for Crush {
fn render_summary(&self, summary: &Summary, context_id: &str, _cwd: Option<&str>) -> String {
emit::render_crush(summary, context_id)
}
fn print_summary(&self, summary: &Summary) -> String {
emit::print_crush(summary)
}
fn render_context(
&self,
_entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
_cwd: Option<&str>,
) -> String {
format::render_crush(messages, context_id)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_crush(ctx)
}
}
pub(crate) struct Gemini;
impl ClientBehavior for Gemini {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String {
emit::render_gemini(summary, context_id, cwd)
}
fn print_summary(&self, summary: &Summary) -> String {
emit::print_gemini(summary)
}
fn render_context(
&self,
_entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
_cwd: Option<&str>,
) -> String {
format::render_gemini(messages, context_id)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_gemini(ctx)
}
}
pub(crate) struct Goose;
impl ClientBehavior for Goose {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String {
emit::render_goose(summary, context_id, cwd)
}
fn print_summary(&self, _summary: &Summary) -> String {
emit::print_goose()
}
fn render_context(
&self,
_entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
cwd: Option<&str>,
) -> String {
format::render_goose(messages, context_id, cwd)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_goose(ctx)
}
}
pub(crate) struct Opencode;
impl ClientBehavior for Opencode {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String {
emit::render_opencode(summary, context_id, cwd)
}
fn print_summary(&self, summary: &Summary) -> String {
emit::print_opencode(summary)
}
fn render_context(
&self,
entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
cwd: Option<&str>,
) -> String {
format::render_opencode(entries, messages, context_id, cwd)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_opencode(ctx)
}
}
pub(crate) struct Pi;
impl ClientBehavior for Pi {
fn render_summary(&self, summary: &Summary, context_id: &str, cwd: Option<&str>) -> String {
emit::render_pi(summary, context_id, cwd)
}
fn print_summary(&self, summary: &Summary) -> String {
emit::print_pi(summary)
}
fn render_context(
&self,
entries: &[Entry],
messages: &[ConversationMessage],
context_id: &str,
cwd: Option<&str>,
) -> String {
format::render_pi(entries, messages, context_id, cwd)
}
fn import_context(&self, ctx: &Context) -> anyhow::Result<String> {
import::write_pi(ctx)
}
}
impl Client {
pub(crate) fn behavior(self) -> &'static dyn ClientBehavior {
match self {
Self::Claude => &Claude,
Self::Codex => &Codex,
Self::Crush => &Crush,
Self::Gemini => &Gemini,
Self::Goose => &Goose,
Self::Opencode => &Opencode,
Self::Pi => &Pi,
}
}
}