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
JavaScript
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 = [];
}
}