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