Skip to content

Commit fc9999e

Browse files
author
Bartok9
committed
feat(cli): add buzz users me for external-agent identity (#2663)
OpenClaw/external bridges hold BUZZ_PRIVATE_KEY but had no first-class self-identity command short of embedding secp256k1. Print hex pubkey + npub locally with no relay I/O (alias: whoami). Signed-off-by: Bartok9 <danielrpike9@gmail.com>
1 parent 8342dfc commit fc9999e

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

crates/buzz-cli/src/commands/users.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,34 @@ use nostr::PublicKey;
44
use crate::client::{extract_d_tag, normalize_write_response, BuzzClient};
55
use crate::error::CliError;
66
use crate::validate::validate_hex64;
7+
use nostr::ToBech32;
78

89
// TODO(phase-4): Replace raw nostr::EventBuilder usage in cmd_set_presence with buzz-sdk builder
910

11+
/// Build identity JSON for `buzz users me` (unit-testable without a live client).
12+
pub(crate) fn me_identity_json(pubkey_hex: &str, npub_bech32: &str) -> serde_json::Value {
13+
serde_json::json!({
14+
"pubkey": pubkey_hex,
15+
"npub": npub_bech32,
16+
})
17+
}
18+
19+
/// Print the active CLI identity (hex pubkey + npub) from the loaded private key.
20+
///
21+
/// No relay I/O — agents can resolve "who am I?" before connecting. Refs #2663.
22+
pub async fn cmd_me(
23+
client: &BuzzClient,
24+
_format: &crate::OutputFormat,
25+
) -> Result<(), CliError> {
26+
let pk = client.keys().public_key();
27+
let hex = pk.to_hex();
28+
let npub = pk
29+
.to_bech32()
30+
.map_err(|e| CliError::Other(format!("npub encode failed: {e}")))?;
31+
println!("{}", me_identity_json(&hex, &npub));
32+
Ok(())
33+
}
34+
1035
/// Get user profiles (kind:0 metadata events).
1136
///
1237
/// - 0 pubkeys, no name → query our own profile
@@ -536,6 +561,7 @@ pub async fn dispatch(
536561
) -> Result<(), CliError> {
537562
use crate::UsersCmd;
538563
match cmd {
564+
UsersCmd::Me => cmd_me(client, format).await,
539565
UsersCmd::Get {
540566
pubkeys,
541567
name,
@@ -762,4 +788,26 @@ mod tests {
762788
let event = json!({"pubkey": "user", "tags": [["p"]]});
763789
assert_eq!(presence_subject(&event), "user");
764790
}
791+
792+
#[test]
793+
fn me_identity_json_includes_pubkey_and_npub() {
794+
let hex = "a".repeat(64);
795+
let v = super::me_identity_json(
796+
&hex,
797+
"npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5s0xov",
798+
);
799+
assert_eq!(v["pubkey"], hex);
800+
assert!(v["npub"].as_str().unwrap().starts_with("npub1"));
801+
}
802+
803+
#[test]
804+
fn me_identity_from_generated_keys_roundtrips_bech32() {
805+
use nostr::{Keys, ToBech32};
806+
let keys = Keys::generate();
807+
let hex = keys.public_key().to_hex();
808+
let npub = keys.public_key().to_bech32().expect("npub");
809+
let v = super::me_identity_json(&hex, &npub);
810+
assert_eq!(v["pubkey"].as_str().unwrap().len(), 64);
811+
assert_eq!(v["npub"].as_str().unwrap(), npub);
812+
}
765813
}

crates/buzz-cli/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,12 @@ pub enum DmsCmd {
807807

808808
#[derive(Subcommand)]
809809
pub enum UsersCmd {
810+
/// Print the CLI identity derived from BUZZ_PRIVATE_KEY (no relay round-trip)
811+
///
812+
/// External agents (OpenClaw, custom bridges) hold a private key but often
813+
/// need their own pubkey without embedding secp256k1. Refs #2663 gap #1.
814+
#[command(name = "me", alias = "whoami")]
815+
Me,
810816
/// Look up user profiles by pubkey or name
811817
Get {
812818
/// User pubkey(s) to look up (64-char hex). Omit for your own profile

0 commit comments

Comments
 (0)