Menyeragamkan format kode sesuai rustfmt (126 file). Sebelumnya lefthook pre-commit 'cargo fmt --check' akan gagal pada commit apa pun.
187 lines
6.6 KiB
Rust
187 lines
6.6 KiB
Rust
//! # Built-in Kana Engineering Best Practices Engine
|
|
//!
|
|
//! This module provides compile-time embedded skills, architecture audit,
|
|
//! code-quality scanning, and commit-message validation as **built-in**
|
|
//! features of the zesdex binary — not external configuration files.
|
|
//!
|
|
//! ## Modules
|
|
//!
|
|
//! | Module | Purpose |
|
|
//! |--------|---------|
|
|
//! | [`skills`] | Compile-time embedded skill markdown files via `include_dir!` |
|
|
//! | [`arch_audit`] | Clean-architecture layering violation scanner |
|
|
//! | [`code_quality`] | Clean-code rule checker (unwrap, missing docs, etc.) |
|
|
//! | [`commit`] | Conventional Commits message validator |
|
|
//!
|
|
//! ## Usage
|
|
//!
|
|
//! The [`BestPracticeEngine`] struct provides a unified API that tools call.
|
|
//! New tool implementations in `crate::tools::best_practice` delegate to this
|
|
//! engine.
|
|
|
|
pub mod arch_audit;
|
|
pub mod code_quality;
|
|
pub mod commit;
|
|
pub mod explore;
|
|
pub mod skills;
|
|
|
|
use anyhow::Result;
|
|
use std::path::Path;
|
|
|
|
/// Unified engine for all best-practice operations.
|
|
///
|
|
/// Wraps the individual audit, quality, and commit modules behind a single
|
|
/// struct that tools and subagents can call without knowing the module layout.
|
|
#[derive(Default)]
|
|
pub struct BestPracticeEngine {
|
|
/// Compile-time embedded skills, lazy-loaded.
|
|
embedded_skills: std::sync::OnceLock<skills::EmbeddedSkills>,
|
|
}
|
|
|
|
impl BestPracticeEngine {
|
|
/// Create a new engine (skills index is built lazily on first access).
|
|
pub fn new() -> Self {
|
|
BestPracticeEngine {
|
|
embedded_skills: std::sync::OnceLock::new(),
|
|
}
|
|
}
|
|
|
|
// ── Skills ─────────────────────────────────────────────────────────
|
|
|
|
/// Access the embedded skills index.
|
|
pub fn skills(&self) -> &skills::EmbeddedSkills {
|
|
self.embedded_skills
|
|
.get_or_init(skills::EmbeddedSkills::load)
|
|
}
|
|
|
|
/// List all available embedded-skills names.
|
|
pub fn list_skills(&self) -> Vec<&'static str> {
|
|
self.skills().list()
|
|
}
|
|
|
|
/// Get the full content of a skill by name.
|
|
pub fn get_skill(&self, name: &str) -> Option<&'static str> {
|
|
self.skills().get(name)
|
|
}
|
|
|
|
/// Get skill summaries (name + description).
|
|
pub fn skill_summaries(&self) -> Vec<(&'static str, &'static str)> {
|
|
self.skills().summaries()
|
|
}
|
|
|
|
// ── Architecture Audit ─────────────────────────────────────────────
|
|
|
|
/// Run a full architecture layering audit on a workspace directory.
|
|
pub fn audit_layering(&self, workspace_root: &Path) -> Result<arch_audit::AuditReport> {
|
|
arch_audit::audit_layering(workspace_root)
|
|
}
|
|
|
|
// ── Code Quality ───────────────────────────────────────────────────
|
|
|
|
/// Run a full code-quality scan on a workspace directory.
|
|
pub fn scan_quality(&self, workspace_root: &Path) -> Result<code_quality::CodeQualityReport> {
|
|
code_quality::scan_quality(workspace_root)
|
|
}
|
|
|
|
// ── Commit Convention ──────────────────────────────────────────────
|
|
|
|
/// Validate a commit message against Conventional Commits.
|
|
pub fn validate_commit(&self, message: &str) -> Result<(), Vec<String>> {
|
|
commit::validate_commit_message(message)
|
|
}
|
|
|
|
/// Parse a commit message into its structured fields.
|
|
pub fn parse_commit(&self, message: &str) -> Option<commit::CommitInfo> {
|
|
commit::parse_commit_message(message)
|
|
}
|
|
|
|
/// Get a commit template suggestion.
|
|
pub fn suggest_commit_template(&self, type_: &str, scope: Option<&str>) -> String {
|
|
commit::suggest_template(type_, scope)
|
|
}
|
|
|
|
// ── Combined Audit ─────────────────────────────────────────────────
|
|
|
|
/// Run all audits (layering + code quality) and return combined results.
|
|
pub fn audit_all(&self, workspace_root: &Path) -> Result<CombinedAuditReport> {
|
|
let layering = self.audit_layering(workspace_root)?;
|
|
let quality = self.scan_quality(workspace_root)?;
|
|
|
|
Ok(CombinedAuditReport { layering, quality })
|
|
}
|
|
}
|
|
|
|
/// Combined report from all audits.
|
|
#[derive(Debug, Clone)]
|
|
pub struct CombinedAuditReport {
|
|
pub layering: arch_audit::AuditReport,
|
|
pub quality: code_quality::CodeQualityReport,
|
|
}
|
|
|
|
impl CombinedAuditReport {
|
|
/// Format the full report as a human-readable string.
|
|
pub fn format(&self) -> String {
|
|
let mut out = String::new();
|
|
|
|
// ── Layering ──
|
|
out.push_str(&format!(
|
|
"=== Architecture Layering Audit ===\n\
|
|
Files scanned: {}\n",
|
|
self.layering.files_scanned
|
|
));
|
|
if self.layering.violations.is_empty() {
|
|
out.push_str(" ✅ No layering violations found.\n");
|
|
} else {
|
|
for v in &self.layering.violations {
|
|
out.push_str(&format!(
|
|
" [{}] {}:{} — {}\n",
|
|
v.severity, v.file, v.line, v.message
|
|
));
|
|
}
|
|
}
|
|
|
|
// ── Code Quality ──
|
|
out.push_str(&format!(
|
|
"\n=== Code Quality Scan ===\n\
|
|
Files scanned: {}\n",
|
|
self.quality.files_scanned
|
|
));
|
|
if self.quality.findings.is_empty() {
|
|
out.push_str(" ✅ No code-quality issues found.\n");
|
|
} else {
|
|
let by_rule = self.quality.count_by_rule();
|
|
out.push_str(" By rule:\n");
|
|
for (rule, count) in &by_rule {
|
|
out.push_str(&format!(" {rule}: {count}\n"));
|
|
}
|
|
out.push_str(" Top findings:\n");
|
|
for f in self.quality.findings.iter().take(20) {
|
|
out.push_str(&format!(
|
|
" [{}] {}:{} — {}: {}\n",
|
|
f.severity, f.file, f.line, f.rule, f.message
|
|
));
|
|
}
|
|
if self.quality.findings.len() > 20 {
|
|
out.push_str(&format!(
|
|
" ... and {} more findings.\n",
|
|
self.quality.findings.len() - 20
|
|
));
|
|
}
|
|
}
|
|
|
|
out
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn engine_lists_skills() {
|
|
let engine = BestPracticeEngine::new();
|
|
let names = engine.list_skills();
|
|
assert!(names.contains(&"clean-code"));
|
|
}
|
|
}
|