vite-plus 0.1.20-alpha.3 → 0.1.20

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,19 +1,16 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "../chunk-q7NCDQ7-.js";
2
2
  import { a as require_cross_spawn } from "../tsconfig-DQTf06oN.js";
3
3
  import { a as printHeader, i as muted, o as success, r as log, t as accent } from "../terminal-CxTMfsxZ.js";
4
- import { i as resolveViteConfig, n as hasViteConfig, t as findWorkspaceRoot } from "../resolve-vite-config-C1KX9CZU.js";
5
- import { $ as multiselect, A as setPackageManager, B as runViteFmt, D as rewriteMonorepo, E as promptPrettierMigration, G as templatesDir, H as selectPackageManager, K as DependencyType, L as defaultInteractive, O as rewriteMonorepoProject, Q as log$1, R as downloadPackageManager$1, T as promptEslintMigration, V as runViteInstall, W as displayRelative, X as confirm, Y as cancel, Z as intro, a as writeAgentInstructions, at as q, d as detectEslintProject, f as detectFramework, g as hasFrameworkShim, it as require_picocolors, k as rewriteStandaloneProject, m as detectPrettierProject, n as detectExistingAgentTargetPaths, nt as spinner, o as addFrameworkShim, q as PackageManager, r as selectAgentTargetPaths, rt as text, tt as select, v as injectCreateDefaultTemplate, y as installGitHooks, z as promptGitHooks } from "../agent-C8Me6C5u.js";
4
+ import { B as runViteInstall, D as rewriteMonorepoProject, E as rewriteMonorepo, G as DependencyType, I as defaultInteractive, J as cancel, K as PackageManager, L as downloadPackageManager$1, O as rewriteStandaloneProject, Q as multiselect, R as promptGitHooks, T as promptPrettierMigration, U as displayRelative, V as selectPackageManager, W as templatesDir, X as intro, Y as confirm, Z as log$1, a as writeAgentInstructions, d as detectEslintProject, et as select, f as detectFramework, g as hasFrameworkShim, it as q, k as setPackageManager, m as detectPrettierProject, n as detectExistingAgentTargetPaths, nt as text, o as addFrameworkShim, r as selectAgentTargetPaths, rt as require_picocolors, tt as spinner, v as installGitHooks, w as promptEslintMigration, z as runViteFmt } from "../agent-D_WSpD0r.js";
6
5
  import { t as lib_default } from "../lib-BamM40b7.js";
7
- import { c as editJsonFile, o as fetchNpmResource, s as getNpmRegistry, t as checkNpmPackageExists, u as readJsonFile } from "../package-CrKanQYM.js";
8
- import { a as detectExistingEditors, c as writeEditorConfigs, n as updatePackageJsonWithDeps, r as updateWorkspaceConfig, s as selectEditors, t as detectWorkspace$1 } from "../workspace-Du9O0xar.js";
6
+ import { c as readJsonFile, o as editJsonFile, t as checkNpmPackageExists } from "../package-D_LD1iiI.js";
7
+ import { a as detectExistingEditors, c as writeEditorConfigs, n as updatePackageJsonWithDeps, r as updateWorkspaceConfig, s as selectEditors, t as detectWorkspace$1 } from "../workspace-DVOyShUK.js";
9
8
  import { t as renderCliDoc } from "../help-BtkjXtRM.js";
10
9
  import path from "node:path";
11
10
  import { runCommand, vitePlusHeader } from "../../binding/index.js";
12
11
  import fs from "node:fs";
13
12
  import { styleText } from "node:util";
14
- import os from "node:os";
15
13
  import fsPromises from "node:fs/promises";
16
- import { createHash, randomUUID } from "node:crypto";
17
14
  import assert from "node:assert";
18
15
  //#region src/create/command.ts
19
16
  var import_cross_spawn = /* @__PURE__ */ __toESM(require_cross_spawn(), 1);
