docs(site): land the bilingual Rspress documentation site with GitHub Pages delivery #1385
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: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| # Nightly release-boundary matrix (packed-matrix job): the scaffolder | |
| # template tests beyond the per-PR minimal-template smoke. | |
| schedule: | |
| - cron: '17 6 * * *' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # PR pushes cancel the superseded run of the same PR (only the latest commit | |
| # matters). Pushes to main, the nightly schedule, and manual dispatches get | |
| # SHA-keyed groups with no cancellation, so a new main push can never kill an | |
| # in-flight main or nightly run. Same pattern as package-preview.yml. | |
| concurrency: | |
| group: ci-${{ github.event.pull_request.number || github.sha }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| # PR-only docs allowlist: docs/**, agent-patterns/**, website/** (the | |
| # Rspress site, validated by docs.yml), .changeset/*.md, and top-level *.md. | |
| # Nested markdown elsewhere is code because examples and packages contain | |
| # compiled SKILL.md artifacts, and package markdown affects npm pack audits. | |
| # Classification fails open so uncertain PRs run every heavy job; pushes to | |
| # main never skip any job based on changed paths. | |
| # Path rules and fail-open listing checks live in | |
| # scripts/classify-docs-only.mjs (unit-tested). This job sparse-checkouts | |
| # only that script so the vendored Effect subtree never lands on the | |
| # classify critical path. | |
| changes: | |
| if: github.event_name == 'pull_request' | |
| name: Detect changed paths | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| permissions: | |
| pull-requests: read | |
| outputs: | |
| docs_only: ${{ steps.classify.outputs.docs_only }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| filter: blob:none | |
| persist-credentials: false | |
| sparse-checkout: | | |
| scripts/classify-docs-only.mjs | |
| sparse-checkout-cone-mode: false | |
| - name: Classify changed files | |
| id: classify | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| set -euo pipefail | |
| files_file="$(mktemp)" | |
| trap 'rm -f "$files_file"' EXIT | |
| if ! changed_files="$( | |
| gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" \ | |
| --jq '.changed_files' | |
| )"; then | |
| echo "Could not read the PR changed-files count; failing open so heavy jobs run." | |
| node scripts/classify-docs-only.mjs --listing-error | |
| exit 0 | |
| fi | |
| if ! gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/files" \ | |
| --paginate \ | |
| --jq '.[] | [.filename, (.previous_filename // "")] | @tsv' \ | |
| > "$files_file"; then | |
| echo "Could not list changed files; failing open so heavy jobs run." | |
| node scripts/classify-docs-only.mjs --listing-error | |
| exit 0 | |
| fi | |
| node scripts/classify-docs-only.mjs \ | |
| --changed-files-count "$changed_files" \ | |
| --listing "$files_file" | |
| # Builds and checks every public example through its own toolchain. | |
| examples-check: | |
| needs: changes | |
| if: >- | |
| ${{ !cancelled() && github.event_name != 'schedule' && | |
| (github.event_name != 'pull_request' || needs.changes.outputs.docs_only != 'true') }} | |
| name: Examples check (Node 22.19) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/setup@v2 | |
| with: | |
| cache: true | |
| install: false | |
| runtime: node@22.19.0 | |
| - run: pnpm install --frozen-lockfile | |
| - run: pnpm examples:check | |
| verify: | |
| needs: changes | |
| if: >- | |
| ${{ !cancelled() && github.event_name != 'schedule' && | |
| (github.event_name != 'pull_request' || needs.changes.outputs.docs_only != 'true') }} | |
| name: Verify (Node ${{ matrix.node-version }}) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| # Measured PR Verify cost was 3 legs × ~7 minutes, about 75% of PR | |
| # runner-minutes. PRs run newest-LTS Node 24; every main push and manual | |
| # dispatch still gates on the full supported matrix. | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| node-version: ${{ github.event_name == 'pull_request' && fromJSON('["24"]') || fromJSON('["22.19.0","24","26"]') }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/setup@v2 | |
| with: | |
| cache: true | |
| install: false | |
| runtime: node@${{ matrix.node-version }} | |
| - run: pnpm install --frozen-lockfile | |
| # Tests launch branded Chrome (`channel: 'chrome'`), which Playwright | |
| # installs system-wide via apt — never into ~/.cache/ms-playwright, so | |
| # a browser cache cannot help. In CI, `playwright install chrome` | |
| # unconditionally removes and re-downloads ~120 MB of Chrome per job, | |
| # while ubuntu-latest images already ship Google Chrome stable with its | |
| # OS deps. Reuse it; fall back to the full install (browser + deps) if | |
| # the runner image ever drops it. | |
| - name: Ensure branded Chrome for Playwright | |
| run: | | |
| if command -v google-chrome >/dev/null 2>&1; then | |
| echo "Using preinstalled $(google-chrome --version)" | |
| else | |
| pnpm exec playwright install --with-deps chrome | |
| fi | |
| # Build first: checked-in suites and API tests import the package's built type | |
| # declarations, so typecheck requires dist (same order as `pnpm check`). | |
| - run: pnpm build | |
| - name: Package lint (publint) | |
| run: pnpm lint:package | |
| - run: pnpm typecheck | |
| - run: pnpm lint | |
| - run: pnpm test | |
| release-gates: | |
| needs: changes | |
| if: >- | |
| ${{ !cancelled() && github.event_name != 'schedule' && | |
| (github.event_name != 'pull_request' || needs.changes.outputs.docs_only != 'true') }} | |
| name: Release gates (Node 22.19) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/setup@v2 | |
| with: | |
| cache: true | |
| install: false | |
| runtime: node@22.19.0 | |
| - run: pnpm install --frozen-lockfile | |
| # Reuse the runner image's Chrome; see the Verify job for the rationale. | |
| - name: Ensure branded Chrome for Playwright | |
| run: | | |
| if command -v google-chrome >/dev/null 2>&1; then | |
| echo "Using preinstalled $(google-chrome --version)" | |
| else | |
| pnpm exec playwright install --with-deps chrome | |
| fi | |
| # Per-PR packed pool: single pack+install proofs plus the | |
| # minimal-template scaffolder smoke. The full template matrix runs in | |
| # the nightly packed-matrix job and in pre-publish `pnpm check:release`. | |
| - run: pnpm check:release:ci | |
| # Binary-gated real-host install proofs. The proof suites skip their Claude | |
| # and Codex legs when the CLIs are absent, which is how #364 changed the | |
| # Codex `interface.logo` emission and broke both proofs on main without CI | |
| # noticing (#367/#368 repaired them from local runs). This job installs the | |
| # exact CLI versions pinned in each adapter's schema PROVENANCE.json | |
| # (`hostCli`, kept equal to `observedCliVersion` by scripts/host-cli-pins.mjs), | |
| # fails closed if `claude`/`codex --version` differs from the pin, and runs | |
| # the source-built proofs, the packed-tarball proofs, and the packed Claude | |
| # plugin validation. Nothing here needs a login: every proof runs against an | |
| # isolated HOME / CLAUDE_CONFIG_DIR / CODEX_HOME and no secrets are passed. | |
| # Signed-in smokes (`claude -p`, `codex exec`, the Eval harnesses) stay in | |
| # the opt-in native-host-smoke workflow. | |
| host-install-proofs: | |
| needs: changes | |
| if: >- | |
| ${{ !cancelled() && github.event_name != 'schedule' && | |
| (github.event_name != 'pull_request' || needs.changes.outputs.docs_only != 'true') }} | |
| name: Host install proofs (Node 22.19) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/setup@v2 | |
| with: | |
| cache: true | |
| install: false | |
| runtime: node@22.19.0 | |
| - run: pnpm install --frozen-lockfile | |
| - name: Read pinned host CLI versions | |
| id: pins | |
| run: node scripts/host-cli-pins.mjs print | |
| # The global npm prefix holding both CLIs (Claude Code and Codex ship | |
| # platform-native binaries), keyed by OS, arch, and the exact pins | |
| # (package name and version per host) so a deliberate re-pin of either | |
| # misses the cache and installs fresh. | |
| - name: Restore pinned host CLIs | |
| id: host-cli-cache | |
| uses: actions/cache@v6 | |
| with: | |
| path: ${{ runner.temp }}/host-cli | |
| key: host-cli-${{ runner.os }}-${{ runner.arch }}-${{ steps.pins.outputs.pins }} | |
| - name: Install pinned host CLIs | |
| if: steps.host-cli-cache.outputs.cache-hit != 'true' | |
| run: node scripts/host-cli-pins.mjs install --prefix "$RUNNER_TEMP/host-cli" | |
| # ubuntu runner: npm's global executables live in <prefix>/bin (the | |
| # script's globalBinDirectory rule; Windows would be the prefix itself). | |
| - name: Expose host CLIs on PATH | |
| run: echo "$RUNNER_TEMP/host-cli/bin" >> "$GITHUB_PATH" | |
| - name: Verify host CLI versions match the schema pins | |
| run: node scripts/host-cli-pins.mjs verify | |
| - run: pnpm build | |
| - name: Host install proofs (source-built bundle) | |
| run: pnpm test:host-install | |
| - name: Host install proofs (packed tarball) | |
| run: pnpm test:host-install:packed | |
| - name: Packed Claude plugin validation proof | |
| env: | |
| AGENT_BUNDLE_PACKAGE_PREBUILT: '1' | |
| run: pnpm test:packed:native | |
| # Release-boundary scaffolder template matrix (mcp-server, cli-tool) plus | |
| # the full packed pool — the nightly form of pre-publish `check:release`. | |
| packed-matrix: | |
| if: github.event_name == 'schedule' | |
| name: Packed release matrix (Node 22.19) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 40 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/setup@v2 | |
| with: | |
| cache: true | |
| install: false | |
| runtime: node@22.19.0 | |
| - run: pnpm install --frozen-lockfile | |
| # Reuse the runner image's Chrome; see the Verify job for the rationale. | |
| - name: Ensure branded Chrome for Playwright | |
| run: | | |
| if command -v google-chrome >/dev/null 2>&1; then | |
| echo "Using preinstalled $(google-chrome --version)" | |
| else | |
| pnpm exec playwright install --with-deps chrome | |
| fi | |
| - run: pnpm check:release | |
| # Nightly evidence-capture pool: documentation-artifact browser | |
| # journeys whose behavioral contracts are already proven per PR by the | |
| # integration pool (see nightlyEvidenceTestFiles). | |
| - run: pnpm test:evidence | |
| rsc-runtime-micro-eval: | |
| # Deterministic end-to-end spot-check of the built RSC runtime artifacts | |
| # (hook -> RSC worker -> shared kernel state -> MCP tool lowering) without | |
| # any real Claude/Codex host. Login-free real-host install proofs run in | |
| # the host-install-proofs job; signed-in native smokes stay skip-gated in | |
| # the manually dispatched native-host-smoke workflow on purpose. | |
| needs: changes | |
| if: >- | |
| ${{ !cancelled() && github.event_name != 'schedule' && | |
| (github.event_name != 'pull_request' || needs.changes.outputs.docs_only != 'true') }} | |
| name: RSC runtime micro-eval (Node 22.19) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/setup@v2 | |
| with: | |
| cache: true | |
| install: false | |
| runtime: node@22.19.0 | |
| - run: pnpm install --frozen-lockfile | |
| - run: pnpm eval:spot | |
| dependency-review: | |
| if: github.event_name == 'pull_request' | |
| name: Dependency review | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/dependency-review-action@v5 |