//! Root clap parser and dispatch entry point. use clap::Parser; use miette::Result; use std::process::ExitCode; use tracing_subscriber::{EnvFilter, fmt}; use crate::commands::Command; use crate::common::diagnostics::install_miette_handler; /// Top-level `atproto-devtool` CLI. #[derive(Debug, Parser)] #[command( name = "atproto-devtool", version, about = "Diagnostics and conformance tooling for atproto services.", long_about = None, )] struct Cli { /// Enable verbose (DEBUG-level) logging to stderr. #[arg(long, global = true)] verbose: bool, /// Disable ANSI color in rendered diagnostics. #[arg(long, global = true)] no_color: bool, #[command(subcommand)] command: Command, } /// Parse `std::env::args()`, install global handlers, and dispatch. /// /// Returns `Result` to propagate exit codes through /// the dispatch chain. The main handler renders errors with exit code 1. pub async fn run() -> Result { let cli = Cli::parse(); // Check NO_COLOR environment variable in addition to --no-color flag. // NO_COLOR takes effect if present and non-empty, per https://no-color.org/ let no_color = cli.no_color || std::env::var("NO_COLOR").is_ok(); install_miette_handler(no_color)?; install_tracing(cli.verbose); cli.command.run(no_color).await } fn install_tracing(verbose: bool) { let default_filter = if verbose { "debug" } else { "warn" }; let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default_filter)); let _ = fmt() .with_env_filter(filter) .with_writer(std::io::stderr) .try_init(); }