vite-plus 0.2.6 → 0.2.8

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 (61) hide show
  1. package/AGENTS.md +4 -0
  2. package/LICENSE +5 -1
  3. package/README.md +1 -1
  4. package/bin/vpr +3 -2
  5. package/binding/index.cjs +193 -80
  6. package/binding/index.d.cts +99 -8
  7. package/dist/agent-CI79DuSy.js +600 -0
  8. package/dist/bin.js +1367 -11
  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 +13 -126
  12. package/dist/{constants-CaXMuYUG.js → constants-BppDcRc1.js} +1 -1
  13. package/dist/create/bin.js +90 -77
  14. package/dist/{define-config-iGV0CGUk.cjs → define-config-CEm_MtvJ.cjs} +1 -1
  15. package/dist/{define-config-hV8qyU8p.js → define-config-DPnHe1Mx.js} +2 -2
  16. package/dist/{define-config-eLQH9us2.d.ts → define-config-DWoAkNdp.d.ts} +16 -0
  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-CSQWHI6y.js} +3 -8
  21. package/dist/dist-DT25H9pj.js +3 -0
  22. package/dist/{agent-0gFJkIKu.js → editor-CGWdbLgD.js} +709 -579
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/{json-DiRs8ceZ.js → json-BU88uu6o.js} +2 -6
  27. package/dist/migration/bin.js +60 -50
  28. package/dist/{oxlint-plugin-config-CMSCIkks.js → oxlint-plugin-config-BHOzlwMw.js} +1 -1
  29. package/dist/oxlint-plugin.js +1 -1
  30. package/dist/pack-bin.js +2 -2
  31. package/dist/{package-CP5EUXlu.js → package-hV-77cBb.js} +2 -2
  32. package/dist/{tsconfig-Cac-NNdT.js → prompts-DYap08te.js} +32 -174
  33. package/dist/{resolve-vite-config-BY7PB-LW.js → resolve-vite-config-EWXclqvV.js} +1 -1
  34. package/dist/{rolldown-runtime-C7HZzL1F.js → rolldown-runtime-CMFfr-1z.js} +1 -1
  35. package/dist/staged/bin.js +20 -23
  36. package/dist/{help-YP84FSEz.js → terminal-CrqqK8WT.js} +39 -2
  37. package/dist/tsconfig-CVUKLfL8.js +151 -0
  38. package/dist/{tsgolint-path-B-yOos8p.js → tsgolint-path-eMZT-oea.js} +4 -2
  39. package/dist/tsgolint-path.js +1 -1
  40. package/dist/version.js +5 -5
  41. package/dist/versions.js +5 -5
  42. package/docs/config/index.md +13 -0
  43. package/docs/config/staged.md +2 -1
  44. package/docs/guide/build.md +1 -1
  45. package/docs/guide/ci.md +28 -3
  46. package/docs/guide/commit-hooks.md +76 -9
  47. package/docs/guide/dev.md +4 -0
  48. package/docs/guide/env.md +8 -4
  49. package/docs/guide/index.md +1 -1
  50. package/docs/guide/install.md +2 -0
  51. package/docs/guide/installer-env-vars.md +3 -3
  52. package/docs/guide/migrate.md +11 -3
  53. package/docs/guide/monorepo.md +94 -6
  54. package/docs/guide/run.md +15 -0
  55. package/docs/guide/test.md +4 -0
  56. package/docs/guide/troubleshooting.md +9 -5
  57. package/package.json +18 -24
  58. package/dist/dist-CtM2JRbM.js +0 -3
  59. package/dist/editor-D4T70tKk.js +0 -675
  60. package/dist/terminal-uTv0ZaMr.js +0 -33
  61. package/dist/{log-update-DHZRyJ2m.js → log-update-CoW8Z4Dl.js} +1 -1
@@ -1,40 +1,26 @@
1
- import { r as __toESM } from "./rolldown-runtime-C7HZzL1F.js";
2
- import { a as VITEST_AGE_GATE_EXEMPT_PACKAGES, c as VITE_PLUS_OVERRIDE_PACKAGES, d as isForceOverrideMode, l as VITE_PLUS_VERSION, n as BASEURL_TSCONFIG_WARNING, o as VITEST_VERSION, s as VITE_PLUS_NAME } from "./constants-CaXMuYUG.js";
3
- import { i as ensureVitePlusImportRuleDefaults, r as createDefaultVitePlusLintConfig } from "./oxlint-plugin-config-CMSCIkks.js";
4
- import { B as runCommandSilently, D as require_semver, E as PackageManager, M as multiselect, P as select, R as isCancel, V as require_cross_spawn, a as hasTypesToRewriteInTsconfig, b as scalarString, c as rewriteTypesInTsconfig, i as hasBaseUrlInTsconfig, j as log, k as confirm, l as cancelAndExit, n as findTsconfigFiles, o as hasVitestTypesInTsconfig, s as removeDeprecatedTsconfigFalseOption, v as editYamlFile, w as getSpinner, y as readYamlFile } from "./tsconfig-Cac-NNdT.js";
5
- import { a as writeJsonFile, i as readJsonFile, n as editJsonFile, r as isJsonFile } from "./json-DiRs8ceZ.js";
6
- import { t as require_dist } from "./dist-CKz3vcoG.js";
7
- import { n as detectPackageMetadata } from "./package-CP5EUXlu.js";
1
+ import { r as __toESM } from "./rolldown-runtime-CMFfr-1z.js";
2
+ import { a as VITEST_AGE_GATE_EXEMPT_PACKAGES, c as VITE_PLUS_OVERRIDE_PACKAGES, d as isForceOverrideMode, l as VITE_PLUS_VERSION, n as BASEURL_TSCONFIG_WARNING, o as VITEST_VERSION, s as VITE_PLUS_NAME } from "./constants-BppDcRc1.js";
3
+ import { i as ensureVitePlusImportRuleDefaults, r as createDefaultVitePlusLintConfig } from "./oxlint-plugin-config-BHOzlwMw.js";
4
+ import { A as isCancel, C as log, E as select, M as runCommandSilently, N as require_cross_spawn, d as readYamlFile, f as scalarString, g as getSpinner, t as cancelAndExit, u as editYamlFile, v as PackageManager, w as multiselect, x as confirm, y as require_semver } from "./prompts-DYap08te.js";
5
+ import { a as writeJsonFile, c as parse, i as readJsonFile, n as editJsonFile, o as applyEdits, r as isJsonFile, s as modify, t as detectFormattingOptions } from "./json-BU88uu6o.js";
6
+ import { t as require_dist } from "./dist-CSQWHI6y.js";
7
+ import { a as hasTypesToRewriteInTsconfig, c as rewriteTypesInTsconfig, i as hasBaseUrlInTsconfig, n as findTsconfigFiles, o as hasVitestTypesInTsconfig, s as removeDeprecatedTsconfigFalseOption } from "./tsconfig-CVUKLfL8.js";
8
+ import { n as detectPackageMetadata, r as getScopeFromPackageName } from "./package-hV-77cBb.js";
9
+ import { f as displayRelative, l as SUPPORTED_GIT_HOOK_NAMES, p as rulesDir, u as findUnsafeHookInstallPath } from "./agent-CI79DuSy.js";
8
10
  import { n as addMigrationWarning, t as addManualStep } from "./report-BS7ULx7A.js";
9
11
  import path, { posix, win32 } from "node:path";
10
- import { hasConfigKey, mergeJsonConfig, mergeTsdownConfig, rewriteEslint, rewriteImportsInDirectory, rewriteScripts, wrapLazyPlugins } from "../binding/index.js";
12
+ import { detectWorkspace, hasConfigKey, mergeJsonConfig, mergeTsdownConfig, rewriteEslint, rewriteImportsInDirectory, rewritePrettier, rewriteScripts, wrapLazyPlugins } from "../binding/index.js";
13
+ import { styleText } from "node:util";
11
14
  import * as actualFS from "node:fs";
12
15
  import fs from "node:fs";
13
- import { lstatSync, readdir, readdirSync, readlinkSync, realpathSync as realpathSync$1 } from "fs";
14
- import { styleText } from "node:util";
15
- import { fileURLToPath } from "node:url";
16
16
  import os from "node:os";
17
+ import { lstatSync as lstatSync$1, readdir, readdirSync, readlinkSync, realpathSync as realpathSync$1 } from "fs";
18
+ import { fileURLToPath } from "node:url";
17
19
  import "oxlint";
18
20
  import fsPromises, { lstat, readdir as readdir$1, readlink, realpath } from "node:fs/promises";
19
21
  import { EventEmitter } from "node:events";
20
22
  import Stream from "node:stream";
21
23
  import { StringDecoder } from "node:string_decoder";
22
- //#region src/utils/path.ts
23
- function findPkgRoot() {
24
- let dir = import.meta.dirname;
25
- while (dir !== path.dirname(dir)) {
26
- if (fs.existsSync(path.join(dir, "package.json"))) return dir;
27
- dir = path.dirname(dir);
28
- }
29
- return dir;
30
- }
31
- const pkgRoot = findPkgRoot();
32
- const templatesDir = path.join(pkgRoot, "templates");
33
- const rulesDir = path.join(pkgRoot, "rules");
34
- function displayRelative(to, from = process.cwd()) {
35
- return path.relative(from, to).replaceAll("\\", "/");
36
- }
37
- //#endregion
38
24
  //#region src/migration/migrator/shared.ts
39
25
  var import_semver = /* @__PURE__ */ __toESM(require_semver(), 1);
40
26
  const LINT_STAGED_JSON_CONFIG_FILES = [".lintstagedrc.json", ".lintstagedrc"];
@@ -743,6 +729,184 @@ async function promptEslintMigration(projectPath, interactive, packages) {
743
729
  return true;
744
730
  }
745
731
  //#endregion
