@wonderwhy-er/desktop-commander
Version:
MCP server for terminal operations and file editing
180 lines (174 loc) • 7.68 kB
JavaScript
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)}`);
}
}