use anyhow::Result;
use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal};
use crate::channel::CliChannelHandle;
use crate::commands::MetaCommand;
pub struct InteractiveLoop {
handle: CliChannelHandle,
editor: Reedline,
prompt: DefaultPrompt,
}
impl InteractiveLoop {
pub fn new(handle: CliChannelHandle) -> Self {
let editor = Reedline::create();
let prompt = DefaultPrompt::default();
Self {
handle,
editor,
prompt,
}
}
pub fn with_prompt_label(handle: CliChannelHandle, left: &str) -> Self {
let editor = Reedline::create();
let prompt = DefaultPrompt::new(
DefaultPromptSegment::Basic(left.to_string()),
DefaultPromptSegment::Empty,
);
Self {
handle,
editor,
prompt,
}
}
pub async fn run(&mut self) -> Result<()> {
println!("Oxios CLI — type .help for commands\n");
loop {
let signal = self.editor.read_line(&self.prompt);
match signal {
Ok(Signal::Success(line)) => {
let trimmed = line.trim().to_string();
if trimmed.is_empty() {
continue;
}
if let Some(cmd) = MetaCommand::parse(&trimmed) {
if self.handle_meta(cmd).await? {
break; }
continue;
}
if self.handle.is_processing() {
println!("⏳ 이전 요청을 처리 중입니다. 잠시만 기다려주세요.");
continue;
}
self.handle.set_processing(true);
self.handle.send_user_message(trimmed).await?;
self.handle.touch_session();
}
Ok(Signal::CtrlC) => {
println!("\n(Ctrl+C again to quit, or type .quit)");
}
Ok(Signal::CtrlD) => {
println!("\nGoodbye!");
break;
}
Err(err) => {
tracing::error!("Readline error: {err}");
break;
}
}
}
Ok(())
}
async fn handle_meta(&self, cmd: MetaCommand) -> Result<bool> {
match cmd {
MetaCommand::Quit => {
println!("Goodbye!");
Ok(true)
}
MetaCommand::Help => {
print!("{}", MetaCommand::help_text());
Ok(false)
}
MetaCommand::Reset => {
self.handle.reset_session();
println!("Session reset.");
Ok(false)
}
MetaCommand::Model(Some(name)) => {
println!("Switching model to: {name}");
Ok(false)
}
MetaCommand::Model(None) => {
println!("Current model: (default)");
Ok(false)
}
MetaCommand::Persona(Some(name)) => {
println!("Switching persona to: {name}");
Ok(false)
}
MetaCommand::Persona(None) => {
println!("Current persona: (default)");
Ok(false)
}
MetaCommand::Space(None) => {
println!("📋 .space 명령어는 현재 Surface(Web 대시보드)에서만 사용 가능합니다.");
Ok(false)
}
MetaCommand::Space(Some(_id_or_name)) => {
println!("📋 .space 명령어는 현재 Surface(Web 대시보드)에서만 사용 가능합니다.");
Ok(false)
}
MetaCommand::Spaces => {
println!("📋 .spaces 명령어는 현재 Surface(Web 대시보드)에서만 사용 가능합니다.");
Ok(false)
}
MetaCommand::Clear => {
print!("\x1b[2J\x1b[H");
Ok(false)
}
}
}
}