//! `pic kv ls | get` — read-only KV inspection (G2). //! //! Wraps the read-only `/api/v1/admin/apps/{id}/kv*` surface. There is no //! `set`/`rm` on purpose: KV writes go through `kv::set` in scripts (which //! emit the change events triggers depend on); an admin write would bypass //! that, so the CLI stays read-only (matching the queues precedent). use std::io::Write; use anyhow::{bail, Result}; use crate::client::Client; use crate::config; use crate::output::{OutputMode, Table}; pub async fn ls( app: Option<&str>, group: Option<&str>, collection: &str, limit: u32, mode: OutputMode, ) -> Result<()> { let creds = config::resolve()?; let client = Client::from_creds(&creds)?; let page = match (app, group) { (Some(a), None) => client.kv_list(a, collection, limit).await?, // §11.6 M4: a group's shared-KV collection. (None, Some(g)) => client.group_kv_list(g, collection, limit).await?, _ => bail!("provide exactly one of --app or --group"), }; let mut table = Table::new(["key"]); for k in page.keys { table.row([k]); } table.print(mode); if page.next_cursor.is_some() { let _ = writeln!( std::io::stderr(), "(more keys available — raise --limit to see them)" ); } Ok(()) } pub async fn get( app: Option<&str>, group: Option<&str>, collection: &str, key: &str, ) -> Result<()> { let creds = config::resolve()?; let client = Client::from_creds(&creds)?; let value = match (app, group) { (Some(a), None) => client.kv_get(a, collection, key).await?, (None, Some(g)) => client.group_kv_get(g, collection, key).await?, _ => bail!("provide exactly one of --app or --group"), }; // Always emit the JSON value (pretty) so it pipes cleanly into jq. let pretty = serde_json::to_string_pretty(&value).unwrap_or_else(|_| value.to_string()); println!("{pretty}"); Ok(()) }