summaryrefslogtreecommitdiff
path: root/packages/core/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/core/src/utils')
-rw-r--r--packages/core/src/utils/bfsFileSearch.test.ts39
-rw-r--r--packages/core/src/utils/bfsFileSearch.ts11
-rw-r--r--packages/core/src/utils/getFolderStructure.test.ts33
-rw-r--r--packages/core/src/utils/getFolderStructure.ts34
-rw-r--r--packages/core/src/utils/memoryDiscovery.ts15
5 files changed, 117 insertions, 15 deletions
diff --git a/packages/core/src/utils/bfsFileSearch.test.ts b/packages/core/src/utils/bfsFileSearch.test.ts
index 83e9b0b9..3ce452de 100644
--- a/packages/core/src/utils/bfsFileSearch.test.ts
+++ b/packages/core/src/utils/bfsFileSearch.test.ts
@@ -145,4 +145,43 @@ describe('bfsFileSearch', () => {
});
expect(result).toEqual(['/test/subdir1/file1.txt']);
});
+
+ it('should respect .geminiignore files', async () => {
+ const mockFs = vi.mocked(fsPromises);
+ const mockGitUtils = vi.mocked(gitUtils);
+
+ mockGitUtils.isGitRepository.mockReturnValue(false);
+
+ const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
+ vi.mocked(mockReaddir).mockImplementation(async (dir) => {
+ if (dir === '/test') {
+ return [
+ createMockDirent('.geminiignore', true),
+ createMockDirent('subdir1', false),
+ createMockDirent('subdir2', false),
+ ];
+ }
+ if (dir === '/test/subdir1') {
+ return [createMockDirent('file1.txt', true)];
+ }
+ if (dir === '/test/subdir2') {
+ return [createMockDirent('file1.txt', true)];
+ }
+ return [];
+ });
+
+ vi.mocked(fs).readFileSync.mockReturnValue('subdir2');
+
+ const fileService = new FileDiscoveryService('/test');
+ const result = await bfsFileSearch('/test', {
+ fileName: 'file1.txt',
+ fileService,
+ fileFilteringOptions: {
+ respectGitIgnore: true,
+ respectGeminiIgnore: true,
+ },
+ });
+
+ expect(result).toEqual(['/test/subdir1/file1.txt']);
+ });
});
diff --git a/packages/core/src/utils/bfsFileSearch.ts b/packages/core/src/utils/bfsFileSearch.ts
index e552f520..790521e0 100644
--- a/packages/core/src/utils/bfsFileSearch.ts
+++ b/packages/core/src/utils/bfsFileSearch.ts
@@ -8,7 +8,7 @@ import * as fs from 'fs/promises';
import * as path from 'path';
import { Dirent } from 'fs';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
-
+import { FileFilteringOptions } from '../config/config.js';
// Simple console logger for now.
// TODO: Integrate with a more robust server-side logger.
const logger = {
@@ -22,6 +22,7 @@ interface BfsFileSearchOptions {
maxDirs?: number;
debug?: boolean;
fileService?: FileDiscoveryService;
+ fileFilteringOptions?: FileFilteringOptions;
}
/**
@@ -69,7 +70,13 @@ export async function bfsFileSearch(
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
- if (fileService?.shouldGitIgnoreFile(fullPath)) {
+ if (
+ fileService?.shouldIgnoreFile(fullPath, {
+ respectGitIgnore: options.fileFilteringOptions?.respectGitIgnore,
+ respectGeminiIgnore:
+ options.fileFilteringOptions?.respectGeminiIgnore,
+ })
+ ) {
continue;
}
diff --git a/packages/core/src/utils/getFolderStructure.test.ts b/packages/core/src/utils/getFolderStructure.test.ts
index 3d7c125e..b6354745 100644
--- a/packages/core/src/utils/getFolderStructure.test.ts
+++ b/packages/core/src/utils/getFolderStructure.test.ts
@@ -307,6 +307,7 @@ describe('getFolderStructure gitignore', () => {
createDirent('file1.txt', 'file'),
createDirent('node_modules', 'dir'),
createDirent('ignored.txt', 'file'),
+ createDirent('gem_ignored.txt', 'file'),
createDirent('.gemini', 'dir'),
] as any;
}
@@ -327,6 +328,9 @@ describe('getFolderStructure gitignore', () => {
if (path === '/test/project/.gitignore') {
return 'ignored.txt\nnode_modules/\n.gemini/\n!/.gemini/config.yaml';
}
+ if (path === '/test/project/.geminiignore') {
+ return 'gem_ignored.txt\nnode_modules/\n.gemini/\n!/.gemini/config.yaml';
+ }
return '';
});
@@ -347,10 +351,37 @@ describe('getFolderStructure gitignore', () => {
const fileService = new FileDiscoveryService('/test/project');
const structure = await getFolderStructure('/test/project', {
fileService,
- respectGitIgnore: false,
+ fileFilteringOptions: {
+ respectGeminiIgnore: false,
+ respectGitIgnore: false,
+ },
});
expect(structure).toContain('ignored.txt');
// node_modules is still ignored by default
expect(structure).toContain('node_modules/...');
});
+
+ it('should ignore files and folders specified in .geminiignore', async () => {
+ const fileService = new FileDiscoveryService('/test/project');
+ const structure = await getFolderStructure('/test/project', {
+ fileService,
+ });
+ expect(structure).not.toContain('gem_ignored.txt');
+ expect(structure).toContain('node_modules/...');
+ expect(structure).not.toContain('logs.json');
+ });
+
+ it('should not ignore files if respectGeminiIgnore is false', async () => {
+ const fileService = new FileDiscoveryService('/test/project');
+ const structure = await getFolderStructure('/test/project', {
+ fileService,
+ fileFilteringOptions: {
+ respectGeminiIgnore: false,
+ respectGitIgnore: true, // Explicitly disable gemini ignore only
+ },
+ });
+ expect(structure).toContain('gem_ignored.txt');
+ // node_modules is still ignored by default
+ expect(structure).toContain('node_modules/...');
+ });
});
diff --git a/packages/core/src/utils/getFolderStructure.ts b/packages/core/src/utils/getFolderStructure.ts
index 6798a147..15588a4b 100644
--- a/packages/core/src/utils/getFolderStructure.ts
+++ b/packages/core/src/utils/getFolderStructure.ts
@@ -9,6 +9,8 @@ import { Dirent } from 'fs';
import * as path from 'path';
import { getErrorMessage, isNodeError } from './errors.js';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
+import { FileFilteringOptions } from '../config/config.js';
+import { DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js';
const MAX_ITEMS = 200;
const TRUNCATION_INDICATOR = '...';
@@ -26,16 +28,16 @@ interface FolderStructureOptions {
fileIncludePattern?: RegExp;
/** For filtering files. */
fileService?: FileDiscoveryService;
- /** Whether to use .gitignore patterns. */
- respectGitIgnore?: boolean;
+ /** File filtering ignore options. */
+ fileFilteringOptions?: FileFilteringOptions;
}
-
// Define a type for the merged options where fileIncludePattern remains optional
type MergedFolderStructureOptions = Required<
Omit<FolderStructureOptions, 'fileIncludePattern' | 'fileService'>
> & {
fileIncludePattern?: RegExp;
fileService?: FileDiscoveryService;
+ fileFilteringOptions?: FileFilteringOptions;
};
/** Represents the full, unfiltered information about a folder and its contents. */
@@ -126,8 +128,13 @@ async function readFullStructure(
}
const fileName = entry.name;
const filePath = path.join(currentPath, fileName);
- if (options.respectGitIgnore && options.fileService) {
- if (options.fileService.shouldGitIgnoreFile(filePath)) {
+ if (options.fileService) {
+ const shouldIgnore =
+ (options.fileFilteringOptions.respectGitIgnore &&
+ options.fileService.shouldGitIgnoreFile(filePath)) ||
+ (options.fileFilteringOptions.respectGeminiIgnore &&
+ options.fileService.shouldGeminiIgnoreFile(filePath));
+ if (shouldIgnore) {
continue;
}
}
@@ -160,14 +167,16 @@ async function readFullStructure(
const subFolderName = entry.name;
const subFolderPath = path.join(currentPath, subFolderName);
- let isIgnoredByGit = false;
- if (options.respectGitIgnore && options.fileService) {
- if (options.fileService.shouldGitIgnoreFile(subFolderPath)) {
- isIgnoredByGit = true;
- }
+ let isIgnored = false;
+ if (options.fileService) {
+ isIgnored =
+ (options.fileFilteringOptions.respectGitIgnore &&
+ options.fileService.shouldGitIgnoreFile(subFolderPath)) ||
+ (options.fileFilteringOptions.respectGeminiIgnore &&
+ options.fileService.shouldGeminiIgnoreFile(subFolderPath));
}
- if (options.ignoredFolders.has(subFolderName) || isIgnoredByGit) {
+ if (options.ignoredFolders.has(subFolderName) || isIgnored) {
const ignoredSubFolder: FullFolderInfo = {
name: subFolderName,
path: subFolderPath,
@@ -295,7 +304,8 @@ export async function getFolderStructure(
ignoredFolders: options?.ignoredFolders ?? DEFAULT_IGNORED_FOLDERS,
fileIncludePattern: options?.fileIncludePattern,
fileService: options?.fileService,
- respectGitIgnore: options?.respectGitIgnore ?? true,
+ fileFilteringOptions:
+ options?.fileFilteringOptions ?? DEFAULT_FILE_FILTERING_OPTIONS,
};
try {
diff --git a/packages/core/src/utils/memoryDiscovery.ts b/packages/core/src/utils/memoryDiscovery.ts
index ab240ea8..33231823 100644
--- a/packages/core/src/utils/memoryDiscovery.ts
+++ b/packages/core/src/utils/memoryDiscovery.ts
@@ -15,6 +15,10 @@ import {
} from '../tools/memoryTool.js';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
import { processImports } from './memoryImportProcessor.js';
+import {
+ DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
+ FileFilteringOptions,
+} from '../config/config.js';
// Simple console logger, similar to the one previously in CLI's config.ts
// TODO: Integrate with a more robust server-side logger if available/appropriate.
@@ -85,6 +89,7 @@ async function getGeminiMdFilePathsInternal(
debugMode: boolean,
fileService: FileDiscoveryService,
extensionContextFilePaths: string[] = [],
+ fileFilteringOptions: FileFilteringOptions,
): Promise<string[]> {
const allPaths = new Set<string>();
const geminiMdFilenames = getAllGeminiMdFilenames();
@@ -181,11 +186,18 @@ async function getGeminiMdFilePathsInternal(
}
upwardPaths.forEach((p) => allPaths.add(p));
+ // Merge options with memory defaults, with options taking precedence
+ const mergedOptions = {
+ ...DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
+ ...fileFilteringOptions,
+ };
+
const downwardPaths = await bfsFileSearch(resolvedCwd, {
fileName: geminiMdFilename,
maxDirs: MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY,
debug: debugMode,
fileService,
+ fileFilteringOptions: mergedOptions, // Pass merged options as fileFilter
});
downwardPaths.sort(); // Sort for consistent ordering, though hierarchy might be more complex
if (debugMode && downwardPaths.length > 0)
@@ -282,11 +294,13 @@ export async function loadServerHierarchicalMemory(
debugMode: boolean,
fileService: FileDiscoveryService,
extensionContextFilePaths: string[] = [],
+ fileFilteringOptions?: FileFilteringOptions,
): Promise<{ memoryContent: string; fileCount: number }> {
if (debugMode)
logger.debug(
`Loading server hierarchical memory for CWD: ${currentWorkingDirectory}`,
);
+
// For the server, homedir() refers to the server process's home.
// This is consistent with how MemoryTool already finds the global path.
const userHomePath = homedir();
@@ -296,6 +310,7 @@ export async function loadServerHierarchicalMemory(
debugMode,
fileService,
extensionContextFilePaths,
+ fileFilteringOptions || DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
);
if (filePaths.length === 0) {
if (debugMode) logger.debug('No GEMINI.md files found in hierarchy.');