diff --git a/.env.example b/.env.example index db5a7ea25c7..c906b314b8b 100644 --- a/.env.example +++ b/.env.example @@ -34,6 +34,10 @@ REDIS_URL=redis://localhost:6379 # Max connections in the relay's shared Redis pool (default 16). # BUZZ_REDIS_POOL_SIZE=16 +# Max connections in each of the relay's Postgres pools — writer and, when +# READ_DATABASE_URL is set, reader (default 50). +# BUZZ_DB_POOL_SIZE=50 + # ----------------------------------------------------------------------------- # Typesense (search) # ----------------------------------------------------------------------------- @@ -50,6 +54,11 @@ 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. # BUZZ_RELAY_PRIVATE_KEY=<32-byte hex private key> +# COS follow-up authority. When set, this must be the exact 64-character +# lowercase-hex public key derived from the Estate bridge's protected +# BUZZ_PRIVATE_KEY. Unset disables the feature; blank/malformed values abort +# relay startup. The relay advertises the accepted key in NIP-11 `cos_follow_up`. +# BUZZ_COS_FOLLOW_UP_BRIDGE_PUBKEY=<64-lowercase-hex-public-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). @@ -105,7 +114,10 @@ RELAY_URL=ws://localhost:3000 # ----------------------------------------------------------------------------- # Logging / Tracing # ----------------------------------------------------------------------------- -RUST_LOG=buzz_relay=debug,buzz_db=debug,buzz_auth=debug,buzz_pubsub=debug,tower_http=debug +RUST_LOG=buzz_relay=debug,buzz_datastore=info,buzz_db=debug,buzz_auth=debug,buzz_pubsub=debug,tower_http=debug +# Optional OpenTelemetry-only target filter. This is deliberately independent +# from RUST_LOG so log verbosity changes cannot break trace parentage. +# BUZZ_OTEL_FILTER=buzz_relay=info,buzz_datastore=info # OTLP tracing endpoint (optional — leave unset to disable) # OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..f36b1615d06 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +# Git for Windows defaults to core.autocrlf=true, so without this every text +# file lands in the working copy with CRLF. Biome formats with LF +# (biome.json sets no lineEnding override), which fails `biome check` on +# effectively every file, and +# desktop/src/features/messages/ui/virtuaWheelModePatch.test.mjs asserts on +# patches/*.patch with `\n`-joined patterns. Normalize to LF in the working +# copy on every platform; the stored blobs are already LF. +* text=auto eol=lf diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 325a485102a..238878c7493 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,4 +5,4 @@ ### Testing - + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad7f77f6bfe..322da7eb277 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,9 @@ jobs: - 'rust-toolchain.toml' - 'deny.toml' - '.github/workflows/ci.yml' + - '.github/workflows/docker.yml' - 'scripts/run-tests.sh' + - 'scripts/test-docker-tag-matrix.sh' - 'justfile' desktop: - 'desktop/**' @@ -59,10 +61,13 @@ jobs: mobile: - 'mobile/**' - 'scripts/mobile-release.sh' + - 'scripts/mobile-worktree-overrides.sh' + - 'scripts/mobile-worktree-clean.sh' - 'scripts/publish-mobile-release-candidate.sh' - 'scripts/release-rulesets.sh' - 'scripts/test-mobile-release-contract.sh' - 'scripts/test-mobile-release-candidate-publisher.sh' + - 'scripts/test-mobile-worktree-overrides.sh' - '.github/workflows/mobile-release-candidate.yml' - '.github/workflows/ci.yml' - name: Release workflow source contract @@ -71,6 +76,10 @@ jobs: run: | scripts/test-mobile-release-contract.sh scripts/test-mobile-release-candidate-publisher.sh + - name: Mobile worktree identity contract + run: scripts/test-mobile-worktree-overrides.sh + - name: Docker tag matrix contract + run: scripts/test-docker-tag-matrix.sh rust-lint: name: Rust Lint @@ -335,6 +344,7 @@ jobs: cargo build --profile ci -p buzz-relay -p git-credential-nostr cargo nextest archive \ --cargo-profile ci \ + -p buzz-db \ -p buzz-relay \ -p buzz-test-client \ --lib \ @@ -666,11 +676,11 @@ jobs: done cat /tmp/buzz-relay.log exit 1 - - name: Invite claim security tests + - name: Invite security tests run: | cargo nextest run \ --archive-file target/ci/backend-integration-tests.tar.zst \ - -E 'package(buzz-relay) and test(claim_)' \ + -E '(package(buzz-db) and test(/relay_invite::tests/)) or (package(buzz-relay) and test(/api::invites::tests/))' \ --run-ignored ignored-only env: DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz @@ -1010,16 +1020,20 @@ jobs: touch "desktop/src-tauri/binaries/buzz-dev-mcp-$TARGET" touch "desktop/src-tauri/binaries/git-credential-nostr-$TARGET" touch "desktop/src-tauri/binaries/buzz-$TARGET" - # Mesh rev is derived from Cargo.lock so a dependency bump needs no - # lockstep edit here; the cache key tracks it automatically. + # Resolve the exact desktop Mesh dependency so the native cache and build + # always use the same checkout, even when the root lockfile contains + # another mesh-llm-sdk version. - name: Resolve mesh-llm rev id: mesh_rev run: | set -euo pipefail - REV=$(python3 -c 'import tomllib; d=tomllib.load(open("Cargo.lock", "rb")); p=next(p for p in d["package"] if p["name"] == "mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])') - [[ -n "$REV" ]] || { echo "::error::could not resolve mesh-llm rev from Cargo.lock"; exit 1; } + metadata=$(cargo metadata --manifest-path desktop/src-tauri/Cargo.toml --features mesh-llm --format-version 1) + REV=$(python3 -c 'import json,sys; data=json.load(sys.stdin); p=next(p for p in data["packages"] if p["name"]=="mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])' <<<"$metadata") + SDK_MANIFEST=$(python3 -c 'import json,sys; data=json.load(sys.stdin); print(next(p["manifest_path"] for p in data["packages"] if p["name"]=="mesh-llm-sdk"))' <<<"$metadata") + MESH_ROOT=$(cd "$(dirname "$SDK_MANIFEST")/../.." && pwd) + [[ -n "$REV" ]] || { echo "::error::could not resolve desktop mesh-llm rev from Cargo metadata"; exit 1; } echo "rev=$REV" >> "$GITHUB_OUTPUT" - echo "short=${REV:0:7}" >> "$GITHUB_OUTPUT" + echo "root=$MESH_ROOT" >> "$GITHUB_OUTPUT" - name: Restore mesh llama build cache id: llama_cache uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 @@ -1029,16 +1043,13 @@ jobs: - name: Build mesh llama native libraries if: steps.llama_cache.outputs.cache-hit != 'true' env: - MESH_REV_SHORT: ${{ steps.mesh_rev.outputs.short }} + MESH_ROOT: ${{ steps.mesh_rev.outputs.root }} run: | set -euo pipefail - cargo fetch --manifest-path desktop/src-tauri/Cargo.toml - SHORT="$MESH_REV_SHORT" - MESH_ROOT=$(find "${CARGO_HOME:-$HOME/.cargo}/git/checkouts" -path "*/$SHORT" -type d -name "$SHORT" | head -1) - if [[ -z "$MESH_ROOT" ]]; then - echo "::error::mesh-llm checkout for $SHORT not found after cargo fetch" + [[ -x "$MESH_ROOT/scripts/prepare-llama.sh" && -x "$MESH_ROOT/scripts/build-llama.sh" ]] || { + echo "::error::mesh-llm build scripts not found under resolved checkout $MESH_ROOT" exit 1 - fi + } export LLAMA_STAGE_BACKEND=metal export LLAMA_STAGE_BUILD_DIR="$GITHUB_WORKSPACE/.cache/mesh-llama/build-stage-abi-metal" export CMAKE_OSX_DEPLOYMENT_TARGET=10.15 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 31080652eaf..967acce1880 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,6 +1,8 @@ name: Docker image -# Builds and publishes the public Buzz relay image as ghcr.io/block/buzz. +# Builds and publishes the MAC Workspace relay image as ghcr.io/marccopson/buzz. +# Normal tags contain stripped binaries; matching debug-* tags contain the same +# optimized binaries with line-table debug information for native profilers. # # Strategy: each architecture builds on its native runner (ubuntu-24.04 for # amd64, ubuntu-24.04-arm for arm64), pushes to GHCR by digest, then a final @@ -14,9 +16,11 @@ name: Docker image # the relay image version tracks crates/buzz-relay/Cargo.toml, never desktop. # # Triggers: -# - push to main → :main + :sha-<7> +# - push to main or mac → : + :sha-<40> +# + :debug- + :debug-sha-<40> # - push tags relay-v*.*.* → :{version} + :{major}.{minor} + :{major} -# (+ :latest for stable, NOT for prereleases) +# + matching :debug-* tags +# (+ :latest/:debug-latest for stable releases) # - pull_request → build only (no push), cache stays warm # - workflow_dispatch → manual relay-tag rescue at the tag itself # @@ -37,7 +41,7 @@ name: Docker image on: push: - branches: [main] + branches: [main, mac] tags: ["relay-v[0-9]*"] pull_request: paths: @@ -72,7 +76,7 @@ env: # Single source of truth for the image name. Set GHCR_IMAGE as a repo # variable to override (e.g., for forks that want to push to their own # namespace without forking this file). - IMAGE_NAME: ${{ vars.GHCR_IMAGE != '' && vars.GHCR_IMAGE || 'ghcr.io/block/buzz' }} + IMAGE_NAME: ${{ vars.GHCR_IMAGE != '' && vars.GHCR_IMAGE || 'ghcr.io/marccopson/buzz' }} jobs: build: @@ -95,10 +99,6 @@ jobs: runner: ubuntu-24.04-arm arch: arm64 - outputs: - # Used downstream by `merge` to stitch the manifest. - version: ${{ steps.meta.outputs.version }} - steps: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 @@ -154,7 +154,7 @@ jobs: # prereleases, not main pushes). tags: | type=ref,event=branch,enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }} - type=sha,prefix=sha-,format=short,enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }} + type=raw,value=sha-${{ github.sha }},enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }} type=semver,pattern={{version}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}}.{{minor}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}},match=^relay-v(.*)$,value=${{ inputs.version }} @@ -163,12 +163,13 @@ jobs: org.opencontainers.image.description=WebSocket relay server for the Buzz communications platform org.opencontainers.image.licenses=Apache-2.0 - - name: Build and push by digest - id: build + - name: Build and push release image by digest + id: build-release uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . file: ./Dockerfile + target: runtime platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} # Push by digest, not by tag — the merge job assembles the tags @@ -178,27 +179,51 @@ jobs: cache-from: | type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }} cache-to: | - ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref={0}-buildcache:{1},mode=max,compression=zstd', env.IMAGE_NAME, matrix.arch) || '' }} + ${{ github.event_name != 'pull_request' && format('type=registry,ref={0}-buildcache:{1},mode=max,compression=zstd', env.IMAGE_NAME, matrix.arch) || '' }} - - name: Export digest + - name: Build and push debug image by digest + id: build-debug + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 + with: + context: . + file: ./Dockerfile + target: runtime-debug + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + cache-from: | + type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }} + + - name: Export release and debug digests if: github.event_name != 'pull_request' env: - DIGEST: ${{ steps.build.outputs.digest }} + RELEASE_DIGEST: ${{ steps.build-release.outputs.digest }} + DEBUG_DIGEST: ${{ steps.build-debug.outputs.digest }} run: | - mkdir -p /tmp/digests - touch "/tmp/digests/${DIGEST#sha256:}" + mkdir -p /tmp/digests-release /tmp/digests-debug + touch "/tmp/digests-release/${RELEASE_DIGEST#sha256:}" + touch "/tmp/digests-debug/${DEBUG_DIGEST#sha256:}" - - name: Upload digest + - name: Upload release digest if: github.event_name != 'pull_request' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: digests-${{ matrix.arch }} - path: /tmp/digests/* + name: digests-release-${{ matrix.arch }} + path: /tmp/digests-release/* + if-no-files-found: error + retention-days: 1 + + - name: Upload debug digest + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: digests-debug-${{ matrix.arch }} + path: /tmp/digests-debug/* if-no-files-found: error retention-days: 1 merge: - name: Merge multi-arch manifest + name: Merge ${{ matrix.variant }} multi-arch manifest if: github.event_name != 'pull_request' runs-on: ubuntu-24.04 needs: build @@ -208,13 +233,21 @@ jobs: packages: write # push the merged manifest id-token: write # OIDC for provenance attestation on the manifest attestations: write + strategy: + fail-fast: false + matrix: + include: + - variant: release + tag_prefix: "" + - variant: debug + tag_prefix: debug- steps: - name: Download all per-arch digests uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: /tmp/digests - pattern: digests-* + pattern: digests-${{ matrix.variant }}-* merge-multiple: true - name: Set up Docker Buildx @@ -237,13 +270,32 @@ jobs: # the build job's `meta` step for why match=^relay-v(.*)$, why # value=${{ inputs.version }} carries the rescue-dispatch version, # and why :latest is left to flavor.latest=auto. + flavor: | + latest=auto + prefix=${{ matrix.tag_prefix }},onlatest=true tags: | type=ref,event=branch,enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }} - type=sha,prefix=sha-,format=short,enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }} + type=raw,value=sha-${{ github.sha }},enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }} type=semver,pattern={{version}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}}.{{minor}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}},match=^relay-v(.*)$,value=${{ inputs.version }} + - name: Verify debug branch tag matrix + if: matrix.variant == 'debug' && github.ref_type == 'branch' + env: + IMAGE_NAME: ${{ env.IMAGE_NAME }} + META_TAGS: ${{ steps.meta.outputs.tags }} + run: | + set -euo pipefail + expected_branch="${IMAGE_NAME}:debug-${GITHUB_REF_NAME}" + expected_sha="${IMAGE_NAME}:debug-sha-${GITHUB_SHA}" + grep -Fxq "$expected_branch" <<< "$META_TAGS" + grep -Fxq "$expected_sha" <<< "$META_TAGS" + if grep -Fq "${IMAGE_NAME}:debug-debug-" <<< "$META_TAGS"; then + echo "debug tag prefix was applied twice" >&2 + exit 1 + fi + - name: Create and push manifest list id: manifest working-directory: /tmp/digests @@ -274,7 +326,7 @@ jobs: - name: Attest provenance for the merged image # Sigstore-signed in-toto attestation, verifiable with: - # gh attestation verify oci://ghcr.io/block/buzz: --owner block + # gh attestation verify oci://: --owner uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 with: subject-name: ${{ env.IMAGE_NAME }} @@ -284,11 +336,12 @@ jobs: - name: Summary env: IMAGE_NAME: ${{ env.IMAGE_NAME }} + VARIANT: ${{ matrix.variant }} MERGED_DIGEST: ${{ steps.manifest.outputs.digest }} META_TAGS: ${{ steps.meta.outputs.tags }} run: | { - echo "### Published \`${IMAGE_NAME}\`" + echo "### Published \`${IMAGE_NAME}\` (${VARIANT})" echo echo "**Digest:** \`${MERGED_DIGEST}\`" echo @@ -299,12 +352,13 @@ jobs: echo echo "Verify provenance:" echo '```' - echo "gh attestation verify oci://${IMAGE_NAME}@${MERGED_DIGEST} --owner block" + echo "gh attestation verify oci://${IMAGE_NAME}@${MERGED_DIGEST} --owner ${GITHUB_REPOSITORY_OWNER}" echo '```' } >> "$GITHUB_STEP_SUMMARY" push-gateway-build: name: Build public push gateway (${{ matrix.platform }}) + if: github.repository == 'block/buzz' runs-on: ${{ matrix.runner }} timeout-minutes: 60 permissions: @@ -365,7 +419,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} outputs: type=image,name=ghcr.io/block/buzz-push-gateway,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} cache-from: type=registry,ref=ghcr.io/block/buzz-push-gateway-buildcache:${{ matrix.arch }} - cache-to: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref=ghcr.io/block/buzz-push-gateway-buildcache:{0},mode=max,compression=zstd', matrix.arch) || '' }} + cache-to: ${{ github.event_name != 'pull_request' && format('type=registry,ref=ghcr.io/block/buzz-push-gateway-buildcache:{0},mode=max,compression=zstd', matrix.arch) || '' }} - name: Export digest if: github.event_name != 'pull_request' env: @@ -382,7 +436,7 @@ jobs: push-gateway-merge: name: Publish public push gateway image - if: github.event_name != 'pull_request' + if: github.repository == 'block/buzz' && github.event_name != 'pull_request' runs-on: ubuntu-24.04 needs: push-gateway-build timeout-minutes: 15 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c613924e574..c9578d9c574 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -137,15 +137,19 @@ jobs: cargo build --release -p buzz-acp -p buzz-agent -p buzz-dev-mcp -p git-credential-nostr -p buzz-cli ./scripts/bundle-sidecars.sh - # Mesh rev derived from Cargo.lock (no lockstep edit on dep bump); cache key tracks it. + # Resolve the exact desktop Mesh dependency so the native cache and build + # always use the same checkout. - name: Resolve mesh-llm rev id: mesh_rev run: | set -euo pipefail - REV=$(python3 -c 'import tomllib; d=tomllib.load(open("Cargo.lock", "rb")); p=next(p for p in d["package"] if p["name"] == "mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])') - [[ -n "$REV" ]] || { echo "::error::could not resolve mesh-llm rev from Cargo.lock"; exit 1; } + metadata=$(cargo metadata --manifest-path desktop/src-tauri/Cargo.toml --features mesh-llm --format-version 1) + REV=$(python3 -c 'import json,sys; data=json.load(sys.stdin); p=next(p for p in data["packages"] if p["name"]=="mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])' <<<"$metadata") + SDK_MANIFEST=$(python3 -c 'import json,sys; data=json.load(sys.stdin); print(next(p["manifest_path"] for p in data["packages"] if p["name"]=="mesh-llm-sdk"))' <<<"$metadata") + MESH_ROOT=$(cd "$(dirname "$SDK_MANIFEST")/../.." && pwd) + [[ -n "$REV" ]] || { echo "::error::could not resolve desktop mesh-llm rev from Cargo metadata"; exit 1; } echo "rev=$REV" >> "$GITHUB_OUTPUT" - echo "short=${REV:0:7}" >> "$GITHUB_OUTPUT" + echo "root=$MESH_ROOT" >> "$GITHUB_OUTPUT" - name: Restore mesh llama build cache id: llama_cache uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 @@ -155,14 +159,11 @@ jobs: - name: Build mesh llama native libraries if: steps.llama_cache.outputs.cache-hit != 'true' env: - MESH_REV_SHORT: ${{ steps.mesh_rev.outputs.short }} + MESH_ROOT: ${{ steps.mesh_rev.outputs.root }} run: | set -euo pipefail - cargo fetch --manifest-path desktop/src-tauri/Cargo.toml - SHORT="$MESH_REV_SHORT" - MESH_ROOT=$(find "${CARGO_HOME:-$HOME/.cargo}/git/checkouts" -path "*/$SHORT" -type d -name "$SHORT" | head -1) - if [[ -z "$MESH_ROOT" ]]; then - echo "::error::mesh-llm checkout for $SHORT not found after cargo fetch" + if [[ ! -x "$MESH_ROOT/scripts/prepare-llama.sh" || ! -x "$MESH_ROOT/scripts/build-llama.sh" ]]; then + echo "::error::mesh-llm build scripts not found under resolved checkout $MESH_ROOT" exit 1 fi export LLAMA_STAGE_BACKEND=metal diff --git a/.github/workflows/signed-macos-canary.yml b/.github/workflows/signed-macos-canary.yml index fb0656028af..4e80dbe868d 100644 --- a/.github/workflows/signed-macos-canary.yml +++ b/.github/workflows/signed-macos-canary.yml @@ -96,15 +96,19 @@ jobs: cargo build --release -p buzz-acp -p buzz-agent -p buzz-dev-mcp -p git-credential-nostr -p buzz-cli ./scripts/bundle-sidecars.sh - # Mesh rev derived from Cargo.lock (no lockstep edit on dep bump); cache key tracks it. + # Resolve the exact desktop Mesh dependency so the native cache and build + # always use the same checkout. - name: Resolve mesh-llm rev id: mesh_rev run: | set -euo pipefail - REV=$(python3 -c 'import tomllib; d=tomllib.load(open("Cargo.lock", "rb")); p=next(p for p in d["package"] if p["name"] == "mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])') - [[ -n "$REV" ]] || { echo "::error::could not resolve mesh-llm rev from Cargo.lock"; exit 1; } + metadata=$(cargo metadata --manifest-path desktop/src-tauri/Cargo.toml --features mesh-llm --format-version 1) + REV=$(python3 -c 'import json,sys; data=json.load(sys.stdin); p=next(p for p in data["packages"] if p["name"]=="mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])' <<<"$metadata") + SDK_MANIFEST=$(python3 -c 'import json,sys; data=json.load(sys.stdin); print(next(p["manifest_path"] for p in data["packages"] if p["name"]=="mesh-llm-sdk"))' <<<"$metadata") + MESH_ROOT=$(cd "$(dirname "$SDK_MANIFEST")/../.." && pwd) + [[ -n "$REV" ]] || { echo "::error::could not resolve desktop mesh-llm rev from Cargo metadata"; exit 1; } echo "rev=$REV" >> "$GITHUB_OUTPUT" - echo "short=${REV:0:7}" >> "$GITHUB_OUTPUT" + echo "root=$MESH_ROOT" >> "$GITHUB_OUTPUT" - name: Restore mesh llama build cache id: llama_cache @@ -116,13 +120,11 @@ jobs: - name: Build mesh llama native libraries if: steps.llama_cache.outputs.cache-hit != 'true' env: - MESH_REV_SHORT: ${{ steps.mesh_rev.outputs.short }} + MESH_ROOT: ${{ steps.mesh_rev.outputs.root }} run: | set -euo pipefail - cargo fetch --manifest-path desktop/src-tauri/Cargo.toml - MESH_ROOT=$(find "${CARGO_HOME:-$HOME/.cargo}/git/checkouts" -path "*/$MESH_REV_SHORT" -type d -name "$MESH_REV_SHORT" | head -1) - if [[ -z "$MESH_ROOT" ]]; then - echo "::error::mesh-llm checkout for $MESH_REV_SHORT not found after cargo fetch" + if [[ ! -x "$MESH_ROOT/scripts/prepare-llama.sh" || ! -x "$MESH_ROOT/scripts/build-llama.sh" ]]; then + echo "::error::mesh-llm build scripts not found under resolved checkout $MESH_ROOT" exit 1 fi export LLAMA_STAGE_BACKEND=metal diff --git a/AGENTS.md b/AGENTS.md index 79bae9d4945..7ff0eb4d477 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -343,9 +343,19 @@ Add specs to `desktop/tests/e2e/` and register them in `playwright.config.ts` (`smoke` project `testMatch`). Every test calls `installMockBridge(page)` for mock Tauri IPC. Mock pubkey, channel names, and UUIDs live in `e2eBridge.ts`. +**Always build with `pnpm build:e2e`, never `pnpm run build`.** The mock Tauri +bridge is compiled in only for `--mode e2e` (see `installE2eBridgeIfConfigured` +in `desktop/src/main.tsx`). A plain `pnpm run build` strips it, so +`window.__TAURI_INTERNALS__` is never defined and **every** mock-mode spec fails +with `Cannot read properties of undefined (reading 'invoke')` — the app renders +"Community connection failed" instead of the UI under test. That looks exactly +like a product bug rather than a build mistake, so it burns real time. +`pnpm test:e2e:smoke` and `pnpm test:e2e:integration` run the right build for +you; prefer them over a manual build plus `playwright test`. + **Stale server:** `reuseExistingServer: true` means a previous build's server -serves old code. Kill port 4173 and `pnpm run build` before re-running tests -after code changes. +serves old code. Kill port 4173 and re-run `pnpm build:e2e` before re-running +tests after code changes. **`addInitScript` before bridge:** `page.addInitScript` (localStorage seeding) must run BEFORE `installMockBridge(page)` — React reads state on mount, the @@ -555,6 +565,15 @@ To run the app locally (starts Docker, relay, iOS simulator automatically): just mobile-dev ``` +When run from a git worktree, `just mobile-dev` (and `just +mobile-build-android`) give the debug build a per-worktree app identifier +(keyed to the worktree directory name) and a branch-labelled app name via +`scripts/mobile-worktree-overrides.sh`, so builds from multiple worktrees +install side by side. Release builds are unaffected. `just mobile-clean` +removes stale worktree-suffixed installs from simulators/emulators. See +[mobile/README.md](mobile/README.md) for direct Xcode / Android Studio +usage. + ### Testing Conventions - Prefer **widget tests** over unit tests for UI components — test the diff --git a/CHANGELOG.md b/CHANGELOG.md index 12239365046..cfd3b16d0aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,59 @@ # Changelog +## v0.5.0 + +- feat(invites): add use-limited invite links ([#3141](https://github.com/block/buzz/pull/3141)) ([`d500c2d5c`](https://github.com/block/buzz/commit/d500c2d5cf5d9aabe0ca4ebebfcafdbe5f5b7fd3)) +- fix(node): bump Buzz-supplied Node runtimes past OpenClaw's >=24.15.0 floor ([#3218](https://github.com/block/buzz/pull/3218)) ([`98a7b1334`](https://github.com/block/buzz/commit/98a7b1334823ee0be3e3fa5cab7a2e349e438dab)) +- fix(desktop): preserve thread anchor through layout reflow ([#3212](https://github.com/block/buzz/pull/3212)) ([`9810d8545`](https://github.com/block/buzz/commit/9810d8545937329f229ff40d8a19edc9e3e325c1)) +- feat(search): parse from:/in:/after:/before: and pass them in the filter ([#2871](https://github.com/block/buzz/pull/2871)) ([`cb2a265b5`](https://github.com/block/buzz/commit/cb2a265b5399426e808461c1a16713754c593258)) +- fix(desktop): fetch join policies through native networking ([#2862](https://github.com/block/buzz/pull/2862)) ([`0019f8076`](https://github.com/block/buzz/commit/0019f80765e96f056e81b57789b8b5fb80936f72)) +- fix(desktop): republish agent identity records when a persona rename propagates ([#2607](https://github.com/block/buzz/pull/2607)) ([`7ca0bbd94`](https://github.com/block/buzz/commit/7ca0bbd946fd82a7008132f94d069a97bb53f94b)) +- fix(desktop): keep project Inbox previews compact ([#3193](https://github.com/block/buzz/pull/3193)) ([`de1396050`](https://github.com/block/buzz/commit/de13960505fd798070e177cb33b1663100ac06bb)) +- Inbox refactor ([#2045](https://github.com/block/buzz/pull/2045)) ([`2bd4c24b7`](https://github.com/block/buzz/commit/2bd4c24b71335e7ce272ec6de6491f7f37f4b20d)) +- Fix composer selection formatting and drop overlay ([#3172](https://github.com/block/buzz/pull/3172)) ([`99da5b7eb`](https://github.com/block/buzz/commit/99da5b7ebb19e26453e075bfb949672122b31be3)) +- Refine pending message status ([#3153](https://github.com/block/buzz/pull/3153)) ([`75588eaff`](https://github.com/block/buzz/commit/75588eaff2354d620e554c055b80ec83735ddb0a)) +- fix(desktop): recover full local storage on startup ([#3182](https://github.com/block/buzz/pull/3182)) ([`174c38e4b`](https://github.com/block/buzz/commit/174c38e4bd1ed8498641546bc4fcb6d5a4c9cede)) +- fix(desktop): keep collapsed table separators out of spoilers ([#3169](https://github.com/block/buzz/pull/3169)) ([`4d8b676bb`](https://github.com/block/buzz/commit/4d8b676bb283a1917cec5850c3b7327fe122b0c1)) +- feat(desktop): redesign agent runtime settings ([#3093](https://github.com/block/buzz/pull/3093)) ([`d98da7389`](https://github.com/block/buzz/commit/d98da7389e60cfbd79b219aa411449fe2e53a18a)) +- fix(desktop): use forward slashes for git credential.helper on Windows ([#3023](https://github.com/block/buzz/pull/3023)) ([`899531684`](https://github.com/block/buzz/commit/8995316844f7ad50552fbae67fbd35119262796f)) +- chore(desktop): add AgentCreationPreview file-size override to unblock main CI ([#3154](https://github.com/block/buzz/pull/3154)) ([`b92a1f4bf`](https://github.com/block/buzz/commit/b92a1f4bf400e7da5ab7a010cdd81a69497d8191)) +- fix(desktop): make the test loader work on Windows ([#2758](https://github.com/block/buzz/pull/2758)) ([`8bb43d519`](https://github.com/block/buzz/commit/8bb43d51912894553f2670b2d285a96cf09cd472)) +- fix(desktop): make lint and unit-test gates work on Windows ([#2943](https://github.com/block/buzz/pull/2943)) ([`545bb46b8`](https://github.com/block/buzz/commit/545bb46b824a3fbf4401062f03b72531d832ebb9)) +- feat(desktop): add search to agent emoji picker ([#2630](https://github.com/block/buzz/pull/2630)) ([`313f793c8`](https://github.com/block/buzz/commit/313f793c8753d413c22ff8edfe420d5ee78708bc)) +- fix(desktop): keep identity key help dialog readable in dark mode ([#2854](https://github.com/block/buzz/pull/2854)) ([`be275cfc6`](https://github.com/block/buzz/commit/be275cfc6c7b80fe43e9d66c6d14b6d2bbe58a10)) +- feat(acp): title agent sessions from the agent and channel name ([#3028](https://github.com/block/buzz/pull/3028)) ([`f2fe3b63c`](https://github.com/block/buzz/commit/f2fe3b63c21be55907175715c076cd3a9195b74d)) +- feat(git): use agent display name as git author name ([#3040](https://github.com/block/buzz/pull/3040)) ([`18eef633d`](https://github.com/block/buzz/commit/18eef633d88ac465c61d98f12655fbf51dc3ca44)) +- fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) ([#3135](https://github.com/block/buzz/pull/3135)) ([`31e2de196`](https://github.com/block/buzz/commit/31e2de1966672e73e026af3c54f3a1a9a2f5e103)) +- fix(desktop): read the newest pair-scoped harness log ([#3134](https://github.com/block/buzz/pull/3134)) ([`654f38490`](https://github.com/block/buzz/commit/654f384906b5c720a60a199d85031a6f1cb6efc9)) +- feat(desktop): handle project work from Inbox ([#3117](https://github.com/block/buzz/pull/3117)) ([`c5c4f390b`](https://github.com/block/buzz/commit/c5c4f390b6713256e2efb8394c59823ebad73db6)) +- fix(desktop): clarify identity key button when key exists ([#2357](https://github.com/block/buzz/pull/2357)) ([`87b3fcd3c`](https://github.com/block/buzz/commit/87b3fcd3c0131683569dd4268b099d18b25dcd5e)) +- Restore Goose and Buzz Agent to onboarding harness selection ([#2731](https://github.com/block/buzz/pull/2731)) ([`7fc0cc82d`](https://github.com/block/buzz/commit/7fc0cc82db4d9dced9c258bbe8b530164a832a77)) +- fix(desktop): render rich project work item content ([#3100](https://github.com/block/buzz/pull/3100)) ([`afb272bb7`](https://github.com/block/buzz/commit/afb272bb7b8d7d45d7de676fa97dcd5a8eefacc7)) +- feat(acp): bring your own harness (BYOH) — generic ACP runtime seam + settings gallery ([#2773](https://github.com/block/buzz/pull/2773)) ([`95fdf9788`](https://github.com/block/buzz/commit/95fdf978800982389b120c66ff5e766d785419c7)) +- feat(desktop): use collective mesh routing for Auto ([#2825](https://github.com/block/buzz/pull/2825)) ([`16d4ec335`](https://github.com/block/buzz/commit/16d4ec335e210295a9d9f77f36c1e85a18b6814a)) +- fix(desktop): strip legacy baked team instructions from stored prompts ([#3035](https://github.com/block/buzz/pull/3035)) ([`aee631448`](https://github.com/block/buzz/commit/aee63144843854ee32ed9d36a2e7511c82ddc6b0)) +- feat(agents): lower default agent parallelism from 24 to 10 ([#3038](https://github.com/block/buzz/pull/3038)) ([`5d8ede446`](https://github.com/block/buzz/commit/5d8ede446f8fdc48146fe56d389cab6bf3500f92)) +- Polish community rail and mobile pairing ([#2972](https://github.com/block/buzz/pull/2972)) ([`e6c90bb7c`](https://github.com/block/buzz/commit/e6c90bb7c430d1b2af16508b634f9a5283b7fa3b)) +- fix(desktop): remove bundled libsystemd from AppImage ([#2353](https://github.com/block/buzz/pull/2353)) ([`a31fc4d2f`](https://github.com/block/buzz/commit/a31fc4d2f35d51cdf45ff8c61fc3a07f49c665e8)) +- fix(desktop): make agent definition authoritative for model/provider/prompt ([#1968](https://github.com/block/buzz/pull/1968)) ([`8c0e8cb16`](https://github.com/block/buzz/commit/8c0e8cb1656b04ad269bce3c2deeda2a943ae78a)) +- chore(desktop): delete dead persona catalog UI cluster ([#2886](https://github.com/block/buzz/pull/2886)) ([`8e67cf399`](https://github.com/block/buzz/commit/8e67cf399d0291bcdbc69cd0402983ca030f05bb)) +- fix(desktop): surface install failures hidden by curl-pipe exit codes ([#2892](https://github.com/block/buzz/pull/2892)) ([`166c6655e`](https://github.com/block/buzz/commit/166c6655e8bca87d83ad60c087fb70a32a026baf)) +- Refactor managed-agent runtime into cohesive modules ([#2974](https://github.com/block/buzz/pull/2974)) ([`74b63e184`](https://github.com/block/buzz/commit/74b63e1846212af6e6751a62cfc631f74b1dfe07)) +- fix(desktop): make Linux AppImage GStreamer work on non-Debian distros ([#2176](https://github.com/block/buzz/pull/2176)) ([`cc6c4d347`](https://github.com/block/buzz/commit/cc6c4d3471629fad018bcf645f9471a01b9ffe2f)) +- refactor(desktop): remove Agent directory section from Agents page ([#2290](https://github.com/block/buzz/pull/2290)) ([`5d1233e84`](https://github.com/block/buzz/commit/5d1233e841b0efa91470bb45467b2c8e4284ebf6)) +- fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard ([#2904](https://github.com/block/buzz/pull/2904)) ([`ab7aa8b12`](https://github.com/block/buzz/commit/ab7aa8b1200710dbc2d7a8661ed5aab95c4199c1)) +- fix(desktop): supervise and re-arm relay-mesh runtime ([#2823](https://github.com/block/buzz/pull/2823)) ([`aa51dab9d`](https://github.com/block/buzz/commit/aa51dab9da5fef7054d03cf1a1207986d0000684)) +- fix(agents): run live Databricks discovery instead of the fallback list ([#2890](https://github.com/block/buzz/pull/2890)) ([`8eb6e3eb6`](https://github.com/block/buzz/commit/8eb6e3eb601174249642373a6a367262fa476753)) +- fix(desktop): retire prepend mode on every reader wheel ([#2913](https://github.com/block/buzz/pull/2913)) ([`07d0265cf`](https://github.com/block/buzz/commit/07d0265cfc212ef02e1c26153bf58ff46ce5ffe6)) +- fix(desktop): consolidate prepend scroll correction ([#2855](https://github.com/block/buzz/pull/2855)) ([`25e7864b3`](https://github.com/block/buzz/commit/25e7864b35f4dfd1c0ff31304a38555230a85f8d)) +- fix(desktop): track concurrent agent turns up to the harness maximum ([#2882](https://github.com/block/buzz/pull/2882)) ([`20bff5910`](https://github.com/block/buzz/commit/20bff591023daffc5ee1032cff02b54b75da3567)) +- fix(relay): preserve reconnect backoff ([#2759](https://github.com/block/buzz/pull/2759)) ([`499c5d349`](https://github.com/block/buzz/commit/499c5d349dab13bc906b1af5fe1fcb09ce2afa81)) +- refactor(relay): expose reconnect timing policy ([#2310](https://github.com/block/buzz/pull/2310)) ([`2f0041595`](https://github.com/block/buzz/commit/2f0041595d72529c06885680d2bd07ddb6a0beb4)) +- fix(desktop): clear stale working badges on agent stop/restart ([#2803](https://github.com/block/buzz/pull/2803)) ([`a64cc71f6`](https://github.com/block/buzz/commit/a64cc71f6c1605279b1a6fbd0fe904a2984cbdb0)) +- fix(desktop): surface agent rename relay profile sync failure as a warning toast ([#2279](https://github.com/block/buzz/pull/2279)) ([`5e3d2e484`](https://github.com/block/buzz/commit/5e3d2e4849c0f2512330801d804fb96f4ab72d28)) +- fix(discovery): inject PATH into Codex adapter planning ([#2767](https://github.com/block/buzz/pull/2767)) ([`6ab3835f3`](https://github.com/block/buzz/commit/6ab3835f3fe89ee215819fe8d193463c0ae7472b)) + + ## v0.4.26 - Style mobile pairing QR codes ([#2775](https://github.com/block/buzz/pull/2775)) ([`50655ac09`](https://github.com/block/buzz/commit/50655ac097fbf1a7db1a5284dccc7e2a0b0f1bfc)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 87c12bf29d8..9723188cc99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -130,10 +130,10 @@ just reset # Wipe all dev state and recreate it; installed Buzz is preserved ``` Development desktop state uses separate bundle identifiers -(`xyz.block.buzz.app.dev` and per-worktree variants), a separate keyring service +(`com.macsurfacing.workspace.dev` and per-worktree variants), a separate keyring service (`buzz-desktop-dev`), and `~/.buzz-dev`. `just reset` removes those dev-only locations and the local Docker volumes. It does not touch the installed app's -`xyz.block.buzz.app` data, `buzz-desktop` keyring service, or `~/.buzz` nest. +`com.macsurfacing.workspace` data, `buzz-desktop` keyring service, or `~/.buzz` nest. --- @@ -284,9 +284,34 @@ required. The scope (in parentheses) is optional but encouraged. - How to test it manually (if applicable) - Any follow-up work deferred to a future PR -### Review Process +6. **Shows the UI** — any PR that changes the desktop or mobile UI includes + before/after screenshots (or a short recording for interactions) in the + description. We can't run every branch locally — screenshots let us review + UI changes same-day instead of waiting for someone to build your branch. -- We prioritize focused PRs that follow this guide and review as capacity allows. +### PRs We're Unlikely to Merge + +Some kinds of PRs usually get closed — not because they're bad ideas, but +because we can't safely review them without prior discussion: + +- **Large refactors or dependency swaps** without a prior issue agreeing on + the direction +- **Cosmetic renames or style-only churn** that doesn't fix a bug or improve + clarity +- **Entirely new features** with no prior discussion +- **Drive-by changes bundled into an unrelated fix** — split them out + +If you're considering any of these, open an issue first and we'll tell you +quickly whether it's a direction we'd merge. That saves your time as much as +ours. + +### What to Expect After You Open a PR + +- Maintainers triage new PRs on a best-effort cadence. Focused PRs that + follow this guide move fastest. +- Duplicates and PRs that skip this guide may be closed with a pointer here + rather than a full review. A close isn't a rejection of you or the idea — + address the gaps and reopen (or open a fresh PR) anytime. - Address review comments by pushing new commits (don't force-push during review; it makes it hard to see what changed). - Once approved, a maintainer will squash-merge your PR. diff --git a/Cargo.lock b/Cargo.lock index 9d0190868de..6996d2ab5e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -775,6 +775,7 @@ dependencies = [ "futures-util", "hex", "httparse", + "libc", "nix 0.31.3", "nostr", "reqwest 0.13.4", @@ -925,6 +926,7 @@ dependencies = [ name = "buzz-core" version = "0.1.0" dependencies = [ + "base64", "chrono", "hex", "hmac 0.13.0", @@ -949,6 +951,7 @@ dependencies = [ "chrono", "hex", "nostr", + "rand 0.10.1", "serde", "serde_json", "sha2 0.11.0", @@ -3039,11 +3042,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if 1.0.4", - "js-sys", "libc", "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] @@ -5457,9 +5458,9 @@ dependencies = [ [[package]] name = "nostr" -version = "0.44.3" +version = "0.44.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d8f0fe13526800300a36bf3b7c5f752e62e32ab81c74a8e5caa2865708625a" +checksum = "e826dd648489de2c5b293920e20b92932ef820302007c1987c758d4d06eeb2cf" dependencies = [ "base64", "bech32", @@ -6823,15 +6824,16 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" dependencies = [ "aws-lc-rs", "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", - "rand 0.9.4", + "rand 0.10.1", + "rand_pcg", "ring", "rustc-hash", "rustls", diff --git a/Cargo.toml b/Cargo.toml index 3499285f917..3ac7ee4cce1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ reqwest = { version = "0.13", features = ["json", "rustls"], default-features = sha2 = "0.11" hex = "0.4" hmac = "0.13" +base64 = "0.22" # Randomness rand = "0.10" diff --git a/Dockerfile b/Dockerfile index 661be6c3a7c..d883ac6b015 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,6 +59,9 @@ RUN apt-get update \ ca-certificates \ git \ && rm -rf /var/lib/apt/lists/* +# Keep enough DWARF for native profilers to resolve optimized code to source +# locations. The normal runtime strips it below; runtime-debug retains it. +ENV CARGO_PROFILE_RELEASE_DEBUG=line-tables-only COPY --from=planner /build/recipe.json recipe.json # Cook the full workspace recipe — relay deps include workspace siblings, so # scoping to -p buzz-relay misses transitive deps and re-builds them later. @@ -66,8 +69,12 @@ RUN cargo chef cook --release --recipe-path recipe.json COPY . . RUN cargo build --release --locked -p buzz-relay --bin buzz-relay \ -p buzz-admin --bin buzz-admin \ - -p buzz-pair-relay --bin buzz-pair-relay \ - && strip target/release/buzz-relay \ + -p buzz-pair-relay --bin buzz-pair-relay + +# Derive the normal release binaries from the same optimized ELF files as the +# debug image so the two variants cannot drift at code-generation time. +FROM builder AS stripped-binaries +RUN strip target/release/buzz-relay \ && strip target/release/buzz-admin \ && strip target/release/buzz-pair-relay @@ -111,8 +118,8 @@ COPY web/ web/ COPY admin-web/ admin-web/ RUN pnpm -C web build && pnpm -C admin-web build -# ─── Stage 5: runtime ─────────────────────────────────────────────────────── -FROM debian:${DEBIAN_VERSION}-slim AS runtime +# ─── Stage 5: shared runtime ──────────────────────────────────────────────── +FROM debian:${DEBIAN_VERSION}-slim AS runtime-base # OCI annotations: required for GHCR to auto-link the image to this repo and # inherit its visibility. org.opencontainers.image.source is the load-bearing @@ -135,9 +142,6 @@ RUN apt-get update \ && useradd --system --uid 1000 --gid 1000 --home-dir /var/lib/buzz \ --create-home --shell /usr/sbin/nologin buzz -COPY --from=builder /build/target/release/buzz-relay /usr/local/bin/buzz-relay -COPY --from=builder /build/target/release/buzz-admin /usr/local/bin/buzz-admin -COPY --from=builder /build/target/release/buzz-pair-relay /usr/local/bin/buzz-pair-relay COPY --from=web-builder /build/web/dist /srv/buzz/web COPY --from=web-builder /build/admin-web/dist /srv/buzz/admin-web @@ -157,3 +161,18 @@ USER buzz:buzz WORKDIR /var/lib/buzz ENTRYPOINT ["/usr/local/bin/buzz-relay"] + +# Optimized binaries with line-table debug information for native profiling. +# Published under debug-* tags; runtime behavior otherwise matches the normal +# image exactly. +FROM runtime-base AS runtime-debug +COPY --from=builder /build/target/release/buzz-relay /usr/local/bin/buzz-relay +COPY --from=builder /build/target/release/buzz-admin /usr/local/bin/buzz-admin +COPY --from=builder /build/target/release/buzz-pair-relay /usr/local/bin/buzz-pair-relay + +# Keep the stripped runtime as the final/default Dockerfile target so existing +# `docker build .` callers and release tags retain their current behavior. +FROM runtime-base AS runtime +COPY --from=stripped-binaries /build/target/release/buzz-relay /usr/local/bin/buzz-relay +COPY --from=stripped-binaries /build/target/release/buzz-admin /usr/local/bin/buzz-admin +COPY --from=stripped-binaries /build/target/release/buzz-pair-relay /usr/local/bin/buzz-pair-relay diff --git a/Justfile b/Justfile index 701a1f06b2c..4a8f8d504c6 100644 --- a/Justfile +++ b/Justfile @@ -92,7 +92,11 @@ build-release: cargo build --workspace --release # Run repo lint and formatting checks -check: fmt-check clippy desktop-check desktop-tauri-fmt-check desktop-tauri-clippy web-check mobile-check +check: fmt-check clippy desktop-check desktop-tauri-fmt-check desktop-tauri-clippy web-check mobile-check docker-tag-matrix-check + +# Verify Docker release/debug tag generation cannot double-apply a variant prefix +docker-tag-matrix-check: + ./scripts/test-docker-tag-matrix.sh # Format all Rust code fmt: @@ -620,11 +624,12 @@ mobile-check: mobile-test: unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter test -# Compile an unsigned Android debug APK +# Compile an unsigned Android debug APK (worktree-aware debug identity) mobile-build-android: + ./scripts/mobile-worktree-overrides.sh unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter build apk --debug --no-pub -# Run the mobile app on iOS simulator +# Run the mobile app on iOS simulator (worktree-aware debug identity) mobile-dev: #!/usr/bin/env bash set -euo pipefail @@ -632,10 +637,15 @@ mobile-dev: open -a Simulator sleep 3 fi + ./scripts/mobile-worktree-overrides.sh cd {{mobile_dir}} unset GIT_DIR GIT_WORK_TREE flutter run +# Uninstall stale worktree-suffixed Buzz debug installs (production apps kept) +mobile-clean: + ./scripts/mobile-worktree-clean.sh + # ─── Database ───────────────────────────────────────────────────────────────── # Apply database migrations diff --git a/RELEASING.md b/RELEASING.md index 9785122aadd..063b813e2ce 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -57,10 +57,13 @@ or mobile GitHub Release. 2. **Merge the PR.** `auto-tag-on-release-pr-merge` pushes `relay-v`. 3. **The tag triggers `docker.yml`.** Stable releases update the version - aliases and `latest`; prereleases do not. + aliases and `latest`; prereleases do not. Each release also publishes an + optimized, symbol-bearing image under matching `debug-` tags (for example, + `debug-0.3.0` and `debug-latest`) for native profiling. The ordinary tags + remain stripped and are the default for deployments that do not need it. Every push to `main` continues to publish the rolling relay `:main` and -`:sha-<7>` tags. +`:sha-<7>` tags, plus matching `:debug-main` and `:debug-sha-<7>` variants. ### Mobile diff --git a/TESTING.md b/TESTING.md index 51a5eb44c1d..1f40580ba2d 100644 --- a/TESTING.md +++ b/TESTING.md @@ -281,6 +281,7 @@ out of the box with `just setup` or `just relay`. Common overrides: | `BUZZ_AUDIT_ENABLED` | `true` | Tamper-evident event/media audit log. Set `false`/`0`/`off` to skip its DB pool and writes. Does not disable the separate moderation audit trail. | | `BUZZ_AUTO_MIGRATE` | `false` | Opt in with `true`/`1`/`yes`/`on` to run embedded SQLx migrations on relay startup | | `RELAY_OWNER_PUBKEY` | unset | Bootstrapped as `owner` in `relay_members` at first start | +| `BUZZ_COS_FOLLOW_UP_BRIDGE_PUBKEY` | unset | Exact 64-character lowercase-hex COS bridge public key. Unset disables the feature; invalid present values abort startup. | | `BUZZ_ALLOW_NIP_OA_AUTH` | `false` | Enable NIP-OA owner attestation for membership | | `BUZZ_WEB_DIR` | unset (source), `/srv/buzz/web` (container) | Directory containing the invite landing bundle; the production container enables it so `/invite/{code}` always works | | `BUZZ_SERVE_GIT_WEB_GUI` | `false` | Set to `true` or `1` to expose the bundled Git repository browser at `/` and `/repos/...`; invite routes do not depend on this flag | diff --git a/admin-web/index.html b/admin-web/index.html index 961040e83ff..7ae83bb18d4 100644 --- a/admin-web/index.html +++ b/admin-web/index.html @@ -5,7 +5,7 @@ - Buzz admin + MAC Workspace Admin
diff --git a/admin-web/public/favicon.svg b/admin-web/public/favicon.svg index 716bbd3dc62..deaf4c3828e 100644 --- a/admin-web/public/favicon.svg +++ b/admin-web/public/favicon.svg @@ -1,20 +1,5 @@ - - - - - - - - - - - - - - + + + + diff --git a/admin-web/src/App.tsx b/admin-web/src/App.tsx index 49202e9778d..4a3bd633449 100644 --- a/admin-web/src/App.tsx +++ b/admin-web/src/App.tsx @@ -7,7 +7,12 @@ import { useState, } from "react"; import { ApiFailure, request } from "./api"; -import type { FeedbackDetail, FeedbackSummary, Report } from "./types"; +import type { + FeedbackDetail, + FeedbackSummary, + Report, + ReportDetail as ReportDetailData, +} from "./types"; import { useResource } from "./useResource"; function usePath() { @@ -89,7 +94,7 @@ function Reports() { {(reports) => @@ -131,7 +136,10 @@ function Reports() { } function ReportDetail({ id }: { id: string }) { - const resource = useResource(() => request(`/reports/${id}`), id); + const resource = useResource( + () => request(`/reports/${id}`), + id, + ); return ( {report.target} + {report.targetKind === "event" ? ( + <> +
Message
+
+ {report.message ? ( +
+ {report.message.deletedAt ? ( + Deleted + ) : null} +

{report.message.content}

+
+ Author + {report.message.authorPubkey} + Created + +
+
+ ) : ( +

+ Message content is unavailable. It may have expired or + been removed from event storage. +

+ )} +
+ + ) : null}
Note
{report.note ?? "No note provided."} @@ -203,7 +237,7 @@ function FeedbackList() { {(items) => { @@ -658,17 +692,8 @@ function date(value: string) { : parsed.toLocaleString(); } -function BuzzMark() { - return ( - - ); +function WorkspaceMark() { + return ; } function ReportIcon() { @@ -781,10 +806,10 @@ export function App() {
- + - Buzz Admin + MAC Workspace Admin