Commit Graph

315 Commits

Author SHA1 Message Date
Michael Neale
51c89d4e64 fix(serverless): standard multi-relay Nostr — fix split-brain reads, query flood, single-relay live subscription
The serverless transport was behaving like it talked to the bespoke Sprout
server instead of a standard multi-relay Nostr client. Three real bugs:

1. Split-brain: messages were sent over the multi-relay pool (landing on
   whichever relay accepts, e.g. nos.lol when damus rate-limits) but READ over
   a single-relay live WS (damus only) — so your own message was invisible.
   Fix: in serverless, send + history + LIVE SUBSCRIPTION all go through the
   Rust multi-relay pool. New persistent pool subscribe()/unsubscribe() keeps a
   REQ open on ALL relays at once and merges+dedups (standard Nostr, like damus
   SimplePool). New commands: query_channel_messages, subscribe/unsubscribe_
   channel_messages; events streamed to the UI via serverless-event:<channel>.

2. Query flood: get_channels ran {kinds:[39000],limit:5000} (discover ALL
   network channels) + a 500-id member-count batch on a public relay. Fix:
   serverless skips network-wide discovery; only your member channels are
   listed (4 scoped queries).

3. Diagnostics: added [serverless]/[pool] backend logging and [relay] webview
   console logging so failures are visible, not silent.

Proven with live tests against damus+nos.lol: multi-relay publish survives
per-relay rate-limit, and the live subscription delivers a message published
to a different relay than the naive primary (the split-brain fix).
2026-06-02 15:35:28 +10:00
Michael Neale
74deb9cf77 feat(serverless): NIP-17 encrypted DMs + private channels (desktop)
Serverless private channels and DMs are made private by encryption (no
server to enforce access). Messages are NIP-17 gift-wrapped (kind 1059)
to every member; the relay only sees opaque blobs addressed by #p.

- crate::encrypted: build_gift_wraps (one per member) + unwrap_gift
- send_channel_message: routes serverless DM/private channels through
  encryption (rumor=kind9 with h tag -> seal -> wrap per member)
- decrypt_gift_wrap command + relayClient encrypted fetch/subscribe
  (query kind1059 #p=me, decrypt, route by inner h tag)
- proven end-to-end over wss://relay.damus.io (group A->{A,B,C}, B reads)

Agent-side gift-wrap support (sprout-acp) follows separately.
2026-06-02 10:10:10 +10:00
Michael Neale
8934a07051 feat(serverless): multi-relay support — publish-to-all, read-deduped
Serverless workspaces now take a comma-separated relay list (seeded with the
5 default public relays) for redundancy:
- ws_relay query/submit/publish fan out to all relays concurrently; reads
  merge+dedup by event id, writes succeed if any relay accepts
- relay_ws_urls_with_override parses the comma list; live WS uses first relay
- setup UIs (Welcome + AddWorkspace) have multi-select relay chips
- integration test proves publish-to-2 / read-deduped-from-2
2026-06-02 09:25:24 +10:00
Michael Neale
c508603543 feat(serverless): default public relays from deez mesh client
Add DEFAULT_PUBLIC_RELAYS (sourced from deez/crates/mesh-client
DEFAULT_RELAYS) as quick-pick chips when creating a serverless
workspace, in both the Add Workspace dialog and the Welcome screen.

- relay.damus.io, nos.lol, relay.nostr.band, nostr.land, nostr.wine
- chips one-tap fill the relay URL field (serverless mode only)
- DEFAULT_SERVERLESS_RELAY prefills when serverless is first enabled
2026-06-02 08:05:57 +10:00
Michael Neale
84f84931f1 feat(serverless): run channels, DMs, messages, and agents against a generic Nostr relay
Adds a 'serverless' workspace mode that points the desktop app at any generic
public Nostr relay (e.g. wss://relay.damus.io) with zero Sprout server
infrastructure — no Postgres, no HTTP /query|/events bridge, no NIP-98 auth.
Reuses Sprout's native event kinds (39000 channel metadata, 39002 membership,
kind 9 messages, h-tag scoping); 'serverless' is purely a transport + auth
concern, so the server-mode path is untouched.

Transport: reads/writes go over plain WebSocket (REQ/EOSE, EVENT/OK) instead
of the HTTP bridge; NIP-42 AUTH is answered only if the relay challenges.

Desktop backend:
- AppState.serverless flag + is_serverless(); apply_workspace gains a flag
- ws_relay.rs: query_relay_ws / submit_event_ws / publish_signed_event_ws
- relay.rs: query_relay/submit_event + agent profile sync branch to WS
- events.rs: build_channel_metadata_serverless (39000) + members (39002)
- create_channel/open_dm publish those events directly (DM ids = UUIDv5 over
  sorted participants so both sides converge without a server)
- managed agents inherit SPROUT_SERVERLESS into the ACP subprocess env

Agents (full support, not a follow-up):
- sprout-acp: RestClient + HarnessRelay gain serverless mode; query/submit use
  plain WS, NIP-42 handshake skipped on (re)connect; SPROUT_SERVERLESS env/arg
- sprout-cli: SproutClient serverless WS query/submit; --serverless flag,
  to_ws_url helper, NetworkMsg error variant
- npub respond-to permissions are in-process and work unchanged

Frontend:
- Workspace.mode + workspaceMode()/isServerlessWorkspace() helpers
- relayClient.setServerless() skips the AUTH-wait on connect; late challenges
  still answered so writes succeed on relays that require auth
- ServerlessContext/useIsServerless() hides search, pulse, projects, workflows
- Serverless toggle in the Add Workspace dialog and Welcome screen

Docs: docs/SPROUT_LITE_MODE.md updated with the implementation + testing steps.
2026-06-01 20:42:29 +10:00
thomaspblock
bc23620fcf Fix desktop glass chrome and inbox previews (#793)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 20:27:16 -07:00
Will Pfleger
85861f33fe feat: add code block support to message composer (#788) 2026-05-29 11:38:10 -07:00
thomaspblock
d77b111b15 Update desktop navigation chrome and search (#779)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 08:26:41 -07:00
tlongwell-block
5ee2cd0517 feat(desktop): reload webview on Cmd/Ctrl+R (#785) 2026-05-29 10:24:56 -04:00
Will Pfleger
3f3ec64791 feat(desktop): thread-aware notifications with mutable follow/mute controls (#761) 2026-05-28 18:43:41 -04:00
Will Pfleger
03e678cfbc fix(desktop): improve model picker message and runtime dropdown clarity (#778) 2026-05-28 18:21:12 -04:00
Wes
9db8f6ccb8 desktop: float unread indicator + fix sidebar scroll jump (#777)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
2026-05-28 15:15:19 -07:00
Wes
fec6a683ea feat(sidebar): add More unread floating buttons (#771)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
2026-05-28 11:05:02 -07:00
Taylor Ho
8eedec7403 chore: improve markdown spacing (#766) 2026-05-28 17:35:10 +00:00
Taylor Ho
835a44aad0 fix: prevent inline links rendering in 2-column grid layout (#767) 2026-05-28 17:34:35 +00:00
Wes
30654e95f6 Polish desktop Pulse and Home views (#764)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
2026-05-28 08:17:02 -07:00
Will Pfleger
f42839c740 feat(desktop): worktree agent data sync, retired persona cleanup, mcp_command reconciliation (#728)
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
2026-05-27 16:46:16 -04:00
Wes
35821574c0 feat(desktop): redesign status UI with full emoji picker and presence sub-menu (#760)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
2026-05-27 13:13:33 -07:00
Wes
8946653af8 fix(desktop): add support for deeplinking to channel/messages (#759)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
2026-05-27 12:27:34 -07:00
Wes
11c8c0d4cf fix(desktop): add top padding to forum view to clear overlay header (#758)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
2026-05-27 12:26:28 -07:00
Wes
f1e25b21da feat(desktop): editable attachments + data-loss fix on message edit (#755)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: summer <summer@sprout>
2026-05-26 19:59:06 -07:00
Will Pfleger
7df4681fee feat(desktop): dock bounce, mark-as-read toggle, and bulk mark-all-read (#753) 2026-05-26 17:38:29 -07:00
Wes
ab71ade9e7 fix: prevent agent settings from being silently deleted on channel deletion (#752)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-26 16:09:09 -07:00
Wes
7ac0466e12 fix: agent management UI fixes (permissions, parallelism, form validation) (#750) 2026-05-26 13:39:49 -07:00
Wes
8a468a9876 fix: UI fixes for system message avatars and agents page (#749)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-26 10:46:34 -07:00
tlongwell-block
59f51a8ac7 feat(desktop): hide archived identities from discovery surfaces (NIP-IA) (#734)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
2026-05-23 13:58:01 -04:00
tlongwell-block
79399d9b8e feat: NIP-IA identity archival (relay backend + desktop) (#733)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
2026-05-23 12:03:38 -04:00
Will Pfleger
839097112c fix(deps): migrate Tailwind CSS from v3 to v4 (#711) 2026-05-22 20:45:47 -04:00
Will Pfleger
4269fd2720 Show all ACP runtimes with install status and one-click install (#724) 2026-05-22 20:33:35 -04:00
thomaspblock
441b6c4b1a Fix inbox thread navigation highlights (#720)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 22:17:52 -04:00
Taylor Ho
ee4ee5f850 fix: composer UX improvements (cursor, upload guard, scroll, paste, perf) (#694) 2026-05-21 22:53:10 +00:00
Will Pfleger
091e38ff0a Fix SPROUT_SHARE_IDENTITY worktree dev workflow breaks (#702) 2026-05-21 17:53:20 -04:00
tlongwell-block
4373a13fb3 fix(relay): avoid websocket writes in stall watchdog (#697)
Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Dawn (sprout agent) <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
2026-05-21 12:56:12 -04:00
tlongwell-block
a96cb487f4 fix(desktop): project home read-state from the shared NIP-RS marker (#631)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Dawn (sprout agent) <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
2026-05-20 17:13:59 -04:00
Taylor Ho
af08b0f0e8 fix: prevent agent proliferation when adding bots to channels (#621) 2026-05-20 12:08:34 -07:00
Will Pfleger
c8f99bbc31 fix: surface swallowed errors across crates and emit turn failures to activity log (#628) 2026-05-20 14:55:20 -04:00
thomaspblock
b5e5a39bf0 Refine Pulse composer and post actions (#629)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 13:04:47 -04:00
Mat Balez
2da3402f10 [codex] Add copy button for rendered code blocks (#619)
Signed-off-by: Mat Balez <60949391+matbalez@users.noreply.github.com>
2026-05-20 14:25:03 +00:00
tlongwell-block
5370a75ca4 feat(relay): surface connection loss in the workspace header (#623)
Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
2026-05-20 09:36:52 -04:00
tlongwell-block
2392e6523a fix(composer): use native ProseMirror inserts for autocomplete (mentions / channels / emoji) (#618)
Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Quinn (sprout agent) <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@sprout-oss.stage.blox.sqprod.co>
2026-05-19 20:28:40 -04:00
thomaspblock
b881d5319c Refine thread reply alignment (#620)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 19:11:49 -04:00
tlongwell-block
2fed74bdcd Show channels in command search (#617)
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
2026-05-19 14:33:53 -04:00
thomaspblock
3973080dce Refine conversation visual affordances (#615)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 08:54:41 -04:00
Will Pfleger
50b350dc58 fix(desktop): worktree support — workspace boundary + shared identity (#610) 2026-05-18 19:11:34 -04:00
tlongwell-block
6e1418e571 feat(huddle): fix concurrent-speaker mixing + jitter buffer + protocol v2 (up to 10 peers) (#609)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
2026-05-18 16:34:52 -04:00
tlongwell-block
c0eb5affcf refactor(huddle): switch local TTS to Pocket TTS (Kyutai/sherpa-onnx) (#607)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Signed-off-by: npub1cc3ha7z055mu0rwwu7806t2wt8mj3pvu0uv5mfp2c50dahaqhczshdalg6 <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1cc3ha7z055mu0rwwu7806t2wt8mj3pvu0uv5mfp2c50dahaqhczshdalg6 <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
2026-05-18 14:28:27 -04:00
thomaspblock
137a4e268f Update inbox conversation experience (#608)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 13:48:47 -04:00
thomaspblock
17eea2d267 Fix full-width message layouts (#591)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 09:04:09 -04:00
tlongwell-block
3daf8d6ae1 feat(huddle): swap STT default to Parakeet TDT-CTC 110M (EN, int8) (#562)
Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
2026-05-15 22:22:05 -04:00
tlongwell-block
7763072ef9 fix(desktop): derive unread state from NIP-RS + relay catch-up only (#599)
Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
2026-05-15 14:46:33 -04:00