Skip to content

fix: add timeout, home/root blocking, and default exclusions to glob tool#637

Merged
anandgupta42 merged 7 commits intomainfrom
fix/glob-timeout-hang
Apr 4, 2026
Merged

fix: add timeout, home/root blocking, and default exclusions to glob tool#637
anandgupta42 merged 7 commits intomainfrom
fix/glob-timeout-hang

Conversation

@anandgupta42
Copy link
Copy Markdown
Contributor

@anandgupta42 anandgupta42 commented Apr 4, 2026

What does this PR do?

Fixes glob tool hanging indefinitely when scanning broad directories (e.g., ~ with **/dbt_project.yml). Closes the 3 gaps vs industry best practices (Roo Code, Cline, Codex CLI).

Changes:

  1. 30s timeout — kills rg process after 30s, returns partial results with actionable guidance
  2. Home/root directory blocking — immediately returns error for / and ~ (like Roo Code/Cline)
  3. Default directory exclusions — skips node_modules/, dist/, build/, .cache/, .venv/, etc. (24 patterns from IGNORE_PATTERNS)
  4. Correct error handling — only treats AbortError from timeout as timeout; ENOENT/permission errors propagate
  5. Process cleanuplocalAbort controller kills rg on early loop exit (100-file limit)
  6. 11 tests covering all paths

Upstream context: Related upstream issues (#18954, #5220) exist but no fixes merged. Our approach matches industry patterns used by Roo Code (10s timeout + 16 dir exclusions + home blocking) and Cline.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Issue for this PR

Closes #636

How did you verify your code works?

  • All 11 glob tool tests pass
  • Existing util/glob (12), tool/grep (11), util/abort (6) tests pass — no regressions
  • Typecheck passes
  • Upstream marker check passes (--strict)
  • 6-model consensus code review — unanimous APPROVE

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • New and existing unit tests pass locally with my changes
  • I have added tests that prove my fix is effective
  • I ran the upstream marker check (bun run script/upstream/analyze.ts --markers --base main --strict)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added 30-second timeout for file searches with support for partial results.
    • Implemented automatic exclusion of common directories (node_modules, dist, build) from search patterns.
  • Bug Fixes

    • Added safety checks to prevent searches in overly broad directories (root filesystem and home directory).
    • Improved messaging for timeout scenarios and truncated results.

- Add `abortAfter` timeout that kills the `rg` process after 30 seconds
- Return partial results on timeout with actionable guidance message
- Fix error handling: only treat `AbortError` from timeout signal as
  timeout — properly re-throw ENOENT, permission, and user abort errors
- Add `localAbort` controller to kill `rg` process on early loop exit
  (e.g., 100-file limit hit), preventing background resource waste
- Add comprehensive glob tool tests (6 tests covering basic matching,
  truncation, user abort, nested patterns, and custom path)

Closes #636

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 256dc5c4-86af-41a0-bf88-7490cfe8773e

📥 Commits

Reviewing files that changed from the base of the PR and between f30aed0 and 50d3407.

📒 Files selected for processing (2)
  • packages/opencode/src/tool/glob.ts
  • packages/opencode/test/tool/glob.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/opencode/src/tool/glob.ts
  • packages/opencode/test/tool/glob.test.ts

📝 Walkthrough

Walkthrough

The glob tool adds a 30s abortable ripgrep scan, blocks searches for / and the user's home, applies default ignore patterns to globs, and updates output/metadata to distinguish timed-out, empty, partial, and truncated results.

Changes

Cohort / File(s) Summary
Glob tool implementation
packages/opencode/src/tool/glob.ts
Wraps ripgrep file iteration with a 30s abortAfter timeout combined via AbortSignal.any; rejects searches for / or os.homedir() as "too broad"; merges params.pattern with default exclusions (IGNORE_PATTERNS); suppresses timeout AbortError to return partial results and marks timedOut; treats non-timeout errors as real errors; updates output messages and metadata.truncated to reflect timeouts.
Glob tool tests
packages/opencode/test/tool/glob.test.ts
Adds comprehensive Bun tests covering pattern matching, recursive **, path scoping, default exclusions (node_modules, dist, build), 100-item truncation, abort-signal handling, blocking home/root searches, timeout reporting, and error propagation for true failures.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant GlobTool
participant AbortUtil
participant Ripgrep
participant FileSystem
Client->>GlobTool: call execute(params, ctx)
GlobTool->>AbortUtil: create localAbort + abortAfter(30s)
GlobTool->>GlobTool: validate path (reject / or homedir)
GlobTool->>Ripgrep: start files() with merged globs & AbortSignal.any(ctx.abort, localAbort)
Ripgrep->>FileSystem: scan filesystem (subject to ignores)
alt timeout occurs
AbortUtil->>Ripgrep: abort (kill child)
Ripgrep-->>GlobTool: throws AbortError (suppressed)
GlobTool->>Client: return partial results + "timed out" message, metadata.truncated = true
else completes or truncated by count
Ripgrep-->>GlobTool: yields matches
GlobTool->>Client: return results, metadata.truncated reflects count|timeout
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through files in fields of code,
A thirty-second carrot steadied my road.
If home or root are far too wide, I say "too broad"—no roam,
Partial baskets kept when timeouts come,
A tidy search, then back to my burrow home. 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main changes: timeout logic, home/root directory blocking, and default exclusions for the glob tool.
Description check ✅ Passed The PR description covers all required sections: a clear summary of what changed and why, a detailed test plan showing all tests pass, and a completed checklist with checkmarks.
Linked Issues check ✅ Passed All coding requirements from issue #636 are met: 30s timeout via abortAfter [#636], home/root blocking returning errors [#636], default exclusions from IGNORE_PATTERNS [#636], proper error handling distinguishing timeout from real errors [#636], and localAbort controller for process cleanup [#636].
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the glob tool hanging issue: timeout implementation, blocking broad paths, default exclusions, error handling, and comprehensive test coverage align with issue #636 requirements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/glob-timeout-hang

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/opencode/test/tool/glob.test.ts (1)

20-135: Add a deterministic timeout-path test for the new behavior.

This suite is strong, but it does not directly assert the timeout branch (timedOut messaging + metadata.truncated on timeout). Since timeout handling is the main change, add one focused test that forces timeout deterministically (e.g., mocked abortAfter or injected short timeout).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/tool/glob.test.ts` around lines 20 - 135, Add a new
unit test that deterministically exercises the timeout branch of
GlobTool.execute: create a temp dir with enough files (or mock/inject a very
short timeout/abortAfter value) then call GlobTool.init() and invoke
glob.execute with a ctx or option that triggers immediate timeout; assert that
result.output contains the "timedOut" message (or exact timeout string used in
the code) and that result.metadata.truncated (or metadata.count and truncated
flags) reflect a timeout. Reference GlobTool.init, glob.execute, the
timeout/abortAfter mechanism or ctx.abort, and the metadata.truncated/timedOut
behavior when adding the test. Ensure the test forces an abort deterministically
rather than relying on timing flakiness.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/src/tool/glob.ts`:
- Around line 66-73: When handling errors in the catch block inside glob.ts,
don't suppress every error when timeout.signal.aborted is true; instead detect
that the thrown error is an AbortError (e.g., check err.name === 'AbortError' or
use an AbortError type guard), ensure the timeout actually fired
(timeout.signal.aborted) and that the context wasn't a user-initiated abort
(ctx.abort or ctx.signal), then set timedOut = true only for timeout-generated
AbortErrors; for any other error (permission errors, ENOENT, or user aborts via
ctx.abort) rethrow the error so they aren't masked. Reference symbols:
timeout.signal.aborted, err (caught error), timedOut, and ctx.abort/ctx.signal.

---

Nitpick comments:
In `@packages/opencode/test/tool/glob.test.ts`:
- Around line 20-135: Add a new unit test that deterministically exercises the
timeout branch of GlobTool.execute: create a temp dir with enough files (or
mock/inject a very short timeout/abortAfter value) then call GlobTool.init() and
invoke glob.execute with a ctx or option that triggers immediate timeout; assert
that result.output contains the "timedOut" message (or exact timeout string used
in the code) and that result.metadata.truncated (or metadata.count and truncated
flags) reflect a timeout. Reference GlobTool.init, glob.execute, the
timeout/abortAfter mechanism or ctx.abort, and the metadata.truncated/timedOut
behavior when adding the test. Ensure the test forces an abort deterministically
rather than relying on timing flakiness.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7699a825-4154-4f6c-bfb4-d012528de821

📥 Commits

Reviewing files that changed from the base of the PR and between 0d34855 and f30aed0.

📒 Files selected for processing (2)
  • packages/opencode/src/tool/glob.ts
  • packages/opencode/test/tool/glob.test.ts

anandgupta42 and others added 2 commits April 4, 2026 09:00
… tool

- Block glob searches from `/` and `~` with immediate helpful message
- Add default directory exclusions (`node_modules/`, `dist/`, `build/`,
  `.cache/`, `.venv/`, etc.) reusing `IGNORE_PATTERNS` from `ls` tool
- Document `.gitignore` and `.ignore` file support in glob tool description
- Add 5 new tests: home/root blocking, subdirectory of home allowed,
  `node_modules` excluded, `dist`/`build` excluded
- Add `altimate_change` markers to all custom code in upstream file

Closes #636

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wrap `truncated || timedOut` in marker block
- Revert glob.txt description changes (triggers marker check on .txt files)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anandgupta42 anandgupta42 changed the title fix: add 30s timeout to glob tool to prevent indefinite hangs fix: add timeout, home/root blocking, and default exclusions to glob tool Apr 4, 2026
anandgupta42 and others added 3 commits April 4, 2026 09:03
- Add `AbortError` type check to catch block: only suppress errors that
  are AbortErrors AND from our timeout AND not user-initiated aborts
- Add test for ENOENT propagation (non-abort errors not masked as timeout)
- Add test for normal completion without timeout on small directories

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ignal`

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anandgupta42 anandgupta42 merged commit 9806411 into main Apr 4, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Glob tool hangs indefinitely on broad directory patterns

1 participant