From bfe8d74e6bc42f3231152983678f5086d7c616c0 Mon Sep 17 00:00:00 2001 From: "gemini-cli[bot]" Date: Wed, 29 Apr 2026 22:31:24 +0000 Subject: [PATCH] # Fix: Inconsistent Case-Sensitivity in GrepTool This PR fixes an inconsistency in the `GrepTool` where the system grep strategy was case-sensitive, while the `git grep` and JavaScript fallback strategies were case-insensitive. ## Changes - Added the `-i` flag to the `grepArgs` array in the system grep strategy within `packages/core/src/tools/grep.ts`. - Added a unit test in `packages/core/src/tools/grep.test.ts` to verify that the `-i` flag is correctly passed to the system `grep` command. ## Impact All search strategies in `GrepTool` now behave consistently with regard to case-sensitivity (defaulting to case-insensitive). ## Verification - Ran `npm test -w @google/gemini-cli-core -- src/tools/grep.test.ts`. - All 33 tests passed, including the new regression test. --- packages/core/src/tools/grep.test.ts | 30 +++++++++++++++++++++++++++- packages/core/src/tools/grep.ts | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/core/src/tools/grep.test.ts b/packages/core/src/tools/grep.test.ts index 4af684b1cd..3a03a734c2 100644 --- a/packages/core/src/tools/grep.test.ts +++ b/packages/core/src/tools/grep.test.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2025 Google LLC + * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ @@ -314,6 +314,34 @@ describe('GrepTool', () => { ); }, 30000); + it('should pass -i flag to system grep for case-insensitivity', async () => { + vi.mocked(execStreaming).mockImplementationOnce(() => + createLineGenerator(['fileA.txt:1:hello world']), + ); + + const params: GrepToolParams = { pattern: 'HELLO' }; + const invocation = grepTool.build(params) as unknown as { + isCommandAvailable: (command: string) => Promise; + execute: (options: ExecuteOptions) => Promise; + }; + // Force system grep strategy by mocking isCommandAvailable and ensuring git grep is not used + invocation.isCommandAvailable = vi.fn(async (command: string) => { + if (command === 'git') return false; + if (command === 'grep') return true; + return false; + }); + + await invocation.execute({ abortSignal }); + + expect(execStreaming).toHaveBeenCalledWith( + 'grep', + expect.arrayContaining(['-i']), + expect.objectContaining({ + cwd: expect.any(String), + }), + ); + }); + it('should throw an error if params are invalid', async () => { const params = { dir_path: '.' } as unknown as GrepToolParams; // Invalid: pattern missing expect(() => grepTool.build(params)).toThrow( diff --git a/packages/core/src/tools/grep.ts b/packages/core/src/tools/grep.ts index 34be588573..d89da94aab 100644 --- a/packages/core/src/tools/grep.ts +++ b/packages/core/src/tools/grep.ts @@ -465,7 +465,7 @@ class GrepToolInvocation extends BaseToolInvocation< const grepAvailable = await this.isCommandAvailable('grep'); if (grepAvailable) { strategyUsed = 'system grep'; - const grepArgs = ['-r', '-n', '-H', '-E', '-I']; + const grepArgs = ['-r', '-n', '-H', '-E', '-I', '-i']; // Extract directory names from exclusion patterns for grep --exclude-dir const globExcludes = this.fileExclusions.getGlobExcludes(); const commonExcludes = globExcludes