2026-06-10 19:29:51 -04:00
# Buzz — development task runner
2026-03-09 15:15:25 -04:00
set dotenv-load : = true
2026-03-09 13:02:11 -07:00
desktop_dir := "desktop"
desktop_tauri_manifest := "desktop/src-tauri/Cargo.toml"
2026-05-04 13:49:48 -06:00
web_dir := "web"
2026-03-09 13:02:11 -07:00
2026-07-23 13:48:52 -04:00
# Opt-in mesh-llm. Off by default so `just dev`/`just staging`/`just production`
# skip ~420 extra crates + the llama.cpp native runtime build and stay fast to
# iterate on. Turn on to test mesh compute features: `just mesh=1 dev` /
# `just mesh=1 staging` / `just mesh=1 production`.
2026-06-22 15:11:50 -07:00
mesh := ""
2026-07-17 14:19:29 -06:00
# Reset only the current standalone desktop instance before launch.
# Usage: `just fresh=1 desktop-standalone`.
fresh := ""
2026-03-09 15:15:25 -04:00
# List all available tasks
default :
@just --list
# ─── Dev Environment ─────────────────────────────────────────────────────────
2026-06-18 17:24:05 -04:00
# Install required dev tools via Hermit and create .env (safe to re-run)
bootstrap :
#!/usr/bin/env bash
set -euo pipefail
export PATH = "{{justfile_directory()}}/bin: $PATH "
# Hermit's bin/ symlinks auto-download pinned tool versions on first use.
# Running each tool once triggers the download if not already cached.
echo "Ensuring toolchain via Hermit..."
cargo --version &
node --version &
pnpm --version &
wait
if ! command -v docker & >/dev/null; then
echo "Error: Docker is required but not installed."
echo "Install it from https://docs.docker.com/get-docker/"
exit 1
fi
if [[ ! -f .env ]] ; then
cp .env.example .env
echo "Created .env from .env.example — review it before running just dev."
fi
2026-03-26 10:35:28 -07:00
# Start Docker services, run migrations, install desktop deps
2026-06-18 17:24:05 -04:00
setup : bootstrap
2026-03-09 15:15:25 -04:00
./scripts/dev-setup.sh
2026-07-10 22:06:32 -04:00
# Install git hooks via lefthook (dispatches from the shared .git/hooks dir so all
# linked worktrees inherit the same hooks without a worktree-relative .hooks path)
2026-05-26 18:05:42 -04:00
hooks :
2026-07-10 22:06:32 -04:00
#!/usr/bin/env bash
set -euo pipefail
2026-07-21 13:42:02 -04:00
# Use the Hermit-pinned lefthook (bin/lefthook self-downloads on first use):
# works with no pre-installed lefthook and guarantees the pinned version
# rather than whatever happens to be on PATH.
export PATH = "{{justfile_directory()}}/bin: $PATH "
2026-07-10 22:06:32 -04:00
# --path-format=absolute guarantees an absolute path from every invocation context:
# without it, --git-common-dir returns ".git" from the main checkout and a
# relative hooksPath would break linked-worktree dispatch just like .hooks did.
HOOKS_DIR = " $( git rev-parse --path-format= absolute --git-common-dir) /hooks"
git config --local core.hooksPath " $HOOKS_DIR "
2026-05-26 18:05:42 -04:00
lefthook install --force
2026-07-16 00:10:29 +10:00
# Wipe development state and recreate a clean environment. Installed Buzz is preserved.
[confirm( "This will DELETE all development data and preserve installed Buzz. Continue? (y/N)" )]
2026-03-09 15:15:25 -04:00
reset :
./scripts/dev-reset.sh --yes
# Stop all dev services (keep data)
down :
docker compose down
# Show dev service status
ps :
docker compose ps
# Tail all service logs
logs *ARGS :
docker compose logs -f {{ ARGS}}
# ─── Build & Check ───────────────────────────────────────────────────────────
2026-03-09 13:02:11 -07:00
# Build the Rust workspace
2026-03-09 15:15:25 -04:00
build :
cargo build --workspace
2026-03-09 13:02:11 -07:00
# Build the Rust workspace in release mode
2026-03-09 15:15:25 -04:00
build-release :
cargo build --workspace --release
2026-03-09 13:02:11 -07:00
# Run repo lint and formatting checks
2026-05-28 17:42:35 -04:00
check : fmt -check clippy desktop -check desktop -tauri -fmt -check desktop -tauri -clippy web -check mobile -check
2026-03-09 15:15:25 -04:00
# Format all Rust code
fmt :
cargo fmt --all
# Check formatting without modifying files
fmt-check :
cargo fmt --all -- --check
# Run clippy with warnings as errors
clippy :
cargo clippy --workspace --all-targets -- -D warnings
2026-05-04 18:09:25 -06:00
# Install JS dependencies (pnpm workspace — installs all packages from root)
2026-03-09 13:02:11 -07:00
desktop-install :
2026-05-04 18:09:25 -06:00
pnpm install
2026-03-09 13:02:11 -07:00
2026-05-04 18:09:25 -06:00
# Install JS dependencies reproducibly for CI (pnpm workspace)
2026-03-09 13:02:11 -07:00
desktop-install-ci :
2026-05-04 18:09:25 -06:00
pnpm install --frozen-lockfile
2026-03-09 13:02:11 -07:00
# Run desktop lint and format checks
desktop-check :
cd {{ desktop_dir}} && pnpm check
2026-05-28 17:42:35 -04:00
# Fix desktop lint and format issues
desktop-fix :
cd {{ desktop_dir}} && pnpm exec biome check --write . && pnpm check:file-sizes
2026-05-28 08:17:02 -07:00
# Run desktop TS helper unit tests
desktop-test :
cd {{ desktop_dir}} && pnpm test
2026-03-09 13:02:11 -07:00
# Run desktop TypeScript checks
desktop-typecheck :
cd {{ desktop_dir}} && pnpm typecheck
# Build desktop frontend assets
desktop-build :
cd {{ desktop_dir}} && pnpm build
2026-03-24 14:30:10 -07:00
# Format desktop Tauri Rust code
desktop-tauri-fmt :
cargo fmt --manifest-path {{ desktop_tauri_manifest}} --all
# Check desktop Tauri Rust formatting
desktop-tauri-fmt-check :
cargo fmt --manifest-path {{ desktop_tauri_manifest}} --all -- --check
2026-05-26 18:05:42 -04:00
# Format all code (Rust + Tauri Rust + Dart)
fmt-all : fmt desktop -tauri -fmt mobile -fmt
2026-05-28 17:42:35 -04:00
# Fix all formatting and lint issues
fix-all : fmt desktop -tauri -fmt desktop -fix web -fix mobile -fix
2026-04-20 13:30:37 -06:00
# Ensure sidecar placeholder binaries exist (Tauri validates externalBin at compile time)
2026-06-18 17:24:05 -04:00
# Sidecar binary list must stay in sync with desktop-release-build below.
2026-04-20 13:30:37 -06:00
_ensure-sidecar-stubs :
2026-04-18 09:38:27 -06:00
#!/usr/bin/env bash
set -euo pipefail
TARGET = $( rustc -vV | sed -n 's|host: ||p' )
mkdir -p desktop/src-tauri/binaries
2026-08-02 14:39:27 -04:00
SIDECARS =( buzz-acp buzz-agent buzz-dev-mcp git-credential-nostr buzz)
if [[ " $TARGET " != *windows* ]] ; then
SIDECARS +=( buzz-backend-kubernetes)
fi
for bin in " ${ SIDECARS [@] } " ; do
2026-04-20 13:30:37 -06:00
touch "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
done
2026-05-29 18:26:24 -04:00
# Ensure Docker dev services (Postgres, Redis, etc.) are running and healthy
_ensure-services :
#!/usr/bin/env bash
set -euo pipefail
2026-06-10 19:29:51 -04:00
pg = $( docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' buzz-postgres 2>/dev/null || echo "not_found" )
redis = $( docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' buzz-redis 2>/dev/null || echo "not_found" )
2026-05-29 18:26:24 -04:00
if [[ " $pg " == "healthy" && " $redis " == "healthy" ]] ; then
echo "Services already healthy"
exit 0
fi
echo "Starting services..."
docker compose up -d || true
echo -n "Waiting for services"
for i in $( seq 1 40) ; do
2026-06-10 19:29:51 -04:00
pg = $( docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' buzz-postgres 2>/dev/null || echo "not_found" )
redis = $( docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' buzz-redis 2>/dev/null || echo "not_found" )
2026-05-29 18:26:24 -04:00
if [[ " $pg " == "healthy" && " $redis " == "healthy" ]] ; then
echo " ready"
exit 0
fi
echo -n "."
sleep 3
done
echo " timed out"
exit 1
2026-06-29 12:39:02 -04:00
# Apply database migrations and seed the local dev community if the dev database is running
2026-05-29 18:26:24 -04:00
_ensure-migrations : _ensure -services
2026-06-16 08:39:19 -04:00
cargo run -p buzz-admin -- migrate
2026-06-29 12:39:02 -04:00
./scripts/seed-local-community.sh
2026-05-29 18:26:24 -04:00
2026-05-28 17:42:35 -04:00
# Run clippy on the desktop Tauri Rust crate
desktop-tauri-clippy : _ensure -sidecar -stubs
2026-08-03 21:51:17 -04:00
cargo clippy --manifest-path {{ desktop_tauri_manifest}} --workspace --all-targets -- -D warnings
2026-05-28 17:42:35 -04:00
2026-04-20 13:30:37 -06:00
# Check the desktop Tauri Rust crate compiles
desktop-tauri-check : _ensure -sidecar -stubs
2026-03-09 13:02:11 -07:00
cargo check --manifest-path {{ desktop_tauri_manifest}}
2026-05-28 08:17:02 -07:00
# Run desktop Tauri Rust unit tests
desktop-tauri-test : _ensure -sidecar -stubs
2026-08-03 21:51:17 -04:00
cd desktop/src-tauri && cargo test --workspace
# Run the native terminal latency gate explicitly on a known-idle host.
# This is intentionally excluded from shared CI: scheduler contention makes a
# wall-clock assertion flaky, and the release profile is the shipped shape.
desktop-terminal-performance-test :
cargo test --manifest-path desktop/src-tauri/crates/buzz-terminal/Cargo.toml --release --test latency g3_renderer_acquire_stays_within_frame_budget -- --ignored --exact --nocapture
2026-05-28 08:17:02 -07:00
2026-08-05 18:58:24 -07:00
# Verify compiled-flag behavior under both compile states (clean + capability set).
# Runs the auto-connect and owner-only access focused tests twice with
# independently supplied expected values; build.rs rerun-if-env-changed
# triggers recompilation.
2026-07-16 15:47:35 -04:00
desktop-tauri-test-compiled-flags : _ensure -sidecar -stubs
#!/usr/bin/env bash
set -euo pipefail
cd desktop/src-tauri
echo "=== Clean build (no flag) → expect false ==="
2026-07-23 14:59:10 -06:00
env -u BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY \
BUZZ_TEST_EXPECTED_AUTO_CONNECT_DEFAULT_RELAY = false \
cargo test compiled_flag_matches_expected -- --ignored --nocapture
2026-08-05 18:58:24 -07:00
env -u BUZZ_BUILD_AGENT_ACCESS_OWNER_ONLY \
BUZZ_TEST_EXPECTED_AGENT_ACCESS_OWNER_ONLY = false \
cargo test --lib
env -u BUZZ_BUILD_AGENT_ACCESS_OWNER_ONLY \
BUZZ_TEST_EXPECTED_AGENT_ACCESS_OWNER_ONLY = false \
cargo test compiled_policy_matches_expected -- --ignored --nocapture
echo "=== Internal build (flags set) → expect true ==="
2026-07-23 14:59:10 -06:00
BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY = 1 \
BUZZ_TEST_EXPECTED_AUTO_CONNECT_DEFAULT_RELAY = true \
cargo test compiled_flag_matches_expected -- --ignored --nocapture
2026-08-05 18:58:24 -07:00
BUZZ_BUILD_AGENT_ACCESS_OWNER_ONLY = 1 \
BUZZ_TEST_EXPECTED_AGENT_ACCESS_OWNER_ONLY = true \
cargo test --lib
BUZZ_BUILD_AGENT_ACCESS_OWNER_ONLY = 1 \
BUZZ_TEST_EXPECTED_AGENT_ACCESS_OWNER_ONLY = true \
cargo test compiled_policy_matches_expected -- --ignored --nocapture
2026-07-16 15:47:35 -04:00
echo "Both compiled states verified."
2026-04-20 12:52:39 -06:00
# Build the full desktop Tauri app locally (unsigned, for testing)
2026-06-18 17:24:05 -04:00
# Sidecar binary list must stay in sync with _ensure-sidecar-stubs above.
# pnpm install is unconditional here: release builds must start from a clean dep tree.
2026-04-20 12:52:39 -06:00
desktop-release-build target="aarch64-apple-darwin" :
#!/usr/bin/env bash
set -euo pipefail
TARGET ={{ target}}
mkdir -p desktop/src-tauri/binaries
2026-06-11 01:06:29 -07:00
touch "desktop/src-tauri/binaries/buzz-acp- $TARGET "
touch "desktop/src-tauri/binaries/buzz-agent- $TARGET "
2026-08-02 14:39:27 -04:00
if [[ " $TARGET " != *windows* ]] ; then
touch "desktop/src-tauri/binaries/buzz-backend-kubernetes- $TARGET "
fi
2026-06-11 01:06:29 -07:00
touch "desktop/src-tauri/binaries/buzz-dev-mcp- $TARGET "
2026-05-02 11:46:49 -04:00
touch "desktop/src-tauri/binaries/git-credential-nostr- $TARGET "
2026-06-11 01:06:29 -07:00
touch "desktop/src-tauri/binaries/buzz- $TARGET "
2026-05-04 18:09:25 -06:00
pnpm install
2026-06-03 14:30:46 -04:00
cd {{ desktop_dir}} && pnpm tauri build --features mesh-llm --target {{ target}}
2026-04-20 12:52:39 -06:00
2026-03-09 13:02:11 -07:00
# Run desktop checks suitable for CI / pre-push
2026-05-28 08:17:02 -07:00
desktop-ci : desktop -check desktop -test desktop -tauri -fmt -check desktop -build desktop -tauri -check desktop -tauri -test
2026-03-09 13:02:11 -07:00
2026-03-09 19:16:43 -07:00
# Seed deterministic channel data for desktop Playwright tests
2026-05-29 18:26:24 -04:00
desktop-e2e-seed : _ensure -migrations
2026-03-09 19:16:43 -07:00
./scripts/setup-desktop-test-data.sh
# Run desktop browser smoke tests
desktop-e2e-smoke :
cd {{ desktop_dir}} && pnpm test:e2e:smoke
# Run desktop relay-backed e2e tests
2026-05-29 18:26:24 -04:00
desktop-e2e-integration : _ensure -migrations
2026-03-09 19:16:43 -07:00
cd {{ desktop_dir}} && pnpm test:e2e:integration
2026-08-13 15:49:40 -06:00
# Run the deterministic desktop correctness smoke against an isolated local relay
desktop-release-smoke :
./scripts/run-desktop-release-smoke.sh
2026-07-15 22:43:32 -06:00
# Run only the e2e specs changed vs origin/main (both projects) before pushing
desktop-e2e-pre-push : _ensure -migrations
git fetch origin main
2026-07-19 22:09:56 +02:00
cd {{ desktop_dir}} && pnpm build:e2e && pnpm exec playwright test --only-changed= origin/main
2026-07-15 22:43:32 -06:00
2026-03-09 15:15:25 -04:00
# Run all checks suitable for CI / pre-push (no infra needed)
2026-05-28 08:17:02 -07:00
ci : check test -unit desktop -test desktop -build desktop -tauri -check desktop -tauri -test web -build mobile -test
2026-03-09 15:15:25 -04:00
# ─── Test ─────────────────────────────────────────────────────────────────────
# Run all tests (unit + integration)
test :
./scripts/run-tests.sh all
# Run unit tests only (no infra needed)
test-unit :
2026-05-22 17:28:13 -04:00
#!/usr/bin/env bash
2026-08-02 14:39:27 -04:00
set -euo pipefail
2026-05-22 17:28:13 -04:00
if command -v cargo-nextest & >/dev/null; then
2026-06-10 19:29:51 -04:00
cargo nextest run -p buzz-core -p buzz-auth --lib
2026-07-31 09:41:09 -04:00
cargo nextest run -p buzz-voice --lib
2026-07-30 09:28:10 -04:00
cargo nextest run -p buzz-cli
2026-06-29 12:39:02 -04:00
# buzz-db migrator/lint tests: pure SQL-parsing unit tests (no infra).
# They guard the embedded-migrator invariant (exactly the consolidated
# 0001; cutover/backfill stays an operator script, not startup state)
# and the tenant-scoping lints. The Postgres-backed buzz-db tests are
# #[ignore]d, so --lib runs only the infra-free set. Without this gate a
# stray file in migrations/ or a broken lint ships green.
cargo nextest run -p buzz-db --lib
# Multi-tenant conformance gate (buzz-conformance): the independent
# replay checker + golden fixtures. No infra — pure in-process trace
# replay — so it belongs in the unit job. Run all targets (lib + the
# tests/replay_fixtures.rs integration test), not just --lib.
cargo nextest run -p buzz-conformance
2026-07-14 11:17:21 -04:00
# Gateway unit and black-box HTTP tests are infra-free. Postgres-backed
# contract/race tests run in the dedicated CI job below.
cargo nextest run -p buzz-push-gateway
2026-08-02 14:39:27 -04:00
# Kubernetes backend provider: the decision layers (state machine, GC
# planner, env precedence, naming, wire) are pure functions with a fake
# substrate, so they belong in the unit job. Enumerated explicitly
# because nothing in CI runs `cargo test --workspace` — workspace
# membership alone buys clippy/check, not a single executed test.
cargo nextest run -p buzz-backend-kubernetes
2026-08-17 11:23:28 -04:00
# buzz-agent model-capabilities corpus: the Rust half of the
# cross-language drift guard. `model_capabilities.rs` embeds
# scripts/model-capabilities.json + scripts/normative-corpus.json via
# include_str! and replays all 103 vectors as pure in-process tests (no
# infra). Enumerated explicitly because nothing in CI runs
# `cargo test --workspace`; without this step a manifest edit that
# diverges Rust from the corpus ships green.
cargo nextest run -p buzz-agent --lib
2026-05-22 17:28:13 -04:00
else
./scripts/run-tests.sh unit
fi
2026-03-09 15:15:25 -04:00
# Run integration tests only (starts services if needed)
test-integration :
./scripts/run-tests.sh integration
2026-08-17 11:23:28 -04:00
# Regenerate the model-capability normative corpus from the production Rust
# resolver. The corpus is a golden snapshot, never hand-edited: this runs the
# `#[ignore]`d writer test in buzz-agent, which serializes `resolve()` over the
# inputs-only question table to scripts/normative-corpus.json. Run this after
# any model-capabilities.json edit, then commit the regenerated file. The
# `corpus_matches_generated_snapshot` gate fails CI if the committed file drifts.
regen-model-corpus :
cargo test -p buzz-agent --lib model_capabilities::tests::regen_corpus_file -- --ignored --exact
2026-07-16 00:10:29 +10:00
# Buzz shared compute e2e: current desktop discovery/admission logic and
# Playwright UI coverage.
2026-06-18 17:24:05 -04:00
mesh-e2e :
2026-07-16 00:10:29 +10:00
cargo test --manifest-path {{ desktop_dir}} /src-tauri/Cargo.toml --features mesh-llm mesh_llm --lib
cd {{ desktop_dir}} && pnpm test:e2e:smoke -- mesh-compute.spec.ts
2026-06-18 17:24:05 -04:00
2026-07-16 00:10:29 +10:00
# Reset only development state, seed deterministic local channels, and launch
# the mesh-enabled desktop with the repository's public Tyler test identity.
# This is for local verification only; never point this identity at staging/prod.
[confirm( "This will reset development data, preserve installed Buzz, then launch a seeded mesh dev app. Continue? (y/N)" )]
mesh-dev-fresh :
#!/usr/bin/env bash
set -euo pipefail
./scripts/dev-reset.sh --yes
./scripts/setup-desktop-test-data.sh
export BUZZ_PRIVATE_KEY = "3dbaebadb5dfd777ff25149ee230d907a15a9e1294b40b830661e65bb42f6c03"
export BUZZ_REQUIRE_RELAY_MEMBERSHIP = true
export BUZZ_ALLOW_NIP_OA_AUTH = true
export RELAY_OWNER_PUBKEY = "e5ebc6cdb579be112e336cc319b5989b4bb6af11786ea90dbe52b5f08d741b34"
export BUZZ_RELAY_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000001"
export BUZZ_RECONCILE_CHANNELS = true
export BUZZ_RESET_WEBVIEW_STATE = 1
exec just mesh = 1 dev
# Real serve->client->inference on this machine (not CI).
2026-06-18 17:24:05 -04:00
mesh-e2e-hardware :
#!/usr/bin/env bash
set -euo pipefail
cargo run -p buzz-relay --example mesh_serve_client_smoke
2026-07-16 00:10:29 +10:00
# Three isolated node processes: trusted member joins and infers; stranger is rejected.
# Uses temp homes and explicit mesh owner keystores. Never reads the Buzz Keychain.
mesh-e2e-admission :
#!/usr/bin/env bash
set -euo pipefail
cargo run -p buzz-relay --example mesh_admission_smoke
# Full hardware confidence suite: routing, owner admission, and real agent inference.
mesh-e2e-confidence :
#!/usr/bin/env bash
set -euo pipefail
cargo build --release -p buzz-agent -p buzz-dev-mcp
cargo run -p buzz-relay --example mesh_serve_client_smoke
cargo run -p buzz-relay --example mesh_admission_smoke
cargo run -p buzz-relay --example mesh_agent_e2e
2026-06-18 17:24:05 -04:00
# Take desktop screenshots using the mock bridge
desktop-screenshot *ARGS :
#!/usr/bin/env bash
set -euo pipefail
2026-07-19 22:09:56 +02:00
pnpm -C {{ desktop_dir}} build:e2e
2026-06-18 17:24:05 -04:00
cd {{ desktop_dir}}
if ! curl -sf http://127.0.0.1:4173/ >/dev/null 2>& 1; then
python3 -m http.server 4173 -d dist >/dev/null 2>& 1 &
trap "kill $! 2>/dev/null || true" EXIT
for i in $( seq 1 20) ; do curl -sf http://127.0.0.1:4173/ >/dev/null && break; sleep 0.5; done
fi
node tests/helpers/screenshot.mjs {{ ARGS}}
2026-03-09 15:15:25 -04:00
# ─── Run ──────────────────────────────────────────────────────────────────────
2026-05-29 18:26:24 -04:00
# Start the relay server (auto-starts Docker services if needed)
2026-06-18 17:24:05 -04:00
relay : bootstrap _ensure -migrations
#!/usr/bin/env bash
set -euo pipefail
export PATH = "{{justfile_directory()}}/bin: $PATH "
2026-06-10 19:29:51 -04:00
cargo run -p buzz-relay
2026-03-09 15:15:25 -04:00
2026-05-05 13:20:13 -06:00
# Start the relay with the built web UI served from it
2026-06-18 17:24:05 -04:00
relay-web : bootstrap _ensure -migrations
2026-05-05 13:20:13 -06:00
#!/usr/bin/env bash
set -euo pipefail
2026-06-18 17:24:05 -04:00
export PATH = "{{justfile_directory()}}/bin: $PATH "
2026-05-05 13:20:13 -06:00
[[ -d node_modules ]] || pnpm install
pnpm -C web build
2026-06-10 19:29:51 -04:00
BUZZ_WEB_DIR = ./web/dist cargo run -p buzz-relay
2026-05-05 13:20:13 -06:00
2026-07-17 12:50:06 -07:00
# Build and run the private read-only admin dashboard
admin : bootstrap _ensure -migrations
#!/usr/bin/env bash
set -euo pipefail
export PATH = "{{justfile_directory()}}/bin: $PATH "
[[ -d node_modules ]] || pnpm install
pnpm -C admin-web build
export BUZZ_ADMIN_HOST = " ${ BUZZ_ADMIN_HOST :- admin .localhost: 3000 } "
export BUZZ_ADMIN_WEB_DIR = " ${ BUZZ_ADMIN_WEB_DIR :- {{justfile_directory() } }/admin-web/dist}"
echo "Admin dashboard: http:// ${ BUZZ_ADMIN_HOST } /reports"
cargo run -p buzz-relay
# Seed deterministic reports and product feedback for local admin dashboard review
admin-seed : _ensure -migrations
./scripts/seed-admin-dashboard.sh
# Run focused relay and browser checks for the read-only admin dashboard
admin-check : fmt -check
cargo check -p buzz-relay --all-targets
cargo test -p buzz-relay api::admin
cargo test -p buzz-relay router::tests
pnpm -C admin-web check
pnpm -C admin-web exec playwright test
2026-03-09 15:15:25 -04:00
# Start the relay server in release mode
2026-05-29 18:26:24 -04:00
relay-release : _ensure -migrations
2026-06-10 19:29:51 -04:00
cargo run -p buzz-relay --release
2026-03-09 15:15:25 -04:00
2026-03-12 22:16:00 -04:00
2026-06-18 17:24:05 -04:00
# Run the desktop Tauri app in dev mode with a local relay (ports and identity derived from worktree)
dev *ARGS : bootstrap _ensure -sidecar -stubs _ensure -migrations
2026-04-08 11:39:51 +10:00
#!/usr/bin/env bash
set -euo pipefail
2026-06-18 17:24:05 -04:00
export PATH = "{{justfile_directory()}}/bin: $PATH "
2026-06-29 12:39:02 -04:00
bind_addr = " ${ BUZZ_BIND_ADDR :- 0 .0.0.0: 3000 } "
relay_port = " ${ bind_addr ##*: } " ; [[ -n " $relay_port " ]] || relay_port = 3000
health_port = " ${ BUZZ_HEALTH_PORT :- 8080 } "
metrics_port = " ${ BUZZ_METRICS_PORT :- 9102 } "
if command -v lsof >/dev/null 2>& 1; then
for spec in "relay: $relay_port " "health: $health_port " "metrics: $metrics_port " ; do
name = " ${ spec %%:* } " ; port = " ${ spec ##*: } "
if lsof -nP -iTCP:" $port " -sTCP:LISTEN >/dev/null 2>& 1; then
echo "Error: $name port $port is already in use; refusing to launch desktop against a stale relay." >& 2
lsof -nP -iTCP:" $port " -sTCP:LISTEN >& 2 || true
echo "Stop the process above (often a stale buzz-relay) and rerun: just dev" >& 2
exit 1
fi
done
fi
2026-08-02 14:39:27 -04:00
cargo build -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr -p buzz-relay
2026-07-16 00:10:29 +10:00
# Docker Desktop's forwarded MinIO port can stall under the deployment
# probe's 32 concurrent writers. Keep the gate enabled in local dev, using
# the bounded profile already used by the relay test launcher.
export BUZZ_GIT_PROBE_WRITERS = " ${ BUZZ_GIT_PROBE_WRITERS :- 8 } "
export BUZZ_GIT_PROBE_ROUNDS = " ${ BUZZ_GIT_PROBE_ROUNDS :- 2 } "
2026-06-18 17:24:05 -04:00
./target/debug/buzz-relay &
RELAY_PID = $!
cleanup() {
[[ -n " ${ INSTANCE_ID :- } " ]] && ../scripts/cleanup-instance-agents.sh " $INSTANCE_ID " || true
kill " $RELAY_PID " 2>/dev/null || true
}
trap cleanup EXIT
2026-07-16 00:10:29 +10:00
relay_ready = false
for _ in $( seq 1 120) ; do
if ! kill -0 " $RELAY_PID " 2>/dev/null; then
echo "Error: buzz-relay exited during startup; refusing to launch desktop." >& 2
wait " $RELAY_PID " || true
exit 1
fi
if curl --silent --fail --max-time 1 "http://127.0.0.1: ${ health_port } /_readiness" >/dev/null; then
relay_ready = true
break
fi
sleep 0.5
done
if [[ " $relay_ready " != true ]] ; then
echo "Error: buzz-relay did not become healthy within 60 seconds; refusing to launch desktop." >& 2
exit 1
fi
2026-04-08 11:39:51 +10:00
cd {{ desktop_dir}}
[[ -d node_modules ]] || pnpm install
source ../scripts/instance-env.sh
2026-06-11 01:06:29 -07:00
INSTANCE_ID = $( node -e "console.log(JSON.parse(process.env.BUZZ_TAURI_CONFIG).identifier)" )
echo "Starting on Vite port ${ BUZZ_VITE_PORT } , relay ${ BUZZ_RELAY_URL } "
2026-06-22 15:11:50 -07:00
FEATURES =() ; [[ -n "{{mesh}}" ]] && FEATURES =( --features mesh-llm)
pnpm exec tauri dev ${ FEATURES [@]+ " ${ FEATURES [@] } " } --config " $BUZZ_TAURI_CONFIG " {{ ARGS}}
2026-03-09 13:02:11 -07:00
2026-07-15 23:01:51 -06:00
# Run only the desktop app. No relay, database, Docker, migrations, or .env are needed.
# The app opens normally and asks for a community before making a relay connection.
desktop-standalone *ARGS : _ensure -sidecar -stubs
#!/usr/bin/env bash
set -euo pipefail
export PATH = "{{justfile_directory()}}/bin: $PATH "
2026-08-02 14:39:27 -04:00
cargo build -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr
2026-07-15 23:01:51 -06:00
TARGET = $( rustc -vV | sed -n 's|host: ||p' )
TARGET_DIR = $( cargo metadata --format-version 1 --no-deps | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).target_directory" )
2026-08-02 14:39:27 -04:00
for bin in buzz-acp buzz-agent buzz-backend-kubernetes buzz-dev-mcp git-credential-nostr buzz; do
2026-07-15 23:01:51 -06:00
cp " ${ TARGET_DIR } /debug/ ${ bin } " "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
2026-07-17 14:19:29 -06:00
chmod +x "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
2026-07-15 23:01:51 -06:00
done
cd {{ desktop_dir}}
[[ -d node_modules ]] || pnpm install
unset BUZZ_PRIVATE_KEY BUZZ_SHARE_IDENTITY
2026-07-17 14:19:29 -06:00
if [[ -n "{{fresh}}" ]] ; then
export BUZZ_RESET_WEBVIEW_STATE = 1
fi
2026-07-15 23:01:51 -06:00
source ../scripts/instance-env.sh
INSTANCE_ID = $( node -e "console.log(JSON.parse(process.env.BUZZ_TAURI_CONFIG).identifier)" )
export BUZZ_DEV_KEYRING_SERVICE = "buzz-desktop-dev. ${ BUZZ_INSTANCE_SLUG :- main } "
2026-07-17 14:19:29 -06:00
if [[ -n "{{fresh}}" ]] ; then
../scripts/reset-desktop-standalone-state.sh " $INSTANCE_ID " " $BUZZ_DEV_KEYRING_SERVICE "
fi
2026-07-15 23:01:51 -06:00
trap '../scripts/cleanup-instance-agents.sh "$INSTANCE_ID" || true' EXIT
echo "Starting standalone desktop on Vite port ${ BUZZ_VITE_PORT } ; no relay services were started"
pnpm exec tauri dev --config " $BUZZ_TAURI_CONFIG " {{ ARGS}}
2026-04-07 12:03:14 -07:00
# Run the desktop app against the internal staging relay (installs deps + builds agent tools automatically)
2026-06-18 17:24:05 -04:00
staging *ARGS : bootstrap _ensure -sidecar -stubs
2026-04-15 10:49:00 -10:00
#!/usr/bin/env bash
set -euo pipefail
2026-06-18 17:24:05 -04:00
export PATH = "{{justfile_directory()}}/bin: $PATH "
pnpm install # unconditional: staging must always start with a clean dep tree
2026-08-02 14:39:27 -04:00
cargo build --release -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr
2026-06-22 15:11:50 -07:00
FEATURES =()
if [[ -n "{{mesh}}" ]] ; then
FEATURES =( --features mesh-llm)
fi
2026-08-02 16:17:55 -04:00
# Replace 0-byte sidecar stubs with real binaries so tauri dev picks them up.
# buzz: the CLI sidecar. buzz-backend-kubernetes: provider discovery scans the
# exe dir for executable buzz-backend-* files, so the non-executable stub that
# tauri dev copies next to the exe would hide the provider from "Run on".
2026-05-19 20:53:46 -04:00
TARGET = $( rustc -vV | sed -n 's|host: ||p' )
2026-07-10 14:42:32 +10:00
TARGET_DIR = $( cargo metadata --format-version 1 --no-deps | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).target_directory" )
2026-08-02 16:17:55 -04:00
STAGING_SIDECARS =( buzz)
if [[ " $TARGET " != *windows* ]] ; then
STAGING_SIDECARS +=( buzz-backend-kubernetes)
fi
for bin in " ${ STAGING_SIDECARS [@] } " ; do
cp " ${ TARGET_DIR } /release/ ${ bin } " "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
chmod +x "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
done
2026-04-15 10:49:00 -10:00
cd {{ desktop_dir}}
2026-06-11 01:06:29 -07:00
export BUZZ_RELAY_URL = "wss://sprout-oss.stage.blox.sqprod.co"
2026-06-18 17:24:05 -04:00
source ../scripts/instance-env.sh
2026-06-10 17:38:39 -04:00
# Ctrl+C kills the Tauri app before its in-process sweep finishes, leaking
# agent workers. Reap this instance's agents on exit as a backstop.
2026-06-11 01:06:29 -07:00
INSTANCE_ID = $( node -e "console.log(JSON.parse(process.env.BUZZ_TAURI_CONFIG).identifier)" )
2026-06-18 17:24:05 -04:00
trap '../scripts/cleanup-instance-agents.sh "$INSTANCE_ID" || true' EXIT
2026-06-11 01:06:29 -07:00
echo "Starting staging on Vite port ${ BUZZ_VITE_PORT } , relay ${ BUZZ_RELAY_URL } "
2026-06-22 15:11:50 -07:00
pnpm exec tauri dev ${ FEATURES [@]+ " ${ FEATURES [@] } " } --config " $BUZZ_TAURI_CONFIG " {{ ARGS}}
2026-04-07 12:03:14 -07:00
2026-07-23 13:48:52 -04:00
# Run the desktop app against the production relay (installs deps + builds agent tools automatically)
production *ARGS : bootstrap _ensure -sidecar -stubs
#!/usr/bin/env bash
set -euo pipefail
export PATH = "{{justfile_directory()}}/bin: $PATH "
pnpm install # unconditional: production must always start with a clean dep tree
2026-08-02 14:39:27 -04:00
cargo build --release -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr
2026-07-23 13:48:52 -04:00
FEATURES =()
if [[ -n "{{mesh}}" ]] ; then
FEATURES =( --features mesh-llm)
fi
2026-08-02 16:17:55 -04:00
# Replace 0-byte sidecar stubs with real binaries so tauri dev picks them up.
# buzz: the CLI sidecar. buzz-backend-kubernetes: provider discovery scans the
# exe dir for executable buzz-backend-* files, so the non-executable stub that
# tauri dev copies next to the exe would hide the provider from "Run on".
2026-07-23 13:48:52 -04:00
TARGET = $( rustc -vV | sed -n 's|host: ||p' )
TARGET_DIR = $( cargo metadata --format-version 1 --no-deps | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).target_directory" )
2026-08-02 16:17:55 -04:00
PRODUCTION_SIDECARS =( buzz)
if [[ " $TARGET " != *windows* ]] ; then
PRODUCTION_SIDECARS +=( buzz-backend-kubernetes)
fi
for bin in " ${ PRODUCTION_SIDECARS [@] } " ; do
cp " ${ TARGET_DIR } /release/ ${ bin } " "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
chmod +x "desktop/src-tauri/binaries/ ${ bin } - ${ TARGET } "
done
2026-07-23 13:48:52 -04:00
cd {{ desktop_dir}}
export BUZZ_RELAY_URL = "wss://buzz.block.builderlab.xyz"
source ../scripts/instance-env.sh
# Ctrl+C kills the Tauri app before its in-process sweep finishes, leaking
# agent workers. Reap this instance's agents on exit as a backstop.
INSTANCE_ID = $( node -e "console.log(JSON.parse(process.env.BUZZ_TAURI_CONFIG).identifier)" )
trap '../scripts/cleanup-instance-agents.sh "$INSTANCE_ID" || true' EXIT
echo "Starting production on Vite port ${ BUZZ_VITE_PORT } , relay ${ BUZZ_RELAY_URL } "
pnpm exec tauri dev ${ FEATURES [@]+ " ${ FEATURES [@] } " } --config " $BUZZ_TAURI_CONFIG " {{ ARGS}}
2026-04-08 11:39:51 +10:00
# Run the desktop frontend dev server (port derived from worktree)
2026-03-09 13:02:11 -07:00
desktop-dev :
2026-04-08 11:39:51 +10:00
#!/usr/bin/env bash
set -euo pipefail
cd {{ desktop_dir}}
[[ -d node_modules ]] || pnpm install
source ../scripts/instance-env.sh
2026-06-10 19:29:51 -04:00
echo "Starting frontend dev server on Vite port ${ BUZZ_VITE_PORT } , relay ${ BUZZ_RELAY_URL } "
pnpm exec vite --port " ${ BUZZ_VITE_PORT } " --strictPort
2026-03-09 13:02:11 -07:00
2026-05-04 13:49:48 -06:00
# ─── Web ─────────────────────────────────────────────────────────────────────
# Run the web frontend dev server (port derived from worktree to avoid collisions)
web :
#!/usr/bin/env bash
set -euo pipefail
[[ -d node_modules ]] || pnpm install
source scripts/instance-env.sh
2026-06-10 19:29:51 -04:00
export VITE_PORT = $(( BUZZ_VITE_PORT + 100 ))
export VITE_RELAY_URL = " ${ BUZZ_RELAY_URL } "
echo "Starting web dev server on port ${ VITE_PORT } , relay ${ BUZZ_RELAY_URL } "
2026-05-04 13:49:48 -06:00
cd {{ web_dir}}
pnpm exec vite --port " ${ VITE_PORT } " --strictPort
# Run web lint and format checks
web-check :
cd {{ web_dir}} && pnpm check
2026-05-28 17:42:35 -04:00
# Fix web lint and format issues
web-fix :
cd {{ web_dir}} && pnpm exec biome check --write . && pnpm check:file-sizes
2026-05-04 13:49:48 -06:00
# Run web TypeScript checks
web-typecheck :
cd {{ web_dir}} && pnpm typecheck
# Build web frontend assets
web-build :
cd {{ web_dir}} && pnpm build
# Run web browser smoke tests
web-e2e-smoke :
cd {{ web_dir}} && pnpm test:e2e:smoke
2026-04-13 09:55:14 -07:00
# ─── Mobile ──────────────────────────────────────────────────────────────────
mobile_dir := "mobile"
# Install mobile Flutter dependencies
mobile-install :
2026-04-21 07:48:15 -06:00
unset GIT_DIR GIT_WORK_TREE; cd {{ mobile_dir}} && flutter pub get
2026-04-13 09:55:14 -07:00
2026-05-26 18:05:42 -04:00
# Format all Dart code
mobile-fmt :
unset GIT_DIR GIT_WORK_TREE; cd {{ mobile_dir}} && dart format .
2026-05-28 17:42:35 -04:00
# Fix mobile formatting and run analysis
mobile-fix :
unset GIT_DIR GIT_WORK_TREE; cd {{ mobile_dir}} && dart format . && flutter analyze
2026-04-13 09:55:14 -07:00
# Run mobile lint and format checks
mobile-check :
2026-06-30 13:27:37 -06:00
unset GIT_DIR GIT_WORK_TREE; cd {{ mobile_dir}} && dart format --output= none --set-exit-if-changed . && flutter analyze && node ./scripts/check-file-sizes.mjs
2026-04-13 09:55:14 -07:00
# Run mobile tests
mobile-test :
2026-04-21 07:48:15 -06:00
unset GIT_DIR GIT_WORK_TREE; cd {{ mobile_dir}} && flutter test
2026-04-13 09:55:14 -07:00
2026-07-30 15:29:40 +01:00
# Regenerate the emoji dataset asset from desktop's emoji-mart install.
# Output is committed — rerun after bumping @emoji-mart/data.
mobile-emoji-data :
node {{ mobile_dir}} /scripts/generate-emoji-data.mjs
2026-07-26 13:47:35 -07:00
# Compile an unsigned Android debug APK (worktree-aware debug identity)
2026-07-14 14:59:34 -06:00
mobile-build-android :
2026-07-26 13:47:35 -07:00
./scripts/mobile-worktree-overrides.sh
2026-07-14 14:59:34 -06:00
unset GIT_DIR GIT_WORK_TREE; cd {{ mobile_dir}} && flutter build apk --debug --no-pub
2026-07-26 13:47:35 -07:00
# Run the mobile app on iOS simulator (worktree-aware debug identity)
2026-05-29 18:26:24 -04:00
mobile-dev :
#!/usr/bin/env bash
set -euo pipefail
if ! pgrep -x Simulator & >/dev/null; then
open -a Simulator
sleep 3
fi
2026-07-26 13:47:35 -07:00
./scripts/mobile-worktree-overrides.sh
2026-05-29 18:26:24 -04:00
cd {{ mobile_dir}}
unset GIT_DIR GIT_WORK_TREE
flutter run
2026-07-26 13:47:35 -07:00
# Uninstall stale worktree-suffixed Buzz debug installs (production apps kept)
mobile-clean :
./scripts/mobile-worktree-clean.sh
2026-03-09 15:15:25 -04:00
# ─── Database ─────────────────────────────────────────────────────────────────
2026-06-16 08:39:19 -04:00
# Apply database migrations
2026-06-18 17:24:05 -04:00
migrate : _ensure -migrations
2026-03-09 15:15:25 -04:00
# ─── Utilities ────────────────────────────────────────────────────────────────
# Remove build artifacts
clean :
cargo clean
2026-04-03 10:12:12 -07:00
cargo clean --manifest-path desktop/src-tauri/Cargo.toml
2026-03-09 15:15:25 -04:00
2026-03-09 13:02:11 -07:00
# Check the Rust workspace compiles without producing binaries
2026-03-09 15:15:25 -04:00
check-compile :
cargo check --workspace --all-targets
2026-03-14 18:19:42 -04:00
2026-05-27 19:25:09 -04:00
# ─── Release ─────────────────────────────────────────────────────────────────
# Read the current desktop version from package.json
get-current-version :
@node -p "require('./desktop/package.json').version"
2026-06-23 18:35:30 -04:00
# Read the current relay version from its crate manifest
get-current-relay-version :
@grep -m1 '^version = ' crates/buzz-relay/Cargo.toml | sed -E 's/version = "(.*)"/\1/'
2026-05-27 19:25:09 -04:00
# Compute next minor version (e.g., 0.3.0 → 0.4.0)
get-next-minor-version :
@python3 -c "v=' $( just get-current-version) '.split('.'); print(f'{v[0]}.{int(v[1])+1}.0')"
# Compute next patch version (e.g., 0.3.0 → 0.3.1)
get-next-patch-version :
@python3 -c "v=' $( just get-current-version) '.split('.'); print(f'{v[0]}.{v[1]}.{int(v[2])+1}')"
2026-06-23 18:35:30 -04:00
# Compute next relay patch version (e.g., 0.3.0 → 0.3.1)
get-next-relay-patch-version :
@python3 -c "v=' $( just get-current-relay-version) '.split('.'); print(f'{v[0]}.{v[1]}.{int(v[2])+1}')"
# Update version in desktop package manifests and regenerate lockfiles
bump-desktop-version version :
2026-05-27 19:25:09 -04:00
#!/usr/bin/env bash
set -euo pipefail
# desktop/package.json
cd desktop && npm pkg set "version={{ version }}" && cd ..
# desktop/src-tauri/tauri.conf.json
node -e "
const fs = require('fs');
const p = 'desktop/src-tauri/tauri.conf.json';
const c = JSON.parse(fs.readFileSync(p, 'utf8'));
c.version = '{{ version }}';
fs.writeFileSync(p, JSON.stringify(c, null, 2) + '\n');
"
2026-05-28 09:10:28 -07:00
# JSON.stringify expands arrays/objects in a way biome rejects; reformat to match.
( cd desktop && pnpm exec biome format --write src-tauri/tauri.conf.json)
2026-05-27 19:25:09 -04:00
# desktop/src-tauri/Cargo.toml — only first version line (under [package])
node -e "
const fs = require('fs');
const p = 'desktop/src-tauri/Cargo.toml';
let t = fs.readFileSync(p, 'utf8');
t = t.replace(/^version = \".*\"/m, 'version = \"{{ version }}\"');
fs.writeFileSync(p, t);
"
# Regenerate lockfiles
pnpm install --lockfile-only
2026-06-10 19:29:51 -04:00
cargo update -p buzz-desktop --manifest-path desktop/src-tauri/Cargo.toml
2026-06-23 18:35:30 -04:00
echo "Bumped desktop manifests to {{ version }} and regenerated lockfiles"
2026-05-27 19:25:09 -04:00
2026-06-23 18:35:30 -04:00
# Bump the relay crate version and regenerate the lockfile
bump-relay-version version :
#!/usr/bin/env bash
set -euo pipefail
# buzz-relay carries its own `version =` (not version.workspace), so the
# replace targets the package version line only.
perl -i -pe 's/^version = ".*"/version = "{{ version }}"/' crates/buzz-relay/Cargo.toml
cargo update -p buzz-relay
echo "Bumped buzz-relay to {{ version }} and regenerated Cargo.lock"
2026-07-30 12:27:56 -06:00
# Open or update the desktop release PR from an immutable origin/main snapshot
2026-06-23 18:35:30 -04:00
release-desktop *ARGS :
2026-05-27 19:25:09 -04:00
#!/usr/bin/env bash
set -euo pipefail
ARG = "{{ ARGS }}"
2026-06-23 18:35:30 -04:00
if [[ -z " $ARG " || " $ARG " == "patch" ]] ; then
2026-05-27 19:25:09 -04:00
VERSION = $( just get-next-patch-version)
else
VERSION = " $ARG "
fi
2026-07-30 12:27:56 -06:00
scripts/prepare-desktop-release.sh " $VERSION "
2026-06-23 18:35:30 -04:00
# Open or update the relay release PR (ghcr.io/block/buzz image)
release-relay *ARGS :
#!/usr/bin/env bash
set -euo pipefail
ARG = "{{ ARGS }}"
if [[ -z " $ARG " || " $ARG " == "patch" ]] ; then
VERSION = $( just get-next-relay-patch-version)
else
VERSION = " $ARG "
fi
just _release-pr relay " $VERSION "
2026-07-23 15:05:59 -07:00
# Shared release-PR engine for desktop and relay. Mobile publishes immutable
# candidate tags directly from remote main instead of using metadata-only PRs.
2026-06-23 18:35:30 -04:00
_release-pr lane version :
#!/usr/bin/env bash
set -euo pipefail
VERSION = "{{ version }}"
if ! echo " $VERSION " | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$' ; then
echo "Error: ' $VERSION ' is not valid semver (expected X.Y.Z)"
exit 1
fi
# Lane-specific identifiers. The bump command runs after the branch switch.
case "{{ lane }}" in
desktop)
BRANCH_PREFIX = "version-bump"
TAG_FETCH = 'v*'
TAG_MATCH = 'v[0-9]*'
TAG_EXCLUDE = '*-*'
TAG_PREFIX = "v"
CHANGELOG = "CHANGELOG.md"
ADD_FILES =( desktop/package.json desktop/src-tauri/tauri.conf.json desktop/src-tauri/Cargo.toml desktop/src-tauri/Cargo.lock pnpm-lock.yaml CHANGELOG.md)
2026-07-10 15:55:01 -04:00
LOG_PATHS =( desktop/ crates/buzz-core/ crates/buzz-persona/ crates/buzz-sdk/ crates/buzz-agent/)
2026-06-23 18:35:30 -04:00
ARTIFACT = "Buzz Desktop" ;;
relay)
BRANCH_PREFIX = "relay-release"
TAG_FETCH = 'relay-v*'
TAG_MATCH = 'relay-v[0-9]*'
TAG_EXCLUDE = 'relay-v*-*'
TAG_PREFIX = "relay-v"
CHANGELOG = "crates/buzz-relay/CHANGELOG.md"
ADD_FILES =( crates/buzz-relay/Cargo.toml Cargo.lock crates/buzz-relay/CHANGELOG.md)
2026-07-10 15:55:01 -04:00
LOG_PATHS =( crates/buzz-relay/ crates/buzz-core/ crates/buzz-db/ crates/buzz-auth/ crates/buzz-pubsub/ crates/buzz-search/ crates/buzz-audit/ crates/buzz-media/ crates/buzz-sdk/ crates/buzz-workflow/ crates/buzz-conformance/ migrations/)
2026-06-23 18:35:30 -04:00
ARTIFACT = "Buzz Relay" ;;
*)
echo "Error: unknown release lane '{{ lane }}'"
exit 1 ;;
esac
echo "Preparing ${ ARTIFACT } release v ${ VERSION } ..."
# Must run on main with a clean, up-to-date tree.
2026-05-27 19:25:09 -04:00
CURRENT_BRANCH = $( git symbolic-ref --short HEAD)
if [[ " $CURRENT_BRANCH " != "main" ]] ; then
echo "Error: must be on main branch (currently on ' $CURRENT_BRANCH ')"
exit 1
fi
2026-05-28 16:29:25 -07:00
git fetch origin refs/heads/main:refs/remotes/origin/main --no-tags
2026-06-23 18:35:30 -04:00
# Release tags are remote-owned state; sync only this lane's tags so stale
# local tags from older histories do not make release preflight fail.
git fetch origin "+refs/tags/ ${ TAG_FETCH } :refs/tags/ ${ TAG_FETCH } "
2026-05-27 19:25:09 -04:00
if [[ " $( git rev-parse HEAD) " != " $( git rev-parse origin/main) " ]] ; then
echo "Error: local main is not up-to-date with origin/main. Run 'git pull' first."
exit 1
fi
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "Error: working tree is dirty. Commit or stash changes first."
exit 1
fi
2026-06-23 18:35:30 -04:00
# Switch to the release branch (create, or reset to main if it exists).
BRANCH = " ${ BRANCH_PREFIX } / ${ VERSION } "
2026-06-10 12:50:18 -04:00
if git rev-parse --verify "refs/heads/ $BRANCH " >/dev/null 2>& 1; then
echo "Branch ' $BRANCH ' already exists — resetting to origin/main..."
git switch " $BRANCH "
git reset --hard origin/main
elif git ls-remote --exit-code --heads origin " $BRANCH " >/dev/null 2>& 1; then
echo "Branch ' $BRANCH ' exists on remote — checking out and resetting to origin/main..."
git switch -c " $BRANCH " --track "origin/ $BRANCH "
git reset --hard origin/main
else
git switch -c " $BRANCH "
fi
2026-06-23 18:35:30 -04:00
# Lane-specific bump (the one diverging step).
case "{{ lane }}" in
desktop) just bump-desktop-version " $VERSION " ;;
relay) just bump-relay-version " $VERSION " ;;
esac
# Generate the changelog from commits since this lane's last release tag.
LAST_TAG = $( git describe --tags --abbrev= 0 --match " $TAG_MATCH " --exclude " $TAG_EXCLUDE " 2>/dev/null || echo "" )
2026-06-16 18:44:12 -04:00
REPO = $( git remote get-url origin | sed -E 's|.*github\.com[:/]||; s|\.git$||' )
format_log() {
local range = " $1 "
2026-07-10 15:55:01 -04:00
git log " $range " --format= "%h %H %s" --no-merges -- " ${ LOG_PATHS [@] } " | while IFS = ' ' read -r short full rest; do
2026-06-16 18:44:12 -04:00
local pr subject
2026-06-18 21:28:56 -04:00
pr = $( printf '%s' " $rest " | grep -oE '\(#[0-9]+\)$' | grep -oE '[0-9]+' || true )
2026-06-16 18:44:12 -04:00
if [[ -n " $pr " ]] ; then
subject = $( printf '%s' " $rest " | sed -E 's/ \(#[0-9]+\)$//' )
printf -- '- %s ([#%s](https://github.com/%s/pull/%s)) ([`%s`](https://github.com/%s/commit/%s))\n' \
" $subject " " $pr " " $REPO " " $pr " " $short " " $REPO " " $full "
else
printf -- '- %s ([`%s`](https://github.com/%s/commit/%s))\n' \
" $rest " " $short " " $REPO " " $full "
fi
done
}
2026-05-27 19:25:09 -04:00
TMPFILE = $( mktemp)
{
echo "# Changelog"
echo ""
2026-06-23 18:35:30 -04:00
echo "## ${ TAG_PREFIX }${ VERSION } "
2026-05-27 19:25:09 -04:00
echo ""
if [[ -n " $LAST_TAG " ]] ; then
2026-06-16 18:44:12 -04:00
format_log " ${ LAST_TAG } ..HEAD"
2026-05-27 19:25:09 -04:00
else
2026-06-16 18:44:12 -04:00
echo "- Initial release"
2026-05-27 19:25:09 -04:00
fi
echo ""
2026-06-23 18:35:30 -04:00
if [[ -f " $CHANGELOG " ]] ; then
tail -n +2 " $CHANGELOG "
2026-05-27 19:25:09 -04:00
fi
} > " $TMPFILE "
2026-06-23 18:35:30 -04:00
mkdir -p " $( dirname " $CHANGELOG " ) "
mv " $TMPFILE " " $CHANGELOG "
# Commit.
git add " ${ ADD_FILES [@] } "
RELEASE_MSG = "chore(release): release ${ ARTIFACT } version ${ VERSION } "
2026-06-10 12:50:18 -04:00
if [[ " $( git log -1 --format= '%s' 2>/dev/null) " == " $RELEASE_MSG " ]] ; then
git commit --amend --no-edit
else
git commit -m " $RELEASE_MSG "
fi
2026-06-23 18:35:30 -04:00
# Push and open/update the PR.
2026-06-10 12:50:18 -04:00
git push --force-with-lease -u origin " $BRANCH "
2026-06-23 18:35:30 -04:00
PR_BODY = "## ${ ARTIFACT } release v ${ VERSION } " $'\n\n'
2026-05-27 19:25:09 -04:00
if [[ -n " $LAST_TAG " ]] ; then
PR_BODY += "### Changes since ${ LAST_TAG } :" $'\n\n'
2026-07-10 15:41:23 -04:00
CHANGELOG_BODY = $( format_log " ${ LAST_TAG } ..HEAD~1" )
MAX_LOG = 62000
if (( ${# CHANGELOG_BODY } > MAX_LOG )) ; then
TRUNCATED = $( printf '%s' " $CHANGELOG_BODY " | awk -v max = " $MAX_LOG " \
'BEGIN{n=0} {line_len=length($0)+1; if(n+line_len>max) exit; n+=line_len; print}' )
SHOWN = $( printf '%s\n' " $TRUNCATED " | grep -c '^-' || true )
TOTAL = $( printf '%s\n' " $CHANGELOG_BODY " | grep -c '^-' || true )
SKIPPED = $(( TOTAL - SHOWN ))
CHANGELOG_BODY = " ${ TRUNCATED } " $'\n' "_… and ${ SKIPPED } more commits — [compare ${ LAST_TAG } … ${ TAG_PREFIX }${ VERSION } ](https://github.com/ ${ REPO } /compare/ ${ LAST_TAG } ... ${ TAG_PREFIX }${ VERSION } )_"
fi
PR_BODY += " ${ CHANGELOG_BODY } " $'\n\n'
2026-05-27 19:25:09 -04:00
else
PR_BODY += "Initial release." $'\n\n'
fi
PR_BODY += "**To release:** merge this PR. The tag and build will happen automatically."
2026-06-23 18:35:30 -04:00
PR_TITLE = "chore(release): release ${ ARTIFACT } version ${ VERSION } "
2026-06-10 12:50:18 -04:00
EXISTING_PR = $( gh pr list --head " $BRANCH " --json url --jq '.[0].url' 2>/dev/null || true )
if [[ -n " $EXISTING_PR " ]] ; then
2026-06-23 18:35:30 -04:00
gh pr edit " $BRANCH " --title " $PR_TITLE " --body " $PR_BODY "
2026-06-10 12:50:18 -04:00
PR_URL = " $EXISTING_PR "
echo ""
echo "Updated existing release PR: ${ PR_URL } "
else
2026-06-23 18:35:30 -04:00
PR_URL = $( gh pr create --title " $PR_TITLE " --body " $PR_BODY " )
2026-06-10 12:50:18 -04:00
echo ""
echo "Release PR opened: ${ PR_URL } "
fi
2026-05-27 19:25:09 -04:00
echo "Merge it to trigger the release build."
2026-03-14 18:19:42 -04:00
# ─── Agent Harness ────────────────────────────────────────────────────────────
2026-06-10 19:29:51 -04:00
# Run a goose agent connected to a Buzz relay (foreground)
goose relay="ws : //localhost :3000" agents ="1" heartbeat ="0" prompt ="" key ="$BUZZ_PRIVATE_KEY ":
2026-03-14 18:19:42 -04:00
#!/usr/bin/env bash
set -euo pipefail
2026-06-18 17:24:05 -04:00
export PATH = "{{justfile_directory()}}/bin: $PATH "
source ./scripts/_goose-env.sh "{{relay}}" "{{key}}" "{{agents}}" "{{heartbeat}}" "{{prompt}}"
2026-06-10 19:29:51 -04:00
exec env " ${ env_args [@] } " ./target/release/buzz-acp
2026-03-14 18:19:42 -04:00
# Run a goose agent in the background (screen session named 'goose-agent-N')
2026-06-10 19:29:51 -04:00
goose-bg relay="ws : //localhost :3000" agents ="1" heartbeat ="0" prompt ="" key ="$BUZZ_PRIVATE_KEY ":
2026-03-14 18:19:42 -04:00
#!/usr/bin/env bash
set -euo pipefail
2026-06-18 17:24:05 -04:00
export PATH = "{{justfile_directory()}}/bin: $PATH "
source ./scripts/_goose-env.sh "{{relay}}" "{{key}}" "{{agents}}" "{{heartbeat}}" "{{prompt}}"
2026-06-10 19:29:51 -04:00
screen -dmS goose-agent-{{ agents}} bash -c " $( printf '%q ' env " ${ env_args [@] } " ) ./target/release/buzz-acp"
2026-03-14 18:19:42 -04:00
echo "Agent running in screen session 'goose-agent-{{agents}}'. Attach with: screen -r goose-agent-{{agents}}"
2026-07-08 11:32:11 -04:00
# ─── Benchmarking ─────────────────────────────────────────────────────────────
# Run the Buzz orchestra benchmark — leaderboard-eligible by default (TB 2.1, k=5, Sonnet+Haiku). Stands up its own Docker stack; --gui opens a live spectator desktop app; other flags pass to benchmark.py (--dataset/--path, --include-task, --attempts, --manifest, --dry-run, ...)
benchmark *ARGS :
#!/usr/bin/env bash
set -euo pipefail
export PATH = "{{justfile_directory()}}/bin: $PATH "
uv run --project benchmarks/harbor-buzz-orchestra/testbed \
benchmarks/harbor-buzz-orchestra/scripts/benchmark.py {{ ARGS}}
# Stop the benchmark Docker stack (state and channels are kept)
benchmark-down :
docker compose --project-name buzz-benchmark down