zerostart-cli 0.0.31 → 0.0.35

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 (2) hide show
  1. package/out/cli.js +138 -611
  2. package/package.json +1 -1
package/out/cli.js CHANGED
@@ -51,7 +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 program = new commander_1.Command();
54
- // Basic ASCII banner for maximum compatibility
54
+ // Basic ASCII banner
55
55
  function showBanner() {
56
56
  console.log();
57
57
  console.log(chalk_1.default.cyan('------------------------------------------------------------'));
@@ -59,13 +59,10 @@ function showBanner() {
59
59
  console.log(chalk_1.default.gray(' Create and deploy projects in seconds '));
60
60
  console.log(chalk_1.default.cyan('------------------------------------------------------------'));
61
61
  }
62
- // Show GitHub token help (ASCII only)
63
- // Open URL in default browser
64
62
  function openUrl(url) {
65
63
  const start = (process.platform == 'darwin' ? 'open' : process.platform == 'win32' ? 'start' : 'xdg-open');
66
64
  (0, child_process_1.exec)(`${start} "${url}"`);
67
65
  }
68
- // Show GitHub token help (ASCII only)
69
66
  function showGitHubTokenHelp() {
70
67
  const tokenUrl = 'https://github.com/settings/tokens/new?scopes=repo&description=ZeroStart%20CLI%20Token';
71
68
  console.log();
@@ -73,17 +70,99 @@ function showGitHubTokenHelp() {
73
70
  console.log(chalk_1.default.gray(' +----------------------------------------------------------+'));
74
71
  console.log(chalk_1.default.gray(' | ') + chalk_1.default.white('Opening GitHub in your browser... ') + chalk_1.default.gray(' |'));
75
72
  console.log(chalk_1.default.gray(' | ') + chalk_1.default.cyan(tokenUrl.substring(0, 50) + '...') + chalk_1.default.gray(' |'));
76
- console.log(chalk_1.default.gray(' | |'));
77
- console.log(chalk_1.default.gray(' | ') + chalk_1.default.white('1. Scroll down and click "Generate token" ') + chalk_1.default.gray(' |'));
78
- console.log(chalk_1.default.gray(' | ') + chalk_1.default.white('2. Copy the token and paste it below ') + chalk_1.default.gray(' |'));
79
73
  console.log(chalk_1.default.gray(' +----------------------------------------------------------+'));
80
74
  console.log();
81
75
  openUrl(tokenUrl);
82
76
  }
77
+ async function initializeProject(name, language, type, options) {
78
+ const cwd = process.cwd();
79
+ const projectPath = path.join(cwd, name);
80
+ if (fs.existsSync(projectPath)) {
81
+ console.log(chalk_1.default.red('\n Error: Directory "' + name + '" already exists!'));
82
+ process.exit(1);
83
+ }
84
+ const config = {
85
+ name,
86
+ language,
87
+ type,
88
+ isTheRepoPublic: options.isPublic,
89
+ description: `A ${type} project in ${language}`,
90
+ path: projectPath
91
+ };
92
+ const spinner = (0, ora_1.default)({ text: 'Initializing...', color: 'cyan' }).start();
93
+ try {
94
+ const templateManager = new TemplateManager_1.TemplateManager();
95
+ const gitManager = new GitManager_1.GitManager();
96
+ const gitHubService = options.githubToken ? new GitHubServiceCLI_1.GitHubServiceCLI(options.githubToken) : null;
97
+ if (!await gitManager.checkGitInstalled()) {
98
+ spinner.fail(chalk_1.default.red('Git is not installed!'));
99
+ return;
100
+ }
101
+ spinner.text = chalk_1.default.cyan('Generating project structure...');
102
+ await templateManager.createProjectStructure(config);
103
+ spinner.succeed(chalk_1.default.green('Project structure created'));
104
+ if (type !== types_1.ProjectType.DSAPractice) {
105
+ spinner.start(chalk_1.default.cyan('Initializing Git repository...'));
106
+ await gitManager.init(projectPath);
107
+ await gitManager.commit(projectPath, "Initial commit");
108
+ spinner.succeed(chalk_1.default.green('Git repository initialized'));
109
+ }
110
+ if (options.createRemote) {
111
+ spinner.start(chalk_1.default.cyan('Creating GitHub repository...'));
112
+ let repoUrl;
113
+ if (options.authMethod === 'GitHub CLI') {
114
+ repoUrl = await gitManager.createRepoWithGh(projectPath, name, options.isPublic);
115
+ }
116
+ else if (gitHubService) {
117
+ repoUrl = await gitHubService.createRepo(config);
118
+ }
119
+ if (repoUrl) {
120
+ spinner.succeed(chalk_1.default.green('GitHub repository created'));
121
+ spinner.start(chalk_1.default.cyan('Pushing to GitHub...'));
122
+ if (options.authMethod !== 'GitHub CLI')
123
+ await gitManager.addRemote(projectPath, repoUrl);
124
+ await gitManager.push(projectPath);
125
+ spinner.succeed(chalk_1.default.green('Pushed to GitHub'));
126
+ }
127
+ else {
128
+ spinner.warn(chalk_1.default.yellow('GitHub repository creation failed'));
129
+ }
130
+ }
131
+ console.log();
132
+ console.log(chalk_1.default.bold.green(' Success! Your project is ready!'));
133
+ console.log(chalk_1.default.gray(' Location: ') + chalk_1.default.cyan(projectPath));
134
+ console.log();
135
+ const isWeb = [types_1.ProjectLanguage.React, types_1.ProjectLanguage.HTMLCSS].includes(language);
136
+ const isPractice = type === types_1.ProjectType.DSAPractice;
137
+ if (!isWeb || isPractice) {
138
+ const gdbLinks = {
139
+ [types_1.ProjectLanguage.Python]: 'https://www.onlinegdb.com/online_python_compiler',
140
+ [types_1.ProjectLanguage.Java]: 'https://www.onlinegdb.com/online_java_compiler',
141
+ [types_1.ProjectLanguage.CPP]: 'https://www.onlinegdb.com/online_c++_compiler',
142
+ [types_1.ProjectLanguage.NodeJS]: 'https://www.onlinegdb.com/online_node.js_compiler',
143
+ [types_1.ProjectLanguage.React]: 'https://www.onlinegdb.com/'
144
+ };
145
+ const link = gdbLinks[language] || 'https://www.onlinegdb.com/';
146
+ console.log(chalk_1.default.bold.yellow(' Practice Online:'));
147
+ console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(link));
148
+ console.log(chalk_1.default.gray(' (Opening in your browser...)'));
149
+ openUrl(link);
150
+ return;
151
+ }
152
+ console.log(chalk_1.default.bold(' Get started:'));
153
+ console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(`cd ${name}`));
154
+ console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('code .') + chalk_1.default.gray(' (or your favorite editor)'));
155
+ console.log();
156
+ }
157
+ catch (error) {
158
+ spinner.fail(chalk_1.default.red('Error: ' + error.message));
159
+ }
160
+ }
83
161
  program
