repopilot 0.8.0

Local-first CLI for repository audit, architecture risk detection, baseline tracking, and CI-friendly code review.
Documentation
use crate::audits::traits::ProjectAudit;
use crate::findings::types::{Evidence, Finding, FindingCategory, Severity};
use crate::scan::config::ScanConfig;
use crate::scan::facts::ScanFacts;
use std::path::PathBuf;

pub struct DeepNestingAudit;

impl ProjectAudit for DeepNestingAudit {
    fn audit(&self, facts: &ScanFacts, config: &ScanConfig) -> Vec<Finding> {
        let root_depth = facts.root_path.components().count();

        let deepest = facts
            .files
            .iter()
            .filter_map(|file| {
                let depth = file.path.components().count().saturating_sub(root_depth);
                if depth > config.max_directory_depth {
                    Some((file.path.clone(), depth))
                } else {
                    None
                }
            })
            .max_by_key(|(_, depth)| *depth);

        match deepest {
            None => vec![],
            Some((path, depth)) => vec![build_finding(path, depth, config.max_directory_depth)],
        }
    }
}

fn build_finding(deepest_path: PathBuf, depth: usize, threshold: usize) -> Finding {
    Finding {
        id: String::new(),
        rule_id: "architecture.deep-nesting".to_string(),
        title: "Deeply nested directory structure detected".to_string(),
        description: format!(
            "The project contains files nested {depth} levels deep, exceeding the threshold of {threshold}. Deep nesting often indicates over-engineered module hierarchies."
        ),
        category: FindingCategory::Architecture,
        severity: Severity::Low,
        evidence: vec![Evidence {
            path: deepest_path,
            line_start: 1,
            line_end: None,
            snippet: format!("Nesting depth: {depth}; threshold is {threshold}."),
        }],
        workspace_package: None,
        docs_url: None,
    }
}