genbox 1.0.220 → 1.0.222

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.
@@ -1446,18 +1446,43 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
1446
1446
  installClaudeCode: config.defaults?.install_claude_code,
1447
1447
  envVars: resolved.env,
1448
1448
  apps: resolved.apps.map(a => a.name),
1449
- appConfigs: resolved.apps.map(a => ({
1450
- name: a.name,
1451
- path: a.path.startsWith('/') ? a.path : `${resolved.repos[0]?.path || '/home/dev'}/${a.path}`,
1452
- type: a.type,
1453
- port: a.port,
1454
- framework: a.framework,
1455
- runner: a.runner,
1456
- docker: a.docker,
1457
- healthcheck: a.healthcheck,
1458
- dependsOn: a.dependsOn,
1459
- commands: a.commands,
1460
- })),
1449
+ appConfigs: resolved.apps.map(a => {
1450
+ // Resolve app path - paths in genbox.yaml are relative to workspace root
1451
+ // e.g., path: "api" with workspace "goodpass" -> /home/dev/goodpass/api
1452
+ let resolvedPath;
1453
+ if (a.path.startsWith('/')) {
1454
+ // Absolute path - use as-is
1455
+ resolvedPath = a.path;
1456
+ }
1457
+ else {
1458
+ // Relative path - resolve from workspace root
1459
+ // First check if there's a matching repo with an absolute path
1460
+ const appConfig = config.apps[a.name];
1461
+ if (appConfig?.repo && config.repos?.[appConfig.repo]?.path) {
1462
+ resolvedPath = config.repos[appConfig.repo].path;
1463
+ }
1464
+ else if (config.repos?.[a.name]?.path) {
1465
+ resolvedPath = config.repos[a.name].path;
1466
+ }
1467
+ else {
1468
+ // Fall back to workspace-relative path
1469
+ const workspaceRoot = resolved.repos[0]?.path?.replace(/\/[^/]+$/, '') || '/home/dev';
1470
+ resolvedPath = `${workspaceRoot}/${a.path}`;
1471
+ }
1472
+ }
1473
+ return {
1474
+ name: a.name,
1475
+ path: resolvedPath,
1476
+ type: a.type,
1477
+ port: a.port,
1478
+ framework: a.framework,
1479
+ runner: a.runner,
1480
+ docker: a.docker,
1481
+ healthcheck: a.healthcheck,
1482
+ dependsOn: a.dependsOn,
1483
+ commands: a.commands,
1484
+ };
1485
+ }),
1461
1486
  infrastructure: resolved.infrastructure.map(i => ({
1462
1487
  name: i.name,
1463
1488
  type: i.type,
@@ -406,8 +406,6 @@ async function runSoftRebuild(options) {
406
406
  continue;
407
407
  // Check for PM2 ecosystem file or package.json scripts
408
408
  const hasPm2Config = await sshExec(ip, keyPath, `test -f ${repoPath}/ecosystem.config.js -o -f ${repoPath}/ecosystem.config.cjs && echo yes || echo no`, 10);
409
- // PM2 watch flags for hot reload in dev environment
410
- const watchFlags = '--watch --ignore-watch "node_modules .git dist build .next"';
411
409
  if (hasPm2Config.output === 'yes') {
412
410
  log(`Starting ${app.name} with PM2...`, 'info');
413
411
  const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start ecosystem.config.js 2>/dev/null || pm2 start ecosystem.config.cjs`, {
@@ -419,31 +417,14 @@ async function runSoftRebuild(options) {
419
417
  }
420
418
  }
421
419
  else {
422
- // Check for dev script in package.json first (preferred), then start script
423
- const hasDevScript = await sshExec(ip, keyPath, `grep -q '"dev"' ${repoPath}/package.json 2>/dev/null && echo yes || echo no`, 10);
424
- if (hasDevScript.output === 'yes') {
425
- log(`Starting ${app.name} with PM2 (pnpm dev)...`, 'info');
426
- const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run dev" --name ${app.name} ${watchFlags}`, {
427
- onStdout: (line) => log(line, 'dim'),
428
- timeoutSecs: 60,
429
- });
430
- if (pm2Result.success) {
431
- log(`✓ Started ${app.name}`, 'success');
432
- }
433
- }
434
- else {
435
- // Fall back to start script
436
- const hasStartScript = await sshExec(ip, keyPath, `grep -q '"start"' ${repoPath}/package.json 2>/dev/null && echo yes || echo no`, 10);
437
- if (hasStartScript.output === 'yes') {
438
- log(`Starting ${app.name} with PM2 (pnpm start)...`, 'info');
439
- const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run start" --name ${app.name} ${watchFlags}`, {
440
- onStdout: (line) => log(line, 'dim'),
441
- timeoutSecs: 60,
442
- });
443
- if (pm2Result.success) {
444
- log(`✓ Started ${app.name}`, 'success');
445
- }
446
- }
420
+ // Always use dev script - dev servers have built-in hot-reload, no --watch needed
421
+ log(`Starting ${app.name} with PM2 (pnpm dev)...`, 'info');
422
+ const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run dev" --name ${app.name}`, {
423
+ onStdout: (line) => log(line, 'dim'),
424
+ timeoutSecs: 60,
425
+ });
426
+ if (pm2Result.success) {
427
+ log(`✓ Started ${app.name}`, 'success');
447
428
  }
448
429
  }
449
430
  }
@@ -159,38 +159,38 @@ exports.restartCommand = new commander_1.Command('restart')
159
159
  appPath = findResult.stdout.trim();
160
160
  }
161
161
  }
162
- const startCmd = app.commands?.dev || app.commands?.start || 'npm run dev';
162
+ // Always use dev command - dev servers have built-in hot-reload
163
+ const startCmd = app.commands?.dev || 'npm run dev';
163
164
  // For frontend apps with a configured port, add port argument
164
165
  // This is needed for frameworks like Next.js that accept -p/--port
165
166
  const portArg = app.port ? ` -- -p ${app.port}` : '';
166
- // Start the app with PM2 (with watch enabled for hot reload)
167
+ // Start the app with PM2 (dev servers have built-in hot-reload, no --watch needed)
167
168
  // Parse the start command - if it's "npm run X", use pm2 start npm -- run X
168
169
  // If it's just a script name like "dev", treat it as npm run <script>
169
- const watchFlags = '--watch --ignore-watch "node_modules .git dist build .next"';
170
170
  let pm2Cmd;
171
171
  if (startCmd.startsWith('npm run ')) {
172
172
  const script = startCmd.replace('npm run ', '');
173
- pm2Cmd = `pm2 start npm --name "${app.name}" ${watchFlags} -- run ${script}${portArg}`;
173
+ pm2Cmd = `pm2 start npm --name "${app.name}" -- run ${script}${portArg}`;
174
174
  }
175
175
  else if (startCmd.startsWith('pnpm ')) {
176
176
  const script = startCmd.replace('pnpm ', '');
177
- pm2Cmd = `pm2 start pnpm --name "${app.name}" ${watchFlags} -- ${script}${portArg}`;
177
+ pm2Cmd = `pm2 start pnpm --name "${app.name}" -- ${script}${portArg}`;
178
178
  }
179
179
  else if (startCmd.startsWith('yarn ')) {
180
180
  const script = startCmd.replace('yarn ', '');
181
- pm2Cmd = `pm2 start yarn --name "${app.name}" ${watchFlags} -- ${script}${portArg}`;
181
+ pm2Cmd = `pm2 start yarn --name "${app.name}" -- ${script}${portArg}`;
182
182
  }
183
183
  else if (startCmd.startsWith('bun ')) {
184
184
  const script = startCmd.replace('bun ', '');
185
- pm2Cmd = `pm2 start bun --name "${app.name}" ${watchFlags} -- ${script}${portArg}`;
185
+ pm2Cmd = `pm2 start bun --name "${app.name}" -- ${script}${portArg}`;
186
186
  }
