UNPKG

mcp-booster

Version:

Servidor MCP com CoConuT (Continuous Chain of Thought) para uso com Cursor IDE - Pacote Global NPM

314 lines (313 loc) 11 kB
"use strict"; /** * Sistema de cache para resultados de similaridade * Melhora o desempenho evitando recálculos de similaridade entre textos */ Object.defineProperty(exports, "__esModule", { value: true }); exports.PathUtils = exports.SimilarityCache = exports.LRUCache = void 0; /** * Classe de cache genérico com limite de tamanho e expiração */ class LRUCache { constructor(maxSize = 1000, ttl = 0) { this.cache = new Map(); this.maxSize = maxSize; this.ttl = ttl; } /** * Gera uma chave de cache a partir de um objeto */ generateKey(obj) { return JSON.stringify(obj); } /** * Verifica se uma entrada expirou */ isExpired(entry) { if (this.ttl === 0) return false; const now = Date.now(); return now - entry.timestamp > this.ttl; } /** * Obtém um valor do cache */ get(key) { const cacheKey = this.generateKey(key); const entry = this.cache.get(cacheKey); if (!entry) return undefined; // Verificar expiração if (this.isExpired(entry)) { this.cache.delete(cacheKey); return undefined; } // Atualizar timestamp para LRU entry.timestamp = Date.now(); return entry.value; } /** * Define um valor no cache */ set(key, value) { const cacheKey = this.generateKey(key); // Verificar se já existe para atualizar if (this.cache.has(cacheKey)) { this.cache.set(cacheKey, { key: cacheKey, value, timestamp: Date.now() }); return; } // Verificar tamanho do cache e remover o item mais antigo se necessário if (this.cache.size >= this.maxSize) { let oldest = null; let oldestKey = ''; for (const [k, entry] of this.cache.entries()) { if (!oldest || entry.timestamp < oldest.timestamp) { oldest = entry; oldestKey = k; } } if (oldestKey) { this.cache.delete(oldestKey); } } // Adicionar nova entrada this.cache.set(cacheKey, { key: cacheKey, value, timestamp: Date.now() }); } /** * Remove um valor do cache */ delete(key) { const cacheKey = this.generateKey(key); return this.cache.delete(cacheKey); } /** * Limpa o cache */ clear() { this.cache.clear(); } /** * Retorna o tamanho atual do cache */ size() { return this.cache.size; } } exports.LRUCache = LRUCache; /** * Cache específico para resultados de similaridade */ class SimilarityCache { constructor(maxSize = 1000) { this.cache = new LRUCache(maxSize); } /** * Obtém um valor de similaridade do cache */ getSimilarity(text1, text2, algorithm) { const key = { text1, text2, algorithm }; return this.cache.get(key); } /** * Armazena um valor de similaridade no cache */ setSimilarity(text1, text2, algorithm, similarity) { const key = { text1, text2, algorithm }; this.cache.set(key, similarity); } /** * Limpa o cache de similaridade */ clear() { this.cache.clear(); } /** * Retorna o tamanho atual do cache */ size() { return this.cache.size(); } } exports.SimilarityCache = SimilarityCache; /** * Utilitários para manipulação de paths */ class PathUtils { /** * Decodifica um caminho que pode estar URL-encoded * Resolve o problema do Windows onde paths vem como /c%3A/... em vez de /c:/... * @param path Caminho que pode estar URL-encoded * @returns Caminho decodificado */ static decodePath(path) { if (!path || typeof path !== 'string') { return path; } try { // Verificar se o path parece estar URL-encoded (contém %) if (path.includes('%')) { // Decodificar usando decodeURIComponent const decoded = decodeURIComponent(path); // Log para debug (pode ser removido em produção) if (decoded !== path) { console.debug(`PathUtils: Decoded URL-encoded path: ${path} -> ${decoded}`); } return decoded; } // Se não contém %, retornar como está return path; } catch (error) { // Se falhar na decodificação, retornar o path original console.warn(`PathUtils: Failed to decode path "${path}":`, error); return path; } } /** * Normaliza um caminho removendo barras duplas e resolvendo relativos * Melhorado para Windows com tratamento de barras backward, caminhos WSL/Unix e resolução adequada * @param path Caminho a ser normalizado * @returns Caminho normalizado e resolvido */ static normalizePath(path) { if (!path || typeof path !== 'string') { return path; } try { // Primeiro decodificar se necessário let decoded = this.decodePath(path); // Importar path module para normalização adequada const nodePath = require('path'); // No Windows, tratar caminhos especiais if (process.platform === 'win32') { // Detectar e converter caminhos WSL/Unix no formato /c/... para C:\... const wslPathMatch = decoded.match(/^\/([a-zA-Z])(\/.*)?$/); if (wslPathMatch) { // Converter /c/path para C:\path const driveLetter = wslPathMatch[1].toUpperCase(); const restOfPath = wslPathMatch[2] || ''; decoded = `${driveLetter}:${restOfPath.replace(/\//g, '\\')}`; if (process.env.DEBUG) { console.debug(`PathUtils: Converted WSL path: ${path} -> ${decoded}`); } } // Se o caminho contém dois pontos (drive letter já formatado), garantir formato Windows else if (decoded.match(/^\/[a-zA-Z]:/)) { // Converter /c:/ para c:\ decoded = decoded.substring(1); } } // Usar path.resolve para normalização completa e resolução de relativos const resolved = nodePath.resolve(decoded); // Log para debug if (process.env.DEBUG && resolved !== path) { console.debug(`PathUtils: Normalized path: ${path} -> ${resolved}`); } return resolved; } catch (error) { // Se falhar na normalização, tentar normalização básica console.warn(`PathUtils: Failed to normalize path "${path}":`, error); // Fallback: normalização básica com tratamento WSL let decoded = this.decodePath(path); // Fallback para Windows com WSL if (process.platform === 'win32') { const wslPathMatch = decoded.match(/^\/([a-zA-Z])(\/.*)?$/); if (wslPathMatch) { const driveLetter = wslPathMatch[1].toUpperCase(); const restOfPath = wslPathMatch[2] || ''; return `${driveLetter}:${restOfPath.replace(/\//g, '\\')}`; } } return decoded .replace(/\/+/g, '/') // Substituir múltiplas barras por uma .replace(/\/$/, '') // Remover barra final .trim(); } } /** * Verifica se um diretório pode ser criado/escrito * @param dirPath Caminho do diretório * @returns true se pode escrever, false caso contrário */ static canWriteToDirectory(dirPath) { try { const fs = require('fs'); const nodePath = require('path'); // Se o diretório não existe, verificar se podemos criar if (!fs.existsSync(dirPath)) { // Verificar se podemos criar o diretório pai const parentDir = nodePath.dirname(dirPath); if (!fs.existsSync(parentDir)) { return this.canWriteToDirectory(parentDir); } // Tentar verificar permissões no diretório pai try { fs.accessSync(parentDir, fs.constants.W_OK); return true; } catch { return false; } } // Se existe, verificar se podemos escrever try { fs.accessSync(dirPath, fs.constants.W_OK); return true; } catch { return false; } } catch (error) { console.warn(`PathUtils: Error checking write permissions for "${dirPath}":`, error); return false; } } /** * Cria um diretório de forma segura com verificações de permissão * @param dirPath Caminho do diretório a ser criado * @returns Resultado da operação */ static safeCreateDirectory(dirPath) { try { const fs = require('fs'); // Verificar se já existe if (fs.existsSync(dirPath)) { // Verificar se é um diretório e se podemos escrever const stats = fs.statSync(dirPath); if (!stats.isDirectory()) { return { success: false, error: `Path exists but is not a directory: ${dirPath}` }; } if (!this.canWriteToDirectory(dirPath)) { return { success: false, error: `No write permission for directory: ${dirPath}` }; } return { success: true }; } // Verificar se podemos criar if (!this.canWriteToDirectory(dirPath)) { return { success: false, error: `No permission to create directory: ${dirPath}` }; } // Criar o diretório fs.mkdirSync(dirPath, { recursive: true }); // Verificar se foi criado com sucesso if (!fs.existsSync(dirPath)) { return { success: false, error: `Directory creation failed: ${dirPath}` }; } return { success: true }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, error: `Error creating directory "${dirPath}": ${errorMessage}` }; } } } exports.PathUtils = PathUtils;