Files
zesdex/apps/infrastructure/src/tools/best_practice.rs
T
asepharyana 8ecc588a3e feat(best_practice): add code quality scanning and commit message validation
- Implemented a code quality scanner that checks for common clean-code violations in Rust source files, including missing documentation, usage of `.unwrap()` in production code, and commented-out code.
- Introduced a commit message validator that follows the Conventional Commits specification, ensuring proper formatting and providing suggestions for invalid messages.
- Created a unified BestPracticeEngine to encapsulate the functionalities of skills, architecture audits, code quality checks, and commit message validation.
- Added tests for both the code quality scanner and commit message validator to ensure reliability and correctness.
2026-07-21 07:21:22 +07:00

340 lines
14 KiB
Rust

//! Built-in best-practice tools for zesdex.
//!
//! These tools allow the LLM agent to run architecture audits, code-quality
//! scans, commit-message validation, and skill lookups — all as compiled-in
//! features of the zesdex binary.
//!
//! # Tools
//!
//! | Tool name | Action |
//! |-----------|--------|
//! | `best_practice` | Run architecture audit, code-quality scan, or skill lookup |
//! | `commit_convention` | Validate or suggest commit messages |
use crate::best_practice::BestPracticeEngine;
use crate::tools::{arg_str, Tool, ToolCtx};
use anyhow::{bail, Result};
use serde_json::{json, Value};
use std::sync::OnceLock;
use tracing::instrument;
// ---------------------------------------------------------------------------
// Shared engine instance (lazy, created once)
// ---------------------------------------------------------------------------
fn engine() -> &'static BestPracticeEngine {
static ENGINE: OnceLock<BestPracticeEngine> = OnceLock::new();
ENGINE.get_or_init(BestPracticeEngine::new)
}
// ───────────────────────────────────────────────────────────────────────────
// best_practice
// ───────────────────────────────────────────────────────────────────────────
/// Run best-practice audits (architecture, code quality, skills).
pub struct BestPractice;
impl Tool for BestPractice {
fn name(&self) -> &'static str {
"best_practice"
}
fn description(&self) -> &'static str {
"Run architecture audit, code-quality scan, embedded-skills lookup, \
or commit-message validation. Sub-actions: 'audit_all', 'audit_layering', \
'scan_quality', 'list_skills', 'get_skill', 'validate_commit', 'suggest_commit'."
}
fn parameters(&self) -> Value {
json!({
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"audit_all",
"audit_layering",
"scan_quality",
"list_skills",
"get_skill",
"validate_commit",
"suggest_commit"
],
"description": "Which action to perform"
},
"workspace": {
"type": "string",
"description": "Path to workspace root (required for audit/scan actions)"
},
"skill_name": {
"type": "string",
"description": "Skill name to retrieve (required for 'get_skill')"
},
"commit_message": {
"type": "string",
"description": "Commit message to validate (required for 'validate_commit')"
},
"commit_type": {
"type": "string",
"description": "Commit type for template suggestion (e.g. 'feat', 'fix')"
},
"commit_scope": {
"type": "string",
"description": "Optional scope for template suggestion"
}
},
"required": ["action"]
})
}
#[instrument(skip(self, _ctx, args))]
fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result<String> {
let action = arg_str(args, "action")?;
let eng = engine();
match action.as_str() {
"list_skills" => {
let skills = eng.list_skills();
let summaries = eng.skill_summaries();
let mut out = String::from("=== Embedded Best-Practice Skills ===\n\n");
for (name, desc) in &summaries {
out.push_str(&format!(" {name:<40} {desc}\n"));
}
if skills.is_empty() {
out.push_str(" (no skills embedded)\n");
}
Ok(out)
}
"get_skill" => {
let name = arg_str(args, "skill_name")?;
match eng.get_skill(&name) {
Some(content) => Ok(content.to_string()),
None => {
let available = eng.list_skills();
bail!(
"Skill '{name}' not found. Available skills: {}",
available.join(", ")
)
}
}
}
"validate_commit" => {
let msg = arg_str(args, "commit_message")?;
match eng.validate_commit(&msg) {
Ok(()) => Ok("✅ Commit message is valid.".to_string()),
Err(errors) => {
let mut out = String::from("❌ Commit message validation failed:\n");
for err in &errors {
out.push_str(&format!(" - {err}\n"));
}
// Suggest a template.
if let Some(parsed) = eng.parse_commit(&msg) {
let tpl = eng.suggest_commit_template(&parsed.type_, parsed.scope.as_deref());
out.push_str(&format!("\nTemplate: {tpl}\n"));
}
Ok(out)
}
}
}
"suggest_commit" => {
let type_ = arg_str(args, "commit_type")?;
let scope = args.get("commit_scope").and_then(|v| v.as_str());
let tpl = eng.suggest_commit_template(&type_, scope);
Ok(format!(
"Suggested commit template:\n\n {tpl}\n\n\
Valid types: feat, fix, chore, docs, refactor, test, style, perf, ci, build, revert"
))
}
"audit_layering" | "audit_all" | "scan_quality" => {
let workspace = match args.get("workspace").and_then(|v| v.as_str()) {
Some(w) => w.to_string(),
None => bail!("'workspace' argument is required for '{action}'"),
};
let ws_path = std::path::Path::new(&workspace);
// Use the host's dirs data dir when workspace is the default data directory.
let report = match action.as_str() {
"audit_layering" => {
let r = eng.audit_layering(ws_path)?;
let mut out = format!(
"=== Architecture Layering Audit ===\n\
Files scanned: {}\n",
r.files_scanned
);
if r.violations.is_empty() {
out.push_str(" ✅ No layering violations found.\n");
} else {
out.push_str(&format!(" Errors: {}\n", r.error_count()));
out.push_str(&format!(" Warnings: {}\n", r.warning_count()));
for v in &r.violations {
out.push_str(&format!(
" [{}] {}:{}{}\n",
v.severity, v.file, v.line, v.message
));
}
}
out
}
"scan_quality" => {
let r = eng.scan_quality(ws_path)?;
let mut out = format!(
"=== Code Quality Scan ===\n\
Files scanned: {}\n",
r.files_scanned
);
if r.findings.is_empty() {
out.push_str(" ✅ No code-quality issues found.\n");
} else {
let by_rule = r.count_by_rule();
out.push_str(" By rule:\n");
for (rule, count) in &by_rule {
out.push_str(&format!(" {rule}: {count}\n"));
}
for f in r.findings.iter().take(15) {
out.push_str(&format!(
" [{}] {}:{}{}: {}\n",
f.severity, f.file, f.line, f.rule, f.message
));
}
if r.findings.len() > 15 {
out.push_str(&format!(
" ... and {} more findings.\n",
r.findings.len() - 15
));
}
}
out
}
_ => {
let combined = eng.audit_all(ws_path)?;
combined.format()
}
};
Ok(report)
}
other => bail!("Unknown action '{other}'"),
}
}
}
// ───────────────────────────────────────────────────────────────────────────
// commit_convention
// ───────────────────────────────────────────────────────────────────────────
/// Dedicated commit-message validation tool.
pub struct CommitConvention;
impl Tool for CommitConvention {
fn name(&self) -> &'static str {
"commit_convention"
}
fn description(&self) -> &'static str {
"Validate a git commit message against Conventional Commits format (Bahasa Indonesia). \
Checks type, scope, description casing, length, and punctuation."
}
fn parameters(&self) -> Value {
json!({
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The full commit message to validate"
}
},
"required": ["message"]
})
}
#[instrument(skip(self, _ctx, args))]
fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result<String> {
let msg = arg_str(args, "message")?;
let eng = engine();
// Try to parse for additional context.
let info = eng.parse_commit(&msg);
match eng.validate_commit(&msg) {
Ok(()) => {
let mut out = String::from("✅ Valid Conventional Commit.\n");
if let Some(i) = info {
out.push_str(&format!(" Type: {}\n", i.type_));
if let Some(ref s) = i.scope {
out.push_str(&format!(" Scope: {s}\n"));
}
out.push_str(&format!(" Breaking: {}\n", i.breaking));
out.push_str(&format!(" Description: {}\n", i.description));
}
Ok(out)
}
Err(errors) => {
let mut out = String::from("❌ Invalid commit message:\n");
for err in &errors {
out.push_str(&format!(" - {err}\n"));
}
// Provide a template suggestion.
out.push_str("\nExpected format:\n");
out.push_str(" feat(scope): <imperative description>\n");
out.push_str(" fix(scope): <imperative description>\n");
out.push_str(" chore: <imperative description>\n");
out.push_str(" docs: <imperative description>\n");
Ok(out)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_ctx() -> ToolCtx {
// Minimal context for unit tests
let temp = std::env::temp_dir().join("zesdex-bptest");
let _ = std::fs::create_dir_all(&temp);
ToolCtx::builder()
.workspaces(vec![temp.clone()])
.session_dir(temp.clone())
.build()
}
#[test]
fn best_practice_list_skills() {
let tool = BestPractice;
let args = json!({"action": "list_skills"});
let result = tool.run(&test_ctx(), &args).unwrap();
assert!(result.contains("clean-code"), "should list clean-code: {result}");
assert!(result.contains("commit-convention"), "should list commit-convention: {result}");
}
#[test]
fn best_practice_get_skill() {
let tool = BestPractice;
let args = json!({"action": "get_skill", "skill_name": "clean-code"});
let result = tool.run(&test_ctx(), &args).unwrap();
assert!(result.contains("Clean Code"), "should contain skill content: {result}");
}
#[test]
fn commit_convention_valid() {
let tool = CommitConvention;
let args = json!({"message": "feat(tool): add best practice audit"});
let result = tool.run(&test_ctx(), &args).unwrap();
assert!(result.contains("✅"), "valid commit should succeed: {result}");
}
#[test]
fn commit_convention_invalid() {
let tool = CommitConvention;
let args = json!({"message": "Add new feature"});
let result = tool.run(&test_ctx(), &args).unwrap();
assert!(result.contains("❌"), "invalid commit should fail: {result}");
}
}