vite-plus 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/AGENTS.md +7 -0
  2. package/README.md +13 -6
  3. package/binding/index.cjs +57 -54
  4. package/binding/index.d.cts +100 -3
  5. package/dist/{agent-CI79DuSy.js → agent-Wqx0MPk0.js} +4 -188
  6. package/dist/bin.js +298 -278
  7. package/dist/command-CLJK5jGW.js +2 -0
  8. package/dist/command-CguLh2KL.js +471 -0
  9. package/dist/config/bin.js +29 -15
  10. package/dist/{constants-BppDcRc1.js → constants-Bn-U8o4v.js} +13 -3
  11. package/dist/create/bin.js +197 -247
  12. package/dist/{define-config-DPnHe1Mx.js → define-config-GXUdVT-0.js} +3 -3
  13. package/dist/{define-config-CEm_MtvJ.cjs → define-config-WiVlryJ2.cjs} +2 -2
  14. package/dist/define-config.cjs +1 -1
  15. package/dist/define-config.js +1 -1
  16. package/dist/{dist-CSQWHI6y.js → dist-BDYZP12R.js} +193 -149
  17. package/dist/dist-Dqv1-Clg.js +3 -0
  18. package/dist/{editor-CGWdbLgD.js → editor-CC4DqODz.js} +736 -153
  19. package/dist/{terminal-CrqqK8WT.js → help-BmKpeOP9.js} +27 -34
  20. package/dist/hooks/bin.d.ts +1 -0
  21. package/dist/hooks/bin.js +131 -0
  22. package/dist/hooks-DFqViZqZ.js +573 -0
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/{json-BU88uu6o.js → json-cULBl7Pi.js} +145 -139
  26. package/dist/migration/bin.js +67 -21
  27. package/dist/migration/compat/worker.js +1 -1
  28. package/dist/{oxlint-plugin-config-BHOzlwMw.js → oxlint-plugin-config-DX5ezKbB.js} +1 -1
  29. package/dist/oxlint-plugin.js +1 -1
  30. package/dist/pack-bin.js +5 -4
  31. package/dist/{package-hV-77cBb.js → package-CBe9EWPY.js} +2 -2
  32. package/dist/{prompts-DYap08te.js → prompts-DF3yU-eU.js} +136 -512
  33. package/dist/{report-BS7ULx7A.js → report-ZNR1Mk6h.js} +1 -0
  34. package/dist/{resolve-vite-config-EWXclqvV.js → resolve-vite-config-ipGb39Jo.js} +2 -9
  35. package/dist/staged/bin.js +299 -251
  36. package/dist/terminal-MKGAuy-p.js +39 -0
  37. package/dist/test/browser/providers/playwright/context.d.ts +1 -1
  38. package/dist/test/browser/providers/playwright.d.ts +6 -6
  39. package/dist/test/browser/providers/preview/context.d.ts +1 -1
  40. package/dist/test/browser/providers/preview.d.ts +4 -4
  41. package/dist/test/browser/providers/webdriverio/context.d.ts +1 -1
  42. package/dist/test/browser/providers/webdriverio.d.ts +6 -6
  43. package/dist/test/browser-playwright/context.d.ts +1 -1
  44. package/dist/test/browser-playwright.d.ts +6 -6
  45. package/dist/test/browser-preview/context.d.ts +1 -1
  46. package/dist/test/browser-preview.d.ts +4 -4
  47. package/dist/test/browser-webdriverio/context.d.ts +1 -1
  48. package/dist/test/browser-webdriverio.d.ts +6 -6
  49. package/dist/test/context.d.ts +3 -3
  50. package/dist/test/locators.d.ts +1 -1
  51. package/dist/toolchain.d.ts +25 -0
  52. package/dist/toolchain.js +194 -0
  53. package/dist/toolchain.json +193 -0
  54. package/dist/tsconfig-BVHG3DpR.js +2 -0
  55. package/dist/{tsconfig-CVUKLfL8.js → tsconfig-LD2QhQ0O.js} +5 -4
  56. package/dist/tsgolint-path.js +1 -1
  57. package/dist/version.js +5 -4
  58. package/dist/versions.d.ts +3 -3
  59. package/dist/versions.js +6 -6
  60. package/docs/guide/ci.md +37 -4
  61. package/docs/guide/commit-hooks.md +87 -14
  62. package/docs/guide/create.md +7 -4
  63. package/docs/guide/env.md +20 -6
  64. package/docs/guide/fmt.md +2 -2
  65. package/docs/guide/github-actions-cache.md +5 -1
  66. package/docs/guide/ide-integration.md +61 -2
  67. package/docs/guide/index.md +3 -1
  68. package/docs/guide/install.md +27 -1
  69. package/docs/guide/installer-env-vars.md +53 -6
  70. package/docs/guide/lint.md +3 -1
  71. package/docs/guide/migrate-rules.md +9 -0
  72. package/docs/guide/migrate.md +41 -4
  73. package/docs/guide/monorepo.md +4 -4
  74. package/docs/guide/test.md +8 -0
  75. package/docs/guide/troubleshooting.md +12 -4
  76. package/docs/guide/upgrade.md +75 -5
  77. package/package.json +36 -33
  78. package/rules/vite-tools.yml +0 -7
  79. package/dist/dist-DT25H9pj.js +0 -3
  80. package/docs/_data/team.ts +0 -131
  81. package/docs/package.json +0 -30
  82. package/docs/pnpm-lock.yaml +0 -4003
  83. package/docs/pnpm-workspace.yaml +0 -6
  84. package/docs/public/checkmark.svg +0 -1
  85. package/docs/public/cta-background.jpg +0 -0
  86. package/docs/public/favicon.svg +0 -1
  87. package/docs/public/icon.svg +0 -1
  88. package/docs/public/logo.svg +0 -1
  89. package/docs/public/og.jpg +0 -0
  90. package/docs/vite.config.ts +0 -17
  91. package/dist/{log-update-CoW8Z4Dl.js → log-update-DHZRyJ2m.js} +1 -1
  92. package/dist/{tsgolint-path-eMZT-oea.js → tsgolint-path-CbDReEOx.js} +1 -1
