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