UNPKG

code-context-mcp

Version:

MCP server for semantic code search powered by MongoDB Atlas Vector Search and Voyage AI embeddings

192 lines 9.4 kB
import * as fs from "fs"; import * as path from "path"; import * as os from "os"; export class SnapshotManager { snapshotFilePath; indexedCodebases = []; indexingCodebases = new Map(); // Map of codebase path to progress percentage constructor() { // Initialize snapshot file path this.snapshotFilePath = path.join(os.homedir(), '.context', 'mcp-codebase-snapshot.json'); } getIndexedCodebases() { // Read from JSON file to ensure consistency and persistence try { if (!fs.existsSync(this.snapshotFilePath)) { return []; } const snapshotData = fs.readFileSync(this.snapshotFilePath, 'utf8'); const snapshot = JSON.parse(snapshotData); return snapshot.indexedCodebases || []; } catch (error) { console.warn(`[SNAPSHOT-DEBUG] Error reading indexed codebases from file:`, error); // Fallback to memory if file reading fails return [...this.indexedCodebases]; } } getIndexingCodebases() { // Read from JSON file to ensure consistency and persistence try { if (!fs.existsSync(this.snapshotFilePath)) { return []; } const snapshotData = fs.readFileSync(this.snapshotFilePath, 'utf8'); const snapshot = JSON.parse(snapshotData); // Handle both legacy array format and new object format if (Array.isArray(snapshot.indexingCodebases)) { // Legacy format: return the array directly return snapshot.indexingCodebases; } else if (snapshot.indexingCodebases && typeof snapshot.indexingCodebases === 'object') { // New format: return the keys of the object return Object.keys(snapshot.indexingCodebases); } return []; } catch (error) { console.warn(`[SNAPSHOT-DEBUG] Error reading indexing codebases from file:`, error); // Fallback to memory if file reading fails return Array.from(this.indexingCodebases.keys()); } } getIndexingCodebasesWithProgress() { return new Map(this.indexingCodebases); } getIndexingProgress(codebasePath) { // Read from JSON file to ensure consistency and persistence try { if (!fs.existsSync(this.snapshotFilePath)) { return undefined; } const snapshotData = fs.readFileSync(this.snapshotFilePath, 'utf8'); const snapshot = JSON.parse(snapshotData); // Handle both legacy array format and new object format if (Array.isArray(snapshot.indexingCodebases)) { // Legacy format: if path exists in array, assume 0% progress return snapshot.indexingCodebases.includes(codebasePath) ? 0 : undefined; } else if (snapshot.indexingCodebases && typeof snapshot.indexingCodebases === 'object') { // New format: return the actual progress percentage return snapshot.indexingCodebases[codebasePath]; } return undefined; } catch (error) { console.warn(`[SNAPSHOT-DEBUG] Error reading progress from file for ${codebasePath}:`, error); // Fallback to memory if file reading fails return this.indexingCodebases.get(codebasePath); } } addIndexingCodebase(codebasePath, progress = 0) { this.indexingCodebases.set(codebasePath, progress); } updateIndexingProgress(codebasePath, progress) { if (this.indexingCodebases.has(codebasePath)) { this.indexingCodebases.set(codebasePath, progress); } } removeIndexingCodebase(codebasePath) { this.indexingCodebases.delete(codebasePath); } addIndexedCodebase(codebasePath) { if (!this.indexedCodebases.includes(codebasePath)) { this.indexedCodebases.push(codebasePath); } } removeIndexedCodebase(codebasePath) { this.indexedCodebases = this.indexedCodebases.filter(path => path !== codebasePath); } moveFromIndexingToIndexed(codebasePath) { this.removeIndexingCodebase(codebasePath); this.addIndexedCodebase(codebasePath); } loadCodebaseSnapshot() { console.log('[SNAPSHOT-DEBUG] Loading codebase snapshot from:', this.snapshotFilePath); try { if (!fs.existsSync(this.snapshotFilePath)) { console.log('[SNAPSHOT-DEBUG] Snapshot file does not exist. Starting with empty codebase list.'); return; } const snapshotData = fs.readFileSync(this.snapshotFilePath, 'utf8'); const snapshot = JSON.parse(snapshotData); console.log('[SNAPSHOT-DEBUG] Loaded snapshot:', snapshot); // Validate that the codebases still exist const validCodebases = []; for (const codebasePath of snapshot.indexedCodebases) { if (fs.existsSync(codebasePath)) { validCodebases.push(codebasePath); console.log(`[SNAPSHOT-DEBUG] Validated codebase: ${codebasePath}`); } else { console.warn(`[SNAPSHOT-DEBUG] Codebase no longer exists, removing: ${codebasePath}`); } } // Handle indexing codebases - treat them as not indexed since they were interrupted // Support both legacy array format and new object format let indexingCodebasesList = []; if (Array.isArray(snapshot.indexingCodebases)) { // Legacy format: string[] indexingCodebasesList = snapshot.indexingCodebases; console.log(`[SNAPSHOT-DEBUG] Found legacy indexingCodebases array format with ${indexingCodebasesList.length} entries`); } else if (snapshot.indexingCodebases && typeof snapshot.indexingCodebases === 'object') { // New format: Record<string, number> indexingCodebasesList = Object.keys(snapshot.indexingCodebases); console.log(`[SNAPSHOT-DEBUG] Found new indexingCodebases object format with ${indexingCodebasesList.length} entries`); } for (const codebasePath of indexingCodebasesList) { if (fs.existsSync(codebasePath)) { console.warn(`[SNAPSHOT-DEBUG] Found interrupted indexing codebase: ${codebasePath}. Treating as not indexed.`); // Don't add to validIndexingCodebases - treat as not indexed } else { console.warn(`[SNAPSHOT-DEBUG] Interrupted indexing codebase no longer exists: ${codebasePath}`); } } // Restore state - only fully indexed codebases this.indexedCodebases = validCodebases; this.indexingCodebases = new Map(); // Reset indexing codebases since they were interrupted console.log(`[SNAPSHOT-DEBUG] Restored ${validCodebases.length} fully indexed codebases.`); console.log(`[SNAPSHOT-DEBUG] Reset ${indexingCodebasesList.length} interrupted indexing codebases.`); // Save updated snapshot if we removed any invalid paths or reset indexing codebases const originalIndexingCount = Array.isArray(snapshot.indexingCodebases) ? snapshot.indexingCodebases.length : Object.keys(snapshot.indexingCodebases || {}).length; if (validCodebases.length !== snapshot.indexedCodebases.length || originalIndexingCount > 0) { this.saveCodebaseSnapshot(); } } catch (error) { console.error('[SNAPSHOT-DEBUG] Error loading snapshot:', error); console.log('[SNAPSHOT-DEBUG] Starting with empty codebase list due to snapshot error.'); } } saveCodebaseSnapshot() { console.log('[SNAPSHOT-DEBUG] Saving codebase snapshot to:', this.snapshotFilePath); try { // Ensure directory exists const snapshotDir = path.dirname(this.snapshotFilePath); if (!fs.existsSync(snapshotDir)) { fs.mkdirSync(snapshotDir, { recursive: true }); console.log('[SNAPSHOT-DEBUG] Created snapshot directory:', snapshotDir); } // Convert Map to object for JSON serialization const indexingCodebasesObject = {}; this.indexingCodebases.forEach((progress, path) => { indexingCodebasesObject[path] = progress; }); const snapshot = { indexedCodebases: this.indexedCodebases, indexingCodebases: indexingCodebasesObject, lastUpdated: new Date().toISOString() }; fs.writeFileSync(this.snapshotFilePath, JSON.stringify(snapshot, null, 2)); console.log('[SNAPSHOT-DEBUG] Snapshot saved successfully. Indexed codebases:', this.indexedCodebases.length, 'Indexing codebases:', this.indexingCodebases.size); } catch (error) { console.error('[SNAPSHOT-DEBUG] Error saving snapshot:', error); } } } //# sourceMappingURL=snapshot.js.map