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    /// Worker base URL override (for RPC/Intent send)
46    #[arg(long, global = true, env = "BACKPAC_WORKER_URL")]
47    pub worker_url: Option<String>,
48
49    #[command(subcommand)]
50    pub command: Commands,
51}
52
53#[derive(Subcommand, Debug)]
54pub enum Commands {
55    /// Authenticate with the Backpac gateway via EIP-4361.
56    Auth(auth::AuthArgs),
57
58    /// Manage DID-anchored agent identities.
59    Identity(identity::IdentityArgs),
60
61    /// Create and manage Proofs of Intent.
62    Poi(poi::PoiArgs),
63
64    /// Submit, query, and verify execution intents.
65    Intent(intent::IntentArgs),
66
67    /// Retrieve and verify cryptographic Proofs of Transport.
68    Proof(proof::ProofArgs),
69
70    /// Read and write persistent CLI configuration.
71    Config(config_cmd::ConfigArgs),
72
73    /// Watch execution intents or agent notifications via real-time streams.
74    Watch(watch::WatchArgs),
75
76    /// Execute direct JSON-RPC operations (balance, quote, nonce, health).
77    #[command(flatten)]
78    Rpc(rpc::RpcCommands),
79
80    /// Fetch and verify a Proof of Intent/Execution in one step.
81    Receive(receive::ReceiveArgs),
82}
83
84impl Cli {
85    pub async fn execute(&self) -> Result<(), CairnError> {
86        match &self.command {
87            Commands::Auth(args) => args.execute(self).await,
88            Commands::Identity(args) => args.execute(self).await,
89            Commands::Poi(args) => args.execute(self).await,
90            Commands::Intent(args) => args.execute(self).await,
91            Commands::Proof(args) => args.execute(self).await,
92            Commands::Config(args) => args.execute(self).await,
93            Commands::Watch(args) => args.execute(self).await,
94            Commands::Rpc(cmd) => cmd.execute(self).await,
95            Commands::Receive(args) => args.execute(self).await,
96        }
97    }
98}
99
100/// Helper to print output in the requested format.
101pub fn output_json(value: &serde_json::Value, format: &str) {
102    if format == "text" {
103        // Flat key=value for piping
104        if let Some(obj) = value.as_object() {
105            for (k, v) in obj {
106                match v {
107                    serde_json::Value::String(s) => println!("{}={}", k, s),
108                    serde_json::Value::Null => println!("{}=null", k),
109                    _ => println!("{}={}", k, v),
110                }
111            }
112        } else {
113            println!("{}", value);
114        }
115    } else {
116        println!("{}", serde_json::to_string_pretty(value).unwrap());
117    }
118}