Skip to content

Commit 7478077

Browse files
Merge remote-tracking branch 'origin/main' into initial_revisions
* origin/main: Add desktop Home feed (#12) Add desktop Playwright e2e harness (#11) Update desktop icon and persist window state (#9) feat: add channel creation flow (#8) Improve message markdown display and formatting (#7) feat(desktop): connect chat to relay (#6) docs(readme): clarify desktop setup (#4) feat: add desktop app (#3) # Conflicts: # crates/sprout-test-client/tests/e2e_rest_api.rs
2 parents 43ac326 + 194ddc6 commit 7478077

158 files changed

Lines changed: 16618 additions & 75 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 172 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,181 @@ env:
88
CARGO_TERM_COLOR: always
99

1010
jobs:
11-
check:
11+
rust-lint:
12+
name: Rust Lint
1213
runs-on: ubuntu-latest
1314
timeout-minutes: 30
15+
permissions:
16+
contents: read
1417
steps:
1518
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
16-
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
19+
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
20+
- uses: Swatinem/rust-cache@ad397744b0d591a723ab90405b7247fac0e6b8db # v2
21+
- name: Format check
22+
run: just fmt-check
23+
- name: Clippy
24+
run: just clippy
25+
26+
unit-tests:
27+
name: Unit Tests
28+
runs-on: ubuntu-latest
29+
timeout-minutes: 30
30+
permissions:
31+
contents: read
32+
steps:
33+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
34+
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
35+
- uses: Swatinem/rust-cache@ad397744b0d591a723ab90405b7247fac0e6b8db # v2
36+
- name: Unit tests
37+
run: just test-unit
38+
39+
desktop:
40+
name: Desktop
41+
runs-on: ubuntu-latest
42+
timeout-minutes: 45
43+
permissions:
44+
contents: read
45+
steps:
46+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
47+
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
48+
- uses: Swatinem/rust-cache@ad397744b0d591a723ab90405b7247fac0e6b8db # v2
1749
with:
18-
components: rustfmt, clippy
50+
workspaces: desktop/src-tauri
51+
- name: Install Tauri dependencies (Linux)
52+
env:
53+
DEBIAN_FRONTEND: noninteractive
54+
run: |
55+
sudo apt-get update \
56+
-o Acquire::Retries=3 \
57+
-o Acquire::http::Timeout=30 \
58+
-o Acquire::https::Timeout=30
59+
sudo apt-get install -y --no-install-recommends \
60+
-o Acquire::Retries=3 \
61+
-o Acquire::http::Timeout=30 \
62+
-o Acquire::https::Timeout=30 \
63+
-o DPkg::Lock::Timeout=120 \
64+
build-essential \
65+
curl \
66+
file \
67+
libayatana-appindicator3-dev \
68+
libgtk-3-dev \
69+
librsvg2-dev \
70+
libssl-dev \
71+
libwebkit2gtk-4.1-dev \
72+
libxdo-dev \
73+
patchelf \
74+
wget
75+
- name: Install desktop dependencies
76+
run: just desktop-install-ci
77+
- name: Install Playwright Chromium
78+
run: cd desktop && pnpm exec playwright install --with-deps chromium
79+
- name: Desktop lint and format
80+
run: just desktop-check
81+
- name: Desktop build
82+
run: just desktop-build
83+
- name: Desktop smoke e2e
84+
run: cd desktop && pnpm exec playwright test --project=smoke
85+
- name: Desktop Tauri check
86+
run: just desktop-tauri-check
87+
- name: Upload desktop e2e artifacts
88+
if: failure()
89+
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4
90+
with:
91+
name: desktop-e2e-artifacts
92+
path: |
93+
desktop/playwright-report
94+
desktop/test-results
95+
if-no-files-found: ignore
96+
97+
desktop-e2e-integration:
98+
name: Desktop E2E Integration
99+
runs-on: ubuntu-latest
100+
timeout-minutes: 45
101+
permissions:
102+
contents: read
103+
steps:
104+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
105+
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
19106
- uses: Swatinem/rust-cache@ad397744b0d591a723ab90405b7247fac0e6b8db # v2
20-
- run: cargo fmt --all -- --check
21-
- run: cargo clippy --workspace --all-targets -- -D warnings
22-
- run: cargo test --workspace
23-
- run: cargo install cargo-audit --locked
24-
- run: cargo audit --ignore RUSTSEC-2023-0071 --ignore RUSTSEC-2024-0384
25-
- run: cargo install cargo-deny --locked
26-
- run: cargo deny check
107+
with:
108+
workspaces: desktop/src-tauri
109+
- name: Install desktop dependencies
110+
run: just desktop-install-ci
111+
- name: Install Playwright Chromium
112+
run: cd desktop && pnpm exec playwright install --with-deps chromium
113+
- name: Desktop build
114+
run: just desktop-build
115+
- name: Start integration services
116+
run: docker compose up -d
117+
- name: Wait for integration services
118+
run: |
119+
wait_healthy() {
120+
local service="$1"
121+
local container="$2"
122+
for attempt in $(seq 1 60); do
123+
status=$(docker inspect --format='{{.State.Health.Status}}' "${container}" 2>/dev/null || echo "not_found")
124+
if [ "${status}" = "healthy" ]; then
125+
echo "${service} is healthy"
126+
return 0
127+
fi
128+
sleep 2
129+
done
130+
docker logs "${container}" || true
131+
return 1
132+
}
133+
wait_healthy "MySQL" "sprout-mysql"
134+
wait_healthy "Redis" "sprout-redis"
135+
wait_healthy "Typesense" "sprout-typesense"
136+
- name: Build relay
137+
run: cargo build -p sprout-relay
138+
- name: Start relay
139+
run: |
140+
nohup env \
141+
DATABASE_URL=mysql://sprout:sprout_dev@localhost:3306/sprout \
142+
REDIS_URL=redis://localhost:6379 \
143+
TYPESENSE_URL=http://localhost:8108 \
144+
TYPESENSE_API_KEY=sprout_dev_key \
145+
RELAY_URL=ws://localhost:3000 \
146+
SPROUT_BIND_ADDR=0.0.0.0:3000 \
147+
SPROUT_REQUIRE_AUTH_TOKEN=false \
148+
./target/debug/sprout-relay > /tmp/sprout-relay.log 2>&1 &
149+
echo $! > /tmp/sprout-relay.pid
150+
for attempt in $(seq 1 60); do
151+
if ! kill -0 "$(cat /tmp/sprout-relay.pid)" 2>/dev/null; then
152+
cat /tmp/sprout-relay.log
153+
exit 1
154+
fi
155+
status_code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/api/channels || true)
156+
if [ "${status_code}" != "000" ]; then
157+
exit 0
158+
fi
159+
sleep 1
160+
done
161+
cat /tmp/sprout-relay.log
162+
exit 1
163+
- name: Seed desktop e2e data
164+
run: bash scripts/setup-desktop-test-data.sh
165+
- name: Desktop relay-backed e2e
166+
run: cd desktop && pnpm exec playwright test --project=integration
167+
- name: Upload desktop integration artifacts
168+
if: failure()
169+
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4
170+
with:
171+
name: desktop-e2e-integration-artifacts
172+
path: |
173+
desktop/playwright-report
174+
desktop/test-results
175+
/tmp/sprout-relay.log
176+
if-no-files-found: ignore
177+
178+
security:
179+
name: Security
180+
runs-on: ubuntu-latest
181+
timeout-minutes: 20
182+
permissions:
183+
contents: read
184+
steps:
185+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
186+
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
187+
- name: Dependency policy
188+
run: cargo-deny check

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ Thumbs.db
2121
# Scratch / working files (AI reviews, notes, drafts)
2222
.scratch/
2323

