// cli.rs — CLI commands for sovereign addressing // // Commands: encode, bytes, receipt, verify use clap::{Parser, Subcommand}; use std::fs; use std::io::{self, Read}; use crate::{sovereign_address, sovereign_address_bytes, worm_receipt, verify_address, verify_receipt}; #[derive(Parser)] #[command(name = "snapaddr", about = "SnapKitty Sovereign Addressing")] pub struct Cli { #[command(subcommand)] pub command: Commands, } #[derive(Subcommand)] pub enum Commands { /// Compute sovereign address of a JSON value Encode { /// JSON file path (reads stdin if not provided) #[arg(value_name = "FILE")] file: Option, }, /// Compute raw address bytes Bytes { /// JSON file path #[arg(value_name = "FILE")] file: Option, }, /// Generate WORM receipt Receipt { /// JSON file path #[arg(value_name = "FILE")] file: Option, }, /// Verify address or receipt Verify { /// JSON file path #[arg(value_name = "FILE")] file: String, /// Expected address (for address verification) #[arg(long)] address: Option, }, /// Validate JSON admissibility Validate { /// JSON file path #[arg(value_name = "FILE")] file: Option, }, } /// Read JSON from file or stdin. fn read_json(file: Option<&str>) -> Result> { let input = match file { Some(path) => fs::read_to_string(path)?, None => { let mut buf = String::new(); io::stdin().read_to_string(&mut buf)?; buf } }; Ok(serde_json::from_str(&input)?) } /// Run the CLI. pub fn run() -> Result<(), Box> { let cli = Cli::parse(); match cli.command { Commands::Encode { file } => { let value = read_json(file.as_deref())?; let addr = sovereign_address(&value)?; println!("{}", addr); } Commands::Bytes { file } => { let value = read_json(file.as_deref())?; let bytes = sovereign_address_bytes(&value)?; for b in &bytes { print!("{:02x}", b); } println!(); } Commands::Receipt { file } => { let value = read_json(file.as_deref())?; let receipt = worm_receipt(&value)?; println!("{}", serde_json::to_string_pretty(&receipt)?); } Commands::Verify { file, address } => { let value = read_json(Some(&file))?; if let Some(addr) = address { let ok = verify_address(&value, &addr)?; if ok { println!("✓ Address verified"); } else { println!("✗ Address mismatch"); std::process::exit(1); } } else { // Verify receipt let receipt = worm_receipt(&value)?; let ok = verify_receipt(&receipt)?; if ok { println!("✓ Receipt verified"); println!("{}", serde_json::to_string_pretty(&receipt)?); } else { println!("✗ Receipt verification failed"); std::process::exit(1); } } } Commands::Validate { file } => { let value = read_json(file.as_deref())?; let result = crate::admissibility::validate_admissible(&value); match result { Ok(()) => println!("✓ JSON is admissible"), Err(e) => { println!("✗ Not admissible: {}", e); std::process::exit(1); } } } } Ok(()) }