agentdiff 0.1.18

Audit and trace autonomous AI code contributions in git repositories
use anyhow::Result;
use colored::Colorize;

use crate::cli::ConsolidateArgs;
use crate::store::{self, Store};

pub fn run(store: &Store, args: &ConsolidateArgs) -> Result<()> {
    let branch = args
        .branch
        .as_deref()
        .ok_or_else(|| anyhow::anyhow!("--branch is required"))?;

    // Read traces from per-branch ref
    let branch_traces = store.load_branch_traces(branch)?;

    if branch_traces.is_empty() {
        println!("No traces found for branch '{branch}'");
        return Ok(());
    }

    // Read existing meta traces
    let mut meta_traces = store.load_meta_traces()?;
    let existing_ids: std::collections::HashSet<String> =
        meta_traces.iter().map(|t| t.id.clone()).collect();

    // Append only new traces
    let new_traces: Vec<_> = branch_traces
        .into_iter()
        .filter(|t| !existing_ids.contains(&t.id))
        .collect();

    let new_count = new_traces.len();
    meta_traces.extend(new_traces);

    // Write to meta ref (refs/agentdiff/meta — custom namespace, not refs/heads/).
    let jsonl = store::traces_to_jsonl(&meta_traces)?;
    store::write_to_ref(
        &store.repo_root,
        "refs/agentdiff/meta",
        "traces.jsonl",
        &jsonl,
        &format!("agentdiff: consolidate {branch} ({new_count} traces)"),
    )?;

    // Delete the per-branch ref (local)
    let ref_name = store::branch_ref_name(branch);
    if let Err(e) = store::delete_ref(&store.repo_root, &ref_name) {
        eprintln!("{} could not delete local ref: {e}", "warn".yellow());
    }

    // Push meta ref via GitHub API + delete remote per-branch ref.
    // Uses push_content_to_ref (not git push) so refs/agentdiff/* namespace
    // is not blocked by branch protection rules.
    if args.push {
        store::push_content_to_ref(
            &store.repo_root,
            "refs/agentdiff/meta",
            "traces.jsonl",
            &jsonl,
            &format!("agentdiff: consolidate {branch} ({new_count} traces)"),
        )?;
        if let Err(e) = store::delete_remote_ref(&store.repo_root, &ref_name) {
            eprintln!("{} could not delete remote ref: {e}", "warn".yellow());
        }
    }

    println!(
        "{} Consolidated {} trace(s) from '{}' into agentdiff-meta ({} total)",
        "ok".green(),
        new_count,
        branch,
        meta_traces.len()
    );

    Ok(())
}