Skip to content

fix: bundle ripgrep and fall back to it when VS Code's copy is not found#243

Open
0xMink wants to merge 7 commits into
mainfrom
fix/bundle-ripgrep-fallback
Open

fix: bundle ripgrep and fall back to it when VS Code's copy is not found#243
0xMink wants to merge 7 commits into
mainfrom
fix/bundle-ripgrep-fallback

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' newer staged-install layout, where program files moved into a per-build subfolder (microsoft/vscode#252063). getBinPath only checked four hardcoded paths under vscode.env.appRoot, none of which resolve on that layout.

This bundles a ripgrep binary inside the extension and uses it as a fallback:

  • Add @vscode/ripgrep as a build devDependency.
  • New copyRipgrep esbuild plugin copies the platform rg binary into dist/bin/ so it ships inside the VSIX.
  • getBinPath gains a final fallback to the bundled binary; VS Code's own copy is still preferred when present.
  • CI asserts the binary is present in the packaged VSIX.

All three getBinPath callers (search_files, list_files, file-search) inherit the fix with no changes.

Scope — PR 1 of 2

The extension ships a single universal VSIX, and @vscode/ripgrep installs only the build host's platform binary, so the released VSIX carries rg for the CI build platform only. That fully fixes that platform and is a non-regression elsewhere — on a platform whose binary is not bundled, the fallback simply finds nothing, exactly as before this change. A follow-up PR will move to platform-specific VSIXs so every platform ships a usable binary.

Test plan

  • vitest — new getBinPath tests: fallback used when nothing exists under the app root; VS Code's own copy preferred over the bundled one; undefined when ripgrep exists nowhere.
  • pnpm vsix — the packaged VSIX contains extension/dist/bin/rg.
  • Install the built VSIX on a VS Code Insiders machine with the staged-install layout and confirm search_files / list_files work.

Summary by CodeRabbit

  • Bug Fixes
    • Bundled a platform/architecture-specific ripgrep binary and added a fallback so search and file-listing work when ripgrep isn't found in some VS Code installs (fixes "Could not find ripgrep binary").
  • Tests
    • Added coverage to ensure the extension prefers a VS Code-provided ripgrep when present, falls back to the bundled copy, and reports when none are available.
  • Chores
    • Added a packaged-content check to validate the bundled ripgrep is included in release artifacts.

Review Change Stack

@0xMink 0xMink requested a review from taltas as a code owner May 22, 2026 00:10
Copilot AI review requested due to automatic review settings May 22, 2026 00:10
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 06724554-4376-4491-9ea8-c01fef4f0fc0

📥 Commits

Reviewing files that changed from the base of the PR and between 838fb91 and db9f134.

📒 Files selected for processing (1)
  • src/services/ripgrep/index.ts

📝 Walkthrough

Walkthrough

Bundles a ripgrep binary into the extension build, exposes a platform-arch scoped bundledRgPath, updates runtime lookup to prefer VS Code’s ripgrep and fall back to the bundled binary, adds tests, a Changeset, and a VSIX packaging check.

Changes

Ripgrep bundling and fallback

Layer / File(s) Summary
Dependency and build infrastructure
src/package.json, src/esbuild.mjs
Adds @vscode/ripgrep as a devDependency and a copyRipgrep esbuild plugin that copies the resolved ripgrep binary into dist/bin/<platform>-<arch>/ and sets executable permissions on build end.
Ripgrep service contract and fallback logic
src/services/ripgrep/index.ts
Exports bundledRgPath and updates getBinPath to check node_modules.asar.unpacked/@vscode/ripgrep/bin/ and to fall back to the bundled ripgrep when VS Code paths are unavailable.
Test infrastructure and fallback verification
src/services/ripgrep/__tests__/index.spec.ts
Adds Vitest mocking for fileExistsAtPath and tests for getBinPath covering bundled fallback, VS Code-preferred binary, and missing-everywhere cases; asserts platform-arch scoped bundled path.
Release documentation and packaging verification
.changeset/bundle-ripgrep-fallback.md, .github/workflows/marketplace-publish.yml
Adds a Changeset describing the bundling/fallback, and the marketplace publish workflow adds a VSIX verification that extension/dist/bin/<segment>/rg is present.

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested reviewers

  • hannesrudolph
  • edelauna

🐰 I found a binary and tucked it away,
In dist/bin it now safely will stay.
When VS Code can’t find it and searches go thin,
The bundled rg hops in with a grin.
Now searches resume — let the tests begin!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. 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 accurately summarizes the main change: bundling ripgrep and adding fallback logic when VS Code's copy is unavailable.
Description check ✅ Passed The description includes all critical sections: issue context, implementation details, scope clarification, and test plan, though the Related GitHub Issue section lacks an explicit issue number.
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/bundle-ripgrep-fallback

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/index.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration 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

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 addresses failures in search_files / list_files caused by VS Code Insiders’ staged-install layout by bundling a ripgrep binary into the extension and falling back to it when VS Code’s built-in copy cannot be found.

Changes:

  • Add @vscode/ripgrep as a build-time dependency and copy its rg binary into dist/bin/ during the esbuild step.
  • Update getBinPath to prefer VS Code’s rg but fall back to the bundled binary when necessary.
  • Add unit tests for the new fallback behavior and add CI validation that the VSIX contains the bundled binary.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/services/ripgrep/index.ts Adds a bundled rg path and extends getBinPath with a bundled-binary fallback.