732
+ //#region src/migration/migrator/prettier.ts
733
+ function detectPrettierProject(projectPath, packages) {
734
+ const packageJsonPath = path.join(projectPath, "package.json");
735
+ if (!fs.existsSync(packageJsonPath)) return { hasDependency: false };
736
+ const pkg = readJsonFile(packageJsonPath);
737
+ let hasDependency = !!(pkg.devDependencies?.prettier || pkg.dependencies?.prettier);
738
+ const configFile = detectConfigs(projectPath).prettierConfig;
739
+ if (!hasDependency && packages) for (const wp of packages) {
740
+ const pkgJsonPath = path.join(projectPath, wp.path, "package.json");
741
+ if (!fs.existsSync(pkgJsonPath)) continue;
742
+ const wpPkg = readJsonFile(pkgJsonPath);
743
+ if (wpPkg.devDependencies?.prettier || wpPkg.dependencies?.prettier) {
744
+ hasDependency = true;
745
+ break;
746
+ }
747
+ }
748
+ return {
749
+ hasDependency,
750
+ configFile
751
+ };
752
+ }
753
+ /**
754
+ * Run `vp fmt --migrate=prettier` step with graceful error handling.
755
+ * Returns true on success, false on failure.
756
+ */
757
+ async function runPrettierMigrateStep(vpBin, cwd, spinner, failMessage, manualHint) {
758
+ try {
759
+ const result = await runCommandSilently({
760
+ command: vpBin,
761
+ args: ["fmt", "--migrate=prettier"],
762
+ cwd,
763
+ envs: process.env
764
+ });
765
+ if (result.exitCode !== 0) {
766
+ spinner.stop(failMessage);
767
+ const stderr = result.stderr.toString().trim();
768
+ if (stderr) log.warn(`⚠ ${stderr}`);
769
+ log.info(manualHint);
770
+ return false;
771
+ }
772
+ return true;
773
+ } catch {
774
+ spinner.stop(failMessage);
775
+ log.info(manualHint);
776
+ return false;
777
+ }
778
+ }
779
+ async function migratePrettierToOxfmt(projectPath, interactive, prettierConfigFile, packages, options) {
780
+ const vpBin = process.env.VP_CLI_BIN ?? "vp";
781
+ const spinner = options?.silent ? {
782
+ start: () => {},
783
+ stop: () => {},
784
+ pause: () => {},
785
+ resume: () => {},
786
+ cancel: () => {},
787
+ error: () => {},
788
+ clear: () => {},
789
+ message: () => {},
790
+ isCancelled: false
791
+ } : getSpinner(interactive);
792
+ if (prettierConfigFile) {
793
+ let tempPrettierConfig;
794
+ if (prettierConfigFile === "package.json#prettier") {
795
+ const packageJsonPath = path.join(projectPath, "package.json");
796
+ const pkg = readJsonFile(packageJsonPath);
797
+ if (pkg.prettier) {
798
+ tempPrettierConfig = path.join(projectPath, ".prettierrc.json");
799
+ fs.writeFileSync(tempPrettierConfig, JSON.stringify(pkg.prettier, null, 2));
800
+ } else return true;
801
+ }
802
+ try {
803
+ spinner.start("Migrating Prettier config to Oxfmt...");
804
+ if (!await runPrettierMigrateStep(vpBin, projectPath, spinner, "Prettier migration failed", "You can run `vp fmt --migrate=prettier` manually later")) return false;
805
+ spinner.stop("Prettier config migrated to .oxfmtrc.json");
806
+ } finally {
807
+ if (tempPrettierConfig) try {
808
+ fs.unlinkSync(tempPrettierConfig);
809
+ } catch {}
810
+ }
811
+ }
812
+ if (options?.report) options.report.prettierMigrated = true;
813
+ deletePrettierConfigFiles(projectPath, options?.report, options?.silent);
814
+ rewritePrettierPackageJson(path.join(projectPath, "package.json"));
815
+ if (packages) for (const pkg of packages) rewritePrettierPackageJson(path.join(projectPath, pkg.path, "package.json"));
816
+ rewritePrettierLintStagedConfigFiles(projectPath, options?.report);
817
+ const prettierIgnorePath = path.join(projectPath, ".prettierignore");
818
+ if (fs.existsSync(prettierIgnorePath)) warnMigration(`${displayRelative(prettierIgnorePath)} found — Oxfmt supports .prettierignore, but using the \`ignorePatterns\` option is recommended.`, options?.report);
819
+ return true;
820
+ }
821
+ function deletePrettierConfigFiles(basePath, report, silent = false) {
822
+ const configs = detectConfigs(basePath);
823
+ if (configs.prettierConfig && configs.prettierConfig !== "package.json#prettier") {
824
+ const configPath = path.join(basePath, configs.prettierConfig);
825
+ if (fs.existsSync(configPath)) {
826
+ fs.unlinkSync(configPath);
827
+ if (report) report.removedConfigCount++;
828
+ if (!silent) log.success(`✔ Removed ${displayRelative(configPath)}`);
829
+ }
830
+ }
831
+ for (const file of PRETTIER_CONFIG_FILES) {
832
+ if (file === configs.prettierConfig) continue;
833
+ const configPath = path.join(basePath, file);
834
+ if (fs.existsSync(configPath)) {
835
+ fs.unlinkSync(configPath);
836
+ if (report) report.removedConfigCount++;
837
+ if (!silent) log.success(`✔ Removed ${displayRelative(configPath)}`);
838
+ }
839
+ }
840
+ editJsonFile(path.join(basePath, "package.json"), (pkg) => {
841
+ if (pkg.prettier) {
842
+ delete pkg.prettier;
843
+ return pkg;
844
+ }
845
+ });
846
+ }
847
+ function rewritePrettierPackageJson(packageJsonPath) {
848
+ if (!fs.existsSync(packageJsonPath)) return;
849
+ editJsonFile(packageJsonPath, (pkg) => {
850
+ let changed = false;
851
+ if (pkg.devDependencies) {
852
+ for (const dep of Object.keys(pkg.devDependencies)) if (dep === "prettier" || dep.startsWith("prettier-plugin-")) {
853
+ delete pkg.devDependencies[dep];
854
+ changed = true;
855
+ }
856
+ }
857
+ if (pkg.dependencies) {
858
+ for (const dep of Object.keys(pkg.dependencies)) if (dep === "prettier" || dep.startsWith("prettier-plugin-")) {
859
+ delete pkg.dependencies[dep];
860
+ changed = true;
861
+ }
862
+ }
863
+ if (pkg.scripts) {
864
+ const updated = rewritePrettier(JSON.stringify(pkg.scripts));
865
+ if (updated) {
866
+ pkg.scripts = JSON.parse(updated);
867
+ changed = true;
868
+ }
869
+ }
870
+ if (pkg["lint-staged"]) {
871
+ const updated = rewritePrettier(JSON.stringify(pkg["lint-staged"]));
872
+ if (updated) {
873
+ pkg["lint-staged"] = JSON.parse(updated);
874
+ changed = true;
875
+ }
876
+ }
877
+ return changed ? pkg : void 0;
878
+ });
879
+ }
880
+ function rewritePrettierLintStagedConfigFiles(projectPath, report) {
881
+ rewriteToolLintStagedConfigFiles(projectPath, rewritePrettier, "prettier", report);
882
+ }
883
+ function warnPackageLevelPrettier() {
884
+ log.warn("Prettier detected in workspace packages but no root config found. Package-level Prettier must be migrated manually.");
885
+ }
886
+ async function confirmPrettierMigration(interactive) {
887
+ if (interactive) {
888
+ const confirmed = await confirm({
889
+ message: "Migrate Prettier to Oxfmt?\n " + styleText("gray", "Oxfmt is Vite+'s built-in formatter that replaces Prettier with faster performance. Your configuration will be converted automatically."),
890
+ initialValue: true
891
+ });
892
+ if (isCancel(confirmed)) cancelAndExit();
893
+ return confirmed;
894
+ }
895
+ log.info("Prettier configuration detected. Auto-migrating to Oxfmt...");
896
+ return true;
897
+ }
898
+ async function promptPrettierMigration(projectPath, interactive, packages) {
899
+ const prettierProject = detectPrettierProject(projectPath, packages);
900
+ if (!prettierProject.hasDependency) return false;
901
+ if (!prettierProject.configFile) {
902
+ warnPackageLevelPrettier();
903
+ return false;
904
+ }
905
+ if (!await confirmPrettierMigration(interactive)) return false;
906
+ if (!await migratePrettierToOxfmt(projectPath, interactive, prettierProject.configFile, packages)) cancelAndExit("Prettier migration failed.", 1);
907
+ return true;
908
+ }
909
+ //#endregion
746
910
  //#region src/migration/migrator/tsconfig.ts