84
162
  .name('zerostart')
85
163
  .description('Create and deploy a complete project with one command')
86
- .version('0.0.31');
164
+ .version('0.0.35');
165
+ // Standalone deployment commands
87
166
  program
88
167
  .command('deploy-vercel')
89
168
  .description('Deploy the current project to Vercel')
@@ -91,80 +170,11 @@ program
91
170
  showBanner();
92
171
  const vercelManager = new VercelManager_1.VercelManager();
93
172
  const cwd = process.cwd();
94
- // 1. Check Install
95
- let vercelInstalled = await vercelManager.checkVercelInstalled();
96
- if (!vercelInstalled) {
97
- const { installVercel } = await inquirer_1.default.prompt([{
98
- type: 'confirm',
99
- name: 'installVercel',
100
- message: 'Vercel CLI not found. Install it globally?',
101
- default: true
102
- }]);
103
- if (installVercel) {
104
- const iSpinner = (0, ora_1.default)('Installing Vercel CLI...').start();
105
- if (await vercelManager.installGlobal()) {
106
- iSpinner.succeed(chalk_1.default.green('Vercel CLI installed!'));
107
- vercelInstalled = true;
108
- }
109
- else {
110
- iSpinner.fail(chalk_1.default.red('Failed to install Vercel CLI.'));
111
- return;
112
- }
113
- }
114
- else {
115
- return;
116
- }
117
- }
118
- // 2. Auth & Deploy
119
- if (vercelInstalled) {
120
- const vSpinner = (0, ora_1.default)('Checking Vercel authentication...').start();
121
- const loggedIn = await vercelManager.checkAuth();
122
- if (!loggedIn) {
123
- vSpinner.stop();
124
- console.log(chalk_1.default.yellow('\n Authentication required.'));
125
- const { doLogin } = await inquirer_1.default.prompt([{
126
- type: 'confirm',
127
- name: 'doLogin',
128
- message: 'Log in to Vercel now?',
129
- default: true
130
- }]);
131
- if (doLogin) {
132
- const loginSuccess = await vercelManager.login();
133
- if (!loginSuccess) {
134
- console.log(chalk_1.default.red('\n Login failed.'));
135
- return;
136
- }
137
- }
138
- else {
139
- return;
140
- }
141
- }
142
- else {
143
- vSpinner.succeed(chalk_1.default.green('Authenticated'));
144
- }
145
- // Prompt for project name for Vercel
146
- const defaultName = path.basename(cwd);
147
- const { vName } = await inquirer_1.default.prompt([{
148
- type: 'input',
149
- name: 'vName',
150
- message: 'Vercel Project Name:',
151
- default: defaultName,
152
- validate: (input) => {
153
- if (input.trim() === '')
154
- return 'Name is required';
155
- return true;
156
- }
157
- }]);
158
- const dSpinner = (0, ora_1.default)('Deploying to Vercel...').start();
173
+ if (await vercelManager.checkAuth()) {
174
+ const { vName } = await inquirer_1.default.prompt([{ type: 'input', name: 'vName', message: 'Vercel Project Name:', default: path.basename(cwd) }]);
159
175
  const url = await vercelManager.deploy(cwd, vName);
160
- if (url) {
161
- dSpinner.succeed(chalk_1.default.green('Deployed to Vercel!'));
162
- console.log(chalk_1.default.gray(' URL: ') + chalk_1.default.cyan(url));
163
- }
164
- else {
165
- dSpinner.fail(chalk_1.default.red('Deployment failed'));
166
- console.log(chalk_1.default.gray(' Try running ') + chalk_1.default.cyan('vercel deploy') + chalk_1.default.gray(' manually.'));
167
- }
176
+ if (url)
177
+ console.log(chalk_1.default.green('Deployed! URL: ') + chalk_1.default.cyan(url));
168
178
  }
169
179
  });
