repopilot 0.13.0

Local-first CLI for repository audit, architecture risk detection, baseline tracking, and CI-friendly code review.
Documentation
pub fn config_fingerprint(config: &ScanConfig) -> String {
    let input = CacheFingerprintInput {
        cache_schema_version: CACHE_SCHEMA_VERSION,
        repopilot_version: env!("CARGO_PKG_VERSION"),
        scan_config: config,
        file_audits: registered_file_audits(config)
            .into_iter()
            .map(|registration| AuditFingerprint {
                audit_id: registration.metadata.audit_id,
                kind: registration.metadata.kind.label(),
                category: registration.metadata.category,
                rule_ids: registration.metadata.rule_ids.to_vec(),
            })
            .collect(),
        project_audits: registered_project_audits(config)
            .into_iter()
            .map(|registration| AuditFingerprint {
                audit_id: registration.metadata.audit_id,
                kind: registration.metadata.kind.label(),
                category: registration.metadata.category,
                rule_ids: registration.metadata.rule_ids.to_vec(),
            })
            .collect(),
        rules: all_rule_metadata()
            .map(|rule| RuleFingerprint {
                rule_id: rule.rule_id,
                title: rule.title,
                category: rule.category.clone(),
                default_severity: rule.default_severity,
                docs_url: rule.docs_url,
                description: rule.description,
                recommendation: rule.recommendation,
            })
            .collect(),
    };

    match serde_json::to_vec(&input) {
        Ok(bytes) => stable_hash_hex(&bytes),
        Err(_) => stable_hash_hex(format!("{config:?}:{}", CACHE_SCHEMA_VERSION).as_bytes()),
    }
}

pub fn stable_hash_hex(bytes: &[u8]) -> String {
    let digest = Sha256::digest(bytes);
    digest.iter().map(|byte| format!("{byte:02x}")).collect()
}

#[derive(Serialize)]
struct CacheFingerprintInput<'a> {
    cache_schema_version: u32,
    repopilot_version: &'static str,
    scan_config: &'a ScanConfig,
    file_audits: Vec<AuditFingerprint>,
    project_audits: Vec<AuditFingerprint>,
    rules: Vec<RuleFingerprint>,
}

#[derive(Serialize)]
struct AuditFingerprint {
    audit_id: &'static str,
    kind: &'static str,
    category: FindingCategory,
    rule_ids: Vec<&'static str>,
}

#[derive(Serialize)]
struct RuleFingerprint {
    rule_id: &'static str,
    title: &'static str,
    category: FindingCategory,
    default_severity: Severity,
    docs_url: Option<&'static str>,
    description: &'static str,
    recommendation: Option<&'static str>,
}