@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
404 lines (403 loc) • 14 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.ErrorContextManager = exports.BreadcrumbLevel = exports.ErrorLevel = void 0;
exports.createErrorContextManager = createErrorContextManager;
exports.getGlobalErrorContext = getGlobalErrorContext;
exports.setGlobalErrorContext = setGlobalErrorContext;
const events_1 = require("events");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
var ErrorLevel;
(function (ErrorLevel) {
ErrorLevel[ErrorLevel["DEBUG"] = 0] = "DEBUG";
ErrorLevel[ErrorLevel["INFO"] = 1] = "INFO";
ErrorLevel[ErrorLevel["WARNING"] = 2] = "WARNING";
ErrorLevel[ErrorLevel["ERROR"] = 3] = "ERROR";
ErrorLevel[ErrorLevel["FATAL"] = 4] = "FATAL";
})(ErrorLevel || (exports.ErrorLevel = ErrorLevel = {}));
var BreadcrumbLevel;
(function (BreadcrumbLevel) {
BreadcrumbLevel[BreadcrumbLevel["DEBUG"] = 0] = "DEBUG";
BreadcrumbLevel[BreadcrumbLevel["INFO"] = 1] = "INFO";
BreadcrumbLevel[BreadcrumbLevel["WARNING"] = 2] = "WARNING";
BreadcrumbLevel[BreadcrumbLevel["ERROR"] = 3] = "ERROR";
})(BreadcrumbLevel || (exports.BreadcrumbLevel = BreadcrumbLevel = {}));
class ErrorContextManager extends events_1.EventEmitter {
constructor(options = {}) {
super();
this.breadcrumbs = [];
this.context = {};
this.tags = {};
this.maxBreadcrumbs = options.maxBreadcrumbs ?? 100;
this.maxContextSize = options.maxContextSize ?? 10000;
this.enableStackTrace = options.enableStackTrace ?? true;
this.enableEnvironment = options.enableEnvironment ?? true;
this.enableMemoryInfo = options.enableMemoryInfo ?? true;
this.enableFileContext = options.enableFileContext ?? false;
this.storageDir = options.storageDir ?? path.join(process.cwd(), '.re-shell', 'errors');
this.autoCapture = options.autoCapture ?? true;
if (this.autoCapture) {
this.setupAutoCapture();
}
}
setupAutoCapture() {
// Capture unhandled exceptions
process.on('uncaughtException', (error) => {
this.captureException(error, {
level: ErrorLevel.FATAL,
command: 'unknown',
args: {},
options: {}
});
});
// Capture unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
const error = reason instanceof Error ? reason : new Error(String(reason));
this.captureException(error, {
level: ErrorLevel.ERROR,
command: 'unknown',
args: {},
options: {},
context: { promise: promise.toString() }
});
});
}
captureException(error, context) {
const errorId = this.generateErrorId();
const errorContext = {
id: errorId,
timestamp: new Date(),
command: context.command,
args: context.args,
options: context.options,
error,
stack: this.enableStackTrace ? this.captureStackTrace(error) : '',
environment: this.enableEnvironment ? this.captureEnvironment() : {},
context: {
...this.context,
...context.context
},
breadcrumbs: [...this.breadcrumbs],
tags: {
...this.tags,
...context.tags
},
level: context.level ?? ErrorLevel.ERROR
};
// Store error context
this.storeErrorContext(errorContext);
// Emit event
this.emit('error:captured', errorContext);
return errorId;
}
generateErrorId() {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substring(2, 8);
return `${timestamp}-${random}`;
}
captureStackTrace(error) {
if (error.stack) {
return error.stack;
}
// Capture current stack if error doesn't have one
const stackTrace = new Error().stack;
return stackTrace?.split('\n').slice(2).join('\n') || '';
}
captureEnvironment() {
const memUsage = process.memoryUsage();
return {
platform: os.platform(),
arch: os.arch(),
nodeVersion: process.version,
cliVersion: this.getCliVersion(),
cwd: process.cwd(),
memory: {
rss: memUsage.rss,
heapTotal: memUsage.heapTotal,
heapUsed: memUsage.heapUsed,
external: memUsage.external
},
timing: {
uptime: os.uptime(),
processUptime: process.uptime()
}
};
}
getCliVersion() {
try {
const packagePath = path.join(__dirname, '..', '..', 'package.json');
const pkg = fs.readJsonSync(packagePath);
return pkg.version;
}
catch {
return 'unknown';
}
}
storeErrorContext(errorContext) {
try {
// Ensure directory exists
fs.ensureDirSync(this.storageDir);
// Write error context to file
const filename = `error-${errorContext.id}.json`;
const filepath = path.join(this.storageDir, filename);
const data = {
...errorContext,
error: {
name: errorContext.error.name,
message: errorContext.error.message,
stack: errorContext.error.stack
}
};
fs.writeJsonSync(filepath, data, { spaces: 2 });
// Clean up old error files (keep last 50)
this.cleanupOldErrors();
}
catch (storeError) {
// Don't throw errors from error storage
console.error('Failed to store error context:', storeError);
}
}
cleanupOldErrors() {
try {
const files = fs.readdirSync(this.storageDir)
.filter(f => f.startsWith('error-') && f.endsWith('.json'))
.sort();
if (files.length > 50) {
const toDelete = files.slice(0, files.length - 50);
for (const file of toDelete) {
fs.unlinkSync(path.join(this.storageDir, file));
}
}
}
catch {
// Ignore cleanup errors
}
}
addBreadcrumb(breadcrumb) {
const fullBreadcrumb = {
...breadcrumb,
timestamp: new Date()
};
this.breadcrumbs.push(fullBreadcrumb);
// Trim breadcrumbs if needed
if (this.breadcrumbs.length > this.maxBreadcrumbs) {
this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs);
}
this.emit('breadcrumb:added', fullBreadcrumb);
}
setContext(key, value) {
this.context[key] = value;
// Check context size
const contextSize = JSON.stringify(this.context).length;
if (contextSize > this.maxContextSize) {
// Remove oldest entries
const keys = Object.keys(this.context);
const toRemove = Math.ceil(keys.length * 0.1); // Remove 10%
for (let i = 0; i < toRemove; i++) {
delete this.context[keys[i]];
}
}
this.emit('context:set', { key, value });
}
removeContext(key) {
delete this.context[key];
this.emit('context:removed', { key });
}
getContext() {
return { ...this.context };
}
setTag(key, value) {
this.tags[key] = value;
this.emit('tag:set', { key, value });
}
removeTag(key) {
delete this.tags[key];
this.emit('tag:removed', { key });
}
getTags() {
return { ...this.tags };
}
getBreadcrumbs() {
return [...this.breadcrumbs];
}
clearBreadcrumbs() {
this.breadcrumbs = [];
this.emit('breadcrumbs:cleared');
}
clearContext() {
this.context = {};
this.emit('context:cleared');
}
clearTags() {
this.tags = {};
this.emit('tags:cleared');
}
clear() {
this.clearBreadcrumbs();
this.clearContext();
this.clearTags();
this.emit('cleared');
}
getErrorContext(errorId) {
try {
const filepath = path.join(this.storageDir, `error-${errorId}.json`);
if (fs.existsSync(filepath)) {
const data = fs.readJsonSync(filepath);
return data;
}
}
catch {
// Ignore read errors
}
return null;
}
getAllErrorContexts() {
try {
const files = fs.readdirSync(this.storageDir)
.filter(f => f.startsWith('error-') && f.endsWith('.json'))
.sort()
.reverse(); // Most recent first
const contexts = [];
for (const file of files) {
try {
const filepath = path.join(this.storageDir, file);
const data = fs.readJsonSync(filepath);
contexts.push(data);
}
catch {
// Skip corrupted files
}
}
return contexts;
}
catch {
return [];
}
}
deleteErrorContext(errorId) {
try {
const filepath = path.join(this.storageDir, `error-${errorId}.json`);
if (fs.existsSync(filepath)) {
fs.unlinkSync(filepath);
this.emit('error:deleted', { errorId });
return true;
}
}
catch {
// Ignore delete errors
}
return false;
}
getRecentErrors(count = 10) {
return this.getAllErrorContexts().slice(0, count);
}
searchErrors(query) {
const allErrors = this.getAllErrorContexts();
return allErrors.filter(error => {
if (query.command && !error.command.includes(query.command)) {
return false;
}
if (query.level !== undefined && error.level !== query.level) {
return false;
}
if (query.tag && !Object.keys(error.tags).includes(query.tag)) {
return false;
}
if (query.dateFrom && error.timestamp < query.dateFrom) {
return false;
}
if (query.dateTo && error.timestamp > query.dateTo) {
return false;
}
return true;
});
}
generateReport() {
const allErrors = this.getAllErrorContexts();
const now = new Date();
const day = 24 * 60 * 60 * 1000;
const errorsByLevel = {};
const errorsByCommand = {};
let last24Hours = 0;
let last7Days = 0;
let last30Days = 0;
for (const error of allErrors) {
// Count by level
const level = ErrorLevel[error.level];
errorsByLevel[level] = (errorsByLevel[level] || 0) + 1;
// Count by command
errorsByCommand[error.command] = (errorsByCommand[error.command] || 0) + 1;
// Count by time periods
const errorTime = new Date(error.timestamp).getTime();
const timeDiff = now.getTime() - errorTime;
if (timeDiff <= day)
last24Hours++;
if (timeDiff <= 7 * day)
last7Days++;
if (timeDiff <= 30 * day)
last30Days++;
}
return {
summary: {
totalErrors: allErrors.length,
errorsByLevel,
errorsByCommand,
recentErrors: last24Hours
},
trends: {
last24Hours,
last7Days,
last30Days
}
};
}
}
exports.ErrorContextManager = ErrorContextManager;
// Global error context manager
let globalErrorContext = null;
function createErrorContextManager(options) {
return new ErrorContextManager(options);
}
function getGlobalErrorContext() {
if (!globalErrorContext) {
globalErrorContext = new ErrorContextManager();
}
return globalErrorContext;
}
function setGlobalErrorContext(manager) {
globalErrorContext = manager;
}