You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: install() should replace husky hook paths instead of skipping (#772)
When `core.hooksPath` is set to `.husky/_` or `.husky`, `install()` was
treating it as a genuinely custom path and refusing to overwrite. This
caused both `vp config` and `vp migrate` to skip hooks setup. Now husky
paths are recognized and replaced with `.vite-hooks/_`.
Add `vp config` and `vp staged` as built-in commands. `vp config` is a unified configuration command that sets up git hooks (husky-compatible reimplementation, not a bundled dependency) and agent integration. `vp staged` bundles lint-staged and reads config from the `staged` key in `vite.config.ts`. Projects get a zero-config pre-commit hook that runs `vp check --fix` on staged files — no extra devDependencies needed.
5
+
Add `vp config` and `vp staged` as built-in commands. `vp config` is a `prepare`-lifecycle command that installs git hook shims (husky-compatible reimplementation, not a bundled dependency). `vp staged` bundles lint-staged and reads config from the `staged` key in `vite.config.ts`. Projects get a zero-config pre-commit hook that runs `vp check --fix` on staged files — no extra devDependencies needed.
6
6
7
7
## Motivation
8
8
@@ -21,50 +21,129 @@ Pain points:
21
21
22
22
By building these capabilities into vite-plus, projects get pre-commit hooks with zero extra devDependencies. Both `vp create` and `vp migrate` set this up automatically.
23
23
24
-
## Command Syntax
24
+
## User Workflows
25
+
26
+
There are three distinct entry points, each with a different responsibility:
27
+
28
+
### New projects: `vp create`
29
+
30
+
`vp create` scaffolds a new project and optionally sets up the full hooks pipeline:
31
+
32
+
1. Prompts "Set up pre-commit hooks?" (default: yes)
- Runs `vp config --hooks-only` to install hook shims and set `core.hooksPath`
54
+
- Removes husky and lint-staged from `devDependencies`
55
+
56
+
Flags: `--hooks` (force), `--no-hooks` (skip)
57
+
58
+
### Ongoing use: `vp config` (prepare lifecycle)
59
+
60
+
`vp config` is the command that runs on every `npm install` via the `prepare` script. It reinstalls hook shims — it does **not** create the `staged` config or the pre-commit hook file. Those are created by `vp create`/`vp migrate`.
61
+
62
+
```json
63
+
{ "scripts": { "prepare": "vp config" } }
64
+
```
65
+
66
+
When `npm_lifecycle_event=prepare` (set by npm/pnpm/yarn during `npm install`), agent setup is skipped automatically — only hooks are reinstalled.
# Run staged linters on staged files (runs bundled lint-staged with staged config)
33
-
vp staged
98
+
Behavior:
34
99
35
-
# Control hooks setup during create/migrate
36
-
vp create --hooks # Force hooks setup
37
-
vp create --no-hooks # Skip hooks setup
38
-
vp migrate --hooks # Force hooks setup
39
-
vp migrate --no-hooks # Skip hooks setup
100
+
1. Built-in husky-compatible install logic (reimplementation of husky v9, not a bundled dependency)
101
+
2. Sets `core.hooksPath` to `<hooks-dir>/_` (default: `.vite-hooks/_`)
102
+
3. Creates hook scripts in `<hooks-dir>/_/` that source the user-defined hooks in `<hooks-dir>/`
103
+
4. Agent integration: injects agent instructions and MCP config (skipped during `prepare` lifecycle — see point 9)
104
+
5. Safe to run multiple times (idempotent)
105
+
6. Exits 0 and skips hooks if `VITE_GIT_HOOKS=0` or `HUSKY=0` environment variable is set (backwards compatible)
106
+
7. Exits 0 and skips hooks if `.git` directory doesn't exist (safe during `npm install` in consumer projects)
107
+
8. Exits 1 on real errors (git command not found, `git config` failed)
108
+
9.`prepare` lifecycle detection: when `npm_lifecycle_event=prepare`, agent setup is skipped. This ensures `"prepare": "vp config"` only installs hooks during install — agent setup is handled by `vp create`/`vp migrate`
109
+
10. Interactive mode: prompts on first run for hooks and agent setup; updates silently on subsequent runs
110
+
11. Non-interactive mode: runs everything by default
111
+
112
+
### `vp staged`
113
+
114
+
```bash
115
+
vp staged # Run staged linters on staged files
40
116
```
41
117
118
+
Behavior:
119
+
120
+
1. Reads config from `staged` key in `vite.config.ts` via `resolveConfig()`
121
+
2. If `staged` key not found, exits with a warning and setup instructions
122
+
3. Passes config to bundled lint-staged via its programmatic API
123
+
4. Runs configured commands on git-staged files only
124
+
5. Exits with non-zero code if any command fails
125
+
6. Does not support custom config file paths — config must be in `vite.config.ts`
126
+
42
127
Both commands are listed under "Core Commands" in `vp -h` (global and local CLI).
43
128
44
-
## User-Facing Configuration
129
+
## Configuration
45
130
46
-
### vite.config.ts + package.json (zero extra devDependencies)
131
+
### `vite.config.ts`
47
132
48
133
```typescript
49
-
// vite.config.ts
50
134
exportdefaultdefineConfig({
51
135
staged: {
52
136
'*': 'vp check --fix',
53
137
},
54
138
});
55
139
```
56
140
57
-
```json
58
-
// package.json (new project)
59
-
{
60
-
"scripts": {
61
-
"prepare": "vp config"
62
-
}
63
-
}
64
-
```
141
+
`vp staged` reads config from the `staged` key via Vite's `resolveConfig()`. If no `staged` key is found, it exits with a warning and instructions to add the config. Standalone config files (`.lintstagedrc.*`, `lint-staged.config.*`) are not supported by the migration — projects using those formats are warned to migrate manually.
142
+
143
+
### `package.json`
65
144
66
145
```json
67
-
// package.json (migrated from husky — default .husky dir migrates to .vite-hooks)
146
+
// New project
68
147
{
69
148
"scripts": {
70
149
"prepare": "vp config"
@@ -73,7 +152,7 @@ export default defineConfig({
73
152
```
74
153
75
154
```json
76
-
// package.json (migrated from husky with custom dir — dir is preserved)
155
+
// Migrated from husky with custom dir — dir is preserved
77
156
{
78
157
"scripts": {
79
158
"prepare": "vp config --hooks-dir .config/husky"
@@ -91,7 +170,7 @@ If the project already has a prepare script, `vp config` is prepended:
91
170
}
92
171
```
93
172
94
-
### .vite-hooks/pre-commit (or custom dir for projects with non-default husky dir)
173
+
### `.vite-hooks/pre-commit`
95
174
96
175
```
97
176
vp staged
@@ -101,36 +180,7 @@ vp staged
101
180
102
181
`vp check --fix` already handles unsupported file types gracefully (it only processes files that match known extensions). Using `*` simplifies the configuration — no need to maintain a list of extensions.
103
182
104
-
### Config Discovery
105
-
106
-
`vp staged` reads config from the `staged` key in `vite.config.ts` via Vite's `resolveConfig()`. If no `staged` key is found, it exits with a warning and instructions to add the config. Standalone config files (`.lintstagedrc.*`, `lint-staged.config.*`) are not supported by the migration — projects using those formats are warned to migrate manually.
107
-
108
-
## Behavior
109
-
110
-
### `vp config`
111
-
112
-
1. Built-in husky-compatible install logic (reimplementation of husky v9, not a bundled dependency)
113
-
2. Sets `core.hooksPath` to `<hooks-dir>/_` (default: `.vite-hooks/_`)
114
-
3. Creates hook scripts in `<hooks-dir>/_/` that source the user-defined hooks in `<hooks-dir>/`
115
-
4. Agent integration: injects agent instructions and MCP config (skipped during `prepare` lifecycle — see point 11)
116
-
5. Safe to run multiple times (idempotent)
117
-
6. Exits 0 and skips hooks if `VITE_GIT_HOOKS=0` or `HUSKY=0` environment variable is set (backwards compatible)
118
-
7. Exits 0 and skips hooks if `.git` directory doesn't exist (safe during `npm install` in consumer projects)
119
-
8. Exits 1 on real errors (git command not found, `git config` failed)
120
-
9. Interactive mode: prompts on first run for hooks and agent setup; updates silently on subsequent runs
121
-
10. Non-interactive mode: runs everything by default
122
-
11.`prepare` lifecycle detection: when `npm_lifecycle_event=prepare` (set by npm/pnpm/yarn during `npm install`), agent setup is skipped automatically. This ensures `"prepare": "vp config"` only installs hooks during install — agent setup is a one-time operation handled by `vp create`/`vp migrate`, not repeated on every `npm install`
123
-
124
-
### `vp staged`
125
-
126
-
1. Reads config from `staged` key in `vite.config.ts` via `resolveConfig()`
127
-
2. If `staged` key not found, exits with a warning and setup instructions
128
-
3. Passes config to bundled lint-staged via its programmatic API
129
-
4. Runs configured commands on git-staged files only
130
-
5. Exits with non-zero code if any command fails
131
-
6. Does not support custom config file paths — config must be in vite.config.ts
132
-
133
-
### Automatic Setup
183
+
## Automatic Setup
134
184
135
185
Both `vp create` and `vp migrate` prompt the user before setting up pre-commit hooks:
136
186
@@ -139,14 +189,21 @@ Both `vp create` and `vp migrate` prompt the user before setting up pre-commit h
139
189
-**`--hooks` flag**: Force hooks setup (no prompt)
140
190
-**`--no-hooks` flag**: Skip hooks setup entirely (no prompt)
141
191
142
-
#### `vp create`
192
+
```bash
193
+
vp create --hooks # Force hooks setup
194
+
vp create --no-hooks # Skip hooks setup
195
+
vp migrate --hooks # Force hooks setup
196
+
vp migrate --no-hooks # Skip hooks setup
197
+
```
198
+
199
+
### `vp create`
143
200
144
201
- After project creation and migration rewrite, prompts for hooks setup
145
202
- If accepted, calls `rewritePrepareScript()` then `setupGitHooks()` — same as `vp migrate`
146
203
-`rewritePrepareScript()` rewrites any template-provided `"prepare": "husky"` to `"prepare": "vp config"` before `setupGitHooks()` runs
147
204
- Creates `.vite-hooks/pre-commit` with `vp staged`
148
205
149
-
####`vp migrate`
206
+
### `vp migrate`
150
207
151
208
Migration rewrite (`rewritePackageJson`) uses `vite-tools.yml` rules to rewrite tool commands (vite, oxlint, vitest, etc.) in all scripts. Crucially, the husky rule is **not** in `vite-tools.yml` — it lives in a separate `vite-prepare.yml` and is only applied to `scripts.prepare` via `rewritePrepareScript()`. This ensures husky is never accidentally rewritten in non-prepare scripts.
152
209
@@ -163,10 +220,14 @@ Hook setup behavior:
163
220
-**Has `husky install`** — `rewritePrepareScript()` collapses `"husky install"` → `"husky"` before applying the ast-grep rule, so `"husky install .hooks"` becomes `"vp config --hooks-dir .hooks"` (custom dir preserved)
164
221
-**Has existing prepare script** (e.g. `"npm run build"`) — composes as `"vp config && npm run build"` (prepend so hooks are active before other prepare tasks; idempotent if already contains `vp config`)
165
222
-**Has lint-staged** — migrates `"lint-staged"` key to `staged` in vite.config.ts, keeps existing config (already rewritten by migration rules), removes lint-staged from devDeps
223
+
224
+
## Migration Edge Cases
225
+
166
226
-**Has husky <9.0.0** — detected **before** migration rewrite. Warns "please upgrade to husky v9+ first", skips hooks setup, and also skips lint-staged migration (`skipStagedMigration` flag). This preserves the `lint-staged` config in package.json and standalone config files, since `.husky/pre-commit` still references `npx lint-staged`.
167
227
-**Has other tool (simple-git-hooks, lefthook, yorkie)** — warns and skips
168
228
-**Subdirectory project** (e.g. `vp migrate foo`) — if the project path differs from the git root, warns "Subdirectory project detected" and skips hooks setup entirely. This prevents `vp config` from setting `core.hooksPath` to a subdirectory path, which would hijack the repo-wide hooks.
169
229
-**No .git directory** — adds package.json config and creates hook pre-commit file, but skips `vp config` hook install (no `core.hooksPath` to set)
230
+
-**Standalone lint-staged config** (`.lintstagedrc.*`, `lint-staged.config.*`) — not supported by auto-migration. Projects using those formats are warned to migrate manually.
170
231
- After creating the pre-commit hook, runs `vp config` directly to install hook shims (does not rely on npm install lifecycle, which may not run in CI or snap test contexts)
171
232
172
233
## Implementation Architecture
@@ -218,7 +279,7 @@ Husky <9.0.0 is not supported by auto migration — `vp migrate` detects unsuppo
0 commit comments