Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/tools/definitions/grepSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export const grepSearchTool: Tool = {
function: {
name: BuiltInToolNames.GrepSearch,
description:
"Performs a regex search over the repository using ripgrep. Will not include results for many build, cache, secrets dirs/files. Output may be truncated, so use targeted queries",
"Performs a regular expression (regex) search over the repository using ripgrep. Will not include results for many build, cache, secrets dirs/files. Output may be truncated, so use targeted queries",
parameters: {
type: "object",
required: ["query"],
properties: {
query: {
type: "string",
description:
"The search query to use. Must be the exact string to be searched or a valid ripgrep expression. Use regex with alternation (e.g., 'word1|word2|word3) or character classes to find multiple potential words in a single search.",
"The regex pattern to search for within file contents. Use regex with alternation (e.g., 'word1|word2|word3') or character classes to find multiple potential words in a single search.",
},
},
},
Expand Down
10 changes: 0 additions & 10 deletions core/util/regexValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,6 @@ export function prepareQueryForRipgrep(query: string): {
query: string;
warning?: string;
} {
// Check if it looks like a literal search that should be escaped
if (looksLikeLiteralSearch(query)) {
return {
query: escapeLiteralForRegex(query),
warning:
"Query contained special regex characters and was escaped for literal text search",
};
}

// Otherwise validate and sanitize as regex
const validation = validateAndSanitizeRegex(query);

return {
Expand Down
27 changes: 7 additions & 20 deletions core/util/regexValidator.vitest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ describe("looksLikeLiteralSearch", () => {
describe("prepareQueryForRipgrep", () => {
it("should escape literal-looking queries", () => {
const result = prepareQueryForRipgrep("hello.world");
expect(result.query).toBe("hello\\.world");
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("hello.world");
});

it("should sanitize regex patterns", () => {
Expand All @@ -130,14 +129,12 @@ describe("prepareQueryForRipgrep", () => {
describe("real-world examples", () => {
it("should escape file patterns", () => {
const result = prepareQueryForRipgrep("*.js");
expect(result.query).toBe("\\*\\.js");
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("*.js");
});

it("should escape function calls", () => {
const result = prepareQueryForRipgrep("console.log()");
expect(result.query).toBe("console\\.log\\(\\)");
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("console.log()");
});

it("should not escape proper regex patterns", () => {
Expand All @@ -163,8 +160,7 @@ describe("problematic patterns that originally failed", () => {

it("should handle dollar signs in shell patterns", () => {
const result = prepareQueryForRipgrep("$(command)");
expect(result.query).toBe("\\$\\(command\\)");
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("$(command)");
});

it("should handle escaped dollar signs", () => {
Expand Down Expand Up @@ -253,8 +249,7 @@ describe("patterns that should NOT be over-sanitized", () => {
describe("edge cases that could trigger false positives", () => {
it("should not treat mathematical expressions as problematic", () => {
const result = prepareQueryForRipgrep("a + b * c");
expect(result.query).toBe("a \\+ b \\* c"); // Should be escaped as literal
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("a + b * c"); // Should be escaped as literal
});

it("should not break regex that uses word boundaries", () => {
Expand All @@ -271,8 +266,7 @@ describe("patterns that should NOT be over-sanitized", () => {

it("should not treat IPv4 addresses as problematic regex", () => {
const result = prepareQueryForRipgrep("192.168.1.1");
expect(result.query).toBe("192\\.168\\.1\\.1"); // Should be escaped as literal
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("192.168.1.1"); // Should be escaped as literal
});

it("should not break hex color codes", () => {
Expand All @@ -285,8 +279,7 @@ describe("patterns that should NOT be over-sanitized", () => {
describe("patterns that should preserve user intent", () => {
it("should not sanitize intentional regex alternation", () => {
const result = prepareQueryForRipgrep("(foo|bar)");
expect(result.query).toBe("\\(foo\\|bar\\)"); // Should be escaped as literal since unescaped
expect(result.warning).toContain("escaped for literal text search");
expect(result.query).toBe("(foo|bar)"); // Should be escaped as literal since unescaped
});

it("should preserve escaped alternation in regex", () => {
Expand All @@ -300,11 +293,5 @@ describe("patterns that should NOT be over-sanitized", () => {
expect(result.query).toBe("name LIKE '%john%'"); // No regex metacharacters here
expect(result.warning).toBeUndefined();
});

it("should not break CSS selectors when used as literal search", () => {
const result = prepareQueryForRipgrep(".class-name > div:nth-child(2)");
expect(result.query).toBe("\\.class-name > div:nth-child\\(2\\)");
expect(result.warning).toContain("escaped for literal text search");
});
});
});
Loading