mirror of
https://github.com/khodges42/exoshell.git
synced 2026-06-14 18:08:37 +00:00
Added /keys and /help keys through src/keybindings.rs, wired into src/app.rs and src/repl.rs. It documents key actions and explicit slash-command fallbacks for copy, explain, discard, context, and stance without adding a premature TUI dependency.
70 lines
1.8 KiB
Rust
70 lines
1.8 KiB
Rust
mod app;
|
|
mod commands;
|
|
mod config;
|
|
pub mod context;
|
|
mod formatting;
|
|
mod keybindings;
|
|
mod prompts;
|
|
mod providers;
|
|
mod repl;
|
|
mod shell;
|
|
mod transcripts;
|
|
|
|
use std::io::{IsTerminal, Read};
|
|
|
|
use crate::app::{App, CliOptions};
|
|
use crate::config::Config;
|
|
use crate::providers::openai_compatible::OpenAiCompatibleProvider;
|
|
use crate::providers::router::ModelRouterProvider;
|
|
use crate::repl::Repl;
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
if let Err(error) = run().await {
|
|
eprintln!("error: {error}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
|
|
async fn run() -> Result<(), app::AppError> {
|
|
let options = CliOptions::parse(std::env::args().skip(1))?;
|
|
|
|
if options.show_help {
|
|
println!("{}", CliOptions::help());
|
|
return Ok(());
|
|
}
|
|
|
|
let mut config = Config::load(options.config_path.as_deref())?;
|
|
config.apply_cli_overrides(&options)?;
|
|
let base_provider = OpenAiCompatibleProvider::from_config(&config)?;
|
|
let provider: Box<dyn crate::providers::Provider> = if config.router.enabled {
|
|
Box::new(ModelRouterProvider::new(
|
|
base_provider,
|
|
config.router.clone(),
|
|
)?)
|
|
} else {
|
|
Box::new(base_provider)
|
|
};
|
|
let mut app = App::new(config, provider);
|
|
|
|
for note in options.context_notes {
|
|
println!("{}", app.add_note_context(note)?);
|
|
}
|
|
|
|
for path in options.context_files {
|
|
println!("{}", app.add_file_context(path)?);
|
|
}
|
|
|
|
if !std::io::stdin().is_terminal() {
|
|
let mut piped = String::new();
|
|
std::io::stdin()
|
|
.read_to_string(&mut piped)
|
|
.map_err(|error| app::AppError::Repl(crate::repl::ReplError::Io(error)))?;
|
|
if !piped.trim().is_empty() {
|
|
println!("{}", app.add_stdin_context(piped)?);
|
|
}
|
|
}
|
|
|
|
Repl::new(app).run().await
|
|
}
|