170
180
  program
@@ -174,539 +184,56 @@ program
174
184
  showBanner();
175
185
  const netlifyManager = new NetlifyManager_1.NetlifyManager();
176
186
  const cwd = process.cwd();
177
- // 1. Check Install
178
- let netlifyInstalled = await netlifyManager.checkNetlifyInstalled();
179
- if (!netlifyInstalled) {
180
- const { installNetlify } = await inquirer_1.default.prompt([{
181
- type: 'confirm',
182
- name: 'installNetlify',
183
- message: 'Netlify CLI not found. Install it globally?',
184
- default: true
185
- }]);
186
- if (installNetlify) {
187
- const iSpinner = (0, ora_1.default)('Installing Netlify CLI...').start();
188
- if (await netlifyManager.installGlobal()) {
189
- iSpinner.succeed(chalk_1.default.green('Netlify CLI installed!'));
190
- netlifyInstalled = true;
191
- }
192
- else {
193
- iSpinner.fail(chalk_1.default.red('Failed to install Netlify CLI.'));
194
- return;
195
- }
196
- }
197
- else {
198
- return;
199
- }
200
- }
201
- // 2. Auth & Deploy
202
- if (netlifyInstalled) {
203
- const nSpinner = (0, ora_1.default)('Checking Netlify authentication...').start();
204
- const loggedIn = await netlifyManager.checkAuth();
205
- if (!loggedIn) {
206
- nSpinner.stop();
207
- console.log(chalk_1.default.yellow('\n Authentication required.'));
208
- const { doLogin } = await inquirer_1.default.prompt([{
209
- type: 'confirm',
210
- name: 'doLogin',
211
- message: 'Log in to Netlify now?',
212
- default: true
213
- }]);
214
- if (doLogin) {
215
- const loginSuccess = await netlifyManager.login();
216
- if (!loginSuccess) {
217
- console.log(chalk_1.default.red('\n Login failed.'));
218
- return;
219
- }
220
- }
221
- else {
222
- return;
223
- }
224
- }
225
- else {
226
- nSpinner.succeed(chalk_1.default.green('Authenticated'));
227
- }
228
- // Enforce name for standalone deploy
229
- const defaultName = path.basename(cwd);
230
- let siteName = defaultName;
231
- let siteCreated = false;
232
- let activeSiteId = undefined;
233
- while (!siteCreated) {
234
- const result = await netlifyManager.createSite(siteName, cwd);
235
- if (result.success) {
236
- siteCreated = true;
237
- activeSiteId = result.siteId;
238
- }
239
- else if (result.reason === 'taken') {
240
- console.log(chalk_1.default.yellow(`\n The site name "${siteName}" is already taken.`));
241
- const { newName } = await inquirer_1.default.prompt([{
242
- type: 'input',
243
- name: 'newName',
244
- message: 'Enter a unique name for your Netlify site:',
245
- validate: (input) => {
246
- if (input.trim() === '')
247
- return 'Name is required';
248
- if (!/^[a-zA-Z0-9-_]+$/.test(input))
249
- return 'Use only letters, numbers, hyphens, and underscores';
250
- return true;
251
- }
252
- }]);
253
- siteName = newName;
254
- }
255
- else {
256
- console.log(chalk_1.default.red('\n Failed to configure Netlify site.'));
257
- const { action } = await inquirer_1.default.prompt([{
258
- type: 'list',
259
- name: 'action',
260
- message: 'What would you like to do?',
261
- choices: ['Try again with a different name', 'Continue deployment anyway', 'Abort']
262
- }]);
263
- if (action === 'Abort')
264
- return;
265
- if (action === 'Continue deployment anyway')
266
- break;
267
- const { retryName } = await inquirer_1.default.prompt([{
268
- type: 'input',
269
- name: 'retryName',
270
- message: 'Enter a unique name:',
271
- validate: (input) => {
272
- if (input.trim() === '')
273
- return 'Name is required';
274
- return true;
275
- }
276
- }]);
277
- siteName = retryName;
278
- }
279
- }
280
- const dSpinner = (0, ora_1.default)('Deploying to Netlify...').start();
281
- dSpinner.stop();
282
- const success = await netlifyManager.deploy(cwd, activeSiteId);
283
- if (success) {
284
- console.log();
187
+ if (await netlifyManager.checkAuth()) {
188
+ const { nName } = await inquirer_1.default.prompt([{ type: 'input', name: 'nName', message: 'Netlify Project Name:', default: path.basename(cwd) }]);
189
+ const res = await netlifyManager.createSite(nName, cwd);
190
+ const success = await netlifyManager.deploy(cwd, res.siteId);
191
+ if (success)
285
192
  console.log(chalk_1.default.green(' ✔ Deployed to Netlify!'));
286
- console.log(chalk_1.default.gray(' Run ') + chalk_1.default.cyan('netlify open') + chalk_1.default.gray(' to view your site.'));
287
- }
288
- else {
289
- console.log();
290
- console.log(chalk_1.default.red(' ✖ Deployment failed'));
291
- console.log(chalk_1.default.gray(' Try running ') + chalk_1.default.cyan('netlify login') + chalk_1.default.gray(' and ') + chalk_1.default.cyan('netlify deploy') + chalk_1.default.gray(' manually.'));
292
- }
293
193
  }
294
194
  });
