fix(codemods): install with the project's real package manager - #3041
Merged
Merged
Conversation
Contributor
🚀 Preview DeploymentPreview environments are ready:
Images:
|
mfal
force-pushed
the
claude/codemods-package-manager
branch
from
August 31, 2026 16:03
e1492b2 to
44fe599
Compare
mfal
marked this pull request as ready for review
August 31, 2026 16:27
This was referenced Sep 1, 2026
`list` printed a runnable command per codemod entry with the path argument fixed to `src`. On a project whose sources are anywhere else, pasting that line runs the codemod against a directory that does not exist — and the run then reports "no files under <path> were processed. Is the path right?", sending the reader after a path the tool handed them. `displaySourcePath` sits beside `resolveSourcePath` and makes the same choice in the form a reader would type: an explicit `--path` verbatim, else `src` when it exists, else `.` — never an omitted argument, which would default back to `src` and pick the wrong tree. `renderList` takes it as `path`, and both call sites fill it: `list` from `--path` and the real cwd, `upgrade` with the path that run actually used, so a command copied out of the by-hand block works. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 8d1a0b9) (cherry picked from commit f3c77b6)
`upgrade` detected a package manager lockfiles-in-cwd-only, and the execution had three further holes. All of it is live in the published `latest` — the upgrade CLI shipped in 1.1.0 — so this is a fix on `main`, not a feature. Implements the approved design in `2026-08-31-upgrade-cli-package-manager-design.md`. The reported failure: a Yarn 4 workspace package. It has no lockfile of its own, so detection fell through to npm and ran `npm install` on a `workspace:*` manifest — `EUNSUPPORTEDPROTOCOL`, after the bump was already written. `package-manager-detector@1.8.0` (MIT, zero dependencies) does detection and command resolution; execution stays ours, because that is where the test seams, the frozen-lockfile quirks and the Windows handling live. Verified its behaviour against the installed package rather than from memory: strategies apply in order per directory walking up, `version` is the string `"berry"` for Yarn 2+, and its `"install"` is the plain install for every agent. - Detection walks up, and now covers `packageManager`, `devEngines.packageManager` and the `node_modules` install metadata as well as lockfiles. npm stays the fallback. - A `packageManager` pin is honoured: binary satisfies it → run directly; mismatch or missing → corepack with `COREPACK_ENABLE_DOWNLOAD_PROMPT=0`; no corepack → refuse *before* installing, naming the pin, the found version and the install page. Checked rather than always-corepack because corepack ignores PATH and downloads into its own cache, which would hit offline CI. The check is `semver.satisfies`, not a string compare: `pnpm@8` yields the pin `"8"` against a reported `8.15.0`. - `shell` on win32. Node has refused to spawn `.cmd` without a shell since 2024, so every non-npm manager died with ENOENT there. - The install log names agent, pin and the command actually run, so a wrong detection is visible. `install` returns that description; the failure message also names the detected manager and says the bump itself is already correct. - `resolveInvoke` gives the printed commands the right prefix — `npx` (npm and Yarn Classic, which has no `dlx`), `pnpm dlx`, `yarn dlx`, `bun x`. Verified end to end: from a nested package of a pnpm workspace, `list` prints `pnpm dlx … <id> .`, picking up both the manager from the root and the path from the package. Consequence, accepted deliberately: the bare `list` now reads lockfiles and `package.json` up the tree, so "reads no manifest" is gone from the README. It still hits no network. A command a reader can paste beats that claim. `MIGRATION.md` stays on `npx` — it is generated and cannot know the reader's manager — but now says so and names the equivalents. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mfal
force-pushed
the
claude/codemods-package-manager
branch
from
September 1, 2026 09:38
eb49e1b to
112bea7
Compare
Contributor
Coverage Report for ./packages/components/
File CoverageNo changed files found. |
The cherry-pick from the `next`-based branch carried `next`'s release bump with it — `1.2.0-next.0` against a `lerna.json` that says `1.1.3`. The `package.json` merge driver only runs on merges, not on `cherry-pick`, so nothing caught it locally either: `pnpm lint` does not include the version guard, which is its own CI step. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mfal
enabled auto-merge (squash)
September 1, 2026 11:29
Lisa18289
approved these changes
Sep 1, 2026
mfal
added a commit
that referenced
this pull request
Sep 2, 2026
The entry said `action: manual` while being the same shape as `password-tools-subpath-renamed`, which ships a codemod — one exact module specifier, swapped. Two entries with the same shape and different `action` values is hard to explain to a reader budgeting manual review. Modelled on that neighbour: every JS/TS form that names a module, and an exact match rather than a prefix, since `./styles` had nothing underneath it (so `all-layered.css` beside it is untouched). What it cannot reach is an `@import` in a `.css`/`.scss`, and `apply` says so rather than implying full coverage. `catalog.test.ts` named `renamed-css-export` as its example of a manual entry; adding the codemod broke a test that was only checking that the parser reads a non-codemod `action`. Made it id-independent — the correspondence between `action` and the transform file is enforced separately, over every entry. Reported from a real upgrade run. Extracted from #3041, which targets `next` for its package-manager work; this one corrects a catalogue entry that is already published, so it belongs on `main`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mfal
added a commit
that referenced
this pull request
Sep 2, 2026
The entry said `action: manual` while its change is mechanically decidable for
the cases the source spells out. `accent-box-color-to-background-color` is the
template: ship a codemod for the decidable subset and say in `apply` what it
will not touch.
Two changes with different decidability, and the transform treats them
differently:
- `maxWidth` always goes. The prop was removed from the type, so an explicit
attribute is wrong at any value — `maxWidth={computed}` included. Decidable
without reading the value.
- `width`/`minWidth` go only where the source literally says `null`, which is
what "no explicit width" is spelled as now. `width={maybeNull}` could be
anything at runtime and is left alone, exactly as
`accent-box-color-to-background-color` leaves `color={expression}`.
Scoped like its neighbours: only elements resolving to `TableColumn` through a
Flow import, named, aliased or namespace, subpath entries included. A spread
that might carry `maxWidth` is invisible and stays — `apply` names both gaps
rather than implying full coverage.
Reported from a real upgrade run. Extracted from #3041 for the
same reason as the entry before it: the catalogue entry is already published.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
upgradedetected a package manager lockfiles-in-cwd-only, and the execution hadthree further holes. All of it is live in the published
latest— the upgradeCLI shipped in 1.1.0 — so this targets
mainas afix, notnext.Implements the approved design in
2026-08-31-upgrade-cli-package-manager-design.md.The install
The reported failure: a Yarn 4 workspace package. It has no lockfile of its
own, so detection fell through to npm and ran
npm installon aworkspace:*manifest —
EUNSUPPORTEDPROTOCOL, after the bump was already written.package-manager-detector@1.8.0(MIT, zero dependencies) does detection andcommand resolution; execution stays ours, because that is where the test seams,
the frozen-lockfile quirks and the Windows handling live. Its behaviour was
verified against the installed package rather than from memory: strategies apply
in order per directory walking up,
versionis the string"berry"for Yarn 2+,and its
"install"is the plain install for every agent (the frozen variants area separate command there).
packageManager,devEngines.packageManagerand thenode_modulesinstall metadata as well aslockfiles. npm stays the fallback.
packageManagerpin is honoured. Binary satisfies it → run directly;mismatch or missing → corepack with
COREPACK_ENABLE_DOWNLOAD_PROMPT=0; nocorepack → refuse before installing, naming the pin, the found version and
the install page. Checked rather than always-corepack because corepack ignores
PATHand downloads into its own cache, which would hit offline CI. The checkis
semver.satisfies, not a string compare:pnpm@8yields the pin"8"against a reported
8.15.0.shellon win32. Node has refused to spawn.cmdwithout a shell since2024, so every non-npm manager died with ENOENT there.
is visible instead of silent. The failure message also names the detected
manager and says the bump itself is already correct.
The commands it prints
resolveInvokegives every printed command the right prefix —npx(npm andYarn Classic, which has no
dlx),pnpm dlx,yarn dlx,bun x— anddisplaySourcePathgives it the right path.listused to hardcodesrc, so ona project whose sources live elsewhere, pasting the printed line ran the codemod
against a directory that does not exist, and the failing run then blamed the path.
Verified end to end from a nested package of a pnpm workspace:
listprintspnpm dlx @mittwald/flow-codemods@latest <id> .— manager from the workspaceroot, path from the package.
Accepted trade: the bare
listnow reads lockfiles andpackage.jsonup thetree, so "reads no manifest" is gone from the README. It still hits no network. A
command a reader can paste beats that claim.
MIGRATION.mdstays onnpx— it isgenerated and cannot know the reader's manager — but now says so and names the
equivalents.
Scope
The two catalogue findings from the same upgrade run that used to sit here have
moved to their own PR against
main: #3047. What is left is theCLI work, which is why the base and the type changed.
Verification
test:compileclean,pnpm lintclean (0 errors,prettier green),
pnpm nx build codemodsregenerates nothing furtherinstall.test.tscovers the monorepo walk-up, the Yarn-4-as-berry distinction,devEngines, the pin tree with a stubbed probe (match → direct, mismatch →corepack, no corepack → throws naming both versions), and that
"berry"isnever treated as a pin
regenerates
MIGRATION.mdbyte-identicallyFollow-up
Two sentences in the versioning-page prompt (#3038) become redundant
once this ships: the note that
listhardcodessrc, and the warning thatpackage-manager detection is directory-local. Both stay harmless — they are
defensive advice, not claims that become wrong — and they are correct for every
currently published version. Worth trimming in a follow-up.
🤖 Generated with Claude Code