Read codemod target versions from workspace manifests at build time#2419
Conversation
The committed generated versions.ts went stale after every release: the changesets version PR bumps package.json files without regenerating, so source builds of the codemod wrote outdated versions into migrated projects (and every local build dirtied the tree regenerating the file). Replace the generated file with a plain source module that imports the six workspace package.json files directly; the bundler inlines the version fields at build time. Deletes the generator script, the prebuild hook, and the generated/ directory.
🦋 Changeset detectedLatest commit: 372c597 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
There was a problem hiding this comment.
LGTM — clean removal of committed derived state; the codemod's version map now stays in lockstep with the workspace manifests by construction. Only nit is the import-order lint warning noted inline.
Extended reasoning...
Overview
This PR is confined to packages/codemod internals: it deletes the committed generated src/generated/versions.ts, the generateVersions.ts script, and the prebuild hook, replacing them with a plain src/versions.ts that imports the six sibling workspace package.json files so the bundler inlines the version fields at build time. Two import-specifier updates and a changeset round out the diff (net −28 lines).
Correctness
The approach is sound and verified: the shared tsconfig base (common/tsconfig/tsconfig.json) already enables resolveJsonModule and moduleResolution: bundler, so no config changes are needed; tsdown bundles the JSON imports into dist, so the published artifact (which ships only dist/) has no runtime dependency on sibling manifests. The map's shape and keys are unchanged, so consumers (packageJsonUpdater.ts, batchTest.ts) are unaffected beyond the specifier rename. The only issue found is a cosmetic simple-import-sort warning from the un-resorted import blocks (flagged inline); it does not fail CI.
Security risks
None. This is dev-tooling/build-process code in the codemod package — no protocol, transport, auth, or runtime SDK surface is touched. The versions written into migrated projects now come from the workspace manifests instead of a hand-committed copy, which is strictly more accurate.
Level of scrutiny
Low-to-moderate: this is a small, well-scoped refactor of internal tooling that removes duplicated derived state rather than adding API surface, aligning with the repo's minimalism principle. V2_PACKAGE_VERSIONS is internal to the codemod, there are no breaking changes, the changeset accurately describes the change, and the author's testing (dist inspection, CLI runs against fixtures, full suite, clean working tree after build) covers the relevant failure modes.
There was a problem hiding this comment.
LGTM — clean removal of committed derived state; the versions now flow from the workspace manifests at build time and the earlier import-sort nit was addressed.
Extended reasoning...
Overview
This PR is confined to the internal @modelcontextprotocol/codemod package: it deletes the committed src/generated/versions.ts and its generator script/prebuild hook, and replaces them with a plain src/versions.ts that imports the six workspace package.json files so the bundler inlines the version fields at build time. The two consumers (packageJsonUpdater.ts, bin/batchTest.ts) only have their import specifiers updated, plus a changeset.
Security risks
None. No network, auth, or user-input handling is touched; the change only affects which version strings the codemod writes into migrated projects' package.json files, sourced from the repo's own manifests.
Level of scrutiny
Low. This is dev/build tooling for an internal, non-runtime-exported constant (V2_PACKAGE_VERSIONS is not part of any public API surface). The shared tsconfig already sets resolveJsonModule and moduleResolution: bundler, so the JSON imports typecheck, and tsdown bundles the relative JSON imports into dist, so the published artifact has no runtime reads of sibling manifests. The design (delete derived state rather than keep it in sync by process) is the simpler alternative and removes a recurring stale-file problem after each changesets release.
Other factors
The bug-hunting pass found no issues; my earlier inline note about import ordering was addressed in the follow-up commit (verified via lint:fix). CI covers typecheck/lint/build/tests for the package, and the author reports the built CLI now writes the current beta.2 ranges with idempotent re-runs. No documentation or migration-guide updates are needed since behavior toward end users is a bugfix (correct versions) with no API change.
Running
pnpm install && pnpm buildon a fresh clone leaves the repo dirty: the build regeneratespackages/codemod/src/generated/versions.tswith contents that differ from what's committed.Motivation and Context
The file is generated from the workspace
package.jsonversions, but the changesets "Version Packages" PR bumps those manifests without regenerating it (most recently #2416, beta.1 → beta.2). So after every release the committed copy is stale — every local build produces the diff, and source builds of the codemod write the stale versions into migrated projects (^2.0.0-beta.1instead of^2.0.0-beta.2). Published artifacts were unaffected since publishing rebuilds.Fix: stop committing derived state.
src/versions.tsis now a normal source file that imports the six workspacepackage.jsons; the bundler inlines the version fields at build time. The generator script,prebuildhook, andgenerated/directory are deleted. Version bumps flow through automatically; the only hand-maintained part is the name→path list the generator already hardcoded, now as imports that fail typecheck if a package moves. No tsconfig changes needed (resolveJsonModuleandmoduleResolution: bundlerare already set).How Has This Been Tested?
pnpm buildno longer modifies the tree.dist/has all six versions inlined; no runtime reads of sibling manifests.^2.0.0-beta.2(was stale^2.0.0-beta.1), devDependencies placement kept,--dry-runwrites nothing, re-run is idempotent.Breaking Changes
None.
V2_PACKAGE_VERSIONSis internal to the codemod.Types of changes
Checklist
Additional context
Alternatives considered: gitignoring the generated file (CI typechecks before building, so fresh clones would need extra generate hooks) and regenerating inside the changesets version command (fixes the release writer but keeps the duplicated state in sync by process rather than by construction).