use clap::{Parser, Subcommand};
mod commands;
mod output;
#[derive(Parser)]
#[command(
name = "graphyn",
version,
about = "⚡ Understand the blast radius before you pull the trigger.",
long_about = "\
Graphyn is a code intelligence engine that models your codebase as a \
living graph of symbol relationships, so coding agents and developers \
know exactly what will break before making a change.\n\
\n\
QUICK START:\n \
graphyn analyze ./my-repo\n \
graphyn query blast-radius UserPayload\n \
graphyn query usages UserPayload\n \
graphyn status",
author = "Graphyn Contributors"
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Analyze {
#[arg(default_value = ".")]
path: String,
},
Query {
#[command(subcommand)]
subcommand: QueryCommands,
},
Watch {
#[arg(default_value = ".")]
path: String,
},
Serve {
#[arg(long, default_value = "7700")]
port: u16,
#[arg(long)]
stdio: bool,
},
Status {
#[arg(default_value = ".")]
path: String,
},
}
#[derive(Subcommand)]
enum QueryCommands {
#[command(name = "blast-radius")]
BlastRadius {
symbol: String,
#[arg(long, short)]
file: Option<String>,
#[arg(long, short, default_value = "3")]
depth: usize,
#[arg(long, default_value = ".")]
path: String,
},
#[command(name = "usages")]
Usages {
symbol: String,
#[arg(long, short)]
file: Option<String>,
#[arg(long, default_value = ".")]
path: String,
},
#[command(name = "deps")]
Deps {
symbol: String,
#[arg(long, short)]
file: Option<String>,
#[arg(long, short, default_value = "3")]
depth: usize,
#[arg(long, default_value = ".")]
path: String,
},
}
fn main() {
let cli = Cli::parse();
let result = match cli.command {
Commands::Analyze { path } => commands::analyze::run(&path),
Commands::Query { subcommand } => match subcommand {
QueryCommands::BlastRadius {
symbol,
file,
depth,
path,
} => commands::query::run_blast_radius(&symbol, file.as_deref(), depth, &path),
QueryCommands::Usages { symbol, file, path } => {
commands::query::run_usages(&symbol, file.as_deref(), &path)
}
QueryCommands::Deps {
symbol,
file,
depth,
path,
} => commands::query::run_deps(&symbol, file.as_deref(), depth, &path),
},
Commands::Watch { path } => commands::watch::run(&path),
Commands::Serve { port, stdio } => commands::serve::run(port, stdio),
Commands::Status { path } => commands::status::run(&path),
};
if let Err(e) = result {
output::error(&e.to_string());
std::process::exit(1);
}
}