vite-plus 0.1.3 → 0.1.4

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.
@@ -1,14 +1,14 @@
1
1
  import { i as __toESM, t as __commonJSMin } from "./chunk-CgnkrU7a.js";
2
- import { A as select, C as cancel, D as multiselect, E as log, M as Ct, S as PackageManager, T as intro, a as selectAgentTargetPaths, c as defaultInteractive, d as promptGitHooks, f as runViteFmt, g as displayRelative, j as text, l as downloadPackageManager$1, m as selectPackageManager, o as writeAgentInstructions, p as runViteInstall, r as detectExistingAgentTargetPaths, w as confirm, x as DependencyType, y as templatesDir } from "./agent-BE4Xze8Q.js";
2
+ import { A as select, C as cancel, D as multiselect, E as log, M as text, N as Ct, S as PackageManager, T as intro, a as selectAgentTargetPaths, c as defaultInteractive, d as promptGitHooks, f as runViteFmt, g as displayRelative, j as spinner, l as downloadPackageManager$1, m as selectPackageManager, o as writeAgentInstructions, p as runViteInstall, r as detectExistingAgentTargetPaths, w as confirm, x as DependencyType, y as templatesDir } from "./agent-CpNB3GIY.js";
3
3
  import { t as lib_default } from "./lib-DxappLRQ.js";
4
- import { b as rewriteStandaloneProject, c as writeEditorConfigs, n as updatePackageJsonWithDeps, o as detectExistingEditor, p as installGitHooks, r as updateWorkspaceConfig, s as selectEditor, t as detectWorkspace$1, v as rewriteMonorepo, y as rewriteMonorepoProject } from "./workspace-lRm8huz4.js";
4
+ import { _ as rewriteMonorepo, a as detectExistingEditor, f as installGitHooks, n as updatePackageJsonWithDeps, o as selectEditor, r as updateWorkspaceConfig, s as writeEditorConfigs, t as detectWorkspace$1, v as rewriteMonorepoProject, y as rewriteStandaloneProject } from "./workspace-CiqQdO1L.js";
5
5
  import "./browser-CBapUTD0.js";
6
6
  import { r as readJsonFile, t as editJsonFile } from "./json-BRdVJ52a.js";
7
7
  import "./package-YAMvX5PJ.js";
8
8
  import { a as success, i as muted, n as accent, r as log$1, t as renderCliDoc } from "./help-BAGHa8fD.js";
9
9
  import path from "node:path";
10
10
  import { styleText } from "node:util";
11
- import colors from "picocolors";
11
+ import color from "picocolors";
12
12
  import fs from "node:fs";
13
13
  import { runCommand, vitePlusHeader } from "../../binding/index.js";
14
14
  import spawn from "cross-spawn";
@@ -148,6 +148,11 @@ function parseGitHubUrl(url) {
148
148
  if (match) return match[1].replace(/\.git$/, "");
149
149
  return null;
150
150
  }
151
+ function inferGitHubRepoName(templateName) {
152
+ const degitPath = parseGitHubUrl(templateName);
153
+ if (!degitPath) return null;
154
+ return degitPath.split("/").pop() || null;
155
+ }
151
156
  function discoverTemplate(templateName, templateArgs, workspaceInfo, interactive) {
152
157
  const envs = prependToPathToEnvs(workspaceInfo.downloadPackageManager.binPrefix, { ...process.env });
153
158
  const parentDir = inferParentDir(templateName, workspaceInfo);
@@ -163,11 +168,7 @@ function discoverTemplate(templateName, templateArgs, workspaceInfo, interactive
163
168
  const degitPath = parseGitHubUrl(templateName);
164
169
  if (degitPath) return {
165
170
  command: "degit",
166
- args: [
167
- degitPath,
168
- templateName,
169
- ...templateArgs
170
- ],
171
+ args: [degitPath, ...templateArgs],
171
172
  envs,
172
173
  type: TemplateType.remote,
173
174
  parentDir,
@@ -330,7 +331,7 @@ var require_builtin_modules = /* @__PURE__ */ __commonJSMin(((exports, module) =
330
331
  ];
331
332
  }));
332
333
  //#endregion
333
- //#region src/create/utils.ts
334
+ //#region ../../node_modules/.pnpm/@nkzw+safe-word-list@3.1.0/node_modules/@nkzw/safe-word-list/index.js
334
335
  var import_lib = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
335
336
  const builtins = require_builtin_modules();
336
337
  var scopedPackagePattern = /* @__PURE__ */ new RegExp("^(?:@([^/]+?)[/])?([^/]+?)$");
@@ -387,159 +388,6 @@ var import_lib = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((export
387
388
  };
388
389
  module.exports = validate;
389
390
  })))(), 1);
