8bba7357b1
Addresses cubic-dev-ai P1 + P2 findings on #4115. The original PR relaxed `exitCode > 1` to `> 2` based on the (wrong) claim that ripgrep exits 2 only on non-fatal I/O issues. ripgrep actually uses exit code 2 for BOTH fatal errors (pattern syntax, invalid args) AND non-fatal I/O issues; GNU grep (the fallback backend in grep/cli.ts) likewise uses 2 for fatal errors. So `> 2` would silently suppress fatal errors. The correct fix is just `--no-messages`, which suppresses ripgrep's stderr only for soft I/O issues (broken symlinks, permission denied) while leaving fatal-error messages intact. With the gate kept at `exitCode > 1 && stderr.trim()`: - Broken symlink: ripgrep exits 2, stderr is empty (suppressed) → `stderr.trim()` is falsy → gate fails → partial results survive. - Fatal error: ripgrep exits 2, stderr has the real error message (not suppressed by --no-messages) → gate triggers → error returned. Reverting both `exitCode > 1` → `> 2` changes; keeping the `--no-messages` flag additions and the regression test (test comment updated to describe the cleaner architecture). Verification: bun test src/tools/glob/ src/tools/grep/ → 30 pass / 0 fail. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>