747
911
  function cleanupDeprecatedTsconfigOptions(projectPath, silent = false, report) {
748
912
  const deprecatedOptions = ["esModuleInterop", "allowSyntheticDefaultImports"];
@@ -767,6 +931,66 @@ function hasTsconfigTypesToRewrite(projectPath) {
767
931
  return findTsconfigFiles(projectPath).some((filePath) => hasTypesToRewriteInTsconfig(filePath));
768
932
  }
769
933
  //#endregion
934
+ //#region src/migration/migrator/framework-shim.ts
935
+ const FRAMEWORK_SHIMS = {
936
+ vue: [
937
+ "declare module '*.vue' {",
938
+ " import type { DefineComponent } from 'vue';",
939
+ " const component: DefineComponent<{}, {}, unknown>;",
940
+ " export default component;",
941
+ "}"
942
+ ].join("\n"),
943
+ astro: "/// <reference types=\"astro/client\" />"
944
+ };
945
+ function detectFramework(projectPath) {
946
+ const packageJsonPath = path.join(projectPath, "package.json");
947
+ if (!fs.existsSync(packageJsonPath)) return [];
948
+ const pkg = readJsonFile(packageJsonPath);
949
+ const allDeps = {
950
+ ...pkg.dependencies,
951
+ ...pkg.devDependencies
952
+ };
953
+ return ["vue", "astro"].filter((framework) => !!allDeps[framework]);
954
+ }
955
+ function getEnvDtsPath(projectPath) {
956
+ const srcEnvDts = path.join(projectPath, "src", "env.d.ts");
957
+ const rootEnvDts = path.join(projectPath, "env.d.ts");
958
+ for (const candidate of [srcEnvDts, rootEnvDts]) if (fs.existsSync(candidate)) return candidate;
959
+ return fs.existsSync(path.join(projectPath, "src")) ? srcEnvDts : rootEnvDts;
960
+ }
961
+ function hasFrameworkShim(projectPath, framework) {
962
+ const dirsToScan = [projectPath, path.join(projectPath, "src")];
963
+ for (const dir of dirsToScan) {
964
+ if (!fs.existsSync(dir)) continue;
965
+ let entries;
966
+ try {
967
+ entries = fs.readdirSync(dir);
968
+ } catch {
969
+ continue;
970
+ }
971
+ for (const entry of entries) {
972
+ if (!entry.endsWith(".d.ts")) continue;
973
+ const content = fs.readFileSync(path.join(dir, entry), "utf-8");
974
+ if (framework === "astro") {
975
+ if (content.includes("astro/client")) return true;
976
+ } else if (content.includes(`'*.${framework}'`) || content.includes(`"*.${framework}"`)) return true;
977
+ }
978
+ }
979
+ return false;
980
+ }
981
+ function addFrameworkShim(projectPath, framework, report) {
982
+ const envDtsPath = getEnvDtsPath(projectPath);
983
+ const shim = FRAMEWORK_SHIMS[framework];
984
+ if (fs.existsSync(envDtsPath)) {
985
+ const existing = fs.readFileSync(envDtsPath, "utf-8");
986
+ fs.writeFileSync(envDtsPath, `${existing.trimEnd()}\n\n${shim}\n`, "utf-8");
987
+ } else {
988
+ fs.mkdirSync(path.dirname(envDtsPath), { recursive: true });
989
+ fs.writeFileSync(envDtsPath, `${shim}\n`, "utf-8");
990
+ }
991
+ if (report) report.frameworkShimAdded = true;
992
+ }
993
+ //#endregion
770
994
  //#region src/migration/migrator/vitest-ecosystem.ts
771
995
  var import_dist = require_dist();
772
996
  const VITEST_ALIGN_EXCLUDED = /* @__PURE__ */ new Set(["@vitest/eslint-plugin", "@vitest/coverage-c8"]);
@@ -1062,7 +1286,6 @@ function collectVitestEcosystemInstallDependencyNames(rootDir, packages) {
1062
1286
  }
1063
1287
  //#endregion
1064
1288
  //#region ../../node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js
1065
- var import_cross_spawn = /* @__PURE__ */ __toESM(require_cross_spawn(), 1);
1066
1289
  const balanced = (a, b, str) => {
1067
1290
  const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
1068
1291
  const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
@@ -1252,7 +1475,7 @@ function expand_(str, max, isTop) {
1252
1475
  }
1253
1476
  //#endregion
1254
1477
  //#region ../../node_modules/.pnpm/minimatch@10.2.4/node_modules/minimatch/dist/esm/assert-valid-pattern.js
1255
- const MAX_PATTERN_LENGTH = 1024 * 64;
1478
+ const MAX_PATTERN_LENGTH = 65536;
1256
1479
  const assertValidPattern = (pattern) => {
1257
1480
  if (typeof pattern !== "string") throw new TypeError("invalid pattern");
1258
1481
  if (pattern.length > MAX_PATTERN_LENGTH) throw new TypeError("pattern is too long");
@@ -3982,12 +4205,15 @@ while (this[FLUSHCHUNK](this[BUFFERSHIFT]()) && this[BUFFER].length);
3982
4205
  return isStream;
3983
4206
  }
3984
4207
  };
4208
+ //#endregion
4209
+ //#region ../../node_modules/.pnpm/path-scurry@2.0.1/node_modules/path-scurry/dist/esm/index.js
4210
+ const realpathSync$2 = realpathSync$1.native;
3985
4211
  const defaultFS = {
3986
- lstatSync,
4212
+ lstatSync: lstatSync$1,
3987
4213
  readdir,
3988
4214
  readdirSync,
3989
4215
  readlinkSync,
3990
- realpathSync: realpathSync$1.native,
4216
+ realpathSync: realpathSync$2,
3991
4217
  promises: {
3992
4218
  lstat,
3993
4219
  readdir: readdir$1,
@@ -4055,7 +4281,7 @@ var ResolveCache = class extends L {
4055
4281
  * @internal
4056
4282
  */
4057
4283
  var ChildrenCache = class extends L {
4058
- constructor(maxSize = 16 * 1024) {
4284
+ constructor(maxSize = 16384) {
4059
4285
  super({
4060
4286
  maxSize,
4061
4287
  sizeCalculation: (a) => a.length + 1
@@ -4388,7 +4614,7 @@ var PathBase = class {
4388
4614
  return this[`is${type}`]();
4389
4615
  }
4390
4616
  getType() {
4391
- return this.isUnknown() ? "Unknown" : this.isDirectory() ? "Directory" : this.isFile() ? "File" : this.isSymbolicLink() ? "SymbolicLink" : this.isFIFO() ? "FIFO" : this.isCharacterDevice() ? "CharacterDevice" : this.isBlockDevice() ? "BlockDevice" : /* c8 ignore start */ this.isSocket() ? "Socket" : "Unknown";
4617
+ return this.isUnknown() ? "Unknown" : this.isDirectory() ? "Directory" : this.isFile() ? "File" : this.isSymbolicLink() ? "SymbolicLink" : this.isFIFO() ? "FIFO" : this.isCharacterDevice() ? "CharacterDevice" : this.isBlockDevice() ? "BlockDevice" : /* c8 ignore start */ this.isSocket() ? "Socket" : "Unknown";
4392
4618
  /* c8 ignore stop */
4393
4619
  }
4394
4620
  /**
@@ -5013,7 +5239,7 @@ var PathScurryBase = class {
5013
5239
  *
5014
5240
  * @internal
5015
5241
  */
5016
- constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS } = {}) {
5242
+ constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16384, fs = defaultFS } = {}) {
5017
5243
  this.#fs = fsFromOption(fs);
5018
5244
  if (cwd instanceof URL || cwd.startsWith("file://")) cwd = fileURLToPath(cwd);
5019
5245
  const cwdPath = pathImpl.resolve(cwd);
@@ -6504,6 +6730,96 @@ const glob = Object.assign(glob_, {
6504
6730
  });
6505
6731
  glob.glob = glob;
6506
6732
  //#endregion
6733
+ //#region src/utils/workspace.ts
6734
+ async function detectWorkspace$1(rootDir) {
6735
+ const bindingResult = await detectWorkspace(rootDir);
6736
+ const result = {
6737
+ rootDir,
6738
+ packageManager: void 0,
6739
+ packageManagerVersion: "latest",
6740
+ isMonorepo: false,
6741
+ monorepoScope: "",
6742
+ workspacePatterns: [],
6743
+ parentDirs: [],
6744
+ packages: []
6745
+ };
6746
+ if (bindingResult.packageManagerName) result.packageManager = bindingResult.packageManagerName;
6747
+ if (bindingResult.packageManagerVersion) result.packageManagerVersion = bindingResult.packageManagerVersion;
6748
+ if (bindingResult.isMonorepo) result.isMonorepo = bindingResult.isMonorepo;
6749
+ if (bindingResult.root) result.rootDir = bindingResult.root;
6750
+ if (result.isMonorepo) {
6751
+ const pnpmWorkspaceFile = path.join(result.rootDir, "pnpm-workspace.yaml");
6752
+ const packageJsonFile = path.join(result.rootDir, "package.json");
6753
+ if (fs.existsSync(pnpmWorkspaceFile)) {
6754
+ const workspaceConfig = readYamlFile(pnpmWorkspaceFile);
6755
+ if (Array.isArray(workspaceConfig.packages)) result.workspacePatterns = workspaceConfig.packages;
6756
+ } else if (fs.existsSync(packageJsonFile)) {
6757
+ const pkg = readJsonFile(packageJsonFile);
6758
+ if (Array.isArray(pkg.workspaces)) result.workspacePatterns = pkg.workspaces;
6759
+ else if (pkg.workspaces && Array.isArray(pkg.workspaces.packages)) result.workspacePatterns = pkg.workspaces.packages;
6760
+ }
6761
+ const dirs = /* @__PURE__ */ new Set();
6762
+ for (const pattern of result.workspacePatterns) {
6763
+ if (!pattern.endsWith("*")) continue;
6764
+ const dir = pattern.replace(/\/\*{1,2}$/, "");
6765
+ if (dir) dirs.add(dir);
6766
+ }
6767
+ result.parentDirs = Array.from(dirs).sort();
6768
+ const pkg = readJsonFile(packageJsonFile);
6769
+ if (pkg.name) result.monorepoScope = getScopeFromPackageName(pkg.name);
6770
+ result.packages = discoverWorkspacePackages(result.workspacePatterns, result.rootDir);
6771
+ }
6772
+ return result;
6773
+ }
6774
+ function isBingoTemplate(pkg) {
6775
+ return !!pkg.dependencies?.bingo;
6776
+ }
6777
+ function discoverWorkspacePackages(workspacePatterns, rootDir) {
6778
+ const packages = [];
6779
+ if (workspacePatterns.length === 0) return packages;
6780
+ const packageJsonRelativePaths = globSync(workspacePatterns.map((pattern) => `${pattern}/package.json`), {
6781
+ absolute: false,
6782
+ cwd: rootDir,
6783
+ ignore: ["**/node_modules/**"]
6784
+ });
6785
+ for (const packageJsonRelativePath of packageJsonRelativePaths) {
6786
+ const packageJsonPath = path.join(rootDir, packageJsonRelativePath);
6787
+ const pkg = readJsonFile(packageJsonPath);
6788
+ if (!pkg.name) continue;
6789
+ packages.push({
6790
+ name: pkg.name,
6791
+ path: path.dirname(packageJsonRelativePath).split(path.sep).join("/"),
6792
+ description: pkg.description,
6793
+ version: pkg.version
6794
+ });
6795
+ }
6796
+ return packages;
6797
+ }
6798
+ function updatePackageJsonWithDeps(rootDir, projectDir, dependencies, dependencyType) {
6799
+ const packageJsonPath = path.join(rootDir, projectDir, "package.json");
6800
+ editJsonFile(packageJsonPath, (pkg) => {
6801
+ if (!pkg[dependencyType]) pkg[dependencyType] = {};
6802
+ for (const dep of dependencies) pkg[dependencyType][dep] = "workspace:*";
6803
+ return pkg;
6804
+ });
6805
+ }
6806
+ function updateWorkspaceConfig(projectPath, workspaceInfo) {
6807
+ for (const pattern of workspaceInfo.workspacePatterns) if (minimatch(projectPath, pattern)) return;
6808
+ const parentDir = path.dirname(projectPath);
6809
+ const pattern = parentDir === "." ? projectPath : `${parentDir}/*`;
6810
+ if (workspaceInfo.packageManager === PackageManager.pnpm) editYamlFile(path.join(workspaceInfo.rootDir, "pnpm-workspace.yaml"), (doc) => {
6811
+ let packages = doc.getIn(["packages"]);
6812
+ if (!packages) packages = new import_dist.YAMLSeq();
6813
+ packages.add(new import_dist.Scalar(pattern));
6814
+ doc.setIn(["packages"], packages);
6815
+ });
6816
+ else editJsonFile(path.join(workspaceInfo.rootDir, "package.json"), (pkg) => {
6817
+ if (pkg.workspaces && !Array.isArray(pkg.workspaces)) pkg.workspaces.packages = [...pkg.workspaces.packages || [], pattern];
6818
+ else pkg.workspaces = [...pkg.workspaces || [], pattern];
6819
+ return pkg;
6820
+ });
6821
+ }
6822
+ //#endregion
6507
6823
  //#region src/migration/migrator/catalog.ts
6508
6824
  const BROWSER_PROVIDER_POSTINSTALL_PACKAGES = ["edgedriver", "geckodriver"];
6509
6825
  const PUBLIC_PEER_DEPENDENCY_FALLBACKS = {
@@ -6684,7 +7000,8 @@ function rewritePnpmWorkspaceYaml(projectPath, pnpmMajorVersion, shouldAllowBrow
6684
7000
  * so all overrides must live in pnpm-workspace.yaml.
6685
7001
  */
6686
7002
  function migratePnpmOverridesToWorkspaceYaml(projectPath, overrides) {
6687
- editYamlFile(path.join(projectPath, "pnpm-workspace.yaml"), (doc) => {
7003
+ const pnpmWorkspaceYamlPath = path.join(projectPath, "pnpm-workspace.yaml");
7004
+ editYamlFile(pnpmWorkspaceYamlPath, (doc) => {
6688
7005
  for (const [key, value] of Object.entries(overrides)) doc.setIn(["overrides", scalarString(key)], scalarString(value));
6689
7006
  });
6690
7007
  }
@@ -8059,6 +8376,24 @@ function isProtocolPinnedSpec(spec) {
8059
8376
  }
8060
8377
  //#endregion
8061
8378
  //#region src/migration/migrator/vite-config.ts
8379
+ const SVELTE_RUNE_GLOBALS = {
8380
+ $state: "readonly",
8381
+ $derived: "readonly",
8382
+ $effect: "readonly",
8383
+ $props: "readonly",
8384
+ $bindable: "readonly",
8385
+ $inspect: "readonly",
8386
+ $host: "readonly"
8387
+ };
8388
+ function ensureSvelteRuneGlobals(config) {
8389
+ for (const override of config.overrides ?? []) {
8390
+ if (!override.files.some((file) => !file.startsWith("!") && braceExpand(file).some((pattern) => pattern.includes(".svelte")))) continue;
8391
+ override.globals = {
8392
+ ...SVELTE_RUNE_GLOBALS,
8393
+ ...override.globals
8394
+ };
8395
+ }
8396
+ }
8062
8397
  function removeLintStagedFromPackageJson(packageJsonPath) {
8063
8398
  editJsonFile(packageJsonPath, (pkg) => {
8064
8399
  if (pkg["lint-staged"]) {
@@ -8125,7 +8460,8 @@ function mergeTsdownConfigFile(projectPath, silent = false, report) {
8125
8460
  mergeAndRemoveJsonConfig(projectPath, viteConfig, configs.tsdownConfig, "pack", silent, report);
8126
8461
  return;
8127
8462
  }
8128
- const result = mergeTsdownConfig(fullViteConfigPath, `./${configs.tsdownConfig}`);
8463
+ const tsdownRelativePath = `./${configs.tsdownConfig}`;
8464
+ const result = mergeTsdownConfig(fullViteConfigPath, tsdownRelativePath);
8129
8465
  if (result.updated) {
8130
8466
  fs.writeFileSync(fullViteConfigPath, result.content);
8131
8467
  if (report) report.tsdownImportCount++;
@@ -8149,7 +8485,9 @@ function mergeViteConfigFiles(projectPath, silent = false, report, packages, wor
8149
8485
  if (oxlintJson.options.typeCheck === void 0) oxlintJson.options.typeCheck = true;
8150
8486
  } else warnMigration(BASEURL_TSCONFIG_WARNING, report);
8151
8487
  sanitizeMigratedOxlintConfig(oxlintJson, collectInstalledPackageNames(workspaceRoot ?? projectPath, packages), report);
8152
- writeJsonFile(fullOxlintPath, ensureVitePlusImportRuleDefaults(oxlintJson));
8488
+ ensureSvelteRuneGlobals(oxlintJson);
8489
+ const normalizedOxlintConfig = ensureVitePlusImportRuleDefaults(oxlintJson);
8490
+ writeJsonFile(fullOxlintPath, normalizedOxlintConfig);
8153
8491
  mergeAndRemoveJsonConfig(projectPath, viteConfig, configs.oxlintConfig, "lint", silent, report);
8154
8492
  }
8155
8493
  if (configs.oxfmtConfig) mergeAndRemoveJsonConfig(projectPath, viteConfig, configs.oxfmtConfig, "fmt", silent, report);
@@ -8296,54 +8634,40 @@ function rewriteAllImports(projectPath, silent = false, report, preserveNuxtVite
8296
8634
  }
8297
8635
  //#endregion
8298
8636
  //#region src/migration/migrator/git-hooks.ts
8299
- /**
8300
- * Check if the project has an unsupported husky version (<9.0.0).
8301
- * Uses `semver.coerce` to handle ranges like `^8.0.0` → `8.0.0`.
8302
- * When the specifier is a catalog reference (e.g. `"catalog:"`), resolves
8303
- * it from the active package manager's catalog first — a `catalog:` spec is
8304
- * only meaningful to the manager that owns the workspace, so we never read a
8305
- * leftover/foreign catalog file. When it is still not coercible (e.g.
8306
- * `"latest"`), falls back to the installed version in node_modules via
8307
- * `detectPackageMetadata`.
8308
- * Returns a reason string if hooks migration should be skipped, or null
8309
- * if husky is absent or compatible.
8310
- */
8311
- function checkUnsupportedHuskyVersion(projectPath, deps, prodDeps, packageManager) {
8312
- const huskyVersion = deps?.husky ?? prodDeps?.husky;
8313
- if (!huskyVersion) return null;
8314
- let coerced = import_semver.default.coerce(huskyVersion);
8315
- if (coerced == null && packageManager != null && huskyVersion.startsWith("catalog:")) {
8316
- const resolved = createCatalogDependencyResolver(projectPath, packageManager)?.(huskyVersion, "husky");
8317
- if (resolved) coerced = import_semver.default.coerce(resolved);
8318
- }
8319
- if (coerced == null) {
8320
- const installed = detectPackageMetadata(projectPath, "husky");
8321
- if (installed) coerced = import_semver.default.coerce(installed.version);
8322
- if (coerced == null) return `Could not determine husky version from "${huskyVersion}" — please specify a semver-compatible version (e.g., "^9.0.0") and re-run migration.`;
8323
- }
8324
- if (import_semver.default.satisfies(coerced, "<9.0.0")) return "Detected husky <9.0.0 — please upgrade to husky v9+ first, then re-run migration.";
8325
- return null;
8326
- }
8637
+ var import_cross_spawn = /* @__PURE__ */ __toESM(require_cross_spawn(), 1);
8327
8638
  const OTHER_HOOK_TOOLS = [
8328
8639
  "simple-git-hooks",
8329
8640
  "lefthook",
8330
8641
  "yorkie"
8331
8642
  ];
8332
- const REPLACED_HOOK_PACKAGES = ["husky", "lint-staged"];
8333
- function removeReplacedHookPackages(packageJsonPath) {
8643
+ const SUPPORTED_GIT_HOOK_NAME_SET = new Set(SUPPORTED_GIT_HOOK_NAMES);
8644
+ function removeReplacedStagedPackage(packageJsonPath) {
8334
8645
  editJsonFile(packageJsonPath, (pkg) => {
8335
- for (const name of REPLACED_HOOK_PACKAGES) {
8336
- if (pkg.devDependencies?.[name]) delete pkg.devDependencies[name];
8337
- if (pkg.dependencies?.[name]) delete pkg.dependencies[name];
8338
- }
8646
+ if (pkg.devDependencies?.["lint-staged"]) delete pkg.devDependencies["lint-staged"];
8647
+ if (pkg.dependencies?.["lint-staged"]) delete pkg.dependencies["lint-staged"];
8339
8648
  return pkg;
8340
8649
  });
8341
8650
  }
8342
8651
  function detectLegacyGitHooksMigrationCandidate(projectPath) {
8343
8652
  const packageJsonPath = path.join(projectPath, "package.json");
8344
8653
  if (!fs.existsSync(packageJsonPath)) return false;
8345
- const pkg = readJsonFile(packageJsonPath);
8346
- return getOldHooksDir(projectPath) !== void 0 || pkg["lint-staged"] !== void 0;
8654
+ return readJsonFile(packageJsonPath)["lint-staged"] !== void 0;
8655
+ }
8656
+ function hasHuskySetup(projectPath, pkg) {
8657
+ return pkg.devDependencies?.husky !== void 0 || pkg.dependencies?.husky !== void 0 || pkg.optionalDependencies?.husky !== void 0 || pkg.peerDependencies?.husky !== void 0 || pkg.husky !== void 0 || (pkg.scripts?.prepare ? /\bhusky\b/.test(pkg.scripts.prepare) : false) || fs.existsSync(path.join(projectPath, ".husky"));
8658
+ }
8659
+ function hasExistingViteHooksPolicy(projectPath) {
8660
+ const hooksDir = path.join(projectPath, ".vite-hooks");
8661
+ if (!fs.lstatSync(hooksDir, { throwIfNoEntry: false })?.isDirectory()) return false;
8662
+ return fs.readdirSync(hooksDir, { withFileTypes: true }).some((entry) => entry.isFile() && SUPPORTED_GIT_HOOK_NAME_SET.has(entry.name));
8663
+ }
8664
+ function findNonRegularViteHookPath(projectPath) {
8665
+ for (const hookName of SUPPORTED_GIT_HOOK_NAMES) {
8666
+ const hookPath = path.join(projectPath, ".vite-hooks", hookName);
8667
+ const stats = fs.lstatSync(hookPath, { throwIfNoEntry: false });
8668
+ if (stats && !stats.isFile()) return path.join(".vite-hooks", hookName);
8669
+ }
8670
+ return null;
8347
8671
  }
8348
8672
  /**
8349
8673
  * Walk up from `startPath` looking for `.git` (directory or file — submodules
@@ -8358,36 +8682,45 @@ function findGitRoot(startPath) {
8358
8682
  dir = parent;
8359
8683
  }
8360
8684
  }
8361
- /**
8362
- * Normalize "husky install [dir]" → "husky [dir]" so downstream regex
8363
- * and ast-grep rules can match a single pattern.
8364
- */
8365
- function collapseHuskyInstall(script) {
8366
- return script.replace("husky install ", "husky ").replace("husky install", "husky");
8367
- }
8368
- /**
8369
- * High-level helper: detect old hooks dir, set up git hooks, and rewrite
8370
- * the prepare script. Returns true if hooks were successfully installed.
8371
- */
8372
- function installGitHooks(projectPath, silent = false, report, packageManager) {
8373
- if (setupGitHooks(projectPath, getOldHooksDir(projectPath), silent, report, packageManager)) {
8374
- rewritePrepareScript(projectPath);
8375
- return true;
8685
+ function findWorkspacePackageHookPolicy(workspaceRoot, packages) {
8686
+ for (const pkg of packages) {
8687
+ const packagePath = path.join(workspaceRoot, pkg.path);
8688
+ if (hasExistingViteHooksPolicy(packagePath)) return `Detected project-owned Vite+ hooks in workspace package "${pkg.path}" — leaving the existing hook setup unchanged.`;
8689
+ const packageJsonPath = path.join(packagePath, "package.json");
8690
+ const pkgContent = fs.existsSync(packageJsonPath) ? readJsonFile(packageJsonPath) : {};
8691
+ if (hasHuskySetup(packagePath, pkgContent)) return `Detected Husky in workspace package "${pkg.path}" — leaving its hooks, configuration, and dependencies unchanged.`;
8692
+ const deps = pkgContent.devDependencies;
8693
+ const prodDeps = pkgContent.dependencies;
8694
+ for (const tool of OTHER_HOOK_TOOLS) if (deps?.[tool] || prodDeps?.[tool] || pkgContent[tool]) return `Detected ${tool} in workspace package "${pkg.path}" — leaving the existing hook setup unchanged.`;
8695
+ const gitRoot = findGitRoot(packagePath);
8696
+ if (gitRoot && path.resolve(packagePath) === path.resolve(gitRoot)) {
8697
+ const configuredHooksPath = getConfiguredHooksPath(packagePath);
8698
+ const normalizedHooksPath = normalizeGitHooksPath(configuredHooksPath);
8699
+ if (configuredHooksPath && normalizedHooksPath !== ".vite-hooks/_") return `core.hooksPath is already set to "${configuredHooksPath}" in workspace package "${pkg.path}" — leaving the existing hook setup unchanged.`;
8700
+ }
8376
8701
  }
8377
- return false;
8702
+ return null;
8703
+ }
8704
+ function getConfiguredHooksPath(projectPath) {
8705
+ const result = import_cross_spawn.default.sync("git", [
8706
+ "config",
8707
+ "--get",
8708
+ "core.hooksPath"
8709
+ ], {
8710
+ cwd: projectPath,
8711
+ stdio: "pipe"
8712
+ });
8713
+ return result.status === 0 ? result.stdout?.toString().trim() ?? "" : "";
8714
+ }
8715
+ function normalizeGitHooksPath(hooksPath) {
8716
+ return path.posix.normalize(hooksPath.replaceAll("\\", "/")).replace(/\/$/, "");
8378
8717
  }
8379
8718
  /**
8380
- * Read-only probe: extract the old husky hooks directory from `scripts.prepare`
8381
- * without modifying package.json. Returns undefined when no husky reference is found.
8719
+ * High-level helper that sets up Vite+ hooks when no other hook tool owns the
8720
+ * project. Husky setups are deliberately preserved for a dedicated migration.
8382
8721
  */
8383
- function getOldHooksDir(rootDir) {
8384
- const packageJsonPath = path.join(rootDir, "package.json");
8385
- if (!fs.existsSync(packageJsonPath)) return;
8386
- const pkg = readJsonFile(packageJsonPath);
8387
- if (!pkg.scripts?.prepare) return;
8388
- const match = collapseHuskyInstall(pkg.scripts.prepare).match(/\bhusky(?:\s+([\w./-]+))?/);
8389
- if (!match) return;
8390
- return match[1] ?? ".husky";
8722
+ function installGitHooks(projectPath, silent = false, report, packageManager, packages = []) {
8723
+ return setupGitHooks(projectPath, silent, report, packageManager, packages);
8391
8724
  }
8392
8725
  /**
8393
8726
  * Pre-flight check: verify that git hooks can be set up for this project.
@@ -8397,10 +8730,9 @@ function getOldHooksDir(rootDir) {
8397
8730
  * These checks are deterministic and read-only — they do not modify
8398
8731
  * the project in any way, making them safe to call before migration.
8399
8732
  *
8400
- * `packageManager` is the project's detected manager; it scopes `catalog:`
8401
- * resolution to that manager's catalog so a foreign catalog file is ignored.
8733
+ * The package manager argument remains for API compatibility with callers.
8402
8734
  */
8403
- function preflightGitHooksSetup(projectPath, packageManager) {
8735
+ function preflightGitHooksSetup(projectPath, _packageManager, packages = []) {
8404
8736
  const gitRoot = findGitRoot(projectPath);
8405
8737
  if (gitRoot && path.resolve(projectPath) !== path.resolve(gitRoot)) return "Subdirectory project detected — skipping git hooks setup. Configure hooks at the repository root.";
8406
8738
  const packageJsonPath = path.join(projectPath, "package.json");
@@ -8408,19 +8740,41 @@ function preflightGitHooksSetup(projectPath, packageManager) {
8408
8740
  const pkgContent = readJsonFile(packageJsonPath);
8409
8741
  const deps = pkgContent.devDependencies;
8410
8742
  const prodDeps = pkgContent.dependencies;
8743
+ const configuredHooksPath = gitRoot ? getConfiguredHooksPath(projectPath) : "";
8744
+ const normalizedHooksPath = normalizeGitHooksPath(configuredHooksPath);
8745
+ if (hasHuskySetup(projectPath, pkgContent) || normalizedHooksPath === ".husky" || normalizedHooksPath.startsWith(".husky/")) return "Detected Husky — leaving its hooks, configuration, and dependencies unchanged. Migrate Husky manually before enabling Vite+ hooks.";
8411
8746
  for (const tool of OTHER_HOOK_TOOLS) if (deps?.[tool] || prodDeps?.[tool] || pkgContent[tool]) return `Detected ${tool} — skipping git hooks setup. Please configure git hooks manually, see https://viteplus.dev/guide/migrate#git-hook-tools`;
8412
- const huskyReason = checkUnsupportedHuskyVersion(projectPath, deps, prodDeps, packageManager);
8413
- if (huskyReason) return huskyReason;
8747
+ const workspacePackageReason = findWorkspacePackageHookPolicy(projectPath, packages);
8748
+ if (workspacePackageReason) return workspacePackageReason;
8749
+ const disabledHooksEnvironment = [
8750
+ "HUSKY",
8751
+ "VP_GIT_HOOKS",
8752
+ "VITE_GIT_HOOKS"
8753
+ ].find((name) => process.env[name] === "0");
8754
+ if (disabledHooksEnvironment) return `Git hooks are disabled through ${disabledHooksEnvironment}=0 — skipping git hooks setup.`;
8755
+ if (configuredHooksPath && normalizedHooksPath !== ".vite-hooks/_") return `core.hooksPath is already set to "${configuredHooksPath}" — leaving the existing hook setup unchanged.`;
8756
+ const unsafeInstallPath = findUnsafeHookInstallPath(projectPath, ".vite-hooks");
8757
+ if (unsafeInstallPath) return `Git hook dispatcher path "${unsafeInstallPath.relativePath}" is unsafe — leaving the existing hook setup unchanged.`;
8758
+ const nonRegularHookPath = findNonRegularViteHookPath(projectPath);
8759
+ if (nonRegularHookPath) return `Git hook path "${nonRegularHookPath}" is not a regular file — leaving the existing hook setup unchanged.`;
8414
8760
  if (hasUnsupportedLintStagedConfig(projectPath)) return "Unsupported lint-staged config format — skipping git hooks setup. Please configure git hooks manually.";
8415
8761
  return null;
8416
8762
  }
8417
8763
  /**
8764
+ * Decide whether config rewriting must leave lint-staged configuration in
8765
+ * place. Call this after scaffolding but before rewriting the project so an
8766
+ * existing hook owner never observes a partially migrated configuration.
8767
+ */
8768
+ function shouldSkipStagedMigrationForHooks(projectPath, shouldSetupHooks, packageManager, packages = []) {
8769
+ return !shouldSetupHooks || hasExistingViteHooksPolicy(projectPath) || preflightGitHooksSetup(projectPath, packageManager, packages) !== null;
8770
+ }
8771
+ /**
8418
8772
  * Set up git hooks with husky + lint-staged via vp commands.
8419
8773
  * Skips if another hook tool is detected (warns user).
8420
8774
  * Returns true if hooks were successfully set up, false if skipped.
8421
8775
  */
8422
- function setupGitHooks(projectPath, oldHooksDir, silent = false, report, packageManager) {
8423
- const reason = preflightGitHooksSetup(projectPath, packageManager);
8776
+ function setupGitHooks(projectPath, silent = false, report, packageManager, packages = []) {
8777
+ const reason = preflightGitHooksSetup(projectPath, packageManager, packages);
8424
8778
  if (reason) {
8425
8779
  warnMigration(reason, report);
8426
8780
  return false;
@@ -8428,73 +8782,29 @@ function setupGitHooks(projectPath, oldHooksDir, silent = false, report, package
8428
8782
  const packageJsonPath = path.join(projectPath, "package.json");
8429
8783
  if (!fs.existsSync(packageJsonPath)) return false;
8430
8784
  const gitRoot = findGitRoot(projectPath);
8431
- const isCustomDir = oldHooksDir != null && oldHooksDir !== ".husky";
8432
- const hooksDir = isCustomDir ? oldHooksDir : ".vite-hooks";
8785
+ const hooksDir = ".vite-hooks";
8786
+ const hasExistingHookPolicy = hasExistingViteHooksPolicy(projectPath);
8433
8787
  editJsonFile(packageJsonPath, (pkg) => {
8434
8788
  if (!pkg.scripts) pkg.scripts = {};
8435
8789
  if (!pkg.scripts.prepare) pkg.scripts.prepare = "vp config";
8436
- else if (!pkg.scripts.prepare.includes("vp config") && !/\bhusky\b/.test(pkg.scripts.prepare)) pkg.scripts.prepare = `vp config && ${pkg.scripts.prepare}`;
8790
+ else if (!pkg.scripts.prepare.includes("vp config")) pkg.scripts.prepare = `vp config && ${pkg.scripts.prepare}`;
8437
8791
  return pkg;
8438
8792
  });
8439
8793
  let stagedMerged = hasStagedConfigInViteConfig(projectPath);
8440
8794
  const hasStandaloneConfig = hasStandaloneLintStagedConfig(projectPath);
8441
- if (!stagedMerged && !hasStandaloneConfig) {
8795
+ if (!hasExistingHookPolicy && !stagedMerged && !hasStandaloneConfig) {
8442
8796
  const stagedConfig = readJsonFile(packageJsonPath)?.["lint-staged"] ?? DEFAULT_STAGED_CONFIG;
8443
8797
  const updated = rewriteScripts(JSON.stringify(stagedConfig), readRulesYaml());
8444
8798
  stagedMerged = mergeStagedConfigToViteConfig(projectPath, updated ? JSON.parse(updated) : stagedConfig, silent, report);
8445
8799
  }
8446
- if (stagedMerged) removeLintStagedFromPackageJson(packageJsonPath);
8447
- if (oldHooksDir && !isCustomDir) {
8448
- const oldDir = path.join(projectPath, oldHooksDir);
8449
- if (fs.existsSync(oldDir)) {
8450
- const targetDir = path.join(projectPath, hooksDir);
8451
- fs.mkdirSync(targetDir, { recursive: true });
8452
- for (const entry of fs.readdirSync(oldDir, { withFileTypes: true })) {
8453
- if (entry.isDirectory() || entry.name.startsWith(".")) continue;
8454
- const src = path.join(oldDir, entry.name);
8455
- const dest = path.join(targetDir, entry.name);
8456
- fs.copyFileSync(src, dest);
8457
- fs.chmodSync(dest, 493);
8458
- }
8459
- fs.rmSync(oldDir, {
8460
- recursive: true,
8461
- force: true
8462
- });
8463
- }
8464
- }
8465
- if (stagedMerged) createPreCommitHook(projectPath, hooksDir);
8800
+ if (!hasExistingHookPolicy && stagedMerged) removeLintStagedFromPackageJson(packageJsonPath);
8801
+ if (!hasExistingHookPolicy && stagedMerged) createPreCommitHook(projectPath, hooksDir);
8466
8802
  if (!gitRoot) {
8467
- removeReplacedHookPackages(packageJsonPath);
8803
+ if (!hasExistingHookPolicy && stagedMerged) removeReplacedStagedPackage(packageJsonPath);
8468
8804
  return true;
8469
8805
  }
8470
- if (oldHooksDir) {
8471
- const checkResult = import_cross_spawn.default.sync("git", [
8472
- "config",
8473
- "--local",
8474
- "core.hooksPath"
8475
- ], {
8476
- cwd: projectPath,
8477
- stdio: "pipe"
8478
- });
8479
- const existingPath = checkResult.status === 0 ? checkResult.stdout?.toString().trim() : "";
8480
- if (existingPath === `${oldHooksDir}/_` || existingPath === oldHooksDir) import_cross_spawn.default.sync("git", [
8481
- "config",
8482
- "--local",
8483
- "--unset",
8484
- "core.hooksPath"
8485
- ], {
8486
- cwd: projectPath,
8487
- stdio: "pipe"
8488
- });
8489
- }
8490
8806
  const vpBin = process.env.VP_CLI_BIN ?? "vp";
8491
- const configArgs = isCustomDir ? [
8492
- "config",
8493
- "--no-agent",
8494
- "--hooks-dir",
8495
- hooksDir
8496
- ] : ["config", "--no-agent"];
8497
- const configResult = import_cross_spawn.default.sync(vpBin, configArgs, {
8807
+ const configResult = import_cross_spawn.default.sync(vpBin, ["config", "--no-agent"], {
8498
8808
  cwd: projectPath,
8499
8809
  stdio: "pipe"
8500
8810
  });
@@ -8504,7 +8814,7 @@ function setupGitHooks(projectPath, oldHooksDir, silent = false, report, package
8504
8814
  warnMigration(`Git hooks not configured — ${stdout}`, report);
8505
8815
  return false;
8506
8816
  }
8507
- removeReplacedHookPackages(packageJsonPath);
8817
+ if (!hasExistingHookPolicy && stagedMerged) removeReplacedStagedPackage(packageJsonPath);
8508
8818
  if (report) report.gitHooksConfigured = true;
8509
8819
  if (!silent) log.success("✔ Git hooks configured");
8510
8820
  return true;
@@ -8529,85 +8839,14 @@ function hasUnsupportedLintStagedConfig(projectPath) {
8529
8839
  if (fs.existsSync(lintstagedrcPath) && !isJsonFile(lintstagedrcPath)) return true;
8530
8840
  return false;
8531
8841
  }
8532
- /**
8533
- * Create pre-commit hook file in the hooks directory.
8534
- */
8535
- const STALE_LINT_STAGED_PATTERNS = [/^((?:[A-Z_][A-Z0-9_]*(?:=\S*)?\s+)*)(pnpm|pnpm exec|npx|yarn|yarn run|npm exec|npm run|bunx|bun run|bun x)\s+lint-staged\b/, /^((?:[A-Z_][A-Z0-9_]*(?:=\S*)?\s+)*)lint-staged\b/];
8536
8842
  const DEFAULT_STAGED_CONFIG = { "*": "vp check --fix" };
8537
- /**
8538
- * Ensure the pre-commit hook exists with `vp staged`, and that
8539
- * vite.config.ts contains a `staged` block (using the default config
8540
- * if none is present). Called by `vp config` after hook installation.
8541
- */
8542
- function ensurePreCommitHook(projectPath, dir = ".vite-hooks") {
8543
- if (!hasStagedConfigInViteConfig(projectPath)) mergeStagedConfigToViteConfig(projectPath, DEFAULT_STAGED_CONFIG, true);
8544
- createPreCommitHook(projectPath, dir);
8545
- }
8546
8843
  function createPreCommitHook(projectPath, dir = ".vite-hooks") {
8547
8844
  const huskyDir = path.join(projectPath, dir);
8548
8845
  fs.mkdirSync(huskyDir, { recursive: true });
8549
8846
  const hookPath = path.join(huskyDir, "pre-commit");
8550
- if (fs.existsSync(hookPath)) {
8551
- const existing = fs.readFileSync(hookPath, "utf8");
8552
- if (existing.includes("vp staged")) return;
8553
- const lines = existing.split("\n");
8554
- let replaced = false;
8555
- const result = [];
8556
- for (const line of lines) {
8557
- const trimmed = line.trim();
8558
- if (!replaced) {
8559
- let matched = false;
8560
- for (const pattern of STALE_LINT_STAGED_PATTERNS) {
8561
- const match = pattern.exec(trimmed);
8562
- if (match) {
8563
- const parts = [
8564
- match[1]?.trim() ?? "",
8565
- "vp staged",
8566
- trimmed.slice(match[0].length).trim()
8567
- ].filter(Boolean);
8568
- result.push(parts.join(" "));
8569
- replaced = true;
8570
- matched = true;
8571
- break;
8572
- }
8573
- }
8574
- if (matched) continue;
8575
- }
8576
- result.push(line);
8577
- }
8578
- if (!replaced) fs.writeFileSync(hookPath, `${result.join("\n").trimEnd()}\nvp staged\n`);
8579
- else fs.writeFileSync(hookPath, result.join("\n"));
8580
- } else {
8581
- fs.writeFileSync(hookPath, "vp staged\n");
8582
- fs.chmodSync(hookPath, 493);
8583
- }
8584
- }
8585
- /**
8586
- * Rewrite only `scripts.prepare` in the root package.json using vite-prepare.yml rules.
8587
- * Collapses "husky install" → "husky" before applying ast-grep so that the
8588
- * replace-husky rule produces "vp config" with any directory argument preserved.
8589
- * Returns the old husky hooks dir (if any) for migration to .vite-hooks.
8590
- * Called only when hooks are being set up (not with --no-hooks).
8591
- */
8592
- function rewritePrepareScript(rootDir) {
8593
- const packageJsonPath = path.join(rootDir, "package.json");
8594
- if (!fs.existsSync(packageJsonPath)) return;
8595
- let oldDir;
8596
- editJsonFile(packageJsonPath, (pkg) => {
8597
- if (!pkg.scripts?.prepare) return pkg;
8598
- const prepare = collapseHuskyInstall(pkg.scripts.prepare);
8599
- const updated = rewriteScripts(JSON.stringify({ prepare }), readPrepareRulesYaml());
8600
- if (updated) {
8601
- let newPrepare = JSON.parse(updated).prepare;
8602
- newPrepare = newPrepare.replace(/\bvp config(?:\s+(?!-)([\w./-]+))?/, (_match, dir) => {
8603
- oldDir = dir ?? ".husky";
8604
- return dir ? `vp config --hooks-dir ${dir}` : "vp config";
8605
- });
8606
- pkg.scripts.prepare = newPrepare;
8607
- } else if (prepare !== pkg.scripts.prepare) pkg.scripts.prepare = prepare;
8608
- return pkg;
8609
- });
8610
- return oldDir;
8847
+ if (fs.existsSync(hookPath)) return;
8848
+ fs.writeFileSync(hookPath, "vp staged\n");
8849
+ fs.chmodSync(hookPath, 493);
8611
8850
  }
8612
8851
  //#endregion
8613
8852
  //#region src/migration/migrator/setup.ts
@@ -8750,10 +8989,9 @@ function migrateNodeVersionManagerFile(projectPath, detection, report) {
8750
8989
  //#endregion
8751
8990
  //#region src/migration/migrator/core-finalization.ts
8752
8991
  const RULES_YAML_PATH = path.join(rulesDir, "vite-tools.yml");
8753
- const PREPARE_RULES_YAML_PATH = path.join(rulesDir, "vite-prepare.yml");
8992
+ path.join(rulesDir, "vite-prepare.yml");
8754
8993
  let cachedRulesYaml;
8755
8994
  let cachedRulesYamlNoLintStaged;
8756
- let cachedPrepareRulesYaml;
8757
8995
  function readRulesYaml() {
8758
8996
  cachedRulesYaml ??= fs.readFileSync(RULES_YAML_PATH, "utf8");
8759
8997
  return cachedRulesYaml;
@@ -8764,10 +9002,6 @@ function getScriptRulesYaml(skipStagedMigration) {
8764
9002
  cachedRulesYamlNoLintStaged ??= yaml.split("\n\n\n").filter((block) => !block.includes("id: replace-lint-staged")).join("\n\n\n");
8765
9003
  return cachedRulesYamlNoLintStaged;
8766
9004
  }
8767
- function readPrepareRulesYaml() {
8768
- cachedPrepareRulesYaml ??= fs.readFileSync(PREPARE_RULES_YAML_PATH, "utf8");
8769
- return cachedPrepareRulesYaml;
8770
- }
8771
9005
  function getCoreMigrationProjectPaths(workspaceInfo) {
8772
9006
  return [workspaceInfo.rootDir, ...(workspaceInfo.packages ?? []).map((pkg) => path.join(workspaceInfo.rootDir, pkg.path))];
8773
9007
  }
@@ -8995,300 +9229,186 @@ function rewriteMonorepoProject(projectPath, packageManager, skipStagedMigration
8995
9229
  if (!deferLazyPluginWrapping) wrapLazyPluginsInViteConfig(projectPath, silent, report);
8996
9230
  }
8997
9231
  //#endregion
8998
- //#region src/utils/agent.ts
8999
- const AGENTS = [
9000
- {
9001
- id: "agents",
9002
- label: "AGENTS.md",
9003
- targetPath: "AGENTS.md",
9004
- hint: "Codex, Amp, OpenCode, and similar agents",
9005
- aliases: [
9006
- "agents.md",
9007
- "chatgpt",
9008
- "chatgpt-codex",
9009
- "codex",
9010
- "amp",
9011
- "kilo",
9012
- "kilo-code",
9013
- "kiro",
9014
- "kiro-cli",
9015
- "opencode",
9016
- "other"
9017
- ]
9018
- },
9019
- {
9020
- id: "claude",
9021
- label: "CLAUDE.md",
9022
- targetPath: "CLAUDE.md",
9023
- hint: "Claude Code",
9024
- aliases: ["claude.md", "claude-code"]
9025
- },
9026
- {
9027
- id: "gemini",
9028
- label: "GEMINI.md",
9029
- targetPath: "GEMINI.md",
9030
- hint: "Gemini CLI",
9031
- aliases: ["gemini.md", "gemini-cli"]
9032
- },
9033
- {
9034
- id: "copilot",
9035
- label: ".github/copilot-instructions.md",
9036
- targetPath: ".github/copilot-instructions.md",
9037
- hint: "GitHub Copilot",
9038
- aliases: ["github-copilot", "copilot-instructions.md"]
9039
- },
9040
- {
9041
- id: "cursor",
9042
- label: ".cursor/rules/viteplus.mdc",
9043
- targetPath: ".cursor/rules/viteplus.mdc",
9044
- hint: "Cursor",
9045
- aliases: ["viteplus.mdc"]
9232
+ //#region src/utils/editor.ts
9233
+ const VSCODE_SETTINGS = {
9234
+ "editor.defaultFormatter": "oxc.oxc-vscode",
9235
+ "[javascript]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
9236
+ "[javascriptreact]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
9237
+ "[typescript]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
9238
+ "[typescriptreact]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
9239
+ "oxc.fmt.configPath": "./vite.config.ts",
9240
+ "editor.formatOnSave": true,
9241
+ "editor.formatOnSaveMode": "file",
9242
+ "editor.codeActionsOnSave": { "source.fixAll.oxc": "explicit" }
9243
+ };
9244
+ const VSCODE_EXTENSIONS = { recommendations: ["VoidZero.vite-plus-extension-pack"] };
9245
+ const ZED_SETTINGS = {
9246
+ lsp: {
9247
+ oxlint: { initialization_options: { settings: {
9248
+ run: "onType",
9249
+ fixKind: "safe_fix",
9250
+ typeAware: true,
9251
+ unusedDisableDirectives: "deny"
9252
+ } } },
9253
+ oxfmt: { initialization_options: { settings: {
9254
+ "fmt.configPath": "./vite.config.ts",
9255
+ run: "onSave"
9256
+ } } }
9046
9257
  },
9047
- {
9048
- id: "jetbrains",
9049
- label: ".aiassistant/rules/viteplus.md",
9050
- targetPath: ".aiassistant/rules/viteplus.md",
9051
- hint: "JetBrains AI Assistant",
9052
- aliases: [
9053
- "jetbrains",
9054
- "jetbrains-ai-assistant",
9055
- "aiassistant",
9056
- "viteplus.md"
9057
- ]
9258
+ languages: Object.fromEntries([
9259
+ "CSS",
9260
+ "GraphQL",
9261
+ "Handlebars",
9262
+ "HTML",
9263
+ "JavaScript",
9264
+ "JSX",
9265
+ "JSON",
9266
+ "JSON5",
9267
+ "JSONC",
9268
+ "Less",
9269
+ "Markdown",
9270
+ "MDX",
9271
+ "SCSS",
9272
+ "TypeScript",
9273
+ "TSX",
9274
+ "Vue.js",
9275
+ "YAML"
9276
+ ].map((language) => [language, {
9277
+ format_on_save: "on",
9278
+ prettier: { allowed: false },
9279
+ formatter: [{ language_server: { name: "oxfmt" } }],
9280
+ ...language === "JavaScript" ? { code_action: "source.fixAll.oxc" } : {}
9281
+ }]))
9282
+ };
9283
+ const EDITORS = [{
9284
+ id: "vscode",
9285
+ label: "VSCode",
9286
+ targetDir: ".vscode",
9287
+ files: {
9288
+ "settings.json": VSCODE_SETTINGS,
9289
+ "extensions.json": VSCODE_EXTENSIONS
9290
+ }
9291
+ }, {
9292
+ id: "zed",
9293
+ label: "Zed",
9294
+ targetDir: ".zed",
9295
+ files: { "settings.json": ZED_SETTINGS }
9296
+ }];
9297
+ async function selectEditor({ interactive, editor, onCancel }) {
9298
+ if (editor === false) return;
9299
+ if (interactive && !editor) {
9300
+ const editorOptions = EDITORS.map((option) => ({
9301
+ label: option.label,
9302
+ value: option.id,
9303
+ hint: option.targetDir
9304
+ }));
9305
+ const otherOption = {
9306
+ label: "Other",
9307
+ value: null,
9308
+ hint: "Skip writing editor configs"
9309
+ };
9310
+ const selectedEditor = await select({
9311
+ message: "Which editor are you using?\n " + styleText("gray", "Writes editor config files to enable recommended extensions and Oxlint/Oxfmt integrations."),
9312
+ options: [...editorOptions, otherOption],
9313
+ initialValue: "vscode"
9314
+ });
9315
+ if (isCancel(selectedEditor)) {
9316
+ onCancel();
9317
+ return;
9318
+ }
9319
+ if (selectedEditor === null) return;
9320
+ return resolveEditorId(selectedEditor);
9058
9321
  }
9059
- ];
9060
- const AGENT_DEFAULT_ID = "agents";
9061
- const AGENT_STANDARD_PATH = "AGENTS.md";
9062
- const COPILOT_AGENT_ID = "copilot";
9063
- const COPILOT_SETUP_WORKFLOW_PATH = ".github/workflows/copilot-setup-steps.yml";
9064
- const AGENT_INSTRUCTIONS_START_MARKER = "<!--VITE PLUS START-->";
9065
- const AGENT_INSTRUCTIONS_END_MARKER = "<!--VITE PLUS END-->";
9066
- const AGENT_ALIASES = Object.fromEntries(AGENTS.flatMap((option) => (option.aliases ?? []).map((alias) => [normalizeAgentName(alias), option.id])));
9067
- const COPILOT_SETUP_WORKFLOW_CONTENT = `name: "Copilot Setup Steps"
9068
-
9069
- on:
9070
- workflow_dispatch:
9071
- push:
9072
- paths:
9073
- - .github/workflows/copilot-setup-steps.yml
9074
- pull_request:
9075
- paths:
9076
- - .github/workflows/copilot-setup-steps.yml
9077
-
9078
- jobs:
9079
- copilot-setup-steps:
9080
- runs-on: ubuntu-latest
9081
- permissions:
9082
- contents: read
9083
- steps:
9084
- - name: Checkout code
9085
- uses: actions/checkout@v6
9086
- with:
9087
- persist-credentials: false
9088
- - name: Set up Vite+
9089
- uses: voidzero-dev/setup-vp@v1
9090
- with:
9091
- cache: true
9092
- run-install: true
9093
- - name: Verify Vite+
9094
- run: vp --version
9095
- `;
9096
- async function selectAgentTargets({ interactive, agent, onCancel }) {
9097
- if (agent === false) return {
9098
- targetPaths: void 0,
9099
- selectedAgents: []
9100
- };
9101
- if (interactive && !agent) {
9102
- const selectedAgentIds = await multiselect({
9103
- message: "Which coding agent instruction files should Vite+ create?",
9104
- options: AGENTS.map((option) => ({
9322
+ if (editor) return resolveEditorId(editor);
9323
+ }
9324
+ async function selectEditors({ interactive, editor, onCancel }) {
9325
+ if (editor === false) return;
9326
+ if (interactive && !editor) {
9327
+ const selectedEditors = await multiselect({
9328
+ message: "Which editors are you using?\n " + styleText("gray", "Writes editor config files to enable recommended extensions and Oxlint/Oxfmt integrations."),
9329
+ options: EDITORS.map((option) => ({
9105
9330
  label: option.label,
9106
9331
  value: option.id,
9107
- hint: option.hint
9332
+ hint: option.targetDir
9108
9333
  })),
9109
- initialValues: [AGENT_DEFAULT_ID],
9334
+ initialValues: ["vscode"],
9110
9335
  required: false
9111
9336
  });
9112
- if (isCancel(selectedAgentIds)) {
9337
+ if (isCancel(selectedEditors)) {
9113
9338
  onCancel();
9114
- return {
9115
- targetPaths: void 0,
9116
- selectedAgents: []
9117
- };
9339
+ return;
9118
9340
  }
9119
- if (selectedAgentIds.length === 0) return {
9120
- targetPaths: void 0,
9121
- selectedAgents: []
9122
- };
9123
- const selectedAgents = resolveAgentOptions(selectedAgentIds);
9124
- return {
9125
- targetPaths: getAgentTargetPaths(selectedAgents),
9126
- selectedAgents
9127
- };
9341
+ return selectedEditors.length === 0 ? void 0 : resolveEditorIds(selectedEditors);
9128
9342
  }
9129
- const selectedAgents = resolveAgentOptions(agent ?? AGENT_DEFAULT_ID);
9130
- return {
9131
- targetPaths: getAgentTargetPaths(selectedAgents),
9132
- selectedAgents
9133
- };
9134
- }
9135
- async function selectAgentTargetPaths({ interactive, agent, onCancel }) {
9136
- return (await selectAgentTargets({
9137
- interactive,
9138
- agent,
9139
- onCancel
9140
- })).targetPaths;
9141
- }
9142
- function detectExistingAgentTargetPaths(projectRoot) {
9143
- const detectedPaths = [];
9144
- const seenTargetPaths = /* @__PURE__ */ new Set();
9145
- for (const option of AGENTS) {
9146
- if (seenTargetPaths.has(option.targetPath)) continue;
9147
- seenTargetPaths.add(option.targetPath);
9148
- const targetPath = path.join(projectRoot, option.targetPath);
9149
- if (fs.existsSync(targetPath) && !fs.lstatSync(targetPath).isSymbolicLink()) detectedPaths.push(option.targetPath);
9343
+ if (editor) {
9344
+ const editorId = resolveEditorId(editor);
9345
+ return editorId ? [editorId] : void 0;
9150
9346
  }
9151
- return detectedPaths.length > 0 ? detectedPaths : void 0;
9152
- }
9153
- /**
9154
- * Silently update agent instruction files that contain Vite+ markers.
9155
- * - No agent files → no writes
9156
- * - No Vite+ markers → no writes
9157
- * - Markers present, content up to date → no writes
9158
- * - Markers present, content outdated → update marked section
9159
- */
9160
- function updateExistingAgentInstructions(projectRoot) {
9161
- const targetPaths = detectExistingAgentTargetPaths(projectRoot);
9162
- if (!targetPaths) return;
9163
- const templatePath = path.join(pkgRoot, "AGENTS.md");
9164
- if (!fs.existsSync(templatePath)) return;
9165
- const templateContent = fs.readFileSync(templatePath, "utf-8");
9166
- for (const targetPath of targetPaths) try {
9167
- const fullPath = path.join(projectRoot, targetPath);
9168
- const existing = fs.readFileSync(fullPath, "utf-8");
9169
- const updated = replaceMarkedAgentInstructionsSection(existing, templateContent);
9170
- if (updated !== void 0 && updated !== existing) fs.writeFileSync(fullPath, updated);
9171
- } catch {}
9172
9347
  }
9173
- function resolveAgentOptions(agent) {
9174
- const agentNames = parseAgentNames(agent);
9175
- const resolvedAgentNames = agentNames.length > 0 ? agentNames : [AGENT_DEFAULT_ID];
9176
- const dedupedAgents = [];
9177
- const seenAgentIds = /* @__PURE__ */ new Set();
9178
- for (const name of resolvedAgentNames) {
9179
- const option = resolveSingleAgentOption(name);
9180
- if (seenAgentIds.has(option.id)) continue;
9181
- seenAgentIds.add(option.id);
9182
- dedupedAgents.push(option);
9183
- }
9184
- return dedupedAgents;
9185
- }
9186
- function getAgentTargetPaths(agents) {
9187
- const dedupedTargetPaths = [];
9188
- const seenTargetPaths = /* @__PURE__ */ new Set();
9189
- for (const agent of agents) {
9190
- if (seenTargetPaths.has(agent.targetPath)) continue;
9191
- seenTargetPaths.add(agent.targetPath);
9192
- dedupedTargetPaths.push(agent.targetPath);
9193
- }
9194
- return dedupedTargetPaths;
9195
- }
9196
- function parseAgentNames(agent) {
9197
- if (!agent) return [];
9198
- return (Array.isArray(agent) ? agent : [agent]).filter((value) => typeof value === "string").flatMap((value) => value.split(",")).map((value) => value.trim()).filter((value) => value.length > 0);
9199
- }
9200
- function resolveSingleAgentOption(agent) {
9201
- const normalized = normalizeAgentName(agent);
9202
- const alias = AGENT_ALIASES[normalized];
9203
- const resolved = alias ? normalizeAgentName(alias) : normalized;
9204
- return AGENTS.find((option) => normalizeAgentName(option.id) === resolved || normalizeAgentName(option.label) === resolved || normalizeAgentName(option.targetPath) === resolved || option.aliases?.some((candidate) => normalizeAgentName(candidate) === resolved)) ?? AGENTS.find((option) => option.id === AGENT_DEFAULT_ID);
9348
+ function detectExistingEditors(projectRoot) {
9349
+ const editors = [];
9350
+ for (const option of EDITORS) for (const fileName of Object.keys(option.files)) {
9351
+ const filePath = path.join(projectRoot, option.targetDir, fileName);
9352
+ if (fs.existsSync(filePath)) {
9353
+ editors.push(option.id);
9354
+ break;
9355
+ }
9356
+ }
9357
+ return editors.length === 0 ? void 0 : editors;
9205
9358
  }
9206
9359
  /**
9207
- * Detect agent instruction files that would conflict (exist without markers).
9208
- * Returns only files that need a user decision (append or skip).
9360
+ * Detect editor config files that would conflict (already exist).
9209
9361
  * Read-only — does not write or modify any files.
9210
9362
  */
9211
- async function detectAgentConflicts({ projectRoot, targetPaths }) {
9212
- if (!targetPaths || targetPaths.length === 0) return [];
9213
- const sourcePath = path.join(pkgRoot, "AGENTS.md");
9214
- if (!fs.existsSync(sourcePath)) return [];
9215
- const incomingContent = await fsPromises.readFile(sourcePath, "utf-8");
9216
- const shouldLinkToAgents = targetPaths.includes(AGENT_STANDARD_PATH);
9217
- const orderedPaths = shouldLinkToAgents ? [AGENT_STANDARD_PATH, ...targetPaths.filter((p) => p !== AGENT_STANDARD_PATH)] : targetPaths;
9363
+ function detectEditorConflicts({ projectRoot, editorId }) {
9364
+ if (!editorId) return [];
9365
+ const editorConfig = EDITORS.find((e) => e.id === editorId);
9366
+ if (!editorConfig) return [];
9218
9367
  const conflicts = [];
9219
- const seenDestinationPaths = /* @__PURE__ */ new Set();
9220
- const seenRealPaths = /* @__PURE__ */ new Set();
9221
- for (const targetPathToCheck of orderedPaths) {
9222
- const destinationPath = path.join(projectRoot, targetPathToCheck);
9223
- const destinationKey = path.resolve(destinationPath);
9224
- if (seenDestinationPaths.has(destinationKey)) continue;
9225
- seenDestinationPaths.add(destinationKey);
9226
- if (shouldLinkToAgents && targetPathToCheck !== AGENT_STANDARD_PATH) {
9227
- if (await getExistingPathKind(destinationPath) !== "file") continue;
9228
- }
9229
- if (fs.existsSync(destinationPath)) {
9230
- if (fs.lstatSync(destinationPath).isSymbolicLink()) continue;
9231
- const destinationRealPath = await fsPromises.realpath(destinationPath);
9232
- if (seenRealPaths.has(destinationRealPath)) continue;
9233
- if (replaceMarkedAgentInstructionsSection(await fsPromises.readFile(destinationPath, "utf-8"), incomingContent) !== void 0) {
9234
- seenRealPaths.add(destinationRealPath);
9235
- continue;
9236
- }
9237
- conflicts.push({ targetPath: targetPathToCheck });
9238
- seenRealPaths.add(destinationRealPath);
9239
- }
9368
+ for (const fileName of Object.keys(editorConfig.files)) {
9369
+ const filePath = path.join(projectRoot, editorConfig.targetDir, fileName);
9370
+ if (fs.existsSync(filePath)) conflicts.push({
9371
+ fileName,
9372
+ displayPath: `${editorConfig.targetDir}/${fileName}`
9373
+ });
9240
9374
  }
9241
9375
  return conflicts;
9242
9376
  }
9243
- async function writeAgentInstructions({ projectRoot, targetPath, targetPaths, interactive, conflictDecisions, silent = false }) {
9244
- const paths = [...targetPaths ?? [], ...targetPath ? [targetPath] : []];
9245
- if (paths.length === 0) return;
9246
- const sourcePath = path.join(pkgRoot, "AGENTS.md");
9247
- if (!fs.existsSync(sourcePath)) {
9248
- if (!silent) log.warn("Agent instructions template not found; skipping.");
9249
- return;
9250
- }
9251
- const seenDestinationPaths = /* @__PURE__ */ new Set();
9252
- const seenRealPaths = /* @__PURE__ */ new Set();
9253
- const incomingContent = await fsPromises.readFile(sourcePath, "utf-8");
9254
- const shouldLinkToAgents = paths.includes(AGENT_STANDARD_PATH);
9255
- const orderedPaths = shouldLinkToAgents ? [AGENT_STANDARD_PATH, ...paths.filter((p) => p !== AGENT_STANDARD_PATH)] : paths;
9256
- for (const targetPathToWrite of orderedPaths) {
9257
- const destinationPath = path.join(projectRoot, targetPathToWrite);
9258
- const destinationKey = path.resolve(destinationPath);
9259
- if (seenDestinationPaths.has(destinationKey)) continue;
9260
- seenDestinationPaths.add(destinationKey);
9261
- await fsPromises.mkdir(path.dirname(destinationPath), { recursive: true });
9262
- if (shouldLinkToAgents && targetPathToWrite !== AGENT_STANDARD_PATH) {
9263
- if (await tryLinkTargetToAgents(projectRoot, targetPathToWrite, silent)) continue;
9264
- }
9265
- if (fs.existsSync(destinationPath)) {
9266
- if (fs.lstatSync(destinationPath).isSymbolicLink()) {
9267
- if (!silent) log.info(`Skipped writing ${targetPathToWrite} (symlink)`);
9268
- continue;
9269
- }
9270
- const destinationRealPath = await fsPromises.realpath(destinationPath);
9271
- if (seenRealPaths.has(destinationRealPath)) {
9272
- if (!silent) log.info(`Skipped writing ${targetPathToWrite} (duplicate target)`);
9273
- continue;
9274
- }
9275
- const existingContent = await fsPromises.readFile(destinationPath, "utf-8");
9276
- const updatedContent = replaceMarkedAgentInstructionsSection(existingContent, incomingContent);
9277
- if (updatedContent !== void 0) {
9278
- if (updatedContent !== existingContent) await fsPromises.writeFile(destinationPath, updatedContent);
9279
- seenRealPaths.add(destinationRealPath);
9280
- continue;
9281
- }
9377
+ async function writeEditorConfigs({ projectRoot, editorId, interactive, conflictDecisions, silent = false, extraVsCodeSettings }) {
9378
+ const editorIds = normalizeEditorSelection(editorId);
9379
+ if (editorIds.length === 0) return;
9380
+ for (const currentEditorId of editorIds) await writeEditorConfig({
9381
+ projectRoot,
9382
+ editorId: currentEditorId,
9383
+ interactive,
9384
+ conflictDecisions,
9385
+ silent,
9386
+ extraVsCodeSettings
9387
+ });
9388
+ }
9389
+ async function writeEditorConfig({ projectRoot, editorId, interactive, conflictDecisions, silent, extraVsCodeSettings }) {
9390
+ const editorConfig = EDITORS.find((e) => e.id === editorId);
9391
+ if (!editorConfig) return;
9392
+ const targetDir = path.join(projectRoot, editorConfig.targetDir);
9393
+ await fsPromises.mkdir(targetDir, { recursive: true });
9394
+ for (const [fileName, baseIncoming] of Object.entries(editorConfig.files)) {
9395
+ const incoming = editorId === "vscode" && fileName === "settings.json" && extraVsCodeSettings ? {
9396
+ ...extraVsCodeSettings,
9397
+ ...baseIncoming
9398
+ } : baseIncoming;
9399
+ const filePath = path.join(targetDir, fileName);
9400
+ if (fs.existsSync(filePath)) {
9401
+ const displayPath = `${editorConfig.targetDir}/${fileName}`;
9282
9402
  let conflictAction;
9283
- const preResolved = conflictDecisions?.get(targetPathToWrite);
9403
+ const preResolved = conflictDecisions?.get(displayPath) ?? conflictDecisions?.get(fileName);
9284
9404
  if (preResolved) conflictAction = preResolved;
9285
9405
  else if (interactive) {
9286
9406
  const action = await select({
9287
- message: `Agent instructions already exist at ${targetPathToWrite}.\n ` + styleText("gray", "The Vite+ template includes guidance on `vp` commands, the build pipeline, and project conventions."),
9407
+ message: `${displayPath} already exists.\n ` + styleText("gray", `Vite+ adds ${editorConfig.label} settings for the built-in linter and formatter. Merge adds new keys without overwriting existing ones.`),
9288
9408
  options: [{
9289
- label: "Append",
9290
- value: "append",
9291
- hint: "Add template content to the end"
9409
+ label: "Merge",
9410
+ value: "merge",
9411
+ hint: "Merge new settings into existing file"
9292
9412
  }, {
9293
9413
  label: "Skip",
9294
9414
  value: "skip",
@@ -9296,86 +9416,96 @@ async function writeAgentInstructions({ projectRoot, targetPath, targetPaths, in
9296
9416
  }],
9297
9417
  initialValue: "skip"
9298
9418
  });
9299
- conflictAction = isCancel(action) || action === "skip" ? "skip" : "append";
9300
- } else conflictAction = "skip";
9301
- if (conflictAction === "append") await appendAgentContent(destinationPath, targetPathToWrite, existingContent, incomingContent, silent);
9302
- else {
9303
- const suffix = !preResolved && !interactive ? " (already exists)" : "";
9304
- if (!silent) log.info(`Skipped writing ${targetPathToWrite}${suffix}`);
9305
- }
9306
- seenRealPaths.add(destinationRealPath);
9419
+ conflictAction = isCancel(action) || action === "skip" ? "skip" : "merge";
9420
+ } else conflictAction = "merge";
9421
+ if (conflictAction === "merge") mergeAndWriteEditorConfig(filePath, incoming, fileName, displayPath, silent);
9422
+ else if (!silent) log.info(`Skipped writing ${displayPath}`);
9307
9423
  continue;
9308
9424
  }
9309
- await fsPromises.writeFile(destinationPath, incomingContent);
9310
- if (!silent) log.success(`Wrote agent instructions to ${targetPathToWrite}`);
9311
- seenRealPaths.add(await fsPromises.realpath(destinationPath));
9425
+ writeJsonFile(filePath, incoming);
9426
+ if (!silent) log.success(`Wrote editor config to ${editorConfig.targetDir}/${fileName}`);
9312
9427
  }
9313
9428
  }
9314
- async function writeCopilotSetupWorkflow({ projectRoot, silent = false }) {
9315
- const destinationPath = path.join(projectRoot, COPILOT_SETUP_WORKFLOW_PATH);
9316
- await fsPromises.mkdir(path.dirname(destinationPath), { recursive: true });
9317
- if (fs.existsSync(destinationPath)) {
9318
- if (!silent) log.info(`Skipped writing ${COPILOT_SETUP_WORKFLOW_PATH} (already exists)`);
9429
+ function normalizeEditorSelection(editorId) {
9430
+ if (!editorId) return [];
9431
+ return [...new Set(Array.isArray(editorId) ? editorId : [editorId])];
9432
+ }
9433
+ /**
9434
+ * Merge incoming settings into an existing editor JSON/JSONC file by patching the
9435
+ * original text with `jsonc-parser` instead of re-serializing a merged object.
9436
+ * This preserves comments, key order, trailing commas, and untouched formatting.
9437
+ * Existing values always win; only missing keys/branches are inserted.
9438
+ */
9439
+ function mergeAndWriteEditorConfig(filePath, incoming, fileName, displayPath, silent = false) {
9440
+ const originalText = fs.readFileSync(filePath, "utf-8");
9441
+ const existing = parse(originalText);
9442
+ if (!isPlainObject(existing)) throw new Error(`Cannot merge editor config: ${displayPath} is not a JSON object`);
9443
+ const formattingOptions = detectFormattingOptions(originalText);
9444
+ const newText = fileName === "extensions.json" ? mergeExtensionsText(originalText, existing, incoming, formattingOptions) : mergeSettingsText(originalText, existing, incoming, formattingOptions);
9445
+ if (newText === originalText) {
9446
+ if (!silent) log.info(`No changes needed for ${displayPath}`);
9319
9447
  return;
9320
9448
  }
9321
- await fsPromises.writeFile(destinationPath, COPILOT_SETUP_WORKFLOW_CONTENT);
9322
- if (!silent) log.success(`Wrote Copilot setup workflow to ${COPILOT_SETUP_WORKFLOW_PATH}`);
9323
- }
9324
- async function appendAgentContent(destinationPath, targetPath, existingContent, incomingContent, silent = false) {
9325
- const separator = existingContent.endsWith("\n") ? "" : "\n";
9326
- await fsPromises.appendFile(destinationPath, `${separator}\n${incomingContent}`);
9327
- if (!silent) log.success(`Appended agent instructions to ${targetPath}`);
9328
- }
9329
- function normalizeAgentName(value) {
9330
- return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
9331
- }
9332
- function replaceMarkedAgentInstructionsSection(existing, incoming) {
9333
- const existingRange = getMarkedRange(existing, AGENT_INSTRUCTIONS_START_MARKER, AGENT_INSTRUCTIONS_END_MARKER);
9334
- if (!existingRange) return;
9335
- const incomingRange = getMarkedRange(incoming, AGENT_INSTRUCTIONS_START_MARKER, AGENT_INSTRUCTIONS_END_MARKER);
9336
- if (!incomingRange) return;
9337
- return `${existing.slice(0, existingRange.start)}${incoming.slice(incomingRange.start, incomingRange.end)}${existing.slice(existingRange.end)}`;
9338
- }
9339
- async function tryLinkTargetToAgents(projectRoot, targetPath, silent = false) {
9340
- const destinationPath = path.join(projectRoot, targetPath);
9341
- const agentsPath = path.join(projectRoot, AGENT_STANDARD_PATH);
9342
- const symlinkTarget = path.relative(path.dirname(destinationPath), agentsPath);
9343
- const existing = await getExistingPathKind(destinationPath);
9344
- if (existing === "file") return false;
9345
- if (existing === "symlink") {
9346
- const currentLink = await fsPromises.readlink(destinationPath);
9347
- if (path.resolve(path.dirname(destinationPath), currentLink) === agentsPath) {
9348
- if (!silent) log.info(`Skipped linking ${targetPath} (already linked to ${AGENT_STANDARD_PATH})`);
9349
- return true;
9350
- }
9351
- await fsPromises.unlink(destinationPath);
9352
- }
9353
- try {
9354
- await fsPromises.symlink(symlinkTarget, destinationPath);
9355
- } catch (err) {
9356
- if (err.code === "EPERM") {
9357
- await fsPromises.copyFile(agentsPath, destinationPath);
9358
- if (!silent) log.success(`Copied ${AGENT_STANDARD_PATH} to ${targetPath}`);
9359
- return true;
9449
+ fs.writeFileSync(filePath, newText, "utf-8");
9450
+ if (!silent) log.success(`Merged editor config into ${displayPath}`);
9451
+ }
9452
+ function isPlainObject(value) {
9453
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9454
+ }
9455
+ /** Apply a single `jsonc-parser` modification to `text` and return the patched text. */
9456
+ function applyJsoncEdit(text, path, value, options) {
9457
+ return applyEdits(text, modify(text, path, value, options));
9458
+ }
9459
+ /**
9460
+ * Deep-merge missing keys from `incoming` into the existing text. Inserts a whole
9461
+ * branch when it is absent, and recurses only when both sides are non-array objects
9462
+ * so comments inside existing branches are preserved.
9463
+ */
9464
+ function mergeSettingsText(text, existing, incoming, formattingOptions) {
9465
+ let currentText = text;
9466
+ const insertMissing = (existingNode, incomingNode, basePath) => {
9467
+ for (const [key, value] of Object.entries(incomingNode)) {
9468
+ const fullPath = [...basePath, key];
9469
+ if (!(key in existingNode)) currentText = applyJsoncEdit(currentText, fullPath, value, { formattingOptions });
9470
+ else if (isPlainObject(existingNode[key]) && isPlainObject(value)) insertMissing(existingNode[key], value, fullPath);
9360
9471
  }
9361
- throw err;
9472
+ };
9473
+ insertMissing(existing, incoming, []);
9474
+ return currentText;
9475
+ }
9476
+ /**
9477
+ * For `extensions.json`, append missing recommendations without rebuilding the array,
9478
+ * so comments inside the array survive. Existing entries always win.
9479
+ */
9480
+ function mergeExtensionsText(text, existing, incoming, formattingOptions) {
9481
+ const incomingRecs = Array.isArray(incoming["recommendations"]) ? incoming["recommendations"] : [];
9482
+ const existingValue = existing["recommendations"];
9483
+ if (!("recommendations" in existing)) return applyJsoncEdit(text, ["recommendations"], incomingRecs, { formattingOptions });
9484
+ if (!Array.isArray(existingValue)) return text;
9485
+ const existingRecs = new Set(existingValue);
9486
+ let currentText = text;
9487
+ let nextIndex = existingValue.length;
9488
+ for (const rec of incomingRecs) {
9489
+ if (existingRecs.has(rec)) continue;
9490
+ currentText = applyJsoncEdit(currentText, ["recommendations", nextIndex], rec, {
9491
+ formattingOptions,
9492
+ isArrayInsertion: true
9493
+ });
9494
+ nextIndex++;
9362
9495
  }
9363
- if (!silent) log.success(`Linked ${targetPath} to ${AGENT_STANDARD_PATH}`);
9364
- return true;
9496
+ return currentText;
9365
9497
  }
9366
- async function getExistingPathKind(filePath) {
9367
- if (!fs.existsSync(filePath)) return "missing";
9368
- return (await fsPromises.lstat(filePath)).isSymbolicLink() ? "symlink" : "file";
9498
+ function resolveEditorId(editor) {
9499
+ const normalized = editor.trim().toLowerCase();
9500
+ return EDITORS.find((option) => option.id === normalized || option.label.toLowerCase() === normalized)?.id;
9369
9501
  }
9370
- function getMarkedRange(content, startMarker, endMarker) {
9371
- const start = content.indexOf(startMarker);
9372
- if (start === -1) return;
9373
- const endMarkerIndex = content.indexOf(endMarker, start + startMarker.length);
9374
- if (endMarkerIndex === -1) return;
9375
- return {
9376
- start,
9377
- end: endMarkerIndex + endMarker.length
9378
- };
9502
+ function resolveEditorIds(editors) {
9503
+ const editorIds = editors.flatMap((editor) => {
9504
+ const editorId = resolveEditorId(editor);
9505
+ return editorId ? [editorId] : [];
9506
+ });
9507
+ const uniqueEditorIds = [...new Set(editorIds)];
9508
+ return uniqueEditorIds.length === 0 ? void 0 : uniqueEditorIds;
9379
9509
  }
9380
9510
  //#endregion
9381
- export { globSync as A, warnPackageLevelEslint as B, injectLintTypeCheckDefaults as C, ensureVitePlusBootstrap as D, detectVitePlusBootstrapPending as E, migrateEslintToOxlint as F, checkVitestVersion as G, PRETTIER_PACKAGE_JSON_CONFIG as H, promptEslintMigration as I, templatesDir as J, warnMigration as K, rewriteToolLintStagedConfigFiles as L, confirmEslintMigration as M, detectEslintProject as N, configureYarnNodeModulesMode as O, detectIncompatibleEslintIntegration as P, warnIncompatibleEslintIntegration as R, injectCreateDefaultTemplate as S, collectToolchainVersionChanges as T, detectConfigs as U, PRETTIER_CONFIG_FILES as V, checkViteVersion as W, detectLegacyGitHooksMigrationCandidate as _, selectAgentTargets as a, preflightGitHooksSetup as b, writeCopilotSetupWorkflow as c, rewriteStandaloneProject as d, detectPendingCoreMigration as f, setPackageManager as g, migrateNodeVersionManagerFile as h, selectAgentTargetPaths as i, minimatch as j, detectYarnPnpMode as k, rewriteMonorepo as l, detectNodeVersionManagerFile as m, detectAgentConflicts as n, updateExistingAgentInstructions as o, finalizeCoreMigrationForExistingVitePlus as p, displayRelative as q, detectExistingAgentTargetPaths as r, writeAgentInstructions as s, COPILOT_AGENT_ID as t, rewriteMonorepoProject as u, ensurePreCommitHook as v, mergeViteConfigFiles as w, hasStagedConfigInViteConfig as x, installGitHooks as y, warnLegacyEslintConfig as z };
9511
+ export { addFrameworkShim as A, detectIncompatibleEslintIntegration as B, ensureVitePlusBootstrap as C, isBingoTemplate as D, detectWorkspace$1 as E, migratePrettierToOxfmt as F, warnPackageLevelEslint as G, promptEslintMigration as H, promptPrettierMigration as I, checkViteVersion as K, warnPackageLevelPrettier as L, hasFrameworkShim as M, confirmPrettierMigration as N, updatePackageJsonWithDeps as O, detectPrettierProject as P, confirmEslintMigration as R, detectVitePlusBootstrapPending as S, detectYarnPnpMode as T, warnIncompatibleEslintIntegration as U, migrateEslintToOxlint as V, warnLegacyEslintConfig as W, shouldSkipStagedMigrationForHooks as _, writeEditorConfigs as a, mergeViteConfigFiles as b, rewriteStandaloneProject as c, detectNodeVersionManagerFile as d, migrateNodeVersionManagerFile as f, preflightGitHooksSetup as g, installGitHooks as h, selectEditors as i, detectFramework as j, updateWorkspaceConfig as k, detectPendingCoreMigration as l, detectLegacyGitHooksMigrationCandidate as m, detectExistingEditors as n, rewriteMonorepo as o, setPackageManager as p, checkVitestVersion as q, selectEditor as r, rewriteMonorepoProject as s, detectEditorConflicts as t, finalizeCoreMigrationForExistingVitePlus as u, injectCreateDefaultTemplate as v, configureYarnNodeModulesMode as w, collectToolchainVersionChanges as x, injectLintTypeCheckDefaults as y, detectEslintProject as z };