390
- function copy(src, dest) {
391
- if (fs.statSync(src).isDirectory()) copyDir(src, dest);
392
- else fs.copyFileSync(src, dest);
393
- }
394
- function copyDir(srcDir, destDir) {
395
- fs.mkdirSync(destDir, { recursive: true });
396
- for (const file of fs.readdirSync(srcDir)) copy(path.resolve(srcDir, file), path.resolve(destDir, file));
397
- }
398
- /**
399
- * Format the target directory into a valid directory name and package name
400
- *
401
- * Examples:
402
- * ```
403
- * # invalid target directories
404
- * ./ -> { directory: '', packageName: '', error: 'Invalid target directory' }
405
- * /foo/bar -> { directory: '', packageName: '', error: 'Absolute path is not allowed' }
406
- * @scope/ -> { directory: '', packageName: '', error: 'Invalid target directory' }
407
- * ../../foo/bar -> { directory: '', packageName: '', error: 'Invalid target directory' }
408
- *
409
- * # valid target directories
410
- * ./my-package -> { directory: './my-package', packageName: 'my-package' }
411
- * ./foo/bar-package -> { directory: './foo/bar-package', packageName: 'bar-package' }
412
- * ./foo/bar-package/ -> { directory: './foo/bar-package', packageName: 'bar-package' }
413
- * my-package -> { directory: 'my-package', packageName: 'my-package' }
414
- * @my-scope/my-package -> { directory: 'my-package', packageName: '@my-scope/my-package' }
415
- * foo/@my-scope/my-package -> { directory: 'foo/my-package', packageName: '@scope/my-package' }
416
- * ./foo/@my-scope/my-package -> { directory: './foo/my-package', packageName: '@scope/my-package' }
417
- * ./foo/bar/@scope/my-package -> { directory: './foo/bar/my-package', packageName: '@scope/my-package' }
418
- * ```
419
- */
420
- function formatTargetDir(input) {
421
- let targetDir = path.normalize(input.trim());
422
- const parsed = path.parse(targetDir);
423
- if (parsed.root || path.isAbsolute(targetDir)) return {
424
- directory: "",
425
- packageName: "",
426
- error: "Absolute path is not allowed"
427
- };
428
- if (targetDir.includes("..")) return {
429
- directory: "",
430
- packageName: "",
431
- error: "Relative path contains \"..\" which is not allowed"
432
- };
433
- let packageName = parsed.base;
434
- const parentName = path.basename(parsed.dir);
435
- if (parentName.startsWith("@")) {
436
- targetDir = path.join(path.dirname(parsed.dir), packageName);
437
- packageName = `${parentName}/${packageName}`;
438
- }
439
- const result = (0, import_lib.default)(packageName);
440
- if (!result.validForNewPackages) {
441
- const message = result.errors?.[0] ?? result.warnings?.[0] ?? "Invalid package name";
442
- return {
443
- directory: "",
444
- packageName: "",
445
- error: `Parsed package name "${packageName}" is invalid: ${message}`
446
- };
447
- }
448
- return {
449
- directory: targetDir,
450
- packageName
451
- };
452
- }
453
- function getProjectDirFromPackageName(packageName) {
454
- if (packageName.startsWith("@")) return packageName.split("/")[1];
455
- return packageName;
456
- }
457
- function setPackageName(projectDir, packageName) {
458
- editJsonFile(path.join(projectDir, "package.json"), (pkg) => {
459
- pkg.name = packageName;
460
- return pkg;
461
- });
462
- }
463
- function formatDisplayTargetDir(targetDir) {
464
- const normalized = targetDir.split(path.sep).join("/");
465
- if (normalized === "" || normalized === ".") return "./";
466
- if (normalized.startsWith("./") || normalized.startsWith("../") || normalized.startsWith("/") || normalized.startsWith("~")) return normalized;
467
- return `./${normalized}`;
468
- }
469
- //#endregion
470
- //#region src/create/prompts.ts
471
- async function promptPackageNameAndTargetDir(defaultPackageName, interactive) {
472
- let packageName;
473
- let targetDir;
474
- if (interactive) {
475
- const selected = await text({
476
- message: "Package name:",
477
- placeholder: defaultPackageName,
478
- defaultValue: defaultPackageName,
479
- validate: (value) => {
480
- if (value == null || value.length === 0) return;
481
- const result = value ? (0, import_lib.default)(value) : null;
482
- if (result?.validForNewPackages) return;
483
- return result?.errors?.[0] ?? result?.warnings?.[0] ?? "Invalid package name";
484
- }
485
- });
486
- if (Ct(selected)) cancelAndExit();
487
- packageName = selected;
488
- targetDir = getProjectDirFromPackageName(packageName);
489
- } else {
490
- packageName = defaultPackageName;
491
- targetDir = getProjectDirFromPackageName(packageName);
492
- log.info(`Using default package name: ${accent(packageName)}`);
493
- }
494
- return {
495
- packageName,
496
- targetDir
497
- };
498
- }
499
- async function checkProjectDirExists(projectDirFullPath, interactive) {
500
- if (!fs.existsSync(projectDirFullPath) || isEmpty(projectDirFullPath)) return;
501
- if (!interactive) {
502
- log.info("Use --directory to specify a different location or remove the directory first");
503
- cancelAndExit(`Target directory "${projectDirFullPath}" is not empty`, 1);
504
- }
505
- const overwrite = await select({
506
- message: `Target directory "${projectDirFullPath}" is not empty. Please choose how to proceed:`,
507
- options: [{
508
- label: "Cancel operation",
509
- value: "no"
510
- }, {
511
- label: "Remove existing files and continue",
512
- value: "yes"
513
- }]
514
- });
515
- if (Ct(overwrite)) cancelAndExit();
516
- switch (overwrite) {
517
- case "yes":
518
- emptyDir(projectDirFullPath);
519
- break;
520
- case "no": cancelAndExit();
521
- }
522
- }
523
- function cancelAndExit(message = "Operation cancelled", exitCode = 0) {
524
- cancel(message);
525
- process.exit(exitCode);
526
- }
527
- function isEmpty(path) {
528
- const files = fs.readdirSync(path);
529
- return files.length === 0 || files.length === 1 && files[0] === ".git";
530
- }
531
- function emptyDir(dir) {
532
- if (!fs.existsSync(dir)) return;
533
- for (const file of fs.readdirSync(dir)) {
534
- if (file === ".git") continue;
535
- fs.rmSync(path.resolve(dir, file), {
536
- recursive: true,
537
- force: true
538
- });
539
- }
540
- }
541
- //#endregion
542
- //#region ../../node_modules/.pnpm/@nkzw+safe-word-list@3.1.0/node_modules/@nkzw/safe-word-list/index.js
543
391
  const words = [
544
392
  "ability",
545
393
  "able",
@@ -3291,6 +3139,213 @@ function getRandomProjectName(options = {}) {
3291
3139
  return scope ? `${scope}/${projectName}` : projectName;
3292
3140
  }
3293
3141
  //#endregion
3142
+ //#region src/create/utils.ts
3143
+ function copy(src, dest) {
3144
+ if (fs.statSync(src).isDirectory()) copyDir(src, dest);
3145
+ else fs.copyFileSync(src, dest);
3146
+ }
3147
+ function copyDir(srcDir, destDir) {
3148
+ fs.mkdirSync(destDir, { recursive: true });
3149
+ for (const file of fs.readdirSync(srcDir)) copy(path.resolve(srcDir, file), path.resolve(destDir, file));
3150
+ }
3151
+ /**
3152
+ * Format the target directory into a valid directory name and package name
3153
+ *
3154
+ * Examples:
3155
+ * ```
3156
+ * # invalid target directories
3157
+ * ./ -> { directory: '', packageName: '', error: 'Invalid target directory' }
3158
+ * /foo/bar -> { directory: '', packageName: '', error: 'Absolute path is not allowed' }
3159
+ * @scope/ -> { directory: '', packageName: '', error: 'Invalid target directory' }
3160
+ * ../../foo/bar -> { directory: '', packageName: '', error: 'Invalid target directory' }
3161
+ *
3162
+ * # valid target directories
3163
+ * ./my-package -> { directory: './my-package', packageName: 'my-package' }
3164
+ * ./foo/bar-package -> { directory: './foo/bar-package', packageName: 'bar-package' }
3165
+ * ./foo/bar-package/ -> { directory: './foo/bar-package', packageName: 'bar-package' }
3166
+ * my-package -> { directory: 'my-package', packageName: 'my-package' }
3167
+ * @my-scope/my-package -> { directory: 'my-package', packageName: '@my-scope/my-package' }
3168
+ * foo/@my-scope/my-package -> { directory: 'foo/my-package', packageName: '@scope/my-package' }
3169
+ * ./foo/@my-scope/my-package -> { directory: './foo/my-package', packageName: '@scope/my-package' }
3170
+ * ./foo/bar/@scope/my-package -> { directory: './foo/bar/my-package', packageName: '@scope/my-package' }
3171
+ * ```
3172
+ */
3173
+ function formatTargetDir(input) {
3174
+ let targetDir = path.normalize(input.trim());
3175
+ const parsed = path.parse(targetDir);
3176
+ if (parsed.root || path.isAbsolute(targetDir)) return {
3177
+ directory: "",
3178
+ packageName: "",
3179
+ error: "Absolute path is not allowed"
3180
+ };
3181
+ if (targetDir.includes("..")) return {
3182
+ directory: "",
3183
+ packageName: "",
3184
+ error: "Relative path contains \"..\" which is not allowed"
3185
+ };
3186
+ let packageName = parsed.base;
3187
+ const parentName = path.basename(parsed.dir);
3188
+ if (parentName.startsWith("@")) {
3189
+ targetDir = path.join(path.dirname(parsed.dir), packageName);
3190
+ packageName = `${parentName}/${packageName}`;
3191
+ }
3192
+ const result = (0, import_lib.default)(packageName);
3193
+ if (!result.validForNewPackages) {
3194
+ const message = result.errors?.[0] ?? result.warnings?.[0] ?? "Invalid package name";
3195
+ return {
3196
+ directory: "",
3197
+ packageName: "",
3198
+ error: `Parsed package name "${packageName}" is invalid: ${message}`
3199
+ };
3200
+ }
3201
+ return {
3202
+ directory: targetDir,
3203
+ packageName
3204
+ };
3205
+ }
3206
+ function getProjectDirFromPackageName(packageName) {
3207
+ if (packageName.startsWith("@")) return packageName.split("/")[1];
3208
+ return packageName;
3209
+ }
3210
+ function setPackageName(projectDir, packageName) {
3211
+ editJsonFile(path.join(projectDir, "package.json"), (pkg) => {
3212
+ pkg.name = packageName;
3213
+ return pkg;
3214
+ });
3215
+ }
3216
+ function formatDisplayTargetDir(targetDir) {
3217
+ const normalized = targetDir.split(path.sep).join("/");
3218
+ if (normalized === "" || normalized === ".") return "./";
3219
+ if (normalized.startsWith("./") || normalized.startsWith("../") || normalized.startsWith("/") || normalized.startsWith("~")) return normalized;
3220
+ return `./${normalized}`;
3221
+ }
3222
+ //#endregion
3223
+ //#region src/create/prompts.ts
3224
+ async function promptPackageNameAndTargetDir(defaultPackageName, interactive) {
3225
+ let packageName;
3226
+ let targetDir;
3227
+ if (interactive) {
3228
+ const selected = await text({
3229
+ message: "Package name:",
3230
+ placeholder: defaultPackageName,
3231
+ defaultValue: defaultPackageName,
3232
+ validate: (value) => {
3233
+ if (value == null || value.length === 0) return;
3234
+ const result = value ? (0, import_lib.default)(value) : null;
3235
+ if (result?.validForNewPackages) return;
3236
+ return result?.errors?.[0] ?? result?.warnings?.[0] ?? "Invalid package name";
3237
+ }
3238
+ });
3239
+ if (Ct(selected)) cancelAndExit();
3240
+ packageName = selected;
3241
+ targetDir = getProjectDirFromPackageName(packageName);
3242
+ } else {
3243
+ packageName = defaultPackageName;
3244
+ targetDir = getProjectDirFromPackageName(packageName);
3245
+ log.info(`Using default package name: ${accent(packageName)}`);
3246
+ }
3247
+ return {
3248
+ packageName,
3249
+ targetDir
3250
+ };
3251
+ }
3252
+ async function promptTargetDir(defaultTargetDir, interactive, options) {
3253
+ let targetDir;
3254
+ if (interactive) {
3255
+ const selected = await text({
3256
+ message: "Target directory:",
3257
+ placeholder: defaultTargetDir,
3258
+ defaultValue: defaultTargetDir,
3259
+ validate: (value) => validateTargetDir(value ?? defaultTargetDir, options?.cwd).error
3260
+ });
3261
+ if (Ct(selected)) cancelAndExit();
3262
+ targetDir = validateTargetDir(selected ?? defaultTargetDir, options?.cwd).directory;
3263
+ } else {
3264
+ targetDir = validateTargetDir(defaultTargetDir, options?.cwd).directory;
3265
+ log.info(`Using default target directory: ${accent(targetDir)}`);
3266
+ }
3267
+ return targetDir;
3268
+ }
3269
+ function suggestAvailableTargetDir(defaultTargetDir, cwd) {
3270
+ let suggestedTargetDir = defaultTargetDir;
3271
+ let attempt = 1;
3272
+ while (!isTargetDirAvailable(path.join(cwd, suggestedTargetDir))) {
3273
+ suggestedTargetDir = getRandomProjectName({ fallbackName: `${defaultTargetDir}-${attempt}` });
3274
+ attempt++;
3275
+ }
3276
+ return suggestedTargetDir;
3277
+ }
3278
+ async function checkProjectDirExists(projectDirFullPath, interactive) {
3279
+ if (isTargetDirAvailable(projectDirFullPath)) return;
3280
+ if (!interactive) {
3281
+ log.info("Use --directory to specify a different location or remove the directory first");
3282
+ cancelAndExit(`Target directory "${projectDirFullPath}" is not empty`, 1);
3283
+ }
3284
+ const overwrite = await select({
3285
+ message: `Target directory "${projectDirFullPath}" is not empty. Please choose how to proceed:`,
3286
+ options: [{
3287
+ label: "Cancel operation",
3288
+ value: "no"
3289
+ }, {
3290
+ label: "Remove existing files and continue",
3291
+ value: "yes"
3292
+ }]
3293
+ });
3294
+ if (Ct(overwrite)) cancelAndExit();
3295
+ switch (overwrite) {
3296
+ case "yes":
3297
+ emptyDir(projectDirFullPath);
3298
+ break;
3299
+ case "no": cancelAndExit();
3300
+ }
3301
+ }
3302
+ function cancelAndExit(message = "Operation cancelled", exitCode = 0) {
3303
+ cancel(message);
3304
+ process.exit(exitCode);
3305
+ }
3306
+ function isEmpty(path) {
3307
+ const files = fs.readdirSync(path);
3308
+ return files.length === 0 || files.length === 1 && files[0] === ".git";
3309
+ }
3310
+ function emptyDir(dir) {
3311
+ if (!fs.existsSync(dir)) return;
3312
+ for (const file of fs.readdirSync(dir)) {
3313
+ if (file === ".git") continue;
3314
+ fs.rmSync(path.resolve(dir, file), {
3315
+ recursive: true,
3316
+ force: true
3317
+ });
3318
+ }
3319
+ }
3320
+ function isTargetDirAvailable(projectDirFullPath) {
3321
+ return !fs.existsSync(projectDirFullPath) || isEmpty(projectDirFullPath);
3322
+ }
3323
+ function validateTargetDir(input, cwd) {
3324
+ const value = input?.trim() ?? "";
3325
+ if (!value) return {
3326
+ directory: "",
3327
+ error: "Target directory is required"
3328
+ };
3329
+ const targetDir = path.normalize(value);
3330
+ if (!targetDir || targetDir === ".") return {
3331
+ directory: "",
3332
+ error: "Target directory is required"
3333
+ };
3334
+ if (path.isAbsolute(targetDir)) return {
3335
+ directory: "",
3336
+ error: "Absolute path is not allowed"
3337
+ };
3338
+ if (targetDir.includes("..")) return {
3339
+ directory: "",
3340
+ error: "Relative path contains \"..\" which is not allowed"
3341
+ };
3342
+ if (cwd && !isTargetDirAvailable(path.join(cwd, targetDir))) return {
3343
+ directory: "",
3344
+ error: `Target directory "${targetDir}" already exists`
3345
+ };
3346
+ return { directory: targetDir };
3347
+ }
3348
+ //#endregion
3294
3349
  //#region src/create/templates/generator.ts
3295
3350
  async function executeGeneratorScaffold(workspaceInfo, templateInfo, options) {
3296
3351
  if (!options?.silent) log.step("Creating generator scaffold...");
@@ -3320,7 +3375,7 @@ async function executeGeneratorScaffold(workspaceInfo, templateInfo, options) {
3320
3375
  }
3321
3376
  //#endregion
3322
3377
  //#region src/create/templates/remote.ts
3323
- const { gray, yellow } = colors;
3378
+ const { gray, yellow } = color;
3324
3379
  async function executeRemoteTemplate(workspaceInfo, templateInfo, options) {
3325
3380
  const silent = options?.silent ?? false;
3326
3381
  if (!silent) log.step("Generating project…");
@@ -3403,8 +3458,8 @@ async function executeBuiltinTemplate(workspaceInfo, templateInfo, options) {
3403
3458
  if (!templateInfo.interactive) templateInfo.args.push("--no-interactive");
3404
3459
  } else if (templateInfo.command === BuiltinTemplate.library) {
3405
3460
  templateInfo.command = "create-tsdown@latest";
3406
- if (!templateInfo.interactive) {
3407
- if (!templateInfo.args.find((arg) => arg.startsWith("--template") || arg.startsWith("-t"))) templateInfo.args.push("--template", "default");
3461
+ if (!templateInfo.interactive || options?.silent) {
3462
+ if (!templateInfo.args.some((arg) => arg.startsWith("--template") || arg.startsWith("-t"))) templateInfo.args.push("--template", "default");
3408
3463
  }
3409
3464
  }
3410
3465
  templateInfo.args.unshift(templateInfo.targetDir);
@@ -3745,6 +3800,9 @@ function getTemplateOption(args) {
3745
3800
  if (arg.startsWith("--template=")) return arg.slice(11);
3746
3801
  }
3747
3802
  }
3803
+ function hasExplicitTargetDir(args) {
3804
+ return args[0] !== void 0 && !args[0].startsWith("-");
3805
+ }
3748
3806
  function formatTemplateName(templateName) {
3749
3807
  const templateAliases = {
3750
3808
  lit: "Lit",
@@ -3828,6 +3886,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
3828
3886
  let selectedAgentTargetPaths;
3829
3887
  let selectedEditor;
3830
3888
  let selectedParentDir;
3889
+ let remoteTargetDir;
3831
3890
  let shouldSetupHooks = false;
3832
3891
  if (!selectedTemplateName) {
3833
3892
  const templates = [];
@@ -3936,6 +3995,15 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
3936
3995
  if (isInSubdirectory && !compactOutput) log.info(`Use ${accent("--directory")} to specify a different target location.`);
3937
3996
  selectedParentDir = inferParentDir(selectedTemplateName, workspaceInfoOptional) ?? workspaceInfoOptional.parentDirs[0];
3938
3997
  }
3998
+ if (isGitHubUrl(selectedTemplateName)) if (hasExplicitTargetDir(selectedTemplateArgs)) remoteTargetDir = selectedTemplateArgs[0];
3999
+ else {
4000
+ const inferredTargetDir = inferGitHubRepoName(selectedTemplateName) ?? "template";
4001
+ const remoteTargetBaseDir = selectedParentDir ? path.join(workspaceInfoOptional.rootDir, selectedParentDir) : workspaceInfoOptional.rootDir;
4002
+ const defaultTargetDir = suggestAvailableTargetDir(inferredTargetDir, remoteTargetBaseDir);
4003
+ if (defaultTargetDir !== inferredTargetDir && options.interactive) log.info(` Target directory "${inferredTargetDir}" already exists. Suggested: ${accent(defaultTargetDir)}`);
4004
+ remoteTargetDir = await promptTargetDir(defaultTargetDir, options.interactive, { cwd: remoteTargetBaseDir });
4005
+ selectedTemplateArgs = [remoteTargetDir, ...selectedTemplateArgs];
4006
+ }
3939
4007
  if (isBuiltinTemplate && !targetDir) if (selectedTemplateName === BuiltinTemplate.monorepo) {
3940
4008
  const selected = await promptPackageNameAndTargetDir(getRandomProjectName({ fallbackName: "vite-plus-monorepo" }), options.interactive);
3941
4009
  packageName = selected.packageName;
@@ -3968,10 +4036,55 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
3968
4036
  onCancel: () => cancelAndExit()
3969
4037
  });
3970
4038
  shouldSetupHooks = await promptGitHooks(options);
4039
+ const createProgress = options.interactive && compactOutput ? spinner({ indicator: "timer" }) : void 0;
4040
+ let createProgressStarted = false;
4041
+ let createProgressMessage = "Scaffolding project";
4042
+ const updateCreateProgress = (message) => {
4043
+ createProgressMessage = message;
4044
+ if (!createProgress) return;
4045
+ if (createProgressStarted) {
4046
+ createProgress.message(message);
4047
+ return;
4048
+ }
4049
+ createProgress.start(message);
4050
+ createProgressStarted = true;
4051
+ };
4052
+ const clearCreateProgress = () => {
4053
+ if (createProgress && createProgressStarted) {
4054
+ createProgress.clear();
4055
+ createProgressStarted = false;
4056
+ }
4057
+ };
4058
+ const failCreateProgress = (message) => {
4059
+ if (createProgress && createProgressStarted) {
4060
+ createProgress.error(message);
4061
+ createProgressStarted = false;
4062
+ }
4063
+ };
4064
+ const pauseCreateProgress = () => {
4065
+ if (createProgress && createProgressStarted) {
4066
+ createProgress.pause();
4067
+ createProgressStarted = false;
4068
+ }
4069
+ };
4070
+ const resumeCreateProgress = () => {
4071
+ if (createProgress && !createProgressStarted) {
4072
+ createProgress.resume(createProgressMessage);
4073
+ createProgressStarted = true;
4074
+ }
4075
+ };
4076
+ updateCreateProgress("Scaffolding project");
3971
4077
  const templateInfo = discoverTemplate(selectedTemplateName, selectedTemplateArgs, workspaceInfo, options.interactive);
3972
4078
  if (selectedParentDir) templateInfo.parentDir = selectedParentDir;
3973
4079
  if (targetDir) templateInfo.parentDir = void 0;
4080
+ if (remoteTargetDir) {
4081
+ const projectDir = templateInfo.parentDir ? path.join(templateInfo.parentDir, remoteTargetDir) : remoteTargetDir;
4082
+ pauseCreateProgress();
4083
+ await checkProjectDirExists(path.join(workspaceInfo.rootDir, projectDir), options.interactive);
4084
+ resumeCreateProgress();
4085
+ }
3974
4086
  if (templateInfo.command === BuiltinTemplate.monorepo) {
4087
+ updateCreateProgress("Creating monorepo");
3975
4088
  await checkProjectDirExists(path.join(workspaceInfo.rootDir, targetDir), options.interactive);
3976
4089
  const result = await executeMonorepoTemplate(workspaceInfo, {
3977
4090
  ...templateInfo,
@@ -3979,25 +4092,38 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
3979
4092
  targetDir
3980
4093
  }, options.interactive, { silent: compactOutput });
3981
4094
  const { projectDir } = result;
3982
- if (result.exitCode !== 0 || !projectDir) cancelAndExit(`Failed to create monorepo, exit code: ${result.exitCode}`, result.exitCode);
4095
+ if (result.exitCode !== 0 || !projectDir) {
4096
+ failCreateProgress("Scaffolding failed");
4097
+ cancelAndExit(`Failed to create monorepo, exit code: ${result.exitCode}`, result.exitCode);
4098
+ }
3983
4099
  const fullPath = path.join(workspaceInfo.rootDir, projectDir);
4100
+ updateCreateProgress("Writing agent instructions");
4101
+ pauseCreateProgress();
3984
4102
  await writeAgentInstructions({
3985
4103
  projectRoot: fullPath,
3986
4104
  targetPaths: selectedAgentTargetPaths,
3987
4105
  interactive: options.interactive,
3988
4106
  silent: compactOutput
3989
4107
  });
4108
+ resumeCreateProgress();
4109
+ updateCreateProgress("Writing editor configs");
4110
+ pauseCreateProgress();
3990
4111
  await writeEditorConfigs({
3991
4112
  projectRoot: fullPath,
3992
4113
  editorId: selectedEditor,
3993
4114
  interactive: options.interactive,
3994
4115
  silent: compactOutput
3995
4116
  });
4117
+ resumeCreateProgress();
3996
4118
  workspaceInfo.rootDir = fullPath;
4119
+ updateCreateProgress("Integrating monorepo");
3997
4120
  rewriteMonorepo(workspaceInfo, void 0, compactOutput);
3998
4121
  if (shouldSetupHooks) installGitHooks(fullPath, compactOutput);
4122
+ updateCreateProgress("Installing dependencies");
3999
4123
  const installSummary = await runViteInstall(fullPath, options.interactive, void 0, { silent: compactOutput });
4124
+ updateCreateProgress("Formatting code");
4000
4125
  await runViteFmt(fullPath, options.interactive, void 0, { silent: compactOutput });
4126
+ clearCreateProgress();
4001
4127
  showCreateSummary({
4002
4128
  description: describeScaffold(selectedTemplateName, selectedTemplateArgs),
4003
4129
  installSummary,
@@ -4018,35 +4144,56 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4018
4144
  packageName = selected.packageName;
4019
4145
  targetDir = templateInfo.parentDir ? path.join(templateInfo.parentDir, selected.targetDir) : selected.targetDir;
4020
4146
  }
4147
+ pauseCreateProgress();
4021
4148
  await checkProjectDirExists(targetDir, options.interactive);
4149
+ resumeCreateProgress();
4150
+ updateCreateProgress("Generating project");
4022
4151
  result = await executeBuiltinTemplate(workspaceInfo, {
4023
4152
  ...templateInfo,
4024
4153
  packageName,
4025
4154
  targetDir
4026
4155
  }, { silent: compactOutput });
4027
- } else result = await executeRemoteTemplate(workspaceInfo, templateInfo, { silent: compactOutput });
4028
- if (result.exitCode !== 0) process.exit(result.exitCode);
4156
+ } else {
4157
+ updateCreateProgress("Generating project");
4158
+ result = await executeRemoteTemplate(workspaceInfo, templateInfo, { silent: compactOutput });
4159
+ }
4160
+ if (result.exitCode !== 0) {
4161
+ failCreateProgress("Scaffolding failed");
4162
+ process.exit(result.exitCode);
4163
+ }
4029
4164
  const projectDir = result.projectDir;
4030
- if (!projectDir) process.exit(0);
4165
+ if (!projectDir) {
4166
+ clearCreateProgress();
4167
+ process.exit(0);
4168
+ }
4031
4169
  const fullPath = path.join(workspaceInfo.rootDir, projectDir);
4170
+ const agentInstructionsRoot = isMonorepo ? workspaceInfo.rootDir : fullPath;
4171
+ updateCreateProgress("Writing agent instructions");
4172
+ pauseCreateProgress();
4032
4173
  await writeAgentInstructions({
4033
- projectRoot: isMonorepo ? workspaceInfo.rootDir : fullPath,
4174
+ projectRoot: agentInstructionsRoot,
4034
4175
  targetPaths: selectedAgentTargetPaths,
4035
4176
  interactive: options.interactive,
4036
4177
  silent: compactOutput
4037
4178
  });
4179
+ resumeCreateProgress();
4180
+ updateCreateProgress("Writing editor configs");
4181
+ pauseCreateProgress();
4038
4182
  await writeEditorConfigs({
4039
4183
  projectRoot: fullPath,
4040
4184
  editorId: selectedEditor,
4041
4185
  interactive: options.interactive,
4042
4186
  silent: compactOutput
4043
4187
  });
4188
+ resumeCreateProgress();
4044
4189
  let installSummary;
4045
4190
  if (isMonorepo) {
4046
4191
  if (!compactOutput) log.step("Monorepo integration...");
4192
+ updateCreateProgress("Integrating into monorepo");
4047
4193
  rewriteMonorepoProject(fullPath, workspaceInfo.packageManager, void 0, compactOutput);
4048
4194
  if (workspaceInfo.packages.length > 0) {
4049
4195
  if (options.interactive) {
4196
+ pauseCreateProgress();
4050
4197
  const selectedDepTypeOptions = await multiselect({
4051
4198
  message: `Add workspace dependencies to ${accent(projectDir)}?`,
4052
4199
  options: [
@@ -4072,17 +4219,24 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4072
4219
  if (!Ct(selected)) selectedDeps = selected;
4073
4220
  if (selectedDeps.length > 0) updatePackageJsonWithDeps(workspaceInfo.rootDir, projectDir, selectedDeps, selectedDepType);
4074
4221
  }
4222
+ resumeCreateProgress();
4075
4223
  }
4076
4224
  }
4077
4225
  updateWorkspaceConfig(projectDir, workspaceInfo);
4226
+ updateCreateProgress("Installing dependencies");
4078
4227
  installSummary = await runViteInstall(workspaceInfo.rootDir, options.interactive, void 0, { silent: compactOutput });
4228
+ updateCreateProgress("Formatting code");
4079
4229
  await runViteFmt(workspaceInfo.rootDir, options.interactive, [projectDir], { silent: compactOutput });
4080
4230
  } else {
4231
+ updateCreateProgress("Applying Vite+ project setup");
4081
4232
  rewriteStandaloneProject(fullPath, workspaceInfo, void 0, compactOutput);
4082
4233
  if (shouldSetupHooks) installGitHooks(fullPath, compactOutput);
4234
+ updateCreateProgress("Installing dependencies");
4083
4235
  installSummary = await runViteInstall(fullPath, options.interactive, void 0, { silent: compactOutput });
4236
+ updateCreateProgress("Formatting code");
4084
4237
  await runViteFmt(fullPath, options.interactive, void 0, { silent: compactOutput });
4085
4238
  }
4239
+ clearCreateProgress();
4086
4240
  showCreateSummary({
4087
4241
  description: describeScaffold(selectedTemplateName, selectedTemplateArgs),
4088
4242
  installSummary,