diff options
| author | Igor Soarez <igor@soarez.org> | 2026-11-08 15:10:48 +0000 |
|---|---|---|
| committer | Igor Soarez <igor@soarez.org> | 2026-11-08 15:10:48 +0000 |
| commit | 9004966da6491b368d12abeeb175256eedb78a2a (patch) | |
| tree | 4719e393d674053731ef79af24c50d3e3982dce3 | |
| parent | 66fbd3015ff68aa94f1faff1ad84740052b86a0d (diff) | |
navigate: do not require the debugger
Attaching first (for the Leave-site prompt) made chrome_navigate fail on a tab
whose page holds another extension's frame, such as a 1Password inline prompt,
which is exactly when navigating away is the way out. Attach is now best effort.
| -rw-r--r-- | extensions/chrome-profile-bridge/browser-extension/service_worker.js | 11 | ||||
| -rw-r--r-- | test-suite/unit/leave-site-prompt.test.mjs | 7 |
2 files changed, 16 insertions, 2 deletions
diff --git a/extensions/chrome-profile-bridge/browser-extension/service_worker.js b/extensions/chrome-profile-bridge/browser-extension/service_worker.js index 7fbbbba..3dcb0f4 100644 --- a/extensions/chrome-profile-bridge/browser-extension/service_worker.js +++ b/extensions/chrome-profile-bridge/browser-extension/service_worker.js @@ -1981,8 +1981,15 @@ async function dispatch(action, params) { await registerInitScript(tab.id, params.initScript); } // Attach first: the debugger is how we hear about, and answer, a "Leave site?" prompt. - await attachDebugger(tab.id); - await cdp(tab.id, "Page.enable", {}).catch(() => undefined); + // Best effort: another extension's frame on the page (a password manager's inline prompt) + // makes Chrome refuse the attach, and navigating away is often how a stuck tab is freed. + // Without the debugger we cannot answer a Leave-site prompt, but the navigation still runs. + try { + await attachDebugger(tab.id); + await cdp(tab.id, "Page.enable", {}).catch(() => undefined); + } catch (error) { + console.warn(`[pi-chrome] navigating tab ${tab.id} without the debugger: ${error?.message || error}`); + } dialogPolicy.set(tab.id, { leave: params.leaveIfAsked === true }); const dialogDismissed = new Promise((resolve) => dialogWaiters.set(tab.id, resolve)); const waitsForLoad = params.waitUntilLoad !== false; diff --git a/test-suite/unit/leave-site-prompt.test.mjs b/test-suite/unit/leave-site-prompt.test.mjs index 417d0b0..63d844a 100644 --- a/test-suite/unit/leave-site-prompt.test.mjs +++ b/test-suite/unit/leave-site-prompt.test.mjs @@ -99,3 +99,10 @@ test("the tool and the primer tell the agent what the prompt is and when to leav assert.match(src, /ask the user, because leaving discards unsaved work for good/); assert.match(src, /9\. A page can open dialogs you cannot see/); }); + +test("a tab the debugger cannot attach to (another extension's frame) still navigates", async () => { + const { w } = worker(undefined); + w.attachDebugger = async () => { throw new Error("Cannot access a chrome-extension:// URL of different extension"); }; + const result = await w.dispatch("page.navigate", { url: "https://other.test/", timeoutMs: 5000 }); + assert.equal(result.id, 2); +}); |
