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.
- package/dist/commands/create.js +369 -130
- package/dist/commands/db-sync.js +364 -0
- package/dist/commands/init.js +899 -398
- package/dist/commands/profiles.js +333 -0
- package/dist/commands/push.js +140 -47
- package/dist/config-loader.js +529 -0
- package/dist/index.js +5 -1
- package/dist/profile-resolver.js +547 -0
- package/dist/scanner/compose-parser.js +441 -0
- package/dist/scanner/config-generator.js +620 -0
- package/dist/scanner/env-analyzer.js +503 -0
- package/dist/scanner/framework-detector.js +621 -0
- package/dist/scanner/index.js +424 -0
- package/dist/scanner/runtime-detector.js +330 -0
- package/dist/scanner/structure-detector.js +412 -0
- package/dist/scanner/types.js +7 -0
- package/dist/schema-v3.js +12 -0
- package/package.json +2 -1
|
@@ -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
|
+
});
|
package/dist/commands/push.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
68
|
-
|
|
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 =
|
|
73
|
-
const
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
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
|
-
|
|
121
|
-
|
|
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
|
-
|
|
137
|
-
|
|
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 =
|
|
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 (
|
|
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.'));
|