use std::collections::BTreeMap;
use aristo_core::canon::{
CanonCatalogue, CanonClient, CanonError, HttpCanonClient, MockCanonClient,
};
use crate::commands::index::workspace_or_error;
use crate::{CliError, CliResult};
const CATALOGUE_REL: &str = ".aristo/catalogue.json";
pub(crate) fn run() -> CliResult<()> {
let ws = workspace_or_error()?;
let client: Box<dyn CanonClient> = if let Some(mock) = MockCanonClient::from_env() {
Box::new(mock)
} else {
match aristo_core::auth::resolve_full() {
Ok(creds) => {
let base_url = crate::data_plane::resolve_base(&creds.server);
Box::new(HttpCanonClient::new(base_url, &creds.token))
}
Err(_) => {
return Err(CliError::Other {
message: "canon catalogue requires authentication.\n \
Run `aristo auth login` first."
.into(),
exit_code: 1,
});
}
}
};
let catalogue = client.catalogue().map_err(canon_error_to_cli)?;
let aristo_dir = ws.aristo_dir();
std::fs::create_dir_all(&aristo_dir).map_err(CliError::Io)?;
let out_path = aristo_dir.join("catalogue.json");
let json = serde_json::to_string_pretty(&catalogue).map_err(|e| CliError::Other {
message: format!("serializing catalogue: {e}"),
exit_code: 1,
})?;
std::fs::write(&out_path, json).map_err(CliError::Io)?;
print_summary(&catalogue);
Ok(())
}
fn print_summary(catalogue: &CanonCatalogue) {
if !catalogue.notice.is_empty() {
for line in &catalogue.notice {
println!("{line}");
}
println!();
}
let total = catalogue.entries.len();
println!(
"ok: downloaded {total} canon entr{} to {CATALOGUE_REL} (gitignored local snapshot)",
if total == 1 { "y" } else { "ies" }
);
if total == 0 {
println!(
" note: the catalogue is empty — the instance has no canon corpus configured, \
or `[instance] url` isn't set to a conductor."
);
return;
}
let backed = catalogue
.entries
.iter()
.filter(|e| e.tier_label() == "aristos")
.count();
println!(
" backed (aristos): {backed} · unbacked (kanon): {}",
total - backed
);
let mut by_category: BTreeMap<&str, usize> = BTreeMap::new();
for e in &catalogue.entries {
*by_category.entry(e.category.as_str()).or_default() += 1;
}
println!(" by category:");
for (cat, n) in &by_category {
println!(" {cat}: {n}");
}
println!(" read/search the full snapshot at {CATALOGUE_REL}");
}
fn canon_error_to_cli(e: CanonError) -> CliError {
CliError::Other {
message: format!("canon catalogue error: {e}"),
exit_code: 1,
}
}