@versatil/sdlc-framework
Version:
🚀 AI-Native SDLC framework with 11-MCP ecosystem, RAG memory, OPERA orchestration, and 6 specialized agents achieving ZERO CONTEXT LOSS. Features complete CI/CD pipeline with 7 GitHub workflows (MCP testing, security scanning, performance benchmarking),
179 lines (154 loc) • 3.61 kB
text/typescript
/**
* LRU (Least Recently Used) Cache Implementation
* Manages memory-efficient caching with automatic eviction
*/
export interface CacheEntry<V> {
value: V;
timestamp: number;
accessCount: number;
}
export interface CacheStats {
size: number;
maxSize: number;
hits: number;
misses: number;
evictions: number;
hitRate: number;
}
export class LRUCache<K, V> {
private cache: Map<K, CacheEntry<V>>;
private maxSize: number;
private maxAge: number;
private stats: {
hits: number;
misses: number;
evictions: number;
};
constructor(maxSize: number = 1000, maxAgeMs: number = 3600000) {
this.cache = new Map();
this.maxSize = maxSize;
this.maxAge = maxAgeMs;
this.stats = { hits: 0, misses: 0, evictions: 0 };
}
/**
* Get value from cache
*/
get(key: K): V | undefined {
const entry = this.cache.get(key);
if (!entry) {
this.stats.misses++;
return undefined;
}
// Check if expired
if (Date.now() - entry.timestamp > this.maxAge) {
this.cache.delete(key);
this.stats.misses++;
this.stats.evictions++;
return undefined;
}
// Update access stats
entry.accessCount++;
entry.timestamp = Date.now();
// Move to end (most recently used)
this.cache.delete(key);
this.cache.set(key, entry);
this.stats.hits++;
return entry.value;
}
/**
* Set value in cache
*/
set(key: K, value: V): void {
// Check if key exists
if (this.cache.has(key)) {
this.cache.delete(key);
}
// Evict oldest if at capacity
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
this.stats.evictions++;
}
this.cache.set(key, {
value,
timestamp: Date.now(),
accessCount: 0
});
}
/**
* Check if key exists
*/
has(key: K): boolean {
const entry = this.cache.get(key);
if (!entry) return false;
// Check expiration
if (Date.now() - entry.timestamp > this.maxAge) {
this.cache.delete(key);
return false;
}
return true;
}
/**
* Delete key from cache
*/
delete(key: K): boolean {
return this.cache.delete(key);
}
/**
* Clear all entries
*/
clear(): void {
this.cache.clear();
}
/**
* Get cache statistics
*/
getStats(): CacheStats {
return {
size: this.cache.size,
maxSize: this.maxSize,
hits: this.stats.hits,
misses: this.stats.misses,
evictions: this.stats.evictions,
hitRate: this.stats.hits / (this.stats.hits + this.stats.misses) || 0
};
}
/**
* Get all keys
*/
keys(): K[] {
return Array.from(this.cache.keys());
}
/**
* Get cache size
*/
get size(): number {
return this.cache.size;
}
/**
* Cleanup expired entries
*/
cleanup(): void {
const now = Date.now();
const keysToDelete: K[] = [];
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > this.maxAge) {
keysToDelete.push(key);
}
}
for (const key of keysToDelete) {
this.cache.delete(key);
this.stats.evictions++;
}
}
/**
* Get entries sorted by access count (for analytics)
*/
getTopEntries(limit: number = 10): Array<{ key: K; accessCount: number }> {
const entries = Array.from(this.cache.entries());
return entries
.sort((a, b) => b[1].accessCount - a[1].accessCount)
.slice(0, limit)
.map(([key, entry]) => ({ key, accessCount: entry.accessCount }));
}
}