@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
843 lines (842 loc) ⢠32.7 kB
JavaScript
"use strict";
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.CrashReporter = exports.CrashSeverity = exports.CrashType = void 0;
exports.createCrashReporter = createCrashReporter;
exports.getGlobalCrashReporter = getGlobalCrashReporter;
exports.setGlobalCrashReporter = setGlobalCrashReporter;
const events_1 = require("events");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
var CrashType;
(function (CrashType) {
CrashType["UNCAUGHT_EXCEPTION"] = "uncaught_exception";
CrashType["UNHANDLED_REJECTION"] = "unhandled_rejection";
CrashType["ASSERTION_ERROR"] = "assertion_error";
CrashType["MEMORY_ERROR"] = "memory_error";
CrashType["TIMEOUT_ERROR"] = "timeout_error";
CrashType["FILE_SYSTEM_ERROR"] = "file_system_error";
CrashType["NETWORK_ERROR"] = "network_error";
CrashType["DEPENDENCY_ERROR"] = "dependency_error";
CrashType["CONFIGURATION_ERROR"] = "configuration_error";
CrashType["PERMISSION_ERROR"] = "permission_error";
CrashType["OPERATION_FAILURE"] = "operation_failure";
CrashType["PLUGIN_ERROR"] = "plugin_error";
CrashType["BUILD_ERROR"] = "build_error";
CrashType["CUSTOM"] = "custom";
})(CrashType || (exports.CrashType = CrashType = {}));
var CrashSeverity;
(function (CrashSeverity) {
CrashSeverity["LOW"] = "low";
CrashSeverity["MEDIUM"] = "medium";
CrashSeverity["HIGH"] = "high";
CrashSeverity["CRITICAL"] = "critical";
})(CrashSeverity || (exports.CrashSeverity = CrashSeverity = {}));
class CrashReporter extends events_1.EventEmitter {
constructor(workspaceRoot, options = {}) {
super();
this.workspaceRoot = workspaceRoot;
this.options = options;
this.issuePatterns = new Map();
this.recentLogs = [];
this.recentErrors = [];
this.hookInstalled = false;
this.defaultOptions = {
enableRemoteReporting: false,
enableLocalStorage: true,
maxReportsStored: 100,
enableAutoRecovery: true,
enableUserNotification: true,
anonymizeData: true,
reportingLevel: CrashSeverity.MEDIUM,
retryAttempts: 3
};
this.sessionId = this.generateSessionId();
this.startTime = new Date();
this.crashReportsPath = path.join(workspaceRoot, '.re-shell', 'crash-reports');
this.options = { ...this.defaultOptions, ...options };
this.ensureReportsDirectory();
this.loadKnownIssuePatterns();
this.installGlobalHooks();
}
ensureReportsDirectory() {
try {
fs.ensureDirSync(this.crashReportsPath);
}
catch (error) {
console.warn('Failed to create crash reports directory:', error);
}
}
loadKnownIssuePatterns() {
// Memory issues
this.registerIssuePattern({
id: 'memory_heap_out_of_memory',
name: 'Memory Heap Exceeded',
description: 'JavaScript heap out of memory error',
pattern: /JavaScript heap out of memory/i,
severity: CrashSeverity.HIGH,
category: 'Memory',
knownCauses: [
'Large file processing',
'Memory leaks in plugins',
'Insufficient Node.js heap size',
'Processing too many files simultaneously'
],
suggestedFixes: [
'Increase Node.js heap size with --max-old-space-size',
'Process files in smaller batches',
'Check for memory leaks in custom plugins',
'Use streaming for large file operations'
],
documentationLink: 'https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes'
});
// Permission issues
this.registerIssuePattern({
id: 'permission_denied_eacces',
name: 'Permission Denied',
description: 'File system permission error',
pattern: /EACCES|permission denied/i,
severity: CrashSeverity.MEDIUM,
category: 'Permissions',
knownCauses: [
'Insufficient file system permissions',
'Files owned by different user',
'Read-only file system',
'Protected system directories'
],
suggestedFixes: [
'Run with appropriate user permissions',
'Change file ownership: sudo chown -R $USER:$USER .',
'Check directory permissions',
'Use sudo if accessing system directories'
]
});
// Network issues
this.registerIssuePattern({
id: 'network_connection_refused',
name: 'Network Connection Refused',
description: 'Unable to connect to remote service',
pattern: /ECONNREFUSED|connection refused/i,
severity: CrashSeverity.MEDIUM,
category: 'Network',
knownCauses: [
'Service is not running',
'Incorrect port or URL',
'Firewall blocking connection',
'Network connectivity issues'
],
suggestedFixes: [
'Verify service is running and accessible',
'Check network connectivity',
'Verify firewall settings',
'Check proxy configuration'
]
});
// Dependency issues
this.registerIssuePattern({
id: 'module_not_found',
name: 'Module Not Found',
description: 'Required module cannot be found',
pattern: /Cannot find module|Module not found/i,
severity: CrashSeverity.HIGH,
category: 'Dependencies',
knownCauses: [
'Missing dependencies',
'Corrupted node_modules',
'Version incompatibility',
'Path resolution issues'
],
suggestedFixes: [
'Run npm install or yarn install',
'Delete node_modules and reinstall',
'Check package.json for correct dependencies',
'Clear package manager cache'
],
autoRecovery: async () => {
try {
const { execSync } = require('child_process');
execSync('npm install', { stdio: 'inherit' });
return true;
}
catch {
return false;
}
}
});
// Configuration issues
this.registerIssuePattern({
id: 'invalid_configuration',
name: 'Invalid Configuration',
description: 'Configuration file is invalid or corrupted',
pattern: (error, context) => {
return error.message.includes('configuration') &&
(error.message.includes('invalid') || error.message.includes('parse'));
},
severity: CrashSeverity.MEDIUM,
category: 'Configuration',
knownCauses: [
'Syntax error in config file',
'Invalid configuration values',
'Missing required configuration',
'Corrupted configuration file'
],
suggestedFixes: [
'Validate configuration syntax',
'Reset to default configuration',
'Check for required fields',
'Restore from backup'
]
});
// File system issues
this.registerIssuePattern({
id: 'file_system_full',
name: 'File System Full',
description: 'No space left on device',
pattern: /ENOSPC|no space left on device/i,
severity: CrashSeverity.CRITICAL,
category: 'FileSystem',
knownCauses: [
'Disk space exhausted',
'Inode exhaustion',
'Temporary files accumulation',
'Large log files'
],
suggestedFixes: [
'Free up disk space',
'Clean temporary files',
'Remove old log files',
'Move files to different location'
]
});
// Plugin issues
this.registerIssuePattern({
id: 'plugin_error',
name: 'Plugin Error',
description: 'Error in plugin execution',
pattern: (error, context) => {
return context.pluginsLoaded.length > 0 &&
(error.stack?.includes('plugin') || error.message.includes('plugin'));
},
severity: CrashSeverity.MEDIUM,
category: 'Plugins',
knownCauses: [
'Plugin compatibility issues',
'Plugin dependency conflicts',
'Malformed plugin code',
'Plugin API misuse'
],
suggestedFixes: [
'Update plugins to latest versions',
'Disable problematic plugins',
'Check plugin compatibility',
'Report issue to plugin author'
]
});
}
installGlobalHooks() {
if (this.hookInstalled)
return;
// Uncaught exceptions
process.on('uncaughtException', (error) => {
this.reportCrash(CrashType.UNCAUGHT_EXCEPTION, error, CrashSeverity.CRITICAL);
});
// Unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
const error = reason instanceof Error ? reason : new Error(String(reason));
this.reportCrash(CrashType.UNHANDLED_REJECTION, error, CrashSeverity.HIGH);
});
// Exit events
process.on('exit', () => {
this.handleGracefulShutdown();
});
process.on('SIGINT', () => {
this.handleGracefulShutdown();
process.exit(0);
});
process.on('SIGTERM', () => {
this.handleGracefulShutdown();
process.exit(0);
});
this.hookInstalled = true;
}
registerIssuePattern(pattern) {
this.issuePatterns.set(pattern.id, pattern);
this.emit('pattern:registered', pattern);
}
async reportCrash(type, error, severity = CrashSeverity.MEDIUM, context) {
const reportId = this.generateReportId();
try {
const crashReport = {
id: reportId,
timestamp: new Date(),
type,
severity,
error: {
name: error.name,
message: error.message,
stack: error.stack,
code: error.code,
signal: error.signal
},
context: await this.gatherContext(context),
systemInfo: await this.gatherSystemInfo(),
diagnostics: await this.gatherDiagnostics(),
fingerprint: this.generateFingerprint(error),
recovered: false,
reportedToRemote: false
};
// Store locally if enabled
if (this.options.enableLocalStorage) {
await this.storeReportLocally(crashReport);
}
// Analyze the crash
const analysis = await this.analyzeCrash(crashReport);
// Attempt auto-recovery if enabled
if (this.options.enableAutoRecovery && analysis.recoverable) {
const recovered = await this.attemptAutoRecovery(analysis);
crashReport.recovered = recovered;
if (recovered) {
this.emit('crash:recovered', { report: crashReport, analysis });
}
}
// Send to remote if enabled and severity is high enough
if (this.options.enableRemoteReporting &&
this.shouldReportRemotely(severity)) {
await this.sendToRemote(crashReport);
}
// Notify user if enabled
if (this.options.enableUserNotification) {
this.notifyUser(crashReport, analysis);
}
this.emit('crash:reported', { report: crashReport, analysis });
return reportId;
}
catch (reportingError) {
console.error('Failed to report crash:', reportingError);
this.emit('crash:reporting_failed', { error: reportingError, originalError: error });
return reportId;
}
}
async gatherContext(partial) {
const memoryUsage = process.memoryUsage();
const uptime = Date.now() - this.startTime.getTime();
// Filter environment variables for privacy
const env = this.options.anonymizeData
? this.anonymizeEnvironment(process.env)
: { ...process.env };
return {
command: process.argv[2] || 'unknown',
args: process.argv.slice(3),
workingDirectory: process.cwd(),
sessionId: this.sessionId,
uptime,
memoryUsage,
environmentVariables: env,
recentLogs: [...this.recentLogs],
activeOperations: [], // TODO: Get from operation manager
pluginsLoaded: [], // TODO: Get from plugin manager
configurationState: {}, // TODO: Get from config manager
...partial
};
}
async gatherSystemInfo() {
const cpus = os.cpus();
return {
platform: os.platform(),
arch: os.arch(),
nodeVersion: process.version,
cliVersion: await this.getCliVersion(),
homeDirectory: this.options.anonymizeData ? '<anonymized>' : os.homedir(),
totalMemory: os.totalmem(),
freeMemory: os.freemem(),
cpuModel: cpus[0]?.model || 'Unknown',
cpuCores: cpus.length,
loadAverage: os.loadavg(),
uptime: os.uptime(),
diskSpace: await this.getDiskSpace()
};
}
async gatherDiagnostics() {
return {
healthChecks: [], // TODO: Get from health diagnostics
networkConnectivity: await this.testNetworkConnectivity(),
fileSystemPermissions: await this.testFileSystemPermissions(),
dependencyVersions: await this.getDependencyVersions(),
configurationValid: await this.validateConfiguration(),
recentErrors: [...this.recentErrors],
performanceMetrics: {
averageResponseTime: 0, // TODO: Calculate from metrics
memoryTrend: 'stable', // TODO: Analyze memory usage trend
cpuUsage: 0 // TODO: Get current CPU usage
}
};
}
async analyzeCrash(report) {
const matchedPatterns = [];
// Match against known patterns
for (const pattern of this.issuePatterns.values()) {
let matches = false;
let confidence = 0;
if (pattern.pattern instanceof RegExp) {
if (pattern.pattern.test(report.error.message) ||
(report.error.stack && pattern.pattern.test(report.error.stack))) {
matches = true;
confidence = 0.8;
}
}
else if (typeof pattern.pattern === 'function') {
matches = pattern.pattern(new Error(report.error.message), report.context);
confidence = matches ? 0.7 : 0;
}
if (matches) {
matchedPatterns.push({
pattern,
confidence,
extractedData: this.extractPatternData(pattern, report)
});
}
}
// Sort by confidence
matchedPatterns.sort((a, b) => b.confidence - a.confidence);
// Determine root cause and recommendations
const bestMatch = matchedPatterns[0];
const rootCause = bestMatch ? bestMatch.pattern.description : 'Unknown error';
const recommendations = [];
const quickFixes = [];
if (bestMatch) {
recommendations.push(...bestMatch.pattern.suggestedFixes);
if (bestMatch.pattern.autoRecovery) {
quickFixes.push({
description: `Auto-fix for ${bestMatch.pattern.name}`,
action: bestMatch.pattern.autoRecovery,
safe: true
});
}
}
// Find similar issues
const similarIssues = await this.findSimilarIssues(report);
return {
reportId: report.id,
matchedPatterns,
rootCause,
recommendations,
quickFixes,
similarIssues,
severity: bestMatch ? bestMatch.pattern.severity : report.severity,
recoverable: quickFixes.length > 0 || this.isRecoverableError(report)
};
}
extractPatternData(pattern, report) {
// Extract relevant data based on pattern type
switch (pattern.category) {
case 'Memory':
return {
memoryUsage: report.context.memoryUsage,
totalMemory: report.systemInfo.totalMemory,
freeMemory: report.systemInfo.freeMemory
};
case 'Dependencies':
return {
dependencies: report.diagnostics.dependencyVersions,
nodeVersion: report.systemInfo.nodeVersion
};
default:
return null;
}
}
async attemptAutoRecovery(analysis) {
for (const quickFix of analysis.quickFixes) {
if (quickFix.safe) {
try {
this.emit('recovery:attempt', quickFix);
const success = await quickFix.action();
if (success) {
this.emit('recovery:success', quickFix);
return true;
}
}
catch (error) {
this.emit('recovery:failed', { quickFix, error });
}
}
}
return false;
}
isRecoverableError(report) {
// Check if error type is generally recoverable
const recoverableTypes = [
CrashType.NETWORK_ERROR,
CrashType.DEPENDENCY_ERROR,
CrashType.CONFIGURATION_ERROR,
CrashType.TIMEOUT_ERROR
];
return recoverableTypes.includes(report.type);
}
async findSimilarIssues(report) {
try {
const reportFiles = await fs.readdir(this.crashReportsPath);
const similarReports = [];
for (const file of reportFiles.slice(0, 50)) { // Limit search
if (file.endsWith('.json') && !file.includes(report.id)) {
try {
const otherReport = await fs.readJson(path.join(this.crashReportsPath, file));
if (this.isSimilarError(report, otherReport)) {
similarReports.push(otherReport.id);
}
}
catch {
// Skip corrupted reports
}
}
}
return similarReports.slice(0, 5); // Return top 5 similar issues
}
catch {
return [];
}
}
isSimilarError(report1, report2) {
// Check if fingerprints match (exact same error)
if (report1.fingerprint === report2.fingerprint) {
return true;
}
// Check if error names and types match
if (report1.error.name === report2.error.name && report1.type === report2.type) {
return true;
}
// Check if error messages are similar (basic similarity)
const similarity = this.calculateStringSimilarity(report1.error.message, report2.error.message);
return similarity > 0.7;
}
calculateStringSimilarity(str1, str2) {
const words1 = str1.toLowerCase().split(/\s+/);
const words2 = str2.toLowerCase().split(/\s+/);
const commonWords = words1.filter(word => words2.includes(word));
const totalWords = new Set([...words1, ...words2]).size;
return commonWords.length / totalWords;
}
async storeReportLocally(report) {
try {
const reportPath = path.join(this.crashReportsPath, `${report.id}.json`);
await fs.writeJson(reportPath, report, { spaces: 2 });
// Cleanup old reports if limit exceeded
await this.cleanupOldReports();
}
catch (error) {
console.warn('Failed to store crash report locally:', error);
}
}
async cleanupOldReports() {
try {
const reportFiles = await fs.readdir(this.crashReportsPath);
const jsonFiles = reportFiles.filter(f => f.endsWith('.json'));
if (jsonFiles.length > this.options.maxReportsStored) {
// Sort by modification time and remove oldest
const fileStats = await Promise.all(jsonFiles.map(async (file) => ({
file,
stats: await fs.stat(path.join(this.crashReportsPath, file))
})));
fileStats.sort((a, b) => a.stats.mtime.getTime() - b.stats.mtime.getTime());
const toDelete = fileStats.slice(0, jsonFiles.length - this.options.maxReportsStored);
for (const { file } of toDelete) {
await fs.unlink(path.join(this.crashReportsPath, file));
}
}
}
catch (error) {
console.warn('Failed to cleanup old crash reports:', error);
}
}
shouldReportRemotely(severity) {
const severityOrder = [CrashSeverity.LOW, CrashSeverity.MEDIUM, CrashSeverity.HIGH, CrashSeverity.CRITICAL];
const currentIndex = severityOrder.indexOf(severity);
const thresholdIndex = severityOrder.indexOf(this.options.reportingLevel);
return currentIndex >= thresholdIndex;
}
async sendToRemote(report) {
if (!this.options.remoteEndpoint)
return;
try {
const anonymizedReport = this.options.anonymizeData ? this.anonymizeReport(report) : report;
const response = await fetch(this.options.remoteEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(this.options.apiKey && { 'Authorization': `Bearer ${this.options.apiKey}` })
},
body: JSON.stringify(anonymizedReport)
});
if (response.ok) {
report.reportedToRemote = true;
this.emit('crash:reported_remote', report);
}
else {
throw new Error(`Remote reporting failed: ${response.status}`);
}
}
catch (error) {
this.emit('crash:remote_failed', { report, error });
}
}
anonymizeReport(report) {
const anonymized = { ...report };
// Anonymize paths
anonymized.context.workingDirectory = this.anonymizePath(report.context.workingDirectory);
anonymized.systemInfo.homeDirectory = '<anonymized>';
// Remove potentially sensitive environment variables
anonymized.context.environmentVariables = this.anonymizeEnvironment(report.context.environmentVariables);
// Anonymize error stack traces
if (anonymized.error.stack) {
anonymized.error.stack = this.anonymizeStackTrace(anonymized.error.stack);
}
return anonymized;
}
anonymizePath(filePath) {
const homeDir = os.homedir();
return filePath.replace(homeDir, '~').replace(/\/Users\/[^\/]+/, '/Users/<user>');
}
anonymizeEnvironment(env) {
const sensitiveKeys = ['PATH', 'HOME', 'USER', 'USERNAME', 'USERPROFILE'];
const result = {};
for (const [key, value] of Object.entries(env)) {
if (sensitiveKeys.some(k => key.includes(k))) {
result[key] = '<anonymized>';
}
else if (key.startsWith('RE_SHELL_')) {
result[key] = value; // Keep Re-Shell specific vars
}
}
return result;
}
anonymizeStackTrace(stack) {
const homeDir = os.homedir();
return stack
.replace(new RegExp(homeDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '~')
.replace(/\/Users\/[^\/]+/g, '/Users/<user>');
}
notifyUser(report, analysis) {
console.error(`\nš„ Re-Shell CLI Crash Detected (${report.id})`);
console.error(`Type: ${report.type}`);
console.error(`Severity: ${report.severity}`);
console.error(`Error: ${report.error.message}\n`);
if (analysis.rootCause) {
console.error(`Root Cause: ${analysis.rootCause}\n`);
}
if (analysis.recommendations.length > 0) {
console.error('Suggested Fixes:');
analysis.recommendations.slice(0, 3).forEach((rec, i) => {
console.error(` ${i + 1}. ${rec}`);
});
console.error('');
}
if (report.recovered) {
console.error('ā
Auto-recovery was successful');
}
else if (analysis.quickFixes.length > 0) {
console.error('š§ Auto-recovery options are available');
}
console.error(`š Full report saved: ${report.id}`);
console.error('');
}
handleGracefulShutdown() {
// Perform final cleanup and reporting
this.emit('shutdown');
}
// Utility methods
generateReportId() {
return `crash_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}
generateSessionId() {
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}
generateFingerprint(error) {
const crypto = require('crypto');
const data = `${error.name}:${error.message}:${error.stack?.split('\n')[0] || ''}`;
return crypto.createHash('sha256').update(data).digest('hex').substr(0, 16);
}
async getCliVersion() {
try {
const packagePath = path.join(__dirname, '..', '..', 'package.json');
const pkg = await fs.readJson(packagePath);
return pkg.version || 'unknown';
}
catch {
return 'unknown';
}
}
async getDiskSpace() {
try {
const stats = await fs.stat(this.workspaceRoot);
return {
total: 0, // TODO: Implement platform-specific disk space check
free: 0,
used: 0
};
}
catch {
return undefined;
}
}
async testNetworkConnectivity() {
try {
const https = require('https');
return new Promise((resolve) => {
const req = https.get('https://registry.npmjs.org/', (res) => {
resolve(res.statusCode === 200);
});
req.on('error', () => resolve(false));
req.setTimeout(5000, () => {
req.destroy();
resolve(false);
});
});
}
catch {
return false;
}
}
async testFileSystemPermissions() {
try {
const testFile = path.join(os.tmpdir(), 're-shell-permission-test');
await fs.writeFile(testFile, 'test');
await fs.readFile(testFile);
await fs.unlink(testFile);
return true;
}
catch {
return false;
}
}
async getDependencyVersions() {
try {
const packagePath = path.join(this.workspaceRoot, 'package.json');
if (await fs.pathExists(packagePath)) {
const pkg = await fs.readJson(packagePath);
return {
...pkg.dependencies,
...pkg.devDependencies
};
}
}
catch {
// Ignore errors
}
return {};
}
async validateConfiguration() {
try {
const configPath = path.join(this.workspaceRoot, '.re-shell', 'config.yaml');
return await fs.pathExists(configPath);
}
catch {
return false;
}
}
// Public methods for logging and error tracking
addLogEntry(message) {
this.recentLogs.push(`${new Date().toISOString()}: ${message}`);
// Keep only recent logs
if (this.recentLogs.length > 100) {
this.recentLogs = this.recentLogs.slice(-50);
}
}
recordError(error, context) {
this.recentErrors.push({
timestamp: new Date(),
error,
context
});
// Keep only recent errors
if (this.recentErrors.length > 50) {
this.recentErrors = this.recentErrors.slice(-25);
}
}
// Query methods
async getReports(limit = 10) {
try {
const reportFiles = await fs.readdir(this.crashReportsPath);
const jsonFiles = reportFiles.filter(f => f.endsWith('.json'));
const reports = [];
for (const file of jsonFiles.slice(0, limit)) {
try {
const report = await fs.readJson(path.join(this.crashReportsPath, file));
reports.push(report);
}
catch {
// Skip corrupted reports
}
}
return reports.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
}
catch {
return [];
}
}
async getReport(id) {
try {
const reportPath = path.join(this.crashReportsPath, `${id}.json`);
if (await fs.pathExists(reportPath)) {
return await fs.readJson(reportPath);
}
}
catch {
// Ignore errors
}
return null;
}
getSessionInfo() {
return {
id: this.sessionId,
startTime: this.startTime,
uptime: Date.now() - this.startTime.getTime()
};
}
}
exports.CrashReporter = CrashReporter;
// Global crash reporter
let globalCrashReporter = null;
function createCrashReporter(workspaceRoot, options) {
return new CrashReporter(workspaceRoot, options);
}
function getGlobalCrashReporter() {
if (!globalCrashReporter) {
globalCrashReporter = new CrashReporter(process.cwd());
}
return globalCrashReporter;
}
function setGlobalCrashReporter(reporter) {
globalCrashReporter = reporter;
}