use std::path::PathBuf;
use clap::{CommandFactory, Parser, Subcommand};
use muster::{
adapter::{
cli::{self, RunArgs},
config::{YamlConfigSource, YamlProjectRegistry, YamlSettingsStore},
notifier::DesktopNotifier,
path::FsPathCompleter,
pty::PortablePtyRunner,
tui::{self, Adapters, TerminalGuard},
},
application::Workspace,
constants::APP_NAME,
domain::port::ConfigSource,
error::Result,
};
#[derive(Parser)]
#[command(about = "A terminal workspace for running CLI agents and dev processes")]
struct Args {
#[arg(short, long, global = true, default_value = "muster.yml")]
config: PathBuf,
#[command(subcommand)]
command: Option<Command>,
}
#[derive(Subcommand)]
enum Command {
Run(RunArgs),
}
fn main() -> Result<()> {
clap_complete::CompleteEnv::with_factory(Args::command).complete();
let args = Args::parse();
match args.command {
Some(Command::Run(run_args)) => run_capture(run_args, args.config),
None => run_tui(args.config),
}
}
fn run_capture(args: RunArgs, config: PathBuf) -> Result<()> {
let registry = YamlProjectRegistry;
if let Err(error) = cli::run(args, config, ®istry) {
eprintln!("{APP_NAME}: {error}");
std::process::exit(1);
}
Ok(())
}
fn run_tui(config_path: PathBuf) -> Result<()> {
install_panic_hook();
let config = YamlConfigSource::builder()
.path(config_path.clone())
.build();
let workspace = Workspace::builder()
.processes(config.load()?.to_processes())
.build();
let adapters = Adapters::builder()
.runner(Box::new(PortablePtyRunner))
.registry(Box::new(YamlProjectRegistry))
.completer(Box::new(FsPathCompleter))
.notifier(Box::new(DesktopNotifier::new()))
.settings_store(Box::new(YamlSettingsStore))
.build();
let mut guard = TerminalGuard::new()?;
tui::run(&mut guard, workspace, adapters, config_path)
}
fn install_panic_hook() {
let previous = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
let _ = TerminalGuard::restore();
previous(info);
}));
}