Skip to content

fix: resolve ripgrep from @vscode/ripgrep-universal and the system PATH#248

Closed
0xMink wants to merge 1 commit into
mainfrom
fix/ripgrep-path-resolution
Closed

fix: resolve ripgrep from @vscode/ripgrep-universal and the system PATH#248
0xMink wants to merge 1 commit into
mainfrom
fix/ripgrep-path-resolution

Conversation

@0xMink
Copy link
Copy Markdown
Contributor

@0xMink 0xMink commented May 22, 2026

Summary

search_files and list_files fail with Could not find ripgrep binary on VS Code Insiders. Insiders' staged-install builds ship ripgrep as the @vscode/ripgrep-universal package, with the binary nested under bin/<platform>-<arch>/ (e.g. bin/win32-x64/rg.exe) — a layout getBinPath did not recognize (it only knew @vscode/ripgrep / vscode-ripgrep with the binary directly in bin/).

getBinPath now resolves ripgrep in this order:

  1. The VS Code installation — the existing @vscode/ripgrep / vscode-ripgrep paths, plus the @vscode/ripgrep-universal/bin/<platform>-<arch>/ layout (and its .asar.unpacked variant).
  2. The system PATH — new fallback, covering VS Code forks whose install layout is not recognized, headless / CLI hosts with no VS Code installation, and machines with a user-installed ripgrep.

VS Code's own copy is still preferred; PATH is only consulted when no copy is found in the installation. All three getBinPath callers (search_files, list_files, file-search) inherit the fix with no changes.

Out of scope (intentional)

  • No bundled ripgrep. The extension does not ship its own rg — it resolves an existing one.
  • Graceful degradation when ripgrep is genuinely absent (returning a clear result instead of throwing) is left as a follow-up — what search_files / list_files should return in that case is a small design question worth deciding separately.

Test plan

  • vitest — 5 new getBinPath tests: classic @vscode/ripgrep layout, @vscode/ripgrep-universal layout, system-PATH fallback, VS Code copy preferred over PATH, and undefined when ripgrep is absent everywhere.
  • tsc --noEmit clean; lint passes.
  • Install a build on a VS Code Insiders machine with the staged-install layout and confirm search_files / list_files work.

Summary by CodeRabbit

Release Notes

  • Improvements
    • Enhanced ripgrep binary discovery to support additional VS Code installation layouts and configurations
    • Implemented fallback mechanism to search system PATH when ripgrep is not found in standard installation directories
    • Improved reliability and compatibility of file search functionality across different environments

Review Change Stack

search_files and list_files threw "Could not find ripgrep binary" on VS Code Insiders, whose staged-install builds ship ripgrep as @vscode/ripgrep-universal with the binary nested under bin/<platform>-<arch>/ — a layout getBinPath did not recognize. getBinPath now also checks that layout, and falls back to ripgrep on the system PATH when no copy is found in the VS Code install (covering VS Code forks and headless/CLI hosts).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

📝 Walkthrough

Walkthrough

This PR enhances ripgrep binary discovery to support VS Code's @vscode/ripgrep-universal staged-install layout with platform-specific subdirectories, adds a system PATH fallback when VS Code binaries are absent, and provides comprehensive test coverage validating all resolution scenarios.

Changes

Ripgrep binary discovery enhancement

Layer / File(s) Summary
Binary discovery implementation and documentation
src/services/ripgrep/index.ts
Computes ripgrepUniversalBinDir from process.platform/process.arch, introduces findRipgrepOnPath() to scan system PATH for rg/rg.exe, and updates getBinPath resolution order to check classic layout, universal layout (both normal and asar.unpacked), and finally system PATH.
Binary discovery test suite
src/services/ripgrep/__tests__/index.spec.ts
Mocks fileExistsAtPath to enable deterministic testing and adds comprehensive getBinPath test cases covering classic layout, universal layout with platform/arch directories, system PATH fallback, VS Code preference over PATH, and undefined return when no binary is found.

🎯 2 (Simple) | ⏱️ ~12 minutes

🐰 A ripgrep discovery dance so fine,
Cross platforms, universal design!
From VS Code paths to PATH we roam,
Finding binaries, bringing them home! 🏠✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing the required 'Related GitHub Issue' section (no issue number provided), though it includes comprehensive Summary, Out of Scope, and Test Plan sections covering implementation details and verification steps. Add the 'Related GitHub Issue' section with the issue number (e.g., 'Closes: #248') as required by the template. Consider adding a brief Test Procedure section clarifying manual verification steps if possible.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: resolving ripgrep from the @vscode/ripgrep-universal package and system PATH, which directly addresses the core issue fixed in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ 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/ripgrep-path-resolution

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/services/ripgrep/__tests__/index.spec.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

src/services/ripgrep/index.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


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
Contributor

@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)
src/services/ripgrep/__tests__/index.spec.ts (1)

88-93: ⚡ Quick win

Add a test for the .asar.unpacked universal-layout branch.

getBinPath checks both universal paths, but the suite currently validates only the non-.asar.unpacked variant. Adding one case will lock in that fallback branch.

