From 8c4e873899b97f6abd14bc45928ccb465f83010c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Hou=C5=A1ka?= Date: Wed, 21 Oct 2026 21:25:32 +0200 Subject: [PATCH] fix(coding-agent): grep tool ignores ripgrep config via --no-config The built-in grep tool spawned rg with the inherited environment, so RIPGREP_CONFIG_PATH (e.g. a config containing --fixed-strings) silently changed tool semantics: literal: false searches became literal and the agent got incomplete results with no error. Pass --no-config so the tool contract is deterministic. Users who want custom rg behavior can use the bash tool or wrap grep in an extension. closes #11203 --- packages/coding-agent/src/core/tools/grep.ts | 4 +++- packages/coding-agent/test/tools.test.ts | 25 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/core/tools/grep.ts b/packages/coding-agent/src/core/tools/grep.ts index 44f7e212b..a9562c69f 100644 --- a/packages/coding-agent/src/core/tools/grep.ts +++ b/packages/coding-agent/src/core/tools/grep.ts @@ -159,7 +159,9 @@ export function createGrepToolDefinition( return lines; }; - const args: string[] = ["--json", "--line-number", "--color=never", "--hidden"]; + // --no-config: the tool contract (literal, glob, limit, ...) must not depend on + // ambient user config like RIPGREP_CONFIG_PATH. Users can customize via bash or extensions. + const args: string[] = ["--no-config", "--json", "--line-number", "--color=never", "--hidden"]; if (ignoreCase) args.push("--ignore-case"); if (literal) args.push("--fixed-strings"); if (glob) args.push("--glob", glob); diff --git a/packages/coding-agent/test/tools.test.ts b/packages/coding-agent/test/tools.test.ts index ae1644396..91432623f 100644 --- a/packages/coding-agent/test/tools.test.ts +++ b/packages/coding-agent/test/tools.test.ts @@ -908,6 +908,31 @@ describe("Coding Agent Tools", () => { expect(output).not.toContain("match two"); }); + // https://github.com/earendil-works/pi/issues/11203 + it("should ignore RIPGREP_CONFIG_PATH", async () => { + const configFile = join(testDir, "rg-config"); + const testFile = join(testDir, "fixture.txt"); + writeFileSync(configFile, "--fixed-strings\n"); + writeFileSync(testFile, "aXb\na.b\n"); + + const previous = process.env.RIPGREP_CONFIG_PATH; + process.env.RIPGREP_CONFIG_PATH = configFile; + try { + const result = await grepTool.execute("test-call-rg-config", { + pattern: "a.b", + path: testFile, + literal: false, + }); + + const output = getTextOutput(result); + expect(output).toContain("fixture.txt:1: aXb"); + expect(output).toContain("fixture.txt:2: a.b"); + } finally { + if (previous === undefined) delete process.env.RIPGREP_CONFIG_PATH; + else process.env.RIPGREP_CONFIG_PATH = previous; + } + }); + it("should treat flag-like patterns as search text", async () => { const marker = join(testDir, "grep-injection-marker"); const payload = join(testDir, "payload.sh");