@mrxkun/mcfast-mcp 3.5.10 → 3.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +78 -4
- package/src/strategies/tree-sitter/queries.js +14 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrxkun/mcfast-mcp",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.12",
|
|
4
4
|
"description": "Ultra-fast code editing with WASM acceleration, fuzzy patching, multi-layer caching, and 8 unified tools. Optimized for AI code assistants with 80-98% latency reduction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/index.js
CHANGED
|
@@ -595,11 +595,31 @@ async function reportAudit(data) {
|
|
|
595
595
|
/**
|
|
596
596
|
* Handle regex-based filesystem search using grep
|
|
597
597
|
* Uses native grep for high-performance regex searching
|
|
598
|
+
* Includes validation for unsupported regex patterns
|
|
598
599
|
*/
|
|
599
600
|
async function handleRegexSearch({ query, path: searchPath, caseSensitive = false }) {
|
|
600
601
|
const start = Date.now();
|
|
601
602
|
|
|
602
603
|
try {
|
|
604
|
+
// Validate regex pattern before executing
|
|
605
|
+
const validation = validateRegex(query);
|
|
606
|
+
if (!validation.valid) {
|
|
607
|
+
const latency = Date.now() - start;
|
|
608
|
+
return {
|
|
609
|
+
content: [{
|
|
610
|
+
type: "text",
|
|
611
|
+
text: `⚠️ Invalid regex pattern: ${validation.error}\n\nQuery: "${query}"\n\n💡 Tips:\n• Basic regex works: \\bword\\b, [a-z]+, (foo|bar)\n• Avoid lookbehind (?<=...) and lookahead (?=...) - not supported by grep\n• Use word boundaries \\b instead of lookarounds\n• Escape special chars: \\\\, \\+, \\*`
|
|
612
|
+
}],
|
|
613
|
+
isError: true
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Warn about potentially unsupported patterns
|
|
618
|
+
if (validation.warnings.length > 0) {
|
|
619
|
+
console.error(`${colors.yellow}[Regex Warning]${colors.reset} Pattern may not work as expected:`);
|
|
620
|
+
validation.warnings.forEach(w => console.error(` - ${w}`));
|
|
621
|
+
}
|
|
622
|
+
|
|
603
623
|
const flags = [
|
|
604
624
|
"-r", // Recursive
|
|
605
625
|
"-n", // Line number
|
|
@@ -618,10 +638,18 @@ async function handleRegexSearch({ query, path: searchPath, caseSensitive = fals
|
|
|
618
638
|
"--exclude-dir=.cache"
|
|
619
639
|
].join(" ");
|
|
620
640
|
|
|
621
|
-
|
|
641
|
+
// Escape quotes in query to prevent command injection
|
|
642
|
+
const escapedQuery = query.replace(/"/g, '\\"');
|
|
643
|
+
const command = `grep ${flags} ${excludes} -E "${escapedQuery}" "${searchPath}" 2>&1`;
|
|
622
644
|
|
|
623
645
|
try {
|
|
624
|
-
const { stdout } = await execAsync(command, { maxBuffer: 10 * 1024 * 1024 }); // 10MB buffer
|
|
646
|
+
const { stdout, stderr } = await execAsync(command, { maxBuffer: 10 * 1024 * 1024 }); // 10MB buffer
|
|
647
|
+
|
|
648
|
+
// Check for grep regex errors in stderr
|
|
649
|
+
if (stderr && stderr.includes('Invalid regular expression')) {
|
|
650
|
+
throw new Error(`grep: ${stderr}`);
|
|
651
|
+
}
|
|
652
|
+
|
|
625
653
|
const results = stdout.trim().split('\n').filter(Boolean);
|
|
626
654
|
|
|
627
655
|
const latency = Date.now() - start;
|
|
@@ -686,6 +714,12 @@ async function handleRegexSearch({ query, path: searchPath, caseSensitive = fals
|
|
|
686
714
|
content: [{ type: "text", text: `🔍 Regex Search: No matches found for "${query}" in ${searchPath} (${latency}ms)` }]
|
|
687
715
|
};
|
|
688
716
|
}
|
|
717
|
+
|
|
718
|
+
// Handle regex syntax errors
|
|
719
|
+
if (execErr.stderr && execErr.stderr.includes('Invalid')) {
|
|
720
|
+
throw new Error(`Invalid regex syntax: ${execErr.stderr}. Try simplifying your pattern.`);
|
|
721
|
+
}
|
|
722
|
+
|
|
689
723
|
throw execErr;
|
|
690
724
|
}
|
|
691
725
|
} catch (error) {
|
|
@@ -700,12 +734,52 @@ async function handleRegexSearch({ query, path: searchPath, caseSensitive = fals
|
|
|
700
734
|
});
|
|
701
735
|
|
|
702
736
|
return {
|
|
703
|
-
content: [{ type: "text", text: `❌ Regex search error: ${error.message}` }],
|
|
737
|
+
content: [{ type: "text", text: `❌ Regex search error: ${error.message}\n\n💡 Try using a simpler pattern without lookarounds (?<= or ?=)` }],
|
|
704
738
|
isError: true
|
|
705
739
|
};
|
|
706
740
|
}
|
|
707
741
|
}
|
|
708
742
|
|
|
743
|
+
/**
|
|
744
|
+
* Validate regex pattern for compatibility with grep
|
|
745
|
+
* Returns { valid: boolean, error?: string, warnings: string[] }
|
|
746
|
+
*/
|
|
747
|
+
function validateRegex(pattern) {
|
|
748
|
+
const warnings = [];
|
|
749
|
+
|
|
750
|
+
try {
|
|
751
|
+
// Test if it's valid JavaScript regex
|
|
752
|
+
new RegExp(pattern);
|
|
753
|
+
} catch (e) {
|
|
754
|
+
return { valid: false, error: e.message, warnings };
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// Check for patterns not supported by basic grep (PCRE-only features)
|
|
758
|
+
const unsupportedPatterns = [
|
|
759
|
+
{ regex: /\(\?<[=!]/, name: 'Lookbehind (?<=...) or negative lookbehind (?<!...)' },
|
|
760
|
+
{ regex: /\(\?=[^=]/, name: 'Lookahead (?=...)' },
|
|
761
|
+
{ regex: /\(\?![^=]/, name: 'Negative lookahead (?!...)' },
|
|
762
|
+
{ regex: /\(\?<\w+>/, name: 'Named capture groups (?<name>...)' },
|
|
763
|
+
{ regex: /\\p\{/, name: 'Unicode properties (\\p{...})' },
|
|
764
|
+
{ regex: /\(\?#/, name: 'Comments (?#...)' },
|
|
765
|
+
{ regex: /\(\?\d*\)/, name: 'Subroutine calls (?1)' },
|
|
766
|
+
{ regex: /\(\?&\w+\)/, name: 'Subroutine calls (?&name)' }
|
|
767
|
+
];
|
|
768
|
+
|
|
769
|
+
for (const { regex, name } of unsupportedPatterns) {
|
|
770
|
+
if (regex.test(pattern)) {
|
|
771
|
+
warnings.push(`Pattern uses ${name} which may not be supported by grep. Results may be incomplete.`);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// Check for potentially dangerous patterns (catastrophic backtracking)
|
|
776
|
+
if (/\(\w+\+\+?\)|\(\w+\*\*?\)\*\*?/.test(pattern)) {
|
|
777
|
+
warnings.push('Pattern may cause performance issues (nested quantifiers)');
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return { valid: true, warnings };
|
|
781
|
+
}
|
|
782
|
+
|
|
709
783
|
// ============================================
|
|
710
784
|
|
|
711
785
|
/**
|
|
@@ -2188,7 +2262,7 @@ async function handleReferencesInDirectory({ path: dirPath, symbol }) {
|
|
|
2188
2262
|
output += ` ${colors.dim}${m.line}:${colors.reset} ${m.content}\n`;
|
|
2189
2263
|
});
|
|
2190
2264
|
if (matches.length > 5) {
|
|
2191
|
-
output += ` ${colors.dim}... and ${matches.length - 5} more${colors.reset}\n`;
|
|
2265
|
+
output += ` ${colors.dim}... and ${matches.length - 5} more matches${colors.reset}\n`;
|
|
2192
2266
|
}
|
|
2193
2267
|
output += "\n";
|
|
2194
2268
|
});
|
|
@@ -9,6 +9,13 @@ export const QUERIES = {
|
|
|
9
9
|
(class_declaration name: (type_identifier) @name) @class
|
|
10
10
|
(method_definition key: (property_identifier) @name) @method
|
|
11
11
|
(interface_declaration name: (type_identifier) @name) @interface
|
|
12
|
+
(export_statement
|
|
13
|
+
(function_declaration name: (identifier) @name)) @export_function
|
|
14
|
+
(export_statement
|
|
15
|
+
(class_declaration name: (type_identifier) @name)) @export_class
|
|
16
|
+
(export_statement
|
|
17
|
+
(lexical_declaration
|
|
18
|
+
(variable_declarator name: (identifier) @name))) @export_const
|
|
12
19
|
`,
|
|
13
20
|
references: `
|
|
14
21
|
(identifier) @ref
|
|
@@ -41,6 +48,13 @@ export const QUERIES = {
|
|
|
41
48
|
(class_declaration name: (identifier) @name) @class
|
|
42
49
|
(method_definition key: (property_identifier) @name) @method
|
|
43
50
|
(variable_declarator name: (identifier) @name init: (arrow_function)) @arrow_function
|
|
51
|
+
(export_statement
|
|
52
|
+
(function_declaration name: (identifier) @name)) @export_function
|
|
53
|
+
(export_statement
|
|
54
|
+
(class_declaration name: (identifier) @name)) @export_class
|
|
55
|
+
(export_statement
|
|
56
|
+
(lexical_declaration
|
|
57
|
+
(variable_declarator name: (identifier) @name))) @export_const
|
|
44
58
|
`,
|
|
45
59
|
references: `
|
|
46
60
|
(identifier) @ref
|