diff --git a/.env.example b/.env.example
index 3d1c9a96d..e18070f01 100644
--- a/.env.example
+++ b/.env.example
@@ -1,5 +1,5 @@
# =============================================================================
-# Sprout Backend — Local Development Environment
+# Buzz Backend — Local Development Environment
# =============================================================================
# Copy this file to .env and adjust as needed:
# cp .env.example .env
@@ -18,12 +18,12 @@
# -----------------------------------------------------------------------------
# Database (Postgres 17)
# -----------------------------------------------------------------------------
-DATABASE_URL=postgres://sprout:sprout_dev@localhost:5432/sprout
+DATABASE_URL=postgres://buzz:buzz_dev@localhost:5432/buzz
PGHOST=localhost
PGPORT=5432
-PGUSER=sprout
-PGPASSWORD=sprout_dev
-PGDATABASE=sprout
+PGUSER=buzz
+PGPASSWORD=buzz_dev
+PGDATABASE=buzz
# -----------------------------------------------------------------------------
# Redis 7
@@ -33,23 +33,23 @@ REDIS_URL=redis://localhost:6379
# -----------------------------------------------------------------------------
# Typesense (search)
# -----------------------------------------------------------------------------
-TYPESENSE_API_KEY=sprout_dev_key
+TYPESENSE_API_KEY=buzz_dev_key
TYPESENSE_URL=http://localhost:8108
# -----------------------------------------------------------------------------
# Relay (WebSocket server)
# -----------------------------------------------------------------------------
# Bind address for the relay (host:port)
-SPROUT_BIND_ADDR=0.0.0.0:3000
+BUZZ_BIND_ADDR=0.0.0.0:3000
# Public WebSocket URL — used in NIP-42 auth challenges
RELAY_URL=ws://localhost:3000
# Stable relay signing key. Set this in dev if you want REST-created forum posts
# to keep resolving to the original author across relay restarts.
-# SPROUT_RELAY_PRIVATE_KEY=<32-byte hex private key>
+# BUZZ_RELAY_PRIVATE_KEY=<32-byte hex private key>
# Optional: path to the web UI dist directory. When set, the relay serves
# the web frontend at / for browser requests. Leave unset for local dev
# (use `just web` for Vite HMR instead).
-# SPROUT_WEB_DIR=./web/dist
+# BUZZ_WEB_DIR=./web/dist
# -----------------------------------------------------------------------------
# Git (NIP-34 bare repositories)
@@ -57,7 +57,7 @@ RELAY_URL=ws://localhost:3000
# Root directory for bare git repos. Repos are stored at
# {path}/{owner_hex}/{repo_id}.git/. Default: ./repos (relative to CWD).
# Set an absolute path to keep repos stable across worktrees.
-# SPROUT_GIT_REPO_PATH=./repos
+# BUZZ_GIT_REPO_PATH=./repos
# -----------------------------------------------------------------------------
# Ephemeral Channels (TTL testing)
@@ -65,125 +65,125 @@ RELAY_URL=ws://localhost:3000
# Override the TTL for all ephemeral channels (in seconds). When set, any
# channel created with a TTL tag will use this value instead of the
# client-provided one. Unset to use the client-provided TTL.
-# SPROUT_EPHEMERAL_TTL_OVERRIDE=60
+# BUZZ_EPHEMERAL_TTL_OVERRIDE=60
# How often the reaper checks for expired ephemeral channels (default: 60s).
-# SPROUT_REAPER_INTERVAL_SECS=5
+# BUZZ_REAPER_INTERVAL_SECS=5
# -----------------------------------------------------------------------------
# Logging / Tracing
# -----------------------------------------------------------------------------
-RUST_LOG=sprout_relay=debug,sprout_db=debug,sprout_auth=debug,sprout_pubsub=debug,tower_http=debug
+RUST_LOG=buzz_relay=debug,buzz_db=debug,buzz_auth=debug,buzz_pubsub=debug,tower_http=debug
# OTLP tracing endpoint (optional — leave unset to disable)
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
# -----------------------------------------------------------------------------
-# ACP (Agent Communication Protocol — sprout-acp harness)
+# ACP (Agent Communication Protocol — buzz-acp harness)
# -----------------------------------------------------------------------------
-# The ACP harness bridges Sprout events to AI agents. Each env var below maps
+# The ACP harness bridges Buzz events to AI agents. Each env var below maps
# to a CLI flag of the same name (lowercase, hyphens → underscores). All values
# are optional unless noted; defaults are shown in comments.
#
# Quick start:
-# SPROUT_PRIVATE_KEY= SPROUT_RELAY_URL=ws://localhost:3000 sprout-acp
+# BUZZ_PRIVATE_KEY= BUZZ_RELAY_URL=ws://localhost:3000 buzz-acp
# ── Identity & auth ──────────────────────────────────────────────────────────
# Nostr private key (hex or bech32). REQUIRED — identifies the agent on the relay.
-# SPROUT_PRIVATE_KEY=<32-byte hex or nsec1… private key>
+# BUZZ_PRIVATE_KEY=<32-byte hex or nsec1… private key>
# Relay WebSocket URL the harness connects to.
# Note: the relay itself uses RELAY_URL (above); this is the ACP harness's
# connection target — they happen to point at the same place in local dev.
-# SPROUT_RELAY_URL=ws://localhost:3000
+# BUZZ_RELAY_URL=ws://localhost:3000
# ── Agent subprocess ─────────────────────────────────────────────────────────
# Binary to spawn as the AI agent (e.g. "goose", "codex-acp", "claude-code").
-# SPROUT_ACP_AGENT_COMMAND=goose
+# BUZZ_ACP_AGENT_COMMAND=goose
# Comma-separated arguments passed to the agent binary.
# Goose default: "acp". Codex/Claude default: "" (empty).
-# SPROUT_ACP_AGENT_ARGS=acp
+# BUZZ_ACP_AGENT_ARGS=acp
-# Binary for an optional MCP server sidecar (e.g. sprout-dev-mcp for sprout-agent).
-# SPROUT_ACP_MCP_COMMAND=
+# Binary for an optional MCP server sidecar (e.g. buzz-dev-mcp for buzz-agent).
+# BUZZ_ACP_MCP_COMMAND=
# Number of parallel agent subprocesses (1–32).
-# SPROUT_ACP_AGENTS=1
+# BUZZ_ACP_AGENTS=1
# Desired LLM model ID. Applied to every new ACP session.
-# Use `sprout-acp models` to discover available model IDs.
-# SPROUT_ACP_MODEL=
+# Use `buzz-acp models` to discover available model IDs.
+# BUZZ_ACP_MODEL=
# ── Timeouts & sessions ──────────────────────────────────────────────────────
# Max seconds per agent turn before timeout (default 320 = ~5 min).
-# SPROUT_ACP_TURN_TIMEOUT=320
+# BUZZ_ACP_TURN_TIMEOUT=320
# Max turns per session before proactive rotation. 0 = disabled (rotate only
# on MaxTokens / MaxTurnRequests). Recommended: 50 for long-running agents.
-# SPROUT_ACP_MAX_TURNS_PER_SESSION=0
+# BUZZ_ACP_MAX_TURNS_PER_SESSION=0
# ── Prompts ──────────────────────────────────────────────────────────────────
# System prompt injected into every agent session (inline text).
-# SPROUT_ACP_SYSTEM_PROMPT=
+# BUZZ_ACP_SYSTEM_PROMPT=
# Path to a file containing the system prompt (mutually exclusive with above).
-# SPROUT_ACP_SYSTEM_PROMPT_FILE=
+# BUZZ_ACP_SYSTEM_PROMPT_FILE=
# Message sent to the agent immediately after session creation.
-# SPROUT_ACP_INITIAL_MESSAGE=
+# BUZZ_ACP_INITIAL_MESSAGE=
# ── Heartbeat ────────────────────────────────────────────────────────────────
# Seconds between heartbeat prompts. 0 = disabled. Must be 0 or ≥10.
# Recommended: 60 for long-running agents to prevent idle session timeouts.
-# SPROUT_ACP_HEARTBEAT_INTERVAL=0
+# BUZZ_ACP_HEARTBEAT_INTERVAL=0
# Heartbeat prompt text (inline). Mutually exclusive with file variant.
-# SPROUT_ACP_HEARTBEAT_PROMPT=
+# BUZZ_ACP_HEARTBEAT_PROMPT=
# Path to a file containing the heartbeat prompt.
-# SPROUT_ACP_HEARTBEAT_PROMPT_FILE=
+# BUZZ_ACP_HEARTBEAT_PROMPT_FILE=
# ── Subscription & filtering ─────────────────────────────────────────────────
# Subscribe mode: "mentions" (default), "all", or "config" (rule-based).
-# SPROUT_ACP_SUBSCRIBE=mentions
+# BUZZ_ACP_SUBSCRIBE=mentions
# Comma-separated event kind numbers to subscribe to (overrides mode defaults).
-# SPROUT_ACP_KINDS=
+# BUZZ_ACP_KINDS=
# Comma-separated channel UUIDs to limit subscription scope.
-# SPROUT_ACP_CHANNELS=
+# BUZZ_ACP_CHANNELS=
# Set to true to disable the @-mention filter in mentions mode.
-# SPROUT_ACP_NO_MENTION_FILTER=false
+# BUZZ_ACP_NO_MENTION_FILTER=false
# Path to TOML config file for rule-based subscriptions (config mode).
-# SPROUT_ACP_CONFIG=./sprout-acp.toml
+# BUZZ_ACP_CONFIG=./buzz-acp.toml
# ── Dedup & self-ignore ──────────────────────────────────────────────────────
# How to handle duplicate events: "queue" (default) or "drop".
-# SPROUT_ACP_DEDUP=queue
+# BUZZ_ACP_DEDUP=queue
# Set to true to process the agent's own messages (default: ignore self).
-# SPROUT_ACP_NO_IGNORE_SELF=false
+# BUZZ_ACP_NO_IGNORE_SELF=false
# ── Context ──────────────────────────────────────────────────────────────────
# Max context messages fetched for thread replies and DMs (0–100). 0 = disabled.
-# SPROUT_ACP_CONTEXT_MESSAGE_LIMIT=12
+# BUZZ_ACP_CONTEXT_MESSAGE_LIMIT=12
# ── Presence & typing ────────────────────────────────────────────────────────
# Set to true to disable automatic online/offline presence status.
-# SPROUT_ACP_NO_PRESENCE=false
+# BUZZ_ACP_NO_PRESENCE=false
# Set to true to disable typing indicators while the agent is processing.
-# SPROUT_ACP_NO_TYPING=false
+# BUZZ_ACP_NO_TYPING=false
# ── Advanced tuning ──────────────────────────────────────────────────────────
# Event channel buffer capacity (WebSocket → harness). Increase for
# high-throughput agents. Minimum 1.
-# SPROUT_ACP_EVENT_BUFFER=256
+# BUZZ_ACP_EVENT_BUFFER=256
# ── Legacy aliases ───────────────────────────────────────────────────────────
# These are accepted for backward compatibility but the canonical names above
# are preferred:
-# SPROUT_ACP_PRIVATE_KEY → SPROUT_PRIVATE_KEY
+# BUZZ_ACP_PRIVATE_KEY → BUZZ_PRIVATE_KEY
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 17a418868..b2956dbf1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -169,28 +169,28 @@ jobs:
EXTRACT_DIR="${RUNNER_TEMP}/signed-app-extract"
rm -rf "$EXTRACT_DIR" && mkdir -p "$EXTRACT_DIR"
ditto -x -k "$SIGNED_APP_ZIP" "$EXTRACT_DIR"
- rm -rf "${APP_DIR}/Sprout.app"
- cp -R "${EXTRACT_DIR}/Sprout.app" "${APP_DIR}/Sprout.app"
+ rm -rf "${APP_DIR}/Buzz.app"
+ cp -R "${EXTRACT_DIR}/Buzz.app" "${APP_DIR}/Buzz.app"
# Rebuild the updater archive from the signed .app and re-sign it with the Tauri updater key.
- rm -f "${APP_DIR}/Sprout.app.tar.gz" "${APP_DIR}/Sprout.app.tar.gz.sig"
- (cd "$APP_DIR" && tar -czf Sprout.app.tar.gz Sprout.app)
- TARBALL_ABS="$(pwd)/${APP_DIR}/Sprout.app.tar.gz"
+ rm -f "${APP_DIR}/Buzz.app.tar.gz" "${APP_DIR}/Buzz.app.tar.gz.sig"
+ (cd "$APP_DIR" && tar -czf Buzz.app.tar.gz Buzz.app)
+ TARBALL_ABS="$(pwd)/${APP_DIR}/Buzz.app.tar.gz"
(cd desktop && pnpm tauri signer sign "$TARBALL_ABS")
- name: Verify code signature
run: |
codesign --verify --deep --strict --verbose=2 \
- desktop/src-tauri/target/release/bundle/macos/Sprout.app
+ desktop/src-tauri/target/release/bundle/macos/Buzz.app
spctl --assess --type execute --verbose=4 \
- desktop/src-tauri/target/release/bundle/macos/Sprout.app
+ desktop/src-tauri/target/release/bundle/macos/Buzz.app
- name: Locate build artifacts
id: artifacts
run: |
BUNDLE_DIR="desktop/src-tauri/target/release/bundle"
- # Find the DMG (Tauri names it Sprout__.dmg)
+ # Find the DMG (Tauri names it Buzz__.dmg)
DMG=$(find "$BUNDLE_DIR/dmg" -name '*.dmg' -type f | head -1)
if [[ -z "$DMG" ]]; then
echo "::error::No DMG found in $BUNDLE_DIR/dmg"
@@ -234,11 +234,11 @@ jobs:
NOTES=$(awk "/^## v${VERSION}$/,/^## v/" CHANGELOG.md | sed '$d')
fi
if [[ -z "$NOTES" ]]; then
- NOTES="Sprout Desktop v${VERSION}"
+ NOTES="Buzz Desktop v${VERSION}"
fi
gh release create "v${VERSION}" \
--target "$RELEASE_SHA" \
- --title "Sprout Desktop v${VERSION}" \
+ --title "Buzz Desktop v${VERSION}" \
--notes "$NOTES" \
"$DMG_PATH"
@@ -246,7 +246,7 @@ jobs:
run: |
gh release create buzz-desktop-latest \
--prerelease \
- --title "Sprout Desktop Auto-Update" \
+ --title "Buzz Desktop Auto-Update" \
--notes "Rolling release for the Tauri auto-updater. Do not download manually — use the versioned release instead." \
2>/dev/null || true
gh release upload buzz-desktop-latest \
@@ -349,12 +349,12 @@ jobs:
EXTRACT_DIR="${RUNNER_TEMP}/signed-app-extract-x64"
rm -rf "$EXTRACT_DIR" && mkdir -p "$EXTRACT_DIR"
ditto -x -k "$SIGNED_APP_ZIP" "$EXTRACT_DIR"
- rm -rf "${APP_DIR}/Sprout.app"
- cp -R "${EXTRACT_DIR}/Sprout.app" "${APP_DIR}/Sprout.app"
+ rm -rf "${APP_DIR}/Buzz.app"
+ cp -R "${EXTRACT_DIR}/Buzz.app" "${APP_DIR}/Buzz.app"
- name: Verify code signature
run: |
- APP_DIR="desktop/src-tauri/target/${TARGET}/release/bundle/macos/Sprout.app"
+ APP_DIR="desktop/src-tauri/target/${TARGET}/release/bundle/macos/Buzz.app"
codesign --verify --deep --strict --verbose=2 "$APP_DIR"
spctl --assess --type execute --verbose=4 "$APP_DIR"
diff --git a/RELEASING.md b/RELEASING.md
index 0d9db50e3..4697e9838 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -1,4 +1,4 @@
-# Releasing Sprout Desktop
+# Releasing Buzz Desktop
## Quick Start
diff --git a/desktop/README.md b/desktop/README.md
index dd5700a29..d53698a9d 100644
--- a/desktop/README.md
+++ b/desktop/README.md
@@ -1,4 +1,4 @@
-# Sprout
+# Buzz
Desktop chat shell with:
diff --git a/desktop/index.html b/desktop/index.html
index 603ec5976..a2073d47f 100644
--- a/desktop/index.html
+++ b/desktop/index.html
@@ -2,7 +2,7 @@
-
+
diff --git a/desktop/package.json b/desktop/package.json
index e5bf264e8..365e8f8d1 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -1,5 +1,5 @@
{
- "name": "sprout",
+ "name": "buzz",
"private": true,
"version": "0.3.16",
"type": "module",
diff --git a/desktop/public/buzz.svg b/desktop/public/buzz.svg
new file mode 100644
index 000000000..8eaee9320
--- /dev/null
+++ b/desktop/public/buzz.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/desktop/public/sprout.svg b/desktop/public/sprout.svg
deleted file mode 100644
index 079a16ddf..000000000
--- a/desktop/public/sprout.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/desktop/scripts/build-release-config.mjs b/desktop/scripts/build-release-config.mjs
index 9c642d0f5..389d18aec 100644
--- a/desktop/scripts/build-release-config.mjs
+++ b/desktop/scripts/build-release-config.mjs
@@ -12,7 +12,7 @@ import { resolve } from "node:path";
// 2. bundle.createUpdaterArtifacts = true so Tauri produces the .tar.gz
// archive and .sig signature during the build.
// 3. plugins.updater with the public key and endpoint from env vars.
-// Both SPROUT_UPDATER_PUBLIC_KEY and SPROUT_UPDATER_ENDPOINT are required -
+// Both BUZZ_UPDATER_PUBLIC_KEY and BUZZ_UPDATER_ENDPOINT are required -
// the script fails if either is missing (OSS builds always ship with updater).
//
// Apple code signing and notarization happen post-build via
@@ -24,12 +24,12 @@ const outputConfigPath = resolve(
"src-tauri/tauri.release.conf.json",
);
-const updaterPubkey = process.env.SPROUT_UPDATER_PUBLIC_KEY;
-const updaterEndpoint = process.env.SPROUT_UPDATER_ENDPOINT;
+const updaterPubkey = process.env.BUZZ_UPDATER_PUBLIC_KEY;
+const updaterEndpoint = process.env.BUZZ_UPDATER_ENDPOINT;
const missing = [];
-if (!updaterPubkey) missing.push("SPROUT_UPDATER_PUBLIC_KEY");
-if (!updaterEndpoint) missing.push("SPROUT_UPDATER_ENDPOINT");
+if (!updaterPubkey) missing.push("BUZZ_UPDATER_PUBLIC_KEY");
+if (!updaterEndpoint) missing.push("BUZZ_UPDATER_ENDPOINT");
if (missing.length > 0) {
console.error(
`Error: required environment variable(s) missing: ${missing.join(", ")}`,
diff --git a/desktop/scripts/generate-oss-latest-json.sh b/desktop/scripts/generate-oss-latest-json.sh
index cedde5dcf..da0f615e7 100755
--- a/desktop/scripts/generate-oss-latest-json.sh
+++ b/desktop/scripts/generate-oss-latest-json.sh
@@ -14,7 +14,7 @@ ARCHIVE_URL="$3"
# only. Supporting Intel Macs (darwin-x86_64) would require a matrix build.
jq -n \
--arg version "$VERSION" \
- --arg notes "Sprout v$VERSION" \
+ --arg notes "Buzz v$VERSION" \
--arg pub_date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg signature "$(cat "$SIG_FILE")" \
--arg url "$ARCHIVE_URL" \
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index cf7753b23..03cba426b 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -844,6 +844,68 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "buzz-desktop"
+version = "0.3.16"
+dependencies = [
+ "anyhow",
+ "atomic-write-file",
+ "audioadapter-buffers",
+ "axum",
+ "base64 0.22.1",
+ "buzz-core",
+ "buzz-persona",
+ "buzz-sdk",
+ "bzip2 0.6.1",
+ "chrono",
+ "ctrlc",
+ "dirs",
+ "earshot",
+ "futures-util",
+ "hex",
+ "infer",
+ "libc",
+ "mesh-llm-host-runtime",
+ "mesh-llm-sdk",
+ "neteq",
+ "nostr",
+ "objc2-app-kit",
+ "opus",
+ "png 0.18.1",
+ "regex",
+ "reqwest 0.13.4",
+ "rodio",
+ "rubato",
+ "serde",
+ "serde_json",
+ "serde_yaml",
+ "sha2 0.11.0",
+ "sherpa-onnx",
+ "strip-ansi-escapes",
+ "tar",
+ "tauri",
+ "tauri-build",
+ "tauri-plugin-deep-link",
+ "tauri-plugin-dialog",
+ "tauri-plugin-global-shortcut",
+ "tauri-plugin-notification",
+ "tauri-plugin-opener",
+ "tauri-plugin-process",
+ "tauri-plugin-single-instance",
+ "tauri-plugin-updater",
+ "tauri-plugin-websocket",
+ "tauri-plugin-window-state",
+ "tempfile",
+ "tokio",
+ "tokio-tungstenite 0.29.0",
+ "tokio-util",
+ "url",
+ "uuid",
+ "windows-sys 0.61.2",
+ "zeroize",
+ "zip 8.6.0",
+]
+
[[package]]
name = "buzz-persona"
version = "0.1.0"
@@ -8220,68 +8282,6 @@ dependencies = [
"der",
]
-[[package]]
-name = "sprout-desktop"
-version = "0.3.16"
-dependencies = [
- "anyhow",
- "atomic-write-file",
- "audioadapter-buffers",
- "axum",
- "base64 0.22.1",
- "buzz-core",
- "buzz-persona",
- "buzz-sdk",
- "bzip2 0.6.1",
- "chrono",
- "ctrlc",
- "dirs",
- "earshot",
- "futures-util",
- "hex",
- "infer",
- "libc",
- "mesh-llm-host-runtime",
- "mesh-llm-sdk",
- "neteq",
- "nostr",
- "objc2-app-kit",
- "opus",
- "png 0.18.1",
- "regex",
- "reqwest 0.13.4",
- "rodio",
- "rubato",
- "serde",
- "serde_json",
- "serde_yaml",
- "sha2 0.11.0",
- "sherpa-onnx",
- "strip-ansi-escapes",
- "tar",
- "tauri",
- "tauri-build",
- "tauri-plugin-deep-link",
- "tauri-plugin-dialog",
- "tauri-plugin-global-shortcut",
- "tauri-plugin-notification",
- "tauri-plugin-opener",
- "tauri-plugin-process",
- "tauri-plugin-single-instance",
- "tauri-plugin-updater",
- "tauri-plugin-websocket",
- "tauri-plugin-window-state",
- "tempfile",
- "tokio",
- "tokio-tungstenite 0.29.0",
- "tokio-util",
- "url",
- "uuid",
- "windows-sys 0.61.2",
- "zeroize",
- "zip 8.6.0",
-]
-
[[package]]
name = "sse-stream"
version = "0.2.3"
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 0e2d63bfe..8ce2ada77 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -1,9 +1,9 @@
[workspace]
[package]
-name = "sprout-desktop"
+name = "buzz-desktop"
version = "0.3.16"
-description = "Sprout desktop app"
+description = "Buzz desktop app"
authors = ["you"]
edition = "2021"
@@ -13,7 +13,7 @@ edition = "2021"
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
-name = "sprout_lib"
+name = "buzz_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[features]
@@ -61,9 +61,9 @@ nostr = { version = "0.44", features = ["nip44"] }
zeroize = "1"
reqwest = { version = "0.13", features = ["json", "query", "stream"] }
url = "2"
-sprout-core = { package = "buzz-core", path = "../../crates/buzz-core" }
-sprout-persona = { package = "buzz-persona", path = "../../crates/buzz-persona" }
-sprout-sdk = { package = "buzz-sdk", path = "../../crates/buzz-sdk" }
+buzz_core_pkg = { package = "buzz-core", path = "../../crates/buzz-core" }
+buzz_persona_pkg = { package = "buzz-persona", path = "../../crates/buzz-persona" }
+buzz_sdk_pkg = { package = "buzz-sdk", path = "../../crates/buzz-sdk" }
mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "ebc3ab4c4b5f4a45d5bc942c66c18583800c3f82", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "ebc3ab4c4b5f4a45d5bc942c66c18583800c3f82", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
base64 = "0.22"
diff --git a/desktop/src-tauri/Info.plist b/desktop/src-tauri/Info.plist
index b46d11a26..61604f062 100644
--- a/desktop/src-tauri/Info.plist
+++ b/desktop/src-tauri/Info.plist
@@ -3,10 +3,10 @@
CFBundleDisplayName
- Sprout
+ Buzz
CFBundleName
- Sprout
+ Buzz
NSMicrophoneUsageDescription
- Sprout needs microphone access for voice huddles.
+ Buzz needs microphone access for voice huddles.
diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs
index aaef37143..cb5fcb48d 100644
--- a/desktop/src-tauri/build.rs
+++ b/desktop/src-tauri/build.rs
@@ -1,11 +1,11 @@
fn main() {
println!("cargo:rerun-if-env-changed=BUZZ_RELAY_URL");
println!("cargo:rerun-if-env-changed=BUZZ_RELAY_HTTP");
- println!("cargo:rerun-if-env-changed=SPROUT_UPDATER_PUBLIC_KEY");
- println!("cargo:rerun-if-env-changed=SPROUT_UPDATER_ENDPOINT");
- println!("cargo:rerun-if-env-changed=SPROUT_BUILD_DATABRICKS_HOST");
- println!("cargo:rerun-if-env-changed=SPROUT_BUILD_DATABRICKS_MODEL");
- println!("cargo:rustc-check-cfg=cfg(sprout_updater_enabled)");
+ println!("cargo:rerun-if-env-changed=BUZZ_UPDATER_PUBLIC_KEY");
+ println!("cargo:rerun-if-env-changed=BUZZ_UPDATER_ENDPOINT");
+ println!("cargo:rerun-if-env-changed=BUZZ_BUILD_DATABRICKS_HOST");
+ println!("cargo:rerun-if-env-changed=BUZZ_BUILD_DATABRICKS_MODEL");
+ println!("cargo:rustc-check-cfg=cfg(buzz_updater_enabled)");
if let Ok(relay_url) = std::env::var("BUZZ_RELAY_URL") {
println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_RELAY_URL={relay_url}");
@@ -15,25 +15,25 @@ fn main() {
println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_RELAY_HTTP={relay_http}");
}
- if let Ok(host) = std::env::var("SPROUT_BUILD_DATABRICKS_HOST") {
- println!("cargo:rustc-env=SPROUT_DESKTOP_BUILD_DATABRICKS_HOST={host}");
+ if let Ok(host) = std::env::var("BUZZ_BUILD_DATABRICKS_HOST") {
+ println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_DATABRICKS_HOST={host}");
}
- if let Ok(model) = std::env::var("SPROUT_BUILD_DATABRICKS_MODEL") {
- println!("cargo:rustc-env=SPROUT_DESKTOP_BUILD_DATABRICKS_MODEL={model}");
+ if let Ok(model) = std::env::var("BUZZ_BUILD_DATABRICKS_MODEL") {
+ println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_DATABRICKS_MODEL={model}");
}
- let updater_public_key = std::env::var("SPROUT_UPDATER_PUBLIC_KEY")
+ let updater_public_key = std::env::var("BUZZ_UPDATER_PUBLIC_KEY")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty());
- let updater_endpoint = std::env::var("SPROUT_UPDATER_ENDPOINT")
+ let updater_endpoint = std::env::var("BUZZ_UPDATER_ENDPOINT")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty());
if updater_public_key.is_some() && updater_endpoint.is_some() {
- println!("cargo:rustc-cfg=sprout_updater_enabled");
+ println!("cargo:rustc-cfg=buzz_updater_enabled");
}
tauri_build::build()
diff --git a/desktop/src-tauri/icons/128x128.png b/desktop/src-tauri/icons/128x128.png
index 8ed6c1568..3dc83a86e 100644
Binary files a/desktop/src-tauri/icons/128x128.png and b/desktop/src-tauri/icons/128x128.png differ
diff --git a/desktop/src-tauri/icons/128x128@2x.png b/desktop/src-tauri/icons/128x128@2x.png
index ba7bd53b9..059434892 100644
Binary files a/desktop/src-tauri/icons/128x128@2x.png and b/desktop/src-tauri/icons/128x128@2x.png differ
diff --git a/desktop/src-tauri/icons/32x32.png b/desktop/src-tauri/icons/32x32.png
index a63e6d7a2..f6273ef38 100644
Binary files a/desktop/src-tauri/icons/32x32.png and b/desktop/src-tauri/icons/32x32.png differ
diff --git a/desktop/src-tauri/icons/64x64.png b/desktop/src-tauri/icons/64x64.png
index 6fbecf1d2..c48f2d5c6 100644
Binary files a/desktop/src-tauri/icons/64x64.png and b/desktop/src-tauri/icons/64x64.png differ
diff --git a/desktop/src-tauri/icons/Square107x107Logo.png b/desktop/src-tauri/icons/Square107x107Logo.png
index 6eb074d09..3ad9aa66c 100644
Binary files a/desktop/src-tauri/icons/Square107x107Logo.png and b/desktop/src-tauri/icons/Square107x107Logo.png differ
diff --git a/desktop/src-tauri/icons/Square142x142Logo.png b/desktop/src-tauri/icons/Square142x142Logo.png
index 8d8672baa..2b8eab9ee 100644
Binary files a/desktop/src-tauri/icons/Square142x142Logo.png and b/desktop/src-tauri/icons/Square142x142Logo.png differ
diff --git a/desktop/src-tauri/icons/Square150x150Logo.png b/desktop/src-tauri/icons/Square150x150Logo.png
index 40b116d8d..e46260d29 100644
Binary files a/desktop/src-tauri/icons/Square150x150Logo.png and b/desktop/src-tauri/icons/Square150x150Logo.png differ
diff --git a/desktop/src-tauri/icons/Square284x284Logo.png b/desktop/src-tauri/icons/Square284x284Logo.png
index 77f479007..2bbbe0d2e 100644
Binary files a/desktop/src-tauri/icons/Square284x284Logo.png and b/desktop/src-tauri/icons/Square284x284Logo.png differ
diff --git a/desktop/src-tauri/icons/Square30x30Logo.png b/desktop/src-tauri/icons/Square30x30Logo.png
index d0dfdb903..f7a711237 100644
Binary files a/desktop/src-tauri/icons/Square30x30Logo.png and b/desktop/src-tauri/icons/Square30x30Logo.png differ
diff --git a/desktop/src-tauri/icons/Square310x310Logo.png b/desktop/src-tauri/icons/Square310x310Logo.png
index 868a9a382..2786fde22 100644
Binary files a/desktop/src-tauri/icons/Square310x310Logo.png and b/desktop/src-tauri/icons/Square310x310Logo.png differ
diff --git a/desktop/src-tauri/icons/Square44x44Logo.png b/desktop/src-tauri/icons/Square44x44Logo.png
index bf4881bc9..783d8e4e3 100644
Binary files a/desktop/src-tauri/icons/Square44x44Logo.png and b/desktop/src-tauri/icons/Square44x44Logo.png differ
diff --git a/desktop/src-tauri/icons/Square71x71Logo.png b/desktop/src-tauri/icons/Square71x71Logo.png
index 43313b472..b3b37bef3 100644
Binary files a/desktop/src-tauri/icons/Square71x71Logo.png and b/desktop/src-tauri/icons/Square71x71Logo.png differ
diff --git a/desktop/src-tauri/icons/Square89x89Logo.png b/desktop/src-tauri/icons/Square89x89Logo.png
index e6460683d..436dbea88 100644
Binary files a/desktop/src-tauri/icons/Square89x89Logo.png and b/desktop/src-tauri/icons/Square89x89Logo.png differ
diff --git a/desktop/src-tauri/icons/StoreLogo.png b/desktop/src-tauri/icons/StoreLogo.png
index a87f16dea..878b90d0a 100644
Binary files a/desktop/src-tauri/icons/StoreLogo.png and b/desktop/src-tauri/icons/StoreLogo.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
index f54dfd401..3cc375095 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
index 276bc9625..bc5c7153e 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
index 9f22a9f0a..84efd0b18 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
index 47a91a100..81283d034 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
index 0ce6fe0da..5c11514c1 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
index 26f3ffce8..135fcc884 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
index 47a779f44..9e1e5f2e6 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
index 8ad065422..c9cec30e2 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
index cc8bca4fd..cf2f8832f 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
index bad8ea6b3..fc9fd7fa6 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
index a194a3f8e..367ec1a18 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
index bad8ea6b3..0b0701084 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
index 054aeb042..650d42691 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png
index a7397c296..06a23a314 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
index 054aeb042..0abbb8ebb 100644
Binary files a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/desktop/src-tauri/icons/android/values/ic_launcher_background.xml b/desktop/src-tauri/icons/android/values/ic_launcher_background.xml
index ea9c223a6..f432ea70d 100644
--- a/desktop/src-tauri/icons/android/values/ic_launcher_background.xml
+++ b/desktop/src-tauri/icons/android/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #fff
+ #050506
\ No newline at end of file
diff --git a/desktop/src-tauri/icons/buzz-source.png b/desktop/src-tauri/icons/buzz-source.png
new file mode 100644
index 000000000..004236528
Binary files /dev/null and b/desktop/src-tauri/icons/buzz-source.png differ
diff --git a/desktop/src-tauri/icons/icon.icns b/desktop/src-tauri/icons/icon.icns
index 07b2e16d0..12e81456e 100644
Binary files a/desktop/src-tauri/icons/icon.icns and b/desktop/src-tauri/icons/icon.icns differ
diff --git a/desktop/src-tauri/icons/icon.ico b/desktop/src-tauri/icons/icon.ico
index 138c35c8c..6b9f750de 100644
Binary files a/desktop/src-tauri/icons/icon.ico and b/desktop/src-tauri/icons/icon.ico differ
diff --git a/desktop/src-tauri/icons/icon.png b/desktop/src-tauri/icons/icon.png
index f116cb4b6..d6cc19e83 100644
Binary files a/desktop/src-tauri/icons/icon.png and b/desktop/src-tauri/icons/icon.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png
index 925d67740..95b2cda20 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
index 96701250d..b46df45f0 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png
index 96701250d..b46df45f0 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png
index 2c0e50700..c86a6d9ab 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png
index 12d38f5e5..b8faba669 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
index 1760c0fd2..b61ec5b15 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png
index 1760c0fd2..b61ec5b15 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png
index 5ac9160f2..843deddfa 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png
index 96701250d..b46df45f0 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
index 9cfc369ee..fec2d3794 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png
index 2ddae2912..fec2d3794 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png
index 4f6a5c552..35bf0a56a 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-512@2x.png b/desktop/src-tauri/icons/ios/AppIcon-512@2x.png
index 966b452fd..2ee3675d7 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-512@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-512@2x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png b/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png
index 4f6a5c552..35bf0a56a 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png b/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png
index 765d8bb13..97ef3b888 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png b/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png
index 284e5dddb..29852fe45 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png b/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png
index ed5869dd8..7170dedfc 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png differ
diff --git a/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
index dbfbc97ab..3f030d7dd 100644
Binary files a/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png differ
diff --git a/desktop/src-tauri/icons/sprout-art.png b/desktop/src-tauri/icons/sprout-art.png
deleted file mode 100644
index 65bb6059a..000000000
Binary files a/desktop/src-tauri/icons/sprout-art.png and /dev/null differ
diff --git a/desktop/src-tauri/icons/sprout-rounded.svg b/desktop/src-tauri/icons/sprout-rounded.svg
deleted file mode 100644
index d5c546c91..000000000
--- a/desktop/src-tauri/icons/sprout-rounded.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/desktop/src-tauri/icons/sprout-source.png b/desktop/src-tauri/icons/sprout-source.png
deleted file mode 100644
index 22b097412..000000000
Binary files a/desktop/src-tauri/icons/sprout-source.png and /dev/null differ
diff --git a/desktop/src-tauri/src/app_state.rs b/desktop/src-tauri/src/app_state.rs
index 24512c51b..a20dc815e 100644
--- a/desktop/src-tauri/src/app_state.rs
+++ b/desktop/src-tauri/src/app_state.rs
@@ -35,7 +35,7 @@ pub struct AppState {
pub media_proxy_port: AtomicU16,
/// IOKit power assertion state — prevents idle sleep while agents run.
pub prevent_sleep: Arc>,
- /// In-process mesh-llm node started by Sprout Desktop.
+ /// In-process mesh-llm node started by Buzz Desktop.
#[cfg(feature = "mesh-llm")]
pub mesh_llm_runtime: AsyncMutex>,
/// Runtime-owned relay-mesh control plane (call-me-now listener + connect
@@ -48,16 +48,16 @@ pub struct AppState {
pub fn build_app_state() -> AppState {
// Env var takes precedence (dev/CI). If absent, resolve_persisted_identity()
// in setup() will replace the ephemeral placeholder with a persisted key.
- let (keys, source) = match std::env::var("SPROUT_PRIVATE_KEY") {
+ let (keys, source) = match std::env::var("BUZZ_PRIVATE_KEY") {
Ok(nsec) => match Keys::parse(nsec.trim()) {
Ok(keys) => (keys, "configured"),
Err(error) => {
- eprintln!("sprout-desktop: invalid SPROUT_PRIVATE_KEY: {error}");
+ eprintln!("buzz-desktop: invalid BUZZ_PRIVATE_KEY: {error}");
(Keys::generate(), "ephemeral")
}
},
Err(std::env::VarError::NotUnicode(_)) => {
- eprintln!("sprout-desktop: SPROUT_PRIVATE_KEY contains invalid UTF-8");
+ eprintln!("buzz-desktop: BUZZ_PRIVATE_KEY contains invalid UTF-8");
(Keys::generate(), "ephemeral")
}
Err(std::env::VarError::NotPresent) => (Keys::generate(), "ephemeral"),
@@ -65,7 +65,7 @@ pub fn build_app_state() -> AppState {
if source == "configured" {
eprintln!(
- "sprout-desktop: configured identity pubkey {}",
+ "buzz-desktop: configured identity pubkey {}",
keys.public_key().to_hex()
);
}
@@ -126,7 +126,7 @@ impl AppState {
/// Resolve the user's identity key from the app data directory.
///
-/// Priority: `SPROUT_PRIVATE_KEY` env var (already handled in `build_app_state`)
+/// Priority: `BUZZ_PRIVATE_KEY` env var (already handled in `build_app_state`)
/// → `{app_data_dir}/identity.key` file → generate + save.
///
/// Writes use `atomic-write-file` which handles temp file creation, fsync,
@@ -135,7 +135,7 @@ pub fn resolve_persisted_identity(app: &AppHandle, state: &AppState) -> Result<(
// Only skip file-based resolution if the env var was present AND parsed
// successfully. A malformed env var should fall through to the persisted
// key rather than leaving the app on an ephemeral identity.
- if let Ok(nsec) = std::env::var("SPROUT_PRIVATE_KEY") {
+ if let Ok(nsec) = std::env::var("BUZZ_PRIVATE_KEY") {
if Keys::parse(nsec.trim()).is_ok() {
return Ok(());
}
@@ -153,7 +153,7 @@ pub fn resolve_persisted_identity(app: &AppHandle, state: &AppState) -> Result<(
match load_key_file(&key_path) {
Ok(keys) => {
eprintln!(
- "sprout-desktop: persisted identity pubkey {}",
+ "buzz-desktop: persisted identity pubkey {}",
keys.public_key().to_hex()
);
*state.keys.lock().map_err(|e| e.to_string())? = keys;
@@ -168,7 +168,7 @@ pub fn resolve_persisted_identity(app: &AppHandle, state: &AppState) -> Result<(
.unwrap_or(0);
let bad_name = format!("identity.key.bad.{ts}");
eprintln!(
- "sprout-desktop: corrupt identity.key ({error}), quarantining to {bad_name}"
+ "buzz-desktop: corrupt identity.key ({error}), quarantining to {bad_name}"
);
let bad_path = data_dir.join(bad_name);
if std::fs::rename(&key_path, &bad_path).is_err() {
@@ -183,7 +183,7 @@ pub fn resolve_persisted_identity(app: &AppHandle, state: &AppState) -> Result<(
save_key_file(&key_path, &keys)?;
eprintln!(
- "sprout-desktop: generated and saved identity pubkey {}",
+ "buzz-desktop: generated and saved identity pubkey {}",
keys.public_key().to_hex()
);
*state.keys.lock().map_err(|e| e.to_string())? = keys;
diff --git a/desktop/src-tauri/src/commands/agent_models.rs b/desktop/src-tauri/src/commands/agent_models.rs
index a24e1d404..6eee455c7 100644
--- a/desktop/src-tauri/src/commands/agent_models.rs
+++ b/desktop/src-tauri/src/commands/agent_models.rs
@@ -16,7 +16,7 @@ use crate::{
util::now_iso,
};
-/// Query available models from an agent via `sprout-acp models --json`.
+/// Query available models from an agent via `buzz-acp models --json`.
///
/// Spawns a short-lived subprocess (no relay connection needed). The subprocess
/// starts the agent, queries its model catalog, and exits. ~2-5s total.
@@ -92,14 +92,14 @@ pub async fn get_agent_models(
}
}
}
- // User env layering — written LAST so it overrides any Sprout-set env above.
+ // User env layering — written LAST so it overrides any Buzz-set env above.
for (k, v) in &merged_env {
cmd.env(k, v);
}
cmd.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.output()
- .map_err(|e| format!("failed to spawn sprout-acp models: {e}"))
+ .map_err(|e| format!("failed to spawn buzz-acp models: {e}"))
})
.await
.map_err(|e| format!("model discovery task failed: {e}"))?
@@ -113,7 +113,7 @@ pub async fn get_agent_models(
let stderr_redacted =
crate::managed_agents::redact_env_values_in(stderr.as_ref(), &env_for_redaction);
return Err(format!(
- "sprout-acp models failed (exit {}): {stderr_redacted}",
+ "buzz-acp models failed (exit {}): {stderr_redacted}",
output.status.code().unwrap_or(-1)
));
}
@@ -270,7 +270,7 @@ pub async fn update_managed_agent(
{
Ok(()) => None,
Err(e) => {
- eprintln!("sprout-desktop: relay profile sync failed after rename: {e}");
+ eprintln!("buzz-desktop: relay profile sync failed after rename: {e}");
Some(e)
}
}
@@ -286,7 +286,7 @@ pub async fn update_managed_agent(
// ── Model normalization ───────────────────────────────────────────────────────
-/// Normalize raw `sprout-acp models --json` output into a typed DTO for the frontend.
+/// Normalize raw `buzz-acp models --json` output into a typed DTO for the frontend.
///
/// Merges models from both ACP paths (stable configOptions + unstable SessionModelState),
/// deduplicates by ID (stable takes precedence), and returns a unified list.
diff --git a/desktop/src-tauri/src/commands/agents.rs b/desktop/src-tauri/src/commands/agents.rs
index 9bbc7f6c7..76f34bc59 100644
--- a/desktop/src-tauri/src/commands/agents.rs
+++ b/desktop/src-tauri/src/commands/agents.rs
@@ -20,7 +20,7 @@ use crate::{
};
/// Read the workspace owner's pubkey hex from app state without holding the
-/// lock for longer than necessary. Used to populate `SPROUT_ACP_AGENT_OWNER`
+/// lock for longer than necessary. Used to populate `BUZZ_ACP_AGENT_OWNER`
/// as a fallback for legacy agent records that have no NIP-OA `auth_tag`.
fn workspace_owner_hex(state: &AppState) -> Result {
let keys = state.keys.lock().map_err(|e| e.to_string())?;
@@ -313,7 +313,7 @@ pub async fn create_managed_agent(
crate::managed_agents::validate_user_env_keys(&input.env_vars)?;
// Validate & normalize the respond-to allowlist BEFORE any side effects.
- // The harness has its own validator (sprout-acp/src/config.rs) but we want
+ // The harness has its own validator (buzz-acp/src/config.rs) but we want
// to catch malformed input at the boundary so the agent never tries to
// start with a list that will crash it on launch.
let respond_to_allowlist =
@@ -384,12 +384,12 @@ pub async fn create_managed_agent(
// No tokens are minted. Fail closed: bad auth tag → don't create agent.
let auth_tag = {
let owner_keys = state.keys.lock().map_err(|e| e.to_string())?;
- // Bridge nostr 0.37 → 0.36 (sprout-sdk) via hex round-trip.
+ // Bridge nostr 0.37 → 0.36 (buzz-sdk) via hex round-trip.
let compat_owner = nostr::Keys::parse(&owner_keys.secret_key().to_secret_hex())
.map_err(|e| format!("failed to bridge owner keys: {e}"))?;
let compat_agent = nostr::PublicKey::from_hex(&agent_keys.public_key().to_hex())
.map_err(|e| format!("failed to bridge agent pubkey: {e}"))?;
- let tag = sprout_sdk::nip_oa::compute_auth_tag(&compat_owner, &compat_agent, "")
+ let tag = buzz_sdk_pkg::nip_oa::compute_auth_tag(&compat_owner, &compat_agent, "")
.map_err(|e| format!("failed to compute NIP-OA auth tag: {e}"))?;
Some(tag)
};
@@ -647,7 +647,7 @@ pub async fn create_managed_agent(
if let Err(persist_err) = persist_create_deploy_error(&app, &state, &pubkey, &e)
{
eprintln!(
- "sprout-desktop: failed to persist deploy-prep error for {pubkey}: {persist_err}"
+ "buzz-desktop: failed to persist deploy-prep error for {pubkey}: {persist_err}"
);
}
Some(e)
@@ -834,7 +834,7 @@ pub async fn start_managed_agent(
.await
{
eprintln!(
- "sprout-desktop: profile reconciliation failed for agent {reconcile_pubkey}: {e}"
+ "buzz-desktop: profile reconciliation failed for agent {reconcile_pubkey}: {e}"
);
}
});
@@ -1103,7 +1103,7 @@ pub fn discover_backend_providers() -> Vec {
#[tauri::command]
pub async fn probe_backend_provider(binary_path: String) -> Result {
- // Validate that the requested path is actually a discovered sprout-backend-* binary.
+ // Validate that the requested path is actually a discovered buzz-backend-* binary.
// This prevents arbitrary binary execution via a compromised frontend or IPC.
let candidates = discover_provider_candidates();
let path = std::path::PathBuf::from(&binary_path);
@@ -1115,7 +1115,7 @@ pub async fn probe_backend_provider(binary_path: String) -> Result) -> Result
let events = query_relay(
&state,
&[serde_json::json!({
- "kinds": [sprout_core::kind::KIND_DM_VISIBILITY],
+ "kinds": [buzz_core_pkg::kind::KIND_DM_VISIBILITY],
"#p": [&my_pubkey],
"limit": 1,
})],
diff --git a/desktop/src-tauri/src/commands/engrams.rs b/desktop/src-tauri/src/commands/engrams.rs
index c10c2c483..13e9ecb96 100644
--- a/desktop/src-tauri/src/commands/engrams.rs
+++ b/desktop/src-tauri/src/commands/engrams.rs
@@ -22,8 +22,8 @@ use nostr::PublicKey;
use serde::Serialize;
use tauri::{AppHandle, State};
-use sprout_core::engram::{self, extract_refs, select_head, validate_and_decrypt, Body};
-use sprout_core::kind::KIND_AGENT_ENGRAM;
+use buzz_core_pkg::engram::{self, extract_refs, select_head, validate_and_decrypt, Body};
+use buzz_core_pkg::kind::KIND_AGENT_ENGRAM;
use crate::{app_state::AppState, managed_agents::load_managed_agents, relay::query_relay};
diff --git a/desktop/src-tauri/src/commands/identity.rs b/desktop/src-tauri/src/commands/identity.rs
index f883298e1..4c0e6ce53 100644
--- a/desktop/src-tauri/src/commands/identity.rs
+++ b/desktop/src-tauri/src/commands/identity.rs
@@ -37,10 +37,10 @@ pub fn get_default_relay_url() -> String {
#[tauri::command]
pub fn is_shared_identity() -> bool {
- std::env::var("SPROUT_SHARE_IDENTITY")
+ std::env::var("BUZZ_SHARE_IDENTITY")
.map(|v| v == "1")
.unwrap_or(false)
- && std::env::var("SPROUT_PRIVATE_KEY")
+ && std::env::var("BUZZ_PRIVATE_KEY")
.ok()
.and_then(|k| Keys::parse(k.trim()).ok())
.is_some()
@@ -112,7 +112,7 @@ pub fn decrypt_observer_event(
return Err("observer event has invalid signature".into());
}
- sprout_core::observer::decrypt_observer_payload(&keys, &event)
+ buzz_core_pkg::observer::decrypt_observer_payload(&keys, &event)
.map_err(|error| format!("decrypt observer event failed: {error}"))
}
@@ -132,12 +132,13 @@ pub fn build_observer_control_event(
let agent_pubkey = PublicKey::from_hex(agent_pubkey.trim())
.map_err(|error| format!("invalid agent pubkey: {error}"))?;
let agent_pubkey_hex = agent_pubkey.to_hex();
- let encrypted = sprout_core::observer::encrypt_observer_payload(&keys, &agent_pubkey, &payload)
- .map_err(|error| format!("encrypt observer control failed: {error}"))?;
- let builder = sprout_sdk::build_agent_observer_frame(
+ let encrypted =
+ buzz_core_pkg::observer::encrypt_observer_payload(&keys, &agent_pubkey, &payload)
+ .map_err(|error| format!("encrypt observer control failed: {error}"))?;
+ let builder = buzz_sdk_pkg::build_agent_observer_frame(
&agent_pubkey_hex,
&agent_pubkey_hex,
- sprout_core::observer::OBSERVER_FRAME_CONTROL,
+ buzz_core_pkg::observer::OBSERVER_FRAME_CONTROL,
&encrypted,
)
.map_err(|error| format!("build observer control failed: {error}"))?;
@@ -187,7 +188,7 @@ pub fn import_identity(
bech32
};
- eprintln!("sprout-desktop: imported identity pubkey {}", pubkey_hex);
+ eprintln!("buzz-desktop: imported identity pubkey {}", pubkey_hex);
Ok(IdentityInfo {
pubkey: pubkey_hex,
diff --git a/desktop/src-tauri/src/commands/identity_archive.rs b/desktop/src-tauri/src/commands/identity_archive.rs
index 5df6463af..64459061b 100644
--- a/desktop/src-tauri/src/commands/identity_archive.rs
+++ b/desktop/src-tauri/src/commands/identity_archive.rs
@@ -27,7 +27,7 @@ use crate::{
///
/// Mirrors the verification the relay will do (per spec gotcha #3: the
/// preimage subject is the *target* pubkey, not the request signer). The
-/// `sprout-sdk` lives on nostr 0.36; the desktop is on 0.37, so we bridge
+/// `buzz-sdk` lives on nostr 0.36; the desktop is on 0.37, so we bridge
/// via hex round-trip exactly like `relay::build_profile_event` does.
fn extract_oa_owner(target_kind0: &nostr::Event) -> Option<(String, [String; 4])> {
let target_hex = target_kind0.pubkey.to_hex();
@@ -39,7 +39,7 @@ fn extract_oa_owner(target_kind0: &nostr::Event) -> Option<(String, [String; 4])
continue;
}
let json = serde_json::to_string(slice).ok()?;
- match sprout_sdk::nip_oa::verify_auth_tag(&json, &target_compat) {
+ match buzz_sdk_pkg::nip_oa::verify_auth_tag(&json, &target_compat) {
Ok(owner) => {
let raw: [String; 4] = [
slice[0].clone(),
@@ -228,7 +228,7 @@ pub struct ArchivedIdentitiesSnapshot {
/// fetch wired up (the sibling relay-signed kind:13534 membership list is
/// consumed the same way). Author-filtering against NIP-11 `self` is the
/// correct hardening for an untrusted/multi-relay client and is tracked as a
-/// follow-up — not a runtime gap on Sprout's relay.
+/// follow-up — not a runtime gap on Buzz's relay.
#[tauri::command]
pub async fn list_archived_identities(
state: State<'_, AppState>,
@@ -273,15 +273,16 @@ mod tests {
/// Build a fake `kind:0` with a valid NIP-OA auth tag for a fresh owner.
fn kind0_with_auth(agent: &Keys, owner: &Keys) -> nostr::Event {
- // Compute auth tag via sprout-sdk (nostr 0.36) and bridge.
+ // Compute auth tag via buzz-sdk (nostr 0.36) and bridge.
let agent_hex = agent.public_key().to_hex();
let agent_compat = nostr::PublicKey::from_hex(&agent_hex).unwrap();
let owner_compat_secret =
nostr::SecretKey::from_slice(owner.secret_key().as_secret_bytes()).unwrap();
let owner_compat_keys = nostr::Keys::new(owner_compat_secret);
- let tag_json = sprout_sdk::nip_oa::compute_auth_tag(&owner_compat_keys, &agent_compat, "")
- .expect("compute_auth_tag");
- let compat_tag = sprout_sdk::nip_oa::parse_auth_tag(&tag_json).unwrap();
+ let tag_json =
+ buzz_sdk_pkg::nip_oa::compute_auth_tag(&owner_compat_keys, &agent_compat, "")
+ .expect("compute_auth_tag");
+ let compat_tag = buzz_sdk_pkg::nip_oa::parse_auth_tag(&tag_json).unwrap();
let tag = Tag::parse(compat_tag.as_slice()).unwrap();
EventBuilder::new(Kind::Metadata, "{}")
.tags([tag])
diff --git a/desktop/src-tauri/src/commands/media.rs b/desktop/src-tauri/src/commands/media.rs
index faf743c6a..fbe5528f6 100644
--- a/desktop/src-tauri/src/commands/media.rs
+++ b/desktop/src-tauri/src/commands/media.rs
@@ -173,7 +173,7 @@ fn sign_blossom_upload_auth(
if let Some(domain) = extract_server_authority(base_url) {
tags.push(Tag::parse(vec!["server".to_string(), domain]).map_err(|e| e.to_string())?);
}
- EventBuilder::new(Kind::from(24242), "Upload sprout-media")
+ EventBuilder::new(Kind::from(24242), "Upload buzz-media")
.tags(tags)
.sign_with_keys(keys)
.map_err(|e| e.to_string())
@@ -321,7 +321,7 @@ async fn process_picked_path(
if let Some(poster) = poster_bytes {
match do_upload(poster, "image/jpeg", state).await {
Ok(poster_desc) => descriptor.image = Some(poster_desc.url),
- Err(e) => eprintln!("sprout-desktop: poster upload failed (non-fatal): {e}"),
+ Err(e) => eprintln!("buzz-desktop: poster upload failed (non-fatal): {e}"),
}
}
@@ -398,7 +398,7 @@ pub async fn upload_media_bytes(
// All blocking I/O runs off the async runtime via spawn_blocking.
tokio::task::spawn_blocking(move || -> Result<(Vec, Option>), String> {
let tmp_input =
- std::env::temp_dir().join(format!("sprout-drop-{}", uuid::Uuid::new_v4()));
+ std::env::temp_dir().join(format!("buzz-drop-{}", uuid::Uuid::new_v4()));
// Cleanup guard: remove temp file on ALL exit paths (including write failure).
let result = (|| {
std::fs::write(&tmp_input, &data)
@@ -422,7 +422,7 @@ pub async fn upload_media_bytes(
if let Some(poster) = poster_bytes {
match do_upload(poster, "image/jpeg", &state).await {
Ok(poster_desc) => descriptor.image = Some(poster_desc.url),
- Err(e) => eprintln!("sprout-desktop: poster upload failed (non-fatal): {e}"),
+ Err(e) => eprintln!("buzz-desktop: poster upload failed (non-fatal): {e}"),
}
}
diff --git a/desktop/src-tauri/src/commands/media_transcode.rs b/desktop/src-tauri/src/commands/media_transcode.rs
index 604e7b5b7..96aabed6c 100644
--- a/desktop/src-tauri/src/commands/media_transcode.rs
+++ b/desktop/src-tauri/src/commands/media_transcode.rs
@@ -111,8 +111,7 @@ pub(super) fn transcode_to_mp4(
ffmpeg: &std::path::Path,
) -> Result {
// UUID-based temp path — unique across concurrent uploads.
- let output =
- std::env::temp_dir().join(format!("sprout-transcode-{}.mp4", uuid::Uuid::new_v4()));
+ let output = std::env::temp_dir().join(format!("buzz-transcode-{}.mp4", uuid::Uuid::new_v4()));
let result = run_ffmpeg_with_timeout(
std::process::Command::new(ffmpeg)
@@ -167,7 +166,7 @@ pub(super) fn extract_poster_frame(
mp4_path: &std::path::Path,
ffmpeg: &std::path::Path,
) -> Result {
- let output = std::env::temp_dir().join(format!("sprout-poster-{}.jpg", uuid::Uuid::new_v4()));
+ let output = std::env::temp_dir().join(format!("buzz-poster-{}.jpg", uuid::Uuid::new_v4()));
// Poster extraction is a single-frame decode — 30s is generous.
let poster_timeout = std::time::Duration::from_secs(30);
@@ -194,7 +193,7 @@ pub(super) fn extract_poster_frame(
{
if !result.status.success() {
let stderr = String::from_utf8_lossy(&result.stderr);
- eprintln!("sprout-desktop: poster seek-to-1s failed, trying first frame: {stderr}");
+ eprintln!("buzz-desktop: poster seek-to-1s failed, trying first frame: {stderr}");
}
let _ = std::fs::remove_file(&output);
let fallback = run_ffmpeg_with_timeout(
@@ -211,7 +210,7 @@ pub(super) fn extract_poster_frame(
if !fallback.status.success() || !output.exists() {
let stderr = String::from_utf8_lossy(&fallback.stderr);
- eprintln!("sprout-desktop: poster frame extraction failed: {stderr}");
+ eprintln!("buzz-desktop: poster frame extraction failed: {stderr}");
let _ = std::fs::remove_file(&output);
return Err("ffmpeg could not extract a poster frame".to_string());
}
@@ -238,7 +237,7 @@ pub(super) fn transcode_and_extract_poster(
bytes
}
Err(e) => {
- eprintln!("sprout-desktop: poster extraction failed (non-fatal): {e}");
+ eprintln!("buzz-desktop: poster extraction failed (non-fatal): {e}");
None
}
};
diff --git a/desktop/src-tauri/src/commands/mesh_llm.rs b/desktop/src-tauri/src/commands/mesh_llm.rs
index c1b5ddad8..ecac20588 100644
--- a/desktop/src-tauri/src/commands/mesh_llm.rs
+++ b/desktop/src-tauri/src/commands/mesh_llm.rs
@@ -347,7 +347,7 @@ pub(crate) async fn ensure_relay_mesh_for_record(
{
// Non-fatal: the one-sided dial may still punch on a favorable NAT.
// Surface the reason without blocking the agent's spawn.
- eprintln!("sprout-mesh: saved-start connect-request failed: {error}");
+ eprintln!("buzz-mesh: saved-start connect-request failed: {error}");
}
}
}
@@ -503,7 +503,7 @@ mod tests {
/// frontend selected earlier.
///
/// Hardware-gated (`#[ignore]`): loads a real model. Run with:
- /// cargo test -p sprout-desktop --features mesh-llm \
+ /// cargo test -p buzz-desktop --features mesh-llm \
/// ensure_serve_runtime_serves_other_model -- --ignored --nocapture
#[tokio::test]
#[ignore = "loads a real model; run manually with --ignored"]
diff --git a/desktop/src-tauri/src/commands/messages.rs b/desktop/src-tauri/src/commands/messages.rs
index abbe0b0e6..51164106c 100644
--- a/desktop/src-tauri/src/commands/messages.rs
+++ b/desktop/src-tauri/src/commands/messages.rs
@@ -284,19 +284,19 @@ pub async fn send_channel_message(
let media = media_tags.unwrap_or_default();
let emoji = emoji_tags.unwrap_or_default();
let mention_refs_only = mention_tags.unwrap_or_default();
- let kind_num = kind.unwrap_or(sprout_core::kind::KIND_STREAM_MESSAGE);
+ let kind_num = kind.unwrap_or(buzz_core_pkg::kind::KIND_STREAM_MESSAGE);
let mut resolved_root: Option = None;
let builder = match kind_num {
- sprout_core::kind::KIND_FORUM_POST => events::build_forum_post(
+ buzz_core_pkg::kind::KIND_FORUM_POST => events::build_forum_post(
channel_uuid,
content.trim(),
&mention_refs,
&media,
&mention_refs_only,
)?,
- sprout_core::kind::KIND_FORUM_COMMENT => {
+ buzz_core_pkg::kind::KIND_FORUM_COMMENT => {
let parent_id = parent_event_id
.as_deref()
.ok_or("forum comment requires parent_event_id")?;
@@ -362,7 +362,7 @@ pub async fn add_reaction(
// Custom-emoji reaction (NIP-30): kind:7 with `:shortcode:` content and
// an `["emoji", shortcode, url]` tag. Delegates to the SDK builder so
// shortcode normalization + validation match the relay exactly.
- Some(url) => sprout_sdk::build_custom_emoji_reaction(target_eid, emoji.trim(), &url)
+ Some(url) => buzz_sdk_pkg::build_custom_emoji_reaction(target_eid, emoji.trim(), &url)
.map_err(|e| format!("invalid custom emoji reaction: {e}"))?,
None => events::build_reaction(target_eid, emoji.trim())?,
};
diff --git a/desktop/src-tauri/src/commands/pairing.rs b/desktop/src-tauri/src/commands/pairing.rs
index cbed4d52e..1168b9f1b 100644
--- a/desktop/src-tauri/src/commands/pairing.rs
+++ b/desktop/src-tauri/src/commands/pairing.rs
@@ -1,13 +1,13 @@
use std::sync::Arc;
use std::time::Duration;
+use buzz_core_pkg::kind::KIND_PAIRING;
+use buzz_core_pkg::pairing::qr::encode_qr;
+use buzz_core_pkg::pairing::session::PairingSession;
+use buzz_core_pkg::pairing::types::{AbortReason, PayloadType};
use futures_util::{SinkExt, StreamExt};
use nostr::ToBech32;
use serde::Serialize;
-use sprout_core::kind::KIND_PAIRING;
-use sprout_core::pairing::qr::encode_qr;
-use sprout_core::pairing::session::PairingSession;
-use sprout_core::pairing::types::{AbortReason, PayloadType};
use tauri::{AppHandle, Emitter, State};
use tokio::sync::mpsc;
use tokio_tungstenite::{connect_async, tungstenite::Message};
@@ -400,7 +400,7 @@ fn event_to_relay_json(event: &nostr::Event) -> String {
format!("[\"EVENT\",{}]", nostr::JsonUtil::as_json(event))
}
-/// Parse a relay EVENT message into a nostr 0.36 Event (sprout-core compatible).
+/// Parse a relay EVENT message into a nostr 0.36 Event (buzz-core compatible).
fn parse_relay_event(text: &str, sub_id: &str) -> Option {
let arr: serde_json::Value = serde_json::from_str(text).ok()?;
let arr = arr.as_array()?;
diff --git a/desktop/src-tauri/src/commands/profile.rs b/desktop/src-tauri/src/commands/profile.rs
index 40fac227f..e218ca36e 100644
--- a/desktop/src-tauri/src/commands/profile.rs
+++ b/desktop/src-tauri/src/commands/profile.rs
@@ -1,7 +1,7 @@
use std::collections::HashMap;
+use buzz_core_pkg::PresenceStatus;
use serde_json::Value;
-use sprout_core::PresenceStatus;
use tauri::State;
use crate::{
@@ -196,7 +196,7 @@ pub async fn search_users(
// NIP-50 full-text search on kind:0 profiles. The relay's HTTP bridge
// intercepts the `search` field on POST /query and routes to Typesense
- // (see `crates/sprout-relay/src/api/bridge.rs::handle_bridge_search`),
+ // (see `crates/buzz-relay/src/api/bridge.rs::handle_bridge_search`),
// so we get indexed, server-side search instead of fetching every kind:0
// and scanning client-side. The old path was capped at 2000 kind:0 events
// by the relay's HTTP bridge limit, which silently hid users on busy relays.
diff --git a/desktop/src-tauri/src/commands/teams.rs b/desktop/src-tauri/src/commands/teams.rs
index ad8930f9f..aba201b2f 100644
--- a/desktop/src-tauri/src/commands/teams.rs
+++ b/desktop/src-tauri/src/commands/teams.rs
@@ -260,7 +260,7 @@ fn parse_team_from_pack_zip(zip_bytes: &[u8]) -> Result (true, None),
Err(e) => {
eprintln!(
- "sprout-desktop: add agent to parent channel failed (may already be member): {e}"
+ "buzz-desktop: add agent to parent channel failed (may already be member): {e}"
);
(false, Some(e))
}
diff --git a/desktop/src-tauri/src/huddle/audio_output.rs b/desktop/src-tauri/src/huddle/audio_output.rs
index 7af9256a7..02acf2730 100644
--- a/desktop/src-tauri/src/huddle/audio_output.rs
+++ b/desktop/src-tauri/src/huddle/audio_output.rs
@@ -83,7 +83,7 @@ pub(crate) fn open_output_sink_by_name(
}
}
eprintln!(
- "sprout-desktop: preferred output device {name:?} not found, falling back to default"
+ "buzz-desktop: preferred output device {name:?} not found, falling back to default"
);
}
diff --git a/desktop/src-tauri/src/huddle/mod.rs b/desktop/src-tauri/src/huddle/mod.rs
index b2e6e769a..a25b9def3 100644
--- a/desktop/src-tauri/src/huddle/mod.rs
+++ b/desktop/src-tauri/src/huddle/mod.rs
@@ -106,7 +106,7 @@ pub async fn set_voice_input_mode(
// Best-effort restart — if models aren't ready, the pipeline
// stays down until the next hotstart cycle picks it up.
if let Err(e) = maybe_start_stt_pipeline(&state, &eph_id).await {
- eprintln!("sprout-desktop: STT pipeline restart on mode switch failed: {e}");
+ eprintln!("buzz-desktop: STT pipeline restart on mode switch failed: {e}");
}
}
}
@@ -203,7 +203,7 @@ pub async fn start_huddle(
events::build_huddle_guidelines(&ephemeral_channel_id, &guidelines)
{
if let Err(e) = submit_event(guidelines_builder, &state).await {
- eprintln!("sprout-desktop: huddle guidelines (kind:48106) failed: {e}");
+ eprintln!("buzz-desktop: huddle guidelines (kind:48106) failed: {e}");
}
}
@@ -214,7 +214,7 @@ pub async fn start_huddle(
match submit_event(add_builder, &state).await {
Ok(_) => successful_agents.push(pubkey.clone()),
Err(e) => {
- eprintln!("sprout-desktop: huddle add_member failed for {pubkey}: {e}");
+ eprintln!("buzz-desktop: huddle add_member failed for {pubkey}: {e}");
// Intentionally not added — policy rejected this agent.
}
}
@@ -266,7 +266,7 @@ pub async fn start_huddle(
if let Ok(archive_builder) = events::build_archive(ephemeral_uuid) {
if let Err(ae) = submit_event(archive_builder, &state).await {
eprintln!(
- "sprout-desktop: rollback archive of {ephemeral_channel_id} failed: {ae}"
+ "buzz-desktop: rollback archive of {ephemeral_channel_id} failed: {ae}"
);
}
}
@@ -287,7 +287,7 @@ pub async fn start_huddle(
if let Ok(archive_builder) = events::build_archive(ephemeral_uuid) {
if let Err(ae) = submit_event(archive_builder, &state).await {
eprintln!(
- "sprout-desktop: rollback archive of {ephemeral_channel_id} failed: {ae}"
+ "buzz-desktop: rollback archive of {ephemeral_channel_id} failed: {ae}"
);
}
}
@@ -423,7 +423,7 @@ async fn emit_end_and_archive(
events::build_huddle_ended(parent_channel_id, ephemeral_channel_id)
{
if let Err(e) = submit_event(ended_builder, state).await {
- eprintln!("sprout-desktop: huddle_ended event failed: {e}");
+ eprintln!("buzz-desktop: huddle_ended event failed: {e}");
}
}
}
@@ -431,7 +431,7 @@ async fn emit_end_and_archive(
if let Ok(uuid) = parse_channel_uuid(ephemeral_channel_id) {
if let Ok(archive_builder) = events::build_archive(uuid) {
if let Err(e) = submit_event(archive_builder, state).await {
- eprintln!("sprout-desktop: archive ephemeral channel failed: {e}");
+ eprintln!("buzz-desktop: archive ephemeral channel failed: {e}");
}
}
}
@@ -481,14 +481,14 @@ pub async fn leave_huddle(state: State<'_, AppState>) -> Result<(), String> {
// Archive subsumes leave (the channel is gone, membership is moot).
// This avoids the "cannot remove the last owner" relay error that
// build_leave hits when the creator is the sole remaining member.
- eprintln!("sprout-desktop: last human left huddle — auto-ending");
+ eprintln!("buzz-desktop: last human left huddle — auto-ending");
emit_end_and_archive(&parent_channel_id, &ephemeral_channel_id, &state).await;
} else {
// Other humans still in the huddle — just remove self from membership.
if let Ok(eph_uuid) = parse_channel_uuid(&ephemeral_channel_id) {
if let Ok(leave_builder) = events::build_leave(eph_uuid) {
if let Err(e) = submit_event(leave_builder, &state).await {
- eprintln!("sprout-desktop: huddle leave ephemeral channel failed: {e}");
+ eprintln!("buzz-desktop: huddle leave ephemeral channel failed: {e}");
}
}
}
@@ -671,14 +671,14 @@ pub async fn check_pipeline_hotstart(state: State<'_, AppState>) -> Result<(), S
// Start TTS first (so STT can capture tts_cancel).
if !has_tts && (tts_ready || models::is_tts_ready()) {
if let Err(e) = maybe_start_tts_pipeline(&state).await {
- eprintln!("sprout-desktop: TTS hotstart failed: {e}");
+ eprintln!("buzz-desktop: TTS hotstart failed: {e}");
}
}
if !has_stt && (stt_ready || models::is_stt_ready()) {
if let Some(eph_id) = &ephemeral_channel_id {
if let Err(e) = maybe_start_stt_pipeline(&state, eph_id).await {
- eprintln!("sprout-desktop: STT hotstart failed: {e}");
+ eprintln!("buzz-desktop: STT hotstart failed: {e}");
}
}
}
@@ -812,7 +812,7 @@ pub async fn set_tts_enabled(enabled: bool, state: State<'_, AppState>) -> Resul
};
if matches!(phase, HuddlePhase::Connected | HuddlePhase::Active) {
if let Err(e) = maybe_start_tts_pipeline(&state).await {
- eprintln!("sprout-desktop: TTS pipeline restart failed: {e}");
+ eprintln!("buzz-desktop: TTS pipeline restart failed: {e}");
}
}
}
@@ -853,7 +853,7 @@ pub async fn speak_agent_message(text: String, state: State<'_, AppState>) -> Re
// Lazy-start: models may have finished downloading after the huddle began.
if needs_pipeline {
if let Err(e) = maybe_start_tts_pipeline(&state).await {
- eprintln!("sprout-desktop: TTS lazy-start failed: {e}");
+ eprintln!("buzz-desktop: TTS lazy-start failed: {e}");
}
}
diff --git a/desktop/src-tauri/src/huddle/models.rs b/desktop/src-tauri/src/huddle/models.rs
index 98729b2fb..8571c4043 100644
--- a/desktop/src-tauri/src/huddle/models.rs
+++ b/desktop/src-tauri/src/huddle/models.rs
@@ -1,17 +1,17 @@
//! Model download manager for STT (Parakeet TDT-CTC 110M) and TTS (Pocket TTS) models.
//!
//! Mental model:
-//! app launch → start_stt_download (background) → ~/.sprout/models/parakeet-tdt-ctc-110m-en/
-//! app launch → start_tts_download (background) → ~/.sprout/models/pocket-tts/
+//! app launch → start_stt_download (background) → ~/.buzz/models/parakeet-tdt-ctc-110m-en/
+//! app launch → start_tts_download (background) → ~/.buzz/models/pocket-tts/
//! STT pipeline → is_stt_ready() → stt_model_dir() → run inference
//! TTS pipeline → is_tts_ready() → tts_model_dir() → run synthesis
//!
-//! Models are downloaded once and cached. A version manifest (`.sprout-model-manifest`)
+//! Models are downloaded once and cached. A version manifest (`.buzz-model-manifest`)
//! is written alongside model files — if the on-disk version doesn't match the
//! compiled-in version, the model is re-downloaded.
//!
//! Upgrade note: an older Moonshine STT model directory at
-//! `~/.sprout/models/moonshine-tiny/` is removed best-effort once the new STT
+//! `~/.buzz/models/moonshine-tiny/` is removed best-effort once the new STT
//! model finishes installing successfully. Cleanup is gated on the new model
//! being Ready, so a failed download never removes the previous on-disk model
//! during migration. If removal fails (permissions, etc.) the leftover is
@@ -94,7 +94,7 @@ const STT_MODEL_VERSION: &str = "2";
const TTS_MODEL_VERSION: &str = "2";
/// Filename for the version manifest written alongside model files.
-const MANIFEST_FILENAME: &str = ".sprout-model-manifest";
+const MANIFEST_FILENAME: &str = ".buzz-model-manifest";
// ── Constants ─────────────────────────────────────────────────────────────────
@@ -117,12 +117,12 @@ const STT_DOWNLOAD_URL: &str =
/// Subdirectory name produced by `tar xjf` on the archive.
const STT_ARCHIVE_SUBDIR: &str = "sherpa-onnx-nemo-parakeet_tdt_ctc_110m-en-36000-int8";
-/// Final directory name under `~/.sprout/models/`.
+/// Final directory name under `~/.buzz/models/`.
const STT_MODEL_DIR_NAME: &str = "parakeet-tdt-ctc-110m-en";
/// All files that must be present for the model to be considered ready.
///
-/// Includes the attribution sidecar written by Sprout during install. The
+/// Includes the attribution sidecar written by Buzz during install. The
/// upstream archive does not ship a license file, so readiness should require
/// the local CC-BY-4.0 attribution to travel with the cached model bytes.
const STT_EXPECTED_FILES: &[&str] = &["model.int8.onnx", "tokens.txt", STT_LICENSE_FILE_NAME];
@@ -143,7 +143,7 @@ Licensed under the Creative Commons Attribution 4.0 International License
Original model: https://huggingface.co/nvidia/parakeet-tdt_ctc-110m
Converted to ONNX with int8 quantization by the sherpa-onnx project
-(https://github.com/k2-fsa/sherpa-onnx); Sprout ships this conversion
+(https://github.com/k2-fsa/sherpa-onnx); Buzz ships this conversion
unmodified.
Provided \"AS IS\", without warranty of any kind, express or implied. See the
@@ -152,7 +152,7 @@ license text for full warranty disclaimer.
// ── Pocket TTS model ──────────────────────────────────────────────────────────
-/// Final directory name under `~/.sprout/models/`.
+/// Final directory name under `~/.buzz/models/`.
const TTS_MODEL_DIR_NAME: &str = "pocket-tts";
/// Attribution sidecar written next to the Pocket TTS model files.
@@ -184,7 +184,7 @@ https://datashare.ed.ac.uk/handle/10283/3443 (CC-BY-4.0).
Recording enhancement (denoise/dereverb) by ai-coustics:
https://ai-coustics.com/
-Sprout ships all ONNX/model artifacts and the reference voice WAV unmodified,
+Buzz ships all ONNX/model artifacts and the reference voice WAV unmodified,
renamed only by placement in the local model directory.
Provided \"AS IS\", without warranty of any kind, express or implied. See the
@@ -391,7 +391,7 @@ where
/// Per-model state + config. `ModelManager` owns two of these (stt, tts).
#[derive(Clone)]
struct ModelSlot {
- dir_name: &'static str, // subdir under ~/.sprout/models/
+ dir_name: &'static str, // subdir under ~/.buzz/models/
expected_files: &'static [&'static str], // files required for "ready"
version: &'static str, // manifest version; increment to force re-download
status: Arc>,
@@ -474,7 +474,7 @@ impl ModelSlot {
// is accessible on the current thread. Tauri's runtime is always available.
tauri::async_runtime::spawn(async move {
if let Err(e) = download_fn(http_client).await {
- eprintln!("sprout-desktop: {name} download failed: {e}");
+ eprintln!("buzz-desktop: {name} download failed: {e}");
slot.set_status(ModelStatus::Error(e));
}
});
@@ -539,18 +539,18 @@ impl ModelSlot {
/// Cheap to clone — all inner state is behind `Arc`.
#[derive(Clone)]
pub struct ModelManager {
- /// `~/.sprout/models/`
+ /// `~/.buzz/models/`
models_dir: PathBuf,
stt: ModelSlot,
tts: ModelSlot,
}
impl ModelManager {
- /// Create a new `ModelManager` rooted at `~/.sprout/models/`.
+ /// Create a new `ModelManager` rooted at `~/.buzz/models/`.
///
/// Returns `None` if the home directory cannot be resolved.
pub fn new() -> Option {
- let models_dir = dirs::home_dir()?.join(".sprout").join("models");
+ let models_dir = dirs::home_dir()?.join(".buzz").join("models");
Some(Self {
models_dir,
stt: ModelSlot::new(STT_MODEL_DIR_NAME, STT_EXPECTED_FILES, STT_MODEL_VERSION),
@@ -654,7 +654,7 @@ impl ModelManager {
.join(format!("{STT_MODEL_DIR_NAME}.tar.bz2"));
let temp_dir = self.models_dir.join(format!("{STT_MODEL_DIR_NAME}.tmp"));
- eprintln!("sprout-desktop: downloading STT model from {STT_DOWNLOAD_URL}");
+ eprintln!("buzz-desktop: downloading STT model from {STT_DOWNLOAD_URL}");
let response = fetch_url(&http_client, STT_DOWNLOAD_URL, "stt archive").await?;
let slot = self.stt.clone();
@@ -674,7 +674,7 @@ impl ModelManager {
},
)
.await?;
- eprintln!("sprout-desktop: downloaded {bytes} bytes, wrote to disk");
+ eprintln!("buzz-desktop: downloaded {bytes} bytes, wrote to disk");
// Verify archive integrity before extraction.
let hash = sha256_file(&archive_path).await?;
@@ -690,7 +690,7 @@ impl ModelManager {
});
fresh_temp_dir(&temp_dir).await?;
- eprintln!("sprout-desktop: extracting STT archive…");
+ eprintln!("buzz-desktop: extracting STT archive…");
let (ap, td) = (archive_path.clone(), temp_dir.clone());
tokio::task::spawn_blocking(move || extract_archive(&ap, &td))
.await
@@ -735,7 +735,7 @@ impl ModelManager {
cleanup_legacy_moonshine_dir(&self.models_dir).await;
eprintln!(
- "sprout-desktop: STT model ready at {}",
+ "buzz-desktop: STT model ready at {}",
self.stt.model_dir(&self.models_dir).display()
);
Ok(())
@@ -743,10 +743,10 @@ impl ModelManager {
/// Download and verify the Pocket TTS model files from HuggingFace.
///
- /// Downloads files into `~/.sprout/models/pocket-tts/`:
+ /// Downloads files into `~/.buzz/models/pocket-tts/`:
/// - five ONNX sessions (Pocket TTS + Mimi codec)
/// - `vocab.json` / `token_scores.json` for sherpa-onnx text conditioning
- /// - upstream `LICENSE` plus Sprout's `MODEL_LICENSE.txt` attribution sidecar
+ /// - upstream `LICENSE` plus Buzz's `MODEL_LICENSE.txt` attribution sidecar
/// - `reference_sample.wav` as the bundled default voice
///
/// Files are written to a temp directory first, then moved atomically.
@@ -776,7 +776,7 @@ impl ModelManager {
let total_files = downloads.len() as u32;
for (i, (url, filename)) in downloads.iter().enumerate() {
- eprintln!("sprout-desktop: downloading Pocket TTS {filename} from {url}");
+ eprintln!("buzz-desktop: downloading Pocket TTS {filename} from {url}");
let response = fetch_url(&http_client, url, filename)
.await
@@ -810,7 +810,7 @@ impl ModelManager {
.inspect_err(|_| {
let _ = std::fs::remove_dir_all(&temp_dir);
})?;
- eprintln!("sprout-desktop: downloaded {bytes} bytes ({filename}), wrote to disk");
+ eprintln!("buzz-desktop: downloaded {bytes} bytes ({filename}), wrote to disk");
let expected = TTS_FILE_HASHES
.iter()
@@ -850,7 +850,7 @@ impl ModelManager {
}
eprintln!(
- "sprout-desktop: Pocket TTS model ready at {}",
+ "buzz-desktop: Pocket TTS model ready at {}",
self.tts.model_dir(&self.models_dir).display()
);
Ok(())
@@ -882,7 +882,7 @@ pub fn is_stt_ready() -> bool {
/// Best-effort cleanup of the legacy Moonshine STT model directory.
///
-/// Removes `~/.sprout/models/moonshine-tiny/` if present (~70 MB on disk).
+/// Removes `~/.buzz/models/moonshine-tiny/` if present (~70 MB on disk).
/// Idempotent — no-op if the directory is absent. Errors are logged and
/// swallowed; the leftover is harmless and the user can remove it manually.
///
@@ -897,11 +897,11 @@ async fn cleanup_legacy_moonshine_dir(models_dir: &Path) {
}
match tokio::fs::remove_dir_all(&legacy).await {
Ok(()) => eprintln!(
- "sprout-desktop: removed legacy STT model dir {}",
+ "buzz-desktop: removed legacy STT model dir {}",
legacy.display()
),
Err(e) => eprintln!(
- "sprout-desktop: could not remove legacy STT model dir {}: {e} \
+ "buzz-desktop: could not remove legacy STT model dir {}: {e} \
(harmless — remove manually to reclaim disk space)",
legacy.display()
),
diff --git a/desktop/src-tauri/src/huddle/pipeline.rs b/desktop/src-tauri/src/huddle/pipeline.rs
index 73642cb1a..bcb6e5ea5 100644
--- a/desktop/src-tauri/src/huddle/pipeline.rs
+++ b/desktop/src-tauri/src/huddle/pipeline.rs
@@ -60,10 +60,10 @@ pub(crate) async fn post_connect_setup(
// Start pipelines: TTS first (so STT can capture tts_cancel for barge-in).
if let Err(e) = maybe_start_tts_pipeline(state).await {
- eprintln!("sprout-desktop: TTS pipeline failed to start: {e}");
+ eprintln!("buzz-desktop: TTS pipeline failed to start: {e}");
}
if let Err(e) = maybe_start_stt_pipeline(state, ephemeral_channel_id).await {
- eprintln!("sprout-desktop: STT pipeline failed to start: {e}");
+ eprintln!("buzz-desktop: STT pipeline failed to start: {e}");
}
Ok(())
@@ -273,14 +273,14 @@ pub(crate) fn spawn_transcription_task(
match events::build_message(channel_uuid, &t, None, &p_tags, &[], &[], &[]) {
Ok(b) => b,
Err(e) => {
- eprintln!("sprout-desktop: STT build_message: {e}");
+ eprintln!("buzz-desktop: STT build_message: {e}");
continue;
}
};
let event = match builder.sign_with_keys(&keys) {
Ok(e) => e,
Err(e) => {
- eprintln!("sprout-desktop: STT sign event: {e}");
+ eprintln!("buzz-desktop: STT sign event: {e}");
continue;
}
};
@@ -294,7 +294,7 @@ pub(crate) fn spawn_transcription_task(
) {
Ok(h) => h,
Err(e) => {
- eprintln!("sprout-desktop: STT NIP-98 auth: {e}");
+ eprintln!("buzz-desktop: STT NIP-98 auth: {e}");
continue;
}
};
@@ -311,12 +311,12 @@ pub(crate) fn spawn_transcription_task(
Ok(resp) if resp.status().is_success() => {}
Ok(resp) => {
eprintln!(
- "sprout-desktop: STT kind:9 post failed: HTTP {}",
+ "buzz-desktop: STT kind:9 post failed: HTTP {}",
resp.status()
);
}
Err(e) => {
- eprintln!("sprout-desktop: STT kind:9 post failed: {e}");
+ eprintln!("buzz-desktop: STT kind:9 post failed: {e}");
}
}
}
diff --git a/desktop/src-tauri/src/huddle/playout.rs b/desktop/src-tauri/src/huddle/playout.rs
index ffdfc7bfb..69548bcfc 100644
--- a/desktop/src-tauri/src/huddle/playout.rs
+++ b/desktop/src-tauri/src/huddle/playout.rs
@@ -98,7 +98,7 @@ impl PeerSlot {
last_packet_at: tokio::time::Instant::now(),
}),
Err(e) => {
- eprintln!("sprout-desktop: jitter buffer init peer {peer_idx}: {e}");
+ eprintln!("buzz-desktop: jitter buffer init peer {peer_idx}: {e}");
None
}
}
@@ -194,7 +194,7 @@ pub(crate) async fn run_playout_recv_loop(
// queue grow without bound.
if slot.player.len() >= PLAYOUT_QUEUE_HIGH_WATER {
eprintln!(
- "sprout-desktop: playout queue high-water for peer {peer_idx} \
+ "buzz-desktop: playout queue high-water for peer {peer_idx} \
(depth={}) — dropping oldest frame",
slot.player.len(),
);
@@ -204,7 +204,7 @@ pub(crate) async fn run_playout_recv_loop(
}
Err(e) => {
eprintln!(
- "sprout-desktop: jitter get_audio peer {peer_idx}: {e}"
+ "buzz-desktop: jitter get_audio peer {peer_idx}: {e}"
);
}
}
@@ -237,7 +237,7 @@ pub(crate) async fn run_playout_recv_loop(
// the slice is too short, which `if data.len() <= ...`
// already guards. Defensive log + drop.
eprintln!(
- "sprout-desktop: dropping malformed audio frame from peer {peer_idx} ({} bytes)",
+ "buzz-desktop: dropping malformed audio frame from peer {peer_idx} ({} bytes)",
data.len(),
);
continue;
@@ -281,7 +281,7 @@ pub(crate) async fn run_playout_recv_loop(
.insert_packet(header.seq, header.ts_48k, opus_bytes)
{
eprintln!(
- "sprout-desktop: jitter insert peer {peer_idx}: {err}"
+ "buzz-desktop: jitter insert peer {peer_idx}: {err}"
);
} else {
// Heartbeat for the playout tick's idle-peer
diff --git a/desktop/src-tauri/src/huddle/pocket.rs b/desktop/src-tauri/src/huddle/pocket.rs
index a0639802d..73d40f4f1 100644
--- a/desktop/src-tauri/src/huddle/pocket.rs
+++ b/desktop/src-tauri/src/huddle/pocket.rs
@@ -23,7 +23,7 @@
//! in . CC-BY-4.0, base recording
//! from the VCTK corpus, enhanced by ai-coustics.
//!
-//! Sprout ships these files unmodified; see the on-disk `MODEL_LICENSE.txt`
+//! Buzz ships these files unmodified; see the on-disk `MODEL_LICENSE.txt`
//! sidecar written by `huddle::models` during install for the canonical
//! CC-BY-4.0 §3(a)(1) attribution block.
//!
@@ -539,7 +539,7 @@ impl PocketTts {
let sample_rate = audio.sample_rate();
if sample_rate != SAMPLE_RATE as i32 {
eprintln!(
- "sprout-desktop: Pocket TTS returned unexpected sample rate {sample_rate}Hz \
+ "buzz-desktop: Pocket TTS returned unexpected sample rate {sample_rate}Hz \
(expected {SAMPLE_RATE}Hz); playback speed may be wrong"
);
}
diff --git a/desktop/src-tauri/src/huddle/relay_api.rs b/desktop/src-tauri/src/huddle/relay_api.rs
index e840d24f6..eb3fea92d 100644
--- a/desktop/src-tauri/src/huddle/relay_api.rs
+++ b/desktop/src-tauri/src/huddle/relay_api.rs
@@ -183,7 +183,7 @@ pub(crate) async fn connect_audio_relay(
})
.await
{
- eprintln!("sprout-desktop: audio relay pipeline exited: {e}");
+ eprintln!("buzz-desktop: audio relay pipeline exited: {e}");
}
// Only emit the disconnect event for UNEXPECTED exits.
@@ -292,7 +292,7 @@ async fn audio_relay_pipeline(args: AudioRelayPipelineArgs) -> Result<(), String
let n = match encode_result {
Ok(n) => n,
Err(e) => {
- eprintln!("sprout-desktop: opus encode error: {e}");
+ eprintln!("buzz-desktop: opus encode error: {e}");
continue;
}
};
@@ -363,7 +363,7 @@ pub(crate) async fn fetch_channel_members_with_roles(
let events = query_relay(state, std::slice::from_ref(&filter))
.await
.map_err(|e| {
- eprintln!("sprout-desktop: fetch channel members failed: {e}");
+ eprintln!("buzz-desktop: fetch channel members failed: {e}");
e
})?;
diff --git a/desktop/src-tauri/src/huddle/stt.rs b/desktop/src-tauri/src/huddle/stt.rs
index 50ec6e819..6f502ca72 100644
--- a/desktop/src-tauri/src/huddle/stt.rs
+++ b/desktop/src-tauri/src/huddle/stt.rs
@@ -216,7 +216,7 @@ fn stt_worker(
let mut resampler = match Fft::::new(48_000, 16_000, 1024, 2, 1, FixedSync::Input) {
Ok(r) => r,
Err(e) => {
- eprintln!("sprout-desktop: STT resampler init failed: {e}");
+ eprintln!("buzz-desktop: STT resampler init failed: {e}");
return;
}
};
@@ -239,7 +239,7 @@ fn stt_worker(
let model_path = model_dir.join("model.int8.onnx");
if !tokens_path.exists() || !model_path.exists() {
eprintln!(
- "sprout-desktop: STT model not found at {} — STT disabled",
+ "buzz-desktop: STT model not found at {} — STT disabled",
model_dir.display()
);
drain_until_shutdown(audio_rx, &shutdown);
@@ -257,7 +257,7 @@ fn stt_worker(
let recognizer = match OfflineRecognizer::create(&cfg) {
Some(r) => r,
None => {
- eprintln!("sprout-desktop: OfflineRecognizer::create returned None — STT disabled");
+ eprintln!("buzz-desktop: OfflineRecognizer::create returned None — STT disabled");
drain_until_shutdown(audio_rx, &shutdown);
return;
}
@@ -369,7 +369,7 @@ fn resample_chunk(resampler: &mut rubato::Fft, chunk_48k: &[f32]) -> Vec a,
Err(e) => {
- eprintln!("sprout-desktop: STT resample input error: {e}");
+ eprintln!("buzz-desktop: STT resample input error: {e}");
return Vec::new();
}
};
@@ -377,7 +377,7 @@ fn resample_chunk(resampler: &mut rubato::Fft, chunk_48k: &[f32]) -> Vec out.take_data(),
Err(e) => {
- eprintln!("sprout-desktop: STT resample error: {e}");
+ eprintln!("buzz-desktop: STT resample error: {e}");
Vec::new()
}
}
@@ -545,7 +545,7 @@ fn flush_to_stt(
if !text.is_empty() {
if let Err(e) = text_tx.blocking_send(text) {
- eprintln!("sprout-desktop: STT text channel closed: {e}");
+ eprintln!("buzz-desktop: STT text channel closed: {e}");
}
}
}
diff --git a/desktop/src-tauri/src/huddle/tts.rs b/desktop/src-tauri/src/huddle/tts.rs
index 21fbb94ea..482f01010 100644
--- a/desktop/src-tauri/src/huddle/tts.rs
+++ b/desktop/src-tauri/src/huddle/tts.rs
@@ -208,7 +208,7 @@ impl TtsPipeline {
/// `TEXT_QUEUE_DEPTH`) — caller may log and discard.
pub fn speak(&self, text: String) -> Result<(), String> {
self.text_tx.try_send(text).map_err(|e| {
- eprintln!("sprout-desktop: TTS queue saturated, dropping message: {e}");
+ eprintln!("buzz-desktop: TTS queue saturated, dropping message: {e}");
format!("TTS queue full, dropping: {e}")
})
}
@@ -254,7 +254,7 @@ fn tts_worker(
Ok(e) => e,
Err(e) => {
eprintln!(
- "sprout-desktop: TTS engine init failed (model_dir={}): {e}. TTS disabled.",
+ "buzz-desktop: TTS engine init failed (model_dir={}): {e}. TTS disabled.",
model_dir.display()
);
drain_until_shutdown(text_rx, &shutdown);
@@ -268,7 +268,7 @@ fn tts_worker(
Ok(s) => s,
Err(e) => {
eprintln!(
- "sprout-desktop: TTS voice style load failed ({voice_name}): {e}. TTS disabled."
+ "buzz-desktop: TTS voice style load failed ({voice_name}): {e}. TTS disabled."
);
drain_until_shutdown(text_rx, &shutdown);
return;
@@ -284,11 +284,11 @@ fn tts_worker(
let t = std::time::Instant::now();
match engine.synth_chunk("warmup", "en", &style, SYNTH_STEPS, SYNTH_SPEED) {
Ok(_) => eprintln!(
- "sprout-desktop: TTS warmup completed in {:.0}ms",
+ "buzz-desktop: TTS warmup completed in {:.0}ms",
t.elapsed().as_millis()
),
Err(e) => eprintln!(
- "sprout-desktop: TTS warmup failed after {:.0}ms: {e} — first utterance may be slow",
+ "buzz-desktop: TTS warmup failed after {:.0}ms: {e} — first utterance may be slow",
t.elapsed().as_millis()
),
}
@@ -301,7 +301,7 @@ fn tts_worker(
{
Ok(h) => h,
Err(e) => {
- eprintln!("sprout-desktop: TTS audio output failed: {e}. TTS disabled.");
+ eprintln!("buzz-desktop: TTS audio output failed: {e}. TTS disabled.");
drain_until_shutdown(text_rx, &shutdown);
return;
}
@@ -373,14 +373,14 @@ fn tts_worker(
let channels = match NonZero::new(1u16) {
Some(c) => c,
None => {
- eprintln!("sprout-desktop: TTS channel count invariant violated");
+ eprintln!("buzz-desktop: TTS channel count invariant violated");
break;
}
};
let rate = match NonZero::new(SAMPLE_RATE) {
Some(r) => r,
None => {
- eprintln!("sprout-desktop: TTS sample rate invariant violated");
+ eprintln!("buzz-desktop: TTS sample rate invariant violated");
break;
}
};
@@ -432,7 +432,7 @@ fn tts_worker(
}
Ok(_) => {}
Err(e) => {
- eprintln!("sprout-desktop: TTS synth failed: {e}");
+ eprintln!("buzz-desktop: TTS synth failed: {e}");
}
}
}
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 8794e94e8..e98c86696 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -233,13 +233,13 @@ fn shutdown_managed_agents(app: &tauri::AppHandle) -> Result<(), String> {
// All tracked PIDs have already been killed above, so pass an empty skip list.
managed_agents::sweep_orphaned_agent_processes(app, &[]);
- // System-wide sweep: agent workers (goose, sprout-agent, etc.) are spawned
- // in their own process groups by sprout-acp, so group-kills above only
+ // System-wide sweep: agent workers (goose, buzz-agent, etc.) are spawned
+ // in their own process groups by buzz-acp, so group-kills above only
// reach the harness, not the workers. Scan all user processes and kill any
// known agent binaries that are still running.
managed_agents::sweep_system_agent_processes(&managed_agents::current_instance_id(app), &[]);
- // Dead-instance reaping: find agents belonging to Sprout instances
+ // Dead-instance reaping: find agents belonging to Buzz instances
// whose desktop process is no longer running and reap them.
managed_agents::reap_dead_instance_agents(&managed_agents::current_instance_id(app), &[]);
@@ -282,7 +282,7 @@ fn parse_message_deep_link(url: &Url) -> Option {
}))
}
-/// Handle an incoming `buzz://` deep link URL, with `sprout://` accepted as a legacy alias.
+/// Handle an incoming `buzz://` deep link URL.
///
/// Currently supports:
/// - `buzz://connect?relay=` — emits `deep-link-connect` to the frontend
@@ -290,13 +290,13 @@ fn handle_deep_link_url(app: &tauri::AppHandle, url_str: &str) {
let url = match Url::parse(url_str) {
Ok(u) => u,
Err(e) => {
- eprintln!("sprout-desktop: invalid deep link URL {url_str:?}: {e}");
+ eprintln!("buzz-desktop: invalid deep link URL {url_str:?}: {e}");
return;
}
};
- if url.scheme() != "sprout" && url.scheme() != "buzz" {
- eprintln!("sprout-desktop: ignoring unsupported deep link scheme: {url_str}");
+ if url.scheme() != "buzz" {
+ eprintln!("buzz-desktop: ignoring unsupported deep link scheme: {url_str}");
return;
}
@@ -307,7 +307,7 @@ fn handle_deep_link_url(app: &tauri::AppHandle, url_str: &str) {
.find(|(k, _)| k == "relay")
.map(|(_, v)| v.into_owned());
let Some(relay_url) = relay else {
- eprintln!("sprout-desktop: connect deep link missing relay param: {url_str}");
+ eprintln!("buzz-desktop: connect deep link missing relay param: {url_str}");
return;
};
// Validate the relay URL is ws:// or wss://
@@ -315,13 +315,13 @@ fn handle_deep_link_url(app: &tauri::AppHandle, url_str: &str) {
Ok(parsed) if parsed.scheme() == "ws" || parsed.scheme() == "wss" => {}
Ok(parsed) => {
eprintln!(
- "sprout-desktop: rejecting non-websocket relay URL scheme {:?}: {relay_url}",
+ "buzz-desktop: rejecting non-websocket relay URL scheme {:?}: {relay_url}",
parsed.scheme()
);
return;
}
Err(e) => {
- eprintln!("sprout-desktop: invalid relay URL {relay_url:?}: {e}");
+ eprintln!("buzz-desktop: invalid relay URL {relay_url:?}: {e}");
return;
}
}
@@ -337,16 +337,16 @@ fn handle_deep_link_url(app: &tauri::AppHandle, url_str: &str) {
// structure on this side (serde JSON) and let the TS code own
// any further normalisation.
let Some(payload) = parse_message_deep_link(&url) else {
- eprintln!("sprout-desktop: message deep link missing channel or id: {url_str}");
+ eprintln!("buzz-desktop: message deep link missing channel or id: {url_str}");
return;
};
let _ = app.emit("deep-link-message", payload);
}
Some(action) => {
- eprintln!("sprout-desktop: unknown deep link action: {action}");
+ eprintln!("buzz-desktop: unknown deep link action: {action}");
}
None => {
- eprintln!("sprout-desktop: deep link missing action: {url_str}");
+ eprintln!("buzz-desktop: deep link missing action: {url_str}");
}
}
}
@@ -377,7 +377,7 @@ pub fn run() {
}
// Forward any deep link URLs from the duplicate launch.
for arg in &argv {
- if arg.starts_with("sprout://") || arg.starts_with("buzz://") {
+ if arg.starts_with("buzz://") {
handle_deep_link_url(app, arg);
}
}
@@ -494,23 +494,23 @@ pub fn run() {
// Only register the updater in release builds that were compiled with a
// real updater configuration. Local unsigned builds omit that config and
// should still launch for debugging.
- #[cfg(sprout_updater_enabled)]
+ #[cfg(buzz_updater_enabled)]
let builder = if cfg!(debug_assertions) {
builder
} else {
builder.plugin(tauri_plugin_updater::Builder::new().build())
};
- #[cfg(not(sprout_updater_enabled))]
+ #[cfg(not(buzz_updater_enabled))]
let builder = builder;
let shutdown_started = Arc::new(AtomicBool::new(false));
let restore_shutdown_started = Arc::clone(&shutdown_started);
let app = builder
- .register_asynchronous_uri_scheme_protocol("sprout-media", |ctx, request, responder| {
+ .register_asynchronous_uri_scheme_protocol("buzz-media", |ctx, request, responder| {
let app = ctx.app_handle().clone();
tauri::async_runtime::spawn(async move {
- let response = media_proxy::handle_sprout_media(&app, &request).await;
+ let response = media_proxy::handle_buzz_media(&app, &request).await;
responder.respond(response);
});
})
@@ -520,6 +520,10 @@ pub fn run() {
let app_handle = app.handle().clone();
let shutdown_started = Arc::clone(&restore_shutdown_started);
+ // Copy legacy app data into the Buzz app data directory
+ // before any state is loaded from disk.
+ migration::migrate_legacy_app_data_dir(&app_handle);
+
// Sync shared agent data from the canonical dev data directory to
// this worktree's data directory. Must run before
// restore_managed_agents_on_launch (which reads managed-agents.json).
@@ -530,7 +534,7 @@ pub fn run() {
migration::migrate_persona_provider_to_runtime(&app_handle);
if let Err(e) = managed_agents::sync_team_personas(&app_handle) {
- eprintln!("sprout-desktop: sync-team-personas: {e}");
+ eprintln!("buzz-desktop: sync-team-personas: {e}");
}
// Resolve persisted identity key (env var → file → generate+save).
@@ -574,19 +578,19 @@ pub fn run() {
.store(port, std::sync::atomic::Ordering::Relaxed);
});
- // Create the Sprout nest (~/.sprout) before agents are restored,
+ // Create the Buzz nest (~/.buzz) before agents are restored,
// so default_agent_workdir() resolves to the nest directory.
// Non-fatal: agents fall back to $HOME if nest creation fails.
if let Err(error) = ensure_nest() {
- eprintln!("sprout-desktop: failed to create nest: {error}");
+ eprintln!("buzz-desktop: failed to create nest: {error}");
}
- // Create/update ~/.local/bin/sprout symlink pointing to the
+ // Create/update the local CLI symlink pointing to the
// bundled CLI binary. Non-fatal: agents find CLI via PATH.
if let Ok(exe) = std::env::current_exe() {
if let Some(parent) = exe.parent() {
if let Err(error) = managed_agents::ensure_cli_symlink(parent) {
- eprintln!("sprout-desktop: failed to create CLI symlink: {error}");
+ eprintln!("buzz-desktop: failed to create CLI symlink: {error}");
}
}
}
@@ -604,7 +608,7 @@ pub fn run() {
use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, Modifiers, Shortcut};
let shortcut = Shortcut::new(Some(Modifiers::CONTROL), Code::Space);
if let Err(e) = app.handle().global_shortcut().register(shortcut) {
- eprintln!("sprout-desktop: failed to register PTT shortcut: {e}");
+ eprintln!("buzz-desktop: failed to register PTT shortcut: {e}");
}
}
@@ -628,7 +632,7 @@ pub fn run() {
if let Err(error) =
restore_managed_agents_on_launch(&app_handle, shutdown_started.as_ref()).await
{
- eprintln!("sprout-desktop: failed to restore managed agents: {error}");
+ eprintln!("buzz-desktop: failed to restore managed agents: {error}");
}
});
@@ -855,7 +859,7 @@ pub fn run() {
}
std::process::exit(0);
}) {
- eprintln!("sprout-desktop: failed to register signal handler: {e}");
+ eprintln!("buzz-desktop: failed to register signal handler: {e}");
}
}
@@ -866,7 +870,7 @@ pub fn run() {
if !run_shutdown_done.swap(true, Ordering::SeqCst) {
prevent_sleep::release(&app_handle.state::().prevent_sleep);
if let Err(error) = shutdown_managed_agents(app_handle) {
- eprintln!("sprout-desktop: failed to stop managed agents: {error}");
+ eprintln!("buzz-desktop: failed to stop managed agents: {error}");
}
}
}
@@ -905,7 +909,7 @@ mod tests {
#[test]
fn parse_message_deep_link_extracts_required_params() {
- let url = Url::parse("sprout://message?channel=abc&id=xyz").unwrap();
+ let url = Url::parse("buzz://message?channel=abc&id=xyz").unwrap();
let payload = parse_message_deep_link(&url).expect("required params present");
assert_eq!(payload["channelId"], "abc");
assert_eq!(payload["messageId"], "xyz");
@@ -922,33 +926,33 @@ mod tests {
#[test]
fn parse_message_deep_link_includes_thread_root() {
- let url = Url::parse("sprout://message?channel=abc&id=xyz&thread=root1").unwrap();
+ let url = Url::parse("buzz://message?channel=abc&id=xyz&thread=root1").unwrap();
let payload = parse_message_deep_link(&url).expect("required params present");
assert_eq!(payload["threadRootId"], "root1");
}
#[test]
fn parse_message_deep_link_rejects_missing_id() {
- let url = Url::parse("sprout://message?channel=abc").unwrap();
+ let url = Url::parse("buzz://message?channel=abc").unwrap();
assert!(parse_message_deep_link(&url).is_none());
}
#[test]
fn parse_message_deep_link_rejects_empty_channel() {
// Regression: `channel=&id=foo` previously produced channelId: "".
- let url = Url::parse("sprout://message?channel=&id=foo").unwrap();
+ let url = Url::parse("buzz://message?channel=&id=foo").unwrap();
assert!(parse_message_deep_link(&url).is_none());
}
#[test]
fn parse_message_deep_link_rejects_empty_id() {
- let url = Url::parse("sprout://message?channel=abc&id=").unwrap();
+ let url = Url::parse("buzz://message?channel=abc&id=").unwrap();
assert!(parse_message_deep_link(&url).is_none());
}
#[test]
fn parse_message_deep_link_treats_empty_thread_as_absent() {
- let url = Url::parse("sprout://message?channel=abc&id=xyz&thread=").unwrap();
+ let url = Url::parse("buzz://message?channel=abc&id=xyz&thread=").unwrap();
let payload = parse_message_deep_link(&url).expect("required params present");
assert!(payload["threadRootId"].is_null());
}
diff --git a/desktop/src-tauri/src/main.rs b/desktop/src-tauri/src/main.rs
index 0488c8271..13cb6c1b7 100644
--- a/desktop/src-tauri/src/main.rs
+++ b/desktop/src-tauri/src/main.rs
@@ -2,5 +2,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
- sprout_lib::run()
+ buzz_lib::run()
}
diff --git a/desktop/src-tauri/src/managed_agents/backend.rs b/desktop/src-tauri/src/managed_agents/backend.rs
index 8ee8d16f9..0eada757d 100644
--- a/desktop/src-tauri/src/managed_agents/backend.rs
+++ b/desktop/src-tauri/src/managed_agents/backend.rs
@@ -408,10 +408,10 @@ pub fn validate_provider_config(config: &serde_json::Value) -> Result<(), String
Ok(())
}
-/// Enumerate PATH for sprout-backend-* executables. Returns (id, path) pairs.
+/// Enumerate PATH for buzz-backend-* executables. Returns (id, path) pairs.
/// Only includes files that are executable. Does NOT execute any binaries.
pub fn discover_provider_candidates() -> Vec<(String, PathBuf)> {
- let prefix = "sprout-backend-";
+ let prefix = "buzz-backend-";
let mut seen = std::collections::HashSet::new();
let mut results = Vec::new();
@@ -441,7 +441,7 @@ pub fn discover_provider_candidates() -> Vec<(String, PathBuf)> {
/// 3. Returns the canonical path of the discovered binary
///
/// All deploy, start, and create paths MUST use this instead of raw
-/// `resolve_command(format!("sprout-backend-{id}"))` to prevent a compromised
+/// `resolve_command(format!("buzz-backend-{id}"))` to prevent a compromised
/// frontend/IPC caller from steering execution to an arbitrary binary.
pub fn resolve_provider_binary(provider_id: &str) -> Result {
// Reject IDs that could be path components or shell metacharacters.
@@ -467,7 +467,7 @@ pub fn resolve_provider_binary(provider_id: &str) -> Result {
.canonicalize()
.map_err(|e| format!("provider binary not accessible: {e}")),
None => Err(format!(
- "provider 'sprout-backend-{provider_id}' not found on PATH"
+ "provider 'buzz-backend-{provider_id}' not found on PATH"
)),
}
}
diff --git a/desktop/src-tauri/src/managed_agents/discovery.rs b/desktop/src-tauri/src/managed_agents/discovery.rs
index 3e6e9f330..88f5c2d6a 100644
--- a/desktop/src-tauri/src/managed_agents/discovery.rs
+++ b/desktop/src-tauri/src/managed_agents/discovery.rs
@@ -11,7 +11,7 @@ pub(crate) struct KnownAcpRuntime {
pub commands: &'static [&'static str],
pub aliases: &'static [&'static str],
pub avatar_url: &'static str,
- /// Legacy MCP server binary field. Vestigial — all agents now use sprout CLI
+ /// Legacy MCP server binary field. Vestigial — all agents now use the bundled CLI.
/// directly. Will be removed when runtime discovery is simplified.
pub mcp_command: Option<&'static str>,
/// Whether to enable MCP hook tools (`_Stop`, `_PostCompact`) for this agent.
@@ -29,8 +29,8 @@ pub(crate) struct KnownAcpRuntime {
/// Human-readable hint about installing the ACP adapter.
pub adapter_install_hint: &'static str,
/// Harness-specific skill discovery directory (e.g. `.goose/skills`).
- /// `Some(dir)` → Sprout creates a symlink at `//sprout-cli`
- /// pointing to the canonical `.agents/skills/sprout-cli`. `None` → this
+ /// `Some(dir)` → Buzz creates a symlink at `//buzz-cli`
+ /// pointing to the canonical `.agents/skills/buzz-cli`. `None` → this
/// runtime reads the canonical path directly or has no skill support.
pub skill_dir: Option<&'static str>,
/// Whether this runtime handles model switching via ACP protocol natively.
@@ -47,8 +47,8 @@ pub(crate) struct KnownAcpRuntime {
const GOOSE_AVATAR_URL: &str = "https://goose-docs.ai/img/logo_dark.png";
const CLAUDE_CODE_AVATAR_URL: &str = "https://anthropic.gallerycdn.vsassets.io/extensions/anthropic/claude-code/2.1.77/1773707456892/Microsoft.VisualStudio.Services.Icons.Default";
const CODEX_AVATAR_URL: &str = "https://openai.gallerycdn.vsassets.io/extensions/openai/chatgpt/26.5313.41514/1773706730621/Microsoft.VisualStudio.Services.Icons.Default";
-const SPROUT_AGENT_AVATAR_URL: &str =
- "https://raw.githubusercontent.com/block/sprout/refs/heads/main/crates/sprout-agent/sprout-agent.png";
+const BUZZ_AGENT_AVATAR_URL: &str =
+ "https://raw.githubusercontent.com/block/buzz/refs/heads/main/crates/buzz-agent/buzz-agent.png";
fn common_binary_paths() -> &'static [PathBuf] {
use std::sync::OnceLock;
@@ -137,18 +137,18 @@ const KNOWN_ACP_RUNTIMES: &[KnownAcpRuntime] = &[
default_env: &[],
},
KnownAcpRuntime {
- id: "sprout-agent",
- label: "Sprout Agent",
- commands: &["sprout-agent"],
+ id: "buzz-agent",
+ label: "Buzz Agent",
+ commands: &["buzz-agent"],
aliases: &[],
- avatar_url: SPROUT_AGENT_AVATAR_URL,
- mcp_command: Some("sprout-dev-mcp"),
+ avatar_url: BUZZ_AGENT_AVATAR_URL,
+ mcp_command: Some("buzz-dev-mcp"),
mcp_hooks: true,
underlying_cli: None,
cli_install_commands: &[],
adapter_install_commands: &[],
- install_instructions_url: "https://github.com/block/sprout",
- cli_install_hint: "Ships with the Sprout desktop app.",
+ install_instructions_url: "https://github.com/block/buzz",
+ cli_install_hint: "Ships with the Buzz desktop app.",
adapter_install_hint: "",
skill_dir: None,
supports_acp_model_switching: true,
@@ -232,7 +232,7 @@ fn default_agent_args(command: &str) -> Option> {
match normalize_command_identity(command).as_str() {
"goose" => Some(vec!["acp".to_string()]),
"codex" | "codex-acp" | "claude-agent-acp" | "claude-code-acp" | "claude-code"
- | "claudecode" | "sprout-agent" => Some(Vec::new()),
+ | "claudecode" | "buzz-agent" => Some(Vec::new()),
_ => None,
}
}
@@ -288,17 +288,37 @@ fn command_search_dirs() -> Vec {
unique
}
+fn is_executable_file(path: &Path) -> bool {
+ let Ok(metadata) = path.metadata() else {
+ return false;
+ };
+ if !metadata.is_file() {
+ return false;
+ }
+
+ #[cfg(unix)]
+ {
+ use std::os::unix::fs::PermissionsExt;
+ metadata.permissions().mode() & 0o111 != 0
+ }
+
+ #[cfg(not(unix))]
+ {
+ true
+ }
+}
+
fn resolve_workspace_command(command: &str) -> Option {
if command_looks_like_path(command) {
let path = PathBuf::from(command);
- return path.exists().then_some(path);
+ return is_executable_file(&path).then_some(path);
}
let file_name = executable_basename(command);
command_search_dirs()
.into_iter()
.map(|dir| dir.join(&file_name))
- .find(|candidate| candidate.exists())
+ .find(|candidate| is_executable_file(candidate))
}
fn resolve_cache() -> &'static std::sync::Mutex>>
@@ -351,7 +371,7 @@ fn resolve_command_uncached(command: &str) -> Option {
}
for candidate in path_candidates_from_env(command) {
- if candidate.exists() {
+ if is_executable_file(&candidate) {
return Some(candidate);
}
}
@@ -361,7 +381,7 @@ fn resolve_command_uncached(command: &str) -> Option {
}
for dir in common_binary_paths() {
let candidate = dir.join(executable_basename(command));
- if candidate.exists() {
+ if is_executable_file(&candidate) {
return Some(candidate);
}
}
@@ -401,7 +421,7 @@ fn find_via_login_shell(command: &str) -> Option {
let stdout = run_in_login_shell(&["-l", "-c", r#"command -v -- "$1""#, "_", command])?;
let resolved = stdout.lines().rfind(|line| !line.trim().is_empty())?;
let path = PathBuf::from(resolved.trim());
- (path.is_absolute() && path.exists()).then_some(path)
+ (path.is_absolute() && is_executable_file(&path)).then_some(path)
}
/// Return the user's full PATH from a login shell.
@@ -543,7 +563,7 @@ mod tests {
use super::{
classify_runtime, find_via_login_shell, managed_agent_avatar_url, normalize_agent_args,
- CLAUDE_CODE_AVATAR_URL, CODEX_AVATAR_URL, GOOSE_AVATAR_URL, SPROUT_AGENT_AVATAR_URL,
+ BUZZ_AGENT_AVATAR_URL, CLAUDE_CODE_AVATAR_URL, CODEX_AVATAR_URL, GOOSE_AVATAR_URL,
};
use crate::managed_agents::AcpAvailabilityStatus;
@@ -596,25 +616,25 @@ mod tests {
}
#[test]
- fn resolves_sprout_agent_avatar() {
+ fn resolves_buzz_agent_avatar() {
assert_eq!(
- managed_agent_avatar_url("sprout-agent"),
- Some(SPROUT_AGENT_AVATAR_URL.to_string())
+ managed_agent_avatar_url("buzz-agent"),
+ Some(BUZZ_AGENT_AVATAR_URL.to_string())
);
assert_eq!(
- managed_agent_avatar_url("/usr/local/bin/sprout-agent"),
- Some(SPROUT_AGENT_AVATAR_URL.to_string())
+ managed_agent_avatar_url("/usr/local/bin/buzz-agent"),
+ Some(BUZZ_AGENT_AVATAR_URL.to_string())
);
}
#[test]
- fn normalizes_sprout_agent_args_to_empty() {
+ fn normalizes_buzz_agent_args_to_empty() {
assert_eq!(
- normalize_agent_args("sprout-agent", Vec::new()),
+ normalize_agent_args("buzz-agent", Vec::new()),
Vec::::new()
);
assert_eq!(
- normalize_agent_args("sprout-agent", vec!["acp".into()]),
+ normalize_agent_args("buzz-agent", vec!["acp".into()]),
Vec::::new()
);
}
@@ -622,7 +642,7 @@ mod tests {
#[test]
fn login_shell_lookup_treats_command_as_data() {
let marker =
- std::env::temp_dir().join(format!("sprout-discovery-marker-{}", uuid::Uuid::new_v4()));
+ std::env::temp_dir().join(format!("buzz-discovery-marker-{}", uuid::Uuid::new_v4()));
let payload = format!("doesnotexist; touch {} #", marker.display());
let resolved = find_via_login_shell(&payload);
@@ -637,6 +657,34 @@ mod tests {
);
}
+ #[cfg(unix)]
+ #[test]
+ fn explicit_path_resolution_ignores_non_executable_files() {
+ use std::os::unix::fs::PermissionsExt;
+
+ let dir =
+ std::env::temp_dir().join(format!("buzz-discovery-path-{}", uuid::Uuid::new_v4()));
+ std::fs::create_dir_all(&dir).expect("create temp dir");
+ let bin = dir.join("buzz-acp");
+ std::fs::write(&bin, "").expect("write placeholder");
+ std::fs::set_permissions(&bin, std::fs::Permissions::from_mode(0o644))
+ .expect("chmod placeholder");
+
+ assert!(
+ super::resolve_workspace_command(bin.to_str().expect("utf8 path")).is_none(),
+ "non-executable placeholder must not resolve"
+ );
+
+ std::fs::set_permissions(&bin, std::fs::Permissions::from_mode(0o755))
+ .expect("chmod executable");
+ assert_eq!(
+ super::resolve_workspace_command(bin.to_str().expect("utf8 path")),
+ Some(bin.clone())
+ );
+
+ let _ = std::fs::remove_dir_all(dir);
+ }
+
#[test]
fn classifies_available_when_adapter_found() {
let (status, cmd, path) = classify_runtime(
diff --git a/desktop/src-tauri/src/managed_agents/env_vars.rs b/desktop/src-tauri/src/managed_agents/env_vars.rs
index 27bfe944e..979bbcde1 100644
--- a/desktop/src-tauri/src/managed_agents/env_vars.rs
+++ b/desktop/src-tauri/src/managed_agents/env_vars.rs
@@ -55,7 +55,7 @@ pub(crate) fn filter_derived_provider_model_env_vars(
.collect()
}
-/// Env var keys that Sprout sets itself and users must not override from
+/// Env var keys that Buzz sets itself and users must not override from
/// the persona/agent env_vars UI. Three categories:
///
/// 1. **Identity / secrets** — overriding would swap the agent's nsec or
@@ -107,8 +107,8 @@ pub(crate) fn is_reserved_env_key(key: &str) -> bool {
/// nit: Rust's `Command::env` will happily accept a key containing `=`
/// or whitespace and pass it straight into the child's environ block,
/// where `getenv("FOO")` then matches whatever comes after the first
-/// `=`. That means a key like `SPROUT_AUTH_TAG=x` with value `forged`
-/// lands as `SPROUT_AUTH_TAG=x=forged` in the child env and
+/// `=`. That means a key like `BUZZ_AUTH_TAG=x` with value `forged`
+/// lands as `BUZZ_AUTH_TAG=x=forged` in the child env and
/// `getenv("BUZZ_AUTH_TAG")` returns `"x=forged"` — a full reserved-
/// key bypass. Rejecting non-POSIX keys closes this hole at the
/// boundary where the input enters the system.
@@ -200,7 +200,7 @@ pub fn validate_user_env_keys(env_vars: &BTreeMap) -> Result<(),
reserved.dedup();
if !reserved.is_empty() {
return Err(format!(
- "the following env vars are reserved by Sprout and cannot be overridden: {}",
+ "the following env vars are reserved by Buzz and cannot be overridden: {}",
reserved.join(", ")
));
}
@@ -260,7 +260,7 @@ pub(crate) fn merged_user_env(
merged.retain(|k, v| {
if is_reserved_env_key(k) {
eprintln!(
- "sprout-desktop: ignoring reserved env var `{k}` from persona/agent overrides"
+ "buzz-desktop: ignoring reserved env var `{k}` from persona/agent overrides"
);
return false;
}
@@ -270,7 +270,7 @@ pub(crate) fn merged_user_env(
// smuggle a reserved key past us via `=`-in-key tricks. See
// `is_well_formed_env_key` for the exploit.
eprintln!(
- "sprout-desktop: ignoring malformed env var key `{}` from persona/agent overrides",
+ "buzz-desktop: ignoring malformed env var key `{}` from persona/agent overrides",
display_invalid_key(k)
);
return false;
@@ -280,13 +280,13 @@ pub(crate) fn merged_user_env(
// have escaped the value validator; drop them here rather
// than crash the spawn. We deliberately do NOT log the value.
eprintln!(
- "sprout-desktop: ignoring env var `{k}` with NUL byte in value"
+ "buzz-desktop: ignoring env var `{k}` with NUL byte in value"
);
return false;
}
if v.len() > MAX_ENV_VALUE_BYTES {
eprintln!(
- "sprout-desktop: ignoring env var `{k}` with oversize value ({} bytes > {MAX_ENV_VALUE_BYTES})",
+ "buzz-desktop: ignoring env var `{k}` with oversize value ({} bytes > {MAX_ENV_VALUE_BYTES})",
v.len()
);
return false;
diff --git a/desktop/src-tauri/src/managed_agents/env_vars/tests.rs b/desktop/src-tauri/src/managed_agents/env_vars/tests.rs
index 9b0d56ade..f4f55c206 100644
--- a/desktop/src-tauri/src/managed_agents/env_vars/tests.rs
+++ b/desktop/src-tauri/src/managed_agents/env_vars/tests.rs
@@ -161,7 +161,7 @@ fn reserved_keys_include_respond_to_gate() {
#[test]
fn reserved_keys_include_code_execution_surface() {
- // The agent/MCP command + args are what Sprout actually exec's.
+ // The agent/MCP command + args are what Buzz actually exec's.
// Overriding lets the user run arbitrary code as the agent.
for key in [
"BUZZ_ACP_AGENT_COMMAND",
diff --git a/desktop/src-tauri/src/managed_agents/mod.rs b/desktop/src-tauri/src/managed_agents/mod.rs
index 263ee7d26..f10376a27 100644
--- a/desktop/src-tauri/src/managed_agents/mod.rs
+++ b/desktop/src-tauri/src/managed_agents/mod.rs
@@ -29,12 +29,12 @@ pub use team_repair::sync_team_personas;
pub use teams::*;
pub use types::*;
-/// Returns the Sprout nest directory (`~/.sprout`) if it exists as a real
+/// Returns the Buzz nest directory (`~/.buzz`) if it exists as a real
/// directory (not a symlink), falling back to the user's home directory.
///
/// Used as the default working directory for spawned agent processes.
/// `ensure_nest()` must be called during app setup before this is first
-/// invoked, so that `~/.sprout` exists and gets cached.
+/// invoked, so that `~/.buzz` exists and gets cached.
///
/// Cached for the process lifetime via `OnceLock`.
/// Returns `None` in sandboxed/containerized environments where `$HOME` is
@@ -45,7 +45,7 @@ pub fn default_agent_workdir() -> Option {
static WORKDIR: OnceLock> = OnceLock::new();
WORKDIR
.get_or_init(|| {
- // Prefer ~/.sprout if it exists (created by ensure_nest()).
+ // Prefer ~/.buzz if it exists (created by ensure_nest()).
// Reject symlinks to prevent redirect attacks — is_dir()
// follows symlinks, so check symlink_metadata() first.
// Fall back to $HOME for resilience.
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index 2f300b62a..8b1f3c62d 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -1,7 +1,7 @@
-//! Sprout Nest — persistent agent workspace at `~/.sprout`.
+//! Buzz Nest — persistent agent workspace at `~/.buzz`.
//!
//! Creates a shared knowledge directory on first launch so every
-//! Sprout-spawned agent starts with orientation (AGENTS.md) and a
+//! Buzz-spawned agent starts with orientation (AGENTS.md) and a
//! place to accumulate research, plans, and logs across sessions.
//!
//! Static template content in AGENTS.md (above the managed-section markers)
@@ -34,9 +34,9 @@ const NEST_DIRS: &[&str] = &[
/// Fully static — no runtime interpolation, no secrets, no user paths.
const AGENTS_MD: &str = include_str!("nest_agents.md");
-/// Default SKILL.md content for the sprout-cli skill.
-/// Written to ~/.sprout/.agents/skills/sprout-cli/SKILL.md on first init.
-const SPROUT_CLI_SKILL_MD: &str = include_str!("nest_skill.md");
+/// Default SKILL.md content for the buzz-cli skill.
+/// Written to ~/.buzz/.agents/skills/buzz-cli/SKILL.md on first init.
+const BUZZ_CLI_SKILL_MD: &str = include_str!("nest_skill.md");
/// Template content version for AGENTS.md static content (above managed markers).
/// Bump this when changing `nest_agents.md` to trigger refresh on existing installs.
@@ -47,18 +47,18 @@ const NEST_AGENTS_VERSION: u32 = 4;
/// Bump this when changing `nest_skill.md` to trigger refresh on existing installs.
const NEST_SKILL_VERSION: u32 = 3;
-const BEGIN_MARKER: &str = "";
+const BEGIN_MARKER: &str = "";
/// Canonical skill directory path relative to the nest root.
-const CANONICAL_SKILL_DIR: &str = ".agents/skills/sprout-cli";
-/// Returns the nest root path (`~/.sprout`), or `None` if the home
+const CANONICAL_SKILL_DIR: &str = ".agents/skills/buzz-cli";
+/// Returns the nest root path (`~/.buzz`), or `None` if the home
/// directory cannot be resolved.
pub fn nest_dir() -> Option {
- dirs::home_dir().map(|h| h.join(".sprout"))
+ dirs::home_dir().map(|h| h.join(".buzz"))
}
-/// Creates the Sprout nest at `~/.sprout` if it doesn't already exist.
+/// Creates the Buzz nest at `~/.buzz` if it doesn't already exist.
///
/// Delegates to [`ensure_nest_at`] with the resolved nest directory.
/// Returns an error string if the home directory cannot be resolved.
@@ -67,13 +67,13 @@ pub fn ensure_nest() -> Result<(), String> {
ensure_nest_at(&root)
}
-/// Creates a Sprout nest at the given `root` path.
+/// Creates a Buzz nest at the given `root` path.
///
/// - Creates the root directory and all subdirectories.
/// - Writes `AGENTS.md` only if it doesn't already exist.
-/// - Writes `.agents/skills/sprout-cli/SKILL.md` only if it doesn't already exist.
+/// - Writes `.agents/skills/buzz-cli/SKILL.md` only if it doesn't already exist.
/// - Creates harness-specific symlinks pointing to the canonical
-/// `.agents/skills/sprout-cli` directory for each known provider.
+/// `.agents/skills/buzz-cli` directory for each known provider.
/// - Sets 700 permissions on the root, all subdirectories, and the skill
/// directory tree (Unix).
///
@@ -132,7 +132,7 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
}
}
- // Write sprout-cli skill to the harness-agnostic .agents path.
+ // Write buzz-cli skill to the harness-agnostic .agents path.
// The first-init write uses the new canonical path; migration from
// the old .claude path is handled in refresh_skill_md_if_stale.
let agents_skill_dir = root.join(CANONICAL_SKILL_DIR);
@@ -147,7 +147,7 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
{
Ok(mut file) => {
use std::io::Write;
- file.write_all(SPROUT_CLI_SKILL_MD.as_bytes())
+ file.write_all(BUZZ_CLI_SKILL_MD.as_bytes())
.map_err(|e| format!("write {}: {e}", skill_md.display()))?;
}
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {}
@@ -157,7 +157,7 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
}
// Create harness-specific symlinks for all known providers.
- // Migration of the old .claude/skills/sprout-cli real dir is handled in
+ // Migration of the old .claude/skills/buzz-cli real dir is handled in
// refresh_skill_md_if_stale; ensure_skill_symlinks skips paths that already exist.
ensure_skill_symlinks(root)?;
@@ -225,7 +225,7 @@ fn ensure_skill_symlinks(root: &Path) -> Result<(), String> {
for skill_dir in known_skill_dirs() {
let parent = root.join(skill_dir);
fs::create_dir_all(&parent).map_err(|e| format!("create {}: {e}", parent.display()))?;
- let link = parent.join("sprout-cli");
+ let link = parent.join("buzz-cli");
if link.symlink_metadata().is_ok() {
continue; // symlink or real path exists — skip
}
@@ -243,18 +243,18 @@ fn ensure_skill_symlinks(_root: &Path) -> Result<(), String> {
Ok(())
}
-/// Ensures `~/.local/bin/sprout` is a symlink to the bundled CLI binary.
+/// Ensures `~/.local/bin/buzz` is a symlink to the bundled CLI binary.
///
/// Creates the symlink if it doesn't exist, updates it if it already points
-/// to a Sprout app bundle, and leaves it alone if it points elsewhere (to
+/// to a Buzz app bundle, and leaves it alone if it points elsewhere (to
/// avoid clobbering another tool's binary).
///
/// Non-fatal: callers should ignore errors — the symlink is a convenience
/// for human Terminal use; agents find the CLI via PATH augmentation.
#[cfg(unix)]
pub fn ensure_cli_symlink(exe_parent: &Path) -> Result<(), String> {
- let sprout_bin = exe_parent.join("sprout");
- if !sprout_bin.exists() {
+ let buzz_bin = exe_parent.join("buzz");
+ if !buzz_bin.exists() {
return Ok(()); // CLI not bundled (e.g., dev builds without sidecars).
}
@@ -264,16 +264,16 @@ pub fn ensure_cli_symlink(exe_parent: &Path) -> Result<(), String> {
.join("bin");
fs::create_dir_all(&local_bin).map_err(|e| format!("create {}: {e}", local_bin.display()))?;
- let link = local_bin.join("sprout");
+ let link = local_bin.join("buzz");
match link.symlink_metadata() {
Ok(meta) if meta.file_type().is_symlink() => {
- // Symlink exists — only update if it points to a Sprout bundle.
+ // Symlink exists — only update if it points to a Buzz bundle.
if let Ok(target) = fs::read_link(&link) {
let target_str = target.display().to_string();
if target_str.contains(".app/Contents/MacOS") {
- // Sprout-owned symlink — update to current bundle path.
+ // Buzz-owned symlink — update to current bundle path.
let _ = fs::remove_file(&link);
- std::os::unix::fs::symlink(&sprout_bin, &link)
+ std::os::unix::fs::symlink(&buzz_bin, &link)
.map_err(|e| format!("symlink {}: {e}", link.display()))?;
}
// Otherwise: symlink points elsewhere — don't clobber.
@@ -284,7 +284,7 @@ pub fn ensure_cli_symlink(exe_parent: &Path) -> Result<(), String> {
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
// No file exists — create the symlink.
- std::os::unix::fs::symlink(&sprout_bin, &link)
+ std::os::unix::fs::symlink(&buzz_bin, &link)
.map_err(|e| format!("symlink {}: {e}", link.display()))?;
}
Err(e) => {
@@ -311,7 +311,7 @@ fn read_version_file(path: &Path) -> u32 {
/// Refresh AGENTS.md static content if the template version has changed.
///
-/// Preserves everything from the `\nold section\n\n\nafter\n",
+ "# Header\n\nsome content\n\n\nold section\n\n\nafter\n",
)
.unwrap();
upsert_managed_section(&file, "new section").unwrap();
let result = fs::read_to_string(&file).unwrap();
- assert!(result.contains(""));
+ assert!(result.contains(""));
assert!(result.contains("new section"));
assert!(!result.contains("old section"));
assert!(result.contains("# Header"));
@@ -1052,10 +1052,10 @@ mod tests {
let result = fs::read_to_string(&file).unwrap();
assert!(result.contains("# Header"));
assert!(result.contains("existing content"));
- assert!(result.contains(""));
+ assert!(result.contains(""));
assert!(result.contains("injected section"));
- let begin_pos = result.find("\nsome middle content\n\nold section\n",
+ "# Header\n\n\nsome middle content\n\nold section\n",
)
.unwrap();
@@ -1142,7 +1142,7 @@ mod tests {
let file = tmp.path().join("AGENTS.md");
fs::write(
&file,
- "# Header\n\nsome content\n\n\norphaned section without end marker\n",
+ "# Header\n\nsome content\n\n\norphaned section without end marker\n",
)
.unwrap();
@@ -1183,7 +1183,7 @@ mod tests {
let file = tmp.path().join("AGENTS.md");
fs::write(
&file,
- "# Header\n\n\nfirst block\n\n\nbetween blocks\n\n\nsecond block\n\n",
+ "# Header\n\n\nfirst block\n\n\nbetween blocks\n\n\nsecond block\n\n",
)
.unwrap();
@@ -1216,7 +1216,7 @@ mod tests {
// Indented by 4 spaces — not at column 0, so should NOT match as a real marker.
fs::write(
&file,
- "# Header\n\n \n\nReal content here\n",
+ "# Header\n\n \n\nReal content here\n",
)
.unwrap();
@@ -1225,7 +1225,7 @@ mod tests {
let result = fs::read_to_string(&file).unwrap();
assert!(
- result.contains(" "),
+ result.contains(" "),
"indented marker inside code block must be preserved verbatim"
);
assert!(
@@ -1239,7 +1239,7 @@ mod tests {
// The real markers appended at the end must be at line-start (column 0).
let begin_pos = result
- .find("\nexisting section\n\n",
+ "# Header\n\n\nexisting section\n\n",
)
.unwrap();
@@ -1323,7 +1323,7 @@ mod tests {
#[test]
fn refresh_agents_md_writes_version_file() {
let tmp = tempfile::tempdir().unwrap();
- let root = tmp.path().join(".sprout");
+ let root = tmp.path().join(".buzz");
ensure_nest_at(&root).unwrap();
let version = fs::read_to_string(root.join(".nest-agents-version")).unwrap();
assert_eq!(version.trim(), NEST_AGENTS_VERSION.to_string());
@@ -1332,17 +1332,17 @@ mod tests {
#[test]
fn refresh_skill_md_writes_version_file() {
let tmp = tempfile::tempdir().unwrap();
- let root = tmp.path().join(".sprout");
+ let root = tmp.path().join(".buzz");
ensure_nest_at(&root).unwrap();
let version =
- fs::read_to_string(root.join(".agents/skills/sprout-cli/.skill-version")).unwrap();
+ fs::read_to_string(root.join(".agents/skills/buzz-cli/.skill-version")).unwrap();
assert_eq!(version.trim(), NEST_SKILL_VERSION.to_string());
}
#[test]
fn refresh_agents_md_preserves_managed_section() {
let tmp = tempfile::tempdir().unwrap();
- let root = tmp.path().join(".sprout");
+ let root = tmp.path().join(".buzz");
ensure_nest_at(&root).unwrap();
// Simulate a managed section update.
@@ -1362,7 +1362,7 @@ mod tests {
let content = fs::read_to_string(&agents_md).unwrap();
// Static content should be refreshed (from template).
assert!(
- content.starts_with("# Sprout Nest"),
+ content.starts_with("# Buzz Nest"),
"template header must be present"
);
// Managed section should be preserved.
@@ -1377,7 +1377,7 @@ mod tests {
#[test]
fn refresh_skips_when_version_current() {
let tmp = tempfile::tempdir().unwrap();
- let root = tmp.path().join(".sprout");
+ let root = tmp.path().join(".buzz");
ensure_nest_at(&root).unwrap();
// Manually change AGENTS.md content after version file is written.
@@ -1397,20 +1397,20 @@ mod tests {
#[test]
fn refresh_skill_overwrites_on_version_bump() {
let tmp = tempfile::tempdir().unwrap();
- let root = tmp.path().join(".sprout");
+ let root = tmp.path().join(".buzz");
ensure_nest_at(&root).unwrap();
- let skill_md = root.join(".agents/skills/sprout-cli/SKILL.md");
+ let skill_md = root.join(".agents/skills/buzz-cli/SKILL.md");
fs::write(&skill_md, "stale skill content").unwrap();
// Remove version file to simulate upgrade.
- let _ = fs::remove_file(root.join(".agents/skills/sprout-cli/.skill-version"));
+ let _ = fs::remove_file(root.join(".agents/skills/buzz-cli/.skill-version"));
ensure_nest_at(&root).unwrap();
let content = fs::read_to_string(&skill_md).unwrap();
assert_eq!(
- content, SPROUT_CLI_SKILL_MD,
+ content, BUZZ_CLI_SKILL_MD,
"SKILL.md must be refreshed on version bump"
);
}
diff --git a/desktop/src-tauri/src/managed_agents/nest_agents.md b/desktop/src-tauri/src/managed_agents/nest_agents.md
index eed14ff20..427018be7 100644
--- a/desktop/src-tauri/src/managed_agents/nest_agents.md
+++ b/desktop/src-tauri/src/managed_agents/nest_agents.md
@@ -1,6 +1,6 @@
-# Sprout Nest
+# Buzz Nest
-Your persistent workspace. Created once by the Sprout desktop app. The static content above the managed-section markers is regenerated on upgrades — add custom notes below the markers or in separate files.
+Your persistent workspace. Created once by the Buzz desktop app. The static content above the managed-section markers is regenerated on upgrades — add custom notes below the markers or in separate files.
## Directory Layout
@@ -16,7 +16,7 @@ Your persistent workspace. Created once by the Sprout desktop app. The static co
Filenames: `ALL_CAPS_WITH_UNDERSCORES.md` (e.g., `OAUTH_FLOW_NOTES.md`).
-The `sprout` CLI is your primary tool interface — run `sprout --help` for commands. The CLI skill file has the full reference.
+The bundled CLI is your primary tool interface — run its `--help` command for usage. The CLI skill file has the full reference.
## Knowledge File Conventions
@@ -54,9 +54,9 @@ The human operator signs off for accountability.
- **Signing:** if the agent has a registered signing key, sign commits. If not, commits will land unverified — this is acceptable until agent SSH keys are provisioned. Do NOT use the human's signing key.
- **Verify before pushing:** `git log -1` should show the human's `Signed-off-by` trailer.
-
+
## Active Agents
-*(No agents deployed yet. Add agents in the Sprout desktop app.)*
+*(No agents deployed yet. Add agents in the Buzz desktop app.)*
-
+
diff --git a/desktop/src-tauri/src/managed_agents/nest_skill.md b/desktop/src-tauri/src/managed_agents/nest_skill.md
index 5117d396a..3dbf780e0 100644
--- a/desktop/src-tauri/src/managed_agents/nest_skill.md
+++ b/desktop/src-tauri/src/managed_agents/nest_skill.md
@@ -1,20 +1,20 @@
---
-name: sprout-cli
+name: buzz-cli
description: >
- Sprout CLI for relay operations: messaging, channels, DMs, users, workflows,
+ Buzz CLI for relay operations: messaging, channels, DMs, users, workflows,
feed, reactions, canvas, social, repos, uploads, and agent memory.
version: 1
---
-# Sprout CLI Skill
+# Buzz CLI Skill
## Environment
-`SPROUT_PRIVATE_KEY` is set by the harness at runtime or by the developer's environment. If missing, tell the user to set it (hex or nsec format). Never read or echo the value.
+`BUZZ_PRIVATE_KEY` is set by the harness at runtime or by the developer's environment. If missing, tell the user to set it (hex or nsec format). Never read or echo the value.
-`SPROUT_RELAY_URL` defaults to `http://localhost:3000`. In development, the user may need to set this to a staging or production relay URL.
+`BUZZ_RELAY_URL` defaults to `http://localhost:3000`. In development, the user may need to set this to a staging or production relay URL.
-Run `sprout --help` and `sprout --help` to discover all flags, arguments, and usage. This skill documents only what `--help` cannot tell you.
+Run the bundled CLI with `--help` and ` --help` to discover all flags, arguments, and usage. This skill documents only what `--help` cannot tell you.
## Output Contracts
@@ -45,10 +45,10 @@ Output varies by command group — `--help` shows flags but not response shapes.
`--format compact` is a global flag — position it before the subcommand:
```bash
-sprout --format compact channels list # [{channel_id, name}]
-sprout --format compact messages get --channel # [{id, content, created_at}]
-sprout --format compact users get # [{pubkey, display_name}]
-sprout --format compact feed get # [{id, content, created_at}]
+buzz --format compact channels list # [{channel_id, name}]
+buzz --format compact messages get --channel # [{id, content, created_at}]
+buzz --format compact users get # [{pubkey, display_name}]
+buzz --format compact feed get # [{id, content, created_at}]
```
Write commands are unaffected. `--format json` (default) returns full fields.
@@ -59,10 +59,10 @@ Write commands are unaffected. `--format json` (default) returns full fields.
```bash
# ✅ Correct — notification delivered automatically
-sprout messages send --channel --content "@Alice check this"
+buzz messages send --channel --content "@Alice check this"
# Multiple mentions — same pattern
-sprout messages send --channel --content "@Alice @Bob review please"
+buzz messages send --channel --content "@Alice @Bob review please"
```
## DM Management
@@ -98,7 +98,7 @@ sprout messages send --channel --content "@Alice @Bob review please"
4. **`dms open` returns `dm_id`** — use this value as `--channel` for subsequent `messages send/get` commands on that DM.
5. **Content max 65,536 bytes** (exit 1 if exceeded). Diffs auto-truncate at 61,440 bytes at a hunk boundary.
6. **`users get` always returns an array** — even for a single pubkey lookup. Never expect a bare object.
-7. **All `mem` subcommands accept `--owner `** — for querying or writing memories owned by a different pubkey in multi-agent scenarios. Defaults to the owner from `SPROUT_AUTH_TAG`.
+7. **All `mem` subcommands accept `--owner `** — for querying or writing memories owned by a different pubkey in multi-agent scenarios. Defaults to the owner from `BUZZ_AUTH_TAG`.
8. **`mem rm` cannot delete `core`** — use `mem set core ''` instead.
## Forum Posts
@@ -125,9 +125,9 @@ Message content is rendered as GitHub-flavored Markdown on both desktop and mobi
For safe concurrent writes, use hash-based conflict detection:
```bash
-HASH=$(sprout mem hash ) # 1. get current SHA-256
+HASH=$(buzz mem hash ) # 1. get current SHA-256
# ... build unified diff ...
-sprout mem patch --base-hash "$HASH" --patch-file diff.patch # 2. apply with check
+buzz mem patch --base-hash "$HASH" --patch-file diff.patch # 2. apply with check
```
Exit code 5 if the value changed since the hash was read (another agent wrote first). Retry by re-reading, re-diffing, and re-patching.
@@ -138,9 +138,9 @@ Flags: `--dry-run` to preview without writing, `--no-base-hash` to skip conflict
The relay has no push or webhook support. Poll with a `--since` cursor:
-1. `sprout messages get --channel --limit 50` — note the maximum `created_at` from results
+1. `buzz messages get --channel --limit 50` — note the maximum `created_at` from results
2. Sleep 10-30 seconds
-3. `sprout messages get --channel --since --limit 50`
+3. `buzz messages get --channel --since --limit 50`
4. Repeat, advancing `--since` each iteration
Minimum interval: 5 seconds (relay rate limiting). Use 10s for low-latency, 30s for background monitoring. `feed get` always returns newest-first regardless of `--since`.
diff --git a/desktop/src-tauri/src/managed_agents/persona_card.rs b/desktop/src-tauri/src/managed_agents/persona_card.rs
index 48466302b..68d9b30a4 100644
--- a/desktop/src-tauri/src/managed_agents/persona_card.rs
+++ b/desktop/src-tauri/src/managed_agents/persona_card.rs
@@ -51,19 +51,19 @@ pub fn parse_png_persona(png_bytes: &[u8]) -> Result = None;
+ let mut buzz_text: Option<&str> = None;
let mut chara_text: Option<&str> = None;
for chunk in &info.uncompressed_latin1_text {
match chunk.keyword.as_str() {
- "sprout_persona" if sprout_text.is_none() => sprout_text = Some(&chunk.text),
+ "buzz_persona_pkg" if buzz_text.is_none() => buzz_text = Some(&chunk.text),
"chara" | "ccv3" if chara_text.is_none() => chara_text = Some(&chunk.text),
_ => {}
}
}
- let fields = if let Some(text) = sprout_text {
- parse_sprout_payload(text)?
+ let fields = if let Some(text) = buzz_text {
+ parse_buzz_payload(text)?
} else if let Some(text) = chara_text {
parse_chara_payload(text)?
} else {
@@ -96,8 +96,8 @@ fn decode_b64_json(b64: &str) -> Result {
serde_json::from_slice(&bytes).map_err(|e| format!("Invalid JSON: {e}"))
}
-/// Extracted fields from a Sprout persona JSON payload.
-struct SproutPersonaFields {
+/// Extracted fields from a Buzz persona JSON payload.
+struct BuzzPersonaFields {
display_name: String,
system_prompt: String,
avatar_url: Option,
@@ -107,9 +107,9 @@ struct SproutPersonaFields {
name_pool: Vec,
}
-/// Extract and validate fields from a Sprout persona JSON value
+/// Extract and validate fields from a Buzz persona JSON value
/// (shared by both the PNG tEXt-chunk path and the standalone JSON path).
-fn extract_sprout_fields(v: &Value) -> Result {
+fn extract_buzz_fields(v: &Value) -> Result {
let version = v.get("version").and_then(|v| v.as_u64()).unwrap_or(0);
if version != 1 {
return Err(format!("Unsupported persona version: {version}"));
@@ -172,7 +172,7 @@ fn extract_sprout_fields(v: &Value) -> Result {
.collect()
})
.unwrap_or_default();
- Ok(SproutPersonaFields {
+ Ok(BuzzPersonaFields {
display_name: name,
system_prompt: prompt,
avatar_url,
@@ -183,12 +183,12 @@ fn extract_sprout_fields(v: &Value) -> Result {
})
}
-fn parse_sprout_payload(b64: &str) -> Result {
+fn parse_buzz_payload(b64: &str) -> Result {
let v = decode_b64_json(b64)?;
- extract_sprout_fields(&v)
+ extract_buzz_fields(&v)
}
-fn parse_chara_payload(b64: &str) -> Result {
+fn parse_chara_payload(b64: &str) -> Result {
let v = decode_b64_json(b64)?;
let data = v.get("data").ok_or("Missing 'data' in chara payload")?;
let name = data
@@ -217,7 +217,7 @@ fn parse_chara_payload(b64: &str) -> Result {
if prompt.is_empty() {
return Err("Chara card has no system_prompt or description".to_string());
}
- Ok(SproutPersonaFields {
+ Ok(BuzzPersonaFields {
display_name: name,
system_prompt: prompt,
avatar_url: None,
@@ -234,7 +234,7 @@ fn parse_chara_payload(b64: &str) -> Result {
pub fn parse_json_persona(json_bytes: &[u8]) -> Result {
let v: Value = serde_json::from_slice(json_bytes).map_err(|e| format!("Invalid JSON: {e}"))?;
- let fields = extract_sprout_fields(&v)?;
+ let fields = extract_buzz_fields(&v)?;
Ok(ParsedPersonaPreview {
display_name: fields.display_name,
@@ -288,13 +288,13 @@ pub fn encode_persona_json(
pub fn parse_md_persona(md_bytes: &[u8]) -> Result {
let content =
std::str::from_utf8(md_bytes).map_err(|e| format!("Invalid UTF-8 in .persona.md: {e}"))?;
- let config = sprout_persona::persona::parse_persona_md(content)
+ let config = buzz_persona_pkg::persona::parse_persona_md(content)
.map_err(|e| format!("Failed to parse .persona.md: {e}"))?;
// Split "provider:model" into separate fields for the preview.
let model = match config.model.as_deref() {
Some(s) if !s.is_empty() => {
- let (_prov, id) = sprout_persona::persona::split_model(s);
+ let (_prov, id) = buzz_persona_pkg::persona::split_model(s);
Some(id.to_owned())
}
_ => None,
@@ -395,7 +395,7 @@ pub fn parse_zip_pack(zip_bytes: &[u8]) -> Result = resolved
@@ -572,7 +572,7 @@ mod tests {
buf
}
- /// Helper: build a PNG with a sprout_persona tEXt chunk for the given name/prompt.
+ /// Helper: build a PNG with a buzz_persona_pkg tEXt chunk for the given name/prompt.
fn make_test_persona_png(name: &str, prompt: &str) -> Vec {
let payload = serde_json::json!({
"version": 1,
@@ -580,7 +580,7 @@ mod tests {
"systemPrompt": prompt,
});
let b64 = STANDARD.encode(payload.to_string().as_bytes());
- make_png_with_text("sprout_persona", &b64)
+ make_png_with_text("buzz_persona_pkg", &b64)
}
/// Helper: build a plain PNG with no metadata.
@@ -632,14 +632,14 @@ mod tests {
fn parse_png_unknown_version() {
let payload = serde_json::json!({"version": 99, "displayName": "X", "systemPrompt": "Y"});
let b64 = STANDARD.encode(payload.to_string().as_bytes());
- let png = make_png_with_text("sprout_persona", &b64);
+ let png = make_png_with_text("buzz_persona_pkg", &b64);
let err = parse_png_persona(&png).unwrap_err();
assert!(err.contains("Unsupported persona version"));
}
#[test]
fn parse_png_malformed_base64() {
- let png = make_png_with_text("sprout_persona", "!!!not-base64!!!");
+ let png = make_png_with_text("buzz_persona_pkg", "!!!not-base64!!!");
let err = parse_png_persona(&png).unwrap_err();
assert!(err.contains("Invalid base64"));
}
@@ -647,7 +647,7 @@ mod tests {
#[test]
fn parse_png_malformed_json() {
let b64 = STANDARD.encode(b"not json at all");
- let png = make_png_with_text("sprout_persona", &b64);
+ let png = make_png_with_text("buzz_persona_pkg", &b64);
let err = parse_png_persona(&png).unwrap_err();
assert!(err.contains("Invalid JSON"));
}
@@ -656,7 +656,7 @@ mod tests {
fn parse_png_empty_fields() {
let payload = serde_json::json!({"version": 1, "displayName": "", "systemPrompt": "Y"});
let b64 = STANDARD.encode(payload.to_string().as_bytes());
- let png = make_png_with_text("sprout_persona", &b64);
+ let png = make_png_with_text("buzz_persona_pkg", &b64);
let err = parse_png_persona(&png).unwrap_err();
assert!(err.contains("displayName is empty"));
}
@@ -680,14 +680,14 @@ mod tests {
}
#[test]
- fn parse_png_chara_ignored_when_sprout_present() {
- // Build a PNG with both sprout_persona and chara chunks.
- let sprout = serde_json::json!({"version": 1, "displayName": "Sprout Name", "systemPrompt": "Sprout prompt"});
+ fn parse_png_chara_ignored_when_buzz_present() {
+ // Build a PNG with both buzz_persona_pkg and chara chunks.
+ let buzz = serde_json::json!({"version": 1, "displayName": "Buzz Name", "systemPrompt": "Buzz prompt"});
let chara = serde_json::json!({
"spec": "chara_card_v2", "spec_version": "2.0",
"data": {"name": "Chara Name", "system_prompt": "Chara prompt", "description": ""}
});
- let sprout_b64 = STANDARD.encode(sprout.to_string().as_bytes());
+ let buzz_b64 = STANDARD.encode(buzz.to_string().as_bytes());
let chara_b64 = STANDARD.encode(chara.to_string().as_bytes());
let mut buf = Vec::new();
@@ -695,7 +695,7 @@ mod tests {
let mut enc = Encoder::new(Cursor::new(&mut buf), 1, 1);
enc.set_color(ColorType::Rgba);
enc.set_depth(BitDepth::Eight);
- enc.add_text_chunk("sprout_persona".to_string(), sprout_b64)
+ enc.add_text_chunk("buzz_persona_pkg".to_string(), buzz_b64)
.unwrap();
enc.add_text_chunk("chara".to_string(), chara_b64).unwrap();
let mut w = enc.write_header().unwrap();
@@ -703,8 +703,8 @@ mod tests {
}
let result = parse_png_persona(&buf).unwrap();
- assert_eq!(result.display_name, "Sprout Name");
- assert_eq!(result.system_prompt, "Sprout prompt");
+ assert_eq!(result.display_name, "Buzz Name");
+ assert_eq!(result.system_prompt, "Buzz prompt");
}
#[test]
@@ -767,7 +767,7 @@ mod tests {
#[test]
fn parse_png_duplicate_chunks() {
- // Two sprout_persona chunks — should use the first and ignore the second.
+ // Two buzz_persona_pkg chunks — should use the first and ignore the second.
let payload1 =
serde_json::json!({"version": 1, "displayName": "First", "systemPrompt": "Prompt 1"});
let payload2 =
@@ -780,9 +780,9 @@ mod tests {
let mut enc = Encoder::new(Cursor::new(&mut buf), 1, 1);
enc.set_color(ColorType::Rgba);
enc.set_depth(BitDepth::Eight);
- enc.add_text_chunk("sprout_persona".to_string(), b64_1)
+ enc.add_text_chunk("buzz_persona_pkg".to_string(), b64_1)
.unwrap();
- enc.add_text_chunk("sprout_persona".to_string(), b64_2)
+ enc.add_text_chunk("buzz_persona_pkg".to_string(), b64_2)
.unwrap();
let mut w = enc.write_header().unwrap();
w.write_image_data(&[0, 0, 0, 255]).unwrap();
diff --git a/desktop/src-tauri/src/managed_agents/personas.rs b/desktop/src-tauri/src/managed_agents/personas.rs
index 35eb575f5..06eb95774 100644
--- a/desktop/src-tauri/src/managed_agents/personas.rs
+++ b/desktop/src-tauri/src/managed_agents/personas.rs
@@ -178,7 +178,7 @@ RIGHT — kickoff with no `@`, no ping:
Then later, when actually ready to assign:
-> "@scout — PHASE: PLAN REVIEW + RESEARCH. Worktree: /tmp/sprout-auth. Plan: . Deliverable: verdict + research brief."
+> "@scout — PHASE: PLAN REVIEW + RESEARCH. Worktree: /tmp/buzz-auth. Plan: . Deliverable: verdict + research brief."
# Size The Task First
@@ -452,7 +452,7 @@ You are read-only, but you still resolve questions yourself before pinging Kit:
# Standalone Mode
-If you're invoked outside a Sprout team channel (or by an agent that isn't Kit), apply the same protocols. Default to FULL REVIEW for completed work or PLAN REVIEW + RESEARCH for plans. Report to whoever invoked you.
+If you're invoked outside a Buzz team channel (or by an agent that isn't Kit), apply the same protocols. Default to FULL REVIEW for completed work or PLAN REVIEW + RESEARCH for plans. Report to whoever invoked you.
Your name is Scout. You are friendly and helpful. You are understated, but have a sense of humor."#,
model: None,
@@ -616,7 +616,7 @@ fn migrate_retired_personas(stored: &mut [PersonaRecord], now: &str) -> bool {
if needs_suffix || record.is_active {
let was_unmodified = record.system_prompt == *original_prompt;
eprintln!(
- "sprout-desktop: persona-migration: retiring {} persona '{}' → '{} (retired)'",
+ "buzz-desktop: persona-migration: retiring {} persona '{}' → '{} (retired)'",
if was_unmodified {
"unmodified"
} else {
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index ec25981db..808546aa4 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -2,7 +2,7 @@ use super::ManagedAgentRecord;
pub use super::RelayMeshConfig;
pub const RELAY_MESH_API_BASE_URL: &str = "http://127.0.0.1:9337/v1";
-pub const RELAY_MESH_API_KEY_PLACEHOLDER: &str = "sprout-mesh-local";
+pub const RELAY_MESH_API_KEY_PLACEHOLDER: &str = "buzz-mesh-local";
/// Resolve a record's relay-mesh config, typed field first.
///
@@ -19,7 +19,7 @@ pub fn relay_mesh_config(record: &ManagedAgentRecord) -> Option
}
/// Returns the relay-mesh model id for agents whose provider env points at the
-/// local mesh client endpoint created by Sprout's relay-mesh preset.
+/// local mesh client endpoint created by Buzz's relay-mesh preset.
///
/// Prefer [`relay_mesh_config`]; this remains as a convenience for call sites
/// that only need the model id.
@@ -69,7 +69,7 @@ mod tests {
auth_tag: Some("tag".into()),
relay_url: "ws://localhost:3000".into(),
avatar_url: None,
- acp_command: "sprout-acp".into(),
+ acp_command: "buzz-acp".into(),
agent_command: "goose".into(),
agent_args: vec![],
mcp_command: String::new(),
diff --git a/desktop/src-tauri/src/managed_agents/restore.rs b/desktop/src-tauri/src/managed_agents/restore.rs
index aa9b3a03d..2bad0fd36 100644
--- a/desktop/src-tauri/src/managed_agents/restore.rs
+++ b/desktop/src-tauri/src/managed_agents/restore.rs
@@ -61,7 +61,7 @@ pub async fn restore_managed_agents_on_launch(
// process group whose parent harness exited).
super::sweep_system_agent_processes(&super::current_instance_id(app), &tracked_pids);
- // Dead-instance reaping: find agents belonging to Sprout instances
+ // Dead-instance reaping: find agents belonging to Buzz instances
// whose desktop process is no longer running and reap them.
super::reap_dead_instance_agents(&super::current_instance_id(app), &tracked_pids);
@@ -232,7 +232,7 @@ pub async fn restore_managed_agents_on_launch(
crate::commands::reconcile_agent_profile(&state, &reconcile_app, &pubkey, &data)
.await
{
- eprintln!("sprout-desktop: profile reconciliation failed for agent {pubkey}: {e}");
+ eprintln!("buzz-desktop: profile reconciliation failed for agent {pubkey}: {e}");
}
});
}
diff --git a/desktop/src-tauri/src/managed_agents/runtime.rs b/desktop/src-tauri/src/managed_agents/runtime.rs
index a42ed8627..6e140c9e2 100644
--- a/desktop/src-tauri/src/managed_agents/runtime.rs
+++ b/desktop/src-tauri/src/managed_agents/runtime.rs
@@ -13,16 +13,16 @@ use crate::{
type RespondToEnv = (Vec<(&'static str, String)>, Vec<&'static str>);
-/// Binary name fragments for all known agent/harness processes that Sprout
+/// Binary name fragments for all known agent/harness processes that Buzz
/// may spawn. Used by `process_belongs_to_us()` and the orphan sweep to
/// identify processes we should clean up. Both hyphenated and underscored
/// variants are listed because macOS `proc_name()` and Linux `/proc/comm`
/// may report either form depending on how the binary was built.
pub(crate) const KNOWN_AGENT_BINARIES: &[&str] = &[
- "sprout-acp",
- "sprout_acp",
- "sprout-agent",
- "sprout_agent",
+ "buzz-acp",
+ "buzz_acp",
+ "buzz-agent",
+ "buzz_agent",
"claude-agent-acp",
"claude_agent_acp",
"claude-code-acp",
@@ -30,11 +30,11 @@ pub(crate) const KNOWN_AGENT_BINARIES: &[&str] = &[
"codex-acp",
"codex_acp",
"goose",
- // sprout-dev-mcp's multicall personalities (rg, tree, sprout,
+ // buzz-dev-mcp's multicall personalities (rg, tree, buzz,
// git-credential-nostr, git-sign-nostr) are short-lived per-tool-call
// invocations — not listed here.
- "sprout-dev-mcp",
- "sprout_dev_mcp",
+ "buzz-dev-mcp",
+ "buzz_dev_mcp",
];
/// Check if a process name matches any of our known agent binaries.
@@ -118,11 +118,11 @@ pub(crate) fn process_belongs_to_us(_pid: u32) -> bool {
/// The value stamped into the `BUZZ_MANAGED_AGENT` env var of every agent we
/// spawn, identifying *which* desktop instance owns it. We use the app's bundle
-/// identifier (`xyz.block.sprout.app` for release, `xyz.block.sprout.app.dev`
+/// identifier (`xyz.block.buzz.app` for release, `xyz.block.buzz.app.dev`
/// for `just dev`) because it is stable across restarts — a relaunched dev
/// instance still recognizes its own previously-spawned agents as reclaimable,
/// while never matching another instance's (e.g. a dev build never reaps a DMG
-/// build's agents, and vice versa). This is what lets two Sprouts coexist on
+/// build's agents, and vice versa). This is what lets two Buzzs coexist on
/// one machine without one's cleanup nuking the other's agents.
pub(crate) fn current_instance_id(app: &AppHandle) -> String {
app.config().identifier.clone()
@@ -131,17 +131,17 @@ pub(crate) fn current_instance_id(app: &AppHandle) -> String {
/// Build the full `BUZZ_MANAGED_AGENT=` env entry we match
/// against when scanning processes. Kept here so the spawn stamp and the sweep
/// matcher can never drift apart.
-fn sprout_marker_entry(instance_id: &str) -> Vec {
+fn buzz_marker_entry(instance_id: &str) -> Vec {
format!("BUZZ_MANAGED_AGENT={instance_id}").into_bytes()
}
/// Check if a running process is one of *our* managed agents: it must carry
/// `BUZZ_MANAGED_AGENT=` in its environment, where `instance_id`
/// is this desktop instance's id. A process stamped with a *different* instance
-/// id belongs to another live Sprout app and must never be reaped here.
+/// id belongs to another live Buzz app and must never be reaped here.
#[cfg(target_os = "macos")]
-fn process_has_sprout_marker(pid: u32, instance_id: &str) -> bool {
- let marker = sprout_marker_entry(instance_id);
+fn process_has_buzz_marker(pid: u32, instance_id: &str) -> bool {
+ let marker = buzz_marker_entry(instance_id);
let mut mib: [libc::c_int; 3] = [libc::CTL_KERN, libc::KERN_PROCARGS2, pid as libc::c_int];
let mut buf_size: libc::size_t = 0;
@@ -215,8 +215,8 @@ fn process_has_sprout_marker(pid: u32, instance_id: &str) -> bool {
}
#[cfg(all(unix, not(target_os = "macos")))]
-fn process_has_sprout_marker(pid: u32, instance_id: &str) -> bool {
- let marker = sprout_marker_entry(instance_id);
+fn process_has_buzz_marker(pid: u32, instance_id: &str) -> bool {
+ let marker = buzz_marker_entry(instance_id);
let Ok(data) = std::fs::read(format!("/proc/{pid}/environ")) else {
return false;
};
@@ -224,7 +224,7 @@ fn process_has_sprout_marker(pid: u32, instance_id: &str) -> bool {
}
#[cfg(not(unix))]
-fn process_has_sprout_marker(_pid: u32, _instance_id: &str) -> bool {
+fn process_has_buzz_marker(_pid: u32, _instance_id: &str) -> bool {
false
}
@@ -402,7 +402,7 @@ const PROC_PIDTBSDINFO: libc::c_int = 3;
/// (`instance_id`) that isn't in `skip_pids`. This catches orphans that escaped
/// PID-file-based cleanup (e.g. agent workers spawned with their own process
/// group whose parent harness already exited and had its PID file removed),
-/// while leaving another live Sprout instance's agents untouched.
+/// while leaving another live Buzz instance's agents untouched.
#[cfg(target_os = "macos")]
pub(crate) fn sweep_system_agent_processes(instance_id: &str, skip_pids: &[u32]) {
let my_uid = unsafe { libc::getuid() };
@@ -470,7 +470,7 @@ pub(crate) fn sweep_system_agent_processes(instance_id: &str, skip_pids: &[u32])
if skip_pids.contains(&info.pbi_ppid) {
continue;
}
- if !process_has_sprout_marker(upid, instance_id) {
+ if !process_has_buzz_marker(upid, instance_id) {
continue;
}
orphans.push(pid);
@@ -478,7 +478,7 @@ pub(crate) fn sweep_system_agent_processes(instance_id: &str, skip_pids: &[u32])
if !orphans.is_empty() {
eprintln!(
- "sprout-desktop: system sweep found {} orphaned agent process(es), cleaning up",
+ "buzz-desktop: system sweep found {} orphaned agent process(es), cleaning up",
orphans.len()
);
sigterm_then_sigkill(&orphans);
@@ -529,7 +529,7 @@ pub(crate) fn sweep_system_agent_processes(instance_id: &str, skip_pids: &[u32])
if meta.uid() != my_uid {
continue;
}
- if !process_belongs_to_us(upid) || !process_has_sprout_marker(upid, instance_id) {
+ if !process_belongs_to_us(upid) || !process_has_buzz_marker(upid, instance_id) {
continue;
}
// Live child of a tracked harness — not an orphan. If /proc//stat
@@ -547,7 +547,7 @@ pub(crate) fn sweep_system_agent_processes(instance_id: &str, skip_pids: &[u32])
if !orphans.is_empty() {
eprintln!(
- "sprout-desktop: system sweep found {} orphaned agent process(es), cleaning up",
+ "buzz-desktop: system sweep found {} orphaned agent process(es), cleaning up",
orphans.len()
);
sigterm_then_sigkill(&orphans);
@@ -577,7 +577,7 @@ pub(crate) fn sweep_system_agent_processes_with_grace(
.collect();
if !confirmed.is_empty() {
eprintln!(
- "sprout-desktop: periodic sweep confirmed {} orphaned agent process(es), cleaning up",
+ "buzz-desktop: periodic sweep confirmed {} orphaned agent process(es), cleaning up",
confirmed.len()
);
sigterm_then_sigkill(&confirmed);
@@ -661,7 +661,7 @@ pub(crate) fn collect_same_instance_orphans(
if skip_pids.contains(&info.pbi_ppid) {
continue;
}
- if process_has_sprout_marker(upid, instance_id) {
+ if process_has_buzz_marker(upid, instance_id) {
orphans.insert(upid);
}
}
@@ -702,7 +702,7 @@ pub(crate) fn collect_same_instance_orphans(
if meta.uid() != my_uid {
continue;
}
- if !process_belongs_to_us(upid) || !process_has_sprout_marker(upid, instance_id) {
+ if !process_belongs_to_us(upid) || !process_has_buzz_marker(upid, instance_id) {
continue;
}
// Live child of a tracked harness — not an orphan. If /proc//stat
@@ -727,22 +727,21 @@ pub(crate) fn collect_same_instance_orphans(
std::collections::HashSet::new()
}
-/// Binary names for the Sprout desktop/Tauri process. Used by dead-instance
-/// detection to confirm the owning desktop is still alive. The release .app
-/// bundle reports as "Sprout"; `tauri dev` reports as "sprout-desktop".
-const DESKTOP_BINARY_NAMES: &[&str] = &["Sprout", "sprout-desktop", "sprout_desktop"];
+/// Binary names for the Buzz desktop/Tauri process. Used by dead-instance
+/// detection to confirm the owning desktop is still alive.
+const DESKTOP_BINARY_NAMES: &[&str] = &["Buzz", "buzz-desktop", "buzz_desktop"];
-/// Check if a process name matches a known Sprout desktop binary.
+/// Check if a process name matches a known Buzz desktop binary.
fn is_desktop_binary(name: &str) -> bool {
DESKTOP_BINARY_NAMES.contains(&name)
}
/// Check whether `buf` contains `id` as a complete identifier — not as a
/// prefix of a longer dotted name. The identifier appears in the Tauri config
-/// JSON as `"identifier":"xyz.block.sprout.app.dev"` and in environment entries
+/// JSON as `"identifier":"xyz.block.buzz.app.dev"` and in environment entries
/// as `KEY=...app.dev\0`, so a valid match is followed by a non-identifier byte
/// (not `[A-Za-z0-9._-]`) or sits at the end of the buffer. This prevents
-/// `xyz.block.sprout.app` from matching inside `xyz.block.sprout.app.dev`.
+/// `xyz.block.buzz.app` from matching inside `xyz.block.buzz.app.dev`.
fn buffer_contains_identifier(buf: &[u8], id: &[u8]) -> bool {
if id.is_empty() {
return false;
@@ -765,7 +764,7 @@ fn buffer_contains_identifier(buf: &[u8], id: &[u8]) -> bool {
/// Extract the `BUZZ_MANAGED_AGENT` value from a process's environment.
/// Returns `None` if the process doesn't have the marker or can't be read.
#[cfg(target_os = "macos")]
-fn extract_sprout_marker_value(pid: u32) -> Option {
+fn extract_buzz_marker_value(pid: u32) -> Option {
let prefix = b"BUZZ_MANAGED_AGENT=";
let mut mib: [libc::c_int; 3] = [libc::CTL_KERN, libc::KERN_PROCARGS2, pid as libc::c_int];
@@ -842,7 +841,7 @@ fn extract_sprout_marker_value(pid: u32) -> Option {
}
#[cfg(all(unix, not(target_os = "macos")))]
-fn extract_sprout_marker_value(pid: u32) -> Option {
+fn extract_buzz_marker_value(pid: u32) -> Option {
let prefix = b"BUZZ_MANAGED_AGENT=";
let data = std::fs::read(format!("/proc/{pid}/environ")).ok()?;
for entry in data.split(|&b| b == 0) {
@@ -854,12 +853,12 @@ fn extract_sprout_marker_value(pid: u32) -> Option {
}
#[cfg(not(unix))]
-fn extract_sprout_marker_value(_pid: u32) -> Option {
+fn extract_buzz_marker_value(_pid: u32) -> Option {
None
}
-/// Check if a Sprout desktop process is still alive for the given instance ID.
-/// Scans all user-owned processes named "Sprout" or "sprout-desktop" and checks
+/// Check if a Buzz desktop process is still alive for the given instance ID.
+/// Scans all user-owned processes named "Buzz" or "buzz-desktop" and checks
/// whether any has the identifier in its command-line args (KERN_PROCARGS2 buffer
/// includes both argv and environ — the `--config` JSON from `tauri dev` contains
/// the identifier string).
@@ -1020,11 +1019,11 @@ fn desktop_is_alive_for_instance(_instance_id: &str) -> bool {
false
}
-/// Reap agent processes belonging to dead Sprout desktop instances.
+/// Reap agent processes belonging to dead Buzz desktop instances.
///
/// Scans all user processes for `BUZZ_MANAGED_AGENT=*`, groups them by
/// instance ID, and for each foreign instance (≠ `our_instance_id`) checks
-/// whether a Sprout desktop binary is still alive for that instance. If not,
+/// whether a Buzz desktop binary is still alive for that instance. If not,
/// all agents from that dead instance are reaped.
#[cfg(target_os = "macos")]
pub(crate) fn reap_dead_instance_agents(our_instance_id: &str, skip_pids: &[u32]) {
@@ -1087,7 +1086,7 @@ pub(crate) fn reap_dead_instance_agents(our_instance_id: &str, skip_pids: &[u32]
continue;
}
// Extract the instance ID from this agent's env.
- let Some(agent_instance_id) = extract_sprout_marker_value(upid) else {
+ let Some(agent_instance_id) = extract_buzz_marker_value(upid) else {
continue;
};
// Skip agents belonging to our own instance (handled by sweep_system_agent_processes).
@@ -1106,7 +1105,7 @@ pub(crate) fn reap_dead_instance_agents(our_instance_id: &str, skip_pids: &[u32]
continue;
}
eprintln!(
- "sprout-desktop: reaping {} orphaned agent(s) from dead instance '{instance_id}'",
+ "buzz-desktop: reaping {} orphaned agent(s) from dead instance '{instance_id}'",
agent_pids.len()
);
sigterm_then_sigkill(agent_pids);
@@ -1147,7 +1146,7 @@ pub(crate) fn reap_dead_instance_agents(our_instance_id: &str, skip_pids: &[u32]
if !process_belongs_to_us(upid) {
continue;
}
- let Some(agent_instance_id) = extract_sprout_marker_value(upid) else {
+ let Some(agent_instance_id) = extract_buzz_marker_value(upid) else {
continue;
};
if agent_instance_id == our_instance_id {
@@ -1164,7 +1163,7 @@ pub(crate) fn reap_dead_instance_agents(our_instance_id: &str, skip_pids: &[u32]
continue;
}
eprintln!(
- "sprout-desktop: reaping {} orphaned agent(s) from dead instance '{instance_id}'",
+ "buzz-desktop: reaping {} orphaned agent(s) from dead instance '{instance_id}'",
agent_pids.len()
);
sigterm_then_sigkill(agent_pids);
@@ -1488,7 +1487,7 @@ pub fn spawn_agent_child(
Some(path) => Some(path),
None => {
eprintln!(
- "sprout-desktop: mcp_command {:?} not found, skipping",
+ "buzz-desktop: mcp_command {:?} not found, skipping",
record.mcp_command
);
None
@@ -1501,8 +1500,8 @@ pub fn spawn_agent_child(
.unwrap_or_else(|| record.agent_command.clone());
// Augment PATH for DMG launches so child processes can find:
- // - sprout CLI via ~/.local/bin symlink
- // - bundled sidecars (sprout, sprout-acp, etc.) via exe parent (Contents/MacOS/)
+ // - bundled CLI via ~/.local/bin symlink
+ // - bundled sidecars (buzz, buzz-acp, etc.) via exe parent (Contents/MacOS/)
// - runtimes (node, python, etc.) via login shell PATH
let augmented_path = {
let mut parts: Vec = Vec::new();
@@ -1548,14 +1547,14 @@ pub fn spawn_agent_child(
}
}
// Enable MCP hook tools (_Stop, _PostCompact) for agents that need them.
- // Uses "*" because build_mcp_servers() hard-codes the server name to "sprout-mcp".
+ // Uses "*" because build_mcp_servers() hard-codes the server name to "buzz-mcp".
let runtime_meta = known_acp_runtime(&record.agent_command);
if runtime_meta.is_some_and(|r| r.mcp_hooks) {
command.env("MCP_HOOK_SERVERS", "*");
}
// Only emit BUZZ_ACP_IDLE_TIMEOUT when the user has explicitly set an
- // override. When unset, the sprout-acp harness applies its own default
- // (see `DEFAULT_IDLE_TIMEOUT_SECS` in crates/sprout-acp/src/config.rs),
+ // override. When unset, the buzz-acp harness applies its own default
+ // (see `DEFAULT_IDLE_TIMEOUT_SECS` in crates/buzz-acp/src/config.rs),
// which is the single source of truth. The previously-emitted
// `BUZZ_ACP_TURN_TIMEOUT` is deprecated upstream and was pinning every
// agent to the desktop's stale default (320s), bypassing harness bumps.
@@ -1647,9 +1646,9 @@ pub fn spawn_agent_child(
command.env("BUZZ_ACP_RELAY_OBSERVER", "true");
- // ── Git credential helper for Sprout relay ──────────────────────────
+ // ── Git credential helper for Buzz relay ──────────────────────────
//
- // Agents need to clone/push repos hosted on the Sprout relay's git
+ // Agents need to clone/push repos hosted on the Buzz relay's git
// server, which authenticates via NIP-98. The `git-credential-nostr`
// binary signs auth events using the agent's nostr key.
//
@@ -1676,13 +1675,13 @@ pub fn spawn_agent_child(
command.env("GIT_CONFIG_VALUE_1", "true");
} else {
eprintln!(
- "sprout-desktop: git-credential-nostr not found — agent {} will not have automatic Sprout git auth",
+ "buzz-desktop: git-credential-nostr not found — agent {} will not have automatic Buzz git auth",
record.name,
);
}
- // Baked-in Databricks defaults for internal builds (sprout-releases sets
- // SPROUT_BUILD_DATABRICKS_* at compile time; OSS builds bake nothing).
+ // Baked-in Databricks defaults for internal builds (buzz-releases sets
+ // BUZZ_BUILD_DATABRICKS_* at compile time; OSS builds bake nothing).
// Written BEFORE user env_vars so a GUI/persona override still wins.
for (key, value) in build_databricks_defaults() {
command.env(key, value);
@@ -1691,11 +1690,11 @@ pub fn spawn_agent_child(
// ── User env vars: persona first, then per-agent (last wins) ────────
//
// Precedence: desktop parent env < persona env_vars < agent env_vars.
- // These writes go LAST so user-provided values win over every Sprout-set
+ // These writes go LAST so user-provided values win over every Buzz-set
// env above — EXCEPT reserved keys (BUZZ_PRIVATE_KEY, NOSTR_PRIVATE_KEY,
// BUZZ_AUTH_TAG, BUZZ_API_TOKEN, BUZZ_ACP_PRIVATE_KEY,
// BUZZ_ACP_API_TOKEN), which `merged_user_env` strips. Those carry
- // Sprout's identity and must never be GUI-overridable.
+ // Buzz's identity and must never be GUI-overridable.
// Fail closed on persona-lookup errors: persona env_vars carry API
// credentials, so silently substituting an empty map would spawn an
// unauthenticated agent and surface as a confusing downstream auth error.
@@ -1704,11 +1703,11 @@ pub fn spawn_agent_child(
command.env(key, value);
}
- // Mark as Sprout-managed *and* which desktop instance owns us, so the
+ // Mark as Buzz-managed *and* which desktop instance owns us, so the
// system-wide orphan sweep only reaps this instance's own agents and never
- // another live Sprout's (e.g. a `just dev` build won't kill a DMG build's
- // agents). Propagates automatically through the full tree (sprout-acp →
- // goose → MCP servers) because neither sprout-acp nor goose calls
+ // another live Buzz's (e.g. a `just dev` build won't kill a DMG build's
+ // agents). Propagates automatically through the full tree (buzz-acp →
+ // goose → MCP servers) because neither buzz-acp nor goose calls
// env_clear().
command.env("BUZZ_MANAGED_AGENT", current_instance_id(app));
@@ -1735,22 +1734,22 @@ pub fn spawn_agent_child(
fn child_rust_log_filter() -> String {
match std::env::var("RUST_LOG") {
- Ok(existing) if existing.contains("sprout_acp") => existing,
- Ok(existing) if !existing.trim().is_empty() => format!("{existing},sprout_acp=info"),
- _ => "sprout_acp=info".to_string(),
+ Ok(existing) if existing.contains("buzz_acp") => existing,
+ Ok(existing) if !existing.trim().is_empty() => format!("{existing},buzz_acp=info"),
+ _ => "buzz_acp=info".to_string(),
}
}
/// Databricks host/model baked in at compile time for internal builds. Empty
-/// in OSS builds, where the `SPROUT_BUILD_DATABRICKS_*` env is unset.
+/// in OSS builds, where the `BUZZ_BUILD_DATABRICKS_*` env is unset.
fn build_databricks_defaults() -> Vec<(&'static str, &'static str)> {
let mut defaults = Vec::new();
- if let Some(host) = option_env!("SPROUT_DESKTOP_BUILD_DATABRICKS_HOST") {
+ if let Some(host) = option_env!("BUZZ_DESKTOP_BUILD_DATABRICKS_HOST") {
if !host.is_empty() {
defaults.push(("DATABRICKS_HOST", host));
}
}
- if let Some(model) = option_env!("SPROUT_DESKTOP_BUILD_DATABRICKS_MODEL") {
+ if let Some(model) = option_env!("BUZZ_DESKTOP_BUILD_DATABRICKS_MODEL") {
if !model.is_empty() {
defaults.push(("DATABRICKS_MODEL", model));
}
diff --git a/desktop/src-tauri/src/managed_agents/runtime/tests.rs b/desktop/src-tauri/src/managed_agents/runtime/tests.rs
index 580ae59a2..f8a922da5 100644
--- a/desktop/src-tauri/src/managed_agents/runtime/tests.rs
+++ b/desktop/src-tauri/src/managed_agents/runtime/tests.rs
@@ -5,42 +5,42 @@ use crate::managed_agents::known_acp_runtime;
#[test]
fn identifier_prefix_does_not_match_longer_id() {
// DMG identifier should NOT match inside a dev desktop's config JSON.
- let buf = br#""identifier":"xyz.block.sprout.app.dev""#;
- let id = b"xyz.block.sprout.app";
+ let buf = br#""identifier":"xyz.block.buzz.app.dev""#;
+ let id = b"xyz.block.buzz.app";
assert!(!super::buffer_contains_identifier(buf, id));
}
#[test]
fn identifier_prefix_does_not_match_worktree_slug() {
// Main dev identifier should NOT match inside a worktree desktop's buffer.
- let buf = br#""identifier":"xyz.block.sprout.app.dev.my-branch""#;
- let id = b"xyz.block.sprout.app.dev";
+ let buf = br#""identifier":"xyz.block.buzz.app.dev.my-branch""#;
+ let id = b"xyz.block.buzz.app.dev";
assert!(!super::buffer_contains_identifier(buf, id));
}
#[test]
fn identifier_exact_match_with_quote_boundary() {
// Exact match followed by closing quote — should match.
- let buf = br#""identifier":"xyz.block.sprout.app.dev""#;
- let id = b"xyz.block.sprout.app.dev";
+ let buf = br#""identifier":"xyz.block.buzz.app.dev""#;
+ let id = b"xyz.block.buzz.app.dev";
assert!(super::buffer_contains_identifier(buf, id));
}
#[test]
fn identifier_match_with_null_boundary() {
// In KERN_PROCARGS2, entries are null-delimited.
- let mut buf = b"BUZZ_MANAGED_AGENT=xyz.block.sprout.app.dev".to_vec();
+ let mut buf = b"BUZZ_MANAGED_AGENT=xyz.block.buzz.app.dev".to_vec();
buf.push(0);
buf.extend_from_slice(b"OTHER_VAR=value");
- let id = b"xyz.block.sprout.app.dev";
+ let id = b"xyz.block.buzz.app.dev";
assert!(super::buffer_contains_identifier(&buf, id));
}
#[test]
fn identifier_exact_match_at_end_of_buffer() {
// Exact match with end-of-buffer as the boundary — Thufir's case 1.
- let buf = b"xyz.block.sprout.app.dev";
- let id = b"xyz.block.sprout.app.dev";
+ let buf = b"xyz.block.buzz.app.dev";
+ let id = b"xyz.block.buzz.app.dev";
assert!(super::buffer_contains_identifier(buf, id));
}
@@ -48,10 +48,10 @@ fn identifier_exact_match_at_end_of_buffer() {
fn longer_id_matches_when_short_prefix_also_present() {
// Searching for the longer ID finds it even when a shorter prefix token
// appears earlier — Thufir's "longer-of-prefix must match" case.
- let mut buf = b"xyz.block.sprout.app".to_vec();
+ let mut buf = b"xyz.block.buzz.app".to_vec();
buf.push(0);
- buf.extend_from_slice(br#""identifier":"xyz.block.sprout.app.dev""#);
- let id = b"xyz.block.sprout.app.dev";
+ buf.extend_from_slice(br#""identifier":"xyz.block.buzz.app.dev""#);
+ let id = b"xyz.block.buzz.app.dev";
assert!(super::buffer_contains_identifier(&buf, id));
}
@@ -66,36 +66,36 @@ fn identifier_empty_returns_false() {
#[test]
fn marker_entry_is_namespaced_by_instance_id() {
// The spawn stamp and the sweep matcher must produce identical bytes;
- // both go through sprout_marker_entry, so this pins the on-the-wire
+ // both go through buzz_marker_entry, so this pins the on-the-wire
// format and guards against a dev build (`...app.dev`) matching a
// release build's (`...app`) agents.
assert_eq!(
- super::sprout_marker_entry("xyz.block.sprout.app"),
- b"BUZZ_MANAGED_AGENT=xyz.block.sprout.app".to_vec()
+ super::buzz_marker_entry("xyz.block.buzz.app"),
+ b"BUZZ_MANAGED_AGENT=xyz.block.buzz.app".to_vec()
);
assert_ne!(
- super::sprout_marker_entry("xyz.block.sprout.app"),
- super::sprout_marker_entry("xyz.block.sprout.app.dev")
+ super::buzz_marker_entry("xyz.block.buzz.app"),
+ super::buzz_marker_entry("xyz.block.buzz.app.dev")
);
}
#[test]
-fn sprout_agent_has_mcp_hooks() {
- let p = known_acp_runtime("sprout-agent").expect("should resolve");
+fn buzz_agent_has_mcp_hooks() {
+ let p = known_acp_runtime("buzz-agent").expect("should resolve");
assert!(p.mcp_hooks);
- assert_eq!(p.mcp_command, Some("sprout-dev-mcp"));
+ assert_eq!(p.mcp_command, Some("buzz-dev-mcp"));
}
#[test]
fn databricks_defaults_empty_in_oss_build() {
- // OSS (and normal test) builds set neither SPROUT_BUILD_DATABRICKS_*,
+ // OSS (and normal test) builds set neither BUZZ_BUILD_DATABRICKS_*,
// so nothing is baked in and no DATABRICKS_* is injected on spawn.
assert!(super::build_databricks_defaults().is_empty());
}
#[test]
-fn sprout_agent_resolved_via_path() {
- assert!(known_acp_runtime("/usr/local/bin/sprout-agent").is_some_and(|p| p.mcp_hooks));
+fn buzz_agent_resolved_via_path() {
+ assert!(known_acp_runtime("/usr/local/bin/buzz-agent").is_some_and(|p| p.mcp_hooks));
}
#[test]
@@ -130,7 +130,7 @@ fn fixture(
auth_tag,
relay_url: "ws://localhost:3000".into(),
avatar_url: None,
- acp_command: "sprout-acp".into(),
+ acp_command: "buzz-acp".into(),
agent_command: "goose".into(),
agent_args: vec![],
mcp_command: String::new(),
@@ -374,7 +374,7 @@ fn runtime_metadata_env_vars_skips_provider_when_locked() {
#[test]
fn runtime_metadata_env_vars_injects_model_even_with_acp_model_switching() {
- // sprout-agent has supports_acp_model_switching=true but we still inject
+ // buzz-agent has supports_acp_model_switching=true but we still inject
// the model env var because ACP model switching is post-bootstrap
let vars = runtime_metadata_env_vars(
Some("BUZZ_AGENT_MODEL"),
diff --git a/desktop/src-tauri/src/managed_agents/screenshot_skill.md b/desktop/src-tauri/src/managed_agents/screenshot_skill.md
index 09b797bb2..b822d76a2 100644
--- a/desktop/src-tauri/src/managed_agents/screenshot_skill.md
+++ b/desktop/src-tauri/src/managed_agents/screenshot_skill.md
@@ -9,7 +9,7 @@ version: 1
## CRITICAL: How to Host Screenshots for PRs
-**NEVER use `sprout upload`, the relay media endpoint, or any third-party image
+**NEVER use `buzz upload`, the relay media endpoint, or any third-party image
host (imgur, imgbb, etc.) for PR screenshots.** Relay media URLs fail through
GitHub's camo proxy (`Non-Image content-type returned`). External hosts are
unreliable and may expose content.
diff --git a/desktop/src-tauri/src/managed_agents/storage.rs b/desktop/src-tauri/src/managed_agents/storage.rs
index 5540bddc7..2bd975ca0 100644
--- a/desktop/src-tauri/src/managed_agents/storage.rs
+++ b/desktop/src-tauri/src/managed_agents/storage.rs
@@ -187,7 +187,7 @@ pub fn read_log_tail(path: &Path, max_lines: usize) -> Result {
// Strip ANSI escapes here (not in the harness) so the desktop log view
// renders cleanly while terminals and other tools still get the colors
- // sprout-acp emits.
+ // buzz-acp emits.
let cleaned = strip_ansi_escapes::strip_str(String::from_utf8_lossy(&buf));
let lines: Vec<&str> = cleaned.lines().collect();
let start = lines.len().saturating_sub(max_lines);
@@ -249,10 +249,10 @@ mod tests {
#[test]
fn strips_ansi_from_typical_tracing_line() {
- let input = "\x1b[2m2026-05-27T15:16:32\x1b[0m \x1b[32m INFO\x1b[0m \x1b[2msprout_acp\x1b[0m\x1b[2m:\x1b[0m starting";
+ let input = "\x1b[2m2026-05-27T15:16:32\x1b[0m \x1b[32m INFO\x1b[0m \x1b[2mbuzz_acp\x1b[0m\x1b[2m:\x1b[0m starting";
assert_eq!(
strip_ansi_escapes::strip_str(input),
- "2026-05-27T15:16:32 INFO sprout_acp: starting"
+ "2026-05-27T15:16:32 INFO buzz_acp: starting"
);
}
}
diff --git a/desktop/src-tauri/src/managed_agents/team_repair.rs b/desktop/src-tauri/src/managed_agents/team_repair.rs
index 6e33f433c..e33d36ae2 100644
--- a/desktop/src-tauri/src/managed_agents/team_repair.rs
+++ b/desktop/src-tauri/src/managed_agents/team_repair.rs
@@ -220,7 +220,7 @@ pub fn sync_team_personas(app: &AppHandle) -> Result<(), String> {
for team in &teams {
if team.source_dir.as_ref().is_some_and(|d| d.exists()) {
if let Err(e) = sync_team_from_dir(app, &team.id) {
- eprintln!("sprout-desktop: sync team {}: {e}", team.id);
+ eprintln!("buzz-desktop: sync team {}: {e}", team.id);
}
}
}
diff --git a/desktop/src-tauri/src/managed_agents/teams.rs b/desktop/src-tauri/src/managed_agents/teams.rs
index f0f18fbb3..e8e55c3aa 100644
--- a/desktop/src-tauri/src/managed_agents/teams.rs
+++ b/desktop/src-tauri/src/managed_agents/teams.rs
@@ -230,7 +230,7 @@ pub fn import_team_from_directory(
use uuid::Uuid;
// 1. Validate + resolve at source
- let resolved = sprout_persona::resolve::resolve_pack(source_dir)
+ let resolved = buzz_persona_pkg::resolve::resolve_pack(source_dir)
.map_err(|e| format!("team directory validation failed: {e}"))?;
// 2. Sanitize team ID
@@ -271,7 +271,7 @@ pub fn import_team_from_directory(
}
// 5. Re-validate the copy/symlink target (defense-in-depth)
- let re_resolved = sprout_persona::resolve::resolve_pack(&dest).map_err(|e| {
+ let re_resolved = buzz_persona_pkg::resolve::resolve_pack(&dest).map_err(|e| {
// Clean up on failure
if use_symlink {
let _ = fs::remove_file(&dest);
@@ -445,7 +445,7 @@ pub fn sync_team_from_dir(
}
// Resolve current state of the directory
- let resolved = sprout_persona::resolve::resolve_pack(source_dir)
+ let resolved = buzz_persona_pkg::resolve::resolve_pack(source_dir)
.map_err(|e| format!("failed to resolve team directory: {e}"))?;
let mut personas = super::load_personas(app)?;
diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs
index e90e83e61..029081466 100644
--- a/desktop/src-tauri/src/managed_agents/types.rs
+++ b/desktop/src-tauri/src/managed_agents/types.rs
@@ -20,12 +20,12 @@ pub struct PersonaRecord {
pub avatar_url: Option,
pub system_prompt: String,
/// Preferred ACP runtime ID (e.g., 'goose', 'claude', 'codex'). Determines which agent binary
- /// Sprout spawns. When deploying from this persona, this runtime is pre-selected in the UI.
+ /// Buzz spawns. When deploying from this persona, this runtime is pre-selected in the UI.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub runtime: Option,
/// Opaque, harness-specific model identifier string. Format depends on the runtime and its LLM
/// provider (e.g., 'goose-claude-4-6-opus' for Databricks, 'claude-opus-4-7' for Anthropic
- /// direct). Sprout stores and passes through without interpretation.
+ /// direct). Buzz stores and passes through without interpretation.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub model: Option,
/// LLM inference provider (e.g., 'databricks', 'anthropic', 'openai'). Optional — when set,
@@ -59,7 +59,7 @@ pub struct PersonaRecord {
)]
pub source_team_persona_slug: Option,
/// Harness-level configuration passed to the agent subprocess as environment variables.
- /// Opaque to Sprout — keys and values are runtime-specific.
+ /// Opaque to Buzz — keys and values are runtime-specific.
///
/// Stored as a BTreeMap for deterministic on-disk ordering.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
@@ -123,7 +123,7 @@ pub struct ManagedAgentRecord {
/// creation by matching this ID against the fresh session/new response.
#[serde(default)]
pub model: Option,
- /// Comma-separated toolset string forwarded as SPROUT_TOOLSETS to the MCP subprocess.
+ /// Comma-separated toolset string forwarded as BUZZ_TOOLSETS to the MCP subprocess.
/// When None, the MCP server uses its own default ("default" toolset).
#[serde(default)]
pub mcp_toolsets: Option,
@@ -163,7 +163,7 @@ pub struct ManagedAgentRecord {
pub last_stopped_at: Option,
pub last_exit_code: Option,
pub last_error: Option,
- /// Inbound author gate mode. Translates to `SPROUT_ACP_RESPOND_TO`.
+ /// Inbound author gate mode. Translates to `BUZZ_ACP_RESPOND_TO`.
#[serde(default)]
pub respond_to: RespondTo,
/// Allowlist used when `respond_to == Allowlist`. Stored normalized
@@ -172,7 +172,7 @@ pub struct ManagedAgentRecord {
#[serde(default)]
pub respond_to_allowlist: Vec,
/// Typed marker for relay-mesh agents. `Some(_)` means this agent runs its
- /// inference through Sprout's relay-mesh local endpoint; the `model_ref` is
+ /// inference through Buzz's relay-mesh local endpoint; the `model_ref` is
/// the served model id to route to. `None` is a normal agent.
///
/// This is the source of truth for "is this a mesh agent + which model" —
@@ -544,9 +544,9 @@ pub struct MigrationReport {
pub errors: Vec,
}
-pub const DEFAULT_ACP_COMMAND: &str = "sprout-acp";
+pub const DEFAULT_ACP_COMMAND: &str = "buzz-acp";
pub const DEFAULT_AGENT_COMMAND: &str = "goose";
-/// ~5 min (320s) — matches the CLI harness default (SPROUT_ACP_IDLE_TIMEOUT).
+/// ~5 min (320s) — matches the CLI harness default (BUZZ_ACP_IDLE_TIMEOUT).
pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 320;
/// 1 hour — absolute wall-clock safety cap per turn.
pub const DEFAULT_AGENT_MAX_TURN_DURATION_SECONDS: u64 = 3600;
@@ -566,10 +566,10 @@ fn default_record_active() -> bool {
// ── Inbound author gate ──────────────────────────────────────────────────────
//
-// Mirrors `sprout-acp`'s `--respond-to` CLI flag and the related
+// Mirrors `buzz-acp`'s `--respond-to` CLI flag and the related
// `--respond-to-allowlist` option. Persisted per agent so the desktop can
-// translate the user's choice into `SPROUT_ACP_RESPOND_TO` /
-// `SPROUT_ACP_RESPOND_TO_ALLOWLIST` env vars at spawn time.
+// translate the user's choice into `BUZZ_ACP_RESPOND_TO` /
+// `BUZZ_ACP_RESPOND_TO_ALLOWLIST` env vars at spawn time.
//
// Wire format is kebab-case (`owner-only`, `allowlist`, `anyone`) to match
// the harness CLI vocabulary and the strings the GUI emits.
@@ -589,7 +589,7 @@ pub enum RespondTo {
}
impl RespondTo {
- /// CLI/env wire string (matches `sprout-acp`'s `--respond-to`).
+ /// CLI/env wire string (matches `buzz-acp`'s `--respond-to`).
pub fn as_str(self) -> &'static str {
match self {
Self::OwnerOnly => "owner-only",
@@ -601,7 +601,7 @@ impl RespondTo {
/// Validate and normalize a respond-to allowlist.
///
-/// Rules mirror `sprout-acp/src/config.rs::validate_allowlist`:
+/// Rules mirror `buzz-acp/src/config.rs::validate_allowlist`:
/// - Each entry is exactly 64 hex chars (any case in, lowercase out).
/// - Duplicates removed, insertion order preserved.
///
@@ -662,7 +662,7 @@ mod tests {
"name": "test-agent",
"private_key_nsec": "nsec1fake",
"relay_url": "wss://localhost:3000",
- "acp_command": "sprout-acp",
+ "acp_command": "buzz-acp",
"agent_command": "goose",
"agent_args": [],
"mcp_command": "",
@@ -692,7 +692,7 @@ mod tests {
"private_key_nsec": "nsec1fake",
"auth_tag": "[\"auth\",\"deadbeef\",\"\",\"cafebabe\"]",
"relay_url": "wss://localhost:3000",
- "acp_command": "sprout-acp",
+ "acp_command": "buzz-acp",
"agent_command": "goose",
"agent_args": [],
"mcp_command": "",
@@ -770,7 +770,7 @@ mod tests {
"name": "legacy-agent",
"private_key_nsec": "nsec1fake",
"relay_url": "wss://localhost:3000",
- "acp_command": "sprout-acp",
+ "acp_command": "buzz-acp",
"agent_command": "goose",
"agent_args": [],
"mcp_command": "",
@@ -932,7 +932,7 @@ mod tests {
"name": "test-agent",
"private_key_nsec": "nsec1fake",
"relay_url": "wss://localhost:3000",
- "acp_command": "sprout-acp",
+ "acp_command": "buzz-acp",
"agent_command": "goose",
"agent_args": [],
"mcp_command": "",
diff --git a/desktop/src-tauri/src/media_proxy.rs b/desktop/src-tauri/src/media_proxy.rs
index 7d9da399e..10a02d947 100644
--- a/desktop/src-tauri/src/media_proxy.rs
+++ b/desktop/src-tauri/src/media_proxy.rs
@@ -139,16 +139,16 @@ pub async fn spawn_media_proxy(http_client: reqwest::Client, app_handle: tauri::
axum::serve(listener, app).await.ok();
});
- eprintln!("sprout-desktop: media proxy listening on 127.0.0.1:{port}");
+ eprintln!("buzz-desktop: media proxy listening on 127.0.0.1:{port}");
port
}
/// Proxy media requests through the Rust backend so they traverse the WARP tunnel.
///
/// WKWebView's networking stack bypasses WARP, causing 403s from Cloudflare Access.
-/// This handler routes `sprout-media://localhost/{path}` through reqwest, which
+/// This handler routes `buzz-media://localhost/{path}` through reqwest, which
/// runs in the Tauri process and goes through WARP.
-pub async fn handle_sprout_media(
+pub async fn handle_buzz_media(
app: &tauri::AppHandle,
request: &http::Request>,
) -> http::Response> {
diff --git a/desktop/src-tauri/src/mesh_llm/coordinator.rs b/desktop/src-tauri/src/mesh_llm/coordinator.rs
index 7b252e181..d8f01a96f 100644
--- a/desktop/src-tauri/src/mesh_llm/coordinator.rs
+++ b/desktop/src-tauri/src/mesh_llm/coordinator.rs
@@ -9,7 +9,7 @@
//!
//! Two responsibilities:
//! 1. `spawn_listener` — a long-lived task that holds an authenticated WS to
-//! Sprout's relay (generalizing the proven `commands::pairing` NIP-42
+//! Buzz's relay (generalizing the proven `commands::pairing` NIP-42
//! machinery), subscribes `kind:24622 #p=self`, and dials each paired
//! call-me-now back into the local mesh runtime. Idempotent: one listener
//! per process; re-entrant calls return the live handle.
@@ -31,7 +31,7 @@ use tauri::{AppHandle, Manager};
use tokio::sync::watch;
use tokio_tungstenite::{connect_async, tungstenite::Message};
-use sprout_core::kind::{
+use buzz_core_pkg::kind::{
KIND_MESH_CALL_ME_NOW, KIND_MESH_CONNECT_REQUEST, KIND_MESH_STATUS_REPORT,
};
@@ -138,14 +138,14 @@ async fn status_publisher_loop(app: AppHandle) {
pub(crate) async fn publish_current_status_once(app: &AppHandle, reason: &str) {
let state = app.state::();
if let Err(error) = publish_current_status_for_state(&state).await {
- eprintln!("sprout-mesh: status report after {reason} failed: {error}");
+ eprintln!("buzz-mesh: status report after {reason} failed: {error}");
}
}
pub(crate) async fn publish_stopped_status_once(app: &AppHandle, reason: &str) {
let state = app.state::();
if let Err(error) = publish_stopped_status_for_state(&state).await {
- eprintln!("sprout-mesh: stopped status report after {reason} failed: {error}");
+ eprintln!("buzz-mesh: stopped status report after {reason} failed: {error}");
}
}
@@ -176,14 +176,14 @@ fn stopped_status_payload() -> serde_json::Value {
})
}
-/// The listener task body. Connects, authenticates as the Sprout identity,
+/// The listener task body. Connects, authenticates as the Buzz identity,
/// subscribes `24622 #p=self`, and dials each paired call-me-now. Reconnects
/// with backoff on connection loss; flips `active` to `false` while down so
/// `start_client` won't publish during an outage.
async fn listener_loop(app: AppHandle, active: watch::Sender) {
loop {
if let Err(error) = listener_session(&app, &active).await {
- eprintln!("sprout-mesh: call-me-now listener session ended: {error}");
+ eprintln!("buzz-mesh: call-me-now listener session ended: {error}");
}
let _ = active.send(false);
tokio::time::sleep(RETRY_BACKOFF).await;
@@ -236,7 +236,7 @@ async fn listener_session(app: &AppHandle, active: &watch::Sender) -> Resu
if let Err(error) =
crate::commands::ensure_client_node_for_model_dial_only(&state, &addr).await
{
- eprintln!("sprout-mesh: call-me-now dial failed: {error}");
+ eprintln!("buzz-mesh: call-me-now dial failed: {error}");
}
}
}
@@ -296,7 +296,7 @@ pub async fn start_client(
))
}
-/// Build + sign + submit the kind:24621 connect-request as the Sprout identity.
+/// Build + sign + submit the kind:24621 connect-request as the Buzz identity.
async fn publish_connect_request(
state: &AppState,
request: &RelayMeshConnectRequest<'_>,
@@ -351,7 +351,7 @@ pub(crate) async fn publish_status_report(
/// dropping expired ones.
fn call_me_now_peer_addr(event: &nostr::Event) -> Option {
let payload: serde_json::Value = serde_json::from_str(&event.content).ok()?;
- if payload.get("type")?.as_str()? != "sprout-iroh-call-me-now" {
+ if payload.get("type")?.as_str()? != "buzz-iroh-call-me-now" {
return None;
}
let now = chrono::Utc::now().timestamp().max(0) as u64;
@@ -366,7 +366,7 @@ fn call_me_now_peer_addr(event: &nostr::Event) -> Option {
.map(str::to_string)
}
-/// NIP-42 AUTH as the Sprout identity. Generalized from `commands::pairing`'s
+/// NIP-42 AUTH as the Buzz identity. Generalized from `commands::pairing`'s
/// `handle_nip42_auth` — same flow, signs with `state.keys` instead of a
/// pairing session. Returns `Ok(())` when the relay does not challenge.
async fn authenticate(
@@ -512,7 +512,7 @@ mod tests {
fn call_me_now_peer_addr_extracts_unexpired() {
let future = chrono::Utc::now().timestamp() as u64 + 30;
let event = test_event(&json!({
- "type": "sprout-iroh-call-me-now",
+ "type": "buzz-iroh-call-me-now",
"peer_endpoint_addr": "node-abc",
"attempt_id": "a1",
"expires_at": future,
@@ -523,7 +523,7 @@ mod tests {
#[test]
fn call_me_now_peer_addr_drops_expired() {
let event = test_event(&json!({
- "type": "sprout-iroh-call-me-now",
+ "type": "buzz-iroh-call-me-now",
"peer_endpoint_addr": "node-abc",
"attempt_id": "a1",
"expires_at": 1u64,
diff --git a/desktop/src-tauri/src/mesh_llm/discovery.rs b/desktop/src-tauri/src/mesh_llm/discovery.rs
index fd9ef0abc..ad12a1bf5 100644
--- a/desktop/src-tauri/src/mesh_llm/discovery.rs
+++ b/desktop/src-tauri/src/mesh_llm/discovery.rs
@@ -19,7 +19,7 @@ pub fn availability_from_events(events: Vec) -> MeshAvailability {
return MeshAvailability::unavailable("relay mesh status is not published yet");
}
- // Relay status is now per reporter (d=sprout-relay-mesh:), so a
+ // Relay status is now per reporter (d=buzz-relay-mesh:), so a
// query returns multiple replaceable events. Aggregate them; do not pick the
// newest single event or one member's machines hide everyone else's.
let mut all_targets = Vec::::new();
@@ -102,7 +102,7 @@ pub fn availability_from_events(events: Vec) -> MeshAvailability {
pub fn mesh_status_filter() -> serde_json::Value {
serde_json::json!({
"kinds": [MESH_STATUS_KIND],
- "#k": ["sprout-mesh-status"],
+ "#k": ["buzz-mesh-status"],
"limit": 100
})
}
@@ -112,8 +112,7 @@ fn reporter_pubkey_from_status_event(event: &nostr::Event) -> Option {
let slice = tag.as_slice();
let d = slice.get(1)?;
if slice.first().is_some_and(|name| name == "d") {
- d.strip_prefix("sprout-relay-mesh:")
- .map(ToString::to_string)
+ d.strip_prefix("buzz-relay-mesh:").map(ToString::to_string)
} else {
None
}
diff --git a/desktop/src-tauri/src/mesh_llm/mod.rs b/desktop/src-tauri/src/mesh_llm/mod.rs
index 21cae1c70..99b112b03 100644
--- a/desktop/src-tauri/src/mesh_llm/mod.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod.rs
@@ -21,13 +21,13 @@ const DEFAULT_MESH_CONSOLE_PORT: u16 = 3131;
const MESH_STATUS_KIND: u64 = 30_621;
const MESH_API_PORT_ENV: &str = "BUZZ_MESH_API_PORT";
const MESH_CONSOLE_PORT_ENV: &str = "BUZZ_MESH_CONSOLE_PORT";
-const RELAY_MESH_API_KEY_PLACEHOLDER: &str = "sprout-mesh-local";
+const RELAY_MESH_API_KEY_PLACEHOLDER: &str = "buzz-mesh-local";
/// ACP provider relay-mesh agents run on. Sources of truth for its command +
/// MCP live in the runtime catalog (`known_acp_runtime_exact`); these are
-/// only the fallbacks. `sprout-agent` reads the `SPROUT_AGENT_PROVIDER` /
+/// only the fallbacks. `buzz-agent` reads the `BUZZ_AGENT_PROVIDER` /
/// `OPENAI_COMPAT_*` env vars below — goose (the global default) does not.
-const MESH_AGENT_PROVIDER_ID: &str = "sprout-agent";
-const MESH_AGENT_MCP_COMMAND: &str = "sprout-dev-mcp";
+const MESH_AGENT_PROVIDER_ID: &str = "buzz-agent";
+const MESH_AGENT_MCP_COMMAND: &str = "buzz-dev-mcp";
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index 975a5708a..befcdb1aa 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -34,21 +34,21 @@ fn model_ref_is_family_agnostic() {
}
#[test]
-fn agent_preset_runs_on_sprout_agent_not_goose() {
+fn agent_preset_runs_on_buzz_agent_not_goose() {
// Regression (Tyler): the relay-mesh preset used to hand the agent the
// global default runtime (goose), which ignores the OpenAI-compat env
// vars and falls back to its own provider. Mesh agents must run on
- // sprout-agent, which reads those vars.
+ // buzz-agent, which reads those vars.
let preset = super::agent_preset(super::MeshAgentPresetRequest {
model_id: "Qwen3-8B-Q4_K_M".to_string(),
})
.expect("preset for a valid model id");
- assert_eq!(preset.agent_command, "sprout-agent");
+ assert_eq!(preset.agent_command, "buzz-agent");
assert_ne!(preset.agent_command, "goose");
- assert_eq!(preset.mcp_command, "sprout-dev-mcp");
+ assert_eq!(preset.mcp_command, "buzz-dev-mcp");
- // The env vars sprout-agent's config layer reads (crates/sprout-agent).
+ // The env vars buzz-agent's config layer reads (crates/buzz-agent).
assert_eq!(
preset
.env_vars
diff --git a/desktop/src-tauri/src/mesh_llm/preset.rs b/desktop/src-tauri/src/mesh_llm/preset.rs
index 4c8a69a51..12e12c326 100644
--- a/desktop/src-tauri/src/mesh_llm/preset.rs
+++ b/desktop/src-tauri/src/mesh_llm/preset.rs
@@ -33,14 +33,14 @@ pub fn agent_preset(request: MeshAgentPresetRequest) -> Result Option {
current.parent().map(|p| p.join(CANONICAL_DEV_IDENTIFIER))
}
+fn legacy_app_data_dir(current: &Path) -> Option {
+ let name = current.file_name()?.to_str()?;
+ let legacy_name = if name.starts_with(CANONICAL_DEV_IDENTIFIER) {
+ name.replacen(CANONICAL_DEV_IDENTIFIER, LEGACY_CANONICAL_DEV_IDENTIFIER, 1)
+ } else if name.starts_with("xyz.block.buzz.app") {
+ name.replacen("xyz.block.buzz.app", LEGACY_RELEASE_IDENTIFIER, 1)
+ } else {
+ return None;
+ };
+ current.parent().map(|parent| parent.join(legacy_name))
+}
+
+fn copy_dir_all(src: &Path, dst: &Path) -> std::io::Result<()> {
+ std::fs::create_dir_all(dst)?;
+ for entry in std::fs::read_dir(src)? {
+ let entry = entry?;
+ let src_path = entry.path();
+ let dst_path = dst.join(entry.file_name());
+ let metadata = std::fs::symlink_metadata(&src_path)?;
+ if metadata.file_type().is_symlink() {
+ #[cfg(unix)]
+ {
+ let target = std::fs::read_link(&src_path)?;
+ if dst_path.exists() || dst_path.is_symlink() {
+ let _ = std::fs::remove_file(&dst_path);
+ }
+ std::os::unix::fs::symlink(target, &dst_path)?;
+ }
+ #[cfg(not(unix))]
+ {
+ continue;
+ }
+ } else if metadata.is_dir() {
+ copy_dir_all(&src_path, &dst_path)?;
+ } else if metadata.is_file() {
+ if let Some(parent) = dst_path.parent() {
+ std::fs::create_dir_all(parent)?;
+ }
+ if !dst_path.exists() {
+ std::fs::copy(&src_path, &dst_path)?;
+ }
+ }
+ }
+ Ok(())
+}
+
+/// Copy one-time app state from the legacy app identifier directory to
+/// the current Buzz identifier directory. The Tauri identifier controls the app
+/// data path, so without this copy a product rename would look like a fresh
+/// install and users would lose their persisted identity and agent settings.
+pub fn migrate_legacy_app_data_dir(app: &tauri::AppHandle) {
+ let current_dir = match app.path().app_data_dir() {
+ Ok(dir) => dir,
+ Err(e) => {
+ eprintln!("buzz-desktop: app-data-migration: cannot resolve app data dir: {e}");
+ return;
+ }
+ };
+ let Some(legacy_dir) = legacy_app_data_dir(¤t_dir) else {
+ return;
+ };
+ if !legacy_dir.exists() {
+ return;
+ }
+ match copy_dir_all(&legacy_dir, ¤t_dir) {
+ Ok(()) => eprintln!(
+ "buzz-desktop: app-data-migration: copied legacy data from {} to {}",
+ legacy_dir.display(),
+ current_dir.display()
+ ),
+ Err(error) => eprintln!(
+ "buzz-desktop: app-data-migration: failed to copy {} to {}: {error}",
+ legacy_dir.display(),
+ current_dir.display()
+ ),
+ }
+}
+
/// Read a JSON array of objects from `path`, apply `f` to each object,
/// and write back if any mutation returned `true`.
fn patch_json_records(
@@ -46,7 +126,7 @@ fn patch_json_records(
};
let Ok(mut records) = serde_json::from_str::>(&content) else {
eprintln!(
- "sprout-desktop: patch-json-records: failed to parse {}",
+ "buzz-desktop: patch-json-records: failed to parse {}",
path.display()
);
return;
@@ -68,35 +148,33 @@ fn patch_json_records(
/// data directory to the canonical dev data directory.
///
/// Guards:
-/// - `SPROUT_SHARE_IDENTITY` must be `"1"`
-/// - `SPROUT_PRIVATE_KEY` must parse as valid `nostr::Keys`
+/// - `BUZZ_SHARE_IDENTITY` must be `"1"`
+/// - `BUZZ_PRIVATE_KEY` must parse as valid `nostr::Keys`
/// - The canonical dir must differ from the current dir (skip if we ARE canonical)
/// - The canonical dir must exist
pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
// Guard: only runs when sharing identity with a worktree.
- let is_shared = std::env::var("SPROUT_SHARE_IDENTITY")
+ let is_shared = std::env::var("BUZZ_SHARE_IDENTITY")
.map(|v| v == "1")
.unwrap_or(false);
if !is_shared {
return;
}
- // Guard: SPROUT_PRIVATE_KEY must be a valid nostr key.
- let has_valid_key = std::env::var("SPROUT_PRIVATE_KEY")
+ // Guard: BUZZ_PRIVATE_KEY must be a valid nostr key.
+ let has_valid_key = std::env::var("BUZZ_PRIVATE_KEY")
.ok()
.and_then(|k| k.parse::().ok())
.is_some();
if !has_valid_key {
- eprintln!(
- "sprout-desktop: shared-agent-sync: SPROUT_PRIVATE_KEY missing or invalid, skipping"
- );
+ eprintln!("buzz-desktop: shared-agent-sync: BUZZ_PRIVATE_KEY missing or invalid, skipping");
return;
}
let current_dir = match app.path().app_data_dir() {
Ok(dir) => dir,
Err(e) => {
- eprintln!("sprout-desktop: shared-agent-sync: cannot resolve app data dir: {e}");
+ eprintln!("buzz-desktop: shared-agent-sync: cannot resolve app data dir: {e}");
return;
}
};
@@ -104,9 +182,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
let canonical_dir = match canonical_dev_data_dir(¤t_dir) {
Some(dir) => dir,
None => {
- eprintln!(
- "sprout-desktop: shared-agent-sync: cannot compute canonical dir (no parent)"
- );
+ eprintln!("buzz-desktop: shared-agent-sync: cannot compute canonical dir (no parent)");
return;
}
};
@@ -124,7 +200,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
// Guard: skip if canonical dir doesn't exist.
if !canonical_dir.exists() {
eprintln!(
- "sprout-desktop: shared-agent-sync: canonical dir does not exist: {}",
+ "buzz-desktop: shared-agent-sync: canonical dir does not exist: {}",
canonical_dir.display()
);
return;
@@ -142,7 +218,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
if let Some(parent) = dst.parent() {
if let Err(e) = std::fs::create_dir_all(parent) {
eprintln!(
- "sprout-desktop: shared-agent-sync: failed to create {}: {e}",
+ "buzz-desktop: shared-agent-sync: failed to create {}: {e}",
parent.display()
);
continue;
@@ -166,7 +242,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
match std::os::unix::fs::symlink(&src, &dst) {
Ok(_) => synced += 1,
Err(e) => {
- eprintln!("sprout-desktop: shared-agent-sync: failed to symlink {rel}: {e}");
+ eprintln!("buzz-desktop: shared-agent-sync: failed to symlink {rel}: {e}");
}
}
}
@@ -179,7 +255,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
if !canonical_target.exists() {
if let Err(e) = std::fs::create_dir_all(&canonical_target) {
eprintln!(
- "sprout-desktop: shared-agent-sync: failed to create {}: {e}",
+ "buzz-desktop: shared-agent-sync: failed to create {}: {e}",
canonical_target.display()
);
}
@@ -205,7 +281,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
let _ = std::fs::remove_dir_all(&sibling_dir);
let _ = std::os::unix::fs::symlink(&canonical_target, &sibling_dir);
eprintln!(
- "sprout-desktop: shared-agent-sync: migrated {rel} from {}",
+ "buzz-desktop: shared-agent-sync: migrated {rel} from {}",
sibling.display()
);
break;
@@ -227,7 +303,7 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
if let Some(parent) = dst.parent() {
if let Err(e) = std::fs::create_dir_all(parent) {
eprintln!(
- "sprout-desktop: shared-agent-sync: failed to create {}: {e}",
+ "buzz-desktop: shared-agent-sync: failed to create {}: {e}",
parent.display()
);
continue;
@@ -251,14 +327,14 @@ pub fn sync_shared_agent_data(app: &tauri::AppHandle) {
match std::os::unix::fs::symlink(&src, &dst) {
Ok(_) => synced += 1,
Err(e) => {
- eprintln!("sprout-desktop: shared-agent-sync: failed to symlink {rel}: {e}");
+ eprintln!("buzz-desktop: shared-agent-sync: failed to symlink {rel}: {e}");
}
}
}
if synced > 0 {
eprintln!(
- "sprout-desktop: shared-agent-sync: {synced} item(s) linked to {}",
+ "buzz-desktop: shared-agent-sync: {synced} item(s) linked to {}",
canonical_dir.display()
);
}
@@ -300,7 +376,7 @@ fn reconcile_team_dirs_in_file(path: &Path, canonical_dir: &Path) {
return false;
}
eprintln!(
- "sprout-desktop: team-dir-reconcile: {:?}: {:?} → {:?}",
+ "buzz-desktop: team-dir-reconcile: {:?}: {:?} → {:?}",
obj.get("name").and_then(|v| v.as_str()).unwrap_or("?"),
team_path,
expected,
@@ -417,9 +493,7 @@ pub fn migrate_packs_to_teams(app: &tauri::AppHandle) {
report
.errors
.push(format!("failed to rename packs → teams: {e}"));
- eprintln!(
- "sprout-desktop: packs→teams migration: directory rename failed: {e}"
- );
+ eprintln!("buzz-desktop: packs→teams migration: directory rename failed: {e}");
return;
}
}
@@ -472,7 +546,7 @@ pub fn migrate_packs_to_teams(app: &tauri::AppHandle) {
if report.packs_migrated > 0 || report.personas_updated > 0 || report.agents_updated > 0 {
eprintln!(
- "sprout-desktop: packs→teams migration complete: {} dirs, {} personas, {} agents{}",
+ "buzz-desktop: packs→teams migration complete: {} dirs, {} personas, {} agents{}",
report.packs_migrated,
report.personas_updated,
report.agents_updated,
@@ -504,11 +578,11 @@ fn reconcile_mcp_commands_in_file(path: &Path) {
}
// Only fix values that are clearly stale (empty or a removed binary).
// Leave user-customized values untouched.
- if !current.is_empty() && current != "sprout-mcp-server" {
+ if !current.is_empty() && current != "buzz-mcp-server" {
return false;
}
eprintln!(
- "sprout-desktop: runtime-reconcile: {:?} ({:?}): mcp_command {:?} → {:?}",
+ "buzz-desktop: runtime-reconcile: {:?} ({:?}): mcp_command {:?} → {:?}",
obj.get("name").and_then(|v| v.as_str()).unwrap_or("?"),
agent_command,
current,
diff --git a/desktop/src-tauri/src/migration_tests.rs b/desktop/src-tauri/src/migration_tests.rs
index 133228856..21bf4fcfb 100644
--- a/desktop/src-tauri/src/migration_tests.rs
+++ b/desktop/src-tauri/src/migration_tests.rs
@@ -3,11 +3,11 @@ use super::*;
#[test]
fn canonical_dev_data_dir_replaces_last_component() {
let current =
- PathBuf::from("/Users/me/Library/Application Support/xyz.block.sprout.app.dev.my-branch");
+ PathBuf::from("/Users/me/Library/Application Support/xyz.block.buzz.app.dev.my-branch");
let canonical = canonical_dev_data_dir(¤t).unwrap();
assert_eq!(
canonical,
- PathBuf::from("/Users/me/Library/Application Support/xyz.block.sprout.app.dev")
+ PathBuf::from("/Users/me/Library/Application Support/xyz.block.buzz.app.dev")
);
}
@@ -17,14 +17,58 @@ fn canonical_dev_data_dir_returns_none_for_root() {
assert!(canonical_dev_data_dir(Path::new("/")).is_none());
}
+#[test]
+fn legacy_app_data_dir_maps_release_identifier() {
+ let current = PathBuf::from("/Users/me/Library/Application Support/xyz.block.buzz.app");
+ let legacy = legacy_app_data_dir(¤t).unwrap();
+ assert_eq!(
+ legacy,
+ PathBuf::from("/Users/me/Library/Application Support/xyz.block.sprout.app")
+ );
+}
+
+#[test]
+fn legacy_app_data_dir_maps_dev_worktree_identifier() {
+ let current =
+ PathBuf::from("/Users/me/Library/Application Support/xyz.block.buzz.app.dev.my-branch");
+ let legacy = legacy_app_data_dir(¤t).unwrap();
+ assert_eq!(
+ legacy,
+ PathBuf::from("/Users/me/Library/Application Support/xyz.block.sprout.app.dev.my-branch",)
+ );
+}
+
+#[test]
+fn copy_dir_all_preserves_nested_files_without_overwriting() {
+ let dir = tempfile::tempdir().unwrap();
+ let src = dir.path().join("old");
+ let dst = dir.path().join("new");
+ std::fs::create_dir_all(src.join("agents")).unwrap();
+ std::fs::write(src.join("identity.key"), "old-key").unwrap();
+ std::fs::write(src.join("agents/managed-agents.json"), "old-agents").unwrap();
+ std::fs::create_dir_all(&dst).unwrap();
+ std::fs::write(dst.join("identity.key"), "new-key").unwrap();
+
+ copy_dir_all(&src, &dst).unwrap();
+
+ assert_eq!(
+ std::fs::read_to_string(dst.join("identity.key")).unwrap(),
+ "new-key"
+ );
+ assert_eq!(
+ std::fs::read_to_string(dst.join("agents/managed-agents.json")).unwrap(),
+ "old-agents"
+ );
+}
+
/// Helper: create a temp dir structure mimicking canonical + worktree layout.
/// Packs live in a `.main` sibling (not canonical) to match real-world state.
/// Returns `(parent_dir_handle, canonical_dir, worktree_dir)`.
fn setup_sync_layout() -> (tempfile::TempDir, PathBuf, PathBuf) {
let parent = tempfile::tempdir().unwrap();
let canonical = parent.path().join(CANONICAL_DEV_IDENTIFIER);
- let worktree = parent.path().join("xyz.block.sprout.app.dev.my-branch");
- let main_instance = parent.path().join("xyz.block.sprout.app.dev.main");
+ let worktree = parent.path().join("xyz.block.buzz.app.dev.my-branch");
+ let main_instance = parent.path().join("xyz.block.buzz.app.dev.main");
std::fs::create_dir_all(canonical.join("agents")).unwrap();
std::fs::write(
@@ -264,10 +308,10 @@ fn canonical_dev_data_dir_returns_self_for_canonical_instance() {
// When the current app data dir IS the canonical dev identifier,
// canonical_dev_data_dir returns the exact same path — the caller
// (sync_shared_agent_data) uses this equality to skip the sync.
- // The env-var guards (SPROUT_SHARE_IDENTITY, SPROUT_PRIVATE_KEY)
+ // The env-var guards (BUZZ_SHARE_IDENTITY, BUZZ_PRIVATE_KEY)
// require a live Tauri AppHandle and are covered by integration
// testing only.
- let current = PathBuf::from("/Users/me/Library/Application Support/xyz.block.sprout.app.dev");
+ let current = PathBuf::from("/Users/me/Library/Application Support/xyz.block.buzz.app.dev");
assert_eq!(canonical_dev_data_dir(¤t).unwrap(), current);
// Also verify with a temp dir on the real filesystem.
@@ -316,7 +360,7 @@ fn sync_migrates_teams_from_sibling_to_canonical() {
let main_instance = canonical
.parent()
.unwrap()
- .join("xyz.block.sprout.app.dev.main");
+ .join("xyz.block.buzz.app.dev.main");
// Before sync: canonical has no teams, .main has the real team dir.
assert!(!canonical.join("agents/teams").exists());
@@ -363,7 +407,7 @@ fn team_dir_reconcile_rewrites_worktree_path() {
"{}/agents/packs/com.wpfleger.sietch-tabr",
parent
.path()
- .join("xyz.block.sprout.app.dev.worktree-my-branch")
+ .join("xyz.block.buzz.app.dev.worktree-my-branch")
.display()
);
let expected_path = format!(
@@ -397,7 +441,7 @@ fn team_dir_reconcile_rewrites_new_field_name() {
"{}/agents/teams/com.wpfleger.sietch-tabr",
parent
.path()
- .join("xyz.block.sprout.app.dev.worktree-my-branch")
+ .join("xyz.block.buzz.app.dev.worktree-my-branch")
.display()
);
let expected_path = format!(
@@ -455,7 +499,7 @@ fn team_dir_reconcile_skips_records_without_team_dir() {
&canonical,
&serde_json::json!([{
"name": "Test Agent",
- "agent_command": "sprout-agent"
+ "agent_command": "buzz-agent"
}]),
);
@@ -476,7 +520,7 @@ fn team_dir_reconcile_is_idempotent() {
"{}/agents/packs/com.wpfleger.sietch-tabr",
parent
.path()
- .join("xyz.block.sprout.app.dev.worktree-my-branch")
+ .join("xyz.block.buzz.app.dev.worktree-my-branch")
.display()
);
@@ -719,14 +763,14 @@ fn rename_provider_to_runtime_preserves_existing_runtime_over_provider() {
}
#[test]
-fn reconcile_mcp_commands_clears_stale_sprout_mcp_server() {
+fn reconcile_mcp_commands_clears_stale_buzz_mcp_server() {
let dir = tempfile::tempdir().unwrap();
write_agents_json(
dir.path(),
&serde_json::json!([{
"name": "Solo",
"agent_command": "goose",
- "mcp_command": "sprout-mcp-server"
+ "mcp_command": "buzz-mcp-server"
}]),
);
reconcile_mcp_commands_in_file(&dir.path().join("agents/managed-agents.json"));
@@ -735,19 +779,19 @@ fn reconcile_mcp_commands_clears_stale_sprout_mcp_server() {
}
#[test]
-fn reconcile_mcp_commands_sets_canonical_for_sprout_agent() {
+fn reconcile_mcp_commands_sets_canonical_for_buzz_agent() {
let dir = tempfile::tempdir().unwrap();
write_agents_json(
dir.path(),
&serde_json::json!([{
"name": "Stilgar",
- "agent_command": "sprout-agent",
- "mcp_command": "sprout-mcp-server"
+ "agent_command": "buzz-agent",
+ "mcp_command": "buzz-mcp-server"
}]),
);
reconcile_mcp_commands_in_file(&dir.path().join("agents/managed-agents.json"));
let records = read_agents_json(dir.path());
- assert_eq!(records[0]["mcp_command"], "sprout-dev-mcp");
+ assert_eq!(records[0]["mcp_command"], "buzz-dev-mcp");
}
#[test]
@@ -771,7 +815,7 @@ fn reconcile_mcp_commands_leaves_unknown_runtime_untouched() {
let json = serde_json::json!([{
"name": "Custom",
"agent_command": "my-custom-agent",
- "mcp_command": "sprout-mcp-server"
+ "mcp_command": "buzz-mcp-server"
}]);
write_agents_json(dir.path(), &json);
let path = dir.path().join("agents/managed-agents.json");
@@ -788,7 +832,7 @@ fn reconcile_mcp_commands_is_idempotent() {
&serde_json::json!([{
"name": "Solo",
"agent_command": "goose",
- "mcp_command": "sprout-mcp-server"
+ "mcp_command": "buzz-mcp-server"
}]),
);
let path = dir.path().join("agents/managed-agents.json");
@@ -804,10 +848,10 @@ fn reconcile_mcp_commands_handles_mixed_agents() {
write_agents_json(
dir.path(),
&serde_json::json!([
- {"name": "Stale Goose", "agent_command": "goose", "mcp_command": "sprout-mcp-server"},
+ {"name": "Stale Goose", "agent_command": "goose", "mcp_command": "buzz-mcp-server"},
{"name": "Clean Goose", "agent_command": "goose", "mcp_command": ""},
{"name": "Custom Agent", "agent_command": "goose", "mcp_command": "my-custom-mcp"},
- {"name": "Stale Sprout", "agent_command": "sprout-agent", "mcp_command": "sprout-mcp-server"}
+ {"name": "Stale Buzz", "agent_command": "buzz-agent", "mcp_command": "buzz-mcp-server"}
]),
);
reconcile_mcp_commands_in_file(&dir.path().join("agents/managed-agents.json"));
@@ -815,7 +859,7 @@ fn reconcile_mcp_commands_handles_mixed_agents() {
assert_eq!(records[0]["mcp_command"], "");
assert_eq!(records[1]["mcp_command"], "");
assert_eq!(records[2]["mcp_command"], "my-custom-mcp");
- assert_eq!(records[3]["mcp_command"], "sprout-dev-mcp");
+ assert_eq!(records[3]["mcp_command"], "buzz-dev-mcp");
}
#[test]
@@ -823,7 +867,7 @@ fn reconcile_mcp_commands_skips_record_without_agent_command() {
let dir = tempfile::tempdir().unwrap();
let json = serde_json::json!([{
"name": "No Command",
- "mcp_command": "sprout-mcp-server"
+ "mcp_command": "buzz-mcp-server"
}]);
write_agents_json(dir.path(), &json);
let path = dir.path().join("agents/managed-agents.json");
diff --git a/desktop/src-tauri/src/nostr_convert.rs b/desktop/src-tauri/src/nostr_convert.rs
index 5ea7467de..aeb7f8c59 100644
--- a/desktop/src-tauri/src/nostr_convert.rs
+++ b/desktop/src-tauri/src/nostr_convert.rs
@@ -75,7 +75,7 @@ pub(crate) fn profile_has_valid_oa_owner(event: &Event) -> bool {
let Ok(json) = serde_json::to_string(slice) else {
continue;
};
- if sprout_sdk::nip_oa::verify_auth_tag(&json, &target_pubkey).is_ok() {
+ if buzz_sdk_pkg::nip_oa::verify_auth_tag(&json, &target_pubkey).is_ok() {
return true;
}
}
@@ -590,7 +590,7 @@ mod tests {
let agent_keys = Keys::generate();
let owner_keys = Keys::generate();
let agent_pubkey = agent_keys.public_key();
- let tag_json = sprout_sdk::nip_oa::compute_auth_tag(&owner_keys, &agent_pubkey, "")
+ let tag_json = buzz_sdk_pkg::nip_oa::compute_auth_tag(&owner_keys, &agent_pubkey, "")
.expect("compute auth tag");
let tag_values: Vec = serde_json::from_str(&tag_json).expect("parse auth tag json");
let auth_tag = Tag::parse(tag_values).expect("parse auth tag");
diff --git a/desktop/src-tauri/src/nostr_convert/user_search.rs b/desktop/src-tauri/src/nostr_convert/user_search.rs
index cdee90b72..85a68df14 100644
--- a/desktop/src-tauri/src/nostr_convert/user_search.rs
+++ b/desktop/src-tauri/src/nostr_convert/user_search.rs
@@ -200,7 +200,7 @@ mod tests {
let agent_keys = nostr::Keys::generate();
let owner_keys = nostr::Keys::generate();
let agent_pubkey = agent_keys.public_key();
- let tag_json = sprout_sdk::nip_oa::compute_auth_tag(&owner_keys, &agent_pubkey, "")
+ let tag_json = buzz_sdk_pkg::nip_oa::compute_auth_tag(&owner_keys, &agent_pubkey, "")
.expect("compute auth tag");
let tag_values: Vec = serde_json::from_str(&tag_json).expect("parse auth tag json");
let auth_tag = Tag::parse(tag_values).expect("parse auth tag");
diff --git a/desktop/src-tauri/src/prevent_sleep.rs b/desktop/src-tauri/src/prevent_sleep.rs
index 4679caf06..21e843500 100644
--- a/desktop/src-tauri/src/prevent_sleep.rs
+++ b/desktop/src-tauri/src/prevent_sleep.rs
@@ -62,7 +62,7 @@ pub fn acquire(
#[cfg(target_os = "macos")]
{
let assertion_type = c"PreventUserIdleSystemSleep".as_ptr();
- let reason = c"Sprout \u{2014} agents are active".as_ptr();
+ let reason = c"Buzz \u{2014} agents are active".as_ptr();
unsafe {
let cf_type = macos::CFStringCreateWithCString(
diff --git a/desktop/src-tauri/src/relay.rs b/desktop/src-tauri/src/relay.rs
index e02c23ff2..3333687ff 100644
--- a/desktop/src-tauri/src/relay.rs
+++ b/desktop/src-tauri/src/relay.rs
@@ -5,7 +5,7 @@ use serde::de::DeserializeOwned;
use serde::Deserialize;
use sha2::{Digest, Sha256};
-// nostr 0.36 alias — required for cross-version bridging with sprout-sdk.
+// nostr 0.36 alias — required for cross-version bridging with buzz-sdk.
use crate::app_state::AppState;
@@ -191,7 +191,7 @@ pub async fn query_relay_at(
/// Parse a command-event OK message of the form `"response:"`.
///
-/// Sprout's command kinds (e.g. 41010, 30620, 46020) acknowledge writes via
+/// Buzz's command kinds (e.g. 41010, 30620, 46020) acknowledge writes via
/// relay OK messages whose payload is a `response:`-prefixed JSON document.
/// This helper strips the prefix and deserializes the remainder as `T`.
pub fn parse_command_response(message: &str) -> Result {
@@ -211,7 +211,7 @@ pub fn parse_command_response(message: &str) -> Result String {
let owner_keys = nostr::Keys::generate();
let agent_pubkey_hex = agent_keys.public_key().to_hex();
let agent_compat_pubkey =
nostr::PublicKey::from_hex(&agent_pubkey_hex).expect("valid hex pubkey should parse");
- sprout_sdk::nip_oa::compute_auth_tag(&owner_keys, &agent_compat_pubkey, "")
+ buzz_sdk_pkg::nip_oa::compute_auth_tag(&owner_keys, &agent_compat_pubkey, "")
.expect("compute_auth_tag should not fail with distinct keys")
}
diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json
index 5d41d21e0..9fbe0db08 100644
--- a/desktop/src-tauri/tauri.conf.json
+++ b/desktop/src-tauri/tauri.conf.json
@@ -1,8 +1,8 @@
{
"$schema": "https://schema.tauri.app/config/2",
- "productName": "Sprout",
+ "productName": "Buzz",
"version": "0.3.16",
- "identifier": "xyz.block.sprout.app",
+ "identifier": "xyz.block.buzz.app",
"build": {
"beforeDevCommand": {
"script": "exec ./node_modules/.bin/vite",
@@ -43,7 +43,7 @@
},
"deep-link": {
"desktop": {
- "schemes": ["sprout", "buzz"]
+ "schemes": ["buzz"]
}
}
},
diff --git a/desktop/src-tauri/tauri.dev.conf.json b/desktop/src-tauri/tauri.dev.conf.json
index 30902f2f5..dd2b86c58 100644
--- a/desktop/src-tauri/tauri.dev.conf.json
+++ b/desktop/src-tauri/tauri.dev.conf.json
@@ -1,4 +1,4 @@
{
- "identifier": "xyz.block.sprout.app.dev",
- "productName": "Sprout Dev"
+ "identifier": "xyz.block.buzz.app.dev",
+ "productName": "Buzz Dev"
}
diff --git a/desktop/src/app/App.tsx b/desktop/src/app/App.tsx
index 80b6f4a4c..5eb266cd2 100644
--- a/desktop/src/app/App.tsx
+++ b/desktop/src/app/App.tsx
@@ -1,7 +1,7 @@
import { getCurrentWindow } from "@tauri-apps/api/window";
import { QueryClientProvider } from "@tanstack/react-query";
import { RouterProvider } from "@tanstack/react-router";
-import { Sprout } from "lucide-react";
+import { Hexagon } from "lucide-react";
import {
type ReactNode,
useCallback,
@@ -19,7 +19,7 @@ import type { Workspace } from "@/features/workspaces/types";
import { useWorkspaceInit } from "@/features/workspaces/useWorkspaceInit";
import { useWorkspaces } from "@/features/workspaces/useWorkspaces";
import { WelcomeSetup } from "@/features/workspaces/ui/WelcomeSetup";
-import { createSproutQueryClient } from "@/shared/api/queryClient";
+import { createBuzzQueryClient } from "@/shared/api/queryClient";
import { isSharedIdentity as isSharedIdentityCmd } from "@/shared/api/tauri";
import { listenForDeepLinks } from "@/shared/deep-link";
import { useSystemColorScheme } from "@/shared/theme/useSystemColorScheme";
@@ -31,7 +31,7 @@ const LOADING_TEXT = "Setting up your workspace...";
function AppLoadingGate() {
return (
@@ -40,7 +40,7 @@ function AppLoadingGate() {
className="mt-6 text-center text-3xl font-semibold tracking-tight text-foreground"
>
{LOADING_TEXT}
-
+
{LOADING_TEXT}
@@ -53,7 +53,7 @@ function OnboardingLoadingGate() {
return (
@@ -72,11 +72,11 @@ function OnboardingLoadingGate() {
transitionKey="workspace-connecting"
>
-
+
- Welcome to Sprout
+ Welcome to Buzz
Choose your first workspace to get started.
@@ -120,7 +120,7 @@ function OnboardingLoadingGate() {
}
function WorkspaceQueryProvider({ children }: { children: ReactNode }) {
- const [queryClient] = useState(createSproutQueryClient);
+ const [queryClient] = useState(createBuzzQueryClient);
return (
{children}
diff --git a/desktop/src/app/useWebviewZoomShortcuts.ts b/desktop/src/app/useWebviewZoomShortcuts.ts
index 5ac6dc56c..cda6c0f2e 100644
--- a/desktop/src/app/useWebviewZoomShortcuts.ts
+++ b/desktop/src/app/useWebviewZoomShortcuts.ts
@@ -8,7 +8,7 @@ const MIN_ZOOM_FACTOR = 0.75;
const MAX_ZOOM_FACTOR = 1.5;
const ZOOM_STEP = 0.1;
const BASE_FONT_SIZE_PX = 16;
-const TEXT_SCALE_STORAGE_KEY = "sprout:text-scale";
+const TEXT_SCALE_STORAGE_KEY = "buzz:text-scale";
type ZoomAction = "increase" | "decrease" | "reset";
diff --git a/desktop/src/features/agents/channelAgents.ts b/desktop/src/features/agents/channelAgents.ts
index 539403840..4ce40ec41 100644
--- a/desktop/src/features/agents/channelAgents.ts
+++ b/desktop/src/features/agents/channelAgents.ts
@@ -224,7 +224,7 @@ export async function ensureChannelAgentPresetInChannel(
const created = await createManagedAgent({
name: expectedName,
- acpCommand: "sprout-acp",
+ acpCommand: "buzz-acp",
agentCommand: input.runtime.command,
agentArgs: input.runtime.defaultArgs,
mcpCommand: input.runtime.mcpCommand ?? "",
@@ -366,7 +366,7 @@ export async function createChannelManagedAgent(
const created = await createManagedAgent({
name: trimmedName,
- acpCommand: "sprout-acp",
+ acpCommand: "buzz-acp",
agentCommand: input.runtime.command,
agentArgs: input.runtime.defaultArgs,
mcpCommand: input.runtime.mcpCommand ?? "",
diff --git a/desktop/src/features/agents/lib/friendlyAgentLastError.test.mjs b/desktop/src/features/agents/lib/friendlyAgentLastError.test.mjs
index e1d0ddcc0..e81de8c2f 100644
--- a/desktop/src/features/agents/lib/friendlyAgentLastError.test.mjs
+++ b/desktop/src/features/agents/lib/friendlyAgentLastError.test.mjs
@@ -15,7 +15,7 @@ test("empty/whitespace lastError → null", () => {
assert.equal(friendlyAgentLastError(" "), null);
});
-test("sprout-acp wrapped auth failure → denied copy", () => {
+test("buzz-acp wrapped auth failure → denied copy", () => {
const result = friendlyAgentLastError(
"Agent reported error: llm auth: 401 unauthorized: ...",
);
@@ -25,8 +25,8 @@ test("sprout-acp wrapped auth failure → denied copy", () => {
});
});
-test("unwrapped sprout-agent prefix → denied copy", () => {
- // sprout-agent's AgentError::LlmAuth Display is "llm auth:
"; if the
+test("unwrapped buzz-agent prefix → denied copy", () => {
+ // buzz-agent's AgentError::LlmAuth Display is "llm auth: "; if the
// desktop ever picks that up directly (no AcpError wrapper), we should
// still recognize it as denial.
const result = friendlyAgentLastError("llm auth: 403 forbidden");
diff --git a/desktop/src/features/agents/lib/friendlyAgentLastError.ts b/desktop/src/features/agents/lib/friendlyAgentLastError.ts
index cba5fad38..6060f511d 100644
--- a/desktop/src/features/agents/lib/friendlyAgentLastError.ts
+++ b/desktop/src/features/agents/lib/friendlyAgentLastError.ts
@@ -2,10 +2,10 @@
* Promote certain machine-readable `lastError` strings to user-facing copy.
*
* The mesh-llm seam (Max's commit `5196203…`) flows like this:
- * sprout-agent — gets HTTP 401/403 from the OpenAI-compatible mesh endpoint
+ * buzz-agent — gets HTTP 401/403 from the OpenAI-compatible mesh endpoint
* → raises `AgentError::LlmAuth("…")` (json_rpc_code `-32001`,
* Display prefix `"llm auth: …"`)
- * sprout-acp — wraps it as `AcpError::AgentError("Agent reported error: llm auth: …")`
+ * buzz-acp — wraps it as `AcpError::AgentError("Agent reported error: llm auth: …")`
* desktop managed-agent supervisor — on nonzero exit, scans `read_log_tail`
* for `"Agent reported error:"` / `"llm auth:"` and persists
* that line into `ManagedAgent.lastError` instead of the
@@ -44,7 +44,7 @@ export function friendlyAgentLastError(
const trimmed = raw.trim();
if (trimmed.length === 0) return null;
- // Match either the unwrapped sprout-agent prefix or the sprout-acp wrap.
+ // Match either the unwrapped buzz-agent prefix or the buzz-acp wrap.
// The desktop supervisor recovers whichever appears first in the log tail.
if (
trimmed.startsWith("Agent reported error: llm auth:") ||
diff --git a/desktop/src/features/agents/lib/managedAgentControlActions.test.mjs b/desktop/src/features/agents/lib/managedAgentControlActions.test.mjs
index 81899aa4e..af225e464 100644
--- a/desktop/src/features/agents/lib/managedAgentControlActions.test.mjs
+++ b/desktop/src/features/agents/lib/managedAgentControlActions.test.mjs
@@ -9,7 +9,7 @@ function agent(overrides = {}) {
name: "Mesh Agent",
personaId: null,
relayUrl: "ws://localhost:3000",
- acpCommand: "sprout-acp",
+ acpCommand: "buzz-acp",
agentCommand: "goose",
agentArgs: [],
mcpCommand: "",
@@ -42,7 +42,7 @@ function agent(overrides = {}) {
test("relay-mesh agents delegate start to the backend preflight", async () => {
const meshAgent = agent({
envVars: {
- SPROUT_AGENT_PROVIDER: "openai",
+ BUZZ_AGENT_PROVIDER: "openai",
OPENAI_COMPAT_BASE_URL: "http://127.0.0.1:9337/v1/",
},
});
diff --git a/desktop/src/features/agents/lib/useBotRecents.ts b/desktop/src/features/agents/lib/useBotRecents.ts
index a98bfe32b..8f2f58848 100644
--- a/desktop/src/features/agents/lib/useBotRecents.ts
+++ b/desktop/src/features/agents/lib/useBotRecents.ts
@@ -2,7 +2,7 @@ import * as React from "react";
import type { AgentPersona } from "@/shared/api/types";
-const STORAGE_KEY = "sprout:bot-recents";
+const STORAGE_KEY = "buzz:bot-recents";
const MAX_RECENTS = 8;
// Default persona display names to seed the list when empty.
diff --git a/desktop/src/features/agents/lib/useLastRuntime.ts b/desktop/src/features/agents/lib/useLastRuntime.ts
index 565a7eb7a..e58375590 100644
--- a/desktop/src/features/agents/lib/useLastRuntime.ts
+++ b/desktop/src/features/agents/lib/useLastRuntime.ts
@@ -1,7 +1,7 @@
import * as React from "react";
-const STORAGE_KEY = "sprout:last-runtime";
-const LEGACY_STORAGE_KEY = "sprout:last-runtime-provider";
+const STORAGE_KEY = "buzz:last-runtime";
+const LEGACY_STORAGE_KEY = "buzz:last-runtime-provider";
export function useLastRuntime(): {
lastRuntimeId: string | null;
diff --git a/desktop/src/features/agents/ui/AgentSessionToolItem.tsx b/desktop/src/features/agents/ui/AgentSessionToolItem.tsx
index 6cff5e271..09411f2e6 100644
--- a/desktop/src/features/agents/ui/AgentSessionToolItem.tsx
+++ b/desktop/src/features/agents/ui/AgentSessionToolItem.tsx
@@ -12,7 +12,7 @@ import { UserAvatar } from "@/shared/ui/UserAvatar";
import type { TranscriptItem } from "./agentSessionTypes";
import {
formatToolTitle,
- getSproutToolInfo,
+ getBuzzToolInfo,
getToolStatusDisplay,
} from "./agentSessionToolCatalog";
import {
@@ -35,9 +35,9 @@ export function ToolItem({
const status = getToolStatusDisplay(item.status, item.isError);
const hasArgs = Object.keys(item.args).length > 0;
const hasResult = item.result.trim().length > 0;
- const canonicalToolName = item.sproutToolName ?? item.toolName;
- const sproutTool = getSproutToolInfo(canonicalToolName);
- const ToolIcon = sproutTool?.icon ?? Wrench;
+ const canonicalToolName = item.buzzToolName ?? item.toolName;
+ const buzzTool = getBuzzToolInfo(canonicalToolName);
+ const ToolIcon = buzzTool?.icon ?? Wrench;
const showStatus = status.state !== "output-available";
const toolTitle = formatToolTitle(canonicalToolName, item.title);
const handleToggle = React.useCallback(
@@ -59,15 +59,15 @@ export function ToolItem({
) : null}
{toolTitle}
- {sproutTool ? (
-
+ {buzzTool ? (
+
) : null}
{showStatus ? (
@@ -86,7 +86,7 @@ export function ToolItem({
- getSproutToolInlineAction({
+ getBuzzToolInlineAction({
args,
channelId,
channels,
@@ -289,7 +289,7 @@ function SproutToolInlineAction({
);
}
-type SproutToolInlineActionModel = {
+type BuzzToolInlineActionModel = {
avatar?: React.ReactNode;
label: string;
value: string;
@@ -297,7 +297,7 @@ type SproutToolInlineActionModel = {
onClick?: () => void;
};
-function getSproutToolInlineAction({
+function getBuzzToolInlineAction({
args,
channelId,
channels,
@@ -311,7 +311,7 @@ function getSproutToolInlineAction({
openChannel: (messageId?: string) => void;
profiles: Record | undefined;
resultValue: unknown;
-}): SproutToolInlineActionModel | null {
+}): BuzzToolInlineActionModel | null {
const resultRecord = asRecord(resultValue);
const eventId =
getToolString(args, ["event_id", "eventId"]) ??
diff --git a/desktop/src/features/agents/ui/CreateAgentDialog.tsx b/desktop/src/features/agents/ui/CreateAgentDialog.tsx
index f49d0c592..37f135031 100644
--- a/desktop/src/features/agents/ui/CreateAgentDialog.tsx
+++ b/desktop/src/features/agents/ui/CreateAgentDialog.tsx
@@ -56,7 +56,7 @@ export function CreateAgentDialog({
const allProvidersQuery = useAcpRuntimesQuery();
const backendProvidersQuery = useBackendProvidersQuery();
const { lastRuntimeId, setLastRuntime } = useLastRuntime();
- const [acpCommand, setAcpCommand] = React.useState("sprout-acp");
+ const [acpCommand, setAcpCommand] = React.useState("buzz-acp");
const [agentCommand, setAgentCommand] = React.useState("goose");
const [agentArgs, setAgentArgs] = React.useState("acp");
const [mcpCommand, setMcpCommand] = React.useState("");
@@ -90,7 +90,7 @@ export function CreateAgentDialog({
const [probeError, setProbeError] = React.useState(null);
// ── Relay-mesh flow state ──────────────────────────────────────────────────
- // When `useMesh` is on, the agent runs sprout-agent against a member's
+ // When `useMesh` is on, the agent runs buzz-agent against a member's
// shared compute. The ACP runtime + backend selectors are hidden; runtime
// fields are driven by `mesh_agent_preset(meshModelId)` and the submit
// input carries `model: meshModelId`.
@@ -122,7 +122,7 @@ export function CreateAgentDialog({
() => backendProviders.find((p) => p.id === runOn) ?? null,
[backendProviders, runOn],
);
- // Relay mesh always runs in local mode (sprout-agent + OpenAI-compat env);
+ // Relay mesh always runs in local mode (buzz-agent + OpenAI-compat env);
// when on, it suppresses the backend "Run on" branch even if a stale
// `runOn` value remains. The relay-mesh path is its own thing.
const isProviderMode = !useMesh && runOn !== "local";
@@ -235,7 +235,7 @@ export function CreateAgentDialog({
setRelayUrl("");
setSpawnAfterCreate(true);
setStartOnAppLaunch(true);
- setAcpCommand("sprout-acp");
+ setAcpCommand("buzz-acp");
setAgentCommand("goose");
setAgentArgs("acp");
setMcpCommand("");
@@ -435,7 +435,7 @@ export function CreateAgentDialog({
Create agent
This creates a local agent identity, syncs its display name when
- possible, and can spawn `sprout-acp` immediately.
+ possible, and can spawn `buzz-acp` immediately.
@@ -621,7 +621,7 @@ export function CreateAgentDialog({
/>
- Local Sprout binary checks and ACP runtime discovery now
+ Local Buzz binary checks and ACP runtime discovery now
live in Settings > Doctor.
diff --git a/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx b/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx
index 5c3a96ed0..9dc19d9fb 100644
--- a/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx
+++ b/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx
@@ -181,7 +181,7 @@ export function CreateAgentRuntimeFields({
className="text-xs text-muted-foreground"
id="help-agent-acp-command"
>
- The sprout-acp binary path or alias used to launch the ACP harness
+ The buzz-acp binary path or alias used to launch the ACP harness
process.
@@ -229,7 +229,7 @@ export function CreateAgentRuntimeFields({
className="text-xs text-muted-foreground"
id="help-agent-runtime-args"
>
- sprout-acp splits args on commas, matching the testing guide.
+ buzz-acp splits args on commas, matching the testing guide.
@@ -249,7 +249,7 @@ export function CreateAgentRuntimeFields({
id="help-agent-mcp-command"
>
Optional. Only needed for agents that use a custom MCP server (e.g.
- sprout-agent with sprout-dev-mcp). Leave blank for most agents.
+ buzz-agent with buzz-dev-mcp). Leave blank for most agents.
@@ -292,7 +292,7 @@ export function CreateAgentRuntimeFields({
className="text-xs text-muted-foreground"
id="help-agent-parallelism"
>
- Number of ACP worker subprocesses. sprout-acp allows 1-32.
+ Number of ACP worker subprocesses. buzz-acp allows 1-32.
@@ -309,7 +309,7 @@ export function CreateAgentRuntimeFields({
value={mcpToolsets}
/>
- Comma-separated list of toolsets to expose via SPROUT_TOOLSETS.
+ Comma-separated list of toolsets to expose via BUZZ_TOOLSETS.
Available: default, channel_admin, dms, canvas, workflow_admin,
identity, forums, social, media. Leave blank for default toolsets
(default, canvas, forums, dms, media).
@@ -332,7 +332,7 @@ export function CreateAgentRuntimeFields({
className="text-xs text-muted-foreground"
id="help-agent-system-prompt"
>
- Blank means no override. sprout-acp will not add a [System] prompt.
+ Blank means no override. buzz-acp will not add a [System] prompt.
>
diff --git a/desktop/src/features/agents/ui/RespondToField.tsx b/desktop/src/features/agents/ui/RespondToField.tsx
index 45631cd2e..2e903bfeb 100644
--- a/desktop/src/features/agents/ui/RespondToField.tsx
+++ b/desktop/src/features/agents/ui/RespondToField.tsx
@@ -17,7 +17,7 @@ import { UserAvatar } from "@/shared/ui/UserAvatar";
* Inbound author gate UI for create/edit agent dialogs.
*
* Dropdown:
- * - Owner only (default; matches `sprout-acp --respond-to=owner-only`)
+ * - Owner only (default; matches `buzz-acp --respond-to=owner-only`)
* - Anyone (`--respond-to=anyone` — fully open bot)
* - Allowlist (`--respond-to=allowlist`, plus the chip list as
* `--respond-to-allowlist`)
diff --git a/desktop/src/features/agents/ui/SecretRevealDialog.tsx b/desktop/src/features/agents/ui/SecretRevealDialog.tsx
index ad563879e..bcbe55655 100644
--- a/desktop/src/features/agents/ui/SecretRevealDialog.tsx
+++ b/desktop/src/features/agents/ui/SecretRevealDialog.tsx
@@ -38,7 +38,7 @@ export function SecretRevealDialog({
Private key (nsec)
- This is the agent identity used by `sprout-acp`.
+ This is the agent identity used by `buzz-acp`.
right.length - left.length,
);
-const SPROUT_TOOL_TITLE_ALIASES: Array<[RegExp, string]> = [
+const BUZZ_TOOL_TITLE_ALIASES: Array<[RegExp, string]> = [
[/\bsending message to channel\b/, "send_message"],
[/\bretrieving recent messages from channel\b/, "get_messages"],
[/\bgetting channel details\b/, "get_channel"],
@@ -139,10 +136,10 @@ const SPROUT_TOOL_TITLE_ALIASES: Array<[RegExp, string]> = [
[/\bremoving reaction\b/, "remove_reaction"],
];
-export function getSproutToolInfo(title: string): SproutToolInfo | null {
+export function getBuzzToolInfo(title: string): BuzzToolInfo | null {
const name = normalizeToolName(title);
- const isRead = SPROUT_READ_TOOLS.has(name);
- const isWrite = SPROUT_WRITE_TOOLS.has(name);
+ const isRead = BUZZ_READ_TOOLS.has(name);
+ const isWrite = BUZZ_WRITE_TOOLS.has(name);
if (!isRead && !isWrite) {
return null;
}
@@ -151,8 +148,8 @@ export function getSproutToolInfo(title: string): SproutToolInfo | null {
return {
icon: Workflow,
label: isRead
- ? "Reads workflow state from Sprout."
- : "Updates workflow state in Sprout.",
+ ? "Reads workflow state from Buzz."
+ : "Updates workflow state in Buzz.",
tone: isWrite ? "write" : "read",
};
}
@@ -164,8 +161,8 @@ export function getSproutToolInfo(title: string): SproutToolInfo | null {
return {
icon: Hash,
label: isRead
- ? "Reads channel context from the Sprout relay."
- : "Changes channel state in the Sprout relay.",
+ ? "Reads channel context from the Buzz relay."
+ : "Changes channel state in the Buzz relay.",
tone: isWrite ? "write" : "read",
};
}
@@ -177,15 +174,15 @@ export function getSproutToolInfo(title: string): SproutToolInfo | null {
return {
icon: Users,
label: isRead
- ? "Reads Sprout identity or presence data."
- : "Updates Sprout identity or membership data.",
+ ? "Reads Buzz identity or presence data."
+ : "Updates Buzz identity or membership data.",
tone: isWrite ? "write" : "admin",
};
}
if (name.includes("search") || name === "get_feed") {
return {
icon: Search,
- label: "Searches relay-visible Sprout history.",
+ label: "Searches relay-visible Buzz history.",
tone: "read",
};
}
@@ -196,23 +193,23 @@ export function getSproutToolInfo(title: string): SproutToolInfo | null {
) {
return {
icon: Send,
- label: "Publishes relay-visible Sprout activity.",
+ label: "Publishes relay-visible Buzz activity.",
tone: "write",
};
}
return {
icon: MessageSquare,
- label: isRead ? "Reads from Sprout." : "Writes to Sprout.",
+ label: isRead ? "Reads from Buzz." : "Writes to Buzz.",
tone: isWrite ? "write" : "read",
};
}
export function normalizeToolName(title: string): string {
- const knownName = findSproutToolName(title, true);
+ const knownName = findBuzzToolName(title, true);
if (knownName) return knownName;
- const normalized = normalizeToolNameText(title).replace(/^sprout_/, "");
+ const normalized = normalizeToolNameText(title).replace(/^buzz_/, "");
return normalized.match(/[a-z][a-z0-9_]+/)?.[0] ?? normalized;
}
@@ -225,27 +222,27 @@ export function normalizeToolNameText(value: string): string {
.replace(/^_+|_+$/g, "");
}
-export function findSproutToolName(value: string, includeShortNames: boolean) {
- const alias = findSproutToolAlias(value);
+export function findBuzzToolName(value: string, includeShortNames: boolean) {
+ const alias = findBuzzToolAlias(value);
if (alias) return alias;
const normalized = normalizeToolNameText(value);
return (
- SPROUT_TOOL_NAMES_BY_LENGTH.find(
+ BUZZ_TOOL_NAMES_BY_LENGTH.find(
(name) =>
(includeShortNames || name.length >= 8) && normalized.includes(name),
) ?? null
);
}
-function findSproutToolAlias(value: string) {
+function findBuzzToolAlias(value: string) {
const normalizedPhrase = value
.trim()
.toLowerCase()
.replace(/[_-]+/g, " ")
.replace(/\s+/g, " ");
return (
- SPROUT_TOOL_TITLE_ALIASES.find(([pattern]) =>
+ BUZZ_TOOL_TITLE_ALIASES.find(([pattern]) =>
pattern.test(normalizedPhrase),
)?.[1] ?? null
);
@@ -271,7 +268,7 @@ export function formatToolTitle(
fallbackTitle?: string,
): string {
const name = normalizeToolName(toolName);
- if (SPROUT_READ_TOOLS.has(name) || SPROUT_WRITE_TOOLS.has(name)) {
+ if (BUZZ_READ_TOOLS.has(name) || BUZZ_WRITE_TOOLS.has(name)) {
return name
.split("_")
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
diff --git a/desktop/src/features/agents/ui/agentSessionTranscript.ts b/desktop/src/features/agents/ui/agentSessionTranscript.ts
index 792447365..60cf7f62b 100644
--- a/desktop/src/features/agents/ui/agentSessionTranscript.ts
+++ b/desktop/src/features/agents/ui/agentSessionTranscript.ts
@@ -5,7 +5,7 @@ import type {
TranscriptItem,
} from "./agentSessionTypes";
import {
- findSproutToolName,
+ findBuzzToolName,
isGenericToolTitle,
normalizeToolStatus,
} from "./agentSessionToolCatalog";
@@ -189,7 +189,7 @@ function upsertTool(
id: string,
title: string,
toolName: string,
- sproutToolName: string | null,
+ buzzToolName: string | null,
status: ToolStatus,
args: Record,
result: string,
@@ -198,23 +198,23 @@ function upsertTool(
channelId: string | null,
) {
const existing = d.itemsById.get(id);
- const canonicalSproutToolName =
- sproutToolName ?? findSproutToolName(toolName, true);
+ const canonicalBuzzToolName =
+ buzzToolName ?? findBuzzToolName(toolName, true);
if (existing?.type === "tool") {
const updatedTitle = !isGenericToolTitle(title) ? title : existing.title;
let updatedToolName = existing.toolName;
- let updatedSproutToolName = existing.sproutToolName;
- if (canonicalSproutToolName) {
- updatedSproutToolName = canonicalSproutToolName;
- updatedToolName = canonicalSproutToolName;
- } else if (!existing.sproutToolName && !isGenericToolTitle(toolName)) {
+ let updatedBuzzToolName = existing.buzzToolName;
+ if (canonicalBuzzToolName) {
+ updatedBuzzToolName = canonicalBuzzToolName;
+ updatedToolName = canonicalBuzzToolName;
+ } else if (!existing.buzzToolName && !isGenericToolTitle(toolName)) {
updatedToolName = toolName;
}
replaceItem(d, id, {
...existing,
title: updatedTitle,
toolName: updatedToolName,
- sproutToolName: updatedSproutToolName,
+ buzzToolName: updatedBuzzToolName,
status,
args: Object.keys(args).length > 0 ? args : existing.args,
result: result || existing.result,
@@ -233,8 +233,8 @@ function upsertTool(
id,
type: "tool",
title,
- toolName: canonicalSproutToolName ?? toolName,
- sproutToolName: canonicalSproutToolName,
+ toolName: canonicalBuzzToolName ?? toolName,
+ buzzToolName: canonicalBuzzToolName,
status,
args,
result,
@@ -380,7 +380,7 @@ export function processTranscriptEvent(
`tool:${ch}:${toolId}`,
identity.title,
identity.toolName,
- identity.sproutToolName,
+ identity.buzzToolName,
normalizeToolStatus(asString(update.status) ?? "executing"),
extractToolArgs(update),
extractToolResult(update),
@@ -399,7 +399,7 @@ export function processTranscriptEvent(
`tool:${ch}:${toolId}`,
identity.title,
identity.toolName,
- identity.sproutToolName,
+ identity.buzzToolName,
status,
extractToolArgs(update),
extractToolResult(update),
diff --git a/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.test.mjs b/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.test.mjs
index 4485df6fc..e84af1468 100644
--- a/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.test.mjs
+++ b/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.test.mjs
@@ -25,8 +25,8 @@ test("parsePromptText returns the empty/Prompt fallback for whitespace-only inpu
test("parsePromptText wraps header-less free text in a single Prompt section", () => {
// Free text with no `[header]` becomes one "Prompt" section. Since no
- // section is a "Sprout event", there is no event content to surface, so
- // userText is empty and the title falls through to "Sprout event".
+ // section is a "Buzz event", there is no event content to surface, so
+ // userText is empty and the title falls through to "Buzz event".
const result = parsePromptText("just some free text");
assert.deepEqual(
result.sections.map((s) => s.title),
@@ -34,18 +34,18 @@ test("parsePromptText wraps header-less free text in a single Prompt section", (
);
assert.equal(result.sections[0].body, "just some free text");
assert.equal(result.userText, "");
- assert.equal(result.userTitle, "Sprout event");
+ assert.equal(result.userTitle, "Buzz event");
assert.equal(result.userPubkey, null);
});
-// --- parsePromptText: Sprout event section ---
+// --- parsePromptText: Buzz event section ---
test("parsePromptText extracts content, hex pubkey, and a title-cased kind", () => {
const text = [
"[System]",
"system preamble here",
"",
- "[Sprout event: @mention]",
+ "[Buzz event: @mention]",
"Channel: demo",
`From: Wes (hex: ${HEX})`,
"Content: hello @Brain please look",
@@ -61,13 +61,13 @@ test("parsePromptText extracts content, hex pubkey, and a title-cased kind", ()
// Both headers become sections.
assert.deepEqual(
result.sections.map((s) => s.title),
- ["System", "Sprout event: @mention"],
+ ["System", "Buzz event: @mention"],
);
});
test("parsePromptText lowercases the extracted hex pubkey", () => {
const text = [
- "[Sprout event: dm]",
+ "[Buzz event: dm]",
`From: Someone (hex: ${HEX_UPPER})`,
"Content: hi",
].join("\n");
@@ -77,7 +77,7 @@ test("parsePromptText lowercases the extracted hex pubkey", () => {
});
test("parsePromptText yields a null pubkey when From has no hex", () => {
- const text = ["[Sprout event: note]", "From: Someone", "Content: hi"].join(
+ const text = ["[Buzz event: note]", "From: Someone", "Content: hi"].join(
"\n",
);
@@ -87,10 +87,10 @@ test("parsePromptText yields a null pubkey when From has no hex", () => {
assert.equal(result.userTitle, "Note");
});
-test("parsePromptText defaults the title to 'Sprout event' when no kind is present", () => {
- const text = ["[Sprout event]", "Content: x"].join("\n");
+test("parsePromptText defaults the title to 'Buzz event' when no kind is present", () => {
+ const text = ["[Buzz event]", "Content: x"].join("\n");
const result = parsePromptText(text);
- assert.equal(result.userTitle, "Sprout event");
+ assert.equal(result.userTitle, "Buzz event");
});
test("parsePromptText leading text before a header becomes a Prompt section", () => {
diff --git a/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.ts b/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.ts
index 4a69afbb0..00c13c056 100644
--- a/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.ts
+++ b/desktop/src/features/agents/ui/agentSessionTranscriptHelpers.ts
@@ -1,6 +1,6 @@
import type { ObserverEvent, PromptSection } from "./agentSessionTypes";
import {
- findSproutToolName,
+ findBuzzToolName,
isGenericToolTitle,
normalizeToolName,
} from "./agentSessionToolCatalog";
@@ -29,9 +29,10 @@ export function parsePromptText(text: string): {
};
}
- const eventSection = sections.find((section) =>
- section.title.toLowerCase().startsWith("sprout event"),
- );
+ const eventSection = sections.find((section) => {
+ const title = section.title.toLowerCase();
+ return title.startsWith("buzz event") || title.startsWith("buzz event");
+ });
const eventContent = eventSection
? extractEventContent(eventSection.body)
: "";
@@ -43,7 +44,7 @@ export function parsePromptText(text: string): {
return {
sections,
userText: eventContent,
- userTitle: eventKind ? titleCase(eventKind) : "Sprout event",
+ userTitle: eventKind ? titleCase(eventKind) : "Buzz event",
userPubkey: eventAuthorPubkey,
};
}
@@ -144,14 +145,14 @@ export function extractToolArgs(
export function extractToolIdentity(update: Record): {
title: string;
toolName: string;
- sproutToolName: string | null;
+ buzzToolName: string | null;
} {
const candidates = collectToolNameCandidates(update);
const knownName =
candidates
- .map((candidate) => findSproutToolName(candidate, true))
+ .map((candidate) => findBuzzToolName(candidate, true))
.find((candidate): candidate is string => Boolean(candidate)) ??
- findSproutToolName(JSON.stringify(update), false);
+ findBuzzToolName(JSON.stringify(update), false);
const firstSpecific = candidates.find(
(candidate) => !isGenericToolTitle(candidate),
);
@@ -160,7 +161,7 @@ export function extractToolIdentity(update: Record): {
return {
title,
toolName: knownName ?? normalizeToolName(firstSpecific ?? title),
- sproutToolName: knownName,
+ buzzToolName: knownName,
};
}
diff --git a/desktop/src/features/agents/ui/agentSessionTypes.ts b/desktop/src/features/agents/ui/agentSessionTypes.ts
index 381fa4d6d..2ff4ea305 100644
--- a/desktop/src/features/agents/ui/agentSessionTypes.ts
+++ b/desktop/src/features/agents/ui/agentSessionTypes.ts
@@ -60,7 +60,7 @@ export type TranscriptItem =
type: "tool";
title: string;
toolName: string;
- sproutToolName: string | null;
+ buzzToolName: string | null;
status: ToolStatus;
args: Record;
result: string;
@@ -76,7 +76,7 @@ export type PromptSection = {
body: string;
};
-export type SproutToolInfo = {
+export type BuzzToolInfo = {
icon: LucideIcon;
label: string;
tone: "read" | "write" | "admin";
diff --git a/desktop/src/features/agents/usePreventSleep.ts b/desktop/src/features/agents/usePreventSleep.ts
index ff5797b2d..2ac5dfbd1 100644
--- a/desktop/src/features/agents/usePreventSleep.ts
+++ b/desktop/src/features/agents/usePreventSleep.ts
@@ -5,7 +5,7 @@ import { listen } from "@tauri-apps/api/event";
// Intentionally not scoped per-pubkey — multi-user desktop is rare and the
// setting applies to the machine's sleep behavior regardless of account.
-const STORAGE_KEY = "sprout-prevent-sleep";
+const STORAGE_KEY = "buzz-prevent-sleep";
function readPreference(): boolean {
return window.localStorage.getItem(STORAGE_KEY) === "true";
diff --git a/desktop/src/features/channels/isDmNotifiableKind.test.mjs b/desktop/src/features/channels/isDmNotifiableKind.test.mjs
index b51b99c77..ebea80b13 100644
--- a/desktop/src/features/channels/isDmNotifiableKind.test.mjs
+++ b/desktop/src/features/channels/isDmNotifiableKind.test.mjs
@@ -6,7 +6,7 @@ import { isDmNotifiableKind } from "./isDmNotifiableKind.ts";
// Regression guard for the phantom-DM-notification bug: when kind:5 deletes
// gained an `h` tag, they started matching the live DM subscription. Without
// this gate, deleting a DM message fires a "New message" toast on the other
-// side. Reactions (7), Sprout-native deletes (9005), edits (40003), diffs
+// side. Reactions (7), Buzz-native deletes (9005), edits (40003), diffs
// (40008), and system messages (40099) hit the same subscription and must
// also be filtered.
@@ -20,11 +20,7 @@ test("human-visible message kinds fire DM notifications", () => {
test("non-message kinds do NOT fire DM notifications", () => {
assert.equal(isDmNotifiableKind(5), false, "kind:5 NIP-09 deletion");
assert.equal(isDmNotifiableKind(7), false, "kind:7 reaction");
- assert.equal(
- isDmNotifiableKind(9005),
- false,
- "kind:9005 Sprout-native delete",
- );
+ assert.equal(isDmNotifiableKind(9005), false, "kind:9005 Buzz-native delete");
assert.equal(isDmNotifiableKind(40003), false, "kind:40003 message edit");
assert.equal(isDmNotifiableKind(40008), false, "kind:40008 message diff");
assert.equal(isDmNotifiableKind(40099), false, "kind:40099 system message");
diff --git a/desktop/src/features/channels/readState/readStateFormat.ts b/desktop/src/features/channels/readState/readStateFormat.ts
index 7c3b5d58e..6ce0d69c5 100644
--- a/desktop/src/features/channels/readState/readStateFormat.ts
+++ b/desktop/src/features/channels/readState/readStateFormat.ts
@@ -11,15 +11,15 @@ export const READ_STATE_HORIZON_SECONDS = 7 * 24 * 60 * 60;
const MAX_CONTEXTS = 10_000;
export function localReadStateKey(pubkey: string): string {
- return `sprout.channel-read-state.v2:${pubkey}`;
+ return `buzz.channel-read-state.v2:${pubkey}`;
}
export function localPublishableContextKey(pubkey: string): string {
- return `sprout.channel-read-state.publishable.v1:${pubkey}`;
+ return `buzz.channel-read-state.publishable.v1:${pubkey}`;
}
export function localSourceCreatedAtKey(pubkey: string): string {
- return `sprout.channel-read-state.source-created-at.v1:${pubkey}`;
+ return `buzz.channel-read-state.source-created-at.v1:${pubkey}`;
}
export function isPlainRecord(
diff --git a/desktop/src/features/channels/readState/readStateManager.ts b/desktop/src/features/channels/readState/readStateManager.ts
index b04bb0327..c777e3694 100644
--- a/desktop/src/features/channels/readState/readStateManager.ts
+++ b/desktop/src/features/channels/readState/readStateManager.ts
@@ -20,8 +20,8 @@ import {
writeStoredReadState,
} from "@/features/channels/readState/readStateStorage";
-const CLIENT_ID_KEY_PREFIX = "sprout.nip-rs.client-id";
-const SLOT_ID_KEY_PREFIX = "sprout.nip-rs.slot-id";
+const CLIENT_ID_KEY_PREFIX = "buzz.nip-rs.client-id";
+const SLOT_ID_KEY_PREFIX = "buzz.nip-rs.slot-id";
const DEBOUNCE_MS = 5_000;
function generateHex(bytes: number): string {
diff --git a/desktop/src/features/channels/ui/BotActivityBar.tsx b/desktop/src/features/channels/ui/BotActivityBar.tsx
index 54a19c6e9..4111848df 100644
--- a/desktop/src/features/channels/ui/BotActivityBar.tsx
+++ b/desktop/src/features/channels/ui/BotActivityBar.tsx
@@ -28,7 +28,7 @@ const HEADLINE_ROTATION_MS = 2200;
function getActivityHeadline(item: TranscriptItem): string | null {
if (item.type === "tool") {
- return formatToolTitle(item.sproutToolName ?? item.toolName, item.title);
+ return formatToolTitle(item.buzzToolName ?? item.toolName, item.title);
}
if (item.type === "message") {
diff --git a/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx b/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx
index c862c7c5d..6dc74b073 100644
--- a/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx
+++ b/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx
@@ -23,7 +23,7 @@ export function RightAuxiliaryPane({
}: RightAuxiliaryPaneProps) {
return (
): void {
}
}
-const MUTED_STORAGE_PREFIX = "sprout-thread-muted.v1";
+const MUTED_STORAGE_PREFIX = "buzz-thread-muted.v1";
const MAX_MUTED_ENTRIES = 1000;
function mutedStorageKey(pubkey: string): string {
@@ -157,7 +157,7 @@ export type ThreadActivityItem = {
tags: string[][];
};
-const ACTIVITY_STORAGE_PREFIX = "sprout-thread-activity.v1";
+const ACTIVITY_STORAGE_PREFIX = "buzz-thread-activity.v1";
const MAX_ACTIVITY_ITEMS = 100;
function activityStorageKey(pubkey: string): string {
diff --git a/desktop/src/features/custom-emoji/emojiMartCategory.ts b/desktop/src/features/custom-emoji/emojiMartCategory.ts
index c1184e881..e67bd1c93 100644
--- a/desktop/src/features/custom-emoji/emojiMartCategory.ts
+++ b/desktop/src/features/custom-emoji/emojiMartCategory.ts
@@ -11,7 +11,7 @@ export function buildCustomEmojiCategory(customEmoji: CustomEmoji[]) {
if (customEmoji.length === 0) return undefined;
return [
{
- id: "sprout-custom",
+ id: "buzz-custom",
name: "Custom",
emojis: customEmoji.map((e) => ({
id: e.shortcode,
diff --git a/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx b/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx
index 9ef8e4707..e01a3e367 100644
--- a/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx
+++ b/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx
@@ -219,7 +219,7 @@ export function CustomEmojiSettingsCard() {
) : pendingUpload === null ? (
- Choose an image first; Sprout will suggest a name from the
+ Choose an image first; Buzz will suggest a name from the
filename.
) : ownDuplicate ? (
diff --git a/desktop/src/features/home/useFeedItemState.ts b/desktop/src/features/home/useFeedItemState.ts
index c393e4b04..affb91b4c 100644
--- a/desktop/src/features/home/useFeedItemState.ts
+++ b/desktop/src/features/home/useFeedItemState.ts
@@ -1,6 +1,6 @@
import * as React from "react";
-const DONE_STORAGE_KEY = "sprout-home-feed-done.v1";
+const DONE_STORAGE_KEY = "buzz-home-feed-done.v1";
const MAX_ITEMS = 500;
function doneStorageKey(pubkey: string) {
diff --git a/desktop/src/features/home/useResizableInboxListWidth.ts b/desktop/src/features/home/useResizableInboxListWidth.ts
index 083217ea4..a3d6c1aad 100644
--- a/desktop/src/features/home/useResizableInboxListWidth.ts
+++ b/desktop/src/features/home/useResizableInboxListWidth.ts
@@ -4,7 +4,7 @@ const INBOX_LIST_DEFAULT_WIDTH_PX = 320;
export const INBOX_COLUMN_MIN_WIDTH_PX = 300;
export const INBOX_SINGLE_COLUMN_BREAKPOINT_PX = INBOX_COLUMN_MIN_WIDTH_PX * 2;
const INBOX_LIST_MAX_WIDTH_PX = 520;
-const INBOX_LIST_WIDTH_SESSION_KEY = "sprout.desktop.home-inbox-list-width";
+const INBOX_LIST_WIDTH_SESSION_KEY = "buzz.desktop.home-inbox-list-width";
function clampInboxListWidth(width: number): number {
return Math.max(
diff --git a/desktop/src/features/mesh-compute/applyMeshAgentPreset.test.mjs b/desktop/src/features/mesh-compute/applyMeshAgentPreset.test.mjs
index 67ba99401..71e1eddcd 100644
--- a/desktop/src/features/mesh-compute/applyMeshAgentPreset.test.mjs
+++ b/desktop/src/features/mesh-compute/applyMeshAgentPreset.test.mjs
@@ -9,16 +9,16 @@ import {
const PRESET = {
providerId: "relay-mesh",
label: "Relay mesh",
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "Qwen3-8B-Q4_K_M",
envVars: {
- SPROUT_AGENT_PROVIDER: "openai",
+ BUZZ_AGENT_PROVIDER: "openai",
OPENAI_COMPAT_BASE_URL: "http://127.0.0.1:9337/v1",
OPENAI_COMPAT_MODEL: "Qwen3-8B-Q4_K_M",
- OPENAI_COMPAT_API_KEY: "sprout-mesh-local",
+ OPENAI_COMPAT_API_KEY: "buzz-mesh-local",
OPENAI_COMPAT_API: "chat",
},
};
@@ -27,10 +27,10 @@ const PRESET = {
test("patch carries the fields a managed-agent draft needs", () => {
const patch = meshAgentPresetPatch(PRESET);
- assert.equal(patch.acpCommand, "sprout-acp");
- assert.equal(patch.agentCommand, "sprout-agent");
+ assert.equal(patch.acpCommand, "buzz-acp");
+ assert.equal(patch.agentCommand, "buzz-agent");
assert.deepEqual(patch.agentArgs, []);
- assert.equal(patch.mcpCommand, "sprout-dev-mcp");
+ assert.equal(patch.mcpCommand, "buzz-dev-mcp");
assert.equal(patch.model, "Qwen3-8B-Q4_K_M");
assert.equal(patch.envVars.OPENAI_COMPAT_MODEL, "Qwen3-8B-Q4_K_M");
});
@@ -63,13 +63,13 @@ test("empty draft has no overrides", () => {
test("matching draft has no overrides", () => {
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "Qwen3-8B-Q4_K_M",
envVars: {
- SPROUT_AGENT_PROVIDER: "openai",
+ BUZZ_AGENT_PROVIDER: "openai",
OPENAI_COMPAT_BASE_URL: "http://127.0.0.1:9337/v1",
},
},
@@ -81,10 +81,10 @@ test("matching draft has no overrides", () => {
test("differing model is reported as override", () => {
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "llama-3.2-3b-instruct",
envVars: {},
},
@@ -93,13 +93,13 @@ test("differing model is reported as override", () => {
assert.deepEqual(overrides, ["model"]);
});
-test("non-sprout-agent runtime + non-mesh model both reported", () => {
+test("non-buzz-agent runtime + non-mesh model both reported", () => {
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
+ acpCommand: "buzz-acp",
agentCommand: "goose",
agentArgs: ["acp"],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "gpt-4o",
envVars: {},
},
@@ -111,13 +111,13 @@ test("non-sprout-agent runtime + non-mesh model both reported", () => {
test("overlapping env-var with differing value is reported", () => {
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "Qwen3-8B-Q4_K_M",
envVars: {
- SPROUT_AGENT_PROVIDER: "anthropic",
+ BUZZ_AGENT_PROVIDER: "anthropic",
},
},
PRESET,
@@ -128,13 +128,13 @@ test("overlapping env-var with differing value is reported", () => {
test("overlapping env-var with same value is NOT reported", () => {
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "Qwen3-8B-Q4_K_M",
envVars: {
- SPROUT_AGENT_PROVIDER: "openai",
+ BUZZ_AGENT_PROVIDER: "openai",
},
},
PRESET,
@@ -145,10 +145,10 @@ test("overlapping env-var with same value is NOT reported", () => {
test("additive env-var (new key) is not an override", () => {
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "Qwen3-8B-Q4_K_M",
envVars: {
SOME_USER_VAR: "kept",
@@ -164,10 +164,10 @@ test("empty model string treated like null (no override)", () => {
// "" instead of null. Either should be treated as "user hasn't picked yet."
const overrides = detectMeshPresetOverrides(
{
- acpCommand: "sprout-acp",
- agentCommand: "sprout-agent",
+ acpCommand: "buzz-acp",
+ agentCommand: "buzz-agent",
agentArgs: [],
- mcpCommand: "sprout-dev-mcp",
+ mcpCommand: "buzz-dev-mcp",
model: "",
envVars: {},
},
diff --git a/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx b/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx
index b5060a853..3af762234 100644
--- a/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx
+++ b/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx
@@ -18,8 +18,8 @@ import {
import { classifyModelRef, modelRefHintLabel } from "../classifyModelRef";
import { useMeshNodeStatus } from "../hooks/useMeshNodeStatus";
-const MODEL_DRAFT_STORAGE_KEY = "sprout.mesh-compute.share.model.v1";
-const MAX_VRAM_DRAFT_STORAGE_KEY = "sprout.mesh-compute.share.max-vram-gb.v1";
+const MODEL_DRAFT_STORAGE_KEY = "buzz.mesh-compute.share.model.v1";
+const MAX_VRAM_DRAFT_STORAGE_KEY = "buzz.mesh-compute.share.max-vram-gb.v1";
function readDraft(key: string): string {
try {
@@ -284,9 +284,9 @@ export function MeshComputeSettingsCard() {
- Sprout will not publish your machine to public Nostr relays,
- auto-discover other networks, or share your endpoint outside this
- relay's members. Only members of this relay can dial in.
+ Buzz will not publish your machine to public Nostr relays, auto-discover
+ other networks, or share your endpoint outside this relay's members.
+ Only members of this relay can dial in.
);
diff --git a/desktop/src/features/messages/lib/customEmojiNode.test.mjs b/desktop/src/features/messages/lib/customEmojiNode.test.mjs
index 05dd44462..594d7ac34 100644
--- a/desktop/src/features/messages/lib/customEmojiNode.test.mjs
+++ b/desktop/src/features/messages/lib/customEmojiNode.test.mjs
@@ -102,37 +102,37 @@ function runRule(rule, src, pos) {
}
test("rule fires for a boundary :shortcode: (start of string)", () => {
- const rule = captureRule(["sprout"]);
- const { matched, advanced } = runRule(rule, ":sprout:", 0);
+ const rule = captureRule(["buzz"]);
+ const { matched, advanced } = runRule(rule, ":buzz:", 0);
assert.equal(matched, true);
- assert.equal(advanced, ":sprout:".length);
+ assert.equal(advanced, ":buzz:".length);
});
test("rule fires for a :shortcode: preceded by whitespace", () => {
- const rule = captureRule(["sprout"]);
+ const rule = captureRule(["buzz"]);
// pos points at the `:` after the space.
- const { matched } = runRule(rule, "hi :sprout:", 3);
+ const { matched } = runRule(rule, "hi :buzz:", 3);
assert.equal(matched, true);
});
-test("rule does NOT fire when the colon is glued to a word char (not:sprout:)", () => {
- const rule = captureRule(["sprout"]);
+test("rule does NOT fire when the colon is glued to a word char (not:buzz:)", () => {
+ const rule = captureRule(["buzz"]);
// pos points at the `:` immediately after `not`.
- const { matched } = runRule(rule, "not:sprout:", 3);
+ const { matched } = runRule(rule, "not:buzz:", 3);
assert.equal(matched, false);
});
-test("rule does NOT fire inside a URL-like sequence (http://x:y:sprout:)", () => {
- const rule = captureRule(["sprout"]);
- const src = "http://x:y:sprout:";
+test("rule does NOT fire inside a URL-like sequence (http://x:y:buzz:)", () => {
+ const rule = captureRule(["buzz"]);
+ const src = "http://x:y:buzz:";
// pos points at the `:` immediately after `y` (a word char).
- const { matched } = runRule(rule, src, src.indexOf(":sprout:"));
+ const { matched } = runRule(rule, src, src.indexOf(":buzz:"));
assert.equal(matched, false);
});
test("rule fires after punctuation boundary (e.g. parenthesis)", () => {
- const rule = captureRule(["sprout"]);
+ const rule = captureRule(["buzz"]);
// `(` is not a word char, so a `:shortcode:` after it still materializes.
- const { matched } = runRule(rule, "(:sprout:)", 1);
+ const { matched } = runRule(rule, "(:buzz:)", 1);
assert.equal(matched, true);
});
diff --git a/desktop/src/features/messages/lib/customEmojiNode.ts b/desktop/src/features/messages/lib/customEmojiNode.ts
index f1fbb03c3..3696aab0c 100644
--- a/desktop/src/features/messages/lib/customEmojiNode.ts
+++ b/desktop/src/features/messages/lib/customEmojiNode.ts
@@ -64,8 +64,8 @@ export function registerCustomEmojiMarkdownIt(
md: any,
options: CustomEmojiNodeOptions,
): void {
- const RULE_NAME = "sprout_custom_emoji";
- const TOKEN_TYPE = "sprout_custom_emoji";
+ const RULE_NAME = "buzz_custom_emoji";
+ const TOKEN_TYPE = "buzz_custom_emoji";
// `parse.setup` runs on every parse against the *same* markdown-it instance,
// so only register the rule + renderer once — `ruler.before` throws on a
@@ -78,8 +78,8 @@ export function registerCustomEmojiMarkdownIt(
if (state.src.charCodeAt(state.pos) !== 0x3a /* : */) return false;
// Word-boundary guard: don't fire when the `:` is glued to a preceding
- // word char. This keeps prose and URLs intact — `not:sprout:` and
- // `http://x:y:sprout:` must NOT turn the inner `:sprout:` into an image;
+ // word char. This keeps prose and URLs intact — `not:buzz:` and
+ // `http://x:y:buzz:` must NOT turn the inner `:buzz:` into an image;
// only a `:shortcode:` at a boundary (start of line, after whitespace or
// punctuation) materializes. Slack-style boundary semantics.
if (state.pos > 0) {
diff --git a/desktop/src/features/messages/lib/formatTimelineMessages.test.mjs b/desktop/src/features/messages/lib/formatTimelineMessages.test.mjs
index 3dce9df6d..fa7232614 100644
--- a/desktop/src/features/messages/lib/formatTimelineMessages.test.mjs
+++ b/desktop/src/features/messages/lib/formatTimelineMessages.test.mjs
@@ -52,7 +52,7 @@ test("kind:5 (NIP-09) deletion hides the target message", () => {
);
});
-test("kind:9005 (NIP-29 / Sprout-native) deletion hides the target message", () => {
+test("kind:9005 (NIP-29 / Buzz-native) deletion hides the target message", () => {
// This is the actual reported bug: agents emit kind:9005 deletes via the
// CLI. Without recognizing 9005 as a deletion marker the message stayed
// rendered until manual refresh.
diff --git a/desktop/src/features/messages/lib/messageLink.test.mjs b/desktop/src/features/messages/lib/messageLink.test.mjs
index 3cb650f34..410cafb44 100644
--- a/desktop/src/features/messages/lib/messageLink.test.mjs
+++ b/desktop/src/features/messages/lib/messageLink.test.mjs
@@ -93,10 +93,8 @@ test("parseMessageLink rejects malformed URL strings", () => {
assert.equal(r.ok === false && r.reason, "invalid-url");
});
-test("parseMessageLink accepts legacy sprout://message links", () => {
- const r = parseMessageLink(
- `sprout://message?channel=${CHANNEL}&id=${MESSAGE}`,
- );
+test("parseMessageLink accepts legacy buzz://message links", () => {
+ const r = parseMessageLink(`buzz://message?channel=${CHANNEL}&id=${MESSAGE}`);
assert.equal(r.ok, true);
assert.deepEqual(r.ok && r.value, {
channelId: CHANNEL,
@@ -105,17 +103,17 @@ test("parseMessageLink accepts legacy sprout://message links", () => {
});
});
-test("isMessageLink matches buzz://message and legacy sprout://message", () => {
+test("isMessageLink matches buzz://message and legacy buzz://message", () => {
assert.equal(
isMessageLink(`buzz://message?channel=${CHANNEL}&id=${MESSAGE}`),
true,
);
assert.equal(
- isMessageLink(`sprout://message?channel=${CHANNEL}&id=${MESSAGE}`),
+ isMessageLink(`buzz://message?channel=${CHANNEL}&id=${MESSAGE}`),
true,
);
assert.equal(isMessageLink("buzz://connect?relay=wss://x"), false);
- assert.equal(isMessageLink("sprout://connect?relay=wss://x"), false);
+ assert.equal(isMessageLink("buzz://connect?relay=wss://x"), false);
assert.equal(isMessageLink("https://example.com"), false);
assert.equal(isMessageLink(undefined), false);
assert.equal(isMessageLink(""), false);
diff --git a/desktop/src/features/messages/lib/messageLink.ts b/desktop/src/features/messages/lib/messageLink.ts
index 573401651..02e892aaf 100644
--- a/desktop/src/features/messages/lib/messageLink.ts
+++ b/desktop/src/features/messages/lib/messageLink.ts
@@ -5,7 +5,6 @@
*/
const MESSAGE_LINK_SCHEME = "buzz:";
-const LEGACY_MESSAGE_LINK_SCHEME = "sprout:";
const MESSAGE_LINK_HOST = "message";
export type MessageLinkInput = {
@@ -57,10 +56,8 @@ export function buildMessageLink(input: MessageLinkInput): string {
}
/**
- * Parse a `buzz://message?…` URL. Legacy `sprout://message?…` links are
- * accepted so already-copied message links keep working during the rename.
- * Returns a discriminated result so callers can render a fallback (e.g. a
- * plain link) without throwing.
+ * Parse a `buzz://message?…` URL. Returns a discriminated result so callers can
+ * render a fallback (e.g. a plain link) without throwing.
*/
export function parseMessageLink(url: string): MessageLinkParseResult {
let parsed: URL;
@@ -70,10 +67,7 @@ export function parseMessageLink(url: string): MessageLinkParseResult {
return { ok: false, reason: "invalid-url" };
}
- if (
- parsed.protocol !== MESSAGE_LINK_SCHEME &&
- parsed.protocol !== LEGACY_MESSAGE_LINK_SCHEME
- ) {
+ if (parsed.protocol !== MESSAGE_LINK_SCHEME) {
return { ok: false, reason: "wrong-scheme" };
}
// `new URL("buzz://message?…")` puts "message" in `hostname`.
@@ -106,10 +100,5 @@ export function parseMessageLink(url: string): MessageLinkParseResult {
*/
export function isMessageLink(href: string | undefined | null): boolean {
if (!href) return false;
- return (
- href.startsWith("buzz://message?") ||
- href === "buzz://message" ||
- href.startsWith("sprout://message?") ||
- href === "sprout://message"
- );
+ return href.startsWith("buzz://message?") || href === "buzz://message";
}
diff --git a/desktop/src/features/messages/lib/normalizeMentionClipboard.ts b/desktop/src/features/messages/lib/normalizeMentionClipboard.ts
index c9d2fd73a..a04c70dad 100644
--- a/desktop/src/features/messages/lib/normalizeMentionClipboard.ts
+++ b/desktop/src/features/messages/lib/normalizeMentionClipboard.ts
@@ -1,5 +1,5 @@
/**
- * Detect whether clipboard HTML contains Sprout mention / channel-link
+ * Detect whether clipboard HTML contains Buzz mention / channel-link
* elements (marked with `data-mention` or `data-channel-link` attributes).
*/
export function hasMentionClipboardHtml(html: string): boolean {
@@ -7,7 +7,7 @@ export function hasMentionClipboardHtml(html: string): boolean {
}
/**
- * Normalize clipboard HTML that contains Sprout mention / channel-link
+ * Normalize clipboard HTML that contains Buzz mention / channel-link
* elements. Replaces the styled `` and
* `` wrappers with unstyled text nodes so
* TipTap's Bold extension doesn't misinterpret their font-weight as bold.
diff --git a/desktop/src/features/messages/lib/remarkMessageLinks.ts b/desktop/src/features/messages/lib/remarkMessageLinks.ts
index bf0cbe449..cafd584c9 100644
--- a/desktop/src/features/messages/lib/remarkMessageLinks.ts
+++ b/desktop/src/features/messages/lib/remarkMessageLinks.ts
@@ -1,7 +1,7 @@
/**
* Remark plugin that detects bare `buzz://message?…` URLs in text nodes and
* replaces each with a custom `message-link` HAST element. Legacy
- * `sprout://message?…` URLs are accepted during the rename. The `markdown.tsx`
+ * `buzz://message?…` URLs are accepted during the rename. The `markdown.tsx`
* components map renders that as an inline pill (channel name + click-to-open)
* instead of the raw 100-char URL.
*
@@ -20,7 +20,7 @@
// --experimental-strip-types`. `tsconfig.json` enables `allowImportingTsExtensions`.
import { createRemarkPrefixPlugin } from "../../../shared/lib/createRemarkPrefixPlugin.ts";
-const MESSAGE_URL_PATTERN = /(?:buzz|sprout):\/\/message\?[^\s<>"')\]]+/g;
+const MESSAGE_URL_PATTERN = /(?:buzz|buzz):\/\/message\?[^\s<>"')\]]+/g;
const TRAILING_PUNCTUATION_PATTERN = /[.,;:!?]+$/;
function trimMessageLinkMatch(matchText: string) {
diff --git a/desktop/src/features/messages/lib/useRichTextEditor.ts b/desktop/src/features/messages/lib/useRichTextEditor.ts
index 0fe54d8a3..e293aa9ab 100644
--- a/desktop/src/features/messages/lib/useRichTextEditor.ts
+++ b/desktop/src/features/messages/lib/useRichTextEditor.ts
@@ -304,11 +304,10 @@ export function useRichTextEditor({
openOnClick: false,
autolink: true,
linkOnPaste: true,
- // Allow Buzz message links through TipTap's URL sanitiser. Keep the
- // legacy Sprout protocol so already-copied links survive paste.
+ // Allow Buzz message links through TipTap's URL sanitiser.
// http(s) and mailto are accepted by default; non-listed protocols are
// stripped on paste/typed input.
- protocols: ["buzz", "sprout"],
+ protocols: ["buzz"],
HTMLAttributes: {
class: "text-primary underline underline-offset-4 cursor-pointer",
},
diff --git a/desktop/src/features/messages/lib/useThreadFollows.ts b/desktop/src/features/messages/lib/useThreadFollows.ts
index b78b6b358..d7ee0fe3b 100644
--- a/desktop/src/features/messages/lib/useThreadFollows.ts
+++ b/desktop/src/features/messages/lib/useThreadFollows.ts
@@ -1,6 +1,6 @@
import * as React from "react";
-const STORAGE_KEY_PREFIX = "sprout-thread-follows.v1";
+const STORAGE_KEY_PREFIX = "buzz-thread-follows.v1";
const MAX_ENTRIES = 500;
type ThreadFollowEntry = {
diff --git a/desktop/src/features/messages/ui/DiffViewer.css b/desktop/src/features/messages/ui/DiffViewer.css
index 04e43e91e..d6747173d 100644
--- a/desktop/src/features/messages/ui/DiffViewer.css
+++ b/desktop/src/features/messages/ui/DiffViewer.css
@@ -1,26 +1,26 @@
:root {
- --sprout-diff-insert-gutter-bg: 143 58% 91%;
- --sprout-diff-insert-code-bg: 140 56% 96%;
- --sprout-diff-insert-edit-bg: 142 44% 82%;
- --sprout-diff-insert-text: 143 63% 20%;
- --sprout-diff-delete-gutter-bg: 352 73% 93%;
- --sprout-diff-delete-code-bg: 356 87% 97%;
- --sprout-diff-delete-edit-bg: 353 64% 84%;
- --sprout-diff-delete-text: 356 55% 24%;
+ --buzz-diff-insert-gutter-bg: 143 58% 91%;
+ --buzz-diff-insert-code-bg: 140 56% 96%;
+ --buzz-diff-insert-edit-bg: 142 44% 82%;
+ --buzz-diff-insert-text: 143 63% 20%;
+ --buzz-diff-delete-gutter-bg: 352 73% 93%;
+ --buzz-diff-delete-code-bg: 356 87% 97%;
+ --buzz-diff-delete-edit-bg: 353 64% 84%;
+ --buzz-diff-delete-text: 356 55% 24%;
}
.dark {
- --sprout-diff-insert-gutter-bg: 143 33% 20%;
- --sprout-diff-insert-code-bg: 143 29% 15%;
- --sprout-diff-insert-edit-bg: 143 30% 27%;
- --sprout-diff-insert-text: 143 47% 78%;
- --sprout-diff-delete-gutter-bg: 353 28% 20%;
- --sprout-diff-delete-code-bg: 353 25% 15%;
- --sprout-diff-delete-edit-bg: 353 31% 27%;
- --sprout-diff-delete-text: 352 71% 83%;
+ --buzz-diff-insert-gutter-bg: 143 33% 20%;
+ --buzz-diff-insert-code-bg: 143 29% 15%;
+ --buzz-diff-insert-edit-bg: 143 30% 27%;
+ --buzz-diff-insert-text: 143 47% 78%;
+ --buzz-diff-delete-gutter-bg: 353 28% 20%;
+ --buzz-diff-delete-code-bg: 353 25% 15%;
+ --buzz-diff-delete-edit-bg: 353 31% 27%;
+ --buzz-diff-delete-text: 352 71% 83%;
}
-.sprout-diff-theme {
+.buzz-diff-theme {
--diff-background-color: transparent;
--diff-text-color: hsl(var(--foreground));
--diff-font-family:
@@ -28,46 +28,42 @@
"Source Code Pro", Menlo, Consolas, monospace;
--diff-selection-background-color: hsl(var(--accent) / 0.9);
--diff-selection-text-color: hsl(var(--accent-foreground));
- --diff-gutter-insert-background-color: hsl(
- var(--sprout-diff-insert-gutter-bg)
- );
- --diff-gutter-insert-text-color: hsl(var(--sprout-diff-insert-text));
- --diff-gutter-delete-background-color: hsl(
- var(--sprout-diff-delete-gutter-bg)
- );
- --diff-gutter-delete-text-color: hsl(var(--sprout-diff-delete-text));
+ --diff-gutter-insert-background-color: hsl(var(--buzz-diff-insert-gutter-bg));
+ --diff-gutter-insert-text-color: hsl(var(--buzz-diff-insert-text));
+ --diff-gutter-delete-background-color: hsl(var(--buzz-diff-delete-gutter-bg));
+ --diff-gutter-delete-text-color: hsl(var(--buzz-diff-delete-text));
--diff-gutter-selected-background-color: hsl(var(--accent) / 0.45);
--diff-gutter-selected-text-color: hsl(var(--foreground));
- --diff-code-insert-background-color: hsl(var(--sprout-diff-insert-code-bg));
- --diff-code-insert-text-color: hsl(var(--sprout-diff-insert-text));
- --diff-code-delete-background-color: hsl(var(--sprout-diff-delete-code-bg));
- --diff-code-delete-text-color: hsl(var(--sprout-diff-delete-text));
+ --diff-code-insert-background-color: hsl(var(--buzz-diff-insert-code-bg));
+ --diff-code-insert-text-color: hsl(var(--buzz-diff-insert-text));
+ --diff-code-delete-background-color: hsl(var(--buzz-diff-delete-code-bg));
+ --diff-code-delete-text-color: hsl(var(--buzz-diff-delete-text));
--diff-code-insert-edit-background-color: hsl(
- var(--sprout-diff-insert-edit-bg)
+ var(--buzz-diff-insert-edit-bg)
);
- --diff-code-insert-edit-text-color: hsl(var(--sprout-diff-insert-text));
+ --diff-code-insert-edit-text-color: hsl(var(--buzz-diff-insert-text));
--diff-code-delete-edit-background-color: hsl(
- var(--sprout-diff-delete-edit-bg)
+ var(--buzz-diff-delete-edit-bg)
);
- --diff-code-delete-edit-text-color: hsl(var(--sprout-diff-delete-text));
+ --diff-code-delete-edit-text-color: hsl(var(--buzz-diff-delete-text));
--diff-code-selected-background-color: hsl(var(--accent) / 0.35);
--diff-code-selected-text-color: hsl(var(--foreground));
--diff-omit-gutter-line-color: hsl(var(--border));
}
-.sprout-diff-theme .diff {
+.buzz-diff-theme .diff {
font-size: 12px;
}
-.sprout-diff-theme .diff td {
+.buzz-diff-theme .diff td {
border: 0;
}
-.sprout-diff-theme .sprout-diff-line {
+.buzz-diff-theme .buzz-diff-line {
line-height: 1.35;
}
-.sprout-diff-theme .sprout-diff-gutter {
+.buzz-diff-theme .buzz-diff-gutter {
min-width: 3.5rem;
padding: 0.125rem 0.5rem;
border-right: 1px solid hsl(var(--border) / 0.65);
@@ -75,24 +71,24 @@
font-size: 11px;
}
-.sprout-diff-theme .sprout-diff-code {
+.buzz-diff-theme .buzz-diff-code {
padding: 0.125rem 0.75rem 0.125rem 0.5rem;
white-space: pre-wrap;
word-break: normal;
overflow-wrap: anywhere;
}
-.sprout-diff-theme .diff-code-edit {
+.buzz-diff-theme .diff-code-edit {
border-radius: 0.2rem;
}
-.sprout-diff-theme .diff-decoration-content {
+.buzz-diff-theme .diff-decoration-content {
padding: 0.2rem 0.75rem;
background: hsl(var(--muted) / 0.35);
color: hsl(var(--muted-foreground));
font-size: 11px;
}
-.sprout-diff-theme .diff-gutter-omit::before {
+.buzz-diff-theme .diff-gutter-omit::before {
margin-left: 2.65rem;
}
diff --git a/desktop/src/features/messages/ui/DiffViewer.tsx b/desktop/src/features/messages/ui/DiffViewer.tsx
index f570e0f0c..4c9e501e4 100644
--- a/desktop/src/features/messages/ui/DiffViewer.tsx
+++ b/desktop/src/features/messages/ui/DiffViewer.tsx
@@ -75,7 +75,7 @@ export function DiffViewer({
}
return (
-
+
{files.map((file) => {
const label = getDiffFileLabel(file, fallbackFilePath);
@@ -123,14 +123,14 @@ export function DiffViewer({
{file.hunks.length > 0 ? (
{(hunks) =>
diff --git a/desktop/src/features/messages/ui/MessageComposer.tsx b/desktop/src/features/messages/ui/MessageComposer.tsx
index 6f378b353..def6920db 100644
--- a/desktop/src/features/messages/ui/MessageComposer.tsx
+++ b/desktop/src/features/messages/ui/MessageComposer.tsx
@@ -30,7 +30,7 @@ import {
useRichTextEditor,
} from "@/features/messages/lib/useRichTextEditor";
import { useTypingBroadcast } from "@/features/messages/useTypingBroadcast";
-import { getSproutCodeBlockClipboardText } from "@/shared/lib/codeBlockClipboard";
+import { getBuzzCodeBlockClipboardText } from "@/shared/lib/codeBlockClipboard";
import { cn } from "@/shared/lib/cn";
import type { ChannelType } from "@/shared/api/types";
import { Button } from "@/shared/ui/button";
@@ -628,11 +628,11 @@ export function MessageComposer({
return true;
}
- // --- Sprout code-block paste ---
- // The code block copy button writes a small Sprout marker alongside
+ // --- Buzz code-block paste ---
+ // The code block copy button writes a small Buzz marker alongside
// plain text. Use it to paste back as a literal code block so Markdown
// parsing cannot reshape indentation, fence markers, or headings.
- const codeBlockText = getSproutCodeBlockClipboardText(
+ const codeBlockText = getBuzzCodeBlockClipboardText(
event.clipboardData,
);
if (codeBlockText !== null) {
diff --git a/desktop/src/features/notifications/hooks.ts b/desktop/src/features/notifications/hooks.ts
index 341e53b06..9f7d37b78 100644
--- a/desktop/src/features/notifications/hooks.ts
+++ b/desktop/src/features/notifications/hooks.ts
@@ -29,7 +29,7 @@ export type { DesktopNotificationPermissionState } from "./lib/desktop";
// v2: settings model reworked around per-event rows (flutter default sound,
// slotAlertsEnabled, no singleSound/soundEnabled) — v1 values are abandoned.
-const NOTIFICATION_SETTINGS_STORAGE_KEY = "sprout-notification-settings.v2";
+const NOTIFICATION_SETTINGS_STORAGE_KEY = "buzz-notification-settings.v2";
const HOME_FEED_SEEN_MAX_ITEMS = 500;
export type NotificationSettings = {
@@ -231,7 +231,7 @@ export function useNotificationSettings(pubkey?: string) {
}));
setErrorMessage(
nextPermission === "denied"
- ? "Desktop notifications are blocked for Sprout. Enable them in system settings to turn alerts on."
+ ? "Desktop notifications are blocked for Buzz. Enable them in system settings to turn alerts on."
: "Desktop notifications are unavailable in this environment.",
);
return false;
@@ -473,12 +473,12 @@ export function useHomeFeedNotifications(pubkey: string | undefined) {
}
window.addEventListener(
- "sprout:e2e-home-feed-updated",
+ "buzz:e2e-home-feed-updated",
handleMockHomeFeedUpdate,
);
return () => {
window.removeEventListener(
- "sprout:e2e-home-feed-updated",
+ "buzz:e2e-home-feed-updated",
handleMockHomeFeedUpdate,
);
};
diff --git a/desktop/src/features/notifications/lib/desktop.ts b/desktop/src/features/notifications/lib/desktop.ts
index f11001446..e7c73350a 100644
--- a/desktop/src/features/notifications/lib/desktop.ts
+++ b/desktop/src/features/notifications/lib/desktop.ts
@@ -33,15 +33,15 @@ type DesktopNotificationPayload = {
title: string;
};
-const DESKTOP_NOTIFICATION_ACTION_EVENT = "sprout:desktop-notification-action";
+const DESKTOP_NOTIFICATION_ACTION_EVENT = "buzz:desktop-notification-action";
type DesktopNotificationOptions = NotificationOptions & {
extra?: Record;
};
type TestWindow = Window & {
- __SPROUT_E2E_APP_BADGE_COUNT__?: number;
- __SPROUT_E2E_APP_BADGE_STATE__?: AppBadgeState["kind"];
+ __BUZZ_E2E_APP_BADGE_COUNT__?: number;
+ __BUZZ_E2E_APP_BADGE_STATE__?: AppBadgeState["kind"];
};
function hasNotificationApi() {
@@ -56,7 +56,7 @@ function notificationExtra(
}
return {
- sproutNotificationTarget: target,
+ buzzNotificationTarget: target,
};
}
@@ -177,7 +177,7 @@ export async function listenForDesktopNotificationActions(
try {
pluginListener = await onAction((notification) => {
const target = parseNotificationTarget(
- notification.extra?.sproutNotificationTarget,
+ notification.extra?.buzzNotificationTarget,
);
if (!target) {
return;
@@ -202,9 +202,9 @@ export async function listenForDesktopNotificationActions(
export async function setDesktopAppBadge(state: AppBadgeState): Promise {
if (typeof window !== "undefined") {
const testWindow = window as TestWindow;
- testWindow.__SPROUT_E2E_APP_BADGE_COUNT__ =
+ testWindow.__BUZZ_E2E_APP_BADGE_COUNT__ =
state.kind === "count" ? state.count : 0;
- testWindow.__SPROUT_E2E_APP_BADGE_STATE__ = state.kind;
+ testWindow.__BUZZ_E2E_APP_BADGE_STATE__ = state.kind;
}
if (!isTauri()) {
diff --git a/desktop/src/features/notifications/lib/feed.ts b/desktop/src/features/notifications/lib/feed.ts
index 3529053af..ec7295018 100644
--- a/desktop/src/features/notifications/lib/feed.ts
+++ b/desktop/src/features/notifications/lib/feed.ts
@@ -33,7 +33,7 @@ export function notificationBody(item: FeedItem) {
const fallback =
item.kind === 46010
? "A workflow is waiting for your approval."
- : "Something in Sprout needs your attention.";
+ : "Something in Buzz needs your attention.";
const body = content.length > 0 ? content : fallback;
if (body.length <= FEED_NOTIFICATION_BODY_MAX_LENGTH) {
diff --git a/desktop/src/features/notifications/use-feed-desktop-notifications.ts b/desktop/src/features/notifications/use-feed-desktop-notifications.ts
index e85094f41..60b3f11f2 100644
--- a/desktop/src/features/notifications/use-feed-desktop-notifications.ts
+++ b/desktop/src/features/notifications/use-feed-desktop-notifications.ts
@@ -25,7 +25,7 @@ import {
} from "./lib/sound";
import type { NotificationSettings } from "./hooks";
-const HOME_FEED_SEEN_STORAGE_KEY = "sprout-home-feed-seen.v1";
+const HOME_FEED_SEEN_STORAGE_KEY = "buzz-home-feed-seen.v1";
const HOME_FEED_SEEN_MAX_ITEMS = 500;
function homeFeedSeenStorageKey(pubkey: string) {
diff --git a/desktop/src/features/onboarding/hooks.ts b/desktop/src/features/onboarding/hooks.ts
index c01a289e6..bfb3eca77 100644
--- a/desktop/src/features/onboarding/hooks.ts
+++ b/desktop/src/features/onboarding/hooks.ts
@@ -28,7 +28,7 @@ async function autoJoinDefaultChannel(
}
}
-const ONBOARDING_COMPLETION_STORAGE_KEY = "sprout-onboarding-complete.v1";
+const ONBOARDING_COMPLETION_STORAGE_KEY = "buzz-onboarding-complete.v1";
type OnboardingGateStage = "blocking" | "onboarding" | "ready";
type UseFirstRunOnboardingGateOptions = {
diff --git a/desktop/src/features/onboarding/ui/AvatarStep.tsx b/desktop/src/features/onboarding/ui/AvatarStep.tsx
index 156ca9f4a..a99c69013 100644
--- a/desktop/src/features/onboarding/ui/AvatarStep.tsx
+++ b/desktop/src/features/onboarding/ui/AvatarStep.tsx
@@ -46,12 +46,10 @@ function ErrorBanner({ message }: { message: string | null }) {
}
const NEUTRAL_EMOJI_PICKER_THEME_VARS = {
- "--sprout-emoji-picker-rgb-background":
- "var(--sprout-onboarding-emoji-picker-background)",
- "--sprout-emoji-picker-rgb-color":
- "var(--sprout-onboarding-emoji-picker-color)",
- "--sprout-emoji-picker-rgb-input":
- "var(--sprout-onboarding-emoji-picker-input)",
+ "--buzz-emoji-picker-rgb-background":
+ "var(--buzz-onboarding-emoji-picker-background)",
+ "--buzz-emoji-picker-rgb-color": "var(--buzz-onboarding-emoji-picker-color)",
+ "--buzz-emoji-picker-rgb-input": "var(--buzz-onboarding-emoji-picker-input)",
} as React.CSSProperties;
const AVATAR_ACTIONS_MOTION_TRANSITION = {
@@ -88,8 +86,8 @@ function AvatarPreview({
>
0 && "sprout-avatar-squish",
+ "buzz-avatar-emoji-glyph flex h-full w-full items-center justify-center text-[6rem] leading-[100px]",
+ avatarSquishKey > 0 && "buzz-avatar-squish",
)}
data-testid="onboarding-avatar-preview-emoji"
key={avatarSquishKey}
diff --git a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx
index e523b41ee..5a34585e2 100644
--- a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx
+++ b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx
@@ -401,9 +401,9 @@ export function OnboardingFlow({
return (
diff --git a/desktop/src/features/onboarding/ui/ProfileStep.tsx b/desktop/src/features/onboarding/ui/ProfileStep.tsx
index 49e7b75c4..04e00c92c 100644
--- a/desktop/src/features/onboarding/ui/ProfileStep.tsx
+++ b/desktop/src/features/onboarding/ui/ProfileStep.tsx
@@ -78,7 +78,7 @@ export function ProfileStep({
Name
diff --git a/desktop/src/features/onboarding/ui/SetupStep.tsx b/desktop/src/features/onboarding/ui/SetupStep.tsx
index e6f9fd0b1..d53cf3678 100644
--- a/desktop/src/features/onboarding/ui/SetupStep.tsx
+++ b/desktop/src/features/onboarding/ui/SetupStep.tsx
@@ -345,7 +345,7 @@ function RuntimeProvidersSection({
Agent harnesses
- Sprout can launch local ACP-compatible agent harnesses. Install or
+ Buzz can launch local ACP-compatible agent harnesses. Install or
verify the runtimes this desktop app can see.
diff --git a/desktop/src/features/onboarding/ui/ThemeStep.tsx b/desktop/src/features/onboarding/ui/ThemeStep.tsx
index 0ba54fcdc..ffe8c47fd 100644
--- a/desktop/src/features/onboarding/ui/ThemeStep.tsx
+++ b/desktop/src/features/onboarding/ui/ThemeStep.tsx
@@ -538,7 +538,7 @@ export function ThemeStep({ actions, direction }: ThemeStepProps) {
Pick a theme
- Choose a look that makes Sprout feel like yours.
+ Choose a look that makes Buzz feel like yours.
diff --git a/desktop/src/features/presence/hooks.ts b/desktop/src/features/presence/hooks.ts
index c25d051b9..ed205d82e 100644
--- a/desktop/src/features/presence/hooks.ts
+++ b/desktop/src/features/presence/hooks.ts
@@ -15,7 +15,7 @@ const PRESENCE_HEARTBEAT_INTERVAL_MS = 30_000;
const PRESENCE_IDLE_TIMEOUT_MS = 5 * 60_000;
const PRESENCE_STATUS_TICK_INTERVAL_MS = 30_000;
const PRESENCE_TTL_SECONDS = 90;
-const PRESENCE_PREFERENCE_STORAGE_KEY = "sprout-presence-preference";
+const PRESENCE_PREFERENCE_STORAGE_KEY = "buzz-presence-preference";
type PresencePreference = "auto" | "away" | "offline" | null;
diff --git a/desktop/src/features/profile/ui/ProfileAvatarEditor.tsx b/desktop/src/features/profile/ui/ProfileAvatarEditor.tsx
index 7b3f30451..5ae567faf 100644
--- a/desktop/src/features/profile/ui/ProfileAvatarEditor.tsx
+++ b/desktop/src/features/profile/ui/ProfileAvatarEditor.tsx
@@ -654,7 +654,7 @@ export function ProfileAvatarEditor({
) : (
@@ -883,7 +883,7 @@ export function ProfileAvatarEditor({
aria-valuemax={360}
aria-valuemin={0}
aria-valuenow={customHue}
- className="sprout-avatar-hue-scrubber relative mt-3 h-10 w-full cursor-pointer select-none rounded-full touch-none"
+ className="buzz-avatar-hue-scrubber relative mt-3 h-10 w-full cursor-pointer select-none rounded-full touch-none"
data-testid={`${testIdPrefix}-custom-color-hue`}
onKeyDown={(event) => {
if (
diff --git a/desktop/src/features/profile/ui/ProfileAvatarEditor.utils.ts b/desktop/src/features/profile/ui/ProfileAvatarEditor.utils.ts
index 4aa341e83..0e739bd55 100644
--- a/desktop/src/features/profile/ui/ProfileAvatarEditor.utils.ts
+++ b/desktop/src/features/profile/ui/ProfileAvatarEditor.utils.ts
@@ -461,9 +461,9 @@ export function useEmojiMartStyles(
return;
}
- if (!shadowRoot.querySelector("#sprout-emoji-mart-style")) {
+ if (!shadowRoot.querySelector("#buzz-emoji-mart-style")) {
const style = document.createElement("style");
- style.id = "sprout-emoji-mart-style";
+ style.id = "buzz-emoji-mart-style";
style.textContent = EMOJI_MART_SHADOW_CSS;
shadowRoot.appendChild(style);
}
@@ -492,9 +492,9 @@ export function useEmojiMartThemeVars() {
);
setThemeVars({
- "--sprout-emoji-picker-rgb-background": muted ?? "54, 58, 79",
- "--sprout-emoji-picker-rgb-color": foreground ?? "245, 247, 255",
- "--sprout-emoji-picker-rgb-input": background ?? "47, 51, 68",
+ "--buzz-emoji-picker-rgb-background": muted ?? "54, 58, 79",
+ "--buzz-emoji-picker-rgb-color": foreground ?? "245, 247, 255",
+ "--buzz-emoji-picker-rgb-input": background ?? "47, 51, 68",
} as React.CSSProperties);
};
diff --git a/desktop/src/features/settings/UpdateChecker.tsx b/desktop/src/features/settings/UpdateChecker.tsx
index c03971bbb..4d524760f 100644
--- a/desktop/src/features/settings/UpdateChecker.tsx
+++ b/desktop/src/features/settings/UpdateChecker.tsx
@@ -15,7 +15,7 @@ export function UpdateChecker() {
Software Updates
- Keep Sprout up to date with the latest features and fixes.
+ Keep Buzz up to date with the latest features and fixes.
diff --git a/desktop/src/features/settings/ui/MobilePairingCard.tsx b/desktop/src/features/settings/ui/MobilePairingCard.tsx
index 0571855bb..2e6c77c49 100644
--- a/desktop/src/features/settings/ui/MobilePairingCard.tsx
+++ b/desktop/src/features/settings/ui/MobilePairingCard.tsx
@@ -185,7 +185,7 @@ function PairingDialog({
? "Verify the security code matches your mobile device."
: step === "done"
? "Your mobile device is now paired."
- : "Scan this QR code with the Sprout mobile app to securely pair."}
+ : "Scan this QR code with the Buzz mobile app to securely pair."}
@@ -249,7 +249,7 @@ function PairingDialog({
- You are about to transfer your Sprout identity to another
+ You are about to transfer your Buzz identity to another
device. Only confirm if you initiated this pairing.
@@ -324,7 +324,7 @@ export function MobilePairingCard({
Mobile
- Connect the Sprout mobile app to this relay by scanning a QR code. The
+ Connect the Buzz mobile app to this relay by scanning a QR code. The
connection is secured with end-to-end encryption and a verification
code.
diff --git a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx
index 4122742c1..cfe3c9bb2 100644
--- a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx
+++ b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx
@@ -361,7 +361,7 @@ export function ProfileSettingsCard({
Profile
- Update how your name, avatar, and bio appear across Sprout.
+ Update how your name, avatar, and bio appear across Buzz.
@@ -429,8 +429,8 @@ export function ProfileSettingsCard({
>
0 && "sprout-avatar-squish",
+ "buzz-avatar-emoji-glyph flex h-full w-full items-center justify-center text-[6rem] leading-[100px]",
+ avatarSquishKey > 0 && "buzz-avatar-squish",
)}
data-testid="profile-avatar-preview-emoji"
key={avatarSquishKey}
diff --git a/desktop/src/features/settings/ui/SettingsPanels.tsx b/desktop/src/features/settings/ui/SettingsPanels.tsx
index f54850108..54a36ab11 100644
--- a/desktop/src/features/settings/ui/SettingsPanels.tsx
+++ b/desktop/src/features/settings/ui/SettingsPanels.tsx
@@ -186,7 +186,7 @@ function ThemeSettingsCard() {
Appearance
- Choose a theme for Sprout. Light and dark mode is auto-detected.
+ Choose a theme for Buzz. Light and dark mode is auto-detected.
diff --git a/desktop/src/features/sidebar/lib/channelMutesStorage.ts b/desktop/src/features/sidebar/lib/channelMutesStorage.ts
index 504086a37..098a34c2f 100644
--- a/desktop/src/features/sidebar/lib/channelMutesStorage.ts
+++ b/desktop/src/features/sidebar/lib/channelMutesStorage.ts
@@ -1,4 +1,4 @@
-const STORAGE_KEY_PREFIX = "sprout-channel-mutes.v1";
+const STORAGE_KEY_PREFIX = "buzz-channel-mutes.v1";
export type ChannelMuteEntry = {
muted: boolean;
diff --git a/desktop/src/features/sidebar/lib/channelSectionsStorage.test.mjs b/desktop/src/features/sidebar/lib/channelSectionsStorage.test.mjs
index 390e255d4..2fa111490 100644
--- a/desktop/src/features/sidebar/lib/channelSectionsStorage.test.mjs
+++ b/desktop/src/features/sidebar/lib/channelSectionsStorage.test.mjs
@@ -200,5 +200,5 @@ test("writeChannelSectionsStore: returns false when setItem throws", () => {
});
test("storageKey: returns expected format with pubkey", () => {
- assert.equal(storageKey("abc123"), "sprout-channel-sections.v1:abc123");
+ assert.equal(storageKey("abc123"), "buzz-channel-sections.v1:abc123");
});
diff --git a/desktop/src/features/sidebar/lib/channelSectionsStorage.ts b/desktop/src/features/sidebar/lib/channelSectionsStorage.ts
index a5e22528c..d4a5be708 100644
--- a/desktop/src/features/sidebar/lib/channelSectionsStorage.ts
+++ b/desktop/src/features/sidebar/lib/channelSectionsStorage.ts
@@ -1,4 +1,4 @@
-const STORAGE_KEY_PREFIX = "sprout-channel-sections.v1";
+const STORAGE_KEY_PREFIX = "buzz-channel-sections.v1";
export type ChannelSection = {
id: string;
diff --git a/desktop/src/features/sidebar/lib/channelStarsStorage.ts b/desktop/src/features/sidebar/lib/channelStarsStorage.ts
index b5fd94531..997919c6e 100644
--- a/desktop/src/features/sidebar/lib/channelStarsStorage.ts
+++ b/desktop/src/features/sidebar/lib/channelStarsStorage.ts
@@ -1,4 +1,4 @@
-const STORAGE_KEY_PREFIX = "sprout-channel-stars.v1";
+const STORAGE_KEY_PREFIX = "buzz-channel-stars.v1";
export type ChannelStarEntry = {
starred: boolean;
diff --git a/desktop/src/features/sidebar/ui/NewDirectMessageDialog.tsx b/desktop/src/features/sidebar/ui/NewDirectMessageDialog.tsx
index b1fb688c8..70b34d6a3 100644
--- a/desktop/src/features/sidebar/ui/NewDirectMessageDialog.tsx
+++ b/desktop/src/features/sidebar/ui/NewDirectMessageDialog.tsx
@@ -114,7 +114,7 @@ export function NewDirectMessageDialog({
New direct message
- Pick 1 to 8 people. If the conversation already exists, Sprout will
+ Pick 1 to 8 people. If the conversation already exists, Buzz will
reopen it.
diff --git a/desktop/src/features/workspaces/ui/AddWorkspaceDialog.tsx b/desktop/src/features/workspaces/ui/AddWorkspaceDialog.tsx
index 69fcc34dc..4ae9d43c8 100644
--- a/desktop/src/features/workspaces/ui/AddWorkspaceDialog.tsx
+++ b/desktop/src/features/workspaces/ui/AddWorkspaceDialog.tsx
@@ -64,8 +64,8 @@ export function AddWorkspaceDialog({
Add Workspace
- Connect to another Sprout relay. Each workspace has its own
- channels, messages, and identity.
+ Connect to another Buzz relay. Each workspace has its own channels,
+ messages, and identity.
@@ -420,7 +420,7 @@ export function WelcomeSetup({
return (
@@ -440,11 +440,11 @@ export function WelcomeSetup({
transitionKey={`welcome-${welcomeEffect}-${transitionDirection}`}
>
-
+
- Welcome to Sprout
+ Welcome to Buzz
Choose your first workspace to get started.
diff --git a/desktop/src/features/workspaces/workspaceStorage.ts b/desktop/src/features/workspaces/workspaceStorage.ts
index 550ea8615..25d7747d0 100644
--- a/desktop/src/features/workspaces/workspaceStorage.ts
+++ b/desktop/src/features/workspaces/workspaceStorage.ts
@@ -1,7 +1,7 @@
import type { Workspace } from "./types";
-const WORKSPACES_KEY = "sprout-workspaces";
-const ACTIVE_WORKSPACE_KEY = "sprout-active-workspace-id";
+const WORKSPACES_KEY = "buzz-workspaces";
+const ACTIVE_WORKSPACE_KEY = "buzz-active-workspace-id";
export function loadWorkspaces(): Workspace[] {
try {
@@ -71,9 +71,9 @@ export function deriveWorkspaceName(relayUrl: string): string {
return "Local Dev";
}
const parts = host.split(".");
- // Detect staging environments (e.g. sprout-oss.stage.blox.sqprod.co)
+ // Detect staging environments (e.g. buzz-oss.stage.blox.sqprod.co)
if (parts.some((p) => p === "stage" || p === "staging")) {
- return "Sprout (staging)";
+ return "Buzz (staging)";
}
// Use the first subdomain segment or the domain itself
if (parts.length >= 2) {
diff --git a/desktop/src/main.tsx b/desktop/src/main.tsx
index 67d8290b0..b0d26fecd 100644
--- a/desktop/src/main.tsx
+++ b/desktop/src/main.tsx
@@ -10,7 +10,7 @@ import { Toaster } from "@/shared/ui/sonner";
import { TooltipProvider } from "@/shared/ui/tooltip";
type E2eWindow = Window & {
- __SPROUT_E2E__?: unknown;
+ __BUZZ_E2E__?: unknown;
};
function renderApp() {
@@ -35,7 +35,7 @@ function renderApp() {
async function installE2eBridgeIfConfigured() {
// Keep the large E2E bridge out of the normal startup path and production
// bundle; only load it when tests explicitly inject an E2E config.
- if (!(window as E2eWindow).__SPROUT_E2E__) {
+ if (!(window as E2eWindow).__BUZZ_E2E__) {
return;
}
diff --git a/desktop/src/shared/api/customEmoji.test.mjs b/desktop/src/shared/api/customEmoji.test.mjs
index 3a28964e1..9a0c384d1 100644
--- a/desktop/src/shared/api/customEmoji.test.mjs
+++ b/desktop/src/shared/api/customEmoji.test.mjs
@@ -24,7 +24,7 @@ function ev(tags) {
test("parses emoji tags into shortcode/url pairs", () => {
const out = customEmojiFromEvent(
ev([
- ["d", "sprout:custom-emoji"],
+ ["d", "buzz:custom-emoji"],
["emoji", "party_parrot", "https://relay/p.gif"],
["emoji", "shipit", "https://relay/s.png"],
]),
@@ -65,7 +65,7 @@ test("ignores non-emoji tags", () => {
const out = customEmojiFromEvent(
ev([
["d", "x"],
- ["client", "sprout"],
+ ["client", "buzz"],
["emoji", "yes", "https://relay/y.png"],
]),
);
diff --git a/desktop/src/shared/api/customEmoji.ts b/desktop/src/shared/api/customEmoji.ts
index a4a24dfe1..4f97cb2a7 100644
--- a/desktop/src/shared/api/customEmoji.ts
+++ b/desktop/src/shared/api/customEmoji.ts
@@ -2,7 +2,7 @@
* Workspace custom emoji (NIP-30, per-user sets).
*
* Each member publishes their OWN kind:30030 parameterized-replaceable event,
- * signed as themselves, keyed by `(pubkey, 30030, "sprout:custom-emoji")`. The
+ * signed as themselves, keyed by `(pubkey, 30030, "buzz:custom-emoji")`. The
* "workspace palette" shown in the picker/renderer is the client-side UNION of
* every member's set, collapsed to one entry per shortcode (deterministic
* winner) — a view computed on read, not stored state. Downstream identity is
@@ -25,7 +25,7 @@ import type { CustomEmoji } from "@/shared/lib/remarkCustomEmoji";
export const KIND_EMOJI_SET = 30030;
/** d-tag for a member's own custom emoji set. */
-export const CUSTOM_EMOJI_SET_D_TAG = "sprout:custom-emoji";
+export const CUSTOM_EMOJI_SET_D_TAG = "buzz:custom-emoji";
/**
* Resolve the image URL for a reaction whose content is a custom-emoji
diff --git a/desktop/src/shared/api/queryClient.ts b/desktop/src/shared/api/queryClient.ts
index 196998cca..fead8c825 100644
--- a/desktop/src/shared/api/queryClient.ts
+++ b/desktop/src/shared/api/queryClient.ts
@@ -1,6 +1,6 @@
import { QueryClient } from "@tanstack/react-query";
-export function createSproutQueryClient() {
+export function createBuzzQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
diff --git a/desktop/src/shared/api/tauriMesh.ts b/desktop/src/shared/api/tauriMesh.ts
index 0237a3a6c..8f22d563c 100644
--- a/desktop/src/shared/api/tauriMesh.ts
+++ b/desktop/src/shared/api/tauriMesh.ts
@@ -61,7 +61,7 @@ export type MeshNodeStatus = {
export type MeshCallMeNow = {
v: 1;
- type: "sprout-iroh-call-me-now";
+ type: "buzz-iroh-call-me-now";
peer_endpoint_addr: string;
peer_endpoint_id?: string;
attempt_id: string;
diff --git a/desktop/src/shared/api/types.ts b/desktop/src/shared/api/types.ts
index a6c6b1c1c..653a1be99 100644
--- a/desktop/src/shared/api/types.ts
+++ b/desktop/src/shared/api/types.ts
@@ -298,7 +298,7 @@ export type ManagedAgent = {
startOnAppLaunch: boolean;
backend: ManagedAgentBackend;
backendAgentId: string | null;
- /** Who the agent should respond to. Maps to `sprout-acp --respond-to`. */
+ /** Who the agent should respond to. Maps to `buzz-acp --respond-to`. */
respondTo: RespondToMode;
/**
* Normalized 64-char lowercase hex pubkeys. Used only when `respondTo` is
@@ -308,7 +308,7 @@ export type ManagedAgent = {
};
/**
- * Inbound author gate mode. Mirrors `sprout-acp`'s `--respond-to` CLI flag.
+ * Inbound author gate mode. Mirrors `buzz-acp`'s `--respond-to` CLI flag.
* `"nobody"` is supported by the harness but not surfaced through this API —
* it's a heartbeat-only mode without a meaningful GUI use case.
*/
@@ -473,7 +473,7 @@ export type AgentPersona = {
systemPrompt: string;
/** Preferred ACP runtime ID (e.g. "goose", "claude"). */
runtime: string | null;
- /** Opaque, harness-specific model identifier string. Sprout stores and passes through without interpretation. */
+ /** Opaque, harness-specific model identifier string. Buzz stores and passes through without interpretation. */
model: string | null;
/** LLM inference provider (e.g. "databricks", "anthropic"). Injected as the runtime's provider env var at spawn time. */
provider: string | null;
diff --git a/desktop/src/shared/constants/kinds.ts b/desktop/src/shared/constants/kinds.ts
index 191dee2ed..5dac8d1c3 100644
--- a/desktop/src/shared/constants/kinds.ts
+++ b/desktop/src/shared/constants/kinds.ts
@@ -1,7 +1,7 @@
export const KIND_DELETION = 5;
export const KIND_REACTION = 7;
export const KIND_STREAM_MESSAGE = 9;
-// Sprout-native deletion. The relay soft-deletes the target and emits a
+// Buzz-native deletion. The relay soft-deletes the target and emits a
// kind:40099 system message. Treated as a deletion marker alongside kind:5.
export const KIND_NIP29_DELETE_EVENT = 9005;
export const KIND_STREAM_MESSAGE_V2 = 40002;
@@ -49,13 +49,13 @@ export const CHANNEL_MESSAGE_EVENT_KINDS = [
KIND_FORUM_COMMENT,
] as const;
-// Keep this in sync with the Home-feed mention query in sprout-db.
+// Keep this in sync with the Home-feed mention query in buzz-db.
export const HOME_MENTION_EVENT_KINDS = [...CHANNEL_MESSAGE_EVENT_KINDS];
export const CHANNEL_EVENT_KINDS = [
KIND_DELETION, // 5 — NIP-09 event deletions
KIND_REACTION, // 7 — NIP-25 reactions
- KIND_NIP29_DELETE_EVENT, // 9005 — NIP-29 / Sprout-native deletions
+ KIND_NIP29_DELETE_EVENT, // 9005 — NIP-29 / Buzz-native deletions
...CHANNEL_MESSAGE_EVENT_KINDS,
40001, // legacy: pre-migration stream messages
KIND_STREAM_MESSAGE_EDIT, // 40003 — message edits
diff --git a/desktop/src/shared/features/store.ts b/desktop/src/shared/features/store.ts
index ee55fc392..113fe27cb 100644
--- a/desktop/src/shared/features/store.ts
+++ b/desktop/src/shared/features/store.ts
@@ -4,12 +4,12 @@
* The localStorage key is derived from `manifest.version` so a schema bump
* naturally orphans the old key — clean reset, no migration logic.
*
- * sprout-feature-overrides-v${manifest.version}
+ * buzz-feature-overrides-v${manifest.version}
* → JSON object of { [featureId]: boolean }
*/
import { manifest } from "./manifest";
-export const OVERRIDES_KEY = `sprout-feature-overrides-v${manifest.version}`;
+export const OVERRIDES_KEY = `buzz-feature-overrides-v${manifest.version}`;
export type FeatureOverrides = Record;
diff --git a/desktop/src/shared/features/useFeatureEnabled.ts b/desktop/src/shared/features/useFeatureEnabled.ts
index 906a12b39..9d1594d7f 100644
--- a/desktop/src/shared/features/useFeatureEnabled.ts
+++ b/desktop/src/shared/features/useFeatureEnabled.ts
@@ -63,7 +63,7 @@ function getSnapshot(): string {
/**
* Server-side snapshot for useSyncExternalStore.
*
- * Sprout is a Tauri desktop app and does not currently SSR. Returning an
+ * Buzz is a Tauri desktop app and does not currently SSR. Returning an
* explicit empty-state snapshot is safer than omitting this argument: under
* any future test harness or SSR experiment, the hook returns "no overrides"
* instead of throwing.
@@ -73,7 +73,7 @@ const getServerSnapshot = (): string => "{}";
function getParsedSnapshot(): Record {
// Ensure snapshot is fresh
getSnapshot();
- return cachedParsed!;
+ return cachedParsed ?? {};
}
// ---------------------------------------------------------------------------
diff --git a/desktop/src/shared/hooks/useThreadPanelWidth.ts b/desktop/src/shared/hooks/useThreadPanelWidth.ts
index 172a47a1a..2988d5cb0 100644
--- a/desktop/src/shared/hooks/useThreadPanelWidth.ts
+++ b/desktop/src/shared/hooks/useThreadPanelWidth.ts
@@ -5,7 +5,7 @@ export const THREAD_PANEL_MIN_WIDTH_PX = 300;
export const THREAD_PANEL_SINGLE_COLUMN_BREAKPOINT_PX =
THREAD_PANEL_MIN_WIDTH_PX * 2;
const THREAD_PANEL_MAX_WIDTH_PX = 720;
-const THREAD_PANEL_WIDTH_SESSION_KEY = "sprout.desktop.thread-panel-width";
+const THREAD_PANEL_WIDTH_SESSION_KEY = "buzz.desktop.thread-panel-width";
function clampThreadPanelWidth(width: number): number {
return Math.max(
diff --git a/desktop/src/shared/layout/chromeLayout.ts b/desktop/src/shared/layout/chromeLayout.ts
index 7bdd90d12..7c90b892e 100644
--- a/desktop/src/shared/layout/chromeLayout.ts
+++ b/desktop/src/shared/layout/chromeLayout.ts
@@ -2,8 +2,8 @@ export const TOP_CHROME_HEIGHT_DEFAULT = "2.5rem";
export const CHANNEL_CONTENT_TOP_PADDING_DEFAULT = "5.75rem";
export const chromeCssVars = {
- topChromeHeight: "--sprout-top-chrome-height",
- channelContentTopPadding: "--sprout-channel-content-top-padding",
+ topChromeHeight: "--buzz-top-chrome-height",
+ channelContentTopPadding: "--buzz-channel-content-top-padding",
} as const;
export const chromeCssVarDefaults = {
@@ -19,38 +19,38 @@ export const channelContentTopPaddingMeasurement = {
/** Tailwind class fragments for layout under the global top chrome. */
export const topChromeInset = {
/** Absolute/fixed top offset below the search bar. */
- top: "top-(--sprout-top-chrome-height,2.5rem)",
+ top: "top-(--buzz-top-chrome-height,2.5rem)",
/** Padding-top clearing the global top chrome. */
- padding: "pt-(--sprout-top-chrome-height,2.5rem)",
+ padding: "pt-(--buzz-top-chrome-height,2.5rem)",
/** `after:` pseudo-element top offset. */
- afterTop: "after:top-(--sprout-top-chrome-height,2.5rem)",
+ afterTop: "after:top-(--buzz-top-chrome-height,2.5rem)",
/** Horizontal divider at the bottom edge of the global top chrome inset. */
divider:
- "before:pointer-events-none before:absolute before:inset-x-0 before:top-(--sprout-top-chrome-height,2.5rem) before:h-px before:bg-border/35 before:content-['']",
+ "before:pointer-events-none before:absolute before:inset-x-0 before:top-(--buzz-top-chrome-height,2.5rem) before:h-px before:bg-border/35 before:content-['']",
/** Shared header backdrop and bottom border below the inset row. */
headerBase:
"relative z-40 shrink-0 border-b border-border/35 bg-background/75 backdrop-blur-md supports-backdrop-filter:bg-background/65 dark:bg-background/45 dark:backdrop-blur-xl dark:supports-backdrop-filter:bg-background/35",
/** Vertical pane divider starting below the global top chrome. */
verticalDivider:
- "after:pointer-events-none after:absolute after:bottom-0 after:right-0 after:top-(--sprout-top-chrome-height,2.5rem) after:z-40 after:w-px after:bg-border/35 after:content-['']",
+ "after:pointer-events-none after:absolute after:bottom-0 after:right-0 after:top-(--buzz-top-chrome-height,2.5rem) after:z-40 after:w-px after:bg-border/35 after:content-['']",
} as const;
/** Tailwind class fragments for the global top chrome backdrop strip. */
export const topChromeBackdrop = {
/** Height matching the global top chrome search/drag strip. */
- height: "h-(--sprout-top-chrome-height,2.5rem)",
+ height: "h-(--buzz-top-chrome-height,2.5rem)",
/** `after:` pseudo-element offset aligned to the bottom of top chrome. */
- dividerTop: "after:top-(--sprout-top-chrome-height,2.5rem)",
+ dividerTop: "after:top-(--buzz-top-chrome-height,2.5rem)",
} as const;
/** Tailwind class fragments for measured channel header chrome. */
export const channelChrome = {
/** Padding-top that clears the measured channel header chrome. */
- contentPadding: "pt-(--sprout-channel-content-top-padding,5.75rem)",
+ contentPadding: "pt-(--buzz-channel-content-top-padding,5.75rem)",
/** Absolute/fixed top offset below the measured channel header chrome. */
- top: "top-(--sprout-channel-content-top-padding,5.75rem)",
+ top: "top-(--buzz-channel-content-top-padding,5.75rem)",
/** Height matching the measured channel header chrome. */
- headerHeight: "h-(--sprout-channel-content-top-padding,5.75rem)",
+ headerHeight: "h-(--buzz-channel-content-top-padding,5.75rem)",
/** Negative margin for overlaid channel chrome that should not affect flow. */
- negativeMargin: "-mb-(--sprout-channel-content-top-padding,5.75rem)",
+ negativeMargin: "-mb-(--buzz-channel-content-top-padding,5.75rem)",
} as const;
diff --git a/desktop/src/shared/lib/codeBlockClipboard.ts b/desktop/src/shared/lib/codeBlockClipboard.ts
index 45cc4ff09..bc6d50063 100644
--- a/desktop/src/shared/lib/codeBlockClipboard.ts
+++ b/desktop/src/shared/lib/codeBlockClipboard.ts
@@ -1,4 +1,4 @@
-const SPROUT_CODE_BLOCK_ATTRIBUTE = "data-sprout-code-block";
+const BUZZ_CODE_BLOCK_ATTRIBUTE = "data-buzz-code-block";
function escapeHtml(value: string) {
return value
@@ -8,9 +8,9 @@ function escapeHtml(value: string) {
.replace(/"/g, """);
}
-function createSproutCodeBlockHtml(code: string) {
+function createBuzzCodeBlockHtml(code: string) {
// Keep the code as one text node; the paste reader recovers it via textContent.
- return `${escapeHtml(code)} `;
+ return `${escapeHtml(code)} `;
}
export async function copyCodeBlockToClipboard(code: string) {
@@ -26,7 +26,7 @@ export async function copyCodeBlockToClipboard(code: string) {
try {
await clipboard.write([
new ClipboardItem({
- "text/html": new Blob([createSproutCodeBlockHtml(code)], {
+ "text/html": new Blob([createBuzzCodeBlockHtml(code)], {
type: "text/html",
}),
"text/plain": new Blob([code], { type: "text/plain" }),
@@ -41,17 +41,17 @@ export async function copyCodeBlockToClipboard(code: string) {
await clipboard.writeText(code);
}
-export function getSproutCodeBlockClipboardText(
+export function getBuzzCodeBlockClipboardText(
clipboardData: DataTransfer | null | undefined,
) {
const html = clipboardData?.getData("text/html");
- if (!html?.includes(SPROUT_CODE_BLOCK_ATTRIBUTE)) {
+ if (!html?.includes(BUZZ_CODE_BLOCK_ATTRIBUTE)) {
return null;
}
const document = new DOMParser().parseFromString(html, "text/html");
- const code = document.querySelector(`[${SPROUT_CODE_BLOCK_ATTRIBUTE}] code`);
- const fallback = document.querySelector(`[${SPROUT_CODE_BLOCK_ATTRIBUTE}]`);
+ const code = document.querySelector(`[${BUZZ_CODE_BLOCK_ATTRIBUTE}] code`);
+ const fallback = document.querySelector(`[${BUZZ_CODE_BLOCK_ATTRIBUTE}]`);
return code?.textContent ?? fallback?.textContent ?? null;
}
diff --git a/desktop/src/shared/lib/emojiOnly.test.mjs b/desktop/src/shared/lib/emojiOnly.test.mjs
index b60376fcf..c51c2c024 100644
--- a/desktop/src/shared/lib/emojiOnly.test.mjs
+++ b/desktop/src/shared/lib/emojiOnly.test.mjs
@@ -4,7 +4,7 @@ import test from "node:test";
import { isEmojiOnlyMessage } from "./emojiOnly.ts";
const CUSTOM_EMOJI = [
- { shortcode: "sprout", url: "https://relay/sprout.png" },
+ { shortcode: "buzz", url: "https://relay/buzz.png" },
{ shortcode: "party_parrot", url: "https://relay/parrot.gif" },
];
@@ -15,16 +15,13 @@ test("detects unicode emoji-only messages", () => {
});
test("detects known custom emoji-only shortcode messages", () => {
- assert.equal(isEmojiOnlyMessage(":sprout:", CUSTOM_EMOJI), true);
- assert.equal(
- isEmojiOnlyMessage(":sprout: :party_parrot:", CUSTOM_EMOJI),
- true,
- );
- assert.equal(isEmojiOnlyMessage(":Sprout:", CUSTOM_EMOJI), true);
+ assert.equal(isEmojiOnlyMessage(":buzz:", CUSTOM_EMOJI), true);
+ assert.equal(isEmojiOnlyMessage(":buzz: :party_parrot:", CUSTOM_EMOJI), true);
+ assert.equal(isEmojiOnlyMessage(":Buzz:", CUSTOM_EMOJI), true);
});
test("allows mixed unicode and custom emoji", () => {
- assert.equal(isEmojiOnlyMessage("😀 :sprout: ❤️", CUSTOM_EMOJI), true);
+ assert.equal(isEmojiOnlyMessage("😀 :buzz: ❤️", CUSTOM_EMOJI), true);
});
test("rejects prose, markdown, and unknown shortcodes", () => {
diff --git a/desktop/src/shared/lib/mediaUrl.ts b/desktop/src/shared/lib/mediaUrl.ts
index 104135caa..b172f618d 100644
--- a/desktop/src/shared/lib/mediaUrl.ts
+++ b/desktop/src/shared/lib/mediaUrl.ts
@@ -8,11 +8,11 @@
* For video, the proxy streams via axum — no buffering the entire file.
* Images and other media also benefit from this path.
*
- * Only URLs hosted on the Sprout relay are rewritten. External Blossom URLs
+ * Only URLs hosted on the Buzz relay are rewritten. External Blossom URLs
* (e.g. nostr.build, void.cat) are returned unchanged — they aren't behind
* Cloudflare Access and can be loaded directly by WKWebView. Without this
* origin check, external Blossom URLs would be proxied to the wrong server
- * (the Sprout relay), resulting in 404s.
+ * (the Buzz relay), resulting in 404s.
*/
import { invoke } from "@tauri-apps/api/core";
@@ -26,7 +26,7 @@ const RELAY_MEDIA_RE =
let cachedPort: number | null = null;
let portPromise: Promise | null = null;
-/** Cached relay origin (e.g. "https://sprout-oss.stage.blox.sqprod.co"). */
+/** Cached relay origin (e.g. "https://buzz-oss.stage.blox.sqprod.co"). */
let cachedRelayOrigin: string | null = null;
const POLL_INTERVAL_MS = 100;
@@ -81,11 +81,11 @@ export function resetMediaCaches(): void {
}
/**
- * If `url` is a Blossom media URL hosted on the Sprout relay, rewrite it
+ * If `url` is a Blossom media URL hosted on the Buzz relay, rewrite it
* to go through the localhost streaming proxy. External Blossom URLs and
* non-Blossom URLs are returned unchanged.
*
- * Falls back to sprout-media:// if the proxy port isn't available yet.
+ * Falls back to buzz-media:// if the proxy port isn't available yet.
*/
export function rewriteRelayUrl(url: string): string {
const m = RELAY_MEDIA_RE.exec(url);
@@ -108,5 +108,5 @@ export function rewriteRelayUrl(url: string): string {
portPromise = fetchProxyPort();
}
- return `sprout-media://localhost/media/${m[1]}`;
+ return `buzz-media://localhost/media/${m[1]}`;
}
diff --git a/desktop/src/shared/styles/globals.css b/desktop/src/shared/styles/globals.css
index 0af6fb944..468406089 100644
--- a/desktop/src/shared/styles/globals.css
+++ b/desktop/src/shared/styles/globals.css
@@ -2,7 +2,7 @@
@import "tw-animate-css";
@config "../../../tailwind.config.js";
-.sprout-emoji-mart {
+.buzz-emoji-mart {
align-items: stretch;
display: flex;
justify-content: stretch;
@@ -10,7 +10,7 @@
width: 100%;
}
-.sprout-emoji-mart > div {
+.buzz-emoji-mart > div {
align-items: stretch;
display: flex;
height: 100%;
@@ -21,17 +21,17 @@
width: 100%;
}
-.sprout-emoji-mart em-emoji-picker {
+.buzz-emoji-mart em-emoji-picker {
--border-radius: 12px;
--category-icon-size: 24px;
--color-border: transparent;
--color-border-over: rgb(255 255 255 / 0.1);
--font-family: inherit;
--font-size: 14px;
- --rgb-accent: var(--sprout-emoji-picker-rgb-color, 245, 247, 255);
- --rgb-background: var(--sprout-emoji-picker-rgb-background, 54, 58, 79);
- --rgb-color: var(--sprout-emoji-picker-rgb-color, 245, 247, 255);
- --rgb-input: var(--sprout-emoji-picker-rgb-input, 47, 51, 68);
+ --rgb-accent: var(--buzz-emoji-picker-rgb-color, 245, 247, 255);
+ --rgb-background: var(--buzz-emoji-picker-rgb-background, 54, 58, 79);
+ --rgb-color: var(--buzz-emoji-picker-rgb-color, 245, 247, 255);
+ --rgb-input: var(--buzz-emoji-picker-rgb-input, 47, 51, 68);
--shadow: none;
height: 100%;
max-height: 100%;
@@ -40,47 +40,47 @@
width: 100%;
}
-@keyframes sprout-avatar-squish {
+@keyframes buzz-avatar-squish {
0% {
transform: translate(
- var(--sprout-avatar-emoji-offset-x, 0px),
- var(--sprout-avatar-emoji-offset-y, 0px)
+ var(--buzz-avatar-emoji-offset-x, 0px),
+ var(--buzz-avatar-emoji-offset-y, 0px)
)
scale(1);
}
42% {
transform: translate(
- var(--sprout-avatar-emoji-offset-x, 0px),
- var(--sprout-avatar-emoji-offset-y, 0px)
+ var(--buzz-avatar-emoji-offset-x, 0px),
+ var(--buzz-avatar-emoji-offset-y, 0px)
)
scaleX(0.96) scaleY(0.88);
}
100% {
transform: translate(
- var(--sprout-avatar-emoji-offset-x, 0px),
- var(--sprout-avatar-emoji-offset-y, 0px)
+ var(--buzz-avatar-emoji-offset-x, 0px),
+ var(--buzz-avatar-emoji-offset-y, 0px)
)
scale(1);
}
}
-.sprout-avatar-emoji-glyph {
- --sprout-avatar-emoji-offset-x: 1px;
- --sprout-avatar-emoji-offset-y: 7px;
+.buzz-avatar-emoji-glyph {
+ --buzz-avatar-emoji-offset-x: 1px;
+ --buzz-avatar-emoji-offset-y: 7px;
transform: translate(
- var(--sprout-avatar-emoji-offset-x),
- var(--sprout-avatar-emoji-offset-y)
+ var(--buzz-avatar-emoji-offset-x),
+ var(--buzz-avatar-emoji-offset-y)
);
}
-.sprout-avatar-squish {
- animation: sprout-avatar-squish 200ms ease-out;
+.buzz-avatar-squish {
+ animation: buzz-avatar-squish 200ms ease-out;
transform-origin: center;
}
-.sprout-setup-loading-shell {
+.buzz-setup-loading-shell {
background-image:
radial-gradient(circle at top, hsl(var(--primary) / 0.18), transparent 46%),
radial-gradient(
@@ -91,9 +91,8 @@
linear-gradient(180deg, hsl(var(--background)), hsl(var(--muted) / 0.55));
}
-.sprout-setup-loading-text {
- animation: sprout-setup-character-rise 700ms cubic-bezier(0.2, 0.8, 0.2, 1)
- both;
+.buzz-setup-loading-text {
+ animation: buzz-setup-character-rise 700ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
backface-visibility: hidden;
display: inline-block;
opacity: 0;
@@ -102,7 +101,7 @@
will-change: transform, opacity;
}
-@keyframes sprout-setup-character-rise {
+@keyframes buzz-setup-character-rise {
from {
opacity: 0;
transform: translate3d(0, 32px, 0);
@@ -115,14 +114,14 @@
}
@media (prefers-reduced-motion: reduce) {
- .sprout-setup-loading-text {
+ .buzz-setup-loading-text {
animation: none;
opacity: 1;
transform: none;
}
}
-.sprout-avatar-hue-scrubber {
+.buzz-avatar-hue-scrubber {
background: linear-gradient(
90deg,
#ff0000 0%,
@@ -139,7 +138,7 @@
-webkit-user-select: none;
}
-.sprout-animated-count {
+.buzz-animated-count {
display: inline-block;
font-kerning: none;
font-variant-numeric: tabular-nums;
@@ -147,28 +146,28 @@
white-space: nowrap;
}
-.sprout-animated-count__motion {
+.buzz-animated-count__motion {
display: inline-flex;
line-height: 1;
}
-.sprout-animated-count__static {
+.buzz-animated-count__static {
display: none;
}
-.sprout-animated-count__slot {
+.buzz-animated-count__slot {
display: inline-block;
height: 1em;
line-height: 1;
}
-.sprout-animated-count__slot--digit {
+.buzz-animated-count__slot--digit {
overflow: hidden;
text-align: center;
width: 1ch;
}
-.sprout-animated-count__reel {
+.buzz-animated-count__reel {
display: flex;
flex-direction: column;
height: 2em;
@@ -176,39 +175,38 @@
will-change: transform;
}
-.sprout-animated-count__reel > span {
+.buzz-animated-count__reel > span {
display: block;
height: 1em;
line-height: 1;
}
-.sprout-animated-count__slot[data-direction="up"] .sprout-animated-count__reel {
- animation: sprout-animated-count-roll-up 260ms cubic-bezier(0.2, 0.8, 0.2, 1)
+.buzz-animated-count__slot[data-direction="up"] .buzz-animated-count__reel {
+ animation: buzz-animated-count-roll-up 260ms cubic-bezier(0.2, 0.8, 0.2, 1)
both;
}
-.sprout-animated-count__slot[data-direction="down"]
- .sprout-animated-count__reel {
- animation: sprout-animated-count-roll-down 260ms
- cubic-bezier(0.2, 0.8, 0.2, 1) both;
+.buzz-animated-count__slot[data-direction="down"] .buzz-animated-count__reel {
+ animation: buzz-animated-count-roll-down 260ms cubic-bezier(0.2, 0.8, 0.2, 1)
+ both;
}
-.sprout-animated-count__symbol {
+.buzz-animated-count__symbol {
display: inline-block;
line-height: 1;
}
-.sprout-animated-count__symbol[data-direction="up"] {
- animation: sprout-animated-count-symbol-up 220ms
- cubic-bezier(0.2, 0.8, 0.2, 1) both;
+.buzz-animated-count__symbol[data-direction="up"] {
+ animation: buzz-animated-count-symbol-up 220ms cubic-bezier(0.2, 0.8, 0.2, 1)
+ both;
}
-.sprout-animated-count__symbol[data-direction="down"] {
- animation: sprout-animated-count-symbol-down 220ms
+.buzz-animated-count__symbol[data-direction="down"] {
+ animation: buzz-animated-count-symbol-down 220ms
cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
-@keyframes sprout-animated-count-roll-up {
+@keyframes buzz-animated-count-roll-up {
from {
transform: translateY(0);
}
@@ -218,7 +216,7 @@
}
}
-@keyframes sprout-animated-count-roll-down {
+@keyframes buzz-animated-count-roll-down {
from {
transform: translateY(-1em);
}
@@ -228,7 +226,7 @@
}
}
-@keyframes sprout-animated-count-symbol-up {
+@keyframes buzz-animated-count-symbol-up {
from {
opacity: 0;
transform: translateY(0.25em);
@@ -240,7 +238,7 @@
}
}
-@keyframes sprout-animated-count-symbol-down {
+@keyframes buzz-animated-count-symbol-down {
from {
opacity: 0;
transform: translateY(-0.25em);
@@ -253,11 +251,11 @@
}
@media (prefers-reduced-motion: reduce) {
- .sprout-animated-count__motion {
+ .buzz-animated-count__motion {
display: none;
}
- .sprout-animated-count__static {
+ .buzz-animated-count__static {
display: inline;
}
}
@@ -642,12 +640,12 @@
}
@layer components {
- .sprout-startup-shell {
+ .buzz-startup-shell {
min-height: 100dvh;
width: 100%;
}
- .sprout-onboarding-neutral-theme {
+ .buzz-onboarding-neutral-theme {
--background: 0 0% 100%;
--foreground: 0 0% 9%;
--primary: 0 0% 9%;
@@ -661,12 +659,12 @@
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 9%;
- --sprout-onboarding-emoji-picker-background: 245, 245, 245;
- --sprout-onboarding-emoji-picker-color: 23, 23, 23;
- --sprout-onboarding-emoji-picker-input: 255, 255, 255;
+ --buzz-onboarding-emoji-picker-background: 245, 245, 245;
+ --buzz-onboarding-emoji-picker-color: 23, 23, 23;
+ --buzz-onboarding-emoji-picker-input: 255, 255, 255;
}
- .dark .sprout-onboarding-neutral-theme {
+ .dark .buzz-onboarding-neutral-theme {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
@@ -680,12 +678,12 @@
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
- --sprout-onboarding-emoji-picker-background: 38, 38, 38;
- --sprout-onboarding-emoji-picker-color: 250, 250, 250;
- --sprout-onboarding-emoji-picker-input: 10, 10, 10;
+ --buzz-onboarding-emoji-picker-background: 38, 38, 38;
+ --buzz-onboarding-emoji-picker-color: 250, 250, 250;
+ --buzz-onboarding-emoji-picker-input: 10, 10, 10;
}
- .sprout-onboarding-neutral-theme[data-system-color-scheme="light"] {
+ .buzz-onboarding-neutral-theme[data-system-color-scheme="light"] {
--background: 0 0% 100%;
--foreground: 0 0% 9%;
--primary: 0 0% 9%;
@@ -699,12 +697,12 @@
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 9%;
- --sprout-onboarding-emoji-picker-background: 245, 245, 245;
- --sprout-onboarding-emoji-picker-color: 23, 23, 23;
- --sprout-onboarding-emoji-picker-input: 255, 255, 255;
+ --buzz-onboarding-emoji-picker-background: 245, 245, 245;
+ --buzz-onboarding-emoji-picker-color: 23, 23, 23;
+ --buzz-onboarding-emoji-picker-input: 255, 255, 255;
}
- .sprout-onboarding-neutral-theme[data-system-color-scheme="dark"] {
+ .buzz-onboarding-neutral-theme[data-system-color-scheme="dark"] {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
@@ -718,49 +716,49 @@
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
- --sprout-onboarding-emoji-picker-background: 38, 38, 38;
- --sprout-onboarding-emoji-picker-color: 250, 250, 250;
- --sprout-onboarding-emoji-picker-input: 10, 10, 10;
+ --buzz-onboarding-emoji-picker-background: 38, 38, 38;
+ --buzz-onboarding-emoji-picker-color: 250, 250, 250;
+ --buzz-onboarding-emoji-picker-input: 10, 10, 10;
}
- .sprout-onboarding-transition-content {
- animation-delay: var(--sprout-onboarding-transition-delay, 0ms);
+ .buzz-onboarding-transition-content {
+ animation-delay: var(--buzz-onboarding-transition-delay, 0ms);
}
- .sprout-onboarding-transition-line[data-onboarding-effect="line-slide"]
- > .sprout-onboarding-transition-content {
+ .buzz-onboarding-transition-line[data-onboarding-effect="line-slide"]
+ > .buzz-onboarding-transition-content {
animation-duration: 650ms;
animation-fill-mode: backwards;
animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
- .sprout-onboarding-transition-line[data-onboarding-effect="line-slide"][data-onboarding-direction="forward"]
- > .sprout-onboarding-transition-content {
- animation-name: sprout-onboarding-line-slide-forward;
+ .buzz-onboarding-transition-line[data-onboarding-effect="line-slide"][data-onboarding-direction="forward"]
+ > .buzz-onboarding-transition-content {
+ animation-name: buzz-onboarding-line-slide-forward;
}
- .sprout-onboarding-transition-line[data-onboarding-effect="line-slide"][data-onboarding-direction="backward"]
- > .sprout-onboarding-transition-content {
- animation-name: sprout-onboarding-line-slide-backward;
+ .buzz-onboarding-transition-line[data-onboarding-effect="line-slide"][data-onboarding-direction="backward"]
+ > .buzz-onboarding-transition-content {
+ animation-name: buzz-onboarding-line-slide-backward;
}
- .sprout-onboarding-transition-line[data-onboarding-effect="mask-reveal-up"] {
+ .buzz-onboarding-transition-line[data-onboarding-effect="mask-reveal-up"] {
overflow: visible;
}
- .sprout-onboarding-transition-line[data-onboarding-effect="mask-reveal-up"]
- > .sprout-onboarding-transition-content {
- animation: sprout-onboarding-mask-reveal-up 760ms
+ .buzz-onboarding-transition-line[data-onboarding-effect="mask-reveal-up"]
+ > .buzz-onboarding-transition-content {
+ animation: buzz-onboarding-mask-reveal-up 760ms
cubic-bezier(0.22, 1, 0.36, 1) both;
- animation-delay: var(--sprout-onboarding-transition-delay, 0ms);
+ animation-delay: var(--buzz-onboarding-transition-delay, 0ms);
transform-origin: 50% 70%;
}
- .sprout-onboarding-name-placeholder-caret {
- animation: sprout-onboarding-caret-blink 1.1s steps(1, end) infinite;
+ .buzz-onboarding-name-placeholder-caret {
+ animation: buzz-onboarding-caret-blink 1.1s steps(1, end) infinite;
}
- @keyframes sprout-onboarding-caret-blink {
+ @keyframes buzz-onboarding-caret-blink {
0%,
55% {
opacity: 1;
@@ -772,7 +770,7 @@
}
}
- @keyframes sprout-onboarding-line-slide-forward {
+ @keyframes buzz-onboarding-line-slide-forward {
from {
opacity: 0;
transform: translateX(-48px);
@@ -784,7 +782,7 @@
}
}
- @keyframes sprout-onboarding-line-slide-backward {
+ @keyframes buzz-onboarding-line-slide-backward {
from {
opacity: 0;
transform: translateX(48px);
@@ -796,7 +794,7 @@
}
}
- @keyframes sprout-onboarding-mask-reveal-up {
+ @keyframes buzz-onboarding-mask-reveal-up {
from {
filter: blur(8px);
opacity: 0;
@@ -816,7 +814,7 @@
}
@media (max-width: 640px) {
- @keyframes sprout-onboarding-line-slide-forward {
+ @keyframes buzz-onboarding-line-slide-forward {
from {
opacity: 0;
transform: translateX(-24px);
@@ -828,7 +826,7 @@
}
}
- @keyframes sprout-onboarding-line-slide-backward {
+ @keyframes buzz-onboarding-line-slide-backward {
from {
opacity: 0;
transform: translateX(24px);
@@ -842,14 +840,14 @@
}
@media (prefers-reduced-motion: reduce) {
- .sprout-onboarding-transition-content {
+ .buzz-onboarding-transition-content {
animation: none;
filter: none;
opacity: 1;
transform: none;
}
- .sprout-onboarding-name-placeholder-caret {
+ .buzz-onboarding-name-placeholder-caret {
animation: none;
}
}
diff --git a/desktop/src/shared/theme/ThemeProvider.tsx b/desktop/src/shared/theme/ThemeProvider.tsx
index 39a3faf72..7c848bd8d 100644
--- a/desktop/src/shared/theme/ThemeProvider.tsx
+++ b/desktop/src/shared/theme/ThemeProvider.tsx
@@ -15,9 +15,9 @@ import {
loadThemeData,
} from "./theme-loader";
-export const THEME_STORAGE_KEY = "sprout-theme";
-const CACHE_KEY = "sprout-theme-cache";
-export const ACCENT_STORAGE_KEY = "sprout-accent-color";
+export const THEME_STORAGE_KEY = "buzz-theme";
+const CACHE_KEY = "buzz-theme-cache";
+export const ACCENT_STORAGE_KEY = "buzz-accent-color";
export const NEUTRAL_ACCENT = "neutral";
export const ACCENT_COLORS = [
diff --git a/desktop/src/shared/ui/AnimatedCount.tsx b/desktop/src/shared/ui/AnimatedCount.tsx
index 11ef9b90c..4b27fc60c 100644
--- a/desktop/src/shared/ui/AnimatedCount.tsx
+++ b/desktop/src/shared/ui/AnimatedCount.tsx
@@ -50,8 +50,8 @@ function AnimatedCountSlot({
return (
{renderSlotText(current)}
@@ -62,7 +62,7 @@ function AnimatedCountSlot({
if (!isDigit) {
return (
0 ? "up" : "down"}
key={`${version}-${previous}-${current}`}
>
@@ -73,11 +73,11 @@ function AnimatedCountSlot({
return (
0 ? "up" : "down"}
>
{direction > 0 ? (
@@ -161,9 +161,9 @@ export function AnimatedCount({ className, value }: AnimatedCountProps) {
const slots = getAnimatedCountSlots(transition.previous, transition.current);
return (
-
+
{transition.current}
-
+
{slots.map((slot) => (
))}
-
+
{transition.current}
diff --git a/desktop/src/shared/ui/TopChromeBackdrop.tsx b/desktop/src/shared/ui/TopChromeBackdrop.tsx
index d1827d664..c437f6073 100644
--- a/desktop/src/shared/ui/TopChromeBackdrop.tsx
+++ b/desktop/src/shared/ui/TopChromeBackdrop.tsx
@@ -10,7 +10,7 @@ import { topChromeBackdrop } from "@/shared/layout/chromeLayout";
* pointer-events-none) and sits at z-40 — below the global chrome controls
* (z-[45]) but above page content.
*
- * Height follows `--sprout-top-chrome-height` on the app `` inset.
+ * Height follows `--buzz-top-chrome-height` on the app `` inset.
* Pass `className` to override for panels whose own header occupies the top.
*/
export function TopChromeBackdrop({ className }: { className?: string }) {
diff --git a/desktop/src/shared/ui/markdown.test.mjs b/desktop/src/shared/ui/markdown.test.mjs
index 6c8fefd10..80171341a 100644
--- a/desktop/src/shared/ui/markdown.test.mjs
+++ b/desktop/src/shared/ui/markdown.test.mjs
@@ -433,7 +433,7 @@ test("rehypeImageGallery: mixed content paragraph is not image-only", () => {
// schemes (returns `""`) before our `a` component override can see them,
// which would break copy → paste → click for `buzz://message?…` links
// end-to-end. We pass a custom `urlTransform` that delegates to the
-// default for `buzz://message` and legacy `sprout://message` hrefs.
+// default for `buzz://message` and legacy `buzz://message` hrefs.
//
// This test renders real `` with the production transform
// and asserts the link href survives to the rendered DOM. Mirrors the
@@ -489,11 +489,11 @@ test("messageLinkUrlTransform: passes http(s) through unchanged", () => {
assert.match(html, /href="https:\/\/example\.com\/path"/);
});
-test("messageLinkUrlTransform: preserves legacy sprout://message href", () => {
+test("messageLinkUrlTransform: preserves legacy buzz://message href", () => {
const html = renderMarkdown(
- "Click [here](sprout://message?channel=abc&id=xyz)",
+ "Click [here](buzz://message?channel=abc&id=xyz)",
);
- assert.match(html, /href="sprout:\/\/message\?channel=abc&(?:amp;)?id=xyz"/);
+ assert.match(html, /href="buzz:\/\/message\?channel=abc&(?:amp;)?id=xyz"/);
});
test("messageLinkUrlTransform: leaves non-message buzz:// schemes to default", () => {
@@ -537,12 +537,12 @@ test("remarkMessageLinks: bare buzz://message URL is replaced", () => {
assert.equal(para.children[0].data.hName, "message-link");
});
-test("remarkMessageLinks: legacy bare sprout://message URL is replaced", () => {
- const tree = runPlugin(paragraph(text("sprout://message?channel=c&id=m")));
+test("remarkMessageLinks: legacy bare buzz://message URL is replaced", () => {
+ const tree = runPlugin(paragraph(text("buzz://message?channel=c&id=m")));
const para = tree.children[0];
assert.equal(para.children.length, 1);
assert.equal(para.children[0].type, "message-link");
- assert.equal(para.children[0].value, "sprout://message?channel=c&id=m");
+ assert.equal(para.children[0].value, "buzz://message?channel=c&id=m");
});
test("remarkMessageLinks: mid-sentence URL splits surrounding text", () => {
diff --git a/desktop/src/shared/ui/sidebar.tsx b/desktop/src/shared/ui/sidebar.tsx
index 358412405..00b465553 100644
--- a/desktop/src/shared/ui/sidebar.tsx
+++ b/desktop/src/shared/ui/sidebar.tsx
@@ -27,7 +27,7 @@ import {
const SIDEBAR_COOKIE_NAME = "sidebar_state";
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
-const SIDEBAR_WIDTH_STORAGE_KEY = "sprout-sidebar-width";
+const SIDEBAR_WIDTH_STORAGE_KEY = "buzz-sidebar-width";
const SIDEBAR_WIDTH_DEFAULT = 300;
const SIDEBAR_WIDTH_DEFAULT_HAPTIC_THRESHOLD = 2;
const SIDEBAR_WIDTH_DEFAULT_SNAP_DISTANCE = 8;
diff --git a/desktop/src/testing/e2eBridge.ts b/desktop/src/testing/e2eBridge.ts
index 7414a9715..90e88d577 100644
--- a/desktop/src/testing/e2eBridge.ts
+++ b/desktop/src/testing/e2eBridge.ts
@@ -464,9 +464,9 @@ function createMockRelayMembershipEvent(): RelayEvent {
/**
* Per-user custom emoji sets (kind:30030) the mock WS serves for
* `listCustomEmoji` REQs. The workspace palette is the client-side UNION of
- * every member's own set (d=`sprout:custom-emoji`). We serve TWO member-authored
+ * every member's own set (d=`buzz:custom-emoji`). We serve TWO member-authored
* sets from distinct pubkeys so the e2e exercises the union/collapse path, not
- * a single relay-owned set. `:sprout:` is the stable shortcode exercised by
+ * a single relay-owned set. `:buzz:` is the stable shortcode exercised by
* custom-emoji.spec.ts (claimed by BOTH members with different URLs, so the
* palette must collapse it to one deterministic winner); `:narf:` proves a
* second member's distinct emoji unions in.
@@ -478,7 +478,7 @@ function createMockCustomEmojiSetEvents(): RelayEvent[] {
"",
[
["d", CUSTOM_EMOJI_SET_D_TAG],
- ["emoji", "sprout", "https://example.com/e2e/sprout.png"],
+ ["emoji", "buzz", "https://example.com/e2e/buzz.png"],
// A relay-hosted emoji whose URL matches rewriteRelayUrl()'s pattern,
// used by the reaction guard to assert the proxy rewrite fires.
["emoji", REACTION_EMOJI_SHORTCODE, REACTION_EMOJI_URL],
@@ -493,9 +493,9 @@ function createMockCustomEmojiSetEvents(): RelayEvent[] {
[
["d", CUSTOM_EMOJI_SET_D_TAG],
["emoji", "narf", "https://example.com/e2e/narf.png"],
- // member B claims :sprout: with a DIFFERENT url — unionCustomEmoji must
+ // member B claims :buzz: with a DIFFERENT url — unionCustomEmoji must
// collapse it to one deterministic winner, never expose two URLs.
- ["emoji", "sprout", "https://example.com/e2e/sprout-b.png"],
+ ["emoji", "buzz", "https://example.com/e2e/buzz-b.png"],
],
"b".repeat(64),
),
@@ -544,22 +544,22 @@ function updateMockRelayMembershipFromAdminEvent(event: RelayEvent): boolean {
declare global {
interface Window {
- __SPROUT_E2E__?: E2eConfig;
- __SPROUT_E2E_COMMANDS__?: string[];
- __SPROUT_E2E_COMMAND_PAYLOADS__?: Array<{
+ __BUZZ_E2E__?: E2eConfig;
+ __BUZZ_E2E_COMMANDS__?: string[];
+ __BUZZ_E2E_COMMAND_PAYLOADS__?: Array<{
command: string;
payload: unknown;
}>;
- __SPROUT_E2E_COMMAND_LOG__?: Array<{
+ __BUZZ_E2E_COMMAND_LOG__?: Array<{
command: string;
payload: unknown;
}>;
- __SPROUT_E2E_WEBVIEW_ZOOM__?: number;
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_WEBVIEW_ZOOM__?: number;
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
kind?: number;
}) => boolean;
- __SPROUT_E2E_EMIT_MOCK_MESSAGE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
channelName: string;
content: string;
parentEventId?: string | null;
@@ -568,27 +568,27 @@ declare global {
mentionPubkeys?: string[];
extraTags?: string[][];
}) => RelayEvent;
- __SPROUT_E2E_EMIT_MOCK_TYPING__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_TYPING__?: (input: {
channelName: string;
pubkey?: string;
}) => RelayEvent;
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise;
- __SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?: (item: RawFeedItem) => RawFeedItem;
- __SPROUT_E2E_SIGNED_EVENTS__?: Array<{
+ __BUZZ_E2E_PUSH_MOCK_FEED_ITEM__?: (item: RawFeedItem) => RawFeedItem;
+ __BUZZ_E2E_SIGNED_EVENTS__?: Array<{
content: string;
kind: number;
tags: string[][];
}>;
- __SPROUT_E2E_SET_STALL_WEBSOCKET_SENDS__?: (stall: boolean) => void;
- __SPROUT_E2E_SET_MESH__?: (mesh: {
+ __BUZZ_E2E_SET_STALL_WEBSOCKET_SENDS__?: (stall: boolean) => void;
+ __BUZZ_E2E_SET_MESH__?: (mesh: {
admitted?: boolean;
models?: Array<{ id: string; name: string | null }>;
denyReason?: string;
}) => void;
- __SPROUT_E2E_EMIT_MOCK_READ_STATE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_READ_STATE__?: (input: {
clientId: string;
contexts: Record;
createdAt: number;
@@ -606,13 +606,13 @@ const KIND_DELETION = 5; // NIP-09 deletion
// Fake media-proxy port the mock answers for `get_media_proxy_port`, so
// `rewriteRelayUrl()` produces a real `http://localhost:/media/...` src
-// in e2e (instead of the `sprout-media://` fallback). The reaction guard
+// in e2e (instead of the `buzz-media://` fallback). The reaction guard
// asserts against this exact port.
const MOCK_MEDIA_PROXY_PORT = 54321;
// A relay-hosted custom emoji used by the reaction guard. Its URL matches
// `rewriteRelayUrl()`'s `/media/{64-hex}.{ext}` pattern on the relay origin, so
-// reacting with it exercises the proxy rewrite (unlike the `:sprout:` fixture,
+// reacting with it exercises the proxy rewrite (unlike the `:buzz:` fixture,
// whose external example.com URL passes through unchanged).
const REACTION_EMOJI_SHORTCODE = "react";
const REACTION_EMOJI_SHA = "c".repeat(64);
@@ -629,7 +629,7 @@ const REACTION_TARGET_CONTENT = "React to me with a custom emoji";
// id so it is a valid reaction target and never collides with the regular
// REACTION_TARGET_EVENT_ID.
const SYSTEM_REACTION_TARGET_EVENT_ID = "e".repeat(64);
-const E2E_IDENTITY_OVERRIDE_STORAGE_KEY = "sprout:e2e-identity-override.v1";
+const E2E_IDENTITY_OVERRIDE_STORAGE_KEY = "buzz:e2e-identity-override.v1";
const DEFAULT_MOCK_IDENTITY = {
pubkey: "deadbeef".repeat(8),
display_name: "npub1mock...",
@@ -931,7 +931,7 @@ function buildSeededManagedAgent(seed: MockManagedAgentSeed): MockManagedAgent {
name: seed.name,
persona_id: seed.personaId ?? null,
relay_url: DEFAULT_RELAY_WS_URL,
- acp_command: "sprout-acp",
+ acp_command: "buzz-acp",
agent_command: "goose",
agent_args: ["acp"],
mcp_command: "",
@@ -958,7 +958,7 @@ function buildSeededManagedAgent(seed: MockManagedAgentSeed): MockManagedAgent {
respond_to_allowlist: [],
private_key_nsec: `nsec1mock${seed.pubkey.slice(0, 20)}`,
log_lines: [
- `sprout-acp starting: relay=${DEFAULT_RELAY_WS_URL} agent_pubkey=${seed.pubkey} parallelism=1`,
+ `buzz-acp starting: relay=${DEFAULT_RELAY_WS_URL} agent_pubkey=${seed.pubkey} parallelism=1`,
"profile created; harness not started",
],
};
@@ -1460,7 +1460,7 @@ let mockManagedAgents: MockManagedAgent[] = [];
// Mesh-compute mock state — TEST-ONLY.
//
-// This entire module (e2eBridge.ts) is loaded only when `window.__SPROUT_E2E__`
+// This entire module (e2eBridge.ts) is loaded only when `window.__BUZZ_E2E__`
// is set by the Playwright harness; it never runs in a shipped build. These
// handlers stub the `mesh_*` Tauri commands with the SHAPES the UI expects
// (availability, node status, preset) so the desktop UI flow can be exercised
@@ -1822,7 +1822,7 @@ function getManagedAgentRelayMembership(pubkey: string) {
}
function getConfig(): E2eConfig | undefined {
- return window.__SPROUT_E2E__;
+ return window.__BUZZ_E2E__;
}
function readStoredIdentityOverride(): TestIdentity | undefined {
@@ -4195,16 +4195,16 @@ async function handleDiscoverAcpRuntimes(
underlying_cli_path: null,
},
{
- id: "sprout-agent",
- label: "Sprout Agent",
+ id: "buzz-agent",
+ label: "Buzz Agent",
avatar_url: "",
availability: "available",
- command: "sprout-agent",
- binary_path: "/usr/local/bin/sprout-agent",
+ command: "buzz-agent",
+ binary_path: "/usr/local/bin/buzz-agent",
default_args: [],
- mcp_command: "sprout-dev-mcp",
- install_hint: "Ships with the Sprout desktop app.",
- install_instructions_url: "https://github.com/block/sprout",
+ mcp_command: "buzz-dev-mcp",
+ install_hint: "Ships with the Buzz desktop app.",
+ install_instructions_url: "https://github.com/block/buzz",
can_auto_install: false,
underlying_cli_path: null,
},
@@ -4250,12 +4250,10 @@ async function handleDiscoverManagedAgentPrereqs(
return {
acp: {
command:
- configuredPrereqs?.acp?.command ??
- args.input?.acpCommand ??
- "sprout-acp",
+ configuredPrereqs?.acp?.command ?? args.input?.acpCommand ?? "buzz-acp",
resolved_path:
configuredPrereqs?.acp?.resolvedPath ??
- "/Users/wesb/dev/sprout/target/debug/sprout-acp",
+ "/Users/wesb/dev/buzz/target/debug/buzz-acp",
available: configuredPrereqs?.acp?.available ?? true,
},
mcp: {
@@ -4677,7 +4675,7 @@ async function handleCreateManagedAgent(args: {
name,
persona_id: args.input.personaId ?? null,
relay_url: args.input.relayUrl ?? DEFAULT_RELAY_WS_URL,
- acp_command: args.input.acpCommand ?? "sprout-acp",
+ acp_command: args.input.acpCommand ?? "buzz-acp",
agent_command: args.input.agentCommand ?? "goose",
agent_args:
args.input.agentArgs && args.input.agentArgs.length > 0
@@ -4707,7 +4705,7 @@ async function handleCreateManagedAgent(args: {
respond_to_allowlist: args.input.respondToAllowlist ?? [],
private_key_nsec: `nsec1mock${pubkey.slice(0, 20)}`,
log_lines: [
- `sprout-acp starting: relay=${args.input.relayUrl ?? DEFAULT_RELAY_WS_URL} agent_pubkey=${pubkey} parallelism=${args.input.parallelism ?? 1}`,
+ `buzz-acp starting: relay=${args.input.relayUrl ?? DEFAULT_RELAY_WS_URL} agent_pubkey=${pubkey} parallelism=${args.input.parallelism ?? 1}`,
args.input.systemPrompt?.trim()
? `system prompt override configured (${args.input.systemPrompt.trim().length} chars)`
: "system prompt override not set",
@@ -4753,10 +4751,10 @@ function isRelayMeshManagedAgent(agent: MockManagedAgent): boolean {
const env = agent.env_vars ?? {};
return (
agent.backend.type === "local" &&
- env.SPROUT_AGENT_PROVIDER === "openai" &&
+ env.BUZZ_AGENT_PROVIDER === "openai" &&
env.OPENAI_COMPAT_BASE_URL?.replace(/\/+$/, "") ===
"http://127.0.0.1:9337/v1" &&
- env.OPENAI_COMPAT_API_KEY === "sprout-mesh-local"
+ env.OPENAI_COMPAT_API_KEY === "buzz-mesh-local"
);
}
@@ -5690,12 +5688,12 @@ export function maybeInstallE2eTauriMocks() {
resetMockUserStatuses();
mockWebsocketSendMutexWedged = false;
mockWindows("main");
- window.__SPROUT_E2E_COMMANDS__ = [];
- window.__SPROUT_E2E_COMMAND_PAYLOADS__ = [];
- window.__SPROUT_E2E_COMMAND_LOG__ = [];
- window.__SPROUT_E2E_SIGNED_EVENTS__ = [];
- window.__SPROUT_E2E_WEBVIEW_ZOOM__ = 1;
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__ = ({
+ window.__BUZZ_E2E_COMMANDS__ = [];
+ window.__BUZZ_E2E_COMMAND_PAYLOADS__ = [];
+ window.__BUZZ_E2E_COMMAND_LOG__ = [];
+ window.__BUZZ_E2E_SIGNED_EVENTS__ = [];
+ window.__BUZZ_E2E_WEBVIEW_ZOOM__ = 1;
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__ = ({
channelName,
content,
parentEventId,
@@ -5721,7 +5719,7 @@ export function maybeInstallE2eTauriMocks() {
extraTags,
);
};
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__ = ({ channelName, pubkey }) => {
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__ = ({ channelName, pubkey }) => {
const channel = mockChannels.find(
(candidate) => candidate.name === channelName,
);
@@ -5731,10 +5729,7 @@ export function maybeInstallE2eTauriMocks() {
return emitMockTypingIndicator(channel.id, pubkey ?? CHARLIE_PUBKEY);
};
- window.__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__ = ({
- channelName,
- kind,
- }) => {
+ window.__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__ = ({ channelName, kind }) => {
const channel = mockChannels.find(
(candidate) => candidate.name === channelName,
);
@@ -5744,13 +5739,13 @@ export function maybeInstallE2eTauriMocks() {
return hasMockLiveSubscription(channel.id, kind);
};
- window.__SPROUT_E2E_PUSH_MOCK_FEED_ITEM__ = (item) => {
+ window.__BUZZ_E2E_PUSH_MOCK_FEED_ITEM__ = (item) => {
const category = item.category === "mention" ? "mentions" : item.category;
mockFeedOverrides[category].unshift(item);
- window.dispatchEvent(new CustomEvent("sprout:e2e-home-feed-updated"));
+ window.dispatchEvent(new CustomEvent("buzz:e2e-home-feed-updated"));
return item;
};
- window.__SPROUT_E2E_EMIT_MOCK_READ_STATE__ = ({
+ window.__BUZZ_E2E_EMIT_MOCK_READ_STATE__ = ({
clientId,
contexts,
createdAt,
@@ -5774,7 +5769,7 @@ export function maybeInstallE2eTauriMocks() {
emitMockLiveEvent(GLOBAL_MOCK_SUBSCRIPTION, event);
return event;
};
- window.__SPROUT_E2E_SET_STALL_WEBSOCKET_SENDS__ = (stall) => {
+ window.__BUZZ_E2E_SET_STALL_WEBSOCKET_SENDS__ = (stall) => {
const config = getConfig();
if (!config?.mock) return;
config.mock.stallWebsocketSends = stall;
@@ -5783,7 +5778,7 @@ export function maybeInstallE2eTauriMocks() {
// Tests flip `admitted` to exercise the denial path: mesh_ensure_client_node
// rejects when not admitted, which proves relay membership is the gate and
// that the create flow surfaces denial copy without spawning the agent.
- window.__SPROUT_E2E_SET_MESH__ = (mesh) => {
+ window.__BUZZ_E2E_SET_MESH__ = (mesh) => {
if (mesh.admitted !== undefined) mockMeshState.admitted = mesh.admitted;
if (mesh.models !== undefined) mockMeshState.models = mesh.models;
if (mesh.denyReason !== undefined)
@@ -5808,7 +5803,7 @@ export function maybeInstallE2eTauriMocks() {
const handleMockCommand = async (command: string, payload: unknown) => {
const activeConfig = getConfig();
const identity = getActiveIdentity(activeConfig);
- window.__SPROUT_E2E_COMMANDS__?.push(command);
+ window.__BUZZ_E2E_COMMANDS__?.push(command);
const loggedPayload = (() => {
try {
return JSON.parse(JSON.stringify(payload ?? null));
@@ -5816,11 +5811,11 @@ export function maybeInstallE2eTauriMocks() {
return null;
}
})();
- window.__SPROUT_E2E_COMMAND_PAYLOADS__?.push({
+ window.__BUZZ_E2E_COMMAND_PAYLOADS__?.push({
command,
payload: loggedPayload,
});
- window.__SPROUT_E2E_COMMAND_LOG__?.push({ command, payload });
+ window.__BUZZ_E2E_COMMAND_LOG__?.push({ command, payload });
switch (command) {
case "mesh_availability":
@@ -5897,7 +5892,7 @@ export function maybeInstallE2eTauriMocks() {
identity?.pubkey ?? DEFAULT_MOCK_IDENTITY.pubkey
).toLowerCase();
if (reporterPubkey && reporterPubkey !== selfPubkey) {
- window.__SPROUT_E2E_SIGNED_EVENTS__?.push({
+ window.__BUZZ_E2E_SIGNED_EVENTS__?.push({
kind: 24621,
tags: [["p", reporterPubkey]],
content: JSON.stringify({
@@ -5932,15 +5927,15 @@ export function maybeInstallE2eTauriMocks() {
providerId: "relay-mesh" as const,
label: "Run on relay mesh",
acpCommand: "",
- agentCommand: "sprout-agent",
+ agentCommand: "buzz-agent",
agentArgs: [],
mcpCommand: "",
model,
envVars: {
- SPROUT_AGENT_PROVIDER: "openai",
+ BUZZ_AGENT_PROVIDER: "openai",
OPENAI_COMPAT_BASE_URL: "http://127.0.0.1:9337/v1",
OPENAI_COMPAT_MODEL: model,
- OPENAI_COMPAT_API_KEY: "sprout-mesh-local",
+ OPENAI_COMPAT_API_KEY: "buzz-mesh-local",
OPENAI_COMPAT_API: "chat",
},
};
@@ -6259,7 +6254,7 @@ export function maybeInstallE2eTauriMocks() {
case "download_file":
// The save dialog can't run headlessly; report a successful save so the
// FileCard / image-menu click handlers resolve. Specs assert the
- // command was invoked via `__SPROUT_E2E_COMMANDS__`, not the dialog.
+ // command was invoked via `__BUZZ_E2E_COMMANDS__`, not the dialog.
return true;
case "get_event":
return handleGetEvent(
@@ -6267,7 +6262,7 @@ export function maybeInstallE2eTauriMocks() {
activeConfig,
);
case "sign_event":
- window.__SPROUT_E2E_SIGNED_EVENTS__?.push({
+ window.__BUZZ_E2E_SIGNED_EVENTS__?.push({
content: (payload as { content: string }).content,
kind: (payload as { kind: number }).kind,
tags: (payload as { tags: string[][] }).tags,
@@ -6383,9 +6378,7 @@ export function maybeInstallE2eTauriMocks() {
payload as Parameters[0],
);
case "plugin:webview|set_webview_zoom":
- window.__SPROUT_E2E_WEBVIEW_ZOOM__ = (
- payload as { value: number }
- ).value;
+ window.__BUZZ_E2E_WEBVIEW_ZOOM__ = (payload as { value: number }).value;
return;
case "plugin:event|listen":
// Tauri event system (pairing, huddle) — no-op in e2e, return unlisten fn ID
@@ -6414,7 +6407,7 @@ export function maybeInstallE2eTauriMocks() {
throw new Error(`Unsupported mocked Tauri command: ${command}`);
}
};
- window.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ = (command, payload) =>
+ window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ = (command, payload) =>
handleMockCommand(command, payload ?? null);
mockIPC(handleMockCommand);
diff --git a/desktop/tests/e2e/agents.spec.ts b/desktop/tests/e2e/agents.spec.ts
index 57ddfc921..527706d04 100644
--- a/desktop/tests/e2e/agents.spec.ts
+++ b/desktop/tests/e2e/agents.spec.ts
@@ -46,14 +46,14 @@ async function waitForInvokeBridge(page: import("@playwright/test").Page) {
await page.waitForFunction(
() => {
const tauriWindow = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: unknown;
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
__TAURI_INTERNALS__?: {
invoke?: unknown;
};
};
return (
- typeof tauriWindow.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
+ typeof tauriWindow.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
typeof tauriWindow.__TAURI_INTERNALS__?.invoke === "function"
);
},
@@ -72,7 +72,7 @@ async function invokeTauri(
return page.evaluate(
async ({ command: targetCommand, payload: targetPayload }) => {
const tauriWindow = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise;
@@ -85,7 +85,7 @@ async function invokeTauri(
};
const invoke =
- tauriWindow.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ ??
+ tauriWindow.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ ??
tauriWindow.__TAURI_INTERNALS__?.invoke;
if (!invoke) {
throw new Error("Mock invoke bridge is unavailable.");
@@ -107,7 +107,7 @@ async function invokeTauriExpectError(
return page.evaluate(
async ({ command: targetCommand, payload: targetPayload }) => {
const tauriWindow = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise;
@@ -120,7 +120,7 @@ async function invokeTauriExpectError(
};
const invoke =
- tauriWindow.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ ??
+ tauriWindow.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ ??
tauriWindow.__TAURI_INTERNALS__?.invoke;
if (!invoke) {
throw new Error("Mock invoke bridge is unavailable.");
diff --git a/desktop/tests/e2e/badge.spec.ts b/desktop/tests/e2e/badge.spec.ts
index 83c45f6f9..be5954250 100644
--- a/desktop/tests/e2e/badge.spec.ts
+++ b/desktop/tests/e2e/badge.spec.ts
@@ -16,12 +16,12 @@ async function waitForMockLiveSubscription(
return (
(
window as Window & {
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
kind?: number;
}) => boolean;
}
- ).__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
+ ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: currentChannelName,
kind: k,
}) ?? false
@@ -36,12 +36,12 @@ async function waitForMockLiveSubscription(
async function getBadgeState(page: import("@playwright/test").Page) {
return page.evaluate(() => {
const w = window as Window & {
- __SPROUT_E2E_APP_BADGE_STATE__?: string;
- __SPROUT_E2E_APP_BADGE_COUNT__?: number;
+ __BUZZ_E2E_APP_BADGE_STATE__?: string;
+ __BUZZ_E2E_APP_BADGE_COUNT__?: number;
};
return {
- state: w.__SPROUT_E2E_APP_BADGE_STATE__ ?? "none",
- count: w.__SPROUT_E2E_APP_BADGE_COUNT__ ?? 0,
+ state: w.__BUZZ_E2E_APP_BADGE_STATE__ ?? "none",
+ count: w.__BUZZ_E2E_APP_BADGE_COUNT__ ?? 0,
};
});
}
@@ -72,7 +72,7 @@ test("dot badge for regular message in inactive channel", async ({ page }) => {
await page.evaluate(
({ pubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "random",
content: "Regular message, no mention",
kind: 40002,
@@ -94,7 +94,7 @@ test("numeric badge for @mention in inactive channel", async ({ page }) => {
await page.evaluate(
({ pubkey, mentionPubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "random",
content: "Hey @tyler check this out",
kind: 40002,
@@ -119,7 +119,7 @@ test("numeric badge for DM message", async ({ page }) => {
await waitForMockLiveSubscription(page, "alice-tyler");
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "alice-tyler",
content: "Hey, got a minute?",
pubkey,
@@ -140,7 +140,7 @@ test("numeric badge for broadcast reply in inactive channel", async ({
await page.evaluate(
({ pubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "random",
content: "Broadcast reply to the channel",
kind: 40002,
@@ -173,7 +173,7 @@ test("mark-as-read via context menu clears channel unread indicator", async ({
await page.evaluate(
({ pubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "random",
content: "Message to be marked read",
kind: 40002,
@@ -224,12 +224,12 @@ test("remote read-state rollback is ignored while local mark-unread still shows
return (
(
window as Window & {
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
kind?: number;
}) => boolean;
}
- ).__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
+ ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: "general",
kind: 30078,
}) ?? false
@@ -249,14 +249,14 @@ test("remote read-state rollback is ignored while local mark-unread still shows
({ clientId, slotId, channelId, ts }) => {
(
window as Window & {
- __SPROUT_E2E_EMIT_MOCK_READ_STATE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_READ_STATE__?: (input: {
clientId: string;
contexts: Record;
createdAt: number;
slotId: string;
}) => unknown;
}
- ).__SPROUT_E2E_EMIT_MOCK_READ_STATE__?.({
+ ).__BUZZ_E2E_EMIT_MOCK_READ_STATE__?.({
clientId,
slotId,
contexts: { [channelId]: ts },
@@ -277,14 +277,14 @@ test("remote read-state rollback is ignored while local mark-unread still shows
({ clientId, slotId, channelId, ts, createdAt }) => {
(
window as Window & {
- __SPROUT_E2E_EMIT_MOCK_READ_STATE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_READ_STATE__?: (input: {
clientId: string;
contexts: Record;
createdAt: number;
slotId: string;
}) => unknown;
}
- ).__SPROUT_E2E_EMIT_MOCK_READ_STATE__?.({
+ ).__BUZZ_E2E_EMIT_MOCK_READ_STATE__?.({
clientId,
slotId,
contexts: { [channelId]: ts },
@@ -314,14 +314,14 @@ test("remote read-state rollback is ignored while local mark-unread still shows
({ clientId, slotId, channelId, ts, createdAt }) => {
(
window as Window & {
- __SPROUT_E2E_EMIT_MOCK_READ_STATE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_READ_STATE__?: (input: {
clientId: string;
contexts: Record;
createdAt: number;
slotId: string;
}) => unknown;
}
- ).__SPROUT_E2E_EMIT_MOCK_READ_STATE__?.({
+ ).__BUZZ_E2E_EMIT_MOCK_READ_STATE__?.({
clientId,
slotId,
contexts: { [channelId]: ts },
diff --git a/desktop/tests/e2e/channel-mute-screenshots.spec.ts b/desktop/tests/e2e/channel-mute-screenshots.spec.ts
index 692e96271..43c5d8967 100644
--- a/desktop/tests/e2e/channel-mute-screenshots.spec.ts
+++ b/desktop/tests/e2e/channel-mute-screenshots.spec.ts
@@ -4,7 +4,7 @@ import { TEST_IDENTITIES, installMockBridge } from "../helpers/bridge";
const MOCK_PUBKEY = "deadbeef".repeat(8);
const ENGINEERING_CHANNEL_ID = "1c7e1c02-87bb-5e88-b2da-5a7a9432d0c9";
-const MUTE_STORAGE_KEY = `sprout-channel-mutes.v1:${MOCK_PUBKEY}`;
+const MUTE_STORAGE_KEY = `buzz-channel-mutes.v1:${MOCK_PUBKEY}`;
const SHOTS = "test-results/channel-mute";
function seedMuteState(
@@ -37,11 +37,11 @@ async function waitForMockLiveSubscription(
({ ch }) =>
(
window as Window & {
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
}) => boolean;
}
- ).__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({ channelName: ch }) ??
+ ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({ channelName: ch }) ??
false,
{ ch: channelName },
);
@@ -114,14 +114,14 @@ test.describe("channel muting screenshots", () => {
({ pubkey, mockPubkey }) => {
(
window as Window & {
- __SPROUT_E2E_EMIT_MOCK_MESSAGE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
channelName: string;
content: string;
pubkey: string;
mentionPubkeys: string[];
}) => unknown;
}
- ).__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ ).__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "engineering",
content: "Hey check this out",
pubkey,
diff --git a/desktop/tests/e2e/channel-star-screenshots.spec.ts b/desktop/tests/e2e/channel-star-screenshots.spec.ts
index e98da67c4..321991e3b 100644
--- a/desktop/tests/e2e/channel-star-screenshots.spec.ts
+++ b/desktop/tests/e2e/channel-star-screenshots.spec.ts
@@ -4,7 +4,7 @@ import { installMockBridge } from "../helpers/bridge";
const MOCK_PUBKEY = "deadbeef".repeat(8);
const ENGINEERING_CHANNEL_ID = "1c7e1c02-87bb-5e88-b2da-5a7a9432d0c9";
-const STAR_STORAGE_KEY = `sprout-channel-stars.v1:${MOCK_PUBKEY}`;
+const STAR_STORAGE_KEY = `buzz-channel-stars.v1:${MOCK_PUBKEY}`;
const SHOTS = "test-results/channel-star";
function seedStarState(
diff --git a/desktop/tests/e2e/channels.spec.ts b/desktop/tests/e2e/channels.spec.ts
index ac9418559..33da69eea 100644
--- a/desktop/tests/e2e/channels.spec.ts
+++ b/desktop/tests/e2e/channels.spec.ts
@@ -64,12 +64,12 @@ async function waitForMockLiveSubscription(
return (
(
window as Window & {
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
kind?: number;
}) => boolean;
}
- ).__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
+ ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: currentChannelName,
kind,
}) ?? false
@@ -139,8 +139,8 @@ async function getManagedAgentPubkey(
async function readCommandLog(page: import("@playwright/test").Page) {
return page.evaluate(() => {
return (
- (window as Window & { __SPROUT_E2E_COMMANDS__?: string[] })
- .__SPROUT_E2E_COMMANDS__ ?? []
+ (window as Window & { __BUZZ_E2E_COMMANDS__?: string[] })
+ .__BUZZ_E2E_COMMANDS__ ?? []
);
});
}
@@ -150,12 +150,12 @@ async function readCommandPayloadLog(page: import("@playwright/test").Page) {
return (
(
window as Window & {
- __SPROUT_E2E_COMMAND_LOG__?: Array<{
+ __BUZZ_E2E_COMMAND_LOG__?: Array<{
command: string;
payload: unknown;
}>;
}
- ).__SPROUT_E2E_COMMAND_LOG__ ?? []
+ ).__BUZZ_E2E_COMMAND_LOG__ ?? []
);
});
}
@@ -169,9 +169,9 @@ async function invokeMockCommand(
return Boolean(
(
window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: unknown;
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
}
- ).__SPROUT_E2E_INVOKE_MOCK_COMMAND__,
+ ).__BUZZ_E2E_INVOKE_MOCK_COMMAND__,
);
});
@@ -185,12 +185,12 @@ async function invokeMockCommand(
}) => {
const invoke = (
window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise;
}
- ).__SPROUT_E2E_INVOKE_MOCK_COMMAND__;
+ ).__BUZZ_E2E_INVOKE_MOCK_COMMAND__;
if (!invoke) {
throw new Error("Mock bridge is not installed.");
@@ -373,9 +373,9 @@ test("archived channels stay out of all sidebar sections", async ({ page }) => {
return Boolean(
(
window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: unknown;
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
}
- ).__SPROUT_E2E_INVOKE_MOCK_COMMAND__,
+ ).__BUZZ_E2E_INVOKE_MOCK_COMMAND__,
);
});
await page.evaluate(
@@ -390,12 +390,12 @@ test("archived channels stay out of all sidebar sections", async ({ page }) => {
}) => {
const invoke = (
window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise<{ id: string }>;
}
- ).__SPROUT_E2E_INVOKE_MOCK_COMMAND__;
+ ).__BUZZ_E2E_INVOKE_MOCK_COMMAND__;
if (!invoke) {
throw new Error("Mock bridge is not installed.");
@@ -510,7 +510,7 @@ test("shows and clears activity indicators for active channel agents", async ({
await waitForMockLiveSubscription(page, "agents", KIND_TYPING_INDICATOR);
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__?.({
channelName: "agents",
pubkey,
});
@@ -533,7 +533,7 @@ test("shows and clears activity indicators for active channel agents", async ({
await expect(page.getByTestId("message-typing-indicator")).toHaveCount(0);
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "agents",
content: "Done.",
pubkey,
@@ -547,7 +547,7 @@ test("shows and clears activity indicators for active channel agents", async ({
await page.waitForTimeout(1_200);
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__?.({
channelName: "agents",
pubkey,
});
@@ -569,7 +569,7 @@ test("typing indicator shows avatars and maintains stable name order", async ({
// Alice starts typing first
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__?.({
channelName: "random",
pubkey,
});
@@ -588,7 +588,7 @@ test("typing indicator shows avatars and maintains stable name order", async ({
// Bob starts typing second
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__?.({
channelName: "random",
pubkey,
});
@@ -601,7 +601,7 @@ test("typing indicator shows avatars and maintains stable name order", async ({
// Alice re-broadcasts — order should stay "alice and bob", not flip
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__?.({
channelName: "random",
pubkey,
});
@@ -613,7 +613,7 @@ test("typing indicator shows avatars and maintains stable name order", async ({
// Bob re-broadcasts — order should still stay "alice and bob"
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_TYPING__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_TYPING__?.({
channelName: "random",
pubkey,
});
@@ -636,7 +636,7 @@ test("sidebar shows unread indicator for newly active channels", async ({
// alice — simulating a real "another user posted while I was elsewhere".
await page.evaluate(
({ pubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "random",
content: "Unread update for #random",
kind: 40002,
@@ -665,7 +665,7 @@ test("sidebar shows unread indicator for new forum posts", async ({ page }) => {
// Emit as alice — the unread tracker ignores self-authored messages.
await page.evaluate(
({ pubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "watercooler",
content: "Unread update for the forum",
kind: 45001,
@@ -689,7 +689,7 @@ test("sidebar clears unread indicator after opening a DM", async ({ page }) => {
await waitForMockLiveSubscription(page, "alice-tyler");
await page.evaluate((pubkey) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "alice-tyler",
content: "Unread update for the DM",
pubkey,
diff --git a/desktop/tests/e2e/custom-emoji-screenshots.spec.ts b/desktop/tests/e2e/custom-emoji-screenshots.spec.ts
index 981f6bdf4..4d1f9d4e6 100644
--- a/desktop/tests/e2e/custom-emoji-screenshots.spec.ts
+++ b/desktop/tests/e2e/custom-emoji-screenshots.spec.ts
@@ -6,7 +6,7 @@ import { installMockBridge } from "../helpers/bridge";
// hard assertion suite — it documents the two user-visible surfaces Tyler asked
// to verify: the composer rendering and the settings card's own-vs-workspace
// split. Artifacts land in test-results/.
-const SHORTCODE = "sprout";
+const SHORTCODE = "buzz";
const SHOTS = "test-results/custom-emoji";
test.beforeEach(async ({ page }) => {
@@ -48,13 +48,13 @@ test("settings card splits My emoji from read-only Workspace emoji", async ({
await expect(page.getByTestId("settings-view")).toBeVisible();
await page.getByTestId("settings-nav-custom-emoji").click();
- // The mock identity owns :sprout: (removable); :narf: belongs to another
+ // The mock identity owns :buzz: (removable); :narf: belongs to another
// member (read-only, no trash button).
const card = page.getByTestId("settings-custom-emoji");
- await expect(card.getByTestId("custom-emoji-mine")).toContainText(":sprout:");
+ await expect(card.getByTestId("custom-emoji-mine")).toContainText(":buzz:");
const mine = card.getByTestId("custom-emoji-mine");
await expect(
- mine.getByRole("button", { name: "Remove :sprout:" }),
+ mine.getByRole("button", { name: "Remove :buzz:" }),
).toBeVisible();
const workspace = card.getByTestId("custom-emoji-workspace");
diff --git a/desktop/tests/e2e/custom-emoji.spec.ts b/desktop/tests/e2e/custom-emoji.spec.ts
index 0b80b7919..490280e67 100644
--- a/desktop/tests/e2e/custom-emoji.spec.ts
+++ b/desktop/tests/e2e/custom-emoji.spec.ts
@@ -9,13 +9,13 @@ import { installMockBridge } from "../helpers/bridge";
// still serializing to `:shortcode:` on send. The message timeline renders the
// same shortcode as `img[data-custom-emoji]` via remarkCustomEmoji.
//
-// The `:sprout:` shortcode lives in a member-authored kind:30030 set
-// (d=`sprout:custom-emoji`) served by the mock bridge from two distinct
+// The `:buzz:` shortcode lives in a member-authored kind:30030 set
+// (d=`buzz:custom-emoji`) served by the mock bridge from two distinct
// pubkeys. `listCustomEmoji` reads every member's set over the relay WS and
// unions them (deduped by shortcode+url) into the workspace palette — which is
// live even in mock-bridge mode (the mock only intercepts Tauri commands), so
// this spec uses the simpler mock-bridge setup like messaging.spec.ts.
-const SHORTCODE = "sprout";
+const SHORTCODE = "buzz";
async function openGeneral(page: import("@playwright/test").Page) {
await page.goto("/");
@@ -114,7 +114,7 @@ test("custom emoji round-trips through select-all + send to the timeline", async
// `:react:` is a relay-hosted fixture emoji (URL on the relay origin matching
// rewriteRelayUrl()'s /media/{64-hex}.{ext} pattern), and the mock bridge
// answers get_media_proxy_port with port 54321 so the rewrite resolves to a
-// real localhost URL rather than the sprout-media:// fallback.
+// real localhost URL rather than the buzz-media:// fallback.
const REACTION_SHORTCODE = "react";
const MOCK_MEDIA_PROXY_PORT = 54321;
@@ -258,7 +258,7 @@ test("editing a message with a custom emoji shows the image, not the shortcode (
// Open it for editing. The composer loads via setContent — the path the
// markdown parse rule fixes. The known shortcode must render as the inline
- // node, NOT as literal `:sprout:` text.
+ // node, NOT as literal `:buzz:` text.
await openMessageEditor(page, "edit-bug1");
await expect(input.locator("img[data-custom-emoji]")).toHaveCount(1);
await expect(input.locator("img[data-custom-emoji]")).toHaveAttribute(
@@ -296,7 +296,7 @@ test("adding a custom emoji while editing keeps the image after save (Bug 2)", a
// After the edit round-trips through edit_message → kind:40003 (with emoji
// tags) → applyEditTagOverlay, the timeline must render the emoji as an
- // , not a bare `:sprout:`. The pre-fix edit path shipped no emoji tags,
+ // , not a bare `:buzz:`. The pre-fix edit path shipped no emoji tags,
// so this row would show literal text and fail here.
await expect(
row.locator(`img[data-custom-emoji][alt=":${SHORTCODE}:"]`),
diff --git a/desktop/tests/e2e/file-attachment.spec.ts b/desktop/tests/e2e/file-attachment.spec.ts
index c8e2968c9..6b1ba8d1d 100644
--- a/desktop/tests/e2e/file-attachment.spec.ts
+++ b/desktop/tests/e2e/file-attachment.spec.ts
@@ -52,8 +52,8 @@ test("upload a file and see a FileCard in the timeline", async ({ page }) => {
.poll(() =>
page.evaluate(
() =>
- (window as Window & { __SPROUT_E2E_COMMANDS__?: string[] })
- .__SPROUT_E2E_COMMANDS__ ?? [],
+ (window as Window & { __BUZZ_E2E_COMMANDS__?: string[] })
+ .__BUZZ_E2E_COMMANDS__ ?? [],
),
)
.toContain("download_file");
@@ -94,8 +94,8 @@ test("forum posts emit a FileCard for generic attachments, not a broken image",
.poll(() =>
page.evaluate(
() =>
- (window as Window & { __SPROUT_E2E_COMMANDS__?: string[] })
- .__SPROUT_E2E_COMMANDS__ ?? [],
+ (window as Window & { __BUZZ_E2E_COMMANDS__?: string[] })
+ .__BUZZ_E2E_COMMANDS__ ?? [],
),
)
.toContain("download_file");
diff --git a/desktop/tests/e2e/integration.spec.ts b/desktop/tests/e2e/integration.spec.ts
index ca616bbb1..ef6a8f3fa 100644
--- a/desktop/tests/e2e/integration.spec.ts
+++ b/desktop/tests/e2e/integration.spec.ts
@@ -138,13 +138,13 @@ async function joinChannel(
async function getLoggedNotifications(page: import("@playwright/test").Page) {
return page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_NOTIFICATIONS__?: Array<{
+ __BUZZ_E2E_NOTIFICATIONS__?: Array<{
body: string | null;
title: string;
}>;
};
- return win.__SPROUT_E2E_NOTIFICATIONS__ ?? [];
+ return win.__BUZZ_E2E_NOTIFICATIONS__ ?? [];
});
}
diff --git a/desktop/tests/e2e/mentions.spec.ts b/desktop/tests/e2e/mentions.spec.ts
index 55a2a4e1f..a26cf1045 100644
--- a/desktop/tests/e2e/mentions.spec.ts
+++ b/desktop/tests/e2e/mentions.spec.ts
@@ -30,8 +30,8 @@ function autocomplete(page: import("@playwright/test").Page) {
async function readCommandLog(page: import("@playwright/test").Page) {
return page.evaluate(() => {
return (
- (window as Window & { __SPROUT_E2E_COMMANDS__?: string[] })
- .__SPROUT_E2E_COMMANDS__ ?? []
+ (window as Window & { __BUZZ_E2E_COMMANDS__?: string[] })
+ .__BUZZ_E2E_COMMANDS__ ?? []
);
});
}
@@ -41,12 +41,12 @@ async function readCommandPayloads(page: import("@playwright/test").Page) {
return (
(
window as Window & {
- __SPROUT_E2E_COMMAND_PAYLOADS__?: Array<{
+ __BUZZ_E2E_COMMAND_PAYLOADS__?: Array<{
command: string;
payload: unknown;
}>;
}
- ).__SPROUT_E2E_COMMAND_PAYLOADS__ ?? []
+ ).__BUZZ_E2E_COMMAND_PAYLOADS__ ?? []
);
});
}
@@ -67,12 +67,12 @@ async function waitForMockLiveSubscription(
return (
(
window as Window & {
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
kind?: number;
}) => boolean;
}
- ).__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
+ ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: currentChannelName,
kind: expectedKind,
}) ?? false
@@ -650,7 +650,7 @@ test("system add and remove rows use agent mention styling for managed agents",
await page.evaluate(
({ actorPubkey, kind, targetPubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "general",
content: JSON.stringify({
type: "member_joined",
@@ -659,7 +659,7 @@ test("system add and remove rows use agent mention styling for managed agents",
}),
kind,
});
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "general",
content: JSON.stringify({
type: "member_removed",
diff --git a/desktop/tests/e2e/mesh-compute.spec.ts b/desktop/tests/e2e/mesh-compute.spec.ts
index cd9b2f5c4..e80c4b84a 100644
--- a/desktop/tests/e2e/mesh-compute.spec.ts
+++ b/desktop/tests/e2e/mesh-compute.spec.ts
@@ -9,16 +9,16 @@ import { openSettings } from "../helpers/settings";
// invariant and the membership-denial copy.
type E2eWindow = Window & {
- __SPROUT_E2E__?: { mock?: { meshReporterPubkey?: string } };
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: unknown;
+ __BUZZ_E2E__?: { mock?: { meshReporterPubkey?: string } };
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
__TAURI_INTERNALS__?: { invoke?: unknown };
- __SPROUT_E2E_COMMANDS__?: string[];
- __SPROUT_E2E_SIGNED_EVENTS__?: Array<{
+ __BUZZ_E2E_COMMANDS__?: string[];
+ __BUZZ_E2E_SIGNED_EVENTS__?: Array<{
content: string;
kind: number;
tags: string[][];
}>;
- __SPROUT_E2E_SET_MESH__?: (mesh: {
+ __BUZZ_E2E_SET_MESH__?: (mesh: {
admitted?: boolean;
models?: Array<{ id: string; name: string | null }>;
denyReason?: string;
@@ -29,7 +29,7 @@ async function waitForInvokeBridge(page: import("@playwright/test").Page) {
await page.waitForFunction(() => {
const w = window as E2eWindow;
return (
- typeof w.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
+ typeof w.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
typeof w.__TAURI_INTERNALS__?.invoke === "function"
);
}, null);
@@ -45,15 +45,13 @@ async function gotoApp(page: import("@playwright/test").Page) {
/** Ordered command names the bridge recorded so far. */
async function commands(page: import("@playwright/test").Page) {
- return page.evaluate(
- () => (window as E2eWindow).__SPROUT_E2E_COMMANDS__ ?? [],
- );
+ return page.evaluate(() => (window as E2eWindow).__BUZZ_E2E_COMMANDS__ ?? []);
}
/** Signed event templates the bridge recorded so far. */
async function signedEvents(page: import("@playwright/test").Page) {
return page.evaluate(
- () => (window as E2eWindow).__SPROUT_E2E_SIGNED_EVENTS__ ?? [],
+ () => (window as E2eWindow).__BUZZ_E2E_SIGNED_EVENTS__ ?? [],
);
}
@@ -62,7 +60,7 @@ async function setMesh(
mesh: { admitted?: boolean; denyReason?: string },
) {
await page.evaluate((m) => {
- (window as E2eWindow).__SPROUT_E2E_SET_MESH__?.(m);
+ (window as E2eWindow).__BUZZ_E2E_SET_MESH__?.(m);
}, mesh);
}
@@ -215,10 +213,10 @@ test("Run-on-relay-mesh canonicalizes the mesh connect #p target", async ({
}) => {
await page.addInitScript(() => {
const w = window as E2eWindow;
- w.__SPROUT_E2E__ = {
- ...(w.__SPROUT_E2E__ ?? {}),
+ w.__BUZZ_E2E__ = {
+ ...(w.__BUZZ_E2E__ ?? {}),
mock: {
- ...(w.__SPROUT_E2E__?.mock ?? {}),
+ ...(w.__BUZZ_E2E__?.mock ?? {}),
meshReporterPubkey:
" CAFEBABECAFEBABECAFEBABECAFEBABECAFEBABECAFEBABECAFEBABECAFEBABE ",
},
@@ -301,12 +299,12 @@ test("saved relay-mesh agents restart via the backend serve-target preflight", a
const agents = await page.evaluate(async () => {
const w = window as E2eWindow & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise>;
};
- const invoke = w.__SPROUT_E2E_INVOKE_MOCK_COMMAND__;
+ const invoke = w.__BUZZ_E2E_INVOKE_MOCK_COMMAND__;
if (!invoke) throw new Error("Mock invoke bridge is unavailable.");
return invoke("list_managed_agents");
});
@@ -358,7 +356,7 @@ test("saved relay-mesh agents restart via the backend serve-target preflight", a
await expect(
page.evaluate(async (agentPubkey) => {
- const invoke = (window as E2eWindow).__SPROUT_E2E_INVOKE_MOCK_COMMAND__ as
+ const invoke = (window as E2eWindow).__BUZZ_E2E_INVOKE_MOCK_COMMAND__ as
| ((
command: string,
payload?: Record,
diff --git a/desktop/tests/e2e/messaging.spec.ts b/desktop/tests/e2e/messaging.spec.ts
index 8ecd80336..610f174e0 100644
--- a/desktop/tests/e2e/messaging.spec.ts
+++ b/desktop/tests/e2e/messaging.spec.ts
@@ -597,7 +597,7 @@ test("opens a single-level thread panel with inline expansion", async ({
await page.evaluate(
({ content, parentEventId, pubkey }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "general",
content,
parentEventId,
@@ -663,7 +663,7 @@ test("thread panel width uses session storage and reset handle", async ({
await page.addInitScript((width) => {
window.sessionStorage.setItem(
- "sprout.desktop.thread-panel-width",
+ "buzz.desktop.thread-panel-width",
String(width),
);
}, customWidthPx);
diff --git a/desktop/tests/e2e/onboarding.spec.ts b/desktop/tests/e2e/onboarding.spec.ts
index b7a09f4c4..27e699204 100644
--- a/desktop/tests/e2e/onboarding.spec.ts
+++ b/desktop/tests/e2e/onboarding.spec.ts
@@ -4,8 +4,8 @@ import { nsecEncode } from "nostr-tools/nip19";
import { installMockBridge, TEST_IDENTITIES } from "../helpers/bridge";
-const E2E_IDENTITY_OVERRIDE_STORAGE_KEY = "sprout:e2e-identity-override.v1";
-const HOME_SEEN_STORAGE_KEY_PREFIX = "sprout-home-feed-seen.v1:";
+const E2E_IDENTITY_OVERRIDE_STORAGE_KEY = "buzz:e2e-identity-override.v1";
+const HOME_SEEN_STORAGE_KEY_PREFIX = "buzz-home-feed-seen.v1:";
const DEFAULT_MOCK_PUBKEY = "deadbeef".repeat(8);
const BLANK_TYLER_IDENTITY = {
...TEST_IDENTITIES.tyler,
@@ -54,7 +54,7 @@ async function seedOnboardingCompletion(page: Page, pubkey: string) {
window.localStorage.setItem(storageKey, "true");
},
{
- storageKey: `sprout-onboarding-complete.v1:${pubkey}`,
+ storageKey: `buzz-onboarding-complete.v1:${pubkey}`,
},
);
}
@@ -122,12 +122,12 @@ async function getMockProfile(page: Page) {
return page.evaluate(async () => {
const invoke = (
window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise;
}
- ).__SPROUT_E2E_INVOKE_MOCK_COMMAND__;
+ ).__BUZZ_E2E_INVOKE_MOCK_COMMAND__;
if (!invoke) {
throw new Error("Mock invoke bridge is unavailable.");
}
@@ -156,9 +156,7 @@ async function continueToSetupPage(page: Page) {
await expect(page.getByTestId("onboarding-page-theme")).toBeVisible();
await page.getByTestId("onboarding-theme-option-github-light").click();
await expect
- .poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-theme")),
- )
+ .poll(() => page.evaluate(() => window.localStorage.getItem("buzz-theme")))
.toBe("github-light");
await page.getByTestId("onboarding-next").click();
await expect(page.getByTestId("onboarding-page-2")).toBeVisible();
@@ -190,7 +188,7 @@ test("first-run default workspace handoff gives immediate stepper feedback", asy
);
await page.goto("/");
- await expect(page.getByText("Welcome to Sprout")).toBeVisible();
+ await expect(page.getByText("Welcome to Buzz")).toBeVisible();
await page
.getByRole("button", { name: "Continue with Block Inc. workspace" })
.click();
@@ -246,7 +244,7 @@ test("welcome can continue using an existing Nostr key", async ({ page }) => {
await expect
.poll(() =>
page.evaluate(() => {
- const rawWorkspaces = window.localStorage.getItem("sprout-workspaces");
+ const rawWorkspaces = window.localStorage.getItem("buzz-workspaces");
const workspaces = rawWorkspaces
? (JSON.parse(rawWorkspaces) as Array<{ pubkey?: string }>)
: [];
@@ -363,9 +361,7 @@ test("avatar step accepts an avatar URL before theme selection", async ({
await expect(page.getByTestId("onboarding-page-theme")).toBeVisible();
await page.getByTestId("onboarding-theme-option-github-light").click();
await expect
- .poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-theme")),
- )
+ .poll(() => page.evaluate(() => window.localStorage.getItem("buzz-theme")))
.toBe("github-light");
await page.getByTestId("onboarding-next").click();
await expect(page.getByTestId("onboarding-page-2")).toBeVisible();
@@ -387,10 +383,10 @@ test("failed avatar saves can continue without saving the avatar", async ({
.fill("https://example.com/morty.png");
await page.evaluate(() => {
const testWindow = window as Window & {
- __SPROUT_E2E__?: { mock?: { profileUpdateError?: string } };
+ __BUZZ_E2E__?: { mock?: { profileUpdateError?: string } };
};
- if (testWindow.__SPROUT_E2E__?.mock) {
- testWindow.__SPROUT_E2E__.mock.profileUpdateError =
+ if (testWindow.__BUZZ_E2E__?.mock) {
+ testWindow.__BUZZ_E2E__.mock.profileUpdateError =
"Temporary avatar sync failure.";
}
});
@@ -418,13 +414,11 @@ test("theme step offers skip instead of going back", async ({ page }) => {
.getByTestId("onboarding-avatar-url")
.fill("https://example.com/morty.png");
await expect
- .poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-theme")),
- )
+ .poll(() => page.evaluate(() => window.localStorage.getItem("buzz-theme")))
.toBe("github-light-default");
await expect
.poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-accent-color")),
+ page.evaluate(() => window.localStorage.getItem("buzz-accent-color")),
)
.toBe("neutral");
await expect
@@ -436,13 +430,11 @@ test("theme step offers skip instead of going back", async ({ page }) => {
await expect(page.getByTestId("onboarding-page-theme")).toBeVisible();
await expect
- .poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-theme")),
- )
+ .poll(() => page.evaluate(() => window.localStorage.getItem("buzz-theme")))
.toBe("github-light-default");
await expect
.poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-accent-color")),
+ page.evaluate(() => window.localStorage.getItem("buzz-accent-color")),
)
.toBe("neutral");
await expect(
@@ -454,13 +446,13 @@ test("theme step offers skip instead of going back", async ({ page }) => {
await page.getByTestId("onboarding-accent-color-blue").click();
await expect
.poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-accent-color")),
+ page.evaluate(() => window.localStorage.getItem("buzz-accent-color")),
)
.toBe("#3b82f6");
await page.getByTestId("onboarding-accent-color-neutral").click();
await expect
.poll(() =>
- page.evaluate(() => window.localStorage.getItem("sprout-accent-color")),
+ page.evaluate(() => window.localStorage.getItem("buzz-accent-color")),
)
.toBe("neutral");
await expect(page.getByTestId("onboarding-back")).toHaveCount(0);
@@ -728,8 +720,8 @@ test("membership denial can import a different invited key", async ({
.poll(() =>
page.evaluate(
() =>
- (window as Window & { __SPROUT_E2E_COMMANDS__?: string[] })
- .__SPROUT_E2E_COMMANDS__ ?? [],
+ (window as Window & { __BUZZ_E2E_COMMANDS__?: string[] })
+ .__BUZZ_E2E_COMMANDS__ ?? [],
),
)
.toEqual(expect.arrayContaining(["plugin:websocket|disconnect"]));
diff --git a/desktop/tests/e2e/persona-env-vars.spec.ts b/desktop/tests/e2e/persona-env-vars.spec.ts
index cecb2261f..eb9382e8a 100644
--- a/desktop/tests/e2e/persona-env-vars.spec.ts
+++ b/desktop/tests/e2e/persona-env-vars.spec.ts
@@ -18,11 +18,11 @@ async function waitForInvokeBridge(page: import("@playwright/test").Page) {
await page.waitForFunction(
() => {
const w = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: unknown;
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
__TAURI_INTERNALS__?: { invoke?: unknown };
};
return (
- typeof w.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
+ typeof w.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
typeof w.__TAURI_INTERNALS__?.invoke === "function"
);
},
@@ -40,7 +40,7 @@ async function invokeTauri(
return page.evaluate(
async ({ command: c, payload: p }) => {
const w = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
c: string,
p?: Record,
) => Promise;
@@ -49,7 +49,7 @@ async function invokeTauri(
};
};
const invoke =
- w.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ ?? w.__TAURI_INTERNALS__?.invoke;
+ w.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ ?? w.__TAURI_INTERNALS__?.invoke;
if (!invoke) throw new Error("Mock invoke bridge is unavailable.");
return (await invoke(c, p)) as T;
},
diff --git a/desktop/tests/e2e/profile-custom-emoji-status.spec.ts b/desktop/tests/e2e/profile-custom-emoji-status.spec.ts
index 454813b32..05a0f846a 100644
--- a/desktop/tests/e2e/profile-custom-emoji-status.spec.ts
+++ b/desktop/tests/e2e/profile-custom-emoji-status.spec.ts
@@ -2,7 +2,7 @@ import { expect, test } from "@playwright/test";
import { installMockBridge } from "../helpers/bridge";
-const SHORTCODE = "sprout";
+const SHORTCODE = "buzz";
const STATUS_TEXT = "testing custom status";
async function openProfilePopover(page: import("@playwright/test").Page) {
diff --git a/desktop/tests/e2e/profile.spec.ts b/desktop/tests/e2e/profile.spec.ts
index 3d6b29913..ae1db3ab2 100644
--- a/desktop/tests/e2e/profile.spec.ts
+++ b/desktop/tests/e2e/profile.spec.ts
@@ -97,12 +97,11 @@ async function waitForMockLiveSubscription(page: Page, channelName: string) {
return (
(
window as Window & {
- __SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+ __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
channelName: string;
}) => boolean;
}
- ).__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({ channelName }) ??
- false
+ ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({ channelName }) ?? false
);
}, channelName);
})
@@ -378,7 +377,7 @@ test("uploads local profile avatar files before saving", async ({ page }) => {
await expect(page.getByTestId("profile-avatar-url")).toHaveValue("");
const pastedAvatarUrl = await page.evaluate(
- () => new URL("/sprout.svg", window.location.href).href,
+ () => new URL("/buzz.svg", window.location.href).href,
);
await page.getByTestId("profile-avatar-url").click();
await page.keyboard.insertText(pastedAvatarUrl);
@@ -406,8 +405,8 @@ test("uploads local profile avatar files before saving", async ({ page }) => {
.poll(() =>
page.evaluate(
() =>
- (window as Window & { __SPROUT_E2E_COMMANDS__?: string[] })
- .__SPROUT_E2E_COMMANDS__ ?? [],
+ (window as Window & { __BUZZ_E2E_COMMANDS__?: string[] })
+ .__BUZZ_E2E_COMMANDS__ ?? [],
),
)
.toEqual(expect.arrayContaining(["upload_media_bytes", "update_profile"]));
@@ -429,7 +428,7 @@ test("renders emoji avatars with a static background layer", async ({
"background-color",
"rgb(255, 231, 92)",
);
- await expect(avatarPreview).not.toHaveClass(/sprout-avatar-squish/);
+ await expect(avatarPreview).not.toHaveClass(/buzz-avatar-squish/);
await expect(page.getByTestId("profile-avatar-preview-emoji")).toHaveText(
"😀",
);
@@ -574,13 +573,13 @@ test("renders agent memories seeded through the Playwright mock bridge", async (
({ pubkey }) => {
const emit = (
window as Window & {
- __SPROUT_E2E_EMIT_MOCK_MESSAGE__?: (input: {
+ __BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
channelName: string;
content: string;
pubkey: string;
}) => unknown;
}
- ).__SPROUT_E2E_EMIT_MOCK_MESSAGE__;
+ ).__BUZZ_E2E_EMIT_MOCK_MESSAGE__;
if (!emit) {
throw new Error("Mock message emitter is unavailable.");
}
@@ -663,10 +662,10 @@ test("notification settings drive the Home badge and desktop alerts", async ({
async function getAppBadgeCount() {
return page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_APP_BADGE_COUNT__?: number;
+ __BUZZ_E2E_APP_BADGE_COUNT__?: number;
};
- return win.__SPROUT_E2E_APP_BADGE_COUNT__ ?? 0;
+ return win.__BUZZ_E2E_APP_BADGE_COUNT__ ?? 0;
});
}
@@ -690,7 +689,7 @@ test("notification settings drive the Home badge and desktop alerts", async ({
await page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?: (item: {
+ __BUZZ_E2E_PUSH_MOCK_FEED_ITEM__?: (item: {
category: "mention" | "needs_action" | "activity" | "agent_activity";
channel_id: string | null;
channel_name: string;
@@ -703,7 +702,7 @@ test("notification settings drive the Home badge and desktop alerts", async ({
}) => unknown;
};
- win.__SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?.({
+ win.__BUZZ_E2E_PUSH_MOCK_FEED_ITEM__?.({
category: "mention",
channel_id: "1c7e1c02-87bb-5e88-b2da-5a7a9432d0c9",
channel_name: "engineering",
@@ -730,26 +729,26 @@ test("notification settings drive the Home badge and desktop alerts", async ({
.poll(() =>
page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_NOTIFICATIONS__?: Array<{
+ __BUZZ_E2E_NOTIFICATIONS__?: Array<{
body: string | null;
title: string;
}>;
};
- return win.__SPROUT_E2E_NOTIFICATIONS__?.length ?? 0;
+ return win.__BUZZ_E2E_NOTIFICATIONS__?.length ?? 0;
}),
)
.toBe(1);
const notifications = await page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_NOTIFICATIONS__?: Array<{
+ __BUZZ_E2E_NOTIFICATIONS__?: Array<{
body: string | null;
title: string;
}>;
};
- return win.__SPROUT_E2E_NOTIFICATIONS__ ?? [];
+ return win.__BUZZ_E2E_NOTIFICATIONS__ ?? [];
});
expect(notifications).toEqual([
@@ -761,10 +760,10 @@ test("notification settings drive the Home badge and desktop alerts", async ({
const clickedNotification = await page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_CLICK_NOTIFICATION__?: (index: number) => boolean;
+ __BUZZ_E2E_CLICK_NOTIFICATION__?: (index: number) => boolean;
};
- return win.__SPROUT_E2E_CLICK_NOTIFICATION__?.(0) ?? false;
+ return win.__BUZZ_E2E_CLICK_NOTIFICATION__?.(0) ?? false;
});
expect(clickedNotification).toBe(true);
@@ -806,7 +805,7 @@ test("desktop notification clicks open the matching forum thread", async ({
await page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?: (item: {
+ __BUZZ_E2E_PUSH_MOCK_FEED_ITEM__?: (item: {
category: "mention" | "needs_action" | "activity" | "agent_activity";
channel_id: string | null;
channel_name: string;
@@ -819,7 +818,7 @@ test("desktop notification clicks open the matching forum thread", async ({
}) => unknown;
};
- win.__SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?.({
+ win.__BUZZ_E2E_PUSH_MOCK_FEED_ITEM__?.({
category: "mention",
channel_id: "a27e1ee9-76a6-5bdf-a5d5-1d85610dad11",
channel_name: "watercooler",
@@ -837,23 +836,23 @@ test("desktop notification clicks open the matching forum thread", async ({
.poll(() =>
page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_NOTIFICATIONS__?: Array<{
+ __BUZZ_E2E_NOTIFICATIONS__?: Array<{
body: string | null;
title: string;
}>;
};
- return win.__SPROUT_E2E_NOTIFICATIONS__?.length ?? 0;
+ return win.__BUZZ_E2E_NOTIFICATIONS__?.length ?? 0;
}),
)
.toBe(1);
const clickedNotification = await page.evaluate(() => {
const win = window as Window & {
- __SPROUT_E2E_CLICK_NOTIFICATION__?: (index: number) => boolean;
+ __BUZZ_E2E_CLICK_NOTIFICATION__?: (index: number) => boolean;
};
- return win.__SPROUT_E2E_CLICK_NOTIFICATION__?.(0) ?? false;
+ return win.__BUZZ_E2E_CLICK_NOTIFICATION__?.(0) ?? false;
});
expect(clickedNotification).toBe(true);
@@ -922,7 +921,7 @@ test("opens settings with the keyboard shortcut and updates theme", async ({
// Theme name persists in localStorage
await expect
- .poll(() => page.evaluate(() => localStorage.getItem("sprout-theme")))
+ .poll(() => page.evaluate(() => localStorage.getItem("buzz-theme")))
.toBe("github-light");
// Switch back to a dark theme — verifies light→dark transition
@@ -935,7 +934,7 @@ test("opens settings with the keyboard shortcut and updates theme", async ({
.toBe(true);
await expect
- .poll(() => page.evaluate(() => localStorage.getItem("sprout-theme")))
+ .poll(() => page.evaluate(() => localStorage.getItem("buzz-theme")))
.toBe("dracula");
// Close settings with keyboard shortcut
@@ -953,8 +952,8 @@ test("supports webview zoom keyboard shortcuts", async ({ page }) => {
const getTextScaleState = () =>
page.evaluate(() => ({
fontSize: getComputedStyle(document.documentElement).fontSize,
- storedScale: localStorage.getItem("sprout:text-scale"),
- webviewZoom: window.__SPROUT_E2E_WEBVIEW_ZOOM__,
+ storedScale: localStorage.getItem("buzz:text-scale"),
+ webviewZoom: window.__BUZZ_E2E_WEBVIEW_ZOOM__,
}));
const dispatchPrimaryShortcut = (
key: string,
@@ -1013,7 +1012,7 @@ test("supports webview zoom keyboard shortcuts", async ({ page }) => {
});
});
-test("shows doctor checks for local sprout tooling", async ({ page }) => {
+test("shows doctor checks for local CLI tooling", async ({ page }) => {
await page.goto("/");
await openSettings(page, "doctor");
diff --git a/desktop/tests/e2e/relay-reconnect.spec.ts b/desktop/tests/e2e/relay-reconnect.spec.ts
index 1e9fb7a09..516286d71 100644
--- a/desktop/tests/e2e/relay-reconnect.spec.ts
+++ b/desktop/tests/e2e/relay-reconnect.spec.ts
@@ -9,9 +9,9 @@ async function setMockWebsocketSendsStalled(
await page.evaluate((shouldStall) => {
const setter = (
window as Window & {
- __SPROUT_E2E_SET_STALL_WEBSOCKET_SENDS__?: (stall: boolean) => void;
+ __BUZZ_E2E_SET_STALL_WEBSOCKET_SENDS__?: (stall: boolean) => void;
}
- ).__SPROUT_E2E_SET_STALL_WEBSOCKET_SENDS__;
+ ).__BUZZ_E2E_SET_STALL_WEBSOCKET_SENDS__;
if (!setter) {
throw new Error("E2E websocket stall setter is not installed.");
}
diff --git a/desktop/tests/e2e/sidebar.spec.ts b/desktop/tests/e2e/sidebar.spec.ts
index c869b2543..18c2b1882 100644
--- a/desktop/tests/e2e/sidebar.spec.ts
+++ b/desktop/tests/e2e/sidebar.spec.ts
@@ -2,7 +2,7 @@ import { expect, test, type Page } from "@playwright/test";
import { installMockBridge } from "../helpers/bridge";
-const SIDEBAR_WIDTH_STORAGE_KEY = "sprout-sidebar-width";
+const SIDEBAR_WIDTH_STORAGE_KEY = "buzz-sidebar-width";
const DEFAULT_SIDEBAR_WIDTH = 300;
test.beforeEach(async ({ page }) => {
diff --git a/desktop/tests/e2e/team-management-screenshots.spec.ts b/desktop/tests/e2e/team-management-screenshots.spec.ts
index b497c929f..e05172429 100644
--- a/desktop/tests/e2e/team-management-screenshots.spec.ts
+++ b/desktop/tests/e2e/team-management-screenshots.spec.ts
@@ -8,14 +8,14 @@ async function waitForInvokeBridge(page: import("@playwright/test").Page) {
await page.waitForFunction(
() => {
const tauriWindow = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: unknown;
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
__TAURI_INTERNALS__?: {
invoke?: unknown;
};
};
return (
- typeof tauriWindow.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
+ typeof tauriWindow.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
typeof tauriWindow.__TAURI_INTERNALS__?.invoke === "function"
);
},
@@ -34,7 +34,7 @@ async function invokeMockCommand(
return page.evaluate(
async ({ command: cmd, payload: pl }) => {
const tauriWindow = window as Window & {
- __SPROUT_E2E_INVOKE_MOCK_COMMAND__?: (
+ __BUZZ_E2E_INVOKE_MOCK_COMMAND__?: (
command: string,
payload?: Record,
) => Promise;
@@ -47,7 +47,7 @@ async function invokeMockCommand(
};
const invoke =
- tauriWindow.__SPROUT_E2E_INVOKE_MOCK_COMMAND__ ??
+ tauriWindow.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ ??
tauriWindow.__TAURI_INTERNALS__?.invoke;
if (!invoke) {
throw new Error("Mock invoke bridge is unavailable.");
diff --git a/desktop/tests/helpers/bridge.ts b/desktop/tests/helpers/bridge.ts
index 7758f6c30..037e71495 100644
--- a/desktop/tests/helpers/bridge.ts
+++ b/desktop/tests/helpers/bridge.ts
@@ -155,8 +155,7 @@ type BridgeOptions = {
user?: keyof typeof TEST_IDENTITIES;
};
-const ONBOARDING_COMPLETION_STORAGE_KEY_PREFIX =
- "sprout-onboarding-complete.v1:";
+const ONBOARDING_COMPLETION_STORAGE_KEY_PREFIX = "buzz-onboarding-complete.v1:";
const DEFAULT_MOCK_PUBKEY = "deadbeef".repeat(8);
const DEFAULT_RELAY_WS_URL = "ws://localhost:3000";
@@ -181,14 +180,14 @@ export function createMockAgentMemoryListing(
I prefer concise updates, explicit next steps, and visual polish before edge-case handling.
-See [[mem/preferences/ui-density]] and [[mem/projects/sprout-memory-viewer]] for details.
+See [[mem/preferences/ui-density]] and [[mem/projects/buzz-memory-viewer]] for details.
A retired launch checklist used to live at [[mem/archive/deleted-launch-checklist]], but that memory was deleted after the plan changed.`,
eventId: "mock-core",
createdAt: 1_700_000_000,
outgoingRefs: [
"mem/preferences/ui-density",
- "mem/projects/sprout-memory-viewer",
+ "mem/projects/buzz-memory-viewer",
"mem/archive/deleted-launch-checklist",
],
},
@@ -208,14 +207,14 @@ A retired launch checklist used to live at [[mem/archive/deleted-launch-checklis
outgoingRefs: [],
},
{
- slug: "mem/projects/sprout-memory-viewer",
- body: "Building the IXI-7 read-only memory viewer in the profile panel.\n\nChild memory: [[mem/projects/sprout-memory-viewer/notes]]",
+ slug: "mem/projects/buzz-memory-viewer",
+ body: "Building the IXI-7 read-only memory viewer in the profile panel.\n\nChild memory: [[mem/projects/buzz-memory-viewer/notes]]",
eventId: "mock-project",
createdAt: 1_700_000_300,
- outgoingRefs: ["mem/projects/sprout-memory-viewer/notes"],
+ outgoingRefs: ["mem/projects/buzz-memory-viewer/notes"],
},
{
- slug: "mem/projects/sprout-memory-viewer/notes",
+ slug: "mem/projects/buzz-memory-viewer/notes",
body: "Tree should auto-expand core. Everything else collapsed with a one-line preview.",
eventId: "mock-project-notes",
createdAt: 1_700_000_400,
@@ -295,10 +294,10 @@ async function seedDefaultWorkspace(page: Page, relayWsUrl?: string) {
addedAt: new Date().toISOString(),
};
window.localStorage.setItem(
- "sprout-workspaces",
+ "buzz-workspaces",
JSON.stringify([workspace]),
);
- window.localStorage.setItem("sprout-active-workspace-id", workspaceId);
+ window.localStorage.setItem("buzz-active-workspace-id", workspaceId);
},
{ relayUrl: relayWsUrl ?? DEFAULT_RELAY_WS_URL },
);
@@ -375,18 +374,18 @@ export async function installBridge(page: Page, options: BridgeOptions) {
});
const testWindow = window as Window & {
- __SPROUT_E2E__?: Record;
- __SPROUT_E2E_APP_BADGE_COUNT__?: number;
- __SPROUT_E2E_APP_BADGE_STATE__?: string;
- __SPROUT_E2E_CLICK_NOTIFICATION__?: (index: number) => boolean;
- __SPROUT_E2E_NOTIFICATIONS__?: Array<{
+ __BUZZ_E2E__?: Record;
+ __BUZZ_E2E_APP_BADGE_COUNT__?: number;
+ __BUZZ_E2E_APP_BADGE_STATE__?: string;
+ __BUZZ_E2E_CLICK_NOTIFICATION__?: (index: number) => boolean;
+ __BUZZ_E2E_NOTIFICATIONS__?: Array<{
body: string | null;
title: string;
}>;
};
- const currentConfig = testWindow.__SPROUT_E2E__ ?? {};
+ const currentConfig = testWindow.__BUZZ_E2E__ ?? {};
- testWindow.__SPROUT_E2E__ = {
+ testWindow.__BUZZ_E2E__ = {
...currentConfig,
identity: bridgeIdentity ?? currentConfig.identity,
mock,
@@ -394,9 +393,9 @@ export async function installBridge(page: Page, options: BridgeOptions) {
relayHttpUrl: relayHttpUrl ?? currentConfig.relayHttpUrl,
relayWsUrl: relayWsUrl ?? currentConfig.relayWsUrl,
};
- testWindow.__SPROUT_E2E_APP_BADGE_COUNT__ = 0;
- testWindow.__SPROUT_E2E_APP_BADGE_STATE__ = "none";
- testWindow.__SPROUT_E2E_CLICK_NOTIFICATION__ = (index: number) => {
+ testWindow.__BUZZ_E2E_APP_BADGE_COUNT__ = 0;
+ testWindow.__BUZZ_E2E_APP_BADGE_STATE__ = "none";
+ testWindow.__BUZZ_E2E_CLICK_NOTIFICATION__ = (index: number) => {
const notification = notificationInstances[index];
if (!notification) {
return false;
@@ -407,7 +406,7 @@ export async function installBridge(page: Page, options: BridgeOptions) {
notification.onclick?.(event);
return true;
};
- testWindow.__SPROUT_E2E_NOTIFICATIONS__ = notificationLog;
+ testWindow.__BUZZ_E2E_NOTIFICATIONS__ = notificationLog;
},
{
identity,
diff --git a/desktop/tests/helpers/features.ts b/desktop/tests/helpers/features.ts
index 21e0ee073..b4d55cc24 100644
--- a/desktop/tests/helpers/features.ts
+++ b/desktop/tests/helpers/features.ts
@@ -34,4 +34,4 @@ export const PREVIEW_FEATURE_IDS: string[] = manifest.features
* Mirrors `OVERRIDES_KEY` in `src/shared/features/store.ts` so a manifest
* version bump flows through to E2E seeding without manual updates.
*/
-export const FEATURE_OVERRIDES_STORAGE_KEY = `sprout-feature-overrides-v${manifest.version}`;
+export const FEATURE_OVERRIDES_STORAGE_KEY = `buzz-feature-overrides-v${manifest.version}`;
diff --git a/desktop/tests/helpers/screenshot.mjs b/desktop/tests/helpers/screenshot.mjs
index 8a3978c9e..096a6d182 100644
--- a/desktop/tests/helpers/screenshot.mjs
+++ b/desktop/tests/helpers/screenshot.mjs
@@ -1,6 +1,6 @@
#!/usr/bin/env node
//
-// Standalone Playwright screenshot helper for the Sprout desktop app.
+// Standalone Playwright screenshot helper for the Buzz desktop app.
//
// Launches headless Chromium with the E2E mock bridge pre-injected (same
// setup as installMockBridge in bridge.ts), navigates to a route, optionally
@@ -67,7 +67,7 @@ function bail(msg) {
const BASE_URL = "http://127.0.0.1:4173";
const DEFAULT_MOCK_PUBKEY = "deadbeef".repeat(8);
-const ONBOARDING_PREFIX = "sprout-onboarding-complete.v1:";
+const ONBOARDING_PREFIX = "buzz-onboarding-complete.v1:";
const TEST_PUBKEYS = [
DEFAULT_MOCK_PUBKEY,
@@ -92,8 +92,8 @@ await page.addInitScript(() => {
relayUrl: "ws://localhost:3000",
addedAt: new Date().toISOString(),
};
- window.localStorage.setItem("sprout-workspaces", JSON.stringify([workspace]));
- window.localStorage.setItem("sprout-active-workspace-id", workspaceId);
+ window.localStorage.setItem("buzz-workspaces", JSON.stringify([workspace]));
+ window.localStorage.setItem("buzz-active-workspace-id", workspaceId);
});
// Seed onboarding completion for all known identities
@@ -129,8 +129,8 @@ await page.addInitScript(() => {
writable: true,
});
- window.__SPROUT_E2E__ = { mode: "mock" };
- window.__SPROUT_E2E_APP_BADGE_COUNT__ = 0;
+ window.__BUZZ_E2E__ = { mode: "mock" };
+ window.__BUZZ_E2E_APP_BADGE_COUNT__ = 0;
});
try {
@@ -184,7 +184,7 @@ try {
for (const ch of targetChannels) {
await page.waitForFunction(
(name) =>
- window.__SPROUT_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
+ window.__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: name,
}) ?? false,
ch,
@@ -195,7 +195,7 @@ try {
for (const msg of messages) {
await page.evaluate(
(m) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.(m);
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.(m);
},
{ ...msg, pubkey: msg.pubkey ?? DEFAULT_MOCK_PUBKEY },
);
diff --git a/desktop/tests/helpers/seed.ts b/desktop/tests/helpers/seed.ts
index 8833792dd..4aafb7e4c 100644
--- a/desktop/tests/helpers/seed.ts
+++ b/desktop/tests/helpers/seed.ts
@@ -3,18 +3,17 @@ import { request } from "@playwright/test";
const tylerPubkey =
"e5ebc6cdb579be112e336cc319b5989b4bb6af11786ea90dbe52b5f08d741b34";
const isCi = Boolean(process.env.CI);
-const relayBaseUrl =
- process.env.SPROUT_E2E_RELAY_URL ?? "http://127.0.0.1:3000";
+const relayBaseUrl = process.env.BUZZ_E2E_RELAY_URL ?? "http://127.0.0.1:3000";
const seedTimeoutMs = Number.parseInt(
- process.env.SPROUT_E2E_SEED_TIMEOUT_MS ?? (isCi ? "60000" : "25000"),
+ process.env.BUZZ_E2E_SEED_TIMEOUT_MS ?? (isCi ? "60000" : "25000"),
10,
);
const requestTimeoutMs = Number.parseInt(
- process.env.SPROUT_E2E_SEED_REQUEST_TIMEOUT_MS ?? (isCi ? "5000" : "2000"),
+ process.env.BUZZ_E2E_SEED_REQUEST_TIMEOUT_MS ?? (isCi ? "5000" : "2000"),
10,
);
const retryDelayMs = Number.parseInt(
- process.env.SPROUT_E2E_SEED_RETRY_DELAY_MS ?? "1000",
+ process.env.BUZZ_E2E_SEED_RETRY_DELAY_MS ?? "1000",
10,
);
diff --git a/desktop/tests/helpers/zoom-shot.mjs b/desktop/tests/helpers/zoom-shot.mjs
index 1776df532..3a9de2834 100644
--- a/desktop/tests/helpers/zoom-shot.mjs
+++ b/desktop/tests/helpers/zoom-shot.mjs
@@ -27,7 +27,7 @@ mkdirSync(resolve(a.outdir), { recursive: true });
const BASE = `http://127.0.0.1:${a.port}`;
const DEFAULT_MOCK_PUBKEY = "deadbeef".repeat(8);
-const ONBOARDING_PREFIX = "sprout-onboarding-complete.v1:";
+const ONBOARDING_PREFIX = "buzz-onboarding-complete.v1:";
const TEST_PUBKEYS = [
DEFAULT_MOCK_PUBKEY,
"e5ebc6cdb579be112e336cc319b5989b4bb6af11786ea90dbe52b5f08d741b34",
@@ -48,8 +48,8 @@ await page.addInitScript(() => {
relayUrl: "ws://localhost:3000",
addedAt: new Date().toISOString(),
};
- window.localStorage.setItem("sprout-workspaces", JSON.stringify([ws]));
- window.localStorage.setItem("sprout-active-workspace-id", id);
+ window.localStorage.setItem("buzz-workspaces", JSON.stringify([ws]));
+ window.localStorage.setItem("buzz-active-workspace-id", id);
});
await page.addInitScript(
({ prefix, pubkeys }) => {
@@ -77,8 +77,8 @@ await page.addInitScript(() => {
value: MockNotification,
writable: true,
});
- window.__SPROUT_E2E__ = { mode: "mock" };
- window.__SPROUT_E2E_APP_BADGE_COUNT__ = 0;
+ window.__BUZZ_E2E__ = { mode: "mock" };
+ window.__BUZZ_E2E_APP_BADGE_COUNT__ = 0;
});
try {
@@ -102,7 +102,7 @@ try {
// Send a message via mock so we have something to thread.
await page.evaluate(
({ ch }) => {
- window.__SPROUT_E2E_EMIT_MOCK_MESSAGE__?.({
+ window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: ch,
content: "Header spacing comparison anchor message",
pubkey: "deadbeef".repeat(8),
diff --git a/justfile b/justfile
index 86006d6b7..e04909fd6 100644
--- a/justfile
+++ b/justfile
@@ -274,6 +274,7 @@ proxy-release:
dev *ARGS: _ensure-sidecar-stubs
#!/usr/bin/env bash
set -euo pipefail
+ cargo build -p buzz-acp -p buzz-agent -p buzz-dev-mcp -p buzz-cli
cd {{desktop_dir}}
[[ -d node_modules ]] || pnpm install
source ../scripts/instance-env.sh
diff --git a/scripts/dev-setup.sh b/scripts/dev-setup.sh
index b60601ab3..7a3d6e8e7 100755
--- a/scripts/dev-setup.sh
+++ b/scripts/dev-setup.sh
@@ -49,6 +49,18 @@ load_env() {
set +o allexport
fi
+ # Smooth the local rename path for developers with a pre-Buzz .env copied
+ # from .env.example. Only rewrite the old default values; custom values stay
+ # untouched.
+ if [[ "${DATABASE_URL:-}" == "postgres://sprout:sprout_dev@localhost:5432/sprout" ]]; then
+ warn "Migrating legacy default DATABASE_URL from sprout to buzz for this setup run"
+ DATABASE_URL="postgres://buzz:buzz_dev@localhost:5432/buzz"
+ fi
+ if [[ "${PGUSER:-}" == "sprout" ]]; then PGUSER="buzz"; fi
+ if [[ "${PGPASSWORD:-}" == "sprout_dev" ]]; then PGPASSWORD="buzz_dev"; fi
+ if [[ "${PGDATABASE:-}" == "sprout" ]]; then PGDATABASE="buzz"; fi
+ if [[ "${TYPESENSE_API_KEY:-}" == "sprout_dev_key" ]]; then TYPESENSE_API_KEY="buzz_dev_key"; fi
+
export DATABASE_URL="${DATABASE_URL:-postgres://buzz:buzz_dev@localhost:5432/buzz}"
export PGHOST="${PGHOST:-localhost}"
export PGPORT="${PGPORT:-5432}"
@@ -60,6 +72,35 @@ load_env() {
export TYPESENSE_URL="${TYPESENSE_URL:-http://localhost:8108}"
}
+cleanup_legacy_sprout_containers() {
+ local legacy_containers
+ legacy_containers=$(docker ps -a --format '{{.Names}}' | grep -E '^sprout-(postgres|redis|typesense|adminer|keycloak|minio|minio-init|prometheus)$' || true)
+ if [[ -z "${legacy_containers}" ]]; then
+ return
+ fi
+
+ warn "Stopping/removing legacy sprout-* dev containers so buzz-* containers can bind the standard ports"
+ echo "${legacy_containers}" | xargs docker stop >/dev/null 2>&1 || true
+ echo "${legacy_containers}" | xargs docker rm >/dev/null 2>&1 || true
+ success "Legacy sprout-* containers removed (volumes preserved)"
+}
+
+fail_if_local_redis_blocks_compose() {
+ if ! command -v lsof >/dev/null 2>&1; then
+ return
+ fi
+ if docker ps --format '{{.Names}}' | grep -qx 'buzz-redis'; then
+ return
+ fi
+ local redis_pids
+ redis_pids=$(lsof -nP -iTCP:6379 -sTCP:LISTEN 2>/dev/null | awk 'NR > 1 && $1 == "redis-ser" {print $2}' | sort -u | tr '
+' ' ' || true)
+ if [[ -n "${redis_pids}" ]]; then
+ error "Local Redis is already listening on port 6379 (pid(s): ${redis_pids}). Stop it before running setup: brew services stop redis"
+ exit 1
+ fi
+}
+
postgres_accepting_connections() {
docker exec buzz-postgres \
pg_isready -h localhost -p 5432 -U "${PGUSER}" -d "${PGDATABASE}" \
@@ -67,6 +108,8 @@ postgres_accepting_connections() {
}
load_env
+cleanup_legacy_sprout_containers
+fail_if_local_redis_blocks_compose
# ---- Start services ---------------------------------------------------------
diff --git a/scripts/instance-env.sh b/scripts/instance-env.sh
index 4d1cc2e55..e77cf1f37 100755
--- a/scripts/instance-env.sh
+++ b/scripts/instance-env.sh
@@ -43,18 +43,23 @@ if git rev-parse --is-inside-work-tree &>/dev/null; then
# tauri-plugin-single-instance or the app data directory.
if [[ "${BUZZ_SHARE_IDENTITY:-0}" == "1" ]]; then
CANONICAL_KEY="$HOME/Library/Application Support/xyz.block.buzz.app.dev/identity.key"
+ LEGACY_CANONICAL_KEY="$HOME/Library/Application Support/xyz.block.sprout.app.dev/identity.key"
if [[ -f "$CANONICAL_KEY" ]]; then
export BUZZ_PRIVATE_KEY="$(cat "$CANONICAL_KEY")"
+ elif [[ -f "$LEGACY_CANONICAL_KEY" ]]; then
+ export BUZZ_PRIVATE_KEY="$(cat "$LEGACY_CANONICAL_KEY")"
else
- echo "⚠ BUZZ_SHARE_IDENTITY=1 but no identity found at $CANONICAL_KEY — run Buzz from repo root first" >&2
+ echo "⚠ BUZZ_SHARE_IDENTITY=1 but no identity found at $CANONICAL_KEY or $LEGACY_CANONICAL_KEY — run Buzz from repo root first" >&2
fi
fi
- ICON_DIR="$(pwd)/src-tauri/target/dev-icons"
+ ICON_DIR="$WORKTREE_ROOT/desktop/src-tauri/target/dev-icons"
mkdir -p "$ICON_DIR"
DEV_ICON="$ICON_DIR/icon.icns"
+ GENERATE_DEV_ICON="$WORKTREE_ROOT/scripts/generate-dev-icon.swift"
+ BASE_ICON="$WORKTREE_ROOT/desktop/src-tauri/icons/icon.icns"
- if swift ../scripts/generate-dev-icon.swift src-tauri/icons/icon.icns "$DEV_ICON" "$BUZZ_WORKTREE_LABEL"; then
+ if swift "$GENERATE_DEV_ICON" "$BASE_ICON" "$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\"]}}"