diff --git a/crates/buzz-cli/src/commands/patches.rs b/crates/buzz-cli/src/commands/patches.rs index 13f1714d06..1ec378129f 100644 --- a/crates/buzz-cli/src/commands/patches.rs +++ b/crates/buzz-cli/src/commands/patches.rs @@ -110,6 +110,38 @@ pub async fn cmd_list_patches( Ok(()) } +/// Read patch status events (kind:1630-1633) for a repo — the read side of sign-off. +/// Mirrors `cmd_list_patches` but selects status kinds instead of the patch kind, so +/// operator sign-off (a signed `merged` status event) is queryable, not write-only. +pub async fn cmd_list_status( + client: &BuzzClient, + repo_owner: &str, + repo_id: &str, + patch: Option<&str>, + limit: Option, +) -> Result<(), CliError> { + validate_hex64(repo_owner)?; + validate_repo_id(repo_id)?; + + let a_value = format!("30617:{repo_owner}:{repo_id}"); + let mut filter = serde_json::json!({ + "kinds": [1630, 1631, 1632, 1633], + "#a": [a_value] + }); + + if let Some(root) = patch { + validate_hex64(root)?; + filter["#e"] = serde_json::json!([root]); + } + if let Some(n) = limit { + filter["limit"] = serde_json::json!(n); + } + + let resp = client.query(&filter).await?; + println!("{resp}"); + Ok(()) +} + #[allow(clippy::too_many_arguments)] pub async fn cmd_patch_status( client: &BuzzClient, @@ -244,6 +276,12 @@ pub async fn dispatch(cmd: crate::PatchesCmd, client: &BuzzClient) -> Result<(), author, limit, } => cmd_list_patches(client, &repo_owner, &repo_id, author.as_deref(), limit).await, + PatchesCmd::StatusList { + repo_owner, + repo_id, + patch, + limit, + } => cmd_list_status(client, &repo_owner, &repo_id, patch.as_deref(), limit).await, PatchesCmd::Status { root, status, diff --git a/crates/buzz-cli/src/lib.rs b/crates/buzz-cli/src/lib.rs index 6ab81a082d..32d5a8d49b 100644 --- a/crates/buzz-cli/src/lib.rs +++ b/crates/buzz-cli/src/lib.rs @@ -1254,6 +1254,21 @@ pub enum PatchesCmd { #[arg(long)] limit: Option, }, + /// Read patch status events (NIP-34 kind:1630-1633) for a repo — the read side of sign-off + StatusList { + /// Repo owner pubkey (64-char hex) + #[arg(long)] + repo_owner: String, + /// Repo identifier (d-tag) + #[arg(long)] + repo_id: String, + /// Only status events referencing this patch root event id + #[arg(long)] + patch: Option, + /// Maximum number of results + #[arg(long)] + limit: Option, + }, /// Set status on a patch (open/merged/closed/draft — NIP-34 kind:1630-1633) Status { /// Root patch event id (first patch of the series/revision) @@ -1968,7 +1983,7 @@ mod tests { ); assert_eq!( names(&cmd, "patches"), - vec!["get", "list", "send", "status"] + vec!["get", "list", "send", "status", "status-list"] ); assert_eq!( names(&cmd, "issues"), @@ -2005,7 +2020,7 @@ mod tests { ("media", 1), ("messages", 8), ("pack", 2), - ("patches", 4), + ("patches", 5), ("pr", 5), ("reactions", 3), ("repos", 4),