mod commands;
mod git;
mod history;
mod tui;
use clap::{Parser, Subcommand};
use std::process::Command;
const EXAMPLES: &str = "\x1b[1mExamples:\x1b[0m
slu commit -m \"fix\" Plain git — passed straight through
slu push …so are push, log, rebase, diff, everything
slu search -r api_key Sleuth a string across every repo, all branches
slu scan -t aws,token Audit repos for custom secret terms
slu repos --dirty Show only repos with uncommitted/unpushed work
slu sync --pull Fetch all repos and fast-forward where safe
slu tidy List merged branches that are safe to delete
slu each pull --ff-only Run any git command in every repo
slu trace --graph A prettier log (git log itself is untouched)
slu ilog Interactive TUI: browse commits and their diffs
slu ibranch Interactive TUI: browse branches and their commits
slu update Update sluuz itself to the latest release
Run `slu <command> --help` for options specific to a superpower command.";
#[derive(Parser)]
#[command(
name = "sluuz",
bin_name = "slu",
version,
about = "git, but it sleuths — a git superset with cross-repo & history superpowers",
after_help = EXAMPLES,
arg_required_else_help = true
)]
struct Cli {
#[command(subcommand)]
command: Cmd,
}
#[derive(Subcommand)]
enum Cmd {
Search(commands::search::Args),
Scan(commands::scan::Args),
Repos(commands::repos::Args),
Sync(commands::sync::Args),
Tidy(commands::tidy::Args),
Each(commands::each::Args),
Trace(commands::trace::Args),
Ilog(commands::ilog::Args),
Ibranch(commands::ibranch::Args),
Update(commands::update::Args),
#[command(external_subcommand)]
Git(Vec<String>),
}
fn main() {
let cli = Cli::parse();
match cli.command {
Cmd::Search(args) => commands::search::run(args),
Cmd::Scan(args) => commands::scan::run(args),
Cmd::Repos(args) => commands::repos::run(args),
Cmd::Sync(args) => commands::sync::run(args),
Cmd::Tidy(args) => commands::tidy::run(args),
Cmd::Each(args) => commands::each::run(args),
Cmd::Trace(args) => commands::trace::run(args),
Cmd::Ilog(args) => commands::ilog::run(args),
Cmd::Ibranch(args) => commands::ibranch::run(args),
Cmd::Update(args) => commands::update::run(args),
Cmd::Git(args) => passthrough(&args),
}
}
fn passthrough(args: &[String]) -> ! {
match Command::new("git").args(args).status() {
Ok(status) => std::process::exit(status.code().unwrap_or(1)),
Err(e) => {
eprintln!("slu: could not run git: {e}");
std::process::exit(127);
}
}
}