Suggested test addition
+	it("resolves ripgrep from the .asar.unpacked `@vscode/ripgrep-universal` layout", async () => {
+		const rg = path.join(
+			appRoot,
+			"node_modules.asar.unpacked/@vscode/ripgrep-universal/bin",
+			platformDir,
+			binName,
+		)
+		mockFileExists.mockImplementation(async (p: string) => p === rg)
+
+		expect(await getBinPath(appRoot)).toBe(rg)
+	})
As per coding guidelines, "Use package-local unit tests for pure logic, parsing, state transitions, validation, serialization, request construction, retry decisions, and error handling."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/ripgrep/__tests__/index.spec.ts` around lines 88 - 93, Add a
unit test in src/services/ripgrep/__tests__/index.spec.ts that mirrors the
existing VS Code Insiders test but targets the ".asar.unpacked" universal-layout
branch: construct the expected path using path.join(appRoot,
"node_modules/@vscode/ripgrep-universal.asar.unpacked/bin", platformDir,
binName), stub/mock mockFileExists to return true only for that path, then
assert that await getBinPath(appRoot) resolves to that .asar.unpacked path;
reuse the existing test's structure and the same symbols (getBinPath,
mockFileExists, appRoot, platformDir, binName) so the fallback branch is
exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/ripgrep/index.ts`:
- Around line 102-107: The PATH probing loop in findRipgrepOnPath uses raw PATH
segments (pathEnv split by path.delimiter) which can include surrounding quotes
and cause path.join(dir, binName) to produce invalid paths; update the loop to
trim whitespace and strip any surrounding single or double quotes from each dir
before constructing candidate (use the existing variables pathEnv, dir, binName,
candidate) so the existence check uses an unquoted directory string and
correctly finds the binary.

---

Nitpick comments:
In `@src/services/ripgrep/__tests__/index.spec.ts`:
- Around line 88-93: Add a unit test in
src/services/ripgrep/__tests__/index.spec.ts that mirrors the existing VS Code
Insiders test but targets the ".asar.unpacked" universal-layout branch:
construct the expected path using path.join(appRoot,
"node_modules/@vscode/ripgrep-universal.asar.unpacked/bin", platformDir,
binName), stub/mock mockFileExists to return true only for that path, then
assert that await getBinPath(appRoot) resolves to that .asar.unpacked path;
reuse the existing test's structure and the same symbols (getBinPath,
mockFileExists, appRoot, platformDir, binName) so the fallback branch is
exercised.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4191523-257a-4774-b312-eb78a96f22bf

📥 Commits

Reviewing files that changed from the base of the PR and between 45b239c and 051b67b.

📒 Files selected for processing (2)
  • src/services/ripgrep/__tests__/index.spec.ts
  • src/services/ripgrep/index.ts

Comment on lines +102 to +107
for (const dir of pathEnv.split(path.delimiter)) {
if (dir.length === 0) {
continue
}

const candidate = path.join(dir, binName)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle quoted PATH entries before probing candidate binaries.

findRipgrepOnPath currently uses raw PATH segments. If a segment is quoted (e.g. "C:\Program Files\Ripgrep"), path.join keeps quotes and the existence check fails, so fallback can incorrectly return undefined.

Proposed fix
-	for (const dir of pathEnv.split(path.delimiter)) {
-		if (dir.length === 0) {
+	for (const rawDir of pathEnv.split(path.delimiter)) {
+		const dir = rawDir.trim().replace(/^"(.*)"$/, "$1")
+		if (dir.length === 0) {
 			continue
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/ripgrep/index.ts` around lines 102 - 107, The PATH probing loop
in findRipgrepOnPath uses raw PATH segments (pathEnv split by path.delimiter)
which can include surrounding quotes and cause path.join(dir, binName) to
produce invalid paths; update the loop to trim whitespace and strip any
surrounding single or double quotes from each dir before constructing candidate
(use the existing variables pathEnv, dir, binName, candidate) so the existence
check uses an unquoted directory string and correctly finds the binary.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes ripgrep resolution failures in environments where VS Code ships ripgrep via the newer @vscode/ripgrep-universal package layout (notably VS Code Insiders staged-install builds), and adds a fallback to locate rg via the system PATH when no VS Code-bundled binary is found.

Changes:

  • Extend getBinPath to recognize @vscode/ripgrep-universal/bin/<platform>-<arch>/ (including .asar.unpacked) in addition to existing ripgrep package layouts.
  • Add a system PATH fallback for ripgrep resolution when the VS Code installation lookup fails.
  • Add unit tests covering classic layout, universal layout, PATH fallback behavior, precedence, and “not found” behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/services/ripgrep/index.ts Updates ripgrep binary resolution to support @vscode/ripgrep-universal layout and introduces PATH fallback logic.
src/services/ripgrep/__tests__/index.spec.ts Adds getBinPath test coverage for the new resolution paths and fallback order.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +95 to +111
async function findRipgrepOnPath(): Promise<string | undefined> {
const pathEnv = process.env.PATH

if (!pathEnv) {
return undefined
}

for (const dir of pathEnv.split(path.delimiter)) {
if (dir.length === 0) {
continue
}

const candidate = path.join(dir, binName)

if (await fileExistsAtPath(candidate)) {
return candidate
}
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 71.42857% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/services/ripgrep/index.ts 71.42% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@edelauna
Copy link
Copy Markdown
Contributor

edelauna commented May 22, 2026

Thanks so much for investigating and looking into this.

I'm going to close this for now. As discussed in dms on Discord I think this is a bit of over engineering to handle what amounts to an edge case. My preference would be to continue to use the Vscode packaged rg, and maybe update how that gets resolved, or add a non fatal fallback route.

@edelauna edelauna closed this May 22, 2026
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.

3 participants