src/services/ripgrep/__tests__/index.spec.ts Adds tests to validate fallback selection and preference order.
src/package.json Adds @vscode/ripgrep to enable bundling the binary at build time.
src/esbuild.mjs Introduces copyRipgrep plugin to copy rg into the dist output.
pnpm-lock.yaml Locks the new @vscode/ripgrep dependency.
.github/workflows/marketplace-publish.yml Adds a packaged-VSIX assertion that extension/dist/bin/rg is present.
.changeset/bundle-ripgrep-fallback.md Documents the patch-level change for release notes.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

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

Comment on lines 106 to +110
(await checkPath("node_modules/@vscode/ripgrep/bin/")) ||
(await checkPath("node_modules/vscode-ripgrep/bin")) ||
(await checkPath("node_modules.asar.unpacked/vscode-ripgrep/bin/")) ||
(await checkPath("node_modules.asar.unpacked/@vscode/ripgrep/bin/"))
(await checkPath("node_modules.asar.unpacked/@vscode/ripgrep/bin/")) ||
((await fileExistsAtPath(bundledRgPath)) ? bundledRgPath : undefined)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 838fb91.

The bundled binary is now copied to and resolved from dist/bin/<platform>-<arch>/ (e.g. dist/bin/linux-x64/rg). bundledRgPath includes the ${process.platform}-${process.arch} segment, so on macOS it resolves to dist/bin/darwin-arm64/rg — which a Linux-built universal VSIX does not contain — and the fallback correctly yields nothing instead of an incompatible binary. A test was added asserting the path is platform/arch-scoped.

Comment thread src/esbuild.mjs
Comment on lines +96 to +105
const { rgPath } = await import("@vscode/ripgrep")
if (!rgPath) {
throw new Error("[copyRipgrep] @vscode/ripgrep did not provide rgPath")
}
const rgDestDir = path.join(distDir, "bin")
fs.mkdirSync(rgDestDir, { recursive: true })
const rgDest = path.join(rgDestDir, path.basename(rgPath))
fs.copyFileSync(rgPath, rgDest)
fs.chmodSync(rgDest, 0o755)
console.log(`[copyRipgrep] Copied ${rgPath} to ${rgDest}`)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 838fb91.

copyRipgrep now writes the binary under dist/bin/${process.platform}-${process.arch}/, and getBinPath resolves the matching <platform>-<arch> segment at runtime. A binary built for one OS can no longer be picked up by the fallback on another — even though the VSIX is universal and rg shares a filename across Linux and macOS.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

0xMink added 2 commits May 22, 2026 00:39
The published VSIX is universal but copyRipgrep bundled only the build host's rg. Because rg (no extension) is the binary name on both Linux and macOS, a macOS user could resolve a Linux-built dist/bin/rg and execute an incompatible binary. Bundle and resolve the binary under dist/bin/<platform>-<arch>/ so the fallback is used only on a host matching the bundled binary.
@proyectoauraorg
Copy link
Copy Markdown
Contributor

Nice fix — preferring VS Code's own rg and falling back to a SHA512-pinned bundled binary is a clean way to handle the staged-install breakage. One QA/hardening thought: logging which rg path actually resolved (VS Code vs bundled vs platform) would make the resolved source visible in support threads and surface any unexpected fallback. Happy to help add resolver-order test coverage (VS Code → bundled → none) if useful. 🙌

Copy link
Copy Markdown
Contributor

@proyectoauraorg proyectoauraorg left a comment

Choose a reason for hiding this comment

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

Code Review: Bundle ripgrep fallback

Overall Assessment: Well-designed solution with thorough testing. Approve with minor suggestions.

Strengths

  1. Clean fallback chain: The getBinPath() now prefers VS Code's own ripgrep and falls back to the bundled copy — correct priority order.

  2. Platform-scoped binary path: The <platform>-<arch> segment in dist/bin/ prevents the universal VSIX from handing a Linux binary to macOS users. Smart design.

  3. Test coverage is excellent: The 4 test cases cover:

    • Fallback when VS Code copy is absent (Insiders staged-install)
    • Preference for VS Code copy over bundled
    • undefined when nothing exists
    • Platform/arch path validation
  4. CI validation: The marketplace-publish.yml change ensures the binary is actually present in the VSIX before publishing.

Minor Suggestions

  1. VSIX size impact: The bundled ripgrep binary adds ~20MB to the VSIX. Consider noting this in the changeset or adding a comment in esbuild.mjs about the size tradeoff. Users on slow connections may notice.

  2. Cross-compilation edge case: If someone builds the VSIX on a CI runner with a different arch than the target (e.g., building on ARM64 for x86 users), the bundled binary would be wrong. This is fine for the current CI setup but worth a comment.

  3. Error message: When @vscode/ripgrep doesn't provide rgPath, the esbuild plugin throws. Consider adding a more descriptive error: "@vscode/ripgrep did not provide rgPath — check that the package is installed correctly".

Nit

The fileExistsAtPath import in the test is clean and the mocking approach is idiomatic Vitest. No issues there.

LGTM 🚀

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