zerostart-cli 0.0.42 → 0.0.44

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/out/cli.js CHANGED
@@ -51,6 +51,7 @@ const VercelManager_1 = require("./managers/VercelManager");
51
51
  const NetlifyManager_1 = require("./managers/NetlifyManager");
52
52
  const child_process_1 = require("child_process");
53
53
  const open_1 = __importDefault(require("open"));
54
+ const ai_1 = require("./commands/ai");
54
55
  const program = new commander_1.Command();
55
56
  // Basic ASCII banner
56
57
  function showBanner() {
@@ -179,7 +180,7 @@ async function initializeProject(name, language, type, options) {
179
180
  program
180
181
  .name('zerostart')
181
182
  .description('Create and deploy a complete project with one command')
182
- .version('0.0.41');
183
+ .version('0.0.44');
183
184
  // zerostart init [project-name]
184
185
  program
185
186
  .command('init [project-name]')
@@ -188,6 +189,14 @@ program
188
189
  showBanner();
189
190
  await startWizard(projectName);
190
191
  });
192
+ // zerostart ai
193
+ program
194
+ .command('ai [prompt]')
195
+ .description('Generate a project using AI based on your description')
196
+ .action(async (prompt) => {
197
+ showBanner();
198
+ await (0, ai_1.handleAICommand)(prompt);
199
+ });
191
200
  // zerostart deploy
192
201
  program
193
202
  .command('deploy')
@@ -509,7 +518,7 @@ program
509
518
  return;
510
519
  }
511
520
  const latestVersion = stdout.trim();
512
- const currentVersion = '0.0.41';
521
+ const currentVersion = '0.0.44';
513
522
  if (latestVersion === currentVersion) {
514
523
  spinner.succeed(chalk_1.default.green('You are using the latest version!'));
515
524
  }
