1use anyhow::Result;
4use clap::Args as ClapArgs;
5use colored::Colorize;
6
7use crate::core::{ConfigManager, Git, NotesManager, ARTIFACTS_NOTES_REF};
8
9#[derive(ClapArgs, Debug)]
11pub struct Args {
12 pub adr_id: String,
14
15 #[arg(long, short, default_value = "text")]
17 pub format: String,
18
19 #[arg(long)]
21 pub extract: Option<String>,
22
23 #[arg(long)]
25 pub remove: bool,
26}
27
28pub fn run(args: Args) -> Result<()> {
34 let git = Git::new();
35 git.check_repository()?;
36
37 let config = ConfigManager::new(git.clone()).load()?;
38 let notes = NotesManager::new(git.clone(), config);
39
40 let adrs = notes.list()?;
42 let adr = adrs
43 .into_iter()
44 .find(|a| a.id == args.adr_id || a.id.contains(&args.adr_id))
45 .ok_or_else(|| anyhow::anyhow!("ADR not found: {}", args.adr_id))?;
46
47 let artifact_content = git.notes_show(ARTIFACTS_NOTES_REF, &adr.commit)?;
49
50 match artifact_content {
51 Some(content) => {
52 let artifact: serde_json::Value = serde_json::from_str(&content)?;
54
55 if args.remove {
56 git.notes_remove(ARTIFACTS_NOTES_REF, &adr.commit)?;
58 eprintln!(
59 "{} Removed artifact {} from ADR {}",
60 "✓".green(),
61 artifact["filename"].as_str().unwrap_or("unknown").cyan(),
62 adr.id.cyan()
63 );
64 } else if let Some(extract_name) = &args.extract {
65 use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
67
68 let encoded = artifact["content"]
69 .as_str()
70 .ok_or_else(|| anyhow::anyhow!("No content in artifact"))?;
71
72 let decoded = BASE64.decode(encoded)?;
73 std::fs::write(extract_name, decoded)?;
74
75 eprintln!(
76 "{} Extracted {} ({} bytes)",
77 "✓".green(),
78 extract_name.cyan(),
79 artifact["size"]
80 );
81 } else if args.format.as_str() == "json" {
82 let mut listing = artifact;
84 if let Some(obj) = listing.as_object_mut() {
85 obj.remove("content");
86 }
87 println!("{}", serde_json::to_string_pretty(&listing)?);
88 } else {
89 eprintln!("{} Artifacts for ADR {}:", "→".blue(), adr.id.cyan());
90 println!();
91 println!(
92 " {} {}",
93 "Filename:".bold(),
94 artifact["filename"].as_str().unwrap_or("unknown").cyan()
95 );
96 println!(
97 " {} {} bytes",
98 "Size:".bold(),
99 artifact["size"].as_u64().unwrap_or(0)
100 );
101 if let Some(desc) = artifact["description"].as_str() {
102 if !desc.is_empty() {
103 println!(" {} {}", "Description:".bold(), desc);
104 }
105 }
106 }
107 },
108 None => {
109 eprintln!("{} No artifacts found for ADR {}", "→".yellow(), adr.id);
110 },
111 }
112
113 Ok(())
114}