@@ -141,8 +138,7 @@ const BuiltinTemplate = {
141
138
  const TemplateType = {
142
139
  builtin: "builtin",
143
140
  bingo: "bingo",
144
- remote: "remote",
145
- bundled: "bundled"
141
+ remote: "remote"
146
142
  };
147
143
  //#endregion
148
144
  //#region src/create/discovery.ts
@@ -160,18 +156,9 @@ function inferGitHubRepoName(templateName) {
160
156
  if (!degitPath) return null;
161
157
  return degitPath.split("/").pop() || null;
162
158
  }
163
- function discoverTemplate(templateName, templateArgs, workspaceInfo, interactive, bundledLocalPath, skipShorthand) {
159
+ function discoverTemplate(templateName, templateArgs, workspaceInfo, interactive) {
164
160
  const envs = prependToPathToEnvs(workspaceInfo.downloadPackageManager.binPrefix, { ...process.env });
165
161
  const parentDir = inferParentDir(templateName, workspaceInfo);
166
- if (bundledLocalPath) return {
167
- command: "",
168
- args: [...templateArgs],
169
- envs,
170
- type: TemplateType.bundled,
171
- parentDir,
172
- interactive,
173
- localPath: bundledLocalPath
174
- };
175
162
  if (templateName.startsWith("vite:")) return {
176
163
  command: templateName,
177
164
  args: [...templateArgs],
@@ -217,7 +204,7 @@ function discoverTemplate(templateName, templateArgs, workspaceInfo, interactive
217
204
  };
218
205
  }
219
206
  return {
220
- command: skipShorthand ? templateName : expandCreateShorthand(templateName),
207
+ command: expandCreateShorthand(templateName),
221
208
  args: [...templateArgs],
222
209
  envs,
223
210
  type: TemplateType.remote,
@@ -299,591 +286,6 @@ function getInitialTemplateOptions(isMonorepo) {
299
286
  ];
300
287
  }
301
288
  //#endregion
302
- //#region src/create/org-manifest.ts
303
- /**
304
- * Parse the org picker specifier: `@scope` (scope only → picker) or
305
- * `@scope:name` (direct manifest-entry selection). Colon mirrors the
306
- * existing `vite:monorepo` / `vite:library` builtin-template syntax and
307
- * keeps manifest entries syntactically distinct from real
308
- * `@scope/package-name` npm specifiers.
309
- *
310
- * Returns `null` for anything else — including the plain `@scope/name`
311
- * form, which routes to the existing `@scope/create-name` shorthand as
312
- * it did before the org-manifest feature.
313
- *
314
- * The optional `version` suffix (`@scope@1.2.3`, `@scope:name@1.2.3`)
315
- * pins `@scope/create` to a specific release rather than `dist-tags.latest`.
316
- */
317
- function parseOrgScopedSpec(spec) {
318
- if (!spec.startsWith("@")) return null;
319
- if (spec.includes("/")) return null;
320
- const colonIndex = spec.indexOf(":");
321
- if (colonIndex === -1) {
322
- const atIndex = spec.indexOf("@", 1);
323
- if (atIndex === -1) return { scope: spec };
324
- const version = spec.slice(atIndex + 1);
325
- return version ? {
326
- scope: spec.slice(0, atIndex),
327
- version
328
- } : { scope: spec.slice(0, atIndex) };
329
- }
330
- const scope = spec.slice(0, colonIndex);
331
- const rest = spec.slice(colonIndex + 1);
332
- const atIndex = rest.indexOf("@");
333
- const name = atIndex === -1 ? rest : rest.slice(0, atIndex);
334
- const version = atIndex === -1 ? "" : rest.slice(atIndex + 1);
335
- if (!name) return version ? {
336
- scope,
337
- version
338
- } : { scope };
339
- return version ? {
340
- scope,
341
- name,
342
- version
343
- } : {
344
- scope,
345
- name
346
- };
347
- }
348
- /**
349
- * Schema-level failure. Never falls through silently — a maintainer who
350
- * shipped an invalid manifest should see the offending field.
351
- */
352
- var OrgManifestSchemaError = class extends Error {
353
- constructor(message, packageName) {
354
- super(`${packageName}: ${message}`);
355
- this.packageName = packageName;
356
- this.name = "OrgManifestSchemaError";
357
- }
358
- };
359
- function isRelativePath(spec) {
360
- return spec.startsWith("./") || spec.startsWith("../");
361
- }
362
- function validateEntry(entry, index, packageName) {
363
- if (!entry || typeof entry !== "object") throw new OrgManifestSchemaError(`createConfig.templates[${index}] must be an object`, packageName);
364
- const raw = entry;
365
- const requireString = (field) => {
366
- const value = raw[field];
367
- if (typeof value !== "string" || value.length === 0) throw new OrgManifestSchemaError(`createConfig.templates[${index}].${field} must be a non-empty string`, packageName);
368
- return value;
369
- };
370
- const name = requireString("name");
371
- if (name.startsWith("__vp_")) throw new OrgManifestSchemaError(`createConfig.templates[${index}].name uses the reserved \`__vp_\` prefix`, packageName);
372
- const description = requireString("description");
373
- const template = requireString("template");
374
- let monorepo;
375
- if (raw.monorepo !== void 0) {
376
- if (typeof raw.monorepo !== "boolean") throw new OrgManifestSchemaError(`createConfig.templates[${index}].monorepo must be a boolean`, packageName);
377
- monorepo = raw.monorepo;
378
- }
379
- if (isRelativePath(template)) {
380
- const resolved = path.posix.resolve("/root", template.replaceAll("\\", "/"));
381
- if (resolved !== "/root" && !resolved.startsWith("/root/")) throw new OrgManifestSchemaError(`createConfig.templates[${index}].template escapes the package root: ${template}`, packageName);
382
- }
383
- return {
384
- name,
385
- description,
386
- template,
387
- ...monorepo !== void 0 ? { monorepo } : {}
388
- };
389
- }
390
- function validateManifest(raw, packageName) {
391
- if (!raw || typeof raw !== "object") return null;
392
- const createConfig = raw.createConfig;
393
- if (!createConfig || typeof createConfig !== "object") return null;
394
- const templates = createConfig.templates;
395
- if (templates === void 0) return null;
396
- if (!Array.isArray(templates)) throw new OrgManifestSchemaError("createConfig.templates must be an array", packageName);
397
- if (templates.length === 0) return null;
398
- const entries = [];
399
- const seen = /* @__PURE__ */ new Set();
400
- for (let index = 0; index < templates.length; index += 1) {
401
- const entry = validateEntry(templates[index], index, packageName);
402
- if (seen.has(entry.name)) throw new OrgManifestSchemaError(`createConfig.templates[${index}].name duplicates an earlier entry: "${entry.name}"`, packageName);
403
- seen.add(entry.name);
404
- entries.push(entry);
405
- }
406
- return entries;
407
- }
408
- async function fetchPackument(scope, packageName) {
409
- const response = await fetchNpmResource(`${getNpmRegistry(scope)}/${packageName}`, {
410
- headers: { accept: "application/json" },
411
- timeoutMs: 5e3
412
- });
413
- if (response.status === 404) return null;
414
- if (!response.ok) throw new Error(`npm registry responded with ${response.status} for ${packageName}`);
415
- return await response.json();
416
- }
417
- /**
418
- * Fetch `@scope/create` from the npm registry and parse its `createConfig.templates`
419
- * manifest.
420
- *
421
- * Returns `null` when:
422
- * - the package does not exist on the registry (404), or
423
- * - the package exists but has no `createConfig.templates` field
424
- *
425
- * Throws when:
426
- * - the `createConfig.templates` field is present but malformed (`OrgManifestSchemaError`), or
427
- * - the registry request fails for any non-404 reason
428
- *
429
- * `requestedVersion` pins the lookup to a specific `versions[...]` entry
430
- * (equivalent to `vp create @scope@1.2.3`); omit it to resolve `dist-tags.latest`.
431
- */
432
- async function readOrgManifest(scope, requestedVersion) {
433
- if (!scope.startsWith("@")) return null;
434
- const packageName = `${scope}/create`;
435
- const packument = await fetchPackument(scope, packageName);
436
- if (!packument) return null;
437
- let resolvedVersion;
438
- if (requestedVersion) {
439
- resolvedVersion = packument["dist-tags"]?.[requestedVersion] ?? (packument.versions?.[requestedVersion] ? requestedVersion : void 0);
440
- if (!resolvedVersion) throw new OrgManifestSchemaError(`version "${requestedVersion}" not found (known tags: ${Object.keys(packument["dist-tags"] ?? {}).join(", ") || "none"})`, packageName);
441
- } else {
442
- resolvedVersion = packument["dist-tags"]?.latest;
443
- if (!resolvedVersion) return null;
444
- }
445
- const meta = packument.versions?.[resolvedVersion];
446
- if (!meta) return null;
447
- const templates = validateManifest(meta, packageName);
448
- if (!templates) return null;
449
- if (!meta.dist?.tarball) throw new OrgManifestSchemaError(`missing dist.tarball for ${resolvedVersion}`, packageName);
450
- return {
451
- scope,
452
- packageName,
453
- version: resolvedVersion,
454
- tarballUrl: meta.dist.tarball,
455
- integrity: meta.dist.integrity,
456
- templates
457
- };
458
- }
459
- /**
460
- * Apply the in-monorepo filter rule from the RFC: entries with
461
- * `monorepo: true` are hidden when the command is invoked inside an
462
- * existing monorepo, mirroring `initial-template-options.ts:9-31`.
463
- */
464
- function filterManifestForContext(templates, isMonorepo) {
465
- if (!isMonorepo) return [...templates];
466
- return templates.filter((entry) => !entry.monorepo);
467
- }
468
- //#endregion
469
- //#region src/create/org-picker.ts
470
- const ORG_PICKER_CANCEL = Symbol("org-picker-cancel");
471
- const ORG_PICKER_BUILTIN_ESCAPE = Symbol("org-picker-builtin-escape");
472
- const ESCAPE_HATCH = Symbol("builtin-escape");
473
- /**
474
- * Render the interactive picker for an org manifest. Always appends a
475
- * trailing "Vite+ built-in templates" escape-hatch entry.
476
- *
477
- * Context-filters entries with `monorepo: true` when running inside an
478
- * existing monorepo, mirroring `initial-template-options.ts:9-31`.
479
- *
480
- * Returns `ORG_PICKER_BUILTIN_ESCAPE` when the escape hatch is selected,
481
- * or `ORG_PICKER_CANCEL` when the user hits Ctrl-C.
482
- */
483
- async function pickOrgTemplate(manifest, opts) {
484
- const filtered = filterManifestForContext(manifest.templates, opts.isMonorepo);
485
- if (filtered.length === 0) return ORG_PICKER_BUILTIN_ESCAPE;
486
- const escapeValue = `__vp_builtin_escape__::${randomUUID()}`;
487
- const lookup = /* @__PURE__ */ new Map();
488
- const options = filtered.map((entry) => {
489
- lookup.set(entry.name, entry);
490
- return {
491
- value: entry.name,
492
- label: entry.name,
493
- hint: entry.description
494
- };
495
- });
496
- lookup.set(escapeValue, ESCAPE_HATCH);
497
- const builtinHint = opts.isMonorepo ? "Use defaults (application / library)" : "Use defaults (monorepo / application / library)";
498
- options.push({
499
- value: escapeValue,
500
- label: "Vite+ built-in templates",
501
- hint: builtinHint
502
- });
503
- const picked = await select({
504
- message: `Pick a template from ${manifest.scope}`,
505
- options
506
- });
507
- if (q(picked)) return ORG_PICKER_CANCEL;
508
- const found = lookup.get(picked);
509
- if (found === ESCAPE_HATCH) return ORG_PICKER_BUILTIN_ESCAPE;
510
- if (!found) throw new Error(`org-picker: prompts.select returned an unregistered value: ${picked}`);
511
- return {
512
- kind: "entry",
513
- entry: found
514
- };
515
- }
516
- /**
517
- * Render the manifest as a plain-text table for the `--no-interactive`
518
- * error output. Fixed column order so AI agents and scripts can recover
519
- * available template names without a `--json` flag.
520
- */
521
- function formatManifestTable(manifest, isMonorepo) {
522
- const visible = filterManifestForContext(manifest.templates, isMonorepo);
523
- const filteredCount = manifest.templates.length - visible.length;
524
- const nameWidth = Math.max(4, ...visible.map((entry) => entry.name.length));
525
- const descWidth = Math.max(11, ...visible.map((entry) => entry.description.length));
526
- const lines = [];
527
- lines.push(` ${"NAME".padEnd(nameWidth)} ${"DESCRIPTION".padEnd(descWidth)} TEMPLATE`);
528
- for (const entry of visible) lines.push(` ${entry.name.padEnd(nameWidth)} ${entry.description.padEnd(descWidth)} ${entry.template}`);
529
- return {
530
- lines,
531
- filteredCount
532
- };
533
- }
534
- //#endregion
535
- //#region ../../node_modules/.pnpm/nanotar@0.3.0/node_modules/nanotar/dist/index.mjs
536
- const tarItemTypeMap = {
537
- "0": "file",
538
- "1": "hardLink",
539
- "2": "symbolicLink",
540
- "3": "characterDevice",
541
- "4": "blockDevice",
542
- "5": "directory",
543
- "6": "fifo",
544
- "7": "contiguousFile",
545
- "g": "globalExtendedHeader",
546
- "x": "extendedHeader",
547
- "D": "gnuDirectory",
548
- "I": "gnuInodeMetadata",
549
- "K": "gnuLongLinkName",
550
- "L": "gnuLongFileName",
551
- "N": "gnuOldLongFileName",
552
- "M": "gnuMultiVolume",
553
- "S": "gnuSparseFile",
554
- "E": "gnuExtendedSparse",
555
- "A": "solarisAcl",
556
- "V": "solarisVolumeLabel",
557
- "X": "solarisOldExtendedHeader"
558
- };
559
- function parseTar(data, opts) {
560
- const buffer = data.buffer || data;
561
- const files = [];
562
- let offset = 0;
563
- let nextExtendedHeader;
564
- let globalExtendedHeader;
565
- while (offset < buffer.byteLength - 512) {
566
- let name = _readString(buffer, offset, 100);
567
- if (name.length === 0) break;
568
- if (nextExtendedHeader) {
569
- const longName = nextExtendedHeader.path || nextExtendedHeader.linkpath;
570
- if (longName) name = longName;
571
- }
572
- const mode = _readString(buffer, offset + 100, 8).trim();
573
- const uid = Number.parseInt(_readString(buffer, offset + 108, 8));
574
- const gid = Number.parseInt(_readString(buffer, offset + 116, 8));
575
- const size = _readNumber(buffer, offset + 124, 12);
576
- const seek = 512 + 512 * Math.trunc(size / 512) + (size % 512 ? 512 : 0);
577
- const mtime = _readNumber(buffer, offset + 136, 12);
578
- const _type = _readString(buffer, offset + 156, 1) || "0";
579
- const type = tarItemTypeMap[_type] || _type;
580
- switch (type) {
581
- case "extendedHeader":
582
- case "globalExtendedHeader": {
583
- const headers = _parseExtendedHeaders(new Uint8Array(buffer, offset + 512, size));
584
- if (type === "extendedHeader") nextExtendedHeader = headers;
585
- else {
586
- nextExtendedHeader = void 0;
587
- globalExtendedHeader = {
588
- ...globalExtendedHeader,
589
- ...headers
590
- };
591
- }
592
- offset += seek;
593
- continue;
594
- }
595
- case "gnuLongFileName":
596
- case "gnuOldLongFileName":
597
- case "gnuLongLinkName":
598
- nextExtendedHeader = { path: _readString(buffer, offset + 512, size) };
599
- offset += seek;
600
- continue;
601
- }
602
- const user = _readString(buffer, offset + 265, 32);
603
- const group = _readString(buffer, offset + 297, 32);
604
- name = _sanitizePath(name);
605
- const meta = {
606
- name,
607
- type,
608
- size,
609
- attrs: {
610
- ...globalExtendedHeader,
611
- ...nextExtendedHeader,
612
- mode,
613
- uid,
614
- gid,
615
- mtime,
616
- user,
617
- group
618
- }
619
- };
620
- nextExtendedHeader = void 0;
621
- if (opts?.filter && !opts.filter(meta)) {
622
- offset += seek;
623
- continue;
624
- }
625
- if (opts?.metaOnly) {
626
- files.push(meta);
627
- offset += seek;
628
- continue;
629
- }
630
- const data2 = size === 0 ? void 0 : new Uint8Array(buffer, offset + 512, size);
631
- files.push({
632
- ...meta,
633
- data: data2,
634
- get text() {
635
- return new TextDecoder().decode(this.data);
636
- }
637
- });
638
- offset += seek;
639
- }
640
- return files;
641
- }
642
- async function parseTarGzip(data, opts = {}) {
643
- const stream = new ReadableStream({ start(controller) {
644
- controller.enqueue(new Uint8Array(data));
645
- controller.close();
646
- } }).pipeThrough(new DecompressionStream(opts.compression ?? "gzip"));
647
- return parseTar(await new Response(stream).arrayBuffer(), opts);
648
- }
649
- function _sanitizePath(path) {
650
- let normalized = path.replace(/\\/g, "/");
651
- normalized = normalized.replace(/^[a-zA-Z]:\//, "");
652
- normalized = normalized.replace(/^\/+/, "");
653
- const hasLeadingDotSlash = normalized.startsWith("./");
654
- const parts = normalized.split("/");
655
- const resolved = [];
656
- for (const part of parts) if (part === "..") resolved.pop();
657
- else if (part !== "." && part !== "") resolved.push(part);
658
- let result = resolved.join("/");
659
- if (hasLeadingDotSlash && !result.startsWith("./")) result = "./" + result;
660
- if (path.endsWith("/") && !result.endsWith("/")) result += "/";
661
- return result;
662
- }
663
- function _readString(buffer, offset, size) {
664
- const view = new Uint8Array(buffer, offset, size);
665
- const i = view.indexOf(0);
666
- return new TextDecoder().decode(i === -1 ? view : view.slice(0, i));
667
- }
668
- function _readNumber(buffer, offset, size) {
669
- const view = new Uint8Array(buffer, offset, size);
670
- let str = "";
671
- for (let i = 0; i < size; i++) str += String.fromCodePoint(view[i]);
672
- return Number.parseInt(str, 8);
673
- }
674
- function _parseExtendedHeaders(data) {
675
- const dataStr = new TextDecoder().decode(data);
676
- const headers = {};
677
- for (const line of dataStr.split("\n")) {
678
- const s = line.split(" ")[1]?.split("=");
679
- if (s) headers[s[0]] = s[1];
680
- }
681
- return headers;
682
- }
683
- //#endregion
684
- //#region src/create/org-tarball.ts
685
- function getCacheRoot() {
686
- const home = process.env.VP_HOME || path.join(os.homedir(), ".vite-plus");
687
- return path.join(home, "tmp", "create-org");
688
- }
689
- /**
690
- * Replace characters that are illegal in Windows path segments
691
- * (`\ / : * ? " < > |` plus the IPv6 bracket pair `[ ]`). The host
692
- * comes from `new URL(...).host` which can carry a port (`:4873`) or
693
- * IPv6 literal (`[::1]`); both end up in the cache path otherwise.
694
- */
695
- function sanitizeHostForPath(host) {
696
- return host.replaceAll(/[\\/:*?"<>|[\]]/g, "_");
697
- }
698
- /**
699
- * Cache extracted tarballs under `<host>/<scope>/create/<version>` so two
700
- * repos resolving the same `<scope>@<version>` through different registries
701
- * (via `.npmrc` scope mappings) don't share a cache slot. The registry
702
- * guarantees `manifest.tarballUrl` is a valid URL, so any parse failure
703
- * here is a real bug worth surfacing.
704
- */
705
- function getExtractionDir(manifest) {
706
- const { host } = new URL(manifest.tarballUrl);
707
- return path.join(getCacheRoot(), sanitizeHostForPath(host), manifest.scope, "create", manifest.version);
708
- }
709
- function parseIntegrity(integrity) {
710
- const match = integrity.split(/\s+/)[0].match(/^(sha\d+)-(.+)$/);
711
- if (!match) return null;
712
- return {
713
- algorithm: match[1],
714
- expected: match[2]
715
- };
716
- }
717
- function verifyIntegrity(bytes, integrity) {
718
- if (!integrity) return;
719
- const parsed = parseIntegrity(integrity);
720
- if (!parsed) return;
721
- const hash = createHash(parsed.algorithm);
722
- hash.update(bytes);
723
- const actual = hash.digest("base64");
724
- if (actual !== parsed.expected) throw new Error(`integrity check failed: expected ${integrity}, got ${parsed.algorithm}-${actual}`);
725
- }
726
- const MAX_TARBALL_BYTES = 50 * 1024 * 1024;
727
- async function downloadTarball(url) {
728
- const response = await fetchNpmResource(url, { timeoutMs: 3e4 });
729
- if (!response.ok) throw new Error(`failed to download tarball (${response.status}): ${url}`);
730
- const contentLength = Number(response.headers.get("content-length"));
731
- if (Number.isFinite(contentLength) && contentLength > MAX_TARBALL_BYTES) throw new Error(`tarball exceeds ${MAX_TARBALL_BYTES} byte size limit: ${url}`);
732
- const reader = response.body?.getReader();
733
- if (!reader) throw new Error(`tarball response has no body: ${url}`);
734
- const chunks = [];
735
- let total = 0;
736
- while (true) {
737
- const { done, value } = await reader.read();
738
- if (done) break;
739
- total += value.byteLength;
740
- if (total > MAX_TARBALL_BYTES) {
741
- await reader.cancel();
742
- throw new Error(`tarball exceeds ${MAX_TARBALL_BYTES} byte size limit: ${url}`);
743
- }
744
- chunks.push(value);
745
- }
746
- const bytes = new Uint8Array(total);
747
- let offset = 0;
748
- for (const chunk of chunks) {
749
- bytes.set(chunk, offset);
750
- offset += chunk.byteLength;
751
- }
752
- return bytes;
753
- }
754
- const STAGING_SUFFIX_PREFIX = ".tmp-";
755
- /**
756
- * Parse a tar entry's stored mode (always octal) into the numeric
757
- * permission bits (low 9 bits — `rwxrwxrwx`). Returns `undefined` when
758
- * the mode is missing or unparsable so the caller leaves the file with
759
- * its default (umask-derived) permissions instead of downgrading.
760
- */
761
- function parseEntryMode(raw) {
762
- if (!raw) return;
763
- const parsed = Number.parseInt(raw, 8);
764
- if (!Number.isFinite(parsed)) return;
765
- return parsed & 511;
766
- }
767
- /**
768
- * Strip the `package/` prefix from an `npm pack` tarball entry. Returns
769
- * `null` for entries to skip (root dir, PaxHeader, anything outside
770
- * `package/`).
771
- */
772
- function normalizeEntryName(rawName) {
773
- const name = rawName.replace(/^\.\//, "").replace(/\\/g, "/");
774
- if (!name || name === "package" || name === "package/") return null;
775
- if (name.startsWith("PaxHeader/") || name.includes("/PaxHeader/")) return null;
776
- if (!name.startsWith("package/")) return null;
777
- return name.slice(8);
778
- }
779
- async function extractTarballTo(bytes, destDir) {
780
- const entries = await parseTarGzip(bytes);
781
- const stagingDir = `${destDir}${STAGING_SUFFIX_PREFIX}${process.pid}-${Date.now()}`;
782
- await fs.promises.mkdir(stagingDir, { recursive: true });
783
- const resolvedStaging = path.resolve(stagingDir);
784
- try {
785
- for (const entry of entries) {
786
- const relativeName = normalizeEntryName(entry.name);
787
- if (relativeName === null) continue;
788
- const targetPath = path.join(stagingDir, relativeName);
789
- const resolvedTarget = path.resolve(targetPath);
790
- if (resolvedTarget !== resolvedStaging && !resolvedTarget.startsWith(`${resolvedStaging}${path.sep}`)) throw new Error(`tarball entry escapes extraction root: ${entry.name}`);
791
- if (entry.type === "directory" || relativeName.endsWith("/")) {
792
- await fs.promises.mkdir(targetPath, { recursive: true });
793
- continue;
794
- }
795
- await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });
796
- const data = entry.data ?? new Uint8Array(0);
797
- await fs.promises.writeFile(targetPath, data);
798
- const mode = parseEntryMode(entry.attrs?.mode);
799
- if (mode !== void 0) await fs.promises.chmod(targetPath, mode);
800
- }
801
- try {
802
- await fs.promises.rename(stagingDir, destDir);
803
- } catch (error) {
804
- const code = error.code;
805
- if ((code === "ENOTEMPTY" || code === "EEXIST") && fs.existsSync(path.join(destDir, "package.json"))) {
806
- await fs.promises.rm(stagingDir, {
807
- recursive: true,
808
- force: true
809
- }).catch(() => {});
810
- return;
811
- }
812
- throw error;
813
- }
814
- } catch (error) {
815
- await fs.promises.rm(stagingDir, {
816
- recursive: true,
817
- force: true
818
- }).catch(() => {});
819
- throw error;
820
- }
821
- }
822
- const STAGING_STALE_MS = 1440 * 60 * 1e3;
823
- /**
824
- * Remove `<destDir>.tmp-*` siblings left behind by a previous crash so
825
- * repeated aborts don't accumulate orphaned staging trees. Only deletes
826
- * entries whose mtime is older than 24 hours — a concurrent `vp create`
827
- * that's still actively extracting will always be younger than that, so
828
- * the age gate keeps this safe to run at the top of every extract.
829
- */
830
- async function cleanupStaleStagingDirs(destDir) {
831
- const parent = path.dirname(destDir);
832
- const prefix = `${path.basename(destDir)}${STAGING_SUFFIX_PREFIX}`;
833
- let entries;
834
- try {
835
- entries = await fs.promises.readdir(parent);
836
- } catch {
837
- return;
838
- }
839
- const cutoff = Date.now() - STAGING_STALE_MS;
840
- await Promise.all(entries.filter((name) => name.startsWith(prefix)).map(async (name) => {
841
- const fullPath = path.join(parent, name);
842
- try {
843
- if ((await fs.promises.stat(fullPath)).mtimeMs < cutoff) await fs.promises.rm(fullPath, {
844
- recursive: true,
845
- force: true
846
- });
847
- } catch {}
848
- }));
849
- }
850
- /**
851
- * Ensure the `@org/create` package tarball for the given manifest has been
852
- * downloaded and extracted locally. Returns the absolute path to the
853
- * extracted package root (i.e. the directory that contains
854
- * `package.json`).
855
- *
856
- * Idempotent: subsequent calls for the same `<scope, version>` reuse the
857
- * cached extraction. Concurrent calls race on the final rename; the loser
858
- * cleans up and returns the existing directory.
859
- */
860
- async function ensureOrgPackageExtracted(manifest) {
861
- const extractedRoot = getExtractionDir(manifest);
862
- if (fs.existsSync(path.join(extractedRoot, "package.json"))) return extractedRoot;
863
- const parent = path.dirname(extractedRoot);
864
- await fs.promises.mkdir(parent, { recursive: true });
865
- await cleanupStaleStagingDirs(extractedRoot);
866
- const bytes = await downloadTarball(manifest.tarballUrl);
867
- verifyIntegrity(bytes, manifest.integrity);
868
- await extractTarballTo(bytes, extractedRoot);
869
- return extractedRoot;
870
- }
871
- /**
872
- * Resolve a manifest entry's relative `./...` path against an already-
873
- * extracted package root, rejecting any path that escapes the root (via
874
- * `..` walks or an absolute specifier).
875
- *
876
- * Existence is NOT checked here — the subsequent `copyDir` surfaces any
877
- * missing-directory error with a clearer errno.
878
- */
879
- function resolveBundledPath(extractedRoot, relativePath) {
880
- if (path.isAbsolute(relativePath)) throw new Error(`bundled template path must be relative, got ${relativePath}`);
881
- const resolvedRoot = path.resolve(extractedRoot);
882
- const resolvedTarget = path.resolve(extractedRoot, relativePath);
883
- if (resolvedTarget !== resolvedRoot && !resolvedTarget.startsWith(`${resolvedRoot}${path.sep}`)) throw new Error(`bundled template path escapes the package root: ${relativePath}`);
884
- return resolvedTarget;
885
- }
886
- //#endregion
887
289
  //#region ../../node_modules/.pnpm/validate-npm-package-name@7.0.2/node_modules/validate-npm-package-name/lib/builtin-modules.json
888
290
  var require_builtin_modules = /* @__PURE__ */ __commonJSMin(((exports, module) => {
889
291
  module.exports = [
@@ -3848,24 +3250,6 @@ function setPackageName(projectDir, packageName) {
3848
3250
  return pkg;
3849
3251
  });
3850
3252
  }
3851
- /**
3852
- * Make sure the scaffolded project's `.gitignore` excludes `node_modules`.
3853
- *
3854
- * Called right after `git init` so even bundled `@org` templates (which
3855
- * may ship without a `.gitignore`) don't end up tracking installed
3856
- * dependencies on the user's first commit. No-op when an existing
3857
- * `.gitignore` already lists `node_modules`.
3858
- */
3859
- function ensureGitignoreNodeModules(projectDir) {
3860
- const gitignorePath = path.join(projectDir, ".gitignore");
3861
- let content = "";
3862
- try {
3863
- content = fs.readFileSync(gitignorePath, "utf-8");
3864
- } catch {}
3865
- if (/^\s*node_modules\/?\s*$/m.test(content)) return;
3866
- const prefix = content === "" || content.endsWith("\n") ? "" : "\n";
3867
- fs.appendFileSync(gitignorePath, `${prefix}node_modules\n`);
3868
- }
3869
3253
  function formatDisplayTargetDir(targetDir) {
3870
3254
  const normalized = targetDir.split(path.sep).join("/");
3871
3255
  if (normalized === "" || normalized === ".") return "./";
@@ -4007,109 +3391,6 @@ function validateTargetDir(input, cwd) {
4007
3391
  return { directory: targetDir };
4008
3392
  }
4009
3393
  //#endregion
4010
- //#region src/create/org-resolve.ts
4011
- function printNonInteractiveTable(manifest, orgSpec, isMonorepo) {
4012
- const { lines, filteredCount } = formatManifestTable(manifest, isMonorepo);
4013
- const [firstVisible] = filterManifestForContext(manifest.templates, isMonorepo);
4014
- const body = [
4015
- "",
4016
- `A template name is required when running \`vp create ${orgSpec.scope}\` in non-interactive mode.`,
4017
- "",
4018
- `Available templates in ${manifest.packageName}:`,
4019
- "",
4020
- ...lines
4021
- ];
4022
- if (filteredCount > 0) body.push("", `(omitted ${filteredCount} monorepo-only ${filteredCount === 1 ? "entry" : "entries"} because this workspace is already a monorepo)`);
4023
- body.push("", "Examples:");
4024
- if (firstVisible) body.push(" # Scaffold a specific template from the org", ` vp create ${orgSpec.scope}:${firstVisible.name} --no-interactive`, "");
4025
- body.push(" # Or use a Vite+ built-in template", " vp create vite:application --no-interactive", "");
4026
- process.stderr.write(body.join("\n"));
4027
- }
4028
- function rejectMonorepoEntryInsideMonorepo(entry, isMonorepo) {
4029
- if (entry.monorepo && isMonorepo) {
4030
- log$1.info("You are already in a monorepo workspace.\nUse a different template or run this command outside the monorepo");
4031
- cancelAndExit("Cannot create a monorepo inside an existing monorepo", 1);
4032
- }
4033
- }
4034
- async function resolveEntry(manifest, entry) {
4035
- if (isRelativePath(entry.template)) return {
4036
- kind: "bundled",
4037
- bundledLocalPath: resolveBundledPath(await ensureOrgPackageExtracted(manifest), entry.template),
4038
- entryName: entry.name,
4039
- scope: manifest.scope,
4040
- ...entry.monorepo === true ? { monorepo: true } : {}
4041
- };
4042
- return {
4043
- kind: "replaced",
4044
- templateName: entry.template
4045
- };
4046
- }
4047
- /**
4048
- * If `selectedTemplateName` points at an `@scope[/name]` org whose
4049
- * `@scope/create` package publishes a `createConfig.templates` manifest, apply the
4050
- * manifest rules (picker / direct lookup / escape hatch / bundled
4051
- * extraction) and report the outcome.
4052
- *
4053
- * The caller — `packages/cli/src/create/bin.ts` — decides what to do next
4054
- * based on the returned variant.
4055
- */
4056
- async function resolveOrgManifestForCreate(args) {
4057
- const orgSpec = parseOrgScopedSpec(args.templateName);
4058
- if (!orgSpec) return { kind: "passthrough" };
4059
- let manifest;
4060
- try {
4061
- manifest = await readOrgManifest(orgSpec.scope, orgSpec.version);
4062
- } catch (error) {
4063
- cancelAndExit(error instanceof OrgManifestSchemaError ? error.message : `Failed to read ${orgSpec.scope}/create manifest: ${error.message}`, 1);
4064
- }
4065
- if (!manifest) {
4066
- if (orgSpec.name !== void 0) cancelAndExit(`No \`createConfig.templates\` manifest in ${orgSpec.scope}/create — \`@org:name\` requires one.`, 1);
4067
- log$1.info(`No \`createConfig.templates\` manifest in ${orgSpec.scope}/create — running it as a normal package.`);
4068
- return { kind: "passthrough" };
4069
- }
4070
- if (orgSpec.name === void 0) {
4071
- if (!args.interactive) {
4072
- printNonInteractiveTable(manifest, orgSpec, args.isMonorepo);
4073
- process.exit(1);
4074
- }
4075
- const picked = await pickOrgTemplate(manifest, { isMonorepo: args.isMonorepo });
4076
- if (picked === ORG_PICKER_CANCEL) cancelAndExit();
4077
- if (picked === ORG_PICKER_BUILTIN_ESCAPE) {
4078
- if (args.isMonorepo && manifest.templates.every((t) => t.monorepo)) log$1.info(`No templates from ${manifest.packageName} are applicable inside a monorepo — showing Vite+ built-in templates instead.`);
4079
- return { kind: "escape-hatch" };
4080
- }
4081
- rejectMonorepoEntryInsideMonorepo(picked.entry, args.isMonorepo);
4082
- return resolveEntry(manifest, picked.entry);
4083
- }
4084
- const entry = manifest.templates.find((candidate) => candidate.name === orgSpec.name);
4085
- if (!entry) {
4086
- const available = filterManifestForContext(manifest.templates, args.isMonorepo).map((t) => t.name).join(", ");
4087
- cancelAndExit(`No template named "${orgSpec.name}" in ${manifest.packageName}. Available: ${available || "(none applicable in this context)"}.`, 1);
4088
- }
4089
- rejectMonorepoEntryInsideMonorepo(entry, args.isMonorepo);
4090
- return resolveEntry(manifest, entry);
4091
- }
4092
- /**
4093
- * Read `create.defaultTemplate` from the workspace root's `vite.config.ts`.
4094
- *
4095
- * Walks up from `startDir` via `findWorkspaceRoot` (monorepo markers
4096
- * only — `pnpm-workspace.yaml`, `workspaces` in `package.json`,
4097
- * `lerna.json`) so monorepo invocations from any subdirectory still
4098
- * pick up the root config. Standalone repos without a monorepo marker
4099
- * only see a config that sits at `startDir` itself.
4100
- *
4101
- * Best-effort: if there's no config file or evaluation fails, return
4102
- * `undefined` so the create flow behaves as if no default was set.
4103
- */
4104
- async function getConfiguredDefaultTemplate(startDir) {
4105
- const projectRoot = findWorkspaceRoot(startDir) ?? startDir;
4106
- if (!hasViteConfig(projectRoot)) return;
4107
- try {
4108
- const value = (await resolveViteConfig(projectRoot)).create?.defaultTemplate;
4109
- if (typeof value === "string" && value.length > 0) return value;
4110
- } catch {}
4111
- }
4112
- //#endregion
4113
3394
  //#region src/create/templates/generator.ts
4114
3395
  async function executeGeneratorScaffold(workspaceInfo, templateInfo, options) {
4115
3396
  if (!options?.silent) log$1.step("Creating generator scaffold...");
@@ -4257,38 +3538,24 @@ async function executeBuiltinTemplate(workspaceInfo, templateInfo, options) {
4257
3538
  };
4258
3539
  }
4259
3540
  //#endregion
4260
- //#region src/create/templates/bundled.ts
4261
- /**
4262
- * Scaffold a bundled template by copying the pre-extracted directory at
4263
- * `localPath` into `workspaceInfo.rootDir/targetDir`.
4264
- */
4265
- async function executeBundledTemplate(workspaceInfo, templateInfo) {
4266
- assert(templateInfo.localPath, "localPath is required for bundled templates");
4267
- assert(templateInfo.targetDir, "targetDir is required");
4268
- assert(templateInfo.packageName, "packageName is required");
4269
- const destDir = path.join(workspaceInfo.rootDir, templateInfo.targetDir);
4270
- try {
4271
- copyDir(templateInfo.localPath, destDir);
4272
- } catch (error) {
4273
- if (error.code === "ENOENT") throw new Error(`bundled template directory not found: ${templateInfo.localPath}`, { cause: error });
4274
- throw error;
4275
- }
4276
- try {
4277
- setPackageName(destDir, templateInfo.packageName);
4278
- } catch {}
4279
- return {
4280
- exitCode: 0,
4281
- projectDir: templateInfo.targetDir
4282
- };
4283
- }
4284
- //#endregion
4285
3541
  //#region src/create/templates/monorepo.ts
4286
3542
  const InitialMonorepoAppDir = "apps/website";
4287
- async function executeMonorepoTemplate(workspaceInfo, templateInfo, options) {
3543
+ async function executeMonorepoTemplate(workspaceInfo, templateInfo, interactive, options) {
4288
3544
  assert(templateInfo.packageName, "packageName is required");
4289
3545
  assert(templateInfo.targetDir, "targetDir is required");
4290
3546
  workspaceInfo.monorepoScope = getScopeFromPackageName(templateInfo.packageName);
4291
3547
  const fullPath = path.join(workspaceInfo.rootDir, templateInfo.targetDir);
3548
+ let initGit = true;
3549
+ if (interactive && !options?.silent) {
3550
+ const selected = await confirm({
3551
+ message: `Initialize git repository:`,
3552
+ initialValue: true
3553
+ });
3554
+ if (q(selected)) {
3555
+ log$1.info("Operation cancelled. Skipping git initialization");
3556
+ initGit = false;
3557
+ } else initGit = selected;
3558
+ } else if (!options?.silent) log$1.info(`Initializing git repository (default: yes)`);
4292
3559
  if (!options?.silent) {
4293
3560
  log$1.info(`Target directory: ${formatDisplayTargetDir(templateInfo.targetDir)}`);
4294
3561
  log$1.step("Creating Vite+ monorepo...");
@@ -4325,6 +3592,18 @@ async function executeMonorepoTemplate(workspaceInfo, templateInfo, options) {
4325
3592
  if (fs.existsSync(yarnrcPath)) fs.unlinkSync(yarnrcPath);
4326
3593
  }
4327
3594
  if (!options?.silent) log$1.success("Monorepo template created");
3595
+ if (initGit) {
3596
+ const gitResult = import_cross_spawn.default.sync("git", ["init"], {
3597
+ stdio: "pipe",
3598
+ cwd: fullPath
3599
+ });
3600
+ if (gitResult.status === 0) {
3601
+ if (!options?.silent) log$1.success("Git repository initialized");
3602
+ } else {
3603
+ log$1.warn("Failed to initialize git repository");
3604
+ if (gitResult.stderr) log$1.info(gitResult.stderr.toString());
3605
+ }
3606
+ }
4328
3607
  if (!options?.silent) log$1.step("Creating default application in apps/website...");
4329
3608
  const appResult = await runRemoteTemplateCommand(workspaceInfo, fullPath, discoverTemplate("create-vite@latest", [
4330
3609
  InitialMonorepoAppDir,
@@ -4387,10 +3666,7 @@ const helpMessage = renderCliDoc({
4387
3666
  `- Default: ${accent("vite:monorepo")}, ${accent("vite:application")}, ${accent("vite:library")}, ${accent("vite:generator")}`,
4388
3667
  "- Remote: vite, @tanstack/start, create-next-app,",
4389
3668
  " create-nuxt, github:user/repo, https://github.com/user/template-repo, etc.",
4390
- "- Local: @company/generator-*, ./tools/create-ui-component",
4391
- `- Org scope: ${accent("@your-org")} → picker from ${accent("@your-org/create")}'s ${accent("createConfig.templates")} manifest`,
4392
- `- Org entry: ${accent("@your-org:web")} → manifest entry "web" from ${accent("@your-org/create")}`,
4393
- `When omitted, uses \`create.defaultTemplate\` from vite.config.ts if set.`
3669
+ "- Local: @company/generator-*, ./tools/create-ui-component"
4394
3670
  ]
4395
3671
  }]
4396
3672
  },
@@ -4467,11 +3743,7 @@ const helpMessage = renderCliDoc({
4467
3743
  "",
4468
3744
  ` ${muted("# Use templates from GitHub (via degit)")}`,
4469
3745
  ` ${accent("vp create github:user/repo")}`,
4470
- ` ${accent("vp create https://github.com/user/template-repo")}`,
4471
- "",
4472
- ` ${muted("# Pick from an org that publishes @scope/create with createConfig.templates")}`,
4473
- ` ${accent("vp create @your-org")} ${muted("# interactive picker")}`,
4474
- ` ${accent("vp create @your-org:web")} ${muted("# direct manifest-entry selection")}`
3746
+ ` ${accent("vp create https://github.com/user/template-repo")}`
4475
3747
  ]
4476
3748
  }
4477
3749
  ]
@@ -4651,6 +3923,20 @@ async function main() {
4651
3923
  await showAvailableTemplates();
4652
3924
  return;
4653
3925
  }
3926
+ if (!templateName && !options.interactive) {
3927
+ console.error(`
3928
+ A template name is required when running in non-interactive mode
3929
+
3930
+ Usage: vp create [TEMPLATE] [OPTIONS] [-- TEMPLATE_OPTIONS]
3931
+
3932
+ Example:
3933
+ ${muted("# Create a new application in non-interactive mode with a custom target directory")}
3934
+ vp create vite:application --no-interactive --directory=apps/my-app
3935
+
3936
+ Use \`vp create --list\` to list all available templates, or run \`vp create --help\` for more information.
3937
+ `);
3938
+ process.exit(1);
3939
+ }
4654
3940
  if (options.interactive) intro(vitePlusHeader());
4655
3941
  let targetDir = "";
4656
3942
  let packageName = "";
@@ -4678,39 +3964,7 @@ async function main() {
4678
3964
  let selectedParentDir;
4679
3965
  let remoteTargetDir;
4680
3966
  let shouldSetupHooks = false;
4681
- let bundled;
4682
- let skipShorthandExpansion = false;
4683
3967
  const installArgs = process.env.CI ? ["--no-frozen-lockfile"] : void 0;
4684
- if (!selectedTemplateName) {
4685
- const defaultTemplate = await getConfiguredDefaultTemplate(workspaceInfoOptional.rootDir);
4686
- if (defaultTemplate) selectedTemplateName = defaultTemplate;
4687
- }
4688
- if (selectedTemplateName) {
4689
- const resolved = await resolveOrgManifestForCreate({
4690
- templateName: selectedTemplateName,
4691
- isMonorepo,
4692
- interactive: options.interactive
4693
- });
4694
- if (resolved.kind === "replaced") {
4695
- selectedTemplateName = resolved.templateName;
4696
- skipShorthandExpansion = true;
4697
- } else if (resolved.kind === "bundled") bundled = resolved;
4698
- else if (resolved.kind === "escape-hatch") selectedTemplateName = "";
4699
- }
4700
- if (!selectedTemplateName && !options.interactive) {
4701
- console.error(`
4702
- A template name is required when running in non-interactive mode
4703
-
4704
- Usage: vp create [TEMPLATE] [OPTIONS] [-- TEMPLATE_OPTIONS]
4705
-
4706
- Example:
4707
- ${muted("# Create a new application in non-interactive mode with a custom target directory")}
4708
- vp create vite:application --no-interactive --directory=apps/my-app
4709
-
4710
- Use \`vp create --list\` to list all available templates, or run \`vp create --help\` for more information.
4711
- `);
4712
- process.exit(1);
4713
- }
4714
3968
  if (!selectedTemplateName) {
4715
3969
  const template = await select({
4716
3970
  message: "",
@@ -4720,11 +3974,8 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4720
3974
  selectedTemplateName = template;
4721
3975
  }
4722
3976
  const isBuiltinTemplate = selectedTemplateName.startsWith("vite:");
4723
- const isBundledTemplate = bundled !== void 0;
4724
- const isBundledMonorepo = bundled?.monorepo === true;
4725
- const isDirectScaffoldTemplate = isBuiltinTemplate || isBundledTemplate;
4726
- if (!isDirectScaffoldTemplate) compactOutput = false;
4727
- if (targetDir && !isDirectScaffoldTemplate) cancelAndExit("The --directory option is only available for builtin and bundled @org templates", 1);
3977
+ if (!isBuiltinTemplate) compactOutput = false;
3978
+ if (targetDir && !isBuiltinTemplate) cancelAndExit("The --directory option is only available for builtin templates", 1);
4728
3979
  if (selectedTemplateName === BuiltinTemplate.monorepo && isMonorepo) {
4729
3980
  log$1.info("You are already in a monorepo workspace.\nUse a different template or run this command outside the monorepo");
4730
3981
  cancelAndExit("Cannot create a monorepo inside an existing monorepo", 1);
@@ -4786,9 +4037,9 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4786
4037
  remoteTargetDir = await promptTargetDir(defaultTargetDir, options.interactive, { cwd: remoteTargetBaseDir });
4787
4038
  selectedTemplateArgs = [remoteTargetDir, ...selectedTemplateArgs];
4788
4039
  }
4789
- const directScaffoldFallbackName = bundled ? `vite-plus-${bundled.entryName}` : selectedTemplateName === BuiltinTemplate.monorepo ? "vite-plus-monorepo" : `vite-plus-${selectedTemplateName.split(":")[1]}`;
4790
- if (isDirectScaffoldTemplate && (!targetDir || targetDir === ".")) if (targetDir === ".") {
4791
- packageName = deriveDefaultPackageName(cwd, workspaceInfoOptional.monorepoScope, directScaffoldFallbackName);
4040
+ if (isBuiltinTemplate && (!targetDir || targetDir === ".")) if (targetDir === ".") {
4041
+ const fallbackName = selectedTemplateName === BuiltinTemplate.monorepo ? "vite-plus-monorepo" : `vite-plus-${selectedTemplateName.split(":")[1]}`;
4042
+ packageName = deriveDefaultPackageName(cwd, workspaceInfoOptional.monorepoScope, fallbackName);
4792
4043
  if (isMonorepo) {
4793
4044
  if (!cwdRelativeToRoot) cancelAndExit("Cannot scaffold into the monorepo root directory. Use --directory to specify a target directory", 1);
4794
4045
  const enclosingPackage = workspaceInfoOptional.packages.find((pkg) => cwdRelativeToRoot === pkg.path || cwdRelativeToRoot.startsWith(`${pkg.path}/`));
@@ -4803,7 +4054,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4803
4054
  } else {
4804
4055
  const selected = await promptPackageNameAndTargetDir(getRandomProjectName({
4805
4056
  scope: workspaceInfoOptional.monorepoScope,
4806
- fallbackName: directScaffoldFallbackName
4057
+ fallbackName: `vite-plus-${selectedTemplateName.split(":")[1]}`
4807
4058
  }), options.interactive);
4808
4059
  packageName = selected.packageName;
4809
4060
  targetDir = selectedParentDir ? path.join(selectedParentDir, selected.targetDir).split(path.sep).join("/") : selected.targetDir;
@@ -4871,7 +4122,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4871
4122
  }
4872
4123
  };
4873
4124
  updateCreateProgress("Scaffolding project");
4874
- const templateInfo = discoverTemplate(selectedTemplateName, selectedTemplateArgs, workspaceInfo, options.interactive, bundled?.bundledLocalPath, skipShorthandExpansion);
4125
+ const templateInfo = discoverTemplate(selectedTemplateName, selectedTemplateArgs, workspaceInfo, options.interactive);
4875
4126
  if (selectedParentDir) templateInfo.parentDir = selectedParentDir;
4876
4127
  if (targetDir) templateInfo.parentDir = void 0;
4877
4128
  if (remoteTargetDir) {
@@ -4880,50 +4131,20 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4880
4131
  await checkProjectDirExists(path.join(workspaceInfo.rootDir, projectDir), options.interactive);
4881
4132
  resumeCreateProgress();
4882
4133
  }
4883
- if (templateInfo.command === BuiltinTemplate.monorepo || isBundledMonorepo) {
4884
- let shouldInitGit = true;
4885
- if (options.interactive && !compactOutput) {
4886
- pauseCreateProgress();
4887
- const selected = await confirm({
4888
- message: "Initialize git repository:",
4889
- initialValue: true
4890
- });
4891
- resumeCreateProgress();
4892
- if (q(selected)) {
4893
- log$1.info("Operation cancelled. Skipping git initialization");
4894
- shouldInitGit = false;
4895
- } else shouldInitGit = selected;
4896
- } else if (!compactOutput) log$1.info("Initializing git repository (default: yes)");
4134
+ if (templateInfo.command === BuiltinTemplate.monorepo) {
4897
4135
  updateCreateProgress("Creating monorepo");
4898
4136
  await checkProjectDirExists(path.join(workspaceInfo.rootDir, targetDir), options.interactive);
4899
- const result = isBundledMonorepo ? await executeBundledTemplate(workspaceInfo, {
4137
+ const result = await executeMonorepoTemplate(workspaceInfo, {
4900
4138
  ...templateInfo,
4901
4139
  packageName,
4902
4140
  targetDir
4903
- }) : await executeMonorepoTemplate(workspaceInfo, {
4904
- ...templateInfo,
4905
- packageName,
4906
- targetDir
4907
- }, { silent: compactOutput });
4141
+ }, options.interactive, { silent: compactOutput });
4908
4142
  const { projectDir } = result;
4909
4143
  if (result.exitCode !== 0 || !projectDir) {
4910
4144
  failCreateProgress("Scaffolding failed");
4911
4145
  cancelAndExit(`Failed to create monorepo, exit code: ${result.exitCode}`, result.exitCode);
4912
4146
  }
4913
4147
  const fullPath = path.join(workspaceInfo.rootDir, projectDir);
4914
- if (shouldInitGit) {
4915
- const gitResult = import_cross_spawn.default.sync("git", ["init"], {
4916
- stdio: "pipe",
4917
- cwd: fullPath
4918
- });
4919
- if (gitResult.status === 0) {
4920
- if (!compactOutput) log$1.success("Git repository initialized");
4921
- ensureGitignoreNodeModules(fullPath);
4922
- } else {
4923
- log$1.warn("Failed to initialize git repository");
4924
- if (gitResult.stderr) log$1.info(gitResult.stderr.toString());
4925
- }
4926
- }
4927
4148
  updateCreateProgress("Writing agent instructions");
4928
4149
  pauseCreateProgress();
4929
4150
  await writeAgentInstructions({
@@ -4946,7 +4167,6 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4946
4167
  workspaceInfo.rootDir = fullPath;
4947
4168
  updateCreateProgress("Integrating monorepo");
4948
4169
  rewriteMonorepo(workspaceInfo, void 0, compactOutput);
4949
- if (bundled?.monorepo) injectCreateDefaultTemplate(fullPath, bundled.scope, compactOutput);
4950
4170
  if (shouldSetupHooks) installGitHooks(fullPath, compactOutput);
4951
4171
  updateCreateProgress("Installing dependencies");
4952
4172
  const installSummary = await runViteInstall(fullPath, options.interactive, installArgs, { silent: compactOutput });
@@ -4964,17 +4184,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
4964
4184
  return;
4965
4185
  }
4966
4186
  let result;
4967
- if (templateInfo.type === TemplateType.bundled) {
4968
- pauseCreateProgress();
4969
- await checkProjectDirExists(path.join(workspaceInfo.rootDir, targetDir), options.interactive);
4970
- resumeCreateProgress();
4971
- updateCreateProgress("Copying template files");
4972
- result = await executeBundledTemplate(workspaceInfo, {
4973
- ...templateInfo,
4974
- packageName,
4975
- targetDir
4976
- });
4977
- } else if (templateInfo.type === TemplateType.builtin) {
4187
+ if (templateInfo.type === TemplateType.builtin) {
4978
4188
  if (!targetDir) {
4979
4189
  const selected = await promptPackageNameAndTargetDir(getRandomProjectName({
4980
4190
  scope: workspaceInfo.monorepoScope,