@svton/cli 1.0.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,722 @@
1
+ #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // src/index.ts
10
+ import { Command } from "commander";
11
+
12
+ // src/commands/create.ts
13
+ import inquirer from "inquirer";
14
+ import chalk2 from "chalk";
15
+ import ora from "ora";
16
+ import fs3 from "fs-extra";
17
+ import path2 from "path";
18
+ import validateNpmPackageName from "validate-npm-package-name";
19
+
20
+ // src/utils/template.ts
21
+ import fs2 from "fs-extra";
22
+
23
+ // src/utils/logger.ts
24
+ import chalk from "chalk";
25
+ var logger = {
26
+ info: (message) => {
27
+ console.log(message);
28
+ },
29
+ success: (message) => {
30
+ console.log(chalk.green(message));
31
+ },
32
+ warn: (message) => {
33
+ console.log(chalk.yellow(message));
34
+ },
35
+ error: (message) => {
36
+ console.log(chalk.red(message));
37
+ },
38
+ debug: (message) => {
39
+ if (process.env.DEBUG) {
40
+ console.log(chalk.gray(`[DEBUG] ${message}`));
41
+ }
42
+ }
43
+ };
44
+
45
+ // src/utils/copy-template.ts
46
+ import fs from "fs-extra";
47
+ import path from "path";
48
+ async function copyTemplateFiles(config) {
49
+ const { template, projectPath } = config;
50
+ const cliDir = path.dirname(path.dirname(__dirname));
51
+ const frameworkRoot = path.dirname(path.dirname(cliDir));
52
+ const templateDir = path.join(frameworkRoot, "templates");
53
+ logger.debug(`Copying template files from: ${templateDir}`);
54
+ if (!await fs.pathExists(templateDir)) {
55
+ logger.warn("Template directory not found, using built-in minimal templates");
56
+ await copyBuiltInTemplates(config);
57
+ return;
58
+ }
59
+ const originalCwd = process.cwd();
60
+ process.chdir(projectPath);
61
+ try {
62
+ switch (template) {
63
+ case "full-stack":
64
+ await copyBackendTemplate(templateDir, config);
65
+ await copyAdminTemplate(templateDir, config);
66
+ await copyMobileTemplate(templateDir, config);
67
+ await copyTypesTemplate(templateDir, config);
68
+ break;
69
+ case "backend-only":
70
+ await copyBackendTemplate(templateDir, config);
71
+ await copyTypesTemplate(templateDir, config);
72
+ break;
73
+ case "admin-only":
74
+ await copyAdminTemplate(templateDir, config);
75
+ await copyTypesTemplate(templateDir, config);
76
+ break;
77
+ case "mobile-only":
78
+ await copyMobileTemplate(templateDir, config);
79
+ await copyTypesTemplate(templateDir, config);
80
+ break;
81
+ }
82
+ } finally {
83
+ process.chdir(originalCwd);
84
+ }
85
+ }
86
+ async function copyBackendTemplate(sourceDir, config) {
87
+ const sourcePath = path.join(sourceDir, "apps/backend");
88
+ const destPath = "apps/backend";
89
+ await fs.ensureDir(destPath);
90
+ await fs.copy(sourcePath, destPath, {
91
+ filter: (src) => {
92
+ const relativePath = path.relative(sourcePath, src);
93
+ return !relativePath.includes("node_modules") && !relativePath.includes("dist") && !relativePath.includes(".env") && !relativePath.includes(".env.local");
94
+ }
95
+ });
96
+ await replacePackageNames(destPath, config);
97
+ logger.debug("Backend template copied");
98
+ }
99
+ async function copyAdminTemplate(sourceDir, config) {
100
+ const sourcePath = path.join(sourceDir, "apps/admin");
101
+ const destPath = "apps/admin";
102
+ await fs.ensureDir(destPath);
103
+ await fs.copy(sourcePath, destPath, {
104
+ filter: (src) => {
105
+ const relativePath = path.relative(sourcePath, src);
106
+ return !relativePath.includes("node_modules") && !relativePath.includes(".next") && !relativePath.includes(".env.local");
107
+ }
108
+ });
109
+ await replacePackageNames(destPath, config);
110
+ logger.debug("Admin template copied");
111
+ }
112
+ async function copyMobileTemplate(sourceDir, config) {
113
+ const sourcePath = path.join(sourceDir, "apps/mobile");
114
+ const destPath = "apps/mobile";
115
+ await fs.ensureDir(destPath);
116
+ await fs.copy(sourcePath, destPath, {
117
+ filter: (src) => {
118
+ const relativePath = path.relative(sourcePath, src);
119
+ return !relativePath.includes("node_modules") && !relativePath.includes("dist");
120
+ }
121
+ });
122
+ await replacePackageNames(destPath, config);
123
+ logger.debug("Mobile template copied");
124
+ }
125
+ async function copyTypesTemplate(sourceDir, config) {
126
+ const sourcePath = path.join(sourceDir, "packages/types");
127
+ const destPath = "packages/types";
128
+ await fs.ensureDir(destPath);
129
+ await fs.copy(sourcePath, destPath, {
130
+ filter: (src) => {
131
+ const relativePath = path.relative(sourcePath, src);
132
+ return !relativePath.includes("node_modules") && !relativePath.includes("dist");
133
+ }
134
+ });
135
+ await replacePackageNames(destPath, config);
136
+ logger.debug("Types package copied");
137
+ }
138
+ async function replacePackageNames(directory, config) {
139
+ const { projectName, orgName } = config;
140
+ const filesToUpdate = await findFilesToUpdate(directory);
141
+ for (const filePath of filesToUpdate) {
142
+ try {
143
+ let content = await fs.readFile(filePath, "utf8");
144
+ content = content.replace(/@svton\//g, `${orgName}/`).replace(/community-next/g, projectName).replace(/community-helper/g, projectName).replace(/社区助手/g, projectName);
145
+ await fs.writeFile(filePath, content);
146
+ } catch (error) {
147
+ logger.debug(`Failed to update file ${filePath}: ${error}`);
148
+ }
149
+ }
150
+ }
151
+ async function findFilesToUpdate(directory) {
152
+ const files = [];
153
+ const traverse = async (dir) => {
154
+ const entries = await fs.readdir(dir, { withFileTypes: true });
155
+ for (const entry of entries) {
156
+ const fullPath = path.join(dir, entry.name);
157
+ if (entry.isDirectory()) {
158
+ await traverse(fullPath);
159
+ } else if (entry.isFile()) {
160
+ const ext = path.extname(entry.name);
161
+ const shouldUpdate = [".json", ".ts", ".tsx", ".js", ".jsx", ".md", ".yaml", ".yml", ".env.example"].includes(ext);
162
+ if (shouldUpdate) {
163
+ files.push(fullPath);
164
+ }
165
+ }
166
+ }
167
+ };
168
+ await traverse(directory);
169
+ return files;
170
+ }
171
+ async function copyBuiltInTemplates(config) {
172
+ logger.info("Creating minimal project structure...");
173
+ const { template } = config;
174
+ if (template === "full-stack" || template === "backend-only") {
175
+ await createMinimalBackend(config);
176
+ }
177
+ if (template === "full-stack" || template === "admin-only") {
178
+ await createMinimalAdmin(config);
179
+ }
180
+ if (template === "full-stack" || template === "mobile-only") {
181
+ await createMinimalMobile(config);
182
+ }
183
+ await createMinimalTypes(config);
184
+ }
185
+ async function createMinimalBackend(config) {
186
+ const dir = "apps/backend";
187
+ await fs.ensureDir(dir);
188
+ const packageJson = {
189
+ name: `${config.orgName}/backend`,
190
+ version: "1.0.0",
191
+ description: "Backend API server",
192
+ scripts: {
193
+ build: "nest build",
194
+ dev: "nest start --watch",
195
+ start: "node dist/main",
196
+ lint: 'eslint "src/**/*.{ts,tsx}"',
197
+ "type-check": "tsc --noEmit"
198
+ },
199
+ dependencies: {
200
+ "@nestjs/common": "^10.3.0",
201
+ "@nestjs/core": "^10.3.0",
202
+ "@nestjs/platform-express": "^10.3.0",
203
+ "reflect-metadata": "^0.2.1",
204
+ "rxjs": "^7.8.1"
205
+ },
206
+ devDependencies: {
207
+ "@nestjs/cli": "^10.2.1",
208
+ "@types/node": "^20.10.0",
209
+ "typescript": "^5.3.0"
210
+ }
211
+ };
212
+ await fs.writeJson(path.join(dir, "package.json"), packageJson, { spaces: 2 });
213
+ }
214
+ async function createMinimalAdmin(config) {
215
+ const dir = "apps/admin";
216
+ await fs.ensureDir(dir);
217
+ const packageJson = {
218
+ name: `${config.orgName}/admin`,
219
+ version: "1.0.0",
220
+ description: "Admin panel",
221
+ scripts: {
222
+ dev: "next dev -p 3001",
223
+ build: "next build",
224
+ start: "next start -p 3001",
225
+ lint: "next lint",
226
+ "type-check": "tsc --noEmit"
227
+ },
228
+ dependencies: {
229
+ "next": "^15.5.0",
230
+ "react": "^19.0.0",
231
+ "react-dom": "^19.0.0"
232
+ },
233
+ devDependencies: {
234
+ "@types/node": "^22.10.2",
235
+ "@types/react": "^19.0.2",
236
+ "@types/react-dom": "^19.0.2",
237
+ "typescript": "^5.7.3"
238
+ }
239
+ };
240
+ await fs.writeJson(path.join(dir, "package.json"), packageJson, { spaces: 2 });
241
+ }
242
+ async function createMinimalMobile(config) {
243
+ const dir = "apps/mobile";
244
+ await fs.ensureDir(dir);
245
+ const packageJson = {
246
+ name: `${config.orgName}/mobile`,
247
+ version: "1.0.0",
248
+ description: "Mobile application",
249
+ scripts: {
250
+ "build:weapp": "taro build --type weapp",
251
+ "dev:weapp": "taro build --type weapp --watch",
252
+ dev: "npm run dev:weapp",
253
+ lint: 'eslint "src/**/*.{ts,tsx}"',
254
+ "type-check": "tsc --noEmit"
255
+ },
256
+ dependencies: {
257
+ "@tarojs/components": "3.6.23",
258
+ "@tarojs/runtime": "3.6.23",
259
+ "@tarojs/taro": "3.6.23",
260
+ "@tarojs/react": "3.6.23",
261
+ "react": "^18.2.0"
262
+ },
263
+ devDependencies: {
264
+ "@tarojs/cli": "3.6.23",
265
+ "@types/react": "^18.2.45",
266
+ "typescript": "^5.3.3"
267
+ }
268
+ };
269
+ await fs.writeJson(path.join(dir, "package.json"), packageJson, { spaces: 2 });
270
+ }
271
+ async function createMinimalTypes(config) {
272
+ const dir = "packages/types";
273
+ await fs.ensureDir(dir);
274
+ const packageJson = {
275
+ name: `${config.orgName}/types`,
276
+ version: "1.0.0",
277
+ description: "Shared type definitions",
278
+ main: "./dist/index.js",
279
+ types: "./dist/index.d.ts",
280
+ scripts: {
281
+ build: "tsup src/index.ts --format cjs,esm --dts",
282
+ dev: "tsup src/index.ts --format cjs,esm --dts --watch",
283
+ "type-check": "tsc --noEmit"
284
+ },
285
+ devDependencies: {
286
+ "tsup": "^8.0.1",
287
+ "typescript": "^5.3.3"
288
+ }
289
+ };
290
+ await fs.writeJson(path.join(dir, "package.json"), packageJson, { spaces: 2 });
291
+ }
292
+
293
+ // src/utils/template.ts
294
+ async function generateFromTemplate(config) {
295
+ await createRootFiles(config);
296
+ await copyTemplateFiles({
297
+ projectName: config.projectName,
298
+ orgName: config.orgName,
299
+ template: config.template,
300
+ projectPath: config.projectPath
301
+ });
302
+ }
303
+ async function createRootFiles(config) {
304
+ const { projectName, orgName, packageManager } = config;
305
+ const packageJson = {
306
+ name: projectName,
307
+ version: "1.0.0",
308
+ private: true,
309
+ description: `Full-stack application based on Svton architecture`,
310
+ scripts: {
311
+ dev: "turbo run dev",
312
+ [`dev:backend`]: `turbo run dev --filter=${orgName}/backend`,
313
+ [`dev:admin`]: `turbo run dev --filter=${orgName}/admin`,
314
+ [`dev:mobile`]: `turbo run dev --filter=${orgName}/mobile`,
315
+ build: "turbo run build",
316
+ lint: "turbo run lint",
317
+ "type-check": "turbo run type-check",
318
+ clean: "turbo run clean && rm -rf node_modules"
319
+ },
320
+ devDependencies: {
321
+ turbo: "^1.11.0",
322
+ typescript: "^5.3.0",
323
+ "@types/node": "^20.10.0",
324
+ prettier: "^3.1.0",
325
+ eslint: "^8.55.0"
326
+ },
327
+ packageManager: `${packageManager}@8.12.0`,
328
+ engines: {
329
+ node: ">=18.0.0",
330
+ pnpm: ">=8.0.0"
331
+ }
332
+ };
333
+ await fs2.writeJson("package.json", packageJson, { spaces: 2 });
334
+ const workspaceConfig = `packages:
335
+ - 'apps/*'
336
+ - 'packages/*'
337
+ `;
338
+ await fs2.writeFile("pnpm-workspace.yaml", workspaceConfig);
339
+ const turboConfig = {
340
+ "$schema": "https://turbo.build/schema.json",
341
+ pipeline: {
342
+ build: {
343
+ dependsOn: ["^build"],
344
+ outputs: ["dist/**", ".next/**", "build/**"]
345
+ },
346
+ dev: {
347
+ cache: false,
348
+ persistent: true
349
+ },
350
+ lint: {
351
+ outputs: []
352
+ },
353
+ "type-check": {
354
+ dependsOn: ["^build"],
355
+ outputs: []
356
+ },
357
+ clean: {
358
+ cache: false
359
+ }
360
+ }
361
+ };
362
+ await fs2.writeJson("turbo.json", turboConfig, { spaces: 2 });
363
+ const gitignore = `# Dependencies
364
+ node_modules/
365
+ .pnpm-store/
366
+
367
+ # Build outputs
368
+ dist/
369
+ build/
370
+ .next/
371
+ .turbo/
372
+
373
+ # Environment
374
+ .env
375
+ .env.local
376
+ .env.*.local
377
+
378
+ # IDE
379
+ .idea/
380
+ .vscode/
381
+ *.swp
382
+ *.swo
383
+
384
+ # OS
385
+ .DS_Store
386
+ Thumbs.db
387
+
388
+ # Logs
389
+ *.log
390
+ npm-debug.log*
391
+ yarn-debug.log*
392
+ yarn-error.log*
393
+
394
+ # Testing
395
+ coverage/
396
+
397
+ # Misc
398
+ *.tsbuildinfo
399
+ `;
400
+ await fs2.writeFile(".gitignore", gitignore);
401
+ const npmrc = `auto-install-peers=true
402
+ strict-peer-dependencies=false
403
+ `;
404
+ await fs2.writeFile(".npmrc", npmrc);
405
+ const dockerCompose = `version: '3.8'
406
+
407
+ services:
408
+ mysql:
409
+ image: mysql:8.0
410
+ container_name: ${projectName}-mysql
411
+ restart: unless-stopped
412
+ environment:
413
+ MYSQL_ROOT_PASSWORD: root123456
414
+ MYSQL_DATABASE: ${projectName}
415
+ MYSQL_USER: ${projectName}
416
+ MYSQL_PASSWORD: ${projectName}123456
417
+ ports:
418
+ - '3306:3306'
419
+ volumes:
420
+ - mysql_data:/var/lib/mysql
421
+ command: --default-authentication-plugin=mysql_native_password
422
+
423
+ redis:
424
+ image: redis:7-alpine
425
+ container_name: ${projectName}-redis
426
+ restart: unless-stopped
427
+ ports:
428
+ - '6379:6379'
429
+ volumes:
430
+ - redis_data:/data
431
+
432
+ volumes:
433
+ mysql_data:
434
+ redis_data:
435
+ `;
436
+ await fs2.writeFile("docker-compose.yml", dockerCompose);
437
+ const readme = await generateReadme(config);
438
+ await fs2.writeFile("README.md", readme);
439
+ }
440
+ async function generateReadme(config) {
441
+ const { projectName, orgName, template } = config;
442
+ return `# ${projectName}
443
+
444
+ > Based on Svton architecture - Full-stack application
445
+
446
+ ## \u{1F680} Quick Start
447
+
448
+ ### Prerequisites
449
+
450
+ - Node.js >= 18.0.0
451
+ - pnpm >= 8.0.0
452
+ - Docker (for MySQL and Redis)
453
+
454
+ ### Installation
455
+
456
+ \`\`\`bash
457
+ # Install dependencies
458
+ pnpm install
459
+
460
+ # Start databases
461
+ docker-compose up -d
462
+
463
+ # Configure environment variables
464
+ cp apps/backend/.env.example apps/backend/.env
465
+
466
+ # Generate Prisma client
467
+ pnpm --filter ${orgName}/backend prisma:generate
468
+
469
+ # Run database migrations
470
+ pnpm --filter ${orgName}/backend prisma:migrate
471
+
472
+ # Start development servers
473
+ pnpm dev
474
+ \`\`\`
475
+
476
+ ### Services
477
+
478
+ | Service | URL |
479
+ |---------|-----|
480
+ | Backend API | http://localhost:3000 |
481
+ | Admin Panel | http://localhost:3001 |
482
+ | API Docs | http://localhost:3000/api-docs |
483
+
484
+ ## \u{1F4C1} Project Structure
485
+
486
+ \`\`\`
487
+ ${projectName}/
488
+ \u251C\u2500\u2500 apps/
489
+ ${template === "full-stack" || template === "backend-only" ? "\u2502 \u251C\u2500\u2500 backend/ # " + orgName + "/backend - NestJS API" : ""}
490
+ ${template === "full-stack" || template === "admin-only" ? "\u2502 \u251C\u2500\u2500 admin/ # " + orgName + "/admin - Next.js Admin Panel" : ""}
491
+ ${template === "full-stack" || template === "mobile-only" ? "\u2502 \u2514\u2500\u2500 mobile/ # " + orgName + "/mobile - Taro Mini Program" : ""}
492
+ \u251C\u2500\u2500 packages/
493
+ \u2502 \u2514\u2500\u2500 types/ # ${orgName}/types - Shared Type Definitions
494
+ \u251C\u2500\u2500 package.json
495
+ \u251C\u2500\u2500 pnpm-workspace.yaml
496
+ \u251C\u2500\u2500 turbo.json
497
+ \u2514\u2500\u2500 docker-compose.yml
498
+ \`\`\`
499
+
500
+ ## \u{1F6E0}\uFE0F Commands
501
+
502
+ \`\`\`bash
503
+ pnpm dev # Start all services
504
+ pnpm dev:backend # Start backend only
505
+ pnpm dev:admin # Start admin panel only
506
+ pnpm dev:mobile # Start mobile app only
507
+ pnpm build # Build all projects
508
+ pnpm lint # Run linting
509
+ pnpm clean # Clean build artifacts
510
+ \`\`\`
511
+
512
+ ## \u{1F4DA} Documentation
513
+
514
+ - [Svton Architecture](https://github.com/svton/svton)
515
+
516
+ ---
517
+
518
+ Generated with \`create-svton-app\`
519
+ `;
520
+ }
521
+
522
+ // src/utils/install.ts
523
+ import { execSync } from "child_process";
524
+ async function installDependencies(packageManager) {
525
+ try {
526
+ const command = getInstallCommand(packageManager);
527
+ logger.debug(`Running: ${command}`);
528
+ execSync(command, {
529
+ stdio: "inherit",
530
+ cwd: process.cwd()
531
+ });
532
+ } catch (error) {
533
+ throw new Error(`Failed to install dependencies with ${packageManager}`);
534
+ }
535
+ }
536
+ function getInstallCommand(packageManager) {
537
+ switch (packageManager) {
538
+ case "npm":
539
+ return "npm install";
540
+ case "yarn":
541
+ return "yarn install";
542
+ case "pnpm":
543
+ return "pnpm install";
544
+ default:
545
+ throw new Error(`Unsupported package manager: ${packageManager}`);
546
+ }
547
+ }
548
+
549
+ // src/utils/git.ts
550
+ import { execSync as execSync2 } from "child_process";
551
+ async function initGit(projectName) {
552
+ try {
553
+ try {
554
+ execSync2("git status", { stdio: "ignore" });
555
+ logger.debug("Git repository already exists, skipping initialization");
556
+ return;
557
+ } catch {
558
+ }
559
+ execSync2("git init", { stdio: "ignore" });
560
+ execSync2("git add .", { stdio: "ignore" });
561
+ execSync2(`git commit -m "feat: initialize ${projectName} project"`, {
562
+ stdio: "ignore"
563
+ });
564
+ logger.debug("Git repository initialized successfully");
565
+ } catch (error) {
566
+ logger.warn("Failed to initialize Git repository");
567
+ logger.debug(error instanceof Error ? error.message : String(error));
568
+ }
569
+ }
570
+
571
+ // src/commands/create.ts
572
+ async function createProject(projectName, options = {}) {
573
+ try {
574
+ const validation = validateNpmPackageName(projectName);
575
+ if (!validation.validForNewPackages) {
576
+ logger.error(`Invalid project name: ${projectName}`);
577
+ if (validation.errors) {
578
+ validation.errors.forEach((error) => logger.error(`- ${error}`));
579
+ }
580
+ process.exit(1);
581
+ }
582
+ const projectPath = path2.resolve(process.cwd(), projectName);
583
+ if (await fs3.pathExists(projectPath)) {
584
+ logger.error(`Directory ${projectName} already exists!`);
585
+ process.exit(1);
586
+ }
587
+ logger.info(chalk2.blue("\u{1F680} Welcome to Svton App Generator!"));
588
+ logger.info("");
589
+ const answers = await inquirer.prompt([
590
+ {
591
+ type: "input",
592
+ name: "org",
593
+ message: "Organization name (will be used as @org/package-name):",
594
+ default: options.org || projectName,
595
+ validate: (input) => {
596
+ if (!input.trim()) return "Organization name is required";
597
+ return true;
598
+ }
599
+ },
600
+ {
601
+ type: "list",
602
+ name: "template",
603
+ message: "Choose a template:",
604
+ choices: [
605
+ { name: "Full Stack (Backend + Admin + Mobile)", value: "full-stack" },
606
+ { name: "Backend Only (NestJS + Prisma)", value: "backend-only" },
607
+ { name: "Admin Only (Next.js)", value: "admin-only" },
608
+ { name: "Mobile Only (Taro)", value: "mobile-only" }
609
+ ],
610
+ default: options.template || "full-stack"
611
+ },
612
+ {
613
+ type: "list",
614
+ name: "packageManager",
615
+ message: "Package manager:",
616
+ choices: ["pnpm", "npm", "yarn"],
617
+ default: options.packageManager || "pnpm"
618
+ },
619
+ {
620
+ type: "confirm",
621
+ name: "installDeps",
622
+ message: "Install dependencies?",
623
+ default: !options.skipInstall
624
+ },
625
+ {
626
+ type: "confirm",
627
+ name: "initGit",
628
+ message: "Initialize Git repository?",
629
+ default: !options.skipGit
630
+ }
631
+ ]);
632
+ const config = {
633
+ projectName,
634
+ orgName: answers.org.startsWith("@") ? answers.org : `@${answers.org}`,
635
+ template: answers.template,
636
+ packageManager: answers.packageManager,
637
+ installDeps: answers.installDeps,
638
+ initGit: answers.initGit,
639
+ projectPath
640
+ };
641
+ logger.info("");
642
+ logger.info(chalk2.cyan("\u{1F4CB} Project Configuration:"));
643
+ logger.info(` Project Name: ${chalk2.white(config.projectName)}`);
644
+ logger.info(` Organization: ${chalk2.white(config.orgName)}`);
645
+ logger.info(` Template: ${chalk2.white(config.template)}`);
646
+ logger.info(` Package Manager: ${chalk2.white(config.packageManager)}`);
647
+ logger.info(` Install Dependencies: ${chalk2.white(config.installDeps ? "Yes" : "No")}`);
648
+ logger.info(` Initialize Git: ${chalk2.white(config.initGit ? "Yes" : "No")}`);
649
+ logger.info("");
650
+ const { proceed } = await inquirer.prompt([
651
+ {
652
+ type: "confirm",
653
+ name: "proceed",
654
+ message: "Proceed with project creation?",
655
+ default: true
656
+ }
657
+ ]);
658
+ if (!proceed) {
659
+ logger.info(chalk2.yellow("Project creation cancelled."));
660
+ return;
661
+ }
662
+ await createProjectFromTemplate(config);
663
+ logger.info("");
664
+ logger.success(chalk2.green("\u{1F389} Project created successfully!"));
665
+ logger.info("");
666
+ logger.info(chalk2.cyan("Next steps:"));
667
+ logger.info(` ${chalk2.gray("$")} cd ${projectName}`);
668
+ if (!config.installDeps) {
669
+ logger.info(` ${chalk2.gray("$")} ${config.packageManager} install`);
670
+ }
671
+ if (config.template === "full-stack" || config.template === "backend-only") {
672
+ logger.info(` ${chalk2.gray("$")} docker-compose up -d`);
673
+ logger.info(` ${chalk2.gray("$")} ${config.packageManager} --filter ${config.orgName}/backend prisma:generate`);
674
+ logger.info(` ${chalk2.gray("$")} ${config.packageManager} --filter ${config.orgName}/backend prisma:migrate`);
675
+ }
676
+ logger.info(` ${chalk2.gray("$")} ${config.packageManager} dev`);
677
+ logger.info("");
678
+ logger.info(chalk2.gray("Happy coding! \u{1F680}"));
679
+ } catch (error) {
680
+ logger.error("Failed to create project:");
681
+ logger.error(error instanceof Error ? error.message : String(error));
682
+ process.exit(1);
683
+ }
684
+ }
685
+ async function createProjectFromTemplate(config) {
686
+ const spinner = ora("Creating project...").start();
687
+ try {
688
+ await fs3.ensureDir(config.projectPath);
689
+ process.chdir(config.projectPath);
690
+ spinner.text = "Generating project files...";
691
+ await generateFromTemplate(config);
692
+ if (config.installDeps) {
693
+ spinner.text = "Installing dependencies...";
694
+ await installDependencies(config.packageManager);
695
+ }
696
+ if (config.initGit) {
697
+ spinner.text = "Initializing Git repository...";
698
+ await initGit(config.projectName);
699
+ }
700
+ spinner.succeed("Project created successfully!");
701
+ } catch (error) {
702
+ spinner.fail("Failed to create project");
703
+ throw error;
704
+ }
705
+ }
706
+
707
+ // package.json
708
+ var version = "1.0.0";
709
+
710
+ // src/index.ts
711
+ function cli() {
712
+ const program = new Command();
713
+ program.name("svton").description("Svton CLI - Create full-stack applications with NestJS, Next.js, and Taro").version(version);
714
+ program.command("create <project-name>").alias("init").alias("new").description("Create a new Svton project").option("-o, --org <name>", "Organization name (default: project name)").option("--skip-install", "Skip installing dependencies").option("--skip-git", "Skip Git initialization").option("-t, --template <template>", "Template to use", "full-stack").option("-p, --package-manager <pm>", "Package manager to use", "pnpm").action(createProject);
715
+ program.parse();
716
+ }
717
+ if (__require.main === module) {
718
+ cli();
719
+ }
720
+ export {
721
+ cli
722
+ };