oxibrain_cli/cmd/
redact.rs1use oxibrain::{Brain, BrainConfig, RedactTarget};
2use std::path::Path;
3
4pub async fn run(
5 dir: &Path,
6 target: &str,
7 space: &str,
8 dry_run: bool,
9 reason: &str,
10) -> anyhow::Result<()> {
11 let brain = Brain::open(BrainConfig::at(dir)).await?;
12 let space_id = brain.ensure_space(space).await?;
13 let parsed = parse_target(target, &space_id)?;
14 if dry_run {
15 let closure = brain.redact_dry_run(&parsed).await?;
16 print_closure("dry-run", &closure);
17 Ok(())
18 } else {
19 let result = brain.redact(&parsed, reason, "cli").await?;
20 print_closure("redacted", &result.closure);
21 println!("beliefs refolded: {}", result.beliefs_refolded);
22 Ok(())
23 }
24}
25
26fn parse_target(target: &str, space_id: &str) -> anyhow::Result<RedactTarget> {
27 let (kind, id) = target
28 .split_once(':')
29 .ok_or_else(|| anyhow::anyhow!("target must be `kind:id`, got `{target}`"))?;
30 let id = id.trim();
31 if id.is_empty() {
32 anyhow::bail!("target id is empty in `{target}`");
33 }
34 match kind {
35 "episode" => Ok(RedactTarget::Episode { id: id.to_string() }),
36 "entity" => Ok(RedactTarget::Entity {
37 space: space_id.to_string(),
38 entity_id: id.to_string(),
39 }),
40 "predicate" => {
41 let (entity_id, predicate) = id
42 .split_once('/')
43 .ok_or_else(|| anyhow::anyhow!("predicate target must be `entity/predicate`"))?;
44 Ok(RedactTarget::PredicateScoped {
45 space: space_id.to_string(),
46 entity_id: entity_id.to_string(),
47 predicate: predicate.to_string(),
48 })
49 }
50 other => anyhow::bail!("unknown target kind `{other}` (expected episode|entity|predicate)"),
51 }
52}
53
54fn print_closure(label: &str, c: &oxibrain::RedactionClosure) {
55 println!("{label}:");
56 println!(" episodes: {}", c.episodes.len());
57 for id in &c.episodes {
58 println!(" episode:{id}");
59 }
60 println!(" assertions: {}", c.assertions.len());
61 println!(" statements: {}", c.statements.len());
62 for id in &c.statements {
63 println!(" statement:{id}");
64 }
65 println!(" mentions: {}", c.mentions.len());
66 println!(" extractions: {}", c.extractions.len());
67 println!(" summaries: {}", c.summaries.len());
68}