From c7bde868e1bd619c63c2940a3e4db917b2fd6576 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 6 Jul 2026 14:30:08 +0000 Subject: [PATCH] feat(cli): require --clear to empty a relay bucket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `relay set --type T` with no URLs is now rejected (bad_args, exit 2) instead of silently wiping the list — a bare empty `set` is almost always a shell variable that expanded to nothing. Emptying a bucket is explicit: pass `--clear` (mutually exclusive with URLs). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01EjHzNewJ2sfBGCcSwe35Mc --- cli/README.md | 3 ++- .../main/kotlin/com/vitorpamplona/amethyst/cli/Main.kt | 4 ++-- .../vitorpamplona/amethyst/cli/commands/RelayCommands.kt | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cli/README.md b/cli/README.md index dc30b1cad1..e7148f67ab 100644 --- a/cli/README.md +++ b/cli/README.md @@ -462,7 +462,8 @@ event but do not broadcast — run `relay publish-lists` to push them. |---|---| | `amy relay add URL [--type T] [--marker read\|write\|both]` | Append URL to a bucket (default `all`). `--marker` sets the read/write role for `nip65` (default `both`). | | `amy relay remove URL [--type T]` | Drop URL from a bucket (default `all`). | -| `amy relay set --type T [URL…] [--marker read\|write\|both]` | Replace a bucket's whole list. Passing no URLs clears it. | +| `amy relay set --type T URL… [--marker read\|write\|both]` | Replace a bucket's whole list. | +| `amy relay set --type T --clear` | Empty a bucket. Clearing is explicit — a bare `set` with no URLs is rejected (guards against a shell variable that expanded to nothing); `--clear` and URLs are mutually exclusive. | | `amy relay list [--type T]` | Print the configured relays for every bucket, or just `T`. | | `amy relay publish-lists` | Broadcast every configured relay list to the union of your relays. | diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Main.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Main.kt index dbe443a71a..747dffafa3 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Main.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Main.kt @@ -396,8 +396,8 @@ private fun printUsage() { | [--marker read|write|both] T=nip65|inbox|key_package|search|private|blocked| | trusted|proxy|indexer|broadcast|feeds|all | relay remove URL [--type T] drop URL from a bucket (default all) - | relay set --type T [URL…] replace a bucket's whole list (no URLs clears it) - | [--marker read|write|both] + | relay set --type T URL… [--marker read|write|both] replace a bucket's whole list + | relay set --type T --clear empty a bucket (URLs and --clear are mutually exclusive) | relay list [--type T] print configured relays (all buckets, or just T) | relay publish-lists broadcast every configured relay list | relay info URL fetch + print a relay's NIP-11 info document diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/RelayCommands.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/RelayCommands.kt index 06e1564651..bab540dc65 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/RelayCommands.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/RelayCommands.kt @@ -323,6 +323,14 @@ object RelayCommands { // dedupe, preserve order val relays = normalized.distinctBy { it.url } + // Clearing a bucket is destructive, so it must be explicit: `--clear` + // with no URLs. A bare `set` with no URLs is almost always a shell + // variable that expanded to nothing — reject it rather than silently + // wiping the list. (require → IllegalArgumentException → bad_args/exit 2.) + val clear = args.bool("clear") + require(relays.isNotEmpty() || clear) { "set needs at least one URL, or --clear to empty the $type list" } + require(relays.isEmpty() || !clear) { "--clear cannot be combined with relay URLs" } + Context.open(dataDir).use { ctx -> val signed: Event = if (type == NIP65) {