genbox 1.0.96 → 1.0.98

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/dist/scanner/index.js +117 -11
  2. package/package.json +1 -1
@@ -66,6 +66,8 @@ class ProjectScanner {
66
66
  const apps = await this.discoverApps(root, structure, compose, options.exclude);
67
67
  // Layer 5.5: Apply framework detection to apps (ports, commands, etc.)
68
68
  await this.applyFrameworkDefaults(root, apps, frameworks);
69
+ // Layer 5.6: Ensure unique ports for all apps (avoid collisions)
70
+ this.ensureUniquePorts(apps);
69
71
  // Layer 6: Analyze environment variables (skip if option set)
70
72
  const envAnalysis = options.skipEnv
71
73
  ? { required: [], optional: [], secrets: [], references: [], sources: [] }
@@ -168,20 +170,41 @@ class ProjectScanner {
168
170
  const hasStartScript = !!(pkg.scripts?.start || pkg.scripts?.dev || pkg.scripts?.serve);
169
171
  const type = this.inferAppTypeFromPackage(entry.name, pkg, hasStartScript);
170
172
  // Try to detect framework
173
+ // Priority: fullstack frameworks > meta-frameworks > dev servers > UI libraries
171
174
  let framework;
172
175
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
176
+ // 1. Fullstack/meta-frameworks (most specific)
173
177
  if (deps['next'])
174
178
  framework = 'nextjs';
179
+ else if (deps['nuxt'])
180
+ framework = 'nuxt';
181
+ else if (deps['@remix-run/react'])
182
+ framework = 'remix';
183
+ else if (deps['astro'])
184
+ framework = 'astro';
185
+ else if (deps['@sveltejs/kit'])
186
+ framework = 'sveltekit';
187
+ // 2. Backend frameworks
175
188
  else if (deps['@nestjs/core'])
176
189
  framework = 'nestjs';
190
+ else if (deps['fastify'])
191
+ framework = 'fastify';
192
+ else if (deps['express'])
193
+ framework = 'express';
194
+ else if (deps['hono'])
195
+ framework = 'hono';
196
+ // 3. Dev servers (determines port)
197
+ else if (deps['vite'])
198
+ framework = 'vite';
199
+ // 4. UI libraries (least specific - use dev server port if available)
177
200
  else if (deps['react-admin'])
178
- framework = 'react-admin';
201
+ framework = 'vite'; // react-admin uses vite
179
202
  else if (deps['react'])
180
203
  framework = 'react';
181
204
  else if (deps['vue'])
182
205
  framework = 'vue';
183
- else if (deps['express'])
184
- framework = 'express';
206
+ else if (deps['svelte'])
207
+ framework = 'svelte';
185
208
  // Try to detect port from package.json scripts
186
209
  let port;
187
210
  const devScript = pkg.scripts?.dev || pkg.scripts?.start || '';
@@ -368,18 +391,101 @@ class ProjectScanner {
368
391
  if (!app.framework) {
369
392
  app.framework = appFramework.name;
370
393
  }
371
- // Apply default port from framework
372
- if (!app.port && appFramework.defaultPort) {
373
- app.port = appFramework.defaultPort;
394
+ }
395
+ // Priority 1: Detect port from config files (vite.config.ts, etc.)
396
+ if (!app.port) {
397
+ const configPort = this.detectPortFromConfig(appPath);
398
+ if (configPort) {
399
+ app.port = configPort;
400
+ }
401
+ }
402
+ // Priority 2: Use framework default from detector
403
+ if (!app.port && appFramework?.defaultPort) {
404
+ app.port = appFramework.defaultPort;
405
+ }
406
+ // Priority 3: Use hardcoded framework default as last resort
407
+ if (!app.port && app.framework) {
408
+ app.port = this.getDefaultPortForFramework(app.framework);
409
+ }
410
+ }
411
+ }
412
+ /**
413
+ * Detect port from config files (vite.config.ts, next.config.js, etc.)
414
+ */
415
+ detectPortFromConfig(appPath) {
416
+ const fs = require('fs');
417
+ const pathModule = require('path');
418
+ // Try vite.config.ts/js
419
+ for (const configFile of ['vite.config.ts', 'vite.config.js', 'vite.config.mts', 'vite.config.mjs']) {
420
+ const configPath = pathModule.join(appPath, configFile);
421
+ if (fs.existsSync(configPath)) {
422
+ try {
423
+ const content = fs.readFileSync(configPath, 'utf8');
424
+ // Match server.port or server: { port: XXXX }
425
+ const portMatch = content.match(/server\s*:\s*\{[^}]*port\s*:\s*(\d+)/s) ||
426
+ content.match(/port\s*:\s*(\d+)/);
427
+ if (portMatch) {
428
+ return parseInt(portMatch[1], 10);
429
+ }
374
430
  }
431
+ catch { }
375
432
  }
376
- else if (app.framework) {
377
- // App has framework name but we need to look up its default port
378
- const matchingFramework = frameworks.find(f => f.name === app.framework);
379
- if (matchingFramework?.defaultPort && !app.port) {
380
- app.port = matchingFramework.defaultPort;
433
+ }
434
+ // Try next.config.js/mjs (less common to have port there, but check anyway)
435
+ // Next.js port is usually in package.json scripts or CLI args
436
+ // Try nuxt.config.ts/js
437
+ for (const configFile of ['nuxt.config.ts', 'nuxt.config.js']) {
438
+ const configPath = pathModule.join(appPath, configFile);
439
+ if (fs.existsSync(configPath)) {
440
+ try {
441
+ const content = fs.readFileSync(configPath, 'utf8');
442
+ const portMatch = content.match(/devServer\s*:\s*\{[^}]*port\s*:\s*(\d+)/s) ||
443
+ content.match(/port\s*:\s*(\d+)/);
444
+ if (portMatch) {
445
+ return parseInt(portMatch[1], 10);
446
+ }
381
447
  }
448
+ catch { }
449
+ }
450
+ }
451
+ return undefined;
452
+ }
453
+ /**
454
+ * Get default port for a framework (fallback if config file doesn't specify)
455
+ */
456
+ getDefaultPortForFramework(framework) {
457
+ const portMap = {
458
+ nextjs: 3000,
459
+ nuxt: 3000,
460
+ vite: 5173,
461
+ react: 3000,
462
+ vue: 5173,
463
+ angular: 4200,
464
+ nestjs: 3000,
465
+ express: 3000,
466
+ };
467
+ return portMap[framework];
468
+ }
469
+ /**
470
+ * Ensure all apps have unique ports.
471
+ * When multiple apps have the same port, increment subsequent ones.
472
+ */
473
+ ensureUniquePorts(apps) {
474
+ const usedPorts = new Set();
475
+ for (const app of apps) {
476
+ // Skip libraries and apps without ports
477
+ if (app.type === 'library' || !app.port)
478
+ continue;
479
+ let port = app.port;
480
+ // If port is already used, find the next available one
481
+ while (usedPorts.has(port)) {
482
+ port++;
483
+ }
484
+ // Update app port if it changed
485
+ if (port !== app.port) {
486
+ app.port = port;
382
487
  }
488
+ usedPorts.add(port);
383
489
  }
384
490
  }
385
491
  async detectGit(root) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.96",
3
+ "version": "1.0.98",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {