genbox 1.0.32 → 1.0.34

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.
@@ -1021,7 +1021,20 @@ function createProfilesFromScan(scan, definedEnvironments = []) {
1021
1021
  const profiles = {};
1022
1022
  const frontendApps = scan.apps.filter(a => a.type === 'frontend');
1023
1023
  const backendApps = scan.apps.filter(a => a.type === 'backend' || a.type === 'api');
1024
- const hasApi = scan.apps.some(a => a.name === 'api' || a.type === 'backend');
1024
+ // Docker services are also runnable (api, web services from docker-compose)
1025
+ const dockerServices = scan.compose?.applications || [];
1026
+ const dockerServiceNames = dockerServices.map(s => s.name);
1027
+ // Combine backend apps + Docker services (avoid duplicates)
1028
+ const allBackendNames = new Set([
1029
+ ...backendApps.map(a => a.name),
1030
+ ...dockerServiceNames.filter(name => {
1031
+ // Include Docker services that aren't already in apps OR aren't frontend
1032
+ const existingApp = scan.apps.find(a => a.name === name);
1033
+ return !existingApp || existingApp.type !== 'frontend';
1034
+ }),
1035
+ ]);
1036
+ const backendAppNames = Array.from(allBackendNames);
1037
+ const hasBackend = backendAppNames.length > 0;
1025
1038
  // Determine which environment to use for remote connections
1026
1039
  // Priority: staging > production > first defined
1027
1040
  const remoteEnv = definedEnvironments.includes('staging')
@@ -1045,32 +1058,32 @@ function createProfilesFromScan(scan, definedEnvironments = []) {
1045
1058
  // No remote environment - create local-only profiles
1046
1059
  for (const frontend of frontendApps.slice(0, 3)) {
1047
1060
  profiles[`${frontend.name}-local`] = {
1048
- description: `${frontend.name} with local API`,
1061
+ description: `${frontend.name} with local backend`,
1049
1062
  size: 'medium',
1050
- apps: [frontend.name, ...(hasApi ? ['api'] : [])],
1063
+ apps: [frontend.name, ...backendAppNames],
1051
1064
  };
1052
1065
  }
1053
1066
  }
1054
1067
  // Full local development (with DB copy from available environment)
1055
- if (hasApi && frontendApps.length > 0) {
1068
+ if (hasBackend && frontendApps.length > 0) {
1056
1069
  const primaryFrontend = frontendApps[0];
1057
1070
  const dbSource = remoteEnv || 'staging'; // Use defined env or default
1058
1071
  profiles[`${primaryFrontend.name}-full`] = {
1059
- description: `${primaryFrontend.name} + local API + DB copy`,
1072
+ description: `${primaryFrontend.name} + local backend + DB copy`,
1060
1073
  size: 'large',
1061
- apps: [primaryFrontend.name, 'api'],
1074
+ apps: [primaryFrontend.name, ...backendAppNames],
1062
1075
  database: {
1063
1076
  mode: remoteEnv ? 'copy' : 'local', // Only copy if we have a source
1064
1077
  ...(remoteEnv && { source: dbSource }),
1065
1078
  },
1066
1079
  };
1067
1080
  }
1068
- // API development only
1069
- if (hasApi) {
1070
- profiles['api-dev'] = {
1071
- description: 'API with local infrastructure',
1081
+ // Backend/service development only (for each backend app and Docker service)
1082
+ for (const backendName of backendAppNames) {
1083
+ profiles[`${backendName}-dev`] = {
1084
+ description: `${backendName} with local infrastructure`,
1072
1085
  size: 'medium',
1073
- apps: ['api'],
1086
+ apps: [backendName],
1074
1087
  database: {
1075
1088
  mode: 'local',
1076
1089
  },
@@ -1085,13 +1098,17 @@ function createProfilesFromScan(scan, definedEnvironments = []) {
1085
1098
  default_connection: remoteEnv,
1086
1099
  };
1087
1100
  }
1088
- // Full stack
1089
- if (scan.apps.length > 1) {
1101
+ // Full stack - combine apps + Docker services (deduplicated)
1102
+ const allRunnableNames = new Set([
1103
+ ...scan.apps.filter(a => a.type !== 'library').map(a => a.name),
1104
+ ...dockerServiceNames,
1105
+ ]);
1106
+ if (allRunnableNames.size > 1) {
1090
1107
  const dbSource = remoteEnv || 'staging';
1091
1108
  profiles['full-stack'] = {
1092
1109
  description: 'Everything local' + (remoteEnv ? ' with DB copy' : ''),
1093
1110
  size: 'xl',
1094
- apps: scan.apps.filter(a => a.type !== 'library').map(a => a.name),
1111
+ apps: Array.from(allRunnableNames),
1095
1112
  database: {
1096
1113
  mode: remoteEnv ? 'copy' : 'local',
1097
1114
  ...(remoteEnv && { source: dbSource }),
@@ -1845,11 +1862,24 @@ function convertDetectedToScan(detected) {
1845
1862
  }));
1846
1863
  // Convert infrastructure to compose analysis
1847
1864
  let compose = null;
1848
- if (detected.infrastructure && detected.infrastructure.length > 0) {
1865
+ const hasInfra = detected.infrastructure && detected.infrastructure.length > 0;
1866
+ const hasDockerServices = detected.docker_services && detected.docker_services.length > 0;
1867
+ if (hasInfra || hasDockerServices) {
1849
1868
  compose = {
1850
1869
  files: ['docker-compose.yml'],
1851
- applications: [],
1852
- databases: detected.infrastructure
1870
+ applications: (detected.docker_services || []).map(svc => ({
1871
+ name: svc.name,
1872
+ image: svc.image,
1873
+ build: svc.build_context ? {
1874
+ context: svc.build_context,
1875
+ dockerfile: svc.dockerfile,
1876
+ } : undefined,
1877
+ ports: svc.port ? [{ host: svc.port, container: svc.port }] : [],
1878
+ environment: {},
1879
+ dependsOn: svc.depends_on || [],
1880
+ volumes: [],
1881
+ })),
1882
+ databases: (detected.infrastructure || [])
1853
1883
  .filter(i => i.type === 'database')
1854
1884
  .map(i => ({
1855
1885
  name: i.name,
@@ -1859,7 +1889,7 @@ function convertDetectedToScan(detected) {
1859
1889
  dependsOn: [],
1860
1890
  volumes: [],
1861
1891
  })),
1862
- caches: detected.infrastructure
1892
+ caches: (detected.infrastructure || [])
1863
1893
  .filter(i => i.type === 'cache')
1864
1894
  .map(i => ({
1865
1895
  name: i.name,
@@ -1869,7 +1899,7 @@ function convertDetectedToScan(detected) {
1869
1899
  dependsOn: [],
1870
1900
  volumes: [],
1871
1901
  })),
1872
- queues: detected.infrastructure
1902
+ queues: (detected.infrastructure || [])
1873
1903
  .filter(i => i.type === 'queue')
1874
1904
  .map(i => ({
1875
1905
  name: i.name,
@@ -239,6 +239,30 @@ async function interactiveSelection(detected) {
239
239
  // Filter scripts to only selected ones
240
240
  result.scripts = detected.scripts.filter(s => selectedScripts.includes(s.path));
241
241
  }
242
+ // === Docker Services Selection ===
243
+ if (detected.docker_services && detected.docker_services.length > 0) {
244
+ console.log('');
245
+ console.log(chalk_1.default.blue('=== Detected Docker Services ===\n'));
246
+ for (const svc of detected.docker_services) {
247
+ const portInfo = svc.port ? ` port:${svc.port}` : '';
248
+ console.log(` ${chalk_1.default.cyan(svc.name)}${portInfo}`);
249
+ if (svc.build_context) {
250
+ console.log(chalk_1.default.dim(` build: ${svc.dockerfile || 'Dockerfile'}`));
251
+ }
252
+ }
253
+ console.log();
254
+ const dockerChoices = detected.docker_services.map(svc => ({
255
+ name: `${svc.name}${svc.port ? ` (port ${svc.port})` : ''}`,
256
+ value: svc.name,
257
+ checked: true, // Default: include all
258
+ }));
259
+ const selectedDocker = await prompts.checkbox({
260
+ message: 'Select Docker services to include:',
261
+ choices: dockerChoices,
262
+ });
263
+ // Filter docker services to only selected ones
264
+ result.docker_services = detected.docker_services.filter(svc => selectedDocker.includes(svc.name));
265
+ }
242
266
  // === Infrastructure Selection ===
243
267
  if (detected.infrastructure && detected.infrastructure.length > 0) {
244
268
  console.log('');
@@ -482,6 +506,18 @@ function convertScanToDetected(scan, root) {
482
506
  source: 'docker-compose.yml',
483
507
  });
484
508
  }
509
+ // Save Docker application services (services with build context)
510
+ if (scan.compose.applications && scan.compose.applications.length > 0) {
511
+ detected.docker_services = scan.compose.applications.map(app => ({
512
+ name: app.name,
513
+ build_context: app.build?.context,
514
+ dockerfile: app.build?.dockerfile,
515
+ image: app.image,
516
+ port: app.ports?.[0]?.host,
517
+ depends_on: app.dependsOn?.length ? app.dependsOn : undefined,
518
+ source: 'docker-compose.yml',
519
+ }));
520
+ }
485
521
  }
486
522
  // Git info
487
523
  if (scan.git) {
@@ -649,6 +685,17 @@ function showSummary(detected) {
649
685
  console.log(` ${parts.join(' ')}`);
650
686
  }
651
687
  }
688
+ // Docker Services (applications with build context)
689
+ if (detected.docker_services && detected.docker_services.length > 0) {
690
+ console.log(`\n Docker Services (${detected.docker_services.length}):`);
691
+ for (const svc of detected.docker_services) {
692
+ const portInfo = svc.port ? ` port:${svc.port}` : '';
693
+ console.log(` ${chalk_1.default.cyan(svc.name)}${portInfo}`);
694
+ if (svc.build_context) {
695
+ console.log(chalk_1.default.dim(` build: ${svc.build_context}`));
696
+ }
697
+ }
698
+ }
652
699
  // Infrastructure
653
700
  if (detected.infrastructure && detected.infrastructure.length > 0) {
654
701
  console.log(`\n Infrastructure (${detected.infrastructure.length}):`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {