use std::{path::Path, process::ExitCode};
use anyhow::Result as AnyResult;
use crate::cli as app_cli;
use super::{
render::render_skill,
scan::{scan_memory_skill_advisory, scan_memory_skill_candidate},
store::MemorySkillStore,
types::MemorySkillCandidate,
};
pub fn run(
args: app_cli::MemorySkillArgs,
state_dir: &Path,
config: &crate::config::TruthMirrorConfig,
) -> AnyResult<ExitCode> {
let store = MemorySkillStore::new(state_dir, &config.memory_skill)?;
match args.command {
app_cli::MemorySkillCommand::List => {
let candidates = store.read_candidates()?;
let advisories = store
.read_advisories()?
.into_iter()
.filter(|advisory| !advisory.dismissed)
.collect::<Vec<_>>();
if candidates.is_empty() && advisories.is_empty() {
println!("No memory-skill candidates.");
} else {
for candidate in &candidates {
scan_memory_skill_candidate(candidate, &config.memory_skill)?;
}
for advisory in &advisories {
scan_memory_skill_advisory(advisory, &config.memory_skill)?;
}
for candidate in candidates {
println!(
"{} {} {} {} {}",
candidate.id,
candidate.status,
candidate.candidate_kind.as_str(),
candidate.slug,
candidate.source_commit
);
}
for advisory in advisories {
println!(
"advisory {} suggested {} {} {}",
advisory.id,
advisory.candidate_kind.as_str(),
advisory.slug,
advisory.source_commit
);
}
}
}
app_cli::MemorySkillCommand::Show { candidate_id } => {
let candidate = store.show(&candidate_id)?;
scan_memory_skill_candidate(&candidate, &config.memory_skill)?;
print_candidate(&candidate);
}
app_cli::MemorySkillCommand::Render { candidate_id } => {
let candidate = store.show(&candidate_id)?;
scan_memory_skill_candidate(&candidate, &config.memory_skill)?;
let skill = render_skill(&candidate);
print!("{skill}");
}
app_cli::MemorySkillCommand::Approve {
candidate_id,
apply,
} => match store.approve(&candidate_id, apply)? {
Some(path) => println!("approved and applied {candidate_id} -> {}", path.display()),
None => println!("approved {candidate_id}"),
},
app_cli::MemorySkillCommand::Apply { candidate_id } => {
let path = store.apply(&candidate_id)?;
println!("applied {candidate_id} -> {}", path.display());
}
app_cli::MemorySkillCommand::Reject {
candidate_id,
reason,
} => {
store.reject(&candidate_id, &reason)?;
println!("rejected {candidate_id}");
}
app_cli::MemorySkillCommand::Supersede {
candidate_id,
replacement,
reason,
} => {
store.supersede(&candidate_id, &replacement, &reason)?;
println!("superseded {candidate_id} with {replacement}");
}
app_cli::MemorySkillCommand::DismissAdvisory { advisory_id } => {
store.dismiss_advisory(&advisory_id)?;
println!("dismissed advisory {advisory_id}");
}
}
Ok(ExitCode::SUCCESS)
}
fn print_candidate(candidate: &MemorySkillCandidate) {
println!("id: {}", candidate.id);
println!("status: {}", candidate.status);
println!("kind: {}", candidate.candidate_kind.as_str());
println!("slug: {}", candidate.slug);
println!("title: {}", candidate.title);
println!("description: {}", candidate.description);
println!("source_commit: {}", candidate.source_commit);
println!("source_claim: {}", candidate.source_claim);
println!("truth_label: {}", candidate.truth_label);
println!("occurrence_count: {}", candidate.occurrence_count);
println!("fingerprint: {}", candidate.fingerprint);
println!("ledger_entry_ref: {}", candidate.ledger_entry_ref.display());
println!("source_run_ref: {}", candidate.source_run_ref.display());
print_items("when_to_use", &candidate.when_to_use);
print_items("procedure_steps", &candidate.procedure_steps);
print_items("pitfalls", &candidate.pitfalls);
print_items("verification_steps", &candidate.verification_steps);
println!("occurrence_refs:");
for reference in &candidate.occurrence_refs {
println!(" - {}", reference.display());
}
println!("evidence:");
for reference in &candidate.evidence {
println!(" - {}", reference.display());
}
}
fn print_items(label: &str, items: &[String]) {
println!("{label}:");
for item in items {
println!(" - {item}");
}
}