UNPKG

@claude-vector/core

Version:

Core vector search engine for code intelligence

1,503 lines (1,303 loc) 74.6 kB
/** * Advanced Vector Engine - AI駆動開発に最適化された次世代ベクトル検索エンジン * * 統合機能: * - セマンティックチャンキング(AST-based) * - AI最適化メタデータ管理 * - 増分インデックス更新 * - 開発フェーズ適応 * - Claude最適化プロンプト生成 * - 高度な関連性スコアリング */ import { VectorSearchEngine } from './engine.js'; import { SemanticChunker } from './semantic-chunker.js'; import { AIMetadataManager } from './ai-metadata-manager.js'; import { IncrementalIndexer } from './incremental-indexer.js'; import { DevelopmentPhaseDetector } from './development-phase-detector.js'; import { ClaudePromptOptimizer } from './claude-prompt-optimizer.js'; import { AdvancedRelevanceScorer } from './advanced-relevance-scorer.js'; import { PerformanceProfiler, defaultProfiler } from './performance-profiler.js'; import { MemoryMonitor, defaultMemoryMonitor } from './memory-monitor.js'; import { IndexIntegrityManager } from './index-integrity-manager.js'; import { GracefulShutdownManager } from './graceful-shutdown-manager.js'; import { EventEmitter } from 'events'; export class AdvancedVectorEngine extends EventEmitter { constructor(options = {}) { super(); this.options = { // AI最適化設定 aiOptimization: options.aiOptimization ?? true, semanticChunking: options.semanticChunking ?? true, phaseAdaptation: options.phaseAdaptation ?? true, claudeOptimization: options.claudeOptimization ?? true, // パフォーマンス設定 incrementalIndexing: options.incrementalIndexing ?? true, realTimeUpdates: options.realTimeUpdates ?? false, cacheEnabled: options.cacheEnabled ?? true, // 学習設定 learningEnabled: options.learningEnabled ?? true, feedbackIntegration: options.feedbackIntegration ?? true, // デバッグ設定 verboseLogging: options.verboseLogging ?? false, performanceMonitoring: options.performanceMonitoring ?? true, // パフォーマンスプロファイリング設定 detailedProfiling: options.detailedProfiling ?? false, profilingLevel: options.profilingLevel ?? 'standard', // 'basic', 'standard', 'detailed', 'profiling' profilingOutputFile: options.profilingOutputFile ?? './.claude-performance.json', // メモリ監視設定 memoryMonitoring: options.memoryMonitoring ?? true, memoryAlertThresholdMB: options.memoryAlertThresholdMB ?? 500, memoryLeakThresholdMB: options.memoryLeakThresholdMB ?? 100, memoryMonitoringInterval: options.memoryMonitoringInterval ?? 30000, // 30秒 // インデックス整合性設定 indexIntegrityEnabled: options.indexIntegrityEnabled ?? true, autoBackupEnabled: options.autoBackupEnabled ?? true, autoRecoveryEnabled: options.autoRecoveryEnabled ?? true, integrityCheckOnLoad: options.integrityCheckOnLoad ?? true, maxBackups: options.maxBackups ?? 5, maxRecoveryAttempts: options.maxRecoveryAttempts ?? 3, // グレースフルシャットダウン設定 gracefulShutdownEnabled: options.gracefulShutdownEnabled ?? true, shutdownTimeout: options.shutdownTimeout ?? 30000, forceKillTimeout: options.forceKillTimeout ?? 5000, enableStatePersistence: options.enableStatePersistence ?? true, enableRecovery: options.enableRecovery ?? true, ...options }; // コンポーネントの初期化 this.vectorEngine = new VectorSearchEngine(options); this.semanticChunker = new SemanticChunker(options.semanticChunking || {}); this.metadataManager = new AIMetadataManager(options.aiMetadata || {}); this.phaseDetector = new DevelopmentPhaseDetector(options.phaseDetection || {}); this.promptOptimizer = new ClaudePromptOptimizer(options.claudeOptimization || {}); this.relevanceScorer = new AdvancedRelevanceScorer(options.relevanceScoring || {}); // パフォーマンスプロファイラー初期化 if (this.options.detailedProfiling) { this.profiler = new PerformanceProfiler({ enabled: true, detailLevel: this.options.profilingLevel, outputFile: this.options.profilingOutputFile, realTimeReporting: this.options.verboseLogging, memoryTracking: true }); } else { this.profiler = this.options.performanceMonitoring ? defaultProfiler : null; } // メモリモニター初期化 if (this.options.memoryMonitoring) { this.memoryMonitor = new MemoryMonitor({ enabled: true, monitoringInterval: this.options.memoryMonitoringInterval, alertThresholdMB: this.options.memoryAlertThresholdMB, memoryLeakThresholdMB: this.options.memoryLeakThresholdMB, reportOutputFile: './.claude-memory-report.json', enableGCOptimization: this.options.detailedProfiling, // 詳細プロファイリング時のみGC最適化 verboseLogging: this.options.verboseLogging }); } else { this.memoryMonitor = null; } // インデックス整合性管理 if (this.options.indexIntegrityEnabled) { this.indexIntegrityManager = new IndexIntegrityManager({ enableAutoBackup: this.options.autoBackupEnabled, autoRecoveryEnabled: this.options.autoRecoveryEnabled, maxBackups: this.options.maxBackups, maxRecoveryAttempts: this.options.maxRecoveryAttempts, verboseLogging: this.options.verboseLogging }); } else { this.indexIntegrityManager = null; } // グレースフルシャットダウン管理 if (this.options.gracefulShutdownEnabled) { this.gracefulShutdownManager = new GracefulShutdownManager({ shutdownTimeout: this.options.shutdownTimeout, forceKillTimeout: this.options.forceKillTimeout, enableStatePersistence: this.options.enableStatePersistence, enableRecovery: this.options.enableRecovery, verboseLogging: this.options.verboseLogging, stateFile: './.claude-engine-state.json', logFile: './.claude-engine-shutdown.log' }); } else { this.gracefulShutdownManager = null; } // 増分インデクサーは必要時に初期化 this.incrementalIndexer = null; // 状態管理 this.isInitialized = false; this.projectRoot = null; this.performanceMetrics = { searchCount: 0, totalSearchTime: 0, averageSearchTime: 0, cacheHitRate: 0, indexUpdates: 0 }; // イベントリスナーの設定 this.setupEventListeners(); } /** * イベントリスナーの設定 */ setupEventListeners() { // 開発フェーズ検出のイベント this.phaseDetector.on('phase-detected', (result) => { this.emit('phase-detected', result); if (this.options.verboseLogging) { console.log(`🎯 Phase detected: ${result.phase} (confidence: ${result.confidence.toFixed(2)})`); } }); // 関連性スコアリングのイベント this.relevanceScorer.on('feedback-recorded', (data) => { this.emit('user-feedback', data); if (this.options.verboseLogging) { console.log(`📝 Feedback recorded: ${data.feedbackType} for chunk ${data.chunkId}`); } }); // メモリモニターのイベント if (this.memoryMonitor) { this.memoryMonitor.on('memory_alert', (alert) => { this.emit('memory-alert', alert); if (this.options.verboseLogging) { console.log(`⚠️ Memory Alert: ${alert.type} - ${JSON.stringify(alert.details)}`); } }); this.memoryMonitor.on('alert_resolved', (resolution) => { this.emit('memory-alert-resolved', resolution); if (this.options.verboseLogging) { console.log(`✅ Memory Alert Resolved: ${resolution.type}`); } }); this.memoryMonitor.on('gc_optimization_performed', (data) => { this.emit('gc-optimization', data); if (this.options.verboseLogging) { console.log('♻️ Garbage collection optimization performed'); } }); this.memoryMonitor.on('monitoring_started', (data) => { this.emit('memory-monitoring-started', data); if (this.options.verboseLogging) { console.log(`🔍 Memory monitoring started: ${JSON.stringify(data.options)}`); } }); this.memoryMonitor.on('monitoring_stopped', (data) => { this.emit('memory-monitoring-stopped', data); if (this.options.verboseLogging) { console.log(`🛑 Memory monitoring stopped after ${Math.round(data.duration / 1000)}s`); } }); } // インデックス整合性管理のイベント if (this.indexIntegrityManager) { this.indexIntegrityManager.on('check-completed', (result) => { this.emit('integrity-check-completed', result); if (this.options.verboseLogging) { console.log(`🔍 Integrity check: ${result.isValid ? '✅ Valid' : '❌ Issues found'}`); if (!result.isValid) { console.log(` Corruption level: ${result.corruptionLevel}`); console.log(` Issues: ${result.issues.length}`); } } }); this.indexIntegrityManager.on('recovery-started', (data) => { this.emit('index-recovery-started', data); if (this.options.verboseLogging) { console.log('🔧 Index recovery started'); } }); this.indexIntegrityManager.on('recovery-completed', (result) => { this.emit('index-recovery-completed', result); if (this.options.verboseLogging) { console.log(`🔧 Index recovery: ${result.success ? '✅ Success' : '❌ Failed'}`); console.log(` Strategy: ${result.strategy}`); console.log(` Steps: ${result.steps.length}`); } }); this.indexIntegrityManager.on('backup-created', (result) => { this.emit('index-backup-created', result); if (this.options.verboseLogging) { console.log(`💾 Index backup created: ${result.timestamp}`); console.log(` Size: ${Math.round(result.size / 1024)}KB`); } }); this.indexIntegrityManager.on('rebuild-requested', (data) => { this.emit('index-rebuild-requested', data); if (this.options.verboseLogging) { console.log('🔨 Index rebuild requested due to corruption'); } }); } // グレースフルシャットダウンのイベント if (this.gracefulShutdownManager) { this.gracefulShutdownManager.on('shutdown-initiated', (data) => { this.emit('shutdown-initiated', data); if (this.options.verboseLogging) { console.log(`🛑 Engine shutdown initiated: ${data.reason}`); } }); this.gracefulShutdownManager.on('shutdown-phase-started', (phase) => { this.emit('shutdown-phase-started', phase); if (this.options.verboseLogging) { console.log(`📋 Shutdown phase: ${phase.name}`); } }); this.gracefulShutdownManager.on('shutdown-completed', (result) => { this.emit('shutdown-completed', result); if (this.options.verboseLogging) { console.log(`✅ Engine shutdown completed in ${result.duration}ms`); } }); this.gracefulShutdownManager.on('forced-shutdown', (data) => { this.emit('forced-shutdown', data); if (this.options.verboseLogging) { console.log('🚨 Engine forced shutdown due to timeout'); } }); this.gracefulShutdownManager.on('recovery-available', (data) => { this.emit('recovery-available', data); if (this.options.verboseLogging) { console.log('🔄 Recovery state available from previous session'); } }); // 重要なクリーンアップハンドラーの登録 this.setupCriticalCleanupHandlers(); } // 増分インデクサーのイベント(初期化後に設定) this.on('indexer-initialized', () => { if (this.incrementalIndexer) { this.incrementalIndexer.on('file-changed', (data) => { this.emit('file-changed', data); }); this.incrementalIndexer.on('index-saved', (data) => { this.performanceMetrics.indexUpdates++; this.emit('index-updated', data); }); } }); } /** * 重要なクリーンアップハンドラーの設定 */ setupCriticalCleanupHandlers() { if (!this.gracefulShutdownManager) return; // メモリ監視の停止(重要) this.gracefulShutdownManager.registerCleanupHandler( 'memory-monitor-stop', async () => { if (this.memoryMonitor) { await this.memoryMonitor.stopMonitoring(); if (this.options.verboseLogging) { console.log('🔧 Memory monitoring stopped'); } } }, 'critical' ); // インデックス整合性チェック停止(重要) this.gracefulShutdownManager.registerCleanupHandler( 'index-integrity-cleanup', async () => { if (this.indexIntegrityManager) { this.indexIntegrityManager.cleanup(); if (this.options.verboseLogging) { console.log('🔧 Index integrity manager cleaned up'); } } }, 'critical' ); // 増分インデクサーの停止(重要) this.gracefulShutdownManager.registerCleanupHandler( 'incremental-indexer-stop', async () => { if (this.incrementalIndexer) { await this.incrementalIndexer.stop(); if (this.options.verboseLogging) { console.log('🔧 Incremental indexer stopped'); } } }, 'critical' ); // プロファイラーの停止と保存(重要) this.gracefulShutdownManager.registerCleanupHandler( 'profiler-save', async () => { if (this.profiler) { const stats = this.profiler.getSessionStats(); if (stats.totalSessions > 0) { await this.profiler.saveReport(); if (this.options.verboseLogging) { console.log('🔧 Performance profiler data saved'); } } } }, 'critical' ); // 現在の操作状態の保存(重要) this.gracefulShutdownManager.registerCleanupHandler( 'save-engine-state', async () => { const currentState = { isInitialized: this.isInitialized, projectRoot: this.projectRoot, performanceMetrics: this.performanceMetrics, timestamp: new Date().toISOString(), vectorEngineLoaded: !!(this.vectorEngine.embeddings && this.vectorEngine.chunks) }; try { await this.gracefulShutdownManager.persistCurrentState(currentState); if (this.options.verboseLogging) { console.log('🔧 Engine state saved for recovery'); } } catch (error) { console.warn('⚠️ Failed to save engine state:', error.message); } }, 'critical' ); // ベクトルエンジンの一時データクリーンアップ(通常) this.gracefulShutdownManager.registerCleanupHandler( 'vector-engine-cleanup', async () => { if (this.vectorEngine) { // キャッシュクリア等 if (typeof this.vectorEngine.clearCache === 'function') { this.vectorEngine.clearCache(); } if (this.options.verboseLogging) { console.log('🔧 Vector engine cleaned up'); } } }, 'normal' ); // イベントリスナーのクリーンアップ(通常) this.gracefulShutdownManager.registerCleanupHandler( 'event-listeners-cleanup', async () => { this.removeAllListeners(); if (this.options.verboseLogging) { console.log('🔧 Event listeners cleaned up'); } }, 'normal' ); } /** * アクティブな操作の登録 */ registerActiveOperation(operationId, operationType, metadata = {}) { if (this.gracefulShutdownManager) { this.gracefulShutdownManager.registerActiveOperation(operationId, { type: operationType, startTime: Date.now(), metadata, engine: 'AdvancedVectorEngine' }); } } /** * アクティブな操作の完了 */ completeActiveOperation(operationId, result = {}) { if (this.gracefulShutdownManager) { this.gracefulShutdownManager.completeActiveOperation(operationId, result); } } /** * エンジンの初期化 */ async initialize(projectRoot, options = {}) { const startTime = Date.now(); try { this.projectRoot = projectRoot; // 除外パターンをオプションから設定 if (options.excludePatterns) { this.excludePatterns = options.excludePatterns; if (this.options.verboseLogging) { console.log(`📌 Custom exclude patterns set: ${options.excludePatterns.length} patterns`); } } if (this.options.verboseLogging) { console.log('🚀 Initializing Advanced Vector Engine...'); console.log(` Project: ${projectRoot}`); console.log(` AI Optimization: ${this.options.aiOptimization}`); console.log(` Incremental Indexing: ${this.options.incrementalIndexing}`); } // メモリ監視開始 if (this.memoryMonitor && this.options.memoryMonitoring) { this.memoryMonitor.startMonitoring({ operation: 'engine_initialization', projectRoot: this.projectRoot, aiOptimization: this.options.aiOptimization, incrementalIndexing: this.options.incrementalIndexing }); } // 基本ベクトルエンジンの初期化は後で行う(インデックス読み込み時) // 増分インデクサーの初期化(オプション) if (this.options.incrementalIndexing) { this.incrementalIndexer = new IncrementalIndexer({ ...options.incrementalIndexing, enableRealtime: this.options.realTimeUpdates }); await this.incrementalIndexer.initialize(projectRoot); this.emit('indexer-initialized'); } this.isInitialized = true; const initTime = Date.now() - startTime; this.emit('initialized', { projectRoot, initializationTime: initTime, features: { aiOptimization: this.options.aiOptimization, semanticChunking: this.options.semanticChunking, phaseAdaptation: this.options.phaseAdaptation, incrementalIndexing: !!this.incrementalIndexer } }); if (this.options.verboseLogging) { console.log(`✅ Advanced Vector Engine initialized in ${initTime}ms`); } return { success: true, initializationTime: initTime, features: Object.keys(this.options).filter(key => this.options[key] === true) }; } catch (error) { console.error('❌ Failed to initialize Advanced Vector Engine:', error); throw error; } } /** * インデックスの読み込み */ async loadIndex(embeddingsPath, chunksPath, metadataPath = null) { if (!this.isInitialized) { throw new Error('Engine not initialized. Call initialize() first.'); } const operationId = `loadIndex_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; // アクティブ操作の登録 this.registerActiveOperation(operationId, 'loadIndex', { embeddingsPath, chunksPath, metadataPath, aiOptimization: this.options.aiOptimization }); // プロファイリング開始 const sessionId = this.profiler?.startSession('loadIndex', { embeddingsPath, chunksPath, metadataPath, aiOptimization: this.options.aiOptimization }); const startTime = Date.now(); // メモリ監視スナップショット(読み込み開始前) if (this.memoryMonitor) { this.memoryMonitor.recordMemorySnapshot('loadIndex_start', { embeddingsPath, chunksPath, metadataPath }); } try { // 基本ベクトルエンジンにインデックスを読み込み(詳細測定) let loadResult; if (this.profiler) { const opId = this.profiler.startOperation('vectorEngine.loadIndex'); loadResult = await this.profiler.measureFileIO('load-embeddings', embeddingsPath, async () => { return await this.vectorEngine.loadIndex(embeddingsPath, chunksPath); }); this.profiler.endOperation(opId, { embeddingsCount: loadResult.embeddings?.length || 0, chunksCount: loadResult.chunks?.length || 0 }); } else { loadResult = await this.vectorEngine.loadIndex(embeddingsPath, chunksPath); } // メタデータの読み込み(存在する場合) let metadataResult = null; if (metadataPath) { try { if (this.profiler) { const metaOpId = this.profiler.startOperation('metadata.load'); metadataResult = await this.metadataManager.loadMetadata(this.projectRoot); this.profiler.endOperation(metaOpId); } else { metadataResult = await this.metadataManager.loadMetadata(this.projectRoot); } if (this.options.verboseLogging) { console.log('📊 AI metadata loaded successfully'); } } catch (error) { console.warn('⚠️ AI metadata not found, will generate on demand'); } } // インデックス整合性チェック(オプション) if (this.indexIntegrityManager && this.options.integrityCheckOnLoad) { try { const indexPaths = [embeddingsPath, chunksPath]; if (metadataPath) indexPaths.push(metadataPath); const integrityResult = await this.indexIntegrityManager.checkIndexIntegrity(indexPaths, { type: 'post_load_verification', loadResult, metadataResult }); if (!integrityResult.isValid) { this.emit('integrity-check-failed', integrityResult); if (this.options.verboseLogging) { console.warn(`⚠️ Index integrity issues detected (${integrityResult.corruptionLevel})`); console.warn(` Issues: ${integrityResult.issues.length}`); if (integrityResult.recommendations.length > 0) { console.warn(` Recommendations: ${integrityResult.recommendations.join(', ')}`); } } } } catch (integrityError) { if (this.options.verboseLogging) { console.warn('⚠️ Index integrity check failed:', integrityError.message); } this.emit('integrity-check-error', { error: integrityError }); } } const loadTime = Date.now() - startTime; // プロファイリング終了 const session = this.profiler?.endSession({ operation: 'loadIndex', success: true, totalTime: loadTime, embeddingsCount: loadResult.embeddings?.length || 0, chunksCount: loadResult.chunks?.length || 0, metadataLoaded: !!metadataResult }); // メモリ監視スナップショット(読み込み完了後) if (this.memoryMonitor) { this.memoryMonitor.recordMemorySnapshot('loadIndex_complete', { loadTime, embeddingsCount: loadResult.embeddings?.length || 0, chunksCount: loadResult.chunks?.length || 0, aiMetadataAvailable: !!metadataPath }); } this.emit('index-loaded', { ...loadResult, loadTime, aiMetadataAvailable: !!metadataPath, performanceSession: session?.id }); const result = { ...loadResult, loadTime, aiOptimized: this.options.aiOptimization, performanceSession: session?.id }; // アクティブ操作の完了 this.completeActiveOperation(operationId, { success: true, loadTime, embeddingsCount: loadResult.embeddings?.length || 0, chunksCount: loadResult.chunks?.length || 0 }); return result; } catch (error) { // エラー時もプロファイリング終了 this.profiler?.endSession({ operation: 'loadIndex', success: false, error: error.message }); // アクティブ操作の完了(エラー) this.completeActiveOperation(operationId, { success: false, error: error.message }); console.error('❌ Failed to load index:', error); throw error; } } /** * AI駆動検索 */ async search(query, options = {}) { if (!this.vectorEngine.embeddings || !this.vectorEngine.chunks) { throw new Error('Index not loaded. Call loadIndex() first.'); } const operationId = `search_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; // アクティブ操作の登録 this.registerActiveOperation(operationId, 'search', { query, options, aiOptimization: this.options.aiOptimization, claudeOptimization: this.options.claudeOptimization, phaseAdaptation: this.options.phaseAdaptation }); // プロファイリング開始 const sessionId = this.profiler?.startSession('search', { query, options, aiOptimization: this.options.aiOptimization, claudeOptimization: this.options.claudeOptimization, phaseAdaptation: this.options.phaseAdaptation }); const searchStartTime = Date.now(); this.performanceMetrics.searchCount++; // メモリ監視スナップショット(検索毎10回に1回、または詳細プロファイリング時) if (this.memoryMonitor && (this.options.detailedProfiling || this.performanceMetrics.searchCount % 10 === 0)) { this.memoryMonitor.recordMemorySnapshot('search_execution', { query: query.substring(0, 50), // クエリの最初の50文字のみ searchCount: this.performanceMetrics.searchCount, options: Object.keys(options) }); } try { // 開発フェーズの検出(プロファイリング) let phaseContext = {}; if (this.options.phaseAdaptation) { let phaseResult; if (this.profiler) { const phaseOpId = this.profiler.startOperation('phase.detection'); phaseResult = this.phaseDetector.detectPhase(query, options.context || {}); this.profiler.endOperation(phaseOpId, { detectedPhase: phaseResult.context.phase }); } else { phaseResult = this.phaseDetector.detectPhase(query, options.context || {}); } phaseContext = phaseResult.context; // フェーズ適応パラメータをオプションに統合 options = { ...options, ...phaseResult.strategy, searchThreshold: phaseResult.optimization.searchThreshold || options.searchThreshold, maxResults: phaseResult.optimization.maxResults || options.maxResults }; } // 基本検索の実行(プロファイリング) let baseResults; if (this.profiler) { const searchOpId = this.profiler.startOperation('vector.search'); baseResults = await this.vectorEngine.search(query, options); this.profiler.endOperation(searchOpId, { resultCount: baseResults.results?.length || 0, searchThreshold: options.searchThreshold, maxResults: options.maxResults }); } else { baseResults = await this.vectorEngine.search(query, options); } // AI最適化処理(プロファイリング) let enhancedResults = baseResults; if (this.options.aiOptimization) { if (this.profiler) { const aiOpId = this.profiler.startOperation('ai.enhancement'); enhancedResults = await this.enhanceSearchResults( baseResults, query, phaseContext, options ); this.profiler.endOperation(aiOpId, { originalCount: baseResults.results?.length || 0, enhancedCount: enhancedResults.results?.length || 0 }); } else { enhancedResults = await this.enhanceSearchResults( baseResults, query, phaseContext, options ); } } // Claude最適化フォーマット(プロファイリング) let claudeOptimizedResults = enhancedResults; if (this.options.claudeOptimization) { if (this.profiler) { const claudeOpId = this.profiler.startOperation('claude.optimization'); claudeOptimizedResults = await this.optimizeForClaude( enhancedResults, query, phaseContext ); this.profiler.endOperation(claudeOpId, { optimizedResultCount: claudeOptimizedResults.results?.length || 0 }); } else { claudeOptimizedResults = await this.optimizeForClaude( enhancedResults, query, phaseContext ); } } const searchTime = Date.now() - searchStartTime; this.updatePerformanceMetrics(searchTime); // プロファイリング終了 const session = this.profiler?.endSession({ operation: 'search', success: true, totalTime: searchTime, query, resultCount: claudeOptimizedResults.results?.length || 0, phaseDetected: phaseContext.phase || 'unknown', aiEnhanced: this.options.aiOptimization, claudeOptimized: this.options.claudeOptimization }); // 結果の拡張 const finalResults = { ...claudeOptimizedResults, aiEnhanced: this.options.aiOptimization, claudeOptimized: this.options.claudeOptimization, phaseContext: phaseContext, searchTime, performanceMetrics: this.getPerformanceSnapshot(), performanceSession: session?.id }; this.emit('search-completed', { query, resultCount: finalResults.results.length, searchTime, phaseDetected: phaseContext.phase || 'unknown', performanceSession: session?.id }); // アクティブ操作の完了 this.completeActiveOperation(operationId, { success: true, searchTime, resultCount: finalResults.results.length, phaseDetected: phaseContext.phase || 'unknown' }); return finalResults; } catch (error) { // エラー時もプロファイリング終了 this.profiler?.endSession({ operation: 'search', success: false, error: error.message, query }); // アクティブ操作の完了(エラー) this.completeActiveOperation(operationId, { success: false, error: error.message, query }); console.error('❌ Search failed:', error); this.emit('search-error', { query, error: error.message }); throw error; } } /** * 検索結果のAI最適化 */ async enhanceSearchResults(baseResults, query, phaseContext, options) { if (!baseResults.results || baseResults.results.length === 0) { return baseResults; } const enhancedResults = []; for (const result of baseResults.results) { try { // 安全性チェック:結果の構造を確認 if (!result || !result.chunk || !result.chunk.metadata) { console.warn(`⚠️ Invalid result structure, skipping enhancement`); enhancedResults.push(result); continue; } // 高度な関連性スコアリング const scoringResult = await this.relevanceScorer.calculateRelevanceScore( query, result.chunk, { ...phaseContext, query, projectRoot: this.projectRoot } ); // AI最適化メタデータの生成(必要に応じて) let aiMetadata = result.chunk.metadata; if (!aiMetadata.aiContext || !aiMetadata.semantic) { aiMetadata = await this.metadataManager.generateAIMetadata( result.chunk, result.chunk.metadata.file || 'unknown', phaseContext ); } // 結果の拡張 enhancedResults.push({ ...result, score: scoringResult.finalScore, aiScoring: { originalScore: result.score, enhancedScore: scoringResult.finalScore, dimensionScores: scoringResult.dimensionScores, weights: scoringResult.weights }, chunk: { ...result.chunk, metadata: aiMetadata } }); } catch (error) { console.warn(`⚠️ Failed to enhance result for chunk:`, error.message); // エラーの場合は元の結果を保持 enhancedResults.push(result); } } // 新しいスコアでソート enhancedResults.sort((a, b) => (b.score || 0) - (a.score || 0)); return { ...baseResults, results: enhancedResults, aiEnhanced: true, enhancementInfo: { originalResultCount: baseResults.results.length, enhancedResultCount: enhancedResults.length, averageScoreImprovement: this.calculateScoreImprovement(baseResults.results, enhancedResults) } }; } /** * Claude最適化 */ async optimizeForClaude(searchResults, query, phaseContext) { if (!searchResults.results || searchResults.results.length === 0) { return searchResults; } const claudeContext = { query, phase: phaseContext.phase, projectRoot: this.projectRoot, timestamp: Date.now() }; // 個別チャンクの最適化(安全性チェック付き) const optimizedResults = searchResults.results.map(result => { try { return { ...result, claudeFormatted: this.promptOptimizer.formatForClaude(result.chunk, claudeContext) }; } catch (error) { console.warn(`⚠️ Failed to optimize result for Claude: ${error.message}`); return { ...result, claudeFormatted: { content: result?.content || 'Content unavailable', metadata: { template: 'error', fallback: true } } }; } }); // 複数チャンクの統合最適化(上位結果のみ) const topResults = optimizedResults.slice(0, Math.min(5, optimizedResults.length)); const topChunks = topResults.map(result => result.chunk); const multiChunkFormat = this.promptOptimizer.formatMultipleChunks(topChunks, claudeContext); return { ...searchResults, results: optimizedResults, claudeOptimized: true, claudeFormats: { individual: optimizedResults.map(r => r.claudeFormatted), combined: multiChunkFormat }, claudeContext }; } /** * スコア改善の計算 */ calculateScoreImprovement(originalResults, enhancedResults) { if (originalResults.length === 0 || enhancedResults.length === 0) { return 0; } const originalAvg = originalResults.reduce((sum, r) => sum + (r.score || 0), 0) / originalResults.length; const enhancedAvg = enhancedResults.reduce((sum, r) => sum + (r.score || 0), 0) / enhancedResults.length; return enhancedAvg - originalAvg; } /** * パフォーマンスメトリクスの更新 */ updatePerformanceMetrics(searchTime) { this.performanceMetrics.totalSearchTime += searchTime; this.performanceMetrics.averageSearchTime = this.performanceMetrics.totalSearchTime / this.performanceMetrics.searchCount; } /** * パフォーマンススナップショットの取得 */ getPerformanceSnapshot() { return { searchCount: this.performanceMetrics.searchCount, averageSearchTime: Math.round(this.performanceMetrics.averageSearchTime), indexUpdates: this.performanceMetrics.indexUpdates, cacheHitRate: this.performanceMetrics.cacheHitRate }; } /** * ユーザーフィードバックの記録 */ recordUserFeedback(chunkId, feedbackType, searchContext = {}) { if (!this.options.feedbackIntegration) { return; } this.relevanceScorer.recordUserFeedback(chunkId, feedbackType, searchContext); this.emit('user-feedback-recorded', { chunkId, feedbackType, searchContext, timestamp: Date.now() }); } /** * プロジェクトの完全なインデックス作成 */ async createFullIndex(filePatterns = null, options = {}) { if (!this.isInitialized) { throw new Error('Engine not initialized. Call initialize() first.'); } const startTime = Date.now(); try { if (this.options.verboseLogging) { console.log('🔨 Creating full AI-optimized index...'); } // ファイルパターンのデフォルト設定 const defaultPatterns = [ '**/*.{js,jsx,ts,tsx}', '**/*.md', '**/README.md', '**/CLAUDE.md' ]; const patterns = filePatterns || defaultPatterns; // ファイルの収集と処理 const { chunks, embeddings, metadata } = await this.processProjectFiles(patterns, options); // インデックスの保存 await this.saveAIOptimizedIndex(chunks, embeddings, metadata); const totalTime = Date.now() - startTime; const result = { success: true, totalChunks: chunks.length, totalFiles: [...new Set(chunks.map(c => c.metadata.file))].length, indexingTime: totalTime, aiOptimized: this.options.aiOptimization, semanticChunking: this.options.semanticChunking }; this.emit('index-created', result); if (this.options.verboseLogging) { console.log(`✅ Full index created: ${result.totalChunks} chunks, ${result.totalFiles} files in ${totalTime}ms`); } return result; } catch (error) { console.error('❌ Failed to create full index:', error); throw error; } } /** * プロジェクトファイルの処理 */ async processProjectFiles(patterns, options) { // この部分は簡略化 - 実際の実装では glob とファイル処理を行う const chunks = []; const embeddings = []; const metadata = {}; // プレースホルダー実装 console.log('📁 Processing project files with patterns:', patterns); return { chunks, embeddings, metadata }; } /** * AI最適化インデックスの保存 */ async saveAIOptimizedIndex(chunks, embeddings, metadata) { // この部分は簡略化 - 実際の実装では AI最適化されたインデックスを保存 console.log('💾 Saving AI-optimized index...'); } /** * 最適化されたインデックスをファイルに保存 */ async saveOptimizedIndex(indexData) { const fs = await import('fs/promises'); const path = await import('path'); if (!this.projectRoot) { throw new Error('Project root not initialized'); } // インデックスディレクトリの決定 const indexDir = path.join(this.projectRoot, '.claude-code-index'); try { // ディレクトリが存在しない場合は作成 await fs.mkdir(indexDir, { recursive: true }); // チャンクファイルを保存 if (indexData.chunks) { const chunksPath = path.join(indexDir, 'chunks.json'); console.log(` 📝 Saving ${indexData.chunks.length} chunks to: ${chunksPath}`); await fs.writeFile(chunksPath, JSON.stringify(indexData.chunks, null, 2)); console.log(` ✅ Chunks saved: ${chunksPath}`); } else { console.warn(' ⚠️ No chunks to save'); } // エンベディングファイルを保存 if (indexData.embeddings) { const embeddingsPath = path.join(indexDir, 'embeddings.json'); console.log(` 📝 Saving ${indexData.embeddings.length} embeddings to: ${embeddingsPath}`); await fs.writeFile(embeddingsPath, JSON.stringify(indexData.embeddings, null, 2)); console.log(` ✅ Embeddings saved: ${embeddingsPath}`); } else { console.warn(' ⚠️ No embeddings to save'); } // メタデータファイルを保存 if (indexData.metadata) { const metadataPath = path.join(indexDir, 'metadata.json'); // ファイルレベルのメタデータを構築(IncrementalIndexerと同様の形式) const fileMetadata = this.buildFileMetadataFromChunks(indexData.chunks); // 完全なメタデータオブジェクトを作成 const completeMetadata = { ...indexData.metadata, totalChunks: indexData.chunks ? indexData.chunks.length : 0, totalFiles: fileMetadata ? Object.keys(fileMetadata).length : 0, incrementalUpdate: true, version: '2.0.0', updatedAt: new Date().toISOString(), files: fileMetadata }; await fs.writeFile(metadataPath, JSON.stringify(completeMetadata, null, 2)); console.log(` ✅ Metadata saved: ${metadataPath}`); } console.log(`💾 AI-optimized index saved successfully to: ${indexDir}`); } catch (error) { console.error('❌ Failed to save optimized index:', error); throw error; } } /** * チャンクからファイルレベルのメタデータを構築 */ buildFileMetadataFromChunks(chunks) { if (!chunks || chunks.length === 0) { return {}; } const fileMetadata = {}; // チャンクからファイルレベルのメタデータを構築 for (const chunk of chunks) { if (chunk.metadata && chunk.metadata.file) { const filePath = chunk.metadata.file; // 実際のチャンクデータ構造に基づいて情報を抽出 const lastModified = chunk.metadata.lastModified || (chunk.development && chunk.development.lastModified) || (chunk.metadata.timestamp && new Date(chunk.metadata.timestamp).getTime()) || null; const size = chunk.metadata.size || chunk.metadata.fileSize || (chunk.development && chunk.development.fileSize) || null; const checksum = chunk.metadata.checksum || chunk.metadata.fileChecksum || (chunk.development && chunk.development.fileChecksum) || null; // ファイルの最新情報を取得(複数のチャンクから同じファイルの場合は最新の情報を使用) if (!fileMetadata[filePath]) { fileMetadata[filePath] = { lastModified: lastModified, size: size, checksum: checksum, chunkCount: 0 }; } else if (lastModified && (!fileMetadata[filePath].lastModified || (typeof lastModified === 'string' ? new Date(lastModified).getTime() : lastModified) > (typeof fileMetadata[filePath].lastModified === 'string' ? new Date(fileMetadata[filePath].lastModified).getTime() : fileMetadata[filePath].lastModified))) { // より新しい情報が利用可能な場合に更新 fileMetadata[filePath].lastModified = lastModified; fileMetadata[filePath].size = size || fileMetadata[filePath].size; fileMetadata[filePath].checksum = checksum || fileMetadata[filePath].checksum; } } } // チャンク数をカウント for (const chunk of chunks) { if (chunk.metadata && chunk.metadata.file && fileMetadata[chunk.metadata.file]) { fileMetadata[chunk.metadata.file].chunkCount++; } } return fileMetadata; } /** * プロジェクトインデックスの作成 */ async createProjectIndex() { if (!this.projectAdapter) { const { ProjectAdapter } = await import('./project-adapter.js'); this.projectAdapter = new ProjectAdapter(this.projectRoot); } if (!this.chunkProcessor) { const { ChunkProcessor } = await import('./chunk-processor.js'); this.chunkProcessor = new ChunkProcessor(); } if (!this.embeddingGenerator) { const { EmbeddingGenerator } = await import('./embedding-generator.js'); this.embeddingGenerator = new EmbeddingGenerator({ openaiApiKey: this.options.openaiApiKey }); } console.log('🔍 Analyzing project structure...'); await this.projectAdapter.analyzeProject(); console.log('📂 Collecting project files...'); const files = await this.collectProjectFiles(); // pathモジュールを動的インポート const path = await import('path'); console.log(`📄 Processing ${files.length} files...`); // デバッグ用: services ディレクトリのファイルをログ出力 const servicesFiles = files.filter(f => f.includes('/services/')); if (servicesFiles.length > 0) { console.log(`🔍 Found ${servicesFiles.length} files in services directories:`); servicesFiles.forEach(f => { console.log(` - ${f.substring(f.lastIndexOf('/') + 1)}`); }); } const chunks = []; let totalFiles = 0; const errorFiles = []; const skippedFiles = []; for (const filePath of files) { // デバッグ用: openweathermap-adapter.ts の処理を追跡 if (filePath.includes('openweathermap-adapter')) { console.log(`🎯 Processing openweathermap-adapter.ts: ${filePath}`); } try { const fs = await import('fs/promises'); const content = await fs.readFile(filePath, 'utf-8'); // ファイル統計情報を取得 const stats = await fs.stat(filePath); const crypto = await import('crypto'); const fileStats = { lastModified: stats.mtime.getTime(), size: stats.size, checksum: crypto.createHash('md5').update(content).digest('hex') }; // セマンティックチャンキングを使用するかどうか let fileChunks; if (this.options.semanticChunking && this.semanticChunker) { fileChunks = await this.semanticChunker.chunkFile(filePath, content); } else { // 標準のチャンク処理 fileChunks = await this.chunkProcessor.processFile(filePath, content); } // ファイル統計情報を各チャンクに追加 for (const chunk of fileChunks) { if (chunk.metadata) { chunk.metadata.lastModified = fileStats.lastModified; chunk.metadata.size = fileStats.size; chunk.metadata.checksum = fileStats.checksum; chunk.metadata.fileSize = fileStats.size; // 追加のファイルサイズフィールド chunk.metadata.fileChecksum = fileStats.checksum; // 追加のチェックサムフィールド } // 開発情報にも追加(フォールバック用) if (!chunk.development) { chunk.development = {}; } chunk.development.lastModified = fileStats.lastModified; chunk.development.fileSize = fileStats.size; chunk.development.fileChecksum = fileStats.checksum; } // チャンクが作成されたかチェック if (fileChunks && fileChunks.length > 0) { chunks.push(...fileChunks); totalFiles++; if (filePath.includes('openweathermap-adapter')) { console.log(`✅ Successfully created ${fileChunks.length} chunks for openweathermap-adapter.ts`); } } else { // チャンクが作成されなかった場合 skippedFiles.push({ path: filePath, reason: 'No chunks created' }); if (filePath.includes('openweathermap-adapter')) { console.warn(`⚠️ No chunks created for openweathermap-adapter.ts`); } } if (totalFiles % 10 === 0) { console.log(` 📄 Processed ${totalFiles}/${files.length} files...`); } } catch (error) { console.error(`❌ Failed to process file ${filePath}: ${error.message}`); errorFiles.push({ path: filePath, error: error.message }); // エラーの詳細情報を記録 if (this.options.verboseLogging) { console.error(` Error stack: ${error.stack}`); } // フォールバック: 最低限の情報でチャンクを作成 try { const fs = await import('fs/promises'); const content = await fs.readFile(filePath, 'utf-8'); const fallbackChunk = { content: content.slice(0, 1000), // 最初の1000文字のみ metadata: { file: filePath, error: true, errorMessage: error.message, chunkingMethod: 'error-fallback', startLine: 1, endLine: content.split('\n').length, size: content.length, tokens: Math.ceil(content.length / 4) } }; chunks.push(fallbackChunk); console.warn(`⚠️ Added fallback chunk for ${filePath}`); } catch (fallbackError) { console.error(`❌ Fallback also failed for ${filePath}: ${fallbackError.message}`); } } } // エラーサマリーの表示 if (errorFiles.length > 0) { console.warn(`\n⚠️ Failed to process ${errorFiles.length} files:`); errorFiles.forEach(({ path, error }) => { console.warn(` - ${path}: ${error}`); }); console.warn(`\n💡 These files were added with fallback chunks or skipped entirely.\n`); } // スキップされたファイルの表示 if (skippedFiles.length > 0) { console.warn(`\n⚠️ Skipped ${skippedFiles.length} files (no chunks created):`); skippedFiles.forEach(({ path, reason }) => { console.warn(` - ${path.substring(path.lastIndexOf('/') + 1)}: ${reason}`); }); } console.log(`🔮 Generating embeddings for ${chunks.length} chunks...`); // 動的パフォーマンス設定 const performanceConfig = this.calculateOptimalSettings(chunks.length); console.log(`⚡ Optimized settings: batch=${performanceConfig.batchSize}, estimated=${performanceConfig.estimatedTime}min`); console.log('⏰ Large projects may take several minutes. Use Ctrl+C to safely cancel.'); const embeddings = []; const batchSize = performanceConfig.batchSize; const startTime = Date.now(); let errorCount = 0; // 進捗保存の設定 const progressFile = path.join(this.projectRoot, '.claude-embedding-progress.json'); const saveInterval = 100; // 100個ごとに保存 for (let i = 0; i < chunks.length; i += batchSize) { const batch = chunks.slice(i, Math.min(i + batchSize, chunks.length)); const batchPromises = []; for (let j = 0; j < batch.length; j++) { const chunkIndex = i + j; const promise = this.embeddingGenerator.generateEmbedding(batch[j].content) .catch(error => { errorCount++; console.warn(`⚠️ Failed to generate embedding for chunk ${chunkIndex}: ${error.message}`); // レート制限検出 if (error.message.includes('429') || error.message.includes('rate limit')) { console.log('⏳ Rate limit detected, will adjust timing...'); } return new Array(1536).fill(0); // ダミーエンベディング }); batchPromises.push(promise); } // バッチを並行処理 const batchResults = await Promise.all(batchPromises); embeddings.push(...batchResults); // 詳細進捗表示とパフォーマンス統計 const progress = Math.min(i + batchSize, chunks.length); const elapsed = ((Date.now() - startTime) / 1000); const rate = (progress / elapsed).toFixed(1); const errorRate = ((errorCount / progress) * 100).toFixed(1); // ETA計算 const remaining = chunks.length - progress; const eta = remaining > 0 ? (remaining / parseFloat(rate)).toFixed(0) : 0; console.log(` 🔮 Generated ${progress}/${chunks.length} embeddings (${elapsed.toFixed(1)}s, ${rate}/s, errors: ${errorRate}%, ETA: ${eta}s)`); // 進捗保存(定