forked from 1b-agent/fieldcraft-upstream
* feat(engine): capability catalogue — every toolbar entry, ready or coming soon, and docs/features.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * feat: 98 toolbar icons drawn with VectorCraft from recipes (cargo xtask icons), attributed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * feat(ui): toolbar of tabs and panels from the catalogue, VectorCraft icons recoloured per theme, coming-soon entries greyed with their milestone; ui.toolbar Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * refactor: ready entries are their command; one tooltip; tabs and panels as catalogue runs; icon cache per theme and size; ui.toolbar read-only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: roadmap notes the toolbar and icons Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * feat(ui): deck entries run deck.write with their format, ready when the writer is in FORMATS; file and edit entries; compact and collapsed panels instead of scrolling Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: features page after the Nastran writer (#24) made its deck entry ready Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: features page after the LS-DYNA writer (#25) made its deck entry ready Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * feat: solve.static, solve.frequency and solve.probe on the toolbar (Solve and Results tabs) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
62 lines
1.8 KiB
Rust
62 lines
1.8 KiB
Rust
//! `cargo xtask assets`: every non-code asset in the repository must have a row in
|
|
//! ATTRIBUTION.md (author, source, licence), toolbar icons (`assets/icons`) included.
|
|
|
|
use std::path::Path;
|
|
|
|
const ASSET_EXT: &[&str] = &[
|
|
"png",
|
|
"jpg",
|
|
"jpeg",
|
|
"svg",
|
|
"ico",
|
|
"icns",
|
|
"ttf",
|
|
"otf",
|
|
"woff",
|
|
"woff2",
|
|
"gif",
|
|
"bmp",
|
|
"webp",
|
|
"wav",
|
|
"mp3",
|
|
"stl",
|
|
"step",
|
|
"stp",
|
|
"obj",
|
|
"vectorcraft",
|
|
"solidcraft",
|
|
];
|
|
const SKIP_DIRS: &[&str] = &["target", ".git", "plan", "dist"];
|
|
|
|
fn walk(dir: &Path, root: &Path, out: &mut Vec<String>) {
|
|
let Ok(rd) = std::fs::read_dir(dir) else { return };
|
|
for e in rd.flatten() {
|
|
let p = e.path();
|
|
let name = e.file_name().to_string_lossy().to_string();
|
|
if p.is_dir() {
|
|
if !SKIP_DIRS.contains(&name.as_str()) && !name.starts_with('.') {
|
|
walk(&p, root, out);
|
|
}
|
|
} else if let Some(ext) = p.extension().map(|x| x.to_string_lossy().to_ascii_lowercase())
|
|
&& ASSET_EXT.contains(&ext.as_str())
|
|
&& let Ok(rel) = p.strip_prefix(root)
|
|
{
|
|
out.push(rel.to_string_lossy().replace('\\', "/"));
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn run(root: &Path) -> Result<(), String> {
|
|
let attribution = std::fs::read_to_string(root.join("ATTRIBUTION.md")).map_err(|e| format!("ATTRIBUTION.md: {e}"))?;
|
|
let mut files = Vec::new();
|
|
walk(root, root, &mut files);
|
|
files.sort();
|
|
let missing: Vec<&String> = files.iter().filter(|f| !attribution.contains(f.as_str())).collect();
|
|
if missing.is_empty() {
|
|
println!("assets: {} asset file(s), all attributed", files.len());
|
|
Ok(())
|
|
} else {
|
|
Err(format!("assets missing from ATTRIBUTION.md:\n{}", missing.iter().map(|m| format!(" {m}")).collect::<Vec<_>>().join("\n")))
|
|
}
|
|
}
|