295
- program
296
- .argument('[projectName]', 'Name of the project')
297
- .action(async (projectName) => {
298
- try {
195
+ // Shortcut commands (18 total)
196
+ const shortcuts = [
197
+ { cmd: 'dsa-py', lang: types_1.ProjectLanguage.Python, type: types_1.ProjectType.DSAPractice },
198
+ { cmd: 'dsa-java', lang: types_1.ProjectLanguage.Java, type: types_1.ProjectType.DSAPractice },
199
+ { cmd: 'dsa-cpp', lang: types_1.ProjectLanguage.CPP, type: types_1.ProjectType.DSAPractice },
200
+ { cmd: 'dsa-node', lang: types_1.ProjectLanguage.NodeJS, type: types_1.ProjectType.DSAPractice },
201
+ { cmd: 'web-react', lang: types_1.ProjectLanguage.React, type: types_1.ProjectType.WebApp },
202
+ { cmd: 'web-html', lang: types_1.ProjectLanguage.HTMLCSS, type: types_1.ProjectType.WebApp },
203
+ { cmd: 'web-node', lang: types_1.ProjectLanguage.NodeJS, type: types_1.ProjectType.WebApp },
204
+ { cmd: 'web-py', lang: types_1.ProjectLanguage.Python, type: types_1.ProjectType.WebApp },
205
+ { cmd: 'web-java', lang: types_1.ProjectLanguage.Java, type: types_1.ProjectType.WebApp },
206
+ { cmd: 'web-cpp', lang: types_1.ProjectLanguage.CPP, type: types_1.ProjectType.WebApp },
207
+ { cmd: 'cli-py', lang: types_1.ProjectLanguage.Python, type: types_1.ProjectType.CLITool },
208
+ { cmd: 'cli-node', lang: types_1.ProjectLanguage.NodeJS, type: types_1.ProjectType.CLITool },
209
+ { cmd: 'cli-java', lang: types_1.ProjectLanguage.Java, type: types_1.ProjectType.CLITool },
210
+ { cmd: 'cli-cpp', lang: types_1.ProjectLanguage.CPP, type: types_1.ProjectType.CLITool },
211
+ { cmd: 'ml-py', lang: types_1.ProjectLanguage.Python, type: types_1.ProjectType.MLProject },
212
+ { cmd: 'ml-node', lang: types_1.ProjectLanguage.NodeJS, type: types_1.ProjectType.MLProject },
213
+ { cmd: 'ml-java', lang: types_1.ProjectLanguage.Java, type: types_1.ProjectType.MLProject },
214
+ { cmd: 'ml-cpp', lang: types_1.ProjectLanguage.CPP, type: types_1.ProjectType.MLProject },
215
+ ];
216
+ shortcuts.forEach(s => {
217
+ program.command(s.cmd).argument('[name]', 'Project name', `my-${s.cmd}`).action(n => {
299
218
  showBanner();
300
- // 1. Get Project Name
301
- let name = projectName;
302
- // 2. State-based Prompt Wizard
303
- const wizardSteps = [
304
- {
305
- id: 'name',
306
- type: 'input',
307
- message: 'Project Name:',
308
- validate: (input) => {
309
- if (input.trim() === '')
310
- return chalk_1.default.red('Project name is required!');
311
- if (!/^[a-zA-Z0-9-_]+$/.test(input))
312
- return chalk_1.default.red('Use only letters, numbers, hyphens, and underscores');
313
- return true;
314
- },
315
- skip: !!projectName
316
- },
317
- {
318
- id: 'language',
319
- type: 'list',
320
- message: 'Select Programming Language:',
321
- choices: (ans) => {
322
- const base = Object.values(types_1.ProjectLanguage);
323
- return ans.name ? ['<- Back', ...base] : base;
324
- }
325
- },
326
- {
327
- id: 'type',
328
- type: 'list',
329
- message: 'Select Project Type:',
330
- choices: ['<- Back', ...Object.values(types_1.ProjectType)]
331
- },
332
- {
333
- id: 'visibility',
334
- type: 'list',
335
- message: 'Select Repository Visibility:',
336
- choices: ['<- Back', 'Public', 'Private'],
337
- default: 'Private',
338
- when: (ans) => ans.type !== types_1.ProjectType.DSAPractice
339
- },
340
- {
341
- id: 'createRemote',
342
- type: 'list',
343
- message: 'Push to GitHub?',
344
- choices: ['<- Back', 'Yes', 'No'],
345
- default: 'No',
346
- when: (ans) => ans.type !== types_1.ProjectType.DSAPractice
347
- }
348
- ];
349
- const answers = { name: projectName };
350
- let stepIndex = projectName ? 1 : 0;
351
- while (stepIndex < wizardSteps.length) {
352
- const step = wizardSteps[stepIndex];
353
- // Skip if needed
354
- if (step.skip) {
355
- stepIndex++;
356
- continue;
357
- }
358
- // Handle 'when' logic manually
359
- if (typeof step.when === 'function' && !step.when(answers)) {
360
- stepIndex++;
361
- continue;
362
- }
363
- // Prepare choices (handle dynamic choices)
364
- const promptConfig = { ...step, name: 'value' };
365
- if (typeof step.choices === 'function') {
366
- promptConfig.choices = step.choices(answers);
367
- }
368
- const result = await inquirer_1.default.prompt([promptConfig]);
369
- const value = result.value;
370
- if (value === '<- Back') {
371
- // Go back
372
- stepIndex--;
373
- // Skip back further if the previous step was skipped or not shown
374
- while (stepIndex >= 0) {
375
- const prevStep = wizardSteps[stepIndex];
376
- const isSkipped = !!prevStep.skip;
377
- const whenCondition = prevStep.when;
378
- const isWhenFalse = typeof whenCondition === 'function' && !whenCondition(answers);
379
- if (isSkipped || isWhenFalse) {
380
- stepIndex--;
381
- }
382
- else {
383
- break;
384
- }
385
- }
386
- if (stepIndex < 0)
387
- stepIndex = 0;
388
- continue;
389
- }
390
- // Save answer and move forward
391
- answers[step.id] = value;
392
- stepIndex++;
393
- }
394
- // Normalizing answers for later logic
395
- const normalizedAnswers = {
396
- ...answers,
397
- createRemote: answers.createRemote === 'Yes',
398
- visibility: answers.visibility
399
- };
400
- let githubToken = null;
401
- let authMethod = 'Personal Access Token';
402
- const gitManager = new GitManager_1.GitManager();
403
- // 3. GitHub Auth Flow (also support Back?)
404
- if (normalizedAnswers.createRemote) {
405
- const ghInstalled = await gitManager.checkGhInstalled();
406
- const ghAuth = await gitManager.checkGhAuth();
407
- if (ghInstalled && ghAuth) {
408
- const authAnswer = await inquirer_1.default.prompt([
409
- {
410
- type: 'list',
411
- name: 'method',
412
- message: 'How would you like to authenticate?',
413
- choices: ['<- Back', 'GitHub CLI (Recommended)', 'Personal Access Token']
414
- }
415
- ]);
416
- if (authAnswer.method === '<- Back') {
417
- // This is a special case, we'd need to loop the whole thing
418
- // For now, let's just allow returning to the 'Push to GitHub' question
419
- stepIndex--;
420
- // Re-run the main loop
421
- // Wait, to make this work we should probably put the auth into the wizard steps
422
- // But for simplicity, let's just move forward or let user re-run the whole tool
423
- }
424
- authMethod = authAnswer.method;
425
- }
426
- if (authMethod === 'Personal Access Token') {
427
- showGitHubTokenHelp();
428
- const tokenAnswer = await inquirer_1.default.prompt([
429
- {
430
- type: 'password',
431
- name: 'githubToken',
432
- message: 'Enter GitHub Token (or press Enter to skip):',
433
- mask: '*'
434
- }
435
- ]);
436
- githubToken = tokenAnswer.githubToken?.trim() || null;
437
- if (!githubToken) {
438
- console.log(chalk_1.default.yellow('\n Skipping GitHub integration (no token provided)'));
439
- console.log(chalk_1.default.gray(' You can manually push later with: ') + chalk_1.default.cyan('git remote add origin <url>'));
440
- normalizedAnswers.createRemote = false;
441
- }
442
- }
443
- }
444
- const cwd = process.cwd();
445
- const projectPath = path.join(cwd, name);
446
- if (fs.existsSync(projectPath)) {
447
- console.log();
448
- console.log(chalk_1.default.red(' Error: Directory "' + name + '" already exists!'));
449
- console.log(chalk_1.default.gray(' Try a different name or remove the existing directory'));
450
- console.log();
451
- process.exit(1);
452
- }
453
- const config = {
454
- name: name,
455
- language: answers.language,
456
- type: answers.type,
457
- isTheRepoPublic: answers.visibility === 'Public',
458
- description: `A ${answers.type} project in ${answers.language}`,
459
- path: projectPath
460
- };
461
- console.log();
462
- const spinner = (0, ora_1.default)({
463
- text: 'Initializing...',
464
- color: 'cyan',
465
- spinner: 'dots'
466
- }).start();
467
- try {
468
- // Managers
469
- const templateManager = new TemplateManager_1.TemplateManager();
470
- // gitManager already instantiated
471
- const gitHubService = githubToken ? new GitHubServiceCLI_1.GitHubServiceCLI(githubToken) : null;
472
- // 0. Check Git
473
- if (!await gitManager.checkGitInstalled()) {
474
- spinner.fail(chalk_1.default.red('Git is not installed!'));
475
- console.log(chalk_1.default.yellow('\n Install Git from: ') + chalk_1.default.cyan('https://git-scm.com/'));
476
- console.log();
477
- return;
478
- }
479
- // 1. Structure
480
- spinner.text = chalk_1.default.cyan('Generating project structure...');
481
- await templateManager.createProjectStructure(config);
482
- spinner.succeed(chalk_1.default.green('Project structure created'));
483
- // 2. Git Init & Initial Commits
484
- if (config.type !== types_1.ProjectType.DSAPractice) {
485
- spinner.start(chalk_1.default.cyan('Initializing Git repository...'));
486
- await gitManager.init(config.path);
487
- await gitManager.commit(config.path, "Initial commit");
488
- // Update README and create second commit
489
- try {
490
- const readmePath = path.join(config.path, 'README.md');
491
- if (fs.existsSync(readmePath)) {
492
- fs.appendFileSync(readmePath, '\n\nProject initialized by ZeroStart CLI');
493
- await gitManager.commit(config.path, "Update README.md");
494
- }
495
- }
496
- catch (error) {
497
- console.warn(`Failed to update README: ${error}`);
498
- }
499
- spinner.succeed(chalk_1.default.green('Git repository initialized'));
500
- }
501
- // 3. GitHub
502
- if (normalizedAnswers.createRemote) {
503
- spinner.start(chalk_1.default.cyan('Creating GitHub repository...'));
504
- let repoUrl;
505
- if (authMethod === 'GitHub CLI') {
506
- try {
507
- repoUrl = await gitManager.createRepoWithGh(config.path, config.name, config.isTheRepoPublic);
508
- }
509
- catch (error) {
510
- repoUrl = undefined;
511
- spinner.fail(chalk_1.default.red(`GH CLI Error: ${error.message}`));
512
- }
513
- }
514
- else if (gitHubService) {
515
- repoUrl = await gitHubService.createRepo(config);
516
- }
517
- if (repoUrl) {
518
- spinner.succeed(chalk_1.default.green('GitHub repository created'));
519
- spinner.start(chalk_1.default.cyan('Pushing to GitHub...'));
520
- // If GH CLI used, remote is already set to 'origin'
521
- if (authMethod !== 'GitHub CLI') {
522
- await gitManager.addRemote(config.path, repoUrl);
523
- }
524
- await gitManager.push(config.path);
525
- // Cleanup token if used in URL (only for non-CLI)
526
- if (authMethod !== 'GitHub CLI' && repoUrl.includes('@github.com')) {
527
- const cleanUrl = repoUrl.replace(/\/\/[^@]+@/, '//');
528
- await gitManager.setRemoteUrl(config.path, cleanUrl);
529
- }
530
- spinner.succeed(chalk_1.default.green('Pushed to GitHub'));
531
- }
532
- else {
533
- // Only warn if we actually tried to create a repo (repoUrl is undefined but we entered the block)
534
- if (!spinner.isSpinning) {
535
- // It might have failed in GH CLI block with spinner.fail
536
- }
537
- else {
538
- spinner.warn(chalk_1.default.yellow('GitHub repository creation failed'));
539
- console.log(chalk_1.default.gray(' Check your token permissions and try again'));
540
- }
541
- }
542
- }
543
- // Success message
544
- console.log();
545
- console.log(chalk_1.default.bold.green(' Success! Your project is ready!'));
546
- console.log();
547
- console.log(chalk_1.default.gray(' Location: ') + chalk_1.default.cyan(config.path));
548
- console.log();
549
- console.log(chalk_1.default.bold(' Get started:'));
550
- console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(`cd ${name}`));
551
- console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('code .') + chalk_1.default.gray(' (or your favorite editor)'));
552
- console.log();
553
- // Conditional logic based on language OR project type
554
- const isWebLanguage = [types_1.ProjectLanguage.React, types_1.ProjectLanguage.HTMLCSS].includes(config.language);
555
- const isPractice = config.type === types_1.ProjectType.DSAPractice;
556
- if (!isWebLanguage || isPractice) {
557
- const gdbLinks = {
558
- [types_1.ProjectLanguage.Python]: 'https://www.onlinegdb.com/online_python_compiler',
559
- [types_1.ProjectLanguage.Java]: 'https://www.onlinegdb.com/online_java_compiler',
560
- [types_1.ProjectLanguage.CPP]: 'https://www.onlinegdb.com/online_c++_compiler',
561
- [types_1.ProjectLanguage.NodeJS]: 'https://www.onlinegdb.com/online_node.js_compiler',
562
- [types_1.ProjectLanguage.React]: 'https://www.onlinegdb.com/' // Fallback
563
- };
564
- const link = gdbLinks[config.language] || 'https://www.onlinegdb.com/';
565
- if (link) {
566
- console.log(chalk_1.default.bold.yellow(' Practice Online:'));
567
- console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan(link));
568
- console.log(chalk_1.default.gray(' (Opening in your browser...)'));
569
- console.log();
570
- openUrl(link);
571
- }
572
- return; // Skip deployment
573
- }
574
- // Deployment Integration (Only for Web)
575
- const { deploymentTarget } = await inquirer_1.default.prompt([
576
- {
577
- type: 'list',
578
- name: 'deploymentTarget',
579
- message: 'Select Deployment Provider:',
580
- choices: ['Vercel', 'None'],
581
- default: 'None'
582
- }
583
- ]);
584
- // 4. Install Dependencies & Build (Required for Deployment)
585
- if (deploymentTarget !== 'None' && config.language !== types_1.ProjectLanguage.HTMLCSS) {
586
- console.log();
587
- const iSpinner = (0, ora_1.default)('Installing dependencies...').start();
588
- try {
589
- await new Promise((resolve, reject) => {
590
- (0, child_process_1.exec)('npm install', { cwd: config.path }, (error, stdout, stderr) => {
591
- if (error)
592
- reject(error);
593
- else
594
- resolve(stdout);
595
- });
596
- });
597
- iSpinner.succeed(chalk_1.default.green('Dependencies installed'));
598
- if (config.language === types_1.ProjectLanguage.React || config.type === types_1.ProjectType.WebApp) {
599
- const bSpinner = (0, ora_1.default)('Building project...').start();
600
- await new Promise((resolve, reject) => {
601
- (0, child_process_1.exec)('npm run build', { cwd: config.path }, (error, stdout, stderr) => {
602
- if (error)
603
- reject(error);
604
- else
605
- resolve(stdout);
606
- });
607
- });
608
- bSpinner.succeed(chalk_1.default.green('Project built successfully'));
609
- }
610
- }
611
- catch (error) {
612
- iSpinner.fail(chalk_1.default.red(`Build failed: ${error.message}`));
613
- console.log(chalk_1.default.yellow(' Deployment might fail. Continuing...'));
614
- }
615
- }
616
- if (deploymentTarget === 'Vercel') {
617
- const vercelManager = new VercelManager_1.VercelManager();
618
- let vercelInstalled = await vercelManager.checkVercelInstalled();
619
- if (!vercelInstalled) {
620
- console.log();
621
- const { installVercel } = await inquirer_1.default.prompt([
622
- {
623
- type: 'confirm',
624
- name: 'installVercel',
625
- message: 'Vercel CLI not found. Install it globally?',
626
- default: false
627
- }
628
- ]);
629
- if (installVercel) {
630
- const iSpinner = (0, ora_1.default)('Installing Vercel CLI...').start();
631
- const installed = await vercelManager.installGlobal();
632
- if (installed) {
633
- iSpinner.succeed(chalk_1.default.green('Vercel CLI installed!'));
634
- vercelInstalled = true;
635
- }
636
- else {
637
- iSpinner.fail(chalk_1.default.red('Failed to install Vercel CLI.'));
638
- }
639
- }
640
- }
641
- if (vercelInstalled) {
642
- // Check Auth
643
- const vSpinner = (0, ora_1.default)('Checking Vercel authentication...').start();
644
- const loggedIn = await vercelManager.checkAuth();
645
- if (!loggedIn) {
646
- vSpinner.stop();
647
- console.log(chalk_1.default.yellow('\n Authentication required to deploy.'));
648
- const { doLogin } = await inquirer_1.default.prompt([
649
- {
650
- type: 'confirm',
651
- name: 'doLogin',
652
- message: 'Log in to Vercel now?',
653
- default: true
654
- }
655
- ]);
656
- if (doLogin) {
657
- console.log(chalk_1.default.gray(' Opening Vercel login...'));
658
- const loginSuccess = await vercelManager.login();
659
- if (!loginSuccess) {
660
- console.log(chalk_1.default.red('\n Login failed. Skipping deployment.'));
661
- return;
662
- }
663
- console.log(chalk_1.default.green('\n Successfully logged in!'));
664
- }
665
- else {
666
- console.log(chalk_1.default.yellow(' Skipping deployment (not logged in).'));
667
- return;
668
- }
669
- }
670
- else {
671
- vSpinner.succeed(chalk_1.default.green('Authenticated with Vercel'));
672
- }
673
- const dSpinner = (0, ora_1.default)('Deploying to Vercel...').start();
674
- const deploymentUrl = await vercelManager.deploy(config.path, config.name);
675
- if (deploymentUrl) {
676
- dSpinner.succeed(chalk_1.default.green('Deployed to Vercel!'));
677
- console.log(chalk_1.default.gray(' URL: ') + chalk_1.default.cyan(deploymentUrl));
678
- }
679
- else {
680
- dSpinner.fail(chalk_1.default.red('Vercel deployment failed'));
681
- console.log(chalk_1.default.gray(' Try running ') + chalk_1.default.cyan('vercel deploy') + chalk_1.default.gray(' manually inside the project folder.'));
682
- }
683
- }
684
- }
685
- if (!answers.createRemote || !githubToken && authMethod !== 'GitHub CLI') {
686
- console.log(chalk_1.default.bold.yellow(' To push to GitHub later:'));
687
- console.log(chalk_1.default.gray(' - Create a repository on GitHub'));
688
- console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('git remote add origin <your-repo-url>'));
689
- console.log(chalk_1.default.gray(' - ') + chalk_1.default.cyan('git push -u origin main'));
690
- console.log();
691
- }
692
- }
693
- catch (error) {
694
- spinner.fail(chalk_1.default.red('Error: ' + error.message));
695
- console.log();
696
- console.log(chalk_1.default.gray(' Need help? Check the documentation or open an issue'));
697
- console.log();
698
- }
699
- }
700
- catch (error) {
701
- console.error(chalk_1.default.red('\n Unexpected error:'), error);
702
- console.log();
703
- }
219
+ initializeProject(n, s.lang, s.type, { isPublic: false, createRemote: false, githubToken: null, authMethod: 'none' });
220
+ });
221
+ });
222
+ // Main wizard
223
+ program.argument('[projectName]').action(async (projectName) => {
224
+ showBanner();
225
+ let name = projectName;
226
+ const answers = await inquirer_1.default.prompt([
227
+ { type: 'input', name: 'name', message: 'Project Name:', skip: !!projectName, when: !projectName },
228
+ { type: 'list', name: 'language', message: 'Language:', choices: Object.values(types_1.ProjectLanguage) },
229
+ { type: 'list', name: 'type', message: 'Type:', choices: Object.values(types_1.ProjectType) },
230
+ { type: 'list', name: 'createRemote', message: 'Push to GitHub?', choices: ['Yes', 'No'], default: 'No', when: (ans) => ans.type !== types_1.ProjectType.DSAPractice }
231
+ ]);
232
+ await initializeProject(projectName || answers.name, answers.language, answers.type, {
233
+ isPublic: false,
234
+ createRemote: answers.createRemote === 'Yes',
235
+ githubToken: null,
236
+ authMethod: 'none'
237
+ });
704
238
  });
705
- // Helper functions for emojis (Now text based)
706
- function getLanguageEmoji(lang) {
707
- return '[LANG]';
708
- }
709
- function getTypeEmoji(type) {
710
- return '[TYPE]';
711
- }
712
239
  program.parse(process.argv);
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.31",
8
+ "version": "0.0.35",
9
9
  "engines": {
10
10
  "vscode": "^1.85.0"
11
11
  },