KeiSeiKit-1.0/_primitives/_rust/kei-sage/src/atom_cli.rs
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

152 lines
4.8 KiB
Rust

//! CLI handlers for `atoms-*` subcommands — walks, indexes, queries atoms.
//!
//! Separate from `main.rs` to keep both files under Constructor Pattern
//! 200-LOC limit. `main.rs` wires clap, this module implements the verbs.
use crate::atom_index::index_atoms;
use crate::atoms::{discover_atoms, AtomRecord};
use crate::bfs::bfs;
use crate::facet_query::{discover_primitives_with_roles, matches_all, parse_filters};
use crate::lineage::{discover_lineage, nodes_by_author, trace_lineage};
use crate::pagerank::pagerank;
use crate::rule_index::discover_rules;
use crate::search::fts_search;
use crate::store::Store;
use anyhow::Result;
use std::path::{Path, PathBuf};
pub fn default_atoms_root() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
PathBuf::from(home).join(".claude/agents/_primitives/_rust")
}
pub fn default_rules_root() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
PathBuf::from(home).join(".claude/rules")
}
pub fn default_capabilities_root() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
PathBuf::from(home).join(".claude/_capabilities")
}
pub fn default_manifests_root() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
PathBuf::from(home).join(".claude/_manifests")
}
pub fn default_roles_root() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
PathBuf::from(home).join(".claude/_roles")
}
pub fn cmd_facet_query(
cap_root: &Path,
man_root: &Path,
roles_root: &Path,
filters: &[String],
) -> Result<()> {
let pairs = parse_filters(filters);
let all = discover_primitives_with_roles(cap_root, man_root, Some(roles_root));
for p in all.iter().filter(|p| matches_all(p, &pairs)) {
println!("{}", p.full_id);
}
Ok(())
}
pub fn cmd_lineage(cap_root: &Path, man_root: &Path, id: &str, depth: usize) -> Result<()> {
let nodes = discover_lineage(cap_root, man_root);
let trace = trace_lineage(&nodes, id, depth);
if let Some(f) = &trace.focus {
if let Some(c) = &f.created_at {
if let Some(by) = &f.created_by {
println!("created: {} by {}", c, by);
} else {
println!("created: {}", c);
}
} else if let Some(by) = &f.created_by {
println!("created-by: {}", by);
}
}
println!("ancestors: {}", format_list(&trace.ancestors));
println!("descendants: {}", format_list(&trace.descendants));
Ok(())
}
pub fn cmd_author(cap_root: &Path, man_root: &Path, creator: &str, limit: usize) -> Result<()> {
let nodes = discover_lineage(cap_root, man_root);
for n in nodes_by_author(&nodes, creator, limit) {
let ts = n.created_at.unwrap_or_else(|| "-".into());
println!("{}\t{}", ts, n.id);
}
Ok(())
}
fn format_list(items: &[String]) -> String {
if items.is_empty() { "(none)".into() } else { items.join(", ") }
}
pub fn cmd_atoms_discover(root: &Path) -> Result<()> {
let records = discover_atoms(root)?;
println!("full_id\tkind\tstability\tmd_path");
for r in &records {
println!(
"{}\t{}\t{}\t{}",
r.full_id,
r.kind.as_str(),
r.stability,
r.md_path.display()
);
}
eprintln!("discovered {} atom(s) under {}", records.len(), root.display());
Ok(())
}
pub fn cmd_rules_discover(root: &Path) -> Result<()> {
let records = discover_rules(root)?;
println!("slug\tname\tpath");
for r in &records {
println!("{}\t{}\t{}", r.slug, r.name, r.md_path.display());
}
eprintln!("discovered {} rule(s) under {}", records.len(), root.display());
Ok(())
}
pub fn cmd_atoms_rank(store: &Store, root: &Path, limit: usize) -> Result<()> {
ingest(store, root)?;
for (path, score) in pagerank(store)?.into_iter().take(limit) {
println!("{:.6}\t{}", score, path);
}
Ok(())
}
pub fn cmd_atoms_related(store: &Store, root: &Path, atom_id: &str, depth: i64) -> Result<()> {
ingest(store, root)?;
for r in bfs(store, atom_id, depth)? {
println!("{}\t{}\t(depth {})", r.edge_type, r.path, r.depth);
}
Ok(())
}
pub fn cmd_atoms_search(store: &Store, root: &Path, query: &str, limit: i64) -> Result<()> {
ingest(store, root)?;
for u in fts_search(store, query, limit)? {
if u.unit_type != "atom" {
continue;
}
println!("{}\t{}\t{}", u.id, u.category, u.vault_path);
}
Ok(())
}
fn ingest(store: &Store, root: &Path) -> Result<Vec<AtomRecord>> {
let records = discover_atoms(root)?;
let stats = index_atoms(store, &records)?;
eprintln!(
"indexed {} atom(s), {} wikilink edge(s) from {}",
stats.units_indexed,
stats.edges_indexed,
root.display()
);
Ok(records)
}