187
187
  else if (/^[a-z0-9:-]+$/.test(startCmd) && !startCmd.includes('/')) {
188
188
  // Single word like "dev", "start", "serve" - treat as npm script name
189
- pm2Cmd = `pm2 start npm --name "${app.name}" ${watchFlags} -- run ${startCmd}${portArg}`;
189
+ pm2Cmd = `pm2 start npm --name "${app.name}" -- run ${startCmd}${portArg}`;
190
190
  }
191
191
  else {
192
192
  // Assume it's a direct script/file path
193
- pm2Cmd = `pm2 start "${startCmd}" --name "${app.name}" ${watchFlags}`;
193
+ pm2Cmd = `pm2 start "${startCmd}" --name "${app.name}"`;
194
194
  }
195
195
  pm2Spinner.text = `Starting ${app.name}...`;
196
196
  const fullCmd = `source ~/.nvm/nvm.sh 2>/dev/null; cd ${appPath} && ${pm2Cmd} 2>&1`;
@@ -267,23 +267,24 @@ exports.restartCommand = new commander_1.Command('restart')
267
267
  appPath = findResult.stdout.trim();
268
268
  }
269
269
  }
270
- const startCmd = app.commands?.dev || app.commands?.start || 'npm run dev';
270
+ // Always use dev command - dev servers have built-in hot-reload
271
+ const startCmd = app.commands?.dev || 'npm run dev';
271
272
  const portArg = app.port ? ` -- -p ${app.port}` : '';
272
- const watchFlags = '--watch --ignore-watch "node_modules .git dist build .next"';
273
+ // Dev servers have built-in hot-reload, no --watch needed
273
274
  let pm2Cmd;
274
275
  if (startCmd.startsWith('npm run ')) {
275
276
  const script = startCmd.replace('npm run ', '');
276
- pm2Cmd = `pm2 start npm --name "${app.name}" ${watchFlags} -- run ${script}${portArg}`;
277
+ pm2Cmd = `pm2 start npm --name "${app.name}" -- run ${script}${portArg}`;
277
278
  }
278
279
  else if (startCmd.startsWith('pnpm ')) {
279
280
  const script = startCmd.replace('pnpm ', '');
280
- pm2Cmd = `pm2 start pnpm --name "${app.name}" ${watchFlags} -- ${script}${portArg}`;
281
+ pm2Cmd = `pm2 start pnpm --name "${app.name}" -- ${script}${portArg}`;
281
282
  }
282
283
  else if (/^[a-z0-9:-]+$/.test(startCmd) && !startCmd.includes('/')) {
283
- pm2Cmd = `pm2 start npm --name "${app.name}" ${watchFlags} -- run ${startCmd}${portArg}`;
284
+ pm2Cmd = `pm2 start npm --name "${app.name}" -- run ${startCmd}${portArg}`;
284
285
  }
285
286
  else {
286
- pm2Cmd = `pm2 start "${startCmd}" --name "${app.name}" ${watchFlags}`;
287
+ pm2Cmd = `pm2 start "${startCmd}" --name "${app.name}"`;
287
288
  }
288
289
  pm2Spinner.text = `Starting ${app.name}${app.port ? ` on port ${app.port}` : ''}...`;
289
290
  const startResult = sshExec(target.ipAddress, keyPath, `source ~/.nvm/nvm.sh 2>/dev/null; cd ${appPath} && ${pm2Cmd} 2>&1`, 60);
@@ -236,8 +236,8 @@ Or with pnpm:
236
236
  message: `PM2 is not installed.\n\n${this.getPm2InstallInstructions()}`,
237
237
  };
238
238
  }
239
- // Get start command
240
- const startCommand = app.commands?.dev || app.commands?.start || 'npm run dev';
239
+ // Get dev command (dev servers have their own hot-reload, no need for PM2 watch)
240
+ const startCommand = app.commands?.dev || 'npm run dev';
241
241
  const [cmd, ...args] = startCommand.split(' ');
