#[derive(Debug, Clone, Copy)]
pub struct Article {
pub id: &'static str,
pub title: &'static str,
pub summary: &'static str,
pub body: &'static str,
}
pub const ARTICLES: &[Article] = &[
Article {
id: "overview",
title: "Myco overview",
summary: "Architecture, config paths, host routing, V1 product limits",
body: include_str!("articles/overview.md"),
},
Article {
id: "cli",
title: "User-facing CLI",
summary: "Slash-commands and keybindings the agent cannot press",
body: include_str!("articles/cli.md"),
},
Article {
id: "harness-ops",
title: "Harness ops",
summary: "Find hosts, install from releases or git source, diagnosis checklist",
body: include_str!("articles/harness-ops.md"),
},
];
pub fn article(id: &str) -> Option<&'static Article> {
ARTICLES.iter().find(|a| a.id == id)
}
pub fn known_ids() -> String {
ARTICLES.iter().map(|a| a.id).collect::<Vec<_>>().join(", ")
}
pub fn format_catalog() -> String {
let mut out = String::from("Myco manual — `myco --help <id>` or tool `manual` get:\n\n");
for a in ARTICLES {
out.push_str(&format!("- `{}` — {}\n {}\n", a.id, a.title, a.summary));
}
out
}
pub fn format_article(id: &str) -> Result<String, String> {
match article(id) {
Some(a) => Ok(format!("# {} (`{}`)\n\n{}", a.title, a.id, a.body)),
None => Err(format!(
"unknown manual article {id:?}; known: {}",
known_ids()
)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn articles_nonempty_unique_ids() {
assert!(!ARTICLES.is_empty());
let mut ids: Vec<&str> = ARTICLES.iter().map(|a| a.id).collect();
ids.sort_unstable();
ids.dedup();
assert_eq!(ids.len(), ARTICLES.len(), "duplicate article ids");
assert_eq!(ids, ["cli", "harness-ops", "overview"]); for a in ARTICLES {
assert!(!a.body.trim().is_empty(), "empty body: {}", a.id);
assert!(!a.title.is_empty());
assert!(!a.summary.is_empty());
}
for id in ["worktrees", "computer-use", "coding-norms"] {
assert!(article(id).is_none(), "{id} should not be a manual article");
}
}
#[test]
fn catalog_and_format_article() {
let cat = format_catalog();
for a in ARTICLES {
assert!(cat.contains(a.id), "catalog missing {}", a.id);
let body = format_article(a.id).unwrap();
assert!(body.contains(a.title));
}
assert!(format_article("nope").is_err());
}
}