genbox 1.0.44 → 1.0.46

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.
@@ -221,9 +221,9 @@ exports.createCommand = new commander_1.Command('create')
221
221
  .option('--db <mode>', 'Database mode: none, local, copy, remote')
222
222
  .option('--db-source <source>', 'Database source: staging, production')
223
223
  .option('-s, --size <size>', 'Server size: small, medium, large, xl')
224
- .option('-b, --branch <branch>', 'Git branch to checkout')
225
- .option('-n, --new-branch <name>', 'Create a new branch with this name')
226
- .option('-f, --from-branch <branch>', 'Source branch to create new branch from (defaults to current/default branch)')
224
+ .option('-b, --branch <branch>', 'Use existing git branch (skips new branch creation)')
225
+ .option('-n, --new-branch <name>', 'Create a new branch with this name (defaults to env name)')
226
+ .option('-f, --from-branch <branch>', 'Source branch to create new branch from (defaults to config default or main)')
227
227
  .option('-y, --yes', 'Skip interactive prompts')
228
228
  .option('--dry-run', 'Show what would be created without actually creating')
229
229
  .action(async (nameArg, options) => {
@@ -286,19 +286,19 @@ exports.createCommand = new commander_1.Command('create')
286
286
  }
287
287
  // Silently continue for other errors - the create API will validate
288
288
  }
289
- // Validate branch options
289
+ // Determine branch configuration
290
+ // Default: create new branch from configured default (or 'main') with name = environment name
291
+ let newBranchName = options.newBranch;
292
+ let sourceBranch = options.fromBranch;
293
+ // If -n (--new-branch) is provided without -f (--from-branch), default source to configured default branch
290
294
  if (options.newBranch && !options.fromBranch) {
291
- console.error(chalk_1.default.red('Error: --new-branch (-n) requires --from-branch (-f) to specify the source branch'));
292
- console.log(chalk_1.default.dim(' Example: genbox create my-env -n feature/new -f main'));
293
- return;
295
+ sourceBranch = config.defaults?.branch || 'main';
296
+ console.log(chalk_1.default.dim(` Source branch not specified, using '${sourceBranch}'`));
294
297
  }
295
- // Auto-generate branch name if only -f is provided
296
- let newBranchName = options.newBranch;
298
+ // If -f (--from-branch) is provided without -n (--new-branch), use env name as branch name
297
299
  if (options.fromBranch && !options.newBranch) {
298
- // Generate unique branch name: {genbox-name}-{short-timestamp}
299
- const timestamp = Date.now().toString(36); // Short alphanumeric timestamp
300
- newBranchName = `${name}-${timestamp}`;
301
- console.log(chalk_1.default.dim(` Auto-generated branch name: ${newBranchName}`));
300
+ newBranchName = name;
301
+ console.log(chalk_1.default.dim(` New branch name: ${newBranchName}`));
302
302
  }
303
303
  // Build create options
304
304
  const createOptions = {
@@ -312,7 +312,7 @@ exports.createCommand = new commander_1.Command('create')
312
312
  size: options.size,
313
313
  branch: options.branch,
314
314
  newBranch: newBranchName,
315
- sourceBranch: options.fromBranch,
315
+ sourceBranch: sourceBranch,
316
316
  yes: options.yes,
317
317
  dryRun: options.dryRun,
318
318
  };
@@ -323,7 +323,21 @@ exports.createCommand = new commander_1.Command('create')
323
323
  // Interactive branch selection if no branch options were specified
324
324
  // Skip if: -b (existing branch), -f (new branch from source), -n (explicit new branch name), or -y (skip prompts)
