stax 0.29.4

Fast stacked Git branches and PRs
Documentation
use super::registry::Registry;
use crate::git::GitRepo;
use anyhow::Result;
use colored::Colorize;
use std::process::Command;

pub fn run() -> Result<()> {
    let repo = GitRepo::open()?;
    let git_dir = repo.git_dir()?.to_path_buf();

    let registry = Registry::load(&git_dir)?;

    if registry.entries.is_empty() {
        println!("{}", "No agent worktrees registered.".dimmed());
        return Ok(());
    }

    let existing: Vec<_> = registry
        .entries
        .iter()
        .filter(|e| e.path.exists())
        .collect();

    if existing.is_empty() {
        println!(
            "{}",
            "No live worktrees found. Run `stax agent prune` to clean up.".yellow()
        );
        return Ok(());
    }

    println!(
        "Syncing {} agent {}...\n",
        existing.len(),
        if existing.len() == 1 {
            "worktree"
        } else {
            "worktrees"
        }
    );

    let stax_bin = std::env::current_exe().unwrap_or_else(|_| "stax".into());

    let mut ok = 0usize;
    let mut failed = 0usize;

    for entry in &existing {
        print!("  {} ({}) ... ", entry.name.cyan(), entry.branch.dimmed());

        let output = Command::new(&stax_bin)
            .args(["restack", "--all", "--quiet", "--yes"])
            .current_dir(&entry.path)
            .output();

        match output {
            Ok(o) if o.status.success() => {
                println!("{}", "ok".green());
                ok += 1;
            }
            Ok(o) => {
                let stderr = String::from_utf8_lossy(&o.stderr).trim().to_string();
                let first_line = stderr.lines().next().unwrap_or("unknown error");
                println!("{}{}", "failed".red(), first_line.dimmed());
                failed += 1;
            }
            Err(e) => {
                println!("{}{}", "failed".red(), e.to_string().dimmed());
                failed += 1;
            }
        }
    }

    println!();
    println!(
        "Done: {} synced, {} failed",
        ok.to_string().green(),
        if failed > 0 {
            failed.to_string().red().to_string()
        } else {
            failed.to_string().dimmed().to_string()
        }
    );

    if failed > 0 {
        anyhow::bail!("{} worktree(s) failed to sync", failed);
    }

    Ok(())
}