surf-cli 2.9.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +48 -4
  2. package/dist/content/accessibility-tree.js +11 -0
  3. package/dist/content/accessibility-tree.js.map +1 -0
  4. package/dist/content/visual-indicator.js +111 -0
  5. package/dist/content/visual-indicator.js.map +1 -0
  6. package/dist/manifest.json +11 -2
  7. package/dist/options/options.js +3 -3
  8. package/dist/options/options.js.map +1 -1
  9. package/dist/service-worker/index.js +61 -261
  10. package/dist/service-worker/index.js.map +1 -1
  11. package/native/activity-journal.cjs +55 -0
  12. package/native/chatgpt-client.cjs +2 -0
  13. package/native/cli.cjs +52 -278
  14. package/native/do-executor.cjs +52 -475
  15. package/native/do-parser.cjs +8 -249
  16. package/native/host-helpers.cjs +6 -14
  17. package/native/host-sessions.cjs +5 -1
  18. package/native/host.cjs +199 -1
  19. package/native/network-export.cjs +20 -17
  20. package/native/network-store.cjs +38 -58
  21. package/native/playbook-authoring.cjs +44 -0
  22. package/native/playbook-cli.cjs +157 -0
  23. package/native/playbook-client.cjs +259 -0
  24. package/native/playbook-receipts.cjs +109 -0
  25. package/native/playbook-records.cjs +208 -0
  26. package/native/playbook-runtime.cjs +177 -0
  27. package/native/playbooks.cjs +235 -0
  28. package/native/private-state.cjs +156 -0
  29. package/native/redaction.cjs +104 -0
  30. package/native/workflow-definition.cjs +368 -0
  31. package/native/workflow-runtime.cjs +225 -0
  32. package/package.json +2 -1
  33. package/playbooks/page/ops/read.json +22 -0
  34. package/playbooks/page/playbook.json +7 -0
  35. package/skills/surf/SKILL.md +41 -1
  36. package/dist/content/index.js +0 -116
  37. package/dist/content/index.js.map +0 -1
