create-krispya 0.2.0 → 0.4.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.
Files changed (61) hide show
  1. package/dist/cli.cjs +550 -0
  2. package/dist/cli.d.cts +1 -0
  3. package/dist/cli.d.mts +1 -0
  4. package/dist/cli.d.ts +1 -2
  5. package/dist/cli.mjs +531 -0
  6. package/dist/index.cjs +1696 -0
  7. package/dist/index.d.cts +148 -0
  8. package/dist/index.d.mts +148 -0
  9. package/dist/index.d.ts +88 -27
  10. package/dist/index.mjs +1684 -0
  11. package/package.json +6 -5
  12. package/dist/cli.js +0 -504
  13. package/dist/constants.d.ts +0 -33
  14. package/dist/constants.js +0 -110
  15. package/dist/index.js +0 -397
  16. package/dist/integrations/biome.d.ts +0 -8
  17. package/dist/integrations/biome.js +0 -80
  18. package/dist/integrations/drei.d.ts +0 -3
  19. package/dist/integrations/drei.js +0 -9
  20. package/dist/integrations/eslint.d.ts +0 -3
  21. package/dist/integrations/eslint.js +0 -78
  22. package/dist/integrations/fiber.d.ts +0 -8
  23. package/dist/integrations/fiber.js +0 -35
  24. package/dist/integrations/github-pages.d.ts +0 -3
  25. package/dist/integrations/github-pages.js +0 -58
  26. package/dist/integrations/handle.d.ts +0 -3
  27. package/dist/integrations/handle.js +0 -7
  28. package/dist/integrations/koota.d.ts +0 -8
  29. package/dist/integrations/koota.js +0 -7
  30. package/dist/integrations/leva.d.ts +0 -3
  31. package/dist/integrations/leva.js +0 -7
  32. package/dist/integrations/offscreen.d.ts +0 -3
  33. package/dist/integrations/offscreen.js +0 -12
  34. package/dist/integrations/oxfmt.d.ts +0 -3
  35. package/dist/integrations/oxfmt.js +0 -27
  36. package/dist/integrations/oxlint.d.ts +0 -3
  37. package/dist/integrations/oxlint.js +0 -52
  38. package/dist/integrations/postprocessing.d.ts +0 -3
  39. package/dist/integrations/postprocessing.js +0 -12
  40. package/dist/integrations/prettier.d.ts +0 -3
  41. package/dist/integrations/prettier.js +0 -28
  42. package/dist/integrations/rapier.d.ts +0 -3
  43. package/dist/integrations/rapier.js +0 -7
  44. package/dist/integrations/triplex.d.ts +0 -26
  45. package/dist/integrations/triplex.js +0 -159
  46. package/dist/integrations/uikit.d.ts +0 -3
  47. package/dist/integrations/uikit.js +0 -7
  48. package/dist/integrations/vitest.d.ts +0 -2
  49. package/dist/integrations/vitest.js +0 -20
  50. package/dist/integrations/viverse.d.ts +0 -3
  51. package/dist/integrations/viverse.js +0 -74
  52. package/dist/integrations/xr.d.ts +0 -5
  53. package/dist/integrations/xr.js +0 -51
  54. package/dist/integrations/zustand.d.ts +0 -8
  55. package/dist/integrations/zustand.js +0 -7
  56. package/dist/lib/array.d.ts +0 -1
  57. package/dist/lib/array.js +0 -9
  58. package/dist/merge.d.ts +0 -1
  59. package/dist/merge.js +0 -26
  60. package/dist/utils.d.ts +0 -22
  61. package/dist/utils.js +0 -123
