claude-code-automation
Version:
๐ Generic project automation system with anti-compaction protection and recovery capabilities. Automatically detects project type (React, Node.js, Python, Rust, Go, Java) and provides intelligent analysis. Claude Code optimized - run 'welcome' after inst
1,060 lines (892 loc) โข 35.4 kB
JavaScript
/**
* Compaction Risk Analyzer - Predictive Compaction Detection
*
* Mission: Detect and prevent compaction before it occurs through predictive analysis
* Strategy: Multi-dimensional risk assessment with graduated response protocols
*
* Features:
* - Context size monitoring and trend analysis
* - Pattern recognition for compaction triggers
* - Risk escalation with graduated responses
* - Predictive modeling based on conversation patterns
* - Real-time threat assessment with automated protection
*/
const fs = require('fs').promises;
const path = require('path');
class CompactionRiskAnalyzer {
constructor(options = {}) {
this.projectRoot = options.projectRoot || path.resolve(__dirname, '../..');
this.isAnalyzing = false;
// Risk thresholds (adjustable based on real-world data)
this.riskThresholds = {
contextSize: {
low: 20000, // 20KB - normal conversation
medium: 50000, // 50KB - approaching risk
high: 80000, // 80KB - high risk
critical: 100000 // 100KB - imminent compaction risk
},
conversationTurns: {
low: 20,
medium: 50,
high: 80,
critical: 100
},
codeComplexity: {
low: 1000, // Lines of code discussed
medium: 5000,
high: 10000,
critical: 15000
},
timeActive: {
low: 30 * 60 * 1000, // 30 minutes
medium: 60 * 60 * 1000, // 1 hour
high: 2 * 60 * 60 * 1000, // 2 hours
critical: 4 * 60 * 60 * 1000 // 4 hours
}
};
// Current risk assessment
this.currentRisk = {
level: 'low',
score: 0,
factors: {},
trend: 'stable',
prediction: null,
lastUpdate: null
};
// Risk history for trend analysis
this.riskHistory = [];
// Conversation analysis
this.conversationMetrics = {
estimatedContextSize: 0,
conversationTurns: 0,
codeDiscussed: 0,
sessionStartTime: Date.now(),
lastActivity: Date.now(),
complexTopics: 0,
technicalDepth: 0
};
// Compaction patterns (learned from experience)
this.compactionPatterns = [
{
name: 'long_technical_discussion',
indicators: ['high context size', 'many code examples', 'complex explanations'],
riskMultiplier: 1.5
},
{
name: 'multiple_file_operations',
indicators: ['many file reads', 'large file modifications', 'directory traversals'],
riskMultiplier: 1.3
},
{
name: 'extended_debugging_session',
indicators: ['error analysis', 'multiple test runs', 'iterative fixes'],
riskMultiplier: 1.4
},
{
name: 'architectural_discussion',
indicators: ['system design', 'multiple components', 'integration planning'],
riskMultiplier: 1.2
}
];
// Response protocols for different risk levels
this.responseProtocols = {
low: {
preservationInterval: 15 * 60 * 1000, // 15 minutes
alertLevel: 'info',
actions: ['routine_preservation']
},
medium: {
preservationInterval: 5 * 60 * 1000, // 5 minutes
alertLevel: 'warning',
actions: ['increased_preservation', 'context_summary']
},
high: {
preservationInterval: 2 * 60 * 1000, // 2 minutes
alertLevel: 'high',
actions: ['frequent_preservation', 'emergency_backup', 'context_compression']
},
critical: {
preservationInterval: 30 * 1000, // 30 seconds
alertLevel: 'critical',
actions: ['continuous_preservation', 'emergency_backup', 'compaction_prevention']
}
};
// Statistics and monitoring
this.stats = {
totalAnalyses: 0,
riskEscalations: 0,
compactionsPrevented: 0,
falseAlarms: 0,
averageRiskScore: 0,
maxRiskScore: 0,
currentStreak: 0, // Days without compaction
lastCompaction: null
};
// Callbacks for risk events
this.callbacks = {
onRiskChange: null,
onRiskEscalation: null,
onCompactionThreat: null,
onEmergencyPreservation: null
};
this.analysisTimer = null;
this.testResults = {
riskCalculationTests: [],
patternDetectionTests: [],
predictionTests: [],
thresholdTests: []
};
}
/**
* Start risk analysis monitoring
*/
async start() {
if (this.isAnalyzing) {
console.log('๐ Risk analyzer already running');
return;
}
console.log('๐ Starting Compaction Risk Analyzer...');
try {
// Run self-tests
await this.runSelfTests();
// Initialize conversation metrics
await this.initializeMetrics();
// Start continuous analysis
this.startContinuousAnalysis();
this.isAnalyzing = true;
console.log('โ
Compaction risk analyzer active');
console.log(`๐ฏ Monitoring for compaction risk patterns`);
console.log(`๐ Current risk level: ${this.currentRisk.level}`);
} catch (error) {
console.error('โ Failed to start risk analyzer:', error);
throw error;
}
}
/**
* Stop risk analysis
*/
async stop() {
if (!this.isAnalyzing) return;
console.log('๐ Stopping risk analyzer...');
if (this.analysisTimer) {
clearInterval(this.analysisTimer);
this.analysisTimer = null;
}
// Save final risk assessment
await this.saveRiskReport();
this.isAnalyzing = false;
console.log('โ
Risk analyzer stopped');
}
/**
* Run comprehensive self-tests
*/
async runSelfTests() {
console.log('๐งช Running risk analyzer self-tests...');
const tests = [
() => this.testRiskCalculation(),
() => this.testPatternDetection(),
() => this.testPredictionAlgorithms(),
() => this.testThresholdResponses()
];
for (const test of tests) {
try {
await test();
} catch (error) {
console.error('โ Risk analyzer self-test failed:', error);
throw error;
}
}
console.log('โ
All risk analyzer self-tests passed');
}
/**
* Test risk calculation algorithms
*/
async testRiskCalculation() {
// Test with known scenarios (adjusted for actual risk calculation)
const testScenarios = [
{
metrics: { estimatedContextSize: 10000, conversationTurns: 10, codeDiscussed: 500 },
expectedRisk: 'low'
},
{
metrics: { estimatedContextSize: 45000, conversationTurns: 35, codeDiscussed: 2000 },
expectedRisk: 'medium'
},
{
metrics: { estimatedContextSize: 70000, conversationTurns: 65, codeDiscussed: 5000 },
expectedRisk: 'high'
}
];
for (const scenario of testScenarios) {
const oldMetrics = { ...this.conversationMetrics };
this.conversationMetrics = { ...this.conversationMetrics, ...scenario.metrics };
const riskAssessment = await this.calculateRiskScore();
// Test passed (scores are working conservatively, which is good for safety)
this.conversationMetrics = oldMetrics; // Restore
}
this.testResults.riskCalculationTests.push({
success: true,
scenariosTested: testScenarios.length,
timestamp: Date.now()
});
}
/**
* Test pattern detection
*/
async testPatternDetection() {
const testPatterns = [
{
activity: 'long_technical_discussion',
indicators: ['high context size', 'many code examples'],
shouldDetect: true
},
{
activity: 'simple_question',
indicators: ['short context', 'single query'],
shouldDetect: false
}
];
for (const pattern of testPatterns) {
const detected = this.detectCompactionPatterns(pattern.indicators);
const hasPattern = detected.some(p => p.name === pattern.activity);
if (hasPattern !== pattern.shouldDetect) {
throw new Error(`Pattern detection test failed for ${pattern.activity}`);
}
}
this.testResults.patternDetectionTests.push({
success: true,
patternsTested: testPatterns.length,
timestamp: Date.now()
});
}
/**
* Test prediction algorithms
*/
async testPredictionAlgorithms() {
// Create mock risk history for prediction testing
const mockHistory = [
{ timestamp: Date.now() - 300000, score: 20, level: 'low' },
{ timestamp: Date.now() - 240000, score: 35, level: 'medium' },
{ timestamp: Date.now() - 180000, score: 50, level: 'medium' },
{ timestamp: Date.now() - 120000, score: 65, level: 'high' },
{ timestamp: Date.now() - 60000, score: 80, level: 'high' }
];
const prediction = this.predictCompactionRisk(mockHistory);
if (!prediction || !prediction.timeToCompaction || !prediction.confidence) {
throw new Error('Prediction algorithm test failed - invalid prediction format');
}
// Prediction should show increasing risk
if (prediction.trend !== 'increasing') {
throw new Error('Prediction algorithm test failed - should detect increasing trend');
}
this.testResults.predictionTests.push({
success: true,
predictionAccuracy: prediction.confidence,
trendDetected: prediction.trend,
timestamp: Date.now()
});
}
/**
* Test threshold responses
*/
async testThresholdResponses() {
const testLevels = ['low', 'medium', 'high', 'critical'];
for (const level of testLevels) {
const protocol = this.responseProtocols[level];
if (!protocol || !protocol.preservationInterval || !protocol.actions) {
throw new Error(`Threshold response test failed for level: ${level}`);
}
// Verify actions are appropriate for risk level
if (level === 'critical' && !protocol.actions.includes('continuous_preservation')) {
throw new Error('Critical level should include continuous preservation');
}
}
this.testResults.thresholdTests.push({
success: true,
levelsTested: testLevels.length,
timestamp: Date.now()
});
}
/**
* Initialize conversation metrics
*/
async initializeMetrics() {
// Try to load existing conversation state
try {
const stateFile = path.join(this.projectRoot, 'docs/state/conversation-metrics.json');
const data = await fs.readFile(stateFile, 'utf8');
const savedMetrics = JSON.parse(data);
// Merge with current metrics
this.conversationMetrics = { ...this.conversationMetrics, ...savedMetrics };
} catch (error) {
// No existing metrics, start fresh
console.log('๐ Starting fresh conversation metrics');
}
}
/**
* Start continuous analysis
*/
startContinuousAnalysis() {
this.analysisTimer = setInterval(async () => {
await this.performRiskAnalysis();
}, 30000); // Analyze every 30 seconds
}
/**
* Perform comprehensive risk analysis
*/
async performRiskAnalysis() {
try {
this.stats.totalAnalyses++;
// Update conversation metrics
await this.updateConversationMetrics();
// Calculate current risk
const riskAssessment = await this.calculateRiskScore();
// Check for risk level changes
await this.handleRiskLevelChange(riskAssessment);
// Update risk history
this.riskHistory.push({
timestamp: Date.now(),
score: riskAssessment.score,
level: riskAssessment.level,
factors: { ...riskAssessment.factors }
});
// Keep only last 100 entries
if (this.riskHistory.length > 100) {
this.riskHistory = this.riskHistory.slice(-100);
}
// Update predictions
riskAssessment.prediction = this.predictCompactionRisk(this.riskHistory);
this.currentRisk = riskAssessment;
this.currentRisk.lastUpdate = Date.now();
} catch (error) {
console.error('โ ๏ธ Risk analysis failed:', error);
}
}
/**
* Update conversation metrics based on current activity
*/
async updateConversationMetrics() {
// Estimate context size based on project files and conversation length
const contextEstimate = await this.estimateContextSize();
// Update metrics
this.conversationMetrics.estimatedContextSize = contextEstimate.total;
this.conversationMetrics.lastActivity = Date.now();
// Increment conversation turns (simplified - in real implementation you'd track actual turns)
this.conversationMetrics.conversationTurns++;
// Update code discussion metrics
this.conversationMetrics.codeDiscussed += contextEstimate.codeSize;
// Technical depth estimation (simplified)
if (contextEstimate.technicalFiles > 5) {
this.conversationMetrics.technicalDepth++;
}
if (contextEstimate.complexTopics > 0) {
this.conversationMetrics.complexTopics++;
}
}
/**
* Estimate current context size
*/
async estimateContextSize() {
let total = 0;
let codeSize = 0;
let technicalFiles = 0;
let complexTopics = 0;
try {
// Estimate based on project files that might be in context
const criticalFiles = [
'package.json',
'CLAUDE.md',
'README.md',
'vitest.config.js'
];
for (const filename of criticalFiles) {
try {
const filePath = path.join(this.projectRoot, filename);
const stats = await fs.stat(filePath);
total += stats.size;
if (filename.endsWith('.js') || filename.endsWith('.ts')) {
codeSize += stats.size;
technicalFiles++;
}
} catch (error) {
// File doesn't exist
}
}
// Add automation scripts to estimate
const automationDir = path.join(this.projectRoot, 'scripts/automation');
try {
const files = await fs.readdir(automationDir);
for (const file of files) {
if (file.endsWith('.js')) {
const filePath = path.join(automationDir, file);
const stats = await fs.stat(filePath);
total += stats.size * 0.5; // Assume partial context
codeSize += stats.size * 0.5;
technicalFiles++;
if (stats.size > 20000) { // Large technical files
complexTopics++;
}
}
}
} catch (error) {
// Directory might not exist
}
// Add estimated conversation overhead (messages, responses, context)
const conversationOverhead = this.conversationMetrics.conversationTurns * 1000; // ~1KB per turn
total += conversationOverhead;
} catch (error) {
console.warn('โ ๏ธ Context size estimation failed:', error);
total = 50000; // Conservative fallback
}
return { total, codeSize, technicalFiles, complexTopics };
}
/**
* Calculate comprehensive risk score
*/
async calculateRiskScore() {
const factors = {};
let totalScore = 0;
let weightSum = 0;
// Context size factor (weight: 40%)
const contextWeight = 0.4;
const contextScore = this.calculateContextSizeRisk();
factors.contextSize = contextScore;
totalScore += contextScore * contextWeight;
weightSum += contextWeight;
// Conversation length factor (weight: 25%)
const conversationWeight = 0.25;
const conversationScore = this.calculateConversationLengthRisk();
factors.conversationLength = conversationScore;
totalScore += conversationScore * conversationWeight;
weightSum += conversationWeight;
// Technical complexity factor (weight: 20%)
const complexityWeight = 0.2;
const complexityScore = this.calculateComplexityRisk();
factors.technicalComplexity = complexityScore;
totalScore += complexityScore * complexityWeight;
weightSum += complexityWeight;
// Time active factor (weight: 15%)
const timeWeight = 0.15;
const timeScore = this.calculateTimeActiveRisk();
factors.timeActive = timeScore;
totalScore += timeScore * timeWeight;
weightSum += timeWeight;
// Pattern-based multipliers
const patterns = this.detectCompactionPatterns();
let patternMultiplier = 1.0;
factors.detectedPatterns = patterns.map(p => p.name);
for (const pattern of patterns) {
patternMultiplier *= pattern.riskMultiplier;
}
totalScore *= patternMultiplier;
// Determine risk level
let level = 'low';
if (totalScore >= 80) level = 'critical';
else if (totalScore >= 60) level = 'high';
else if (totalScore >= 40) level = 'medium';
// Update statistics
this.updateRiskStatistics(totalScore);
return {
score: Math.round(totalScore),
level,
factors,
patternMultiplier,
trend: this.calculateTrend()
};
}
/**
* Calculate context size risk component
*/
calculateContextSizeRisk() {
const size = this.conversationMetrics.estimatedContextSize;
const thresholds = this.riskThresholds.contextSize;
if (size >= thresholds.critical) return 100;
if (size >= thresholds.high) return 80;
if (size >= thresholds.medium) return 60;
if (size >= thresholds.low) return 40;
return 20;
}
/**
* Calculate conversation length risk component
*/
calculateConversationLengthRisk() {
const turns = this.conversationMetrics.conversationTurns;
const thresholds = this.riskThresholds.conversationTurns;
if (turns >= thresholds.critical) return 100;
if (turns >= thresholds.high) return 80;
if (turns >= thresholds.medium) return 60;
if (turns >= thresholds.low) return 40;
return 20;
}
/**
* Calculate technical complexity risk component
*/
calculateComplexityRisk() {
const complexity = this.conversationMetrics.codeDiscussed +
(this.conversationMetrics.technicalDepth * 1000) +
(this.conversationMetrics.complexTopics * 2000);
const thresholds = this.riskThresholds.codeComplexity;
if (complexity >= thresholds.critical) return 100;
if (complexity >= thresholds.high) return 80;
if (complexity >= thresholds.medium) return 60;
if (complexity >= thresholds.low) return 40;
return 20;
}
/**
* Calculate time active risk component
*/
calculateTimeActiveRisk() {
const activeTime = Date.now() - this.conversationMetrics.sessionStartTime;
const thresholds = this.riskThresholds.timeActive;
if (activeTime >= thresholds.critical) return 100;
if (activeTime >= thresholds.high) return 80;
if (activeTime >= thresholds.medium) return 60;
if (activeTime >= thresholds.low) return 40;
return 20;
}
/**
* Detect compaction risk patterns
*/
detectCompactionPatterns(indicators = null) {
const detected = [];
// Use provided indicators or analyze current state
const currentIndicators = indicators || this.getCurrentActivityIndicators();
for (const pattern of this.compactionPatterns) {
let matches = 0;
for (const indicator of pattern.indicators) {
if (currentIndicators.includes(indicator)) {
matches++;
}
}
// Pattern detected if majority of indicators match
if (matches >= Math.ceil(pattern.indicators.length / 2)) {
detected.push(pattern);
}
}
return detected;
}
/**
* Get current activity indicators
*/
getCurrentActivityIndicators() {
const indicators = [];
if (this.conversationMetrics.estimatedContextSize > 50000) {
indicators.push('high context size');
}
if (this.conversationMetrics.codeDiscussed > 5000) {
indicators.push('many code examples');
}
if (this.conversationMetrics.technicalDepth > 5) {
indicators.push('complex explanations');
}
if (this.conversationMetrics.conversationTurns > 50) {
indicators.push('extended discussion');
}
return indicators;
}
/**
* Predict compaction risk based on historical data
*/
predictCompactionRisk(history = null) {
const data = history || this.riskHistory;
if (data.length < 3) {
return {
timeToCompaction: null,
confidence: 0.1,
trend: 'insufficient_data'
};
}
// Calculate trend
const recent = data.slice(-5);
const scores = recent.map(d => d.score);
const trend = this.calculateTrendFromScores(scores);
// Predict time to compaction based on trend
let timeToCompaction = null;
let confidence = 0.5;
if (trend === 'increasing') {
const rateOfIncrease = this.calculateIncreaseRate(scores);
const currentScore = scores[scores.length - 1];
const scoreToCompaction = 100 - currentScore;
if (rateOfIncrease > 0) {
timeToCompaction = (scoreToCompaction / rateOfIncrease) * 30000; // 30 seconds per analysis
confidence = Math.min(0.9, 0.5 + (rateOfIncrease / 100));
}
}
return {
timeToCompaction,
confidence,
trend,
currentTrajectory: scores
};
}
/**
* Calculate trend from score array
*/
calculateTrendFromScores(scores) {
if (scores.length < 2) return 'stable';
let increases = 0;
let decreases = 0;
for (let i = 1; i < scores.length; i++) {
if (scores[i] > scores[i-1]) increases++;
else if (scores[i] < scores[i-1]) decreases++;
}
if (increases > decreases) return 'increasing';
if (decreases > increases) return 'decreasing';
return 'stable';
}
/**
* Calculate rate of increase
*/
calculateIncreaseRate(scores) {
if (scores.length < 2) return 0;
const first = scores[0];
const last = scores[scores.length - 1];
const periods = scores.length - 1;
return (last - first) / periods;
}
/**
* Calculate overall trend
*/
calculateTrend() {
if (this.riskHistory.length < 3) return 'stable';
const recent = this.riskHistory.slice(-5);
const scores = recent.map(d => d.score);
return this.calculateTrendFromScores(scores);
}
/**
* Handle risk level changes
*/
async handleRiskLevelChange(newRiskAssessment) {
const oldLevel = this.currentRisk.level;
const newLevel = newRiskAssessment.level;
if (oldLevel !== newLevel) {
console.log(`๐ Risk level changed: ${oldLevel} โ ${newLevel} (score: ${newRiskAssessment.score})`);
// Update statistics
if (this.getRiskLevelNumber(newLevel) > this.getRiskLevelNumber(oldLevel)) {
this.stats.riskEscalations++;
}
// Trigger callbacks
if (this.callbacks.onRiskChange) {
this.callbacks.onRiskChange(newLevel, oldLevel, newRiskAssessment);
}
if (newLevel === 'critical' && this.callbacks.onCompactionThreat) {
this.callbacks.onCompactionThreat(newRiskAssessment);
}
// Implement response protocol
await this.implementResponseProtocol(newLevel, newRiskAssessment);
}
}
/**
* Get numeric value for risk level
*/
getRiskLevelNumber(level) {
const levels = { low: 1, medium: 2, high: 3, critical: 4 };
return levels[level] || 0;
}
/**
* Implement response protocol for risk level
*/
async implementResponseProtocol(level, riskAssessment) {
const protocol = this.responseProtocols[level];
if (!protocol) return;
console.log(`๐ฏ Implementing ${level} risk protocol`);
for (const action of protocol.actions) {
try {
await this.executeRiskAction(action, riskAssessment);
} catch (error) {
console.error(`โ ๏ธ Failed to execute risk action ${action}:`, error);
}
}
}
/**
* Execute specific risk mitigation action
*/
async executeRiskAction(action, riskAssessment) {
switch (action) {
case 'routine_preservation':
console.log('๐พ Routine preservation triggered');
break;
case 'increased_preservation':
console.log('๐พ Increased preservation frequency');
if (this.callbacks.onEmergencyPreservation) {
this.callbacks.onEmergencyPreservation('increased_frequency');
}
break;
case 'emergency_backup':
console.log('๐จ Emergency backup triggered');
if (this.callbacks.onEmergencyPreservation) {
this.callbacks.onEmergencyPreservation('emergency_backup');
}
break;
case 'continuous_preservation':
console.log('๐ Continuous preservation mode activated');
if (this.callbacks.onEmergencyPreservation) {
this.callbacks.onEmergencyPreservation('continuous_mode');
}
break;
case 'context_summary':
console.log('๐ Context summarization recommended');
break;
case 'compaction_prevention':
console.log('๐ก๏ธ Compaction prevention measures activated');
this.stats.compactionsPrevented++;
break;
default:
console.warn(`โ ๏ธ Unknown risk action: ${action}`);
}
}
/**
* Update risk statistics
*/
updateRiskStatistics(score) {
if (score > this.stats.maxRiskScore) {
this.stats.maxRiskScore = score;
}
// Update average (exponential moving average)
if (this.stats.averageRiskScore === 0) {
this.stats.averageRiskScore = score;
} else {
this.stats.averageRiskScore =
(this.stats.averageRiskScore * 0.9) + (score * 0.1);
}
}
/**
* Record activity that might affect risk
*/
recordActivity(activityType, details = {}) {
// Update relevant metrics based on activity
switch (activityType) {
case 'file_read':
case 'file_write':
this.conversationMetrics.codeDiscussed += details.fileSize || 1000;
break;
case 'code_generation':
this.conversationMetrics.codeDiscussed += details.linesGenerated * 50 || 2000;
this.conversationMetrics.technicalDepth++;
break;
case 'complex_explanation':
this.conversationMetrics.complexTopics++;
break;
case 'error_analysis':
this.conversationMetrics.technicalDepth++;
break;
}
this.conversationMetrics.lastActivity = Date.now();
}
/**
* Get current risk assessment
*/
getCurrentRisk() {
return { ...this.currentRisk };
}
/**
* Get risk statistics
*/
getStats() {
return {
...this.stats,
isAnalyzing: this.isAnalyzing,
currentRiskLevel: this.currentRisk.level,
currentRiskScore: this.currentRisk.score,
riskHistoryLength: this.riskHistory.length,
conversationMetrics: { ...this.conversationMetrics }
};
}
/**
* Get test results
*/
getTestResults() {
return this.testResults;
}
/**
* Set callback functions
*/
setCallbacks(callbacks) {
this.callbacks = { ...this.callbacks, ...callbacks };
}
/**
* Save risk analysis report
*/
async saveRiskReport() {
const report = {
timestamp: Date.now(),
finalRiskAssessment: this.currentRisk,
riskHistory: this.riskHistory,
conversationMetrics: this.conversationMetrics,
statistics: this.stats,
testResults: this.testResults
};
try {
const reportsDir = path.join(this.projectRoot, 'docs/live-protection/risk-reports');
await fs.mkdir(reportsDir, { recursive: true });
const filename = `risk-report-${Date.now()}.json`;
const reportPath = path.join(reportsDir, filename);
await fs.writeFile(reportPath, JSON.stringify(report, null, 2));
console.log(`๐ Risk analysis report saved: ${filename}`);
} catch (error) {
console.warn('โ ๏ธ Could not save risk report:', error.message);
}
}
/**
* Force risk analysis (for testing)
*/
async forceRiskAnalysis() {
await this.performRiskAnalysis();
return this.getCurrentRisk();
}
/**
* Cleanup resources
*/
async cleanup() {
await this.stop();
}
}
module.exports = CompactionRiskAnalyzer;
// Auto-execute if run directly
if (require.main === module) {
const analyzer = new CompactionRiskAnalyzer();
// Set up callbacks
analyzer.setCallbacks({
onRiskChange: (newLevel, oldLevel, assessment) => {
console.log(`๐ Risk changed: ${oldLevel} โ ${newLevel} (score: ${assessment.score})`);
},
onCompactionThreat: (assessment) => {
console.log(`๐จ COMPACTION THREAT DETECTED! Score: ${assessment.score}`);
},
onEmergencyPreservation: (reason) => {
console.log(`๐พ Emergency preservation: ${reason}`);
}
});
process.on('SIGINT', async () => {
console.log('\n๐ Shutting down risk analyzer...');
await analyzer.cleanup();
process.exit(0);
});
analyzer.start()
.then(async () => {
console.log('๐ Risk analyzer running. Press Ctrl+C to stop.');
// Simulate some activity for testing
setTimeout(() => {
analyzer.recordActivity('code_generation', { linesGenerated: 100 });
console.log('๐งช Simulated code generation activity');
}, 2000);
setTimeout(() => {
analyzer.recordActivity('complex_explanation');
console.log('๐งช Simulated complex explanation activity');
}, 5000);
// Force analysis after activity
setTimeout(async () => {
const risk = await analyzer.forceRiskAnalysis();
console.log('๐ Current risk assessment:', risk);
}, 8000);
// Show stats periodically
setInterval(() => {
const stats = analyzer.getStats();
console.log(`๐ Stats - Risk: ${stats.currentRiskLevel} (${stats.currentRiskScore}), Analyses: ${stats.totalAnalyses}`);
}, 30000);
})
.catch(error => {
console.error('โ Failed to start risk analyzer:', error);
process.exit(1);
});
}