aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Soarez <igor@soarez.org>2026-11-08 15:10:48 +0000
committerIgor Soarez <igor@soarez.org>2026-11-08 15:10:48 +0000
commit9004966da6491b368d12abeeb175256eedb78a2a (patch)
tree4719e393d674053731ef79af24c50d3e3982dce3
parent66fbd3015ff68aa94f1faff1ad84740052b86a0d (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.js11
-rw-r--r--test-suite/unit/leave-site-prompt.test.mjs7
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);
+});