@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
789 lines (788 loc) • 32.3 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.HealthDiagnostics = exports.HealthStatus = exports.HealthSeverity = exports.HealthCategory = void 0;
exports.createHealthDiagnostics = createHealthDiagnostics;
exports.getGlobalHealthDiagnostics = getGlobalHealthDiagnostics;
exports.setGlobalHealthDiagnostics = setGlobalHealthDiagnostics;
const events_1 = require("events");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
var HealthCategory;
(function (HealthCategory) {
HealthCategory["SYSTEM"] = "system";
HealthCategory["NETWORK"] = "network";
HealthCategory["FILESYSTEM"] = "filesystem";
HealthCategory["DEPENDENCIES"] = "dependencies";
HealthCategory["CONFIGURATION"] = "configuration";
HealthCategory["PERFORMANCE"] = "performance";
HealthCategory["SECURITY"] = "security";
HealthCategory["ENVIRONMENT"] = "environment";
})(HealthCategory || (exports.HealthCategory = HealthCategory = {}));
var HealthSeverity;
(function (HealthSeverity) {
HealthSeverity[HealthSeverity["INFO"] = 0] = "INFO";
HealthSeverity[HealthSeverity["WARNING"] = 1] = "WARNING";
HealthSeverity[HealthSeverity["ERROR"] = 2] = "ERROR";
HealthSeverity[HealthSeverity["CRITICAL"] = 3] = "CRITICAL";
})(HealthSeverity || (exports.HealthSeverity = HealthSeverity = {}));
var HealthStatus;
(function (HealthStatus) {
HealthStatus["HEALTHY"] = "healthy";
HealthStatus["DEGRADED"] = "degraded";
HealthStatus["UNHEALTHY"] = "unhealthy";
HealthStatus["UNKNOWN"] = "unknown";
})(HealthStatus || (exports.HealthStatus = HealthStatus = {}));
class HealthDiagnostics extends events_1.EventEmitter {
constructor() {
super();
this.checks = new Map();
this.running = false;
this.registerBuiltinChecks();
}
registerBuiltinChecks() {
// System checks
this.registerCheck({
id: 'system_memory',
name: 'System Memory',
category: HealthCategory.SYSTEM,
description: 'Check available system memory',
severity: HealthSeverity.WARNING,
timeout: 5000,
enabled: true,
check: async () => {
const total = os.totalmem();
const free = os.freemem();
const used = total - free;
const usagePercentage = (used / total) * 100;
let status = HealthStatus.HEALTHY;
let message = `Memory usage: ${usagePercentage.toFixed(1)}%`;
const suggestions = [];
if (usagePercentage > 90) {
status = HealthStatus.UNHEALTHY;
message = `Critical memory usage: ${usagePercentage.toFixed(1)}%`;
suggestions.push('Close unnecessary applications');
suggestions.push('Restart the system if memory usage remains high');
}
else if (usagePercentage > 80) {
status = HealthStatus.DEGRADED;
message = `High memory usage: ${usagePercentage.toFixed(1)}%`;
suggestions.push('Monitor memory usage');
suggestions.push('Consider closing some applications');
}
return {
status,
message,
details: { total, free, used, usagePercentage },
metrics: { memory_usage: usagePercentage },
suggestions,
timestamp: new Date(),
duration: 0
};
}
});
this.registerCheck({
id: 'system_disk_space',
name: 'Disk Space',
category: HealthCategory.FILESYSTEM,
description: 'Check available disk space',
severity: HealthSeverity.ERROR,
timeout: 5000,
enabled: true,
check: async () => {
try {
const stats = await fs.stat(process.cwd());
// Note: Getting actual disk space requires platform-specific implementations
// This is a simplified version
return {
status: HealthStatus.HEALTHY,
message: 'Disk space check completed',
details: { available: 'unknown' },
suggestions: ['Use platform-specific tools for accurate disk space monitoring'],
timestamp: new Date(),
duration: 0
};
}
catch (error) {
return {
status: HealthStatus.UNHEALTHY,
message: `Disk space check failed: ${error.message}`,
suggestions: ['Check file system permissions', 'Verify working directory exists'],
timestamp: new Date(),
duration: 0
};
}
}
});
this.registerCheck({
id: 'node_version',
name: 'Node.js Version',
category: HealthCategory.ENVIRONMENT,
description: 'Check Node.js version compatibility',
severity: HealthSeverity.ERROR,
timeout: 2000,
enabled: true,
check: async () => {
const nodeVersion = process.version;
const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
let status = HealthStatus.HEALTHY;
let message = `Node.js version: ${nodeVersion}`;
const suggestions = [];
if (majorVersion < 14) {
status = HealthStatus.UNHEALTHY;
message = `Unsupported Node.js version: ${nodeVersion}`;
suggestions.push('Upgrade to Node.js 14 or higher');
suggestions.push('Use a Node.js version manager like nvm');
}
else if (majorVersion < 16) {
status = HealthStatus.DEGRADED;
message = `Old Node.js version: ${nodeVersion}`;
suggestions.push('Consider upgrading to Node.js 16+ for better performance');
}
return {
status,
message,
details: { version: nodeVersion, majorVersion },
suggestions,
timestamp: new Date(),
duration: 0
};
}
});
this.registerCheck({
id: 'package_manager',
name: 'Package Manager',
category: HealthCategory.DEPENDENCIES,
description: 'Check package manager availability',
severity: HealthSeverity.WARNING,
timeout: 10000,
enabled: true,
check: async () => {
const managers = ['npm', 'yarn', 'pnpm', 'bun'];
const available = [];
const unavailable = [];
for (const manager of managers) {
try {
const { execSync } = require('child_process');
execSync(`${manager} --version`, { stdio: 'ignore' });
available.push(manager);
}
catch {
unavailable.push(manager);
}
}
let status = HealthStatus.HEALTHY;
let message = `Available package managers: ${available.join(', ')}`;
const suggestions = [];
if (available.length === 0) {
status = HealthStatus.UNHEALTHY;
message = 'No package managers found';
suggestions.push('Install npm (comes with Node.js)');
suggestions.push('Consider installing yarn or pnpm for better performance');
}
else if (available.length === 1 && available[0] === 'npm') {
status = HealthStatus.DEGRADED;
suggestions.push('Consider installing yarn or pnpm for faster package management');
}
return {
status,
message,
details: { available, unavailable },
suggestions,
timestamp: new Date(),
duration: 0
};
}
});
this.registerCheck({
id: 'git_availability',
name: 'Git Availability',
category: HealthCategory.ENVIRONMENT,
description: 'Check Git installation',
severity: HealthSeverity.WARNING,
timeout: 5000,
enabled: true,
check: async () => {
try {
const { execSync } = require('child_process');
const version = execSync('git --version', { encoding: 'utf8' }).trim();
return {
status: HealthStatus.HEALTHY,
message: `Git is available: ${version}`,
details: { version },
timestamp: new Date(),
duration: 0
};
}
catch (error) {
return {
status: HealthStatus.DEGRADED,
message: 'Git is not available',
suggestions: [
'Install Git from https://git-scm.com/',
'Add Git to your PATH environment variable'
],
timestamp: new Date(),
duration: 0
};
}
}
});
this.registerCheck({
id: 'config_files',
name: 'Configuration Files',
category: HealthCategory.CONFIGURATION,
description: 'Check Re-Shell configuration files',
severity: HealthSeverity.INFO,
timeout: 5000,
enabled: true,
check: async () => {
const configDir = path.join(os.homedir(), '.re-shell');
const configFile = path.join(configDir, 'config.yaml');
const preferencesFile = path.join(configDir, 'preferences.json');
const files = {
configDir: await fs.pathExists(configDir),
configFile: await fs.pathExists(configFile),
preferencesFile: await fs.pathExists(preferencesFile)
};
let status = HealthStatus.HEALTHY;
let message = 'Configuration files are present';
const suggestions = [];
if (!files.configDir) {
status = HealthStatus.DEGRADED;
message = 'Configuration directory not found';
suggestions.push('Run re-shell init to create configuration');
}
else if (!files.configFile && !files.preferencesFile) {
status = HealthStatus.DEGRADED;
message = 'No configuration files found';
suggestions.push('Run re-shell config to set up configuration');
}
return {
status,
message,
details: files,
suggestions,
timestamp: new Date(),
duration: 0
};
},
repair: async () => {
const configDir = path.join(os.homedir(), '.re-shell');
const actions = [];
try {
await fs.ensureDir(configDir);
actions.push(`Created configuration directory: ${configDir}`);
const defaultConfig = {
version: '1.0.0',
created: new Date().toISOString()
};
const configFile = path.join(configDir, 'config.yaml');
if (!await fs.pathExists(configFile)) {
await fs.writeFile(configFile, '# Re-Shell Configuration\nversion: 1.0.0\n');
actions.push(`Created default config file: ${configFile}`);
}
return {
success: true,
message: 'Configuration files repaired successfully',
actions,
timestamp: new Date(),
duration: 0
};
}
catch (error) {
return {
success: false,
message: `Failed to repair configuration: ${error.message}`,
actions,
timestamp: new Date(),
duration: 0
};
}
}
});
this.registerCheck({
id: 'network_connectivity',
name: 'Network Connectivity',
category: HealthCategory.NETWORK,
description: 'Check internet connectivity',
severity: HealthSeverity.WARNING,
timeout: 10000,
enabled: true,
check: async () => {
try {
const https = require('https');
return new Promise((resolve) => {
const startTime = Date.now();
const req = https.get('https://registry.npmjs.org/', (res) => {
const duration = Date.now() - startTime;
if (res.statusCode === 200) {
resolve({
status: HealthStatus.HEALTHY,
message: `Network connectivity OK (${duration}ms)`,
details: { statusCode: res.statusCode, responseTime: duration },
metrics: { response_time: duration },
timestamp: new Date(),
duration
});
}
else {
resolve({
status: HealthStatus.DEGRADED,
message: `Network issues detected (status: ${res.statusCode})`,
details: { statusCode: res.statusCode },
suggestions: ['Check internet connection', 'Verify firewall settings'],
timestamp: new Date(),
duration
});
}
});
req.on('error', (error) => {
resolve({
status: HealthStatus.UNHEALTHY,
message: `Network connectivity failed: ${error.message}`,
suggestions: [
'Check internet connection',
'Verify DNS settings',
'Check proxy configuration'
],
timestamp: new Date(),
duration: Date.now() - startTime
});
});
req.setTimeout(10000, () => {
req.destroy();
resolve({
status: HealthStatus.DEGRADED,
message: 'Network request timed out',
suggestions: ['Check internet connection speed', 'Verify network stability'],
timestamp: new Date(),
duration: Date.now() - startTime
});
});
});
}
catch (error) {
return {
status: HealthStatus.UNHEALTHY,
message: `Network check failed: ${error.message}`,
timestamp: new Date(),
duration: 0
};
}
}
});
this.registerCheck({
id: 'permissions',
name: 'File Permissions',
category: HealthCategory.FILESYSTEM,
description: 'Check file system permissions',
severity: HealthSeverity.ERROR,
timeout: 5000,
enabled: true,
check: async () => {
const testDir = path.join(os.tmpdir(), 'reshell-permission-test');
const testFile = path.join(testDir, 'test.txt');
try {
await fs.ensureDir(testDir);
await fs.writeFile(testFile, 'test');
await fs.readFile(testFile);
await fs.remove(testDir);
return {
status: HealthStatus.HEALTHY,
message: 'File system permissions are correct',
timestamp: new Date(),
duration: 0
};
}
catch (error) {
return {
status: HealthStatus.UNHEALTHY,
message: `Permission error: ${error.message}`,
suggestions: [
'Check file system permissions',
'Run with appropriate user privileges',
'Verify temp directory access'
],
timestamp: new Date(),
duration: 0
};
}
}
});
}
registerCheck(check) {
this.checks.set(check.id, check);
this.emit('check:registered', check);
}
unregisterCheck(id) {
const check = this.checks.get(id);
if (check) {
this.checks.delete(id);
this.emit('check:unregistered', check);
return true;
}
return false;
}
async runDiagnostics(options = {}) {
if (this.running) {
throw new Error('Diagnostics already running');
}
this.running = true;
const startTime = Date.now();
const reportId = this.generateReportId();
try {
this.emit('diagnostics:start', { reportId });
// Filter checks
let checksToRun = Array.from(this.checks.values())
.filter(check => check.enabled);
if (options.categories) {
checksToRun = checksToRun.filter(check => options.categories.includes(check.category));
}
// Sort by dependencies
checksToRun = this.sortChecksByDependencies(checksToRun);
// Run checks
const results = [];
const summary = {
total: checksToRun.length,
healthy: 0,
degraded: 0,
unhealthy: 0,
unknown: 0
};
for (const check of checksToRun) {
this.emit('check:start', check);
try {
const checkStartTime = Date.now();
const result = await this.runSingleCheck(check, options.timeout);
result.duration = Date.now() - checkStartTime;
// Update summary
switch (result.status) {
case HealthStatus.HEALTHY:
summary.healthy++;
break;
case HealthStatus.DEGRADED:
summary.degraded++;
break;
case HealthStatus.UNHEALTHY:
summary.unhealthy++;
break;
default:
summary.unknown++;
break;
}
const checkResult = {
check,
result
};
// Attempt repair if needed and enabled
if (options.includeRepairs &&
check.repair &&
(result.status === HealthStatus.UNHEALTHY ||
result.status === HealthStatus.DEGRADED)) {
this.emit('repair:start', check);
try {
const repairResult = await this.runRepair(check);
checkResult.repairAttempted = true;
checkResult.repairResult = repairResult;
if (repairResult.success) {
this.emit('repair:success', { check, result: repairResult });
}
else {
this.emit('repair:failure', { check, result: repairResult });
}
}
catch (repairError) {
checkResult.repairAttempted = true;
checkResult.repairResult = {
success: false,
message: `Repair failed: ${repairError.message}`,
actions: [],
timestamp: new Date(),
duration: 0
};
this.emit('repair:error', { check, error: repairError });
}
}
results.push(checkResult);
this.emit('check:complete', { check, result });
}
catch (error) {
const errorResult = {
status: HealthStatus.UNKNOWN,
message: `Check failed: ${error.message}`,
timestamp: new Date(),
duration: 0
};
results.push({ check, result: errorResult });
summary.unknown++;
this.emit('check:error', { check, error });
}
}
// Determine overall status
const overallStatus = this.calculateOverallStatus(summary);
// Generate recommendations
const recommendations = this.generateRecommendations(results);
// Create report
const report = {
id: reportId,
timestamp: new Date(),
overallStatus,
summary,
results,
systemInfo: await this.getSystemInfo(),
recommendations,
duration: Date.now() - startTime
};
this.lastReport = report;
this.emit('diagnostics:complete', report);
return report;
}
finally {
this.running = false;
}
}
async runSingleCheck(check, timeout) {
const checkTimeout = timeout || check.timeout;
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Check timed out after ${checkTimeout}ms`));
}, checkTimeout);
check.check()
.then(result => {
clearTimeout(timer);
resolve(result);
})
.catch(error => {
clearTimeout(timer);
reject(error);
});
});
}
async runRepair(check) {
if (!check.repair) {
throw new Error('No repair function available');
}
const startTime = Date.now();
const result = await check.repair();
result.duration = Date.now() - startTime;
return result;
}
sortChecksByDependencies(checks) {
const sorted = [];
const visited = new Set();
const visiting = new Set();
const visit = (check) => {
if (visiting.has(check.id)) {
throw new Error(`Circular dependency detected: ${check.id}`);
}
if (visited.has(check.id)) {
return;
}
visiting.add(check.id);
if (check.dependencies) {
for (const depId of check.dependencies) {
const depCheck = checks.find(c => c.id === depId);
if (depCheck) {
visit(depCheck);
}
}
}
visiting.delete(check.id);
visited.add(check.id);
sorted.push(check);
};
for (const check of checks) {
if (!visited.has(check.id)) {
visit(check);
}
}
return sorted;
}
calculateOverallStatus(summary) {
if (summary.unhealthy > 0) {
return HealthStatus.UNHEALTHY;
}
if (summary.degraded > 0) {
return HealthStatus.DEGRADED;
}
if (summary.unknown > 0) {
return HealthStatus.UNKNOWN;
}
return HealthStatus.HEALTHY;
}
generateRecommendations(results) {
const recommendations = [];
// High-priority recommendations
const unhealthyChecks = results.filter(r => r.result.status === HealthStatus.UNHEALTHY);
const degradedChecks = results.filter(r => r.result.status === HealthStatus.DEGRADED);
if (unhealthyChecks.length > 0) {
recommendations.push(`Address ${unhealthyChecks.length} critical issues immediately`);
}
if (degradedChecks.length > 0) {
recommendations.push(`Review ${degradedChecks.length} warnings for optimal performance`);
}
// Category-specific recommendations
const systemIssues = results.filter(r => r.check.category === HealthCategory.SYSTEM &&
r.result.status !== HealthStatus.HEALTHY);
if (systemIssues.length > 0) {
recommendations.push('System resources may need attention');
}
// Add specific suggestions from checks
for (const result of results) {
if (result.result.suggestions) {
recommendations.push(...result.result.suggestions);
}
}
return Array.from(new Set(recommendations)); // Remove duplicates
}
async getSystemInfo() {
const memory = process.memoryUsage();
const cpus = os.cpus();
return {
platform: os.platform(),
arch: os.arch(),
nodeVersion: process.version,
cliVersion: await this.getCliVersion(),
workingDirectory: process.cwd(),
homeDirectory: os.homedir(),
memory: {
total: os.totalmem(),
free: os.freemem(),
used: memory.rss
},
cpu: {
model: cpus[0]?.model || 'Unknown',
cores: cpus.length,
loadAverage: os.loadavg()
},
uptime: os.uptime()
};
}
async getCliVersion() {
try {
const packagePath = path.join(__dirname, '..', '..', 'package.json');
const pkg = await fs.readJson(packagePath);
return pkg.version || 'unknown';
}
catch {
return 'unknown';
}
}
generateReportId() {
return `health_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}
// Query methods
getChecks() {
return Array.from(this.checks.values());
}
getChecksByCategory(category) {
return Array.from(this.checks.values())
.filter(check => check.category === category);
}
getLastReport() {
return this.lastReport;
}
isRunning() {
return this.running;
}
// Configuration methods
enableCheck(id) {
const check = this.checks.get(id);
if (check) {
check.enabled = true;
this.emit('check:enabled', check);
return true;
}
return false;
}
disableCheck(id) {
const check = this.checks.get(id);
if (check) {
check.enabled = false;
this.emit('check:disabled', check);
return true;
}
return false;
}
// Quick health check
async quickCheck() {
const criticalChecks = Array.from(this.checks.values())
.filter(check => check.enabled && check.severity >= HealthSeverity.ERROR);
let unhealthyCount = 0;
let degradedCount = 0;
for (const check of criticalChecks) {
try {
const result = await this.runSingleCheck(check, 5000);
if (result.status === HealthStatus.UNHEALTHY) {
unhealthyCount++;
}
else if (result.status === HealthStatus.DEGRADED) {
degradedCount++;
}
}
catch {
unhealthyCount++;
}
}
let status = HealthStatus.HEALTHY;
let message = 'System is healthy';
if (unhealthyCount > 0) {
status = HealthStatus.UNHEALTHY;
message = `${unhealthyCount} critical issues detected`;
}
else if (degradedCount > 0) {
status = HealthStatus.DEGRADED;
message = `${degradedCount} warnings detected`;
}
return { status, message, critical: unhealthyCount };
}
}
exports.HealthDiagnostics = HealthDiagnostics;
// Global health diagnostics
let globalHealthDiagnostics = null;
function createHealthDiagnostics() {
return new HealthDiagnostics();
}
function getGlobalHealthDiagnostics() {
if (!globalHealthDiagnostics) {
globalHealthDiagnostics = new HealthDiagnostics();
}
return globalHealthDiagnostics;
}
function setGlobalHealthDiagnostics(diagnostics) {
globalHealthDiagnostics = diagnostics;
}