@zilliz/claude-context-core 0.1.11 → 0.1.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/dist/context.d.ts CHANGED
@@ -41,6 +41,11 @@ export declare class Context {
41
41
  * Get supported extensions
42
42
  */
43
43
  getSupportedExtensions(): string[];
44
+ /**
45
+ * Get supported extensions for the current operation without mutating
46
+ * the Context's persistent extension list.
47
+ */
48
+ getEffectiveSupportedExtensions(additionalExtensions?: string[]): string[];
44
49
  /**
45
50
  * Get ignore patterns
46
51
  */
@@ -81,6 +86,9 @@ export declare class Context {
81
86
  * @param codebasePath Codebase root path
82
87
  * @param progressCallback Optional progress callback function
83
88
  * @param forceReindex Whether to recreate the collection even if it exists
89
+ * @param additionalIgnorePatterns Request-scoped ignore patterns
90
+ * @param additionalSupportedExtensions Request-scoped file extensions
91
+ * @param requestSplitter Request-scoped splitter for this indexing run
84
92
  * @returns Indexing statistics
85
93
  */
86
94
  indexCodebase(codebasePath: string, progressCallback?: (progress: {
@@ -88,7 +96,7 @@ export declare class Context {
88
96
  current: number;
89
97
  total: number;
90
98
  percentage: number;
91
- }) => void, forceReindex?: boolean, additionalIgnorePatterns?: string[]): Promise<{
99
+ }) => void, forceReindex?: boolean, additionalIgnorePatterns?: string[], additionalSupportedExtensions?: string[], requestSplitter?: Splitter): Promise<{
92
100
  indexedFiles: number;
93
101
  totalChunks: number;
94
102
  status: 'completed' | 'limit_reached';
@@ -98,7 +106,7 @@ export declare class Context {
98
106
  current: number;
99
107
  total: number;
100
108
  percentage: number;
101
- }) => void): Promise<{
109
+ }) => void, additionalIgnorePatterns?: string[], additionalSupportedExtensions?: string[], requestSplitter?: Splitter): Promise<{
102
110
  added: number;
103
111
  removed: number;
104
112
  modified: number;
@@ -112,6 +120,11 @@ export declare class Context {
112
120
  * @param threshold Similarity threshold
113
121
  */
114
122
  semanticSearch(codebasePath: string, query: string, topK?: number, threshold?: number, filterExpr?: string): Promise<SemanticSearchResult[]>;
123
+ /**
124
+ * Deduplicate search results by file + line range overlap.
125
+ * Keeps higher-scored result when two results from the same file overlap >50%.
126
+ */
127
+ private deduplicateResults;
115
128
  /**
116
129
  * Check if index exists for codebase
117
130
  * @param codebasePath Codebase path to check
@@ -241,6 +254,7 @@ export declare class Context {
241
254
  * @returns True if pattern matches
242
255
  */
243
256
  private isPatternMatch;
257
+ private matchesDirectoryPattern;
244
258
  /**
245
259
  * Simple glob matching supporting * wildcard
246
260
  * @param text Text to test
@@ -261,6 +275,7 @@ export declare class Context {
261
275
  * @returns Array of custom ignore patterns
262
276
  */
263
277
  private getCustomIgnorePatternsFromEnv;
278
+ private normalizeExtensions;
264
279
  /**
265
280
  * Add custom extensions (from MCP or other sources) without replacing existing ones
266
281
  * @param customExtensions Array of custom extensions to add
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
@@ -37,31 +37,72 @@ const fs = __importStar(require("fs/promises"));
37
37
  const os = __importStar(require("os"));
38
38
  const path = __importStar(require("path"));
39
39
  const context_1 = require("./context");
40
+ const embedding_1 = require("./embedding");
41
+ const synchronizer_1 = require("./sync/synchronizer");
42
+ class TestEmbedding extends embedding_1.Embedding {
43
+ constructor() {
44
+ super(...arguments);
45
+ this.maxTokens = 8192;
46
+ }
47
+ async detectDimension() {
48
+ return 3;
49
+ }
50
+ async embed(text) {
51
+ return { vector: [1, 0, 0], dimension: 3 };
52
+ }
53
+ async embedBatch(texts) {
54
+ return texts.map(() => ({ vector: [1, 0, 0], dimension: 3 }));
55
+ }
56
+ getDimension() {
57
+ return 3;
58
+ }
59
+ getProvider() {
60
+ return 'test';
61
+ }
62
+ }
63
+ class TestSplitter {
64
+ async split(code, language, filePath) {
65
+ return [{
66
+ content: code,
67
+ metadata: {
68
+ startLine: 1,
69
+ endLine: 1,
70
+ language,
71
+ filePath,
72
+ },
73
+ }];
74
+ }
75
+ setChunkSize() { }
76
+ setChunkOverlap() { }
77
+ }
40
78
  const createVectorDatabase = () => ({
41
- createCollection: jest.fn(),
42
- createHybridCollection: jest.fn(),
43
- dropCollection: jest.fn(),
44
- hasCollection: jest.fn(),
45
- listCollections: jest.fn(),
46
- insert: jest.fn(),
47
- insertHybrid: jest.fn(),
48
- search: jest.fn(),
49
- hybridSearch: jest.fn(),
50
- delete: jest.fn(),
51
- query: jest.fn(),
52
- getCollectionDescription: jest.fn(),
53
- checkCollectionLimit: jest.fn(),
54
- getCollectionRowCount: jest.fn(),
79
+ createCollection: jest.fn().mockResolvedValue(undefined),
80
+ createHybridCollection: jest.fn().mockResolvedValue(undefined),
81
+ dropCollection: jest.fn().mockResolvedValue(undefined),
82
+ hasCollection: jest.fn().mockResolvedValue(false),
83
+ listCollections: jest.fn().mockResolvedValue([]),
84
+ insert: jest.fn().mockResolvedValue(undefined),
85
+ insertHybrid: jest.fn().mockResolvedValue(undefined),
86
+ search: jest.fn().mockResolvedValue([]),
87
+ hybridSearch: jest.fn().mockResolvedValue([]),
88
+ delete: jest.fn().mockResolvedValue(undefined),
89
+ query: jest.fn().mockResolvedValue([]),
90
+ getCollectionDescription: jest.fn().mockResolvedValue(''),
91
+ checkCollectionLimit: jest.fn().mockResolvedValue(true),
92
+ getCollectionRowCount: jest.fn().mockResolvedValue(0),
55
93
  });
56
94
  describe('Context ignore pattern isolation', () => {
57
95
  let tempRoot;
58
96
  let originalHome;
97
+ let originalHybridMode;
59
98
  beforeEach(async () => {
60
99
  tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'claude-context-ignore-'));
61
100
  const homeDir = path.join(tempRoot, 'home');
62
101
  await fs.mkdir(homeDir, { recursive: true });
63
102
  originalHome = process.env.HOME;
103
+ originalHybridMode = process.env.HYBRID_MODE;
64
104
  process.env.HOME = homeDir;
105
+ process.env.HYBRID_MODE = 'false';
65
106
  });
66
107
  afterEach(async () => {
67
108
  if (originalHome === undefined) {
@@ -70,6 +111,12 @@ describe('Context ignore pattern isolation', () => {
70
111
  else {
71
112
  process.env.HOME = originalHome;
72
113
  }
114
+ if (originalHybridMode === undefined) {
115
+ delete process.env.HYBRID_MODE;
116
+ }
117
+ else {
118
+ process.env.HYBRID_MODE = originalHybridMode;
119
+ }
73
120
  await fs.rm(tempRoot, { recursive: true, force: true });
74
121
  });
75
122
  it('does not leak file-based ignore patterns between codebases', async () => {
@@ -93,5 +140,89 @@ describe('Context ignore pattern isolation', () => {
93
140
  const withoutRequestIgnores = await context.getEffectiveIgnorePatterns(project);
94
141
  expect(withoutRequestIgnores).not.toContain('*.txt');
95
142
  });
143
+ it('does not leak request custom extensions into persistent supported extensions', () => {
144
+ const context = new context_1.Context({ vectorDatabase: createVectorDatabase() });
145
+ const withRequestExtensions = context.getEffectiveSupportedExtensions(['foo']);
146
+ expect(withRequestExtensions).toContain('.foo');
147
+ const withoutRequestExtensions = context.getSupportedExtensions();
148
+ expect(withoutRequestExtensions).not.toContain('.foo');
149
+ });
150
+ it('does not leak request custom extensions between codebase indexes', async () => {
151
+ const projectA = path.join(tempRoot, 'project-a');
152
+ const projectB = path.join(tempRoot, 'project-b');
153
+ await fs.mkdir(projectA);
154
+ await fs.mkdir(projectB);
155
+ await fs.writeFile(path.join(projectA, 'a.foo'), 'project a custom file');
156
+ await fs.writeFile(path.join(projectB, 'b.foo'), 'project b custom file');
157
+ const vectorDatabase = createVectorDatabase();
158
+ const context = new context_1.Context({
159
+ embedding: new TestEmbedding(),
160
+ vectorDatabase,
161
+ codeSplitter: new TestSplitter(),
162
+ });
163
+ await context.indexCodebase(projectA, undefined, false, [], ['foo']);
164
+ expect(vectorDatabase.insert).toHaveBeenCalledTimes(1);
165
+ expect(vectorDatabase.insert.mock.calls[0][1][0].relativePath).toBe('a.foo');
166
+ vectorDatabase.insert.mockClear();
167
+ await context.indexCodebase(projectB);
168
+ expect(vectorDatabase.insert).not.toHaveBeenCalled();
169
+ });
170
+ it('uses request options when recreating a synchronizer for change indexing', async () => {
171
+ const project = path.join(tempRoot, 'project-with-options');
172
+ await fs.mkdir(project);
173
+ await fs.writeFile(path.join(project, 'custom.foo'), 'custom extension file');
174
+ await fs.writeFile(path.join(project, 'ignored.ts'), 'ignored by request pattern');
175
+ const context = new context_1.Context({ vectorDatabase: createVectorDatabase() });
176
+ try {
177
+ await context.reindexByChange(project, undefined, ['*.ts'], ['foo']);
178
+ const collectionName = context.getCollectionName(project);
179
+ const synchronizer = context.getSynchronizers().get(collectionName);
180
+ expect(synchronizer).toBeDefined();
181
+ expect(synchronizer?.getFileHash('custom.foo')).toBeDefined();
182
+ expect(synchronizer?.getFileHash('ignored.ts')).toBeUndefined();
183
+ expect(context.getSupportedExtensions()).not.toContain('.foo');
184
+ }
185
+ finally {
186
+ await synchronizer_1.FileSynchronizer.deleteSnapshot(project);
187
+ }
188
+ });
189
+ it('treats leading-slash directory ignore patterns as root-anchored and recursive during indexing', async () => {
190
+ const project = path.join(tempRoot, 'project');
191
+ await fs.mkdir(path.join(project, 'Library'), { recursive: true });
192
+ await fs.mkdir(path.join(project, 'src', 'Library'), { recursive: true });
193
+ await fs.writeFile(path.join(project, '.gitignore'), '/Library/\n');
194
+ await fs.writeFile(path.join(project, 'Library', 'generated.md'), 'root library should be ignored');
195
+ await fs.writeFile(path.join(project, 'src', 'Library', 'nested.md'), 'nested library should stay');
196
+ await fs.writeFile(path.join(project, 'src', 'keep.md'), 'regular file should stay');
197
+ const vectorDatabase = createVectorDatabase();
198
+ const context = new context_1.Context({
199
+ embedding: new TestEmbedding(),
200
+ vectorDatabase,
201
+ codeSplitter: new TestSplitter(),
202
+ });
203
+ await context.indexCodebase(project);
204
+ const insertedDocuments = vectorDatabase.insert.mock.calls
205
+ .flatMap(([, documents]) => documents);
206
+ const indexedPaths = insertedDocuments
207
+ .map(document => document.relativePath.replace(/\\/g, '/'))
208
+ .sort();
209
+ expect(indexedPaths).toEqual([
210
+ 'src/Library/nested.md',
211
+ 'src/keep.md',
212
+ ]);
213
+ });
214
+ it('treats leading-slash directory ignore patterns as root-anchored and recursive during sync', async () => {
215
+ const project = path.join(tempRoot, 'project');
216
+ await fs.mkdir(path.join(project, 'Library'), { recursive: true });
217
+ await fs.mkdir(path.join(project, 'src', 'Library'), { recursive: true });
218
+ await fs.writeFile(path.join(project, 'Library', 'generated.md'), 'root library should be ignored');
219
+ await fs.writeFile(path.join(project, 'src', 'Library', 'nested.md'), 'nested library should stay');
220
+ await fs.writeFile(path.join(project, 'src', 'keep.md'), 'regular file should stay');
221
+ const synchronizer = new synchronizer_1.FileSynchronizer(project, ['/Library/'], ['.md']);
222
+ const fileHashes = await synchronizer.generateFileHashes(project);
223
+ expect(fileHashes.has(path.join('Library', 'generated.md'))).toBe(false);
224
+ expect(fileHashes.has(path.join('src', 'Library', 'nested.md'))).toBe(true);
225
+ expect(fileHashes.has(path.join('src', 'keep.md'))).toBe(true);
226
+ });
96
227
  });
97
228
  //# sourceMappingURL=context.ignore-patterns.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.ignore-patterns.test.js","sourceRoot":"","sources":["../src/context.ignore-patterns.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.ignore-patterns.test.js","sourceRoot":"","sources":["../src/context.ignore-patterns.test.ts"],"names":[],"mappings":"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"}
package/dist/context.js CHANGED
@@ -45,7 +45,7 @@ const DEFAULT_SUPPORTED_EXTENSIONS = [
45
45
  // Programming languages
46
46
  '.ts', '.tsx', '.js', '.jsx', '.py', '.java', '.cpp', '.c', '.h', '.hpp',
47
47
  '.cs', '.go', '.rs', '.php', '.rb', '.swift', '.kt', '.scala', '.m', '.mm',
48
- '.dart',
48
+ '.dart', '.sol',
49
49
  // Text and markup files
50
50
  '.md', '.markdown', '.ipynb',
51
51
  // '.txt', '.json', '.yaml', '.yml', '.xml', '.html', '.htm',
@@ -167,6 +167,14 @@ class Context {
167
167
  getSupportedExtensions() {
168
168
  return [...this.supportedExtensions];
169
169
  }
170
+ /**
171
+ * Get supported extensions for the current operation without mutating
172
+ * the Context's persistent extension list.
173
+ */
174
+ getEffectiveSupportedExtensions(additionalExtensions = []) {
175
+ const normalizedExtensions = this.normalizeExtensions(additionalExtensions);
176
+ return [...new Set([...this.supportedExtensions, ...normalizedExtensions])];
177
+ }
170
178
  /**
171
179
  * Get ignore patterns
172
180
  */
@@ -268,12 +276,16 @@ class Context {
268
276
  * @param codebasePath Codebase root path
269
277
  * @param progressCallback Optional progress callback function
270
278
  * @param forceReindex Whether to recreate the collection even if it exists
279
+ * @param additionalIgnorePatterns Request-scoped ignore patterns
280
+ * @param additionalSupportedExtensions Request-scoped file extensions
281
+ * @param requestSplitter Request-scoped splitter for this indexing run
271
282
  * @returns Indexing statistics
272
283
  */
273
- async indexCodebase(codebasePath, progressCallback, forceReindex = false, additionalIgnorePatterns = []) {
284
+ async indexCodebase(codebasePath, progressCallback, forceReindex = false, additionalIgnorePatterns = [], additionalSupportedExtensions = [], requestSplitter) {
274
285
  const isHybrid = this.getIsHybrid();
275
286
  const searchType = isHybrid === true ? 'hybrid search' : 'semantic search';
276
287
  console.log(`[Context] 🚀 Starting to index codebase with ${searchType}: ${codebasePath}`);
288
+ const splitter = requestSplitter || this.codeSplitter;
277
289
  // 1. Compute ignore patterns for this codebase/request without
278
290
  // retaining file-based patterns from previous codebases.
279
291
  const ignorePatterns = await this.loadIgnorePatterns(codebasePath, additionalIgnorePatterns);
@@ -283,7 +295,8 @@ class Context {
283
295
  await this.prepareCollection(codebasePath, forceReindex);
284
296
  // 3. Recursively traverse codebase to get all supported files
285
297
  progressCallback?.({ phase: 'Scanning files...', current: 5, total: 100, percentage: 5 });
286
- const codeFiles = await this.getCodeFiles(codebasePath, ignorePatterns);
298
+ const supportedExtensions = this.getEffectiveSupportedExtensions(additionalSupportedExtensions);
299
+ const codeFiles = await this.getCodeFiles(codebasePath, ignorePatterns, supportedExtensions);
287
300
  console.log(`[Context] 📁 Found ${codeFiles.length} code files`);
288
301
  if (codeFiles.length === 0) {
289
302
  progressCallback?.({ phase: 'No files to index', current: 100, total: 100, percentage: 100 });
@@ -304,7 +317,7 @@ class Context {
304
317
  total: totalFiles,
305
318
  percentage: Math.round(progressPercentage)
306
319
  });
307
- });
320
+ }, splitter);
308
321
  console.log(`[Context] ✅ Codebase indexing completed! Processed ${result.processedFiles} files in total, generated ${result.totalChunks} code chunks`);
309
322
  progressCallback?.({
310
323
  phase: 'Indexing complete!',
@@ -318,14 +331,17 @@ class Context {
318
331
  status: result.status
319
332
  };
320
333
  }
321
- async reindexByChange(codebasePath, progressCallback) {
334
+ async reindexByChange(codebasePath, progressCallback, additionalIgnorePatterns = [], additionalSupportedExtensions = [], requestSplitter) {
322
335
  const collectionName = this.getCollectionName(codebasePath);
323
336
  const synchronizer = this.synchronizers.get(collectionName);
337
+ const splitter = requestSplitter || this.codeSplitter;
324
338
  if (!synchronizer) {
325
- // Load project-specific ignore patterns before creating FileSynchronizer.
326
- const ignorePatterns = await this.loadIgnorePatterns(codebasePath);
339
+ // Recreate the synchronizer with the same request-scoped options that
340
+ // were used for the original indexing task.
341
+ const ignorePatterns = await this.loadIgnorePatterns(codebasePath, additionalIgnorePatterns);
342
+ const supportedExtensions = this.getEffectiveSupportedExtensions(additionalSupportedExtensions);
327
343
  // To be safe, let's initialize if it's not there.
328
- const newSynchronizer = new synchronizer_1.FileSynchronizer(codebasePath, ignorePatterns, this.supportedExtensions);
344
+ const newSynchronizer = new synchronizer_1.FileSynchronizer(codebasePath, ignorePatterns, supportedExtensions);
329
345
  await newSynchronizer.initialize();
330
346
  this.synchronizers.set(collectionName, newSynchronizer);
331
347
  }
@@ -360,7 +376,7 @@ class Context {
360
376
  if (filesToIndex.length > 0) {
361
377
  await this.processFileList(filesToIndex, codebasePath, (filePath, fileIndex, totalFiles) => {
362
378
  updateProgress(`Indexed ${filePath} (${fileIndex}/${totalFiles})`);
363
- });
379
+ }, splitter);
364
380
  }
365
381
  console.log(`[Context] ✅ Re-indexing complete. Added: ${added.length}, Removed: ${removed.length}, Modified: ${modified.length}`);
366
382
  progressCallback?.({ phase: 'Re-indexing complete!', current: totalChanges, total: totalChanges, percentage: 100 });
@@ -448,11 +464,12 @@ class Context {
448
464
  language: result.document.metadata.language || 'unknown',
449
465
  score: result.score
450
466
  }));
451
- console.log(`[Context] Found ${results.length} relevant hybrid results`);
452
- if (results.length > 0) {
453
- console.log(`[Context] 🔍 Top result score: ${results[0].score}, path: ${results[0].relativePath}`);
467
+ const dedupedResults = this.deduplicateResults(results);
468
+ console.log(`[Context] ✅ Found ${results.length} results, ${dedupedResults.length} after dedup`);
469
+ if (dedupedResults.length > 0) {
470
+ console.log(`[Context] 🔍 Top result score: ${dedupedResults[0].score}, path: ${dedupedResults[0].relativePath}`);
454
471
  }
455
- return results;
472
+ return dedupedResults;
456
473
  }
457
474
  else {
458
475
  // Regular semantic search
@@ -469,9 +486,35 @@ class Context {
469
486
  language: result.document.metadata.language || 'unknown',
470
487
  score: result.score
471
488
  }));
472
- console.log(`[Context] Found ${results.length} relevant results`);
473
- return results;
489
+ const dedupedResults = this.deduplicateResults(results);
490
+ console.log(`[Context] ✅ Found ${results.length} results, ${dedupedResults.length} after dedup`);
491
+ return dedupedResults;
492
+ }
493
+ }
494
+ /**
495
+ * Deduplicate search results by file + line range overlap.
496
+ * Keeps higher-scored result when two results from the same file overlap >50%.
497
+ */
498
+ deduplicateResults(results) {
499
+ const kept = [];
500
+ for (const result of results) {
501
+ const overlaps = kept.some((existing) => {
502
+ if (existing.relativePath !== result.relativePath)
503
+ return false;
504
+ const overlapStart = Math.max(existing.startLine, result.startLine);
505
+ const overlapEnd = Math.min(existing.endLine, result.endLine);
506
+ if (overlapStart > overlapEnd)
507
+ return false;
508
+ // Line ranges are inclusive (endLine = startLine + N - 1).
509
+ const overlapSize = overlapEnd - overlapStart + 1;
510
+ const resultSize = result.endLine - result.startLine + 1;
511
+ return resultSize > 0 && overlapSize / resultSize > 0.5;
512
+ });
513
+ if (!overlaps) {
514
+ kept.push(result);
515
+ }
474
516
  }
517
+ return kept;
475
518
  }
