snow-ai 0.3.35 → 0.3.37
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/dist/agents/codebaseIndexAgent.js +1 -0
- package/dist/agents/codebaseReviewAgent.d.ts +61 -0
- package/dist/agents/codebaseReviewAgent.js +301 -0
- package/dist/api/anthropic.js +1 -0
- package/dist/api/chat.js +1 -0
- package/dist/api/embedding.js +1 -0
- package/dist/api/gemini.js +2 -1
- package/dist/api/responses.js +1 -0
- package/dist/api/systemPrompt.d.ts +1 -5
- package/dist/api/systemPrompt.js +198 -141
- package/dist/app.js +14 -6
- package/dist/cli.js +1 -1
- package/dist/hooks/useCommandPanel.js +48 -46
- package/dist/hooks/useConversation.d.ts +2 -1
- package/dist/hooks/useConversation.js +110 -28
- package/dist/hooks/useGlobalExit.js +4 -2
- package/dist/hooks/useKeyboardInput.js +132 -26
- package/dist/hooks/useStreamingState.d.ts +9 -0
- package/dist/hooks/useStreamingState.js +3 -0
- package/dist/i18n/I18nContext.d.ts +14 -0
- package/dist/i18n/I18nContext.js +24 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/lang/en.d.ts +2 -0
- package/dist/i18n/lang/en.js +481 -0
- package/dist/i18n/lang/es.d.ts +2 -0
- package/dist/i18n/lang/es.js +481 -0
- package/dist/i18n/lang/ja.d.ts +2 -0
- package/dist/i18n/lang/ja.js +481 -0
- package/dist/i18n/lang/ko.d.ts +2 -0
- package/dist/i18n/lang/ko.js +481 -0
- package/dist/i18n/lang/zh-TW.d.ts +2 -0
- package/dist/i18n/lang/zh-TW.js +481 -0
- package/dist/i18n/lang/zh.d.ts +2 -0
- package/dist/i18n/lang/zh.js +481 -0
- package/dist/i18n/translations.d.ts +2 -0
- package/dist/i18n/translations.js +14 -0
- package/dist/i18n/types.d.ts +457 -0
- package/dist/i18n/types.js +1 -0
- package/dist/mcp/aceCodeSearch.d.ts +23 -48
- package/dist/mcp/aceCodeSearch.js +154 -144
- package/dist/mcp/codebaseSearch.d.ts +1 -1
- package/dist/mcp/codebaseSearch.js +159 -30
- package/dist/mcp/filesystem.d.ts +3 -80
- package/dist/mcp/filesystem.js +7 -92
- package/dist/mcp/subagent.d.ts +2 -1
- package/dist/mcp/subagent.js +54 -5
- package/dist/ui/components/ChatInput.js +39 -50
- package/dist/ui/components/CommandPanel.d.ts +1 -1
- package/dist/ui/components/CommandPanel.js +20 -13
- package/dist/ui/components/HelpPanel.js +47 -21
- package/dist/ui/components/Menu.js +6 -2
- package/dist/ui/components/MessageList.d.ts +6 -0
- package/dist/ui/components/MessageList.js +1 -1
- package/dist/ui/components/ToolConfirmation.d.ts +4 -1
- package/dist/ui/components/ToolConfirmation.js +28 -2
- package/dist/ui/components/ToolResultPreview.d.ts +2 -1
- package/dist/ui/components/ToolResultPreview.js +26 -22
- package/dist/ui/pages/ChatScreen.js +126 -49
- package/dist/ui/pages/CodeBaseConfigScreen.js +54 -30
- package/dist/ui/pages/ConfigScreen.js +102 -98
- package/dist/ui/pages/CustomHeadersScreen.js +75 -69
- package/dist/ui/pages/LanguageSettingsScreen.d.ts +7 -0
- package/dist/ui/pages/LanguageSettingsScreen.js +89 -0
- package/dist/ui/pages/ProxyConfigScreen.js +27 -23
- package/dist/ui/pages/SensitiveCommandConfigScreen.js +32 -25
- package/dist/ui/pages/SubAgentConfigScreen.js +88 -75
- package/dist/ui/pages/SystemPromptConfigScreen.js +31 -26
- package/dist/ui/pages/WelcomeScreen.js +40 -26
- package/dist/utils/codebaseConfig.d.ts +1 -5
- package/dist/utils/codebaseConfig.js +2 -10
- package/dist/utils/codebaseSearchEvents.d.ts +16 -0
- package/dist/utils/codebaseSearchEvents.js +13 -0
- package/dist/utils/commands/agent.js +2 -2
- package/dist/utils/commands/init.js +1 -1
- package/dist/utils/configManager.js +26 -5
- package/dist/utils/contextCompressor.js +1 -1
- package/dist/utils/languageConfig.d.ts +21 -0
- package/dist/utils/languageConfig.js +61 -0
- package/dist/utils/mcpToolsManager.js +0 -9
- package/dist/utils/notebookManager.js +11 -4
- package/dist/utils/sessionConverter.js +13 -3
- package/dist/utils/subAgentConfig.d.ts +10 -5
- package/dist/utils/subAgentConfig.js +112 -19
- package/dist/utils/subAgentExecutor.d.ts +9 -1
- package/dist/utils/subAgentExecutor.js +122 -9
- package/dist/utils/textBuffer.d.ts +1 -0
- package/dist/utils/textBuffer.js +69 -4
- package/dist/utils/toolExecutor.d.ts +2 -1
- package/dist/utils/toolExecutor.js +1 -2
- package/dist/utils/usageLogger.js +18 -3
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ import { processManager } from '../utils/processManager.js';
|
|
|
7
7
|
import { detectLanguage } from './utils/aceCodeSearch/language.utils.js';
|
|
8
8
|
import { loadExclusionPatterns, shouldExcludeDirectory, readFileWithCache, } from './utils/aceCodeSearch/filesystem.utils.js';
|
|
9
9
|
import { parseFileSymbols, getContext, } from './utils/aceCodeSearch/symbol.utils.js';
|
|
10
|
-
import { isCommandAvailable, parseGrepOutput,
|
|
10
|
+
import { isCommandAvailable, parseGrepOutput, } from './utils/aceCodeSearch/search.utils.js';
|
|
11
11
|
export class ACECodeSearchService {
|
|
12
12
|
constructor(basePath = process.cwd()) {
|
|
13
13
|
Object.defineProperty(this, "basePath", {
|
|
@@ -196,10 +196,11 @@ export class ACECodeSearchService {
|
|
|
196
196
|
await fs.access(cachedPath);
|
|
197
197
|
}
|
|
198
198
|
catch {
|
|
199
|
-
// File no longer exists, remove from
|
|
199
|
+
// File no longer exists, remove from all caches
|
|
200
200
|
this.indexCache.delete(cachedPath);
|
|
201
201
|
this.fileModTimes.delete(cachedPath);
|
|
202
202
|
this.allIndexedFiles.delete(cachedPath);
|
|
203
|
+
this.fileContentCache.delete(cachedPath);
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
206
|
this.lastIndexTime = now;
|
|
@@ -372,6 +373,10 @@ export class ACECodeSearchService {
|
|
|
372
373
|
*/
|
|
373
374
|
async findReferences(symbolName, maxResults = 100) {
|
|
374
375
|
const references = [];
|
|
376
|
+
// Load exclusion patterns
|
|
377
|
+
await this.loadExclusionPatterns();
|
|
378
|
+
// Escape special regex characters to prevent ReDoS
|
|
379
|
+
const escapedSymbol = symbolName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
375
380
|
const searchInDirectory = async (dirPath) => {
|
|
376
381
|
try {
|
|
377
382
|
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
@@ -380,11 +385,8 @@ export class ACECodeSearchService {
|
|
|
380
385
|
break;
|
|
381
386
|
const fullPath = path.join(dirPath, entry.name);
|
|
382
387
|
if (entry.isDirectory()) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
entry.name === 'dist' ||
|
|
386
|
-
entry.name === 'build' ||
|
|
387
|
-
entry.name.startsWith('.')) {
|
|
388
|
+
// Use configurable exclusion check
|
|
389
|
+
if (shouldExcludeDirectory(entry.name, fullPath, this.basePath, this.customExcludes, this.regexCache)) {
|
|
388
390
|
continue;
|
|
389
391
|
}
|
|
390
392
|
await searchInDirectory(fullPath);
|
|
@@ -395,12 +397,14 @@ export class ACECodeSearchService {
|
|
|
395
397
|
try {
|
|
396
398
|
const content = await fs.readFile(fullPath, 'utf-8');
|
|
397
399
|
const lines = content.split('\n');
|
|
398
|
-
// Search for symbol usage
|
|
400
|
+
// Search for symbol usage with escaped symbol name
|
|
401
|
+
const regex = new RegExp(`\\b${escapedSymbol}\\b`, 'g');
|
|
399
402
|
for (let i = 0; i < lines.length; i++) {
|
|
400
403
|
const line = lines[i];
|
|
401
404
|
if (!line)
|
|
402
405
|
continue;
|
|
403
|
-
|
|
406
|
+
// Reset regex for each line
|
|
407
|
+
regex.lastIndex = 0;
|
|
404
408
|
let match;
|
|
405
409
|
while ((match = regex.exec(line)) !== null) {
|
|
406
410
|
if (references.length >= maxResults)
|
|
@@ -410,7 +414,7 @@ export class ACECodeSearchService {
|
|
|
410
414
|
if (line.includes('import') && line.includes(symbolName)) {
|
|
411
415
|
referenceType = 'import';
|
|
412
416
|
}
|
|
413
|
-
else if (
|
|
417
|
+
else if (new RegExp(`(?:function|class|const|let|var)\\s+${escapedSymbol}`).test(line)) {
|
|
414
418
|
referenceType = 'definition';
|
|
415
419
|
}
|
|
416
420
|
else if (line.includes(':') &&
|
|
@@ -491,19 +495,24 @@ export class ACECodeSearchService {
|
|
|
491
495
|
/**
|
|
492
496
|
* Strategy 1: Use git grep for fast searching in Git repositories
|
|
493
497
|
*/
|
|
494
|
-
async gitGrepSearch(pattern, fileGlob, maxResults = 100) {
|
|
498
|
+
async gitGrepSearch(pattern, fileGlob, maxResults = 100, isRegex = false) {
|
|
495
499
|
return new Promise((resolve, reject) => {
|
|
496
|
-
const args = [
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
'-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
500
|
+
const args = ['grep', '--untracked', '-n', '--ignore-case'];
|
|
501
|
+
// Use fixed-strings for literal search, extended regex for pattern search
|
|
502
|
+
if (isRegex) {
|
|
503
|
+
args.push('-E'); // Extended regex
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
args.push('--fixed-strings'); // Literal string matching
|
|
507
|
+
}
|
|
508
|
+
args.push(pattern);
|
|
504
509
|
if (fileGlob) {
|
|
505
|
-
//
|
|
506
|
-
|
|
510
|
+
// Normalize path separators for Windows compatibility
|
|
511
|
+
let gitGlob = fileGlob.replace(/\\/g, '/');
|
|
512
|
+
// Convert ** to * as git grep has limited ** support
|
|
513
|
+
gitGlob = gitGlob.replace(/\*\*/g, '*');
|
|
514
|
+
// Expand glob patterns with braces (e.g., "source/*.{ts,tsx}" -> ["source/*.ts", "source/*.tsx"])
|
|
515
|
+
const expandedGlobs = this.expandGlobBraces(gitGlob);
|
|
507
516
|
args.push('--', ...expandedGlobs);
|
|
508
517
|
}
|
|
509
518
|
const child = spawn('git', args, {
|
|
@@ -563,14 +572,22 @@ export class ACECodeSearchService {
|
|
|
563
572
|
// Ripgrep uses --glob for filtering
|
|
564
573
|
excludeDirs.forEach(dir => args.push('--glob', `!${dir}/`));
|
|
565
574
|
if (fileGlob) {
|
|
566
|
-
|
|
575
|
+
// Normalize path separators for Windows compatibility
|
|
576
|
+
const normalizedGlob = fileGlob.replace(/\\/g, '/');
|
|
577
|
+
// Expand glob patterns with braces
|
|
578
|
+
const expandedGlobs = this.expandGlobBraces(normalizedGlob);
|
|
579
|
+
expandedGlobs.forEach(glob => args.push('--glob', glob));
|
|
567
580
|
}
|
|
568
581
|
}
|
|
569
582
|
else {
|
|
570
583
|
// System grep uses --exclude-dir
|
|
571
584
|
excludeDirs.forEach(dir => args.push(`--exclude-dir=${dir}`));
|
|
572
585
|
if (fileGlob) {
|
|
573
|
-
|
|
586
|
+
// Normalize path separators for Windows compatibility
|
|
587
|
+
const normalizedGlob = fileGlob.replace(/\\/g, '/');
|
|
588
|
+
// Expand glob patterns with braces
|
|
589
|
+
const expandedGlobs = this.expandGlobBraces(normalizedGlob);
|
|
590
|
+
expandedGlobs.forEach(glob => args.push(`--include=${glob}`));
|
|
574
591
|
}
|
|
575
592
|
args.push(pattern, '.');
|
|
576
593
|
}
|
|
@@ -615,11 +632,35 @@ export class ACECodeSearchService {
|
|
|
615
632
|
});
|
|
616
633
|
});
|
|
617
634
|
}
|
|
635
|
+
/**
|
|
636
|
+
* Convert a glob pattern to a RegExp that matches full paths
|
|
637
|
+
* Supports: *, **, ?, {a,b}, [abc]
|
|
638
|
+
*/
|
|
639
|
+
globPatternToRegex(globPattern) {
|
|
640
|
+
// Normalize path separators
|
|
641
|
+
const normalizedGlob = globPattern.replace(/\\/g, '/');
|
|
642
|
+
// First, temporarily replace glob special patterns with placeholders
|
|
643
|
+
// to prevent them from being escaped
|
|
644
|
+
let regexStr = normalizedGlob
|
|
645
|
+
.replace(/\*\*/g, '\x00DOUBLESTAR\x00') // ** -> placeholder
|
|
646
|
+
.replace(/\*/g, '\x00STAR\x00') // * -> placeholder
|
|
647
|
+
.replace(/\?/g, '\x00QUESTION\x00'); // ? -> placeholder
|
|
648
|
+
// Now escape all special regex characters
|
|
649
|
+
regexStr = regexStr.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
650
|
+
// Replace placeholders with actual regex patterns
|
|
651
|
+
regexStr = regexStr
|
|
652
|
+
.replace(/\x00DOUBLESTAR\x00/g, '.*') // ** -> .* (match any path segments)
|
|
653
|
+
.replace(/\x00STAR\x00/g, '[^/]*') // * -> [^/]* (match within single segment)
|
|
654
|
+
.replace(/\x00QUESTION\x00/g, '.'); // ? -> . (match single character)
|
|
655
|
+
return new RegExp(regexStr, 'i');
|
|
656
|
+
}
|
|
618
657
|
/**
|
|
619
658
|
* Strategy 3: Pure JavaScript fallback search
|
|
620
659
|
*/
|
|
621
660
|
async jsTextSearch(pattern, fileGlob, isRegex = false, maxResults = 100) {
|
|
622
661
|
const results = [];
|
|
662
|
+
// Load exclusion patterns
|
|
663
|
+
await this.loadExclusionPatterns();
|
|
623
664
|
// Compile search pattern
|
|
624
665
|
let searchRegex;
|
|
625
666
|
try {
|
|
@@ -635,8 +676,42 @@ export class ACECodeSearchService {
|
|
|
635
676
|
catch (error) {
|
|
636
677
|
throw new Error(`Invalid regex pattern: ${pattern}`);
|
|
637
678
|
}
|
|
638
|
-
// Parse glob pattern if provided
|
|
639
|
-
const globRegex = fileGlob ?
|
|
679
|
+
// Parse glob pattern if provided using improved glob parser
|
|
680
|
+
const globRegex = fileGlob ? this.globPatternToRegex(fileGlob) : null;
|
|
681
|
+
// Binary file extensions (using Set for O(1) lookup)
|
|
682
|
+
const binaryExts = new Set([
|
|
683
|
+
'.jpg',
|
|
684
|
+
'.jpeg',
|
|
685
|
+
'.png',
|
|
686
|
+
'.gif',
|
|
687
|
+
'.bmp',
|
|
688
|
+
'.ico',
|
|
689
|
+
'.svg',
|
|
690
|
+
'.pdf',
|
|
691
|
+
'.zip',
|
|
692
|
+
'.tar',
|
|
693
|
+
'.gz',
|
|
694
|
+
'.rar',
|
|
695
|
+
'.7z',
|
|
696
|
+
'.exe',
|
|
697
|
+
'.dll',
|
|
698
|
+
'.so',
|
|
699
|
+
'.dylib',
|
|
700
|
+
'.mp3',
|
|
701
|
+
'.mp4',
|
|
702
|
+
'.avi',
|
|
703
|
+
'.mov',
|
|
704
|
+
'.woff',
|
|
705
|
+
'.woff2',
|
|
706
|
+
'.ttf',
|
|
707
|
+
'.eot',
|
|
708
|
+
'.class',
|
|
709
|
+
'.jar',
|
|
710
|
+
'.war',
|
|
711
|
+
'.o',
|
|
712
|
+
'.a',
|
|
713
|
+
'.lib',
|
|
714
|
+
]);
|
|
640
715
|
// Search recursively
|
|
641
716
|
const searchInDirectory = async (dirPath) => {
|
|
642
717
|
if (results.length >= maxResults)
|
|
@@ -648,62 +723,26 @@ export class ACECodeSearchService {
|
|
|
648
723
|
break;
|
|
649
724
|
const fullPath = path.join(dirPath, entry.name);
|
|
650
725
|
if (entry.isDirectory()) {
|
|
651
|
-
//
|
|
652
|
-
if (entry.name
|
|
653
|
-
entry.name === '.git' ||
|
|
654
|
-
entry.name === 'dist' ||
|
|
655
|
-
entry.name === 'build' ||
|
|
656
|
-
entry.name === '__pycache__' ||
|
|
657
|
-
entry.name === 'target' ||
|
|
658
|
-
entry.name === '.next' ||
|
|
659
|
-
entry.name === '.nuxt' ||
|
|
660
|
-
entry.name === 'coverage' ||
|
|
661
|
-
entry.name.startsWith('.')) {
|
|
726
|
+
// Use configurable exclusion check
|
|
727
|
+
if (shouldExcludeDirectory(entry.name, fullPath, this.basePath, this.customExcludes, this.regexCache)) {
|
|
662
728
|
continue;
|
|
663
729
|
}
|
|
664
730
|
await searchInDirectory(fullPath);
|
|
665
731
|
}
|
|
666
732
|
else if (entry.isFile()) {
|
|
667
733
|
// Filter by glob if specified
|
|
668
|
-
if (globRegex
|
|
669
|
-
|
|
734
|
+
if (globRegex) {
|
|
735
|
+
// Use relative path from basePath for glob matching
|
|
736
|
+
const relativePath = path
|
|
737
|
+
.relative(this.basePath, fullPath)
|
|
738
|
+
.replace(/\\/g, '/');
|
|
739
|
+
if (!globRegex.test(relativePath)) {
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
670
742
|
}
|
|
671
|
-
// Skip binary files
|
|
743
|
+
// Skip binary files (using Set for fast lookup)
|
|
672
744
|
const ext = path.extname(entry.name).toLowerCase();
|
|
673
|
-
|
|
674
|
-
'.jpg',
|
|
675
|
-
'.jpeg',
|
|
676
|
-
'.png',
|
|
677
|
-
'.gif',
|
|
678
|
-
'.bmp',
|
|
679
|
-
'.ico',
|
|
680
|
-
'.svg',
|
|
681
|
-
'.pdf',
|
|
682
|
-
'.zip',
|
|
683
|
-
'.tar',
|
|
684
|
-
'.gz',
|
|
685
|
-
'.rar',
|
|
686
|
-
'.7z',
|
|
687
|
-
'.exe',
|
|
688
|
-
'.dll',
|
|
689
|
-
'.so',
|
|
690
|
-
'.dylib',
|
|
691
|
-
'.mp3',
|
|
692
|
-
'.mp4',
|
|
693
|
-
'.avi',
|
|
694
|
-
'.mov',
|
|
695
|
-
'.woff',
|
|
696
|
-
'.woff2',
|
|
697
|
-
'.ttf',
|
|
698
|
-
'.eot',
|
|
699
|
-
'.class',
|
|
700
|
-
'.jar',
|
|
701
|
-
'.war',
|
|
702
|
-
'.o',
|
|
703
|
-
'.a',
|
|
704
|
-
'.lib',
|
|
705
|
-
];
|
|
706
|
-
if (binaryExts.includes(ext)) {
|
|
745
|
+
if (binaryExts.has(ext)) {
|
|
707
746
|
continue;
|
|
708
747
|
}
|
|
709
748
|
try {
|
|
@@ -754,10 +793,8 @@ export class ACECodeSearchService {
|
|
|
754
793
|
try {
|
|
755
794
|
const gitAvailable = await isCommandAvailable('git');
|
|
756
795
|
if (gitAvailable) {
|
|
757
|
-
const results = await this.gitGrepSearch(pattern, fileGlob, maxResults);
|
|
758
|
-
if (results.length > 0
|
|
759
|
-
// git grep doesn't support all regex features,
|
|
760
|
-
// fall back if pattern is complex regex and no results
|
|
796
|
+
const results = await this.gitGrepSearch(pattern, fileGlob, maxResults, isRegex);
|
|
797
|
+
if (results.length > 0) {
|
|
761
798
|
return await this.sortResultsByRecency(results);
|
|
762
799
|
}
|
|
763
800
|
}
|
|
@@ -786,27 +823,32 @@ export class ACECodeSearchService {
|
|
|
786
823
|
/**
|
|
787
824
|
* Sort search results by file modification time (recent files first)
|
|
788
825
|
* Files modified within last 24 hours are prioritized
|
|
826
|
+
* Uses parallel stat calls for better performance
|
|
789
827
|
*/
|
|
790
828
|
async sortResultsByRecency(results) {
|
|
791
829
|
if (results.length === 0)
|
|
792
830
|
return results;
|
|
793
831
|
const now = Date.now();
|
|
794
832
|
const recentThreshold = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
|
|
795
|
-
// Get file
|
|
833
|
+
// Get unique file paths
|
|
834
|
+
const uniqueFiles = Array.from(new Set(results.map(r => r.filePath)));
|
|
835
|
+
// Fetch file modification times in parallel using Promise.allSettled
|
|
836
|
+
const statResults = await Promise.allSettled(uniqueFiles.map(async (filePath) => {
|
|
837
|
+
const fullPath = path.resolve(this.basePath, filePath);
|
|
838
|
+
const stats = await fs.stat(fullPath);
|
|
839
|
+
return { filePath, mtimeMs: stats.mtimeMs };
|
|
840
|
+
}));
|
|
841
|
+
// Build map of file modification times
|
|
796
842
|
const fileModTimes = new Map();
|
|
797
|
-
|
|
798
|
-
if (
|
|
799
|
-
|
|
800
|
-
try {
|
|
801
|
-
const fullPath = path.resolve(this.basePath, result.filePath);
|
|
802
|
-
const stats = await fs.stat(fullPath);
|
|
803
|
-
fileModTimes.set(result.filePath, stats.mtimeMs);
|
|
843
|
+
statResults.forEach((result, index) => {
|
|
844
|
+
if (result.status === 'fulfilled') {
|
|
845
|
+
fileModTimes.set(result.value.filePath, result.value.mtimeMs);
|
|
804
846
|
}
|
|
805
|
-
|
|
847
|
+
else {
|
|
806
848
|
// If we can't get stats, treat as old file
|
|
807
|
-
fileModTimes.set(
|
|
849
|
+
fileModTimes.set(uniqueFiles[index], 0);
|
|
808
850
|
}
|
|
809
|
-
}
|
|
851
|
+
});
|
|
810
852
|
// Sort results: recent files first, then by original order
|
|
811
853
|
return results.sort((a, b) => {
|
|
812
854
|
const aMtime = fileModTimes.get(a.filePath) || 0;
|
|
@@ -841,10 +883,10 @@ export class ACECodeSearchService {
|
|
|
841
883
|
/**
|
|
842
884
|
* Search with language-specific context (cross-reference search)
|
|
843
885
|
*/
|
|
844
|
-
async semanticSearch(query, searchType = 'all', language, maxResults = 50) {
|
|
886
|
+
async semanticSearch(query, searchType = 'all', language, symbolType, maxResults = 50) {
|
|
845
887
|
const startTime = Date.now();
|
|
846
888
|
// Get symbol search results
|
|
847
|
-
const symbolResults = await this.searchSymbols(query,
|
|
889
|
+
const symbolResults = await this.searchSymbols(query, symbolType, language, maxResults);
|
|
848
890
|
// Get reference results if needed
|
|
849
891
|
let references = [];
|
|
850
892
|
if (searchType === 'usage' || searchType === 'all') {
|
|
@@ -880,54 +922,6 @@ export class ACECodeSearchService {
|
|
|
880
922
|
export const aceCodeSearchService = new ACECodeSearchService();
|
|
881
923
|
// MCP Tool definitions for integration
|
|
882
924
|
export const mcpTools = [
|
|
883
|
-
{
|
|
884
|
-
name: 'ace-search_symbols',
|
|
885
|
-
description: 'ACE Code Search: Intelligent symbol search across the codebase. Finds functions, classes, variables, and other code symbols with fuzzy matching. Supports multiple programming languages (TypeScript, JavaScript, Python, Go, Rust, Java, C#). Returns precise file locations with line numbers and context.',
|
|
886
|
-
inputSchema: {
|
|
887
|
-
type: 'object',
|
|
888
|
-
properties: {
|
|
889
|
-
query: {
|
|
890
|
-
type: 'string',
|
|
891
|
-
description: 'Symbol name to search for (supports fuzzy matching, e.g., "gfc" can match "getFileContent")',
|
|
892
|
-
},
|
|
893
|
-
symbolType: {
|
|
894
|
-
type: 'string',
|
|
895
|
-
enum: [
|
|
896
|
-
'function',
|
|
897
|
-
'class',
|
|
898
|
-
'method',
|
|
899
|
-
'variable',
|
|
900
|
-
'constant',
|
|
901
|
-
'interface',
|
|
902
|
-
'type',
|
|
903
|
-
'enum',
|
|
904
|
-
'import',
|
|
905
|
-
'export',
|
|
906
|
-
],
|
|
907
|
-
description: 'Filter by specific symbol type (optional)',
|
|
908
|
-
},
|
|
909
|
-
language: {
|
|
910
|
-
type: 'string',
|
|
911
|
-
enum: [
|
|
912
|
-
'typescript',
|
|
913
|
-
'javascript',
|
|
914
|
-
'python',
|
|
915
|
-
'go',
|
|
916
|
-
'rust',
|
|
917
|
-
'java',
|
|
918
|
-
'csharp',
|
|
919
|
-
],
|
|
920
|
-
description: 'Filter by programming language (optional)',
|
|
921
|
-
},
|
|
922
|
-
maxResults: {
|
|
923
|
-
type: 'number',
|
|
924
|
-
description: 'Maximum number of results to return (default: 100)',
|
|
925
|
-
default: 100,
|
|
926
|
-
},
|
|
927
|
-
},
|
|
928
|
-
required: ['query'],
|
|
929
|
-
},
|
|
930
|
-
},
|
|
931
925
|
{
|
|
932
926
|
name: 'ace-find_definition',
|
|
933
927
|
description: 'ACE Code Search: Find the definition of a symbol (Go to Definition). Locates where a function, class, or variable is defined in the codebase. Returns precise location with full signature and context.',
|
|
@@ -967,20 +961,36 @@ export const mcpTools = [
|
|
|
967
961
|
},
|
|
968
962
|
{
|
|
969
963
|
name: 'ace-semantic_search',
|
|
970
|
-
description: 'ACE Code Search:
|
|
964
|
+
description: 'ACE Code Search: 智能符号搜索与语义分析。支持多种搜索模式:(1) definition - 查找符号定义(函数/类/接口);(2) usage - 查找符号引用位置;(3) implementation - 查找具体实现;(4) all - 综合搜索。支持模糊匹配、按语言和符号类型过滤。💡 提示:如果只需要查看单个文件的符号大纲,使用 ace-file_outline 更快。',
|
|
971
965
|
inputSchema: {
|
|
972
966
|
type: 'object',
|
|
973
967
|
properties: {
|
|
974
968
|
query: {
|
|
975
969
|
type: 'string',
|
|
976
|
-
description: '
|
|
970
|
+
description: '搜索查询 (符号名称或模式,支持模糊匹配如 "gfc" 匹配 "getFileContent")',
|
|
977
971
|
},
|
|
978
972
|
searchType: {
|
|
979
973
|
type: 'string',
|
|
980
974
|
enum: ['definition', 'usage', 'implementation', 'all'],
|
|
981
|
-
description: '
|
|
975
|
+
description: '搜索类型:definition (查找声明)、usage (查找使用)、implementation (查找实现)、all (全面搜索)',
|
|
982
976
|
default: 'all',
|
|
983
977
|
},
|
|
978
|
+
symbolType: {
|
|
979
|
+
type: 'string',
|
|
980
|
+
enum: [
|
|
981
|
+
'function',
|
|
982
|
+
'class',
|
|
983
|
+
'method',
|
|
984
|
+
'variable',
|
|
985
|
+
'constant',
|
|
986
|
+
'interface',
|
|
987
|
+
'type',
|
|
988
|
+
'enum',
|
|
989
|
+
'import',
|
|
990
|
+
'export',
|
|
991
|
+
],
|
|
992
|
+
description: '可选:按符号类型筛选 (function, class, variable等)',
|
|
993
|
+
},
|
|
984
994
|
language: {
|
|
985
995
|
type: 'string',
|
|
986
996
|
enum: [
|
|
@@ -992,11 +1002,11 @@ export const mcpTools = [
|
|
|
992
1002
|
'java',
|
|
993
1003
|
'csharp',
|
|
994
1004
|
],
|
|
995
|
-
description: '
|
|
1005
|
+
description: '可选:按编程语言筛选',
|
|
996
1006
|
},
|
|
997
1007
|
maxResults: {
|
|
998
1008
|
type: 'number',
|
|
999
|
-
description: '
|
|
1009
|
+
description: '最大返回结果数 (默认: 50)',
|
|
1000
1010
|
default: 50,
|
|
1001
1011
|
},
|
|
1002
1012
|
},
|
|
@@ -1019,7 +1029,7 @@ export const mcpTools = [
|
|
|
1019
1029
|
},
|
|
1020
1030
|
{
|
|
1021
1031
|
name: 'ace-text_search',
|
|
1022
|
-
description: 'ACE Code Search:
|
|
1032
|
+
description: 'ACE Code Search: Literal text/regex pattern matching (grep-style search). Best for finding exact strings: TODOs, comments, log messages, error strings, string constants. NOT recommended for code understanding or exploring functionality - use semantic search tools for that. Use when you know the exact text pattern you are looking for.',
|
|
1023
1033
|
inputSchema: {
|
|
1024
1034
|
type: 'object',
|
|
1025
1035
|
properties: {
|