Skip to content

fix(migrate): resolve husky version from catalog during hooks check#1710

Merged
fengmk2 merged 8 commits into
mainfrom
fix/migrate-husky-catalog-version
Jun 1, 2026
Merged

fix(migrate): resolve husky version from catalog during hooks check#1710
fengmk2 merged 8 commits into
mainfrom
fix/migrate-husky-catalog-version

Conversation

@fengmk2
Copy link
Copy Markdown
Member

@fengmk2 fengmk2 commented May 29, 2026

Problem

vp migrate's git-hooks preflight could not determine the husky version when it was pinned via a catalog reference. In a pnpm catalog monorepo such as vite-task:

  • package.json"husky": "catalog:"
  • pnpm-workspace.yamlcatalog: { husky: ^9.1.7 } (a compatible v9)

semver.coerce("catalog:") returns null, and the node_modules fallback is empty during migration, so it warned:

⚠ Could not determine husky version from "catalog:" — please specify a semver-compatible version (e.g., "^9.0.0") and re-run migration.

As a result, pre-commit hooks were never configured and husky/lint-staged were left in devDependencies, even though the catalog declared a perfectly compatible version.

Fix

checkUnsupportedHuskyVersion now resolves a catalog: / catalog:<name> spec from the workspace catalog before falling back to node_modules. A new read-only, package-manager-agnostic helper resolveCatalogSpecFromProject looks the spec up in:

  • pnpm-workspace.yaml
  • .yarnrc.yml
  • package.json catalog / catalogs (including Bun's workspaces form)

reusing the existing createCatalogDependencyResolverFromCatalogs. The genuinely-uncoercible path (e.g. "latest" with no catalog entry) still degrades to the same warning.

Testing

  • Added global snap test migration-husky-catalog-version mirroring the real-world vite-task setup. It captured the bug before the fix; after the fix it shows no warning, husky/lint-staged removed, preparevp config, staged config merged into vite.config.ts, and .vite-hooks/pre-commit created.
  • All existing husky/hook global snap tests re-run with no snapshot drift.
  • migration-husky-latest-dist-tag still warns (degradation path intact).
  • 107 migration unit tests pass; vp check (format/lint/type-check) clean.

Note

Low Risk
Behavior change is limited to husky version preflight during optional git-hooks setup; existing semver and node_modules paths are unchanged when catalog resolution does not apply.

Overview
Git hooks preflight now resolves "husky": "catalog:" through the active package manager’s catalog (via existing createCatalogDependencyResolver) before falling back to node_modules, so compatible v9 catalog pins no longer trigger a false “could not determine husky version” warning and skip hook migration.

packageManager is threaded into preflightGitHooksSetup, checkUnsupportedHuskyVersion, setupGitHooks, and installGitHooks from migrate, create, and the already-on-Vite+ hooks path so catalog lookup stays scoped to pnpm vs yarn vs bun (e.g. yarn ignores a stray pnpm-workspace.yaml).

Adds a global snap test migration-husky-catalog-version and unit tests for allow, reject husky <9, and foreign-catalog behavior.

Reviewed by Cursor Bugbot for commit 834fd3a. Configure here.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 29, 2026

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit 83a4c7f
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a1d34442a4e7c0008072e1c

@fengmk2 fengmk2 self-assigned this May 29, 2026
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented May 29, 2026

@cursor review

@fengmk2 fengmk2 added test: e2e Auto run e2e tests test: create-e2e Run `vp create` e2e tests labels May 29, 2026
Comment thread packages/cli/src/migration/migrator.ts Outdated
@fengmk2 fengmk2 force-pushed the fix/migrate-husky-catalog-version branch from 82f3a2a to b608c27 Compare May 31, 2026 02:14
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented May 31, 2026

@cursor review

Comment thread packages/cli/src/migration/migrator.ts Outdated
fengmk2 added 3 commits May 31, 2026 20:26
`vp migrate`'s git-hooks preflight could not determine the husky version
when it was pinned via a catalog reference (e.g. `"husky": "catalog:"`
in package.json with the real version in `pnpm-workspace.yaml`'s catalog).
`semver.coerce("catalog:")` returns null and the node_modules fallback is
empty during migration, so it warned:

  Could not determine husky version from "catalog:" — please specify a
  semver-compatible version (e.g., "^9.0.0") and re-run migration.

As a result pre-commit hooks were never configured and husky/lint-staged
were left in devDependencies, even when the catalog declared a compatible
v9.

`checkUnsupportedHuskyVersion` now resolves a `catalog:`/`catalog:<name>`
spec from the workspace catalog (pnpm-workspace.yaml, .yarnrc.yml, or
package.json `catalog`/`catalogs`) before falling back to node_modules.
Adds the `migration-husky-catalog-version` global snap test covering the
real-world setup.
Address PR review: `resolveCatalogSpecFromProject` duplicated the
file-reading/resolution logic in `createCatalogDependencyResolver`.
Iterate over the package managers and reuse that resolver instead, so
catalog resolution logic stays in sync in one place.
…nager

Address PR review (medium): the previous helper walked every package
manager and returned the first catalog hit, so a leftover/foreign catalog
file (e.g. a stray pnpm-workspace.yaml in a yarn repo) could resolve
husky's version from the wrong catalog and skip/allow hooks migration
incorrectly.

A `catalog:` spec is only meaningful to the manager that owns the
workspace, so thread the detected package manager through
installGitHooks/setupGitHooks/preflightGitHooksSetup into
checkUnsupportedHuskyVersion and resolve the catalog with that manager
only. Adds unit tests covering pnpm catalog resolution (compatible and
<9) and the foreign-catalog case where a yarn project ignores a leftover
pnpm-workspace.yaml.
@fengmk2 fengmk2 force-pushed the fix/migrate-husky-catalog-version branch from 900b944 to 834fd3a Compare May 31, 2026 12:26
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented May 31, 2026

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 834fd3a. Configure here.

fengmk2 added 2 commits May 31, 2026 21:26
Address code-review findings:

- `createCatalogDependencyResolverFromCatalogs` routed `catalog:default` to a
  named `catalogs.default` entry, but pnpm/bun reserve `default` for the
  top-level `catalog:` map. A `husky: "catalog:default"` spec (or any dep using
  the explicit default alias) therefore failed to resolve, producing a spurious
  "Could not determine husky version" warning and skipped hooks. Treat
  `default` as the default catalog, and refactor the bun branch to reuse the
  shared resolver so the fix applies there too and the duplicated logic is gone.

- Strengthen the yarn hooks test to be discriminating (the active manager's
  catalog is used and a foreign one ignored) and add a `catalog:default`
  regression test.
@fengmk2 fengmk2 marked this pull request as ready for review June 1, 2026 02:58
@fengmk2 fengmk2 requested a review from cpojer June 1, 2026 02:58
@fengmk2 fengmk2 merged commit 183f8e7 into main Jun 1, 2026
114 of 117 checks passed
@fengmk2 fengmk2 deleted the fix/migrate-husky-catalog-version branch June 1, 2026 08:07
@fengmk2 fengmk2 mentioned this pull request Jun 1, 2026
fengmk2 added a commit that referenced this pull request Jun 1, 2026
Release vite-plus v0.1.24.

A new `vp pm stage` publishing workflow, hardened installs and upgrades,
a Node-version mismatch reinstall prompt, and the bundled
vite/vitest/tsdown stack moves forward.

### Features

- `vp pm stage`: a new `vp pm` subcommand exposing npm's
staged-publishing workflow (upload a build to a staging area without
2FA, then approve or reject it from a trusted device); it maps to `pnpm
stage` / `npm stage` / `yarn npm ... --staged` per package manager, with
an npm fallback for yarn Classic and bun
([#1715](#1715)), by
@fengmk2
- `vp`: prompt to reinstall when up-to-date global packages were built
against a different Node.js than the active one (defaults to no); adds
`--reinstall-node-mismatch` and `--ignore-node-mismatch`, and skips the
prompt in CI
([#1666](#1666)), by
@liangmiQwQ
- `vp format`: add `format` as a visible alias of `vp fmt`, so the
common slip `vp format` resolves correctly and `vp format --init` /
`--migrate` apply the same `vite.config.ts` wiring as `vp fmt`
([#1727](#1727)), by
@semimikoh

### Fixes & Enhancements

- `vp install` / Node runtime download: HTTP retries now wrap the whole
body stream, hash verification, and archive extraction (not just the
request headers), so truncated or corrupt downloads of package managers
and Node are re-fetched instead of failing on the first attempt
([#1719](#1719)), by
@fengmk2
- `vp upgrade --force` on Windows: install into a fresh directory before
repointing `current`, so the forced reinstall no longer fails trying to
overwrite the running `vp.exe`
([#1714](#1714)), by
@fengmk2
- `vp install -g`: install global packages directly into their final
prefix instead of a temp dir that gets moved, so packages whose
postinstall scripts bake in absolute or relative temp paths still
resolve their bins; a failed package in a multi-package install no
longer removes the shims of the ones that already succeeded
([#1698](#1698)), by
@liangmiQwQ
- `vp why`: remove the `-g` / `--global` flag, which delegated to the
package manager's global mode and ignored Vite+-managed global packages;
`vp why` stays project-scoped while `vp outdated -g` keeps using the
managed global flow
([#1720](#1720)), by
@liangmiQwQ
- Windows installer: remove the existing `current` link via PowerShell
(detecting junctions, symlinks, and stale directories) instead of `cmd
/c rmdir`, which could fail with "The directory is not empty"
([#1726](#1726)), by
@TheAlexLichter
- `vp create`: skip editor-config detection and package-local editor
settings by default when creating a project inside an existing monorepo;
`--editor <name>` stays an explicit opt-in and `--no-editor` an opt-out
([#1729](#1729)), by
@jong-kyung
- `vp create vite:monorepo` (pnpm): keep the aliased `vite`/`vitest` in
the website app's `package.json` so the workspace `overrides.vite:
catalog:` has a direct consumer and `vp why vite` resolves to
`@voidzero-dev/vite-plus-core`; npm/yarn/bun still drop the dead-weight
keys ([#1728](#1728)), by
@fengmk2
- `vp pack`: rewrite direct `createRequire(...)("picomatch")` calls in
bundled tsdown output to the local bundled CJS entry, so packing no
longer depends on an undeclared runtime `picomatch` under pnpm `hoist:
false` ([#1732](#1732)),
by @fengmk2
- `vp migrate`: resolve a `catalog:` husky pin from the workspace
catalog (`pnpm-workspace.yaml`, `.yarnrc.yml`, or `package.json`
catalogs) during the git-hooks preflight, so a compatible catalog-pinned
husky no longer triggers a false "could not determine husky version"
warning and skips hook setup
([#1710](#1710)), by
@fengmk2

### Docs

- Add a **Copy Prompt** button to the docs site that copies an
AI-friendly getting-started prompt (intro, `llms-full.txt` pointer,
install commands, and core `vp` commands) for handing straight to a
coding agent
([#1706](#1706)), by
@fengmk2
- Update `troubleshooting.md`: `vite.config.ts` related issues are
resolved by updating oxlint and oxfmt
([#1708](#1708)), by
@leaysgur
- Clarify the product and repository documentation locations and the new
Run guide/config paths in `AGENTS.md`
([#1707](#1707)), by
@leaysgur

### Chore

- `vp` install: reduce retained `vp` versions from 5 to 3 across the
installer, `vp upgrade`, and the shell/PowerShell bootstrap scripts
(active and previous versions stay protected for rollback); document the
3-version retention and `vp upgrade --rollback`
([#1716](#1716)), by
@fengmk2
- Exclude the snap-tests directory from Vitest config discovery so the
VS Code Vitest extension stops generating a stray
`.vitest-plugin-loaded` file
([#1723](#1723)), by
@liangmiQwQ
- Refresh trusted stack stats on the docs homepage
([#1734](#1734)), by
@voidzero-guard[bot]
- Update @wan9chi's GitHub handle (formerly `branchseer`)
([#1705](#1705)), by
@wan9chi
- Update GitHub Actions
([#1724](#1724),
[#1730](#1730)), by
@renovate[bot]
- Upgrade upstream dependencies: vite `8.0.14 → 8.0.16`, vitest `4.1.7 →
4.1.8`, tsdown `0.22.0 → 0.22.1`, `@vitejs/devtools` `0.2.0 → 0.3.1`
([#1713](#1713),
[#1735](#1735),
[#1737](#1737)), by
@voidzero-guard[bot]

### Bundled Versions

| Tool | Version | Source |
| --- | --- | --- |
| vite | `8.0.16` |
[`f94df87`](vitejs/vite@f94df87)
|
| rolldown | `1.0.3` |
[`a287faa`](rolldown/rolldown@a287faa)
|
| tsdown | `0.22.1` | [npm](https://npmx.dev/package/tsdown/v/0.22.1) |
| vitest | `4.1.8` | [npm](https://npmx.dev/package/vitest/v/4.1.8) |
| oxlint | `1.67.0` | [npm](https://npmx.dev/package/oxlint/v/1.67.0) |
| oxlint-tsgolint | `0.23.0` |
[npm](https://npmx.dev/package/oxlint-tsgolint/v/0.23.0) |
| oxfmt | `0.52.0` | [npm](https://npmx.dev/package/oxfmt/v/0.52.0) |

### New Contributors

Welcome to our new contributor @semimikoh! 🎉

**Full Changelog**:
v0.1.23...v0.1.24

Merging this PR will trigger the release workflow.

---------

Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com>
Co-authored-by: MK <fengmk2@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test: create-e2e Run `vp create` e2e tests test: e2e Auto run e2e tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants