Skip to content

Fix chrome extension bundled path resolution#8914

Merged
steipete merged 5 commits intoopenclaw:mainfrom
kelvinCB:fix/chrome-extension-install-path
Feb 5, 2026
Merged

Fix chrome extension bundled path resolution#8914
steipete merged 5 commits intoopenclaw:mainfrom
kelvinCB:fix/chrome-extension-install-path

Conversation

@kelvinCB
Copy link
Contributor

@kelvinCB kelvinCB commented Feb 4, 2026

Fixes openclaw browser extension install failing on global installs by resolving the bundled extension directory relative to dist/ (npm layout is <root>/dist, extension at <root>/assets/chrome-extension).

  • Update bundledExtensionRootDir() to use ../assets/chrome-extension
  • Adjust test to assert install succeeds using the bundled path

Tests: pnpm test src/cli/browser-cli-extension.test.ts

Greptile Overview

Greptile Summary

This PR updates Chrome extension install logic to resolve the bundled extension directory relative to the compiled dist/ output (so global/npm installs can find assets/chrome-extension), and adjusts the unit test to exercise the default bundled-path install.

The change fits into the CLI’s browser extension install command by altering the internal bundledExtensionRootDir() used when no sourceDir override is provided, ensuring installs copy from the packaged assets into the user’s state directory.

Confidence Score: 4/5

  • This PR is likely safe to merge; the functional change is small and targeted.
  • The path resolution change is straightforward and matches the described npm package layout. Main remaining concerns are test robustness (temp dir choice/cleanup and weakened assertion), which can cause flaky or messy test runs but don’t undermine the core fix.
  • src/cli/browser-cli-extension.test.ts (temp dir creation/cleanup and assertion strength)

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

@openclaw-barnacle openclaw-barnacle bot added the cli CLI command changes label Feb 4, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +11 to +13
const tmp = path.join(process.cwd(), ".tmp-test-openclaw-state", String(Date.now()));

const sourceDir = path.resolve(process.cwd(), "assets/chrome-extension");
const result = await installChromeExtension({ stateDir: tmp, sourceDir });
const result = await installChromeExtension({ stateDir: tmp });
Copy link
Contributor

Choose a reason for hiding this comment

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

[P1] Test writes to a non-unique, non-cleaned state directory

Using path.join(process.cwd(), ".tmp-test-openclaw-state", String(Date.now())) can collide in parallel test runs (same ms) and leaves artifacts in the repo if the test fails/succeeds. This makes CI flakier and can dirty local working trees. Prefer a unique temp dir via fs.mkdtempSync(os.tmpdir()) (or include PID + random) and clean it up in a finally block.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/browser-cli-extension.test.ts
Line: 11:13

Comment:
[P1] Test writes to a non-unique, non-cleaned state directory

Using `path.join(process.cwd(), ".tmp-test-openclaw-state", String(Date.now()))` can collide in parallel test runs (same ms) and leaves artifacts in the repo if the test fails/succeeds. This makes CI flakier and can dirty local working trees. Prefer a unique temp dir via `fs.mkdtempSync(os.tmpdir())` (or include PID + random) and clean it up in a `finally` block.


How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 15 to 16
expect(result.path).toContain(path.join("browser", "chrome-extension"));
expect(fs.existsSync(path.join(result.path, "manifest.json"))).toBe(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2] Assertion is weaker than needed for the intended regression

expect(result.path).toContain(path.join("browser", "chrome-extension")) will pass even if result.path points somewhere unexpected (e.g., a longer unrelated path containing that substring). Since installChromeExtension({ stateDir: tmp }) should deterministically install to path.join(tmp, "browser", "chrome-extension"), asserting exact equality would better lock in the behavior this test cares about.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/browser-cli-extension.test.ts
Line: 15:16

Comment:
[P2] Assertion is weaker than needed for the intended regression

`expect(result.path).toContain(path.join("browser", "chrome-extension"))` will pass even if `result.path` points somewhere unexpected (e.g., a longer unrelated path containing that substring). Since `installChromeExtension({ stateDir: tmp })` should deterministically install to `path.join(tmp, "browser", "chrome-extension")`, asserting exact equality would better lock in the behavior this test cares about.


