genbox 1.0.131 → 1.0.133

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/README.md CHANGED
@@ -193,8 +193,7 @@ Environments auto-destroy after 58 minutes of inactivity to save credits.
193
193
 
194
194
  - **Website**: [genbox.dev](https://genbox.dev)
195
195
  - **Documentation**: [genbox.dev/docs](https://genbox.dev/docs)
196
- - **GitHub**: [github.com/goodpass-co/genbox](https://github.com/goodpass-co/genbox)
197
- - **Issues**: [github.com/goodpass-co/genbox/issues](https://github.com/goodpass-co/genbox/issues)
196
+ - **Support**: [genbox.dev/support](https://genbox.dev/support)
198
197
 
199
198
  ## License
200
199
 
@@ -9,9 +9,17 @@ const chalk_1 = __importDefault(require("chalk"));
9
9
  const api_1 = require("../api");
10
10
  exports.balanceCommand = new commander_1.Command('balance')
11
11
  .description('Show current credit balance')
12
- .action(async () => {
12
+ .option('--json', 'Output as JSON (for scripting)')
13
+ .action(async (options) => {
13
14
  try {
14
15
  const user = await (0, api_1.fetchApi)('/users/me');
16
+ if (options.json) {
17
+ console.log(JSON.stringify({
18
+ userId: user.externalId,
19
+ credits: user.credits,
20
+ }, null, 2));
21
+ return;
22
+ }
15
23
  console.log(chalk_1.default.bold('User ID:'), user.externalId);
16
24
  console.log(chalk_1.default.bold('Credits:'), chalk_1.default.green(user.credits));
17
25
  }
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.completionCommand = void 0;
39
+ exports.completeCommand = exports.completionCommand = void 0;
40
40
  exports.isCompletionInstalledForCurrentShell = isCompletionInstalledForCurrentShell;
41
41
  exports.getCompletionHint = getCompletionHint;
42
42
  const commander_1 = require("commander");
@@ -44,6 +44,59 @@ const chalk_1 = __importDefault(require("chalk"));
44
44
  const os = __importStar(require("os"));
45
45
  const path = __importStar(require("path"));
46
46
  const fs = __importStar(require("fs"));
47
+ const api_1 = require("../api");
48
+ const genbox_selector_1 = require("../genbox-selector");
49
+ // Cache file for genbox names (for fast completion)
50
+ const CACHE_FILE = path.join(os.homedir(), '.genbox', 'completion-cache.json');
51
+ const CACHE_TTL = 60 * 1000; // 1 minute cache
52
+ /**
53
+ * Get cached genbox names or fetch fresh ones
54
+ */
55
+ async function getCachedGenboxNames() {
56
+ const project = (0, genbox_selector_1.getProjectContext)() || undefined;
57
+ // Try to read from cache first
58
+ try {
59
+ if (fs.existsSync(CACHE_FILE)) {
60
+ const cache = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
61
+ const age = Date.now() - cache.timestamp;
62
+ // Use cache if fresh and same project context
63
+ if (age < CACHE_TTL && cache.project === project) {
64
+ return cache.genboxNames;
65
+ }
66
+ }
67
+ }
68
+ catch {
69
+ // Cache read failed, continue to fetch
70
+ }
71
+ // Fetch fresh data
72
+ try {
73
+ const genboxes = await (0, api_1.fetchApi)('/genboxes');
74
+ const names = genboxes
75
+ .filter(g => g.status !== 'terminated')
76
+ .map(g => g.name);
77
+ // Save to cache
78
+ try {
79
+ const cacheDir = path.dirname(CACHE_FILE);
80
+ if (!fs.existsSync(cacheDir)) {
81
+ fs.mkdirSync(cacheDir, { recursive: true });
82
+ }
83
+ const cache = {
84
+ genboxNames: names,
85
+ timestamp: Date.now(),
86
+ project,
87
+ };
88
+ fs.writeFileSync(CACHE_FILE, JSON.stringify(cache));
89
+ }
90
+ catch {
91
+ // Cache write failed, ignore
92
+ }
93
+ return names;
94
+ }
95
+ catch {
96
+ // API call failed, return empty
97
+ return [];
98
+ }
99
+ }
47
100
  // Get all command names for completion
48
101
  const commands = [
49
102
  'init', 'create', 'list', 'ls', 'destroy', 'delete', 'connect', 'balance',
@@ -141,6 +194,11 @@ function generateBashCompletion() {
141
194
  # Or save to a file:
142
195
  # gb completion bash > /etc/bash_completion.d/gb
143
196
 
197
+ # Get genbox names dynamically
198
+ _genbox_names() {
199
+ gb __complete genbox-names 2>/dev/null
200
+ }
201
+
144
202
  _genbox_completions() {
145
203
  local cur prev commands
146
204
  COMPREPLY=()
@@ -186,9 +244,10 @@ _genbox_completions() {
186
244
  COMPREPLY=( $(compgen -W "bash zsh fish --install" -- "\${cur}") )
187
245
  return 0
188
246
  ;;
189
- # Commands that take genbox names - could be enhanced with dynamic completion
190
- create|destroy|delete|connect|status|urls|forward|push|restart|stop|start|resume|extend|rebuild|run|run-prompt)
191
- # For now, no completion for genbox names (would need API call)
247
+ # Commands that take genbox names - dynamic completion
248
+ destroy|delete|connect|status|urls|forward|push|restart|stop|start|resume|extend|rebuild|run|run-prompt|backup|restore-db)
249
+ local genbox_names=$(_genbox_names)
250
+ COMPREPLY=( $(compgen -W "\${genbox_names}" -- "\${cur}") )
192
251
  return 0
193
252
  ;;
194
253
  -s|--size)
@@ -264,6 +323,13 @@ function generateZshCompletion() {
264
323
  # Or save to a file in your fpath:
265
324
  # gb completion zsh > ~/.zsh/completions/_gb
266
325
 
326
+ # Get genbox names dynamically
327
+ _genbox_names() {
328
+ local -a names
329
+ names=(\${(f)"$(gb __complete genbox-names 2>/dev/null)"})
330
+ _describe -t genboxes 'genbox name' names
331
+ }
332
+
267
333
  _genbox() {
268
334
  local -a commands
269
335
  commands=(
@@ -386,29 +452,29 @@ _genbox() {
386
452
  '(-y --yes)'{-y,--yes}'[Skip confirmation]' \\
387
453
  '(-a --all)'{-a,--all}'[Bulk delete mode]' \\
388
454
  '--save-changes[Handle changes]:action:(save trash skip)' \\
389
- '1:name:'
455
+ '1:name:_genbox_names'
390
456
  ;;
391
457
  status)
392
458
  _arguments \\
393
459
  '(-a --all)'{-a,--all}'[Select from all]' \\
394
460
  '(-w --watch)'{-w,--watch}'[Watch mode]' \\
395
- '1:name:'
461
+ '1:name:_genbox_names'
396
462
  ;;
397
463
  connect|urls|restart|stop)
398
464
  _arguments \\
399
465
  '(-a --all)'{-a,--all}'[Select from all]' \\
400
- '1:name:'
466
+ '1:name:_genbox_names'
401
467
  ;;
402
468
  start|resume)
403
469
  _arguments \\
404
470
  '(-a --all)'{-a,--all}'[Select from all]' \\
405
- '1:name:'
471
+ '1:name:_genbox_names'
406
472
  ;;
407
473
  forward)
408
474
  _arguments \\
409
475
  '(-a --all)'{-a,--all}'[Select from all]' \\
410
476
  '(-p --ports)'{-p,--ports}'[Additional ports]:ports:' \\
411
- '1:name:'
477
+ '1:name:_genbox_names'
412
478
  ;;
413
479
  extend)
414
480
  _arguments \\
@@ -416,13 +482,13 @@ _genbox() {
416
482
  '--hours[Hours to extend]:hours:' \\
417
483
  '--disable-auto-destroy[Disable auto-destroy]' \\
418
484
  '--enable-auto-destroy[Enable auto-destroy]' \\
419
- '1:name:'
485
+ '1:name:_genbox_names'
420
486
  ;;
421
487
  rebuild)
422
488
  _arguments \\
423
489
  '(-a --all)'{-a,--all}'[Select from all]' \\
424
490
  '(-y --yes)'{-y,--yes}'[Skip confirmation]' \\
425
- '1:name:'
491
+ '1:name:_genbox_names'
426
492
  ;;
427
493
  help)
428
494
  _values 'command' init create status connect forward restore-db urls push destroy
@@ -446,6 +512,11 @@ function generateFishCompletion() {
446
512
  complete -c genbox -f
447
513
  complete -c gb -f
448
514
 
515
+ # Function to get genbox names dynamically
516
+ function __fish_genbox_names
517
+ gb __complete genbox-names 2>/dev/null
518
+ end
519
+
449
520
  # Main commands
450
521
  complete -c genbox -c gb -n "__fish_use_subcommand" -a "init" -d "Initialize genbox.yaml configuration"
451
522
  complete -c genbox -c gb -n "__fish_use_subcommand" -a "create" -d "Create a new Genbox environment"
@@ -533,6 +604,9 @@ complete -c genbox -c gb -n "__fish_seen_subcommand_from extend" -l hours -d "Ho
533
604
  complete -c genbox -c gb -n "__fish_seen_subcommand_from extend" -l disable-auto-destroy -d "Disable auto-destroy"
534
605
  complete -c genbox -c gb -n "__fish_seen_subcommand_from extend" -l enable-auto-destroy -d "Enable auto-destroy"
535
606
 
607
+ # Dynamic genbox name completion for commands that take a genbox name
608
+ complete -c genbox -c gb -n "__fish_seen_subcommand_from destroy delete connect status urls forward push restart stop start resume extend rebuild backup restore-db run run-prompt" -a "(__fish_genbox_names)" -d "Genbox name"
609
+
536
610
  # Global options
537
611
  complete -c genbox -c gb -s h -l help -d "Show help"
538
612
  complete -c genbox -c gb -s v -l version -d "Show version"
@@ -633,3 +707,27 @@ function getCompletionHint() {
633
707
  return `${chalk_1.default.dim('Enable tab completion for a better experience:')}
634
708
  ${chalk_1.default.cyan(`gb completion ${shellName} --install`)}`;
635
709
  }
710
+ /**
711
+ * Hidden __complete command for dynamic completion support
712
+ * Used by shell completion scripts to get genbox names
713
+ */
714
+ exports.completeCommand = new commander_1.Command('__complete')
715
+ .description('Internal command for shell completions')
716
+ .argument('<type>', 'Completion type: genbox-names')
717
+ .action(async (type) => {
718
+ switch (type) {
719
+ case 'genbox-names':
720
+ try {
721
+ const names = await getCachedGenboxNames();
722
+ // Output names, one per line (for shell parsing)
723
+ names.forEach(name => console.log(name));
724
+ }
725
+ catch {
726
+ // Silently fail - don't break completion
727
+ }
728
+ break;
729
+ default:
730
+ // Unknown type, output nothing
731
+ break;
732
+ }
733
+ });
@@ -323,6 +323,7 @@ exports.destroyCommand = new commander_1.Command('destroy')
323
323
  .option('-y, --yes', 'Skip confirmation and save-work prompts')
324
324
  .option('-a, --all', 'Bulk delete mode - select multiple genboxes to destroy')
325
325
  .option('--save-changes <action>', 'Handle uncommitted changes: save (commit/push/PR), trash (discard), skip (ignore)')
326
+ .addHelpText('after', '\nAliases: gb delete')
326
327
  .action(async (name, options) => {
327
328
  try {
328
329
  // Bulk delete mode when --all is used without a specific name
@@ -0,0 +1,357 @@
1
+ "use strict";
2
+ /**
3
+ * Doctor Command
4
+ *
5
+ * Diagnoses CLI setup and reports any issues.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.doctorCommand = void 0;
45
+ const commander_1 = require("commander");
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ const os = __importStar(require("os"));
50
+ const child_process_1 = require("child_process");
51
+ const config_store_1 = require("../config-store");
52
+ const api_1 = require("../api");
53
+ async function runChecks() {
54
+ const results = [];
55
+ // 1. Check Node.js version
56
+ const nodeVersion = process.version;
57
+ const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0], 10);
58
+ if (majorVersion >= 18) {
59
+ results.push({
60
+ name: 'Node.js',
61
+ status: 'ok',
62
+ message: `${nodeVersion} installed`,
63
+ });
64
+ }
65
+ else {
66
+ results.push({
67
+ name: 'Node.js',
68
+ status: 'error',
69
+ message: `${nodeVersion} is too old`,
70
+ hint: 'Genbox CLI requires Node.js 18 or higher',
71
+ });
72
+ }
73
+ // 2. Check authentication
74
+ const config = config_store_1.ConfigStore.load();
75
+ if (config.auth?.token) {
76
+ const user = config.auth.user;
77
+ if (user?.email) {
78
+ results.push({
79
+ name: 'Authentication',
80
+ status: 'ok',
81
+ message: `Logged in as ${user.email}`,
82
+ });
83
+ }
84
+ else {
85
+ results.push({
86
+ name: 'Authentication',
87
+ status: 'ok',
88
+ message: 'Authenticated',
89
+ });
90
+ }
91
+ // 3. Check API connectivity (only if authenticated)
92
+ try {
93
+ await (0, api_1.fetchApi)('/user/profile');
94
+ results.push({
95
+ name: 'API Connection',
96
+ status: 'ok',
97
+ message: 'Connected to API',
98
+ });
99
+ }
100
+ catch (error) {
101
+ if (error.message?.includes('401') || error.message?.includes('Unauthorized')) {
102
+ results.push({
103
+ name: 'API Connection',
104
+ status: 'error',
105
+ message: 'Token expired or invalid',
106
+ hint: 'Run `gb login` to re-authenticate',
107
+ });
108
+ }
109
+ else {
110
+ results.push({
111
+ name: 'API Connection',
112
+ status: 'warning',
113
+ message: `Could not reach API: ${error.message}`,
114
+ hint: 'Check your internet connection',
115
+ });
116
+ }
117
+ }
118
+ }
119
+ else {
120
+ results.push({
121
+ name: 'Authentication',
122
+ status: 'warning',
123
+ message: 'Not logged in',
124
+ hint: 'Run `gb login` to authenticate',
125
+ });
126
+ }
127
+ // 4. Check SSH configuration
128
+ const sshConfigPath = path.join(os.homedir(), '.ssh', 'config');
129
+ if (fs.existsSync(sshConfigPath)) {
130
+ try {
131
+ const sshConfig = fs.readFileSync(sshConfigPath, 'utf8');
132
+ const hasGenboxHosts = sshConfig.includes('# Genbox') || sshConfig.includes('genbox.dev');
133
+ if (hasGenboxHosts) {
134
+ results.push({
135
+ name: 'SSH Config',
136
+ status: 'ok',
137
+ message: 'Genbox hosts configured',
138
+ });
139
+ }
140
+ else {
141
+ results.push({
142
+ name: 'SSH Config',
143
+ status: 'ok',
144
+ message: 'SSH config exists (no genbox hosts yet)',
145
+ });
146
+ }
147
+ }
148
+ catch {
149
+ results.push({
150
+ name: 'SSH Config',
151
+ status: 'warning',
152
+ message: 'Could not read SSH config',
153
+ hint: 'Check permissions on ~/.ssh/config',
154
+ });
155
+ }
156
+ }
157
+ else {
158
+ results.push({
159
+ name: 'SSH Config',
160
+ status: 'warning',
161
+ message: 'No SSH config file',
162
+ hint: 'SSH config will be created when you create a genbox',
163
+ });
164
+ }
165
+ // 5. Check SSH key
166
+ const sshKeyPath = path.join(os.homedir(), '.ssh', 'id_ed25519');
167
+ const sshKeyPathRsa = path.join(os.homedir(), '.ssh', 'id_rsa');
168
+ if (fs.existsSync(sshKeyPath)) {
169
+ results.push({
170
+ name: 'SSH Key',
171
+ status: 'ok',
172
+ message: 'Ed25519 key found',
173
+ });
174
+ }
175
+ else if (fs.existsSync(sshKeyPathRsa)) {
176
+ results.push({
177
+ name: 'SSH Key',
178
+ status: 'ok',
179
+ message: 'RSA key found',
180
+ });
181
+ }
182
+ else {
183
+ results.push({
184
+ name: 'SSH Key',
185
+ status: 'warning',
186
+ message: 'No SSH key found',
187
+ hint: 'Run `ssh-keygen -t ed25519` to create one',
188
+ });
189
+ }
190
+ // 6. Check genbox.yaml in current directory
191
+ const genboxYamlPath = path.join(process.cwd(), 'genbox.yaml');
192
+ if (fs.existsSync(genboxYamlPath)) {
193
+ try {
194
+ const yaml = require('js-yaml');
195
+ const content = fs.readFileSync(genboxYamlPath, 'utf8');
196
+ const config = yaml.load(content);
197
+ if (config.version && config.project_name) {
198
+ results.push({
199
+ name: 'Project Config',
200
+ status: 'ok',
201
+ message: `genbox.yaml found (v${config.version}, project: ${config.project_name})`,
202
+ });
203
+ }
204
+ else {
205
+ results.push({
206
+ name: 'Project Config',
207
+ status: 'warning',
208
+ message: 'genbox.yaml missing required fields',
209
+ hint: 'Ensure version and project_name are set',
210
+ });
211
+ }
212
+ }
213
+ catch (error) {
214
+ results.push({
215
+ name: 'Project Config',
216
+ status: 'error',
217
+ message: 'Invalid genbox.yaml',
218
+ hint: error.message,
219
+ });
220
+ }
221
+ }
222
+ else {
223
+ results.push({
224
+ name: 'Project Config',
225
+ status: 'ok',
226
+ message: 'No genbox.yaml in current directory',
227
+ });
228
+ }
229
+ // 7. Check .env.genbox
230
+ const envGenboxPath = path.join(process.cwd(), '.env.genbox');
231
+ if (fs.existsSync(genboxYamlPath)) {
232
+ if (fs.existsSync(envGenboxPath)) {
233
+ results.push({
234
+ name: 'Environment',
235
+ status: 'ok',
236
+ message: '.env.genbox found',
237
+ });
238
+ }
239
+ else {
240
+ results.push({
241
+ name: 'Environment',
242
+ status: 'warning',
243
+ message: 'No .env.genbox file',
244
+ hint: 'Create .env.genbox for secrets (GITHUB_PAT, etc.)',
245
+ });
246
+ }
247
+ }
248
+ // 8. Check git
249
+ try {
250
+ (0, child_process_1.execSync)('git --version', { stdio: 'pipe' });
251
+ results.push({
252
+ name: 'Git',
253
+ status: 'ok',
254
+ message: 'Git installed',
255
+ });
256
+ }
257
+ catch {
258
+ results.push({
259
+ name: 'Git',
260
+ status: 'warning',
261
+ message: 'Git not found',
262
+ hint: 'Git is recommended for version control',
263
+ });
264
+ }
265
+ // 9. Check shell completion
266
+ const shell = process.env.SHELL || '';
267
+ let completionInstalled = false;
268
+ const home = os.homedir();
269
+ if (shell.includes('zsh')) {
270
+ const zshrc = path.join(home, '.zshrc');
271
+ if (fs.existsSync(zshrc)) {
272
+ const content = fs.readFileSync(zshrc, 'utf8');
273
+ completionInstalled = content.includes('gb completion');
274
+ }
275
+ }
276
+ else if (shell.includes('bash')) {
277
+ const bashrc = path.join(home, '.bashrc');
278
+ const bashProfile = path.join(home, '.bash_profile');
279
+ for (const file of [bashrc, bashProfile]) {
280
+ if (fs.existsSync(file)) {
281
+ const content = fs.readFileSync(file, 'utf8');
282
+ if (content.includes('gb completion')) {
283
+ completionInstalled = true;
284
+ break;
285
+ }
286
+ }
287
+ }
288
+ }
289
+ else if (shell.includes('fish')) {
290
+ const fishCompletion = path.join(home, '.config', 'fish', 'completions', 'gb.fish');
291
+ completionInstalled = fs.existsSync(fishCompletion);
292
+ }
293
+ if (completionInstalled) {
294
+ results.push({
295
+ name: 'Shell Completion',
296
+ status: 'ok',
297
+ message: 'Tab completion installed',
298
+ });
299
+ }
300
+ else {
301
+ const shellName = shell.includes('zsh') ? 'zsh' : shell.includes('fish') ? 'fish' : 'bash';
302
+ results.push({
303
+ name: 'Shell Completion',
304
+ status: 'ok',
305
+ message: 'Tab completion not installed (optional)',
306
+ hint: `Run \`gb completion ${shellName} --install\` to enable`,
307
+ });
308
+ }
309
+ return results;
310
+ }
311
+ exports.doctorCommand = new commander_1.Command('doctor')
312
+ .description('Check CLI configuration and diagnose issues')
313
+ .action(async () => {
314
+ console.log('');
315
+ console.log(chalk_1.default.bold('Genbox CLI Diagnostics'));
316
+ console.log('');
317
+ const results = await runChecks();
318
+ // Display results
319
+ let hasErrors = false;
320
+ let hasWarnings = false;
321
+ for (const result of results) {
322
+ let statusIcon;
323
+ let statusColor;
324
+ switch (result.status) {
325
+ case 'ok':
326
+ statusIcon = chalk_1.default.green('✓');
327
+ statusColor = chalk_1.default;
328
+ break;
329
+ case 'warning':
330
+ statusIcon = chalk_1.default.yellow('⚠');
331
+ statusColor = chalk_1.default.yellow;
332
+ hasWarnings = true;
333
+ break;
334
+ case 'error':
335
+ statusIcon = chalk_1.default.red('✗');
336
+ statusColor = chalk_1.default.red;
337
+ hasErrors = true;
338
+ break;
339
+ }
340
+ console.log(`${statusIcon} ${chalk_1.default.bold(result.name)}: ${statusColor(result.message)}`);
341
+ if (result.hint) {
342
+ console.log(` ${chalk_1.default.dim(result.hint)}`);
343
+ }
344
+ }
345
+ // Summary
346
+ console.log('');
347
+ if (hasErrors) {
348
+ console.log(chalk_1.default.red('Some issues need to be fixed before using Genbox CLI.'));
349
+ }
350
+ else if (hasWarnings) {
351
+ console.log(chalk_1.default.yellow('Some optional improvements are available.'));
352
+ }
353
+ else {
354
+ console.log(chalk_1.default.green('Everything looks good!'));
355
+ }
356
+ console.log('');
357
+ });