vite-plus 0.2.7 → 0.2.9

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 (89) hide show
  1. package/AGENTS.md +7 -0
  2. package/LICENSE +5 -1
  3. package/README.md +9 -3
  4. package/bin/vpr +3 -2
  5. package/binding/index.cjs +193 -80
  6. package/binding/index.d.cts +106 -11
  7. package/dist/agent-DQU8uS6P.js +416 -0
  8. package/dist/bin.js +1388 -23
  9. package/dist/{cli-truncate-BVOlIIPy.js → cli-truncate-Bg3RDXpi.js} +0 -2
  10. package/dist/client/bundledDevClient.mjs +1 -0
  11. package/dist/config/bin.js +32 -133
  12. package/dist/{constants-BsuzPowC.js → constants-CG513DRa.js} +10 -2
  13. package/dist/create/bin.js +255 -268
  14. package/dist/{define-config-C2KfLHpC.js → define-config-CV4bQG_8.js} +3 -3
  15. package/dist/{define-config-eLQH9us2.d.ts → define-config-DWoAkNdp.d.ts} +16 -0
  16. package/dist/{define-config-DLh9fE95.cjs → define-config-DyNLA_f0.cjs} +1 -1
  17. package/dist/define-config.cjs +1 -1
  18. package/dist/define-config.d.ts +1 -1
  19. package/dist/define-config.js +1 -1
  20. package/dist/{dist-CKz3vcoG.js → dist-BDYZP12R.js} +196 -157
  21. package/dist/dist-Dqv1-Clg.js +3 -0
  22. package/dist/{agent-CPwWJ4qf.js → editor-g4PosU99.js} +819 -628
  23. package/dist/hooks/bin.d.ts +1 -0
  24. package/dist/hooks/bin.js +130 -0
  25. package/dist/hooks-pNCBWtFT.js +570 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/{json-DiRs8ceZ.js → json-qlK6UH0r.js} +40 -38
  30. package/dist/migration/bin.js +65 -58
  31. package/dist/{oxlint-plugin-config-Bxgc4cwF.js → oxlint-plugin-config-BEZ9IUf7.js} +1 -1
  32. package/dist/oxlint-plugin.js +1 -1
  33. package/dist/pack-bin.js +1 -1
  34. package/dist/{package-Ds3uThLb.js → package-B4T8RGMG.js} +2 -2
  35. package/dist/{tsconfig-Jia2vgMG.js → prompts-CHz_98bJ.js} +169 -219
  36. package/dist/{resolve-vite-config-BiuLZnn8.js → resolve-vite-config-Dmeyeyj-.js} +2 -9
  37. package/dist/{rolldown-runtime-C7HZzL1F.js → rolldown-runtime-CMFfr-1z.js} +1 -1
  38. package/dist/staged/bin.js +241 -226
  39. package/dist/terminal-Bz-ps6rJ.js +128 -0
  40. package/dist/test/browser/providers/playwright/context.d.ts +1 -1
  41. package/dist/test/browser/providers/playwright.d.ts +6 -6
  42. package/dist/test/browser/providers/preview/context.d.ts +1 -1
  43. package/dist/test/browser/providers/preview.d.ts +4 -4
  44. package/dist/test/browser/providers/webdriverio/context.d.ts +1 -1
  45. package/dist/test/browser/providers/webdriverio.d.ts +6 -6
  46. package/dist/test/browser-playwright/context.d.ts +1 -1
  47. package/dist/test/browser-playwright.d.ts +6 -6
  48. package/dist/test/browser-preview/context.d.ts +1 -1
  49. package/dist/test/browser-preview.d.ts +4 -4
  50. package/dist/test/browser-webdriverio/context.d.ts +1 -1
  51. package/dist/test/browser-webdriverio.d.ts +6 -6
  52. package/dist/test/context.d.ts +3 -3
  53. package/dist/test/locators.d.ts +1 -1
  54. package/dist/toolchain.d.ts +25 -0
  55. package/dist/toolchain.js +194 -0
  56. package/dist/toolchain.json +193 -0
  57. package/dist/tsconfig-7v_BHagU.js +151 -0
  58. package/dist/{tsgolint-path-B-yOos8p.js → tsgolint-path-CbDReEOx.js} +5 -3
  59. package/dist/tsgolint-path.js +1 -1
  60. package/dist/version.js +6 -6
  61. package/dist/versions.d.ts +3 -3
  62. package/dist/versions.js +6 -6
  63. package/docs/config/index.md +13 -0
  64. package/docs/config/staged.md +2 -1
  65. package/docs/guide/ci.md +37 -4
  66. package/docs/guide/commit-hooks.md +112 -21
  67. package/docs/guide/create.md +7 -4
  68. package/docs/guide/env.md +8 -4
  69. package/docs/guide/fmt.md +2 -2
  70. package/docs/guide/github-actions-cache.md +5 -1
  71. package/docs/guide/ide-integration.md +61 -2
  72. package/docs/guide/index.md +4 -2
  73. package/docs/guide/install.md +27 -0
  74. package/docs/guide/installer-env-vars.md +14 -3
  75. package/docs/guide/lint.md +3 -1
  76. package/docs/guide/migrate.md +49 -4
  77. package/docs/guide/monorepo.md +98 -10
  78. package/docs/guide/troubleshooting.md +12 -3
  79. package/docs/guide/upgrade.md +27 -4
  80. package/docs/package.json +1 -1
  81. package/docs/pnpm-workspace.yaml +7 -0
  82. package/docs/vite.config.ts +3 -0
  83. package/package.json +21 -23
  84. package/rules/vite-tools.yml +0 -7
  85. package/dist/dist-CtM2JRbM.js +0 -3
  86. package/dist/editor-BbT1lTNc.js +0 -675
  87. package/dist/help-YP84FSEz.js +0 -61
  88. package/dist/terminal-uTv0ZaMr.js +0 -33
  89. package/dist/{log-update-DHZRyJ2m.js → log-update-CoW8Z4Dl.js} +1 -1
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,130 @@
1
+ import { i as log, l as renderCliDoc, o as printHeader } from "../terminal-Bz-ps6rJ.js";
2
+ import { t as lib_default } from "../lib-L3DWSRQp.js";
3
+ import { i as enable, l as status, r as disable, t as DEFAULT_HOOKS_DIR } from "../hooks-pNCBWtFT.js";
4
+ //#region src/hooks/args.ts
5
+ const KNOWN_HOOKS_ARG_KEYS = /* @__PURE__ */ new Set([
6
+ "_",
7
+ "help",
8
+ "h",
9
+ "hooks-dir"
10
+ ]);
11
+ /**
12
+ * Reject leftover positionals and unknown flags before enable/disable mutate state.
13
+ */
14
+ function unexpectedHooksArgsError(args) {
15
+ const extra = args._.map(String).filter((value) => value !== "");
16
+ if (extra.length > 0) return `Unexpected argument "${extra[0]}". Use --hooks-dir <path> to set a custom hooks directory.`;
17
+ for (const key of Object.keys(args)) if (!KNOWN_HOOKS_ARG_KEYS.has(key)) return `Unknown option "--${key}".`;
18
+ return null;
19
+ }
20
+ //#endregion
21
+ //#region src/hooks/bin.ts
22
+ const SUBCOMMANDS = [
23
+ "enable",
24
+ "disable",
25
+ "status"
26
+ ];
27
+ function isSubcommand(value) {
28
+ return !!value && SUBCOMMANDS.includes(value);
29
+ }
30
+ function printHelp() {
31
+ const helpMessage = renderCliDoc({
32
+ usage: "vp hooks <COMMAND> [OPTIONS]",
33
+ summary: "Manage the Vite+ Git hook dispatcher for this repository.",
34
+ documentationUrl: "https://viteplus.dev/guide/commit-hooks",
35
+ sections: [
36
+ {
37
+ title: "Commands",
38
+ rows: [
39
+ {
40
+ label: "enable",
41
+ description: "Install or refresh the hook dispatcher (sets core.hooksPath)"
42
+ },
43
+ {
44
+ label: "disable",
45
+ description: "Disable hooks: unset core.hooksPath, remove <dir>/_, persist preference"
46
+ },
47
+ {
48
+ label: "status",
49
+ description: "Show preference, core.hooksPath, and dispatcher state"
50
+ }
51
+ ]
52
+ },
53
+ {
54
+ title: "Options",
55
+ rows: [{
56
+ label: "--hooks-dir <path>",
57
+ description: `Custom hooks directory (default: ${DEFAULT_HOOKS_DIR}, or last used)`
58
+ }, {
59
+ label: "-h, --help",
60
+ description: "Show this help message"
61
+ }]
62
+ },
63
+ {
64
+ title: "Environment",
65
+ rows: [{
66
+ label: "VP_GIT_HOOKS=0",
67
+ description: "Skip dispatcher install in enable (and skip hooks at commit time)"
68
+ }]
69
+ },
70
+ {
71
+ title: "Examples",
72
+ lines: [
73
+ " vp hooks enable",
74
+ " vp hooks enable --hooks-dir .custom-hooks",
75
+ " vp hooks disable",
76
+ " vp hooks status"
77
+ ]
78
+ }
79
+ ]
80
+ });
81
+ printHeader();
82
+ log(helpMessage);
83
+ }
84
+ function applyResult(result) {
85
+ if (result.message) log(result.message);
86
+ if (result.isError) process.exit(1);
87
+ }
88
+ async function main() {
89
+ const raw = process.argv.slice(3);
90
+ const first = raw[0];
91
+ const wantsHelp = raw.includes("-h") || raw.includes("--help");
92
+ if (!first || first === "-h" || first === "--help") {
93
+ printHelp();
94
+ return;
95
+ }
96
+ if (!isSubcommand(first)) {
97
+ log(`Unknown hooks command "${first}". Expected one of: ${SUBCOMMANDS.join(", ")}`);
98
+ process.exit(1);
99
+ }
100
+ const subcommand = first;
101
+ const args = lib_default(raw.slice(1), {
102
+ boolean: ["help"],
103
+ string: ["hooks-dir"],
104
+ alias: { h: "help" }
105
+ });
106
+ if (args.help || wantsHelp) {
107
+ printHelp();
108
+ return;
109
+ }
110
+ const unexpected = unexpectedHooksArgsError(args);
111
+ if (unexpected) {
112
+ log(unexpected);
113
+ process.exit(1);
114
+ }
115
+ const dirFlag = args["hooks-dir"];
116
+ switch (subcommand) {
117
+ case "enable":
118
+ applyResult(enable(dirFlag));
119
+ return;
120
+ case "disable":
121
+ applyResult(disable(dirFlag));
122
+ return;
123
+ case "status":
124
+ applyResult(status(dirFlag));
125
+ return;
126
+ }
127
+ }
128
+ main();
129
+ //#endregion
130
+ export {};
@@ -0,0 +1,570 @@
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 install(dir, options = {}) {
384
+ if (process.env.HUSKY === "0" || process.env.VP_GIT_HOOKS === "0" || process.env.VITE_GIT_HOOKS === "0") return {
385
+ message: "skip install (git hooks disabled)",
386
+ isError: false
387
+ };
388
+ if (!options.ignoreUserPreference && isHooksUserDisabled()) return {
389
+ message: "skip install (hooks disabled; run `vp hooks enable` to re-enable)",
390
+ isError: false
391
+ };
392
+ const location = resolveHooksLocation(dir);
393
+ if ("isError" in location) return location;
394
+ const unsafeInstallPath = findUnsafeHookInstallPath(location.baseDir, location.dir);
395
+ if (unsafeInstallPath) return {
396
+ message: describeUnsafeHookInstallPath(unsafeInstallPath),
397
+ isError: false
398
+ };
399
+ const internal = (x = "") => join(location.baseDir, location.dir, "_", x);
400
+ const existingHooksPath = getEffectiveHooksPath();
401
+ if (existingHooksPath && !hooksPathsEqual(existingHooksPath, location.target, location.toplevel)) return {
402
+ message: `core.hooksPath is already set to "${existingHooksPath}", skipping`,
403
+ isError: false
404
+ };
405
+ rmSync(internal("husky.sh"), { force: true });
406
+ mkdirSync(internal(), { recursive: true });
407
+ writeFileSync(internal(".gitignore"), "*");
408
+ writeFileSync(internal("h"), hookScript(location.dir), { mode: 493 });
409
+ chmodSync(internal("h"), 493);
410
+ for (const hook of SUPPORTED_GIT_HOOK_NAMES) {
411
+ writeFileSync(internal(hook), `#!/usr/bin/env sh\n. "$(dirname "$0")/h"`, { mode: 493 });
412
+ chmodSync(internal(hook), 493);
413
+ }
414
+ const { status, stderr } = spawnSync("git", [
415
+ "config",
416
+ "core.hooksPath",
417
+ location.target
418
+ ]);
419
+ if (status == null) return {
420
+ message: "git command not found",
421
+ isError: true
422
+ };
423
+ if (status) return {
424
+ message: "" + stderr,
425
+ isError: true
426
+ };
427
+ const clearDisabled = setHooksUserDisabled(false);
428
+ if (!clearDisabled.ok) return {
429
+ message: clearDisabled.error || "failed to clear hooks disabled preference",
430
+ isError: true
431
+ };
432
+ const storeDir = setStoredHooksLocation(location.dir, location.prefix);
433
+ if (!storeDir.ok) return {
434
+ message: storeDir.error || "failed to store hooks directory",
435
+ isError: true
436
+ };
437
+ return {
438
+ message: "",
439
+ isError: false
440
+ };
441
+ }
442
+ /**
443
+ * Install (or refresh) the Vite+ hook dispatcher and mark hooks as enabled.
444
+ * Clears a previous `vp hooks disable` preference.
445
+ */
446
+ function enable(dir) {
447
+ const location = resolveHooksLocation(dir);
448
+ if ("isError" in location) return location;
449
+ const result = install(dir, { ignoreUserPreference: true });
450
+ if (result.isError) return result;
451
+ if (result.message) return result;
452
+ return {
453
+ message: `Git hook dispatcher installed at ${displayHooksDir(location)}/_`,
454
+ isError: false
455
+ };
456
+ }
457
+ /**
458
+ * Disable Vite+ hooks in this repo and tear down the dispatcher.
459
+ *
460
+ * - Persists the decision in local git config so `vp config` / prepare do not reinstall
461
+ * - Unsets `core.hooksPath` only when it points at this project's dispatcher
462
+ * - Removes the generated `<dir>/_` directory
463
+ * - Leaves project-owned hooks, staged config, and package.json scripts alone
464
+ */
465
+ function disable(dir) {
466
+ const location = resolveHooksLocation(dir, {
467
+ unstoredPrefix: "root",
468
+ adoptEffectiveDispatcher: true
469
+ });
470
+ if ("isError" in location) return location;
471
+ const displayedDir = displayHooksDir(location);
472
+ const internalDir = join(location.baseDir, location.dir, "_");
473
+ const hasInternalDir = existsSync(internalDir);
474
+ if (hasInternalDir) {
475
+ const unsafeInstallPath = findUnsafeHookInstallPath(location.baseDir, location.dir);
476
+ if (unsafeInstallPath) return {
477
+ message: describeUnsafeHookInstallPath(unsafeInstallPath),
478
+ isError: false
479
+ };
480
+ }
481
+ const existingHooksPath = getEffectiveHooksPath();
482
+ const ownsHooksPath = !!existingHooksPath && hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
483
+ const foreignHooksPath = !!existingHooksPath && !hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
484
+ const actions = [];
485
+ const notes = [];
486
+ const pref = setHooksUserDisabled(true);
487
+ if (!pref.ok) return {
488
+ message: pref.error || "failed to persist hooks disabled preference",
489
+ isError: true
490
+ };
491
+ const storeDir = setStoredHooksLocation(location.dir, location.prefix);
492
+ if (!storeDir.ok) return {
493
+ message: storeDir.error || "failed to store hooks directory",
494
+ isError: true
495
+ };
496
+ actions.push("recorded disable preference (local git config)");
497
+ const unsetError = unsetOwnedHooksPath(location.target);
498
+ if (unsetError) return {
499
+ 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\``,
500
+ isError: true
501
+ };
502
+ if (ownsHooksPath) actions.push(`unset core.hooksPath (was "${existingHooksPath}")`);
503
+ else if (foreignHooksPath) notes.push(`core.hooksPath is set to "${existingHooksPath}" (not Vite+ dispatcher "${location.target}"), left unchanged`);
504
+ if (hasInternalDir) {
505
+ rmSync(internalDir, {
506
+ recursive: true,
507
+ force: true
508
+ });
509
+ actions.push(`removed ${displayedDir}/_`);
510
+ }
511
+ 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.`;
512
+ if (notes.length > 0) return {
513
+ message: `${summary} ${notes.join("; ")}.`,
514
+ isError: false
515
+ };
516
+ return {
517
+ message: summary,
518
+ isError: false
519
+ };
520
+ }
521
+ /**
522
+ * Report whether Vite+ hooks are set up, disabled by preference, and active.
523
+ */
524
+ function status(dir) {
525
+ const location = resolveHooksLocation(dir, {
526
+ unstoredPrefix: "root",
527
+ adoptEffectiveDispatcher: true
528
+ });
529
+ if ("isError" in location) return location;
530
+ const hooksDir = displayHooksDir(location);
531
+ const existingHooksPath = getEffectiveHooksPath();
532
+ const userDisabled = isHooksUserDisabled();
533
+ const dispatcherInstalled = existsSync(join(location.baseDir, location.dir, "_", "h"));
534
+ const ownsHooksPath = !!existingHooksPath && hooksPathsEqual(existingHooksPath, location.target, location.toplevel);
535
+ let projectHooks = [];
536
+ const hooksDirPath = join(location.baseDir, location.dir);
537
+ if (existsSync(hooksDirPath)) try {
538
+ projectHooks = readdirSync(hooksDirPath, { withFileTypes: true }).filter((entry) => entry.isFile() && SUPPORTED_GIT_HOOK_NAMES.includes(entry.name)).map((entry) => entry.name).toSorted();
539
+ } catch {
540
+ projectHooks = [];
541
+ }
542
+ const preferenceLabel = userDisabled ? "disabled (local)" : getStoredHooksDir() || dispatcherInstalled || ownsHooksPath ? "enabled" : "not set";
543
+ const hooksPathLabel = existingHooksPath || "(unset)";
544
+ const ownership = !existingHooksPath ? "" : ownsHooksPath ? " (Vite+ dispatcher)" : " (not Vite+ dispatcher)";
545
+ const dispatcherLabel = dispatcherInstalled ? "installed" : "missing";
546
+ const projectHooksLabel = projectHooks.length > 0 ? projectHooks.join(", ") : "(none)";
547
+ const lines = [
548
+ `Preference: ${preferenceLabel}`,
549
+ `Hooks dir: ${hooksDir}`,
550
+ `core.hooksPath: ${hooksPathLabel}${ownership}`,
551
+ `Dispatcher: ${dispatcherLabel} (${hooksDir}/_)`,
552
+ `Project hooks: ${projectHooksLabel}`
553
+ ];
554
+ const hooksStatus = {
555
+ hooksDir,
556
+ userDisabled,
557
+ hooksPath: existingHooksPath || null,
558
+ ownsHooksPath,
559
+ dispatcherInstalled,
560
+ projectHooks,
561
+ lines
562
+ };
563
+ return {
564
+ message: lines.join("\n"),
565
+ isError: false,
566
+ status: hooksStatus
567
+ };
568
+ }
569
+ //#endregion
570
+ export { findUnsafeHookInstallPath as a, resolveHooksLocation as c, enable as i, status as l, SUPPORTED_GIT_HOOK_NAMES as n, install as o, disable as r, isHooksUserDisabled as s, DEFAULT_HOOKS_DIR as t };
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_define_config = require("./define-config-DLh9fE95.cjs");
1
+ const require_define_config = require("./define-config-DyNLA_f0.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");