cli(messages): allow --content - to read body from stdin (#624)

Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Dawn (sprout agent) <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
tlongwell-block
2026-05-20 02:38:17 +00:00
committed by GitHub
co-authored by Dawn
parent 582cfc8885
commit c0c9cf9271
5 changed files with 34 additions and 4 deletions
+1
View File
@@ -31,6 +31,7 @@ export SPROUT_RELAY_URL="https://relay.example.com"
# Messages
sprout messages send --channel <uuid> --content "Hello"
sprout messages send --channel <uuid> --content "Reply" --reply-to <event-id> --broadcast
sprout messages send --channel <uuid> --content - < message.md # read body from stdin
sprout messages get --channel <uuid> --limit 20
sprout messages thread --channel <uuid> --event <event-id>
sprout messages search --query "architecture"
+6 -1
View File
@@ -190,6 +190,11 @@ REPLY_ID=$(echo "$REPLY" | jq -r '.id // .event_id')
sprout messages send --channel "$CHANNEL_ID" --content "Hey @someone" \
--mention "0000000000000000000000000000000000000000000000000000000000000001" | jq .
# messages send from stdin — safe path for content with shell metacharacters
# (backticks, $vars, code blocks) that would otherwise be expanded by the shell.
echo 'Body with `backticks` and $vars stays literal.' \
| sprout messages send --channel "$CHANNEL_ID" --content - | jq .
# messages get
sprout messages get --channel "$CHANNEL_ID" | jq .
sprout messages get --channel "$CHANNEL_ID" --limit 5 | jq .
@@ -473,7 +478,7 @@ sprout channels delete --channel "$FORUM_ID" | jq .
| # | Command | Tested | Notes |
|---|---------|:------:|-------|
| 1 | `messages send` | ☐ | Basic, reply, broadcast, mentions |
| 1 | `messages send` | ☐ | Basic, reply, broadcast, mentions, stdin |
| 2 | `messages send-diff` | ☐ | Stdin, metadata, branch/PR |
| 3 | `messages edit` | ☐ | |
| 4 | `messages delete` | ☐ | |
+9 -1
View File
@@ -312,7 +312,15 @@ pub struct SendMessageParams {
pub files: Vec<String>,
}
pub async fn cmd_send_message(client: &SproutClient, p: SendMessageParams) -> Result<(), CliError> {
pub async fn cmd_send_message(
client: &SproutClient,
mut p: SendMessageParams,
) -> Result<(), CliError> {
// Allow '-' to read content from stdin. This keeps callers from having to
// jam shell-metacharacter-heavy text (backticks, $vars, etc.) through argv
// quoting — the source of countless self-inflicted command-substitution
// bugs for agent and human users alike.
p.content = read_or_stdin(&p.content)?;
validate_content_size(&p.content)?;
if let Some(ref r) = p.reply_to {
validate_hex64(r)?;
+2 -2
View File
@@ -200,13 +200,13 @@ enum Cmd {
pub enum MessagesCmd {
/// Send a message to a channel
#[command(
after_help = "Examples:\n sprout messages send --channel <UUID> --content \"hello\"\n sprout messages send --channel <UUID> --content \"@alice check this\""
after_help = "Examples:\n sprout messages send --channel <UUID> --content \"hello\"\n sprout messages send --channel <UUID> --content \"@alice check this\"\n echo \"hello from stdin\" | sprout messages send --channel <UUID> --content -"
)]
Send {
/// Channel UUID (from 'sprout channels list')
#[arg(long)]
channel: String,
/// Message text — supports @mentions and markdown
/// Message text — supports @mentions and markdown. Use '-' to read from stdin.
#[arg(long)]
content: String,
/// Nostr event kind (default: channel default)
+16
View File
@@ -442,4 +442,20 @@ mod tests {
assert!(super::validate_repo_id("foo/bar").is_err());
assert!(super::validate_repo_id("a@b").is_err());
}
// --- read_or_stdin ---
#[test]
fn read_or_stdin_passthrough_returns_value() {
// Anything other than "-" is returned verbatim — backticks, $vars,
// newlines must all survive untouched (no shell evaluation happens
// here; we're past argv parsing).
let raw = "literal `backticks` and $vars\nwith newline";
assert_eq!(super::read_or_stdin(raw).unwrap(), raw);
}
#[test]
fn read_or_stdin_passthrough_empty_string() {
assert_eq!(super::read_or_stdin("").unwrap(), "");
}
}