feat(cli): add buzz feed watch for streaming activity events - #3562
Open
mvanhorn wants to merge 1 commit into
Open
feat(cli): add buzz feed watch for streaming activity events#3562mvanhorn wants to merge 1 commit into
mvanhorn wants to merge 1 commit into
Conversation
FeedCmd had exactly one variant, Get, which issues a single REST query and returns. An agent that wants to react to mentions had to poll feed get on a timer and dedupe across window boundaries, paying a latency floor equal to the poll interval and carrying its own cursor. buzz-ws-client is already a buzz-cli dependency and already exposes everything a subscription needs (connect_authenticated, send_raw, next_event, disconnect, and a RelayMessage enum). Only the one-shot publish half was being used. Add buzz feed watch: authenticate, send a NIP-01 REQ with the same filter cmd_get_feed builds, then print one JSON event per line and flush. Eose is silent, notices and closures go to stderr, and an Auth challenge triggers re-authentication. Ctrl-C closes the subscription and disconnects cleanly. NDJSON rather than a JSON array because the stream never terminates, so the array would never close. feed get keeps its array output unchanged. parse_feed_types and build_feed_filter are extracted so get and watch validate identical input and select identical events; a regression test pins the no-flags filter to what feed get sent before. tokio gains the signal feature for ctrl_c. Signed-off-by: Matt Van Horn <mvanhorn@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Simulated demo. Terminal frames are verbatim captured output — the opening is this branch's parent commit answering
unrecognized subcommand 'watch'. The event-delivery diagram is labelled illustrative — not a live capture because no relay was run, and the closing frame states that the receive loop has no automated coverage yet.FeedCmdhas exactly one variant,Get, which issues a single REST query and returns. An agent that wants to react to mentions has to pollbuzz feed get --since <ts>on a timer, which costs a latency floor equal to the poll interval, delivers duplicates at window boundaries that the caller has to dedupe by event id, and pushes cursor management onto the caller.The pieces for a subscription are already in the tree and unused.
buzz-ws-clientis already abuzz-clidependency ("WebSocket client — ephemeral event publish") and already exposesconnect_authenticated,send_raw,next_event,disconnect, and aRelayMessageenum coveringEvent/Eose/Closed/Notice/Auth/Count. Today the CLI uses exactly one of these, for one-shot ephemeral publish. The subscription half of the same client was never wired up.buzz feed watchauthenticates, sends a NIP-01REQwith the same filtercmd_get_feedbuilds, and prints one JSON event per line, flushing immediately:Eoseis silent (it only marks the end of backfill).jq --unbufferedconsumer.Authchallenge triggers re-authentication.--sincereplays backfill first and then stays live, so an agent restarting after a crash resumes from its last seen timestamp in one command.NDJSON rather than a JSON array because the stream never terminates, so the array would never close.
buzz feed getkeeps its existing array output untouched.parse_feed_typesandbuild_feed_filterare extracted fromcmd_get_feedsogetandwatchreject identical bad input and select identical events.tokiogains thesignalandtimefeatures forctrl_cand the idle deadline.Related issue
None found. Searched open issues and PRs for
feed watch,stream subscribe cli— zero hits. #944 (feat(agent): SSE streaming for LLM completions, closed unmerged) is LLM token streaming insidebuzz-agentand shares no surface with a relay subscription.Every comparable platform ships a listen primitive: Slack Socket Mode,
mmctl websocket, Zulip'scall_on_each_message.Testing
cargo test -p buzz-cli— 258 passed, 0 failed. New unit tests incommands::feed::tests, no relay required:CliError::Usage; surrounding whitespace trimmed (parity with today'sfeed getbehavior)feed getsent before this change (regression guard)since,#h,feed_types,limit) appear only when suppliedjust fmtandcargo clippy -p buzz-cli --all-targets -- -D warningsare both clean.Local verification:
Input validation returns before any relay connection is attempted.
Three details in the receive loop are worth a reviewer's attention, since they are the parts a stub test would not have caught:
WsClientError::Timeoutcounts as an idle tick. Any other error — a closed socket, a transport failure — returnsErrrather than being retried, so a dropped connection surfaces instead of spinning.select!branch rather than a check afternext_eventreturns, becausenext_eventanswers relay Pings internally and restarts its own timeout; a chatty relay would otherwise keep it pending past the deadline forever. The deadline resets only on a deliveredEvent.AUTHand withholdsOKcannot swallow a SIGINT or stretch--idle-timeout.The receive loop itself has no automated coverage — that needs a stub WebSocket server.
Cargo.tomlalready carriesaxumas a dev-dependency for "minimal HTTP test server for retry/policy integration tests", so atests/feed_watch.rsdriving a stub relay is the shape to follow if you would like that before merge. Happy to add it.No UI change.
crates/buzz-cli/README.mddocuments the subcommand and the NDJSON contract.AI was used for assistance. I wrote, ran, and reviewed the final code and tests.