Skip to content

fix(grep): keep files without the pattern when grep -v is used - #442

Open
breken-ai wants to merge 1 commit into
activeloopai:mainfrom
breken-ai:fix/grep-invert-keeps-nonmatching-files
Open

breken-ai wants to merge 1 commit into
activeloopai:mainfrom
breken-ai:fix/grep-invert-keeps-nonmatching-files

Conversation

@breken-ai

@breken-ai breken-ai commented Sep 25, 2026 •

Copy link
Copy Markdown

Summary

grep -v foo <dir> should print every line that does not contain foo. That includes all lines of files that never mention foo.

buildGrepSearchOptions (src/shell/grep-core.ts) ignored invertMatch. It still sent the normal content prefilter (summary::text ILIKE '%foo%' / message::text ILIKE '%foo%'), so the backend only returned rows that contain the pattern. Files without it were dropped before refineGrepMatches could invert anything.

Reproduction on ce30de7, going through the same parseBashGrep → handleGrepDirect path the pre-tool-use hook uses (lexical mode, HIVEMIND_SEMANTIC_SEARCH=false). The fake backend applies the ILIKE filter:

memory: /summaries/a.md = "foo line\nkeep a", /summaries/b.md = "only b"
grep -v foo /summaries
  before: "keep a"                                   # b.md missing, prefix lost
  after:  "/summaries/a.md:keep a\n/summaries/b.md:only b"

With a single matching file the result is also wrong: grep -v foo /summaries/b.md returns (no matches) instead of the whole file.

Fix: when invertMatch is set, buildGrepSearchOptions keeps only the path filter. It skips the content, prefilter and multi-word filters, and the line-by-line refinement does the inversion. The grep-interceptor shell path and the hook fast path both use this builder, so both are fixed. Non-inverted searches are unchanged.

Out of scope: in semantic mode (an embedding is available), both paths emit every line of the top-K rows and don't apply -v. That is the existing semantic design, and this PR doesn't change it.

This PR adds a regression test in tests/claude-code/grep-core.test.ts. It fails on main because b.md is missing, and it passes with the fix.

Version Bump

Not bumped. This is a patch-level bug fix, so I've left the release decision to you.

Test plan

  • Tests pass locally (npm test): 5823 passed. The 17 failures are the same on the untouched main checkout and come from the environment: cowork-queue-leak, install-cowork, skillify-state, plugin-cache-gc-bundle, and two graph suites.
  • Relevant new tests added: grep -v keeps files that never contain the pattern. It fails on main and passes on this branch.
  • npm run typecheck passes. grep-core, grep-direct, grep-interceptor, mcp-server and the openclaw tools suites all pass (285 tests).
  • Version bumped in package.json, or no release needed for this change

An AI agent (breken-ai) found this and wrote the fix and test. I reviewed and ran everything above before opening the PR.

Summary by CodeRabbit

  • Bug Fixes
    • Corrected inverted text searches (grep -v) so they return nonmatching lines from files that contain the search term, as well as lines from files without it. This improves results when searching across scoped summary files.

grep -v prints the lines that do not match, but the SQL prefilter still asked
the backend only for rows containing the pattern. A memory file that never
mentions the pattern, whose every line grep -v should print, was dropped
before the line-by-line inversion ran. Skip the content prefilter for an
inverted match and keep only the path filter.
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: activeloopai/hivemind/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: b45ab85f-5091-4f6d-9656-ed163c22f78a

📥 Commits

Reviewing files that changed from the base of the PR and between ce30de7 and 00d6198.

📒 Files selected for processing (2)
  • src/shell/grep-core.ts
  • tests/claude-code/grep-core.test.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

Inverted grep now scans content without literal, alternation, or multi-word prefilters. A regression test checks output from files returned by the SQL prefilter and files omitted from its results.

Changes

Inverted grep

Layer / File(s) Summary
Inverted grep options and regression test
src/shell/grep-core.ts, tests/claude-code/grep-core.test.ts
The option builder enables content scanning and retains the configured LIKE or ILIKE operator without content prefilters. The test checks inverted-match output across SQL-filtered and omitted files.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: efenocchi

Merge Risk: ⚪ Minimal · up to 00d61

The change appears ready to merge after normal checks; no actionable risk is established by the supplied evidence.

Architecture Summary

Architecture risk: 🔵 Low · up to 00d61

The change affects 2 systems.

Changed systems: src, tests

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — src (service) was modified; 1 changed file maps to changed impact.
  • observed — tests (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in src/shell/grep-core.ts: When invertMatch is true, buildGrepSearchOptions now returns early with content scanning enabled and no literal, alternation, or multi-word prefilters; the pattern is escaped and the configured LIKE/ILIKE operator is retained. The existing refinement step handles inversion.
  • observed — Modified behavior in tests/claude-code/grep-core.test.ts: Added a test that simulates SQL filtering rows to those containing foo, then checks inverted matching emits the nonmatching line from that returned file and the line from a file omitted by the filter.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary fix: preserving files without the pattern during inverted grep searches.
Description check ✅ Passed The description includes the summary, technical cause, fix, scope, regression test, test results, and version-bump information. The version-bump checkbox is unchecked, but the description clearly stat…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant