UNPKG

@aaswe/codebase-ai

Version:

AI-Assisted Software Engineering (AASWE) - Rich codebase context for IDE LLMs

355 lines 13 kB
"use strict"; /** * Trigger Orchestrator * * Orchestrates automatic project analysis triggers from various sources * including NPM hooks, file system changes, and manual triggers. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TriggerOrchestrator = void 0; const events_1 = require("events"); const logger_1 = __importDefault(require("../../utils/logger")); const NPMHookManager_1 = require("./NPMHookManager"); const InstallationDetector_1 = require("./InstallationDetector"); const ProjectAnalysisService_1 = require("../project-analysis/ProjectAnalysisService"); /** * Trigger Orchestrator * * Central coordinator for all automatic analysis triggers. * Manages trigger sources, queuing, and execution coordination. */ class TriggerOrchestrator extends events_1.EventEmitter { config; npmHookManager; installationDetector; projectAnalysisService; isInitialized = false; triggerQueue = []; activeTriggers = new Set(); lastAnalysisTime; triggerHistory = []; constructor(config = {}) { super(); this.config = { projectRoot: process.cwd(), enableNPMHooks: true, enableInstallationDetection: true, enableFileWatching: true, analysisDelay: 2000, maxConcurrentAnalyses: 1, cooldownPeriod: 10000, // 10 seconds ...config }; } /** * Initialize the trigger orchestrator */ async initialize() { if (this.isInitialized) { return; } try { logger_1.default.info('Initializing Trigger Orchestrator', { projectRoot: this.config.projectRoot, enableNPMHooks: this.config.enableNPMHooks, enableInstallationDetection: this.config.enableInstallationDetection }); // Initialize project analysis service this.projectAnalysisService = new ProjectAnalysisService_1.ProjectAnalysisService({ rootPath: this.config.projectRoot, generateTTL: true, enableWatching: this.config.enableFileWatching, preserveBusinessContext: true }); await this.projectAnalysisService.initialize(); // Initialize NPM hook manager if (this.config.enableNPMHooks) { this.npmHookManager = new NPMHookManager_1.NPMHookManager({ projectRoot: this.config.projectRoot, analysisDelay: this.config.analysisDelay }); await this.npmHookManager.initialize(); this.setupNPMHookListeners(); } // Initialize installation detector if (this.config.enableInstallationDetection) { this.installationDetector = new InstallationDetector_1.InstallationDetector({ projectRoot: this.config.projectRoot, debounceDelay: this.config.analysisDelay }); await this.installationDetector.startMonitoring(); this.setupInstallationDetectorListeners(); } // Setup project analysis service listeners this.setupProjectAnalysisListeners(); // Start processing trigger queue this.startTriggerProcessing(); this.isInitialized = true; logger_1.default.info('Trigger Orchestrator initialized successfully'); } catch (error) { logger_1.default.error('Failed to initialize Trigger Orchestrator', { error }); throw error; } } /** * Manually trigger analysis */ async triggerAnalysis(reason = 'manual', priority = 'medium', metadata) { const trigger = { id: this.generateTriggerId(), type: 'manual', timestamp: new Date(), source: 'manual', reason, priority, metadata }; logger_1.default.info('Manual analysis trigger requested', { triggerId: trigger.id, reason, priority }); this.queueTrigger(trigger); return trigger.id; } /** * Get trigger status and statistics */ getStatus() { return { isInitialized: this.isInitialized, config: { ...this.config }, queueLength: this.triggerQueue.length, activeTriggers: this.activeTriggers.size, lastAnalysis: this.lastAnalysisTime, recentTriggers: this.triggerHistory.slice(-10) }; } /** * Shutdown the orchestrator */ async shutdown() { logger_1.default.info('Shutting down Trigger Orchestrator'); try { // Stop NPM hook manager if (this.npmHookManager) { await this.npmHookManager.removeHooks(); } // Stop installation detector if (this.installationDetector) { await this.installationDetector.stopMonitoring(); } // Shutdown project analysis service if (this.projectAnalysisService) { await this.projectAnalysisService.shutdown(); } // Clear queues and active triggers this.triggerQueue = []; this.activeTriggers.clear(); this.isInitialized = false; logger_1.default.info('Trigger Orchestrator shutdown completed'); } catch (error) { logger_1.default.error('Error during Trigger Orchestrator shutdown', { error }); throw error; } } // Private methods setupNPMHookListeners() { if (!this.npmHookManager) return; this.npmHookManager.on('analysis_triggered', (event) => { const trigger = { id: this.generateTriggerId(), type: 'npm_hook', timestamp: event.timestamp, source: `npm_${event.triggeredBy}`, reason: `NPM ${event.type} hook triggered`, priority: 'high', metadata: event }; logger_1.default.debug('NPM hook trigger received', { trigger }); this.queueTrigger(trigger); }); } setupInstallationDetectorListeners() { if (!this.installationDetector) return; this.installationDetector.on('installation_detected', (event) => { if (!event.triggerAnalysis) { logger_1.default.debug('Installation detected but analysis not triggered', { type: event.type, changeCount: event.changes.length }); return; } const trigger = { id: this.generateTriggerId(), type: 'installation', timestamp: event.timestamp, source: `${event.packageManager}_${event.type}`, reason: `Package ${event.type}: ${event.changes.length} changes`, priority: this.determinePriority(event), metadata: event }; logger_1.default.debug('Installation trigger received', { trigger }); this.queueTrigger(trigger); }); } setupProjectAnalysisListeners() { if (!this.projectAnalysisService) return; this.projectAnalysisService.on('analysisCompleted', (result) => { logger_1.default.info('Analysis completed', { analysisId: result.analysisId, duration: result.duration, analyzedFiles: result.summary.analyzedFiles }); this.lastAnalysisTime = result.endTime; this.emit('analysis_completed', result); }); this.projectAnalysisService.on('analysisFailed', (event) => { logger_1.default.error('Analysis failed', { analysisId: event.analysisId, error: event.error }); this.emit('analysis_failed', event); }); } queueTrigger(trigger) { // Check cooldown period if (this.lastAnalysisTime && this.isInCooldownPeriod()) { logger_1.default.debug('Trigger queued due to cooldown period', { triggerId: trigger.id, cooldownRemaining: this.getCooldownRemaining() }); } // Add to queue with priority sorting this.triggerQueue.push(trigger); this.triggerQueue.sort((a, b) => { const priorityOrder = { high: 3, medium: 2, low: 1 }; return priorityOrder[b.priority] - priorityOrder[a.priority]; }); this.emit('trigger_queued', trigger); logger_1.default.debug('Trigger queued', { triggerId: trigger.id, queueLength: this.triggerQueue.length, priority: trigger.priority }); } startTriggerProcessing() { // Process triggers every second setInterval(() => { this.processTriggerQueue(); }, 1000); } async processTriggerQueue() { if (this.triggerQueue.length === 0) { return; } // Check if we can process more triggers if (this.activeTriggers.size >= this.config.maxConcurrentAnalyses) { return; } // Check cooldown period if (this.isInCooldownPeriod()) { return; } // Get next trigger const trigger = this.triggerQueue.shift(); if (!trigger) { return; } // Process trigger await this.processTrigger(trigger); } async processTrigger(trigger) { const startTime = new Date(); this.activeTriggers.add(trigger.id); logger_1.default.info('Processing trigger', { triggerId: trigger.id, type: trigger.type, reason: trigger.reason, priority: trigger.priority }); try { this.emit('trigger_processing', trigger); // Execute analysis const analysisResult = await this.projectAnalysisService.analyzeProject(); const endTime = new Date(); const duration = endTime.getTime() - startTime.getTime(); const result = { triggerId: trigger.id, success: true, analysisId: analysisResult.analysisId, startTime, endTime, duration }; this.triggerHistory.push(result); this.emit('trigger_completed', { trigger, result }); logger_1.default.info('Trigger processed successfully', { triggerId: trigger.id, analysisId: analysisResult.analysisId, duration }); } catch (error) { const endTime = new Date(); const duration = endTime.getTime() - startTime.getTime(); const result = { triggerId: trigger.id, success: false, startTime, endTime, duration, error: error instanceof Error ? error.message : 'Unknown error' }; this.triggerHistory.push(result); this.emit('trigger_failed', { trigger, result, error }); logger_1.default.error('Trigger processing failed', { triggerId: trigger.id, error, duration }); } finally { this.activeTriggers.delete(trigger.id); } } isInCooldownPeriod() { if (!this.lastAnalysisTime) { return false; } const timeSinceLastAnalysis = Date.now() - this.lastAnalysisTime.getTime(); return timeSinceLastAnalysis < this.config.cooldownPeriod; } getCooldownRemaining() { if (!this.lastAnalysisTime) { return 0; } const timeSinceLastAnalysis = Date.now() - this.lastAnalysisTime.getTime(); return Math.max(0, this.config.cooldownPeriod - timeSinceLastAnalysis); } determinePriority(event) { // High priority for new package installations if (event.type === 'package_installed') { return 'high'; } // Medium priority for updates if (event.type === 'package_updated') { return 'medium'; } // Low priority for other changes return 'low'; } generateTriggerId() { return `trigger_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } } exports.TriggerOrchestrator = TriggerOrchestrator; //# sourceMappingURL=TriggerOrchestrator.js.map