anthropics / anthropics/claude-code

[BUG] Chrome extension (v1.0.81) missing two CDP setup steps: Emulation.setFocusEmulationEnabled never called + Page.handleJavaScriptDialog only handles beforeunload

Open
#81,137 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Python
Stars
145k
Forks
23.1k
PR merge metrics
PR metrics pending

Description

## Title
[BUG] Chrome extension (v1.0.81) missing two CDP setup steps: `Emulation.setFocusEmulationEnabled` never called + `Page.handleJavaScriptDialog` only handles `beforeunload`

## Body

### Summary

Static analysis of the shipped Chrome extension bundle (`fcoeoabgfenejglbffodgkkbkcdhcgfn` v1.0.81, "Claude") reveals two missing CDP setup steps that cause two large classes of observable failures across `mcp__claude-in-chrome__*` tool calls:

1. **`Emulation.setFocusEmulationEnabled` is never called** → click/type/focus events behave incorrectly when the target tab is not the foreground tab, causing `browser_batch` sequences (click → type → submit) to fail silently.
2. **`Page.handleJavaScriptDialog` is only wired for `beforeunload`** → native `alert()`, `confirm()`, and `prompt()` dialogs are never dismissed, blocking the renderer main thread and causing subsequent `Runtime.evaluate` (and every other tool call on the tab) to hang indefinitely. Result: the tab becomes an unhealthy zombie.

Both are fixable in the extension in ~5 lines of code and would eliminate the majority of repeat failures I see in day-to-day Claude Code sessions.

### Evidence (from the shipped bundle)

Extension path: `~/Library/Application Support/Google/Chrome/Default/Extensions/fcoeoabgfenejglbffodgkkbkcdhcgfn/1.0.81_0/`

#### Finding 1: `setFocusEmulationEnabled` is never called

```
$ rg -c "setFocusEmulationEnabled" ~/Library/Application\ Support/Google/Chrome/Default/Extensions/fcoeoabgfenejglbffodgkkbkcdhcgfn/1.0.81_0/
(no output — zero hits across all 237 files)
```

Meanwhile the extension does call `Input.dispatchMouseEvent` directly (in `assets/mcpPermissions-DsrFI4Sf.js`):

```js
async dispatchMouseEvent(e,t){
...
await this.sendCommand(e,"Input.dispatchMouseEvent",n)
}
```

Without `Emulation.setFocusEmulationEnabled({enabled: true})` on attach, `document.hasFocus()` returns `false` whenever the target tab isn't the frontmost one, and standard focusin/click handler chains break. Playwright sets this by default on every browser context, which is why raw Playwright doesn't hit this failure mode.

#### Finding 2: `Page.handleJavaScriptDialog` is only wired for `beforeunload`

Same bundle (`assets/mcpPermissions-DsrFI4Sf.js`):

```js
if("Page.javascriptDialogOpening"===r){
const t=n?.type;
if("beforeunload"===t){
const t="accept"===(e.beforeunloadPolicyByTab.get(i)??"dismiss");
...
chrome.debugger.sendCommand({tabId:i},"Page.handleJavaScriptDialog",{accept:t},...)
}
// No branch for "alert", "confirm", or "prompt" — event is dropped
}
```

`Page.enable` **is** called on attach (verified: `Page.enable` appears in the bundle), so the `javascriptDialogOpening` event does fire — it's just discarded when `type !== "beforeunload"`. That leaves the renderer's synchronous `confirm()` blocking forever, and every follow-up CDP command that touches the renderer (`Runtime.evaluate`, `DOM.*`, etc.) pends until the tab is manually closed.

### Reproduction

**Repro 1 (silent click failure, related: `browser_batch` reliability):**

1. Open two tabs; call any `mcp__claude-in-chrome__*` action on the non-frontmost one that depends on `document.hasFocus()` (a login form, a rich-text editor, an OAuth consent screen).
2. Click/type events fire on the DOM element but the app's focus-guarded handlers don't run → the flow silently no-ops.
3. Bring the tab to the front and repeat → succeeds.

**Repro 2 (confirm freeze):**

1. Navigate to any page with a button that calls `window.confirm("…")` (or trigger a native delete-confirm on an admin panel).
2. Call `mcp__claude-in-chrome__left_click` on that button.
3. The dialog opens; the extension does not dismiss it.
4. Every subsequent tool call on that tab (`read_page`, `computer`, etc.) hangs / returns "tab not responding". The tab is effectively lost until closed.

### Suggested fix (sketch)

In the CDP command layer of the extension (same file as above):

```js
// (1) After attach + Page.enable, also enable focus emulation:
await this.sendCommandOnce(t, "Page.enable")
await this.sendCommandOnce(t, "Emulation.setFocusEmulationEnabled", { enabled: true })

// (2) Handle non-beforeunload dialogs (policy configurable per tab, default accept):
if ("Page.javascriptDialogOpening" === r) {
const type = n?.type
if (type === "beforeunload") { /* existing branch */ }
else if (type === "alert" || type === "confirm" || type === "prompt") {
chrome.debugger.sendCommand(
{ tabId: i },
"Page.handleJavaScriptDialog",
{ accept: this.dialogPolicyByTab.get(i) ?? true }
)
}
}
```

A small extension of the existing `beforeunloadPolicyByTab` API — e.g. `setDialogPolicy(tabId, {beforeunload, alert, confirm, prompt})` — would let callers keep the safer "dismiss by default" behavior on high-stakes pages while defaulting to auto-accept in normal automation.

### Impact

Across ~90 days of my own sessions (grepped from local Claude Code transcripts):

- ~155 sessions with a `TimeoutError` / navigation-timeout that traces back to a hung tab (Finding 2 as a plausible cause).
- ~30 sessions with `browser_batch` calls where the click landed but the follow-up type/submit didn't (Finding 1).
- Local memory entries `chrome-mcp-silent-click-no-focus-use-form-input`, `chrome-native-confirm-freezes`, `chrome-mcp-cookie-blocked-use-dom-href` already documented as workarounds — all three would become unnecessary if these two CDP setup steps landed upstream.

### Environment

- macOS 15.6 (Darwin 24.6.0)
- Chrome (stable channel)
- Claude Code CLI (current)
- Claude Chrome extension **v1.0.81** (extension ID `fcoeoabgfenejglbffodgkkbkcdhcgfn`)

### Notes

Happy to open a PR if the extension source is public somewhere I don't know about — the bundled JS is unminified enough to patch, but obviously that's not the source of truth. Also happy to run a live repro against a test page if that helps triage.

Labels: `bug`, `area:browser-extension`, `area:chrome`, `platform:macos`

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by locating the public source corresponding to the shipped Chrome extension bundle, especially assets/mcpPermissions-DsrFI4Sf.js and its CDP command layer. Verify the attach flow around Page.enable and the Page.javascriptDialogOpening handler, then reproduce the non-foreground focus case and native dialog hang. Done means both reported behaviors are covered by a source change and regression checks.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.