zerostart-cli 0.0.22 → 0.0.25

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
@@ -83,7 +83,7 @@ function showGitHubTokenHelp() {
83
83
  program
84
84
  .name('zerostart')
85
85
  .description('Create and deploy a complete project with one command')
86
- .version('0.0.22');
86
+ .version('0.0.25');
87
87
  program
88
88
  .command('deploy-vercel')
89
89
  .description('Deploy the current project to Vercel')
@@ -142,8 +142,21 @@ program
142
142
  else {
143
143
  vSpinner.succeed(chalk_1.default.green('Authenticated'));
144
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
+ }]);
145
158
  const dSpinner = (0, ora_1.default)('Deploying to Vercel...').start();
146
- const url = await vercelManager.deploy(cwd);
159
+ const url = await vercelManager.deploy(cwd, vName);
147
160
  if (url) {
148
161
  dSpinner.succeed(chalk_1.default.green('Deployed to Vercel!'));
149
162
  console.log(chalk_1.default.gray(' URL: ') + chalk_1.default.cyan(url));
@@ -212,9 +225,61 @@ program
212
225
  else {
213
226
  nSpinner.succeed(chalk_1.default.green('Authenticated'));
214
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
+ }
215
280
  const dSpinner = (0, ora_1.default)('Deploying to Netlify...').start();
216
- dSpinner.stop(); // Stop spinner to allow interactive input
217
- const success = await netlifyManager.deploy(cwd);
281
+ dSpinner.stop();
282
+ const success = await netlifyManager.deploy(cwd, activeSiteId);
218
283
  if (success) {
219
284
  console.log();
220
285
  console.log(chalk_1.default.green(' ✔ Deployed to Netlify!'));
@@ -596,8 +661,59 @@ program
596
661
  console.log();
597
662
  console.log(chalk_1.default.cyan(` Configuring Netlify site for "${config.name}"...`));
598
663
  // We do this interactively so if name is taken user can see error and handle it (or it just links if they own it)
599
- await netlifyManager.createSite(config.name, config.path);
600
- const success = await netlifyManager.deploy(config.path);
664
+ let siteName = config.name;
665
+ let siteCreated = false;
666
+ let activeSiteId = undefined;
667
+ while (!siteCreated) {
668
+ const result = await netlifyManager.createSite(siteName, config.path);
669
+ if (result.success) {
670
+ siteCreated = true;
671
+ activeSiteId = result.siteId;
672
+ }
673
+ else if (result.reason === 'taken') {
674
+ console.log(chalk_1.default.yellow(`\n The site name "${siteName}" is already taken.`));
675
+ const { newName } = await inquirer_1.default.prompt([{
676
+ type: 'input',
677
+ name: 'newName',
678
+ message: 'Enter a unique name for your Netlify site:',
679
+ validate: (input) => {
680
+ if (input.trim() === '')
681
+ return 'Name is required';
682
+ if (!/^[a-zA-Z0-9-_]+$/.test(input))
683
+ return 'Use only letters, numbers, hyphens, and underscores';
684
+ return true;
685
+ }
686
+ }]);
687
+ siteName = newName;
688
+ }
689
+ else {
690
+ console.log(chalk_1.default.red('\n Failed to create Netlify site. '));
691
+ // Allow user to try to deploy anyway (maybe manual link?) or abort
692
+ const { action } = await inquirer_1.default.prompt([{
693
+ type: 'list',
694
+ name: 'action',
695
+ message: 'What would you like to do?',
696
+ choices: ['Try again with a different name', 'Continue deployment (might fail or link to wrong site)', 'Abort']
697
+ }]);
698
+ if (action === 'Abort')
699
+ return;
700
+ if (action === 'Continue deployment (might fail or link to wrong site)')
701
+ break;
702
+ // If try again, ask for name
703
+ const { retryName } = await inquirer_1.default.prompt([{
704
+ type: 'input',
705
+ name: 'retryName',
706
+ message: 'Enter a unique name:',
707
+ validate: (input) => {
708
+ if (input.trim() === '')
709
+ return 'Name is required';
710
+ return true;
711
+ }
712
+ }]);
713
+ siteName = retryName;
714
+ }
715
+ }
716
+ const success = await netlifyManager.deploy(config.path, activeSiteId);
601
717
  if (success) {
602
718
  console.log();
603
719
  console.log(chalk_1.default.green(' ✔ Deployed to Netlify!'));
@@ -66,25 +66,51 @@ class NetlifyManager {
66
66
  try {
67
67
  console.log(chalk_1.default.cyan(` Creating Netlify site "${name}"...`));
68
68
  return new Promise((resolve) => {
69
- // Using 'sites:create' might prompt if not authenticated, but we check auth before this.
70
69
  const child = (0, child_process_1.spawn)('netlify', ['sites:create', '--name', name], {
71
70
  cwd,
72
- stdio: 'inherit'
71
+ stdio: ['inherit', 'pipe', 'pipe']
72
+ });
73
+ let output = '';
74
+ child.stdout?.on('data', (data) => {
75
+ const str = data.toString();
76
+ output += str;
77
+ process.stdout.write(data);
78
+ });
79
+ child.stderr?.on('data', (data) => {
80
+ output += data.toString();
81
+ process.stderr.write(data);
73
82
  });
74
83
  child.on('close', (code) => {
75
- resolve(code === 0);
84
+ if (code === 0) {
85
+ // Extract Site ID/Project ID
86
+ // Format: "Site ID: 022..." or "Project ID: 022..."
87
+ const idMatch = output.match(/(?:Site|Project)\s+ID:\s+([a-zA-Z0-9-]+)/i);
88
+ const siteId = idMatch ? idMatch[1] : undefined;
89
+ resolve({ success: true, siteId });
90
+ }
91
+ else {
92
+ if (output.toLowerCase().includes('already exists') || output.toLowerCase().includes('taken')) {
93
+ resolve({ success: false, reason: 'taken' });
94
+ }
95
+ else {
96
+ resolve({ success: false, reason: 'error' });
97
+ }
98
+ }
76
99
  });
77
100
  });
78
101
  }
79
102
  catch (error) {
80
103
  console.error('Failed to create Netlify site:', error);
81
- return false;
104
+ return { success: false, reason: 'error' };
82
105
  }
83
106
  }
84
- async deploy(cwd) {
107
+ async deploy(cwd, siteId) {
85
108
  return new Promise((resolve) => {
86
- // Use spawn with stdio: 'inherit' to allow interactive site creation
87
- const child = (0, child_process_1.spawn)('netlify', ['deploy', '--prod'], {
109
+ const args = ['deploy', '--prod'];
110
+ if (siteId) {
111
+ args.push('--site', siteId);
112
+ }
113
+ const child = (0, child_process_1.spawn)('netlify', args, {
88
114
  cwd,
89
115
  stdio: 'inherit'
90
116
  });
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.22",
8
+ "version": "0.0.25",
9
9
  "engines": {
10
10
  "vscode": "^1.85.0"
11
11
  },