UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

120 lines (119 loc) 3.99 kB
export class FuzzyMatcher { static calculateScore(query, target, caseSensitive = false) { if (!query || !target) return 0; const q = caseSensitive ? query : query.toLowerCase(); const t = caseSensitive ? target : target.toLowerCase(); if (q === t) return 1.0; if (t.includes(q)) { const ratio = q.length / t.length; return 0.8 + (ratio * 0.2); } const distance = this.levenshteinDistance(q, t); const maxLength = Math.max(q.length, t.length); const similarity = 1 - (distance / maxLength); let prefixBonus = 0; for (let i = 0; i < Math.min(q.length, t.length); i++) { if (q[i] === t[i]) { prefixBonus += 0.1; } else { break; } } return Math.min(similarity + prefixBonus, 0.79); } static levenshteinDistance(a, b) { const matrix = Array(b.length + 1).fill(null).map(() => Array(a.length + 1).fill(null)); for (let i = 0; i <= a.length; i++) matrix[0][i] = i; for (let j = 0; j <= b.length; j++) matrix[j][0] = j; for (let j = 1; j <= b.length; j++) { for (let i = 1; i <= a.length; i++) { const indicator = a[i - 1] === b[j - 1] ? 0 : 1; matrix[j][i] = Math.min(matrix[j][i - 1] + 1, matrix[j - 1][i] + 1, matrix[j - 1][i - 1] + indicator); } } return matrix[b.length][a.length]; } } export class GlobMatcher { static globToRegex(pattern) { if (pattern.startsWith('**/') && pattern.endsWith('/**')) { const middle = pattern.slice(3, -3); const middlePattern = this.escapeAndConvert(middle); return new RegExp(`^(?:.*/)?${middlePattern}/.*$`, 'i'); } else if (pattern.startsWith('**/')) { const rest = pattern.slice(3); const restPattern = this.escapeAndConvert(rest); return new RegExp(`^(?:.*/)?${restPattern}$`, 'i'); } else if (pattern.endsWith('/**')) { const prefix = pattern.slice(0, -3); const prefixPattern = this.escapeAndConvert(prefix); return new RegExp(`^${prefixPattern}/.*$`, 'i'); } else if (pattern.includes('/**/')) { const parts = pattern.split('/**/'); const escapedParts = parts.map(part => this.escapeAndConvert(part)); return new RegExp(`^${escapedParts.join('/.*/')}$`, 'i'); } else { return new RegExp(`^${this.escapeAndConvert(pattern)}$`, 'i'); } } static escapeAndConvert(pattern) { return pattern .replace(/[+^${}()|[\]\\]/g, '\\$&') .replace(/\./g, '\\.') .replace(/\*/g, '[^/]*') .replace(/\?/g, '[^/]'); } static matches(pattern, path) { try { const regex = this.globToRegex(pattern); return regex.test(path); } catch { return false; } } } export class PriorityQueue { items = []; compareFn; maxSize; constructor(compareFn, maxSize) { this.compareFn = compareFn; this.maxSize = maxSize; } add(item) { this.items.push(item); this.items.sort(this.compareFn); if (this.items.length > this.maxSize) { this.items = this.items.slice(0, this.maxSize); } } toArray() { return [...this.items]; } get size() { return this.items.length; } get isFull() { return this.items.length >= this.maxSize; } getMinScore(scoreFn) { if (this.items.length === 0) return undefined; if (this.items.length < this.maxSize) return 0; return scoreFn(this.items[this.items.length - 1]); } clear() { this.items = []; } }