@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
820 lines (819 loc) • 31 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.PluginCommandCacheManager = exports.PerformanceMonitoringLevel = exports.CacheInvalidationStrategy = exports.CacheStorageStrategy = void 0;
exports.createCommandCacheManager = createCommandCacheManager;
exports.formatCacheSize = formatCacheSize;
exports.formatCacheHitRate = formatCacheHitRate;
exports.formatExecutionTime = formatExecutionTime;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const crypto = __importStar(require("crypto"));
const events_1 = require("events");
// Cache storage strategies
var CacheStorageStrategy;
(function (CacheStorageStrategy) {
CacheStorageStrategy["MEMORY"] = "memory";
CacheStorageStrategy["FILE_SYSTEM"] = "file-system";
CacheStorageStrategy["HYBRID"] = "hybrid";
CacheStorageStrategy["DATABASE"] = "database";
})(CacheStorageStrategy || (exports.CacheStorageStrategy = CacheStorageStrategy = {}));
// Cache invalidation strategies
var CacheInvalidationStrategy;
(function (CacheInvalidationStrategy) {
CacheInvalidationStrategy["TTL"] = "ttl";
CacheInvalidationStrategy["LRU"] = "lru";
CacheInvalidationStrategy["LFU"] = "lfu";
CacheInvalidationStrategy["FIFO"] = "fifo";
CacheInvalidationStrategy["MANUAL"] = "manual";
CacheInvalidationStrategy["EVENT_BASED"] = "event-based";
})(CacheInvalidationStrategy || (exports.CacheInvalidationStrategy = CacheInvalidationStrategy = {}));
// Performance monitoring levels
var PerformanceMonitoringLevel;
(function (PerformanceMonitoringLevel) {
PerformanceMonitoringLevel["NONE"] = "none";
PerformanceMonitoringLevel["BASIC"] = "basic";
PerformanceMonitoringLevel["DETAILED"] = "detailed";
PerformanceMonitoringLevel["VERBOSE"] = "verbose";
})(PerformanceMonitoringLevel || (exports.PerformanceMonitoringLevel = PerformanceMonitoringLevel = {}));
// Plugin command cache manager
class PluginCommandCacheManager extends events_1.EventEmitter {
constructor(config) {
super();
this.memoryCache = new Map();
this.accessOrder = []; // For LRU tracking
this.accessFrequency = new Map(); // For LFU tracking
this.config = {
enabled: true,
strategy: CacheStorageStrategy.HYBRID,
invalidationStrategy: CacheInvalidationStrategy.LRU,
maxSize: 1000,
maxMemoryUsage: 100 * 1024 * 1024, // 100MB
defaultTTL: 5 * 60 * 1000, // 5 minutes
cleanupInterval: 60 * 1000, // 1 minute
compressionEnabled: true,
encryptionEnabled: false,
persistToDisk: true,
performanceMonitoring: PerformanceMonitoringLevel.BASIC,
...config
};
this.metrics = {
totalExecutions: 0,
cacheHits: 0,
cacheMisses: 0,
hitRate: 0,
averageExecutionTime: 0,
averageCachedExecutionTime: 0,
totalMemoryUsage: 0,
totalDiskUsage: 0,
slowestCommands: [],
mostCachedCommands: [],
errorRate: 0,
lastCleanupAt: Date.now()
};
this.initialize();
}
// Initialize cache system
async initialize() {
try {
// Setup encryption if enabled
if (this.config.encryptionEnabled) {
this.encryptionKey = crypto.randomBytes(32);
}
// Setup disk cache directory
if (this.config.persistToDisk && this.config.diskCachePath) {
await fs.ensureDir(this.config.diskCachePath);
}
// Load existing cache from disk
if (this.config.strategy === CacheStorageStrategy.FILE_SYSTEM ||
this.config.strategy === CacheStorageStrategy.HYBRID) {
await this.loadCacheFromDisk();
}
// Setup cleanup interval
if (this.config.cleanupInterval > 0) {
this.cleanupTimer = setInterval(() => {
this.performCleanup();
}, this.config.cleanupInterval);
}
this.emit('cache-initialized', { config: this.config });
}
catch (error) {
this.emit('cache-initialization-error', error);
throw error;
}
}
// Execute command with caching
async executeWithCache(commandId, args, options, context, executor) {
const startTime = performance.now();
this.metrics.totalExecutions++;
try {
if (!this.config.enabled) {
const result = await executor();
const executionTime = performance.now() - startTime;
this.updateMetrics(executionTime, false, true);
return {
hit: false,
value: result,
executionTime,
source: 'execution'
};
}
// Generate cache key
const cacheKey = this.generateCacheKey(commandId, args, options, context);
// Check cache first
const cachedEntry = await this.getCacheEntry(cacheKey);
if (cachedEntry && !this.isExpired(cachedEntry)) {
// Cache hit
this.updateAccessTracking(cacheKey);
const executionTime = performance.now() - startTime;
this.updateMetrics(executionTime, true, true);
this.emit('cache-hit', { commandId, cacheKey, executionTime });
return {
hit: true,
value: cachedEntry.value,
metadata: cachedEntry.metadata,
executionTime,
source: 'cache'
};
}
// Cache miss - execute command
this.metrics.cacheMisses++;
const result = await executor();
const executionTime = performance.now() - startTime;
// Cache the result
const metadata = {
commandId,
argumentsHash: this.hashObject(args),
optionsHash: this.hashObject(options),
contextHash: this.hashContext(context),
executionTime,
success: true,
dependencies: this.extractDependencies(args, options),
invalidators: this.extractInvalidators(commandId, args, options)
};
await this.setCacheEntry(cacheKey, result, metadata);
this.updateMetrics(executionTime, false, true);
this.emit('cache-miss', { commandId, cacheKey, executionTime });
return {
hit: false,
value: result,
metadata,
executionTime,
source: 'execution'
};
}
catch (error) {
const executionTime = performance.now() - startTime;
this.updateMetrics(executionTime, false, false);
// Cache error information for debugging
if (this.config.enabled) {
const cacheKey = this.generateCacheKey(commandId, args, options, context);
const metadata = {
commandId,
argumentsHash: this.hashObject(args),
optionsHash: this.hashObject(options),
contextHash: this.hashContext(context),
executionTime,
success: false,
errorInfo: {
type: error instanceof Error ? error.constructor.name : 'Error',
message: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined
},
dependencies: [],
invalidators: []
};
// Don't cache the error result, but log it for analysis
this.emit('execution-error', { commandId, cacheKey, error, metadata });
}
return {
hit: false,
executionTime,
source: 'execution',
error: error instanceof Error ? error : new Error(String(error))
};
}
}
// Generate cache key
generateCacheKey(commandId, args, options, context) {
const keyData = {
commandId,
args: this.normalizeForHashing(args),
options: this.normalizeForHashing(options),
context: {
// Only include stable context parts that affect command behavior
rootPath: context.cli.rootPath,
configPath: context.cli.configPath,
version: context.cli.version
}
};
return crypto.createHash('sha256')
.update(JSON.stringify(keyData))
.digest('hex');
}
// Get cache entry
async getCacheEntry(key) {
// Check memory first
const memoryEntry = this.memoryCache.get(key);
if (memoryEntry) {
return memoryEntry;
}
// Check disk if hybrid strategy
if (this.config.strategy === CacheStorageStrategy.HYBRID ||
this.config.strategy === CacheStorageStrategy.FILE_SYSTEM) {
return await this.loadCacheEntryFromDisk(key);
}
return undefined;
}
// Set cache entry
async setCacheEntry(key, value, metadata) {
const now = Date.now();
const entry = {
key,
value,
metadata,
createdAt: now,
lastAccessedAt: now,
accessCount: 1,
expiresAt: now + this.config.defaultTTL,
size: this.calculateSize(value),
tags: this.generateTags(metadata)
};
// Store in memory
if (this.config.strategy === CacheStorageStrategy.MEMORY ||
this.config.strategy === CacheStorageStrategy.HYBRID) {
// Check if we need to evict entries
await this.ensureCapacity();
this.memoryCache.set(key, entry);
this.updateAccessOrder(key);
}
// Store on disk
if (this.config.strategy === CacheStorageStrategy.FILE_SYSTEM ||
this.config.strategy === CacheStorageStrategy.HYBRID) {
await this.saveCacheEntryToDisk(key, entry);
}
this.updateMetrics();
this.emit('cache-entry-set', { key, size: entry.size });
}
// Check if cache entry is expired
isExpired(entry) {
if (!entry.expiresAt)
return false;
return Date.now() > entry.expiresAt;
}
// Update access tracking for LRU/LFU
updateAccessTracking(key) {
const entry = this.memoryCache.get(key);
if (entry) {
entry.lastAccessedAt = Date.now();
entry.accessCount++;
this.updateAccessOrder(key);
this.accessFrequency.set(key, (this.accessFrequency.get(key) || 0) + 1);
}
}
// Update access order for LRU
updateAccessOrder(key) {
const index = this.accessOrder.indexOf(key);
if (index !== -1) {
this.accessOrder.splice(index, 1);
}
this.accessOrder.push(key);
}
// Ensure cache capacity
async ensureCapacity() {
// Check size limit
if (this.memoryCache.size >= this.config.maxSize) {
await this.evictEntries(Math.floor(this.config.maxSize * 0.1)); // Evict 10%
}
// Check memory usage
const currentMemoryUsage = this.calculateTotalMemoryUsage();
if (currentMemoryUsage > this.config.maxMemoryUsage) {
const targetReduction = currentMemoryUsage - (this.config.maxMemoryUsage * 0.8);
await this.evictEntriesBySize(targetReduction);
}
}
// Evict cache entries
async evictEntries(count) {
const keysToEvict = [];
switch (this.config.invalidationStrategy) {
case CacheInvalidationStrategy.LRU:
keysToEvict.push(...this.accessOrder.slice(0, count));
break;
case CacheInvalidationStrategy.LFU:
const entriesByFrequency = Array.from(this.memoryCache.keys())
.sort((a, b) => (this.accessFrequency.get(a) || 0) - (this.accessFrequency.get(b) || 0));
keysToEvict.push(...entriesByFrequency.slice(0, count));
break;
case CacheInvalidationStrategy.FIFO:
const entriesByCreation = Array.from(this.memoryCache.entries())
.sort((a, b) => a[1].createdAt - b[1].createdAt);
keysToEvict.push(...entriesByCreation.slice(0, count).map(([key]) => key));
break;
case CacheInvalidationStrategy.TTL:
const expiredEntries = Array.from(this.memoryCache.entries())
.filter(([, entry]) => this.isExpired(entry))
.slice(0, count);
keysToEvict.push(...expiredEntries.map(([key]) => key));
break;
}
for (const key of keysToEvict) {
await this.invalidateEntry(key);
}
this.emit('cache-entries-evicted', { count: keysToEvict.length, keys: keysToEvict });
}
// Evict entries by size
async evictEntriesBySize(targetReduction) {
const entriesBySize = Array.from(this.memoryCache.entries())
.sort((a, b) => b[1].size - a[1].size); // Largest first
let currentReduction = 0;
const keysToEvict = [];
for (const [key, entry] of entriesBySize) {
if (currentReduction >= targetReduction)
break;
keysToEvict.push(key);
currentReduction += entry.size;
}
for (const key of keysToEvict) {
await this.invalidateEntry(key);
}
this.emit('cache-entries-evicted-by-size', {
targetReduction,
actualReduction: currentReduction,
count: keysToEvict.length
});
}
// Invalidate specific cache entry
async invalidateEntry(key) {
const memoryDeleted = this.memoryCache.delete(key);
// Remove from tracking
const accessOrderIndex = this.accessOrder.indexOf(key);
if (accessOrderIndex !== -1) {
this.accessOrder.splice(accessOrderIndex, 1);
}
this.accessFrequency.delete(key);
// Remove from disk
if (this.config.strategy === CacheStorageStrategy.FILE_SYSTEM ||
this.config.strategy === CacheStorageStrategy.HYBRID) {
await this.deleteCacheEntryFromDisk(key);
}
if (memoryDeleted) {
this.emit('cache-entry-invalidated', { key });
}
return memoryDeleted;
}
// Invalidate by tags
async invalidateByTags(tags) {
const keysToInvalidate = [];
for (const [key, entry] of this.memoryCache.entries()) {
if (entry.tags.some(tag => tags.includes(tag))) {
keysToInvalidate.push(key);
}
}
for (const key of keysToInvalidate) {
await this.invalidateEntry(key);
}
this.emit('cache-invalidated-by-tags', { tags, count: keysToInvalidate.length });
return keysToInvalidate.length;
}
// Invalidate by command
async invalidateByCommand(commandId) {
const keysToInvalidate = [];
for (const [key, entry] of this.memoryCache.entries()) {
if (entry.metadata.commandId === commandId) {
keysToInvalidate.push(key);
}
}
for (const key of keysToInvalidate) {
await this.invalidateEntry(key);
}
this.emit('cache-invalidated-by-command', { commandId, count: keysToInvalidate.length });
return keysToInvalidate.length;
}
// Clear all cache
async clearAll() {
this.memoryCache.clear();
this.accessOrder.length = 0;
this.accessFrequency.clear();
if (this.config.strategy === CacheStorageStrategy.FILE_SYSTEM ||
this.config.strategy === CacheStorageStrategy.HYBRID) {
await this.clearDiskCache();
}
this.resetMetrics();
this.emit('cache-cleared');
}
// Perform cleanup
async performCleanup() {
const startTime = Date.now();
let cleanedCount = 0;
// Remove expired entries
const expiredKeys = [];
for (const [key, entry] of this.memoryCache.entries()) {
if (this.isExpired(entry)) {
expiredKeys.push(key);
}
}
for (const key of expiredKeys) {
await this.invalidateEntry(key);
cleanedCount++;
}
// Ensure capacity
await this.ensureCapacity();
this.metrics.lastCleanupAt = Date.now();
this.emit('cache-cleanup-completed', {
duration: Date.now() - startTime,
cleanedCount
});
}
// Load cache from disk
async loadCacheFromDisk() {
if (!this.config.diskCachePath)
return;
try {
const cacheIndexPath = path.join(this.config.diskCachePath, 'index.json');
if (await fs.pathExists(cacheIndexPath)) {
const index = await fs.readJson(cacheIndexPath);
for (const key of index.keys) {
const entry = await this.loadCacheEntryFromDisk(key);
if (entry && !this.isExpired(entry)) {
this.memoryCache.set(key, entry);
this.updateAccessOrder(key);
}
}
}
}
catch (error) {
this.emit('cache-load-error', error);
}
}
// Load cache entry from disk
async loadCacheEntryFromDisk(key) {
if (!this.config.diskCachePath)
return undefined;
try {
const entryPath = path.join(this.config.diskCachePath, `${key}.cache`);
if (await fs.pathExists(entryPath)) {
let data = await fs.readFile(entryPath);
// Decrypt if enabled
if (this.config.encryptionEnabled && this.encryptionKey) {
data = this.decrypt(data);
}
// Decompress if enabled
if (this.config.compressionEnabled) {
const zlib = require('zlib');
data = zlib.gunzipSync(data);
}
return JSON.parse(data.toString());
}
}
catch (error) {
this.emit('cache-entry-load-error', { key, error });
}
return undefined;
}
// Save cache entry to disk
async saveCacheEntryToDisk(key, entry) {
if (!this.config.diskCachePath)
return;
try {
let data = Buffer.from(JSON.stringify(entry));
// Compress if enabled
if (this.config.compressionEnabled) {
const zlib = require('zlib');
data = zlib.gzipSync(data);
}
// Encrypt if enabled
if (this.config.encryptionEnabled && this.encryptionKey) {
data = this.encrypt(data);
}
const entryPath = path.join(this.config.diskCachePath, `${key}.cache`);
await fs.writeFile(entryPath, data);
// Update index
await this.updateDiskCacheIndex();
}
catch (error) {
this.emit('cache-entry-save-error', { key, error });
}
}
// Delete cache entry from disk
async deleteCacheEntryFromDisk(key) {
if (!this.config.diskCachePath)
return;
try {
const entryPath = path.join(this.config.diskCachePath, `${key}.cache`);
if (await fs.pathExists(entryPath)) {
await fs.remove(entryPath);
await this.updateDiskCacheIndex();
}
}
catch (error) {
this.emit('cache-entry-delete-error', { key, error });
}
}
// Update disk cache index
async updateDiskCacheIndex() {
if (!this.config.diskCachePath)
return;
try {
const cacheFiles = await fs.readdir(this.config.diskCachePath);
const keys = cacheFiles
.filter(file => file.endsWith('.cache'))
.map(file => file.replace('.cache', ''));
const indexPath = path.join(this.config.diskCachePath, 'index.json');
await fs.writeJson(indexPath, { keys, updatedAt: Date.now() });
}
catch (error) {
this.emit('cache-index-update-error', error);
}
}
// Clear disk cache
async clearDiskCache() {
if (!this.config.diskCachePath)
return;
try {
if (await fs.pathExists(this.config.diskCachePath)) {
await fs.emptyDir(this.config.diskCachePath);
}
}
catch (error) {
this.emit('cache-clear-error', error);
}
}
// Encrypt data
encrypt(data) {
if (!this.encryptionKey)
return data;
const algorithm = 'aes-256-gcm';
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipher(algorithm, this.encryptionKey);
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
return Buffer.concat([iv, encrypted]);
}
// Decrypt data
decrypt(data) {
if (!this.encryptionKey)
return data;
const algorithm = 'aes-256-gcm';
const iv = data.slice(0, 16);
const encrypted = data.slice(16);
const decipher = crypto.createDecipher(algorithm, this.encryptionKey);
return Buffer.concat([decipher.update(encrypted), decipher.final()]);
}
// Calculate object size
calculateSize(obj) {
return Buffer.byteLength(JSON.stringify(obj), 'utf8');
}
// Calculate total memory usage
calculateTotalMemoryUsage() {
let total = 0;
for (const entry of this.memoryCache.values()) {
total += entry.size;
}
return total;
}
// Generate cache tags
generateTags(metadata) {
const tags = [
`command:${metadata.commandId}`,
`success:${metadata.success}`
];
// Add performance-based tags
if (metadata.executionTime > 1000) {
tags.push('slow');
}
else if (metadata.executionTime < 100) {
tags.push('fast');
}
return tags;
}
// Extract dependencies from arguments/options
extractDependencies(args, options) {
const dependencies = [];
// Add file dependencies
const allValues = [...Object.values(args), ...Object.values(options)];
for (const value of allValues) {
if (typeof value === 'string' && value.includes('/')) {
dependencies.push(`file:${value}`);
}
}
return dependencies;
}
// Extract invalidators
extractInvalidators(commandId, args, options) {
const invalidators = [];
// Commands that might invalidate this cache
if (commandId.includes('build') || commandId.includes('deploy')) {
invalidators.push('file-change', 'config-change');
}
if (commandId.includes('install') || commandId.includes('update')) {
invalidators.push('dependency-change');
}
return invalidators;
}
// Hash object for comparison
hashObject(obj) {
return crypto.createHash('md5').update(JSON.stringify(this.normalizeForHashing(obj))).digest('hex');
}
// Hash context
hashContext(context) {
const contextData = {
rootPath: context.cli.rootPath,
configPath: context.cli.configPath,
version: context.cli.version
};
return crypto.createHash('md5').update(JSON.stringify(contextData)).digest('hex');
}
// Normalize object for hashing
normalizeForHashing(obj) {
if (obj === null || obj === undefined)
return obj;
if (Array.isArray(obj)) {
return obj.map(item => this.normalizeForHashing(item)).sort();
}
if (typeof obj === 'object') {
const normalized = {};
const keys = Object.keys(obj).sort();
for (const key of keys) {
normalized[key] = this.normalizeForHashing(obj[key]);
}
return normalized;
}
return obj;
}
// Update metrics
updateMetrics(executionTime, hit, success) {
if (hit !== undefined) {
if (hit) {
this.metrics.cacheHits++;
}
else {
this.metrics.cacheMisses++;
}
this.metrics.hitRate = this.metrics.cacheHits / (this.metrics.cacheHits + this.metrics.cacheMisses);
}
if (executionTime !== undefined) {
const totalTime = (this.metrics.averageExecutionTime * (this.metrics.totalExecutions - 1)) + executionTime;
this.metrics.averageExecutionTime = totalTime / this.metrics.totalExecutions;
if (hit) {
const totalCachedTime = (this.metrics.averageCachedExecutionTime * (this.metrics.cacheHits - 1)) + executionTime;
this.metrics.averageCachedExecutionTime = totalCachedTime / this.metrics.cacheHits;
}
}
if (success === false) {
this.metrics.errorRate = (this.metrics.errorRate * (this.metrics.totalExecutions - 1) + 1) / this.metrics.totalExecutions;
}
this.metrics.totalMemoryUsage = this.calculateTotalMemoryUsage();
}
// Reset metrics
resetMetrics() {
this.metrics = {
totalExecutions: 0,
cacheHits: 0,
cacheMisses: 0,
hitRate: 0,
averageExecutionTime: 0,
averageCachedExecutionTime: 0,
totalMemoryUsage: 0,
totalDiskUsage: 0,
slowestCommands: [],
mostCachedCommands: [],
errorRate: 0,
lastCleanupAt: Date.now()
};
}
// Get performance metrics
getMetrics() {
return { ...this.metrics };
}
// Get cache configuration
getConfiguration() {
return { ...this.config };
}
// Update configuration
updateConfiguration(updates) {
this.config = { ...this.config, ...updates };
this.emit('configuration-updated', this.config);
}
// Get cache statistics
getCacheStats() {
return {
size: this.memoryCache.size,
memoryUsage: this.calculateTotalMemoryUsage(),
hitRate: this.metrics.hitRate,
totalExecutions: this.metrics.totalExecutions,
averageExecutionTime: this.metrics.averageExecutionTime,
oldestEntry: this.findOldestEntry(),
newestEntry: this.findNewestEntry(),
mostAccessedEntry: this.findMostAccessedEntry(),
largestEntry: this.findLargestEntry()
};
}
// Find oldest entry
findOldestEntry() {
let oldest;
for (const entry of this.memoryCache.values()) {
if (!oldest || entry.createdAt < oldest.createdAt) {
oldest = entry;
}
}
return oldest;
}
// Find newest entry
findNewestEntry() {
let newest;
for (const entry of this.memoryCache.values()) {
if (!newest || entry.createdAt > newest.createdAt) {
newest = entry;
}
}
return newest;
}
// Find most accessed entry
findMostAccessedEntry() {
let mostAccessed;
for (const entry of this.memoryCache.values()) {
if (!mostAccessed || entry.accessCount > mostAccessed.accessCount) {
mostAccessed = entry;
}
}
return mostAccessed;
}
// Find largest entry
findLargestEntry() {
let largest;
for (const entry of this.memoryCache.values()) {
if (!largest || entry.size > largest.size) {
largest = entry;
}
}
return largest;
}
// Destroy cache manager
async destroy() {
if (this.cleanupTimer) {
clearInterval(this.cleanupTimer);
}
if (this.config.persistToDisk) {
await this.updateDiskCacheIndex();
}
this.memoryCache.clear();
this.accessOrder.length = 0;
this.accessFrequency.clear();
this.emit('cache-destroyed');
}
}
exports.PluginCommandCacheManager = PluginCommandCacheManager;
// Utility functions
function createCommandCacheManager(config) {
return new PluginCommandCacheManager(config);
}
function formatCacheSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(1)} ${units[unitIndex]}`;
}
function formatCacheHitRate(hitRate) {
return `${(hitRate * 100).toFixed(1)}%`;
}
function formatExecutionTime(time) {
if (time < 1000) {
return `${time.toFixed(1)}ms`;
}
return `${(time / 1000).toFixed(2)}s`;
}