How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +18 to +21
// `dist/` lives at `<packageRoot>/dist` in npm installs.
// The bundled extension lives at `<packageRoot>/assets/chrome-extension`.
// So we need to go up ONE level from `dist`.
return path.resolve(here, "../assets/chrome-extension");
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3] Comment claims here is dist/, but it’s a file directory

here = path.dirname(fileURLToPath(import.meta.url)) resolves to the directory containing the compiled file (e.g., <packageRoot>/dist/cli), not <packageRoot>/dist. The ../assets/... path is likely still correct, but the comment is slightly misleading and could confuse future adjustments.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/browser-cli-extension.ts
Line: 18:21

Comment:
[P3] Comment claims `here` is `dist/`, but it’s a file directory

`here = path.dirname(fileURLToPath(import.meta.url))` resolves to the directory containing the compiled file (e.g., `<packageRoot>/dist/cli`), not `<packageRoot>/dist`. The `../assets/...` path is likely still correct, but the comment is slightly misleading and could confuse future adjustments.


How can I resolve this? If you propose a fix, please make it concise.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d7c26010d5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 15 to 22
function bundledExtensionRootDir() {
const here = path.dirname(fileURLToPath(import.meta.url));
return path.resolve(here, "../../assets/chrome-extension");

// `dist/` lives at `<packageRoot>/dist` in npm installs.
// The bundled extension lives at `<packageRoot>/assets/chrome-extension`.
// So we need to go up ONE level from `dist`.
return path.resolve(here, "../assets/chrome-extension");
}

Choose a reason for hiding this comment

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

P2 Badge Restore source-tree bundled extension path fallback

The new path calculation only works when import.meta.url is inside dist/…, but in dev/test runs pnpm openclaw … executes the TypeScript from src/cli, so path.resolve(here, "../assets/chrome-extension") resolves to src/assets/chrome-extension (which doesn’t exist). That makes installChromeExtension() throw “Bundled Chrome extension is missing” for local development and tests that use the default path. Consider checking for ../assets and falling back to ../../assets when running from the source tree.

Useful? React with 👍 / 👎.

@kelvinCB
Copy link
Contributor Author

kelvinCB commented Feb 5, 2026

Hi! First PR here in this repo🙏
All checks are green except macOS jobs which have been stuck in queued for ~12 hours (macos-app lint/build/test + checks-macos).
Could someone with admin access please re-run/unblock the macOS jobs and take a quick look?
Thanks!
@steipete @cpojer

@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser app: macos App: macos app: web-ui App: web-ui gateway Gateway runtime extensions: copilot-proxy Extension: copilot-proxy extensions: diagnostics-otel Extension: diagnostics-otel labels Feb 5, 2026
@openclaw-barnacle openclaw-barnacle bot removed channel: nostr Channel integration: nostr channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser app: macos App: macos app: web-ui App: web-ui gateway Gateway runtime extensions: copilot-proxy Extension: copilot-proxy extensions: diagnostics-otel Extension: diagnostics-otel extensions: google-antigravity-auth Extension: google-antigravity-auth extensions: google-gemini-cli-auth Extension: google-gemini-cli-auth extensions: llm-task Extension: llm-task extensions: lobster Extension: lobster extensions: memory-core Extension: memory-core extensions: memory-lancedb Extension: memory-lancedb labels Feb 5, 2026
@steipete
Copy link
Contributor

steipete commented Feb 5, 2026

Landed via temp rebase onto main.\n\n- Gate: pnpm lint && pnpm build && pnpm test (fails: src/auto-reply/command-control.test.ts, src/agents/pi-tools.safe-bins.test.ts, src/agents/pi-tools.workspace-paths.test.ts, src/cli/program.smoke.test.ts, src/hooks/bundled/session-memory/handler.test.ts)\n- Land commit: 63ec16f\n- Merge commit: 1ee1522\n\nThanks @kelvinCB!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants