Skip to main content

cairn_cli/cli/
mod.rs

1pub mod auth;
2pub mod config_cmd;
3pub mod identity;
4pub mod intent;
5pub mod poi;
6pub mod proof;
7
8use clap::{Parser, Subcommand};
9
10use crate::errors::CairnError;
11
12/// Cairn — Backpac's agent-native CLI for autonomous settlement workflows.
13/// 
14/// All commands output structured JSON by default. Pipe-friendly, no interactive prompts.
15#[derive(Parser, Debug)]
16#[command(name = "cairn", version, about, long_about = None)]
17pub struct Cli {
18    /// Output format: json (default) or text
19    #[arg(long, default_value = "json", global = true, env = "CAIRN_OUTPUT")]
20    pub output: String,
21
22    /// Suppress all output (exit code only)
23    #[arg(long, short, global = true)]
24    pub quiet: bool,
25
26    /// API base URL override
27    #[arg(long, global = true, env = "BACKPAC_API_URL")]
28    pub api_url: Option<String>,
29
30    /// JWT override (bypasses saved credentials)
31    #[arg(long, global = true, env = "BACKPAC_JWT")]
32    pub jwt: Option<String>,
33
34    /// Blockchain chain identifier (e.g., ethereum, solana)
35    #[arg(long, global = true, env = "CAIRN_CHAIN")]
36    pub chain: Option<String>,
37
38    /// Network within the chain (e.g., mainnet, sepolia, devnet)
39    #[arg(long, global = true, env = "CAIRN_NETWORK")]
40    pub network: Option<String>,
41
42    #[command(subcommand)]
43    pub command: Commands,
44}
45
46#[derive(Subcommand, Debug)]
47pub enum Commands {
48    /// Authenticate with the Backpac gateway via EIP-4361.
49    Auth(auth::AuthArgs),
50
51    /// Manage DID-anchored agent identities.
52    Identity(identity::IdentityArgs),
53
54    /// Create and manage Proofs of Intent.
55    Poi(poi::PoiArgs),
56
57    /// Submit, query, and verify execution intents.
58    Intent(intent::IntentArgs),
59
60    /// Retrieve and verify cryptographic Proofs of Transport.
61    Proof(proof::ProofArgs),
62
63    /// Read and write persistent CLI configuration.
64    Config(config_cmd::ConfigArgs),
65}
66
67impl Cli {
68    pub async fn execute(&self) -> Result<(), CairnError> {
69        match &self.command {
70            Commands::Auth(args) => args.execute(self).await,
71            Commands::Identity(args) => args.execute(self).await,
72            Commands::Poi(args) => args.execute(self).await,
73            Commands::Intent(args) => args.execute(self).await,
74            Commands::Proof(args) => args.execute(self).await,
75            Commands::Config(args) => args.execute(self).await,
76        }
77    }
78}
79
80/// Helper to print output in the requested format.
81pub fn output_json(value: &serde_json::Value, format: &str) {
82    if format == "text" {
83        // Flat key=value for piping
84        if let Some(obj) = value.as_object() {
85            for (k, v) in obj {
86                match v {
87                    serde_json::Value::String(s) => println!("{}={}", k, s),
88                    serde_json::Value::Null => println!("{}=null", k),
89                    _ => println!("{}={}", k, v),
90                }
91            }
92        } else {
93            println!("{}", value);
94        }
95    } else {
96        println!("{}", serde_json::to_string_pretty(value).unwrap());
97    }
98}