use anyhow::Result;
use kodegraf_core::config::Config;
use kodegraf_core::graph::GraphStore;
use kodegraf_core::{build, config};
pub fn run() -> Result<()> {
let repo_root = config::find_repo_root()?;
let config_path = Config::config_path(&repo_root);
let db_path = Config::graph_db_path(&repo_root);
if !config_path.exists() {
let config_dir = Config::config_dir(&repo_root);
std::fs::create_dir_all(&config_dir)?;
let cfg = Config::detect(&repo_root)?;
cfg.save(&config_path)?;
}
let store = GraphStore::open(&db_path)?;
let stats = store.get_stats()?;
if stats.total_nodes == 0 {
let cfg = Config::load(&config_path)?;
eprintln!("Kodegraf: Building knowledge graph (first session)...");
let result = build::full_build(&repo_root, &cfg, &store)?;
eprintln!(
"Kodegraf: Built — {} files, {} nodes, {} edges.",
result.files_parsed, result.nodes_created, result.edges_created
);
let stats = store.get_stats()?;
print_greeting(&stats);
} else {
let current_ref = get_current_ref(&repo_root).unwrap_or_default();
let stored_ref = store.get_metadata("git_ref").ok().flatten().unwrap_or_default();
if !current_ref.is_empty() && current_ref != stored_ref {
let cfg = Config::load(&config_path)?;
eprintln!("Kodegraf: HEAD changed, updating graph...");
let result = build::incremental_update(&repo_root, &cfg, &store, "HEAD~1")?;
eprintln!(
"Kodegraf: Updated {} files ({} nodes, {} edges).",
result.files_parsed, result.nodes_created, result.edges_created
);
}
print_greeting(&stats);
}
Ok(())
}
fn print_greeting(stats: &kodegraf_core::models::GraphStats) {
println!(
"Kodegraf knowledge graph: {} files, {} functions, {} classes, {} types, {} edges.",
stats.files, stats.functions, stats.classes, stats.types, stats.total_edges
);
if !stats.languages.is_empty() {
println!("Languages: {}.", stats.languages.join(", "));
}
println!();
println!("ALWAYS use Kodegraf MCP tools (kodegraf_find, kodegraf_deps, kodegraf_check) BEFORE Grep/Glob/Read.");
}
fn get_current_ref(repo_root: &std::path::Path) -> Option<String> {
let output = std::process::Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.current_dir(repo_root)
.output()
.ok()?;
if output.status.success() {
let branch = std::process::Command::new("git")
.args(["branch", "--show-current"])
.current_dir(repo_root)
.output()
.ok()?;
let branch_str = String::from_utf8_lossy(&branch.stdout).trim().to_string();
let sha_str = String::from_utf8_lossy(&output.stdout).trim().to_string();
Some(format!("{}@{}", branch_str, sha_str))
} else {
None
}
}