pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
//! Agent Context Query Demo - RAG-Powered Semantic Code Search
//!
//! Demonstrates PMAT's agent context system that indexes functions with
//! quality metadata (TDG, complexity, SATD, Big-O) and enables semantic
//! search via `pmat query`.
//!
//! Unlike grep, `pmat query` understands intent and returns quality-ranked
//! results with full signatures, documentation, and metrics.
//!
//! # Run
//! ```bash
//! cargo run --example agent_context_query_demo
//! ```

use std::path::Path;
use std::process::Command;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("================================================================");
    println!("  PMAT Agent Context Demo (RAG-Powered Semantic Code Search)");
    println!("================================================================\n");

    let pmat = find_pmat_binary()?;
    let project_dir = std::env::current_dir()?;

    // Demo 1: Basic semantic search
    println!("----------------------------------------------------------------");
    println!("  Demo 1: Semantic Search - Find by Intent");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"error handling\" --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "error handling", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 2: Quality-filtered search
    println!("\n----------------------------------------------------------------");
    println!("  Demo 2: Quality-Filtered Search (TDG grade + complexity)");
    println!("----------------------------------------------------------------\n");
    println!(
        "Command: pmat query \"complexity analysis\" --min-grade A --max-complexity 10 --limit 5\n"
    );

    let output = Command::new(&pmat)
        .args([
            "query",
            "complexity analysis",
            "--min-grade",
            "A",
            "--max-complexity",
            "10",
            "--limit",
            "5",
        ])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 3: JSON output for scripting/CI
    println!("\n----------------------------------------------------------------");
    println!("  Demo 3: JSON Output (for CI/CD and scripting)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"MCP tool\" --format json --limit 3\n");

    let output = Command::new(&pmat)
        .args(["query", "MCP tool", "--format", "json", "--limit", "3"])
        .current_dir(&project_dir)
        .output()?;

    // Pretty-print first 40 lines of JSON
    let stdout = String::from_utf8_lossy(&output.stdout);
    for line in stdout.lines().take(40) {
        println!("{}", line);
    }
    if stdout.lines().count() > 40 {
        println!("... (output truncated)");
    }

    // Demo 4: Markdown output for documentation
    println!("\n----------------------------------------------------------------");
    println!("  Demo 4: Markdown Output (for docs and reports)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"TDG scoring\" --format markdown --limit 3\n");

    let output = Command::new(&pmat)
        .args([
            "query",
            "TDG scoring",
            "--format",
            "markdown",
            "--limit",
            "3",
        ])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 5: Language-filtered search
    println!("\n----------------------------------------------------------------");
    println!("  Demo 5: Language-Filtered Search");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"validation\" --language rust --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "validation", "--language", "rust", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 6: PageRank ranking (most important functions)
    println!("\n----------------------------------------------------------------");
    println!("  Demo 6: PageRank Ranking (most important functions)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"error\" --rank-by pagerank --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "error", "--rank-by", "pagerank", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 7: InDegree ranking (most called functions)
    println!("\n----------------------------------------------------------------");
    println!("  Demo 7: InDegree Ranking (most called functions)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"format\" --rank-by indegree --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "format", "--rank-by", "indegree", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 8: Centrality ranking (most connected functions)
    println!("\n----------------------------------------------------------------");
    println!("  Demo 8: Centrality Ranking (hub functions)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"parse\" --rank-by centrality --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "parse", "--rank-by", "centrality", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 9: PageRank filter with JSON
    println!("\n----------------------------------------------------------------");
    println!("  Demo 9: PageRank Filter + JSON (find important MCP code)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"mcp\" --min-pagerank 0.0001 --format json --limit 3\n");

    let output = Command::new(&pmat)
        .args([
            "query",
            "mcp",
            "--min-pagerank",
            "0.0001",
            "--format",
            "json",
            "--limit",
            "3",
        ])
        .current_dir(&project_dir)
        .output()?;

    // Pretty-print JSON
    let stdout = String::from_utf8_lossy(&output.stdout);
    for line in stdout.lines().take(50) {
        println!("{}", line);
    }
    if stdout.lines().count() > 50 {
        println!("... (output truncated)");
    }

    // Demo 10: Coverage Gap Analysis (no query needed)
    println!("\n----------------------------------------------------------------");
    println!("  Demo 10: Coverage Gap Analysis (--coverage-gaps)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query --coverage-gaps --limit 10 --exclude-tests\n");

    let output = Command::new(&pmat)
        .args([
            "query",
            "--coverage-gaps",
            "--limit",
            "10",
            "--exclude-tests",
        ])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 11: Coverage-enriched semantic search
    println!("\n----------------------------------------------------------------");
    println!("  Demo 11: Coverage-Enriched Search (--coverage)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"error handling\" --coverage --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "error handling", "--coverage", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 12: Regex search (rg-like)
    println!("\n----------------------------------------------------------------");
    println!("  Demo 12: Regex Search (--regex, like rg -e)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query --regex \"fn\\s+handle_\\w+\" --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "--regex", r"fn\s+handle_\w+", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 13: Literal search (rg -F like)
    println!("\n----------------------------------------------------------------");
    println!("  Demo 13: Literal Search (--literal, like rg -F)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query --literal \"unwrap()\" --exclude-tests --limit 5\n");

    let output = Command::new(&pmat)
        .args([
            "query",
            "--literal",
            "unwrap()",
            "--exclude-tests",
            "--limit",
            "5",
        ])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 14: Fault-enriched search
    println!("\n----------------------------------------------------------------");
    println!("  Demo 14: Fault Pattern Search (--faults)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"parse\" --faults --exclude-tests --limit 5\n");

    let output = Command::new(&pmat)
        .args([
            "query",
            "parse",
            "--faults",
            "--exclude-tests",
            "--limit",
            "5",
        ])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 15: Churn + Entropy enrichment
    println!("\n----------------------------------------------------------------");
    println!("  Demo 15: Multi-Enrichment (--churn --entropy)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"cache\" --churn --entropy --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "cache", "--churn", "--entropy", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Demo 16: Git history fusion
    println!("\n----------------------------------------------------------------");
    println!("  Demo 16: Git History Fusion (-G, search by commit intent)");
    println!("----------------------------------------------------------------\n");
    println!("Command: pmat query \"fix memory\" -G --limit 5\n");

    let output = Command::new(&pmat)
        .args(["query", "fix memory", "-G", "--limit", "5"])
        .current_dir(&project_dir)
        .output()?;

    print_output(&output);

    // Summary: grep vs pmat query comparison
    println!("\n================================================================");
    println!("  Why pmat query > grep for agents");
    println!("================================================================\n");

    println!("  grep -r \"error\" src/ | head -5");
    println!("  -> 500+ irrelevant matches, no context, no quality info\n");

    println!("  pmat query \"error handling\" --min-grade B --limit 5");
    println!("  -> 5 quality-ranked results with:");
    println!("     - Full function signatures");
    println!("     - TDG grades and complexity scores");
    println!("     - Big-O estimates");
    println!("     - Documentation strings");
    println!("     - Relevance scores");
    println!("     - Graph metrics (PageRank, in/out degree)\n");

    println!("  Coverage gap analysis:");
    println!("  - --coverage-gaps      (find uncovered code, no query needed)");
    println!("  - --coverage           (enrich results with line coverage)");
    println!("  - --uncovered-only     (filter to uncovered functions)\n");

    println!("  Search modes (grep/rg replacement):");
    println!("  - --regex PATTERN      (regex search, like rg -e)");
    println!("  - --literal STRING     (exact match, like rg -F)");
    println!("  - --raw                (file-level search, bypass AST index)\n");

    println!("  Enrichment flags:");
    println!("  - --churn              (git volatility metrics)");
    println!("  - --duplicates         (code clone detection)");
    println!("  - --entropy            (pattern diversity)");
    println!("  - --faults             (fault pattern annotations)");
    println!("  - -G / --git-history   (commit intent fusion)\n");

    println!("  Graph-aware ranking options:");
    println!("  - --rank-by relevance  (default: semantic similarity)");
    println!("  - --rank-by pagerank   (most important functions)");
    println!("  - --rank-by indegree   (most called functions)");
    println!("  - --rank-by centrality (hub functions)");
    println!("  - --rank-by impact     (ROI: missed_lines * pagerank)\n");

    println!("  Agent context is also available via MCP tools:");
    println!("  - pmat_query_code: Semantic search by intent");
    println!("  - pmat_get_function: Get full function with metrics");
    println!("  - pmat_find_similar: Find similar functions");
    println!("  - pmat_index_stats: Index health and statistics\n");

    println!("Done.");
    Ok(())
}

fn print_output(output: &std::process::Output) {
    let stdout = String::from_utf8_lossy(&output.stdout);
    // Skip index-building lines, show results
    for line in stdout.lines() {
        if !line.starts_with("Building index") && !line.starts_with("Loading index") {
            println!("{}", line);
        }
    }
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        if !stderr.is_empty() {
            eprintln!("stderr: {}", stderr);
        }
    }
}

fn find_pmat_binary() -> Result<String, Box<dyn std::error::Error>> {
    // Prefer installed pmat (has latest features) over local builds
    if let Ok(output) = Command::new("pmat").arg("--version").output() {
        if output.status.success() {
            return Ok("pmat".to_string());
        }
    }

    // Fall back to local builds
    let release_path = Path::new("target/release/pmat");
    if release_path.exists() {
        return Ok(release_path.to_string_lossy().to_string());
    }

    let debug_path = Path::new("target/debug/pmat");
    if debug_path.exists() {
        return Ok(debug_path.to_string_lossy().to_string());
    }

    Err("pmat binary not found. Run 'cargo install --path .' first.".into())
}