Merge tag 'v0.3.0' into chore/sync-gemini-cli-v0.3.0

This commit is contained in:
mingholy.lmh
2025-09-10 21:01:40 +08:00
583 changed files with 30160 additions and 10770 deletions

View File

@@ -5,13 +5,17 @@
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { GrepTool, GrepToolParams } from './grep.js';
import path from 'path';
import fs from 'fs/promises';
import os from 'os';
import { Config } from '../config/config.js';
import type { GrepToolParams } from './grep.js';
import { GrepTool } from './grep.js';
import path from 'node:path';
import fs from 'node:fs/promises';
import os from 'node:os';
import type { Config } from '../config/config.js';
import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
import { ToolErrorType } from './tool-error.js';
import * as glob from 'glob';
vi.mock('glob', { spy: true });
// Mock the child_process module to control grep/git grep behavior
vi.mock('child_process', () => ({
@@ -33,14 +37,12 @@ describe('GrepTool', () => {
let grepTool: GrepTool;
const abortSignal = new AbortController().signal;
const mockFileService = {
getGeminiIgnorePatterns: () => [],
} as unknown as FileDiscoveryService;
const mockConfig = {
getTargetDir: () => tempRootDir,
getWorkspaceContext: () => createMockWorkspaceContext(tempRootDir),
getFileService: () => mockFileService,
getFileExclusions: () => ({
getGlobExcludes: () => [],
}),
} as unknown as Config;
beforeEach(async () => {
@@ -230,42 +232,13 @@ describe('GrepTool', () => {
);
});
it('should exclude files matching geminiIgnorePatterns', async () => {
// Create a file that should be ignored
await fs.writeFile(
path.join(tempRootDir, 'ignored-file.txt'),
'this file should be ignored\nit contains the word world',
);
// Update the mock file service to return ignore patterns
mockFileService.getGeminiIgnorePatterns = () => ['ignored-file.txt'];
// Re-create the grep tool with the updated mock
const grepToolWithIgnore = new GrepTool(mockConfig);
// Search for 'world' which exists in both the regular file and the ignored file
const params: GrepToolParams = { pattern: 'world' };
const invocation = grepToolWithIgnore.build(params);
it('should return a GREP_EXECUTION_ERROR on failure', async () => {
vi.mocked(glob.globStream).mockRejectedValue(new Error('Glob failed'));
const params: GrepToolParams = { pattern: 'hello' };
const invocation = grepTool.build(params);
const result = await invocation.execute(abortSignal);
// Should only find matches in the non-ignored files (3 matches)
expect(result.llmContent).toContain(
'Found 3 matches for pattern "world" in the workspace directory',
);
// Should find matches in the regular files
expect(result.llmContent).toContain('File: fileA.txt');
expect(result.llmContent).toContain('L1: hello world');
expect(result.llmContent).toContain('L2: second line with world');
expect(result.llmContent).toContain(
`File: ${path.join('sub', 'fileC.txt')}`,
);
expect(result.llmContent).toContain('L1: another world in sub dir');
// Should NOT find matches in the ignored file
expect(result.llmContent).not.toContain('ignored-file.txt');
expect(result.returnDisplay).toBe('Found 3 matches');
expect(result.error?.type).toBe(ToolErrorType.GREP_EXECUTION_ERROR);
vi.mocked(glob.globStream).mockReset();
});
});
@@ -285,15 +258,13 @@ describe('GrepTool', () => {
);
// Create a mock config with multiple directories
const multiDirFileService = {
getGeminiIgnorePatterns: () => [],
};
const multiDirConfig = {
getTargetDir: () => tempRootDir,
getWorkspaceContext: () =>
createMockWorkspaceContext(tempRootDir, [secondDir]),
getFileService: () => multiDirFileService,
getFileExclusions: () => ({
getGlobExcludes: () => [],
}),
} as unknown as Config;
const multiDirGrepTool = new GrepTool(multiDirConfig);
@@ -340,15 +311,13 @@ describe('GrepTool', () => {
);
// Create a mock config with multiple directories
const multiDirFileService = {
getGeminiIgnorePatterns: () => [],
};
const multiDirConfig = {
getTargetDir: () => tempRootDir,
getWorkspaceContext: () =>
createMockWorkspaceContext(tempRootDir, [secondDir]),
getFileService: () => multiDirFileService,
getFileExclusions: () => ({
getGlobExcludes: () => [],
}),
} as unknown as Config;
const multiDirGrepTool = new GrepTool(multiDirConfig);
@@ -408,6 +377,9 @@ describe('GrepTool', () => {
getTargetDir: () => tempRootDir,
getWorkspaceContext: () =>
createMockWorkspaceContext(tempRootDir, ['/another/dir']),
getFileExclusions: () => ({
getGlobExcludes: () => [],
}),
} as unknown as Config;
const multiDirGrepTool = new GrepTool(multiDirConfig);