rtk-context-engine 2.3.0

RTK — main entrypoint binary and command router CLI
use anyhow::Result;
use std::path::Path;

pub fn symbols_find(query: &str) -> Result<()> {
    let list = rtk_index::query_symbols(query)?;
    if list.is_empty() {
        println!("No symbols found matching: '{}'", query);
        return Ok(());
    }

    println!(
        "{:<12} | {:<40} | {:<10} | Name",
        "Kind", "File Path", "Lines"
    );
    println!("{}", "-".repeat(90));
    for sym in list {
        let lines = format!("{}-{}", sym.line_start, sym.line_end);
        println!(
            "{:<12} | {:<40} | {:<10} | {}",
            sym.kind, sym.file_path, lines, sym.name
        );
    }
    Ok(())
}

pub fn deps_show(file: &str) -> Result<()> {
    let list = rtk_index::query_dependencies(file)?;
    if list.is_empty() {
        println!("No symbol dependencies tracked for file: '{}'", file);
        return Ok(());
    }

    println!("Dependencies for file: {}", file);
    println!("{}", "=".repeat(60));
    for (sym, callees) in list {
        if callees.is_empty() {
            println!("{} ({}) calls: None", sym.name, sym.kind);
        } else {
            println!("{} ({}) calls: {}", sym.name, sym.kind, callees.join(", "));
        }
    }
    Ok(())
}

pub fn refs_find(symbol: &str) -> Result<()> {
    let list = rtk_index::query_references(symbol)?;
    if list.is_empty() {
        println!("No references found calling symbol name: '{}'", symbol);
        return Ok(());
    }

    println!("References calling: {}", symbol);
    println!("{}", "-".repeat(60));
    for sym in list {
        println!(
            "- {} ({}) in {}:{}",
            sym.name, sym.kind, sym.file_path, sym.line_start
        );
    }
    Ok(())
}

pub fn impact_analyze(symbol: &str) -> Result<()> {
    let list = rtk_index::analyze_impact(symbol)?;
    if list.is_empty() {
        println!(
            "No upstream blast radius found for: '{}' (or symbol not found)",
            symbol
        );
        return Ok(());
    }

    let risk = if list.len() > 10 {
        "HIGH"
    } else if list.len() > 3 {
        "MEDIUM"
    } else {
        "LOW"
    };

    println!("Blast Radius Impact Analysis for: {}", symbol);
    println!("Risk Level: {}", risk);
    println!("Affected transitively upstream ({} symbols):", list.len());
    println!("{}", "-".repeat(60));
    for sym in list {
        println!(
            "- {} ({}) in {}:{}",
            sym.name, sym.kind, sym.file_path, sym.line_start
        );
    }
    Ok(())
}

pub fn index_run() -> Result<()> {
    println!("🔍 Indexing codebase AST...");
    let count = rtk_index::index_project(Path::new("."))?;
    println!("✅ Indexed {} symbols successfully.", count);
    Ok(())
}

pub fn graph_export(format: &str, output: &str) -> Result<()> {
    if format.to_lowercase() != "obsidian" {
        return Err(anyhow::anyhow!(
            "Unsupported format: '{}'. Currently supported formats: obsidian",
            format
        ));
    }

    println!(
        "Graph export starting... format: {}, output: {}",
        format, output
    );
    let count = rtk_index::export_obsidian_graph(Path::new(output))?;
    println!(
        "✅ Obsidian graph exported successfully ({} symbol markdown files created in '{}')",
        count, output
    );
    Ok(())
}

pub fn audit_graph() -> Result<()> {
    let metrics = rtk_index::get_graph_metrics()?;
    println!("📊 RTK Code Intelligence Graph Audit Report");
    println!("==========================================");
    println!("Total Symbols:      {}", metrics.symbols_count);
    println!("Total Edges/Calls:  {}", metrics.edges_count);
    println!("Graph Coverage:     {:.2}%", metrics.graph_coverage);
    println!("Query Latency:      {:.4} ms", metrics.query_latency_ms);
    println!("==========================================");
    Ok(())
}