Fix 18 clippy errors across 7 files: - lib.rs: change doc comment to regular comment (empty line after doc) - arch_audit.rs: replace format!() with string literal, use is_none_or - code_quality.rs: collapsible if, map_or → is_none_or - commit.rs: collapsible match guard - explore.rs: needless_range_loop → iterator enumerate - skills.rs: map_or(false,...) → is_some_and - semantic_search.rs: map_or → is_none_or, sort_by → sort_by_key, remove explicit type to avoid type_complexity CI was failing with 'error: could not compile zesdex-infrastructure due to 18 previous errors' at clippy step.
153 lines
5.1 KiB
Rust
153 lines
5.1 KiB
Rust
//! Embedding Kana Engineering best-practice skills as compiled-in static assets.
|
|
//!
|
|
//! Skill markdown files from `apps/infrastructure/skills/` are embedded at
|
|
//! compile time via `include_dir!` and served through [`EmbeddedSkills`].
|
|
//!
|
|
//! # Flow
|
|
//!
|
|
//! `EmbeddedSkills::load()` reads the compile-time directory tree → indexes
|
|
//! every `SKILL.md` by its parent directory name → exposes lookup / listing.
|
|
|
|
use include_dir::{include_dir, Dir, DirEntry};
|
|
use std::collections::HashMap;
|
|
|
|
/// The compile-time-embedded skills directory tree.
|
|
static SKILLS_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/skills");
|
|
|
|
/// Index of embedded best-practice skills, built once at startup.
|
|
///
|
|
/// Each skill is identified by its directory name (e.g. `"clean-code"`) and
|
|
/// its content is the full text of `SKILL.md` within that directory.
|
|
pub struct EmbeddedSkills {
|
|
skills: HashMap<&'static str, &'static str>,
|
|
}
|
|
|
|
impl EmbeddedSkills {
|
|
/// Walk the embedded directory tree and build the skill index.
|
|
///
|
|
/// Flow: iterate `Dir::entries()` → find every `SKILL.md` file →
|
|
/// store `(parent_dir_name, file_contents)` in the map.
|
|
pub fn load() -> Self {
|
|
let mut skills: HashMap<&str, &str> = HashMap::new();
|
|
|
|
fn walk<'a>(dir: &Dir<'a>, skills: &mut HashMap<&'a str, &'a str>) {
|
|
for entry in dir.entries() {
|
|
match entry {
|
|
DirEntry::Dir(sub) => walk(sub, skills),
|
|
DirEntry::File(file) => {
|
|
if file.path().file_name().is_some_and(|n| n == "SKILL.md") {
|
|
if let Some(parent) = file
|
|
.path()
|
|
.parent()
|
|
.and_then(|p| p.file_name())
|
|
.and_then(|n| n.to_str())
|
|
{
|
|
if let Some(content) = file.contents_utf8() {
|
|
skills.entry(parent).or_insert(content);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
walk(&SKILLS_DIR, &mut skills);
|
|
EmbeddedSkills { skills }
|
|
}
|
|
|
|
/// Return the full `SKILL.md` content for a named skill, if present.
|
|
pub fn get(&self, name: &str) -> Option<&'static str> {
|
|
self.skills.get(name).copied()
|
|
}
|
|
|
|
/// List all available skill names.
|
|
pub fn list(&self) -> Vec<&'static str> {
|
|
let mut names: Vec<&str> = self.skills.keys().copied().collect();
|
|
names.sort();
|
|
names
|
|
}
|
|
|
|
/// Return an iterator of `(name, trimmed_description)` pairs.
|
|
///
|
|
/// Description is extracted from the YAML frontmatter `description:` field.
|
|
pub fn summaries(&self) -> Vec<(&'static str, &'static str)> {
|
|
let mut out: Vec<(&str, &str)> = Vec::new();
|
|
for name in self.list() {
|
|
let content = self.skills.get(name).copied().unwrap_or("");
|
|
let desc = Self::extract_description(content).unwrap_or("");
|
|
out.push((name, desc));
|
|
}
|
|
out
|
|
}
|
|
|
|
/// Extract the `description:` field from YAML frontmatter.
|
|
fn extract_description(content: &str) -> Option<&str> {
|
|
let lines: Vec<&str> = content.lines().collect();
|
|
if lines.first()? != &"---" {
|
|
return None;
|
|
}
|
|
for line in &lines[1..] {
|
|
if let Some(rest) = line.strip_prefix("description: ") {
|
|
return Some(rest.trim());
|
|
}
|
|
if line == &"---" {
|
|
break;
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn embedded_skills_loads_known_skills() {
|
|
let skills = EmbeddedSkills::load();
|
|
let names = skills.list();
|
|
assert!(
|
|
names.contains(&"clean-code"),
|
|
"expected clean-code skill, got {names:?}"
|
|
);
|
|
assert!(
|
|
names.contains(&"commit-convention"),
|
|
"expected commit-convention skill, got {names:?}"
|
|
);
|
|
assert!(
|
|
names.contains(&"kana-rust-backend-best-practice"),
|
|
"expected kana-rust-backend-best-practice skill, got {names:?}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn each_skill_has_content() {
|
|
let skills = EmbeddedSkills::load();
|
|
for name in skills.list() {
|
|
let content = skills.get(name);
|
|
assert!(content.is_some(), "skill '{name}' has no content");
|
|
assert!(
|
|
content.unwrap().len() > 50,
|
|
"skill '{name}' content suspiciously short"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn unknown_skill_returns_none() {
|
|
let skills = EmbeddedSkills::load();
|
|
assert!(skills.get("nonexistent-skill").is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn summaries_include_all_skills() {
|
|
let skills = EmbeddedSkills::load();
|
|
let summaries = skills.summaries();
|
|
assert_eq!(summaries.len(), skills.list().len());
|
|
for (name, desc) in &summaries {
|
|
assert!(!desc.is_empty(), "skill '{name}' has empty description");
|
|
}
|
|
}
|
|
}
|