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