refactor: rename sprout backend to buzz (#958)

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
Signed-off-by: Will Pfleger <wpfleger@squareup.com>
Signed-off-by: Will Pfleger <wpfleger96@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1fgdl5qqnh3k3f2xkqrvt7cujalhm623x4s7fdjdj5yrtp5fzjl9qrjpucw <4a1bfa0013bc6d14a8d600d8bf6392efefbd2a26ac3c96c9b2a106b0d12297ca@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Will Pfleger <wpfleger96@gmail.com>
This commit is contained in:
Will Pfleger
2026-06-10 19:29:51 -04:00
committed by GitHub
parent 53e3f09485
commit d99ad131f1
306 changed files with 3249 additions and 3373 deletions

View File

@@ -1,12 +1,12 @@
#!/usr/bin/env bash
# Build Sprig — one deploy-anywhere multicall binary for the Sprout ACP
# Build Sprig — one deploy-anywhere multicall binary for the Buzz ACP
# harness, agent, and developer MCP. The archive exposes these command names:
#
# sprig implementation binary
# sprout-acp link to sprig (ACP harness)
# sprout-agent link to sprig (ACP-compliant agent)
# sprout-dev-mcp link to sprig (developer MCP server; also dispatches
# rg/tree/sprout/git-credential-nostr/git-sign-nostr)
# buzz-acp link to sprig (ACP harness)
# buzz-agent link to sprig (ACP-compliant agent)
# buzz-dev-mcp link to sprig (developer MCP server; also dispatches
# rg/tree/buzz/git-credential-nostr/git-sign-nostr)
#
# Usage:
# ./scripts/build-sprig.sh [version] [target]
@@ -32,9 +32,9 @@
#
# The tarball contains:
# sprig
# sprout-acp
# sprout-agent
# sprout-dev-mcp
# buzz-acp
# buzz-agent
# buzz-dev-mcp
# README.md
# sprig.json { version, git_sha, target, binaries: [{name, sha256, size}] }
@@ -59,7 +59,7 @@ else
fi
BUNDLE_BIN="sprig"
COMMANDS=(sprout-acp sprout-agent sprout-dev-mcp)
COMMANDS=(buzz-acp buzz-agent buzz-dev-mcp)
echo "==> Building Sprig v${VERSION} for ${TARGET}"
echo " git_sha=${GIT_SHA}"
@@ -133,18 +133,18 @@ JSON
cat > "${STAGING}/README.md" <<'README'
# Sprig
Sprig is the all-in-one Sprout agent binary for deploy-anywhere environments.
Sprig is the all-in-one Buzz agent binary for deploy-anywhere environments.
It exposes the ACP harness, ACP agent, and developer MCP command names as symlinks
to one multicall binary so shared Rust runtime/TLS code is stored only once.
Commands:
- `sprig` — prints usage/version. Invoke a personality by one of the links below.
- `sprout-acp` — ACP harness that bridges Sprout channel events to an
- `buzz-acp` — ACP harness that bridges Buzz channel events to an
ACP-compliant agent over stdio.
- `sprout-agent` — ACP-compliant agent (spawns MCP servers, calls LLMs).
- `sprout-dev-mcp` — Developer MCP server (shell, str_replace, todo) and
multicall entrypoint for `rg`, `tree`, `sprout`, `git-credential-nostr`,
- `buzz-agent` — ACP-compliant agent (spawns MCP servers, calls LLMs).
- `buzz-dev-mcp` — Developer MCP server (shell, str_replace, todo) and
multicall entrypoint for `rg`, `tree`, `buzz`, `git-credential-nostr`,
`git-sign-nostr`.
See `sprig.json` for SHA-256s, sizes, target, and source git SHA.
@@ -160,14 +160,14 @@ export PATH="/opt/sprig:$PATH"
```bash
# Agent provider
export SPROUT_AGENT_PROVIDER=anthropic # or openai
export BUZZ_AGENT_PROVIDER=anthropic # or openai
export ANTHROPIC_API_KEY=sk-...
export ANTHROPIC_MODEL=claude-sonnet-4-20250514
# Nostr identity (shared by sprout-acp, git auth, signing, and sprout CLI)
# Nostr identity (shared by buzz-acp, git auth, signing, and buzz CLI)
export NOSTR_PRIVATE_KEY=nsec1...
export SPROUT_PRIVATE_KEY="$NOSTR_PRIVATE_KEY"
export SPROUT_RELAY_URL=https://your-relay.example.com
export BUZZ_PRIVATE_KEY="$NOSTR_PRIVATE_KEY"
export BUZZ_RELAY_URL=https://your-relay.example.com
```
README

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
SIDECARS=(sprout-acp sprout-agent sprout-dev-mcp git-credential-nostr sprout)
SIDECARS=(buzz-acp buzz-agent buzz-dev-mcp git-credential-nostr buzz)
HOST=$(rustc -vV | sed -n 's|host: ||p')
TARGET=${1:-$HOST}
BINARIES_DIR="desktop/src-tauri/binaries"
@@ -20,7 +20,7 @@ for bin in "${SIDECARS[@]}"; do
done
if [[ ${#missing[@]} -gt 0 ]]; then
echo "Error: missing release binaries in $SRC_DIR: ${missing[*]}" >&2
echo "Run 'cargo build --release -p sprout-acp -p sprout-agent -p sprout-dev-mcp -p git-credential-nostr -p sprout-cli' first." >&2
echo "Run 'cargo build --release -p buzz-acp -p buzz-agent -p buzz-dev-mcp -p git-credential-nostr -p buzz-cli' first." >&2
exit 1
fi

View File

@@ -49,19 +49,19 @@ load_env() {
set +o allexport
fi
export DATABASE_URL="${DATABASE_URL:-postgres://sprout:sprout_dev@localhost:5432/sprout}"
export DATABASE_URL="${DATABASE_URL:-postgres://buzz:buzz_dev@localhost:5432/buzz}"
export PGHOST="${PGHOST:-localhost}"
export PGPORT="${PGPORT:-5432}"
export PGUSER="${PGUSER:-sprout}"
export PGPASSWORD="${PGPASSWORD:-sprout_dev}"
export PGDATABASE="${PGDATABASE:-sprout}"
export PGUSER="${PGUSER:-buzz}"
export PGPASSWORD="${PGPASSWORD:-buzz_dev}"
export PGDATABASE="${PGDATABASE:-buzz}"
export REDIS_URL="${REDIS_URL:-redis://localhost:6379}"
export TYPESENSE_API_KEY="${TYPESENSE_API_KEY:-sprout_dev_key}"
export TYPESENSE_API_KEY="${TYPESENSE_API_KEY:-buzz_dev_key}"
export TYPESENSE_URL="${TYPESENSE_URL:-http://localhost:8108}"
}
postgres_accepting_connections() {
docker exec sprout-postgres \
docker exec buzz-postgres \
pg_isready -h localhost -p 5432 -U "${PGUSER}" -d "${PGDATABASE}" \
>/dev/null 2>&1
}
@@ -88,7 +88,7 @@ else
# does not support on partitioned tables. Pre-create any such indexes here
# so pgschema sees them as already existing and skips the CONCURRENTLY path.
log "Pre-creating indexes on partitioned tables (if needed)..."
docker exec sprout-postgres psql -U "${PGUSER}" -d "${PGDATABASE}" -q -c \
docker exec buzz-postgres psql -U "${PGUSER}" -d "${PGDATABASE}" -q -c \
"CREATE INDEX IF NOT EXISTS idx_events_parameterized ON events (kind, pubkey, d_tag, deleted_at) WHERE d_tag IS NOT NULL;" \
2>/dev/null || true
@@ -175,7 +175,7 @@ success "Git hooks installed"
echo ""
echo -e "${GREEN}=======================================================${NC}"
echo -e "${GREEN} Sprout dev environment is ready!${NC}"
echo -e "${GREEN} Buzz dev environment is ready!${NC}"
echo -e "${GREEN}=======================================================${NC}"
echo ""
echo -e " ${BLUE}Postgres${NC} ${DATABASE_URL}"

View File

@@ -2,11 +2,11 @@
# =============================================================================
# e2e-git-perms.sh — End-to-end test for git transport, permissions, and signing
# =============================================================================
# Two bots collaborate on a simple web page via the Sprout relay's git server.
# Two bots collaborate on a simple web page via the Buzz relay's git server.
#
# Prerequisites:
# - Docker services running (postgres, redis, typesense)
# - Relay built: cargo build --release --bin sprout-relay
# - Relay built: cargo build --release --bin buzz-relay
# - Credential helper built: cargo build --release --bin git-credential-nostr
# - Signing program built: cargo build --release --bin git-sign-nostr
# - Python 3 with websocket-client: pip install websocket-client
@@ -89,8 +89,8 @@ trap cleanup EXIT
check_deps() {
local missing=()
if [[ ! -x "${REPO_ROOT}/target/release/sprout-relay" ]]; then
missing+=("sprout-relay (cargo build --release --bin sprout-relay)")
if [[ ! -x "${REPO_ROOT}/target/release/buzz-relay" ]]; then
missing+=("buzz-relay (cargo build --release --bin buzz-relay)")
fi
if [[ ! -x "${REPO_ROOT}/target/release/git-credential-nostr" ]]; then
missing+=("git-credential-nostr (cargo build --release --bin git-credential-nostr)")
@@ -331,27 +331,27 @@ if [[ -f .env ]]; then
set +o allexport
fi
export SPROUT_GIT_REPO_PATH="${REPO_ROOT}/repos"
export SPROUT_GIT_HOOK_HMAC_SECRET="${HMAC_SECRET}"
export SPROUT_BIND_ADDR="${RELAY_HOST}:${RELAY_PORT}"
export BUZZ_GIT_REPO_PATH="${REPO_ROOT}/repos"
export BUZZ_GIT_HOOK_HMAC_SECRET="${HMAC_SECRET}"
export BUZZ_BIND_ADDR="${RELAY_HOST}:${RELAY_PORT}"
export RELAY_URL="${RELAY_WS}"
export RUST_LOG="sprout_relay=warn"
export SPROUT_REQUIRE_AUTH_TOKEN=false
export RUST_LOG="buzz_relay=warn"
export BUZZ_REQUIRE_AUTH_TOKEN=false
# Clean repos dir (isolated test state)
rm -rf "${REPO_ROOT}/repos"
mkdir -p "${REPO_ROOT}/repos"
./target/release/sprout-relay > /tmp/sprout-relay-e2e.log 2>&1 &
./target/release/buzz-relay > /tmp/buzz-relay-e2e.log 2>&1 &
RELAY_PID=$!
# Wait for relay to be ready (poll, not sleep)
for i in $(seq 1 "$RELAY_STARTUP_TIMEOUT"); do
if curl -sf --max-time 2 "${RELAY_HTTP}/" -H "Accept: application/nostr+json" | grep -q "Sprout"; then
if curl -sf --max-time 2 "${RELAY_HTTP}/" -H "Accept: application/nostr+json" | grep -q "Buzz"; then
break
fi
if [[ $i -eq "$RELAY_STARTUP_TIMEOUT" ]]; then
fail "Relay did not start within ${RELAY_STARTUP_TIMEOUT}s. Check /tmp/sprout-relay-e2e.log"
fail "Relay did not start within ${RELAY_STARTUP_TIMEOUT}s. Check /tmp/buzz-relay-e2e.log"
fi
sleep 1
done
@@ -403,7 +403,7 @@ log " Add bot2: $ADD_BOT2"
log "Creating repo: $REPO_NAME..."
CREATE_REPO=$(send_event "$OWNER_PRIVKEY" "$KIND_CREATE_REPO" "" \
"[\"d\", \"$REPO_NAME\"], [\"sprout-channel\", \"$CHANNEL_ID\"]")
"[\"d\", \"$REPO_NAME\"], [\"buzz-channel\", \"$CHANNEL_ID\"]")
log " Create repo: $CREATE_REPO"
# Wait for repo creation side effect (bare repo on disk)
@@ -448,7 +448,7 @@ cat > "$BOT1_DIR/index.html" << 'HTML'
<!DOCTYPE html>
<html>
<head>
<title>Sprout E2E Test Page</title>
<title>Buzz E2E Test Page</title>
<style>
body { font-family: system-ui; max-width: 800px; margin: 0 auto; padding: 2rem; }
h1 { color: #2d5016; }
@@ -456,8 +456,8 @@ cat > "$BOT1_DIR/index.html" << 'HTML'
</style>
</head>
<body>
<h1>🌱 Sprout Collaborative Page</h1>
<p>This page was created by two bots collaborating via Sprout's git server.</p>
<h1>🌱 Buzz Collaborative Page</h1>
<p>This page was created by two bots collaborating via Buzz's git server.</p>
<div class="contributor">
<strong>Bot 1</strong> — Created the initial page structure
</div>
@@ -466,14 +466,14 @@ cat > "$BOT1_DIR/index.html" << 'HTML'
HTML
git -C "$BOT1_DIR" add -A
git -C "$BOT1_DIR" -c user.name="Bot1" -c user.email="bot1@sprout.test" \
git -C "$BOT1_DIR" -c user.name="Bot1" -c user.email="bot1@buzz.test" \
-c init.defaultBranch=main commit -m "Initial page structure"
log "Bot1: pushing..."
if git_push "$BOT1_PRIVKEY" "$BOT1_DIR" -u origin main; then
success "Bot1 push succeeded (member can push)"
else
tail -20 /tmp/sprout-relay-e2e.log
tail -20 /tmp/buzz-relay-e2e.log
fail "Bot1 push failed (member should be able to push)"
fi
@@ -491,19 +491,19 @@ sed -i.bak '/<\/body>/i\
<strong>Bot 2</strong> — Added this section (pushing as bot role → promoted to member)\
</div>\
<footer>\
<p><em>Built with Sprout sovereign git hosting</em></p>\
<p><em>Built with Buzz sovereign git hosting</em></p>\
</footer>' "$BOT2_DIR/index.html"
rm -f "$BOT2_DIR/index.html.bak"
git -C "$BOT2_DIR" add -A
git -C "$BOT2_DIR" -c user.name="Bot2" -c user.email="bot2@sprout.test" \
git -C "$BOT2_DIR" -c user.name="Bot2" -c user.email="bot2@buzz.test" \
commit -m "Add bot2 section and footer"
log "Bot2: pushing..."
if git_push "$BOT2_PRIVKEY" "$BOT2_DIR"; then
success "Bot2 push succeeded (bot promoted to member)"
else
tail -20 /tmp/sprout-relay-e2e.log
tail -20 /tmp/buzz-relay-e2e.log
fail "Bot2 push failed (bot should be promoted to member)"
fi
@@ -576,7 +576,7 @@ git_clone "$BOT1_PRIVKEY" "${RELAY_HTTP}/git/${OWNER_PUBKEY}/${REPO_NAME}" "$UNS
echo "<!-- unsigned change -->" >> "$UNSIGNED_DIR/index.html"
git -C "$UNSIGNED_DIR" add -A
git -C "$UNSIGNED_DIR" -c user.name="Bot1" -c user.email="bot1@sprout.test" \
git -C "$UNSIGNED_DIR" -c user.name="Bot1" -c user.email="bot1@buzz.test" \
commit -m "Unsigned commit (no gpgsign)"
if git_push "$BOT1_PRIVKEY" "$UNSIGNED_DIR"; then
@@ -599,7 +599,7 @@ git -C "$SIGNED_DIR" add -A
NOSTR_PRIVATE_KEY="$BOT1_PRIVKEY" \
git -C "$SIGNED_DIR" \
-c user.name="Bot1" \
-c user.email="bot1@sprout.test" \
-c user.email="bot1@buzz.test" \
-c gpg.format=x509 \
-c "gpg.x509.program=$SIGNER" \
-c commit.gpgsign=true \
@@ -629,7 +629,7 @@ fi
# ── Test: Signed commit with owner attestation (NIP-OA) ──────────────────────
log "Signing with owner attestation (SPROUT_AUTH_TAG)..."
log "Signing with owner attestation (BUZZ_AUTH_TAG)..."
OA_DIR="$WORK_DIR/oa-signed"
git_clone "$BOT1_PRIVKEY" "${RELAY_HTTP}/git/${OWNER_PUBKEY}/${REPO_NAME}" "$OA_DIR" \
@@ -699,10 +699,10 @@ print(json.dumps(["auth", owner_pubkey, "", sig]))
PYEOF
)
NOSTR_PRIVATE_KEY="$BOT1_PRIVKEY" SPROUT_AUTH_TAG="$OA_TAG" \
NOSTR_PRIVATE_KEY="$BOT1_PRIVKEY" BUZZ_AUTH_TAG="$OA_TAG" \
git -C "$OA_DIR" \
-c user.name="Bot1" \
-c user.email="bot1@sprout.test" \
-c user.email="bot1@buzz.test" \
-c gpg.format=x509 \
-c "gpg.x509.program=$SIGNER" \
-c commit.gpgsign=true \
@@ -715,7 +715,7 @@ DECODED_SIG=$(echo "$COMMIT_SIG" | base64 -d 2>/dev/null || echo "$COMMIT_SIG" |
if echo "$DECODED_SIG" | grep -q '"oa"'; then
success "Owner attestation (oa field) present in signature"
else
fail "Owner attestation missing from signature — SPROUT_AUTH_TAG not picked up"
fail "Owner attestation missing from signature — BUZZ_AUTH_TAG not picked up"
fi
# Push it
@@ -829,7 +829,7 @@ log "Hook integrity: testing symlink hook rejection..."
echo "<!-- symlink test -->" >> "$SYMLINK_DIR/index.html"
git -C "$SYMLINK_DIR" add -A
git -C "$SYMLINK_DIR" -c user.name="Bot1" -c user.email="bot1@sprout.test" \
git -C "$SYMLINK_DIR" -c user.name="Bot1" -c user.email="bot1@buzz.test" \
commit -m "Symlink hook test"
if git_push "$BOT1_PRIVKEY" "$SYMLINK_DIR" 2>&1; then
@@ -862,7 +862,7 @@ log "Hook integrity: testing missing hook rejection..."
echo "<!-- missing hook test -->" >> "$MISSING_DIR/index.html"
git -C "$MISSING_DIR" add -A
git -C "$MISSING_DIR" -c user.name="Bot1" -c user.email="bot1@sprout.test" \
git -C "$MISSING_DIR" -c user.name="Bot1" -c user.email="bot1@buzz.test" \
commit -m "Missing hook test"
if git_push "$BOT1_PRIVKEY" "$MISSING_DIR" 2>&1; then

View File

@@ -6,7 +6,7 @@
#
# Prerequisites:
# - Docker services running (postgres, redis, typesense)
# - Relay built: cargo build --release --bin sprout-relay
# - Relay built: cargo build --release --bin buzz-relay
# - nak available on PATH (for event signing)
#
# What it tests:
@@ -138,7 +138,7 @@ send_event() {
# ── Helper: REST call with X-Pubkey header (dev mode) ────────────────────────
#
# When SPROUT_REQUIRE_AUTH_TOKEN=false the relay accepts an X-Pubkey header
# When BUZZ_REQUIRE_AUTH_TOKEN=false the relay accepts an X-Pubkey header
# containing the caller's hex pubkey — no token minting required.
# This is the correct pattern for dev-mode E2E tests.
#
@@ -218,11 +218,11 @@ if [[ -f .env ]]; then
set +o allexport
fi
export SPROUT_BIND_ADDR="0.0.0.0:3000"
export BUZZ_BIND_ADDR="0.0.0.0:3000"
export RELAY_URL="ws://localhost:3000"
export RUST_LOG="sprout_relay=warn"
export SPROUT_REQUIRE_AUTH_TOKEN=false
export SPROUT_REQUIRE_RELAY_MEMBERSHIP=true
export RUST_LOG="buzz_relay=warn"
export BUZZ_REQUIRE_AUTH_TOKEN=false
export BUZZ_REQUIRE_RELAY_MEMBERSHIP=true
# Generate owner keypair BEFORE relay start — main.rs requires RELAY_OWNER_PUBKEY
log "Generating owner keypair..."
@@ -233,22 +233,22 @@ log "Owner pubkey: $OWNER_PUBKEY"
# Generate a stable relay signing key for NIP-43 self-signed events (kind:13534, etc.)
RELAY_SK=$(generate_keypair)
export SPROUT_RELAY_PRIVATE_KEY="$RELAY_SK"
export BUZZ_RELAY_PRIVATE_KEY="$RELAY_SK"
log "Relay signing key set (NIP-43 self-signed events enabled)"
# Kill any existing relay
pkill -f "sprout-relay" 2>/dev/null || true
pkill -f "buzz-relay" 2>/dev/null || true
sleep 1
./target/release/sprout-relay > /tmp/sprout-relay-membership-e2e.log 2>&1 &
./target/release/buzz-relay > /tmp/buzz-relay-membership-e2e.log 2>&1 &
RELAY_PID=$!
for i in $(seq 1 15); do
if curl -s http://localhost:3000/ -H "Accept: application/nostr+json" | grep -q "Sprout"; then
if curl -s http://localhost:3000/ -H "Accept: application/nostr+json" | grep -q "Buzz"; then
break
fi
if [[ $i -eq 15 ]]; then
fatal "Relay did not start. Check /tmp/sprout-relay-membership-e2e.log"
fatal "Relay did not start. Check /tmp/buzz-relay-membership-e2e.log"
fi
sleep 1
done

View File

@@ -1,11 +1,11 @@
#!/usr/bin/env bash
# Computes the full multi-instance desktop dev environment.
# Source this file from desktop dev commands; it exports:
# SPROUT_VITE_PORT, SPROUT_HMR_PORT, VITE_PORT, VITE_HMR_PORT
# SPROUT_RELAY_PORT, SPROUT_RELAY_URL
# SPROUT_INSTANCE_SLUG, SPROUT_WORKTREE_LABEL, VITE_DEV_BRANCH (worktrees only)
# SPROUT_TAURI_CONFIG
# SPROUT_PRIVATE_KEY (worktrees only, when SPROUT_SHARE_IDENTITY=1)
# BUZZ_VITE_PORT, BUZZ_HMR_PORT, VITE_PORT, VITE_HMR_PORT
# BUZZ_RELAY_PORT, BUZZ_RELAY_URL
# BUZZ_INSTANCE_SLUG, BUZZ_WORKTREE_LABEL, VITE_DEV_BRANCH (worktrees only)
# BUZZ_TAURI_CONFIG
# BUZZ_PRIVATE_KEY (worktrees only, when BUZZ_SHARE_IDENTITY=1)
WORKTREE_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
@@ -13,14 +13,14 @@ WORKTREE_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
# gets the same ports. This keeps the Tauri dev config stable between runs and
# preserves Cargo's build cache.
BASE_PORT=$(python3 -c "import hashlib,sys; h=int(hashlib.sha256(sys.argv[1].encode()).hexdigest(), 16); print(10000 + h % 55000)" "$WORKTREE_ROOT")
export SPROUT_VITE_PORT=$BASE_PORT
export SPROUT_HMR_PORT=$((BASE_PORT + 1))
export SPROUT_RELAY_PORT=3000
export VITE_PORT="$SPROUT_VITE_PORT"
export VITE_HMR_PORT="$SPROUT_HMR_PORT"
export SPROUT_RELAY_URL="${SPROUT_RELAY_URL:-ws://localhost:3000}"
export BUZZ_VITE_PORT=$BASE_PORT
export BUZZ_HMR_PORT=$((BASE_PORT + 1))
export BUZZ_RELAY_PORT=3000
export VITE_PORT="$BUZZ_VITE_PORT"
export VITE_HMR_PORT="$BUZZ_HMR_PORT"
export BUZZ_RELAY_URL="${BUZZ_RELAY_URL:-ws://localhost:3000}"
SPROUT_TAURI_CONFIG="{\"build\":{\"devUrl\":\"http://localhost:${SPROUT_VITE_PORT}\",\"beforeDevCommand\":\"exec ./node_modules/.bin/vite --port ${SPROUT_VITE_PORT} --strictPort\"},\"identifier\":\"xyz.block.sprout.app.dev\",\"productName\":\"Sprout Dev\"}"
BUZZ_TAURI_CONFIG="{\"build\":{\"devUrl\":\"http://localhost:${BUZZ_VITE_PORT}\",\"beforeDevCommand\":\"exec ./node_modules/.bin/vite --port ${BUZZ_VITE_PORT} --strictPort\"},\"identifier\":\"xyz.block.buzz.app.dev\",\"productName\":\"Buzz Dev\"}"
unset VITE_DEV_BRANCH
# In worktrees, extract a label from the branch name and derive a unique app
@@ -34,19 +34,19 @@ if git rev-parse --is-inside-work-tree &>/dev/null; then
GIT_COMMON_DIR=$(git rev-parse --git-common-dir 2>/dev/null)
if [[ -n "$GIT_COMMON_DIR" && "$GIT_DIR" != "$GIT_COMMON_DIR" ]]; then
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
export SPROUT_WORKTREE_LABEL="${BRANCH_NAME##*/}"
export SPROUT_INSTANCE_SLUG=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//')
export BUZZ_WORKTREE_LABEL="${BRANCH_NAME##*/}"
export BUZZ_INSTANCE_SLUG=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//')
# SPROUT_SHARE_IDENTITY=1: reuse the main dev checkout's Nostr key so
# BUZZ_SHARE_IDENTITY=1: reuse the main dev checkout's Nostr key so
# worktrees skip onboarding and share the same identity. The per-worktree
# identifier is kept so concurrent instances don't collide on
# tauri-plugin-single-instance or the app data directory.
if [[ "${SPROUT_SHARE_IDENTITY:-0}" == "1" ]]; then
CANONICAL_KEY="$HOME/Library/Application Support/xyz.block.sprout.app.dev/identity.key"
if [[ "${BUZZ_SHARE_IDENTITY:-0}" == "1" ]]; then
CANONICAL_KEY="$HOME/Library/Application Support/xyz.block.buzz.app.dev/identity.key"
if [[ -f "$CANONICAL_KEY" ]]; then
export SPROUT_PRIVATE_KEY="$(cat "$CANONICAL_KEY")"
export BUZZ_PRIVATE_KEY="$(cat "$CANONICAL_KEY")"
else
echo "⚠ SPROUT_SHARE_IDENTITY=1 but no identity found at $CANONICAL_KEY — run Sprout from repo root first" >&2
echo "⚠ BUZZ_SHARE_IDENTITY=1 but no identity found at $CANONICAL_KEY — run Buzz from repo root first" >&2
fi
fi
@@ -54,12 +54,12 @@ if git rev-parse --is-inside-work-tree &>/dev/null; then
mkdir -p "$ICON_DIR"
DEV_ICON="$ICON_DIR/icon.icns"
if swift ../scripts/generate-dev-icon.swift src-tauri/icons/icon.icns "$DEV_ICON" "$SPROUT_WORKTREE_LABEL"; then
echo "🌳 Worktree: ${SPROUT_WORKTREE_LABEL}"
export VITE_DEV_BRANCH="$SPROUT_WORKTREE_LABEL"
SPROUT_TAURI_CONFIG="{\"build\":{\"devUrl\":\"http://localhost:${SPROUT_VITE_PORT}\",\"beforeDevCommand\":\"exec ./node_modules/.bin/vite --port ${SPROUT_VITE_PORT} --strictPort\"},\"identifier\":\"xyz.block.sprout.app.dev.${SPROUT_INSTANCE_SLUG}\",\"productName\":\"Sprout Dev (${SPROUT_WORKTREE_LABEL})\",\"bundle\":{\"icon\":[\"$DEV_ICON\"]}}"
if swift ../scripts/generate-dev-icon.swift src-tauri/icons/icon.icns "$DEV_ICON" "$BUZZ_WORKTREE_LABEL"; then
echo "🌳 Worktree: ${BUZZ_WORKTREE_LABEL}"
export VITE_DEV_BRANCH="$BUZZ_WORKTREE_LABEL"
BUZZ_TAURI_CONFIG="{\"build\":{\"devUrl\":\"http://localhost:${BUZZ_VITE_PORT}\",\"beforeDevCommand\":\"exec ./node_modules/.bin/vite --port ${BUZZ_VITE_PORT} --strictPort\"},\"identifier\":\"xyz.block.buzz.app.dev.${BUZZ_INSTANCE_SLUG}\",\"productName\":\"Buzz Dev (${BUZZ_WORKTREE_LABEL})\",\"bundle\":{\"icon\":[\"$DEV_ICON\"]}}"
fi
fi
fi
export SPROUT_TAURI_CONFIG
export BUZZ_TAURI_CONFIG

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# =============================================================================
# run-tests.sh — Run Sprout test suite
# run-tests.sh — Run Buzz test suite
# =============================================================================
# Usage:
# ./scripts/run-tests.sh # run all tests (default)
@@ -40,14 +40,14 @@ if [[ -f ".env" ]]; then
set +o allexport
else
# Use defaults matching docker-compose.yml
export DATABASE_URL="postgres://sprout:sprout_dev@localhost:5432/sprout"
export DATABASE_URL="postgres://buzz:buzz_dev@localhost:5432/buzz"
export PGHOST=localhost
export PGPORT=5432
export PGUSER=sprout
export PGPASSWORD=sprout_dev
export PGDATABASE=sprout
export PGUSER=buzz
export PGPASSWORD=buzz_dev
export PGDATABASE=buzz
export REDIS_URL="redis://localhost:6379"
export TYPESENSE_API_KEY="sprout_dev_key"
export TYPESENSE_API_KEY="buzz_dev_key"
export TYPESENSE_URL="http://localhost:8108"
fi
@@ -80,11 +80,11 @@ ensure_infra() {
run_unit_tests() {
section "Unit Tests (no infra required)"
run_test_step "sprout-core tests" \
cargo test -p sprout-core --lib -- --nocapture
run_test_step "buzz-core tests" \
cargo test -p buzz-core --lib -- --nocapture
run_test_step "sprout-auth unit tests" \
cargo test -p sprout-auth --lib -- --nocapture
run_test_step "buzz-auth unit tests" \
cargo test -p buzz-auth --lib -- --nocapture
}
# ---- DB / integration tests (infra required) --------------------------------
@@ -94,12 +94,12 @@ run_integration_tests() {
ensure_infra
run_test_step "sprout-db tests" \
cargo test -p sprout-db -- --nocapture
run_test_step "buzz-db tests" \
cargo test -p buzz-db -- --nocapture
run_test_step "sprout-auth integration tests" \
cargo test -p sprout-auth --test '*' -- --nocapture 2>/dev/null || \
run_test_step "sprout-auth (no integration tests found)" true
run_test_step "buzz-auth integration tests" \
cargo test -p buzz-auth --test '*' -- --nocapture 2>/dev/null || \
run_test_step "buzz-auth (no integration tests found)" true
run_test_step "workspace integration tests" \
cargo test --test '*' -- --nocapture 2>/dev/null || \

View File

@@ -2,11 +2,11 @@
set -euo pipefail
DB_HOST="${SPROUT_DB_HOST:-127.0.0.1}"
DB_PORT="${SPROUT_DB_PORT:-5432}"
DB_USER="${SPROUT_DB_USER:-sprout}"
DB_PASS="${SPROUT_DB_PASS:-sprout_dev}"
DB_NAME="${SPROUT_DB_NAME:-sprout}"
DB_HOST="${BUZZ_DB_HOST:-127.0.0.1}"
DB_PORT="${BUZZ_DB_PORT:-5432}"
DB_USER="${BUZZ_DB_USER:-buzz}"
DB_PASS="${BUZZ_DB_PASS:-buzz_dev}"
DB_NAME="${BUZZ_DB_NAME:-buzz}"
SYSTEM_PUBKEY="0000000000000000000000000000000000000000000000000000000000000000"
ALICE_PUBKEY="953d3363262e86b770419834c53d2446409db6d918a57f8f339d495d54ab001f"
@@ -17,9 +17,9 @@ AGENT_PUBKEY="db0b028cd36f4d3e36c8300cce87252c1f7fc9495ffecc53f393fcac341ffd36"
if command -v psql >/dev/null 2>&1; then
run_psql() { PGPASSWORD="$DB_PASS" psql -h"$DB_HOST" -p"$DB_PORT" -U"$DB_USER" -d"$DB_NAME" -qtA "$@"; }
elif docker exec sprout-postgres psql --version >/dev/null 2>&1; then
elif docker exec buzz-postgres psql --version >/dev/null 2>&1; then
run_psql() {
docker exec -e PGPASSWORD="$DB_PASS" sprout-postgres \
docker exec -e PGPASSWORD="$DB_PASS" buzz-postgres \
psql -U"$DB_USER" -d"$DB_NAME" -qtA "$@"
}
else
@@ -43,15 +43,15 @@ PYEOF
echo "Checking database connection..."
run_sql "SELECT 1" >/dev/null
UUID_GENERAL=$(uuid5_hex "sprout.channel.general")
UUID_RANDOM=$(uuid5_hex "sprout.channel.random")
UUID_ENGINEERING=$(uuid5_hex "sprout.channel.engineering")
UUID_AGENTS=$(uuid5_hex "sprout.channel.agents")
UUID_WATERCOOLER=$(uuid5_hex "sprout.channel.watercooler")
UUID_ANNOUNCEMENTS=$(uuid5_hex "sprout.channel.announcements")
UUID_DM_ALICE_TYLER=$(uuid5_hex "sprout.channel.dm.alice-tyler")
UUID_DM_BOB_TYLER=$(uuid5_hex "sprout.channel.dm.bob-tyler")
UUID_DM_BOB_CHARLIE_TYLER=$(uuid5_hex "sprout.channel.dm.bob-charlie-tyler")
UUID_GENERAL=$(uuid5_hex "buzz.channel.general")
UUID_RANDOM=$(uuid5_hex "buzz.channel.random")
UUID_ENGINEERING=$(uuid5_hex "buzz.channel.engineering")
UUID_AGENTS=$(uuid5_hex "buzz.channel.agents")
UUID_WATERCOOLER=$(uuid5_hex "buzz.channel.watercooler")
UUID_ANNOUNCEMENTS=$(uuid5_hex "buzz.channel.announcements")
UUID_DM_ALICE_TYLER=$(uuid5_hex "buzz.channel.dm.alice-tyler")
UUID_DM_BOB_TYLER=$(uuid5_hex "buzz.channel.dm.bob-tyler")
UUID_DM_BOB_CHARLIE_TYLER=$(uuid5_hex "buzz.channel.dm.bob-charlie-tyler")
run_sql "
INSERT INTO channels

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Live e2e test for sprout-proxy — requires relay on :3000 and proxy on :4869
# Live e2e test for buzz-proxy — requires relay on :3000 and proxy on :4869
set -euo pipefail
PROXY_URL="ws://0.0.0.0:4869"
@@ -12,13 +12,13 @@ FAIL=0
ok() { PASS=$((PASS+1)); echo " ✅ $1"; }
fail() { FAIL=$((FAIL+1)); echo " ❌ $1"; }
echo "═══ sprout-proxy e2e tests ═══"
echo "═══ buzz-proxy e2e tests ═══"
echo ""
# ── Test 1: NIP-11 ──────────────────────────────────────────────────────
echo "1. NIP-11 relay info"
NIP11=$(curl -sf "$PROXY_HTTP" -H "Accept: application/nostr+json")
if echo "$NIP11" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['name']=='sprout-proxy'" 2>/dev/null; then
if echo "$NIP11" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['name']=='buzz-proxy'" 2>/dev/null; then
ok "NIP-11 returns valid relay info"
else
fail "NIP-11 check failed"

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env bash
# End-to-end test for sprout-proxy
# End-to-end test for buzz-proxy
# Prerequisites:
# - Sprout relay running on :3000 (just relay)
# - Sprout proxy running on :4869 (just proxy)
# - Buzz relay running on :3000 (just relay)
# - Buzz proxy running on :4869 (just proxy)
# - websocat installed (cargo install websocat)
# - curl installed
# - jq installed
@@ -12,7 +12,7 @@ PROXY_URL="${PROXY_URL:-ws://localhost:4869}"
PROXY_HTTP="${PROXY_HTTP:-http://localhost:4869}"
RELAY_HTTP="${RELAY_HTTP:-http://localhost:3000}"
echo "=== Sprout Proxy E2E Test ==="
echo "=== Buzz Proxy E2E Test ==="
echo "Proxy: $PROXY_URL"
echo "Relay: $RELAY_HTTP"

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
sprout-proxy E2E test using nostr-sdk v0.44 (Python bindings for rust-nostr)
buzz-proxy E2E test using nostr-sdk v0.44 (Python bindings for rust-nostr)
nostr-sdk is the official Rust Nostr SDK with Python/Swift/Flutter bindings.
Second most popular Nostr SDK after nostr-tools, powers native clients.
@@ -37,7 +37,7 @@ def fail(name, detail=""):
async def main():
print("=" * 64)
print(" nostr-sdk v0.44 (Python/Rust) E2E TEST against sprout-proxy")
print(" nostr-sdk v0.44 (Python/Rust) E2E TEST against buzz-proxy")
print("=" * 64)
keys = nostr_sdk.Keys.parse(PRIVKEY_HEX)
@@ -143,7 +143,7 @@ async def main():
all_pass = False
print("=" * 64)
if all_pass:
print(" 🎉 ALL TESTS PASSED — nostr-sdk Python works with sprout-proxy!")
print(" 🎉 ALL TESTS PASSED — nostr-sdk Python works with buzz-proxy!")
else:
print(" ⚠️ Some tests failed")
print("=" * 64)

View File

@@ -1,10 +1,10 @@
/**
* sprout-proxy E2E test using nostr-tools v2.23.3
* buzz-proxy E2E test using nostr-tools v2.23.3
*
* nostr-tools is the most widely-used Nostr library in the ecosystem,
* powering Coracle, Snort, Damus Web, and hundreds of other clients.
*
* Tests the full NIP-28 channel flow through sprout-proxy:
* Tests the full NIP-28 channel flow through buzz-proxy:
* 1. NIP-42 authentication (automatic via onauth callback)
* 2. Channel discovery (kind:40)
* 3. Channel metadata (kind:41)
@@ -26,7 +26,7 @@ const GUEST_PRIVKEY_HEX = process.env.GUEST_PRIVKEY
const CHANNEL_EVENT_ID = process.env.CHANNEL_EVENT_ID
if (!GUEST_PRIVKEY_HEX || !CHANNEL_EVENT_ID) {
console.error('Usage: GUEST_PRIVKEY=<hex> CHANNEL_EVENT_ID=<hex> node test-sprout-proxy.mjs')
console.error('Usage: GUEST_PRIVKEY=<hex> CHANNEL_EVENT_ID=<hex> node test-buzz-proxy.mjs')
process.exit(1)
}
@@ -69,7 +69,7 @@ function list(relay, filters, timeoutMs = 8000) {
async function main() {
console.log('═'.repeat(64))
console.log(' nostr-tools v2.23 E2E TEST against sprout-proxy')
console.log(' nostr-tools v2.23 E2E TEST against buzz-proxy')
console.log('═'.repeat(64))
console.log(` Relay: ${RELAY_URL}`)
console.log(` Pubkey: ${pubkey.slice(0, 24)}...`)
@@ -251,7 +251,7 @@ async function main() {
}
console.log('═'.repeat(64))
console.log(allPass
? ' 🎉 ALL TESTS PASSED — nostr-tools works with sprout-proxy!'
? ' 🎉 ALL TESTS PASSED — nostr-tools works with buzz-proxy!'
: ' ⚠️ Some tests failed')
console.log('═'.repeat(64))
process.exit(allPass ? 0 : 1)

View File

@@ -3,7 +3,7 @@
#
# Prerequisites:
# - Relay running at $RELAY_URL (default: http://localhost:3000)
# - Dev mode (SPROUT_REQUIRE_AUTH_TOKEN=false) or valid API token
# - Dev mode (BUZZ_REQUIRE_AUTH_TOKEN=false) or valid API token
# - ffmpeg, nak, curl, jq, shasum on PATH
#
# Usage: