From 4e7e80a59600c47a5e2588ae3ed8db053b5b04d2 Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Sun, 14 Jun 2026 00:02:22 +0900 Subject: [PATCH] fix(ab-connect): bind to stable tabId as the primary key + retry on mid-flight detach (0.4.8, #23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit claude-in-chrome completes the Rakuten cart→購入手続き→checkout flow that chrome-use 1.2.3 couldn't, because it binds to the browser-level tabId (survives renderer-process swaps) rather than a CDP target/sessionId (torn down by the cross-origin OAuth/SSO nav). chrome-use's relay is already keyed to the stable tabId (cb-tab-, #17) and sends commands by {tabId} — the gap was purely that the extension treated the session→tab map as the source of truth and only reactively re-attached after a failed lookup. Make the tabId the PRIMARY resolution path: derive it straight from the session id (tabIdFromSession), ensure-attach with short retries across the swap window (recoverSessionTab now loops), and route every send through sendCdpToTab, which on a detached-style error drops the stale handle, re-attaches the stable tab, and retries once. So a cross-process nav never surfaces as a hard error — there's no 'session gone' window, matching claude-in-chrome. Builds on 0.4.5/0.4.6 reattach; makes it primary + bulletproof rather than a fallback. --- extensions/ab-connect.crx | Bin 31865 -> 32306 bytes extensions/ab-connect.zip | Bin 31289 -> 31756 bytes extensions/ab-connect/background.js | 98 +++++++++++++++++++--------- extensions/ab-connect/manifest.json | 2 +- 4 files changed, 67 insertions(+), 33 deletions(-) diff --git a/extensions/ab-connect.crx b/extensions/ab-connect.crx index 598d59f3958ac50c1f8473fe5ef3e87ed915cb8c..c2b95a6f09b1064d88c7a9b1dceb0d8a8f3bbb3e 100644 GIT binary patch delta 7660 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 delta 7271 zcmZ{pRa9I}*R7k-xH}2%?(Xg`jYDv0Xxy!X2MzA7!GZ<%;0|e=5CQ}bu0j9TJ{#kl zJw{#ZS+izUtyOnV+#Ou|6&!}93Oo=W001BZ%DSeKFvt-J9ofKyjtyKf@X$XL6Wvgv zC46E407(G=zyOc}EG?`Y?c80woUPfx9w1#50Q}zz*uY-CXaG3iH5>r&SKy$@LGqe> z^7BjuBbf-07FTzz=_dP)5=_|1C(bLpqx-pNp(<83X^1pRd6`<|{mdC97Csr-1~`hvspa_y*9 zwZ)yq(l8N=29gaM1HMF8$l-E;n5xonGePJoT8vpScB+cH?vbbN&%#rCcVCRD(!qIl z)V;b9iL#Tb9X=c>Aot2aqqH&;`jw0CVv{L97zm`G>5j_PT{VOB992nuCCt5=EAyI^ zM((kEP0U#nF)J#{MdEtQEO@LAf|j^V-HKbBxD08DAi6yk^d(jKhHOZN3J6luEJ6(FYciECv9RlHg zs2_oX(?(!xv0ck!)QFXKzx^?`S`{p5(AwE6^!+Clp`>Yo1WsGDJw1!o(QmYDE+UTVls@Sha&mdD`F5-Rqik1eaBchjC$`WnE9 zs~2IejPnES$xCR?4w`;6QM?*Oj_R@MmGIc$R!3QuaoSf5zHKcdFk>V6 zsM0f4SfANW*jVEi9hYm>na$WNZoehNHtUydUh+fFQ9#j&Us-raB4H=ez*tfTD4RQ_ z(@ruI6Ntn@++_Lw$IjRa@_1?Ej`;63jFoizBJwBhUmF6Vs2>AzrLQS2!mAPumB!hj zxZL%oNxHK(-FF;d@9Y^4U9W<8K(_MLDm^|1V!eGX>_eT#jChxD@Na2RT$zuOv>D5L zNCSS>lfm}#1)E85S- zUW{W?K#o(#hEFdRVGOLUx6?2Q)7Ywb(3kCh`;Pajy-K%1y|FZ$N3u=nGPL!W4Yf1X z5=CkW$)jjqJ}M_!{_OK;&FuhmZAqf{_t~#&jk=9|%XXgu!w%2@&U_#T&wV><>ekyE zX0=PQr}TlwbkUERTu;lADtCJ=%cbL!t5_RYglF^w4SkNm1w@~#-`$}PEl48k5wku3 zdbb5-C9!b*&#)z)2SsAE??S;5NVlg^qQVAJWWC~{o0qr99z#u{dLtlcVtA47;~f`_ zMYox)aTsxZs<~d_ln%XDx9{p? zZ15s*yfg1k@-?bn(&dqb4)-J~bqq}xYGtejO>-WHw(sUyO3X>7KRB`HF8lKHJ^|OT zmPzG{)6E*O``Pq5GztdUwsXKB7jae^dcrsD<{eF5?{!bCwWEjaK?ei_$iCJ+sG*vo z{*(D^pBN2i|Am@<7VxGL2Ui4ucHzE@H{muWU1+qsfw3QnUkTq%C0g zk!g18)YHm5Fe(y?umugg!+*9yCC< zGS^vCLuV-k$s?s6BM)JNoE%4f36_)4DHo8cpTmJnEh$L-Zc@F;`c$-{g_w z#3z2sXj;K|b!PZX^NhK;qfKFefbO@GP#`His!3Jc&+!_H%}73#V~!|WCn2>X#?E7?Y}U|>y{Fo`KA((? z$-_lk2fr3LPJ*oFuz&sB?&b9zT=s|fh4PydBc0r++L?(TlZ51avSwT^Au?0<;j4X# zU3PUHzlmF1ise(U;;rJs$L@3O>~L->K2FdNL?hA<=s)=mNbbUTTb z8cK9W|K>&kCGh2=bR?A+JS89DJ0yAM+?-Suc=xs=oBYZsGyjPA1PC|sXp*5(^Ja7} zV7u9aHYaxkh`MfI1i;#ne+Y^+Wyc?Y-$5HDo{Lz`kRtY0^))bFPP|Te-m)LuOLRe# za%zNL2k?cp%d)--|H+`pLBHoFUU#uYdZ9=O&3NqqZelC)n3gQug&Qa~)jss7s>b!E zLr=9#|I#+d`m&!aAF7^Bo=%~c5F(byV!?QpT9L{^lkm`nV(yW(1FTIvH3v>7^J~eo z(YWT{j1$rgy2=T@CLgKihmfEo4yt6)p~*qh30E*atL0^hH|^QXze|ypx`TYE$1G8x zc9D5f-pZ}%Q{ZLcq2Oc7$`Tr7q>dcnUz2F56e}giCUK(kKXJ>>9yt?Zb6sxEc|)*; zw<$4hRHSirKuCSZS@4vGYco^!u4##c8VRW47eni(5Q)AkcW;98LgAJVm)CiIB_ITi zG^qG?hLtLQV1h9y~V(B!zn0Ld-d}4K>72?|J^1+#|;^y7c z9Yy95xiF8%^2Hpm3$EF|mm%3|g-Af_3Q4I=lDx5b9(-XMI7Busw1HSU$%ytfw~(|o zL{FHHe?%LC#Lsy2Dto}jBtdI~r0@99PH9h#)b6KJXacg=5j(VFLfT5RPPb=d#2}U|Cwhm6aYB z_-VJW)%HTK*SmiuN&tPdL?>?l^#I&KN7JWI=?E=n#roG@`b1)VzIPhD!*5Z9;zz+R z7LS4;ib`PRNFRDlm!S)(W|z7vDV*rz*u`{u!u%OKE9R2NXa`a8);-RJq;Sx9q$2f4 z$LRM$eKtGD7A4e}E1X43avcn7m$;t9Oo7bC)t~&dlh*Jn72p#pt&9n6QkE9XzAI?E zJq^n?(~@v-x`Bk&3$X=sc;7@p33L|lq>^mY1A*wGo({>(sLNsFEu3ARGoAhC6@DmD zyqohiilZVCG~=6s(wKrVS;&GJ4yZ_BfzDKW<=E|KVY1-{!zkr4|1(i5BCrL0>E-eT}jf1_TJEzdIw z4mg9AxxV^t@8jY?BBh6U>!-w{-zp+c9eNhKc62H{IL@-C_N#o{KqI7Qd!`p!yo&_# zju`H7&M*FXr7@OY5g=WZACNM*5wuT+H*y}UImEW7YO4p9G^p2IeJxGJq_15K&}5;p zOz{o7Ov4?Co3`^_Fa%RvJ}{lDIL}#jt8OfoEwDI2*`B?G8SA%J$O^ zuH+fZt@7+aT)8_$;Dyc14v9TkEVIHxVn2V6SO-X487kE92Ez0;9_$v zX@V4Cd;-W;nc}#q+-6mk(>w0-!Ir;`ED`NKQBURI$XyA!LW57_Ry&$p zV9p|%sKd72Mdm7ljbPp%9eThqy{%fEXnCr+!#J#M^0NA9duALpzUVR9@K=a<{_4a*f55j zTqDOF<~n+4R@F!N*V)UWA?pjQdyZ7W120luVJxO5UHOM~U zIDnP*YamHQz;wq)Llb{7o*N_nq!ZIyB`ZI& zol24~oZBq!$N3)JCkVR;*v^r%KN3mhiK+9eCwMy4 zHDTFMDilM_9Gqgsc5bQjr8GpPx-{0u&&=h|)K>x^ewE5fs#~pt&}ui`kWxUxa;-tH zWZ)oNh<~X`WO{^FphOmRrXJo;J>JSzrFzahW-iSvkB&F);z9xyWoIlaXl0=XmR;0M z&8X=d;7~5|I1u4lEx6Y4r-T-U_4{VN!f179Ub4YPfU=`|6z-hX-tGkJT&y&)XBtWr znF66bvD|{$Rk`Pc$04MQfUIq=2Ybt;Vv5hZ$9RLiV|ViYQ+uMP*bZ=UH{Wbn2zPI* zM*&awcx8lBU)#b$*C4G1!UXb+_ZjVSubERM^^Dpwu0Z8kM8oCITg^}Q(ZMTG;o*VS z>et|SBJBnK+!v(O%W&|VJ!3W&7`_UAv9R=JS@p?NG)CP!YYKk+0rNik-VMg-A`HQk z^Zo8XB)wy{qnAMM9PM7RJ4Vd~Qg#SMQ z@iw@mTqJ^Q9G`Vf({HaNlX#W)3)Mr9UlFqu0}lF(P2cRjQm$%Cgp5mh4k(J@^Oz86&Fp+Int%l|?+; zF~QVLJ+JO?e^f5`A)UcQeVN4lki3mP}6sVCQZP4Z}>6D+gtaFhx4Z=};*73Oeot?`oFG}D zy<-x>q;n7=1CtH@gnD?Z$ER2k)5()TUQ-K0Vk(UAOS21P!=3(m6U6q+<4dX&nb&#f z%%sy-=kEI&aX@e~1a22<)#w{u?QT-mgK* zxo|7EkA&82g=P;8_ytZn_0p_xz03qCvV^tEbz*RJC-54tPIwALlz+<}{$!cWh4; z+iVHm`mEBNZlwCwm6jJb*J>%8-H(DE#k%SVp6rq?fYnKL9Ha6Kv!|sS#psb+FKjT0 zq7AhUMXY-xk=9=-q{82GEP`6ijh5KIHG5x3d>HJ!RpTAU>f{4?)V27bj85R8588iU zpl(jQPBR#Wj>q#92HnN0fWLkF20S>u^sK(^NJb)5Xj=clIygRuHj=zg9Ic1aAop2n4++4l~WjTv01v6|X zvf!J-8kF9WU@{5EU!ZyP_7}!0UdDZB_JcG|whoy$9#UmW|@{v{d31HKKl`1M-rsF{qw@NlhM&gQJLrM zck9w&Nyf*sOjt))M0$MLV3Gtxi-K~oJ@^BCKHn7XnR}3`$R*TdPM9%t1H(-&eC7y# ze&+?s+wMvf2@A}!PRiv;{DA7$F!Wq3WG9O|>&`GWVH#0PqS2y_)@S1Ulbr>jcT-Q; zHtr-feo|UMbRUJA)#5GQoDy(d$ZIU@({&xG4)AL){Vb8oz8SZ+&cXIwlqUD}*oY|8&reDjKmWe`mZ-2EB~2KV5e z38~>(GrL2qIk}7H8qB4YGDM{+9Cas22dma))of1}rUZJlXnE-qkW<=zg1e&TBH$O- z+&c*iV)9&elW#TBKR+^COfYMVA5q$+Enp(Z$i=N=N~`)hKTdoIc z;G5BBeEL1e>U*0bp(?cL$L|FR3G7>`ANhCVrVMUV;1|ra>OC#43CRfIkob5T&1>eF z;NASDFq&SK(_Ag8?vh1lgsNS7hejxDEOE_Cb9#@uvZI$K5alL~^!VmNS8jd~W4dU8 zo+l@HH`90=B-a`}v|bIY2=avZWAQ*Onw0su3IRVat14WIpFSc0c)8RF!94{7>CZjc zbx{BVRCRl`3a4*0PcWcLS&G1LRl#2FZ#EJEKJHTrN0o^s5>$IqWS8OopPfubjdDT! zq~Zs~n>Qi+w=d}&{a42?XPt~sZnRg{d=rO7L);#XjV^SQSK3enVYM~% z+w;S2R{Tg)mc?Dwjk8LV?Qb&U3U$;0bdMmK3>6YwNHm+84m8nL>daB9lzKn@~ zB{3oHZUGd`QEc`Fty937F@N-p^cF|^+}eW~292>tx&$`ArD*+E4l*ejqP3WlQ~S50 z%o6PLU<#r)653<_X?sKf>b%xgM{y#<66(g$XO}nih7zZfKb_7PxvYO-aTmgkX$(mo zNd+q2yu-ASxj_%pz>>Vcq6YjAok%$*qx=U?G~tnlBEbK_CsHzLNdM7NI%r7#l9p-c z|78QxroZ}2%cK97mZHH;+jLCNjrNyL&CT#HuLk#{=wF(;%l~-uU62t`{zM`6!VRXf zDRo|C(EktefM`!Rf8oULx+Kt>PE5wu8f=a-TYZ)^rW!Gfi+y`RgG}|@?Rcs9(LdVT z&fCX!Nk|Qu34g&7P29=f)r{D*X3R1hS&hJ4yFQNx)pkxM>AdJuW`^4DKq-;4NfeS# zlO#ZH-sI_Ma_H!stU~D~X-C%VPrA#WEQ^;_RMHQUWwi1wpV(B zaw&>_Nd)ix@I@^`9hz0QUI!{~fDMhNJeV3|?~_dDty&Dl8mGXMde;KeLA*fMhL z5bOVfPfZ3s?r?wgZpxSS6`^B_q(2e>QT{!j;_OF4fKCbkxVpG{ zxw6}PLYzRl2!DdDKXS diff --git a/extensions/ab-connect/background.js b/extensions/ab-connect/background.js index ea2d059..f08f994 100644 --- a/extensions/ab-connect/background.js +++ b/extensions/ab-connect/background.js @@ -155,23 +155,56 @@ 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) +// The STABLE Chrome tabId encoded in a `cb-tab-` session id (#17), or +// null for any other session shape (child/iframe sessions). The tabId is the +// real source of truth: it survives the renderer-process swaps (cross-origin +// OAuth/SSO navs) that tear down the page's CDP target — which is why binding to +// it (like claude-in-chrome) rides through the hop that killed the old +// target/sessionId binding (issue #23). +function tabIdFromSession(sessionId) { + const m = /^cb-tab-(\d+)$/.exec(sessionId || '') + return m ? Number(m[1]) : null +} + +// Ensure the debugger is attached to a `cb-tab-` session's tab, re-attaching +// across the transient window of a process swap (with a couple of short retries). +// Returns the tabId on success, or null when the tab is genuinely gone +// (closed / restricted). (issues #20.1, #23) 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 + const tabId = tabIdFromSession(sessionId) + if (tabId == null) return null + for (let i = 0; i < 3; i++) { + const tab = await chrome.tabs.get(tabId).catch(() => null) + if (!eligible(tab)) return null + try { + await attachTab(tabId) + if (tabs.has(tabId)) return tabId + } catch { + // mid-swap: the tab exists but isn't attachable yet — back off and retry. + } + await new Promise((r) => setTimeout(r, 120 + i * 150)) + } + return null +} + +// Send a CDP command to a tab, riding a debugger detach that can happen between +// our attach check and the command itself (a renderer-process swap mid-flight). +// On a detached-style failure, drop the stale handle, re-attach the stable tab, +// and retry once — so a cross-process nav never surfaces as a hard error (#23). +async function sendCdpToTab(tabId, method, params) { + const dbg = { tabId } + try { + return await chrome.debugger.sendCommand(dbg, method, params) + } catch (e) { + const msg = String((e && e.message) || e) + if (!/detached|not attached|target.*(closed|gone)|no target|cannot access|frame.*detached/i.test(msg)) { + throw e + } + detachTab(tabId, false) + const ok = await recoverSessionTab(`cb-tab-${tabId}`) + if (!ok) throw e + return await chrome.debugger.sendCommand(dbg, method, params) } - return tabs.has(tabId) ? tabId : null } function anyConnectedTab() { @@ -232,24 +265,26 @@ async function handleForwardCdpCommand(msg) { // Fail loudly instead so the agent sees an actionable error, not bad data. let tabId if (sessionId) { - tabId = tabForSession(sessionId) - if (!tabId) { - // 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) { + // The stable Chrome tabId encoded in `cb-tab-` is the source of truth + // (it survives renderer-process swaps; the CDP target/sessionId does not). + // Resolve via it primarily — don't depend on a session→tab map entry that the + // detach handler may have cleared — and ensure the debugger is attached, + // re-attaching across a cross-process nav before failing (issues #20.1, #23). + // `tabForSession` still covers child/iframe sessions that aren't `cb-tab-*`. + tabId = tabIdFromSession(sessionId) ?? tabForSession(sessionId) + if (tabId == null) { + throw new Error(`unknown sessionId ${sessionId} for ${method}`) + } + if (!tabs.has(tabId)) { + const recovered = await recoverSessionTab(sessionId) + if (!recovered) { 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.`, ) } + tabId = recovered } } else if (typeof params?.targetId === 'string') { tabId = tabForTarget(params.targetId) @@ -259,18 +294,17 @@ async function handleForwardCdpCommand(msg) { // applies to any attached tab. tabId = anyConnectedTab() } - if (!tabId) throw new Error(`no attached tab for ${method}`) - const dbg = { tabId } + if (tabId == null) throw new Error(`no attached tab for ${method}`) // Re-enabling Runtime can leave a stale state; bounce it (matches upstream). if (method === 'Runtime.enable') { try { - await chrome.debugger.sendCommand(dbg, 'Runtime.disable') + await sendCdpToTab(tabId, 'Runtime.disable', undefined) await new Promise((r) => setTimeout(r, 30)) } catch {} - return await chrome.debugger.sendCommand(dbg, 'Runtime.enable', params) + return await sendCdpToTab(tabId, 'Runtime.enable', params) } - return await chrome.debugger.sendCommand(dbg, method, params) + return await sendCdpToTab(tabId, method, params) } // ---- attach / detach ------------------------------------------------------ diff --git a/extensions/ab-connect/manifest.json b/extensions/ab-connect/manifest.json index 0558ae8..aa6d63b 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.7", + "version": "0.4.8", "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": {