package/dist/cli.mjs ADDED
@@ -0,0 +1,531 @@
1
+ #!/usr/bin/env node
2
+ import { cwd } from 'process';
3
+ import { getBaseTemplate, getLatestPnpmVersion, getLatestNodeVersion, getLatestNpmVersion, generate, generateRandomName, getLanguageFromTemplate } from './index.mjs';
4
+ import { join, dirname } from 'path';
5
+ import { mkdir, writeFile } from 'fs/promises';
6
+ import { Command } from 'commander';
7
+ import * as p from '@clack/prompts';
8
+ import color from 'chalk';
9
+ import { fetch } from 'undici';
10
+
11
+ function getDefaultProjectName(template) {
12
+ const base = getBaseTemplate(template);
13
+ switch (base) {
14
+ case "vanilla":
15
+ return `vanilla-${generateRandomName()}`;
16
+ case "react":
17
+ return `react-${generateRandomName()}`;
18
+ case "r3f":
19
+ return `react-three-${generateRandomName()}`;
20
+ }
21
+ }
22
+ function getDefaultOptions(template, name, projectType = "app", libraryBundler) {
23
+ const baseTemplate = getBaseTemplate(template);
24
+ const base = {
25
+ name,
26
+ template,
27
+ projectType,
28
+ libraryBundler: projectType === "library" ? libraryBundler ?? "unbuild" : void 0,
29
+ packageManager: "pnpm",
30
+ pnpmManageVersions: true,
31
+ nodeVersion: "latest",
32
+ linter: "oxlint",
33
+ formatter: "oxfmt"
34
+ };
35
+ if (baseTemplate === "r3f") {
36
+ return {
37
+ ...base,
38
+ drei: {},
39
+ handle: {},
40
+ leva: {},
41
+ postprocessing: {},
42
+ rapier: {},
43
+ xr: {},
44
+ uikit: {},
45
+ offscreen: {},
46
+ zustand: {},
47
+ koota: {},
48
+ triplex: {},
49
+ viverse: {}
50
+ };
51
+ }
52
+ return base;
53
+ }
54
+ function formatConfigSummary(options) {
55
+ const lines = [];
56
+ const VALUE_COL = 27;
57
+ const formatRow = (label, value, indent = "") => {
58
+ const fullLabel = indent + label;
59
+ const dotCount = Math.max(1, VALUE_COL - fullLabel.length - 1);
60
+ const dots = color.gray(".".repeat(dotCount));
61
+ return `${indent}${label} ${dots} ${value}`;
62
+ };
63
+ const formatLanguage = (lang) => {
64
+ return lang === "typescript" ? "TypeScript" : lang === "javascript" ? "JavaScript" : lang;
65
+ };
66
+ const projectType = options.projectType ?? "app";
67
+ const language = options.template ? getLanguageFromTemplate(options.template) : "typescript";
68
+ lines.push(formatRow("Language", formatLanguage(language)));
69
+ if (projectType === "library") {
70
+ lines.push(formatRow("Bundler", options.libraryBundler ?? "unbuild"));
71
+ } else {
72
+ lines.push(formatRow("Bundler", "vite"));
73
+ }
74
+ lines.push(formatRow("Node version", options.nodeVersion || "latest"));
75
+ lines.push(formatRow("Package manager", options.packageManager || "pnpm"));
76
+ if (options.packageManager === "pnpm") {
77
+ const versionManaged = options.pnpmManageVersions ? "yes" : "no";
78
+ lines.push(formatRow("\u21B3 Version managed", versionManaged, ""));
79
+ }
80
+ if (options.linter) {
81
+ lines.push(formatRow("Linter", options.linter));
82
+ }
83
+ if (options.formatter) {
84
+ lines.push(formatRow("Formatter", options.formatter));
85
+ }
86
+ lines.push(formatRow("Testing", "vitest"));
87
+ if (options.template && getBaseTemplate(options.template) === "r3f") {
88
+ const integrationNames = [
89
+ options.drei && "drei",
90
+ options.handle && "handle",
91
+ options.leva && "leva",
92
+ options.postprocessing && "postproc",
93
+ options.rapier && "rapier",
94
+ options.xr && "xr",
95
+ options.uikit && "uikit",
96
+ options.offscreen && "offscreen",
97
+ options.zustand && "zustand",
98
+ options.koota && "koota",
99
+ options.triplex && "triplex",
100
+ options.viverse && "viverse"
101
+ ].filter(Boolean);
102
+ lines.push("");
103
+ lines.push(color.dim("Integrations"));
104
+ for (let i = 0; i < integrationNames.length; i += 2) {
105
+ const left = `${color.green("\u25CF")} ${integrationNames[i]}`;
106
+ const right = integrationNames[i + 1] ? `${color.green("\u25CF")} ${integrationNames[i + 1]}` : "";
107
+ const spacing = " ".repeat(Math.max(1, 16 - integrationNames[i].length));
108
+ lines.push(` ${left}${spacing}${right}`);
109
+ }
110
+ }
111
+ return lines.join("\n");
112
+ }
113
+ async function promptForCustomization(template, name, projectType) {
114
+ let libraryBundler;
115
+ if (projectType === "library") {
116
+ const bundler = await p.select({
117
+ message: "Library bundler",
118
+ options: [
119
+ { value: "unbuild", label: "unbuild", hint: "unjs, simple config" },
120
+ { value: "tsdown", label: "tsdown", hint: "fast, esbuild-based" }
121
+ ],
122
+ initialValue: "unbuild"
123
+ });
124
+ if (p.isCancel(bundler)) {
125
+ p.cancel("Operation cancelled.");
126
+ process.exit(0);
127
+ }
128
+ libraryBundler = bundler;
129
+ }
130
+ const nodeVersion = await p.text({
131
+ message: "Node.js version",
132
+ placeholder: "latest",
133
+ defaultValue: "latest",
134
+ validate: (value) => {
135
+ if (!value.length) return "Required";
136
+ if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
137
+ return 'Must be "latest" or a valid semver (e.g., "22" or "22.13.0")';
138
+ }
139
+ }
140
+ });
141
+ if (p.isCancel(nodeVersion)) {
142
+ p.cancel("Operation cancelled.");
143
+ process.exit(0);
144
+ }
145
+ const packageManager = await p.select({
146
+ message: "Package manager",
147
+ options: [
148
+ { value: "pnpm", label: "pnpm" },
149
+ { value: "npm", label: "npm" },
150
+ { value: "yarn", label: "yarn" },
151
+ { value: "custom", label: "Other (custom)" }
152
+ ],
153
+ initialValue: "pnpm"
154
+ });
155
+ if (p.isCancel(packageManager)) {
156
+ p.cancel("Operation cancelled.");
157
+ process.exit(0);
158
+ }
159
+ let finalPackageManager = packageManager;
160
+ if (packageManager === "custom") {
161
+ const customPm = await p.text({
162
+ message: "Enter package manager command",
163
+ validate: (value) => {
164
+ if (!value.length) return "Required";
165
+ }
166
+ });
167
+ if (p.isCancel(customPm)) {
168
+ p.cancel("Operation cancelled.");
169
+ process.exit(0);
170
+ }
171
+ finalPackageManager = customPm;
172
+ }
173
+ let pnpmManageVersions = true;
174
+ if (packageManager === "pnpm") {
175
+ const managePnpm = await p.confirm({
176
+ message: "Enable manage-package-manager-versions?",
177
+ initialValue: true
178
+ });
179
+ if (p.isCancel(managePnpm)) {
180
+ p.cancel("Operation cancelled.");
181
+ process.exit(0);
182
+ }
183
+ pnpmManageVersions = managePnpm;
184
+ }
185
+ const linter = await p.select({
186
+ message: "Linter",
187
+ options: [
188
+ { value: "oxlint", label: "Oxlint", hint: "fast, from OXC" },
189
+ { value: "eslint", label: "ESLint", hint: "classic" },
190
+ { value: "biome", label: "Biome", hint: "all-in-one" }
191
+ ],
192
+ initialValue: "oxlint"
193
+ });
194
+ if (p.isCancel(linter)) {
195
+ p.cancel("Operation cancelled.");
196
+ process.exit(0);
197
+ }
198
+ const formatter = await p.select({
199
+ message: "Formatter",
200
+ options: [
201
+ { value: "oxfmt", label: "Oxfmt", hint: "fast, Prettier-compatible" },
202
+ { value: "prettier", label: "Prettier", hint: "classic" },
203
+ { value: "biome", label: "Biome", hint: "all-in-one" }
204
+ ],
205
+ initialValue: "oxfmt"
206
+ });
207
+ if (p.isCancel(formatter)) {
208
+ p.cancel("Operation cancelled.");
209
+ process.exit(0);
210
+ }
211
+ const language = await p.select({
212
+ message: "Language",
213
+ options: [
214
+ { value: "typescript", label: "TypeScript" },
215
+ { value: "javascript", label: "JavaScript" }
216
+ ],
217
+ initialValue: "typescript"
218
+ });
219
+ if (p.isCancel(language)) {
220
+ p.cancel("Operation cancelled.");
221
+ process.exit(0);
222
+ }
223
+ const baseTemplate = getBaseTemplate(template);
224
+ const finalTemplate = language === "javascript" ? `${baseTemplate}-js` : baseTemplate;
225
+ let integrations = [];
226
+ if (baseTemplate === "r3f") {
227
+ const selected = await p.multiselect({
228
+ message: "R3F integrations",
229
+ options: [
230
+ { value: "drei", label: "Drei" },
231
+ { value: "handle", label: "Handle" },
232
+ { value: "leva", label: "Leva" },
233
+ { value: "postprocessing", label: "Postprocessing" },
234
+ { value: "rapier", label: "Rapier" },
235
+ { value: "xr", label: "XR" },
236
+ { value: "uikit", label: "UIKit" },
237
+ { value: "offscreen", label: "Offscreen" },
238
+ { value: "zustand", label: "Zustand" },
239
+ { value: "koota", label: "Koota" },
240
+ { value: "triplex", label: "Triplex" },
241
+ { value: "viverse", label: "Viverse" }
242
+ ],
243
+ initialValues: [
244
+ "drei",
245
+ "handle",
246
+ "leva",
247
+ "postprocessing",
248
+ "rapier",
249
+ "xr",
250
+ "uikit",
251
+ "offscreen",
252
+ "zustand",
253
+ "koota",
254
+ "triplex",
255
+ "viverse"
256
+ ],
257
+ required: false
258
+ });
259
+ if (p.isCancel(selected)) {
260
+ p.cancel("Operation cancelled.");
261
+ process.exit(0);
262
+ }
263
+ integrations = selected;
264
+ }
265
+ return {
266
+ name,
267
+ template: finalTemplate,
268
+ projectType,
269
+ libraryBundler: projectType === "library" ? libraryBundler : void 0,
270
+ nodeVersion,
271
+ packageManager: finalPackageManager,
272
+ pnpmManageVersions,
273
+ linter,
274
+ formatter,
275
+ ...baseTemplate === "r3f" && {
276
+ drei: integrations.includes("drei") ? {} : void 0,
277
+ handle: integrations.includes("handle") ? {} : void 0,
278
+ leva: integrations.includes("leva") ? {} : void 0,
279
+ postprocessing: integrations.includes("postprocessing") ? {} : void 0,
280
+ rapier: integrations.includes("rapier") ? {} : void 0,
281
+ xr: integrations.includes("xr") ? {} : void 0,
282
+ uikit: integrations.includes("uikit") ? {} : void 0,
283
+ offscreen: integrations.includes("offscreen") ? {} : void 0,
284
+ zustand: integrations.includes("zustand") ? {} : void 0,
285
+ koota: integrations.includes("koota") ? {} : void 0,
286
+ triplex: integrations.includes("triplex") ? {} : void 0,
287
+ viverse: integrations.includes("viverse") ? {} : void 0
288
+ }
289
+ };
290
+ }
291
+ async function promptForOptions(name) {
292
+ let projectName = name;
293
+ if (!projectName) {
294
+ const nameResult = await p.text({
295
+ message: "What is your project named?",
296
+ placeholder: generateRandomName(),
297
+ defaultValue: generateRandomName(),
298
+ validate: (value) => {
299
+ if (!value.length) return "Project name is required";
300
+ }
301
+ });
302
+ if (p.isCancel(nameResult)) {
303
+ p.cancel("Operation cancelled.");
304
+ process.exit(0);
305
+ }
306
+ projectName = nameResult;
307
+ }
308
+ const projectType = await p.select({
309
+ message: "Project type",
310
+ options: [
311
+ { value: "app", label: "Application" },
312
+ { value: "library", label: "Library" }
313
+ ],
314
+ initialValue: "app"
315
+ });
316
+ if (p.isCancel(projectType)) {
317
+ p.cancel("Operation cancelled.");
318
+ process.exit(0);
319
+ }
320
+ const template = await p.select({
321
+ message: "Select a template",
322
+ options: [
323
+ { value: "vanilla", label: "Vanilla" },
324
+ { value: "react", label: "React" },
325
+ { value: "r3f", label: "React Three Fiber" }
326
+ ],
327
+ initialValue: "vanilla"
328
+ });
329
+ if (p.isCancel(template)) {
330
+ p.cancel("Operation cancelled.");
331
+ process.exit(0);
332
+ }
333
+ const defaultOptions = getDefaultOptions(
334
+ template,
335
+ projectName,
336
+ projectType
337
+ );
338
+ p.note(formatConfigSummary(defaultOptions), "Template Configuration");
339
+ const action = await p.select({
340
+ message: "Proceed with these settings?",
341
+ options: [
342
+ { value: "confirm", label: "Yes, create project" },
343
+ { value: "customize", label: "No, let me customize" }
344
+ ],
345
+ initialValue: "confirm"
346
+ });
347
+ if (p.isCancel(action)) {
348
+ p.cancel("Operation cancelled.");
349
+ process.exit(0);
350
+ }
351
+ if (action === "confirm") {
352
+ return defaultOptions;
353
+ }
354
+ return promptForCustomization(
355
+ template,
356
+ projectName,
357
+ projectType
358
+ );
359
+ }
360
+ async function main() {
361
+ const program = new Command().name("create-krispya").description(
362
+ "CLI for creating Vanilla, React, and React Three Fiber projects"
363
+ ).argument("[name]", "name for the project").option(
364
+ "--type <type>",
365
+ "project type: app or library (default: app)"
366
+ ).option(
367
+ "--bundler <bundler>",
368
+ "library bundler: unbuild or tsdown (default: unbuild, only for libraries)"
369
+ ).option(
370
+ "--template <type>",
371
+ "project template: vanilla, vanilla-js, react, react-js, r3f, r3f-js (default: vanilla)"
372
+ ).option(
373
+ "--linter <type>",
374
+ "linter: eslint, oxlint, or biome (default: oxlint)"
375
+ ).option(
376
+ "--formatter <type>",
377
+ "formatter: prettier, oxfmt, or biome (default: oxfmt)"
378
+ ).option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option(
379
+ "--package-manager <manager>",
380
+ "specify package manager (e.g. npm, yarn, pnpm)"
381
+ ).option(
382
+ "--pnpm-manage-versions",
383
+ "enable manage-package-manager-versions in pnpm-workspace.yaml (default: true)"
384
+ ).option(
385
+ "--no-pnpm-manage-versions",
386
+ "disable manage-package-manager-versions in pnpm-workspace.yaml"
387
+ ).option(
388
+ "--node-version <version>",
389
+ 'set Node.js version for engines.node field (default: "latest")'
390
+ ).option("-y, --yes", "Skip prompts and use default values").action(async (name, options) => {
391
+ console.clear();
392
+ p.intro(color.bgCyan(color.black(" create-krispya ")));
393
+ let generateOptions;
394
+ if (Object.keys(options).length > 0) {
395
+ const template = options.template ?? "vanilla";
396
+ const baseTemplate = getBaseTemplate(template);
397
+ const defaultName = getDefaultProjectName(template);
398
+ const projectType = options.type ?? "app";
399
+ generateOptions = {
400
+ name: name || defaultName,
401
+ projectType,
402
+ libraryBundler: projectType === "library" ? options.bundler ?? "unbuild" : void 0,
403
+ template,
404
+ linter: options.linter ?? "oxlint",
405
+ formatter: options.formatter ?? "oxfmt",
406
+ ...baseTemplate === "r3f" && {
407
+ drei: options.drei ? {} : void 0,
408
+ handle: options.handle ? {} : void 0,
409
+ leva: options.leva ? {} : void 0,
410
+ postprocessing: options.postprocessing ? {} : void 0,
411
+ rapier: options.rapier ? {} : void 0,
412
+ xr: options.xr ? {} : void 0,
413
+ uikit: options.uikit ? {} : void 0,
414
+ offscreen: options.offscreen ? {} : void 0,
415
+ zustand: options.zustand ? {} : void 0,
416
+ koota: options.koota ? {} : void 0,
417
+ viverse: options.viverse ? {} : void 0,
418
+ triplex: options.triplex ? {} : void 0
419
+ },
420
+ packageManager: options.packageManager,
421
+ pnpmManageVersions: options.pnpmManageVersions,
422
+ nodeVersion: options.nodeVersion ?? "latest"
423
+ };
424
+ } else {
425
+ generateOptions = await promptForOptions(name);
426
+ }
427
+ const base = generateOptions.template ? getBaseTemplate(generateOptions.template) : "vanilla";
428
+ const defaultFallbackName = base === "vanilla" ? "vanilla-app" : base === "react" ? "react-app" : "react-three-app";
429
+ generateOptions.name ??= defaultFallbackName;
430
+ const packageManager = generateOptions.packageManager || "pnpm";
431
+ if (packageManager === "pnpm") {
432
+ generateOptions.pnpmVersion = await getLatestPnpmVersion();
433
+ }
434
+ const nodeVersion = generateOptions.nodeVersion ?? "latest";
435
+ if (nodeVersion === "latest") {
436
+ generateOptions.nodeVersion = await getLatestNodeVersion();
437
+ }
438
+ const versions = {};
439
+ const versionPromises = [
440
+ getLatestNpmVersion("vitest", "4.0.0").then((v) => {
441
+ versions.vitest = v;
442
+ })
443
+ ];
444
+ if (generateOptions.projectType !== "library") {
445
+ versionPromises.push(
446
+ getLatestNpmVersion("vite", "6.3.4").then((v) => {
447
+ versions.vite = v;
448
+ })
449
+ );
450
+ }
451
+ const linter = generateOptions.linter ?? "oxlint";
452
+ if (linter === "eslint") {
453
+ versionPromises.push(
454
+ getLatestNpmVersion("eslint", "9.17.0").then((v) => {
455
+ versions.eslint = v;
456
+ })
457
+ );
458
+ } else if (linter === "oxlint") {
459
+ versionPromises.push(
460
+ getLatestNpmVersion("oxlint", "0.16.0").then((v) => {
461
+ versions.oxlint = v;
462
+ })
463
+ );
464
+ } else if (linter === "biome") {
465
+ versionPromises.push(
466
+ getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
467
+ versions.biome = v;
468
+ })
469
+ );
470
+ }
471
+ const formatter = generateOptions.formatter ?? "oxfmt";
472
+ if (formatter === "prettier") {
473
+ versionPromises.push(
474
+ getLatestNpmVersion("prettier", "3.4.2").then((v) => {
475
+ versions.prettier = v;
476
+ })
477
+ );
478
+ } else if (formatter === "oxfmt") {
479
+ versionPromises.push(
480
+ getLatestNpmVersion("oxfmt", "0.1.0").then((v) => {
481
+ versions.oxfmt = v;
482
+ })
483
+ );
484
+ } else if (formatter === "biome" && linter !== "biome") {
485
+ versionPromises.push(
486
+ getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
487
+ versions.biome = v;
488
+ })
489
+ );
490
+ }
491
+ await Promise.all(versionPromises);
492
+ generateOptions.versions = versions;
493
+ const basePath = join(cwd(), generateOptions.name);
494
+ const s = p.spinner();
495
+ s.start("Creating project...");
496
+ try {
497
+ const files = generate(generateOptions);
498
+ const filePaths = Object.keys(files).sort();
499
+ for (const filePath of filePaths) {
500
+ const fullFilePath = join(basePath, filePath);
501
+ await mkdir(dirname(fullFilePath), { recursive: true });
502
+ const file = files[filePath];
503
+ if (file.type === "text") {
504
+ await writeFile(fullFilePath, file.content);
505
+ } else {
506
+ const response = await fetch(file.url);
507
+ await writeFile(fullFilePath, response.body);
508
+ }
509
+ }
510
+ s.stop("Project created!");
511
+ const isLibrary = generateOptions.projectType === "library";
512
+ const nextSteps = isLibrary ? [
513
+ `cd ${generateOptions.name}`,
514
+ `${packageManager} install`,
515
+ `${packageManager} run build`
516
+ ].join("\n") : [
517
+ `cd ${generateOptions.name}`,
518
+ `${packageManager} install`,
519
+ `${packageManager} run dev`
520
+ ].join("\n");
521
+ p.note(nextSteps, "Next steps");
522
+ p.outro(color.green("Happy coding! \u2728"));
523
+ } catch (error) {
524
+ s.stop("Failed to create project");
525
+ p.log.error(String(error));
526
+ process.exit(1);
527
+ }
528
+ });
529
+ await program.parseAsync();
530
+ }
531
+ main().catch(console.error);