ownserp 0.1.5

OwnSERP, an MCP server for the Serper.dev search API, over stdio and Streamable HTTP
#![allow(clippy::print_stdout, clippy::print_stderr)]
#![cfg_attr(
    test,
    allow(
        clippy::unwrap_used,
        clippy::expect_used,
        clippy::panic,
        clippy::indexing_slicing
    )
)]

use std::io::IsTerminal;
use std::process::ExitCode;

use clap::Parser;

mod audit;
mod cli;
mod config;
mod doctor;
mod output;
mod serve;

fn main() -> ExitCode {
    init_tracing();
    install_panic_hook();
    let parsed = cli::Cli::parse();
    match run(parsed) {
        Ok(()) => ExitCode::SUCCESS,
        Err(error)
            if error
                .downcast_ref::<output::PrintError>()
                .is_some_and(output::PrintError::is_broken_pipe) =>
        {
            ExitCode::SUCCESS
        }
        Err(error) => {
            eprintln!("ownserp: {error:#}");
            ExitCode::FAILURE
        }
    }
}

fn run(parsed: cli::Cli) -> anyhow::Result<()> {
    match parsed.command {
        cli::Command::Serve(args) => serve::run(args),
        cli::Command::Doctor(args) => doctor::run(args),
        cli::Command::Config(args) => config::run(args),
        cli::Command::Audit(args) => audit::run(args),
    }
}

fn init_tracing() {
    let filter = tracing_subscriber::EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info"));
    if std::env::var("OWN_SERPER_LOG_FORMAT").as_deref() == Ok("json") {
        tracing_subscriber::fmt()
            .with_env_filter(filter)
            .with_writer(std::io::stderr)
            .json()
            .init();
    } else {
        let ansi = std::io::stderr().is_terminal() && std::env::var_os("NO_COLOR").is_none();
        tracing_subscriber::fmt()
            .with_env_filter(filter)
            .with_writer(std::io::stderr)
            .with_ansi(ansi)
            .init();
    }
}

fn install_panic_hook() {
    std::panic::set_hook(Box::new(|panic_info| {
        tracing::error!(panic = %panic_info, "process panicked");
    }));
}