From e1ea5f5b0ff38f9cf3a5ab02931a9b2de94b3ff6 Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Wed, 23 Sep 2026 16:12:18 +0000 Subject: [PATCH 1/2] docs(cli): make command descriptions state what the command does The help text had drifted into explaining itself. profile's description was the clearest case -- it recited which kinds it queries and then argued why it doesn't behave like find, which is the reasoning behind the command rather than a description of it. Rewritten flatter throughout, closer to how docker's CLI reads: say what the command does, state the rules a caller can't guess ("--targets cannot be combined with --relays"), and drop the rationale. Short lines lose their parentheticals and "(s)" plurals. Also fixes the error that prompted this. "ncli relay" with no config printed three alternatives crammed into one line and nothing else: Error: no relay config found -- pass --config, run "ncli relay context use ", or add ncli.yaml/relay.yaml here It now prints a short error and then the command's own help, so the flags and examples are right there, and the config search order moved into the description where it belongs. The admin subcommands missing nip11.privkey get the same treatment. Exit code and --json output are unchanged. --- CHANGELOG.md | 7 +++++++ cli/blossom/command.go | 9 ++++----- cli/blossom/download.go | 10 +++++----- cli/blossom/list.go | 6 +++--- cli/blossom/mirror.go | 8 +++----- cli/blossom/report.go | 7 +++---- cli/blossom/rm.go | 7 +++---- cli/blossom/servers.go | 16 +++++++--------- cli/blossom/upload.go | 11 +++++------ cli/bunker/command.go | 34 +++++++++++++++------------------- cli/delegate/command.go | 13 +++++-------- cli/ncli/apply.go | 2 +- cli/ncli/decode.go | 8 ++++---- cli/ncli/dump.go | 7 +++---- cli/ncli/find.go | 11 +++++------ cli/ncli/id.go | 5 ++--- cli/ncli/id_sign.go | 12 ++++-------- cli/ncli/miner.go | 15 +++++++-------- cli/ncli/ping.go | 10 ++++------ cli/ncli/prefs.go | 9 ++++----- cli/ncli/profile.go | 12 ++++-------- cli/ncli/publish.go | 10 ++++------ cli/ncli/root.go | 4 ++-- cli/ncli/version.go | 8 +++----- cli/relay/admin.go | 19 +++++++++---------- cli/relay/command.go | 18 ++++++++++-------- cli/relay/context.go | 16 ++++++++-------- 27 files changed, 134 insertions(+), 160 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db8df76..8de4809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,9 @@ unchanged, so a bare group command still exits 2, never 0. `--json` is untouched: one structured line, never help. (#55) - Updated `nmilat` to v0.4.0. +- Rewrote every command's `--help` description in a flatter style: each + one now states what the command does, with the rules a caller can't + guess stated plainly, instead of explaining the reasoning behind it. ### Fixed @@ -34,6 +37,10 @@ own line) and exited 1 instead of 2. (#55) - `ncli bunker sessions revoke-grant` with no `--method` exited 1 as `internal` instead of 2 as `usage`. (#55) +- `ncli relay` with no config reported three alternatives crammed into + one line and no help. It now prints a short error followed by the + command's help, which lists the flags and where the config is read + from. Same for the `relay` admin subcommands missing `nip11.privkey`. - `ncli relay` could freeze until restarted: a `REQ` held its database read open while sending events, so a write that grew the database file hung every other `REQ` and `EVENT`, health checks included. Fixed diff --git a/cli/blossom/command.go b/cli/blossom/command.go index 88b4781..2ead676 100644 --- a/cli/blossom/command.go +++ b/cli/blossom/command.go @@ -13,13 +13,12 @@ import ( func NewBlossomCommand() *cobra.Command { cmd := &cobra.Command{ Use: "blossom", - Short: "Upload, fetch, and manage content on Blossom media servers", + Short: "Manage content on Blossom media servers", Long: `A client for the Blossom protocol (BUD-01..12): content-addressed blob -storage authenticated with a Nostr identity instead of a login. +storage authenticated with a Nostr identity. -Writes (upload, rm, mirror) fan out to every configured server and exit -non-zero if any one failed; download tries them in order until one -answers.`, +upload, rm and mirror write to every configured server and exit non-zero +if any fails. download reads from them in order until one answers.`, Example: ` ncli blossom upload ./photo.jpg --identity satoshi ncli blossom download -o photo.jpg ncli blossom servers list`, diff --git a/cli/blossom/download.go b/cli/blossom/download.go index 90602e7..514f13a 100644 --- a/cli/blossom/download.go +++ b/cli/blossom/download.go @@ -29,12 +29,12 @@ func newDownloadCommand() *cobra.Command { cmd := &cobra.Command{ Use: "download ", Short: "Download a blob by hash, blossom: URI, or server URL", - Long: `Accepts a bare sha256 hash, a "blossom:." URI (BUD-10), or a -server URL ending in a hash -- tries the configured servers in order -(--server, or the default list), stopping at the first that answers. + Long: `Download a blob, given a bare sha256 hash, a "blossom:." URI +(BUD-10), or a server URL ending in a hash. Servers are tried in order +until one answers. -Writes to --output, or "." in the current directory if -omitted, or streams to stdout with "-o -" (suppressing the summary line).`, +Writes to --output, or to "." in the current directory. Use +"-o -" to stream to stdout.`, Example: ` ncli blossom download ncli blossom download -o -`, Args: common.ExactArgs(1), diff --git a/cli/blossom/list.go b/cli/blossom/list.go index 63d475a..84cfcd8 100644 --- a/cli/blossom/list.go +++ b/cli/blossom/list.go @@ -25,11 +25,11 @@ func newListCommand() *cobra.Command { cmd := &cobra.Command{ Use: "list [identifier]", Short: "List blobs stored under a pubkey", - Long: `List the blobs one pubkey has stored, on the first configured server or -on every one with --all, merged and deduped by hash. + Long: `List the blobs a pubkey has stored on the first configured server, or on +every server with --all, merged and deduplicated by hash. identifier accepts a vault label, npub, hex pubkey, nprofile or nip-05 -address, and defaults to --identity's pubkey when omitted.`, +address, and defaults to --identity's pubkey.`, Example: ` ncli blossom list --identity satoshi ncli blossom list --identity satoshi --all ncli blossom list name@example.com`, diff --git a/cli/blossom/mirror.go b/cli/blossom/mirror.go index ac65e03..c34cf85 100644 --- a/cli/blossom/mirror.go +++ b/cli/blossom/mirror.go @@ -13,11 +13,9 @@ import ( func newMirrorCommand() *cobra.Command { cmd := &cobra.Command{ Use: "mirror ", - Short: "Mirror a blob from a URL onto your Blossom server(s)", - Long: `Sign a BUD-11 authorization and PUT /mirror to every target server -(--server, or the configured default list) -- each server fetches -source-url itself; no bytes pass through ncli. Reports a result per -server.`, + Short: "Mirror a blob from a URL to your Blossom servers", + Long: `Ask every target server to fetch and store a blob from source-url. Each +server downloads it directly; no bytes pass through ncli.`, Example: ` ncli blossom mirror https://example.com/file.jpg --identity satoshi`, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cli/blossom/report.go b/cli/blossom/report.go index a618b46..85cfbca 100644 --- a/cli/blossom/report.go +++ b/cli/blossom/report.go @@ -13,10 +13,9 @@ import ( func newReportCommand() *cobra.Command { cmd := &cobra.Command{ Use: "report ", - Short: "Report a blob to a Blossom server (BUD-09)", - Long: `Sign and submit a kind:1984 report event to a server's PUT /report -- -authenticated by its own signature, not a BUD-11 token. Targets one -server: --server, or the first configured default.`, + Short: "Report a blob to a Blossom server", + Long: `Submit a signed kind:1984 report event for a blob (BUD-09). Targets a +single server: --server, or the first configured one.`, Example: ` ncli blossom report --identity satoshi`, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cli/blossom/rm.go b/cli/blossom/rm.go index d347602..640717c 100644 --- a/cli/blossom/rm.go +++ b/cli/blossom/rm.go @@ -19,10 +19,9 @@ func newRmCommand() *cobra.Command { cmd := &cobra.Command{ Use: "rm ", - Short: "Delete a blob from your Blossom server(s)", - Long: `Sign a hash-scoped BUD-11 authorization and DELETE the blob from every -target server (--server, or the configured default list), reporting a -result per server. Requires --yes in a non-interactive session.`, + Short: "Delete a blob from your Blossom servers", + Long: `Delete a blob from every target server. Requires --yes in a +non-interactive session.`, Example: ` ncli blossom rm --identity satoshi --yes`, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cli/blossom/servers.go b/cli/blossom/servers.go index 4201b75..77dcc1a 100644 --- a/cli/blossom/servers.go +++ b/cli/blossom/servers.go @@ -20,7 +20,7 @@ func newServersCommand() *cobra.Command { cmd := &cobra.Command{ Use: "servers", Short: "Manage the default Blossom server list", - Long: `Manage the server list "ncli blossom" commands fall back to when not given explicit --server flags.`, + Long: `Manage the server list used when a command is given no --server flag.`, Example: ` ncli blossom servers list`, RunE: common.RequireSubcommand, } @@ -267,14 +267,12 @@ func newServersDiscoverCommand() *cobra.Command { cmd := &cobra.Command{ Use: "discover ", - Short: "Discover another identity's published server list (BUD-03)", - Long: `Resolves (vault label/nsec/npub/hex pubkey/nprofile/nip-05) -to a pubkey, then queries your configured Nostr relays for that pubkey's -most recent kind:10063 server-list event, and prints the servers it -declares. - -Unlike "servers add/remove/list", which manage your own default list, -this looks up someone else's published servers.`, + Short: "Show another identity's published server list", + Long: `Print the Blossom servers another identity has published, from their +most recent kind:10063 event (BUD-03). + +identifier accepts a vault label, npub, hex pubkey, nprofile or nip-05 +address.`, Example: ` ncli blossom servers discover npub1...`, Args: common.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cli/blossom/upload.go b/cli/blossom/upload.go index a977d88..4b28700 100644 --- a/cli/blossom/upload.go +++ b/cli/blossom/upload.go @@ -21,13 +21,12 @@ func newUploadCommand() *cobra.Command { cmd := &cobra.Command{ Use: "upload [file...]", - Short: "Upload one or more files to your Blossom server(s)", - Long: `Sign a BUD-11 authorization and PUT each file to every target server -(--server, or the configured default list), reporting a result per -(file, server) pair. Exits non-zero if any pair failed. + Short: "Upload files to your Blossom servers", + Long: `Upload each file to every target server, reporting a result per (file, +server) pair. Exits non-zero if any pair fails. -Pass --optimize to request server-side transcoding/optimization (BUD-05's -PUT /media) instead of a byte-for-byte store.`, +--optimize requests server-side transcoding (BUD-05) instead of storing +the bytes as-is.`, Example: ` ncli blossom upload ./photo.jpg --identity satoshi ncli blossom upload ./photo.jpg --identity satoshi --optimize ncli blossom upload ./photo.jpg --identity satoshi --server https://blossom.example.com`, diff --git a/cli/bunker/command.go b/cli/bunker/command.go index 9e248ad..7010c0e 100644 --- a/cli/bunker/command.go +++ b/cli/bunker/command.go @@ -35,12 +35,11 @@ func NewBunkerCommand() *cobra.Command { cmd := &cobra.Command{ Use: "bunker", Short: "Run ncli as a NIP-46 remote signer", - Long: `Run ncli as a NIP-46 "bunker": listen on relays for other clients' -signing requests, approve or reject them from a live TUI, and remember -per-app decisions so you aren't re-prompted every time. + Long: `Listen on relays for other clients' NIP-46 signing requests and approve +or reject them from a TUI. Per-app decisions are remembered. -On Linux/macOS this leaves a background daemon running when the TUI -closes; reattach with "ncli bunker attach".`, +On Linux and macOS a background daemon keeps running when the TUI +closes. Reattach with "ncli bunker attach".`, Example: ` ncli bunker ncli bunker --identity satoshi ncli bunker attach`, @@ -92,9 +91,8 @@ func newAttachCommand() *cobra.Command { return &cobra.Command{ Use: "attach", Short: "Reattach the TUI to a running bunker daemon", - Long: `Reconnect the interactive TUI to a bunker daemon already started with -"ncli bunker" and left running in the background. Never starts one -itself -- fails if none is running (use "ncli bunker" for that).`, + Long: `Reconnect the TUI to a bunker daemon already running in the background. +Never starts one; fails if none is running.`, Example: ` ncli bunker attach`, RunE: func(cmd *cobra.Command, args []string) error { if err := requireInteractive(cmd); err != nil { @@ -350,7 +348,7 @@ func newSessionsCommand() *cobra.Command { cmd.AddCommand(&cobra.Command{ Use: "grants ", - Short: "List one trusted app's remembered permissions individually", + Short: "List one app's remembered permissions", Example: ` ncli bunker sessions grants `, Args: common.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -445,7 +443,7 @@ func newSessionsCommand() *cobra.Command { func newHistoryCommand() *cobra.Command { return &cobra.Command{ Use: "history", - Short: "List recently resolved requests (approved/rejected/expired)", + Short: "List recently resolved signing requests", Example: ` ncli bunker history`, RunE: func(cmd *cobra.Command, args []string) error { jsonMode, _ := cmd.Flags().GetBool("json") @@ -502,15 +500,13 @@ func newHistoryCommand() *cobra.Command { func newConnectCommand() *cobra.Command { cmd := &cobra.Command{ Use: "connect [nostrconnect-uri]", - Short: "Start a pairing with a running bunker daemon", - Long: `With no argument, generates and prints a fresh bunker:// URI for another -Nostr app to connect to. Given a nostrconnect:// URI, initiates that -pairing instead, blocking until the client confirms or it times out. - ---grants pre-authorizes the app that completes this pairing with a -declared set of permissions (see examples/bunker/ for the YAML shape), -instead of prompting interactively on first use. "ncli bunker sessions -grants " shows what actually landed once paired.`, + Short: "Pair an app with a running bunker daemon", + Long: `Print a fresh bunker:// URI for another Nostr app to connect to. Given a +nostrconnect:// URI, start that pairing instead and block until the +client confirms or it times out. + +--grants pre-authorizes the paired app from a YAML permission file +instead of prompting on first use.`, Example: ` ncli bunker connect ncli bunker connect nostrconnect://... ncli bunker connect --grants grants.yaml`, diff --git a/cli/delegate/command.go b/cli/delegate/command.go index f2fe26f..bd0ddc3 100644 --- a/cli/delegate/command.go +++ b/cli/delegate/command.go @@ -28,14 +28,11 @@ func NewDelegateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "delegate", Short: "Generate a NIP-26 delegation token", - Long: `Launch an interactive wizard that creates and signs NIP-26 delegation -tokens. With --issuer set (via flag or NCLI_DELEGATE_ISSUER), skips the -wizard and generates the token non-interactively instead. - ---issuer and --delegatee both accept a vault label, nsec, npub, hex -pubkey, nprofile, or nip-05 address, and must resolve to a private key -- -a pubkey-only identity has nothing to sign or derive a delegatee key from -and is rejected.`, + Long: `Create and sign a NIP-26 delegation token. Runs an interactive wizard +unless --issuer is set, via the flag or NCLI_DELEGATE_ISSUER. + +--issuer and --delegatee accept a vault label, nsec, npub, hex pubkey, +nprofile or nip-05 address, and must resolve to a private key.`, Example: ` ncli id delegate ncli id delegate --issuer satoshi --delegatee npub1... --kinds 1`, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cli/ncli/apply.go b/cli/ncli/apply.go index 55a7dbe..e1e5c1f 100644 --- a/cli/ncli/apply.go +++ b/cli/ncli/apply.go @@ -14,7 +14,7 @@ var ( applyCmd = &cobra.Command{ Use: "apply", - Short: "Run a client workflow from a config file", + Short: "Run a stream, sync, or inspect workflow", Long: `Run a stream, sync, or inspect workflow defined in a YAML config file.`, Example: ` ncli apply -f sync.yaml ncli apply -f sync.yaml --strict-pow`, diff --git a/cli/ncli/decode.go b/cli/ncli/decode.go index 646847e..078a438 100644 --- a/cli/ncli/decode.go +++ b/cli/ncli/decode.go @@ -12,11 +12,11 @@ import ( var decodeCmd = &cobra.Command{ Use: "decode ", Short: "Decode a NIP-19 entity, cash token, or hub connection", - Long: `Decodes whichever bech32 shape you paste in -- a NIP-19 entity (npub, -nsec, note, nprofile, nevent, naddr), a NIP-CASH cash token, or a NIP-CW -circlehub1... connection -- into its hex keys, relay hints and metadata. + Long: `Decode a bech32 string -- a NIP-19 entity (npub, nsec, note, nprofile, +nevent, naddr), a NIP-CASH cash token, or a NIP-CW circlehub1... +connection -- into its hex keys, relay hints and metadata. -A pairing secret is never included in the output.`, +Pairing secrets are never printed.`, Example: ` ncli decode npub1... ncli decode nevent1... ncli decode npub1... --json`, diff --git a/cli/ncli/dump.go b/cli/ncli/dump.go index cd70d1e..72d0d18 100644 --- a/cli/ncli/dump.go +++ b/cli/ncli/dump.go @@ -19,11 +19,10 @@ var dumpCmd = &cobra.Command{ Use: "dump", Short: "Export events to JSON", Long: `Export events matching a filter to a JSON file, merged and deduplicated -by event ID across every target. +by event ID across all targets. -Targets and filters come from --targets, or --relays plus inline filter -flags -- pick one, not both. Omitting both falls back to "ncli prefs -relays".`, +--targets cannot be combined with --relays or the inline filter flags. +Omit both to use the relays from "ncli prefs relays".`, Example: ` ncli dump -o events.json ncli dump -t targets.yaml -o events.json ncli dump -s wss://relay.example.com -k 1 --since 24h -o recent.json`, diff --git a/cli/ncli/find.go b/cli/ncli/find.go index d4512eb..72df8a0 100644 --- a/cli/ncli/find.go +++ b/cli/ncli/find.go @@ -18,13 +18,12 @@ var ( findCmd = &cobra.Command{ Use: "find [identifier]", Short: "Query events by ID and/or filter", - Long: `Look up events by ID and/or filter across relays or local stores, -stopping at the first target with a match. An npub or nip-05 identifier -defaults to that author's profile (kind 0); pass --kinds to widen it. + Long: `Query events across relays and local stores, stopping at the first +target with a match. An npub or nip-05 identifier returns that author's +profile unless --kinds widens it. Prints a single JSON array. -Targets and filters come from --targets, or --relays plus inline filter -flags -- pick one, not both. Omitting both falls back to "ncli prefs -relays". Always prints a single JSON array to stdout.`, +--targets cannot be combined with --relays or the inline filter flags. +Omit both to use the relays from "ncli prefs relays".`, Example: ` ncli find note1... ncli find npub1... ncli find --authors npub1... --kinds 1 -s wss://relay.example.com`, diff --git a/cli/ncli/id.go b/cli/ncli/id.go index 58c752c..eaaf0ef 100644 --- a/cli/ncli/id.go +++ b/cli/ncli/id.go @@ -20,9 +20,8 @@ import ( var idCmd = &cobra.Command{ Use: "id [identifier]", Short: "Generate or inspect a Nostr identity", - Long: `With no argument, generates a new Nostr keypair. With an identifier -- -a vault label, npub, hex pubkey, nsec, nprofile, or nip-05 address -- -resolves and displays it instead. + Long: `Generate a new keypair, or resolve and display an existing identity +given a vault label, npub, hex pubkey, nsec, nprofile or nip-05 address. --json disables interactive prompts and reads the vault password from NCLI_VAULT_PASSWORD.`, diff --git a/cli/ncli/id_sign.go b/cli/ncli/id_sign.go index 2038047..03fed81 100644 --- a/cli/ncli/id_sign.go +++ b/cli/ncli/id_sign.go @@ -12,15 +12,11 @@ import ( var idSignCmd = &cobra.Command{ Use: "sign", - Short: "Sign one or more unsigned events with a Nostr identity", - Long: `Sign an unsigned event (or array of them) with --identity's private key. + Short: "Sign unsigned events with a Nostr identity", + Long: `Sign an unsigned event, or an array of them, with --identity's private +key. --out is written in the shape it was read. ---events accepts a single event or an array; --out is written in the same -shape, so it chains directly into "ncli publish --events " or -"ncli miner check --events ". - -Fails if an event already declares a pubkey that conflicts with ---identity's resolved pubkey, rather than re-signing under a different key.`, +Fails if an event already declares a different pubkey.`, Example: ` ncli id sign -e events.json -o signed.json --identity satoshi`, Args: func(cmd *cobra.Command, args []string) error { if err := cmd.ValidateRequiredFlags(); err != nil { diff --git a/cli/ncli/miner.go b/cli/ncli/miner.go index 67efd71..c7ca6ce 100644 --- a/cli/ncli/miner.go +++ b/cli/ncli/miner.go @@ -32,10 +32,10 @@ var minerMineCmd = &cobra.Command{ Short: "Mine proof-of-work into an unsigned event", Long: `Mine NIP-13 proof-of-work for an event across multiple CPU cores. -The event comes from --event, or inline from --content/--content-file -- -pick one, not both. Exactly one of --out or --in-place says where the -result goes. If --identity resolves to a private key, the mined event is -signed before it's written.`, +The event comes from --event, or inline from --content/--content-file; +these cannot be combined. Exactly one of --out or --in-place is +required. A mined event is signed if --identity resolves to a private +key.`, Example: ` ncli miner mine -e event.json -o mined.json ncli miner mine -e event.json --in-place --workers 4 ncli miner mine --content "hello" --identity satoshi -d 20 -o mined.json`, @@ -266,11 +266,10 @@ var minerCheckCmd = &cobra.Command{ Use: "check", Short: "Verify proof-of-work", Long: `Verify NIP-13 proof-of-work on already-mined events, read from --events -or fetched live across every target. Exits non-zero if any event fails, -so it drops straight into CI. +or fetched live from every target. Exits non-zero if any event fails. -Live mode takes --targets, or --relays plus inline filter flags -- pick -one, not both. Omitting both falls back to "ncli prefs relays".`, +--targets cannot be combined with --relays or the inline filter flags. +Omit both to use the relays from "ncli prefs relays".`, Example: ` ncli miner check -e events.json ncli miner check -t targets.yaml`, Args: func(cmd *cobra.Command, args []string) error { diff --git a/cli/ncli/ping.go b/cli/ncli/ping.go index f3a006a..3971e50 100644 --- a/cli/ncli/ping.go +++ b/cli/ncli/ping.go @@ -15,13 +15,11 @@ import ( var pingCmd = &cobra.Command{ Use: "ping [relay...]", Short: "Test relay connectivity", - Long: `Probe each target relay with a Limit-1 subscription. Exits non-zero if -any relay was unreachable -- unlike find/dump, which tolerate a dead -target, reachability is the whole point here. + Long: `Probe each relay with a Limit-1 subscription. Local store paths are +skipped. Exits non-zero if any relay is unreachable. -Give relays as positional arguments, or --targets -- pick one, not both. -Omitting both falls back to "ncli prefs relays". --tui shows a live -board instead of log lines.`, +--targets cannot be combined with relay arguments. Omit both to use the +relays from "ncli prefs relays". --tui shows a live board.`, Example: ` ncli ping wss://relay.example.com ncli ping -t targets.yaml ncli ping --tui wss://relay.example.com`, diff --git a/cli/ncli/prefs.go b/cli/ncli/prefs.go index a0f328e..1c03fca 100644 --- a/cli/ncli/prefs.go +++ b/cli/ncli/prefs.go @@ -10,10 +10,9 @@ import ( ) var prefsCmd = &cobra.Command{ - Use: "prefs", - Short: "Manage persistent ncli preferences", - Long: `Manage preferences that persist across projects. Currently just the -default relay list that find, dump, and miner check fall back to.`, + Use: "prefs", + Short: "Manage persistent ncli preferences", + Long: `Manage the preferences ncli persists across projects.`, Example: ` ncli prefs relays list`, RunE: common.RequireSubcommand, } @@ -21,7 +20,7 @@ default relay list that find, dump, and miner check fall back to.`, var prefsRelaysCmd = &cobra.Command{ Use: "relays", Short: "Manage the default relay list", - Long: `Manage the relay list find, dump, and miner check consult when not given explicit targets.`, + Long: `Manage the relay list used when a command is given no explicit targets.`, Example: ` ncli prefs relays list`, RunE: common.RequireSubcommand, } diff --git a/cli/ncli/profile.go b/cli/ncli/profile.go index 9185bea..b5810ff 100644 --- a/cli/ncli/profile.go +++ b/cli/ncli/profile.go @@ -62,14 +62,10 @@ type nip05Status struct { func newProfileCommand() *cobra.Command { cmd := &cobra.Command{ Use: "profile ", - Short: "Show a readable profile card for an identity", - Long: `Looks up one identity's published records in a single query -- profile -metadata (kind:0), contact list (kind:3), relay list (kind:10002), and -Blossom server list (kind:10063) -- and prints them as one card. - -Unlike "find", this aggregates across every target instead of stopping at -the first one with a match, since a relay list often lives on a different -relay than the profile.`, + Short: "Display an identity's published profile", + Long: `Display the profile metadata, following count, relay list, Blossom +servers and lightning address published by an identity. Records are +merged across all targets.`, Example: ` ncli profile npub1... ncli profile name@example.com ncli profile satoshi --json`, diff --git a/cli/ncli/publish.go b/cli/ncli/publish.go index 0917f06..f2470a7 100644 --- a/cli/ncli/publish.go +++ b/cli/ncli/publish.go @@ -14,13 +14,11 @@ import ( var publishCmd = &cobra.Command{ Use: "publish", Short: "Publish signed events to one or more relays", - Long: `Send already-signed events (e.g. from "ncli miner mine --identity" or -"ncli dump") to one or more relays, waiting for each relay's OK. + Long: `Send already-signed events to every target relay and wait for each +relay's OK. --events accepts a single event or an array. ---events accepts a single event or a JSON array; every event is sent to -every relay, and the full (event, relay) result is reported. Omitting ---relays falls back to the relays configured via "ncli prefs relays add". -Exits non-zero if any pair fails.`, +Omit --relays to use the relays from "ncli prefs relays". Exits non-zero +if any event fails on any relay.`, Example: ` ncli publish -e signed.json ncli publish -e signed.json -s wss://relay.example.com`, Args: func(cmd *cobra.Command, args []string) error { diff --git a/cli/ncli/root.go b/cli/ncli/root.go index 49037af..d508314 100644 --- a/cli/ncli/root.go +++ b/cli/ncli/root.go @@ -30,8 +30,8 @@ var ( var RootCmd = &cobra.Command{ Use: "ncli", - Short: "Nostr relay & toolkit CLI", - Long: `Run and operate Nostr relays, and manage events: serve, stream, sync, inspect, export, delegate, administer, and mine.`, + Short: "A CLI for the Nostr protocol", + Long: `Run a relay, stream and sync events, manage keys, and mine proof-of-work.`, Example: ` ncli id ncli find npub1...`, diff --git a/cli/ncli/version.go b/cli/ncli/version.go index f366ba2..c38ea32 100644 --- a/cli/ncli/version.go +++ b/cli/ncli/version.go @@ -12,11 +12,9 @@ import ( var versionCmd = &cobra.Command{ Use: "version", - Short: "Print version and app data location information", - Long: `Print build version information along with the on-disk locations ncli -reads and writes: the app data directory, prefs file, vault file, and log -directory. --json prints the same information as structured JSON, for -scripts or an AI agent.`, + Short: "Show the version and on-disk paths", + Long: `Show build version information and the on-disk locations ncli reads and +writes: app data directory, prefs file, vault file and log directory.`, Example: ` ncli version`, // version just reads embedded build info, so it skips the root's // PersistentPreRun (config loading, log dir/crash log setup) instead diff --git a/cli/relay/admin.go b/cli/relay/admin.go index 589880e..2f7355f 100644 --- a/cli/relay/admin.go +++ b/cli/relay/admin.go @@ -46,7 +46,7 @@ var ( func addRemoteAdminCommands(cmd *cobra.Command) { statsCmd := &cobra.Command{ Use: "stats", - Short: "Display live relay metrics and worker status", + Short: "Show live relay metrics and worker status", Example: ` ncli relay stats --config relay.yaml`, RunE: runStats, } @@ -99,8 +99,7 @@ func addMembershipAdminCommands(cmd *cobra.Command) { }) membersAddCmd := &cobra.Command{ Use: "add ", Short: "Enroll a pubkey as a member", - Long: `Enroll a pubkey as a member directly -- bypasses the self-service -invite-code join flow, no invite claim required.`, + Long: `Enroll a pubkey as a member directly, without an invite code.`, Example: ` ncli relay members add --config relay.yaml ncli relay members add --role member --config relay.yaml`, Args: common.ExactArgs(1), RunE: runMembersAdd, @@ -122,8 +121,8 @@ invite-code join flow, no invite claim required.`, } invitesCreateCmd := &cobra.Command{ Use: "create", Short: "Issue a new invite code", - Long: `Issue a new invite code, for handing out out-of-band (a signup email, a -Discord invite flow) before the invitee has a working Nostr client.`, + Long: `Issue an invite code to hand out before the invitee has a working Nostr +client.`, Example: ` ncli relay invites create --config relay.yaml ncli relay invites create --ttl 24h --max-uses 10 --config relay.yaml`, RunE: runInvitesCreate, @@ -157,9 +156,8 @@ Discord invite flow) before the invitee has a working Nostr client.`, }) rolesCreateCmd := &cobra.Command{ Use: "create ", Short: "Create a role definition", - Long: `NIP-43 defines no "delete" for a role -- once created, an id can only be -superseded (re-run "create" with the same id and new label/description/ -color/order), never removed.`, + Long: `Create a role definition, or supersede an existing one. NIP-43 has no +delete: re-run with the same id to replace it.`, Example: ` ncli relay roles create moderator --label Moderator --config relay.yaml`, Args: common.ExactArgs(1), RunE: runRolesCreate, } @@ -232,8 +230,9 @@ func adminRequestBody(cmd *cobra.Command, method, path string, body interface{}) // nip11.privkey missing from config -- a missing-required-config // mistake, classified here (rather than at each of stats/reindex/ // clear's own RunE) since wrapCLIError keeps this code even when - // the caller re-wraps it via common.RuntimeError. - return nil, &common.CLIError{Err: err, Code: common.CodeUsage} + // the caller re-wraps it via common.RuntimeError. Help follows the + // error because the fix is a flag the caller can see there. + return nil, &common.CLIError{Err: err, Code: common.CodeUsage, Help: common.HelpAfterError} } url := fmt.Sprintf("http://localhost:%d%s", port, path) diff --git a/cli/relay/command.go b/cli/relay/command.go index 479d29e..bf04ea4 100644 --- a/cli/relay/command.go +++ b/cli/relay/command.go @@ -77,7 +77,7 @@ var ( // say that plainly instead of blaming a specific (nonexistent) // required field. Shared with getAdminConfig in admin.go, which hits // the same situation via a different missing field (nip11.privkey). - errNoRelayConfig = errors.New(`no relay config found -- pass --config, run "ncli relay context use ", or add ncli.yaml/relay.yaml here`) + errNoRelayConfig = errors.New("no relay config found; pass --config or --context ") ) type RelayConfig struct { @@ -229,12 +229,14 @@ type AgentAuthConfig struct { func NewRelayCommand() *cobra.Command { cmd := &cobra.Command{ Use: "relay", - Short: "Run the relay server, or operate one that's already running", - Long: `Bare invocation runs the Nostr relay server. Its subcommands instead -operate a relay that's already running, over NIP-98 authenticated HTTP. - --c/--context runs against a named relay context, creating a -minimal one backed by a fresh identity if that name isn't saved yet.`, + Short: "Run and operate a Nostr relay", + Long: `Run the Nostr relay server. The subcommands operate a relay that is +already running, over NIP-98 authenticated HTTP. + +The config is read from --config, the current relay context, or an +ncli.yaml or relay.yaml in the working directory, in that order. +-c/--context runs against a named context, creating a minimal one backed +by a fresh identity if that name isn't saved yet.`, Example: ` ncli relay --config relay.yaml ncli relay --context myrelay ncli relay stats --config relay.yaml`, @@ -285,7 +287,7 @@ func initConfig() error { } ev.Msg("using config file") } else { - return &common.CLIError{Err: errNoRelayConfig, Code: common.CodeUsage} + return &common.CLIError{Err: errNoRelayConfig, Code: common.CodeUsage, Help: common.HelpAfterError} } if err := viper.Unmarshal(&config); err != nil { diff --git a/cli/relay/context.go b/cli/relay/context.go index bf68f6b..a4fba81 100644 --- a/cli/relay/context.go +++ b/cli/relay/context.go @@ -23,10 +23,11 @@ func addContextCommands(cmd *cobra.Command) { contextCmd := &cobra.Command{ Use: "context", Short: "List or switch the current relay config context", - Long: `Bare invocation lists saved relay contexts (name -> config file path), -marking the current one with "*". A context is what every relay command uses -when --config is omitted, taking priority over any ncli.yaml/relay.yaml in -the working directory.`, + Long: `List saved relay contexts (name -> config file path), marking the +current one with "*". + +A relay command uses the current context when --config is omitted, in +preference to any ncli.yaml or relay.yaml in the working directory.`, Example: ` ncli relay context list`, Args: common.NoArgs, RunE: runContextList, @@ -35,7 +36,7 @@ the working directory.`, listCmd := &cobra.Command{ Use: "list", Short: "List saved relay contexts", - Long: `Same as bare "context": lists saved relay contexts, marking the current one with "*".`, + Long: `List saved relay contexts, marking the current one with "*".`, Example: ` ncli relay context list`, Args: common.NoArgs, RunE: runContextList, @@ -64,9 +65,8 @@ the working directory.`, useCmd := &cobra.Command{ Use: "use ", Short: "Switch the current relay context", - Long: `Set name as the current relay context -- every relay command uses its -config file when --config is omitted, even if the working directory has -its own ncli.yaml/relay.yaml.`, + Long: `Set name as the current relay context. Relay commands use its config +file whenever --config is omitted.`, Example: ` ncli relay context use myrelay`, Args: common.ExactArgs(1), RunE: runContextUse, From 7ca04625879f0009597a2ddc79d0c4f6dbd17c56 Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Wed, 23 Sep 2026 16:12:58 +0000 Subject: [PATCH 2/2] docs: add the PR backreference to the changelog (#61) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8de4809..9066a18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - Rewrote every command's `--help` description in a flatter style: each one now states what the command does, with the rules a caller can't guess stated plainly, instead of explaining the reasoning behind it. + (#61) ### Fixed @@ -41,6 +42,7 @@ one line and no help. It now prints a short error followed by the command's help, which lists the flags and where the config is read from. Same for the `relay` admin subcommands missing `nip11.privkey`. + (#61) - `ncli relay` could freeze until restarted: a `REQ` held its database read open while sending events, so a write that grew the database file hung every other `REQ` and `EVENT`, health checks included. Fixed