feat(shell): org + agent navigation in the toolbar breadcrumb; threads-only sidebar #17115
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Checks & Unit Tests | |
| on: | |
| push: | |
| branches: | |
| - main | |
| # Skip pushes to main that only touch the version bump, CI/workflow config, | |
| # or docs — none need the suite re-run (PRs already validated them, and the | |
| # [release] bump is owned by release-mesh). | |
| paths-ignore: | |
| - "apps/mesh/package.json" | |
| - ".github/**" | |
| - "apps/docs/**" | |
| - "**/*.md" | |
| pull_request: | |
| branches: | |
| - main | |
| jobs: | |
| # Gate: skip the (required) check jobs when a PR only touches workflow YAML, | |
| # docs, or markdown. Required checks can't be skipped via workflow-level | |
| # `paths` filters — a never-scheduled required check blocks the merge forever. | |
| # A job skipped via `if`, by contrast, reports as passed. So we keep the | |
| # trigger broad and skip at the job level. Pushes to main always run. | |
| changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| relevant: ${{ steps.filter.outputs.relevant }} | |
| steps: | |
| - name: Detect relevant changes | |
| id: filter | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| HEAD_MSG: ${{ github.event.head_commit.message }} | |
| run: | | |
| if [ "${{ github.event_name }}" != "pull_request" ]; then | |
| # Push to main runs everything — except the [release]: version-bump | |
| # commit, which only touches the version string. release-mesh picks | |
| # that commit up on its own push trigger and cuts the release. | |
| case "$HEAD_MSG" in | |
| '[release]:'*) echo "relevant=false" >> "$GITHUB_OUTPUT" ;; | |
| *) echo "relevant=true" >> "$GITHUB_OUTPUT" ;; | |
| esac | |
| exit 0 | |
| fi | |
| set +e | |
| FILES=$(gh api --paginate \ | |
| "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" \ | |
| --jq '.[].filename') | |
| if [ $? -ne 0 ]; then | |
| echo "Could not list PR files — running to be safe." | |
| echo "relevant=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "Changed files:"; echo "$FILES" | |
| # Run unless every changed file is workflow/docs/markdown. | |
| relevant=false | |
| while IFS= read -r f; do | |
| [ -z "$f" ] && continue | |
| case "$f" in | |
| .github/*|apps/docs/*|deploy/*|*.md) ;; | |
| *) relevant=true; break ;; | |
| esac | |
| done <<< "$FILES" | |
| echo "relevant=$relevant" >> "$GITHUB_OUTPUT" | |
| format: | |
| needs: changes | |
| if: needs.changes.outputs.relevant == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "1.3.14" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Run format check | |
| run: bun run fmt:check | |
| lint: | |
| needs: changes | |
| if: needs.changes.outputs.relevant == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "1.3.14" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Run lint | |
| run: bun run lint | |
| typecheck: | |
| needs: changes | |
| if: needs.changes.outputs.relevant == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "1.3.14" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Run typecheck | |
| run: bun run check:ci | |
| test: | |
| needs: changes | |
| if: needs.changes.outputs.relevant == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "1.3.14" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Run tests | |
| run: | | |
| # Tests are split by filename convention: | |
| # *.test.ts → unit (here) | |
| # *.integration.test.ts → .github/workflows/storage-integration.yml | |
| # *.e2e.test.ts → reserved for the sandbox-daemon workflow | |
| # See TESTING.md for the decision tree. | |
| # | |
| # One bun process per file: cleanest isolation, doesn't share | |
| # ports/sockets/DB pools between files. Bun 1.3.14's teardown | |
| # fixes mean we no longer need the signal-tolerance branches | |
| # we had on 1.3.5 — a real test failure is now the only way | |
| # bun exits non-zero. | |
| set -e | |
| while IFS= read -r f; do | |
| echo "::group::$f" | |
| bun test "$f" | |
| echo "::endgroup::" | |
| done < <(find apps/mesh/src apps/mesh/migrations packages \ | |
| \( -name '*.test.ts' -o -name '*.test.tsx' \) \ | |
| ! -name '*.integration.test.ts' \ | |
| ! -name '*.e2e.test.ts') | |
| build: | |
| needs: changes | |
| if: needs.changes.outputs.relevant == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "1.3.14" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Build server bundle | |
| run: bun run --cwd=apps/mesh build:server | |
| - name: Verify bundle outputs | |
| run: | | |
| test -f apps/mesh/dist/server/server.js | |
| test -f apps/mesh/dist/server/migrate.js | |
| test -f apps/mesh/dist/server/cli.js | |
| - name: Run knip | |
| run: bun run knip | |
| docker-smoke: | |
| needs: changes | |
| if: needs.changes.outputs.relevant == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "1.3.14" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Build daemon bundle | |
| run: bun run --cwd=packages/sandbox build | |
| - name: Build sandbox image | |
| run: | | |
| docker build \ | |
| -t studio-sandbox:ci \ | |
| -f packages/sandbox/image/Dockerfile \ | |
| packages/sandbox | |
| - name: Smoke test | |
| run: | | |
| docker run -d --name sandbox-smoke -p 19999:9000 \ | |
| -e DAEMON_TOKEN="$(printf 't%.0s' {1..32})" \ | |
| -e DAEMON_BOOT_ID="ci-smoke" \ | |
| -e APP_ROOT=/app \ | |
| -e PROXY_PORT=9000 \ | |
| -e DAEMON_NO_AUTOSTART=1 \ | |
| studio-sandbox:ci | |
| for i in $(seq 1 30); do | |
| if curl -fsS http://localhost:19999/health | grep -q '"bootId":"ci-smoke"'; then | |
| echo "ok" | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "smoke test failed — daemon did not return /health with ci-smoke bootId" | |
| docker logs sandbox-smoke | |
| exit 1 | |
| - name: Tear down | |
| if: always() | |
| run: docker rm -f sandbox-smoke || true |