diff --git a/extensions/ab-connect.crx b/extensions/ab-connect.crx index c54c221..08b5b32 100644 Binary files a/extensions/ab-connect.crx and b/extensions/ab-connect.crx differ diff --git a/extensions/ab-connect.zip b/extensions/ab-connect.zip index 45c2a58..d6f9866 100644 Binary files a/extensions/ab-connect.zip and b/extensions/ab-connect.zip differ diff --git a/extensions/ab-connect/background.js b/extensions/ab-connect/background.js index 0f5dd07..4c4cba5 100644 --- a/extensions/ab-connect/background.js +++ b/extensions/ab-connect/background.js @@ -149,6 +149,25 @@ function tabForTarget(targetId) { return null } +// Best-effort recovery for a stale `cb-tab-` session: the handle is gone +// from our maps, but if the underlying Chrome tab still exists and is eligible, +// re-attach to it and return its id so the in-flight command can be retried. +// Returns null when the tab is genuinely gone (closed / restricted), in which +// case the caller surfaces the stale-session error. (issue #20.1) +async function recoverSessionTab(sessionId) { + const m = /^cb-tab-(\d+)$/.exec(sessionId) + if (!m) return null + const tabId = Number(m[1]) + const tab = await chrome.tabs.get(tabId).catch(() => null) + if (!eligible(tab)) return null + try { + await attachTab(tabId) + } catch { + return null + } + return tabs.has(tabId) ? tabId : null +} + function anyConnectedTab() { const it = tabs.keys().next() return it.done ? null : it.value @@ -209,11 +228,22 @@ async function handleForwardCdpCommand(msg) { if (sessionId) { tabId = tabForSession(sessionId) if (!tabId) { - throw new Error( - `stale sessionId ${sessionId} for ${method}: its tab is gone (closed, ` + - `navigated across processes, or lost after an extension restart). ` + - `Re-attach by re-opening your target URL before retrying.`, - ) + // The session's debugger handle is gone, but `cb-tab-` encodes the + // STABLE Chrome tabId (#17). A cross-process navigation (e.g. an SSO + // redirect to another origin), a service-worker restart, or DevTools + // briefly stealing the debugger all tear the handle down while the tab + // itself lives on. Before failing, try to transparently re-attach to that + // same tab and retry — so `open`/`navigate`/`eval` self-heal instead of + // dead-ending the agent (issue #20.1). attachTab re-mints the identical + // `cb-tab-` session, so the daemon's binding stays valid. + tabId = await recoverSessionTab(sessionId) + if (!tabId) { + throw new Error( + `stale sessionId ${sessionId} for ${method}: its tab is gone (closed, ` + + `navigated across processes, or lost after an extension restart). ` + + `Re-attach by re-opening your target URL before retrying.`, + ) + } } } else if (typeof params?.targetId === 'string') { tabId = tabForTarget(params.targetId) diff --git a/extensions/ab-connect/manifest.json b/extensions/ab-connect/manifest.json index a1edb1b..228d276 100644 --- a/extensions/ab-connect/manifest.json +++ b/extensions/ab-connect/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "chrome-use", - "version": "0.4.5", + "version": "0.4.6", "description": "Let chrome-use drive your logged-in Chrome \u2014 install once, no token, no per-use confirmation.", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6vQIyscGIPYPZdSpPwPL0+0gxUROyRgCpmvCSDoc8XUm4qm97VbKnD9Ijc1lV22lNWZtE78gaRjt6BeSfuMgnBymnhLKjN1gU6AI5QUU0mrJyeHdWKvrKQR5FmsM2A7Xr1ykE2SiiS8zNUS3Y/6O5l+Nva7wrVy6E4a2dkBVQkOsu+DV+nEZvhIyuDY5D5SPXqNwUTWTaglwj5mjvHz36xSwCWlPmrtJ+ED0AUyrb2z4GIOmvk4kqtBVrh/UD058klLo4CkYOnIybB5aV6WYuwarfPY4bF/dLggPem+ewLNTUNBuwrxj/A4nUv0LJTuRO8rR7f8WR9qnRCY0Ic5saQIDAQAB", "icons": {