agentdiff 0.1.19

Audit and trace autonomous AI code contributions in git repositories
mod cli;
mod commands;
mod config;
mod data;
mod init;
mod keys;
mod store;
mod util;

use anyhow::Context;
use clap::Parser;
use cli::{Cli, Command};
use config::Config;

fn main() -> anyhow::Result<()> {
    // Suppress broken pipe errors (e.g. `agentdiff export | head`).
    #[cfg(unix)]
    unsafe {
        libc::signal(libc::SIGPIPE, libc::SIG_DFL);
    }
    let cli = Cli::parse();

    let config = Config::load().context("loading config")?;

    // Commands that don't require a git repository.
    let no_repo_needed = matches!(
        &cli.command,
        Command::Config(_) | Command::Configure(_) | Command::Keys(_)
    );

    // Resolve repo root
    let repo_root = if let Some(ref explicit) = cli.repo {
        explicit.clone()
    } else {
        match util::find_repo_root() {
            Ok(root) => root,
            Err(_) => {
                if no_repo_needed {
                    std::env::current_dir()?
                } else {
                    return Err(anyhow::anyhow!(
                        "Not in a git repository. Run agentdiff init in a repo first."
                    ));
                }
            }
        }
    };

    let store = store::Store::new(repo_root.clone(), config.clone());

    match cli.command {
        Command::Configure(args) => {
            let mut cfg = config;
            init::run_configure(
                &mut cfg,
                args.no_claude,
                args.no_cursor,
                args.no_codex,
                args.no_antigravity,
                args.no_windsurf,
                args.no_opencode,
                args.no_copilot,
                args.no_mcp,
            )
        }
        Command::Init(args) => {
            let mut cfg = config;
            init::run_init(&repo_root, &mut cfg, args.no_git_hook, args.migrate)
        }
        Command::List(args) => commands::list::run(&store, &args),
        Command::Blame(args) => commands::blame::run(&store, &args),
        Command::Stats(args) => commands::stats::run(&store, &args),
        Command::Report(args) => commands::report::run(&store, &args),
        Command::Diff(args) => commands::diff::run(&store, &args),
        Command::Log(args) => commands::log::run(&store, &args),
        Command::Show(args) => commands::show::run(&store, &args),
        Command::Ledger(args) => commands::ledger::run(&store, &args),
        Command::SyncNotes => commands::sync_notes::run(&store),
        Command::Config(args) => commands::config_cmd::run(&config, &args),
        Command::Keys(args) => match args.action {
            cli::KeysAction::Init => commands::keys::run_init(),
            cli::KeysAction::Register => commands::keys::run_register(&store),
            cli::KeysAction::Rotate => commands::keys::run_rotate(&store),
        },
        Command::Verify(args) => commands::verify::run(&store, &args),
        Command::Policy(args) => commands::policy::run(&store, &args.action),
        Command::Export(args) => commands::export::run(&store, &args),
        Command::Status => commands::status::run(&store),
        Command::Push(args) => commands::push::run(&store, &args),
        Command::Consolidate(args) => commands::consolidate::run(&store, &args),
        Command::Migrate => commands::migrate::run(&store),
        Command::RemoteStatus(args) => commands::remote_status::run(&store, &args),
        Command::SignEntry => commands::sign_entry::run(&store),
    }
}