genbox 1.0.3 → 1.0.5

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.
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.profilesCommand = void 0;
40
+ const commander_1 = require("commander");
41
+ const prompts = __importStar(require("@inquirer/prompts"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const yaml = __importStar(require("js-yaml"));
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const config_loader_1 = require("../config-loader");
47
+ exports.profilesCommand = new commander_1.Command('profiles')
48
+ .description('List and manage profiles')
49
+ .option('--json', 'Output as JSON')
50
+ .action(async (options) => {
51
+ try {
52
+ const configLoader = new config_loader_1.ConfigLoader();
53
+ const loadResult = await configLoader.load();
54
+ if (!loadResult.config || loadResult.config.version !== '3.0') {
55
+ console.log(chalk_1.default.yellow('Profiles require genbox.yaml v3.0'));
56
+ console.log(chalk_1.default.dim('Run "genbox init" to create a v3 configuration'));
57
+ return;
58
+ }
59
+ const config = loadResult.config;
60
+ const profiles = configLoader.listProfiles(config);
61
+ if (profiles.length === 0) {
62
+ console.log(chalk_1.default.yellow('No profiles defined'));
63
+ console.log(chalk_1.default.dim('Add profiles to genbox.yaml or run "genbox init"'));
64
+ return;
65
+ }
66
+ if (options.json) {
67
+ console.log(JSON.stringify(profiles, null, 2));
68
+ return;
69
+ }
70
+ // Display profiles table
71
+ console.log('');
72
+ console.log(chalk_1.default.bold('Available Profiles:'));
73
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────────────────────'));
74
+ const maxNameLen = Math.max(...profiles.map(p => p.name.length), 12);
75
+ const maxDescLen = Math.min(Math.max(...profiles.map(p => (p.description || '').length), 30), 40);
76
+ // Header
77
+ console.log(chalk_1.default.dim(' ') +
78
+ chalk_1.default.bold('Profile'.padEnd(maxNameLen + 2)) +
79
+ chalk_1.default.bold('Description'.padEnd(maxDescLen + 2)) +
80
+ chalk_1.default.bold('Apps'.padEnd(20)) +
81
+ chalk_1.default.bold('Size'));
82
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────────────────────'));
83
+ for (const profile of profiles) {
84
+ const name = profile.name.padEnd(maxNameLen + 2);
85
+ const desc = (profile.description || '').slice(0, maxDescLen).padEnd(maxDescLen + 2);
86
+ const apps = profile.apps.slice(0, 3).join(', ') + (profile.apps.length > 3 ? '...' : '');
87
+ const appsStr = apps.padEnd(20);
88
+ const size = profile.size || '-';
89
+ const source = profile.source === 'user' ? chalk_1.default.dim(' (user)') : '';
90
+ console.log(` ${chalk_1.default.cyan(name)}${desc}${appsStr}${size}${source}`);
91
+ }
92
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────────────────────'));
93
+ console.log('');
94
+ console.log(chalk_1.default.dim('Usage: genbox create <name> --profile <profile>'));
95
+ }
96
+ catch (error) {
97
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
98
+ }
99
+ });
100
+ // Subcommand: profiles show <name>
101
+ exports.profilesCommand
102
+ .command('show <name>')
103
+ .description('Show details of a specific profile')
104
+ .action(async (name) => {
105
+ try {
106
+ const configLoader = new config_loader_1.ConfigLoader();
107
+ const loadResult = await configLoader.load();
108
+ if (!loadResult.config || loadResult.config.version !== '3.0') {
109
+ console.log(chalk_1.default.yellow('Profiles require genbox.yaml v3.0'));
110
+ return;
111
+ }
112
+ const config = loadResult.config;
113
+ const profile = configLoader.getProfile(config, name);
114
+ if (!profile) {
115
+ console.log(chalk_1.default.red(`Profile '${name}' not found`));
116
+ return;
117
+ }
118
+ console.log('');
119
+ console.log(chalk_1.default.bold(`Profile: ${name}`));
120
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
121
+ if (profile.description) {
122
+ console.log(` ${chalk_1.default.bold('Description:')} ${profile.description}`);
123
+ }
124
+ if (profile.extends) {
125
+ console.log(` ${chalk_1.default.bold('Extends:')} ${profile.extends}`);
126
+ }
127
+ console.log(` ${chalk_1.default.bold('Size:')} ${profile.size || 'default'}`);
128
+ if (profile.apps && profile.apps.length > 0) {
129
+ console.log(` ${chalk_1.default.bold('Apps:')}`);
130
+ for (const app of profile.apps) {
131
+ const appConfig = config.apps[app];
132
+ if (appConfig) {
133
+ console.log(` • ${app} (${appConfig.type}${appConfig.framework ? `, ${appConfig.framework}` : ''})`);
134
+ }
135
+ else {
136
+ console.log(` • ${app} ${chalk_1.default.yellow('(not found)')}`);
137
+ }
138
+ }
139
+ }
140
+ if (profile.connect_to) {
141
+ console.log(` ${chalk_1.default.bold('Connect to:')} ${profile.connect_to} environment`);
142
+ }
143
+ if (profile.database) {
144
+ console.log(` ${chalk_1.default.bold('Database:')}`);
145
+ console.log(` Mode: ${profile.database.mode}`);
146
+ if (profile.database.source) {
147
+ console.log(` Source: ${profile.database.source}`);
148
+ }
149
+ }
150
+ if (profile.infrastructure) {
151
+ console.log(` ${chalk_1.default.bold('Infrastructure:')}`);
152
+ for (const [name, mode] of Object.entries(profile.infrastructure)) {
153
+ console.log(` ${name}: ${mode}`);
154
+ }
155
+ }
156
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
157
+ console.log('');
158
+ console.log(chalk_1.default.dim(`Use: genbox create <name> --profile ${name}`));
159
+ }
160
+ catch (error) {
161
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
162
+ }
163
+ });
164
+ // Subcommand: profiles create
165
+ exports.profilesCommand
166
+ .command('create')
167
+ .description('Interactively create a new profile')
168
+ .action(async () => {
169
+ try {
170
+ const configLoader = new config_loader_1.ConfigLoader();
171
+ const loadResult = await configLoader.load();
172
+ if (!loadResult.config || loadResult.config.version !== '3.0') {
173
+ console.log(chalk_1.default.yellow('Profiles require genbox.yaml v3.0'));
174
+ return;
175
+ }
176
+ const config = loadResult.config;
177
+ console.log(chalk_1.default.blue('\nCreate New Profile\n'));
178
+ // Profile name
179
+ const profileName = await prompts.input({
180
+ message: 'Profile name:',
181
+ validate: (value) => {
182
+ if (!value.trim())
183
+ return 'Name is required';
184
+ if (!/^[a-z0-9-]+$/.test(value))
185
+ return 'Use lowercase letters, numbers, and hyphens';
186
+ if (config.profiles?.[value])
187
+ return 'Profile already exists';
188
+ return true;
189
+ },
190
+ });
191
+ // Description
192
+ const description = await prompts.input({
193
+ message: 'Description:',
194
+ });
195
+ // Apps selection
196
+ const appChoices = Object.entries(config.apps)
197
+ .filter(([_, app]) => app.type !== 'library')
198
+ .map(([name, app]) => ({
199
+ name: `${name} (${app.type})`,
200
+ value: name,
201
+ checked: false,
202
+ }));
203
+ const selectedApps = await prompts.checkbox({
204
+ message: 'Select apps to include:',
205
+ choices: appChoices,
206
+ });
207
+ // Size
208
+ const size = await prompts.select({
209
+ message: 'Server size:',
210
+ choices: [
211
+ { name: 'Small', value: 'small' },
212
+ { name: 'Medium', value: 'medium' },
213
+ { name: 'Large', value: 'large' },
214
+ { name: 'XL', value: 'xl' },
215
+ ],
216
+ });
217
+ // Connect to environment?
218
+ const connectTo = await prompts.select({
219
+ message: 'How should dependencies be resolved?',
220
+ choices: [
221
+ { name: 'Include locally', value: 'local' },
222
+ { name: 'Connect to staging', value: 'staging' },
223
+ { name: 'Connect to production', value: 'production' },
224
+ ],
225
+ });
226
+ // Database mode
227
+ const dbMode = await prompts.select({
228
+ message: 'Database mode:',
229
+ choices: [
230
+ { name: 'None', value: 'none' },
231
+ { name: 'Local empty', value: 'local' },
232
+ { name: 'Copy from staging', value: 'copy-staging' },
233
+ { name: 'Connect to staging', value: 'remote-staging' },
234
+ ],
235
+ });
236
+ // Build profile
237
+ const profile = {
238
+ description: description || undefined,
239
+ size: size,
240
+ apps: selectedApps,
241
+ connect_to: connectTo !== 'local' ? connectTo : undefined,
242
+ database: dbMode !== 'none' ? {
243
+ mode: dbMode.startsWith('copy') ? 'copy' : dbMode.startsWith('remote') ? 'remote' : 'local',
244
+ source: dbMode.includes('staging') ? 'staging' : dbMode.includes('production') ? 'production' : undefined,
245
+ } : undefined,
246
+ };
247
+ // Where to save?
248
+ const saveLocation = await prompts.select({
249
+ message: 'Where to save this profile?',
250
+ choices: [
251
+ { name: 'genbox.yaml (shared with team)', value: 'project' },
252
+ { name: '~/.genbox/profiles.yaml (personal)', value: 'user' },
253
+ ],
254
+ });
255
+ if (saveLocation === 'user') {
256
+ configLoader.saveUserProfile(profileName, profile);
257
+ console.log(chalk_1.default.green(`\n✔ Profile '${profileName}' saved to ~/.genbox/profiles.yaml`));
258
+ }
259
+ else {
260
+ // Add to project config
261
+ if (!config.profiles) {
262
+ config.profiles = {};
263
+ }
264
+ config.profiles[profileName] = profile;
265
+ const configPath = configLoader.getConfigPath();
266
+ const yamlContent = yaml.dump(config, { lineWidth: 120, noRefs: true });
267
+ fs.writeFileSync(configPath, yamlContent);
268
+ console.log(chalk_1.default.green(`\n✔ Profile '${profileName}' added to genbox.yaml`));
269
+ }
270
+ console.log(chalk_1.default.dim(`Use: genbox create <name> --profile ${profileName}`));
271
+ }
272
+ catch (error) {
273
+ if (error.name === 'ExitPromptError') {
274
+ console.log(chalk_1.default.dim('\nCancelled.'));
275
+ return;
276
+ }
277
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
278
+ }
279
+ });
280
+ // Subcommand: profiles delete <name>
281
+ exports.profilesCommand
282
+ .command('delete <name>')
283
+ .description('Delete a profile')
284
+ .option('--user', 'Delete from user profiles')
285
+ .action(async (name, options) => {
286
+ try {
287
+ const configLoader = new config_loader_1.ConfigLoader();
288
+ const loadResult = await configLoader.load();
289
+ if (!loadResult.config || loadResult.config.version !== '3.0') {
290
+ console.log(chalk_1.default.yellow('Profiles require genbox.yaml v3.0'));
291
+ return;
292
+ }
293
+ const config = loadResult.config;
294
+ // Check if profile exists
295
+ const inProject = config.profiles?.[name];
296
+ const userProfiles = configLoader.loadUserProfiles();
297
+ const inUser = userProfiles?.profiles?.[name];
298
+ if (!inProject && !inUser) {
299
+ console.log(chalk_1.default.red(`Profile '${name}' not found`));
300
+ return;
301
+ }
302
+ // Confirm deletion
303
+ const confirm = await prompts.confirm({
304
+ message: `Delete profile '${name}'?`,
305
+ default: false,
306
+ });
307
+ if (!confirm) {
308
+ console.log(chalk_1.default.dim('Cancelled.'));
309
+ return;
310
+ }
311
+ if (options.user && inUser) {
312
+ // Delete from user profiles
313
+ delete userProfiles.profiles[name];
314
+ const userProfilesPath = path.join(require('os').homedir(), '.genbox', 'profiles.yaml');
315
+ fs.writeFileSync(userProfilesPath, yaml.dump(userProfiles));
316
+ console.log(chalk_1.default.green(`✔ Deleted '${name}' from user profiles`));
317
+ }
318
+ else if (inProject) {
319
+ // Delete from project config
320
+ delete config.profiles[name];
321
+ const configPath = configLoader.getConfigPath();
322
+ fs.writeFileSync(configPath, yaml.dump(config, { lineWidth: 120, noRefs: true }));
323
+ console.log(chalk_1.default.green(`✔ Deleted '${name}' from genbox.yaml`));
324
+ }
325
+ }
326
+ catch (error) {
327
+ if (error.name === 'ExitPromptError') {
328
+ console.log(chalk_1.default.dim('\nCancelled.'));
329
+ return;
330
+ }
331
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
332
+ }
333
+ });
@@ -43,7 +43,7 @@ const ora_1 = __importDefault(require("ora"));
43
43
  const fs = __importStar(require("fs"));
44
44
  const path = __importStar(require("path"));
45
45
  const os = __importStar(require("os"));
46
- const config_1 = require("../config");
46
+ const config_loader_1 = require("../config-loader");
47
47
  const api_1 = require("../api");
48
48
  function getPrivateSshKey() {
49
49
  const home = os.homedir();
@@ -58,39 +58,135 @@ function getPrivateSshKey() {
58
58
  }
59
59
  return undefined;
60
60
  }
61
+ function buildLegacyPayload(config, envVars) {
62
+ return {
63
+ name: config.project_name,
64
+ displayName: config.project_name,
65
+ config: {
66
+ version: config.version,
67
+ system: config.system,
68
+ scripts: config.scripts,
69
+ hooks: config.hooks,
70
+ },
71
+ services: config.services,
72
+ repos: config.repos,
73
+ envVars: envVars,
74
+ };
75
+ }
76
+ function buildV3Payload(config, envVars) {
77
+ return {
78
+ name: config.project?.name || 'unnamed',
79
+ displayName: config.project?.name,
80
+ version: '3.0',
81
+ config: config,
82
+ envVars: envVars,
83
+ };
84
+ }
85
+ function displayV3Summary(config, envVars, payload) {
86
+ console.log(chalk_1.default.bold('Workspace Configuration (v3.0):'));
87
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
88
+ console.log(` ${chalk_1.default.bold('Name:')} ${config.project?.name}`);
89
+ console.log(` ${chalk_1.default.bold('Structure:')} ${config.project?.structure || 'unknown'}`);
90
+ // Display apps
91
+ const appNames = Object.keys(config.apps || {});
92
+ if (appNames.length > 0) {
93
+ console.log(` ${chalk_1.default.bold('Apps:')} ${appNames.length} apps`);
94
+ for (const [name, app] of Object.entries(config.apps || {})) {
95
+ const appConfig = app;
96
+ const typeInfo = appConfig.type + (appConfig.framework ? ` (${appConfig.framework})` : '');
97
+ console.log(chalk_1.default.dim(` • ${name}: ${typeInfo}`));
98
+ }
99
+ }
100
+ // Display infrastructure
101
+ const infraNames = Object.keys(config.infrastructure || {});
102
+ if (infraNames.length > 0) {
103
+ console.log(` ${chalk_1.default.bold('Infra:')} ${infraNames.join(', ')}`);
104
+ }
105
+ // Display environments
106
+ const envNames = Object.keys(config.environments || {});
107
+ if (envNames.length > 0) {
108
+ console.log(` ${chalk_1.default.bold('Envs:')} ${envNames.join(', ')}`);
109
+ }
110
+ // Display profiles
111
+ const profileNames = Object.keys(config.profiles || {});
112
+ if (profileNames.length > 0) {
113
+ console.log(` ${chalk_1.default.bold('Profiles:')} ${profileNames.length} profiles`);
114
+ for (const [name, profile] of Object.entries(config.profiles || {})) {
115
+ const desc = profile.description ? ` - ${profile.description.slice(0, 30)}` : '';
116
+ console.log(chalk_1.default.dim(` • ${name}${desc}`));
117
+ }
118
+ }
119
+ // Display env vars count
120
+ const envCount = Object.keys(envVars).length;
121
+ if (envCount > 0) {
122
+ console.log(` ${chalk_1.default.bold('Env Vars:')} ${envCount} variables`);
123
+ console.log(chalk_1.default.dim(` ${Object.keys(envVars).slice(0, 5).join(', ')}${envCount > 5 ? '...' : ''}`));
124
+ }
125
+ // Display files
126
+ if (payload.files && payload.files.length > 0) {
127
+ console.log(` ${chalk_1.default.bold('Files:')} ${payload.files.length} files`);
128
+ }
129
+ // Display SSH key
130
+ if (payload.privateKey) {
131
+ console.log(` ${chalk_1.default.bold('SSH Key:')} Included`);
132
+ }
133
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
134
+ }
135
+ function displayLegacySummary(payload) {
136
+ console.log(chalk_1.default.bold('Workspace Configuration:'));
137
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
138
+ console.log(` ${chalk_1.default.bold('Name:')} ${payload.name}`);
139
+ console.log(` ${chalk_1.default.bold('Version:')} ${payload.config.version || '1.0'}`);
140
+ if (payload.services && Object.keys(payload.services).length > 0) {
141
+ console.log(` ${chalk_1.default.bold('Services:')} ${Object.keys(payload.services).join(', ')}`);
142
+ }
143
+ if (payload.repos && Object.keys(payload.repos).length > 0) {
144
+ console.log(` ${chalk_1.default.bold('Repos:')} ${Object.keys(payload.repos).join(', ')}`);
145
+ }
146
+ const envCount = Object.keys(payload.envVars || {}).length;
147
+ if (envCount > 0) {
148
+ console.log(` ${chalk_1.default.bold('Env Vars:')} ${envCount} variables`);
149
+ console.log(chalk_1.default.dim(` ${Object.keys(payload.envVars).slice(0, 5).join(', ')}${envCount > 5 ? '...' : ''}`));
150
+ }
151
+ if (payload.files && payload.files.length > 0) {
152
+ console.log(` ${chalk_1.default.bold('Files:')} ${payload.files.length} files`);
153
+ }
154
+ if (payload.privateKey) {
155
+ console.log(` ${chalk_1.default.bold('SSH Key:')} Included`);
156
+ }
157
+ console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
158
+ }
61
159
  exports.pushCommand = new commander_1.Command('push')
62
160
  .description('Upload workspace configuration to the cloud')
63
161
  .option('--include-key', 'Include SSH private key for git cloning')
64
162
  .option('--dry-run', 'Show what would be uploaded without actually uploading')
65
163
  .action(async (options) => {
66
164
  try {
67
- // Check for config file
68
- if (!(0, config_1.hasConfig)()) {
165
+ const configLoader = new config_loader_1.ConfigLoader();
166
+ const loadResult = await configLoader.load();
167
+ if (!loadResult.found) {
69
168
  console.log(chalk_1.default.red('Error: genbox.yaml not found. Run "genbox init" first.'));
70
169
  process.exit(1);
71
170
  }
72
- const config = (0, config_1.loadConfig)();
73
- const envVars = (0, config_1.loadEnvVars)();
171
+ const config = loadResult.config;
172
+ const isV3 = config?.version === '3.0';
173
+ // Load env vars
174
+ const envVars = configLoader.loadEnvVars(process.cwd());
74
175
  console.log(chalk_1.default.blue('Preparing workspace configuration...'));
75
176
  console.log('');
76
- // Build the payload
77
- const payload = {
78
- name: config.project_name,
79
- displayName: config.project_name,
80
- config: {
81
- version: config.version,
82
- system: config.system,
83
- scripts: config.scripts,
84
- hooks: config.hooks,
85
- },
86
- services: config.services,
87
- repos: config.repos,
88
- envVars: envVars,
89
- };
90
- // Process files to upload
91
- if (config.files && config.files.length > 0) {
177
+ // Build appropriate payload based on version
178
+ let payload;
179
+ if (isV3) {
180
+ payload = buildV3Payload(config, envVars);
181
+ }
182
+ else {
183
+ payload = buildLegacyPayload(config, envVars);
184
+ }
185
+ // Process files to upload (for both versions)
186
+ const configAny = config;
187
+ if (configAny.files && configAny.files.length > 0) {
92
188
  payload.files = [];
93
- for (const f of config.files) {
189
+ for (const f of configAny.files) {
94
190
  const sourcePath = path.resolve(process.cwd(), f.source);
95
191
  if (fs.existsSync(sourcePath)) {
96
192
  const content = fs.readFileSync(sourcePath, 'utf-8');
@@ -116,37 +212,20 @@ exports.pushCommand = new commander_1.Command('push')
116
212
  console.log(chalk_1.default.yellow('Warning: No SSH private key found in ~/.ssh/'));
117
213
  }
118
214
  }
119
- // Display summary
120
- console.log(chalk_1.default.bold('Workspace Configuration:'));
121
- console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
122
- console.log(` ${chalk_1.default.bold('Name:')} ${payload.name}`);
123
- console.log(` ${chalk_1.default.bold('Version:')} ${payload.config.version || '1.0'}`);
124
- if (payload.services && Object.keys(payload.services).length > 0) {
125
- console.log(` ${chalk_1.default.bold('Services:')} ${Object.keys(payload.services).join(', ')}`);
126
- }
127
- if (payload.repos && Object.keys(payload.repos).length > 0) {
128
- console.log(` ${chalk_1.default.bold('Repos:')} ${Object.keys(payload.repos).join(', ')}`);
129
- }
130
- const envCount = Object.keys(envVars).length;
131
- if (envCount > 0) {
132
- console.log(` ${chalk_1.default.bold('Env Vars:')} ${envCount} variables`);
133
- // Show keys only (not values for security)
134
- console.log(chalk_1.default.dim(` ${Object.keys(envVars).slice(0, 5).join(', ')}${envCount > 5 ? '...' : ''}`));
215
+ // Display appropriate summary
216
+ if (isV3) {
217
+ displayV3Summary(config, envVars, payload);
135
218
  }
136
- if (payload.files && payload.files.length > 0) {
137
- console.log(` ${chalk_1.default.bold('Files:')} ${payload.files.length} files`);
219
+ else {
220
+ displayLegacySummary(payload);
138
221
  }
139
- if (payload.privateKey) {
140
- console.log(` ${chalk_1.default.bold('SSH Key:')} Included`);
141
- }
142
- console.log(chalk_1.default.dim('───────────────────────────────────────────────'));
143
222
  console.log('');
144
223
  // Dry run mode
145
224
  if (options.dryRun) {
146
225
  console.log(chalk_1.default.yellow('Dry run mode - no changes uploaded'));
147
226
  console.log('');
148
227
  console.log(chalk_1.default.dim('Payload preview (env values redacted):'));
149
- const previewPayload = { ...payload };
228
+ const previewPayload = JSON.parse(JSON.stringify(payload));
150
229
  if (previewPayload.envVars) {
151
230
  previewPayload.envVars = Object.fromEntries(Object.keys(previewPayload.envVars).map(k => [k, '***']));
152
231
  }
@@ -167,7 +246,21 @@ exports.pushCommand = new commander_1.Command('push')
167
246
  console.log('');
168
247
  console.log(chalk_1.default.dim('Your configuration is now available in the cloud.'));
169
248
  console.log(chalk_1.default.dim('Team members can run "genbox create <name>" to provision environments.'));
170
- if (!(0, config_1.hasEnvFile)()) {
249
+ if (isV3) {
250
+ const v3Config = config;
251
+ const profileNames = Object.keys(v3Config.profiles || {});
252
+ if (profileNames.length > 0) {
253
+ console.log('');
254
+ console.log(chalk_1.default.dim('Available profiles:'));
255
+ for (const name of profileNames.slice(0, 5)) {
256
+ console.log(chalk_1.default.dim(` genbox create <name> --profile ${name}`));
257
+ }
258
+ if (profileNames.length > 5) {
259
+ console.log(chalk_1.default.dim(` ... and ${profileNames.length - 5} more`));
260
+ }
261
+ }
262
+ }
263
+ if (Object.keys(envVars).length === 0) {
171
264
  console.log('');
172
265
  console.log(chalk_1.default.yellow('Note: No .env.genbox file found.'));
173
266
  console.log(chalk_1.default.dim('Create one with sensitive environment variables that will be'));
@@ -177,7 +270,7 @@ exports.pushCommand = new commander_1.Command('push')
177
270
  catch (error) {
178
271
  spinner.fail(chalk_1.default.red('Failed to upload workspace configuration'));
179
272
  console.error(chalk_1.default.red(`Error: ${error.message}`));
180
- if (error.message.includes('401') || error.message.includes('Unauthorized')) {
273
+ if (error instanceof api_1.AuthenticationError || error.message.includes('401') || error.message.includes('Unauthorized')) {
181
274
  console.log('');
182
275
  console.log(chalk_1.default.yellow('You need to be logged in to push workspace configuration.'));
183
276
  console.log(chalk_1.default.dim('Run "genbox login" to authenticate.'));