325
325
  if (!options.branch && !options.fromBranch && !options.newBranch && !options.yes && resolved.repos.length > 0) {
326
- resolved = await promptForBranchOptions(resolved, config);
326
+ resolved = await promptForBranchOptions(resolved, config, name);
327
+ }
328
+ // Default behavior when -y (non-interactive) and no branch options: create new branch from configured default
329
+ if (!options.branch && !options.fromBranch && !options.newBranch && options.yes && resolved.repos.length > 0) {
330
+ const baseBranch = config.defaults?.branch || 'main';
331
+ resolved = {
332
+ ...resolved,
333
+ repos: resolved.repos.map(repo => ({
334
+ ...repo,
335
+ branch: name, // Branch name same as environment name
336
+ newBranch: name,
337
+ sourceBranch: baseBranch,
338
+ })),
339
+ };
340
+ console.log(chalk_1.default.dim(` Creating new branch '${name}' from '${baseBranch}'`));
327
341
  }
328
342
  // Display resolved configuration
329
343
  displayResolvedConfig(resolved);
@@ -515,59 +529,51 @@ function displayResolvedConfig(resolved) {
515
529
  }
516
530
  /**
517
531
  * Prompt for branch options interactively
532
+ * Default behavior: create new branch from configured default (or 'main') with branch name = environment name
518
533
  */
