@claude-vector/core
Version:
Core vector search engine for code intelligence
1,503 lines (1,303 loc) • 74.6 kB
JavaScript
/**
* 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)`);
// 進捗保存(定