mod cli; use anyhow::{anyhow, Context, Result}; use clap::{Parser, CommandFactory}; use cli::{Cli, Commands, GpuBackend, ModelsCmd, PluginsCmd}; use polyscribe_core::{config::ConfigService, ui::progress::ProgressReporter}; use polyscribe_core::models; // Added: call into core models use polyscribe_host::PluginManager; use tokio::io::AsyncWriteExt; use tracing_subscriber::EnvFilter; fn init_tracing(quiet: bool, verbose: u8) { let level = if quiet { "error" } else { match verbose { 0 => "info", 1 => "debug", _ => "trace", } }; let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(level)); tracing_subscriber::fmt() .with_env_filter(filter) .with_target(false) .with_level(true) .compact() .init(); } #[tokio::main] async fn main() -> Result<()> { let args = Cli::parse(); init_tracing(args.quiet, args.verbose); // Propagate UI flags to core so ui facade can apply policy polyscribe_core::set_quiet(args.quiet); polyscribe_core::set_no_interaction(args.no_interaction); polyscribe_core::set_verbose(args.verbose); polyscribe_core::set_no_progress(args.no_progress); let _cfg = ConfigService::load_or_default().context("loading configuration")?; match args.command { Commands::Transcribe { output: _output, merge: _merge, merge_and_separate: _merge_and_separate, language: _language, set_speaker_names: _set_speaker_names, gpu_backend, gpu_layers, inputs, } => { polyscribe_core::ui::info("starting transcription workflow"); let mut progress = ProgressReporter::new(args.no_interaction); progress.step("Validating inputs"); if inputs.is_empty() { return Err(anyhow!("no inputs provided")); } progress.step("Selecting backend and preparing model"); match gpu_backend { GpuBackend::Auto => {} GpuBackend::Cpu => {} GpuBackend::Cuda => { let _ = gpu_layers; } GpuBackend::Hip => {} GpuBackend::Vulkan => {} } progress.finish_with_message("Transcription completed (stub)"); Ok(()) } Commands::Models { cmd } => { match cmd { ModelsCmd::Update => { polyscribe_core::ui::info("verifying/updating local models"); tokio::task::spawn_blocking(|| models::update_local_models()) .await .map_err(|e| anyhow!("blocking task join error: {e}"))? .context("updating models")?; } ModelsCmd::Download => { polyscribe_core::ui::info("interactive model selection and download"); tokio::task::spawn_blocking(|| models::run_interactive_model_downloader()) .await .map_err(|e| anyhow!("blocking task join error: {e}"))? .context("running downloader")?; polyscribe_core::ui::success("Model download complete."); } } Ok(()) } Commands::Plugins { cmd } => { let pm = PluginManager::default(); match cmd { PluginsCmd::List => { let list = pm.list().context("discovering plugins")?; for item in list { polyscribe_core::ui::info(item.name); } Ok(()) } PluginsCmd::Info { name } => { let info = pm.info(&name).with_context(|| format!("getting info for {}", name))?; let s = serde_json::to_string_pretty(&info)?; polyscribe_core::ui::info(s); Ok(()) } PluginsCmd::Run { name, command, json } => { let payload = json.unwrap_or_else(|| "{}".to_string()); let mut child = pm .spawn(&name, &command) .with_context(|| format!("spawning plugin {name} {command}"))?; if let Some(mut stdin) = child.stdin.take() { stdin .write_all(payload.as_bytes()) .await .context("writing JSON payload to plugin stdin")?; } let status = pm.forward_stdio(&mut child).await?; if !status.success() { polyscribe_core::ui::error(format!("plugin returned non-zero exit code: {}", status)); return Err(anyhow!("plugin failed")); } Ok(()) } } } Commands::Completions { shell } => { use clap_complete::{generate, shells}; use std::io; let mut cmd = Cli::command(); let name = cmd.get_name().to_string(); match shell.as_str() { "bash" => generate(shells::Bash, &mut cmd, name, &mut io::stdout()), "zsh" => generate(shells::Zsh, &mut cmd, name, &mut io::stdout()), "fish" => generate(shells::Fish, &mut cmd, name, &mut io::stdout()), "powershell" => generate(shells::PowerShell, &mut cmd, name, &mut io::stdout()), "elvish" => generate(shells::Elvish, &mut cmd, name, &mut io::stdout()), _ => return Err(anyhow!("unsupported shell: {shell}")), } Ok(()) } Commands::Man => { use clap_mangen::Man; let cmd = Cli::command(); let man = Man::new(cmd); man.render(&mut std::io::stdout())?; Ok(()) } } }