UNPKG

gemini-mcp-tool

Version:

MCP server for Gemini CLI integration

161 lines 5.11 kB
import { createHash } from 'crypto'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import { Logger } from './logger.js'; const CACHE_DIR = path.join(os.tmpdir(), 'gemini-mcp-chunks'); const CACHE_TTL = 10 * 60 * 1000; const MAX_CACHE_FILES = 50; function ensureCacheDir() { if (!fs.existsSync(CACHE_DIR)) { fs.mkdirSync(CACHE_DIR, { recursive: true }); } } /** * Caches chunks from a changeMode response * @param prompt The original prompt (used for hash generation) * @param chunks The parsed and chunked edits * @returns A short cache key for retrieval */ export function cacheChunks(prompt, chunks) { ensureCacheDir(); cleanExpiredFiles(); // Cleanup on each write // Generate deterministic cache key from prompt const promptHash = createHash('sha256').update(prompt).digest('hex'); const cacheKey = promptHash.slice(0, 8); const filePath = path.join(CACHE_DIR, `${cacheKey}.json`); // Store with metadata const cacheData = { chunks, timestamp: Date.now(), promptHash }; try { fs.writeFileSync(filePath, JSON.stringify(cacheData)); Logger.debug(`Cached ${chunks.length} chunks to file: ${cacheKey}.json`); } catch (error) { Logger.error(`Failed to cache chunks: ${error}`); } enforceFileLimits(); return cacheKey; } /** * Retrieves cached chunks if they exist and haven't expired * @param cacheKey The cache key returned from cacheChunks * @returns The cached chunks or null if expired/not found */ export function getChunks(cacheKey) { const filePath = path.join(CACHE_DIR, `${cacheKey}.json`); try { if (!fs.existsSync(filePath)) { return null; } const fileContent = fs.readFileSync(filePath, 'utf-8'); const data = JSON.parse(fileContent); if (Date.now() - data.timestamp > CACHE_TTL) { fs.unlinkSync(filePath); Logger.debug(`Cache expired for ${cacheKey}, deleted file`); return null; } Logger.debug(`Cache hit for ${cacheKey}, returning ${data.chunks.length} chunks`); return data.chunks; } catch (error) { Logger.debug(`Cache read error for ${cacheKey}: ${error}`); try { fs.unlinkSync(filePath); // Clean up bad file } catch { } return null; } } function cleanExpiredFiles() { try { ensureCacheDir(); const files = fs.readdirSync(CACHE_DIR); const now = Date.now(); let cleaned = 0; for (const file of files) { if (!file.endsWith('.json')) continue; const filePath = path.join(CACHE_DIR, file); try { const stats = fs.statSync(filePath); if (now - stats.mtimeMs > CACHE_TTL) { fs.unlinkSync(filePath); cleaned++; } } catch (error) { // Individual file error - continue with others Logger.debug(`Error checking file ${file}: ${error}`); } } if (cleaned > 0) { Logger.debug(`Cleaned ${cleaned} expired cache files`); } } catch (error) { // Non-critical, just log Logger.debug(`Cache cleanup error: ${error}`); } } // maximum file count limit (FIFO) --> LRU? function enforceFileLimits() { try { const files = fs.readdirSync(CACHE_DIR) .filter(f => f.endsWith('.json')) .map(f => ({ name: f, path: path.join(CACHE_DIR, f), mtime: fs.statSync(path.join(CACHE_DIR, f)).mtimeMs })) .sort((a, b) => a.mtime - b.mtime); // Oldest first // Remove oldest files if over limit if (files.length > MAX_CACHE_FILES) { const toRemove = files.slice(0, files.length - MAX_CACHE_FILES); for (const file of toRemove) { try { fs.unlinkSync(file.path); } catch { } } Logger.debug(`Removed ${toRemove.length} old cache files to enforce limit`); } } catch (error) { Logger.debug(`Error enforcing file limits: ${error}`); } } export function getCacheStats() { ensureCacheDir(); let size = 0; try { const files = fs.readdirSync(CACHE_DIR); size = files.filter(f => f.endsWith('.json')).length; } catch { } return { size, ttl: CACHE_TTL, maxSize: MAX_CACHE_FILES, cacheDir: CACHE_DIR }; } export function clearCache() { try { ensureCacheDir(); const files = fs.readdirSync(CACHE_DIR); for (const file of files) { if (file.endsWith('.json')) { fs.unlinkSync(path.join(CACHE_DIR, file)); } } Logger.debug('Cache emptied'); } catch (error) { Logger.error(`Failed to empty cache: ${error}`); } } //# sourceMappingURL=chunkCache.js.map