@@ -0,0 +1,573 @@
1
+ import { isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
2
+ import { chmodSync, existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
3
+ import { spawnSync } from "node:child_process";
4
+ //#region src/config/hooks.ts
5
+ const SUPPORTED_GIT_HOOK_NAMES = [
6
+ "pre-commit",
7
+ "pre-merge-commit",
8
+ "prepare-commit-msg",
9
+ "commit-msg",
10
+ "post-commit",
11
+ "applypatch-msg",
12
+ "pre-applypatch",
13
+ "post-applypatch",
14
+ "pre-rebase",
15
+ "post-rewrite",
16
+ "post-checkout",
17
+ "post-merge",
18
+ "pre-push",
19
+ "pre-auto-gc"
20
+ ];
21
+ const DEFAULT_HOOKS_DIR = ".vite-hooks";
22
+ /** Local git config: user chose `vp hooks disable` (survives prepare / vp config). */
23
+ const PREFERENCE_DISABLED_KEY = "vp.hooks.disabled";
24
+ /** Local git config: last hooks directory used by enable (relative to setup cwd). */
25
+ const PREFERENCE_DIR_KEY = "vp.hooks.dir";
26
+ /** Local git config: `git rev-parse --show-prefix` when the dir was stored. `.` = worktree root. */
27
+ const PREFERENCE_PREFIX_KEY = "vp.hooks.prefix";
28
+ const ROOT_PREFIX_TOKEN = ".";
29
+ function nestedDirname(depth) {
30
+ let expr = "\"$0\"";
31
+ for (let i = 0; i < depth; i++) expr = `"$(dirname ${expr})"`;
32
+ return expr;
33
+ }
34
+ function hookScript(dir) {
35
+ const separators = process.platform === "win32" ? /[\\/]/ : /\//;
36
+ return `#!/usr/bin/env sh
37
+ { [ "$HUSKY" = "2" ] || [ "$VP_GIT_HOOKS" = "2" ] || [ "$VITE_GIT_HOOKS" = "2" ]; } && set -x
38
+ n=$(basename "$0")
39
+ s=$(dirname "$(dirname "$0")")/$n
40
+
41
+ [ ! -f "$s" ] && exit 0
42
+
43
+ i="\${XDG_CONFIG_HOME:-$HOME/.config}/vite-plus/hooks-init.sh"
44
+ [ ! -f "$i" ] && i="\${XDG_CONFIG_HOME:-$HOME/.config}/husky/init.sh"
45
+ [ -f "$i" ] && . "$i"
46
+
47
+ { [ "\${HUSKY-}" = "0" ] || [ "\${VP_GIT_HOOKS-}" = "0" ] || [ "\${VITE_GIT_HOOKS-}" = "0" ]; } && exit 0
48
+
49
+ d=${nestedDirname(dir.split(separators).filter((s) => s !== "" && s !== ".").length + 2)}
50
+ __vp_shell=/bin/sh
51
+ [ -x "$__vp_shell" ] || __vp_shell=$(command -v sh)
52
+
53
+ if [ -n "\${VP_HOME-}" ]; then
54
+ __vp_bin="$VP_HOME/bin"
55
+ elif [ -n "\${HOME-}" ]; then
56
+ __vp_bin="$HOME/.vite-plus/bin"
57
+ else
58
+ __vp_bin=""
59
+ fi
60
+ [ -n "$__vp_bin" ] && [ -d "$__vp_bin" ] && export PATH="$PATH:$__vp_bin"
61
+
62
+ export PATH="$d/node_modules/.bin:$PATH"
63
+ "$__vp_shell" -e "$s" "$@"
64
+ c=$?
65
+
66
+ [ $c != 0 ] && echo "VITE+ - $n script failed (code $c)"
67
+ [ $c = 127 ] && echo "VITE+ - command not found in PATH=$PATH"
68
+ exit $c`;
69
+ }
70
+ function normalizeHooksPath(hooksPath) {
71
+ let normalized = normalize(hooksPath);
72
+ while (normalized.endsWith(sep)) normalized = normalized.slice(0, -1);
73
+ return normalized;
74
+ }
75
+ function getGitToplevel() {
76
+ const result = spawnSync("git", ["rev-parse", "--show-toplevel"]);
77
+ if (result.status == null) return {
78
+ message: "git command not found",
79
+ isError: true
80
+ };
81
+ if (result.status !== 0) return {
82
+ message: ".git can't be found",
83
+ isError: false
84
+ };
85
+ const toplevel = result.stdout.toString().trim();
86
+ try {
87
+ return realpathSync(toplevel);
88
+ } catch {
89
+ return toplevel;
90
+ }
91
+ }
92
+ /** Resolve a core.hooksPath value against the worktree root for ownership checks. */
93
+ function resolveHooksPath(hooksPath, gitRoot) {
94
+ const resolved = isAbsolute(hooksPath) ? hooksPath : resolve(gitRoot, hooksPath);
95
+ try {
96
+ return normalizeHooksPath(realpathSync(resolved));
97
+ } catch {
98
+ return normalizeHooksPath(resolved);
99
+ }
100
+ }
101
+ function hooksPathsEqual(a, b, gitRoot) {
102
+ return resolveHooksPath(a, gitRoot) === resolveHooksPath(b, gitRoot);
103
+ }
104
+ function findUnsafeHookInstallPath(root, dir) {
105
+ const projectRoot = resolve(root);
106
+ const internalPath = resolve(projectRoot, dir, "_");
107
+ const relativeInternalPath = relative(projectRoot, internalPath);
108
+ let currentPath = projectRoot;
109
+ for (const component of relativeInternalPath.split(sep).filter(Boolean)) {
110
+ currentPath = join(currentPath, component);
111
+ const stats = lstatSync(currentPath, { throwIfNoEntry: false });
112
+ if (!stats) return null;
113
+ if (stats.isSymbolicLink()) return {
114
+ kind: "symbolic",
115
+ relativePath: relative(projectRoot, currentPath)
116
+ };
117
+ if (!stats.isDirectory()) return {
118
+ kind: "not-directory",
119
+ relativePath: relative(projectRoot, currentPath)
120
+ };
121
+ }
122
+ for (const filename of [
123
+ "husky.sh",
124
+ ".gitignore",
125
+ "h",
126
+ ...SUPPORTED_GIT_HOOK_NAMES
127
+ ]) {
128
+ const filePath = join(internalPath, filename);
129
+ const stats = lstatSync(filePath, { throwIfNoEntry: false });
130
+ if (!stats) continue;
131
+ if (stats.isSymbolicLink()) return {
132
+ kind: "symbolic",
133
+ relativePath: relative(projectRoot, filePath)
134
+ };
135
+ if (!stats.isFile()) return {
136
+ kind: "not-file",
137
+ relativePath: relative(projectRoot, filePath)
138
+ };
139
+ if (stats.nlink > 1) return {
140
+ kind: "linked",
141
+ relativePath: relative(projectRoot, filePath)
142
+ };
143
+ }
144
+ return null;
145
+ }
146
+ function describeUnsafeHookInstallPath(unsafePath) {
147
+ if (unsafePath.kind === "symbolic") return `symbolic hook path "${unsafePath.relativePath}" not allowed`;
148
+ if (unsafePath.kind === "linked") return `multiply linked hook path "${unsafePath.relativePath}" not allowed`;
149
+ if (unsafePath.kind === "not-directory") return `hook path "${unsafePath.relativePath}" is not a directory`;
150
+ return `hook path "${unsafePath.relativePath}" is not a file`;
151
+ }
152
+ function gitConfigGet(key, options) {
153
+ const args = ["config"];
154
+ if (options?.local) args.push("--local");
155
+ if (options?.bool) args.push("--bool");
156
+ args.push("--get", key);
157
+ const result = spawnSync("git", args);
158
+ if (result.status !== 0) return null;
159
+ return result.stdout?.toString().trim() || null;
160
+ }
161
+ function gitConfigSet(key, value) {
162
+ const result = spawnSync("git", [
163
+ "config",
164
+ "--local",
165
+ key,
166
+ value
167
+ ]);
168
+ if (result.status == null) return {
169
+ ok: false,
170
+ error: "git command not found"
171
+ };
172
+ if (result.status !== 0) return {
173
+ ok: false,
174
+ error: result.stderr?.toString().trim() || `failed to set ${key}`
175
+ };
176
+ return { ok: true };
177
+ }
178
+ function gitConfigUnset(key) {
179
+ const result = spawnSync("git", [
180
+ "config",
181
+ "--local",
182
+ "--unset-all",
183
+ key
184
+ ]);
185
+ if (result.status == null) return {
186
+ ok: false,
187
+ error: "git command not found"
188
+ };
189
+ if (result.status !== 0 && result.status !== 5) return {
190
+ ok: false,
191
+ error: result.stderr?.toString().trim() || `failed to unset ${key}`
192
+ };
193
+ return { ok: true };
194
+ }
195
+ /** Whether the user ran `vp hooks disable` in this repo (local git config). */
196
+ function isHooksUserDisabled() {
197
+ return gitConfigGet(PREFERENCE_DISABLED_KEY, {
198
+ local: true,
199
+ bool: true
200
+ }) === "true";
201
+ }
202
+ function setHooksUserDisabled(disabled) {
203
+ if (disabled) return gitConfigSet(PREFERENCE_DISABLED_KEY, "true");
204
+ return gitConfigUnset(PREFERENCE_DISABLED_KEY);
205
+ }
206
+ function getStoredHooksDir() {
207
+ return gitConfigGet(PREFERENCE_DIR_KEY, { local: true });
208
+ }
209
+ function getStoredHooksPrefix() {
210
+ const value = gitConfigGet(PREFERENCE_PREFIX_KEY, { local: true });
211
+ if (value == null) return null;
212
+ if (value === ROOT_PREFIX_TOKEN) return "";
213
+ return value.replace(/\/$/, "");
214
+ }
215
+ function setStoredHooksLocation(dir, prefix) {
216
+ const storedDir = gitConfigSet(PREFERENCE_DIR_KEY, dir);
217
+ if (!storedDir.ok) return storedDir;
218
+ return gitConfigSet(PREFERENCE_PREFIX_KEY, prefix || ROOT_PREFIX_TOKEN);
219
+ }
220
+ function displayHooksDir(location) {
221
+ return location.prefix ? `${location.prefix}/${location.dir}` : location.dir;
222
+ }
223
+ function getGitWorktree() {
224
+ const toplevel = getGitToplevel();
225
+ if (typeof toplevel !== "string") return toplevel;
226
+ const prefixResult = spawnSync("git", ["rev-parse", "--show-prefix"]);
227
+ if (prefixResult.status == null) return {
228
+ message: "git command not found",
229
+ isError: true
230
+ };
231
+ if (prefixResult.status !== 0) return {
232
+ message: ".git can't be found",
233
+ isError: false
234
+ };
235
+ return {
236
+ toplevel,
237
+ prefix: prefixResult.stdout.toString().trim().replace(/\/$/, "")
238
+ };
239
+ }
240
+ function buildHooksLocation(git, hooksDir, prefix) {
241
+ const dirError = validateHooksDir(hooksDir);
242
+ if (dirError) return dirError;
243
+ const baseDir = prefix ? resolve(git.toplevel, prefix) : git.toplevel;
244
+ const target = prefix ? `${prefix}/${hooksDir}/_` : `${hooksDir}/_`;
245
+ return {
246
+ toplevel: git.toplevel,
247
+ baseDir,
248
+ dir: hooksDir,
249
+ prefix,
250
+ target
251
+ };
252
+ }
253
+ function tryAdoptEffectiveDispatcher(git) {
254
+ const existing = getEffectiveHooksPath();
255
+ if (!existing) return null;
256
+ const abs = isAbsolute(existing) ? existing : resolve(git.toplevel, existing);
257
+ let dispatcherDir;
258
+ try {
259
+ dispatcherDir = realpathSync(abs);
260
+ } catch {
261
+ return null;
262
+ }
263
+ if (!existsSync(join(dispatcherDir, "h"))) return null;
264
+ const hooksAbs = resolve(dispatcherDir, "..");
265
+ const relHooks = relative(git.toplevel, hooksAbs);
266
+ if (!relHooks || relHooks === "." || relHooks.startsWith("..")) return null;
267
+ const posixRel = relHooks.split(sep).join("/");
268
+ let prefix = "";
269
+ let dir = posixRel;
270
+ if (posixRel === ".vite-hooks") {
271
+ prefix = "";
272
+ dir = DEFAULT_HOOKS_DIR;
273
+ } else if (posixRel.endsWith(`/.vite-hooks`)) {
274
+ prefix = posixRel.slice(0, -12);
275
+ dir = DEFAULT_HOOKS_DIR;
276
+ }
277
+ const location = buildHooksLocation(git, dir, prefix);
278
+ return "isError" in location ? null : location;
279
+ }
280
+ /**
281
+ * Resolve where hook files live.
282
+ *
283
+ * An explicit `dir` is relative to the current working directory (current
284
+ * git prefix). Omitting it uses the stored dir + the prefix recorded at
285
+ * enable/disable time, so later commands find the same tree from any cwd.
286
+ */
287
+ function resolveHooksLocation(dir, options = {}) {
288
+ const git = getGitWorktree();
289
+ if ("isError" in git) return git;
290
+ let prefix;
291
+ let hooksDir;
292
+ if (dir !== void 0) {
293
+ prefix = git.prefix;
294
+ hooksDir = dir;
295
+ } else {
296
+ const storedDir = getStoredHooksDir();
297
+ if (storedDir) {
298
+ hooksDir = storedDir;
299
+ prefix = getStoredHooksPrefix() ?? git.prefix;
300
+ } else if (options.adoptEffectiveDispatcher) {
301
+ const adopted = tryAdoptEffectiveDispatcher(git);
302
+ if (adopted) return adopted;
303
+ hooksDir = DEFAULT_HOOKS_DIR;
304
+ prefix = options.unstoredPrefix === "root" ? "" : git.prefix;
305
+ } else {
306
+ hooksDir = DEFAULT_HOOKS_DIR;
307
+ prefix = options.unstoredPrefix === "root" ? "" : git.prefix;
308
+ }
309
+ }
310
+ return buildHooksLocation(git, hooksDir, prefix);
311
+ }
312
+ function validateHooksDir(dir) {
313
+ if (dir.includes("..")) return {
314
+ message: ".. not allowed",
315
+ isError: true
316
+ };
317
+ if (isAbsolute(dir)) return {
318
+ message: "absolute hooks directory not allowed",
319
+ isError: true
320
+ };
321
+ if (relative(process.cwd(), resolve(process.cwd(), dir)) === "") return {
322
+ message: "hooks directory must be a project subdirectory",
323
+ isError: true
324
+ };
325
+ return null;
326
+ }
327
+ function getEffectiveHooksPath() {
328
+ const checkResult = spawnSync("git", [
329
+ "config",
330
+ "--get",
331
+ "core.hooksPath"
332
+ ]);
333
+ return checkResult.status === 0 ? checkResult.stdout?.toString().trim() : "";
334
+ }
335
+ function getScopedHooksPath(scope) {
336
+ const result = spawnSync("git", [
337
+ "config",
338
+ `--${scope}`,
339
+ "--get",
340
+ "core.hooksPath"
341
+ ]);
342
+ return result.status === 0 ? result.stdout?.toString().trim() : "";
343
+ }
344
+ function unsetScopedHooksPath(scope) {
345
+ const result = spawnSync("git", [
346
+ "config",
347
+ `--${scope}`,
348
+ "--unset-all",
349
+ "core.hooksPath"
350
+ ]);
351
+ if (result.status == null) return {
352
+ message: "git command not found",
353
+ isError: true
354
+ };
355
+ if (result.status !== 0 && result.status !== 5) return {
356
+ message: result.stderr?.toString().trim() || `failed to unset ${scope} core.hooksPath`,
357
+ isError: true
358
+ };
359
+ return null;
360
+ }
361
+ /**
362
+ * Unset core.hooksPath only at scopes that actually point at our dispatcher.
363
+ *
364
+ * Must not touch a foreign value at another scope (e.g. local still `.husky/_`
365
+ * while worktree holds the Vite+ target).
366
+ */
367
+ function unsetOwnedHooksPath(target) {
368
+ const toplevel = getGitToplevel();
369
+ if (typeof toplevel !== "string") return toplevel;
370
+ for (const scope of ["local", "worktree"]) {
371
+ const scopedPath = getScopedHooksPath(scope);
372
+ if (!scopedPath || !hooksPathsEqual(scopedPath, target, toplevel)) continue;
373
+ const unsetError = unsetScopedHooksPath(scope);
374
+ if (unsetError) return unsetError;
375
+ }
376
+ const finalPath = getEffectiveHooksPath();
377
+ if (finalPath && hooksPathsEqual(finalPath, target, toplevel)) return {
378
+ message: `could not unset core.hooksPath (still "${finalPath}"); remove it with git config --unset core.hooksPath`,
379
+ isError: true
380
+ };
381
+ return null;
382
+ }
383
+ function isGitHooksEnvDisabled() {
384
+ return process.env.HUSKY === "0" || process.env.VP_GIT_HOOKS === "0" || process.env.VITE_GIT_HOOKS === "0";
385
+ }
386
+ function install(dir, options = {}) {
387
+ if (isGitHooksEnvDisabled()) return {
388
+ message: "skip install (git hooks disabled)",
389
+ isError: false
390
+ };
391
+ if (!options.ignoreUserPreference && isHooksUserDisabled()) return {
392
+ message: "skip install (hooks disabled; run `vp hooks enable` to re-enable)",
393
+ isError: false
394
+ };
395
+ const location = resolveHooksLocation(dir);
396
+ if ("isError" in location) return location;
397
+ const unsafeInstallPath = findUnsafeHookInstallPath(location.baseDir, location.dir);
398
+ if (unsafeInstallPath) return {
399
+ message: describeUnsafeHookInstallPath(unsafeInstallPath),
400
+ isError: false
401
+ };
402
+ const internal = (x = "") => join(location.baseDir, location.dir, "_", x);
403
+ const existingHooksPath = getEffectiveHooksPath();
404
+ if (existingHooksPath && !hooksPathsEqual(existingHooksPath, location.target, location.toplevel)) return {
405
+ message: `core.hooksPath is already set to "${existingHooksPath}", skipping`,
406
+ isError: false
407
+ };
408
+ rmSync(internal("husky.sh"), { force: true });
409
+ mkdirSync(internal(), { recursive: true });
410
+ writeFileSync(internal(".gitignore"), "*");
411
+ writeFileSync(internal("h"), hookScript(location.dir), { mode: 493 });
412
+ chmodSync(internal("h"), 493);
413
+ for (const hook of SUPPORTED_GIT_HOOK_NAMES) {
414
+ writeFileSync(internal(hook), `#!/usr/bin/env sh\n. "$(dirname "$0")/h"`, { mode: 493 });
415
+ chmodSync(internal(hook), 493);
416
+ }
417
+ const { status, stderr } = spawnSync("git", [
418
+ "config",
419
+ "core.hooksPath",
420
+ location.target
421
+ ]);
422
+ if (status == null) return {
423
+ message: "git command not found",
424
+ isError: true
425
+ };
426
+ if (status) return {
427
+ message: "" + stderr,
428
+ isError: true
429
+ };
430
+ const clearDisabled = setHooksUserDisabled(false);
431
+ if (!clearDisabled.ok) return {
432
+ message: clearDisabled.error || "failed to clear hooks disabled preference",
433
+ isError: true
434
+ };
435
+ const storeDir = setStoredHooksLocation(location.dir, location.prefix);
436
+ if (!storeDir.ok) return {
437
+ message: storeDir.error || "failed to store hooks directory",
438
+ isError: true
439
+ };
440
+ return {
441
+ message: "",
442
+ isError: false
443
+ };
444
+ }
445
+ /**
446
+ * Install (or refresh) the Vite+ hook dispatcher and mark hooks as enabled.
447
+ * Clears a previous `vp hooks disable` preference.
448
+ */
449
+ function enable(dir) {
450
+ const location = resolveHooksLocation(dir);
451
+ if ("isError" in location) return location;
452
+ const result = install(dir, { ignoreUserPreference: true });
453
+ if (result.isError) return result;
454
+ if (result.message) return result;
455
+ return {
456
+ message: `Git hook dispatcher installed at ${displayHooksDir(location)}/_`,
457
+ isError: false
458
+ };
459
+ }
460
+ /**
461
+ * Disable Vite+ hooks in this repo and tear down the dispatcher.
462
+ *
463
+ * - Persists the decision in local git config so `vp config` / prepare do not reinstall
464
+ * - Unsets `core.hooksPath` only when it points at this project's dispatcher
465
+ * - Removes the generated `<dir>/_` directory
466
+ * - Leaves project-owned hooks, staged config, and package.json scripts alone
467
+ */
468
+ function disable(dir) {
469
+ const location = resolveHooksLocation(dir, {
470
+ unstoredPrefix: "root",
471
+ adoptEffectiveDispatcher: true
472
+ });
473
+ if ("isError" in location) return location;
474
+ const displayedDir = displayHooksDir(location);
475
+ const internalDir = join(location.baseDir, location.dir, "_");
476
+ const hasInternalDir = existsSync(internalDir);
477
+ if (hasInternalDir) {
478
+ const unsafeInstallPath = findUnsafeHookInstallPath(location.baseDir, location.dir);
479
+ if (unsafeInstallPath) return {
480
+ message: describeUnsafeHookInstallPath(unsafeInstallPath),
481
+ isError: false
482
+ };
483
+ }
484
+ const existingHooksPath = getEffectiveHooksPath();
485
+ const ownsHooksPath = !!existingHooksPath && hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
486
+ const foreignHooksPath = !!existingHooksPath && !hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
487
+ const actions = [];
488
+ const notes = [];
489
+ const pref = setHooksUserDisabled(true);
490
+ if (!pref.ok) return {
491
+ message: pref.error || "failed to persist hooks disabled preference",
492
+ isError: true
493
+ };
494
+ const storeDir = setStoredHooksLocation(location.dir, location.prefix);
495
+ if (!storeDir.ok) return {
496
+ message: storeDir.error || "failed to store hooks directory",
497
+ isError: true
498
+ };
499
+ actions.push("recorded disable preference (local git config)");
500
+ const unsetError = unsetOwnedHooksPath(location.target);
501
+ if (unsetError) return {
502
+ message: `${unsetError.message}; disable preference was recorded (local git config). Run \`vp hooks enable\` to clear it, or \`git config --local --unset vp.hooks.disabled\``,
503
+ isError: true
504
+ };
505
+ if (ownsHooksPath) actions.push(`unset core.hooksPath (was "${existingHooksPath}")`);
506
+ else if (foreignHooksPath) notes.push(`core.hooksPath is set to "${existingHooksPath}" (not Vite+ dispatcher "${location.target}"), left unchanged`);
507
+ if (hasInternalDir) {
508
+ rmSync(internalDir, {
509
+ recursive: true,
510
+ force: true
511
+ });
512
+ actions.push(`removed ${displayedDir}/_`);
513
+ }
514
+ const summary = `Git hooks disabled: ${actions.join("; ")}. Project-owned hooks under ${displayedDir}/ and staged config were left unchanged. Run \`vp hooks enable\` to re-enable.`;
515
+ if (notes.length > 0) return {
516
+ message: `${summary} ${notes.join("; ")}.`,
517
+ isError: false
518
+ };
519
+ return {
520
+ message: summary,
521
+ isError: false
522
+ };
523
+ }
524
+ /**
525
+ * Report whether Vite+ hooks are set up, disabled by preference, and active.
526
+ */
527
+ function status(dir) {
528
+ const location = resolveHooksLocation(dir, {
529
+ unstoredPrefix: "root",
530
+ adoptEffectiveDispatcher: true
531
+ });
532
+ if ("isError" in location) return location;
533
+ const hooksDir = displayHooksDir(location);
534
+ const existingHooksPath = getEffectiveHooksPath();
535
+ const userDisabled = isHooksUserDisabled();
536
+ const dispatcherInstalled = existsSync(join(location.baseDir, location.dir, "_", "h"));
537
+ const ownsHooksPath = !!existingHooksPath && hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
538
+ let projectHooks = [];
539
+ const hooksDirPath = join(location.baseDir, location.dir);
540
+ if (existsSync(hooksDirPath)) try {
541
+ projectHooks = readdirSync(hooksDirPath, { withFileTypes: true }).filter((entry) => entry.isFile() && SUPPORTED_GIT_HOOK_NAMES.includes(entry.name)).map((entry) => entry.name).toSorted();
542
+ } catch {
543
+ projectHooks = [];
544
+ }
545
+ const preferenceLabel = userDisabled ? "disabled (local)" : getStoredHooksDir() || dispatcherInstalled || ownsHooksPath ? "enabled" : "not set";
546
+ const hooksPathLabel = existingHooksPath || "(unset)";
547
+ const ownership = !existingHooksPath ? "" : ownsHooksPath ? " (Vite+ dispatcher)" : " (not Vite+ dispatcher)";
548
+ const dispatcherLabel = dispatcherInstalled ? "installed" : "missing";
549
+ const projectHooksLabel = projectHooks.length > 0 ? projectHooks.join(", ") : "(none)";
550
+ const lines = [
551
+ `Preference: ${preferenceLabel}`,
552
+ `Hooks dir: ${hooksDir}`,
553
+ `core.hooksPath: ${hooksPathLabel}${ownership}`,
554
+ `Dispatcher: ${dispatcherLabel} (${hooksDir}/_)`,
555
+ `Project hooks: ${projectHooksLabel}`
556
+ ];
557
+ const hooksStatus = {
558
+ hooksDir,
559
+ userDisabled,
560
+ hooksPath: existingHooksPath || null,
561
+ ownsHooksPath,
562
+ dispatcherInstalled,
563
+ projectHooks,
564
+ lines
565
+ };
566
+ return {
567
+ message: lines.join("\n"),
568
+ isError: false,
569
+ status: hooksStatus
570
+ };
571
+ }
572
+ //#endregion
573
+ export { findUnsafeHookInstallPath as a, isHooksUserDisabled as c, enable as i, resolveHooksLocation as l, SUPPORTED_GIT_HOOK_NAMES as n, install as o, disable as r, isGitHooksEnvDisabled as s, DEFAULT_HOOKS_DIR as t, status as u };
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_define_config = require("./define-config-CEm_MtvJ.cjs");
1
+ const require_define_config = require("./define-config-WiVlryJ2.cjs");
2
2
  //#region src/index.cts
3
3
  const vite = require("@voidzero-dev/vite-plus-core");
4
4
  const { configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude } = require("vitest/config");
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as defineConfig, c as lazyPlugins, o as defineProject } from "./define-config-DPnHe1Mx.js";
1
+ import { a as defineConfig, c as lazyPlugins, o as defineProject } from "./define-config-GXUdVT-0.js";
2
2
  import { configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude } from "vitest/config";
3
3
  export * from "@voidzero-dev/vite-plus-core";
4
4
  export { configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude, defineConfig, defineProject, lazyPlugins };