genbox 1.0.105 → 1.0.107
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/list.js +19 -7
- package/dist/commands/status.js +27 -59
- package/package.json +1 -1
package/dist/commands/list.js
CHANGED
|
@@ -49,6 +49,12 @@ exports.listCommand = new commander_1.Command('list')
|
|
|
49
49
|
}
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
+
// Sort by createdAt (newest first)
|
|
53
|
+
genboxes.sort((a, b) => {
|
|
54
|
+
const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
55
|
+
const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
56
|
+
return dateB - dateA;
|
|
57
|
+
});
|
|
52
58
|
// Calculate column widths
|
|
53
59
|
const nameWidth = Math.max(12, ...genboxes.map(g => g.name.length + (options.all && g.project ? g.project.length + 3 : 0)));
|
|
54
60
|
const statusWidth = 12;
|
|
@@ -60,25 +66,31 @@ exports.listCommand = new commander_1.Command('list')
|
|
|
60
66
|
// Show project info when listing all
|
|
61
67
|
const projectSuffix = options.all && genbox.project ? ` [${genbox.project}]` : '';
|
|
62
68
|
const nameWithProject = genbox.name + projectSuffix;
|
|
63
|
-
// Format end hour as relative time
|
|
69
|
+
// Format end hour as relative time (destroy happens at 58 min mark, not 60)
|
|
64
70
|
let endHourInfo = '';
|
|
65
71
|
if (genbox.currentHourEnd && genbox.status === 'running') {
|
|
66
72
|
const endTime = new Date(genbox.currentHourEnd);
|
|
67
73
|
const now = new Date();
|
|
68
|
-
|
|
74
|
+
// Subtract 2 minutes since auto-destroy happens at 58 min mark
|
|
75
|
+
const destroyTime = endTime.getTime() - (2 * 60 * 1000);
|
|
76
|
+
const diffMs = destroyTime - now.getTime();
|
|
69
77
|
if (diffMs > 0) {
|
|
70
78
|
const totalSeconds = Math.floor(diffMs / 1000);
|
|
71
79
|
const mins = Math.floor(totalSeconds / 60);
|
|
72
80
|
const secs = totalSeconds % 60;
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
const timeStr = mins > 0
|
|
82
|
+
? `${mins}m:${secs.toString().padStart(2, '0')}s`
|
|
83
|
+
: `${secs}s`;
|
|
84
|
+
// Red color if less than 5 minutes
|
|
85
|
+
if (mins < 5) {
|
|
86
|
+
endHourInfo = chalk_1.default.red(` hour ends in ${timeStr}`);
|
|
75
87
|
}
|
|
76
88
|
else {
|
|
77
|
-
endHourInfo = ` hour ends in ${
|
|
89
|
+
endHourInfo = chalk_1.default.dim(` hour ends in ${timeStr}`);
|
|
78
90
|
}
|
|
79
91
|
}
|
|
80
92
|
else {
|
|
81
|
-
endHourInfo = ' hour
|
|
93
|
+
endHourInfo = chalk_1.default.red(' hour ending...');
|
|
82
94
|
}
|
|
83
95
|
}
|
|
84
96
|
// Show auto-destroy status
|
|
@@ -105,7 +117,7 @@ exports.listCommand = new commander_1.Command('list')
|
|
|
105
117
|
const statusPart = statusColor(genbox.status.padEnd(statusWidth));
|
|
106
118
|
const ipPart = chalk_1.default.dim((genbox.ipAddress || 'Pending IP').padEnd(ipWidth));
|
|
107
119
|
const sizePart = `(${genbox.size})`.padEnd(sizeWidth);
|
|
108
|
-
const extraInfo =
|
|
120
|
+
const extraInfo = endHourInfo + protectedInfo;
|
|
109
121
|
console.log(`${namePart} ${statusPart} ${ipPart} ${sizePart}${extraInfo}`);
|
|
110
122
|
});
|
|
111
123
|
console.log(chalk_1.default.dim('────────────────────────────────────────────────────'));
|
package/dist/commands/status.js
CHANGED
|
@@ -398,80 +398,48 @@ exports.statusCommand = new commander_1.Command('status')
|
|
|
398
398
|
console.log(chalk_1.default.dim(` (updated ${statsAge < 60 ? 'just now' : Math.floor(statsAge / 60) + 'm ago'})`));
|
|
399
399
|
console.log('');
|
|
400
400
|
}
|
|
401
|
-
// Show Docker containers status
|
|
402
|
-
const
|
|
403
|
-
const hasDockerServices =
|
|
401
|
+
// Show Docker containers status from DB (updated by heartbeat)
|
|
402
|
+
const dockerServices = systemStats?.dockerServices || [];
|
|
403
|
+
const hasDockerServices = dockerServices.length > 0;
|
|
404
404
|
if (hasDockerServices) {
|
|
405
405
|
console.log(chalk_1.default.blue('[INFO] === Docker Services ==='));
|
|
406
|
-
console.log('
|
|
407
|
-
|
|
406
|
+
console.log('NAME\t\t\tSTATUS');
|
|
407
|
+
for (const svc of dockerServices) {
|
|
408
|
+
const healthBadge = svc.health
|
|
409
|
+
? (svc.health === 'healthy' ? chalk_1.default.green(' ✓') : chalk_1.default.red(` (${svc.health})`))
|
|
410
|
+
: '';
|
|
411
|
+
console.log(`${svc.name}\t${svc.status}${healthBadge}`);
|
|
412
|
+
}
|
|
408
413
|
console.log('');
|
|
409
414
|
}
|
|
410
|
-
// Show PM2 processes
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
const hasPm2Apps = pm2Status && pm2Status.trim() &&
|
|
414
|
-
!pm2Status.includes('No process') &&
|
|
415
|
-
(pm2Status.includes('online') || pm2Status.includes('stopped') ||
|
|
416
|
-
pm2Status.includes('errored') || pm2Status.includes('launching'));
|
|
415
|
+
// Show PM2 processes from DB (updated by heartbeat)
|
|
416
|
+
const pm2Services = systemStats?.pm2Services || [];
|
|
417
|
+
const hasPm2Apps = pm2Services.length > 0;
|
|
417
418
|
if (hasPm2Apps) {
|
|
418
419
|
console.log(chalk_1.default.blue('[INFO] === PM2 Services ==='));
|
|
419
|
-
console.log(
|
|
420
|
+
console.log('NAME\t\tSTATUS\t\tCPU\tMEM');
|
|
421
|
+
for (const app of pm2Services) {
|
|
422
|
+
const statusColor = app.status === 'online' ? chalk_1.default.green :
|
|
423
|
+
app.status === 'stopped' ? chalk_1.default.yellow : chalk_1.default.red;
|
|
424
|
+
console.log(`${app.name}\t\t${statusColor(app.status)}\t\t${app.cpu || 0}%\t${app.memory || 0}MB`);
|
|
425
|
+
}
|
|
420
426
|
console.log('');
|
|
421
427
|
}
|
|
422
|
-
// Warn if no services are running and
|
|
428
|
+
// Warn if no services are running and show setup errors from DB (no SSH needed)
|
|
423
429
|
if (!hasDockerServices && !hasPm2Apps) {
|
|
424
430
|
console.log(chalk_1.default.yellow('[WARN] No Docker or PM2 services are running!'));
|
|
425
|
-
//
|
|
426
|
-
const
|
|
427
|
-
if (
|
|
428
|
-
// Found
|
|
431
|
+
// Check for setup errors stored in DB (sent by setup callback)
|
|
432
|
+
const setupErrors = target.setupErrors;
|
|
433
|
+
if (setupErrors && setupErrors.trim()) {
|
|
434
|
+
// Found errors from setup - display them
|
|
429
435
|
console.log(chalk_1.default.red('[ERROR] Build failed during setup:'));
|
|
430
|
-
console.log(
|
|
436
|
+
console.log(setupErrors);
|
|
431
437
|
console.log('');
|
|
432
438
|
console.log(chalk_1.default.dim(' Fix the error and run: cd ~/goodpass/api && docker compose up -d'));
|
|
433
439
|
}
|
|
434
440
|
else {
|
|
435
|
-
// No
|
|
436
|
-
console.log(chalk_1.default.dim('
|
|
437
|
-
console.log('');
|
|
438
|
-
const buildResult = sshExec(target.ipAddress, keyPath, 'cd ~/goodpass/api 2>/dev/null && docker compose build 2>&1 | tail -60 || echo "No compose file found"', 120);
|
|
439
|
-
if (buildResult && buildResult.trim()) {
|
|
440
|
-
// Check for common error patterns
|
|
441
|
-
if (buildResult.includes('ERROR') || buildResult.includes('TS2') ||
|
|
442
|
-
buildResult.includes('failed') || buildResult.includes('ELIFECYCLE') ||
|
|
443
|
-
buildResult.includes('exit code') || buildResult.includes('did not complete successfully')) {
|
|
444
|
-
console.log(chalk_1.default.red('[ERROR] Docker build failed:'));
|
|
445
|
-
// Extract just the error portion
|
|
446
|
-
const lines = buildResult.split('\n');
|
|
447
|
-
const errorLines = lines.filter(line => line.includes('ERROR') || line.includes('TS2') || line.includes('TS1') ||
|
|
448
|
-
line.includes('failed') || line.includes('exit code') ||
|
|
449
|
-
line.includes('>') || line.includes('^') ||
|
|
450
|
-
line.match(/^\s*\d+\s*\|/) // Source code lines with line numbers
|
|
451
|
-
).slice(-20);
|
|
452
|
-
if (errorLines.length > 0) {
|
|
453
|
-
console.log(errorLines.join('\n'));
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
// Show last 25 lines if no specific error pattern found
|
|
457
|
-
console.log(lines.slice(-25).join('\n'));
|
|
458
|
-
}
|
|
459
|
-
console.log('');
|
|
460
|
-
console.log(chalk_1.default.dim(' Fix the error and run: cd ~/goodpass/api && docker compose up -d'));
|
|
461
|
-
}
|
|
462
|
-
else if (buildResult.includes('Built') || buildResult.includes('FINISHED')) {
|
|
463
|
-
// Build succeeded, services just need to start
|
|
464
|
-
console.log(chalk_1.default.dim(' Build OK. Start services with: cd ~/goodpass/api && docker compose up -d'));
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
467
|
-
console.log(chalk_1.default.dim(buildResult));
|
|
468
|
-
console.log('');
|
|
469
|
-
console.log(chalk_1.default.dim(' Try: cd ~/goodpass/api && docker compose up -d'));
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
console.log(chalk_1.default.dim(' Try: cd ~/goodpass/api && docker compose up -d'));
|
|
474
|
-
}
|
|
441
|
+
// No errors in DB - services might just need to be started
|
|
442
|
+
console.log(chalk_1.default.dim(' Try: cd ~/goodpass/api && docker compose up -d'));
|
|
475
443
|
}
|
|
476
444
|
console.log('');
|
|
477
445
|
}
|