519
- async function promptForBranchOptions(resolved, config) {
520
- // Get the default branch from config or first repo
521
- const defaultBranch = config.defaults?.branch || resolved.repos[0]?.branch || 'main';
534
+ async function promptForBranchOptions(resolved, config, envName) {
535
+ // Get the default/base branch from config (used as source for new branches)
536
+ const baseBranch = config.defaults?.branch || 'main';
522
537
  console.log(chalk_1.default.blue('=== Branch Configuration ==='));
523
- console.log(chalk_1.default.dim(`Default branch: ${defaultBranch}`));
524
538
  console.log('');
525
539
  const branchChoice = await prompts.select({
526
540
  message: 'Branch option:',
527
541
  choices: [
528
542
  {
529
- name: `Use default branch (${defaultBranch})`,
530
- value: 'default',
543
+ name: `${chalk_1.default.green('Create new branch')} '${chalk_1.default.cyan(envName)}' from '${baseBranch}' ${chalk_1.default.dim('(recommended)')}`,
544
+ value: 'new-from-default',
545
+ },
546
+ {
547
+ name: `Create new branch from a different source`,
548
+ value: 'new-custom',
531
549
  },
532
550
  {
533
- name: 'Use a different existing branch',
551
+ name: 'Use an existing branch',
534
552
  value: 'existing',
535
553
  },
536
554
  {
537
- name: 'Create a new branch',
538
- value: 'new',
555
+ name: `Use '${baseBranch}' directly without creating new branch`,
556
+ value: 'default',
539
557
  },
540
558
  ],
541
- default: 'default',
559
+ default: 'new-from-default',
542
560
  });
543
- if (branchChoice === 'default') {
544
- // Keep resolved repos as-is
545
- return resolved;
546
- }
547
- if (branchChoice === 'existing') {
548
- const branchName = await prompts.input({
549
- message: 'Enter branch name:',
550
- default: defaultBranch,
551
- validate: (value) => {
552
- if (!value.trim())
553
- return 'Branch name is required';
554
- return true;
555
- },
556
- });
557
- // Update all repos with the selected branch
561
+ if (branchChoice === 'new-from-default') {
562
+ // Create new branch from configured default with name = environment name
558
563
  return {
559
564
  ...resolved,
560
565
  repos: resolved.repos.map(repo => ({
561
566
  ...repo,
562
- branch: branchName.trim(),
563
- newBranch: undefined,
564
- sourceBranch: undefined,
567
+ branch: envName,
568
+ newBranch: envName,
569
+ sourceBranch: baseBranch,
565
570
  })),
566
571
  };
567
572
  }
568
- if (branchChoice === 'new') {
573
+ if (branchChoice === 'new-custom') {
569
574
  const newBranchName = await prompts.input({
570
575
  message: 'New branch name:',
576
+ default: envName,
571
577
  validate: (value) => {
572
578
  if (!value.trim())
573
579
  return 'Branch name is required';
@@ -578,7 +584,7 @@ async function promptForBranchOptions(resolved, config) {
578
584
  });
579
585
  const sourceBranch = await prompts.input({
580
586
  message: 'Create from branch:',
581
- default: defaultBranch,
587
+ default: 'main',
582
588
  validate: (value) => {
583
589
  if (!value.trim())
584
590
  return 'Source branch is required';
@@ -596,6 +602,31 @@ async function promptForBranchOptions(resolved, config) {
596
602
  })),
597
603
  };
598
604
  }
605
+ if (branchChoice === 'existing') {
606
+ const branchName = await prompts.input({
607
+ message: 'Enter branch name:',
608
+ default: baseBranch,
609
+ validate: (value) => {
610
+ if (!value.trim())
611
+ return 'Branch name is required';
612
+ return true;
613
+ },
614
+ });
615
+ // Update all repos with the selected branch
616
+ return {
617
+ ...resolved,
618
+ repos: resolved.repos.map(repo => ({
619
+ ...repo,
620
+ branch: branchName.trim(),
621
+ newBranch: undefined,
622
+ sourceBranch: undefined,
623
+ })),
624
+ };
625
+ }
626
+ if (branchChoice === 'default') {
627
+ // Keep resolved repos as-is (no new branch)
628
+ return resolved;
629
+ }
599
630
  return resolved;
600
631
  }
601
632
  /**
@@ -830,6 +861,7 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
830
861
  gitToken: envVars.GIT_TOKEN,
831
862
  gitUserName: gitConfig.userName,
832
863
  gitUserEmail: gitConfig.userEmail,
864
+ installClaudeCode: config.defaults?.install_claude_code,
833
865
  envVars: resolved.env,
834
866
  apps: resolved.apps.map(a => a.name),
835
867
  appConfigs: resolved.apps.map(a => ({
@@ -665,12 +665,25 @@ exports.initCommand = new commander_1.Command('init')
665
665
  v4Config.defaults = {};
666
666
  }
667
667
  v4Config.defaults.size = serverSize;
668
- // Get default branch (use detected branch or allow override)
668
+ // Ask about Claude Code installation
669
+ if (!nonInteractive && !options.fromScan) {
670
+ const installClaudeCode = await prompts.confirm({
671
+ message: 'Install Claude Code CLI on genbox servers?',
672
+ default: true,
673
+ });
674
+ if (installClaudeCode) {
675
+ v4Config.defaults.install_claude_code = true;
676
+ }
677
+ }
678
+ // Get default/base branch (source branch for creating new environment branches)
669
679
  const detectedBranch = scan.git?.branch || 'main';
670
680
  let defaultBranch = detectedBranch;
671
681
  if (!nonInteractive && !options.fromScan) {
682
+ console.log('');
683
+ console.log(chalk_1.default.dim(' When creating environments, a new branch is created from this base branch.'));
684
+ console.log(chalk_1.default.dim(' The new branch name defaults to the environment name.'));
672
685
  const branchInput = await prompts.input({
673
- message: 'Default branch for new environments:',
686
+ message: 'Base branch for new environment branches:',
674
687
  default: detectedBranch,
675
688
  });
676
689
  defaultBranch = branchInput || detectedBranch;
@@ -1132,7 +1132,7 @@ function showSummary(detected) {
1132
1132
  if (detected.git?.remote) {
1133
1133
  console.log(`\n Git: ${detected.git.provider || 'git'} (${detected.git.type})`);
1134
1134
  console.log(` Remote: ${chalk_1.default.dim(detected.git.remote)}`);
1135
- console.log(` Branch: ${chalk_1.default.cyan(detected.git.branch || 'main')} ${chalk_1.default.dim('← default branch for new environments')}`);
1135
+ console.log(` Branch: ${chalk_1.default.cyan(detected.git.branch || 'main')} ${chalk_1.default.dim('← base branch for new environment branches')}`);
1136
1136
  }
1137
1137
  // Per-app git repos (for multi-repo workspaces)
1138
1138
  const appsWithGit = Object.entries(detected.apps).filter(([, app]) => app.git);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {