MCP server providing compressed versions of Read/Grep/Glob: - compressed_read: removes comments, blanks, collapses imports - compressed_grep: groups by file, dedupes adjacent matches - compressed_glob: collapses directories, shows type distribution Test results: 66.7% compression on sample file 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
129 lines
4.3 KiB
JavaScript
129 lines
4.3 KiB
JavaScript
/**
|
|
* Glob Compressor - Compress file listing while preserving useful structure
|
|
*
|
|
* Strategies:
|
|
* - Collapse deep directory paths
|
|
* - Group by directory with counts
|
|
* - Prioritize recently modified files
|
|
* - Show file type distribution
|
|
*/
|
|
function parseFilePath(path) {
|
|
const parts = path.split('/');
|
|
const name = parts.pop() || '';
|
|
const dir = parts.join('/') || '.';
|
|
const ext = name.includes('.') ? name.split('.').pop()?.toLowerCase() || '' : '';
|
|
return { path, dir, name, ext };
|
|
}
|
|
function collapseDirectory(dir, depth) {
|
|
const parts = dir.split('/').filter(p => p);
|
|
if (parts.length <= depth) {
|
|
return dir;
|
|
}
|
|
// Keep first and last N parts
|
|
const keep = Math.floor(depth / 2);
|
|
const start = parts.slice(0, keep);
|
|
const end = parts.slice(-keep);
|
|
return [...start, '...', ...end].join('/');
|
|
}
|
|
function groupByDirectory(files) {
|
|
const grouped = new Map();
|
|
for (const file of files) {
|
|
const existing = grouped.get(file.dir) || [];
|
|
existing.push(file);
|
|
grouped.set(file.dir, existing);
|
|
}
|
|
return grouped;
|
|
}
|
|
function groupByExtension(files) {
|
|
const counts = new Map();
|
|
for (const file of files) {
|
|
const ext = file.ext || '(no extension)';
|
|
counts.set(ext, (counts.get(ext) || 0) + 1);
|
|
}
|
|
return counts;
|
|
}
|
|
export function compressGlob(paths, options = {}) {
|
|
const { maxFiles = 30, collapseDepth = 4, showCounts = true, groupByExtension: showExtensions = true, } = options;
|
|
const originalCount = paths.length;
|
|
if (originalCount === 0) {
|
|
return {
|
|
content: 'No files found.',
|
|
originalCount: 0,
|
|
compressedCount: 0,
|
|
directories: 0,
|
|
savings: '0%',
|
|
};
|
|
}
|
|
const files = paths.map(parseFilePath);
|
|
const byDir = groupByDirectory(files);
|
|
const directories = byDir.size;
|
|
const result = [];
|
|
// Show extension distribution if configured
|
|
if (showExtensions && originalCount > 10) {
|
|
const extCounts = groupByExtension(files);
|
|
const sorted = Array.from(extCounts.entries())
|
|
.sort((a, b) => b[1] - a[1])
|
|
.slice(0, 5);
|
|
result.push('**File types:**');
|
|
for (const [ext, count] of sorted) {
|
|
result.push(` .${ext}: ${count}`);
|
|
}
|
|
result.push('');
|
|
}
|
|
// Sort directories by file count (most files first)
|
|
const sortedDirs = Array.from(byDir.entries())
|
|
.sort((a, b) => b[1].length - a[1].length);
|
|
let totalShown = 0;
|
|
let dirsShown = 0;
|
|
for (const [dir, dirFiles] of sortedDirs) {
|
|
if (totalShown >= maxFiles) {
|
|
const remainingDirs = sortedDirs.length - dirsShown;
|
|
const remainingFiles = originalCount - totalShown;
|
|
if (remainingDirs > 0) {
|
|
result.push(`\n... [${remainingFiles} more files in ${remainingDirs} directories]`);
|
|
}
|
|
break;
|
|
}
|
|
const collapsedDir = collapseDirectory(dir, collapseDepth);
|
|
const fileCount = dirFiles.length;
|
|
// For directories with many files, show summary
|
|
if (fileCount > 5) {
|
|
result.push(`📁 ${collapsedDir}/ (${fileCount} files)`);
|
|
// Show first few files
|
|
const sample = dirFiles.slice(0, 3);
|
|
for (const file of sample) {
|
|
result.push(` ${file.name}`);
|
|
totalShown++;
|
|
}
|
|
if (fileCount > 3) {
|
|
result.push(` ... [${fileCount - 3} more]`);
|
|
}
|
|
}
|
|
else {
|
|
// Show all files for small directories
|
|
result.push(`📁 ${collapsedDir}/`);
|
|
for (const file of dirFiles) {
|
|
result.push(` ${file.name}`);
|
|
totalShown++;
|
|
if (totalShown >= maxFiles)
|
|
break;
|
|
}
|
|
}
|
|
dirsShown++;
|
|
result.push('');
|
|
}
|
|
// Summary line
|
|
if (showCounts) {
|
|
result.unshift(`**Found ${originalCount} files in ${directories} directories**\n`);
|
|
}
|
|
const compressedCount = totalShown;
|
|
const savings = ((1 - result.length / (originalCount + directories)) * 100).toFixed(1);
|
|
return {
|
|
content: result.join('\n').trim(),
|
|
originalCount,
|
|
compressedCount,
|
|
directories,
|
|
savings: `${savings}%`,
|
|
};
|
|
}
|