vite-plus 0.1.14-alpha.3 → 0.1.15-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2828,7 +2828,8 @@ var require_semver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2828
2828
  const PackageManager = {
2829
2829
  pnpm: "pnpm",
2830
2830
  npm: "npm",
2831
- yarn: "yarn"
2831
+ yarn: "yarn",
2832
+ bun: "bun"
2832
2833
  };
2833
2834
  const DependencyType = {
2834
2835
  dependencies: "dependencies",
@@ -2897,7 +2898,8 @@ async function selectPackageManager(interactive, silent = false) {
2897
2898
  hint: "recommended"
2898
2899
  },
2899
2900
  { value: PackageManager.yarn },
2900
- { value: PackageManager.npm }
2901
+ { value: PackageManager.npm },
2902
+ { value: PackageManager.bun }
2901
2903
  ],
2902
2904
  initialValue: PackageManager.pnpm
2903
2905
  });
@@ -3553,7 +3555,7 @@ function rewriteStandaloneProject(projectPath, workspaceInfo, skipStagedMigratio
3553
3555
  ...pkg.resolutions,
3554
3556
  ...VITE_PLUS_OVERRIDE_PACKAGES
3555
3557
  };
3556
- else if (packageManager === PackageManager.npm) pkg.overrides = {
3558
+ else if (packageManager === PackageManager.npm || packageManager === PackageManager.bun) pkg.overrides = {
3557
3559
  ...pkg.overrides,
3558
3560
  ...VITE_PLUS_OVERRIDE_PACKAGES
3559
3561
  };
@@ -3591,6 +3593,7 @@ function rewriteStandaloneProject(projectPath, workspaceInfo, skipStagedMigratio
3591
3593
  function rewriteMonorepo(workspaceInfo, skipStagedMigration, silent = false, report) {
3592
3594
  if (workspaceInfo.packageManager === PackageManager.pnpm) rewritePnpmWorkspaceYaml(workspaceInfo.rootDir);
3593
3595
  else if (workspaceInfo.packageManager === PackageManager.yarn) rewriteYarnrcYml(workspaceInfo.rootDir);
3596
+ else if (workspaceInfo.packageManager === PackageManager.bun) rewriteBunCatalog(workspaceInfo.rootDir);
3594
3597
  rewriteRootWorkspacePackageJson(workspaceInfo.rootDir, workspaceInfo.packageManager, skipStagedMigration);
3595
3598
  for (const pkg of workspaceInfo.packages) rewriteMonorepoProject(path.join(workspaceInfo.rootDir, pkg.path), workspaceInfo.packageManager, skipStagedMigration, silent, report);
3596
3599
  if (!skipStagedMigration) rewriteLintStagedConfigFile(workspaceInfo.rootDir, report);
@@ -3692,6 +3695,27 @@ function rewriteCatalog(doc) {
3692
3695
  }
3693
3696
  }
3694
3697
  /**
3698
+ * Write catalog entries to root package.json for bun.
3699
+ * Bun stores catalogs in package.json under the `catalog` key,
3700
+ * unlike pnpm which uses pnpm-workspace.yaml.
3701
+ * @see https://bun.sh/docs/pm/catalogs
3702
+ */
3703
+ function rewriteBunCatalog(projectPath) {
3704
+ const packageJsonPath = path.join(projectPath, "package.json");
3705
+ if (!fs.existsSync(packageJsonPath)) return;
3706
+ editJsonFile(packageJsonPath, (pkg) => {
3707
+ const catalog = { ...pkg.catalog };
3708
+ for (const [key, value] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) if (!value.startsWith("file:")) catalog[key] = value;
3709
+ if (!VITE_PLUS_VERSION.startsWith("file:")) catalog[VITE_PLUS_NAME] = VITE_PLUS_VERSION;
3710
+ for (const name of REMOVE_PACKAGES) delete catalog[name];
3711
+ pkg.catalog = catalog;
3712
+ const overrides = { ...pkg.overrides };
3713
+ for (const key of Object.keys(VITE_PLUS_OVERRIDE_PACKAGES)) overrides[key] = "catalog:";
3714
+ pkg.overrides = overrides;
3715
+ return pkg;
3716
+ });
3717
+ }
3718
+ /**
3695
3719
  * Rewrite root workspace package.json to add vite-plus dependencies
3696
3720
  * @param projectPath - The path to the project
3697
3721
  */
@@ -3707,7 +3731,7 @@ function rewriteRootWorkspacePackageJson(projectPath, packageManager, skipStaged
3707
3731
  ...pkg.overrides,
3708
3732
  ...VITE_PLUS_OVERRIDE_PACKAGES
3709
3733
  };
3710
- else if (packageManager === PackageManager.pnpm) {
3734
+ else if (packageManager === PackageManager.bun) {} else if (packageManager === PackageManager.pnpm) {
3711
3735
  if (isForceOverrideMode()) pkg.pnpm = {
3712
3736
  ...pkg.pnpm,
3713
3737
  overrides: {
@@ -3998,13 +4022,22 @@ function rewriteAllImports(projectPath, silent = false, report) {
3998
4022
  /**
3999
4023
  * Check if the project has an unsupported husky version (<9.0.0).
4000
4024
  * Uses `semver.coerce` to handle ranges like `^8.0.0` → `8.0.0`.
4001
- * Accepts pre-loaded deps to avoid re-reading package.json when called
4002
- * from contexts that already parsed it.
4025
+ * When the specifier is not coercible (e.g. `"latest"`), falls back to
4026
+ * the installed version in node_modules via `detectPackageMetadata`.
4027
+ * Returns a reason string if hooks migration should be skipped, or null
4028
+ * if husky is absent or compatible.
4003
4029
  */
4004
- function checkUnsupportedHuskyVersion(deps, prodDeps) {
4030
+ function checkUnsupportedHuskyVersion(projectPath, deps, prodDeps) {
4005
4031
  const huskyVersion = deps?.husky ?? prodDeps?.husky;
4006
- if (!huskyVersion) return false;
4007
- return import_semver.default.satisfies(import_semver.default.coerce(huskyVersion) ?? "0.0.0", "<9.0.0");
4032
+ if (!huskyVersion) return null;
4033
+ let coerced = import_semver.default.coerce(huskyVersion);
4034
+ if (coerced == null) {
4035
+ const installed = detectPackageMetadata(projectPath, "husky");
4036
+ if (installed) coerced = import_semver.default.coerce(installed.version);
4037
+ 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.`;
4038
+ }
4039
+ 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.";
4040
+ return null;
4008
4041
  }
4009
4042
  const OTHER_HOOK_TOOLS = [
4010
4043
  "simple-git-hooks",
@@ -4082,7 +4115,8 @@ function preflightGitHooksSetup(projectPath) {
4082
4115
  const deps = pkgContent.devDependencies;
4083
4116
  const prodDeps = pkgContent.dependencies;
4084
4117
  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.`;
4085
- if (checkUnsupportedHuskyVersion(deps, prodDeps)) return "Detected husky <9.0.0 — please upgrade to husky v9+ first, then re-run migration.";
4118
+ const huskyReason = checkUnsupportedHuskyVersion(projectPath, deps, prodDeps);
4119
+ if (huskyReason) return huskyReason;
4086
4120
  if (hasUnsupportedLintStagedConfig(projectPath)) return "Unsupported lint-staged config format — skipping git hooks setup. Please configure git hooks manually.";
4087
4121
  return null;
4088
4122
  }
@@ -1,4 +1,4 @@
1
- import { S as defaultInteractive, i as updateExistingAgentInstructions, u as ensurePreCommitHook, w as promptGitHooks } from "./agent-DTz-Dh1r.js";
1
+ import { S as defaultInteractive, i as updateExistingAgentInstructions, u as ensurePreCommitHook, w as promptGitHooks } from "./agent-soFdSW5Z.js";
2
2
  import { t as lib_default } from "./lib-DxappLRQ.js";
3
3
  import { i as log, t as renderCliDoc } from "./help-HviKaKAU.js";
4
4
  import { join } from "node:path";
@@ -1,9 +1,9 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-BoAXSpZd.js";
2
- import { A as templatesDir, B as select, C as downloadPackageManager$1, D as selectPackageManager, E as runViteInstall, F as confirm, H as text, I as intro, L as log, M as PackageManager, P as cancel, R as multiselect, S as defaultInteractive, T as runViteFmt, U as Ct, V as spinner, _ as rewriteMonorepoProject, a as writeAgentInstructions, d as installGitHooks, g as rewriteMonorepo, j as DependencyType, k as displayRelative, n as detectExistingAgentTargetPaths, r as selectAgentTargetPaths, v as rewriteStandaloneProject, w as promptGitHooks } from "./agent-DTz-Dh1r.js";
2
+ import { A as templatesDir, B as select, C as downloadPackageManager$1, D as selectPackageManager, E as runViteInstall, F as confirm, H as text, I as intro, L as log, M as PackageManager, P as cancel, R as multiselect, S as defaultInteractive, T as runViteFmt, U as Ct, V as spinner, _ as rewriteMonorepoProject, a as writeAgentInstructions, d as installGitHooks, g as rewriteMonorepo, j as DependencyType, k as displayRelative, n as detectExistingAgentTargetPaths, r as selectAgentTargetPaths, v as rewriteStandaloneProject, w as promptGitHooks } from "./agent-soFdSW5Z.js";
3
3
  import { t as lib_default } from "./lib-DxappLRQ.js";
4
4
  import { c as readJsonFile, o as editJsonFile, t as checkNpmPackageExists } from "./package-Y1UTfJnZ.js";
5
5
  import { a as muted, i as log$1, n as accent, o as success, t as renderCliDoc } from "./help-HviKaKAU.js";
6
- import { a as detectExistingEditor, n as updatePackageJsonWithDeps, o as selectEditor, r as updateWorkspaceConfig, s as writeEditorConfigs, t as detectWorkspace$1 } from "./workspace-BlrOxcHM.js";
6
+ import { a as detectExistingEditor, n as updatePackageJsonWithDeps, o as selectEditor, r as updateWorkspaceConfig, s as writeEditorConfigs, t as detectWorkspace$1 } from "./workspace-A1-sHiSV.js";
7
7
  import path from "node:path";
8
8
  import { styleText } from "node:util";
9
9
  import color from "picocolors";
@@ -97,6 +97,10 @@ function getPackageRunner(workspaceInfo) {
97
97
  command: "yarn",
98
98
  args: ["dlx"]
99
99
  };
100
+ case "bun": return {
101
+ command: "bun",
102
+ args: ["x"]
103
+ };
100
104
  default: return {
101
105
  command: "npx",
102
106
  args: []
@@ -105,7 +109,7 @@ function getPackageRunner(workspaceInfo) {
105
109
  }
106
110
  function formatDlxCommand(packageName, args, workspaceInfo) {
107
111
  const runner = getPackageRunner(workspaceInfo);
108
- const dlxArgs = runner.command === "npm" ? ["--", ...args] : args;
112
+ const dlxArgs = runner.command === "npx" ? ["--", ...args] : args;
109
113
  return {
110
114
  command: runner.command,
111
115
  args: [
@@ -3511,13 +3515,19 @@ async function executeBuiltinTemplate(workspaceInfo, templateInfo, options) {
3511
3515
  } else if (templateInfo.command === BuiltinTemplate.library) {
3512
3516
  const libraryTemplateInfo = discoverTemplate(LibraryTemplateRepo, [templateInfo.targetDir], workspaceInfo);
3513
3517
  const result = await runRemoteTemplateCommand(workspaceInfo, workspaceInfo.rootDir, libraryTemplateInfo, false, options?.silent ?? false);
3518
+ if (result.exitCode !== 0) return { exitCode: result.exitCode };
3514
3519
  setPackageName(path.join(workspaceInfo.rootDir, templateInfo.targetDir), templateInfo.packageName);
3515
3520
  return {
3516
3521
  ...result,
3517
3522
  projectDir: templateInfo.targetDir
3518
3523
  };
3519
3524
  }
3525
+ if (templateInfo.command.startsWith("vite:")) {
3526
+ if (!options?.silent) log.error(`Unknown builtin template "${templateInfo.command}". Run ${color.yellow("vp create --list")} to see available templates.`);
3527
+ return { exitCode: 1 };
3528
+ }
3520
3529
  const result = await runRemoteTemplateCommand(workspaceInfo, workspaceInfo.rootDir, templateInfo, false, options?.silent ?? false);
3530
+ if (result.exitCode !== 0) return { exitCode: result.exitCode };
3521
3531
  setPackageName(path.join(workspaceInfo.rootDir, templateInfo.targetDir), templateInfo.packageName);
3522
3532
  return {
3523
3533
  ...result,
@@ -3680,6 +3690,10 @@ const helpMessage = renderCliDoc({
3680
3690
  label: "--no-hooks",
3681
3691
  description: "Skip pre-commit hooks setup"
3682
3692
  },
3693
+ {
3694
+ label: "--package-manager NAME",
3695
+ description: "Use specified package manager (pnpm, npm, yarn, bun)"
3696
+ },
3683
3697
  {
3684
3698
  label: "--verbose",
3685
3699
  description: "Show detailed scaffolding output"
@@ -3823,7 +3837,8 @@ function parseArgs() {
3823
3837
  string: [
3824
3838
  "directory",
3825
3839
  "agent",
3826
- "editor"
3840
+ "editor",
3841
+ "package-manager"
3827
3842
  ],
3828
3843
  default: { interactive: defaultInteractive() }
3829
3844
  });
@@ -3837,7 +3852,8 @@ function parseArgs() {
3837
3852
  verbose: parsed.verbose || false,
3838
3853
  agent: parsed.agent,
3839
3854
  editor: parsed.editor,
3840
- hooks: parsed.hooks
3855
+ hooks: parsed.hooks,
3856
+ packageManager: parsed["package-manager"]
3841
3857
  },
3842
3858
  templateArgs
3843
3859
  };
@@ -4039,7 +4055,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4039
4055
  packageName = selected.packageName;
4040
4056
  targetDir = selectedParentDir ? path.join(selectedParentDir, selected.targetDir).split(path.sep).join("/") : selected.targetDir;
4041
4057
  }
4042
- const packageManager = workspaceInfoOptional.packageManager ?? await selectPackageManager(options.interactive, compactOutput);
4058
+ const packageManager = workspaceInfoOptional.packageManager ?? options.packageManager ?? await selectPackageManager(options.interactive, compactOutput);
4043
4059
  const shouldSilencePackageManagerInstallLog = compactOutput || isMonorepo && workspaceInfoOptional.packageManager !== void 0;
4044
4060
  const downloadResult = await downloadPackageManager$1(packageManager, workspaceInfoOptional.packageManagerVersion, options.interactive, shouldSilencePackageManagerInstallLog);
4045
4061
  const workspaceInfo = {
@@ -4150,7 +4166,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4150
4166
  showCreateSummary({
4151
4167
  description: describeScaffold(selectedTemplateName, selectedTemplateArgs),
4152
4168
  installSummary,
4153
- nextCommand: getNextCommand(projectDir, `vp dev ${InitialMonorepoAppDir}`),
4169
+ nextCommand: getNextCommand(projectDir, "vp run"),
4154
4170
  packageManager: workspaceInfo.packageManager,
4155
4171
  packageManagerVersion: workspaceInfo.downloadPackageManager.version,
4156
4172
  projectDir
@@ -4263,7 +4279,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4263
4279
  showCreateSummary({
4264
4280
  description: describeScaffold(selectedTemplateName, selectedTemplateArgs),
4265
4281
  installSummary,
4266
- nextCommand: isMonorepo ? `vp dev ${projectDir}` : getNextCommand(projectDir, selectedTemplateName === BuiltinTemplate.library ? "vp run dev" : "vp dev"),
4282
+ nextCommand: getNextCommand(projectDir, "vp run"),
4267
4283
  packageManager: workspaceInfo.packageManager,
4268
4284
  packageManagerVersion: workspaceInfo.downloadPackageManager.version,
4269
4285
  projectDir
@@ -1,10 +1,10 @@
1
1
  import { r as __toESM } from "./chunk-BoAXSpZd.js";
2
- import { B as select, C as downloadPackageManager$1, D as selectPackageManager, E as runViteInstall, F as confirm, L as log, M as PackageManager, N as require_semver, O as upgradeYarn, S as defaultInteractive, U as Ct, V as spinner, a as writeAgentInstructions, c as detectEslintProject, d as installGitHooks, f as mergeViteConfigFiles, g as rewriteMonorepo, h as preflightGitHooksSetup, k as displayRelative, l as detectPrettierProject, m as migratePrettierToOxfmt, n as detectExistingAgentTargetPaths, o as checkViteVersion, p as migrateEslintToOxlint, r as selectAgentTargetPaths, s as checkVitestVersion, t as detectAgentConflicts, v as rewriteStandaloneProject, w as promptGitHooks, x as cancelAndExit, z as outro } from "./agent-DTz-Dh1r.js";
2
+ import { B as select, C as downloadPackageManager$1, D as selectPackageManager, E as runViteInstall, F as confirm, L as log, M as PackageManager, N as require_semver, O as upgradeYarn, S as defaultInteractive, U as Ct, V as spinner, a as writeAgentInstructions, c as detectEslintProject, d as installGitHooks, f as mergeViteConfigFiles, g as rewriteMonorepo, h as preflightGitHooksSetup, k as displayRelative, l as detectPrettierProject, m as migratePrettierToOxfmt, n as detectExistingAgentTargetPaths, o as checkViteVersion, p as migrateEslintToOxlint, r as selectAgentTargetPaths, s as checkVitestVersion, t as detectAgentConflicts, v as rewriteStandaloneProject, w as promptGitHooks, x as cancelAndExit, z as outro } from "./agent-soFdSW5Z.js";
3
3
  import { t as lib_default } from "./lib-DxappLRQ.js";
4
4
  import { a as readNearestPackageJson, i as hasVitePlusDependency, m as isForceOverrideMode } from "./package-Y1UTfJnZ.js";
5
5
  import { a as muted, i as log$1, n as accent, t as renderCliDoc } from "./help-HviKaKAU.js";
6
6
  import { r as createMigrationReport } from "./report-C7xbSNED.js";
7
- import { i as detectEditorConflicts, o as selectEditor, s as writeEditorConfigs, t as detectWorkspace$1 } from "./workspace-BlrOxcHM.js";
7
+ import { i as detectEditorConflicts, o as selectEditor, s as writeEditorConfigs, t as detectWorkspace$1 } from "./workspace-A1-sHiSV.js";
8
8
  import path from "node:path";
9
9
  import { styleText } from "node:util";
10
10
  import { vitePlusHeader } from "../../binding/index.js";
@@ -426,7 +426,7 @@ async function executeMigrationPlan(workspaceInfoOptional, plan, interactive) {
426
426
  conflictDecisions: plan.editorConflictDecisions,
427
427
  silent: true
428
428
  });
429
- const installArgs = plan.packageManager === PackageManager.npm ? ["--force"] : void 0;
429
+ const installArgs = plan.packageManager === PackageManager.npm || plan.packageManager === PackageManager.bun ? ["--force"] : void 0;
430
430
  updateMigrationProgress("Installing dependencies");
431
431
  const finalInstallSummary = await runViteInstall(workspaceInfo.rootDir, interactive, installArgs, { silent: true });
432
432
  clearMigrationProgress();
@@ -1,4 +1,4 @@
1
- import { B as select, L as log, M as PackageManager, U as Ct, b as readYamlFile, y as editYamlFile } from "./agent-DTz-Dh1r.js";
1
+ import { B as select, L as log, M as PackageManager, U as Ct, b as readYamlFile, y as editYamlFile } from "./agent-soFdSW5Z.js";
2
2
  import { g as YAMLSeq, y as Scalar } from "./browser-09BZLUYM.js";
3
3
  import { c as readJsonFile, l as writeJsonFile, o as editJsonFile, r as getScopeFromPackageName } from "./package-Y1UTfJnZ.js";
4
4
  import path, { posix, win32 } from "node:path";
@@ -498,7 +498,7 @@ export function rewriteStandaloneProject(projectPath, workspaceInfo, skipStagedM
498
498
  ...VITE_PLUS_OVERRIDE_PACKAGES,
499
499
  };
500
500
  }
501
- else if (packageManager === PackageManager.npm) {
501
+ else if (packageManager === PackageManager.npm || packageManager === PackageManager.bun) {
502
502
  pkg.overrides = {
503
503
  ...pkg.overrides,
504
504
  ...VITE_PLUS_OVERRIDE_PACKAGES,
@@ -559,6 +559,9 @@ export function rewriteMonorepo(workspaceInfo, skipStagedMigration, silent = fal
559
559
  else if (workspaceInfo.packageManager === PackageManager.yarn) {
560
560
  rewriteYarnrcYml(workspaceInfo.rootDir);
561
561
  }
562
+ else if (workspaceInfo.packageManager === PackageManager.bun) {
563
+ rewriteBunCatalog(workspaceInfo.rootDir);
564
+ }
562
565
  rewriteRootWorkspacePackageJson(workspaceInfo.rootDir, workspaceInfo.packageManager, skipStagedMigration);
563
566
  // rewrite packages
564
567
  for (const pkg of workspaceInfo.packages) {
@@ -716,6 +719,42 @@ function rewriteCatalog(doc) {
716
719
  }
717
720
  // TODO: rewrite `catalogs` when OVERRIDE_PACKAGES exists in catalog
718
721
  }
722
+ /**
723
+ * Write catalog entries to root package.json for bun.
724
+ * Bun stores catalogs in package.json under the `catalog` key,
725
+ * unlike pnpm which uses pnpm-workspace.yaml.
726
+ * @see https://bun.sh/docs/pm/catalogs
727
+ */
728
+ function rewriteBunCatalog(projectPath) {
729
+ const packageJsonPath = path.join(projectPath, 'package.json');
730
+ if (!fs.existsSync(packageJsonPath)) {
731
+ return;
732
+ }
733
+ editJsonFile(packageJsonPath, (pkg) => {
734
+ const catalog = { ...pkg.catalog };
735
+ // Add vite-plus managed packages to catalog
736
+ for (const [key, value] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) {
737
+ if (!value.startsWith('file:')) {
738
+ catalog[key] = value;
739
+ }
740
+ }
741
+ if (!VITE_PLUS_VERSION.startsWith('file:')) {
742
+ catalog[VITE_PLUS_NAME] = VITE_PLUS_VERSION;
743
+ }
744
+ // Remove replaced packages from catalog
745
+ for (const name of REMOVE_PACKAGES) {
746
+ delete catalog[name];
747
+ }
748
+ pkg.catalog = catalog;
749
+ // bun overrides support catalog: references
750
+ const overrides = { ...pkg.overrides };
751
+ for (const key of Object.keys(VITE_PLUS_OVERRIDE_PACKAGES)) {
752
+ overrides[key] = 'catalog:';
753
+ }
754
+ pkg.overrides = overrides;
755
+ return pkg;
756
+ });
757
+ }
719
758
  /**
720
759
  * Rewrite root workspace package.json to add vite-plus dependencies
721
760
  * @param projectPath - The path to the project
@@ -740,6 +779,9 @@ function rewriteRootWorkspacePackageJson(projectPath, packageManager, skipStaged
740
779
  ...VITE_PLUS_OVERRIDE_PACKAGES,
741
780
  };
742
781
  }
782
+ else if (packageManager === PackageManager.bun) {
783
+ // bun overrides are handled in rewriteBunCatalog() with catalog: references
784
+ }
743
785
  else if (packageManager === PackageManager.pnpm) {
744
786
  if (isForceOverrideMode()) {
745
787
  // In force-override mode, keep overrides in package.json pnpm.overrides
@@ -1149,15 +1191,30 @@ function rewriteAllImports(projectPath, silent = false, report) {
1149
1191
  /**
1150
1192
  * Check if the project has an unsupported husky version (<9.0.0).
1151
1193
  * Uses `semver.coerce` to handle ranges like `^8.0.0` → `8.0.0`.
1152
- * Accepts pre-loaded deps to avoid re-reading package.json when called
1153
- * from contexts that already parsed it.
1194
+ * When the specifier is not coercible (e.g. `"latest"`), falls back to
1195
+ * the installed version in node_modules via `detectPackageMetadata`.
1196
+ * Returns a reason string if hooks migration should be skipped, or null
1197
+ * if husky is absent or compatible.
1154
1198
  */
1155
- function checkUnsupportedHuskyVersion(deps, prodDeps) {
1199
+ function checkUnsupportedHuskyVersion(projectPath, deps, prodDeps) {
1156
1200
  const huskyVersion = deps?.husky ?? prodDeps?.husky;
1157
1201
  if (!huskyVersion) {
1158
- return false;
1202
+ return null;
1159
1203
  }
1160
- return semver.satisfies(semver.coerce(huskyVersion) ?? '0.0.0', '<9.0.0');
1204
+ let coerced = semver.coerce(huskyVersion);
1205
+ if (coerced == null) {
1206
+ const installed = detectPackageMetadata(projectPath, 'husky');
1207
+ if (installed) {
1208
+ coerced = semver.coerce(installed.version);
1209
+ }
1210
+ if (coerced == null) {
1211
+ return `Could not determine husky version from "${huskyVersion}" — please specify a semver-compatible version (e.g., "^9.0.0") and re-run migration.`;
1212
+ }
1213
+ }
1214
+ if (semver.satisfies(coerced, '<9.0.0')) {
1215
+ return 'Detected husky <9.0.0 — please upgrade to husky v9+ first, then re-run migration.';
1216
+ }
1217
+ return null;
1161
1218
  }
1162
1219
  const OTHER_HOOK_TOOLS = ['simple-git-hooks', 'lefthook', 'yorkie'];
1163
1220
  // Packages replaced by vite-plus built-in commands and should be removed from devDependencies
@@ -1256,8 +1313,9 @@ export function preflightGitHooksSetup(projectPath) {
1256
1313
  return `Detected ${tool} — skipping git hooks setup. Please configure git hooks manually.`;
1257
1314
  }
1258
1315
  }
1259
- if (checkUnsupportedHuskyVersion(deps, prodDeps)) {
1260
- return 'Detected husky <9.0.0 — please upgrade to husky v9+ first, then re-run migration.';
1316
+ const huskyReason = checkUnsupportedHuskyVersion(projectPath, deps, prodDeps);
1317
+ if (huskyReason) {
1318
+ return huskyReason;
1261
1319
  }
1262
1320
  if (hasUnsupportedLintStagedConfig(projectPath)) {
1263
1321
  return 'Unsupported lint-staged config format — skipping git hooks setup. Please configure git hooks manually.';
@@ -6,7 +6,7 @@ export interface CommandRunSummary {
6
6
  status: 'installed' | 'formatted' | 'failed' | 'skipped';
7
7
  }
8
8
  export declare function cancelAndExit(message?: string, exitCode?: number): never;
9
- export declare function selectPackageManager(interactive?: boolean, silent?: boolean): Promise<"pnpm" | "npm" | "yarn">;
9
+ export declare function selectPackageManager(interactive?: boolean, silent?: boolean): Promise<"pnpm" | "npm" | "yarn" | "bun">;
10
10
  export declare function downloadPackageManager(packageManager: PackageManager, version: string, interactive?: boolean, silent?: boolean): Promise<import("../../binding/index.cjs").DownloadPackageManagerResult>;
11
11
  export declare function runViteInstall(cwd: string, interactive?: boolean, extraArgs?: string[], options?: {
12
12
  silent?: boolean;
@@ -15,6 +15,7 @@ export async function selectPackageManager(interactive, silent = false) {
15
15
  { value: PackageManager.pnpm, hint: 'recommended' },
16
16
  { value: PackageManager.yarn },
17
17
  { value: PackageManager.npm },
18
+ { value: PackageManager.bun },
18
19
  ],
19
20
  initialValue: PackageManager.pnpm,
20
21
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plus",
3
- "version": "0.1.14-alpha.3",
3
+ "version": "0.1.15-alpha.0",
4
4
  "description": "The Unified Toolchain for the Web",
5
5
  "homepage": "https://viteplus.dev/guide",
6
6
  "bugs": {
@@ -317,8 +317,8 @@
317
317
  "oxlint": "=1.57.0",
318
318
  "oxlint-tsgolint": "=0.17.3",
319
319
  "picocolors": "^1.1.1",
320
- "@voidzero-dev/vite-plus-core": "0.1.14-alpha.3",
321
- "@voidzero-dev/vite-plus-test": "0.1.14-alpha.3"
320
+ "@voidzero-dev/vite-plus-core": "0.1.15-alpha.0",
321
+ "@voidzero-dev/vite-plus-test": "0.1.15-alpha.0"
322
322
  },
323
323
  "devDependencies": {
324
324
  "@napi-rs/cli": "^3.4.1",
@@ -341,8 +341,8 @@
341
341
  "validate-npm-package-name": "^7.0.2",
342
342
  "yaml": "^2.8.1",
343
343
  "@voidzero-dev/vite-plus-prompts": "0.0.0",
344
- "rolldown": "1.0.0-rc.11",
345
- "vite": "npm:@voidzero-dev/vite-plus-core@0.1.14-alpha.3"
344
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.1.15-alpha.0",
345
+ "rolldown": "1.0.0-rc.11"
346
346
  },
347
347
  "napi": {
348
348
  "binaryName": "vite-plus",
@@ -362,14 +362,14 @@
362
362
  "node": "^20.19.0 || >=22.12.0"
363
363
  },
364
364
  "optionalDependencies": {
365
- "@voidzero-dev/vite-plus-darwin-arm64": "0.1.14-alpha.3",
366
- "@voidzero-dev/vite-plus-darwin-x64": "0.1.14-alpha.3",
367
- "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.1.14-alpha.3",
368
- "@voidzero-dev/vite-plus-linux-arm64-musl": "0.1.14-alpha.3",
369
- "@voidzero-dev/vite-plus-linux-x64-gnu": "0.1.14-alpha.3",
370
- "@voidzero-dev/vite-plus-linux-x64-musl": "0.1.14-alpha.3",
371
- "@voidzero-dev/vite-plus-win32-x64-msvc": "0.1.14-alpha.3",
372
- "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.1.14-alpha.3"
365
+ "@voidzero-dev/vite-plus-darwin-arm64": "0.1.15-alpha.0",
366
+ "@voidzero-dev/vite-plus-darwin-x64": "0.1.15-alpha.0",
367
+ "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.1.15-alpha.0",
368
+ "@voidzero-dev/vite-plus-linux-arm64-musl": "0.1.15-alpha.0",
369
+ "@voidzero-dev/vite-plus-linux-x64-gnu": "0.1.15-alpha.0",
370
+ "@voidzero-dev/vite-plus-linux-x64-musl": "0.1.15-alpha.0",
371
+ "@voidzero-dev/vite-plus-win32-x64-msvc": "0.1.15-alpha.0",
372
+ "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.1.15-alpha.0"
373
373
  },
374
374
  "scripts": {
375
375
  "build": "oxnode -C dev ./build.ts",