242
242
  // Create PM2 name
243
243
  const pm2Name = `${this.projectName}-${app.name}`;
@@ -262,14 +262,12 @@ Or with pnpm:
262
262
  catch {
263
263
  // Not running, continue to start
264
264
  }
265
- // Start with PM2 (with watch enabled for hot reload)
265
+ // Start with PM2 (dev servers have built-in hot-reload, no --watch needed)
266
266
  const pm2Args = [
267
267
  'start',
268
268
  cmd,
269
269
  '--name', pm2Name,
270
270
  '--cwd', appPath,
271
- '--watch',
272
- '--ignore-watch', 'node_modules .git dist build .next .nuxt coverage',
273
271
  '--',
274
272
  ...args,
275
273
  ];
@@ -448,10 +446,10 @@ Or with pnpm:
448
446
  apps: apps.map((app) => ({
449
447
  name: `${this.projectName}-${app.name}`,
450
448
  cwd: app.path ? path.join(this.workdir, app.path) : this.workdir,
451
- script: app.commands?.dev || app.commands?.start || 'npm run dev',
449
+ // Always use dev command - dev servers have built-in hot-reload
450
+ script: app.commands?.dev || 'npm run dev',
452
451
  env: app.env || {},
453
- watch: true,
454
- ignore_watch: ['node_modules', '.git', 'dist', 'build', '.next', '.nuxt', 'coverage', '*.log'],
452
+ // No watch needed - dev servers handle their own hot-reload
455
453
  autorestart: true,
456
454
  })),
457
455
  };
@@ -678,8 +678,8 @@ runcmd:
678
678
  }
679
679
  // Build PM2 command with PORT and HOSTNAME env vars for frameworks that respect them
680
680
  // Include cd inside the bash command string so pnpm runs in the correct directory
681
- // Enable watch for hot reload in dev environment
682
- const pm2StartCmd = `PORT=${appPort} HOSTNAME=0.0.0.0 pm2 start 'cd ${appDir} && ${actualCmd}' --name ${pm2Name} --watch --ignore-watch "node_modules .git dist build .next"`;
681
+ // Dev servers have built-in hot-reload, no --watch needed
682
+ const pm2StartCmd = `PORT=${appPort} HOSTNAME=0.0.0.0 pm2 start 'cd ${appDir} && ${actualCmd}' --name ${pm2Name}`;
683
683
  // Start with PM2
684
684
  (0, child_process_1.execSync)(`ssh ${sshOpts} dev@${info.ipv4} "source /home/dev/.nvm/nvm.sh && ${pm2StartCmd}"`, { stdio: 'pipe', timeout: 60000 });
685
685
  // Get process info
@@ -795,8 +795,8 @@ runcmd:
795
795
  actualCmd = `${detectedPkgMgr} run dev -- --host 0.0.0.0 --port ${appPort}`;
796
796
  }
797
797
  // Build PM2 command with PORT and HOSTNAME env vars
798
- // Enable watch for hot reload in dev environment
799
- const pm2StartCmd = `PORT=${appPort} HOSTNAME=0.0.0.0 pm2 start 'cd ${vmAppPath} && ${actualCmd}' --name ${pm2Name} --watch --ignore-watch "node_modules .git dist build .next"`;
798
+ // Dev servers have built-in hot-reload, no --watch needed
799
+ const pm2StartCmd = `PORT=${appPort} HOSTNAME=0.0.0.0 pm2 start 'cd ${vmAppPath} && ${actualCmd}' --name ${pm2Name}`;
800
800
  // Start with PM2
801
801
  (0, child_process_1.execSync)(`ssh ${sshOpts} dev@${info.ipv4} "source /home/dev/.nvm/nvm.sh && ${pm2StartCmd}"`, { stdio: 'pipe', timeout: 60000 });
802
802
  // Get process info
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.220",
3
+ "version": "1.0.222",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {