use anyhow::Result;
use kodegraf_core::config::Config;
use kodegraf_core::graph::GraphStore;
use kodegraf_core::platforms;
use kodegraf_core::{build, config};
pub fn run(platform_filter: Option<&str>, dry_run: bool) -> Result<()> {
let repo_root = config::find_repo_root()?;
let platforms = if let Some(name) = platform_filter {
let all = platforms::all_platforms();
let matched: Vec<_> = all.into_iter().filter(|p| p.name == name).collect();
if matched.is_empty() {
let names: Vec<&str> = platforms::all_platforms().iter().map(|p| p.name).collect();
anyhow::bail!(
"Unknown platform '{}'. Supported: {}",
name,
names.join(", ")
);
}
matched
} else {
platforms::detect_platforms()
};
if platforms.is_empty() {
println!("No AI coding platforms detected.");
println!();
println!("Supported platforms:");
for p in platforms::all_platforms() {
println!(" {} ({})", p.name, p.display_name);
}
println!();
println!("Install one of these, then run `kodegraf install` again.");
println!("Or target a specific platform: `kodegraf install --platform claude-code`");
return Ok(());
}
println!("Detected {} platform(s):", platforms.len());
for p in &platforms {
println!(" {} ({})", p.display_name, p.name);
}
println!();
if dry_run {
println!("[dry-run] Would configure:");
println!();
println!(" MCP configs:");
for p in &platforms {
let entry = platforms::mcp_server_entry();
println!(" {}: {}", p.display_name, serde_json::to_string_pretty(&entry)?);
}
println!();
println!(" Instruction files: CLAUDE.md, AGENTS.md, .cursorrules, .windsurfrules");
println!(" Hooks: .claude/settings.json (PostToolUse + SessionStart)");
println!(" Skills: .claude/skills/ (4 workflow skills)");
println!(" Auto: init + build (if not already built)");
println!();
println!("Run without --dry-run to apply changes.");
return Ok(());
}
let config_path = Config::config_path(&repo_root);
let db_path = Config::graph_db_path(&repo_root);
let cfg = if config_path.exists() {
println!("Config: already initialized.");
Config::load(&config_path)?
} else {
println!("Initializing Kodegraf...");
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)?;
println!(" Config: .kodegraf/config.toml ({})", cfg.scan.languages.join(", "));
cfg
};
let needs_build = if db_path.exists() {
let store = GraphStore::open(&db_path)?;
let stats = store.get_stats()?;
stats.total_nodes == 0
} else {
true
};
if needs_build {
println!();
println!("Building knowledge graph...");
let store = GraphStore::open(&db_path)?;
let result = build::full_build(&repo_root, &cfg, &store)?;
let stats = store.get_stats()?;
println!(
" {} files parsed → {} nodes, {} edges ({})",
result.files_parsed,
stats.total_nodes,
stats.total_edges,
if stats.languages.is_empty() { "no languages".to_string() } else { stats.languages.join(", ") }
);
} else {
println!("Graph: already built (use `kodegraf build` to rebuild).");
}
println!();
println!("MCP server configs:");
for p in &platforms {
let path = platforms::write_platform_config(p, &repo_root)?;
println!(" {} → {}", p.display_name, path.display());
}
println!();
println!("Instruction files:");
let instruction_files = platforms::inject_all_instruction_files(&repo_root)?;
for file in &instruction_files {
println!(" {}", file);
}
println!();
let hooks_path = platforms::write_hooks_config(&repo_root)?;
println!("Hooks: {}", hooks_path.display());
println!(" PostToolUse → kodegraf update --fast (on Edit|Write|Bash)");
println!(" SessionStart → kodegraf session-greeting");
println!();
println!("Skills:");
let skills = platforms::write_skill_files(&repo_root)?;
for skill in &skills {
println!(" .claude/skills/{}", skill);
}
println!();
println!("Done. Open Claude Code — Kodegraf is ready.");
Ok(())
}