weavatrix-git 0.3.1

Fast, bounded, evidence-carrying Git reader with an optional read-only MCP server
Documentation
use std::{env, path::PathBuf, process::ExitCode, time::Duration};

use mcport::FlushPolicy;
use weavatrix_git::mcp::{open_server, runtime_config};

fn main() -> ExitCode {
    match run(&env::args().skip(1).collect::<Vec<_>>()) {
        Ok(()) => ExitCode::SUCCESS,
        Err(error) => {
            eprintln!("weavatrix-git-mcp: {error}");
            ExitCode::FAILURE
        }
    }
}

fn run(arguments: &[String]) -> Result<(), Box<dyn std::error::Error>> {
    if arguments
        .iter()
        .any(|value| value == "--help" || value == "-h")
    {
        print_help();
        return Ok(());
    }
    if arguments
        .iter()
        .any(|value| value == "--version" || value == "-V")
    {
        println!("weavatrix-git-mcp {}", env!("CARGO_PKG_VERSION"));
        return Ok(());
    }
    if arguments.iter().any(|value| value == "--build-info") {
        print_build_info();
        return Ok(());
    }

    let mut repository = PathBuf::from(".");
    let mut runtime = runtime_config();
    let mut index = 0;
    while index < arguments.len() {
        let option = &arguments[index];
        let value = arguments
            .get(index + 1)
            .ok_or_else(|| format!("{option} requires a value"))?;
        match option.as_str() {
            "--repository" | "-C" => repository = PathBuf::from(value),
            "--max-request-bytes" => runtime.transport.max_request_bytes = parse(value, option)?,
            "--max-response-bytes" => runtime.transport.max_response_bytes = parse(value, option)?,
            "--max-in-flight" => runtime.max_in_flight = parse(value, option)?,
            "--queue-depth" => runtime.queue_depth = parse(value, option)?,
            "--output-queue-depth" => runtime.output_queue_depth = parse(value, option)?,
            "--handler-deadline-ms" => {
                let milliseconds: u64 = parse(value, option)?;
                runtime.handler_deadline =
                    (milliseconds > 0).then(|| Duration::from_millis(milliseconds));
            }
            "--batch-size" => {
                let max_messages = parse(value, option)?;
                runtime.output_flush_policy = if max_messages <= 1 {
                    FlushPolicy::PerMessage
                } else {
                    FlushPolicy::Batch { max_messages }
                };
            }
            _ => return Err(format!("unknown option {option:?}; use --help").into()),
        }
        index += 2;
    }

    open_server(repository)?.serve(runtime)?;
    Ok(())
}

fn parse<T>(value: &str, option: &str) -> Result<T, Box<dyn std::error::Error>>
where
    T: std::str::FromStr,
    T::Err: std::fmt::Display,
{
    value
        .parse()
        .map_err(|error| format!("invalid value for {option}: {error}").into())
}

fn print_build_info() {
    println!(
        concat!(
            "{{\"name\":\"weavatrix-git-mcp\",\"version\":\"{}\",",
            "\"git_sha\":\"{}\",\"platform\":\"{}\",\"arch\":\"{}\"}}"
        ),
        env!("CARGO_PKG_VERSION"),
        option_env!("WEAVATRIX_GIT_BUILD_SHA").unwrap_or("unknown"),
        env::consts::OS,
        env::consts::ARCH
    );
}

fn print_help() {
    println!(
        "\
weavatrix-git-mcp {}

USAGE:
    weavatrix-git-mcp [OPTIONS]

OPTIONS:
    -C, --repository <PATH>       Repository to expose (default: current directory)
        --max-request-bytes <N>   Input frame budget
        --max-response-bytes <N>  Output frame budget
        --max-in-flight <N>       Concurrent handler ceiling
        --queue-depth <N>         Waiting request ceiling
        --output-queue-depth <N>  Complete response queue ceiling
        --handler-deadline-ms <N> Handler deadline; 0 disables it
        --batch-size <N>          Flush after N responses; 1 is interactive
        --build-info              Print native binary provenance
    -V, --version                 Print version
    -h, --help                    Print help",
        env!("CARGO_PKG_VERSION")
    );
}