gemini-cli - 💡(How to fix) Fix Convert bundled ripgrep to platform-specific optionalDependencies [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
google-gemini/gemini-cli#25842Fetched 2026-04-23 07:44:29
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Participants
Timeline (top)
labeled ×2

Convert the bundled ripgrep binaries to platform-specific optionalDependencies (the esbuild / @swc/core / rollup pattern) so that:

  1. npm-installed users get offline ripgrep again — restoring the goal of #25342 for the npm distribution channel.
  2. Each user only downloads the one binary their OS+arch needs (~4–5 MB), instead of either getting nothing (today, after #25841) or all five (~21 MB, what #25342 tried).
  3. The @google/gemini-cli tarball stays well under wombat-dressing-room's per-package upload limit (no recurrence of #25507's E413).

This is the long-term shape that #25841 deliberately did not block on (it required new npm packages + new wombat tokens, and we needed to unblock the release first).

Root Cause

  • Caused by the trade-off in #25841 (this issue's predecessor)
  • The original feature: #25342
  • The release failure that led here: #25507

Code Example

@google/gemini-cli-ripgrep-darwin-arm64   ~3.4 MB
@google/gemini-cli-ripgrep-darwin-x64     ~4.1 MB
@google/gemini-cli-ripgrep-linux-arm64    ~3.8 MB
@google/gemini-cli-ripgrep-linux-x64      ~5.1 MB
@google/gemini-cli-ripgrep-win32-x64      ~4.7 MB

---

{
    "name": "@google/gemini-cli-ripgrep-darwin-arm64",
    "version": "<matches @google/gemini-cli>",
    "os": ["darwin"],
    "cpu": ["arm64"],
    "files": ["bin"],
    "license": "MIT"
  }

---

"optionalDependencies": {
  "@google/gemini-cli-ripgrep-darwin-arm64": "<release-version>",
  "@google/gemini-cli-ripgrep-darwin-x64":   "<release-version>",
  "@google/gemini-cli-ripgrep-linux-arm64":  "<release-version>",
  "@google/gemini-cli-ripgrep-linux-x64":    "<release-version>",
  "@google/gemini-cli-ripgrep-win32-x64":    "<release-version>"
}

---

const candidatePaths = [
  // 1. SEA layout (flattened)
  path.resolve(__dirname, 'vendor/ripgrep', binName),
  // 2. Dev layout
  path.resolve(__dirname, '../../vendor/ripgrep', binName),
  // 3. NEW: npm install layout (optionalDependency)
  tryResolve(`@google/gemini-cli-ripgrep-${platform}-${arch}/bin/${binName}`),
].filter(Boolean);
RAW_BUFFERClick to expand / collapse

Summary

Convert the bundled ripgrep binaries to platform-specific optionalDependencies (the esbuild / @swc/core / rollup pattern) so that:

  1. npm-installed users get offline ripgrep again — restoring the goal of #25342 for the npm distribution channel.
  2. Each user only downloads the one binary their OS+arch needs (~4–5 MB), instead of either getting nothing (today, after #25841) or all five (~21 MB, what #25342 tried).
  3. The @google/gemini-cli tarball stays well under wombat-dressing-room's per-package upload limit (no recurrence of #25507's E413).

This is the long-term shape that #25841 deliberately did not block on (it required new npm packages + new wombat tokens, and we needed to unblock the release first).

Why is this needed?

Today, after #25841, npm-installed users without a system ripgrep on PATH fall back to the JS-based GrepTool (slower, less feature-complete), which is the pre-#25342 behavior. Bringing offline ripgrep back requires either:

  • This issue (per-platform optionalDependencies) — the standard npm pattern; works everywhere npm works; no postinstall network call.
  • A postinstall download script — breaks behind corporate proxies, opt-out unfriendly, slower install.
  • Compressing binaries inside the tarball — adds first-run latency and a writable cache requirement; doesn't address the underlying "we ship N×4 unused bytes" waste.

Proposed plan

1. Five new sub-packages under @google/

@google/gemini-cli-ripgrep-darwin-arm64   ~3.4 MB
@google/gemini-cli-ripgrep-darwin-x64     ~4.1 MB
@google/gemini-cli-ripgrep-linux-arm64    ~3.8 MB
@google/gemini-cli-ripgrep-linux-x64      ~5.1 MB
@google/gemini-cli-ripgrep-win32-x64      ~4.7 MB

Each contains:

  • bin/rg (or rg.exe)
  • package.json with "os" + "cpu" constraints, e.g.:
    {
      "name": "@google/gemini-cli-ripgrep-darwin-arm64",
      "version": "<matches @google/gemini-cli>",
      "os": ["darwin"],
      "cpu": ["arm64"],
      "files": ["bin"],
      "license": "MIT"
    }

2. Wire into @google/gemini-cli

scripts/prepare-npm-release.js adds optionalDependencies to the published cli package.json:

"optionalDependencies": {
  "@google/gemini-cli-ripgrep-darwin-arm64": "<release-version>",
  "@google/gemini-cli-ripgrep-darwin-x64":   "<release-version>",
  "@google/gemini-cli-ripgrep-linux-arm64":  "<release-version>",
  "@google/gemini-cli-ripgrep-linux-x64":    "<release-version>",
  "@google/gemini-cli-ripgrep-win32-x64":    "<release-version>"
}

npm only installs the dependency matching the user's OS+arch — exactly the same mechanism the cli already uses for @lydell/node-pty-*.

3. Runtime resolver

Add a third candidate to getRipgrepPath() in packages/core/src/tools/ripGrep.ts:

const candidatePaths = [
  // 1. SEA layout (flattened)
  path.resolve(__dirname, 'vendor/ripgrep', binName),
  // 2. Dev layout
  path.resolve(__dirname, '../../vendor/ripgrep', binName),
  // 3. NEW: npm install layout (optionalDependency)
  tryResolve(`@google/gemini-cli-ripgrep-${platform}-${arch}/bin/${binName}`),
].filter(Boolean);

Plus a small tryResolve helper that swallows MODULE_NOT_FOUND. SEA build is unchanged — still reads from packages/core/vendor/ripgrep/.

4. Release pipeline (the time-consuming part)

  • Get 5 new wombat-dressing-room publish tokens provisioned by Google OSPO. This is the blocker for total elapsed time — past requests have taken anywhere from 2 days to 2 weeks.
  • Extend .github/actions/npm-auth-token/action.yml to handle the 5 new package names (or refactor to a token-per-package map).
  • Extend .github/actions/publish-release/action.yml with 5 new npm publish --workspace=... steps. Order: ripgrep packages first, then core, then cli, then a2a-server. This way, if ripgrep publish fails, the cli release isn't half-published with broken optionalDependencies.
  • Add a verification step that all 5 ripgrep packages and the cli are at the same version after publish.

5. Tests

  • Unit-test getRipgrepPath() resolution path 3 (mock require.resolve).
  • Add a CI matrix smoke test that on each OS+arch the installed @google/gemini-cli resolves the matching @google/gemini-cli-ripgrep-* package and rg --version works.

Estimated effort

  • Engineering work: ~½ day end-to-end.
  • Total elapsed time: gated on OSPO/wombat token provisioning — anywhere from a few days to a couple of weeks.

Related Issues

  • Caused by the trade-off in #25841 (this issue's predecessor)
  • The original feature: #25342
  • The release failure that led here: #25507

Additional context

  • getRipgrepPath already does multi-candidate path resolution, so adding a third candidate is a one-line change.
  • The cli already uses the same pattern (@lydell/node-pty-* per-platform optional deps for native modules) — this would be the second instance.
  • Consider naming under @google-gemini/ instead of @google/ if the OSPO token process is faster for the former.

extent analysis

TL;DR

The most likely fix involves creating platform-specific optionalDependencies for the ripgrep binaries and updating the getRipgrepPath function to resolve the correct binary based on the user's OS and architecture.

Guidance

  1. Create five new sub-packages under @google/ for each platform-specific ripgrep binary, containing the binary and a package.json with OS and CPU constraints.
  2. Update scripts/prepare-npm-release.js to add the new sub-packages as optionalDependencies to the published @google/gemini-cli package.json.
  3. Modify getRipgrepPath in packages/core/src/tools/ripGrep.ts to include a third candidate path for the optionalDependency layout.
  4. Extend the release pipeline to handle the new packages, including provisioning new wombat-dressing-room publish tokens and updating the npm publish steps.
  5. Add unit tests and CI matrix smoke tests to verify the correct resolution of the ripgrep binary on each OS and architecture.

Example

const candidatePaths = [
  // 1. SEA layout (flattened)
  path.resolve(__dirname, 'vendor/ripgrep', binName),
  // 2. Dev layout
  path.resolve(__dirname, '../../vendor/ripgrep', binName),
  // 3. NEW: npm install layout (optionalDependency)
  tryResolve(`@google/gemini-cli-ripgrep-${platform}-${arch}/bin/${binName}`),
].filter(Boolean);

Notes

The estimated effort for the engineering work is ~½ day, but the total elapsed time may be longer due to the time required for OSPO/wombat token provisioning.

Recommendation

Apply the proposed plan to create platform-specific optionalDependencies for the ripgrep binaries and update the getRipgrepPath function, as this approach is the standard npm pattern and works everywhere npm works without requiring a postinstall network call.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING