Skip to content

fix(browser): install Playwright runtime in package dir, not cwd#1000

Open
LonestoneBot wants to merge 1 commit into
siteboon:mainfrom
LonestoneBot:fix/browser-runtime-install-cwd
Open

fix(browser): install Playwright runtime in package dir, not cwd#1000
LonestoneBot wants to merge 1 commit into
siteboon:mainfrom
LonestoneBot:fix/browser-runtime-install-cwd

Conversation

@LonestoneBot

@LonestoneBot LonestoneBot commented Jul 11, 2026

Copy link
Copy Markdown

Problem

Clicking Install Runtime in the Browser panel spins for a moment, then silently reverts to "not installed" — no error is shown and nothing in the server console indicates a failure. The runtime never becomes usable.

Root cause

installRuntime() in browser-use.service.ts runs the install commands through runCommand(), which spawns them with:

cwd: process.cwd()

process.cwd() is whatever directory CloudCLI happened to be launched from. So npm install --no-save playwright installs Playwright into that directory's node_modules (e.g. ~/some-project/node_modules/playwright).

But the runtime is later resolved with:

const require = createRequire(import.meta.url);
function getPlaywright() { try { return require('playwright'); } catch { return null; } }

require('playwright') resolves relative to this module inside the CloudCLI install, walking up its directory tree — never the launch directory. The two locations never meet:

  1. Install "succeeds" (and Chromium even downloads fine to the shared ~/.cache/ms-playwright / ~/Library/Caches/ms-playwright).
  2. The runtime probe still calls require('playwright'), which still throws → playwrightInstalled: false.
  3. The UI re-renders the same "not installed" state → the button appears to do nothing.

Reproduced against @cloudcli-ai/cloudcli@1.36.1 installed globally: after clicking the button, playwright ends up in the launch dir's node_modules, while require('playwright') from the global package keeps failing.

Fix

Run the install commands from the package root (the nearest package.json ancestor of this module) instead of process.cwd(), so Playwright lands in a node_modules that require() can actually resolve. Verified: installing into the package root makes require('playwright') resolve and the runtime report ready. Works in both the compiled layout (dist-server/...) and dev (tsx server/...), since both resolve to the repo/package root.

runCommand gains an optional cwd param defaulting to the package root, keeping the change contained (it is only used by the install path).

Summary by CodeRabbit

  • Bug Fixes
    • Improved the reliability of runtime browser dependency installations by running them from the correct application directory.
    • Prevented installation behavior from being affected by the server’s current working directory.

The "Install Runtime" button ran `npm install playwright` and
`playwright install chromium` with `cwd: process.cwd()` — the directory
CloudCLI happened to be launched from. Playwright therefore landed in that
directory's `node_modules`, but `getPlaywright()` resolves the package via
`require('playwright')`, which resolves relative to this module inside the
CloudCLI install. The two never meet: the install "succeeds" (and Chromium
downloads to the shared cache) yet the runtime probe keeps reporting
`playwrightInstalled: false`, so the button spins and silently reverts with
no error.

Run the install commands from the package root (the nearest package.json
ancestor of this module) so Playwright lands in a node_modules that
require() can resolve.
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: c7b87d91-2d25-4715-b341-3f2d35d3ce6b

📥 Commits

Reviewing files that changed from the base of the PR and between 5884573 and a58edac.

📒 Files selected for processing (1)
  • server/modules/browser-use/browser-use.service.ts

📝 Walkthrough

Walkthrough

Runtime command execution now finds the nearest owning package.json, caches that package root, and uses it as the default working directory, with process.cwd() as fallback. Callers can still provide an explicit cwd.

Changes

Package-root execution

Layer / File(s) Summary
Resolve and apply package root
server/modules/browser-use/browser-use.service.ts
Package-root detection walks upward from the module directory, caches the result, falls back to process.cwd(), and supplies it as the default runCommand working directory.

Poem

A rabbit hops through folders bright,
Finds package.json by moonlit light.
Commands now run where packages grow,
With cached roots guiding the flow.
If none appear, the cwd says “go!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: Playwright installs now run from the package directory instead of the process cwd.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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