476
519
  /**
477
520
  * Check if index exists for codebase
@@ -591,7 +634,7 @@ class Context {
591
634
  /**
592
635
  * Recursively get all code files in the codebase
593
636
  */
594
- async getCodeFiles(codebasePath, ignorePatterns = this.ignorePatterns) {
637
+ async getCodeFiles(codebasePath, ignorePatterns = this.ignorePatterns, supportedExtensions = this.supportedExtensions) {
595
638
  const files = [];
596
639
  const traverseDirectory = async (currentPath) => {
597
640
  const entries = await fs.promises.readdir(currentPath, { withFileTypes: true });
@@ -606,7 +649,7 @@ class Context {
606
649
  }
607
650
  else if (entry.isFile()) {
608
651
  const ext = path.extname(entry.name);
609
- if (this.supportedExtensions.includes(ext)) {
652
+ if (supportedExtensions.includes(ext)) {
610
653
  files.push(fullPath);
611
654
  }
612
655
  }
@@ -622,7 +665,7 @@ class Context {
622
665
  * @param onFileProcessed Callback called when each file is processed
623
666
  * @returns Object with processed file count and total chunk count
624
667
  */
625
- async processFileList(filePaths, codebasePath, onFileProcessed) {
668
+ async processFileList(filePaths, codebasePath, onFileProcessed, splitter = this.codeSplitter) {
626
669
  const isHybrid = this.getIsHybrid();
627
670
  const EMBEDDING_BATCH_SIZE = Math.max(1, parseInt(env_manager_1.envManager.get('EMBEDDING_BATCH_SIZE') || '100', 10));
628
671
  const CHUNK_LIMIT = 450000;
@@ -636,7 +679,7 @@ class Context {
636
679
  try {
637
680
  const content = await fs.promises.readFile(filePath, 'utf-8');
638
681
  const language = this.getLanguageFromExtension(path.extname(filePath));
639
- const chunks = await this.codeSplitter.split(content, language, filePath);
682
+ const chunks = await splitter.split(content, language, filePath);
640
683
  // Log files with many chunks or large content
641
684
  if (chunks.length > 50) {
642
685
  console.warn(`[Context] ⚠️ File ${filePath} generated ${chunks.length} chunks (${Math.round(content.length / 1024)}KB)`);
@@ -808,6 +851,7 @@ class Context {
808
851
  '.m': 'objective-c',
809
852
  '.mm': 'objective-c',
810
853
  '.dart': 'dart',
854
+ '.sol': 'solidity',
811
855
  '.ipynb': 'jupyter'
812
856
  };
813
857
  return languageMap[ext] || 'text';
@@ -992,22 +1036,46 @@ class Context {
992
1036
  * @returns True if pattern matches
993
1037
  */
994
1038
  isPatternMatch(filePath, pattern) {
1039
+ const cleanPath = filePath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
1040
+ const normalizedPattern = pattern.replace(/\\/g, '/');
1041
+ const cleanPattern = normalizedPattern.replace(/^\/+|\/+$/g, '');
1042
+ const isRootAnchored = normalizedPattern.startsWith('/');
1043
+ const isDirectoryPattern = normalizedPattern.endsWith('/');
1044
+ if (!cleanPath || !cleanPattern) {
1045
+ return false;
1046
+ }
995
1047
  // Handle directory patterns (ending with /)
996
- if (pattern.endsWith('/')) {
997
- const dirPattern = pattern.slice(0, -1);
998
- const pathParts = filePath.split('/');
999
- return pathParts.some(part => this.simpleGlobMatch(part, dirPattern));
1048
+ if (isDirectoryPattern) {
1049
+ if (isRootAnchored) {
1050
+ return this.simpleGlobMatch(cleanPath, cleanPattern) ||
1051
+ cleanPath.startsWith(`${cleanPattern}/`);
1052
+ }
1053
+ return this.matchesDirectoryPattern(cleanPath, cleanPattern);
1054
+ }
1055
+ if (isRootAnchored) {
1056
+ return this.simpleGlobMatch(cleanPath, cleanPattern);
1000
1057
  }
1001
1058
  // Handle file patterns
1002
- if (pattern.includes('/')) {
1059
+ if (cleanPattern.includes('/')) {
1003
1060
  // Pattern with path separator - match exact path
1004
- return this.simpleGlobMatch(filePath, pattern);
1061
+ return this.simpleGlobMatch(cleanPath, cleanPattern);
1005
1062
  }
1006
1063
  else {
1007
1064
  // Pattern without path separator - match filename in any directory
1008
- const fileName = path.basename(filePath);
1009
- return this.simpleGlobMatch(fileName, pattern);
1065
+ const fileName = path.basename(cleanPath);
1066
+ return this.simpleGlobMatch(fileName, cleanPattern);
1067
+ }
1068
+ }
1069
+ matchesDirectoryPattern(filePath, dirPattern) {
1070
+ const pathParts = filePath.split('/');
1071
+ const dirPartCount = dirPattern.split('/').length;
1072
+ for (let i = 0; i <= pathParts.length - dirPartCount; i++) {
1073
+ const candidate = pathParts.slice(i, i + dirPartCount).join('/');
1074
+ if (this.simpleGlobMatch(candidate, dirPattern)) {
1075
+ return true;
1076
+ }
1010
1077
  }
1078
+ return false;
1011
1079
  }
1012
1080
  /**
1013
1081
  * Simple glob matching supporting * wildcard
@@ -1071,6 +1139,12 @@ class Context {
1071
1139
  return [];
1072
1140
  }
1073
1141
  }
1142
+ normalizeExtensions(extensions) {
1143
+ return extensions
1144
+ .map(ext => ext.trim())
1145
+ .filter(ext => ext.length > 0)
1146
+ .map(ext => ext.startsWith('.') ? ext : `.${ext}`);
1147
+ }
1074
1148
  /**
1075
1149
  * Add custom extensions (from MCP or other sources) without replacing existing ones
1076
1150
  * @param customExtensions Array of custom extensions to add
@@ -1078,8 +1152,7 @@ class Context {
1078
1152
  addCustomExtensions(customExtensions) {
1079
1153
  if (customExtensions.length === 0)
1080
1154
  return;
1081
- // Ensure extensions start with dot
1082
- const normalizedExtensions = customExtensions.map(ext => ext.startsWith('.') ? ext : `.${ext}`);
1155
+ const normalizedExtensions = this.normalizeExtensions(customExtensions);
1083
1156
  // Merge current extensions with new custom extensions, avoiding duplicates
1084
1157
  const mergedExtensions = [...this.supportedExtensions, ...normalizedExtensions];
1085
1158
  const uniqueExtensions = [...new Set(mergedExtensions)];