24+
# Playwright artifacts
25+
playwright-report/
26+
test-results/
27+
blob-report/
28+
2429
# sqlx offline query data (generated, not portable)
2530
.sqlx/
2631

CONTRIBUTING.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ unacceptable behavior to **conduct@sprout-relay.org**.
3939
| Tool | Version | Notes |
4040
|------|---------|-------|
4141
| Rust | 1.88+ | Install via [rustup](https://rustup.rs/) |
42+
| Node.js | 24+ | Required for desktop app commands and `just ci` |
43+
| pnpm | 10+ | Required for desktop app commands and `just ci` |
4244
| Docker | 24+ | For MySQL, Redis, Typesense |
4345
| `just` | latest | Task runner — `cargo install just` |
46+
| `lefthook` | latest | Optional; run `lefthook install` for local Git hooks |
4447
| `sqlx-cli` | latest | Optional; `just migrate` falls back to `docker exec` |
4548

4649
This repo uses [Hermit](https://cashapp.github.io/hermit/) for toolchain
@@ -68,6 +71,9 @@ cp .env.example .env
6871

6972
# 4. Start infrastructure + run migrations
7073
just setup
74+
75+
# 5. Install Git hooks (optional, recommended)
76+
lefthook install
7177
```
7278

7379
`just setup` starts Docker services (MySQL on `:3306`, Redis on `:6379`,
@@ -134,7 +140,7 @@ Before opening a PR, run the full CI gate locally:
134140

135141
```bash
136142
just ci
137-
# Runs: fmt-check + clippy + unit tests
143+
# Runs: check + unit tests + desktop build + Tauri check
138144
```
139145

140146
This is the same check that runs in CI. PRs that fail `just ci` will not be

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ members = [
1414
"crates/sprout-admin",
1515
"crates/sprout-workflow",
1616
]
17+
exclude = ["desktop/src-tauri"]
1718
resolver = "2"
1819

1920
[workspace.package]

README.md

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,38 @@ append-only and audited.
9999

100100
## Quick Start
101101

102-
**1. Start infrastructure**
102+
**1. Activate the pinned toolchain**
103+
104+
```bash
105+
. ./bin/activate-hermit
106+
```
107+
108+
Hermit pins Rust, Node.js, pnpm, `just`, and related tooling from `bin/`.
109+
If you prefer not to use Hermit, install the prerequisites manually first.
110+
111+
**2. Start infrastructure**
103112

104113
```bash
105114
cp .env.example .env
106-
docker compose up -d
115+
just setup
107116
```
108117

118+
`just setup` starts Docker services and applies pending database migrations.
119+
109120
Services: MySQL `:3306`, Redis `:6379`, Typesense `:8108`, Adminer `:8082`
110121

111-
**2. Start the relay**
122+
**3. Install desktop dependencies**
123+
124+
```bash
125+
just desktop-install
126+
```
127+
128+
This is required before running `just check`, `just ci`, Git hooks, or any
129+
`just desktop-*` command.
130+
131+
The desktop workflow documented here is macOS-first for now.
132+
133+
**4. Start the relay**
112134

113135
```bash
114136
just relay
@@ -117,25 +139,36 @@ just relay
117139

118140
Relay listens on `ws://localhost:3000` by default.
119141

120-
**3. Mint an API token**
142+
**5. Mint an API token**
121143

122144
```bash
123145
cargo run -p sprout-admin -- mint-token \
124146
--name "my-agent" \
125147
--scopes "messages:read,messages:write,channels:read"
126148
```
127149

128-
Outputs a bearer token. Set it as `SPROUT_API_TOKEN` for the MCP server.
150+
Save the `nsec...` private key and API token from the output. They are shown only once.
129151

130-
**4. Connect an agent via MCP**
152+
**6. Launch an agent with the MCP extension**
131153

132154
```bash
133155
SPROUT_RELAY_URL=ws://localhost:3000 \
134156
SPROUT_API_TOKEN=<token> \
135-
cargo run -p sprout-mcp
157+
SPROUT_PRIVATE_KEY=nsec1... \
158+
goose run --no-profile \
159+
--with-extension "cargo run -p sprout-mcp --bin sprout-mcp-server" \
160+
--instructions "List available Sprout channels."
136161
```
137162

138-
The MCP server speaks stdio JSON-RPC. Wire it into any MCP-compatible agent host.
163+
`sprout-mcp-server` is a stdio MCP extension, so start it through a host such as Goose rather than
164+
as a standalone user-facing process. See [TESTING.md](TESTING.md) for the full multi-agent flow.
165+
166+
**7. Run the desktop app (optional)**
167+
168+
```bash
169+
just desktop-app
170+
# or: just desktop-dev
171+
```
139172

140173
## Configuration
141174

@@ -194,24 +227,36 @@ Set `SPROUT_PRIVATE_KEY` (nsec format) to use a persistent identity.
194227

195228
## Development
196229

197-
**Prerequisites:** Rust 1.88+, Docker, [`just`](https://github.com/casey/just)
230+
**Prerequisites:** Rust 1.88+, Docker, Node.js 24+, pnpm 10+, [`just`](https://github.com/casey/just)
198231

199232
This repo uses [Hermit](https://cashapp.github.io/hermit/) for toolchain pinning. Activate with:
200233

201234
```bash
202235
. ./bin/activate-hermit
203236
```
204237

238+
For a fresh clone, install desktop dependencies before running desktop-aware
239+
checks or hooks:
240+
241+
```bash
242+
just desktop-install
243+
lefthook install
244+
```
245+
205246
**Common tasks**
206247

207248
```bash
208249
just setup # Start Docker services + run migrations
209250
just relay # Run the relay (dev mode)
210-
just build # Build entire workspace
211-
just check # fmt-check + clippy
251+
just build # Build the Rust workspace
252+
just desktop-install # Install desktop dependencies
253+
just desktop-dev # Run the desktop web UI only
254+
just desktop-app # Run the Tauri desktop app
255+
just desktop-ci # Desktop check + build + Tauri Rust check
256+
just check # Rust fmt/clippy + desktop check
212257
just test-unit # Unit tests (no infra required)
213258
just test # All tests (starts services if needed)
214-
just ci # fmt-check + clippy + unit tests (CI gate)
259+
just ci # check + unit tests + desktop build + Tauri check
215260
just migrate # Run pending migrations
216261
just down # Stop Docker services (keep data)
217262
just reset # ⚠️ Wipe all data and recreate environment
@@ -222,9 +267,11 @@ just reset # ⚠️ Wipe all data and recreate environment
222267
```bash
223268
cargo run -p sprout-relay
224269
cargo run -p sprout-admin -- --help
225-
cargo run -p sprout-mcp
270+
cargo run -p sprout-mcp --bin sprout-mcp-server
226271
```
227272

273+
`sprout-mcp-server` is normally launched by Goose or another MCP host.
274+
228275
**Database migrations** live in `migrations/`. The relay applies them automatically on startup.
229276
To run manually: `just migrate` (uses `sqlx` CLI if available, falls back to `docker exec`).
230277

bin/.lefthook-2.1.3.pkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hermit

bin/.node-24.14.0.pkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hermit

bin/.pnpm-10.31.0.pkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hermit

bin/.rustup-1.28.2.pkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hermit

0 commit comments

Comments
 (0)