@@ -568,6 +577,10 @@ const shortcuts = [
568
577
  { cmd: 'dsa-java', lang: types_1.ProjectLanguage.Java, type: types_1.ProjectType.DSAPractice },
569
578
  { cmd: 'dsa-cpp', lang: types_1.ProjectLanguage.CPP, type: types_1.ProjectType.DSAPractice },
570
579
  { cmd: 'web-react', lang: types_1.ProjectLanguage.React, type: types_1.ProjectType.WebApp },
580
+ { cmd: 'web-next', lang: types_1.ProjectLanguage.Nextjs, type: types_1.ProjectType.WebApp },
581
+ { cmd: 'web-vue', lang: types_1.ProjectLanguage.Vue, type: types_1.ProjectType.WebApp },
582
+ { cmd: 'web-svelte', lang: types_1.ProjectLanguage.Svelte, type: types_1.ProjectType.WebApp },
583
+ { cmd: 'web-express', lang: types_1.ProjectLanguage.Express, type: types_1.ProjectType.WebApp },
571
584
  { cmd: 'web-html', lang: types_1.ProjectLanguage.HTMLCSS, type: types_1.ProjectType.WebApp },
572
585
  { cmd: 'web-py', lang: types_1.ProjectLanguage.Python, type: types_1.ProjectType.WebApp },
573
586
  { cmd: 'web-java', lang: types_1.ProjectLanguage.Java, type: types_1.ProjectType.WebApp },
@@ -618,7 +631,17 @@ async function startWizard(initialName) {
618
631
  }
619
632
  else if (step === 2) {
620
633
  const langChoices = category === CAT_WEB
621
- ? [types_1.ProjectLanguage.React, types_1.ProjectLanguage.TypeScript, types_1.ProjectLanguage.HTMLCSS, new inquirer_1.default.Separator(), BACK]
634
+ ? [
635
+ types_1.ProjectLanguage.React,
636
+ types_1.ProjectLanguage.Nextjs,
637
+ types_1.ProjectLanguage.Vue,
638
+ types_1.ProjectLanguage.Svelte,
639
+ types_1.ProjectLanguage.Express,
640
+ types_1.ProjectLanguage.TypeScript,
641
+ types_1.ProjectLanguage.HTMLCSS,
642
+ new inquirer_1.default.Separator(),
643
+ BACK
644
+ ]
622
645
  : [types_1.ProjectLanguage.CPP, types_1.ProjectLanguage.Java, types_1.ProjectLanguage.Python, new inquirer_1.default.Separator(), BACK];
623
646
  const langAns = await inquirer_1.default.prompt([{
624
647
  type: 'list',
@@ -793,11 +816,18 @@ async function startWizard(initialName) {
793
816
  else if (category === CAT_WEB && deployChoice === 'local') {
794
817
  console.log();
795
818
  console.log(chalk_1.default.bold.cyan(' 💻 Run your project locally:'));
796
- if (language === types_1.ProjectLanguage.React || language === types_1.ProjectLanguage.TypeScript) {
819
+ if ([types_1.ProjectLanguage.React, types_1.ProjectLanguage.Nextjs, types_1.ProjectLanguage.Vue, types_1.ProjectLanguage.Svelte, types_1.ProjectLanguage.TypeScript].includes(language)) {
820
+ console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(`cd ${name}`));
821
+ console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('npm install'));
822
+ console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('npm run dev'));
823
+ const port = language === types_1.ProjectLanguage.Nextjs ? '3000' : '5173';
824
+ console.log(chalk_1.default.gray('\n Then open: ') + chalk_1.default.cyan(`http://localhost:${port}`));
825
+ }
826
+ else if (language === types_1.ProjectLanguage.Express) {
797
827
  console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(`cd ${name}`));
798
828
  console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('npm install'));
799
829
  console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('npm run dev'));
800
- console.log(chalk_1.default.gray('\n Then open: ') + chalk_1.default.cyan('http://localhost:5173'));
830
+ console.log(chalk_1.default.gray('\n Server running on: ') + chalk_1.default.cyan('http://localhost:3000'));
801
831
  }
802
832
  else if (language === types_1.ProjectLanguage.HTMLCSS) {
803
833
  console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(`cd ${name}`));
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.handleAICommand = handleAICommand;
40
+ const inquirer_1 = __importDefault(require("inquirer"));
41
+ const ora_1 = __importDefault(require("ora"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const path = __importStar(require("path"));
44
+ const fs = __importStar(require("fs-extra"));
45
+ const aiService_1 = require("../services/aiService");
46
+ const ConfigManager_1 = require("../managers/ConfigManager");
47
+ const open_1 = __importDefault(require("open"));
48
+ async function ensureAuth() {
49
+ const configManager = new ConfigManager_1.ConfigManager();
50
+ const existingKey = await configManager.getOpenAIApiKey();
51
+ if (existingKey) {
52
+ return existingKey;
53
+ }
54
+ console.log(chalk_1.default.yellow(' OpenAI API Key not found.'));
55
+ console.log(chalk_1.default.gray(' To use the AI Architect, you need an API key from OpenAI.'));
56
+ console.log(chalk_1.default.cyan(' 1. Visit: ') + chalk_1.default.white('https://platform.openai.com/api-keys'));
57
+ console.log(chalk_1.default.cyan(' 2. Create a new secret key.'));
58
+ console.log(chalk_1.default.cyan(' 3. Paste it here to save it for future use.\n'));
59
+ const { openLink } = await inquirer_1.default.prompt([{
60
+ type: 'confirm',
61
+ name: 'openLink',
62
+ message: 'Would you like to open the OpenAI API key page in your browser?',
63
+ default: true
64
+ }]);
65
+ if (openLink) {
66
+ await (0, open_1.default)('https://platform.openai.com/api-keys');
67
+ }
68
+ const { apiKey } = await inquirer_1.default.prompt([{
69
+ type: 'password',
70
+ name: 'apiKey',
71
+ message: 'Paste your OpenAI API Key:',
72
+ validate: (input) => input.startsWith('sk-') || 'Invalid key format. Usually starts with "sk-"'
73
+ }]);
74
+ const { saveKey } = await inquirer_1.default.prompt([{
75
+ type: 'confirm',
76
+ name: 'saveKey',
77
+ message: 'Save this key locally for future use?',
78
+ default: true
79
+ }]);
80
+ if (saveKey) {
81
+ await configManager.setOpenAIApiKey(apiKey);
82
+ console.log(chalk_1.default.green(' ✔ Key saved successfully to ~/.zerostart/config.json\n'));
83
+ }
84
+ return apiKey;
85
+ }
86
+ async function handleAICommand(initialPrompt) {
87
+ console.log(chalk_1.default.bold.cyan('\n ✨ ZeroStart AI Architect'));
88
+ console.log(chalk_1.default.gray(' Describe your project and let AI build the foundation.\n'));
89
+ const apiKey = await ensureAuth();
90
+ if (!apiKey)
91
+ return;
92
+ let description = initialPrompt;
93
+ let stack = '';
94
+ if (!description) {
95
+ const answers = await inquirer_1.default.prompt([
96
+ {
97
+ type: 'input',
98
+ name: 'description',
99
+ message: 'Describe your project idea:',
100
+ validate: (input) => input.length > 5 || 'Please provide a more detailed description.'
101
+ },
102
+ {
103
+ type: 'input',
104
+ name: 'stack',
105
+ message: 'Preferred stack (optional, e.g., React, Next.js, Express):',
106
+ default: ''
107
+ }
108
+ ]);
109
+ description = answers.description;
110
+ stack = answers.stack;
111
+ }
112
+ const spinner = (0, ora_1.default)({
113
+ text: 'AI is architecting your project...',
114
+ color: 'cyan'
115
+ }).start();
116
+ try {
117
+ const aiService = new aiService_1.AIService(apiKey);
118
+ const projectTemplate = await aiService.generateProject(description, stack);
119
+ spinner.text = 'AI analysis complete. Generating files...';
120
+ const rootDir = process.cwd();
121
+ // Sanitize project name: lowercase, replace spaces/special chars with dashes, remove redundant dashes
122
+ const sanitizedName = projectTemplate.projectName
123
+ .toLowerCase()
124
+ .replace(/[^a-z0-9\s-]/g, '')
125
+ .replace(/\s+/g, '-')
126
+ .replace(/-+/g, '-')
127
+ .trim();
128
+ // Final safety check: ensuring it stays within the current directory
129
+ const projectDir = path.join(rootDir, path.basename(sanitizedName));
130
+ // Check if directory exists
131
+ if (fs.existsSync(projectDir)) {
132
+ spinner.stop();
133
+ const { overwrite } = await inquirer_1.default.prompt([
134
+ {
135
+ type: 'confirm',
136
+ name: 'overwrite',
137
+ message: `Directory ${chalk_1.default.yellow(projectTemplate.projectName)} already exists. Overwrite?`,
138
+ default: false
139
+ }
140
+ ]);
141
+ if (!overwrite) {
142
+ console.log(chalk_1.default.yellow('\n Aborted. No files were created.'));
143
+ return;
144
+ }
145
+ spinner.start('Removing existing directory...');
146
+ await fs.remove(projectDir);
147
+ spinner.text = 'Generating files...';
148
+ }
149
+ // Create folders
150
+ await fs.ensureDir(projectDir);
151
+ for (const folder of projectTemplate.folders) {
152
+ await fs.ensureDir(path.join(projectDir, folder));
153
+ }
154
+ // Create files
155
+ for (const file of projectTemplate.files) {
156
+ const filePath = path.join(projectDir, file.path);
157
+ await fs.ensureDir(path.dirname(filePath));
158
+ await fs.writeFile(filePath, file.content);
159
+ }
160
+ spinner.succeed(chalk_1.default.green(` ✔ Project "${projectTemplate.projectName}" generated successfully!`));
161
+ console.log('\n' + chalk_1.default.bold(' Next Steps:'));
162
+ console.log(chalk_1.default.cyan(` cd ${path.basename(projectDir)}`));
163
+ if (projectTemplate.dependencies.length > 0 || projectTemplate.devDependencies.length > 0) {
164
+ console.log(chalk_1.default.cyan(' npm install'));
165
+ }
166
+ console.log(chalk_1.default.cyan(' npm start (or your project\'s start command)'));
167
+ console.log();
168
+ if (projectTemplate.dependencies.length > 0) {
169
+ console.log(chalk_1.default.gray(' Key dependencies suggested: ') + chalk_1.default.white(projectTemplate.dependencies.slice(0, 5).join(', ') + (projectTemplate.dependencies.length > 5 ? '...' : '')));
170
+ }
171
+ }
172
+ catch (error) {
173
+ spinner.fail(chalk_1.default.red(` Error: ${error.message}`));
174
+ }
175
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ConfigManager = void 0;
37
+ const fs = __importStar(require("fs-extra"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ class ConfigManager {
41
+ constructor() {
42
+ // Store config in ~/.zerostart/config.json
43
+ const homeDir = os.homedir();
44
+ const configDir = path.join(homeDir, '.zerostart');
45
+ this.configPath = path.join(configDir, 'config.json');
46
+ }
47
+ async ensureConfigDir() {
48
+ const configDir = path.dirname(this.configPath);
49
+ if (!fs.existsSync(configDir)) {
50
+ await fs.ensureDir(configDir);
51
+ }
52
+ }
53
+ async getConfig() {
54
+ try {
55
+ if (fs.existsSync(this.configPath)) {
56
+ const content = await fs.readFile(this.configPath, 'utf8');
57
+ return JSON.parse(content);
58
+ }
59
+ }
60
+ catch (error) {
61
+ console.error('Error reading config file:', error);
62
+ }
63
+ return {};
64
+ }
65
+ async setConfig(newConfig) {
66
+ await this.ensureConfigDir();
67
+ const currentConfig = await this.getConfig();
68
+ const updatedConfig = { ...currentConfig, ...newConfig };
69
+ await fs.writeFile(this.configPath, JSON.stringify(updatedConfig, null, 2));
70
+ }
71
+ async getOpenAIApiKey() {
72
+ // Environment variable takes precedence
73
+ if (process.env.OPENAI_API_KEY) {
74
+ return process.env.OPENAI_API_KEY;
75
+ }
76
+ const config = await this.getConfig();
77
+ return config.openaiApiKey;
78
+ }
79
+ async setOpenAIApiKey(key) {
80
+ await this.setConfig({ openaiApiKey: key });
81
+ }
82
+ }
83
+ exports.ConfigManager = ConfigManager;
@@ -63,6 +63,18 @@ class TemplateManager {
63
63
  case types_1.ProjectLanguage.React:
64
64
  await this.createReactStructure(config);
65
65
  break;
66
+ case types_1.ProjectLanguage.Nextjs:
67
+ await this.createNextjsStructure(config);
68
+ break;
69
+ case types_1.ProjectLanguage.Vue:
70
+ await this.createVueStructure(config);
71
+ break;
72
+ case types_1.ProjectLanguage.Svelte:
73
+ await this.createSvelteStructure(config);
74
+ break;
75
+ case types_1.ProjectLanguage.Express:
76
+ await this.createExpressStructure(config);
77
+ break;
66
78
  case types_1.ProjectLanguage.TypeScript:
67
79
  await this.createTypeScriptStructure(config);
68
80
  break;
@@ -181,8 +193,12 @@ npm start # or python main.py / java -jar target/app.jar
181
193
  let content = '';
182
194
  switch (config.language) {
183
195
  case types_1.ProjectLanguage.React:
196
+ case types_1.ProjectLanguage.Nextjs:
197
+ case types_1.ProjectLanguage.Vue:
198
+ case types_1.ProjectLanguage.Svelte:
199
+ case types_1.ProjectLanguage.Express:
184
200
  case types_1.ProjectLanguage.TypeScript:
185
- content = 'node_modules/\n.env\ndist/\nbuild/';
201
+ content = 'node_modules/\n.env\ndist/\nbuild/\n.next/\n.svelte-kit/';
186
202
  break;
187
203
  case types_1.ProjectLanguage.Python:
188
204
  content = '__pycache__/\n*.pyc\nvenv/\n.env';
@@ -400,6 +416,303 @@ console.log("${config.name} initialized!");
400
416
  `;
401
417
  fs.writeFileSync(path.join(config.path, 'netlify.toml'), netlifyContent);
402
418
  }
419
+ async createNextjsStructure(config) {
420
+ const packageJson = {
421
+ name: config.name,
422
+ version: "0.1.0",
423
+ private: true,
424
+ scripts: {
425
+ dev: "next dev",
426
+ build: "next build",
427
+ start: "next start",
428
+ lint: "next lint"
429
+ },
430
+ dependencies: {
431
+ "next": "14.1.0",
432
+ "react": "^18",
433
+ "react-dom": "^18"
434
+ },
435
+ devDependencies: {
436
+ "typescript": "^5",
437
+ "@types/node": "^20",
438
+ "@types/react": "^18",
439
+ "@types/react-dom": "^18",
440
+ "autoprefixer": "^10.0.1",
441
+ "postcss": "^8",
442
+ "tailwindcss": "^3.3.0",
443
+ "eslint": "^8",
444
+ "eslint-config-next": "14.1.0"
445
+ }
446
+ };
447
+ fs.writeFileSync(path.join(config.path, 'package.json'), JSON.stringify(packageJson, null, 2));
448
+ const app = path.join(config.path, 'app');
449
+ if (!fs.existsSync(app))
450
+ fs.mkdirSync(app);
451
+ fs.writeFileSync(path.join(app, 'layout.tsx'), `
452
+ import type { Metadata } from "next";
453
+ import "./globals.css";
454
+
455
+ export const metadata: Metadata = {
456
+ title: "${config.name}",
457
+ description: "${config.description}",
458
+ };
459
+
460
+ export default function RootLayout({
461
+ children,
462
+ }: Readonly<{
463
+ children: React.ReactNode;
464
+ }>) {
465
+ return (
466
+ <html lang="en">
467
+ <body>{children}</body>
468
+ </html>
469
+ );
470
+ }
471
+ `);
472
+ fs.writeFileSync(path.join(app, 'page.tsx'), `
473
+ export default function Home() {
474
+ return (
475
+ <main className="flex min-h-screen flex-col items-center justify-between p-24">
476
+ <h1 className="text-4xl font-bold">Welcome to ${config.name} (Next.js)</h1>
477
+ </main>
478
+ );
479
+ }
480
+ `);
481
+ fs.writeFileSync(path.join(app, 'globals.css'), `
482
+ @tailwind base;
483
+ @tailwind components;
484
+ @tailwind utilities;
485
+ `);
486
+ fs.writeFileSync(path.join(config.path, 'tailwind.config.ts'), `
487
+ import type { Config } from "tailwindcss";
488
+
489
+ const config: Config = {
490
+ content: [
491
+ "./pages/**/*.{js,ts,jsx,tsx,mdx}",
492
+ "./components/**/*.{js,ts,jsx,tsx,mdx}",
493
+ "./app/**/*.{js,ts,jsx,tsx,mdx}",
494
+ ],
495
+ theme: {
496
+ extend: {},
497
+ },
498
+ plugins: [],
499
+ };
500
+ export default config;
501
+ `);
502
+ fs.writeFileSync(path.join(config.path, 'next.config.mjs'), `
503
+ /** @type {import('next').NextConfig} */
504
+ const nextConfig = {};
505
+
506
+ export default nextConfig;
507
+ `);
508
+ fs.writeFileSync(path.join(config.path, 'tsconfig.json'), `
509
+ {
510
+ "compilerOptions": {
511
+ "lib": ["dom", "dom.iterable", "esnext"],
512
+ "allowJs": true,
513
+ "skipLibCheck": true,
514
+ "strict": true,
515
+ "noEmit": true,
516
+ "esModuleInterop": true,
517
+ "module": "esnext",
518
+ "moduleResolution": "bundler",
519
+ "resolveJsonModule": true,
520
+ "isolatedModules": true,
521
+ "jsx": "preserve",
522
+ "incremental": true,
523
+ "plugins": [
524
+ {
525
+ "name": "next"
526
+ }
527
+ ],
528
+ "paths": {
529
+ "@/*": ["./*"]
530
+ }
531
+ },
532
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
533
+ "exclude": ["node_modules"]
534
+ }
535
+ `);
536
+ this.createNetlifyConfig(config);
537
+ }
538
+ async createVueStructure(config) {
539
+ const packageJson = {
540
+ name: config.name,
541
+ version: "0.0.0",
542
+ private: true,
543
+ type: "module",
544
+ scripts: {
545
+ dev: "vite",
546
+ build: "vue-tsc && vite build",
547
+ preview: "vite preview"
548
+ },
549
+ dependencies: {
550
+ "vue": "^3.4.15"
551
+ },
552
+ devDependencies: {
553
+ "@vitejs/plugin-vue": "^5.0.3",
554
+ "typescript": "^5.3.3",
555
+ "vite": "^5.0.12",
556
+ "vue-tsc": "^1.8.27"
557
+ }
558
+ };
559
+ fs.writeFileSync(path.join(config.path, 'package.json'), JSON.stringify(packageJson, null, 2));
560
+ const src = path.join(config.path, 'src');
561
+ if (!fs.existsSync(src))
562
+ fs.mkdirSync(src);
563
+ fs.writeFileSync(path.join(src, 'App.vue'), `
564
+ <template>
565
+ <div>
566
+ <h1>Hello Vue 3 + Vite!</h1>
567
+ </div>
568
+ </template>
569
+ `);
570
+ fs.writeFileSync(path.join(src, 'main.ts'), `
571
+ import { createApp } from 'vue'
572
+ import App from './App.vue'
573
+
574
+ createApp(App).mount('#app')
575
+ `);
576
+ fs.writeFileSync(path.join(config.path, 'index.html'), `
577
+ <!DOCTYPE html>
578
+ <html lang="en">
579
+ <head>
580
+ <meta charset="UTF-8" />
581
+ <title>${config.name}</title>
582
+ </head>
583
+ <body>
584
+ <div id="app"></div>
585
+ <script type="module" src="/src/main.ts"></script>
586
+ </body>
587
+ </html>
588
+ `);
589
+ fs.writeFileSync(path.join(config.path, 'vite.config.ts'), `
590
+ import { defineConfig } from 'vite'
591
+ import vue from '@vitejs/plugin-vue'
592
+
593
+ export default defineConfig({
594
+ plugins: [vue()],
595
+ })
596
+ `);
597
+ this.createNetlifyConfig(config);
598
+ }
599
+ async createSvelteStructure(config) {
600
+ const packageJson = {
601
+ name: config.name,
602
+ version: "0.0.1",
603
+ private: true,
604
+ type: "module",
605
+ scripts: {
606
+ dev: "vite",
607
+ build: "vite build",
608
+ preview: "vite preview",
609
+ check: "svelte-check --tsconfig ./tsconfig.json"
610
+ },
611
+ devDependencies: {
612
+ "@sveltejs/vite-plugin-svelte": "^3.0.1",
613
+ "@tsconfig/svelte": "^5.0.2",
614
+ "svelte": "^4.2.9",
615
+ "svelte-check": "^3.6.3",
616
+ "tslib": "^2.6.2",
617
+ "typescript": "^5.3.3",
618
+ "vite": "^5.0.12"
619
+ }
620
+ };
621
+ fs.writeFileSync(path.join(config.path, 'package.json'), JSON.stringify(packageJson, null, 2));
622
+ const src = path.join(config.path, 'src');
623
+ if (!fs.existsSync(src))
624
+ fs.mkdirSync(src);
625
+ fs.writeFileSync(path.join(src, 'App.svelte'), `
626
+ <script lang="ts">
627
+ let name = "${config.name}";
628
+ </script>
629
+
630
+ <main>
631
+ <h1>Hello {name} (Svelte)</h1>
632
+ </main>
633
+ `);
634
+ fs.writeFileSync(path.join(src, 'main.ts'), `
635
+ import './app.css'
636
+ import App from './App.svelte'
637
+
638
+ const app = new App({
639
+ target: document.getElementById('app')!,
640
+ })
641
+
642
+ export default app
643
+ `);
644
+ fs.writeFileSync(path.join(src, 'app.css'), `
645
+ :root {
646
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
647
+ }
648
+ `);
649
+ fs.writeFileSync(path.join(config.path, 'index.html'), `
650
+ <!doctype html>
651
+ <html lang="en">
652
+ <head>
653
+ <meta charset="UTF-8" />
654
+ <title>${config.name}</title>
655
+ </head>
656
+ <body>
657
+ <div id="app"></div>
658
+ <script type="module" src="/src/main.ts"></script>
659
+ </body>
660
+ </html>
661
+ `);
662
+ fs.writeFileSync(path.join(config.path, 'vite.config.ts'), `
663
+ import { defineConfig } from 'vite'
664
+ import { svelte } from '@sveltejs/vite-plugin-svelte'
665
+
666
+ export default defineConfig({
667
+ plugins: [svelte()],
668
+ })
669
+ `);
670
+ this.createNetlifyConfig(config);
671
+ }
672
+ async createExpressStructure(config) {
673
+ const packageJson = {
674
+ name: config.name,
675
+ version: "1.0.0",
676
+ description: config.description,
677
+ main: "src/index.js",
678
+ scripts: {
679
+ start: "node src/index.js",
680
+ dev: "nodemon src/index.js"
681
+ },
682
+ dependencies: {
683
+ "express": "^4.18.2",
684
+ "cors": "^2.8.5",
685
+ "dotenv": "^16.3.1"
686
+ },
687
+ devDependencies: {
688
+ "nodemon": "^3.0.2"
689
+ }
690
+ };
691
+ fs.writeFileSync(path.join(config.path, 'package.json'), JSON.stringify(packageJson, null, 2));
692
+ const src = path.join(config.path, 'src');
693
+ if (!fs.existsSync(src))
694
+ fs.mkdirSync(src);
695
+ fs.writeFileSync(path.join(src, 'index.js'), `
696
+ const express = require('express');
697
+ const cors = require('cors');
698
+ require('dotenv').config();
699
+
700
+ const app = express();
701
+ const PORT = process.env.PORT || 3000;
702
+
703
+ app.use(cors());
704
+ app.use(express.json());
705
+
706
+ app.get('/', (req, res) => {
707
+ res.json({ message: 'Welcome to ${config.name} API' });
708
+ });
709
+
710
+ app.listen(PORT, () => {
711
+ console.log(\`Server is running on http://localhost:\${PORT}\`);
712
+ });
713
+ `);
714
+ fs.writeFileSync(path.join(config.path, '.env'), "PORT=3000\n");
715
+ }
403
716
  createNetlifyConfig(config) {
404
717
  const content = `[build]
405
718
  command = "npm run build"
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AIService = void 0;
7
+ const openai_1 = __importDefault(require("openai"));
8
+ const ConfigManager_1 = require("../managers/ConfigManager");
9
+ class AIService {
10
+ constructor(apiKey) {
11
+ this.openai = null;
12
+ if (apiKey) {
13
+ this.openai = new openai_1.default({ apiKey });
14
+ }
15
+ }
16
+ async ensureInitialized() {
17
+ if (this.openai)
18
+ return;
19
+ const configManager = new ConfigManager_1.ConfigManager();
20
+ const apiKey = await configManager.getOpenAIApiKey();
21
+ if (apiKey) {
22
+ this.openai = new openai_1.default({ apiKey });
23
+ }
24
+ }
25
+ async generateProject(prompt, stack) {
26
+ await this.ensureInitialized();
27
+ if (!this.openai) {
28
+ throw new Error('OpenAI API Key not found. Please set it using environment variables or user config.');
29
+ }
30
+ const systemPrompt = `
31
+ You are a world-class software architect and lead developer.
32
+ Generate a complete, professional project structure based on the user's requirements.
33
+
34
+ Strictly follow this JSON schema for your response:
35
+ {
36
+ "projectName": "Name of the project",
37
+ "folders": ["list/of/folders", "src", "src/components"],
38
+ "files": [
39
+ {
40
+ "path": "folder/filename.ext",
41
+ "content": "Full code content"
42
+ }
43
+ ],
44
+ "dependencies": ["list", "of", "npm", "dependencies"],
45
+ "devDependencies": ["list", "of", "npm", "dev", "dependencies"]
46
+ }
47
+
48
+ Rules:
49
+ - Create a robust, production-ready starting point.
50
+ - Include all necessary configuration files:
51
+ - For Node.js: package.json (with scripts), tsconfig.json, .gitignore, README.md.
52
+ - For others: Relevant manifest/config files.
53
+ - Ensure the \`dependencies\` and \`devDependencies\` arrays match what is in the package.json/manifest.
54
+ - Ensure all paths are relative to the project root.
55
+ - Do not include placeholders; provide actual initial code.
56
+ - The output must be valid JSON only.
57
+ `;
58
+ const userMessage = `Project Description: ${prompt}${stack ? `\nPreferred Stack: ${stack}` : ''}`;
59
+ try {
60
+ const response = await this.openai.chat.completions.create({
61
+ model: 'gpt-4o',
62
+ messages: [
63
+ { role: 'system', content: systemPrompt },
64
+ { role: 'user', content: userMessage }
65
+ ],
66
+ response_format: { type: 'json_object' }
67
+ });
68
+ const content = response.choices[0].message.content;
69
+ if (!content) {
70
+ throw new Error('AI returned an empty response.');
71
+ }
72
+ return JSON.parse(content);
73
+ }
74
+ catch (error) {
75
+ if (error.status === 401) {
76
+ throw new Error('Invalid OpenAI API Key.');
77
+ }
78
+ throw new Error(`AI Service Error: ${error.message}`);
79
+ }
80
+ }
81
+ }
82
+ exports.AIService = AIService;
package/out/types.js CHANGED
@@ -4,6 +4,10 @@ exports.ProjectType = exports.ProjectLanguage = void 0;
4
4
  var ProjectLanguage;
5
5
  (function (ProjectLanguage) {
6
6
  ProjectLanguage["React"] = "React";
7
+ ProjectLanguage["Nextjs"] = "Next.js";
8
+ ProjectLanguage["Vue"] = "Vue";
9
+ ProjectLanguage["Svelte"] = "Svelte";
10
+ ProjectLanguage["Express"] = "Express";
7
11
  ProjectLanguage["TypeScript"] = "TypeScript";
8
12
  ProjectLanguage["HTMLCSS"] = "HTML/CSS";
9
13
  ProjectLanguage["Python"] = "Python";
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "zerostart": "./out/cli.js"
6
6
  },
7
7
  "description": "Create and deploy a complete project with one command.",
8
- "version": "0.0.42",
8
+ "version": "0.0.44",
9
9
  "engines": {
10
10
  "vscode": "^1.85.0"
11
11
  },
@@ -29,6 +29,7 @@
29
29
  "lint": "eslint src --ext ts"
30
30
  },
31
31
  "devDependencies": {
32
+ "@types/fs-extra": "^11.0.4",
32
33
  "@types/inquirer": "^9.0.9",
33
34
  "@types/node": "18.x",
34
35
  "@types/ora": "^3.1.0",
@@ -42,8 +43,10 @@
42
43
  "@octokit/rest": "^19.0.13",
43
44
  "chalk": "^4.1.2",
44
45
  "commander": "^14.0.3",
46
+ "fs-extra": "^11.3.3",
45
47
  "inquirer": "^9.3.8",
46
48
  "open": "^8.4.2",
49
+ "openai": "^6.25.0",
47
50
  "ora": "^5.4.1"
48
51
  }
49
- }
52
+ }