Skip to main content

cairn_cli/cli/
poi.rs

1use clap::{Args, Subcommand};
2use serde_json::json;
3
4use crate::client::BackpacClient;
5use crate::config::CairnConfig;
6use crate::errors::CairnError;
7
8use super::{output_json, Cli};
9
10#[derive(Args, Debug)]
11pub struct PoiArgs {
12    #[command(subcommand)]
13    pub command: PoiCommands,
14}
15
16#[derive(Subcommand, Debug)]
17pub enum PoiCommands {
18    /// Create a Proof of Intent for a pending task.
19    Create {
20        /// Blockchain chain (overrides config)
21        #[arg(long)]
22        chain: Option<String>,
23
24        /// Network (overrides config)
25        #[arg(long)]
26        network: Option<String>,
27
28        /// Parent PoI ID for chained intents
29        #[arg(long)]
30        parent: Option<String>,
31
32        /// Maximum chain depth (default: 5)
33        #[arg(long, default_value = "5")]
34        max_depth: u32,
35
36        /// TTL in seconds before the PoI expires (default: 600)
37        #[arg(long, default_value = "600")]
38        ttl: u64,
39
40        /// Additional metadata as JSON string
41        #[arg(long)]
42        metadata: Option<String>,
43    },
44
45    /// Retrieve a Proof of Intent by ID.
46    Get {
47        /// PoI ID to retrieve
48        poi_id: String,
49    },
50}
51
52impl PoiArgs {
53    pub async fn execute(&self, cli: &Cli) -> Result<(), CairnError> {
54        let client = BackpacClient::new(cli.jwt.as_deref(), cli.api_url.as_deref());
55        let config = CairnConfig::load();
56
57        match &self.command {
58            PoiCommands::Create {
59                chain,
60                network,
61                parent,
62                max_depth,
63                ttl,
64                metadata,
65            } => {
66                let c = chain.as_deref().or(cli.chain.as_deref()).unwrap_or(&config.chain);
67                let n = network.as_deref().or(cli.network.as_deref()).unwrap_or(&config.network);
68
69                let mut body = json!({
70                    "chain": c,
71                    "network": n,
72                    "max_chain_depth": max_depth,
73                    "ttl_seconds": ttl,
74                });
75
76                if let Some(p) = parent {
77                    body["parent_poi_id"] = json!(p);
78                }
79
80                if let Some(m) = metadata {
81                    let meta: serde_json::Value = serde_json::from_str(m)
82                        .map_err(|e| CairnError::InvalidInput(format!("Invalid JSON metadata: {}", e)))?;
83                    body["metadata"] = meta;
84                }
85
86                let result = client.post("/v1/pois", &body).await?;
87                output_json(&result, &cli.output);
88                Ok(())
89            }
90
91            PoiCommands::Get { poi_id } => {
92                let path = format!("/v1/pois/{}", poi_id);
93                let result = client.get(&path).await?;
94                output_json(&result, &cli.output);
95                Ok(())
96            }
97        }
98    }
99}