feat(hooks): add built-in pre-commit hook via vp config + vp staged - #674
Merged
Conversation
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
4 times, most recently
from
March 3, 2026 11:19
1be9cef to
8c52fb7
Compare
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
from
March 4, 2026 04:53
710944d to
c6fa1ea
Compare
✅ Deploy Preview for viteplus-staging canceled.
|
fengmk2
marked this pull request as ready for review
March 4, 2026 05:20
fengmk2
commented
Mar 4, 2026
cpojer
reviewed
Mar 4, 2026
cpojer
reviewed
Mar 4, 2026
cpojer
approved these changes
Mar 4, 2026
cpojer
left a comment
Member
There was a problem hiding this comment.
Love it. Only comment is whether it should be check-staged instead, see https://discord.com/channels/1138376133969203262/1478557890574024736/1478625219248787499
fengmk2
commented
Mar 4, 2026
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
2 times, most recently
from
March 4, 2026 10:05
1f1ad34 to
f476500
Compare
fengmk2
commented
Mar 4, 2026
fengmk2
commented
Mar 4, 2026
fengmk2
commented
Mar 4, 2026
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
2 times, most recently
from
March 4, 2026 15:45
a955dc3 to
7153742
Compare
fengmk2
commented
Mar 4, 2026
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
3 times, most recently
from
March 5, 2026 01:57
1d7d3b9 to
63481bb
Compare
Brooooooklyn
approved these changes
Mar 5, 2026
…win32 for subpath test
…r-facing `vite-staged` was an internal intermediate state during refactoring, never a real user config key. Remove the migration branch and rename all snap test fixtures from `vite-staged` to `lint-staged`.
…n setupGitHooks Instead of threading an `unsupported` flag through the rest of the function, return immediately after logging the warning. This removes all `if (!unsupported)` guards and flattens the logic.
Three P1 fixes: 1. vp create: call rewritePrepareScript() before setupGitHooks() so template "prepare": "husky" scripts are rewritten to "vp prepare" before hook setup runs. 2. vp migrate: move hasUnsupportedHuskyVersion() check before the rewrite block and thread skipStagedMigration flag through rewrite functions. This preserves lint-staged config when Husky v8 is detected, instead of deleting it while .husky/pre-commit still references npx lint-staged. 3. setupGitHooks(): detect subdirectory projects by comparing projectPath with git root at function entry. When they differ, warn and skip to prevent vp prepare from hijacking the repo-wide core.hooksPath.
- migration-subpath: assert core.hooksPath is NOT set (no hijack) - migration-add-git-hooks: assert core.hooksPath IS set to .husky/_
Merge the hooks-only `vp prepare` and agent-only `vp init` commands into a single `vp config` command that handles both hooks setup and agent integration in one step. Key changes: - New `vp config` command with `--hooks-dir` flag (default: `.vite-hooks`) - `--hooks-only` internal flag for migration subprocess calls - Default hooks directory changed from `.husky` to `.vite-hooks` - Migration from husky preserves `.husky` via `--hooks-dir .husky` - AST-grep post-processing converts positional dir args to `--hooks-dir` - `createHuskyPreCommitHook()` renamed to `createPreCommitHook()` - RFC updated to reflect the new command design
Three bugs fixed: 1. skipStagedMigration not forwarded to root monorepo rewrite — rewriteRootWorkspacePackageJson called rewriteMonorepoProject without passing skipStagedMigration, so husky v8 detection didn't prevent root package.json lint-staged deletion. 2. .lintstagedrc files deleted even when merge into vite.config.ts failed — now preserved when mergeStagedConfigToViteConfig returns false. 3. package.json lint-staged key deleted before merge confirmation — extraction now defers deletion to callers, which only remove the key after a successful merge. Also fixed setupGitHooks which had a second unconditional deletion path. Also adds config to the interactive command picker and snap tests verifying .vite-hooks/_/ internal hook shim contents.
Guard `createPreCommitHook` on successful staged config availability —
either merged into vite.config.ts or present as a standalone lint-staged
config file. Previously, the hook was created unconditionally, causing
`vp staged` to fail on every commit when no config existed.
Also fix `--concurrent` bare flag parsing: `Number('')` returns 0 (not
NaN), so bare `--concurrent` incorrectly set serial mode instead of
unlimited concurrency.
…patcher - Copy old husky hooks dir contents to .vite-hooks/ during migration - Rebrand hook dispatcher from "husky" to "Vite+" in error messages - Add VITE_GIT_HOOKS env var support alongside HUSKY for backwards compat - Look for init.sh in ~/.config/vite-plus/ first, falling back to ~/.config/husky/ - Remove --hooks-dir flag from migrated prepare scripts (always use .vite-hooks) - Use explicit shell grouping for || && precedence in hook dispatcher - Update snap tests to verify new .vite-hooks/ paths
…to .vite-hooks Only the default .husky dir is migrated to .vite-hooks/. Custom dirs (e.g. .config/husky) keep their --hooks-dir flag and hooks stay in place. Update RFC to document default vs custom dir migration behavior.
The snapshot was stale — rewritePackageJson no longer deletes the lint-staged key (deletion moved to caller after vite.config.ts merge).
1. Pre-commit hook no longer created when standalone lint-staged config exists but staged merge into vite.config.ts failed — vp staged only reads from vite.config.ts so the hook would fail on every commit. 2. Prepare script no longer rewritten before hook setup can abort — rewritePrepareScript now runs after setupGitHooks succeeds, preventing orphaned "vp config" when hooks are skipped (unsupported config, old husky, etc.). Extracted read-only getOldHooksDir() probe and changed setupGitHooks to return boolean. 3. Standalone lint-staged config (.lintstagedrc.json) no longer deleted when "staged" already exists in vite.config.ts — warns user to merge manually instead of silently dropping config.
Split the monolithic config/bin.ts (438 lines) into three focused files: - config/hooks.ts: git hooks constants and install() - config/agent.ts: agent detection, instruction injection, MCP config - config/bin.ts: CLI arg parsing and main() orchestration only
Rename $HOME/.config/vite-plus/init.sh to hooks-init.sh for clarity.
…rn failure on skip Two fixes: 1. Hook dispatcher generated incorrect PATH for nested custom dirs like .config/husky. The dirname depth was hardcoded to 3 levels, which only works for single-segment dirs (.vite-hooks). Now computes depth dynamically from the dir's segment count. 2. setupGitHooks returned true even when vp config reported a skip or failure, causing rewritePrepareScript to rewrite prepare from "husky" to "vp config" while hooks remained unconfigured.
…indows Linux CI runners lack global git user.name/user.email, causing git commit to fail silently in snap tests. Windows CI returns MSYS-style paths from git rev-parse that break path.relative() for core.hooksPath computation.
On Windows CI, git rev-parse returns long path names while process.cwd() may return 8.3 short names (e.g. RUNNER~1 vs runner), causing path.relative() to produce incorrect core.hooksPath values. Use realpathSync to canonicalize both paths before comparison.
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
from
March 5, 2026 12:46
57b92e8 to
cec82af
Compare
Replace --show-toplevel + path.relative() with --show-prefix which returns the relative path from git root to cwd directly. This avoids all Windows path normalization issues (MSYS paths, 8.3 short names) that made path.relative() produce incorrect core.hooksPath values.
…skip staged migration with --no-hooks Two migration bugs fixed: - setupGitHooks() removed husky/lint-staged from devDependencies before confirming hooks were installed, leaving projects with a broken "prepare": "husky" script when core.hooksPath was already set - --no-hooks still ran staged migration, removing lint-staged config from package.json while existing .husky/pre-commit scripts depend on it
fengmk2
force-pushed
the
lint-staged-pre-commit-hook
branch
from
March 5, 2026 14:28
12bf70b to
65311d3
Compare
…e lint-staged scripts Skip agent setup in `vp config` when `npm_lifecycle_event=prepare` so that `npm install` only installs hooks without triggering agent setup on every install. Skip lint-staged script rewrites (e.g. `lint-staged` → `vp staged`) when `skipStagedMigration` is true, preserving scripts like `"check-staged": "lint-staged"` when hooks migration is skipped via --no-hooks.
…t code Unify the three-step hook setup pattern (getOldHooksDir → setupGitHooks → rewritePrepareScript) into a single installGitHooks() helper, replacing three identical copies in migration/bin.ts and create/bin.ts. Also remove redundant `hooks: undefined` from promptGitHooks call in config/bin.ts.
…oks dir, surface staged errors - Extract preflightGitHooksSetup() from setupGitHooks() to run deterministic checks before migration rewrites lint-staged config. When hooks setup would fail (other hook tools, subdirectory project, unsupported lint-staged config), migration now preserves lint-staged scripts and config in package.json instead of rewriting them. - Fix hookScript() path segment counting: filter out '.' segments so paths like "./.config/husky" produce the same depth as ".config/husky". - Surface real resolveViteConfig errors in `vp staged` instead of masking them as "No staged config found".
Member
Author
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.

Bundle husky and lint-staged functionality into vite-plus so projects get
a zero-config pre-commit hook with no extra devDependencies.
vp configmerges hooks setup (vp prepare) and agent integration (vp init) into a single commandvp stageddelegates to bundled lint-staged, reading config fromstagedkey in vite.config.ts.vite-hooks; migration from husky preserves.huskyvia--hooks-dircloses VP-30