fix(marketing): improve hero layout and restore projector demo #14280
Workflow file for this run
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: Test | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - "web/**" | |
| - "electron/**" | |
| - "packages/**" | |
| - "reliability/**" | |
| - "mobile/**" | |
| - "examples/**" | |
| - "scripts/**" | |
| - "Dockerfile" | |
| - ".dockerignore" | |
| - "package.json" | |
| - "package-lock.json" | |
| - "tsconfig.json" | |
| - "tsconfig.*.json" | |
| - "turbo.json" | |
| - ".nvmrc" | |
| - ".github/workflows/test.yml" | |
| - ".github/workflows/quality-checks.yml" | |
| - ".github/actions/setup-build/**" | |
| pull_request: | |
| branches: | |
| - main | |
| # No `paths` filter here: this workflow's "Quality Gate" job is a REQUIRED | |
| # status check. A path-filtered required check is left Pending (never runs) | |
| # when a PR push/merge touches no matching path — e.g. a clean "merge main" | |
| # commit — which blocks the PR and auto-merge indefinitely. Running the gate | |
| # on every PR keeps the required check from getting stuck. (The `push` to | |
| # main above keeps its path filter — there is no required-check to block.) | |
| # Cancel superseded runs for the same branch/PR; the latest push is what matters. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Does this push touch anything but prose? A documentation-only change has | |
| # nothing for typecheck, lint, the test suites, the image build or the | |
| # browser E2E runs to say, and every leg it starts holds a runner other PRs | |
| # queue behind (the account cap is ~20 concurrent jobs). The workflow still | |
| # triggers on every PR — see the `paths` note above — so the required check | |
| # is always reported; the legs inside it skip instead, and a skipped job | |
| # counts as a pass for a required check. | |
| # | |
| # The prose set is deliberately narrow: `docs/**` (the Jekyll site), the | |
| # Markdown at the repo root, the agent instruction files anywhere, and the | |
| # Markdown under `.github/`. Markdown that code reads at run time — a | |
| # sandbox pack's `SKILL.md`, a package `README.md` — is NOT in it and keeps | |
| # running the full gate. | |
| # | |
| # Fails open: the step is `continue-on-error` and the output falls back to | |
| # "true", so a filter that cannot resolve a base runs everything rather than | |
| # waving a change through. | |
| # | |
| # It also decides whether the diff can reach the root workspace at all. | |
| # `marketing/` is a separate npm project — its own lockfile, its own install, | |
| # built and deployed by marketing-ci.yml — and nothing in this workflow | |
| # touches it. A marketing-only PR used to build ~55 backend packages, | |
| # typecheck three apps, run every suite, build the container image and drive | |
| # two browser E2E jobs; with an account-wide cap of ~20 concurrent jobs, that | |
| # is time the rest of the queue spends waiting. `shared` is false for such a | |
| # diff and every leg skips, exactly as it does for prose. | |
| # | |
| # `mobile/` is NOT carved out, though it is also a separate npm project. Its | |
| # typecheck resolves `@nodetool-ai/websocket`'s router types (not a mobile | |
| # dependency at all) and `@nodetool-ai/protocol` through the root workspace, | |
| # so it is not separable from this gate without changing how mobile resolves | |
| # those packages. See the workflows README. | |
| changes: | |
| name: changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| code: ${{ steps.filter.outputs.code || 'true' }} | |
| shared: ${{ steps.filter.outputs.shared || 'true' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| - name: Detect non-documentation changes | |
| id: filter | |
| continue-on-error: true | |
| uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 | |
| with: | |
| filters: | | |
| code: | |
| - '!{docs/**,*.md,**/AGENTS.md,**/CLAUDE.md,.github/**/*.md}' | |
| shared: | |
| - '!{docs/**,*.md,**/AGENTS.md,**/CLAUDE.md,.github/**/*.md,marketing/**,.github/workflows/marketing-ci.yml}' | |
| quality: | |
| name: Quality Gate (npm run check) | |
| needs: changes | |
| # `always()` plus the explicit `== 'false'` test below so a `changes` job | |
| # that never reported (infrastructure failure, not a filter result) runs the | |
| # full gate. Only an explicit "this diff is prose" skips work — a required | |
| # check must never go green because the job that decides was broken. | |
| if: always() | |
| uses: ./.github/workflows/quality-checks.yml | |
| # A called workflow's permissions are capped by the caller's, so the gate's | |
| # `docker` leg only gets its read-only GHCR buildcache access if it is | |
| # granted here too. | |
| permissions: | |
| contents: read | |
| packages: read | |
| with: | |
| # false → every check leg (deps/typecheck/lint/tests) runs to completion | |
| # so each reports its own red/green instead of the first failure masking | |
| # the rest. The required check is the reusable workflow's `quality` gate | |
| # job, surfaced unchanged as "Quality Gate (npm run check) / quality". | |
| fail-fast: false | |
| skip-tests: false | |
| # A documentation-only push skips every leg inside the gate. The gate job | |
| # itself still runs and reports, so the required check lands green. | |
| docs-only: ${{ needs.changes.outputs.code == 'false' }} | |
| # Same fail-safe reading as `docs-only`: the output defaults to 'true', | |
| # so a filter that could not resolve a base runs the whole gate. False | |
| # only for a diff confined to marketing/, whose gate is marketing-ci.yml. | |
| shared: ${{ needs.changes.outputs.shared != 'false' }} | |
| # Heavy jobs run concurrently with the quality gate (both wait only on the | |
| # seconds-long `changes` job) rather than after it, so | |
| # the critical path is max(quality, integration, e2e) instead of | |
| # quality + max(integration, e2e). Trade-off: a PR that fails a static check | |
| # still spends these runner minutes. They build packages themselves (they are | |
| # in this workflow, not the reusable quality-checks one, so they can't consume | |
| # its build artifact without depending on the whole gate — which would undo | |
| # the decoupling). | |
| integration: | |
| name: Workflow Integration Tests | |
| needs: changes | |
| # Same fail-safe reading as the gate above: skip only on an explicit | |
| # "prose", or an explicit "this diff never leaves marketing/" — it runs | |
| # shipped-workflow execution out of packages/base-nodes, which marketing | |
| # cannot reach. | |
| if: ${{ always() && needs.changes.outputs.code != 'false' && needs.changes.outputs.shared != 'false' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Node, install deps, build packages | |
| uses: ./.github/actions/setup-build | |
| - name: Run shipped-workflow execution tests | |
| run: npm run test:integration | |
| workflow-runner-e2e: | |
| name: Workflow Runner Browser E2E | |
| needs: changes | |
| if: ${{ always() && needs.changes.outputs.code != 'false' && needs.changes.outputs.shared != 'false' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Node, install deps, build packages | |
| # mesa-vulkan-drivers ships lavapipe (CPU Vulkan ICD) so headless | |
| # Chromium can acquire a WebGPU adapter on GPU-less CI runners. The | |
| # workflow-runner browser harness uses it to drive shader-pool tests | |
| # (color.brightnessContrast, etc.) against the same module catalog | |
| # the server uses on Node/Dawn. | |
| uses: ./.github/actions/setup-build | |
| with: | |
| extra-apt: mesa-vulkan-drivers | |
| - name: Cache Playwright browsers | |
| id: playwright-cache | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-playwright- | |
| - name: Install Playwright Chromium browser | |
| run: npx playwright install --with-deps chromium | |
| working-directory: packages/workflow-runner | |
| - name: Run workflow-runner browser E2E tests | |
| run: npm run test:e2e --workspace=@nodetool-ai/workflow-runner | |
| - name: Upload Playwright report on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: workflow-runner-playwright-report | |
| path: packages/workflow-runner/playwright-report | |
| retention-days: 7 |