From 6a7e931f7ebf78811651ae965f77f4bdb8efec5d Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 13 Sep 2026 20:48:00 -0700 Subject: [PATCH] Pin Bun for reproducible embedded review bundles CI used a newer minifier than the local release build. Keep the byte-for-byte drift check and use one explicit build toolchain across local regeneration and CI. AI assistance: OpenAI Codex. --- .bun-version | 1 + .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/sync-generated-output.yml | 2 +- scripts/build-component-review.mjs | 3 +++ ui/component-review/README.md | 2 +- 5 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 .bun-version diff --git a/.bun-version b/.bun-version new file mode 100644 index 000000000..7962dcfdb --- /dev/null +++ b/.bun-version @@ -0,0 +1 @@ +1.3.13 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8c84e8e4..4609d8063 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,7 +77,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Install dependencies run: bun install @@ -235,7 +235,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Install dependencies run: bun install @@ -313,7 +313,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Install dependencies run: bun install @@ -359,7 +359,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Cache fixture npm downloads uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 @@ -445,7 +445,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Cache fixture npm downloads uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 @@ -523,7 +523,7 @@ jobs: if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }} uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Cache fixture npm downloads if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }} @@ -600,7 +600,7 @@ jobs: if: ${{ env.DEEPSEEK_API_KEY != '' }} uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Cache fixture npm downloads if: ${{ env.DEEPSEEK_API_KEY != '' }} @@ -665,7 +665,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Install dependencies run: bun install @@ -695,7 +695,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Install dependencies run: bun install --frozen-lockfile - name: Prepare engine and browser before billing diff --git a/.github/workflows/sync-generated-output.yml b/.github/workflows/sync-generated-output.yml index 2f1090ecc..609e18f91 100644 --- a/.github/workflows/sync-generated-output.yml +++ b/.github/workflows/sync-generated-output.yml @@ -67,7 +67,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version: latest + bun-version-file: .bun-version - name: Install dependencies run: bun install --frozen-lockfile diff --git a/scripts/build-component-review.mjs b/scripts/build-component-review.mjs index 5ff942dcc..8ca23967b 100644 --- a/scripts/build-component-review.mjs +++ b/scripts/build-component-review.mjs @@ -1,7 +1,10 @@ // Source bundle embedded in the native engine; no Node/Bun is needed at runtime. import { fileURLToPath } from 'node:url'; import { resolve } from 'node:path'; +import { readFileSync } from 'node:fs'; const root = fileURLToPath(new URL('../', import.meta.url)); +const pinnedBun = readFileSync(resolve(root, '.bun-version'), 'utf8').trim(); +if (Bun.version !== pinnedBun) throw new Error(`Component review bundles require Bun ${pinnedBun}; received ${Bun.version}. Use the pinned toolchain before regenerating tracked output.`); const result = await Bun.build({ entrypoints: [resolve(root, 'ui/component-review/entry.ts')], target: 'browser', format: 'iife', minify: true }); if (!result.success) throw new AggregateError(result.logs, 'Component review bundle failed'); await Bun.write(resolve(root, 'crates/context/assets/component-review.js'), await result.outputs[0].text()); diff --git a/ui/component-review/README.md b/ui/component-review/README.md index affef8b70..2a2fb0e7b 100644 --- a/ui/component-review/README.md +++ b/ui/component-review/README.md @@ -12,7 +12,7 @@ The dashboard route `/dashboard/component-review/` is a temporary review checkpo ## Native runtime -Build the shared UI with `bun run build:component-review`, then rebuild the engine. It embeds the JS and licensed fonts; the runtime needs no Node server or dashboard. The bundled asset is tracked alongside the native consumer, and the bundle test catches source drift. +Use the Bun version in `.bun-version` (also used by CI). Build the shared UI with `bun run build:component-review`, then rebuild the engine. It embeds the JS and licensed fonts; the runtime needs no Node server or dashboard. The bundled asset is tracked alongside the native consumer, and the bundle test catches source drift. From a project, run `impeccable component-review prepare --manifest review.json`. The manifest uses the UI packet shape plus `schemaVersion: 1`; replace each preview/comp/context/thumbnail `url` with a project-relative `path`, and declare each component's `dependencies` (CSS, images, fonts and other inputs used by its rendered preview). The service assigns revisions and round numbers. Paths outside the project are refused. Prepare prints a session ID. Start `impeccable component-review serve --session ` and open the returned loopback URL. `status --session ` reads the saved result. The default store is `~/.impeccable/component-reviews`; a test may use `--store `.