@@ -1,25 +1,21 @@
1
- var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r},n={alt:1,ctrl:2,control:2,meta:4,cmd:4,command:4,win:4,windows:4,shift:8},r={enter:{key:`Enter`,code:`Enter`,keyCode:13,text:`\r`},tab:{key:`Tab`,code:`Tab`,keyCode:9},escape:{key:`Escape`,code:`Escape`,keyCode:27},backspace:{key:`Backspace`,code:`Backspace`,keyCode:8},delete:{key:`Delete`,code:`Delete`,keyCode:46},arrowup:{key:`ArrowUp`,code:`ArrowUp`,keyCode:38},arrowdown:{key:`ArrowDown`,code:`ArrowDown`,keyCode:40},arrowleft:{key:`ArrowLeft`,code:`ArrowLeft`,keyCode:37},arrowright:{key:`ArrowRight`,code:`ArrowRight`,keyCode:39},home:{key:`Home`,code:`Home`,keyCode:36},end:{key:`End`,code:`End`,keyCode:35},pageup:{key:`PageUp`,code:`PageUp`,keyCode:33},pagedown:{key:`PageDown`,code:`PageDown`,keyCode:34},space:{key:` `,code:`Space`,keyCode:32,text:` `},f1:{key:`F1`,code:`F1`,keyCode:112},f2:{key:`F2`,code:`F2`,keyCode:113},f3:{key:`F3`,code:`F3`,keyCode:114},f4:{key:`F4`,code:`F4`,keyCode:115},f5:{key:`F5`,code:`F5`,keyCode:116},f6:{key:`F6`,code:`F6`,keyCode:117},f7:{key:`F7`,code:`F7`,keyCode:118},f8:{key:`F8`,code:`F8`,keyCode:119},f9:{key:`F9`,code:`F9`,keyCode:120},f10:{key:`F10`,code:`F10`,keyCode:121},f11:{key:`F11`,code:`F11`,keyCode:122},f12:{key:`F12`,code:`F12`,keyCode:123}},i=class e{targets=new Map;consoleMessages=new Map;networkRequests=new Map;networkEntries=new Map;consoleCallbacks=new Map;networkCallbacks=new Map;networkRequestStartTimes=new Map;pendingDialogs=new Map;networkEntrySeq=0;static debuggerListenerRegistered=!1;static MAX_INLINE_BODY_SIZE=16*1024;static STATIC_ASSET_TYPES=new Set([`image/png`,`image/jpeg`,`image/gif`,`image/webp`,`image/svg+xml`,`image/x-icon`,`font/woff`,`font/woff2`,`font/ttf`,`font/otf`,`application/font-woff`,`application/font-woff2`,`text/css`,`application/javascript`,`text/javascript`,`application/x-javascript`]);static BINARY_TYPES=new Set([`image/png`,`image/jpeg`,`image/gif`,`image/webp`,`image/x-icon`,`font/woff`,`font/woff2`,`font/ttf`,`font/otf`,`application/font-woff`,`application/font-woff2`,`application/octet-stream`,`application/pdf`,`application/zip`,`audio/mpeg`,`audio/wav`,`audio/ogg`,`video/mp4`,`video/webm`,`video/ogg`]);async attach(e){if(this.targets.has(e))return;let t={tabId:e};try{await chrome.debugger.attach(t,`1.3`)}catch(n){let r=n instanceof Error?n.message:String(n);if(r.includes(`Already attached`)){this.targets.set(e,t);return}throw r.includes(`Cannot access`)||r.includes(`Cannot attach`)?Error(`Cannot control this page. Chrome restricts automation on chrome://, extensions, and web store pages.`):Error(`Failed to attach debugger: ${r}`)}this.targets.set(e,t),this.setupEventListener(),this.consoleMessages.set(e,[]),this.networkRequests.set(e,[]);try{await this.send(e,`Page.enable`)}catch{}}async detach(e){let t=this.targets.get(e);if(t){try{await chrome.debugger.detach(t)}catch(e){console.warn(`[CDPController] Error detaching:`,e)}this.targets.delete(e),this.consoleMessages.delete(e),this.networkRequests.delete(e),this.networkEntries.delete(e),this.consoleCallbacks.delete(e),this.networkCallbacks.delete(e),this.pendingDialogs.delete(e)}}async detachAll(){for(let e of this.targets.keys())await this.detach(e)}setupEventListener(){e.debuggerListenerRegistered||(e.debuggerListenerRegistered=!0,chrome.debugger.onEvent.addListener((e,t,n)=>{let r=e.tabId;!r||!this.targets.has(r)||this.handleCDPEvent(r,t,n)}),chrome.debugger.onDetach.addListener((e,t)=>{let n=e.tabId;n&&this.targets.has(n)&&(this.targets.delete(n),this.consoleMessages.delete(n),this.networkRequests.delete(n),this.networkEntries.delete(n),this.consoleCallbacks.delete(n),this.networkCallbacks.delete(n))}))}handleCDPEvent(e,t,n){switch(t){case`Runtime.consoleAPICalled`:this.handleRuntimeConsole(e,n);break;case`Runtime.exceptionThrown`:this.handleRuntimeException(e,n);break;case`Network.requestWillBeSent`:this.handleNetworkRequest(e,n);break;case`Network.responseReceived`:this.handleNetworkResponse(e,n);break;case`Network.loadingFailed`:this.handleNetworkFailed(e,n);break;case`Network.loadingFinished`:this.handleLoadingFinished(e,n);break;case`Page.javascriptDialogOpening`:this.handleDialogOpening(e,n);break;case`Page.javascriptDialogClosed`:this.pendingDialogs.delete(e);break}}handleRuntimeConsole(e,t){let n=this.consoleMessages.get(e)||[],r=(t.args||[]).map(e=>e.value===void 0?e.description?e.description:``:String(e.value)).join(` `),i=t.stackTrace?.callFrames?.[0],a={type:t.type||`log`,text:r,timestamp:t.timestamp||Date.now(),url:i?.url,line:i?.lineNumber};n.push(a),n.length>1e3&&n.shift(),this.consoleMessages.set(e,n);let o=this.consoleCallbacks.get(e);if(o)for(let e of o.values())e(a)}handleRuntimeException(e,t){let n=this.consoleMessages.get(e)||[],r=t.exceptionDetails;if(!r)return;let i={type:`exception`,text:r.exception?.description||r.text||`Unknown exception`,timestamp:r.timestamp||Date.now(),url:r.url,line:r.lineNumber};n.push(i),n.length>1e3&&n.shift(),this.consoleMessages.set(e,n);let a=this.consoleCallbacks.get(e);if(a)for(let e of a.values())e(i)}handleNetworkRequest(e,t){let n=this.networkRequests.get(e)||[],r=t.request;if(!r)return;let i=t.timestamp?t.timestamp*1e3:Date.now();this.networkRequestStartTimes.set(t.requestId,i);let a={};if(r.headers)for(let[e,t]of Object.entries(r.headers))a[e]=String(t);n.push({requestId:t.requestId,url:r.url,method:r.method,type:t.type,timestamp:i,requestHeaders:a,requestBody:r.postData}),n.length>500&&n.shift(),this.networkRequests.set(e,n),this.networkEntries.has(e)||this.networkEntries.set(e,new Map);let o=this.networkEntries.get(e),s=`r_${i}_${++this.networkEntrySeq}`,c={};if(r.headers)for(let[e,t]of Object.entries(r.headers))c[e]=String(t);let l=r.postData,u=l?l.length:void 0,d={id:s,ts:i,method:r.method,url:r.url,origin:this.extractOrigin(r.url),requestHeaders:c,requestBody:l,requestBodySize:u,tabId:e,tabUrl:t.documentURL,type:t.type,flags:[],_requestId:t.requestId,_responseReceived:!1,_loadingFinished:!1};if(o.size>500){let e=o.keys().next().value;e&&o.delete(e)}o.set(t.requestId,d)}handleNetworkResponse(e,t){let n=(this.networkRequests.get(e)||[]).find(e=>e.requestId===t.requestId);if(n){if(n.status=t.response?.status,n.mimeType=t.response?.mimeType,t.response?.headers){let e={};for(let[n,r]of Object.entries(t.response.headers))e[n]=String(r);n.responseHeaders=e}let r=this.networkCallbacks.get(e);if(r){let e=this.networkRequestStartTimes.get(t.requestId),i=Date.now(),a=e?Math.round(i-e):void 0;for(let e of r.values())e({method:n.method,url:n.url,status:n.status,duration:a,timestamp:i})}}let r=this.networkEntries.get(e)?.get(t.requestId);if(r&&t.response){let e=t.response,n=this.networkRequestStartTimes.get(t.requestId),i=t.timestamp?t.timestamp*1e3:Date.now();n&&(r.ttfb=Math.round(i-n)),r.status=e.status,r.statusText=e.statusText,r.mimeType=e.mimeType;let a={};if(e.headers)for(let[t,n]of Object.entries(e.headers))a[t]=String(n);r.responseHeaders=a,this.isBinaryType(e.mimeType)&&r.flags.push(`binary`),(e.mimeType?.includes(`protobuf`)||e.mimeType?.includes(`x-protobuf`)||e.mimeType?.includes(`application/grpc`))&&r.flags.push(`protobuf`),r._responseReceived=!0}}handleNetworkFailed(e,t){let n=(this.networkRequests.get(e)||[]).find(e=>e.requestId===t.requestId);if(n&&!n.status){n.status=0;let r=this.networkCallbacks.get(e);if(r){let e=this.networkRequestStartTimes.get(t.requestId),i=Date.now(),a=e?Math.round(i-e):void 0;this.networkRequestStartTimes.delete(t.requestId);for(let e of r.values())e({method:n.method,url:n.url,status:0,duration:a,timestamp:i})}}let r=this.networkEntries.get(e)?.get(t.requestId);if(r){let e=this.networkRequestStartTimes.get(t.requestId),n=t.timestamp?t.timestamp*1e3:Date.now();e&&(r.duration=Math.round(n-e)),this.networkRequestStartTimes.delete(t.requestId),r.status=0,r.flags.push(`failed`),r._loadingFinished=!0}}handleDialogOpening(e,t){this.pendingDialogs.set(e,{type:t.type,message:t.message,defaultPrompt:t.defaultPrompt,timestamp:Date.now()})}async handleLoadingFinished(t,n){let r=(this.networkRequests.get(t)||[]).find(e=>e.requestId===n.requestId);if(r){let i=this.networkRequestStartTimes.get(n.requestId),a=n.timestamp?n.timestamp*1e3:Date.now();if(i&&(r.duration=Math.round(a-i)),!this.isStaticAsset(r.mimeType)&&!this.isBinaryType(r.mimeType)&&(n.encodedDataLength||0)<=e.MAX_INLINE_BODY_SIZE)try{let i=await this.send(t,`Network.getResponseBody`,{requestId:n.requestId});if(i.base64Encoded)try{r.responseBody=atob(i.body)}catch{r.responseBody=i.body}else r.responseBody=i.body;r.responseBody&&r.responseBody.length>e.MAX_INLINE_BODY_SIZE&&(r.responseBody=r.responseBody.slice(0,e.MAX_INLINE_BODY_SIZE))}catch{}}let i=this.networkEntries.get(t)?.get(n.requestId);if(!i)return;let a=this.networkRequestStartTimes.get(n.requestId),o=n.timestamp?n.timestamp*1e3:Date.now();if(a&&(i.duration=Math.round(o-a)),this.networkRequestStartTimes.delete(n.requestId),i.responseBodySize=n.encodedDataLength,i._loadingFinished=!0,!this.isStaticAsset(i.mimeType)&&!this.isBinaryType(i.mimeType)&&(n.encodedDataLength||0)<=e.MAX_INLINE_BODY_SIZE)try{let r=await this.send(t,`Network.getResponseBody`,{requestId:n.requestId});if(r.base64Encoded)try{i.responseBody=atob(r.body)}catch{i.responseBody=r.body,i.flags.push(`binary`)}else i.responseBody=r.body;i.responseBody&&i.responseBody.length>e.MAX_INLINE_BODY_SIZE&&(i.responseBody=i.responseBody.slice(0,e.MAX_INLINE_BODY_SIZE),i.flags.push(`truncated`))}catch{}}extractOrigin(e){try{return new URL(e).origin}catch{return``}}isStaticAsset(t){return t?e.STATIC_ASSET_TYPES.has(t):!1}isBinaryType(t){return t?e.BINARY_TYPES.has(t):!1}async enableConsoleTracking(e){await this.ensureAttached(e);try{await this.send(e,`Runtime.enable`)}catch{}}async enableNetworkTracking(e){await this.ensureAttached(e);try{await this.send(e,`Network.enable`,{maxPostDataSize:65536})}catch{}}async handleDialog(e,t,n){try{return await this.send(e,`Page.handleJavaScriptDialog`,{accept:t,promptText:n}),this.pendingDialogs.delete(e),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}getDialogInfo(e){return this.pendingDialogs.get(e)||null}async emulateNetwork(e,t){await this.ensureAttached(e);let n={offline:{offline:!0,latency:0,downloadThroughput:0,uploadThroughput:0},"slow-3g":{offline:!1,latency:2e3,downloadThroughput:5e4,uploadThroughput:5e4},"fast-3g":{offline:!1,latency:562.5,downloadThroughput:18e4,uploadThroughput:84375},"4g":{offline:!1,latency:100,downloadThroughput:4e6,uploadThroughput:3e6},reset:{offline:!1,latency:0,downloadThroughput:-1,uploadThroughput:-1}},r=n[t.toLowerCase().replace(/\s+/g,`-`)];if(!r)return{success:!1,error:`Unknown preset: ${t}. Available: ${Object.keys(n).join(`, `)}`};try{return await this.send(e,`Network.enable`),await this.send(e,`Network.emulateNetworkConditions`,r),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateCPU(e,t){if(await this.ensureAttached(e),t<1)return{success:!1,error:`CPU throttling rate must be >= 1 (1 = no throttle, 4 = 4x slower)`};try{return await this.send(e,`Emulation.setCPUThrottlingRate`,{rate:t}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateGeolocation(e,t,n,r){await this.ensureAttached(e);try{return await this.send(e,`Emulation.setGeolocationOverride`,{latitude:t,longitude:n,accuracy:r||100}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async clearGeolocation(e){await this.ensureAttached(e);try{return await this.send(e,`Emulation.clearGeolocationOverride`),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateDevice(e,t){await this.ensureAttached(e);try{return await this.send(e,`Emulation.setDeviceMetricsOverride`,{width:t.width,height:t.height,deviceScaleFactor:t.deviceScaleFactor,mobile:t.mobile}),t.userAgent&&await this.send(e,`Emulation.setUserAgentOverride`,{userAgent:t.userAgent}),t.touch&&await this.send(e,`Emulation.setTouchEmulationEnabled`,{enabled:!0,maxTouchPoints:5}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async clearDeviceEmulation(e){await this.ensureAttached(e);try{return await this.send(e,`Emulation.clearDeviceMetricsOverride`),await this.send(e,`Emulation.setUserAgentOverride`,{userAgent:``}),await this.send(e,`Emulation.setTouchEmulationEnabled`,{enabled:!1}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateViewport(e,t){await this.ensureAttached(e);try{let n=await this.getViewportSize(e);return await this.send(e,`Emulation.setDeviceMetricsOverride`,{width:t.width||n.width,height:t.height||n.height,deviceScaleFactor:t.deviceScaleFactor||1,mobile:t.mobile||!1}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateTouch(e,t){await this.ensureAttached(e);try{return await this.send(e,`Emulation.setTouchEmulationEnabled`,{enabled:t,maxTouchPoints:t?5:0}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async startPerformanceTrace(e,t){await this.ensureAttached(e);try{return await this.send(e,`Performance.enable`),await this.send(e,`Tracing.start`,{categories:t?.join(`,`)||`devtools.timeline,v8.execute,disabled-by-default-devtools.timeline`,transferMode:`ReturnAsStream`}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async stopPerformanceTrace(e){await this.ensureAttached(e);try{await this.send(e,`Performance.enable`);let t=await this.send(e,`Performance.getMetrics`);await this.send(e,`Tracing.end`),await this.send(e,`Performance.disable`);let n={};for(let e of t.metrics||[])n[e.name]=e.value;return{success:!0,metrics:n}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async getPerformanceMetrics(e){await this.ensureAttached(e);try{await this.send(e,`Performance.enable`);let t=await this.send(e,`Performance.getMetrics`);await this.send(e,`Performance.disable`);let n={};for(let e of t.metrics||[])n[e.name]=e.value;return{success:!0,metrics:n}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async setFileInputBySelector(e,t,n){await this.ensureAttached(e);try{await this.send(e,`DOM.enable`);let r=await this.send(e,`DOM.getDocument`),i=await this.send(e,`DOM.querySelector`,{nodeId:r.root.nodeId,selector:t});return i.nodeId?(await this.send(e,`DOM.setFileInputFiles`,{nodeId:i.nodeId,files:n}),{success:!0}):{success:!1,error:`Could not find element by selector`}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async waitForLoad(e,t=3e4){await this.ensureAttached(e);let n=Date.now();try{for(;Date.now()-n<t;){let t=(await this.send(e,`Runtime.evaluate`,{expression:`document.readyState`,returnByValue:!0})).result?.value;if(t===`complete`)return{success:!0,readyState:t};await new Promise(e=>setTimeout(e,100))}return{success:!1,error:`Timeout waiting for page load (${t}ms)`}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async getFrames(e){await this.ensureAttached(e);try{await this.send(e,`Page.enable`);let t=await this.send(e,`Page.getFrameTree`),n=[],r=(e,t)=>{if(n.push({frameId:e.frame.id,url:e.frame.url,name:e.frame.name||``,parentId:t}),e.childFrames)for(let t of e.childFrames)r(t,e.frame.id)};return r(t.frameTree),{success:!0,frames:n}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async evaluateInFrame(e,t,n){await this.ensureAttached(e);try{let r=await this.send(e,`Page.createIsolatedWorld`,{frameId:t,worldName:`surf-isolated`}),i=`JSON.stringify((function() { ${n} })())`,a=await this.send(e,`Runtime.evaluate`,{expression:i,contextId:r.executionContextId,returnByValue:!0,awaitPromise:!0});if(a.exceptionDetails)return{success:!1,error:a.exceptionDetails.text||a.exceptionDetails.exception?.description||`Evaluation failed`};try{return{success:!0,result:JSON.parse(a.result?.value)}}catch{return{success:!0,result:a.result?.value}}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}getConsoleMessages(e,t){let n=this.consoleMessages.get(e)||[];if(t?.onlyErrors&&(n=n.filter(e=>e.type===`error`||e.type===`exception`)),t?.pattern)try{let e=new RegExp(t.pattern,`i`);n=n.filter(t=>e.test(t.text))}catch{n=n.filter(e=>e.text.includes(t.pattern))}return t?.limit&&(n=n.slice(-t.limit)),[...n]}clearConsoleMessages(e){this.consoleMessages.set(e,[])}getNetworkRequests(e,t){let n=this.networkRequests.get(e)||[];return t?.urlPattern&&(n=n.filter(e=>e.url.includes(t.urlPattern))),t?.limit&&(n=n.slice(-t.limit)),[...n]}clearNetworkRequests(e){this.networkRequests.set(e,[]),this.networkEntries.set(e,new Map)}getNetworkEntries(e,t){let n=this.networkEntries.get(e),r=[];return r=n&&n.size>0?Array.from(n.values()):(this.networkRequests.get(e)||[]).map((t,n)=>({id:`r_${t.timestamp}_${n}`,ts:t.timestamp,method:t.method,url:t.url,origin:this.extractOrigin(t.url),requestHeaders:{},tabId:e,type:t.type,status:t.status,flags:[],_requestId:t.requestId,_responseReceived:!0,_loadingFinished:!0})),t?.includeStatic||(r=r.filter(e=>!this.isStaticAsset(e.mimeType))),t?.urlPattern&&(r=r.filter(e=>e.url.includes(t.urlPattern))),t?.limit&&(r=r.slice(-t.limit)),r}getNetworkEntry(e,t){return this.networkEntries.get(e)?.get(t)||null}async getResponseBody(e,t){await this.ensureAttached(e);try{let n=await this.send(e,`Network.getResponseBody`,{requestId:t});return{success:!0,body:n.body,base64Encoded:n.base64Encoded}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}subscribeToConsole(e,t,n){this.consoleCallbacks.has(e)||this.consoleCallbacks.set(e,new Map),this.consoleCallbacks.get(e).set(t,n)}unsubscribeFromConsole(e,t){let n=this.consoleCallbacks.get(e);n&&(n.delete(t),n.size===0&&this.consoleCallbacks.delete(e))}subscribeToNetwork(e,t,n){this.networkCallbacks.has(e)||this.networkCallbacks.set(e,new Map),this.networkCallbacks.get(e).set(t,n)}unsubscribeFromNetwork(e,t){let n=this.networkCallbacks.get(e);n&&(n.delete(t),n.size===0&&this.networkCallbacks.delete(e))}async evaluateScript(e,t){await this.ensureAttached(e);try{await this.send(e,`Runtime.enable`)}catch{}return this.send(e,`Runtime.evaluate`,{expression:t,returnByValue:!0,awaitPromise:!0,timeout:3e4})}async send(e,t,n){await this.ensureAttached(e);let r=this.targets.get(e);return chrome.debugger.sendCommand(r,t,n)}async sendCommand(e,t,n){return this.send(e,t,n)}async ensureAttached(e){this.targets.has(e)||await this.attach(e)}async getViewportSize(e){let t=await this.send(e,`Page.getLayoutMetrics`),n=t.visualViewport||t.layoutViewport;return{width:Math.round(n.clientWidth),height:Math.round(n.clientHeight)}}async captureScreenshot(e){let t=await this.send(e,`Page.captureScreenshot`,{format:`png`,captureBeyondViewport:!1}),{width:n,height:r}=await this.getViewportSize(e);return{base64:t.data,width:n,height:r}}async captureRegion(e,t,n,r,i){return{base64:(await this.send(e,`Page.captureScreenshot`,{format:`png`,clip:{x:t,y:n,width:r,height:i,scale:1}})).data,width:r,height:i}}async dispatchMouseEvent(e,t,n,r,i={}){let a={type:t,x:Math.round(n),y:Math.round(r),modifiers:i.modifiers||0};(t===`mousePressed`||t===`mouseReleased`||t===`mouseMoved`)&&(a.button=i.button||`none`,(t===`mousePressed`||t===`mouseReleased`)&&(a.clickCount=i.clickCount||1)),t!==`mouseWheel`&&(a.buttons=i.buttons??0),t===`mouseWheel`&&(a.deltaX=i.deltaX||0,a.deltaY=i.deltaY||0),await this.send(e,`Input.dispatchMouseEvent`,a)}async click(e,t,n,r=`left`,i=1,a=0){let o=r===`left`?1:r===`right`?2:r===`middle`?4:0;await this.dispatchMouseEvent(e,`mouseMoved`,t,n,{button:`none`,buttons:0,modifiers:a}),await new Promise(e=>setTimeout(e,100));for(let s=1;s<=i;s++)await this.dispatchMouseEvent(e,`mousePressed`,t,n,{button:r,buttons:o,clickCount:s,modifiers:a}),await new Promise(e=>setTimeout(e,12)),await this.dispatchMouseEvent(e,`mouseReleased`,t,n,{button:r,buttons:0,clickCount:s,modifiers:a}),s<i&&await new Promise(e=>setTimeout(e,100))}async rightClick(e,t,n,r=0){await this.click(e,t,n,`right`,1,r)}async doubleClick(e,t,n,r=0){await this.click(e,t,n,`left`,2,r)}async tripleClick(e,t,n,r=0){await this.click(e,t,n,`left`,3,r)}async hover(e,t,n){await this.dispatchMouseEvent(e,`mouseMoved`,t,n,{button:`none`,buttons:0})}async drag(e,t,n,r,i,a=0){await this.dispatchMouseEvent(e,`mouseMoved`,t,n,{button:`none`,buttons:0}),await new Promise(e=>setTimeout(e,50)),await this.dispatchMouseEvent(e,`mousePressed`,t,n,{button:`left`,buttons:1,clickCount:1,modifiers:a}),await new Promise(e=>setTimeout(e,50)),await this.dispatchMouseEvent(e,`mouseMoved`,r,i,{button:`left`,buttons:1,modifiers:a}),await new Promise(e=>setTimeout(e,50)),await this.dispatchMouseEvent(e,`mouseReleased`,r,i,{button:`left`,buttons:0,clickCount:1,modifiers:a})}async scroll(e,t,n,r,i){await this.dispatchMouseEvent(e,`mouseWheel`,t,n,{deltaX:r,deltaY:i})}async type(e,t){for(let r of t)if(r===`
2
- `||r===`\r`)await this.pressKey(e,`Enter`);else if(this.getKeyDefinition(r)){let t=this.requiresShift(r);await this.pressKey(e,r,t?n.shift:0)}else await this.send(e,`Input.insertText`,{text:r})}requiresShift(e){return/[A-Z!@#$%^&*()_+{}|:"<>?~]/.test(e)}async dispatchKeyEvent(e,t,n,r=0){await this.send(e,`Input.dispatchKeyEvent`,{type:n.text?t:t===`keyDown`?`rawKeyDown`:t,key:n.key,code:n.code,windowsVirtualKeyCode:n.keyCode,modifiers:r,text:n.text??``,unmodifiedText:n.text??``,location:n.location??0})}async pressKey(e,t,n=0){let r=this.getKeyDefinition(t);if(!r)throw Error(`Unknown key: ${t}`);await this.dispatchKeyEvent(e,`keyDown`,r,n),await this.dispatchKeyEvent(e,`keyUp`,r,n)}async pressKeyChord(e,t){let r=t.toLowerCase().split(`+`),i=[],a=``;for(let e of r)e in n?i.push(e):a=e;let o=0;for(let e of i)o|=n[e]||0;a&&await this.pressKey(e,a,o)}getKeyDefinition(e){let t=e.toLowerCase();if(r[t])return r[t];if(e.length===1){let t=e.toUpperCase().charCodeAt(0);return{key:e,code:`Key${e.toUpperCase()}`,keyCode:t,text:e}}return null}parseModifiers(e){if(!e)return 0;let t=0,r=e.toLowerCase().split(`+`);for(let e of r){let r=e.trim();r in n&&(t|=n[r])}return t}},a=!1,o=!1,s=[];chrome.storage.local.get(`debugMode`).then(({debugMode:e})=>{if(a=!!e,o=!0,a)for(let e of s)console.log(`[Surf]`,...e);s.length=0}),chrome.storage.onChanged.addListener((e,t)=>{t===`local`&&e.debugMode&&(a=!!e.debugMode.newValue)});function c(...e){if(!o){s.push(e);return}a&&console.log(`[Surf]`,...e)}var l=new Map;function u(e){let{type:t,streamId:n}=e;if(!n||!l.has(n))return!1;let r=l.get(n);switch(t){case`API_RESPONSE_START`:return r.onStart(e.status,e.headers),!0;case`API_RESPONSE_CHUNK`:return r.onChunk(e.chunk),!0;case`API_RESPONSE_END`:return r.onEnd(),l.delete(n),!0;case`API_RESPONSE_ERROR`:return r.onError(e.error),l.delete(n),!0;default:return!1}}var d=t({initNativeMessaging:()=>_,postToNativeHost:()=>y,sendToNativeHost:()=>v}),f=null,p=null,m=null,h=new Map,g=0;function _(e){p=e,b()}function v(e){return new Promise((t,n)=>{if(!f){n(Error(`Native host not connected`));return}if(e.type===`API_REQUEST`){f.postMessage(e),t({sent:!0});return}let r=++g;h.set(r,{resolve:t,reject:n}),f.postMessage({...e,id:r}),setTimeout(()=>{h.has(r)&&(h.delete(r),n(Error(`Native host request timeout`)))},1e4)})}function y(e){f&&f.postMessage(e)}function b(){m&&=(clearTimeout(m),null);try{f=chrome.runtime.connectNative(`surf.browser.host`),c(`Connecting to native host...`),f.onMessage.addListener(async e=>{if(c(`Received from native host:`,e.type||e.id),e.type===`HOST_READY`){c(`Native host ready`);return}if(e.type?.startsWith(`API_RESPONSE_`)){u(e),chrome.runtime.sendMessage(e).catch(()=>{});return}if(e.id&&h.has(e.id)){let{resolve:t}=h.get(e.id);h.delete(e.id),t(e);return}if(p)try{let t=await p(e);if(!f){c(`Cannot send response - native host disconnected:`,e.id);return}f.postMessage({id:e.id,...t})}catch(t){if(!f){c(`Cannot send error - native host disconnected:`,e.id);return}f.postMessage({id:e.id,error:t instanceof Error?t.message:`Unknown error`})}}),f.onDisconnect.addListener(()=>{let e=chrome.runtime.lastError;c(`Native host disconnected:`,e?.message||`unknown reason`),f=null,e?.message?.includes(`not found`)||(m=setTimeout(b,5e3))})}catch(e){c(`Failed to connect to native host:`,e),m=setTimeout(b,1e4)}}var x=`modulepreload`,S=function(e){return`/`+e},C={},w=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=S(t,n),t=s(t),t in C)return;C[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:x,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};c(`Service worker loaded`);var T=new i,E=new Map,D=new Map;function O(e){return D.get(e)??0}function k(e){return!e||/^(?:about|arc|brave|chrome|chrome-extension|devtools|edge|extension|helium|moz-extension):/i.test(e)}var A=new Map,j=0;function M(){return`screenshot_${++j}_${Date.now()}`}function N(e,t){if(A.set(e,t),A.size>10){let e=A.keys().next().value;e&&A.delete(e)}}function P(e){return A.get(e)||null}function F(e){return new Promise(t=>setTimeout(t,e))}var I={gemini:{openerSelector:`button[aria-label="Upload & tools"], button[aria-label="Open upload file menu"]`,closeSelector:`button[aria-label="Close upload file menu"]`,uploadItemSelector:`[data-test-id="local-images-files-uploader-button"], [data-testid="local-images-files-uploader-button"], button[aria-label^="Upload files"]`},chatgpt:{directInputSelector:`form input[type="file"]:not([accept*="image"]), input[type="file"]:not([accept*="image"]), input[type="file"]`,openerSelector:`button[data-testid="composer-plus-btn"], button[aria-label="Add files and more"]`}};async function L(e,t,n){let r=(await T.sendCommand(e,`Runtime.evaluate`,{expression:`(() => {
3
- const input = document.querySelector(${JSON.stringify(n)});
4
- if (!input || input.tagName !== 'INPUT' || input.type !== 'file') return null;
5
- return input;
6
- })()`,userGesture:!0}))?.result?.objectId;return r?(await T.sendCommand(e,`DOM.setFileInputFiles`,{files:t,objectId:r}),!0):!1}async function R(e,t,n){await T.sendCommand(e,`Page.setInterceptFileChooserDialog`,{enabled:!0});let r=null,i=null,a=()=>{r&&=(clearTimeout(r),null),i&&=(chrome.debugger.onEvent.removeListener(i),null)},o=(o,s)=>new Promise((c,l)=>{r=setTimeout(()=>{a(),l(Error(`${n} file chooser did not open within ${s/1e3}s (attempt ${o})`))},s),i=(n,r,i)=>{n.tabId===e&&r===`Page.fileChooserOpened`&&(a(),T.sendCommand(e,`DOM.setFileInputFiles`,{files:t,backendNodeId:i.backendNodeId}).then(()=>c()).catch(l))},chrome.debugger.onEvent.addListener(i)}),s=async()=>{if(n===`gemini`){await T.sendCommand(e,`Runtime.evaluate`,{expression:`document.querySelector(${JSON.stringify(I.gemini.closeSelector)})?.click()`,userGesture:!0}),await F(300),await T.sendCommand(e,`Runtime.evaluate`,{expression:`document.querySelector(${JSON.stringify(I.gemini.openerSelector)})?.click()`,userGesture:!0}),await F(500),await T.sendCommand(e,`Runtime.evaluate`,{expression:`document.querySelector(${JSON.stringify(I.gemini.uploadItemSelector)})?.click()`,userGesture:!0});return}await T.sendCommand(e,`Runtime.evaluate`,{expression:`document.querySelector(${JSON.stringify(I.chatgpt.openerSelector)})?.click()`,userGesture:!0})},c=[1e4,15e3,2e4],l=null;try{for(let e=1;e<=3;e++)try{let t=o(e,c[e-1]);await s(),await t;return}catch(t){l=t,a(),e<3&&await F(1e3)}throw Error(`${n} file upload failed after 3 attempts: ${l?.message}`)}finally{a();try{await T.sendCommand(e,`Page.setInterceptFileChooserDialog`,{enabled:!1})}catch{}}}async function z(e,t,n){return await T.attach(t),await T.sendCommand(t,`DOM.enable`,{}),e===`chatgpt`&&await L(t,n,I.chatgpt.directInputSelector)||await R(t,n,e),{success:!0}}var B={button:`#FF6B6B`,input:`#4ECDC4`,select:`#45B7D1`,a:`#96CEB4`,textarea:`#FF8C42`,default:`#DDA0DD`};async function V(e,t,n){let r=U(e.base64),i=await createImageBitmap(r),a=new OffscreenCanvas(i.width,i.height),o=a.getContext(`2d`);if(!o)throw Error(`Failed to get canvas context`);o.drawImage(i,0,0),i.close();let s=Math.min(n.scaleX,n.scaleY);for(let e of t){let t=B[e.tag]||B.default,n=Math.round(e.bounds.x*s),r=Math.round(e.bounds.y*s),i=Math.round(e.bounds.width*s),c=Math.round(e.bounds.height*s);if(i<1||c<1)continue;o.strokeStyle=t,o.lineWidth=2,o.setLineDash([4,4]),o.strokeRect(n,r,i,c),o.setLineDash([]);let l=e.ref,u=Math.max(10,Math.min(16,Math.round(a.width*.01)));o.font=`bold ${u}px sans-serif`;let d=o.measureText(l).width+8,f=u+8,p=n+Math.floor((i-d)/2),m=r+2;(i<60||c<30)&&(m=r-f-2<0?r+c+2:r-f-2),p=Math.max(0,Math.min(a.width-d,p)),m=Math.max(0,Math.min(a.height-f,m)),o.fillStyle=t,o.fillRect(p,m,d,f),o.strokeStyle=`white`,o.lineWidth=1,o.strokeRect(p,m,d,f),o.fillStyle=`white`,o.textBaseline=`top`,o.fillText(l,p+4,m+4)}return{base64:await H(await a.convertToBlob({type:`image/png`})),width:a.width,height:a.height}}function H(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{let e=r.result.split(`,`)[1];t(e)},r.onerror=()=>n(Error(`Failed to convert blob to base64`)),r.readAsDataURL(e)})}function U(e,t=`image/png`){let n=atob(e),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return new Blob([r],{type:t})}function W(e){return`return (\n${e}\n);`}function G(e){try{return Function(e),!0}catch(e){return!(e instanceof SyntaxError)}}async function K(e,t){let n=(await T.evaluateScript(e,`(() => ({
1
+ const te="modulepreload",re=function(o){return"/"+o},$={},V=function(i,t,e){let r=Promise.resolve();if(t&&t.length>0){let u=function(d){return Promise.all(d.map(h=>Promise.resolve(h).then(f=>({status:"fulfilled",value:f}),f=>({status:"rejected",reason:f}))))};var s=u;document.getElementsByTagName("link");const a=document.querySelector("meta[property=csp-nonce]"),c=a?.nonce||a?.getAttribute("nonce");r=u(t.map(d=>{if(d=re(d),d in $)return;$[d]=!0;const h=d.endsWith(".css"),f=h?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${d}"]${f}`))return;const w=document.createElement("link");if(w.rel=h?"stylesheet":te,h||(w.as="script"),w.crossOrigin="",w.href=d,c&&w.setAttribute("nonce",c),document.head.appendChild(w),h)return new Promise((p,E)=>{w.addEventListener("load",p),w.addEventListener("error",()=>E(new Error(`Unable to preload CSS for ${d}`)))})}))}function n(a){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=a,window.dispatchEvent(c),!c.defaultPrevented)throw a}return r.then(a=>{for(const c of a||[])c.status==="rejected"&&n(c.reason);return i().catch(n)})},L={alt:1,ctrl:2,control:2,meta:4,cmd:4,command:4,win:4,windows:4,shift:8},Y={enter:{key:"Enter",code:"Enter",keyCode:13,text:"\r"},tab:{key:"Tab",code:"Tab",keyCode:9},escape:{key:"Escape",code:"Escape",keyCode:27},backspace:{key:"Backspace",code:"Backspace",keyCode:8},delete:{key:"Delete",code:"Delete",keyCode:46},arrowup:{key:"ArrowUp",code:"ArrowUp",keyCode:38},arrowdown:{key:"ArrowDown",code:"ArrowDown",keyCode:40},arrowleft:{key:"ArrowLeft",code:"ArrowLeft",keyCode:37},arrowright:{key:"ArrowRight",code:"ArrowRight",keyCode:39},home:{key:"Home",code:"Home",keyCode:36},end:{key:"End",code:"End",keyCode:35},pageup:{key:"PageUp",code:"PageUp",keyCode:33},pagedown:{key:"PageDown",code:"PageDown",keyCode:34},space:{key:" ",code:"Space",keyCode:32,text:" "},f1:{key:"F1",code:"F1",keyCode:112},f2:{key:"F2",code:"F2",keyCode:113},f3:{key:"F3",code:"F3",keyCode:114},f4:{key:"F4",code:"F4",keyCode:115},f5:{key:"F5",code:"F5",keyCode:116},f6:{key:"F6",code:"F6",keyCode:117},f7:{key:"F7",code:"F7",keyCode:118},f8:{key:"F8",code:"F8",keyCode:119},f9:{key:"F9",code:"F9",keyCode:120},f10:{key:"F10",code:"F10",keyCode:121},f11:{key:"F11",code:"F11",keyCode:122},f12:{key:"F12",code:"F12",keyCode:123}};class I{targets=new Map;consoleMessages=new Map;networkRequests=new Map;networkEntries=new Map;consoleCallbacks=new Map;networkCallbacks=new Map;networkRequestStartTimes=new Map;pendingDialogs=new Map;networkEntrySeq=0;static debuggerListenerRegistered=!1;static MAX_INLINE_BODY_SIZE=16*1024;static STATIC_ASSET_TYPES=new Set(["image/png","image/jpeg","image/gif","image/webp","image/svg+xml","image/x-icon","font/woff","font/woff2","font/ttf","font/otf","application/font-woff","application/font-woff2","text/css","application/javascript","text/javascript","application/x-javascript"]);static BINARY_TYPES=new Set(["image/png","image/jpeg","image/gif","image/webp","image/x-icon","font/woff","font/woff2","font/ttf","font/otf","application/font-woff","application/font-woff2","application/octet-stream","application/pdf","application/zip","audio/mpeg","audio/wav","audio/ogg","video/mp4","video/webm","video/ogg"]);async attach(i){if(this.targets.has(i))return;const t={tabId:i};try{await chrome.debugger.attach(t,"1.3")}catch(e){const r=e instanceof Error?e.message:String(e);if(r.includes("Already attached")){this.targets.set(i,t);return}throw r.includes("Cannot access")||r.includes("Cannot attach")?new Error("Cannot control this page. Chrome restricts automation on chrome://, extensions, and web store pages."):new Error(`Failed to attach debugger: ${r}`)}this.targets.set(i,t),this.setupEventListener(),this.consoleMessages.set(i,[]),this.networkRequests.set(i,[]);try{await this.send(i,"Page.enable")}catch{}}async detach(i){const t=this.targets.get(i);if(t){try{await chrome.debugger.detach(t)}catch(e){console.warn("[CDPController] Error detaching:",e)}this.targets.delete(i),this.consoleMessages.delete(i),this.networkRequests.delete(i),this.networkEntries.delete(i),this.consoleCallbacks.delete(i),this.networkCallbacks.delete(i),this.pendingDialogs.delete(i)}}async detachAll(){for(const i of this.targets.keys())await this.detach(i)}setupEventListener(){I.debuggerListenerRegistered||(I.debuggerListenerRegistered=!0,chrome.debugger.onEvent.addListener((i,t,e)=>{const r=i.tabId;!r||!this.targets.has(r)||this.handleCDPEvent(r,t,e)}),chrome.debugger.onDetach.addListener((i,t)=>{const e=i.tabId;e&&this.targets.has(e)&&(this.targets.delete(e),this.consoleMessages.delete(e),this.networkRequests.delete(e),this.networkEntries.delete(e),this.consoleCallbacks.delete(e),this.networkCallbacks.delete(e))}))}handleCDPEvent(i,t,e){switch(t){case"Runtime.consoleAPICalled":this.handleRuntimeConsole(i,e);break;case"Runtime.exceptionThrown":this.handleRuntimeException(i,e);break;case"Network.requestWillBeSent":this.handleNetworkRequest(i,e);break;case"Network.responseReceived":this.handleNetworkResponse(i,e);break;case"Network.loadingFailed":this.handleNetworkFailed(i,e);break;case"Network.loadingFinished":this.handleLoadingFinished(i,e);break;case"Page.javascriptDialogOpening":this.handleDialogOpening(i,e);break;case"Page.javascriptDialogClosed":this.pendingDialogs.delete(i);break}}handleRuntimeConsole(i,t){const e=this.consoleMessages.get(i)||[],n=(t.args||[]).map(u=>u.value!==void 0?String(u.value):u.description?u.description:"").join(" "),s=t.stackTrace?.callFrames?.[0],a={type:t.type||"log",text:n,timestamp:t.timestamp||Date.now(),url:s?.url,line:s?.lineNumber};e.push(a),e.length>1e3&&e.shift(),this.consoleMessages.set(i,e);const c=this.consoleCallbacks.get(i);if(c)for(const u of c.values())u(a)}handleRuntimeException(i,t){const e=this.consoleMessages.get(i)||[],r=t.exceptionDetails;if(!r)return;const n={type:"exception",text:r.exception?.description||r.text||"Unknown exception",timestamp:r.timestamp||Date.now(),url:r.url,line:r.lineNumber};e.push(n),e.length>1e3&&e.shift(),this.consoleMessages.set(i,e);const s=this.consoleCallbacks.get(i);if(s)for(const a of s.values())a(n)}handleNetworkRequest(i,t){const e=this.networkRequests.get(i)||[],r=t.request;if(!r)return;const n=t.timestamp?t.timestamp*1e3:Date.now();this.networkRequestStartTimes.set(t.requestId,n);const s={};if(r.headers)for(const[p,E]of Object.entries(r.headers))s[p]=String(E);e.push({requestId:t.requestId,url:r.url,method:r.method,type:t.type,timestamp:n,requestHeaders:s,requestBody:r.postData}),e.length>500&&e.shift(),this.networkRequests.set(i,e),this.networkEntries.has(i)||this.networkEntries.set(i,new Map);const a=this.networkEntries.get(i),c=++this.networkEntrySeq,u=`r_${n}_${c}`,d={};if(r.headers)for(const[p,E]of Object.entries(r.headers))d[p]=String(E);const h=r.postData,f=h?h.length:void 0,w={id:u,ts:n,method:r.method,url:r.url,origin:this.extractOrigin(r.url),requestHeaders:d,requestBody:h,requestBodySize:f,tabId:i,tabUrl:t.documentURL,type:t.type,flags:[],_requestId:t.requestId,_responseReceived:!1,_loadingFinished:!1};if(a.size>500){const p=a.keys().next().value;p&&a.delete(p)}a.set(t.requestId,w)}handleNetworkResponse(i,t){const r=(this.networkRequests.get(i)||[]).find(a=>a.requestId===t.requestId);if(r){if(r.status=t.response?.status,r.mimeType=t.response?.mimeType,t.response?.headers){const c={};for(const[u,d]of Object.entries(t.response.headers))c[u]=String(d);r.responseHeaders=c}const a=this.networkCallbacks.get(i);if(a){const c=this.networkRequestStartTimes.get(t.requestId),u=Date.now(),d=c?Math.round(u-c):void 0;for(const h of a.values())h({method:r.method,url:r.url,status:r.status,duration:d,timestamp:u})}}const s=this.networkEntries.get(i)?.get(t.requestId);if(s&&t.response){const a=t.response,c=this.networkRequestStartTimes.get(t.requestId),u=t.timestamp?t.timestamp*1e3:Date.now();c&&(s.ttfb=Math.round(u-c)),s.status=a.status,s.statusText=a.statusText,s.mimeType=a.mimeType;const d={};if(a.headers)for(const[h,f]of Object.entries(a.headers))d[h]=String(f);s.responseHeaders=d,this.isBinaryType(a.mimeType)&&s.flags.push("binary"),(a.mimeType?.includes("protobuf")||a.mimeType?.includes("x-protobuf")||a.mimeType?.includes("application/grpc"))&&s.flags.push("protobuf"),s._responseReceived=!0}}handleNetworkFailed(i,t){const r=(this.networkRequests.get(i)||[]).find(a=>a.requestId===t.requestId);if(r&&!r.status){r.status=0;const a=this.networkCallbacks.get(i);if(a){const c=this.networkRequestStartTimes.get(t.requestId),u=Date.now(),d=c?Math.round(u-c):void 0;this.networkRequestStartTimes.delete(t.requestId);for(const h of a.values())h({method:r.method,url:r.url,status:0,duration:d,timestamp:u})}}const s=this.networkEntries.get(i)?.get(t.requestId);if(s){const a=this.networkRequestStartTimes.get(t.requestId),c=t.timestamp?t.timestamp*1e3:Date.now();a&&(s.duration=Math.round(c-a)),this.networkRequestStartTimes.delete(t.requestId),s.status=0,s.flags.push("failed"),s._loadingFinished=!0}}handleDialogOpening(i,t){this.pendingDialogs.set(i,{type:t.type,message:t.message,defaultPrompt:t.defaultPrompt,timestamp:Date.now()})}async handleLoadingFinished(i,t){const r=(this.networkRequests.get(i)||[]).find(d=>d.requestId===t.requestId);if(r){const d=this.networkRequestStartTimes.get(t.requestId),h=t.timestamp?t.timestamp*1e3:Date.now();if(d&&(r.duration=Math.round(h-d)),!this.isStaticAsset(r.mimeType)&&!this.isBinaryType(r.mimeType)&&(t.encodedDataLength||0)<=I.MAX_INLINE_BODY_SIZE)try{const w=await this.send(i,"Network.getResponseBody",{requestId:t.requestId});if(w.base64Encoded)try{r.responseBody=atob(w.body)}catch{r.responseBody=w.body}else r.responseBody=w.body;r.responseBody&&r.responseBody.length>I.MAX_INLINE_BODY_SIZE&&(r.responseBody=r.responseBody.slice(0,I.MAX_INLINE_BODY_SIZE))}catch{}}const s=this.networkEntries.get(i)?.get(t.requestId);if(!s)return;const a=this.networkRequestStartTimes.get(t.requestId),c=t.timestamp?t.timestamp*1e3:Date.now();if(a&&(s.duration=Math.round(c-a)),this.networkRequestStartTimes.delete(t.requestId),s.responseBodySize=t.encodedDataLength,s._loadingFinished=!0,!this.isStaticAsset(s.mimeType)&&!this.isBinaryType(s.mimeType)&&(t.encodedDataLength||0)<=I.MAX_INLINE_BODY_SIZE)try{const d=await this.send(i,"Network.getResponseBody",{requestId:t.requestId});if(d.base64Encoded)try{s.responseBody=atob(d.body)}catch{s.responseBody=d.body,s.flags.push("binary")}else s.responseBody=d.body;s.responseBody&&s.responseBody.length>I.MAX_INLINE_BODY_SIZE&&(s.responseBody=s.responseBody.slice(0,I.MAX_INLINE_BODY_SIZE),s.flags.push("truncated"))}catch{}}extractOrigin(i){try{return new URL(i).origin}catch{return""}}isStaticAsset(i){return i?I.STATIC_ASSET_TYPES.has(i):!1}isBinaryType(i){return i?I.BINARY_TYPES.has(i):!1}async enableConsoleTracking(i){await this.ensureAttached(i);try{await this.send(i,"Runtime.enable")}catch{}}async enableNetworkTracking(i){await this.ensureAttached(i);try{await this.send(i,"Network.enable",{maxPostDataSize:65536})}catch{}}async handleDialog(i,t,e){try{return await this.send(i,"Page.handleJavaScriptDialog",{accept:t,promptText:e}),this.pendingDialogs.delete(i),{success:!0}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}getDialogInfo(i){return this.pendingDialogs.get(i)||null}async emulateNetwork(i,t){await this.ensureAttached(i);const e={offline:{offline:!0,latency:0,downloadThroughput:0,uploadThroughput:0},"slow-3g":{offline:!1,latency:2e3,downloadThroughput:5e4,uploadThroughput:5e4},"fast-3g":{offline:!1,latency:562.5,downloadThroughput:18e4,uploadThroughput:84375},"4g":{offline:!1,latency:100,downloadThroughput:4e6,uploadThroughput:3e6},reset:{offline:!1,latency:0,downloadThroughput:-1,uploadThroughput:-1}},r=e[t.toLowerCase().replace(/\s+/g,"-")];if(!r)return{success:!1,error:`Unknown preset: ${t}. Available: ${Object.keys(e).join(", ")}`};try{return await this.send(i,"Network.enable"),await this.send(i,"Network.emulateNetworkConditions",r),{success:!0}}catch(n){return{success:!1,error:n instanceof Error?n.message:String(n)}}}async emulateCPU(i,t){if(await this.ensureAttached(i),t<1)return{success:!1,error:"CPU throttling rate must be >= 1 (1 = no throttle, 4 = 4x slower)"};try{return await this.send(i,"Emulation.setCPUThrottlingRate",{rate:t}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateGeolocation(i,t,e,r){await this.ensureAttached(i);try{return await this.send(i,"Emulation.setGeolocationOverride",{latitude:t,longitude:e,accuracy:r||100}),{success:!0}}catch(n){return{success:!1,error:n instanceof Error?n.message:String(n)}}}async clearGeolocation(i){await this.ensureAttached(i);try{return await this.send(i,"Emulation.clearGeolocationOverride"),{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async emulateDevice(i,t){await this.ensureAttached(i);try{return await this.send(i,"Emulation.setDeviceMetricsOverride",{width:t.width,height:t.height,deviceScaleFactor:t.deviceScaleFactor,mobile:t.mobile}),t.userAgent&&await this.send(i,"Emulation.setUserAgentOverride",{userAgent:t.userAgent}),t.touch&&await this.send(i,"Emulation.setTouchEmulationEnabled",{enabled:!0,maxTouchPoints:5}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async clearDeviceEmulation(i){await this.ensureAttached(i);try{return await this.send(i,"Emulation.clearDeviceMetricsOverride"),await this.send(i,"Emulation.setUserAgentOverride",{userAgent:""}),await this.send(i,"Emulation.setTouchEmulationEnabled",{enabled:!1}),{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async emulateViewport(i,t){await this.ensureAttached(i);try{const e=await this.getViewportSize(i);return await this.send(i,"Emulation.setDeviceMetricsOverride",{width:t.width||e.width,height:t.height||e.height,deviceScaleFactor:t.deviceScaleFactor||1,mobile:t.mobile||!1}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async emulateTouch(i,t){await this.ensureAttached(i);try{return await this.send(i,"Emulation.setTouchEmulationEnabled",{enabled:t,maxTouchPoints:t?5:0}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async startPerformanceTrace(i,t){await this.ensureAttached(i);try{return await this.send(i,"Performance.enable"),await this.send(i,"Tracing.start",{categories:t?.join(",")||"devtools.timeline,v8.execute,disabled-by-default-devtools.timeline",transferMode:"ReturnAsStream"}),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async stopPerformanceTrace(i){await this.ensureAttached(i);try{await this.send(i,"Performance.enable");const t=await this.send(i,"Performance.getMetrics");await this.send(i,"Tracing.end"),await this.send(i,"Performance.disable");const e={};for(const r of t.metrics||[])e[r.name]=r.value;return{success:!0,metrics:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async getPerformanceMetrics(i){await this.ensureAttached(i);try{await this.send(i,"Performance.enable");const t=await this.send(i,"Performance.getMetrics");await this.send(i,"Performance.disable");const e={};for(const r of t.metrics||[])e[r.name]=r.value;return{success:!0,metrics:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async setFileInputBySelector(i,t,e){await this.ensureAttached(i);try{await this.send(i,"DOM.enable");const r=await this.send(i,"DOM.getDocument"),n=await this.send(i,"DOM.querySelector",{nodeId:r.root.nodeId,selector:t});return n.nodeId?(await this.send(i,"DOM.setFileInputFiles",{nodeId:n.nodeId,files:e}),{success:!0}):{success:!1,error:"Could not find element by selector"}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async waitForLoad(i,t=3e4){await this.ensureAttached(i);const e=Date.now();try{for(;Date.now()-e<t;){const n=(await this.send(i,"Runtime.evaluate",{expression:"document.readyState",returnByValue:!0})).result?.value;if(n==="complete")return{success:!0,readyState:n};await new Promise(s=>setTimeout(s,100))}return{success:!1,error:`Timeout waiting for page load (${t}ms)`}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async getFrames(i){await this.ensureAttached(i);try{await this.send(i,"Page.enable");const t=await this.send(i,"Page.getFrameTree"),e=[],r=(n,s)=>{if(e.push({frameId:n.frame.id,url:n.frame.url,name:n.frame.name||"",parentId:s}),n.childFrames)for(const a of n.childFrames)r(a,n.frame.id)};return r(t.frameTree),{success:!0,frames:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async evaluateInFrame(i,t,e){await this.ensureAttached(i);try{const r=await this.send(i,"Page.createIsolatedWorld",{frameId:t,worldName:"surf-isolated"}),n=`JSON.stringify((function() { ${e} })())`,s=await this.send(i,"Runtime.evaluate",{expression:n,contextId:r.executionContextId,returnByValue:!0,awaitPromise:!0});if(s.exceptionDetails)return{success:!1,error:s.exceptionDetails.text||s.exceptionDetails.exception?.description||"Evaluation failed"};try{return{success:!0,result:JSON.parse(s.result?.value)}}catch{return{success:!0,result:s.result?.value}}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}getConsoleMessages(i,t){let e=this.consoleMessages.get(i)||[];if(t?.onlyErrors&&(e=e.filter(r=>r.type==="error"||r.type==="exception")),t?.pattern)try{const r=new RegExp(t.pattern,"i");e=e.filter(n=>r.test(n.text))}catch{e=e.filter(n=>n.text.includes(t.pattern))}return t?.limit&&(e=e.slice(-t.limit)),[...e]}clearConsoleMessages(i){this.consoleMessages.set(i,[])}getNetworkRequests(i,t){let e=this.networkRequests.get(i)||[];return t?.urlPattern&&(e=e.filter(r=>r.url.includes(t.urlPattern))),t?.limit&&(e=e.slice(-t.limit)),[...e]}clearNetworkRequests(i){this.networkRequests.set(i,[]),this.networkEntries.set(i,new Map)}getNetworkEntries(i,t){const e=this.networkEntries.get(i);let r=[];return e&&e.size>0?r=Array.from(e.values()):r=(this.networkRequests.get(i)||[]).map((s,a)=>({id:`r_${s.timestamp}_${a}`,ts:s.timestamp,method:s.method,url:s.url,origin:this.extractOrigin(s.url),requestHeaders:{},tabId:i,type:s.type,status:s.status,flags:[],_requestId:s.requestId,_responseReceived:!0,_loadingFinished:!0})),t?.includeStatic||(r=r.filter(n=>!this.isStaticAsset(n.mimeType))),t?.urlPattern&&(r=r.filter(n=>n.url.includes(t.urlPattern))),t?.limit&&(r=r.slice(-t.limit)),r}getNetworkEntry(i,t){return this.networkEntries.get(i)?.get(t)||null}async getResponseBody(i,t){await this.ensureAttached(i);try{const e=await this.send(i,"Network.getResponseBody",{requestId:t});return{success:!0,body:e.body,base64Encoded:e.base64Encoded}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}subscribeToConsole(i,t,e){this.consoleCallbacks.has(i)||this.consoleCallbacks.set(i,new Map),this.consoleCallbacks.get(i).set(t,e)}unsubscribeFromConsole(i,t){const e=this.consoleCallbacks.get(i);e&&(e.delete(t),e.size===0&&this.consoleCallbacks.delete(i))}subscribeToNetwork(i,t,e){this.networkCallbacks.has(i)||this.networkCallbacks.set(i,new Map),this.networkCallbacks.get(i).set(t,e)}unsubscribeFromNetwork(i,t){const e=this.networkCallbacks.get(i);e&&(e.delete(t),e.size===0&&this.networkCallbacks.delete(i))}async evaluateScript(i,t){await this.ensureAttached(i);try{await this.send(i,"Runtime.enable")}catch{}return this.send(i,"Runtime.evaluate",{expression:t,returnByValue:!0,awaitPromise:!0,timeout:3e4})}async send(i,t,e){await this.ensureAttached(i);const r=this.targets.get(i);return chrome.debugger.sendCommand(r,t,e)}async sendCommand(i,t,e){return this.send(i,t,e)}async ensureAttached(i){this.targets.has(i)||await this.attach(i)}async getViewportSize(i){const t=await this.send(i,"Page.getLayoutMetrics"),e=t.visualViewport||t.layoutViewport;return{width:Math.round(e.clientWidth),height:Math.round(e.clientHeight)}}async captureScreenshot(i){const t=await this.send(i,"Page.captureScreenshot",{format:"png",captureBeyondViewport:!1}),{width:e,height:r}=await this.getViewportSize(i);return{base64:t.data,width:e,height:r}}async captureRegion(i,t,e,r,n){return{base64:(await this.send(i,"Page.captureScreenshot",{format:"png",clip:{x:t,y:e,width:r,height:n,scale:1}})).data,width:r,height:n}}async dispatchMouseEvent(i,t,e,r,n={}){const s={type:t,x:Math.round(e),y:Math.round(r),modifiers:n.modifiers||0};(t==="mousePressed"||t==="mouseReleased"||t==="mouseMoved")&&(s.button=n.button||"none",(t==="mousePressed"||t==="mouseReleased")&&(s.clickCount=n.clickCount||1)),t!=="mouseWheel"&&(s.buttons=n.buttons??0),t==="mouseWheel"&&(s.deltaX=n.deltaX||0,s.deltaY=n.deltaY||0),await this.send(i,"Input.dispatchMouseEvent",s)}async click(i,t,e,r="left",n=1,s=0){const a=r==="left"?1:r==="right"?2:r==="middle"?4:0;await this.dispatchMouseEvent(i,"mouseMoved",t,e,{button:"none",buttons:0,modifiers:s}),await new Promise(c=>setTimeout(c,100));for(let c=1;c<=n;c++)await this.dispatchMouseEvent(i,"mousePressed",t,e,{button:r,buttons:a,clickCount:c,modifiers:s}),await new Promise(u=>setTimeout(u,12)),await this.dispatchMouseEvent(i,"mouseReleased",t,e,{button:r,buttons:0,clickCount:c,modifiers:s}),c<n&&await new Promise(u=>setTimeout(u,100))}async rightClick(i,t,e,r=0){await this.click(i,t,e,"right",1,r)}async doubleClick(i,t,e,r=0){await this.click(i,t,e,"left",2,r)}async tripleClick(i,t,e,r=0){await this.click(i,t,e,"left",3,r)}async hover(i,t,e){await this.dispatchMouseEvent(i,"mouseMoved",t,e,{button:"none",buttons:0})}async drag(i,t,e,r,n,s=0){await this.dispatchMouseEvent(i,"mouseMoved",t,e,{button:"none",buttons:0}),await new Promise(a=>setTimeout(a,50)),await this.dispatchMouseEvent(i,"mousePressed",t,e,{button:"left",buttons:1,clickCount:1,modifiers:s}),await new Promise(a=>setTimeout(a,50)),await this.dispatchMouseEvent(i,"mouseMoved",r,n,{button:"left",buttons:1,modifiers:s}),await new Promise(a=>setTimeout(a,50)),await this.dispatchMouseEvent(i,"mouseReleased",r,n,{button:"left",buttons:0,clickCount:1,modifiers:s})}async scroll(i,t,e,r,n){await this.dispatchMouseEvent(i,"mouseWheel",t,e,{deltaX:r,deltaY:n})}async type(i,t){for(const e of t)if(e===`
2
+ `||e==="\r")await this.pressKey(i,"Enter");else if(this.getKeyDefinition(e)){const n=this.requiresShift(e);await this.pressKey(i,e,n?L.shift:0)}else await this.send(i,"Input.insertText",{text:e})}requiresShift(i){return/[A-Z!@#$%^&*()_+{}|:"<>?~]/.test(i)}async dispatchKeyEvent(i,t,e,r=0){await this.send(i,"Input.dispatchKeyEvent",{type:e.text?t:t==="keyDown"?"rawKeyDown":t,key:e.key,code:e.code,windowsVirtualKeyCode:e.keyCode,modifiers:r,text:e.text??"",unmodifiedText:e.text??"",location:e.location??0})}async pressKey(i,t,e=0){const r=this.getKeyDefinition(t);if(!r)throw new Error(`Unknown key: ${t}`);await this.dispatchKeyEvent(i,"keyDown",r,e),await this.dispatchKeyEvent(i,"keyUp",r,e)}async pressKeyChord(i,t){const e=t.toLowerCase().split("+"),r=[];let n="";for(const a of e)a in L?r.push(a):n=a;let s=0;for(const a of r)s|=L[a]||0;n&&await this.pressKey(i,n,s)}getKeyDefinition(i){const t=i.toLowerCase();if(Y[t])return Y[t];if(i.length===1){const e=i.toUpperCase().charCodeAt(0);return{key:i,code:`Key${i.toUpperCase()}`,keyCode:e,text:i}}return null}parseModifiers(i){if(!i)return 0;let t=0;const e=i.toLowerCase().split("+");for(const r of e){const n=r.trim();n in L&&(t|=L[n])}return t}}let B=!1,j=!1;const H=[];chrome.storage.local.get("debugMode").then(({debugMode:o})=>{if(B=!!o,j=!0,B)for(const i of H)console.log("[Surf]",...i);H.length=0});chrome.storage.onChanged.addListener((o,i)=>{i==="local"&&o.debugMode&&(B=!!o.debugMode.newValue)});function C(...o){if(!j){H.push(o);return}B&&console.log("[Surf]",...o)}const q=new Map;function oe(o){const{type:i,streamId:t}=o;if(!t||!q.has(t))return!1;const e=q.get(t);switch(i){case"API_RESPONSE_START":return e.onStart(o.status,o.headers),!0;case"API_RESPONSE_CHUNK":return e.onChunk(o.chunk),!0;case"API_RESPONSE_END":return e.onEnd(),q.delete(t),!0;case"API_RESPONSE_ERROR":return e.onError(o.error),q.delete(t),!0;default:return!1}}let v=null,K=null,P=null,R=new Map,ie=0;function J(o){K=o,W()}function ne(o){return new Promise((i,t)=>{if(!v){t(new Error("Native host not connected"));return}if(o.type==="API_REQUEST"){v.postMessage(o),i({sent:!0});return}const e=++ie;R.set(e,{resolve:i,reject:t}),v.postMessage({...o,id:e}),setTimeout(()=>{R.has(e)&&(R.delete(e),t(new Error("Native host request timeout")))},1e4)})}function x(o){v&&v.postMessage(o)}function W(){P&&(clearTimeout(P),P=null);try{v=chrome.runtime.connectNative("surf.browser.host"),C("Connecting to native host..."),v.onMessage.addListener(async o=>{if(C("Received from native host:",o.type||o.id),o.type==="HOST_READY"){C("Native host ready");return}if(o.type?.startsWith("API_RESPONSE_")){oe(o),chrome.runtime.sendMessage(o).catch(()=>{});return}if(o.id&&R.has(o.id)){const{resolve:i}=R.get(o.id);R.delete(o.id),i(o);return}if(K)try{const i=await K(o);if(!v){C("Cannot send response - native host disconnected:",o.id);return}v.postMessage({id:o.id,...i})}catch(i){if(!v){C("Cannot send error - native host disconnected:",o.id);return}v.postMessage({id:o.id,error:i instanceof Error?i.message:"Unknown error"})}}),v.onDisconnect.addListener(()=>{const o=chrome.runtime.lastError;C("Native host disconnected:",o?.message||"unknown reason"),v=null,o?.message?.includes("not found")||(P=setTimeout(W,5e3))})}catch(o){C("Failed to connect to native host:",o),P=setTimeout(W,1e4)}}const X=Object.freeze(Object.defineProperty({__proto__:null,initNativeMessaging:J,postToNativeHost:x,sendToNativeHost:ne},Symbol.toStringTag,{value:"Module"}));C("Service worker loaded");const l=new I,M=new Map,F=new Map;function b(o){return F.get(o)??0}const D=new Map;let se=0;function ae(){return`screenshot_${++se}_${Date.now()}`}function ce(o,i){if(D.set(o,i),D.size>10){const t=D.keys().next().value;t&&D.delete(t)}}function le(o){return D.get(o)||null}const z={button:"#FF6B6B",input:"#4ECDC4",select:"#45B7D1",a:"#96CEB4",textarea:"#FF8C42",default:"#DDA0DD"};async function ue(o,i,t){const e=Q(o.base64),r=await createImageBitmap(e),n=new OffscreenCanvas(r.width,r.height),s=n.getContext("2d");if(!s)throw new Error("Failed to get canvas context");s.drawImage(r,0,0),r.close();const a=Math.min(t.scaleX,t.scaleY);for(const d of i){const h=z[d.tag]||z.default,f=Math.round(d.bounds.x*a),w=Math.round(d.bounds.y*a),p=Math.round(d.bounds.width*a),E=Math.round(d.bounds.height*a);if(p<1||E<1)continue;s.strokeStyle=h,s.lineWidth=2,s.setLineDash([4,4]),s.strokeRect(f,w,p,E),s.setLineDash([]);const _=d.ref,S=Math.max(10,Math.min(16,Math.round(n.width*.01)));s.font=`bold ${S}px sans-serif`;const N=s.measureText(_).width,m=4,y=N+m*2,g=S+m*2;let T=f+Math.floor((p-y)/2),O=w+2;(p<60||E<30)&&(O=w-g-2<0?w+E+2:w-g-2),T=Math.max(0,Math.min(n.width-y,T)),O=Math.max(0,Math.min(n.height-g,O)),s.fillStyle=h,s.fillRect(T,O,y,g),s.strokeStyle="white",s.lineWidth=1,s.strokeRect(T,O,y,g),s.fillStyle="white",s.textBaseline="top",s.fillText(_,T+m,O+m)}const c=await n.convertToBlob({type:"image/png"});return{base64:await Z(c),width:n.width,height:n.height}}function Z(o){return new Promise((i,t)=>{const e=new FileReader;e.onload=()=>{const n=e.result.split(",")[1];i(n)},e.onerror=()=>t(new Error("Failed to convert blob to base64")),e.readAsDataURL(o)})}function Q(o,i="image/png"){const t=atob(o),e=new Uint8Array(t.length);for(let r=0;r<t.length;r++)e[r]=t.charCodeAt(r);return new Blob([e],{type:i})}async function de(o,i){const e=(await l.evaluateScript(o,`(() => ({
7
3
  viewportHeight: window.innerHeight,
8
- totalHeight: Math.min(document.documentElement.scrollHeight, ${t}),
4
+ totalHeight: Math.min(document.documentElement.scrollHeight, ${i}),
9
5
  width: window.innerWidth,
10
6
  devicePixelRatio: window.devicePixelRatio || 1,
11
7
  originalScrollY: window.scrollY,
12
- }))()`)).result?.value;if(!n)throw Error(`Failed to get page dimensions`);let{viewportHeight:r,totalHeight:i,width:a,devicePixelRatio:o,originalScrollY:s}=n,c=[],l=0;for(;l<i;){await T.evaluateScript(e,`window.scrollTo(0, ${l})`),await new Promise(e=>setTimeout(e,300));let t=U((await T.captureScreenshot(e)).base64);c.push(await createImageBitmap(t)),l+=r}await T.evaluateScript(e,`window.scrollTo(0, ${s})`);let u=Math.round(a*o),d=Math.round(i*o),f=new OffscreenCanvas(u,d),p=f.getContext(`2d`);if(!p)throw Error(`Failed to get canvas context`);let m=0,h=Math.round(r*o);for(let e=0;e<c.length;e++){let t=c[e],n=d-m,r=Math.min(h,n);p.drawImage(t,0,0,t.width,r,0,m,t.width,r),m+=r,t.close()}return{base64:await H(await f.convertToBlob({type:`image/png`})),width:u,height:d}}var q=new Map,J=new Map;chrome.webNavigation.onCompleted.addListener(e=>{if(e.frameId===0){D.delete(e.tabId);let t=q.get(e.tabId);t&&(t(),q.delete(e.tabId))}}),chrome.webNavigation.onErrorOccurred.addListener(e=>{if(e.frameId===0){let t=q.get(e.tabId);t&&(t(),q.delete(e.tabId))}}),chrome.tabs.onRemoved.addListener(e=>{T.detach(e),D.delete(e);for(let[t,n]of J)n===e&&J.delete(t);for(let[t,n]of E)n===e&&E.delete(t)});async function Y(e,t=1e4){let n=Date.now()+t,r=e=>new Promise(t=>setTimeout(t,e));for(;Date.now()<n;){try{if((await T.evaluateScript(e,`document.readyState`))?.result?.value===`complete`){await r(1500);return}}catch{}await r(200)}console.warn(`waitForRuntimeReady timed out for tab ${e}`)}async function X(e,t,n,r,i,a=0){switch(n){case`click`:{let n=await chrome.tabs.sendMessage(e,{type:`CLICK_ELEMENT`,ref:t,button:`left`},{frameId:a});return n.error?n:{success:!0,action:`click`,ref:t}}case`fill`:{if(!r)return{error:`fill action requires --value`};let n=await chrome.tabs.sendMessage(e,{type:`FORM_INPUT`,ref:t,value:r},{frameId:a});return n.error?n:{success:!0,action:`fill`,ref:t,value:r}}case`hover`:{let n=await chrome.tabs.sendMessage(e,{type:`GET_ELEMENT_COORDINATES`,ref:t},{frameId:a});return n.error?n:(await i.hover(e,n.x,n.y),{success:!0,action:`hover`,ref:t})}case`text`:return await chrome.tabs.sendMessage(e,{type:`GET_ELEMENT_TEXT`,ref:t},{frameId:a});default:return{error:`Unknown action: ${n}. Use click|fill|hover|text`}}}chrome.runtime.onMessage.addListener((e,t,n)=>(Z(e,t).then(n).catch(e=>n({error:e.message})),!0));async function Z(e,t){let n=e.tabId;switch(e.type){case`GET_CURRENT_TAB_ID`:{let[e]=await chrome.tabs.query({active:!0,currentWindow:!0});return{tabId:e?.id}}case`EXECUTE_SCREENSHOT`:if(!n)throw Error(`No tabId provided`);try{await chrome.tabs.sendMessage(n,{type:`HIDE_FOR_TOOL_USE`},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{let t,r={scaleX:1,scaleY:1},i=!1;if(e.fullpage){t=await K(n,e.maxHeight||4e3);try{let e=await T.getViewportSize(n),i=t.width/e.width;r={scaleX:i,scaleY:i}}catch{}}else try{let e=await T.captureScreenshot(n);t=e;try{let t=await T.getViewportSize(n);r={scaleX:e.width/t.width,scaleY:e.height/t.height}}catch{}}catch(e){let r=await chrome.tabs.get(n);if(!r.windowId)throw e;let a=(await chrome.tabs.captureVisibleTab(r.windowId,{format:`png`})).replace(/^data:image\/png;base64,/,``),o=atob(a),s=new Uint8Array(o.length);for(let e=0;e<o.length;e++)s[e]=o.charCodeAt(e);let c=new Blob([s],{type:`image/png`}),l=await createImageBitmap(c);t={base64:a,width:l.width,height:l.height},l.close(),i=!0}if(e.annotate&&!i)try{let e=await chrome.tabs.sendMessage(n,{type:`GET_ELEMENT_BOUNDS_FOR_ANNOTATION`},{frameId:0});e?.elements&&e.elements.length>0&&(t=await V(t,e.elements,r))}catch{}let a=M();return N(a,t),{...t,screenshotId:a}}finally{try{await chrome.tabs.sendMessage(n,{type:`SHOW_AFTER_TOOL_USE`},{frameId:0})}catch{}}case`EXECUTE_CLICK`:{if(!n)throw Error(`No tabId provided`);let t=e.modifiers?T.parseModifiers(e.modifiers):0;return await T.click(n,e.x,e.y,`left`,1,t),{success:!0}}case`EXECUTE_RIGHT_CLICK`:{if(!n)throw Error(`No tabId provided`);let t=e.modifiers?T.parseModifiers(e.modifiers):0;return await T.rightClick(n,e.x,e.y,t),{success:!0}}case`EXECUTE_DOUBLE_CLICK`:{if(!n)throw Error(`No tabId provided`);let t=e.modifiers?T.parseModifiers(e.modifiers):0;return await T.doubleClick(n,e.x,e.y,t),{success:!0}}case`EXECUTE_TRIPLE_CLICK`:{if(!n)throw Error(`No tabId provided`);let t=e.modifiers?T.parseModifiers(e.modifiers):0;return await T.tripleClick(n,e.x,e.y,t),{success:!0}}case`EXECUTE_DRAG`:{if(!n)throw Error(`No tabId provided`);let t=e.modifiers?T.parseModifiers(e.modifiers):0;return await T.drag(n,e.startX,e.startY,e.endX,e.endY,t),{success:!0}}case`EXECUTE_HOVER`:if(!n)throw Error(`No tabId provided`);return await T.hover(n,e.x,e.y),{success:!0};case`EXECUTE_TYPE`:if(!n)throw Error(`No tabId provided`);if(e.text===void 0||e.text===null)throw Error(`No text provided`);return await T.type(n,e.text),{success:!0};case`TYPE_SUBMIT`:if(!n)throw Error(`No tabId provided`);if(!e.text)throw Error(`No text provided`);return await T.type(n,e.text),await T.pressKey(n,e.submitKey||`Enter`),{success:!0};case`CLICK_TYPE`:{if(!n)throw Error(`No tabId provided`);if(!e.text)throw Error(`No text provided`);let t=O(n),r=!1;if(e.ref)try{(await chrome.tabs.sendMessage(n,{type:`CLICK_ELEMENT`,ref:e.ref,button:`left`},{frameId:t})).error||(r=!0)}catch{}if(!r&&e.coordinate&&(await T.click(n,e.coordinate[0],e.coordinate[1],`left`,1,0),r=!0),!r){let e=await T.evaluateScript(n,`(() => {
8
+ }))()`)).result?.value;if(!e)throw new Error("Failed to get page dimensions");const{viewportHeight:r,totalHeight:n,width:s,devicePixelRatio:a,originalScrollY:c}=e,u=[];let d=0;for(;d<n;){await l.evaluateScript(o,`window.scrollTo(0, ${d})`),await new Promise(g=>setTimeout(g,300));const m=await l.captureScreenshot(o),y=Q(m.base64);u.push(await createImageBitmap(y)),d+=r}await l.evaluateScript(o,`window.scrollTo(0, ${c})`);const h=Math.round(s*a),f=Math.round(n*a),w=new OffscreenCanvas(h,f),p=w.getContext("2d");if(!p)throw new Error("Failed to get canvas context");let E=0;const _=Math.round(r*a);for(let m=0;m<u.length;m++){const y=u[m],g=f-E,T=Math.min(_,g);p.drawImage(y,0,0,y.width,T,0,E,y.width,T),E+=T,y.close()}const S=await w.convertToBlob({type:"image/png"});return{base64:await Z(S),width:h,height:f}}const k=new Map,A=new Map;chrome.webNavigation.onCompleted.addListener(o=>{if(o.frameId===0){F.delete(o.tabId);const i=k.get(o.tabId);i&&(i(),k.delete(o.tabId))}});chrome.webNavigation.onErrorOccurred.addListener(o=>{if(o.frameId===0){const i=k.get(o.tabId);i&&(i(),k.delete(o.tabId))}});chrome.tabs.onRemoved.addListener(o=>{l.detach(o),F.delete(o);for(const[i,t]of A)t===o&&A.delete(i);for(const[i,t]of M)t===o&&M.delete(i)});async function U(o,i=1e4){const t=Date.now()+i,e=r=>new Promise(n=>setTimeout(n,r));for(;Date.now()<t;){try{if((await l.evaluateScript(o,"document.readyState"))?.result?.value==="complete"){await e(1500);return}}catch{}await e(200)}console.warn(`waitForRuntimeReady timed out for tab ${o}`)}async function G(o,i,t,e,r,n=0){switch(t){case"click":{const s=await chrome.tabs.sendMessage(o,{type:"CLICK_ELEMENT",ref:i,button:"left"},{frameId:n});return s.error?s:{success:!0,action:"click",ref:i}}case"fill":{if(!e)return{error:"fill action requires --value"};const s=await chrome.tabs.sendMessage(o,{type:"FORM_INPUT",ref:i,value:e},{frameId:n});return s.error?s:{success:!0,action:"fill",ref:i,value:e}}case"hover":{const s=await chrome.tabs.sendMessage(o,{type:"GET_ELEMENT_COORDINATES",ref:i},{frameId:n});return s.error?s:(await r.hover(o,s.x,s.y),{success:!0,action:"hover",ref:i})}case"text":return await chrome.tabs.sendMessage(o,{type:"GET_ELEMENT_TEXT",ref:i},{frameId:n});default:return{error:`Unknown action: ${t}. Use click|fill|hover|text`}}}chrome.runtime.onMessage.addListener((o,i,t)=>(ee(o,i).then(t).catch(e=>t({error:e.message})),!0));async function ee(o,i){const t=o.tabId;switch(o.type){case"GET_CURRENT_TAB_ID":{const[e]=await chrome.tabs.query({active:!0,currentWindow:!0});return{tabId:e?.id}}case"EXECUTE_SCREENSHOT":{if(!t)throw new Error("No tabId provided");try{await chrome.tabs.sendMessage(t,{type:"HIDE_FOR_TOOL_USE"})}catch{}await new Promise(e=>setTimeout(e,50));try{let e,r={scaleX:1,scaleY:1},n=!1;if(o.fullpage){e=await de(t,o.maxHeight||4e3);try{const a=await l.getViewportSize(t),c=e.width/a.width;r={scaleX:c,scaleY:c}}catch{}}else try{const a=await l.captureScreenshot(t);e=a;try{const c=await l.getViewportSize(t);r={scaleX:a.width/c.width,scaleY:a.height/c.height}}catch{}}catch(a){const c=await chrome.tabs.get(t);if(!c.windowId)throw a;const d=(await chrome.tabs.captureVisibleTab(c.windowId,{format:"png"})).replace(/^data:image\/png;base64,/,""),h=atob(d),f=new Uint8Array(h.length);for(let E=0;E<h.length;E++)f[E]=h.charCodeAt(E);const w=new Blob([f],{type:"image/png"}),p=await createImageBitmap(w);e={base64:d,width:p.width,height:p.height},p.close(),n=!0}if(o.annotate&&!n)try{const a=await chrome.tabs.sendMessage(t,{type:"GET_ELEMENT_BOUNDS_FOR_ANNOTATION"},{frameId:0});a?.elements&&a.elements.length>0&&(e=await ue(e,a.elements,r))}catch{}const s=ae();return ce(s,e),{...e,screenshotId:s}}finally{try{await chrome.tabs.sendMessage(t,{type:"SHOW_AFTER_TOOL_USE"})}catch{}}}case"EXECUTE_CLICK":{if(!t)throw new Error("No tabId provided");const e=o.modifiers?l.parseModifiers(o.modifiers):0;return await l.click(t,o.x,o.y,"left",1,e),{success:!0}}case"EXECUTE_RIGHT_CLICK":{if(!t)throw new Error("No tabId provided");const e=o.modifiers?l.parseModifiers(o.modifiers):0;return await l.rightClick(t,o.x,o.y,e),{success:!0}}case"EXECUTE_DOUBLE_CLICK":{if(!t)throw new Error("No tabId provided");const e=o.modifiers?l.parseModifiers(o.modifiers):0;return await l.doubleClick(t,o.x,o.y,e),{success:!0}}case"EXECUTE_TRIPLE_CLICK":{if(!t)throw new Error("No tabId provided");const e=o.modifiers?l.parseModifiers(o.modifiers):0;return await l.tripleClick(t,o.x,o.y,e),{success:!0}}case"EXECUTE_DRAG":{if(!t)throw new Error("No tabId provided");const e=o.modifiers?l.parseModifiers(o.modifiers):0;return await l.drag(t,o.startX,o.startY,o.endX,o.endY,e),{success:!0}}case"EXECUTE_HOVER":{if(!t)throw new Error("No tabId provided");return await l.hover(t,o.x,o.y),{success:!0}}case"EXECUTE_TYPE":{if(!t)throw new Error("No tabId provided");if(o.text===void 0||o.text===null)throw new Error("No text provided");return await l.type(t,o.text),{success:!0}}case"TYPE_SUBMIT":{if(!t)throw new Error("No tabId provided");if(!o.text)throw new Error("No text provided");return await l.type(t,o.text),await l.pressKey(t,o.submitKey||"Enter"),{success:!0}}case"CLICK_TYPE":{if(!t)throw new Error("No tabId provided");if(!o.text)throw new Error("No text provided");const e=b(t);let r=!1;if(o.ref)try{(await chrome.tabs.sendMessage(t,{type:"CLICK_ELEMENT",ref:o.ref,button:"left"},{frameId:e})).error||(r=!0)}catch{}if(!r&&o.coordinate&&(await l.click(t,o.coordinate[0],o.coordinate[1],"left",1,0),r=!0),!r){const n=await l.evaluateScript(t,`(() => {
13
9
  const el = document.querySelector('textarea, input[type="text"], input[type="search"], input:not([type]), [contenteditable="true"]');
14
10
  if (!el) return null;
15
11
  const r = el.getBoundingClientRect();
16
12
  return { x: r.left + r.width/2, y: r.top + r.height/2 };
17
- })()`);e.result?.value&&(await T.click(n,e.result.value.x,e.result.value.y,`left`,1,0),r=!0)}return r?(await T.type(n,e.text),{success:!0}):{error:`Could not find input element`}}case`CLICK_TYPE_SUBMIT`:{if(!n)throw Error(`No tabId provided`);if(!e.text)throw Error(`No text provided`);let t=O(n),r=!1;if(e.ref)try{(await chrome.tabs.sendMessage(n,{type:`CLICK_ELEMENT`,ref:e.ref,button:`left`},{frameId:t})).error||(r=!0)}catch{}if(!r&&e.coordinate&&(await T.click(n,e.coordinate[0],e.coordinate[1],`left`,1,0),r=!0),!r){let e=await T.evaluateScript(n,`(() => {
13
+ })()`);n.result?.value&&(await l.click(t,n.result.value.x,n.result.value.y,"left",1,0),r=!0)}return r?(await l.type(t,o.text),{success:!0}):{error:"Could not find input element"}}case"CLICK_TYPE_SUBMIT":{if(!t)throw new Error("No tabId provided");if(!o.text)throw new Error("No text provided");const e=b(t);let r=!1;if(o.ref)try{(await chrome.tabs.sendMessage(t,{type:"CLICK_ELEMENT",ref:o.ref,button:"left"},{frameId:e})).error||(r=!0)}catch{}if(!r&&o.coordinate&&(await l.click(t,o.coordinate[0],o.coordinate[1],"left",1,0),r=!0),!r){const n=await l.evaluateScript(t,`(() => {
18
14
  const el = document.querySelector('textarea, input[type="text"], input[type="search"], input:not([type]), [contenteditable="true"]');
19
15
  if (!el) return null;
20
16
  const r = el.getBoundingClientRect();
21
17
  return { x: r.left + r.width/2, y: r.top + r.height/2 };
22
- })()`);e.result?.value&&(await T.click(n,e.result.value.x,e.result.value.y,`left`,1,0),r=!0)}return r?(await T.type(n,e.text),await T.pressKey(n,e.submitKey||`Enter`),{success:!0}):{error:`Could not find input element`}}case`FIND_AND_TYPE`:{if(!n)throw Error(`No tabId provided`);if(!e.text)throw Error(`No text provided`);let t=(await T.evaluateScript(n,`(() => {
18
+ })()`);n.result?.value&&(await l.click(t,n.result.value.x,n.result.value.y,"left",1,0),r=!0)}return r?(await l.type(t,o.text),await l.pressKey(t,o.submitKey||"Enter"),{success:!0}):{error:"Could not find input element"}}case"FIND_AND_TYPE":{if(!t)throw new Error("No tabId provided");if(!o.text)throw new Error("No text provided");const r=(await l.evaluateScript(t,`(() => {
23
19
  const selectors = [
24
20
  'textarea:not([readonly]):not([disabled])',
25
21
  'input[type="text"]:not([readonly]):not([disabled])',
@@ -39,7 +35,7 @@ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],en
39
35
  }
40
36
  }
41
37
  return { found: false };
42
- })()`)).result?.value;return t?.found?(await T.click(n,t.x,t.y,`left`,1,0),await T.type(n,e.text),e.submit&&await T.pressKey(n,e.submitKey||`Enter`),{success:!0,coordinates:{x:t.x,y:t.y}}):{error:`No input field found on page`}}case`AUTOCOMPLETE_SELECT`:{if(!n)throw Error(`No tabId provided`);if(!e.text)throw Error(`No text provided`);let t=O(n),r=!1;if(e.ref)try{(await chrome.tabs.sendMessage(n,{type:`CLICK_ELEMENT`,ref:e.ref,button:`left`},{frameId:t})).error||(r=!0)}catch{}if(!r&&e.coordinate&&(await T.click(n,e.coordinate[0],e.coordinate[1],`left`,1,0),r=!0),!r)return{error:`ref or coordinate required`};await new Promise(e=>setTimeout(e,100)),await T.type(n,e.text);let i=e.waitMs||500;if(await new Promise(e=>setTimeout(e,i)),e.index&&e.index>0)for(let t=0;t<e.index;t++)await T.pressKey(n,`ArrowDown`),await new Promise(e=>setTimeout(e,50));return await T.pressKey(n,`Enter`),{success:!0}}case`SET_INPUT_VALUE`:{if(!n)throw Error(`No tabId provided`);if(e.value===void 0)throw Error(`No value provided`);let t=e.selector,r=e.ref;if(!t&&!r)throw Error(`selector or ref required`);let i=r?`(() => {
38
+ })()`)).result?.value;return r?.found?(await l.click(t,r.x,r.y,"left",1,0),await l.type(t,o.text),o.submit&&await l.pressKey(t,o.submitKey||"Enter"),{success:!0,coordinates:{x:r.x,y:r.y}}):{error:"No input field found on page"}}case"AUTOCOMPLETE_SELECT":{if(!t)throw new Error("No tabId provided");if(!o.text)throw new Error("No text provided");const e=b(t);let r=!1;if(o.ref)try{(await chrome.tabs.sendMessage(t,{type:"CLICK_ELEMENT",ref:o.ref,button:"left"},{frameId:e})).error||(r=!0)}catch{}if(!r&&o.coordinate&&(await l.click(t,o.coordinate[0],o.coordinate[1],"left",1,0),r=!0),!r)return{error:"ref or coordinate required"};await new Promise(s=>setTimeout(s,100)),await l.type(t,o.text);const n=o.waitMs||500;if(await new Promise(s=>setTimeout(s,n)),o.index&&o.index>0)for(let s=0;s<o.index;s++)await l.pressKey(t,"ArrowDown"),await new Promise(a=>setTimeout(a,50));return await l.pressKey(t,"Enter"),{success:!0}}case"SET_INPUT_VALUE":{if(!t)throw new Error("No tabId provided");if(o.value===void 0)throw new Error("No value provided");const e=o.selector,r=o.ref;if(!e&&!r)throw new Error("selector or ref required");const n=r?`(() => {
43
39
  const el = document.querySelector('[data-pi-ref="${r}"]') ||
44
40
  [...document.querySelectorAll('*')].find(e => e.getAttribute?.('data-ref') === '${r}');
45
41
  if (!el) return { error: 'Element not found' };
@@ -47,28 +43,71 @@ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],en
47
43
  const isContentEditable = el.isContentEditable || el.getAttribute('contenteditable') === 'true';
48
44
  const target = isContentEditable ? (el.querySelector('p') || el) : el;
49
45
  if (isContentEditable) {
50
- target.textContent = ${JSON.stringify(e.value)};
46
+ target.textContent = ${JSON.stringify(o.value)};
51
47
  } else {
52
- el.value = ${JSON.stringify(e.value)};
48
+ el.value = ${JSON.stringify(o.value)};
53
49
  }
54
50
  el.dispatchEvent(new Event('input', { bubbles: true }));
55
51
  el.dispatchEvent(new Event('change', { bubbles: true }));
56
52
  return { success: true, contentEditable: isContentEditable };
57
53
  })()`:`(() => {
58
- const el = document.querySelector(${JSON.stringify(t)});
59
- if (!el) return { error: 'Element not found: ' + ${JSON.stringify(t)} };
54
+ const el = document.querySelector(${JSON.stringify(e)});
55
+ if (!el) return { error: 'Element not found: ' + ${JSON.stringify(e)} };
60
56
  el.focus();
61
57
  const isContentEditable = el.isContentEditable || el.getAttribute('contenteditable') === 'true';
62
58
  const target = isContentEditable ? (el.querySelector('p') || el) : el;
63
59
  if (isContentEditable) {
64
- target.textContent = ${JSON.stringify(e.value)};
60
+ target.textContent = ${JSON.stringify(o.value)};
65
61
  } else {
66
- el.value = ${JSON.stringify(e.value)};
62
+ el.value = ${JSON.stringify(o.value)};
67
63
  }
68
64
  el.dispatchEvent(new Event('input', { bubbles: true }));
69
65
  el.dispatchEvent(new Event('change', { bubbles: true }));
70
66
  return { success: true, contentEditable: isContentEditable };
71
- })()`;return(await T.evaluateScript(n,i)).result?.value||{error:`Script failed`}}case`SMART_TYPE`:{if(!n)throw Error(`No tabId provided`);let{selector:t,text:r,clear:i=!0,submit:a=!1}=e;if(!t)throw Error(`selector required`);if(r===void 0)throw Error(`text required`);try{return await chrome.tabs.sendMessage(n,{type:`SMART_TYPE`,selector:t,text:r,clear:i,submit:a},{frameId:O(n)})}catch(e){throw Error(`Could not type into selector: ${e instanceof Error?e.message:String(e)}`)}}case`CLOSE_DIALOGS`:{if(!n)throw Error(`No tabId provided`);let t=e.maxAttempts||3;for(let e=0;e<t;e++)await T.pressKey(n,`Escape`),await new Promise(e=>setTimeout(e,100));return{success:!0}}case`PAGE_STATE`:if(!n)throw Error(`No tabId provided`);return(await T.evaluateScript(n,`(() => {
67
+ })()`;return(await l.evaluateScript(t,n)).result?.value||{error:"Script failed"}}case"SMART_TYPE":{if(!t)throw new Error("No tabId provided");const{selector:e,text:r,clear:n=!0,submit:s=!1}=o;if(!e)throw new Error("selector required");if(r===void 0)throw new Error("text required");const a=`(() => {
68
+ const el = document.querySelector(${JSON.stringify(e)});
69
+ if (!el) return { error: 'Element not found: ' + ${JSON.stringify(e)} };
70
+
71
+ const isContentEditable = el.isContentEditable ||
72
+ el.getAttribute('contenteditable') === 'true';
73
+ const hasContentEditableChild = el.querySelector('[contenteditable="true"]');
74
+
75
+ const target = hasContentEditableChild || el;
76
+ const useContentEditable = isContentEditable || !!hasContentEditableChild;
77
+
78
+ target.focus();
79
+
80
+ if (${n}) {
81
+ if (useContentEditable) {
82
+ target.textContent = '';
83
+ } else {
84
+ target.value = '';
85
+ }
86
+ }
87
+
88
+ if (useContentEditable) {
89
+ target.textContent = ${JSON.stringify(r)};
90
+ } else {
91
+ target.value = ${JSON.stringify(r)};
92
+ }
93
+
94
+ target.dispatchEvent(new Event('input', { bubbles: true }));
95
+ target.dispatchEvent(new Event('change', { bubbles: true }));
96
+
97
+ if (${s}) {
98
+ const form = el.closest('form');
99
+ const submitBtn = document.querySelector('button[type="submit"], button[data-testid*="send"], button[aria-label*="Send"]');
100
+ if (submitBtn) {
101
+ submitBtn.click();
102
+ } else if (form) {
103
+ form.dispatchEvent(new Event('submit', { bubbles: true }));
104
+ } else {
105
+ target.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true }));
106
+ }
107
+ }
108
+
109
+ return { success: true, contentEditable: useContentEditable };
110
+ })()`;return(await l.evaluateScript(t,a)).result?.value||{error:"Script failed"}}case"CLOSE_DIALOGS":{if(!t)throw new Error("No tabId provided");const e=o.maxAttempts||3;for(let r=0;r<e;r++)await l.pressKey(t,"Escape"),await new Promise(n=>setTimeout(n,100));return{success:!0}}case"PAGE_STATE":{if(!t)throw new Error("No tabId provided");return(await l.evaluateScript(t,`(() => {
72
111
  const hasModal = !!(
73
112
  document.querySelector('[role="dialog"]') ||
74
113
  document.querySelector('[role="alertdialog"]') ||
@@ -101,247 +140,8 @@ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],en
101
140
  url: location.href,
102
141
  title: document.title
103
142
  };
104
- })()`)).result?.value||{error:`Failed to get page state`};case`EXECUTE_SCROLL`:{if(!n)throw Error(`No tabId provided`);let t=e.deltaX||0,r=e.deltaY||0,i=(e,t)=>{let n={x:window.scrollX,y:window.scrollY};window.scrollBy(e,t);let r={x:window.scrollX,y:window.scrollY};return{scrollX:r.x,scrollY:r.y,pageHeight:document.documentElement.scrollHeight,viewportHeight:window.innerHeight,scrolled:n.x!==r.x||n.y!==r.y}};try{return(await T.evaluateScript(n,`(${i.toString()})(${t}, ${r})`)).result?.value||{error:`Script failed`}}catch{try{return(await chrome.scripting.executeScript({target:{tabId:n},func:i,args:[t,r]}))[0]?.result||{error:`Script failed`}}catch{return{error:`Cannot scroll on this page (restricted)`}}}}case`EXECUTE_KEY`:{if(!n)throw Error(`No tabId provided`);let t=e.key;if(!t)throw Error(`No key provided`);return t.includes(`+`)?await T.pressKeyChord(n,t):await T.pressKey(n,t),{success:!0}}case`EXECUTE_NAVIGATE`:{if(!n)throw Error(`No tabId provided`);if(!e.url)throw Error(`No url provided`);let t=new Promise(e=>{q.set(n,e),setTimeout(()=>{q.has(n)&&(q.delete(n),e())},3e4)});return await chrome.tabs.update(n,{url:e.url}),await t,await new Promise(e=>setTimeout(e,500)),{success:!0}}case`GET_VIEWPORT_SIZE`:if(!n)throw Error(`No tabId provided`);return await T.getViewportSize(n);case`READ_PAGE`:{if(!n)throw Error(`No tabId provided`);let t=O(n);try{await chrome.tabs.sendMessage(n,{type:`HIDE_FOR_TOOL_USE`},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));let r;try{r=await chrome.tabs.sendMessage(n,{type:`GENERATE_ACCESSIBILITY_TREE`,options:e.options||{}},{frameId:t})}catch{return{error:`Content script not loaded. Try refreshing the page.`,pageContent:``,viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(n,{type:`SHOW_AFTER_TOOL_USE`},{frameId:0})}catch{}}if(e.options?.includeText)try{let i=await chrome.tabs.sendMessage(n,{type:`GET_PAGE_TEXT`,options:{compact:e.options?.compact===!0,maxBytes:e.options?.maxBytes}},{frameId:t});i?.text&&(r.text=i.text)}catch{}if(e.options?.includeScreenshot)try{let e=await T.captureScreenshot(n);return{...r,screenshot:e}}catch{return{...r,screenshotError:`Failed to capture screenshot`}}return r}case`GET_ELEMENT_COORDINATES`:if(!n)throw Error(`No tabId provided`);try{return await chrome.tabs.sendMessage(n,{type:`GET_ELEMENT_COORDINATES`,ref:e.ref},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`FORM_INPUT`:if(!n)throw Error(`No tabId provided`);try{return await chrome.tabs.sendMessage(n,{type:`FORM_INPUT`,ref:e.ref,value:e.value},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`EVAL_IN_PAGE`:if(!n)throw Error(`No tabId provided`);if(!e.code)throw Error(`No code provided`);try{return await chrome.tabs.sendMessage(n,{type:`EVAL_IN_PAGE`,code:e.code},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`SCROLL_TO_ELEMENT`:if(!n)throw Error(`No tabId provided`);try{return await chrome.tabs.sendMessage(n,{type:`SCROLL_TO_ELEMENT`,ref:e.ref},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`SCROLL_TO_POSITION`:{if(!n)throw Error(`No tabId provided`);let t=e.position;if(t===void 0)throw Error(`position required ("top", "bottom", or number)`);let r=e.selector,i=(e,t)=>{let n=t&&document.querySelector(t)||[...document.querySelectorAll(`*`)].filter(e=>e.scrollHeight>e.clientHeight&&e.clientHeight>200).sort((e,t)=>t.scrollHeight-e.scrollHeight)[0]||document.documentElement;return n?(e===`bottom`?n.scrollTop=n.scrollHeight:e===`top`?n.scrollTop=0:typeof e==`number`&&(n.scrollTop=e),{scrollTop:n.scrollTop,scrollHeight:n.scrollHeight,clientHeight:n.clientHeight,atBottom:n.scrollTop+n.clientHeight>=n.scrollHeight-10,atTop:n.scrollTop<10}):{error:`No scrollable container found`}};try{let e=`(${i.toString()})(${JSON.stringify(t)}, ${JSON.stringify(r)})`;return(await T.evaluateScript(n,e)).result?.value||{error:`Script failed`}}catch{try{return(await chrome.scripting.executeScript({target:{tabId:n},func:i,args:[t,r]}))[0]?.result||{error:`Script failed`}}catch{return{error:`Cannot scroll on this page (restricted)`}}}}case`GET_SCROLL_INFO`:{if(!n)throw Error(`No tabId provided`);let t=e.selector,r=e=>{let t=e&&document.querySelector(e)||[...document.querySelectorAll(`*`)].filter(e=>e.scrollHeight>e.clientHeight&&e.clientHeight>200).sort((e,t)=>t.scrollHeight-e.scrollHeight)[0]||document.documentElement;if(!t)return{error:`No scrollable container found`};let n=t.scrollHeight-t.clientHeight;return{scrollTop:t.scrollTop,scrollHeight:t.scrollHeight,clientHeight:t.clientHeight,atBottom:t.scrollTop+t.clientHeight>=t.scrollHeight-10,atTop:t.scrollTop<10,scrollPercentage:n>0?Math.round(t.scrollTop/n*100):100}};try{let e=`(${r.toString()})(${JSON.stringify(t)})`;return(await T.evaluateScript(n,e)).result?.value||{error:`Script failed`}}catch{try{return(await chrome.scripting.executeScript({target:{tabId:n},func:r,args:[t]}))[0]?.result||{error:`Script failed`}}catch{return{error:`Cannot get scroll info on this page (restricted)`}}}}case`GET_PAGE_TEXT`:if(!n)throw Error(`No tabId provided`);try{return await chrome.tabs.sendMessage(n,{type:`GET_PAGE_TEXT`},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`LOCATE_ROLE`:{if(!n)throw Error(`No tabId provided`);if(!e.role)throw Error(`role required`);let t=O(n);try{let r=await chrome.tabs.sendMessage(n,{type:`LOCATE_ROLE`,role:e.role,name:e.name,all:e.all},{frameId:t});return r.error?r:e.action&&r.ref?await X(n,r.ref,e.action,e.value,T,t):r}catch{return{error:`Content script not loaded. Try refreshing the page.`}}}case`LOCATE_TEXT`:{if(!n)throw Error(`No tabId provided`);if(!e.text)throw Error(`text required`);let t=O(n);try{let r=await chrome.tabs.sendMessage(n,{type:`LOCATE_TEXT`,text:e.text,exact:e.exact},{frameId:t});return r.error?r:e.action&&r.ref?await X(n,r.ref,e.action,e.value,T,t):r}catch{return{error:`Content script not loaded. Try refreshing the page.`}}}case`LOCATE_LABEL`:{if(!n)throw Error(`No tabId provided`);if(!e.label)throw Error(`label required`);let t=O(n);try{let r=await chrome.tabs.sendMessage(n,{type:`LOCATE_LABEL`,label:e.label},{frameId:t});return r.error?r:e.action&&r.ref?await X(n,r.ref,e.action,e.value,T,t):r}catch{return{error:`Content script not loaded. Try refreshing the page.`}}}case`GET_ELEMENT_STYLES`:{if(!n)throw Error(`No tabId provided`);if(!e.selector)throw Error(`selector required`);let t=O(n);try{return await chrome.tabs.sendMessage(n,{type:`GET_ELEMENT_STYLES`,selector:e.selector},{frameId:t})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}}case`SELECT_OPTION`:{if(!n)throw Error(`No tabId provided`);if(!e.selector)throw Error(`selector required`);if(!e.values)throw Error(`values required`);let t=O(n);try{return await chrome.tabs.sendMessage(n,{type:`SELECT_OPTION`,selector:e.selector,values:e.values,by:e.by||`value`},{frameId:t})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}}case`SHOW_AGENT_INDICATORS`:case`HIDE_AGENT_INDICATORS`:case`SHOW_STATIC_INDICATOR`:case`HIDE_STATIC_INDICATOR`:if(!n)throw Error(`No tabId provided`);try{return await chrome.tabs.sendMessage(n,{type:e.type},{frameId:0})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`STOP_AGENT`:{let n=e.fromTabId,r;return n===`CURRENT_TAB`&&t.tab?.id?r=t.tab.id:typeof n==`number`&&(r=n),r&&chrome.runtime.sendMessage({type:`STOP_AGENT`,targetTabId:r}),{success:!0}}case`DISMISS_STATIC_INDICATOR`:return{success:!0};case`STATIC_INDICATOR_HEARTBEAT`:return{success:!0};case`CLICK_REF`:if(!n)throw Error(`No tabId provided`);try{let t=await chrome.tabs.sendMessage(n,{type:`CLICK_ELEMENT`,ref:e.ref,button:e.button||`left`},{frameId:O(n)});return t.error?{error:t.error}:{success:!0}}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`HOVER_REF`:if(!n)throw Error(`No tabId provided`);try{let t=await chrome.tabs.sendMessage(n,{type:`GET_ELEMENT_COORDINATES`,ref:e.ref},{frameId:O(n)});return t.error?{error:t.error}:(await T.hover(n,t.x,t.y),{success:!0})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`PING`:return{success:!0,status:`connected`};case`HEALTH_CHECK_URL`:{if(!e.url)throw Error(`No url provided`);let t=e.timeout||3e4,n=e.expect||200,r=Date.now(),i=null;for(;Date.now()-r<t;){try{let t=await fetch(e.url,{method:`GET`});if(await t.text(),t.status===n)return{success:!0,status:t.status,time:Date.now()-r};i=`Got status ${t.status}`}catch(e){i=e instanceof Error?e.message:String(e)}await new Promise(e=>setTimeout(e,500))}return{error:`Timeout waiting for ${e.url} to return ${n}`,lastError:i,time:Date.now()-r}}case`SMOKE_TEST`:{let t=e.urls||[],n=e.savePath!==void 0,r=e.failFast||!1;if(t.length===0)return{error:`No URLs provided for smoke test`};let i=[],a=0,o=0;for(let e of t){let t=Date.now(),s=[],c,l,u;try{l=new URL(e).hostname.replace(/[^a-zA-Z0-9.-]/g,`_`);let t=await chrome.tabs.create({url:e,active:!1});if(!t.id)throw Error(`Failed to create tab`);u=t.id;try{await T.enableConsoleTracking(u)}catch{}await new Promise(e=>{let t=r=>{r.tabId===u&&r.frameId===0&&(chrome.webNavigation.onCompleted.removeListener(t),chrome.webNavigation.onErrorOccurred.removeListener(n),e())},n=r=>{r.tabId===u&&r.frameId===0&&(chrome.webNavigation.onCompleted.removeListener(t),chrome.webNavigation.onErrorOccurred.removeListener(n),s.push(`Navigation error: ${r.error}`),e())};chrome.webNavigation.onCompleted.addListener(t),chrome.webNavigation.onErrorOccurred.addListener(n),setTimeout(()=>{chrome.webNavigation.onCompleted.removeListener(t),chrome.webNavigation.onErrorOccurred.removeListener(n),s.push(`Navigation timeout (30s)`),e()},3e4)}),await new Promise(e=>setTimeout(e,2e3));let r=T.getConsoleMessages(u,{onlyErrors:!0,limit:50});for(let e of r)s.push(`[${e.type}] ${e.text}`);if(n)try{c=(await T.captureScreenshot(u)).base64}catch{}}catch(e){s.push(e instanceof Error?e.message:String(e))}finally{if(u)try{await chrome.tabs.remove(u)}catch{}}let d=Date.now()-t,f=s.length===0?`pass`:`fail`;if(f===`pass`?a++:o++,i.push({url:e,status:f,time:d,errors:s,...c&&{screenshotBase64:c,hostname:l}}),r&&f===`fail`)break}return{results:i,summary:{pass:a,fail:o,total:i.length},savePath:e.savePath}}case`WAIT_FOR_ELEMENT`:{if(!n)throw Error(`No tabId provided`);if(!e.selector)throw Error(`No selector provided`);let t=O(n);try{await chrome.tabs.sendMessage(n,{type:`HIDE_FOR_TOOL_USE`},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(n,{type:`WAIT_FOR_ELEMENT`,selector:e.selector,state:e.state||`visible`,timeout:e.timeout||2e4},{frameId:t})}catch{return{error:`Content script not loaded. Try refreshing the page.`,pageContent:``,viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(n,{type:`SHOW_AFTER_TOOL_USE`},{frameId:0})}catch{}}}case`WAIT_FOR_URL`:if(!n)throw Error(`No tabId provided`);if(!e.pattern)throw Error(`No URL pattern provided`);try{await chrome.tabs.sendMessage(n,{type:`HIDE_FOR_TOOL_USE`},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(n,{type:`WAIT_FOR_URL`,pattern:e.pattern,timeout:e.timeout||2e4},{frameId:0})}catch{return{error:`Content script not loaded. Try refreshing the page.`,pageContent:``,viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(n,{type:`SHOW_AFTER_TOOL_USE`},{frameId:0})}catch{}}case`WAIT_FOR_NETWORK_IDLE`:if(!n)throw Error(`No tabId provided`);try{await chrome.tabs.sendMessage(n,{type:`HIDE_FOR_TOOL_USE`},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(n,{type:`WAIT_FOR_NETWORK_IDLE`,timeout:e.timeout||1e4},{frameId:0})}catch{return{error:`Content script not loaded. Try refreshing the page.`,pageContent:``,viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(n,{type:`SHOW_AFTER_TOOL_USE`},{frameId:0})}catch{}}case`WAIT_FOR_DOM_STABLE`:if(!n)throw Error(`No tabId provided`);try{await chrome.tabs.sendMessage(n,{type:`HIDE_FOR_TOOL_USE`},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(n,{type:`WAIT_FOR_DOM_STABLE`,stable:e.stable||100,timeout:e.timeout||5e3},{frameId:0})}catch{return{error:`Content script not loaded. Try refreshing the page.`,pageContent:``,viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(n,{type:`SHOW_AFTER_TOOL_USE`},{frameId:0})}catch{}}case`DIALOG_ACCEPT`:if(!n)throw Error(`No tabId provided`);return await T.handleDialog(n,!0,e.text);case`DIALOG_DISMISS`:if(!n)throw Error(`No tabId provided`);return await T.handleDialog(n,!1);case`DIALOG_INFO`:{if(!n)throw Error(`No tabId provided`);let e=T.getDialogInfo(n);return e?{hasDialog:!0,type:e.type,message:e.message,defaultPrompt:e.defaultPrompt}:{hasDialog:!1}}case`EMULATE_NETWORK`:{if(!n)throw Error(`No tabId provided`);if(!e.preset)throw Error(`No preset provided`);let t=await T.emulateNetwork(n,e.preset);if(!t.success)throw Error(t.error);return{success:!0,preset:e.preset}}case`EMULATE_CPU`:{if(!n)throw Error(`No tabId provided`);if(e.rate===void 0)throw Error(`No rate provided`);let t=await T.emulateCPU(n,e.rate);if(!t.success)throw Error(t.error);return{success:!0,rate:e.rate}}case`EMULATE_GEO`:{if(!n)throw Error(`No tabId provided`);if(e.clear){let e=await T.clearGeolocation(n);if(!e.success)throw Error(e.error);return{success:!0,cleared:!0}}if(e.latitude===void 0||e.longitude===void 0)throw Error(`Latitude and longitude required`);let t=await T.emulateGeolocation(n,e.latitude,e.longitude,e.accuracy);if(!t.success)throw Error(t.error);return{success:!0,latitude:e.latitude,longitude:e.longitude}}case`EMULATE_DEVICE_LIST`:return{devices:[`iPhone 12`,`iPhone 13`,`iPhone 14`,`iPhone 14 Pro`,`iPhone 14 Pro Max`,`iPhone SE`,`iPad`,`iPad Pro`,`iPad Mini`,`Pixel 5`,`Pixel 6`,`Pixel 7`,`Pixel 7 Pro`,`Galaxy S21`,`Galaxy S22`,`Galaxy S23`,`Galaxy Tab S7`,`Nest Hub`,`Nest Hub Max`]};case`EMULATE_DEVICE`:{if(!n)throw Error(`No tabId provided`);let t=e.device;if(t.toLowerCase()===`reset`){let e=await T.clearDeviceEmulation(n);if(!e.success)throw Error(e.error);return{success:!0,message:`Device emulation reset`}}let r={"iPhone 12":{width:390,height:844,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1`},"iPhone 13":{width:390,height:844,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1`},"iPhone 14":{width:390,height:844,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1`},"iPhone 14 Pro":{width:393,height:852,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1`},"iPhone 14 Pro Max":{width:430,height:932,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1`},"iPhone SE":{width:375,height:667,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1`},iPad:{width:768,height:1024,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1`},"iPad Pro":{width:1024,height:1366,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1`},"iPad Mini":{width:768,height:1024,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1`},"Pixel 5":{width:393,height:851,deviceScaleFactor:2.75,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36`},"Pixel 6":{width:412,height:915,deviceScaleFactor:2.625,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36`},"Pixel 7":{width:412,height:915,deviceScaleFactor:2.625,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36`},"Pixel 7 Pro":{width:412,height:892,deviceScaleFactor:3.5,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36`},"Galaxy S21":{width:360,height:800,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 11; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36`},"Galaxy S22":{width:360,height:780,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 12; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36`},"Galaxy S23":{width:360,height:780,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Mobile Safari/537.36`},"Galaxy Tab S7":{width:800,height:1280,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android 10; SM-T870) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Safari/537.36`},"Nest Hub":{width:1024,height:600,deviceScaleFactor:2,mobile:!1,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.109 Safari/537.36 CrKey/1.54.248666`},"Nest Hub Max":{width:1280,height:800,deviceScaleFactor:2,mobile:!1,touch:!0,userAgent:`Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.109 Safari/537.36 CrKey/1.54.248666`}},i=r[t];if(!i){let e=t.toLowerCase(),n=null;for(let[t,i]of Object.entries(r)){let r=t.toLowerCase(),a=r.replace(/\s+/g,``);(r.includes(e)||e.includes(a))&&(!n||t.length>n.name.length)&&(n={name:t,preset:i})}n&&(i=n.preset)}if(!i)throw Error(`Unknown device: ${t}. Use --list to see available devices.`);let a=await T.emulateDevice(n,i);if(!a.success)throw Error(a.error);return{success:!0,device:t}}case`EMULATE_VIEWPORT`:{if(!n)throw Error(`No tabId provided`);if(!e.width&&!e.height)throw Error(`--width or --height required`);let t=await T.emulateViewport(n,{width:e.width,height:e.height,deviceScaleFactor:e.deviceScaleFactor,mobile:e.mobile});if(!t.success)throw Error(t.error);return{success:!0,width:e.width,height:e.height}}case`EMULATE_TOUCH`:{if(!n)throw Error(`No tabId provided`);let t=await T.emulateTouch(n,e.enabled);if(!t.success)throw Error(t.error);return{success:!0,enabled:e.enabled}}case`FORM_FILL`:if(!n)throw Error(`No tabId provided`);if(!e.data)throw Error(`No data provided`);return await chrome.tabs.sendMessage(n,{type:`FORM_FILL`,data:e.data},{frameId:O(n)});case`PERF_START`:{if(!n)throw Error(`No tabId provided`);let t=await T.startPerformanceTrace(n,e.categories);if(!t.success)throw Error(t.error);return{success:!0,message:`Performance tracing started`}}case`PERF_STOP`:{if(!n)throw Error(`No tabId provided`);let e=await T.stopPerformanceTrace(n);if(!e.success)throw Error(e.error);return{success:!0,metrics:e.metrics}}case`PERF_METRICS`:{if(!n)throw Error(`No tabId provided`);let e=await T.getPerformanceMetrics(n);if(!e.success)throw Error(e.error);return{success:!0,metrics:e.metrics}}case`UPLOAD_FILE`:{if(!n)throw Error(`No tabId provided`);if(!e.ref)throw Error(`No ref provided`);if(!e.files||!e.files.length)throw Error(`No files provided`);let t=await chrome.tabs.sendMessage(n,{type:`GET_FILE_INPUT_SELECTOR`,ref:e.ref},{frameId:O(n)});if(t.error)throw Error(t.error);let r=await T.setFileInputBySelector(n,t.selector,e.files);if(!r.success)throw Error(r.error);return{success:!0,filesSet:e.files.length}}case`WAIT_FOR_LOAD`:{if(!n)throw Error(`No tabId provided`);let t=await T.waitForLoad(n,e.timeout||3e4);if(!t.success)throw Error(t.error);return{success:!0,readyState:t.readyState}}case`GET_FRAMES`:{if(!n)throw Error(`No tabId provided`);let e=await T.getFrames(n);if(!e.success)throw Error(e.error);return{success:!0,frames:e.frames}}case`FRAME_SWITCH`:{if(!n)throw Error(`No tabId provided`);let{selector:t,name:r,index:i}=e;if(!t&&!r&&i===void 0)throw Error(`--selector, --name, or --index required`);let a=await chrome.webNavigation.getAllFrames({tabId:n});if(!a||a.length===0)throw Error(`No frames found in tab`);let o=a.filter(e=>e.frameId!==0);if(o.length===0)throw Error(`No iframes found on this page`);let s=null;if(i!==void 0){if(i<0||i>=o.length)throw Error(`Frame index ${i} out of range. Found ${o.length} frame(s).`);s=o[i]}else if(r){for(let e of o)try{if((await chrome.tabs.sendMessage(n,{type:`GET_FRAME_NAME`},{frameId:e.frameId}))?.name===r){s=e;break}}catch{}if(!s)throw Error(`Frame with name "${r}" not found`)}else if(t)try{let e=await chrome.tabs.sendMessage(n,{type:`GET_FRAME_BY_SELECTOR`,selector:t},{frameId:0});if(e?.error)throw Error(e.error);e?.url&&(s=o.find(t=>t.url===e.url)||null),!s&&o.length===1&&(s=o[0])}catch{throw Error(`Could not find frame with selector "${t}"`)}if(!s)throw Error(`Frame not found`);return D.set(n,s.frameId),{success:!0,frameId:s.frameId,url:s.url}}case`FRAME_MAIN`:if(!n)throw Error(`No tabId provided`);return D.delete(n),{success:!0,message:`Returned to main frame`};case`EVALUATE_IN_FRAME`:{if(!n)throw Error(`No tabId provided`);if(!e.frameId)throw Error(`No frameId provided`);if(!e.code)throw Error(`No code provided`);let t=await T.evaluateInFrame(n,e.frameId,e.code);if(!t.success)throw Error(t.error);return{value:t.result}}case`EXECUTE_JAVASCRIPT`:if(!n)throw Error(`No tabId provided`);if(!e.code)throw Error(`No code provided`);try{await T.evaluateScript(n,`if(!window.piHelpers){const piHelpers={wait(ms){return new Promise(r=>setTimeout(r,ms))},async waitForSelector(sel,opts={}){const{state='visible',timeout=20000}=opts;const isVis=el=>el&&getComputedStyle(el).display!=='none'&&getComputedStyle(el).visibility!=='hidden'&&getComputedStyle(el).opacity!=='0'&&el.offsetWidth>0&&el.offsetHeight>0;const chk=()=>{const el=document.querySelector(sel);switch(state){case'attached':return el;case'detached':return el?null:document.body;case'hidden':return(!el||!isVis(el))?(el||document.body):null;default:return isVis(el)?el:null}};return new Promise((res,rej)=>{const r=chk();if(r){res(state==='detached'||state==='hidden'?null:r);return}const obs=new MutationObserver(()=>{const r=chk();if(r){obs.disconnect();clearTimeout(tid);res(state==='detached'||state==='hidden'?null:r)}});const tid=setTimeout(()=>{obs.disconnect();rej(new Error('Timeout'))},timeout);obs.observe(document.documentElement,{childList:true,subtree:true,attributes:true,attributeFilter:['style','class','hidden']})})},async waitForText(text,opts={}){const{selector,timeout=20000}=opts;const chk=()=>{const root=selector?document.querySelector(selector):document.body;if(!root)return null;const w=document.createTreeWalker(root,NodeFilter.SHOW_TEXT);while(w.nextNode())if(w.currentNode.textContent?.includes(text))return w.currentNode.parentElement;return null};return new Promise((res,rej)=>{const r=chk();if(r){res(r);return}const obs=new MutationObserver(()=>{const r=chk();if(r){obs.disconnect();clearTimeout(tid);res(r)}});const tid=setTimeout(()=>{obs.disconnect();rej(new Error('Timeout'))},timeout);obs.observe(document.documentElement,{childList:true,subtree:true,characterData:true})})},async waitForHidden(sel,t=20000){await piHelpers.waitForSelector(sel,{state:'hidden',timeout:t})},getByRole(role,opts={}){const{name}=opts;const roles={button:['button','input[type=button]','input[type=submit]','input[type=reset]'],link:['a[href]'],textbox:['input:not([type])','input[type=text]','input[type=email]','input[type=password]','textarea'],checkbox:['input[type=checkbox]'],radio:['input[type=radio]'],combobox:['select'],heading:['h1','h2','h3','h4','h5','h6']};const cands=[...document.querySelectorAll('[role='+role+']')];if(roles[role])roles[role].forEach(s=>cands.push(...document.querySelectorAll(s+':not([role])')));if(!name)return cands[0]||null;const n=name.toLowerCase().trim();for(const el of cands){const l=el.getAttribute('aria-label')?.toLowerCase().trim();const t=el.textContent?.toLowerCase().trim();if(l===n||t===n||l?.includes(n)||t?.includes(n))return el}return null}};window.__piHelpers=piHelpers;window.piHelpers=piHelpers}`);let t=W(e.code),r=`(async () => { 'use strict'; ${t} })()`,i=await T.evaluateScript(n,r);if(i.exceptionDetails&&!G(t)&&(i=await T.evaluateScript(n,`(async () => { 'use strict'; ${e.code} })()`)),i.exceptionDetails)return{error:i.exceptionDetails.exception?.description||i.exceptionDetails.text||`Script execution failed`};let a=i.result?.value;return{output:(a===void 0?`undefined`:JSON.stringify(a,null,2))?.substring(0,5e4)||`undefined`}}catch(e){let t=e instanceof Error?e.message:`Script execution failed`;return t.includes(`Cannot access`)||t.includes(`Cannot attach`)?{error:`Cannot execute JavaScript on this page (restricted URL)`}:{error:t}}case`ANIMATE_AUDIT`:{if(!n)throw Error(`No tabId provided`);if(!e.selector||typeof e.selector!=`string`)throw Error(`selector required`);if(typeof e.durationMs==`boolean`)throw Error(`duration must be a number`);if(typeof e.fps==`boolean`)throw Error(`fps must be a number`);let t=e.durationMs===void 0?2e3:Number(e.durationMs),r=e.fps===void 0?10:Number(e.fps);if(!Number.isFinite(t)||t<100||t>1e4)throw Error(`duration must be between 100 and 10000 ms`);if(!Number.isFinite(r)||r<1||r>30)throw Error(`fps must be between 1 and 30`);try{let i=`(async () => {
105
- const selector = ${JSON.stringify(e.selector)};
106
- const durationMs = ${Math.round(t)};
107
- const fps = ${Math.round(r)};
108
- const intervalMs = Math.max(1, Math.round(1000 / fps));
109
- const maxElements = 25;
110
- const maxSamples = Math.min(Math.floor(durationMs / intervalMs) + 1, 301);
111
- const startedAt = Date.now();
112
- const start = performance.now();
113
- const samples = [];
114
- const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
115
- const sample = () => {
116
- const now = performance.now();
117
- const elements = Array.from(document.querySelectorAll(selector)).slice(0, maxElements).map((el, index) => {
118
- const rect = el.getBoundingClientRect();
119
- const style = getComputedStyle(el);
120
- const text = (el.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 120);
121
- return {
122
- selector,
123
- index,
124
- rect: {
125
- x: Math.round(rect.x * 100) / 100,
126
- y: Math.round(rect.y * 100) / 100,
127
- width: Math.round(rect.width * 100) / 100,
128
- height: Math.round(rect.height * 100) / 100,
129
- top: Math.round(rect.top * 100) / 100,
130
- right: Math.round(rect.right * 100) / 100,
131
- bottom: Math.round(rect.bottom * 100) / 100,
132
- left: Math.round(rect.left * 100) / 100,
133
- },
134
- opacity: style.opacity,
135
- transform: style.transform,
136
- visibility: style.visibility,
137
- display: style.display,
138
- text,
139
- };
140
- });
141
- samples.push({ t: Math.round((now - start) * 100) / 100, timestamp: Date.now(), elements });
142
- };
143
-
144
- for (let i = 0; i < maxSamples; i++) {
145
- sample();
146
- const elapsed = performance.now() - start;
147
- if (elapsed >= durationMs || i === maxSamples - 1) break;
148
- await wait(Math.max(0, Math.min(intervalMs, durationMs - elapsed)));
149
- }
150
-
151
- return {
152
- selector,
153
- durationMs,
154
- fps,
155
- intervalMs,
156
- maxElementsPerSample: maxElements,
157
- startedAt,
158
- endedAt: Date.now(),
159
- sampleCount: samples.length,
160
- samples,
161
- };
162
- })()`,a=await T.evaluateScript(n,i);return a.exceptionDetails?{error:a.exceptionDetails.exception?.description||a.exceptionDetails.text||`Animation audit failed`}:a.result?.value??{error:`Animation audit returned no data`}}catch(e){let t=e instanceof Error?e.message:`Animation audit failed`;return t.includes(`Cannot access`)||t.includes(`Cannot attach`)?{error:`Cannot execute animation audit on this page (restricted URL)`}:{error:t}}}case`PERF_AUDIT`:{if(!n)throw Error(`No tabId provided`);if(typeof e.durationMs==`boolean`)throw Error(`duration must be a number`);if(e.trigger!==void 0&&typeof e.trigger!=`string`)throw Error(`trigger must be action:target`);let t=e.durationMs===void 0?3e3:Number(e.durationMs);if(!Number.isFinite(t)||t<100||t>1e4)throw Error(`duration must be between 100 and 10000 ms`);try{let r=`(async () => {
163
- const durationMs = ${Math.round(t)};
164
- const trigger = ${JSON.stringify(e.trigger||null)};
165
- const startedAt = Date.now();
166
- const startedAtPerformance = performance.now();
167
- const supportedEntryTypes = typeof PerformanceObserver !== "undefined" && Array.isArray(PerformanceObserver.supportedEntryTypes) ? PerformanceObserver.supportedEntryTypes : [];
168
- const requestedTypes = ["layout-shift", "long-animation-frame", "event", "longtask", "paint"];
169
- const observedEntryTypes = [];
170
- const entries = {
171
- layoutShifts: [],
172
- longAnimationFrames: [],
173
- events: [],
174
- longTasks: [],
175
- paints: [],
176
- };
177
- const round = (value) => Math.round(value * 100) / 100;
178
- const auditEndsAtPerformance = startedAtPerformance + durationMs;
179
- const inAuditWindow = (entry) => entry.startTime >= startedAtPerformance && entry.startTime <= auditEndsAtPerformance;
180
- const nodeSummary = (node) => {
181
- if (!node || node.nodeType !== Node.ELEMENT_NODE) return null;
182
- const el = node;
183
- return {
184
- tag: el.tagName?.toLowerCase(),
185
- id: el.id || undefined,
186
- className: typeof el.className === "string" ? el.className.slice(0, 120) : undefined,
187
- };
188
- };
189
- const rectSummary = (rect) => rect ? {
190
- x: round(rect.x),
191
- y: round(rect.y),
192
- width: round(rect.width),
193
- height: round(rect.height),
194
- top: round(rect.top),
195
- right: round(rect.right),
196
- bottom: round(rect.bottom),
197
- left: round(rect.left),
198
- } : null;
199
- const pushEntry = (entry) => {
200
- if (!inAuditWindow(entry)) return;
201
- if (entry.entryType === "layout-shift") {
202
- entries.layoutShifts.push({
203
- name: entry.name,
204
- startTime: round(entry.startTime),
205
- duration: round(entry.duration || 0),
206
- value: round(entry.value || 0),
207
- hadRecentInput: Boolean(entry.hadRecentInput),
208
- sources: Array.from(entry.sources || []).slice(0, 10).map((source) => ({
209
- node: nodeSummary(source.node),
210
- previousRect: rectSummary(source.previousRect),
211
- currentRect: rectSummary(source.currentRect),
212
- })),
213
- });
214
- return;
215
- }
216
- if (entry.entryType === "long-animation-frame") {
217
- entries.longAnimationFrames.push({
218
- name: entry.name,
219
- startTime: round(entry.startTime),
220
- duration: round(entry.duration || 0),
221
- renderStart: round(entry.renderStart || 0),
222
- styleAndLayoutStart: round(entry.styleAndLayoutStart || 0),
223
- blockingDuration: round(entry.blockingDuration || 0),
224
- firstUIEventTimestamp: round(entry.firstUIEventTimestamp || 0),
225
- scripts: Array.from(entry.scripts || []).slice(0, 10).map((script) => ({
226
- name: script.name,
227
- sourceURL: script.sourceURL,
228
- sourceFunctionName: script.sourceFunctionName,
229
- duration: round(script.duration || 0),
230
- invoker: script.invoker,
231
- invokerType: script.invokerType,
232
- })),
233
- });
234
- return;
235
- }
236
- if (entry.entryType === "event") {
237
- entries.events.push({
238
- name: entry.name,
239
- startTime: round(entry.startTime),
240
- duration: round(entry.duration || 0),
241
- processingStart: round(entry.processingStart || 0),
242
- processingEnd: round(entry.processingEnd || 0),
243
- interactionId: entry.interactionId || 0,
244
- cancelable: Boolean(entry.cancelable),
245
- });
246
- return;
247
- }
248
- if (entry.entryType === "longtask") {
249
- entries.longTasks.push({
250
- name: entry.name,
251
- startTime: round(entry.startTime),
252
- duration: round(entry.duration || 0),
253
- });
254
- return;
255
- }
256
- if (entry.entryType === "paint") {
257
- entries.paints.push({
258
- name: entry.name,
259
- startTime: round(entry.startTime),
260
- duration: round(entry.duration || 0),
261
- });
262
- }
263
- };
264
- const observers = [];
265
- for (const type of requestedTypes) {
266
- if (!supportedEntryTypes.includes(type)) continue;
267
- try {
268
- const observer = new PerformanceObserver((list) => {
269
- for (const entry of list.getEntries()) pushEntry(entry);
270
- });
271
- const options = type === "event"
272
- ? { type, buffered: true, durationThreshold: 16 }
273
- : { type, buffered: true };
274
- observer.observe(options);
275
- observers.push(observer);
276
- observedEntryTypes.push(type);
277
- } catch {}
278
- }
279
- const fireTrigger = () => {
280
- if (!trigger) return null;
281
- const separator = trigger.indexOf(":");
282
- if (separator === -1) throw new Error("trigger must be action:target");
283
- const action = trigger.slice(0, separator).trim();
284
- const target = trigger.slice(separator + 1).trim();
285
- if (!action || !target) throw new Error("trigger must be action:target");
286
- if (action === "click") {
287
- const el = document.querySelector(target);
288
- if (!el) return { action, selector: target, fired: false };
289
- el.click();
290
- return { action, selector: target, fired: true };
291
- }
292
- if (action === "scroll") {
293
- if (["up", "down", "left", "right"].includes(target)) {
294
- const deltas = { up: [0, -500], down: [0, 500], left: [-500, 0], right: [500, 0] };
295
- const [left, top] = deltas[target];
296
- window.scrollBy({ left, top, behavior: "instant" });
297
- return { action, target, fired: true };
298
- }
299
- if (target === "top" || target === "bottom") {
300
- window.scrollTo({ top: target === "top" ? 0 : document.documentElement.scrollHeight, behavior: "instant" });
301
- return { action, target, fired: true };
302
- }
303
- const el = document.querySelector(target);
304
- if (!el) return { action, selector: target, fired: false };
305
- el.scrollTop = el.scrollHeight;
306
- el.dispatchEvent(new Event("scroll", { bubbles: true }));
307
- return { action, selector: target, fired: true };
308
- }
309
- throw new Error("trigger action must be click or scroll");
310
- };
311
- const triggerResult = fireTrigger();
312
- await new Promise((resolve) => setTimeout(resolve, durationMs));
313
- for (const observer of observers) observer.disconnect();
314
- const cls = entries.layoutShifts
315
- .filter((entry) => !entry.hadRecentInput)
316
- .reduce((sum, entry) => sum + entry.value, 0);
317
- const maxDuration = (items) => items.reduce((max, entry) => Math.max(max, entry.duration || 0), 0);
318
- const longTaskTotalDuration = entries.longTasks.reduce((sum, entry) => sum + (entry.duration || 0), 0);
319
-
320
- return {
321
- durationMs,
322
- startedAt,
323
- endedAt: Date.now(),
324
- elapsedMs: round(performance.now() - startedAtPerformance),
325
- supportedEntryTypes,
326
- observedEntryTypes,
327
- trigger: triggerResult,
328
- summary: {
329
- cumulativeLayoutShift: round(cls),
330
- maxEventDuration: round(maxDuration(entries.events)),
331
- maxLongAnimationFrame: round(maxDuration(entries.longAnimationFrames)),
332
- longTaskTotalDuration: round(longTaskTotalDuration),
333
- counts: {
334
- layoutShifts: entries.layoutShifts.length,
335
- longAnimationFrames: entries.longAnimationFrames.length,
336
- events: entries.events.length,
337
- longTasks: entries.longTasks.length,
338
- paints: entries.paints.length,
339
- },
340
- },
341
- entries,
342
- };
343
- })()`,i=await T.evaluateScript(n,r);return i.exceptionDetails?{error:i.exceptionDetails.exception?.description||i.exceptionDetails.text||`Performance audit failed`}:i.result?.value??{error:`Performance audit returned no data`}}catch(e){let t=e instanceof Error?e.message:`Performance audit failed`;return t.includes(`Cannot access`)||t.includes(`Cannot attach`)?{error:`Cannot execute performance audit on this page (restricted URL)`}:{error:t}}}case`READ_CONSOLE_MESSAGES`:{if(!n)throw Error(`No tabId provided`);try{await T.enableConsoleTracking(n)}catch{}let t=T.getConsoleMessages(n,{onlyErrors:e.onlyErrors,pattern:e.pattern,limit:e.limit||100});return e.clear&&T.clearConsoleMessages(n),{messages:t}}case`CLEAR_CONSOLE_MESSAGES`:if(!n)throw Error(`No tabId provided`);return T.clearConsoleMessages(n),{success:!0};case`READ_NETWORK_REQUESTS`:{if(!n)throw Error(`No tabId provided`);try{await T.enableNetworkTracking(n)}catch{}if(e.full){let t=T.getNetworkEntries(n,{urlPattern:e.urlPattern});e.method&&(t=t.filter(t=>t.method===e.method)),e.status&&(t=t.filter(t=>t.status===e.status)),e.contentType&&(t=t.filter(t=>t.type===e.contentType)),e.clear&&T.clearNetworkRequests(n);let r=e.limit||100;return{entries:t.slice(0,r),format:e.format,verbose:e.verbose}}let t=T.getNetworkRequests(n,{urlPattern:e.urlPattern,limit:e.limit||100});return e.method&&(t=t.filter(t=>t.method===e.method)),e.status&&(t=t.filter(t=>t.status===e.status)),e.contentType&&(t=t.filter(t=>t.type===e.contentType)),e.clear&&T.clearNetworkRequests(n),{requests:t,format:e.format,verbose:e.verbose}}case`EXPORT_NETWORK_REQUESTS`:{if(!n)throw Error(`No tabId provided`);if(e.har&&e.jsonl)throw Error(`network export cannot combine HAR and JSONL`);try{await T.enableNetworkTracking(n)}catch{}let t=T.getNetworkEntries(n,{});if(new TextEncoder().encode(JSON.stringify(t)).byteLength>16*1024*1024)throw Error(`network export source exceeds the 16 MiB native-message limit`);return{entries:t,har:!!e.har,jsonl:!!e.jsonl}}case`CLEAR_NETWORK_REQUESTS`:if(!n)throw Error(`No tabId provided`);return T.clearNetworkRequests(n),{success:!0};case`GET_NETWORK_ENTRIES`:{if(!n)throw Error(`No tabId provided`);try{await T.enableNetworkTracking(n)}catch{}let t=T.getNetworkEntries(n,{urlPattern:e.urlPattern,includeStatic:!e.excludeStatic});return e.origin&&(t=t.filter(t=>t.origin===e.origin)),e.method&&(t=t.filter(t=>t.method===e.method)),e.status&&(t=t.filter(t=>t.status===e.status)),e.type&&(t=t.filter(t=>t.type===e.type)),e.since&&(t=t.filter(t=>t.ts>=e.since)),e.hasBody!==void 0&&(t=t.filter(t=>e.hasBody?t.responseBodySize&&t.responseBodySize>0:!t.responseBodySize)),e.last&&(t=t.slice(-e.last)),e.clear&&T.clearNetworkRequests(n),{entries:t}}case`GET_NETWORK_ENTRY`:{if(!n)throw Error(`No tabId provided`);if(!e.requestId)throw Error(`No requestId provided`);let t=T.getNetworkEntry(n,e.requestId);return t||=T.getNetworkEntries(n,{}).find(t=>t.id===e.requestId)||null,t||=T.getNetworkEntries(n,{}).find(t=>t._requestId===e.requestId)||null,t?{entry:t}:{error:`Entry not found: ${e.requestId}`}}case`GET_RESPONSE_BODY`:{if(!n)throw Error(`No tabId provided`);if(!e.requestId)throw Error(`No requestId provided`);let t=e.requestId;if(e.requestId.startsWith(`r_`)){let r=T.getNetworkEntries(n,{}).find(t=>t.id===e.requestId);r&&(t=r._requestId)}return await T.getResponseBody(n,t)}case`GET_NETWORK_ORIGINS`:{if(!n)throw Error(`No tabId provided`);let e=T.getNetworkEntries(n,{}),t={};for(let n of e)t[n.origin]||(t[n.origin]={count:0,lastSeen:0,size:0}),t[n.origin].count++,t[n.origin].lastSeen=Math.max(t[n.origin].lastSeen,n.ts),t[n.origin].size+=n.responseBodySize||0;return{origins:t}}case`GET_NETWORK_STATS`:{if(!n)throw Error(`No tabId provided`);let e=T.getNetworkEntries(n,{}),t={},r={},i={},a=0,o=1/0,s=0;for(let n of e){t[n.origin]||(t[n.origin]=0),t[n.origin]++;let e=n.method||`GET`;if(r[e]=(r[e]||0)+1,n.status){let e=`${Math.floor(n.status/100)}xx`;i[e]=(i[e]||0)+1}a+=n.responseBodySize||0,n.ts<o&&(o=n.ts),n.ts>s&&(s=n.ts)}return{stats:{totalRequests:e.length,totalSize:a,uniqueOrigins:Object.keys(t).length,startTime:o===1/0?null:o,duration:s&&o!==1/0?s-o:0,byMethod:r,byStatus:i}}}case`RESIZE_WINDOW`:{if(!n)throw Error(`No tabId provided`);if(e.width===void 0&&e.height===void 0)throw Error(`width or height required`);let t=await chrome.tabs.get(n);if(!t.windowId)throw Error(`Tab has no window`);let r=e.width===void 0||e.height===void 0?await chrome.windows.get(t.windowId):null,i=e.width===void 0?r?.width:e.width,a=e.height===void 0?r?.height:e.height;if(i===void 0||a===void 0)throw Error(`current window size unavailable`);return await chrome.windows.update(t.windowId,{width:Math.floor(i),height:Math.floor(a)}),{success:!0,width:i,height:a}}case`TABS_CREATE`:{let t=n?await chrome.tabs.get(n):null,r=await chrome.tabs.create({url:e.url||`about:blank`,active:!1});if(!r.id)throw Error(`Failed to create tab`);return t?.groupId&&t.groupId!==chrome.tabGroups.TAB_GROUP_ID_NONE&&await chrome.tabs.group({tabIds:r.id,groupId:t.groupId}),{success:!0,tabId:r.id,url:r.url||e.url||`about:blank`}}case`UPLOAD_IMAGE`:{if(!n)throw Error(`No tabId provided`);if(!e.screenshotId)throw Error(`screenshotId required`);if(!e.ref&&!e.coordinate)throw Error(`ref or coordinate required`);let t=P(e.screenshotId);if(!t)throw Error(`Screenshot not found: ${e.screenshotId}`);try{return await chrome.tabs.sendMessage(n,{type:`UPLOAD_IMAGE`,base64:t.base64,ref:e.ref,coordinate:e.coordinate,filename:e.filename||`screenshot.png`},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}}case`GET_TABS`:return{tabs:(await chrome.tabs.query({})).map(e=>({id:e.id,title:e.title,url:e.url}))};case`LIST_TABS`:{let t={};return e.windowId&&(t.windowId=e.windowId),{tabs:(await chrome.tabs.query(t)).map(e=>({id:e.id,title:e.title,url:e.url,active:e.active,windowId:e.windowId}))}}case`NEW_TAB`:{let t=e.urls||(e.url?[e.url]:[`about:blank`]),n=[];for(let r=0;r<t.length;r++){let i={url:t[r],active:r===0};e.windowId&&(i.windowId=e.windowId);let a=await chrome.tabs.create(i);a.id&&n.push({tabId:a.id,url:t[r]})}return n.length===1?{success:!0,tabId:n[0].tabId,url:n[0].url}:{success:!0,tabs:n}}case`SWITCH_TAB`:{let t=e.tabId;if(!t)throw Error(`No tabId provided`);let n=await chrome.tabs.update(t,{active:!0});return n.windowId&&await chrome.windows.update(n.windowId,{focused:!0}),{success:!0,tabId:t,url:n.url,title:n.title}}case`CLOSE_TAB`:{let t=e.tabIds||(e.tabId?[e.tabId]:[]);if(t.length===0)throw Error(`No tabId(s) provided`);return await chrome.tabs.remove(t),t.length===1?{success:!0,tabId:t[0]}:{success:!0,closed:t}}case`TAB_MOVE`:{let t=e.tabIds||(e.tabId?[e.tabId]:[]),n=(Array.isArray(t)?t:String(t).split(`,`)).map(e=>Number(e));if(n.length===0)throw Error(`No tabId(s) provided`);if(n.some(e=>!Number.isInteger(e)||e<=0))throw Error(`Invalid tabId(s)`);let r=Number(e.windowId);if(!Number.isInteger(r)||r<=0)throw Error(`No destination windowId provided`);let i=e.index===void 0?-1:Number(e.index);if(!Number.isInteger(i)||i<-1)throw Error(`Invalid tab index`);let a={windowId:r,index:i},o=n.length===1?await chrome.tabs.move(n[0],a):await chrome.tabs.move(n,a);return{success:!0,moved:n,destinationWindowId:r,index:i,tabs:Array.isArray(o)?o:[o]}}case`TABS_REGISTER`:{let t=n;if(!t){let n=e.windowId?{active:!0,windowId:e.windowId}:{active:!0,lastFocusedWindow:!0},[r]=await chrome.tabs.query(n);if(r&&!k(r.url))t=r.id;else throw Error(`Cannot register a restricted browser or extension page. Focus a regular web page, or pass an explicit tabId.`)}if(!t)throw Error(`No active tab found`);if(!e.name)throw Error(`No name provided`);return J.set(e.name,t),{success:!0,name:e.name,tabId:t}}case`TABS_GET_BY_NAME`:{if(!e.name)throw Error(`No name provided`);let t=J.get(e.name);if(!t)return{error:`No tab registered with name "${e.name}"`};try{let e=await chrome.tabs.get(t);return{tabId:t,url:e.url,title:e.title}}catch{return J.delete(e.name),{error:`Tab "${e.name}" no longer exists`}}}case`TABS_LIST_NAMED`:{let e=[];for(let[t,n]of J)try{let r=await chrome.tabs.get(n);e.push({name:t,tabId:n,url:r.url,title:r.title})}catch{J.delete(t)}return{tabs:e}}case`TABS_UNREGISTER`:if(!e.name)throw Error(`No name provided`);return J.delete(e.name)?{success:!0}:{success:!1,error:`No tab registered with name "${e.name}"`};case`GET_AUTH`:{let{sendToNativeHost:e}=await w(async()=>{let{sendToNativeHost:e}=await Promise.resolve().then(()=>d);return{sendToNativeHost:e}},void 0);try{return await e({type:`GET_AUTH`})}catch{return{auth:null,hint:`Native host not connected. Make sure surf native host is installed.`}}}case`NATIVE_API_REQUEST`:{let{sendToNativeHost:t}=await w(async()=>{let{sendToNativeHost:e}=await Promise.resolve().then(()=>d);return{sendToNativeHost:e}},void 0);try{return await t({type:`API_REQUEST`,streamId:e.streamId,url:e.url,method:e.method,headers:e.headers,body:e.body}),{sent:!0}}catch(e){return{error:e instanceof Error?e.message:`Unknown error`}}}case`STREAM_CONSOLE`:{if(!n)throw Error(`No tabId provided`);let t=e.streamId;try{return await T.enableConsoleTracking(n),E.set(t,n),T.subscribeToConsole(n,t,e=>{y({type:`STREAM_EVENT`,streamId:t,event:{type:`console_event`,level:e.type===`exception`?`error`:e.type,text:e.text,timestamp:e.timestamp,url:e.url,line:e.line}})}),{success:!0,streaming:!0}}catch(e){return y({type:`STREAM_ERROR`,streamId:t,error:e instanceof Error?e.message:`Failed to start console stream`}),{error:e instanceof Error?e.message:`Failed to start console stream`}}}case`STREAM_NETWORK`:{if(!n)throw Error(`No tabId provided`);let t=e.streamId;try{return await T.enableNetworkTracking(n),E.set(t,n),T.subscribeToNetwork(n,t,e=>{y({type:`STREAM_EVENT`,streamId:t,event:{type:`network_event`,method:e.method,url:e.url,status:e.status,duration:e.duration,timestamp:e.timestamp}})}),{success:!0,streaming:!0}}catch(e){return y({type:`STREAM_ERROR`,streamId:t,error:e instanceof Error?e.message:`Failed to start network stream`}),{error:e instanceof Error?e.message:`Failed to start network stream`}}}case`STREAM_STOP`:{let t=e.streamId,n=E.get(t);return n!==void 0&&(T.unsubscribeFromConsole(n,t),T.unsubscribeFromNetwork(n,t),E.delete(t)),{success:!0}}case`SEARCH_PAGE`:if(!n)throw Error(`No tabId provided`);if(!e.term)throw Error(`Search term required`);try{return await chrome.tabs.sendMessage(n,{type:`SEARCH_PAGE`,term:e.term,caseSensitive:e.caseSensitive||!1,limit:e.limit||10},{frameId:O(n)})}catch{return{error:`Content script not loaded. Try refreshing the page.`}}case`TAB_GROUP_CREATE`:{let t=[...e.tabIds||[]],r=e.name||`Surf`,i=[`grey`,`blue`,`red`,`yellow`,`green`,`pink`,`purple`,`cyan`,`orange`].includes(e.color)?e.color:`blue`;if(t.length===0&&n&&t.push(n),t.length===0)throw Error(`No tabs specified`);let a=t.length===1?t[0]:t,o=await chrome.tabGroups.query({title:r}),s;return o.length>0?(s=o[0].id,await chrome.tabs.group({tabIds:a,groupId:s})):(s=await chrome.tabs.group({tabIds:a}),await chrome.tabGroups.update(s,{title:r,color:i,collapsed:!1})),{success:!0,groupId:s,name:r,tabIds:t}}case`TAB_GROUP_REMOVE`:{let t=[...e.tabIds||[]];if(t.length===0&&n&&t.push(n),t.length===0)throw Error(`No tabs specified`);let r=t.length===1?t[0]:t;return await chrome.tabs.ungroup(r),{success:!0,ungrouped:t}}case`TAB_GROUPS_LIST`:{let e=await chrome.tabGroups.query({}),t=[];for(let n of e){let e=await chrome.tabs.query({groupId:n.id});t.push({id:n.id,name:n.title||`(unnamed)`,color:n.color,collapsed:n.collapsed,tabs:e.map(e=>({id:e.id,title:e.title,url:e.url}))})}return{groups:t}}case`CLICK_SELECTOR`:{if(!n)throw Error(`No tabId provided`);let t=e.selector,r=e.index||0,i=`(() => {
344
- const elements = document.querySelectorAll(${JSON.stringify(t)});
143
+ })()`)).result?.value||{error:"Failed to get page state"}}case"EXECUTE_SCROLL":{if(!t)throw new Error("No tabId provided");const e=o.deltaX||0,r=o.deltaY||0,n=(s,a)=>{const c={x:window.scrollX,y:window.scrollY};window.scrollBy(s,a);const u={x:window.scrollX,y:window.scrollY};return{scrollX:u.x,scrollY:u.y,scrolled:c.x!==u.x||c.y!==u.y}};try{return(await l.evaluateScript(t,`(${n.toString()})(${e}, ${r})`)).result?.value||{error:"Script failed"}}catch{try{return(await chrome.scripting.executeScript({target:{tabId:t},func:n,args:[e,r]}))[0]?.result||{error:"Script failed"}}catch{return{error:"Cannot scroll on this page (restricted)"}}}}case"EXECUTE_KEY":{if(!t)throw new Error("No tabId provided");const e=o.key;if(!e)throw new Error("No key provided");return e.includes("+")?await l.pressKeyChord(t,e):await l.pressKey(t,e),{success:!0}}case"EXECUTE_NAVIGATE":{if(!t)throw new Error("No tabId provided");if(!o.url)throw new Error("No url provided");const e=new Promise(r=>{k.set(t,r),setTimeout(()=>{k.has(t)&&(k.delete(t),r())},3e4)});return await chrome.tabs.update(t,{url:o.url}),await e,await new Promise(r=>setTimeout(r,500)),{success:!0}}case"GET_VIEWPORT_SIZE":{if(!t)throw new Error("No tabId provided");return await l.getViewportSize(t)}case"READ_PAGE":{if(!t)throw new Error("No tabId provided");const e=b(t);try{await chrome.tabs.sendMessage(t,{type:"HIDE_FOR_TOOL_USE"},{frameId:0})}catch{}await new Promise(n=>setTimeout(n,50));let r;try{r=await chrome.tabs.sendMessage(t,{type:"GENERATE_ACCESSIBILITY_TREE",options:o.options||{}},{frameId:e})}catch{return{error:"Content script not loaded. Try refreshing the page.",pageContent:"",viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(t,{type:"SHOW_AFTER_TOOL_USE"})}catch{}}if(o.options?.includeText)try{const n=await chrome.tabs.sendMessage(t,{type:"GET_PAGE_TEXT"},{frameId:e});n?.text&&(r.text=n.text)}catch{}if(o.options?.includeScreenshot)try{const n=await l.captureScreenshot(t);return{...r,screenshot:n}}catch{return{...r,screenshotError:"Failed to capture screenshot"}}return r}case"GET_ELEMENT_COORDINATES":{if(!t)throw new Error("No tabId provided");try{return await chrome.tabs.sendMessage(t,{type:"GET_ELEMENT_COORDINATES",ref:o.ref},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"FORM_INPUT":{if(!t)throw new Error("No tabId provided");try{return await chrome.tabs.sendMessage(t,{type:"FORM_INPUT",ref:o.ref,value:o.value},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"EVAL_IN_PAGE":{if(!t)throw new Error("No tabId provided");if(!o.code)throw new Error("No code provided");try{return await chrome.tabs.sendMessage(t,{type:"EVAL_IN_PAGE",code:o.code},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"SCROLL_TO_ELEMENT":{if(!t)throw new Error("No tabId provided");try{return await chrome.tabs.sendMessage(t,{type:"SCROLL_TO_ELEMENT",ref:o.ref},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"SCROLL_TO_POSITION":{if(!t)throw new Error("No tabId provided");const e=o.position;if(e===void 0)throw new Error('position required ("top", "bottom", or number)');const r=o.selector,n=(s,a)=>{const c=()=>[...document.querySelectorAll("*")].filter(h=>h.scrollHeight>h.clientHeight&&h.clientHeight>200).sort((h,f)=>f.scrollHeight-h.scrollHeight)[0]||document.documentElement,u=a&&document.querySelector(a)||c();return u?(s==="bottom"?u.scrollTop=u.scrollHeight:s==="top"?u.scrollTop=0:typeof s=="number"&&(u.scrollTop=s),{scrollTop:u.scrollTop,scrollHeight:u.scrollHeight,clientHeight:u.clientHeight,atBottom:u.scrollTop+u.clientHeight>=u.scrollHeight-10,atTop:u.scrollTop<10}):{error:"No scrollable container found"}};try{const s=`(${n.toString()})(${JSON.stringify(e)}, ${JSON.stringify(r)})`;return(await l.evaluateScript(t,s)).result?.value||{error:"Script failed"}}catch{try{return(await chrome.scripting.executeScript({target:{tabId:t},func:n,args:[e,r]}))[0]?.result||{error:"Script failed"}}catch{return{error:"Cannot scroll on this page (restricted)"}}}}case"GET_SCROLL_INFO":{if(!t)throw new Error("No tabId provided");const e=o.selector,r=n=>{const s=()=>[...document.querySelectorAll("*")].filter(d=>d.scrollHeight>d.clientHeight&&d.clientHeight>200).sort((d,h)=>h.scrollHeight-d.scrollHeight)[0]||document.documentElement,a=n&&document.querySelector(n)||s();if(!a)return{error:"No scrollable container found"};const c=a.scrollHeight-a.clientHeight;return{scrollTop:a.scrollTop,scrollHeight:a.scrollHeight,clientHeight:a.clientHeight,atBottom:a.scrollTop+a.clientHeight>=a.scrollHeight-10,atTop:a.scrollTop<10,scrollPercentage:c>0?Math.round(a.scrollTop/c*100):100}};try{const n=`(${r.toString()})(${JSON.stringify(e)})`;return(await l.evaluateScript(t,n)).result?.value||{error:"Script failed"}}catch{try{return(await chrome.scripting.executeScript({target:{tabId:t},func:r,args:[e]}))[0]?.result||{error:"Script failed"}}catch{return{error:"Cannot get scroll info on this page (restricted)"}}}}case"GET_PAGE_TEXT":{if(!t)throw new Error("No tabId provided");try{return await chrome.tabs.sendMessage(t,{type:"GET_PAGE_TEXT"},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"LOCATE_ROLE":{if(!t)throw new Error("No tabId provided");if(!o.role)throw new Error("role required");const e=b(t);try{const r=await chrome.tabs.sendMessage(t,{type:"LOCATE_ROLE",role:o.role,name:o.name,all:o.all},{frameId:e});return r.error?r:o.action&&r.ref?await G(t,r.ref,o.action,o.value,l,e):r}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"LOCATE_TEXT":{if(!t)throw new Error("No tabId provided");if(!o.text)throw new Error("text required");const e=b(t);try{const r=await chrome.tabs.sendMessage(t,{type:"LOCATE_TEXT",text:o.text,exact:o.exact},{frameId:e});return r.error?r:o.action&&r.ref?await G(t,r.ref,o.action,o.value,l,e):r}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"LOCATE_LABEL":{if(!t)throw new Error("No tabId provided");if(!o.label)throw new Error("label required");const e=b(t);try{const r=await chrome.tabs.sendMessage(t,{type:"LOCATE_LABEL",label:o.label},{frameId:e});return r.error?r:o.action&&r.ref?await G(t,r.ref,o.action,o.value,l,e):r}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"GET_ELEMENT_STYLES":{if(!t)throw new Error("No tabId provided");if(!o.selector)throw new Error("selector required");const e=b(t);try{return await chrome.tabs.sendMessage(t,{type:"GET_ELEMENT_STYLES",selector:o.selector},{frameId:e})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"SELECT_OPTION":{if(!t)throw new Error("No tabId provided");if(!o.selector)throw new Error("selector required");if(!o.values)throw new Error("values required");const e=b(t);try{return await chrome.tabs.sendMessage(t,{type:"SELECT_OPTION",selector:o.selector,values:o.values,by:o.by||"value"},{frameId:e})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"SHOW_AGENT_INDICATORS":case"HIDE_AGENT_INDICATORS":case"SHOW_STATIC_INDICATOR":case"HIDE_STATIC_INDICATOR":{if(!t)throw new Error("No tabId provided");try{return await chrome.tabs.sendMessage(t,{type:o.type})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"STOP_AGENT":{const e=o.fromTabId;let r;return e==="CURRENT_TAB"&&i.tab?.id?r=i.tab.id:typeof e=="number"&&(r=e),r&&chrome.runtime.sendMessage({type:"STOP_AGENT",targetTabId:r}),{success:!0}}case"DISMISS_STATIC_INDICATOR":return{success:!0};case"STATIC_INDICATOR_HEARTBEAT":return{success:!0};case"CLICK_REF":{if(!t)throw new Error("No tabId provided");try{const e=await chrome.tabs.sendMessage(t,{type:"CLICK_ELEMENT",ref:o.ref,button:o.button||"left"},{frameId:b(t)});return e.error?{error:e.error}:{success:!0}}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"HOVER_REF":{if(!t)throw new Error("No tabId provided");try{const e=await chrome.tabs.sendMessage(t,{type:"GET_ELEMENT_COORDINATES",ref:o.ref},{frameId:b(t)});return e.error?{error:e.error}:(await l.hover(t,e.x,e.y),{success:!0})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"PING":return{success:!0,status:"connected"};case"HEALTH_CHECK_URL":{if(!o.url)throw new Error("No url provided");const e=o.timeout||3e4,r=o.expect||200,n=Date.now(),s=500;let a=null;for(;Date.now()-n<e;){try{const c=await fetch(o.url,{method:"GET"});if(await c.text(),c.status===r)return{success:!0,status:c.status,time:Date.now()-n};a=`Got status ${c.status}`}catch(c){a=c instanceof Error?c.message:String(c)}await new Promise(c=>setTimeout(c,s))}return{error:`Timeout waiting for ${o.url} to return ${r}`,lastError:a,time:Date.now()-n}}case"SMOKE_TEST":{const e=o.urls||[],r=o.savePath!==void 0,n=o.failFast||!1;if(e.length===0)return{error:"No URLs provided for smoke test"};const s=[];let a=0,c=0;for(const u of e){const d=Date.now(),h=[];let f,w,p;try{w=new URL(u).hostname.replace(/[^a-zA-Z0-9.-]/g,"_");const S=await chrome.tabs.create({url:u,active:!1});if(!S.id)throw new Error("Failed to create tab");p=S.id;try{await l.enableConsoleTracking(p)}catch{}await new Promise(m=>{const y=T=>{T.tabId===p&&T.frameId===0&&(chrome.webNavigation.onCompleted.removeListener(y),chrome.webNavigation.onErrorOccurred.removeListener(g),m())},g=T=>{T.tabId===p&&T.frameId===0&&(chrome.webNavigation.onCompleted.removeListener(y),chrome.webNavigation.onErrorOccurred.removeListener(g),h.push(`Navigation error: ${T.error}`),m())};chrome.webNavigation.onCompleted.addListener(y),chrome.webNavigation.onErrorOccurred.addListener(g),setTimeout(()=>{chrome.webNavigation.onCompleted.removeListener(y),chrome.webNavigation.onErrorOccurred.removeListener(g),h.push("Navigation timeout (30s)"),m()},3e4)}),await new Promise(m=>setTimeout(m,2e3));const N=l.getConsoleMessages(p,{onlyErrors:!0,limit:50});for(const m of N)h.push(`[${m.type}] ${m.text}`);if(r)try{f=(await l.captureScreenshot(p)).base64}catch{}}catch(S){h.push(S instanceof Error?S.message:String(S))}finally{if(p)try{await chrome.tabs.remove(p)}catch{}}const E=Date.now()-d,_=h.length===0?"pass":"fail";if(_==="pass"?a++:c++,s.push({url:u,status:_,time:E,errors:h,...f&&{screenshotBase64:f,hostname:w}}),n&&_==="fail")break}return{results:s,summary:{pass:a,fail:c,total:s.length},savePath:o.savePath}}case"WAIT_FOR_ELEMENT":{if(!t)throw new Error("No tabId provided");if(!o.selector)throw new Error("No selector provided");const e=b(t);try{await chrome.tabs.sendMessage(t,{type:"HIDE_FOR_TOOL_USE"},{frameId:0})}catch{}await new Promise(r=>setTimeout(r,50));try{return await chrome.tabs.sendMessage(t,{type:"WAIT_FOR_ELEMENT",selector:o.selector,state:o.state||"visible",timeout:o.timeout||2e4},{frameId:e})}catch{return{error:"Content script not loaded. Try refreshing the page.",pageContent:"",viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(t,{type:"SHOW_AFTER_TOOL_USE"})}catch{}}}case"WAIT_FOR_URL":{if(!t)throw new Error("No tabId provided");if(!o.pattern)throw new Error("No URL pattern provided");try{await chrome.tabs.sendMessage(t,{type:"HIDE_FOR_TOOL_USE"},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(t,{type:"WAIT_FOR_URL",pattern:o.pattern,timeout:o.timeout||2e4},{frameId:0})}catch{return{error:"Content script not loaded. Try refreshing the page.",pageContent:"",viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(t,{type:"SHOW_AFTER_TOOL_USE"})}catch{}}}case"WAIT_FOR_NETWORK_IDLE":{if(!t)throw new Error("No tabId provided");try{await chrome.tabs.sendMessage(t,{type:"HIDE_FOR_TOOL_USE"},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(t,{type:"WAIT_FOR_NETWORK_IDLE",timeout:o.timeout||1e4},{frameId:0})}catch{return{error:"Content script not loaded. Try refreshing the page.",pageContent:"",viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(t,{type:"SHOW_AFTER_TOOL_USE"})}catch{}}}case"WAIT_FOR_DOM_STABLE":{if(!t)throw new Error("No tabId provided");try{await chrome.tabs.sendMessage(t,{type:"HIDE_FOR_TOOL_USE"},{frameId:0})}catch{}await new Promise(e=>setTimeout(e,50));try{return await chrome.tabs.sendMessage(t,{type:"WAIT_FOR_DOM_STABLE",stable:o.stable||100,timeout:o.timeout||5e3},{frameId:0})}catch{return{error:"Content script not loaded. Try refreshing the page.",pageContent:"",viewport:{width:0,height:0}}}finally{try{await chrome.tabs.sendMessage(t,{type:"SHOW_AFTER_TOOL_USE"},{frameId:0})}catch{}}}case"DIALOG_ACCEPT":{if(!t)throw new Error("No tabId provided");return await l.handleDialog(t,!0,o.text)}case"DIALOG_DISMISS":{if(!t)throw new Error("No tabId provided");return await l.handleDialog(t,!1)}case"DIALOG_INFO":{if(!t)throw new Error("No tabId provided");const e=l.getDialogInfo(t);return e?{hasDialog:!0,type:e.type,message:e.message,defaultPrompt:e.defaultPrompt}:{hasDialog:!1}}case"EMULATE_NETWORK":{if(!t)throw new Error("No tabId provided");if(!o.preset)throw new Error("No preset provided");const e=await l.emulateNetwork(t,o.preset);if(!e.success)throw new Error(e.error);return{success:!0,preset:o.preset}}case"EMULATE_CPU":{if(!t)throw new Error("No tabId provided");if(o.rate===void 0)throw new Error("No rate provided");const e=await l.emulateCPU(t,o.rate);if(!e.success)throw new Error(e.error);return{success:!0,rate:o.rate}}case"EMULATE_GEO":{if(!t)throw new Error("No tabId provided");if(o.clear){const r=await l.clearGeolocation(t);if(!r.success)throw new Error(r.error);return{success:!0,cleared:!0}}if(o.latitude===void 0||o.longitude===void 0)throw new Error("Latitude and longitude required");const e=await l.emulateGeolocation(t,o.latitude,o.longitude,o.accuracy);if(!e.success)throw new Error(e.error);return{success:!0,latitude:o.latitude,longitude:o.longitude}}case"EMULATE_DEVICE_LIST":return{devices:["iPhone 12","iPhone 13","iPhone 14","iPhone 14 Pro","iPhone 14 Pro Max","iPhone SE","iPad","iPad Pro","iPad Mini","Pixel 5","Pixel 6","Pixel 7","Pixel 7 Pro","Galaxy S21","Galaxy S22","Galaxy S23","Galaxy Tab S7","Nest Hub","Nest Hub Max"]};case"EMULATE_DEVICE":{if(!t)throw new Error("No tabId provided");const e=o.device;if(e.toLowerCase()==="reset"){const a=await l.clearDeviceEmulation(t);if(!a.success)throw new Error(a.error);return{success:!0,message:"Device emulation reset"}}const r={"iPhone 12":{width:390,height:844,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"},"iPhone 13":{width:390,height:844,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1"},"iPhone 14":{width:390,height:844,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"},"iPhone 14 Pro":{width:393,height:852,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"},"iPhone 14 Pro Max":{width:430,height:932,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"},"iPhone SE":{width:375,height:667,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1"},iPad:{width:768,height:1024,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"},"iPad Pro":{width:1024,height:1366,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"},"iPad Mini":{width:768,height:1024,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"},"Pixel 5":{width:393,height:851,deviceScaleFactor:2.75,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36"},"Pixel 6":{width:412,height:915,deviceScaleFactor:2.625,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36"},"Pixel 7":{width:412,height:915,deviceScaleFactor:2.625,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36"},"Pixel 7 Pro":{width:412,height:892,deviceScaleFactor:3.5,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36"},"Galaxy S21":{width:360,height:800,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 11; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36"},"Galaxy S22":{width:360,height:780,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 12; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36"},"Galaxy S23":{width:360,height:780,deviceScaleFactor:3,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Mobile Safari/537.36"},"Galaxy Tab S7":{width:800,height:1280,deviceScaleFactor:2,mobile:!0,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android 10; SM-T870) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Safari/537.36"},"Nest Hub":{width:1024,height:600,deviceScaleFactor:2,mobile:!1,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.109 Safari/537.36 CrKey/1.54.248666"},"Nest Hub Max":{width:1280,height:800,deviceScaleFactor:2,mobile:!1,touch:!0,userAgent:"Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.109 Safari/537.36 CrKey/1.54.248666"}};let n=r[e];if(!n){const a=e.toLowerCase();let c=null;for(const[u,d]of Object.entries(r)){const h=u.toLowerCase(),f=h.replace(/\s+/g,"");(h.includes(a)||a.includes(f))&&(!c||u.length>c.name.length)&&(c={name:u,preset:d})}c&&(n=c.preset)}if(!n)throw new Error(`Unknown device: ${e}. Use --list to see available devices.`);const s=await l.emulateDevice(t,n);if(!s.success)throw new Error(s.error);return{success:!0,device:e}}case"EMULATE_VIEWPORT":{if(!t)throw new Error("No tabId provided");if(!o.width&&!o.height)throw new Error("--width or --height required");const e=await l.emulateViewport(t,{width:o.width,height:o.height,deviceScaleFactor:o.deviceScaleFactor,mobile:o.mobile});if(!e.success)throw new Error(e.error);return{success:!0,width:o.width,height:o.height}}case"EMULATE_TOUCH":{if(!t)throw new Error("No tabId provided");const e=await l.emulateTouch(t,o.enabled);if(!e.success)throw new Error(e.error);return{success:!0,enabled:o.enabled}}case"FORM_FILL":{if(!t)throw new Error("No tabId provided");if(!o.data)throw new Error("No data provided");return await chrome.tabs.sendMessage(t,{type:"FORM_FILL",data:o.data},{frameId:b(t)})}case"PERF_START":{if(!t)throw new Error("No tabId provided");const e=await l.startPerformanceTrace(t,o.categories);if(!e.success)throw new Error(e.error);return{success:!0,message:"Performance tracing started"}}case"PERF_STOP":{if(!t)throw new Error("No tabId provided");const e=await l.stopPerformanceTrace(t);if(!e.success)throw new Error(e.error);return{success:!0,metrics:e.metrics}}case"PERF_METRICS":{if(!t)throw new Error("No tabId provided");const e=await l.getPerformanceMetrics(t);if(!e.success)throw new Error(e.error);return{success:!0,metrics:e.metrics}}case"UPLOAD_FILE":{if(!t)throw new Error("No tabId provided");if(!o.ref)throw new Error("No ref provided");if(!o.files||!o.files.length)throw new Error("No files provided");const e=await chrome.tabs.sendMessage(t,{type:"GET_FILE_INPUT_SELECTOR",ref:o.ref},{frameId:b(t)});if(e.error)throw new Error(e.error);const r=await l.setFileInputBySelector(t,e.selector,o.files);if(!r.success)throw new Error(r.error);return{success:!0,filesSet:o.files.length}}case"WAIT_FOR_LOAD":{if(!t)throw new Error("No tabId provided");const e=await l.waitForLoad(t,o.timeout||3e4);if(!e.success)throw new Error(e.error);return{success:!0,readyState:e.readyState}}case"GET_FRAMES":{if(!t)throw new Error("No tabId provided");const e=await l.getFrames(t);if(!e.success)throw new Error(e.error);return{success:!0,frames:e.frames}}case"FRAME_SWITCH":{if(!t)throw new Error("No tabId provided");const{selector:e,name:r,index:n}=o;if(!e&&!r&&n===void 0)throw new Error("--selector, --name, or --index required");const s=await chrome.webNavigation.getAllFrames({tabId:t});if(!s||s.length===0)throw new Error("No frames found in tab");const a=s.filter(u=>u.frameId!==0);if(a.length===0)throw new Error("No iframes found on this page");let c=null;if(n!==void 0){if(n<0||n>=a.length)throw new Error(`Frame index ${n} out of range. Found ${a.length} frame(s).`);c=a[n]}else if(r){for(const u of a)try{if((await chrome.tabs.sendMessage(t,{type:"GET_FRAME_NAME"},{frameId:u.frameId}))?.name===r){c=u;break}}catch{}if(!c)throw new Error(`Frame with name "${r}" not found`)}else if(e)try{const u=await chrome.tabs.sendMessage(t,{type:"GET_FRAME_BY_SELECTOR",selector:e},{frameId:0});if(u?.error)throw new Error(u.error);u?.url&&(c=a.find(d=>d.url===u.url)||null),!c&&a.length===1&&(c=a[0])}catch{throw new Error(`Could not find frame with selector "${e}"`)}if(!c)throw new Error("Frame not found");return F.set(t,c.frameId),{success:!0,frameId:c.frameId,url:c.url}}case"FRAME_MAIN":{if(!t)throw new Error("No tabId provided");return F.delete(t),{success:!0,message:"Returned to main frame"}}case"EVALUATE_IN_FRAME":{if(!t)throw new Error("No tabId provided");if(!o.frameId)throw new Error("No frameId provided");if(!o.code)throw new Error("No code provided");const e=await l.evaluateInFrame(t,o.frameId,o.code);if(!e.success)throw new Error(e.error);return{value:e.result}}case"EXECUTE_JAVASCRIPT":{if(!t)throw new Error("No tabId provided");if(!o.code)throw new Error("No code provided");try{await l.evaluateScript(t,"if(!window.piHelpers){const piHelpers={wait(ms){return new Promise(r=>setTimeout(r,ms))},async waitForSelector(sel,opts={}){const{state='visible',timeout=20000}=opts;const isVis=el=>el&&getComputedStyle(el).display!=='none'&&getComputedStyle(el).visibility!=='hidden'&&getComputedStyle(el).opacity!=='0'&&el.offsetWidth>0&&el.offsetHeight>0;const chk=()=>{const el=document.querySelector(sel);switch(state){case'attached':return el;case'detached':return el?null:document.body;case'hidden':return(!el||!isVis(el))?(el||document.body):null;default:return isVis(el)?el:null}};return new Promise((res,rej)=>{const r=chk();if(r){res(state==='detached'||state==='hidden'?null:r);return}const obs=new MutationObserver(()=>{const r=chk();if(r){obs.disconnect();clearTimeout(tid);res(state==='detached'||state==='hidden'?null:r)}});const tid=setTimeout(()=>{obs.disconnect();rej(new Error('Timeout'))},timeout);obs.observe(document.documentElement,{childList:true,subtree:true,attributes:true,attributeFilter:['style','class','hidden']})})},async waitForText(text,opts={}){const{selector,timeout=20000}=opts;const chk=()=>{const root=selector?document.querySelector(selector):document.body;if(!root)return null;const w=document.createTreeWalker(root,NodeFilter.SHOW_TEXT);while(w.nextNode())if(w.currentNode.textContent?.includes(text))return w.currentNode.parentElement;return null};return new Promise((res,rej)=>{const r=chk();if(r){res(r);return}const obs=new MutationObserver(()=>{const r=chk();if(r){obs.disconnect();clearTimeout(tid);res(r)}});const tid=setTimeout(()=>{obs.disconnect();rej(new Error('Timeout'))},timeout);obs.observe(document.documentElement,{childList:true,subtree:true,characterData:true})})},async waitForHidden(sel,t=20000){await piHelpers.waitForSelector(sel,{state:'hidden',timeout:t})},getByRole(role,opts={}){const{name}=opts;const roles={button:['button','input[type=button]','input[type=submit]','input[type=reset]'],link:['a[href]'],textbox:['input:not([type])','input[type=text]','input[type=email]','input[type=password]','textarea'],checkbox:['input[type=checkbox]'],radio:['input[type=radio]'],combobox:['select'],heading:['h1','h2','h3','h4','h5','h6']};const cands=[...document.querySelectorAll('[role='+role+']')];if(roles[role])roles[role].forEach(s=>cands.push(...document.querySelectorAll(s+':not([role])')));if(!name)return cands[0]||null;const n=name.toLowerCase().trim();for(const el of cands){const l=el.getAttribute('aria-label')?.toLowerCase().trim();const t=el.textContent?.toLowerCase().trim();if(l===n||t===n||l?.includes(n)||t?.includes(n))return el}return null}};window.__piHelpers=piHelpers;window.piHelpers=piHelpers}");const n=`(async () => { 'use strict'; ${o.code.replace(/`/g,"\\`").replace(/\$/g,"\\$")} })()`,s=await l.evaluateScript(t,n);if(s.exceptionDetails)return{error:s.exceptionDetails.exception?.description||s.exceptionDetails.text||"Script execution failed"};const a=s.result?.value;return{output:(a===void 0?"undefined":JSON.stringify(a,null,2))?.substring(0,5e4)||"undefined"}}catch(e){const r=e instanceof Error?e.message:"Script execution failed";return r.includes("Cannot access")||r.includes("Cannot attach")?{error:"Cannot execute JavaScript on this page (restricted URL)"}:{error:r}}}case"READ_CONSOLE_MESSAGES":{if(!t)throw new Error("No tabId provided");try{await l.enableConsoleTracking(t)}catch{}const e=l.getConsoleMessages(t,{onlyErrors:o.onlyErrors,pattern:o.pattern,limit:o.limit||100});return o.clear&&l.clearConsoleMessages(t),{messages:e}}case"CLEAR_CONSOLE_MESSAGES":{if(!t)throw new Error("No tabId provided");return l.clearConsoleMessages(t),{success:!0}}case"READ_NETWORK_REQUESTS":{if(!t)throw new Error("No tabId provided");try{await l.enableNetworkTracking(t)}catch{}if(o.full){let r=l.getNetworkEntries(t,{urlPattern:o.urlPattern});o.method&&(r=r.filter(s=>s.method===o.method)),o.status&&(r=r.filter(s=>s.status===o.status)),o.contentType&&(r=r.filter(s=>s.type===o.contentType)),o.clear&&l.clearNetworkRequests(t);const n=o.limit||100;return{entries:r.slice(0,n),format:o.format,verbose:o.verbose}}let e=l.getNetworkRequests(t,{urlPattern:o.urlPattern,limit:o.limit||100});return o.method&&(e=e.filter(r=>r.method===o.method)),o.status&&(e=e.filter(r=>r.status===o.status)),o.contentType&&(e=e.filter(r=>r.type===o.contentType)),o.clear&&l.clearNetworkRequests(t),{requests:e,format:o.format,verbose:o.verbose}}case"CLEAR_NETWORK_REQUESTS":{if(!t)throw new Error("No tabId provided");return l.clearNetworkRequests(t),{success:!0}}case"GET_NETWORK_ENTRIES":{if(!t)throw new Error("No tabId provided");try{await l.enableNetworkTracking(t)}catch{}let e=l.getNetworkEntries(t,{urlPattern:o.urlPattern,includeStatic:!o.excludeStatic});return o.origin&&(e=e.filter(r=>r.origin===o.origin)),o.method&&(e=e.filter(r=>r.method===o.method)),o.status&&(e=e.filter(r=>r.status===o.status)),o.type&&(e=e.filter(r=>r.type===o.type)),o.since&&(e=e.filter(r=>r.ts>=o.since)),o.hasBody!==void 0&&(e=e.filter(r=>o.hasBody?r.responseBodySize&&r.responseBodySize>0:!r.responseBodySize)),o.last&&(e=e.slice(-o.last)),o.clear&&l.clearNetworkRequests(t),{entries:e}}case"GET_NETWORK_ENTRY":{if(!t)throw new Error("No tabId provided");if(!o.requestId)throw new Error("No requestId provided");let e=l.getNetworkEntry(t,o.requestId);return e||(e=l.getNetworkEntries(t,{}).find(n=>n.id===o.requestId)||null),e||(e=l.getNetworkEntries(t,{}).find(n=>n._requestId===o.requestId)||null),e?{entry:e}:{error:`Entry not found: ${o.requestId}`}}case"GET_RESPONSE_BODY":{if(!t)throw new Error("No tabId provided");if(!o.requestId)throw new Error("No requestId provided");let e=o.requestId;if(o.requestId.startsWith("r_")){const s=l.getNetworkEntries(t,{}).find(a=>a.id===o.requestId);s&&(e=s._requestId)}return await l.getResponseBody(t,e)}case"GET_NETWORK_ORIGINS":{if(!t)throw new Error("No tabId provided");const e=l.getNetworkEntries(t,{}),r={};for(const n of e)r[n.origin]||(r[n.origin]={count:0,lastSeen:0,size:0}),r[n.origin].count++,r[n.origin].lastSeen=Math.max(r[n.origin].lastSeen,n.ts),r[n.origin].size+=n.responseBodySize||0;return{origins:r}}case"GET_NETWORK_STATS":{if(!t)throw new Error("No tabId provided");const e=l.getNetworkEntries(t,{}),r={},n={},s={};let a=0,c=1/0,u=0;for(const d of e){r[d.origin]||(r[d.origin]=0),r[d.origin]++;const h=d.method||"GET";if(n[h]=(n[h]||0)+1,d.status){const f=`${Math.floor(d.status/100)}xx`;s[f]=(s[f]||0)+1}a+=d.responseBodySize||0,d.ts<c&&(c=d.ts),d.ts>u&&(u=d.ts)}return{stats:{totalRequests:e.length,totalSize:a,uniqueOrigins:Object.keys(r).length,startTime:c===1/0?null:c,duration:u&&c!==1/0?u-c:0,byMethod:n,byStatus:s}}}case"RESIZE_WINDOW":{if(!t)throw new Error("No tabId provided");if(!o.width||!o.height)throw new Error("width and height required");const e=await chrome.tabs.get(t);if(!e.windowId)throw new Error("Tab has no window");return await chrome.windows.update(e.windowId,{width:Math.floor(o.width),height:Math.floor(o.height)}),{success:!0,width:o.width,height:o.height}}case"TABS_CREATE":{const e=t?await chrome.tabs.get(t):null,r=await chrome.tabs.create({url:o.url||"about:blank",active:!1});if(!r.id)throw new Error("Failed to create tab");return e?.groupId&&e.groupId!==chrome.tabGroups.TAB_GROUP_ID_NONE&&await chrome.tabs.group({tabIds:r.id,groupId:e.groupId}),{success:!0,tabId:r.id,url:r.url||o.url||"about:blank"}}case"UPLOAD_IMAGE":{if(!t)throw new Error("No tabId provided");if(!o.screenshotId)throw new Error("screenshotId required");if(!o.ref&&!o.coordinate)throw new Error("ref or coordinate required");const e=le(o.screenshotId);if(!e)throw new Error(`Screenshot not found: ${o.screenshotId}`);try{return await chrome.tabs.sendMessage(t,{type:"UPLOAD_IMAGE",base64:e.base64,ref:o.ref,coordinate:o.coordinate,filename:o.filename||"screenshot.png"},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"GET_TABS":return{tabs:(await chrome.tabs.query({})).map(r=>({id:r.id,title:r.title,url:r.url}))};case"LIST_TABS":{const e={};return o.windowId&&(e.windowId=o.windowId),{tabs:(await chrome.tabs.query(e)).map(n=>({id:n.id,title:n.title,url:n.url,active:n.active,windowId:n.windowId}))}}case"NEW_TAB":{const e=o.urls||(o.url?[o.url]:["about:blank"]),r=[];for(let n=0;n<e.length;n++){const s={url:e[n],active:n===0};o.windowId&&(s.windowId=o.windowId);const a=await chrome.tabs.create(s);a.id&&r.push({tabId:a.id,url:e[n]})}return r.length===1?{success:!0,tabId:r[0].tabId,url:r[0].url}:{success:!0,tabs:r}}case"SWITCH_TAB":{const e=o.tabId;if(!e)throw new Error("No tabId provided");const r=await chrome.tabs.update(e,{active:!0});return r.windowId&&await chrome.windows.update(r.windowId,{focused:!0}),{success:!0,tabId:e,url:r.url,title:r.title}}case"CLOSE_TAB":{const e=o.tabIds||(o.tabId?[o.tabId]:[]);if(e.length===0)throw new Error("No tabId(s) provided");return await chrome.tabs.remove(e),e.length===1?{success:!0,tabId:e[0]}:{success:!0,closed:e}}case"TABS_REGISTER":{if(!t)throw new Error("No tabId provided");if(!o.name)throw new Error("No name provided");return A.set(o.name,t),{success:!0,name:o.name,tabId:t}}case"TABS_GET_BY_NAME":{if(!o.name)throw new Error("No name provided");const e=A.get(o.name);if(!e)return{error:`No tab registered with name "${o.name}"`};try{const r=await chrome.tabs.get(e);return{tabId:e,url:r.url,title:r.title}}catch{return A.delete(o.name),{error:`Tab "${o.name}" no longer exists`}}}case"TABS_LIST_NAMED":{const e=[];for(const[r,n]of A)try{const s=await chrome.tabs.get(n);e.push({name:r,tabId:n,url:s.url,title:s.title})}catch{A.delete(r)}return{tabs:e}}case"TABS_UNREGISTER":{if(!o.name)throw new Error("No name provided");return A.delete(o.name)?{success:!0}:{success:!1,error:`No tab registered with name "${o.name}"`}}case"GET_AUTH":{const{sendToNativeHost:e}=await V(async()=>{const{sendToNativeHost:r}=await Promise.resolve().then(()=>X);return{sendToNativeHost:r}},void 0);try{return await e({type:"GET_AUTH"})}catch{return{auth:null,hint:"Native host not connected. Make sure surf native host is installed."}}}case"NATIVE_API_REQUEST":{const{sendToNativeHost:e}=await V(async()=>{const{sendToNativeHost:r}=await Promise.resolve().then(()=>X);return{sendToNativeHost:r}},void 0);try{return await e({type:"API_REQUEST",streamId:o.streamId,url:o.url,method:o.method,headers:o.headers,body:o.body}),{sent:!0}}catch(r){return{error:r instanceof Error?r.message:"Unknown error"}}}case"STREAM_CONSOLE":{if(!t)throw new Error("No tabId provided");const e=o.streamId;try{return await l.enableConsoleTracking(t),M.set(e,t),l.subscribeToConsole(t,e,r=>{x({type:"STREAM_EVENT",streamId:e,event:{type:"console_event",level:r.type==="exception"?"error":r.type,text:r.text,timestamp:r.timestamp,url:r.url,line:r.line}})}),{success:!0,streaming:!0}}catch(r){return x({type:"STREAM_ERROR",streamId:e,error:r instanceof Error?r.message:"Failed to start console stream"}),{error:r instanceof Error?r.message:"Failed to start console stream"}}}case"STREAM_NETWORK":{if(!t)throw new Error("No tabId provided");const e=o.streamId;try{return await l.enableNetworkTracking(t),M.set(e,t),l.subscribeToNetwork(t,e,r=>{x({type:"STREAM_EVENT",streamId:e,event:{type:"network_event",method:r.method,url:r.url,status:r.status,duration:r.duration,timestamp:r.timestamp}})}),{success:!0,streaming:!0}}catch(r){return x({type:"STREAM_ERROR",streamId:e,error:r instanceof Error?r.message:"Failed to start network stream"}),{error:r instanceof Error?r.message:"Failed to start network stream"}}}case"STREAM_STOP":{const e=o.streamId,r=M.get(e);return r!==void 0&&(l.unsubscribeFromConsole(r,e),l.unsubscribeFromNetwork(r,e),M.delete(e)),{success:!0}}case"SEARCH_PAGE":{if(!t)throw new Error("No tabId provided");if(!o.term)throw new Error("Search term required");try{return await chrome.tabs.sendMessage(t,{type:"SEARCH_PAGE",term:o.term,caseSensitive:o.caseSensitive||!1,limit:o.limit||10},{frameId:b(t)})}catch{return{error:"Content script not loaded. Try refreshing the page."}}}case"TAB_GROUP_CREATE":{const e=[...o.tabIds||[]],r=o.name||"Surf",s=["grey","blue","red","yellow","green","pink","purple","cyan","orange"].includes(o.color)?o.color:"blue";if(e.length===0&&t&&e.push(t),e.length===0)throw new Error("No tabs specified");const a=await chrome.tabGroups.query({title:r});let c;return a.length>0?(c=a[0].id,await chrome.tabs.group({tabIds:e,groupId:c})):(c=await chrome.tabs.group({tabIds:e}),await chrome.tabGroups.update(c,{title:r,color:s,collapsed:!1})),{success:!0,groupId:c,name:r,tabIds:e}}case"TAB_GROUP_REMOVE":{const e=[...o.tabIds||[]];if(e.length===0&&t&&e.push(t),e.length===0)throw new Error("No tabs specified");return await chrome.tabs.ungroup(e),{success:!0,ungrouped:e}}case"TAB_GROUPS_LIST":{const e=await chrome.tabGroups.query({}),r=[];for(const n of e){const s=await chrome.tabs.query({groupId:n.id});r.push({id:n.id,name:n.title||"(unnamed)",color:n.color,collapsed:n.collapsed,tabs:s.map(a=>({id:a.id,title:a.title,url:a.url}))})}return{groups:r}}case"CLICK_SELECTOR":{if(!t)throw new Error("No tabId provided");const e=o.selector,r=o.index||0,n=`(() => {
144
+ const elements = document.querySelectorAll(${JSON.stringify(e)});
345
145
  if (elements.length === 0) return { error: "No elements match selector" };
346
146
  if (${r} >= elements.length) return { error: "Index " + ${r} + " out of range (found " + elements.length + " elements)" };
347
147
 
@@ -352,5 +152,5 @@ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],en
352
152
  y: rect.top + rect.height / 2,
353
153
  count: elements.length
354
154
  };
355
- })()`,a=(await T.evaluateScript(n,i)).result?.value;return a?.error?{error:a.error}:a?(await T.click(n,a.x,a.y,`left`,1,0),{success:!0,selector:t,index:r,matchCount:a.count}):{error:`Failed to get element coordinates`}}case`COOKIE_LIST`:{if(!n)throw Error(`No tabId provided`);let e=(await chrome.tabs.get(n)).url;if(!e)throw Error(`Tab has no URL`);return{cookies:await chrome.cookies.getAll({url:e})}}case`COOKIE_GET`:{if(!n)throw Error(`No tabId provided`);let t=(await chrome.tabs.get(n)).url;if(!t)throw Error(`Tab has no URL`);if(!e.name)throw Error(`Cookie name required`);let r=await chrome.cookies.get({url:t,name:e.name});return r?{cookie:r}:{error:`Cookie "${e.name}" not found`}}case`COOKIE_SET`:{if(!n)throw Error(`No tabId provided`);let t=(await chrome.tabs.get(n)).url;if(!t)throw Error(`Tab has no URL`);if(!e.name)throw Error(`Cookie name required`);if(e.value===void 0)throw Error(`Cookie value required`);let r={url:t,name:e.name,value:e.value};if(e.expires){let t=new Date(e.expires).getTime()/1e3;if(isNaN(t))throw Error(`Invalid expiration date: ${e.expires}`);r.expirationDate=t}return{success:!0,cookie:await chrome.cookies.set(r)}}case`COOKIE_CLEAR`:{if(!n)throw Error(`No tabId provided`);let t=(await chrome.tabs.get(n)).url;if(!t)throw Error(`Tab has no URL`);if(!e.name)throw Error(`Cookie name required`);return await chrome.cookies.remove({url:t,name:e.name}),{success:!0,cleared:e.name}}case`COOKIE_CLEAR_ALL`:{if(!n)throw Error(`No tabId provided`);let e=(await chrome.tabs.get(n)).url;if(!e)throw Error(`Tab has no URL`);let t=await chrome.cookies.getAll({url:e});for(let n of t)await chrome.cookies.remove({url:e,name:n.name});return{success:!0,cleared:t.length}}case`TAB_RELOAD`:if(!n)throw Error(`No tabId provided`);return await chrome.tabs.reload(n,{bypassCache:e.hard||!1}),{success:!0};case`ZOOM_GET`:if(!n)throw Error(`No tabId provided`);return{zoom:await chrome.tabs.getZoom(n)};case`ZOOM_SET`:{if(!n)throw Error(`No tabId provided`);let t=e.level;if(t<.25||t>5)throw Error(`Zoom level must be between 0.25 and 5`);return await chrome.tabs.setZoom(n,t),{success:!0,zoom:t}}case`ZOOM_RESET`:if(!n)throw Error(`No tabId provided`);return await chrome.tabs.setZoom(n,0),{success:!0,zoom:1};case`BOOKMARK_ADD`:{if(!n)throw Error(`No tabId provided`);let t=await chrome.tabs.get(n),r={title:t.title||`Untitled`,url:t.url};if(e.folder){let t=(await chrome.bookmarks.search({title:e.folder})).find(e=>!e.url);t&&(r.parentId=t.id)}let i=await chrome.bookmarks.create(r);return{success:!0,bookmark:{id:i.id,title:i.title,url:i.url}}}case`BOOKMARK_REMOVE`:{if(!n)throw Error(`No tabId provided`);let e=await chrome.tabs.get(n);if(!e.url)throw Error(`Tab has no URL`);let t=await chrome.bookmarks.search({url:e.url});if(t.length===0)throw Error(`No bookmark found for this URL`);return await chrome.bookmarks.remove(t[0].id),{success:!0}}case`BOOKMARK_LIST`:{let t=typeof e.limit==`number`?e.limit:50,n=[];if(e.folder){let r=(await chrome.bookmarks.search({title:e.folder})).find(e=>!e.url);r&&(n=(await chrome.bookmarks.getChildren(r.id)).filter(e=>e.url).slice(0,t))}else n=await chrome.bookmarks.getRecent(t);return{bookmarks:n.map(e=>({id:e.id,title:e.title,url:e.url,dateAdded:e.dateAdded}))}}case`HISTORY_LIST`:{let t=typeof e.limit==`number`?e.limit:20;return{history:(await chrome.history.search({text:``,maxResults:t,startTime:0})).map(e=>({url:e.url,title:e.title,lastVisitTime:e.lastVisitTime,visitCount:e.visitCount}))}}case`HISTORY_SEARCH`:{let t=e.query,n=typeof e.limit==`number`?e.limit:20;return{history:(await chrome.history.search({text:t,maxResults:n,startTime:0})).map(e=>({url:e.url,title:e.title,lastVisitTime:e.lastVisitTime,visitCount:e.visitCount}))}}case`GET_CHATGPT_COOKIES`:{let e=await chrome.cookies.getAll({domain:`.chatgpt.com`}),t=await chrome.cookies.getAll({domain:`.openai.com`});return{cookies:[...e,...t]}}case`CHATGPT_NEW_TAB`:{let e=await chrome.tabs.create({url:`https://chatgpt.com/`,active:!0});if(!e.id)throw Error(`Failed to create tab`);return(await chrome.tabs.get(e.id)).status!==`complete`&&await new Promise(t=>{let n=(r,i)=>{r===e.id&&i.status===`complete`&&(chrome.tabs.onUpdated.removeListener(n),t())};chrome.tabs.onUpdated.addListener(n),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(n),t()},3e4)}),await T.attach(e.id),await Y(e.id,1e4),{tabId:e.id}}case`CHATGPT_CLOSE_TAB`:{let t=e.tabId;if(t){try{await T.detach(t)}catch{}try{await chrome.tabs.remove(t)}catch{}}return{success:!0}}case`CHATGPT_CDP_COMMAND`:{let{method:t,params:n}=e;return await T.sendCommand(e.tabId,t,n||{})}case`CHATGPT_EVALUATE`:return await T.evaluateScript(e.tabId,e.expression);case`PERPLEXITY_NEW_TAB`:{let e=await chrome.tabs.create({url:`https://www.perplexity.ai/`,active:!0});if(!e.id)throw Error(`Failed to create tab`);return(await chrome.tabs.get(e.id)).status!==`complete`&&await new Promise(t=>{let n=(r,i)=>{r===e.id&&i.status===`complete`&&(chrome.tabs.onUpdated.removeListener(n),t())};chrome.tabs.onUpdated.addListener(n),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(n),t()},3e4)}),await T.attach(e.id),await Y(e.id,1e4),{tabId:e.id}}case`PERPLEXITY_CLOSE_TAB`:{let t=e.tabId;if(t){try{await T.detach(t)}catch{}try{await chrome.tabs.remove(t)}catch{}}return{success:!0}}case`PERPLEXITY_CDP_COMMAND`:{let{method:t,params:n}=e;return await T.sendCommand(e.tabId,t,n||{})}case`PERPLEXITY_EVALUATE`:return await T.evaluateScript(e.tabId,e.expression);case`GET_TWITTER_COOKIES`:{let e=[`.x.com`,`.twitter.com`,`x.com`,`twitter.com`],t=[];for(let n of e)try{let e=await chrome.cookies.getAll({domain:n});t.push(...e)}catch{}for(let e of[`https://x.com`,`https://twitter.com`])try{let n=await chrome.cookies.getAll({url:e});t.push(...n)}catch{}let n=new Map;for(let e of t)(!n.get(e.name)||e.domain?.includes(`x.com`))&&n.set(e.name,e);return{cookies:Array.from(n.values())}}case`GROK_NEW_TAB`:{let e=await chrome.tabs.create({url:`https://x.com/i/grok`,active:!0});if(!e.id)throw Error(`Failed to create tab`);return(await chrome.tabs.get(e.id)).status!==`complete`&&await new Promise(t=>{let n=(r,i)=>{r===e.id&&i.status===`complete`&&(chrome.tabs.onUpdated.removeListener(n),t())};chrome.tabs.onUpdated.addListener(n),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(n),t()},3e4)}),await T.attach(e.id),await Y(e.id,1e4),{tabId:e.id}}case`GROK_CLOSE_TAB`:{let t=e.tabId;if(t){try{await T.detach(t)}catch{}try{await chrome.tabs.remove(t)}catch{}}return{success:!0}}case`GROK_CDP_COMMAND`:{let{method:t,params:n}=e;return await T.sendCommand(e.tabId,t,n||{})}case`GROK_EVALUATE`:return await T.evaluateScript(e.tabId,e.expression);case`GEMINI_NEW_TAB`:{let e=await chrome.tabs.create({url:`https://gemini.google.com/app`,active:!0});if(!e.id)throw Error(`Failed to create tab`);return{tabId:e.id}}case`GEMINI_CLOSE_TAB`:{let t=e.tabId;if(t){try{await T.detach(t)}catch{}try{await chrome.tabs.remove(t)}catch{}}return{success:!0}}case`AI_UPLOAD_FILE_TO_TAB`:case`UPLOAD_FILE_TO_TAB`:{let{tabId:t,filePaths:n}=e,r=e.type===`UPLOAD_FILE_TO_TAB`?`gemini`:e.provider;if(!t||!n?.length)throw Error(`${e.type} requires tabId and filePaths`);if(r!==`gemini`&&r!==`chatgpt`)throw Error(`Unsupported upload provider: ${r}`);return z(r,t,n)}case`GEMINI_FETCH_URL`:{let t=e.url;if(!t)throw Error(`No URL provided`);let n=await fetch(t,{credentials:`include`});if(!n.ok)throw Error(`Fetch failed: ${n.status}`);let r=await n.blob(),i=new FileReader;return{b64:await new Promise((e,t)=>{i.onload=()=>e(i.result.split(`,`)[1]),i.onerror=()=>t(Error(`FileReader failed`)),i.readAsDataURL(r)}),size:r.size,type:r.type}}case`AISTUDIO_NEW_TAB`:{let t=e.url||`https://aistudio.google.com/prompts/new_chat`,n=await chrome.tabs.create({url:t,active:!0});if(!n.id)throw Error(`Failed to create tab`);return(await chrome.tabs.get(n.id)).status!==`complete`&&await new Promise(e=>{let t=(r,i)=>{r===n.id&&i.status===`complete`&&(chrome.tabs.onUpdated.removeListener(t),e())};chrome.tabs.onUpdated.addListener(t),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(t),e()},3e4)}),await T.attach(n.id),await Y(n.id,1e4),{tabId:n.id}}case`AISTUDIO_CLOSE_TAB`:{let t=e.tabId;if(t){try{await T.detach(t)}catch{}try{await chrome.tabs.remove(t)}catch{}}return{success:!0}}case`AISTUDIO_CDP_COMMAND`:{let{method:t,params:n}=e;return await T.sendCommand(e.tabId,t,n||{})}case`AISTUDIO_EVALUATE`:return await T.evaluateScript(e.tabId,e.expression);case`DOWNLOADS_SEARCH`:return{downloads:(await chrome.downloads.search(e.searchParams||{})).map(e=>({id:e.id,filename:e.filename,state:e.state,error:e.error}))};case`GET_GOOGLE_COOKIES`:{let e=[`.google.com`,`.gemini.google.com`,`accounts.google.com`,`www.google.com`],t=[];for(let n of e)try{let e=await chrome.cookies.getAll({domain:n});t.push(...e)}catch{}for(let e of[`https://gemini.google.com`,`https://aistudio.google.com`,`https://accounts.google.com`,`https://www.google.com`])try{let n=await chrome.cookies.getAll({url:e});t.push(...n)}catch{}let n=new Map;for(let e of t){let t=n.get(e.name);(!t||e.domain===`.google.com`&&e.path===`/`||!t.domain?.includes(`google.com`)&&e.domain?.includes(`google.com`))&&n.set(e.name,e)}return{cookies:Array.from(n.values())}}case`WINDOW_NEW`:{let t=e.url||`data:text/html,<html><head><title>Surf Agent</title></head><body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;color:%23666"><div style="text-align:center"><h2>Agent Window</h2><p>Ready for automation</p></div></body></html>`,n={focused:e.focused!==!1,type:`normal`,url:t};e.width&&e.height&&(n.width=e.width,n.height=e.height),e.incognito&&(n.incognito=!0);let r=await chrome.windows.create(n);if(!r.id)throw Error(`Failed to create window`);let i=(await chrome.tabs.query({windowId:r.id}))[0];return i?.id&&await new Promise(e=>setTimeout(e,150)),{success:!0,windowId:r.id,tabId:i?.id,hint:`Use --window-id ${r.id} to target this window`}}case`WINDOW_LIST`:return{windows:(await chrome.windows.getAll({populate:!0})).map(t=>({id:t.id,focused:t.focused,type:t.type,state:t.state,width:t.width,height:t.height,tabCount:t.tabs?.length||0,tabs:e.includeTabs?t.tabs?.map(e=>({id:e.id,title:e.title,url:e.url,active:e.active})):void 0}))};case`WINDOW_FOCUS`:if(!e.windowId)throw Error(`No windowId provided`);return await chrome.windows.update(e.windowId,{focused:!0}),{success:!0,windowId:e.windowId};case`WINDOW_CLOSE`:if(!e.windowId)throw Error(`No windowId provided`);return await chrome.windows.remove(e.windowId),{success:!0,windowId:e.windowId};case`WINDOW_RESIZE`:{if(!e.windowId)throw Error(`No windowId provided`);let t={};e.width&&(t.width=e.width),e.height&&(t.height=e.height),e.left!==void 0&&(t.left=e.left),e.top!==void 0&&(t.top=e.top),e.state&&(t.state=e.state);let n=await chrome.windows.update(e.windowId,t);return{success:!0,windowId:e.windowId,width:n.width,height:n.height}}default:throw Error(`Unknown message type: ${e.type}`)}}chrome.runtime.onInstalled.addListener(e=>{c(`Extension installed/updated:`,e.reason)});var Q=new Set(`LIST_TABS.NEW_TAB.TABS_NEW.CLOSE_TABS.TAB_MOVE.SWITCH_TAB.TABS_SWITCH.TABS_REGISTER.TABS_UNREGISTER.TABS_LIST_NAMED.TABS_GET_BY_NAME.CREATE_TAB_GROUP.UNGROUP_TABS.LIST_TAB_GROUPS.GET_HISTORY.SEARCH_HISTORY.GET_COOKIES.SET_COOKIE.DELETE_COOKIES.GET_BOOKMARKS.ADD_BOOKMARK.DELETE_BOOKMARK.DIALOG_DISMISS.DIALOG_ACCEPT.DIALOG_INFO.CHATGPT_NEW_TAB.CHATGPT_CLOSE_TAB.CHATGPT_EVALUATE.CHATGPT_CDP_COMMAND.GET_CHATGPT_COOKIES.GET_GOOGLE_COOKIES.GET_TWITTER_COOKIES.PERPLEXITY_NEW_TAB.PERPLEXITY_CLOSE_TAB.PERPLEXITY_EVALUATE.PERPLEXITY_CDP_COMMAND.GROK_NEW_TAB.GROK_CLOSE_TAB.GROK_EVALUATE.GROK_CDP_COMMAND.GEMINI_NEW_TAB.GEMINI_CLOSE_TAB.GEMINI_FETCH_URL.AI_UPLOAD_FILE_TO_TAB.UPLOAD_FILE_TO_TAB.AISTUDIO_NEW_TAB.AISTUDIO_CLOSE_TAB.AISTUDIO_EVALUATE.AISTUDIO_CDP_COMMAND.DOWNLOADS_SEARCH.WINDOW_NEW.WINDOW_LIST.WINDOW_FOCUS.WINDOW_CLOSE.WINDOW_RESIZE.EMULATE_DEVICE_LIST`.split(`.`));_(async e=>{let t=e.tabId,n=e.windowId,r=e.type?.startsWith(`DIALOG_`),i=!Q.has(e.type),a=!1;if(t&&!r)try{await chrome.tabs.get(t)}catch{throw Error(`Invalid tab ID: ${t}. Use 'surf tab.list' to see available tabs.`)}else if(!t&&i){let e,r;if(n){if(e=await chrome.tabs.query({active:!0,windowId:n}),r=e[0],(!r||k(r.url))&&(e=await chrome.tabs.query({windowId:n}),r=e.find(e=>!k(e.url))),!r?.id){let e=await chrome.tabs.create({windowId:n,url:`data:text/html,<html><head><title>Surf</title></head><body></body></html>`,active:!0});if(!e.id)throw Error(`Failed to create tab in window ${n}`);await new Promise(e=>setTimeout(e,100)),r=e,a=!0}}else if(e=await chrome.tabs.query({active:!0,lastFocusedWindow:!0}),r=e[0],(!r||k(r.url))&&(e=await chrome.tabs.query({active:!0,currentWindow:!0}),r=e[0]),(!r||k(r.url))&&(e=await chrome.tabs.query({active:!0}),r=e.find(e=>!k(e.url))),!r?.id)throw Error(`No active tab found. Use 'surf tab.new <url>' to create one, or 'surf tab.list' to see available tabs.`);t=r.id}let o=await Z({...e,tabId:t},{}),s=[];return a&&s.push(`Auto-created tab in window ${n} (no usable tabs existed). Navigate to your target URL.`),{...o,_resolvedTabId:t,_hint:s.length>0?s.join(` `):void 0}});
356
- //# sourceMappingURL=index.js.map
155
+ })()`,a=(await l.evaluateScript(t,n)).result?.value;return a?.error?{error:a.error}:a?(await l.click(t,a.x,a.y,"left",1,0),{success:!0,selector:e,index:r,matchCount:a.count}):{error:"Failed to get element coordinates"}}case"COOKIE_LIST":{if(!t)throw new Error("No tabId provided");const r=(await chrome.tabs.get(t)).url;if(!r)throw new Error("Tab has no URL");return{cookies:await chrome.cookies.getAll({url:r})}}case"COOKIE_GET":{if(!t)throw new Error("No tabId provided");const r=(await chrome.tabs.get(t)).url;if(!r)throw new Error("Tab has no URL");if(!o.name)throw new Error("Cookie name required");const n=await chrome.cookies.get({url:r,name:o.name});return n?{cookie:n}:{error:`Cookie "${o.name}" not found`}}case"COOKIE_SET":{if(!t)throw new Error("No tabId provided");const r=(await chrome.tabs.get(t)).url;if(!r)throw new Error("Tab has no URL");if(!o.name)throw new Error("Cookie name required");if(o.value===void 0)throw new Error("Cookie value required");const n={url:r,name:o.name,value:o.value};if(o.expires){const a=new Date(o.expires).getTime()/1e3;if(isNaN(a))throw new Error(`Invalid expiration date: ${o.expires}`);n.expirationDate=a}return{success:!0,cookie:await chrome.cookies.set(n)}}case"COOKIE_CLEAR":{if(!t)throw new Error("No tabId provided");const r=(await chrome.tabs.get(t)).url;if(!r)throw new Error("Tab has no URL");if(!o.name)throw new Error("Cookie name required");return await chrome.cookies.remove({url:r,name:o.name}),{success:!0,cleared:o.name}}case"COOKIE_CLEAR_ALL":{if(!t)throw new Error("No tabId provided");const r=(await chrome.tabs.get(t)).url;if(!r)throw new Error("Tab has no URL");const n=await chrome.cookies.getAll({url:r});for(const s of n)await chrome.cookies.remove({url:r,name:s.name});return{success:!0,cleared:n.length}}case"TAB_RELOAD":{if(!t)throw new Error("No tabId provided");return await chrome.tabs.reload(t,{bypassCache:o.hard||!1}),{success:!0}}case"ZOOM_GET":{if(!t)throw new Error("No tabId provided");return{zoom:await chrome.tabs.getZoom(t)}}case"ZOOM_SET":{if(!t)throw new Error("No tabId provided");const e=o.level;if(e<.25||e>5)throw new Error("Zoom level must be between 0.25 and 5");return await chrome.tabs.setZoom(t,e),{success:!0,zoom:e}}case"ZOOM_RESET":{if(!t)throw new Error("No tabId provided");return await chrome.tabs.setZoom(t,0),{success:!0,zoom:1}}case"BOOKMARK_ADD":{if(!t)throw new Error("No tabId provided");const e=await chrome.tabs.get(t),r={title:e.title||"Untitled",url:e.url};if(o.folder){const a=(await chrome.bookmarks.search({title:o.folder})).find(c=>!c.url);a&&(r.parentId=a.id)}const n=await chrome.bookmarks.create(r);return{success:!0,bookmark:{id:n.id,title:n.title,url:n.url}}}case"BOOKMARK_REMOVE":{if(!t)throw new Error("No tabId provided");const e=await chrome.tabs.get(t);if(!e.url)throw new Error("Tab has no URL");const r=await chrome.bookmarks.search({url:e.url});if(r.length===0)throw new Error("No bookmark found for this URL");return await chrome.bookmarks.remove(r[0].id),{success:!0}}case"BOOKMARK_LIST":{const e=typeof o.limit=="number"?o.limit:50;let r=[];if(o.folder){const s=(await chrome.bookmarks.search({title:o.folder})).find(a=>!a.url);s&&(r=(await chrome.bookmarks.getChildren(s.id)).filter(c=>c.url).slice(0,e))}else r=await chrome.bookmarks.getRecent(e);return{bookmarks:r.map(n=>({id:n.id,title:n.title,url:n.url,dateAdded:n.dateAdded}))}}case"HISTORY_LIST":{const e=typeof o.limit=="number"?o.limit:20;return{history:(await chrome.history.search({text:"",maxResults:e,startTime:0})).map(n=>({url:n.url,title:n.title,lastVisitTime:n.lastVisitTime,visitCount:n.visitCount}))}}case"HISTORY_SEARCH":{const e=o.query,r=typeof o.limit=="number"?o.limit:20;return{history:(await chrome.history.search({text:e,maxResults:r,startTime:0})).map(s=>({url:s.url,title:s.title,lastVisitTime:s.lastVisitTime,visitCount:s.visitCount}))}}case"GET_CHATGPT_COOKIES":{const e=await chrome.cookies.getAll({domain:".chatgpt.com"}),r=await chrome.cookies.getAll({domain:".openai.com"});return{cookies:[...e,...r]}}case"CHATGPT_NEW_TAB":{const e=await chrome.tabs.create({url:"https://chatgpt.com/",active:!0});if(!e.id)throw new Error("Failed to create tab");return(await chrome.tabs.get(e.id)).status!=="complete"&&await new Promise(n=>{const s=(a,c)=>{a===e.id&&c.status==="complete"&&(chrome.tabs.onUpdated.removeListener(s),n())};chrome.tabs.onUpdated.addListener(s),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(s),n()},3e4)}),await l.attach(e.id),await U(e.id,1e4),{tabId:e.id}}case"CHATGPT_CLOSE_TAB":{const e=o.tabId;if(e){try{await l.detach(e)}catch{}try{await chrome.tabs.remove(e)}catch{}}return{success:!0}}case"CHATGPT_CDP_COMMAND":{const{method:e,params:r}=o;return await l.sendCommand(o.tabId,e,r||{})}case"CHATGPT_EVALUATE":return await l.evaluateScript(o.tabId,o.expression);case"PERPLEXITY_NEW_TAB":{const e=await chrome.tabs.create({url:"https://www.perplexity.ai/",active:!0});if(!e.id)throw new Error("Failed to create tab");return(await chrome.tabs.get(e.id)).status!=="complete"&&await new Promise(n=>{const s=(a,c)=>{a===e.id&&c.status==="complete"&&(chrome.tabs.onUpdated.removeListener(s),n())};chrome.tabs.onUpdated.addListener(s),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(s),n()},3e4)}),await l.attach(e.id),await U(e.id,1e4),{tabId:e.id}}case"PERPLEXITY_CLOSE_TAB":{const e=o.tabId;if(e){try{await l.detach(e)}catch{}try{await chrome.tabs.remove(e)}catch{}}return{success:!0}}case"PERPLEXITY_CDP_COMMAND":{const{method:e,params:r}=o;return await l.sendCommand(o.tabId,e,r||{})}case"PERPLEXITY_EVALUATE":return await l.evaluateScript(o.tabId,o.expression);case"GET_TWITTER_COOKIES":{const e=[".x.com",".twitter.com","x.com","twitter.com"],r=[];for(const a of e)try{const c=await chrome.cookies.getAll({domain:a});r.push(...c)}catch{}const n=["https://x.com","https://twitter.com"];for(const a of n)try{const c=await chrome.cookies.getAll({url:a});r.push(...c)}catch{}const s=new Map;for(const a of r)(!s.get(a.name)||a.domain?.includes("x.com"))&&s.set(a.name,a);return{cookies:Array.from(s.values())}}case"GROK_NEW_TAB":{const e=await chrome.tabs.create({url:"https://x.com/i/grok",active:!0});if(!e.id)throw new Error("Failed to create tab");return(await chrome.tabs.get(e.id)).status!=="complete"&&await new Promise(n=>{const s=(a,c)=>{a===e.id&&c.status==="complete"&&(chrome.tabs.onUpdated.removeListener(s),n())};chrome.tabs.onUpdated.addListener(s),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(s),n()},3e4)}),await l.attach(e.id),await U(e.id,1e4),{tabId:e.id}}case"GROK_CLOSE_TAB":{const e=o.tabId;if(e){try{await l.detach(e)}catch{}try{await chrome.tabs.remove(e)}catch{}}return{success:!0}}case"GROK_CDP_COMMAND":{const{method:e,params:r}=o;return await l.sendCommand(o.tabId,e,r||{})}case"GROK_EVALUATE":return await l.evaluateScript(o.tabId,o.expression);case"GEMINI_NEW_TAB":{const e=await chrome.tabs.create({url:"https://gemini.google.com/app",active:!0});if(!e.id)throw new Error("Failed to create tab");return{tabId:e.id}}case"GEMINI_CLOSE_TAB":{const e=o.tabId;if(e){try{await l.detach(e)}catch{}try{await chrome.tabs.remove(e)}catch{}}return{success:!0}}case"UPLOAD_FILE_TO_TAB":{const{tabId:e,filePaths:r}=o;if(!e||!r?.length)throw new Error("UPLOAD_FILE_TO_TAB requires tabId and filePaths");await l.attach(e),await l.sendCommand(e,"DOM.enable",{}),await l.sendCommand(e,"Page.setInterceptFileChooserDialog",{enabled:!0});let n=null,s=null;const a=()=>{n&&(clearTimeout(n),n=null),s&&(chrome.debugger.onEvent.removeListener(s),s=null)},c=(w,p)=>new Promise((E,_)=>{n=setTimeout(()=>{a(),_(new Error(`File chooser did not open within ${p/1e3}s (attempt ${w})`))},p),s=(S,N,m)=>{S.tabId===e&&N==="Page.fileChooserOpened"&&(a(),l.sendCommand(e,"DOM.setFileInputFiles",{files:r,backendNodeId:m.backendNodeId}).then(()=>E()).catch(_))},chrome.debugger.onEvent.addListener(s)}),u=async()=>{await l.sendCommand(e,"Runtime.evaluate",{expression:`document.querySelector('button[aria-label="Close upload file menu"]')?.click()`,userGesture:!0}),await new Promise(w=>setTimeout(w,300)),await l.sendCommand(e,"Runtime.evaluate",{expression:`document.querySelector('button[aria-label="Open upload file menu"]')?.click()`,userGesture:!0}),await new Promise(w=>setTimeout(w,500)),await l.sendCommand(e,"Runtime.evaluate",{expression:`document.querySelector('[data-test-id="local-images-files-uploader-button"]')?.click()`,userGesture:!0})},d=3,h=[1e4,15e3,2e4];let f=null;try{for(let w=1;w<=d;w++)try{const p=c(w,h[w-1]);return await u(),await p,{success:!0}}catch(p){f=p,a(),w<d&&await new Promise(E=>setTimeout(E,1e3))}throw new Error(`File upload failed after ${d} attempts: ${f?.message}`)}finally{a();try{await l.sendCommand(e,"Page.setInterceptFileChooserDialog",{enabled:!1})}catch{}}}case"GEMINI_FETCH_URL":{const e=o.url;if(!e)throw new Error("No URL provided");const r=await fetch(e,{credentials:"include"});if(!r.ok)throw new Error(`Fetch failed: ${r.status}`);const n=await r.blob(),s=new FileReader;return{b64:await new Promise((c,u)=>{s.onload=()=>c(s.result.split(",")[1]),s.onerror=()=>u(new Error("FileReader failed")),s.readAsDataURL(n)}),size:n.size,type:n.type}}case"AISTUDIO_NEW_TAB":{const e=o.url||"https://aistudio.google.com/prompts/new_chat",r=await chrome.tabs.create({url:e,active:!0});if(!r.id)throw new Error("Failed to create tab");return(await chrome.tabs.get(r.id)).status!=="complete"&&await new Promise(s=>{const a=(c,u)=>{c===r.id&&u.status==="complete"&&(chrome.tabs.onUpdated.removeListener(a),s())};chrome.tabs.onUpdated.addListener(a),setTimeout(()=>{chrome.tabs.onUpdated.removeListener(a),s()},3e4)}),await l.attach(r.id),await U(r.id,1e4),{tabId:r.id}}case"AISTUDIO_CLOSE_TAB":{const e=o.tabId;if(e){try{await l.detach(e)}catch{}try{await chrome.tabs.remove(e)}catch{}}return{success:!0}}case"AISTUDIO_CDP_COMMAND":{const{method:e,params:r}=o;return await l.sendCommand(o.tabId,e,r||{})}case"AISTUDIO_EVALUATE":return await l.evaluateScript(o.tabId,o.expression);case"DOWNLOADS_SEARCH":return{downloads:(await chrome.downloads.search(o.searchParams||{})).map(r=>({id:r.id,filename:r.filename,state:r.state,error:r.error}))};case"GET_GOOGLE_COOKIES":{const e=[".google.com",".gemini.google.com","accounts.google.com","www.google.com"],r=[];for(const a of e)try{const c=await chrome.cookies.getAll({domain:a});r.push(...c)}catch{}const n=["https://gemini.google.com","https://aistudio.google.com","https://accounts.google.com","https://www.google.com"];for(const a of n)try{const c=await chrome.cookies.getAll({url:a});r.push(...c)}catch{}const s=new Map;for(const a of r){const c=s.get(a.name);(!c||a.domain===".google.com"&&a.path==="/"||!c.domain?.includes("google.com")&&a.domain?.includes("google.com"))&&s.set(a.name,a)}return{cookies:Array.from(s.values())}}case"WINDOW_NEW":{const e=o.url||'data:text/html,<html><head><title>Surf Agent</title></head><body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;color:%23666"><div style="text-align:center"><h2>Agent Window</h2><p>Ready for automation</p></div></body></html>',r={focused:o.focused!==!1,type:"normal",url:e};o.width&&o.height&&(r.width=o.width,r.height=o.height),o.incognito&&(r.incognito=!0);const n=await chrome.windows.create(r);if(!n.id)throw new Error("Failed to create window");const a=(await chrome.tabs.query({windowId:n.id}))[0];return a?.id&&await new Promise(c=>setTimeout(c,150)),{success:!0,windowId:n.id,tabId:a?.id,hint:`Use --window-id ${n.id} to target this window`}}case"WINDOW_LIST":return{windows:(await chrome.windows.getAll({populate:!0})).map(r=>({id:r.id,focused:r.focused,type:r.type,state:r.state,width:r.width,height:r.height,tabCount:r.tabs?.length||0,tabs:o.includeTabs?r.tabs?.map(n=>({id:n.id,title:n.title,url:n.url,active:n.active})):void 0}))};case"WINDOW_FOCUS":{if(!o.windowId)throw new Error("No windowId provided");return await chrome.windows.update(o.windowId,{focused:!0}),{success:!0,windowId:o.windowId}}case"WINDOW_CLOSE":{if(!o.windowId)throw new Error("No windowId provided");return await chrome.windows.remove(o.windowId),{success:!0,windowId:o.windowId}}case"WINDOW_RESIZE":{if(!o.windowId)throw new Error("No windowId provided");const e={};o.width&&(e.width=o.width),o.height&&(e.height=o.height),o.left!==void 0&&(e.left=o.left),o.top!==void 0&&(e.top=o.top),o.state&&(e.state=o.state);const r=await chrome.windows.update(o.windowId,e);return{success:!0,windowId:o.windowId,width:r.width,height:r.height}}default:throw new Error(`Unknown message type: ${o.type}`)}}chrome.runtime.onInstalled.addListener(o=>{C("Extension installed/updated:",o.reason)});const he=new Set(["LIST_TABS","NEW_TAB","TABS_NEW","CLOSE_TABS","SWITCH_TAB","TABS_SWITCH","TABS_REGISTER","TABS_UNREGISTER","TABS_LIST_NAMED","TABS_GET_BY_NAME","CREATE_TAB_GROUP","UNGROUP_TABS","LIST_TAB_GROUPS","GET_HISTORY","SEARCH_HISTORY","GET_COOKIES","SET_COOKIE","DELETE_COOKIES","GET_BOOKMARKS","ADD_BOOKMARK","DELETE_BOOKMARK","DIALOG_DISMISS","DIALOG_ACCEPT","DIALOG_INFO","CHATGPT_NEW_TAB","CHATGPT_CLOSE_TAB","CHATGPT_EVALUATE","CHATGPT_CDP_COMMAND","GET_CHATGPT_COOKIES","GET_GOOGLE_COOKIES","GET_TWITTER_COOKIES","PERPLEXITY_NEW_TAB","PERPLEXITY_CLOSE_TAB","PERPLEXITY_EVALUATE","PERPLEXITY_CDP_COMMAND","GROK_NEW_TAB","GROK_CLOSE_TAB","GROK_EVALUATE","GROK_CDP_COMMAND","GEMINI_NEW_TAB","GEMINI_CLOSE_TAB","GEMINI_FETCH_URL","UPLOAD_FILE_TO_TAB","AISTUDIO_NEW_TAB","AISTUDIO_CLOSE_TAB","AISTUDIO_EVALUATE","AISTUDIO_CDP_COMMAND","DOWNLOADS_SEARCH","WINDOW_NEW","WINDOW_LIST","WINDOW_FOCUS","WINDOW_CLOSE","WINDOW_RESIZE","EMULATE_DEVICE_LIST"]);J(async o=>{let i=o.tabId;const t=o.windowId,e=o.type?.startsWith("DIALOG_"),r=!he.has(o.type);let n=!1;if(i&&!e)try{await chrome.tabs.get(i)}catch{throw new Error(`Invalid tab ID: ${i}. Use 'surf tab.list' to see available tabs.`)}else if(!i&&r){let c,u;if(t){c=await chrome.tabs.query({active:!0,windowId:t}),u=c[0];const d=h=>!h||h.startsWith("chrome://")||h.startsWith("chrome-extension://")||h==="about:blank";if((!u||d(u.url))&&(c=await chrome.tabs.query({windowId:t}),u=c.find(h=>!d(h.url))),!u?.id){const h=await chrome.tabs.create({windowId:t,url:"data:text/html,<html><head><title>Surf</title></head><body></body></html>",active:!0});if(!h.id)throw new Error(`Failed to create tab in window ${t}`);await new Promise(f=>setTimeout(f,100)),u=h,n=!0}}else if(c=await chrome.tabs.query({active:!0,lastFocusedWindow:!0}),u=c[0],(!u||u.url?.startsWith("chrome-extension://"))&&(c=await chrome.tabs.query({active:!0,currentWindow:!0}),u=c[0]),(!u||u.url?.startsWith("chrome-extension://")||u.url?.startsWith("chrome://"))&&(c=await chrome.tabs.query({active:!0}),u=c.find(d=>!d.url?.startsWith("chrome-extension://")&&!d.url?.startsWith("chrome://"))),!u?.id)throw new Error("No active tab found. Use 'surf tab.new <url>' to create one, or 'surf tab.list' to see available tabs.");i=u.id}const s=await ee({...o,tabId:i},{}),a=[];return n&&a.push(`Auto-created tab in window ${t} (no usable tabs existed). Navigate to your target URL.`),{...s,_resolvedTabId:i,_hint:a.length>0?a.join(" "):void 0}});
156
+ //# sourceMappingURL=index.js.map