summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorandrew-kramer-inno <[email protected]>2026-01-15 09:40:37 -0800
committerGitHub <[email protected]>2026-01-15 11:40:37 -0600
commit4edb4fa4fa8735a205bd0750513e7c50adf35390 (patch)
treee4c24bd001396db8eca2bc955a0d5f1ac92f0c26
parent63176bb049d00643c65cd7dcd836403f8250022e (diff)
downloadopencode-4edb4fa4fa8735a205bd0750513e7c50adf35390.tar.gz
opencode-4edb4fa4fa8735a205bd0750513e7c50adf35390.zip
fix: handle broken symlinks gracefully in grep tool (#8612)
Co-authored-by: Alex Johnson <[email protected]>
-rw-r--r--packages/opencode/src/tool/grep.ts24
1 files changed, 21 insertions, 3 deletions
diff --git a/packages/opencode/src/tool/grep.ts b/packages/opencode/src/tool/grep.ts
index ad62621e0..097dedf4a 100644
--- a/packages/opencode/src/tool/grep.ts
+++ b/packages/opencode/src/tool/grep.ts
@@ -37,7 +37,15 @@ export const GrepTool = Tool.define("grep", {
await assertExternalDirectory(ctx, searchPath, { kind: "directory" })
const rgPath = await Ripgrep.filepath()
- const args = ["-nH", "--hidden", "--follow", "--field-match-separator=|", "--regexp", params.pattern]
+ const args = [
+ "-nH",
+ "--hidden",
+ "--follow",
+ "--no-messages",
+ "--field-match-separator=|",
+ "--regexp",
+ params.pattern,
+ ]
if (params.include) {
args.push("--glob", params.include)
}
@@ -52,7 +60,10 @@ export const GrepTool = Tool.define("grep", {
const errorOutput = await new Response(proc.stderr).text()
const exitCode = await proc.exited
- if (exitCode === 1) {
+ // Exit codes: 0 = matches found, 1 = no matches, 2 = errors (but may still have matches)
+ // With --no-messages, we suppress error output but still get exit code 2 for broken symlinks etc.
+ // Only fail if exit code is 2 AND no output was produced
+ if (exitCode === 1 || (exitCode === 2 && !output.trim())) {
return {
title: params.pattern,
metadata: { matches: 0, truncated: false },
@@ -60,10 +71,12 @@ export const GrepTool = Tool.define("grep", {
}
}
- if (exitCode !== 0) {
+ if (exitCode !== 0 && exitCode !== 2) {
throw new Error(`ripgrep failed: ${errorOutput}`)
}
+ const hasErrors = exitCode === 2
+
// Handle both Unix (\n) and Windows (\r\n) line endings
const lines = output.trim().split(/\r?\n/)
const matches = []
@@ -124,6 +137,11 @@ export const GrepTool = Tool.define("grep", {
outputLines.push("(Results are truncated. Consider using a more specific path or pattern.)")
}
+ if (hasErrors) {
+ outputLines.push("")
+ outputLines.push("(Some paths were inaccessible and skipped)")
+ }
+
return {
title: params.pattern,
metadata: {