UNPKG

@wonderwhy-er/desktop-commander

Version:

MCP server for terminal operations and file editing

180 lines (174 loc) 7.68 kB
import { fuzzySearchLogger } from '../utils/fuzzySearchLogger.js'; import { createErrorResponse } from '../error-handlers.js'; import { ViewFuzzySearchLogsArgsSchema, AnalyzeFuzzySearchLogsArgsSchema, ClearFuzzySearchLogsArgsSchema } from '../tools/schemas.js'; /** * View recent fuzzy search logs */ export async function handleViewFuzzySearchLogs(args) { try { const parsed = ViewFuzzySearchLogsArgsSchema.parse(args); const logs = await fuzzySearchLogger.getRecentLogs(parsed.count); const logPath = await fuzzySearchLogger.getLogPath(); if (logs.length === 0) { return { content: [{ type: "text", text: `No fuzzy search logs found. Log file location: ${logPath}` }], }; } // Parse and format logs for better readability const formattedLogs = logs.map((log, index) => { const parts = log.split('\t'); if (parts.length >= 16) { const [timestamp, searchText, foundText, similarity, executionTime, exactMatchCount, expectedReplacements, fuzzyThreshold, belowThreshold, diff, searchLength, foundLength, fileExtension, characterCodes, uniqueCharacterCount, diffLength] = parts; return ` --- Log Entry ${index + 1} --- Timestamp: ${timestamp} File Extension: ${fileExtension} Search Text: ${searchText.replace(/\\n/g, '\n').replace(/\\t/g, '\t')} Found Text: ${foundText.replace(/\\n/g, '\n').replace(/\\t/g, '\t')} Similarity: ${(parseFloat(similarity) * 100).toFixed(2)}% Execution Time: ${parseFloat(executionTime).toFixed(2)}ms Exact Match Count: ${exactMatchCount} Expected Replacements: ${expectedReplacements} Below Threshold: ${belowThreshold} Diff: ${diff.replace(/\\n/g, '\n').replace(/\\t/g, '\t')} Search Length: ${searchLength} Found Length: ${foundLength} Character Codes: ${characterCodes} Unique Characters: ${uniqueCharacterCount} Diff Length: ${diffLength} `; } return `Malformed log entry: ${log}`; }).join('\n'); return { content: [{ type: "text", text: `Recent Fuzzy Search Logs (${logs.length} entries):\n\n${formattedLogs}\n\nLog file location: ${logPath}` }], }; } catch (error) { return createErrorResponse(`Failed to view fuzzy search logs: ${error instanceof Error ? error.message : String(error)}`); } } /** * Analyze fuzzy search logs to identify patterns and issues */ export async function handleAnalyzeFuzzySearchLogs(args) { try { const parsed = AnalyzeFuzzySearchLogsArgsSchema.parse(args); const logs = await fuzzySearchLogger.getRecentLogs(100); // Analyze more logs const logPath = await fuzzySearchLogger.getLogPath(); if (logs.length === 0) { return { content: [{ type: "text", text: `No fuzzy search logs found. Log file location: ${logPath}` }], }; } // Parse logs and gather statistics let totalEntries = 0; let exactMatches = 0; let fuzzyMatches = 0; let failures = 0; let belowThresholdCount = 0; const executionTimes = []; const similarities = []; const fileExtensions = new Map(); const commonCharacterCodes = new Map(); for (const log of logs) { const parts = log.split('\t'); if (parts.length >= 16) { totalEntries++; const [timestamp, searchText, foundText, similarity, executionTime, exactMatchCount, expectedReplacements, fuzzyThreshold, belowThreshold, diff, searchLength, foundLength, fileExtension, characterCodes, uniqueCharacterCount, diffLength] = parts; const simValue = parseFloat(similarity); const execTime = parseFloat(executionTime); const exactCount = parseInt(exactMatchCount); const belowThresh = belowThreshold === 'true'; if (exactCount > 0) { exactMatches++; } else if (simValue >= parsed.failureThreshold) { fuzzyMatches++; } else { failures++; } if (belowThresh) { belowThresholdCount++; } executionTimes.push(execTime); similarities.push(simValue); // Track file extensions fileExtensions.set(fileExtension, (fileExtensions.get(fileExtension) || 0) + 1); // Track character codes that appear in diffs if (characterCodes && characterCodes !== '') { const codes = characterCodes.split(','); for (const code of codes) { const key = code.split(':')[0]; commonCharacterCodes.set(key, (commonCharacterCodes.get(key) || 0) + 1); } } } } // Calculate statistics const avgExecutionTime = executionTimes.reduce((a, b) => a + b, 0) / executionTimes.length; const avgSimilarity = similarities.reduce((a, b) => a + b, 0) / similarities.length; // Sort by frequency const sortedExtensions = Array.from(fileExtensions.entries()).sort((a, b) => b[1] - a[1]); const sortedCharCodes = Array.from(commonCharacterCodes.entries()).sort((a, b) => b[1] - a[1]); const analysis = ` === Fuzzy Search Analysis === Total Entries: ${totalEntries} Exact Matches: ${exactMatches} (${((exactMatches / totalEntries) * 100).toFixed(2)}%) Fuzzy Matches: ${fuzzyMatches} (${((fuzzyMatches / totalEntries) * 100).toFixed(2)}%) Failures: ${failures} (${((failures / totalEntries) * 100).toFixed(2)}%) Below Threshold: ${belowThresholdCount} (${((belowThresholdCount / totalEntries) * 100).toFixed(2)}%) Performance: Average Execution Time: ${avgExecutionTime.toFixed(2)}ms Average Similarity: ${(avgSimilarity * 100).toFixed(2)}% File Extensions (Top 5): ${sortedExtensions.slice(0, 5).map(([ext, count]) => `${ext || 'none'}: ${count} times`).join('\n')} Common Character Codes in Diffs (Top 5): ${sortedCharCodes.slice(0, 5).map(([code, count]) => { const charCode = parseInt(code); const char = String.fromCharCode(charCode); const display = charCode < 32 || charCode > 126 ? `\\x${charCode.toString(16).padStart(2, '0')}` : char; return `${code} [${display}]: ${count} times`; }).join('\n')} Log file location: ${logPath} `; return { content: [{ type: "text", text: analysis }], }; } catch (error) { return createErrorResponse(`Failed to analyze fuzzy search logs: ${error instanceof Error ? error.message : String(error)}`); } } /** * Clear fuzzy search logs */ export async function handleClearFuzzySearchLogs(args) { try { ClearFuzzySearchLogsArgsSchema.parse(args); await fuzzySearchLogger.clearLog(); const logPath = await fuzzySearchLogger.getLogPath(); return { content: [{ type: "text", text: `Fuzzy search logs cleared. Log file location: ${logPath}` }], }; } catch (error) { return createErrorResponse(`Failed to clear fuzzy search logs: ${error instanceof Error ? error.message : String(error)}`); } }