genbox 1.0.205 → 1.0.207
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/dist/commands/create.js
CHANGED
|
@@ -605,8 +605,10 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
605
605
|
// Support both v3 and v4 configs
|
|
606
606
|
const config = loadResult.config;
|
|
607
607
|
const profileResolver = new profile_resolver_1.ProfileResolver(configLoader);
|
|
608
|
-
// Use username
|
|
609
|
-
|
|
608
|
+
// Use username for name uniqueness check, but keep workspace as project name
|
|
609
|
+
// The API uses ownerUsername (from user account) for URL generation
|
|
610
|
+
// Lowercase for consistent URL generation
|
|
611
|
+
const workspace = (config.project?.name || 'default').toLowerCase();
|
|
610
612
|
// Handle --restore option: fetch backup info by genbox name
|
|
611
613
|
if (options.restore) {
|
|
612
614
|
// Require genbox name for restore
|
|
@@ -685,8 +687,9 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
685
687
|
if (!selectedProfile && !options.yes && config.profiles && Object.keys(config.profiles).length > 0) {
|
|
686
688
|
selectedProfile = await promptForProfile(config.profiles);
|
|
687
689
|
}
|
|
688
|
-
// Check if name is available
|
|
689
|
-
|
|
690
|
+
// Check if name is available for this user, add incremental suffix if taken
|
|
691
|
+
// Use username for uniqueness (names are unique per user, not per workspace)
|
|
692
|
+
const uniqueResult = await (0, genbox_wizard_1.ensureUniqueName)(name, usernameResult.username);
|
|
690
693
|
if (uniqueResult.wasModified) {
|
|
691
694
|
console.log(chalk_1.default.yellow(` Name '${name}' is already in use, using '${uniqueResult.name}' instead`));
|
|
692
695
|
name = uniqueResult.name;
|
|
@@ -1431,7 +1434,7 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
|
|
|
1431
1434
|
name: resolved.name,
|
|
1432
1435
|
size: resolved.size,
|
|
1433
1436
|
publicKey,
|
|
1434
|
-
workspace: resolved.project.name,
|
|
1437
|
+
workspace: resolved.project.name.toLowerCase(),
|
|
1435
1438
|
services,
|
|
1436
1439
|
files,
|
|
1437
1440
|
postDetails,
|
|
@@ -1662,7 +1665,7 @@ async function createLegacy(name, options) {
|
|
|
1662
1665
|
name,
|
|
1663
1666
|
size,
|
|
1664
1667
|
publicKey,
|
|
1665
|
-
workspace: config.project_name || 'default',
|
|
1668
|
+
workspace: (config.project_name || 'default').toLowerCase(),
|
|
1666
1669
|
services: config.services,
|
|
1667
1670
|
files: filesBundle,
|
|
1668
1671
|
postDetails,
|
package/dist/commands/new.js
CHANGED
|
@@ -183,7 +183,6 @@ exports.newCommand = new commander_1.Command('new')
|
|
|
183
183
|
console.log(chalk_1.default.dim('\nCancelled. Set a username first with: gb username set <name>'));
|
|
184
184
|
return;
|
|
185
185
|
}
|
|
186
|
-
const workspace = usernameResult.username;
|
|
187
186
|
// Size selection
|
|
188
187
|
let size = options.size || preferences.defaultGenboxSize || template.recommendedSize;
|
|
189
188
|
if (!options.yes && !options.size) {
|
|
@@ -250,7 +249,8 @@ exports.newCommand = new commander_1.Command('new')
|
|
|
250
249
|
return;
|
|
251
250
|
}
|
|
252
251
|
// Check if name is available, add incremental suffix if taken
|
|
253
|
-
|
|
252
|
+
// Use username as namespace for name uniqueness (API uses ownerUsername for URL generation)
|
|
253
|
+
const uniqueResult = await (0, genbox_wizard_1.ensureUniqueName)(projectName, usernameResult.username);
|
|
254
254
|
if (uniqueResult.wasModified) {
|
|
255
255
|
console.log(chalk_1.default.yellow(` Name '${projectName}' is already in use, using '${uniqueResult.name}' instead`));
|
|
256
256
|
projectName = uniqueResult.name;
|
|
@@ -286,12 +286,15 @@ exports.newCommand = new commander_1.Command('new')
|
|
|
286
286
|
}
|
|
287
287
|
// Get SSH key
|
|
288
288
|
const publicKey = (0, utils_1.getPublicSshKey)();
|
|
289
|
+
// Get git config for commits
|
|
290
|
+
const gitConfig = (0, utils_1.getGitConfig)();
|
|
289
291
|
// Build payload
|
|
292
|
+
// Note: workspace is 'default' - the API uses ownerUsername (from user account) for URL generation
|
|
290
293
|
const payload = {
|
|
291
294
|
name: projectName,
|
|
292
295
|
size,
|
|
293
296
|
publicKey,
|
|
294
|
-
workspace,
|
|
297
|
+
workspace: 'default',
|
|
295
298
|
template: template.name,
|
|
296
299
|
services: {},
|
|
297
300
|
files: [],
|
|
@@ -299,6 +302,8 @@ exports.newCommand = new commander_1.Command('new')
|
|
|
299
302
|
repos: {},
|
|
300
303
|
installClaudeCode,
|
|
301
304
|
installGeminiCli,
|
|
305
|
+
gitUserName: gitConfig.userName,
|
|
306
|
+
gitUserEmail: gitConfig.userEmail,
|
|
302
307
|
};
|
|
303
308
|
// If template uses createCommand, set it up
|
|
304
309
|
if (template.createCommand) {
|
|
@@ -484,7 +484,7 @@ async function startSessionOnGenbox(provider, genbox) {
|
|
|
484
484
|
const cliCommand = provider === 'claude'
|
|
485
485
|
? 'claude --dangerously-skip-permissions'
|
|
486
486
|
: provider === 'gemini'
|
|
487
|
-
? 'gemini'
|
|
487
|
+
? 'gemini --yolo'
|
|
488
488
|
: 'codex';
|
|
489
489
|
console.log(chalk_1.default.dim(`\nStarting ${provider} on ${targetGenbox.name}...`));
|
|
490
490
|
// Ensure dtach is installed (skip for Docker - already installed during creation)
|
|
@@ -1247,16 +1247,19 @@ async function attachToCloudSession(session) {
|
|
|
1247
1247
|
// Build the remote command
|
|
1248
1248
|
const socketDir = getRemoteDtachSocketDir();
|
|
1249
1249
|
const socketPath = `${socketDir}/${session.name}.sock`;
|
|
1250
|
+
// Detect provider from session name
|
|
1251
|
+
const isGemini = session.name.toLowerCase().includes('gemini');
|
|
1252
|
+
const cliCommand = isGemini ? 'gemini --yolo' : 'claude --dangerously-skip-permissions';
|
|
1250
1253
|
let remoteCmd;
|
|
1251
1254
|
// Note: We use grep to extract GENBOX_PROJECT_DIR from .bashrc since .bashrc may have early return for non-interactive shells
|
|
1252
1255
|
const cdToProject = 'eval $(grep GENBOX_PROJECT_DIR ~/.bashrc 2>/dev/null); cd $GENBOX_PROJECT_DIR 2>/dev/null;';
|
|
1253
1256
|
if (hasDtach) {
|
|
1254
1257
|
// Use dtach for session persistence
|
|
1255
|
-
remoteCmd = `mkdir -p ${socketDir} && dtach -A ${socketPath} bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null;
|
|
1258
|
+
remoteCmd = `mkdir -p ${socketDir} && dtach -A ${socketPath} bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null; ${cliCommand}'`;
|
|
1256
1259
|
}
|
|
1257
1260
|
else {
|
|
1258
1261
|
// Fallback to direct execution (no persistence)
|
|
1259
|
-
remoteCmd = `bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null;
|
|
1262
|
+
remoteCmd = `bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null; ${cliCommand}'`;
|
|
1260
1263
|
}
|
|
1261
1264
|
const sshArgs = [
|
|
1262
1265
|
'-t',
|
|
@@ -1316,19 +1319,23 @@ async function attachToLocalGenboxSession(session) {
|
|
|
1316
1319
|
const hasDtach = await ensureDtachInstalled(vmIp, keyPath);
|
|
1317
1320
|
// Set up SSH multiplexing for faster uploads
|
|
1318
1321
|
setupSshMultiplexing(vmIp, keyPath);
|
|
1322
|
+
// Detect provider from session name
|
|
1323
|
+
const isGemini = session.name.toLowerCase().includes('gemini');
|
|
1324
|
+
const provider = isGemini ? 'gemini' : 'claude';
|
|
1325
|
+
const cliCommand = isGemini ? 'gemini --yolo' : 'claude --dangerously-skip-permissions';
|
|
1319
1326
|
// Start clipboard watcher
|
|
1320
|
-
const clipboardInterval = startClipboardWatcher(vmIp, keyPath,
|
|
1327
|
+
const clipboardInterval = startClipboardWatcher(vmIp, keyPath, provider, genboxName);
|
|
1321
1328
|
// Build the remote command
|
|
1322
1329
|
const socketDir = getRemoteDtachSocketDir();
|
|
1323
|
-
const socketPath = `${socketDir}
|
|
1330
|
+
const socketPath = `${socketDir}/${provider}.sock`;
|
|
1324
1331
|
let remoteCmd;
|
|
1325
1332
|
// Note: We use grep to extract GENBOX_PROJECT_DIR from .bashrc since .bashrc may have early return for non-interactive shells
|
|
1326
1333
|
const cdToProject = 'eval $(grep GENBOX_PROJECT_DIR ~/.bashrc 2>/dev/null); cd $GENBOX_PROJECT_DIR 2>/dev/null;';
|
|
1327
1334
|
if (hasDtach) {
|
|
1328
|
-
remoteCmd = `mkdir -p ${socketDir} && dtach -A ${socketPath} bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null;
|
|
1335
|
+
remoteCmd = `mkdir -p ${socketDir} && dtach -A ${socketPath} bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null; ${cliCommand}'`;
|
|
1329
1336
|
}
|
|
1330
1337
|
else {
|
|
1331
|
-
remoteCmd = `bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null;
|
|
1338
|
+
remoteCmd = `bash -c '${cdToProject} source ~/.nvm/nvm.sh 2>/dev/null; ${cliCommand}'`;
|
|
1332
1339
|
}
|
|
1333
1340
|
// SSH into VM and attach/create dtach session
|
|
1334
1341
|
const sshArgs = [
|
|
@@ -1353,10 +1360,14 @@ async function attachToLocalGenboxSession(session) {
|
|
|
1353
1360
|
else if (session.isolation === 'docker' || session.isolation === 'native') {
|
|
1354
1361
|
// Docker isolation runs infrastructure in containers but apps natively via PM2
|
|
1355
1362
|
// Native isolation runs everything natively
|
|
1356
|
-
// In both cases, we run
|
|
1363
|
+
// In both cases, we run the CLI locally in a dtach session in the workdir
|
|
1357
1364
|
// Note: Image upload not needed for native/docker as files are already local
|
|
1358
1365
|
const workdir = genboxSession.workdir || process.cwd();
|
|
1359
|
-
|
|
1366
|
+
// Detect provider from session name
|
|
1367
|
+
const isGemini = session.name.toLowerCase().includes('gemini');
|
|
1368
|
+
const provider = isGemini ? 'gemini' : 'claude';
|
|
1369
|
+
const cliCommand = isGemini ? 'gemini --yolo' : 'claude --dangerously-skip-permissions';
|
|
1370
|
+
console.log(chalk_1.default.dim(`\nStarting ${provider} session in ${workdir}...`));
|
|
1360
1371
|
// Check for local dtach
|
|
1361
1372
|
const dtachStatus = await ensureLocalDtach();
|
|
1362
1373
|
if (dtachStatus === 'cancel') {
|
|
@@ -1364,14 +1375,14 @@ async function attachToLocalGenboxSession(session) {
|
|
|
1364
1375
|
}
|
|
1365
1376
|
const useDtach = dtachStatus === 'available';
|
|
1366
1377
|
// Build command
|
|
1367
|
-
const sessionName =
|
|
1378
|
+
const sessionName = `${provider}-${session.name}`;
|
|
1368
1379
|
const socketPath = getDtachSocketPath(sessionName);
|
|
1369
1380
|
let cmd;
|
|
1370
1381
|
if (useDtach) {
|
|
1371
|
-
cmd = `cd "${workdir}" && dtach -A "${socketPath}"
|
|
1382
|
+
cmd = `cd "${workdir}" && dtach -A "${socketPath}" ${cliCommand}`;
|
|
1372
1383
|
}
|
|
1373
1384
|
else {
|
|
1374
|
-
cmd = `cd "${workdir}" &&
|
|
1385
|
+
cmd = `cd "${workdir}" && ${cliCommand}`;
|
|
1375
1386
|
}
|
|
1376
1387
|
const proc = (0, child_process_1.spawn)('bash', ['-c', cmd], { stdio: 'inherit' });
|
|
1377
1388
|
await new Promise((resolve) => {
|
|
@@ -1631,7 +1642,7 @@ async function createNewSessionInGenbox(genbox) {
|
|
|
1631
1642
|
const sessionName = `${provider}-${Date.now().toString(36)}`;
|
|
1632
1643
|
const cliCommand = provider === 'claude'
|
|
1633
1644
|
? 'claude --dangerously-skip-permissions'
|
|
1634
|
-
: 'gemini';
|
|
1645
|
+
: 'gemini --yolo';
|
|
1635
1646
|
console.log(chalk_1.default.dim(`\nCreating ${provider} session in ${genbox.name}...`));
|
|
1636
1647
|
if (genbox.type === 'local' && genbox._genboxSession) {
|
|
1637
1648
|
const gs = genbox._genboxSession;
|
|
@@ -1886,7 +1897,7 @@ async function createCloudSessionOnGenbox(provider, workdir) {
|
|
|
1886
1897
|
// Create dtach session on genbox
|
|
1887
1898
|
const sessionName = `${provider}-${Date.now().toString(36)}`;
|
|
1888
1899
|
const keyPath = getPrivateSshKey();
|
|
1889
|
-
const cliCommand = provider === 'claude' ? 'claude --dangerously-skip-permissions' : provider === 'gemini' ? 'gemini' : 'codex';
|
|
1900
|
+
const cliCommand = provider === 'claude' ? 'claude --dangerously-skip-permissions' : provider === 'gemini' ? 'gemini --yolo' : 'codex';
|
|
1890
1901
|
// Ensure dtach is installed
|
|
1891
1902
|
await ensureDtachInstalled(genbox.ipAddress, keyPath);
|
|
1892
1903
|
// Create session in background using nohup with dtach
|
|
@@ -748,6 +748,52 @@ async function ensureUniqueName(name, workspace) {
|
|
|
748
748
|
return { name, wasModified: false };
|
|
749
749
|
}
|
|
750
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* Detect if current directory is a git repository and get its remote URL
|
|
753
|
+
*/
|
|
754
|
+
function detectGitRepo() {
|
|
755
|
+
try {
|
|
756
|
+
// Check if .git exists
|
|
757
|
+
if (!fs.existsSync(path.join(process.cwd(), '.git'))) {
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
760
|
+
// Get the remote origin URL
|
|
761
|
+
const remoteUrl = (0, child_process_1.execSync)('git remote get-url origin 2>/dev/null', {
|
|
762
|
+
encoding: 'utf8',
|
|
763
|
+
cwd: process.cwd(),
|
|
764
|
+
}).trim();
|
|
765
|
+
if (!remoteUrl) {
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
// Get current branch
|
|
769
|
+
let branch = 'main';
|
|
770
|
+
try {
|
|
771
|
+
branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD 2>/dev/null', {
|
|
772
|
+
encoding: 'utf8',
|
|
773
|
+
cwd: process.cwd(),
|
|
774
|
+
}).trim();
|
|
775
|
+
}
|
|
776
|
+
catch {
|
|
777
|
+
// Default to main if we can't detect
|
|
778
|
+
}
|
|
779
|
+
// Normalize URL: convert SSH URLs to HTTPS format for cloning
|
|
780
|
+
// git@github.com:user/repo.git -> github.com/user/repo
|
|
781
|
+
let normalizedUrl = remoteUrl;
|
|
782
|
+
if (remoteUrl.startsWith('git@')) {
|
|
783
|
+
normalizedUrl = remoteUrl.replace('git@', '').replace(':', '/');
|
|
784
|
+
}
|
|
785
|
+
if (normalizedUrl.startsWith('https://')) {
|
|
786
|
+
normalizedUrl = normalizedUrl.replace('https://', '');
|
|
787
|
+
}
|
|
788
|
+
if (normalizedUrl.endsWith('.git')) {
|
|
789
|
+
normalizedUrl = normalizedUrl.slice(0, -4);
|
|
790
|
+
}
|
|
791
|
+
return { url: normalizedUrl, branch };
|
|
792
|
+
}
|
|
793
|
+
catch {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
751
797
|
/**
|
|
752
798
|
* Create a cloud genbox
|
|
753
799
|
*/
|
|
@@ -759,9 +805,117 @@ async function createCloudGenbox(name, options = {}) {
|
|
|
759
805
|
console.log(chalk_1.default.dim(' Run: gb login\n'));
|
|
760
806
|
return { success: false, error: 'Not logged in' };
|
|
761
807
|
}
|
|
762
|
-
//
|
|
808
|
+
// Determine workspace and repos from config or current directory
|
|
809
|
+
let workspace = 'default';
|
|
810
|
+
let repos = {};
|
|
811
|
+
// Initialize provider payload early (needed for template selection)
|
|
763
812
|
const providerPayload = {};
|
|
764
813
|
const provider = options.provider || 'claude';
|
|
814
|
+
// Try to load genbox.yaml for configuration
|
|
815
|
+
const configLoader = new config_loader_1.ConfigLoader();
|
|
816
|
+
const loadResult = await configLoader.load();
|
|
817
|
+
if (loadResult.config) {
|
|
818
|
+
// Use config from genbox.yaml
|
|
819
|
+
const config = loadResult.config;
|
|
820
|
+
workspace = (config.project?.name || 'default').toLowerCase();
|
|
821
|
+
// Build repos from config
|
|
822
|
+
if (config.repos) {
|
|
823
|
+
for (const [repoName, repoConfig] of Object.entries(config.repos)) {
|
|
824
|
+
repos[repoName] = {
|
|
825
|
+
url: repoConfig.url.replace('https://', ''),
|
|
826
|
+
path: repoConfig.path || `/home/dev/${repoName}`,
|
|
827
|
+
branch: repoConfig.branch || 'main',
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
console.log(chalk_1.default.dim(` Using configuration from genbox.yaml`));
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
// No genbox.yaml - try to detect current git repo
|
|
835
|
+
const gitRepo = detectGitRepo();
|
|
836
|
+
if (gitRepo) {
|
|
837
|
+
// Use current directory as the repo
|
|
838
|
+
workspace = path.basename(process.cwd()).toLowerCase();
|
|
839
|
+
const repoName = workspace;
|
|
840
|
+
repos[repoName] = {
|
|
841
|
+
url: gitRepo.url,
|
|
842
|
+
path: `/home/dev/${repoName}`,
|
|
843
|
+
branch: gitRepo.branch,
|
|
844
|
+
};
|
|
845
|
+
console.log(chalk_1.default.dim(` Detected git repo: ${gitRepo.url} (branch: ${gitRepo.branch})`));
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
// No config and no git repo - prompt for template selection
|
|
849
|
+
console.log(chalk_1.default.yellow('\n No genbox.yaml or git repository found.'));
|
|
850
|
+
console.log(chalk_1.default.dim(' Would you like to create from a starter template?'));
|
|
851
|
+
console.log('');
|
|
852
|
+
// Fetch available templates
|
|
853
|
+
let templates = [];
|
|
854
|
+
try {
|
|
855
|
+
templates = await (0, api_1.fetchApi)('/genboxes/starter-templates');
|
|
856
|
+
}
|
|
857
|
+
catch (error) {
|
|
858
|
+
console.log(chalk_1.default.red('Failed to fetch templates:', error.message));
|
|
859
|
+
return { success: false, error: 'Failed to fetch templates' };
|
|
860
|
+
}
|
|
861
|
+
if (templates.length === 0) {
|
|
862
|
+
console.log(chalk_1.default.red('No templates available.'));
|
|
863
|
+
return { success: false, error: 'No templates available' };
|
|
864
|
+
}
|
|
865
|
+
// Show template selection
|
|
866
|
+
const templateChoices = templates.map(t => ({
|
|
867
|
+
name: `${t.icon} ${t.displayName} - ${chalk_1.default.dim(t.description)}`,
|
|
868
|
+
value: t.name,
|
|
869
|
+
}));
|
|
870
|
+
templateChoices.push({
|
|
871
|
+
name: chalk_1.default.dim('Cancel'),
|
|
872
|
+
value: '__cancel__',
|
|
873
|
+
});
|
|
874
|
+
let selectedTemplateName;
|
|
875
|
+
try {
|
|
876
|
+
selectedTemplateName = await (0, select_1.default)({
|
|
877
|
+
message: 'Select a starter template:',
|
|
878
|
+
choices: templateChoices,
|
|
879
|
+
pageSize: 15,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
catch {
|
|
883
|
+
return { success: false, error: 'Cancelled' };
|
|
884
|
+
}
|
|
885
|
+
if (selectedTemplateName === '__cancel__') {
|
|
886
|
+
return { success: false, error: 'Cancelled' };
|
|
887
|
+
}
|
|
888
|
+
const selectedTemplate = templates.find(t => t.name === selectedTemplateName);
|
|
889
|
+
if (!selectedTemplate) {
|
|
890
|
+
return { success: false, error: 'Template not found' };
|
|
891
|
+
}
|
|
892
|
+
// Set workspace to project name (lowercased)
|
|
893
|
+
workspace = name.toLowerCase();
|
|
894
|
+
// Set up template-based creation
|
|
895
|
+
if (selectedTemplate.createCommand) {
|
|
896
|
+
// Template uses create command (e.g., create-next-app)
|
|
897
|
+
providerPayload.template = selectedTemplate.name;
|
|
898
|
+
providerPayload.templateCreateCommand = selectedTemplate.createCommand.replace(/\{\{name\}\}/g, name);
|
|
899
|
+
if (selectedTemplate.setupCommands) {
|
|
900
|
+
providerPayload.templateSetupCommands = selectedTemplate.setupCommands.map(cmd => cmd.replace(/\{\{name\}\}/g, name));
|
|
901
|
+
}
|
|
902
|
+
console.log(chalk_1.default.dim(` Using template: ${selectedTemplate.displayName}`));
|
|
903
|
+
}
|
|
904
|
+
else if (selectedTemplate.repoUrl) {
|
|
905
|
+
// Template uses repo cloning
|
|
906
|
+
repos['main'] = {
|
|
907
|
+
url: selectedTemplate.repoUrl,
|
|
908
|
+
path: `/home/dev/${name}`,
|
|
909
|
+
branch: selectedTemplate.branch || 'main',
|
|
910
|
+
};
|
|
911
|
+
if (selectedTemplate.setupCommands) {
|
|
912
|
+
providerPayload.templateSetupCommands = selectedTemplate.setupCommands.map(cmd => cmd.replace(/\{\{name\}\}/g, name));
|
|
913
|
+
}
|
|
914
|
+
console.log(chalk_1.default.dim(` Using template: ${selectedTemplate.displayName}`));
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
// Set provider-specific options
|
|
765
919
|
if (provider === 'claude') {
|
|
766
920
|
providerPayload.installClaudeCode = true;
|
|
767
921
|
}
|
|
@@ -786,16 +940,22 @@ async function createCloudGenbox(name, options = {}) {
|
|
|
786
940
|
// Codex doesn't need special installation - it's part of OpenAI CLI
|
|
787
941
|
providerPayload.installClaudeCode = true; // Still install Claude as fallback
|
|
788
942
|
}
|
|
943
|
+
// Get git config for commits
|
|
944
|
+
const gitConfig = (0, utils_1.getGitConfig)();
|
|
789
945
|
console.log(chalk_1.default.dim(`\nCreating genbox ${name}...`));
|
|
790
946
|
try {
|
|
791
|
-
// Create genbox
|
|
947
|
+
// Create genbox with repos
|
|
792
948
|
const response = await (0, api_1.fetchApi)('/genboxes', {
|
|
793
949
|
method: 'POST',
|
|
794
950
|
body: JSON.stringify({
|
|
795
951
|
name,
|
|
796
952
|
size: 'small',
|
|
797
953
|
publicKey,
|
|
798
|
-
workspace
|
|
954
|
+
workspace,
|
|
955
|
+
repos,
|
|
956
|
+
useStoredCredentials: true,
|
|
957
|
+
gitUserName: gitConfig.userName,
|
|
958
|
+
gitUserEmail: gitConfig.userEmail,
|
|
799
959
|
...providerPayload,
|
|
800
960
|
...options.payload,
|
|
801
961
|
}),
|
|
@@ -1314,7 +1474,7 @@ async function createLocalVmGenbox(name, provider = 'claude', localOptions = {})
|
|
|
1314
1474
|
const cliPackage = provider === 'gemini' ? '@google/gemini-cli' : '@anthropic-ai/claude-code';
|
|
1315
1475
|
const cliCommand = provider === 'gemini' ? 'gemini' : 'claude';
|
|
1316
1476
|
const helperName = provider === 'gemini' ? 'gem' : 'cld';
|
|
1317
|
-
const helperFlags = provider === 'gemini' ? '--
|
|
1477
|
+
const helperFlags = provider === 'gemini' ? '--yolo' : '--dangerously-skip-permissions';
|
|
1318
1478
|
// Get user's SSH public key (before progress starts)
|
|
1319
1479
|
const publicKey = getPublicSshKey();
|
|
1320
1480
|
if (!publicKey) {
|
|
@@ -2075,7 +2235,6 @@ async function createCloudGenboxFromProject(config, configLoader, options) {
|
|
|
2075
2235
|
console.log(chalk_1.default.dim('\nCancelled. Set a username first with: gb username set <name>'));
|
|
2076
2236
|
return { success: false, error: 'No username set' };
|
|
2077
2237
|
}
|
|
2078
|
-
const workspace = usernameResult.username;
|
|
2079
2238
|
console.log('');
|
|
2080
2239
|
console.log(chalk_1.default.blue('Creating genbox from project...'));
|
|
2081
2240
|
console.log(chalk_1.default.dim(`Project: ${config.project?.name || 'unknown'}`));
|
|
@@ -2113,7 +2272,8 @@ async function createCloudGenboxFromProject(config, configLoader, options) {
|
|
|
2113
2272
|
return { success: false, error: 'Cancelled' };
|
|
2114
2273
|
}
|
|
2115
2274
|
// Check name availability and add incremental suffix if needed
|
|
2116
|
-
|
|
2275
|
+
// Use username for uniqueness (names are unique per user)
|
|
2276
|
+
const uniqueResult = await ensureUniqueName(name, usernameResult.username);
|
|
2117
2277
|
if (uniqueResult.wasModified) {
|
|
2118
2278
|
console.log(chalk_1.default.yellow(` Name '${name}' is already in use, using '${uniqueResult.name}' instead`));
|
|
2119
2279
|
name = uniqueResult.name;
|
|
@@ -2217,7 +2377,6 @@ async function createCloudGenboxFromTemplate(options) {
|
|
|
2217
2377
|
console.log(chalk_1.default.dim('\nCancelled. Set a username first with: gb username set <name>'));
|
|
2218
2378
|
return { success: false, error: 'No username set' };
|
|
2219
2379
|
}
|
|
2220
|
-
const workspace = usernameResult.username;
|
|
2221
2380
|
console.log('');
|
|
2222
2381
|
console.log(chalk_1.default.blue('No genbox.yaml found - creating from template...'));
|
|
2223
2382
|
console.log('');
|
|
@@ -2265,7 +2424,8 @@ async function createCloudGenboxFromTemplate(options) {
|
|
|
2265
2424
|
return { success: false, error: 'Cancelled' };
|
|
2266
2425
|
}
|
|
2267
2426
|
// Check name availability and add incremental suffix if needed
|
|
2268
|
-
|
|
2427
|
+
// Use username for uniqueness (names are unique per user)
|
|
2428
|
+
const uniqueResult = await ensureUniqueName(name, usernameResult.username);
|
|
2269
2429
|
if (uniqueResult.wasModified) {
|
|
2270
2430
|
console.log(chalk_1.default.yellow(` Name '${name}' is already in use, using '${uniqueResult.name}' instead`));
|
|
2271
2431
|
name = uniqueResult.name;
|