Commit Graph

90 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
bf6be68d79 fix(serverless): persistent connection pool — stop rate-limit storm
Root cause of 'everything is rate-limited' / 'noting too much': the
serverless transport opened a FRESH WebSocket per query and per publish
(connect→send→close). get_channels fires ~10 queries, create channel 2
publishes, add-agent several more — each a new connection. Public relays
(damus, nos.lol) aggressively rate-limit connection storms + event
bursts, so every action failed.

Fix (validated against damus/nostr-tools idiomatic patterns + NIP-01/65):
- ws_pool.rs: one persistent WebSocket per relay, reused for all
  queries/publishes; background reader dispatches by sub/event id;
  transparent reconnect; NIP-42 AUTH answered on the same socket.
- Don't block on slow relays: publish returns on FIRST acceptance
  (FuturesUnordered); connect has a 4s timeout; failed relays enter a
  30s cooldown so a dead relay isn't re-dialed every query.
- Multi-relay publish (success if any accepts) confirmed idiomatic —
  not a mistake; it's the resilience model and hides per-relay rate caps.
- Pool cleared on workspace switch.

Verified live: 5-relay burst (15 queries + 6 publishes) that previously
hung 3+min now completes in 17s with zero rate-limits; create→join
roundtrip passes on 2 relays. 426 unit tests pass, clippy clean.

New live test: serverless_burst_no_rate_limit.
2026-06-02 15:05:25 +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
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
Will Pfleger
7beb0f8e68 fix(desktop): reap orphaned agent processes on shutdown and restart (#787) 2026-05-29 18:18:55 +00:00
Will Pfleger
fa7febe40f fix(desktop): sync persona pack directory across worktree instances (#782) 2026-05-28 20:41:23 -04: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
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
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
Will Pfleger
b13db17faf feat(desktop): two-layer agent prompts + dynamic AGENTS.md + MCP gating + harness-agnostic skill path (#584)
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
2026-05-26 17:46:30 -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
4269fd2720 Show all ACP runtimes with install status and one-click install (#724) 2026-05-22 20:33:35 -04:00
Will Pfleger
091e38ff0a Fix SPROUT_SHARE_IDENTITY worktree dev workflow breaks (#702) 2026-05-21 17:53:20 -04:00
Will Pfleger
582cfc8885 Bundle sprout CLI in DMG release + agent PATH discoverability (#614) 2026-05-19 20:53:46 -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
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
Wes
11778f4250 feat(desktop): image download, drag-drop prevention, and drop zone indicator (#542)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-11 23:26:12 +00:00
Wes
1b9f6169ee feat(desktop): channel templates — reusable project settings (#538)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-11 12:31:25 -07:00
tlongwell-block
90b0af136d fix: resolve media proxy relay URL dynamically per-request (#518) 2026-05-09 02:58:58 +00:00
Wes
ec489c5b1a feat(desktop): add keep awake while agents are active setting (#484)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 13:14:00 -07:00
tlongwell-block
454781caae Sprout speaks Nostr. Nothing else. (#475) 2026-05-05 12:03:06 -04:00
Wes
4d0cd58d35 feat: pnpm workspace, deep links, and web repos page (#476)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-04 17:09:25 -07:00
Bradley Axen
c1063a0c92 Update onboarding flow to support membership checks and BYOK (#457) 2026-05-04 19:48:14 +00:00
Wes
e105c9ea5e feat(desktop): add relay membership admin UI in settings (#454)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-02 16:56:41 +00:00
Bradley Axen
fcec10547d Route ACP observer traffic over relay (#421)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Co-authored-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Tyler Longwell <tlongwell@squareup.com>
2026-04-30 09:34:37 -04:00
Bradley Axen
7c2c556d72 feat: Add local ACP session observer (#412) 2026-04-29 04:21:58 +00:00
Wes
2a01ca590d Implement NIP-RS unread state sync (#420)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-28 20:54:09 -07:00
Wes
a9024c2c78 Add multi-workspace support to desktop app (#409)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-28 04:47:11 +00:00
Wes
c1a33e3ff1 feat(desktop): restore Tauri auto-updater support (#393)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 11:55:35 -07:00
Wes
686db1294e feat(desktop): streaming video proxy + player UX improvements (#389)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 09:42:44 -07:00
Wes
2a131df718 fix(desktop): eliminate agent startup beachball (#374)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 14:34:26 -07:00
Wes
cca1d51012 Remove release pipeline from public repo (#360)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 06:55:09 -07:00
Wes
fc67dac4c6 feat: NIP-AB device pairing — Phase 2 (desktop + mobile UI) (#343)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:25:18 -07:00
Wes
12dca80e1a feat(desktop): improve huddle bar UX + audio device selection (#340)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 19:36:46 +00:00
Wes
94d4e16461 feat(mobile): websocket streaming with real-time messaging (#323)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:20:35 -07:00
tlongwell-block
dd6107d0d0 feat: Sprout Huddles — voice conversations with AI agents (#299) 2026-04-14 13:11:09 -04:00
rbrackney-sq
be83699559 feat: add change member role in channel sidebar (#313)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 08:14:36 -07:00
tlongwell-block
d07385fe02 feat: Markdown-based persona packs (crate + ACP + desktop) (#297) 2026-04-11 13:32:14 -04:00
Wes
1211b0edc6 feat(desktop): add Pulse social notes surface (#296)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:09:38 -07:00
tlongwell-block
ff86e0cf49 feat: add Sprout nest — persistent agent workspace at ~/.sprout (#290) 2026-04-10 15:01:26 -04:00
tlongwell-block
61efb883a1 feat: Phase 1 video upload support (Blossom-compliant-ish) (#285) 2026-04-10 12:23:29 -04:00
Wes
4d44f4741f Restore chooser-based persona catalog flow (#275) 2026-04-08 21:04:09 -07:00
Wes
7a1eb31492 [codex] Show recent notes in user popovers (#270) 2026-04-08 12:24:10 -07:00
Wes
7e4bcfb8c2 [codex] Reduce desktop release startup work (#269) 2026-04-08 11:13:14 -07:00
Wes
c0421a50ed [codex] Add workflow UI parity (#250) 2026-04-06 11:41:52 -07:00
Wes
53c2223ba5 [codex] Improve desktop startup shell loading (#241) 2026-04-06 09:19:47 -07:00
Wes
b8ee474302 Fix shutdown: kill all agent processes reliably (#227)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 14:32:24 -07:00
Wes
ddd54a6e84 feat: add Workflows UI surface (#217)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:54:29 -07:00
Wes
3d61fd60e8 feat(desktop): add message editing support (#182)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 14:04:57 -07:00