Coordinate bridge dev builds behind one generation pipeline#20
Merged
Conversation
The bridge generation validation tests reference the real dist/ directory, which only exists after building ai-provider-bridge. The check CI job only builds ai-config and ai-credentials before running tests, so these tests fail with ENOENT in CI while passing locally (where dist/ exists from prior builds). Give the coordinator tests a dedicated vitest config so they only run via test:build-coordinator in the bridge-generation CI job, which builds the bridge first.
wch
enabled auto-merge (squash)
July 21, 2026 16:52
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ai-provider-bridgeisn't a TypeScript project reference — it's built by esbuild, with a separate declaration build on top. Previously, watch mode ran multiple watchers writing into the samedist/independently, so a downstream bundler (Standalone, RStudio, Positron, Desktop) could observe a half-written generation — a missing export, a stale declaration file — and crash or reload-loop. This PR replaces that with one coordinator that owns every JS and declaration write, builds a complete generation in a staging directory, validates it, promotes it without deleting live exports, and only then announces it. Downstream consumers watch that single announcement instead of rawdist/changes, so a warm dev startup that previously fell into a reload/crash cycle now starts cleanly.Changes
scripts/build-coordinator.ts(new) — the sole writer of bridge JS and declarations. Stages a generation, validates package exports and declaration resolution, promotes complete files, then writes.bridge-watch/generation.jsonand emits a machine-readable completed-generation event on stdout. Promotion is atomic per file (not a whole-directory transaction — no host filesystem gives that across platforms without changing the package layout), and a failed promotion rolls back only the files it had already replaced.dist/digests both match the persisted record re-announces the previous generation instead of rebuilding, cutting a several-second warm rebuild down to roughly half a second.scripts/build-inputs.ts(new) — one module that both fingerprints and registers file watches from the same discovered input inventory (bridgesrc//scripts/trees, package and tsconfig metadata, and built output from*/workspace:*sibling dependencies). Fingerprinting and watch coverage previously risked drifting apart if someone updated one without the other; this makes that structurally impossible. A change to a build script itself requests a coordinator restart; every other input change schedules a normal generation build.tsconfig.declarations.json(new) — the single authoritative declaration build, including the Positron subpath. The coordinator rejectsvscodeimports outsidesrc/positron/andvscodereferences outsidedist/positron/..gitignoreupdates for.bridge-watch/.Design decisions
dist/independently is what caused the original half-written-generation races. Centralizing the write path is the only way to guarantee downstream consumers never see an incomplete generation.tsconfig.jsonchange) escape both fingerprinting and live rebuild-on-change.build-inputs.tsis now the one place that answers "what affects the build output."node_modulesis deliberately excluded from the fingerprint; the rootpostinstall --cleanalready forces a rebuild after every dependency change.