Why
The catalog flow is:
- Edit
src/main/providers/catalog.source.json (or gateways/catalog.source.json)
- Run
npm run gen:catalog
npm run build re-emits dist/
- Push
Step 2 is easy to forget. When it slips, the app and CLI silently ship an outdated catalog — the user thinks their new gateway entry is present but TypeScript imports the previous types.
We already have a prebuild hook in package.json:25 that runs gen:catalog before build, which catches part of the case. But:
- It runs for
npm run build; not for npm run typecheck / npm run lint (so PR CI misses changes to source.json that don't include build)
- It doesn't fail loudly — if the script fails (rare but possible) the build still proceeds
- The generated file doesn't carry a metadata fingerprint
Scope
- Add a top-level
scripts/check-catalog-stale.mjs that:
- Runs
gen:catalog logic in-memory (or shells out to it)
- Compares the resulting TS to the current
catalog.generated.ts
- Exits non-zero with a clear diff message if they differ
- Wire it into a new
catalog:check npm script.
- Add it to
.github/workflows/ci.yml app job, run before typecheck.
- Add a hash fingerprint comment to the generated files (
// hash: 7f9b2...) so the check can verify byte-stable output without re-running gen.
- Keep the
prebuild hook as a convenience so local builds stay hassle-free.
Acceptance criteria
Non-goals
- Auto-running gen in CI (CI shouldn't generate files — keep
gen:catalog as a developer step)
- A separate "verify fingerprint" check beyond the
== comparison
References
scripts/gen-catalog.mjs (current generator)
package.json:25 (current prebuild hook)
.github/workflows/ci.yml (app + cli jobs)
Why
The catalog flow is:
src/main/providers/catalog.source.json(orgateways/catalog.source.json)npm run gen:catalognpm run buildre-emitsdist/Step 2 is easy to forget. When it slips, the app and CLI silently ship an outdated catalog — the user thinks their new gateway entry is present but TypeScript imports the previous types.
We already have a
prebuildhook inpackage.json:25that runsgen:catalogbeforebuild, which catches part of the case. But:npm run build; not fornpm run typecheck/npm run lint(so PR CI misses changes tosource.jsonthat don't includebuild)Scope
scripts/check-catalog-stale.mjsthat:gen:cataloglogic in-memory (or shells out to it)catalog.generated.tscatalog:checknpm script..github/workflows/ci.ymlappjob, run beforetypecheck.// hash: 7f9b2...) so the check can verify byte-stable output without re-running gen.prebuildhook as a convenience so local builds stay hassle-free.Acceptance criteria
catalog.source.jsonwithout re-running gen makes CI fail with:"catalog.generated.ts is stale. Run: npm run gen:catalog"npm run catalog:checkaftergen:catalogexits 0.ci.yml's app job (and CLI job if relevant).catalog.generated.tscarries a fingerprint line that updates when source changes.Non-goals
gen:catalogas a developer step)==comparisonReferences
scripts/gen-catalog.mjs(current generator)package.json:25(currentprebuildhook).github/workflows/ci.yml(app + cli jobs)