agentiqa 1.1.7-staging.4883a7e → 1.1.7-staging.7150afd

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 (2) hide show
  1. package/dist/cli.js +6 -5
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -223,7 +223,7 @@ ${d.aiSnapshot}
223
223
  OS: ${m}${v}`;return y&&(_=`[Auto-navigated to: ${y} (from ${p})]`+(y!==d.url?`
224
224
  [Redirected to: ${d.url}]`:`
225
225
  Current URL: ${d.url}`)+`
226
- OS: ${m}${v}`),{env:d,contextText:_}}var xu=["google.com","youtube.com","claude.ai","chatgpt.com","openai.com","gemini.google.com","bing.com","duckduckgo.com","wikipedia.org","facebook.com","instagram.com","tiktok.com","x.com","twitter.com","reddit.com","github.com","amazon.com","netflix.com","linkedin.com","apple.com","microsoft.com","yahoo.com","whatsapp.com"];function Yo(r){if(!r)return{matched:!1,host:null};let e=null;try{let n=r.startsWith("http")?r:`https://${r}`;e=new URL(n).hostname.toLowerCase().replace(/^www\./,"")}catch{return{matched:!1,host:null}}return{matched:xu.some(n=>e===n||e.endsWith(`.${n}`)),host:e}}var Tu="The AI service is temporarily unavailable. Please retry shortly.",d_=/(ai\s*studio|ai_apicallerror|api[\s-]*key|billing|gemini|google\s+ai|openai|anthropic|provider|provider_location_unsupported|quota|rate[\s-]*limit|rate-limited|spend[\s-]*cap|spendcap|llm[\s_-]*access|overage|upgrade\s+url|reason=|location is not supported for the api use|aistudio\.google\.com|cloud\.google\.com\/billing)/i;function Yi(r){if(typeof r!="string")return;let e=r.replace(/\s+/g," ").trim();return e.length>0?e:void 0}function Jo(r){let e=Yi(r);return e?d_.test(e):!1}function Ji(r){let e=Yi(r);if(e)return Jo(e)?Tu:e}function Ki(r){return r.targetHostKind==="loopback"||r.engineReachability==="reached_but_app_crashed"?null:r.providerRegionUnsupported?{reason:"provider_region_unsupported",targetHostKind:r.targetHostKind}:r.engineReachability==="unreachable_dns"||r.engineReachability==="unreachable_connect"||r.engineReachability==="unreachable_tls"||r.engineReachability==="unreachable_4xx"||r.engineReachability==="unreachable_engine_blocked"?{reason:"target_unreachable_from_engine",targetHostKind:r.targetHostKind}:null}var p_={provider_region_unsupported:"Our managed engine couldn't process this run in the current region. Try running the same test from your own machine using the cloud-enabled CLI.",target_unreachable_from_engine:"Our managed engine couldn't reach your target URL \u2014 this often happens with local tunnels and private hosts. Try running the same test from your own machine using the cloud-enabled CLI; it can reach hosts the managed engine cannot."};function Iu(r){return p_[r]}function Eu(r){let e=["agentiqa run",`--engine ${r.engineUrl}`];return r.testPlanId&&e.push(`--plan-id ${r.testPlanId}`),e.push(`--url ${r.targetUrl}`),e.join(" ")}function Qi(r){let e=r.testPlanId??null;return{reason:r.decision.reason,targetHostKind:r.decision.targetHostKind,targetUrl:r.targetUrl,testPlanId:e,engineUrl:r.engineUrl,cliCommand:Eu({engineUrl:r.engineUrl,targetUrl:r.targetUrl,testPlanId:e}),reasonHumanReadable:Iu(r.decision.reason)}}var Xi="assistant_v2_unreachable_target_fallback_offered";function Zi(r){return{reason_class:r.reason,target_host_kind:r.targetHostKind,suggested_cli_command_emitted:r.cliCommand.length>0}}var pn={createSession:()=>"/api/engine/session",getSession:r=>`/api/engine/session/${r}`,agentMessage:r=>`/api/engine/session/${r}/message`,bootstrap:r=>`/api/engine/session/${r}/bootstrap`,runTestPlan:r=>`/api/engine/session/${r}/run`,runnerMessage:r=>`/api/engine/session/${r}/runner-message`,stop:r=>`/api/engine/session/${r}/stop`,addCredentials:r=>`/api/engine/session/${r}/credentials`,setUserProvidedTestEmail:r=>`/api/engine/session/${r}/user-provided-test-email`,deleteSession:r=>`/api/engine/session/${r}`,evaluate:r=>`/api/engine/session/${r}/evaluate`,batchRun:r=>`/api/engine/session/${r}/batch-run`,chatTitle:()=>"/api/engine/chat-title"};function ku(r){if(r.search?.trim())return null;let e=r.labelIds??[];return e.length===0?"_global":e.length===1?`lbl_${e[0]}`:null}function Au(r){let e=new Intl.Collator(void 0,{numeric:!0});return(t,n)=>{let s=t.sortIndices?.[r],o=n.sortIndices?.[r];if(s!=null&&o!=null)return s-o;if(s!=null)return-1;if(o!=null)return 1;if(r!=="_global"){let l=t.sortIndices?._global,c=n.sortIndices?._global;if(l!=null&&c!=null)return l-c;if(l!=null)return-1;if(c!=null)return 1}let a=/^\s*\d/.test(t.title),i=/^\s*\d/.test(n.title);return a!==i?a?-1:1:a?e.compare(t.title,n.title):t.createdAt!==n.createdAt?t.createdAt-n.createdAt:t.id.localeCompare(n.id)}}function el(r){let e=r.indexOf(":");return e===-1?{provider:"google",modelName:r}:{provider:r.slice(0,e),modelName:r.slice(e+1)}}var Ko="google:gemini-3-flash-preview",Ru="google:gemini-3-flash-preview";function pe(r){return`${r}_${crypto.randomUUID()}`}var m_=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,h_=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,f_=/\b(e-?mail)\b/i,g_=/\b(username|user name|login|identifier)\b/i;function Qo(r){return typeof r=="string"&&m_.test(r.trim())}function Xo(r){let e=r?.match(h_)?.[0];return e?tl(e):null}function tl(r){return r.trim().toLowerCase()}function y_(r){return Date.now().toString(36)}function rl(r,e,t){let n=tl(r);if(!Qo(n))return null;let[s,o]=n.split("@");return!s||!o?null:{enabled:!0,canonicalEmail:s.includes("+")?n:`${s}+${y_(e)}@${o}`,inboxEmail:n,canCheckInbox:t.canCheckInbox,source:"environment"}}function wt(r){let e=r?.testingEmailPolicy;return!e?.enabled||!Qo(e.canonicalEmail)?null:e}function Gn(r){let e=r?.userProvidedTestEmail;if(typeof e!="string")return null;let t=tl(e);return Qo(t)?t:null}function nl(r){return Gn(r)??wt(r)?.canonicalEmail??null}function v_(...r){return r.some(e=>typeof e=="string"&&f_.test(e))}function b_(...r){return r.some(e=>typeof e=="string"&&g_.test(e))}function Cu(r){if(r.config?.isDiscoveryRun!==!0||r.actionName!=="type_text_at"&&r.actionName!=="set_focused_input_value")return!1;let e=r.actionName==="type_text_at"?r.text:r.value;return Hr({config:r.config,text:e,inputType:r.inputType,label:r.label,matchedLabel:r.matchedLabel,intent:r.intent,screen:r.screen,stepText:r.stepText})}function Hr(r){return nl(r.config)?r.text==="TEST_EMAIL"||r.inputType?.toLowerCase()==="email"||v_(r.label,r.matchedLabel,r.intent,r.screen,r.stepText)?!0:Qo(r.text)&&b_(r.label,r.matchedLabel,r.intent,r.screen,r.stepText):!1}function sl(r,e,t){let n=nl(t);return n&&(r==="type_text_at"&&typeof e.text=="string"&&Hr({config:t,text:e.text,label:e.label,intent:e.intent,screen:e.screen,stepText:e.stepText})&&(e.text=n),r==="set_focused_input_value"&&typeof e.value=="string"&&Hr({config:t,text:e.value,intent:e.intent,screen:e.screen,stepText:e.stepText})&&(e.value=n)),e}function Fs(r){if(!r?.enabled)return"";let e=r.canCheckInbox?`- The account is NOT created until email verification finishes. The task is NOT complete until you have called check_email, opened the verification link (or entered the verification code) and confirmed the account is verified. A page that says "Check your email" or "User registered. Please check your email to verify" is an intermediate step, not the goal \u2014 do NOT call run_complete or assistant_v2_report at that screen.
226
+ OS: ${m}${v}`),{env:d,contextText:_}}var xu=["google.com","youtube.com","claude.ai","chatgpt.com","openai.com","gemini.google.com","bing.com","duckduckgo.com","wikipedia.org","facebook.com","instagram.com","tiktok.com","x.com","twitter.com","reddit.com","github.com","amazon.com","netflix.com","linkedin.com","apple.com","microsoft.com","yahoo.com","whatsapp.com"];function Yo(r){if(!r)return{matched:!1,host:null};let e=null;try{let n=r.startsWith("http")?r:`https://${r}`;e=new URL(n).hostname.toLowerCase().replace(/^www\./,"")}catch{return{matched:!1,host:null}}return{matched:xu.some(n=>e===n||e.endsWith(`.${n}`)),host:e}}var Tu="The AI service is temporarily unavailable. Please retry shortly.",d_=/(ai\s*studio|ai_apicallerror|api[\s-]*key|billing|gemini|google\s+ai|openai|anthropic|provider|provider_location_unsupported|quota|rate[\s-]*limit|rate-limited|spend[\s-]*cap|spendcap|llm[\s_-]*access|overage|upgrade\s+url|reason=|location is not supported for the api use|aistudio\.google\.com|cloud\.google\.com\/billing)/i;function Yi(r){if(typeof r!="string")return;let e=r.replace(/\s+/g," ").trim();return e.length>0?e:void 0}function Jo(r){let e=Yi(r);return e?d_.test(e):!1}function Ji(r){let e=Yi(r);if(e)return Jo(e)?Tu:e}function Ki(r){return r.targetHostKind==="loopback"||r.engineReachability==="reached_but_app_crashed"?null:r.providerRegionUnsupported?{reason:"provider_region_unsupported",targetHostKind:r.targetHostKind}:r.engineReachability==="unreachable_dns"||r.engineReachability==="unreachable_connect"||r.engineReachability==="unreachable_tls"||r.engineReachability==="unreachable_4xx"||r.engineReachability==="unreachable_engine_blocked"?{reason:"target_unreachable_from_engine",targetHostKind:r.targetHostKind}:null}var p_={provider_region_unsupported:"Our managed engine couldn't process this run in the current region. Try running the same test from your own machine using the cloud-enabled CLI.",target_unreachable_from_engine:"Our managed engine couldn't reach your target URL \u2014 this often happens with local tunnels and private hosts. Try running the same test from your own machine using the cloud-enabled CLI; it can reach hosts the managed engine cannot."};function Iu(r){return p_[r]}function Eu(r){let e=["agentiqa run",`--engine ${r.engineUrl}`];return r.testPlanId&&e.push(`--plan-id ${r.testPlanId}`),e.push(`--url ${r.targetUrl}`),e.join(" ")}function Qi(r){let e=r.testPlanId??null;return{reason:r.decision.reason,targetHostKind:r.decision.targetHostKind,targetUrl:r.targetUrl,testPlanId:e,engineUrl:r.engineUrl,cliCommand:Eu({engineUrl:r.engineUrl,targetUrl:r.targetUrl,testPlanId:e}),reasonHumanReadable:Iu(r.decision.reason)}}var Xi="assistant_v2_unreachable_target_fallback_offered";function Zi(r){return{reason_class:r.reason,target_host_kind:r.targetHostKind,suggested_cli_command_emitted:r.cliCommand.length>0}}var pn={createSession:()=>"/api/engine/session",getSession:r=>`/api/engine/session/${r}`,agentMessage:r=>`/api/engine/session/${r}/message`,bootstrap:r=>`/api/engine/session/${r}/bootstrap`,runTestPlan:r=>`/api/engine/session/${r}/run`,runnerMessage:r=>`/api/engine/session/${r}/runner-message`,stop:r=>`/api/engine/session/${r}/stop`,addCredentials:r=>`/api/engine/session/${r}/credentials`,setUserProvidedTestEmail:r=>`/api/engine/session/${r}/user-provided-test-email`,deleteSession:r=>`/api/engine/session/${r}`,evaluate:r=>`/api/engine/session/${r}/evaluate`,batchRun:r=>`/api/engine/session/${r}/batch-run`,chatTitle:()=>"/api/engine/chat-title"};function ku(r){if(r.search?.trim())return null;let e=r.labelIds??[];return e.length===0?"_global":e.length===1?`lbl_${e[0]}`:null}function Au(r){let e=new Intl.Collator(void 0,{numeric:!0});return(t,n)=>{let s=t.sortIndices?.[r],o=n.sortIndices?.[r];if(s!=null&&o!=null)return s-o;if(s!=null)return-1;if(o!=null)return 1;if(r!=="_global"){let l=t.sortIndices?._global,c=n.sortIndices?._global;if(l!=null&&c!=null)return l-c;if(l!=null)return-1;if(c!=null)return 1}let a=/^\s*\d/.test(t.title),i=/^\s*\d/.test(n.title);return a!==i?a?-1:1:a?e.compare(t.title,n.title):t.createdAt!==n.createdAt?t.createdAt-n.createdAt:t.id.localeCompare(n.id)}}function el(r){let e=r.indexOf(":");return e===-1?{provider:"google",modelName:r}:{provider:r.slice(0,e),modelName:r.slice(e+1)}}var Ko="google:gemini-3-flash-preview",Ru="google:gemini-3-flash-preview";function pe(r){return`${r}_${crypto.randomUUID()}`}var m_=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,h_=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i,f_=/\b(e-?mail)\b/i,g_=/\b(username|user name|login|identifier)\b/i;function Qo(r){return typeof r=="string"&&m_.test(r.trim())}function Xo(r){let e=r?.match(h_)?.[0];return e?tl(e):null}function tl(r){return r.trim().toLowerCase()}function y_(r){return Date.now().toString(36)}function rl(r,e,t){let n=tl(r);if(!Qo(n))return null;let[s,o]=n.split("@");return!s||!o?null:{enabled:!0,canonicalEmail:s.includes("+")?n:`${s}+${y_(e)}@${o}`,inboxEmail:n,canCheckInbox:t.canCheckInbox,source:"environment"}}function wt(r){let e=r?.testingEmailPolicy;return!e?.enabled||!Qo(e.canonicalEmail)?null:e}function Gn(r){let e=r?.userProvidedTestEmail;if(typeof e!="string")return null;let t=tl(e);return Qo(t)?t:null}function nl(r){return Gn(r)??wt(r)?.canonicalEmail??null}function v_(...r){return r.some(e=>typeof e=="string"&&f_.test(e))}function b_(...r){return r.some(e=>typeof e=="string"&&g_.test(e))}function Cu(r){if(r.config?.isDiscoveryRun!==!0||r.actionName!=="type_text_at"&&r.actionName!=="set_focused_input_value")return!1;let e=r.actionName==="type_text_at"?r.text:r.value;return Hr({config:r.config,text:e,inputType:r.inputType,label:r.label,matchedLabel:r.matchedLabel,intent:r.intent,screen:r.screen,stepText:r.stepText})}function Hr(r){return nl(r.config)?r.text==="TEST_EMAIL"?!0:r.config?.isTestPlanReplay?typeof r.text=="string"&&/\{\{\s*[a-z0-9_]+\s*\}\}/i.test(r.text):r.inputType?.toLowerCase()==="email"||v_(r.label,r.matchedLabel,r.intent,r.screen,r.stepText)?!0:Qo(r.text)&&b_(r.label,r.matchedLabel,r.intent,r.screen,r.stepText):!1}function sl(r,e,t){let n=nl(t);return n&&(r==="type_text_at"&&typeof e.text=="string"&&Hr({config:t,text:e.text,label:e.label,intent:e.intent,screen:e.screen,stepText:e.stepText})&&(e.text=n),r==="set_focused_input_value"&&typeof e.value=="string"&&Hr({config:t,text:e.value,intent:e.intent,screen:e.screen,stepText:e.stepText})&&(e.value=n)),e}function Fs(r){if(!r?.enabled)return"";let e=r.canCheckInbox?`- The account is NOT created until email verification finishes. The task is NOT complete until you have called check_email, opened the verification link (or entered the verification code) and confirmed the account is verified. A page that says "Check your email" or "User registered. Please check your email to verify" is an intermediate step, not the goal \u2014 do NOT call run_complete or assistant_v2_report at that screen.
227
227
  - After submitting the signup form, call check_email, click the verification link (or read the verification code and submit it), and confirm verified state before completing.
228
228
  - The inbox is reachable through check_email; that tool will read this same canonical email.
229
229
  `:`- The inbox is not reachable in this environment; block if completing email verification is required.
@@ -835,7 +835,7 @@ ${a}`}}}async handleToolCall(e,t){switch(e.name){case"run_complete":{let a=e.arg
835
835
  ${i}
836
836
 
837
837
  STEPS:
838
- ${a}`}async handleRunComplete(e,t){let n=this._activeRun,s=this._activeTestPlan,{session:o}=t;if(!n)return{response:{status:"ok",note:"No active run \u2014 stopping loop"},done:!0,isMetaTool:!0};let a=e.args.status==="passed"?"passed":"failed",i=String(e.args.summary??""),l=String(e.args.reflection??"").trim(),c=(e.args.stepResults??[]).map((h,f)=>{let p=h.stepIndex??f+1,m=p-1;return{stepIndex:p,status:h.status??"passed",note:h.note,step:s.steps[m],criteriaResults:(h.criteriaResults??[]).map(d=>({check:d.check,strict:s.steps[m]?.criteria?.find(y=>y.check===d.check)?.strict??!0,passed:d.passed,note:d.note}))}});n.status=a,n.summary=i,n.stepResults=c,n.terminationReason="completed",n.endedAt=Date.now(),n.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(n);let u={id:pe("msg"),sessionId:o.id,role:"model",text:`Test ${a}. ${i}`,timestamp:Date.now(),actionName:"run_complete",actionArgs:{status:a,stepResults:c,screenshots:this._screenshots,reflection:l},runId:n.id};return await this.baseDeps.chatRepo.addMessage(u),this.emit("message:added",{sessionId:o.id,message:u}),this.baseDeps.sink.emit({kind:"user_action",ts:Date.now(),sessionId:o.id,action:"test_plan_run_complete",targetId:n.id,metadata:{testPlanId:n.testPlanId,status:n.status,summary:n.summary,stepResults:n.stepResults,testPlanTitle:s?.title}}),this.emit("run:completed",{sessionId:o.id,run:n,runMemory:Object.fromEntries(this._runMemory)}),this._suppressNotifications||this.deps.notificationService?.showTestRunComplete(o.id,s.title,n.status,{projectId:o.projectId,testPlanId:s.id}),{response:{status:"ok"},done:!0,isMetaTool:!0}}handleSignalStep(e,t){let n=e.args.stepIndex,s=this.findUnverifiedVerifyStepBefore(n);return s!==null?(this._currentStepIndex=s,this._currentStepText=this._activeTestPlan.steps[s-1]?.text??null,Promise.resolve(this.buildVerifyEvidenceRequiredResult(s))):(this._currentStepIndex=n,this._currentStepText=this._activeTestPlan.steps[n-1]?.text??null,Promise.resolve({response:{status:"ok",stepIndex:n},isMetaTool:!0,resetLoopDetector:!0}))}async handleProposeUpdate(e,t){let{session:n}=t,s=this._activeRun,o={id:pe("msg"),sessionId:n.id,role:"model",text:"",timestamp:Date.now(),actionName:"propose_update",actionArgs:e.args,runId:s?.id};if(await this.baseDeps.chatRepo.addMessage(o),this.emit("message:added",{sessionId:n.id,message:o}),s){let a=typeof e.args?.reason=="string"&&e.args.reason?`Proposed test plan update: ${e.args.reason}`:"Agent proposed a test plan update";s.status="blocked",s.summary=a,s.terminationReason="supervisor_halted",s.endedAt=Date.now(),s.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(s),this.emit("run:completed",{sessionId:n.id,run:s,runMemory:Object.fromEntries(this._runMemory)})}return{response:{status:"awaiting_approval"},done:!0,isMetaTool:!0}}async handleReportIssue(e,t){let{session:n}=t,s=this._activeRun,o=this._activeTestPlan,a=fo(this.recentActionsSnapshot(),Ar(e.args??{}));if(a)return{response:{status:"issue_rejected",reason:"disabled_control_prerequisite",instruction:Ha(a)},isMetaTool:!0};let i=await this.deps.computerUseService.invoke({sessionId:n.id,action:"screenshot",args:{},config:n.config});if(Rr(Ar(e.args??{}))&&ps(e.args??{},i.aiSnapshot))return{response:{status:"issue_rejected",reason:"negative_state_recovered",instruction:Sn()},isMetaTool:!0};let l=pe("issue"),c=!1,u;if(i.screenshot)try{let v=await this.baseDeps.imageStorageService?.save({projectId:o.projectId,issueId:l,type:"issue",base64:i.screenshot});c=!0,v&&typeof v=="object"&&v.url&&(u=v.url)}catch(v){this.log("error","RunnerRuntime","Failed to save issue screenshot",{error:v?.message})}let h=Date.now(),f=this.recentActionsSnapshot(),p=f.length>0?{capturedAt:h,actions:f}:void 0,m={id:l,projectId:o.projectId,status:"pending",title:e.args.title,description:e.args.description,severity:e.args.severity,category:e.args.category,confidence:e.args.confidence,reproSteps:e.args.reproSteps??[],hasScreenshot:c,screenshotUrl:u,url:i.url??"",detectedAt:h,detectedInRunId:s?.id,detectedInSessionId:n.id,relatedTestPlanId:o.id,relatedStepIndex:this._currentStepIndex??void 0,evidence:p,createdAt:h,updatedAt:h};await this.deps.issuesRepo.upsert(m);let d=m,y={id:pe("msg"),sessionId:n.id,role:"model",text:"",timestamp:Date.now(),actionName:"report_issue",actionArgs:{issueId:d.id,...e.args,evidence:p,screenshotUrl:u},runId:s?.id};return await this.baseDeps.chatRepo.addMessage(y),this.emit("message:added",{sessionId:n.id,message:y}),{response:{status:"reported",issueId:d.id},isMetaTool:!0}}async handleBlocked(e,t){let{session:n}=t,s=this._activeRun,o=Number(e.args?.stepIndex??this._currentStepIndex??1),a=String(e.args?.attempted??"").trim(),i=String(e.args?.obstacle??"").trim(),l=String(e.args?.question??"").trim(),c={sessionId:n.id,id:pe("msg"),role:"model",text:l,timestamp:Date.now(),actionName:"exploration_blocked",actionArgs:{stepIndex:o,attempted:a,obstacle:i,question:l},runId:s?.id};return await this.baseDeps.chatRepo.addMessage(c),this.emit("message:added",{sessionId:n.id,message:c}),s&&(s.status="blocked",s.summary=i||"Agent blocked",s.terminationReason="supervisor_halted",s.endedAt=Date.now(),s.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(s),this.emit("run:completed",{sessionId:n.id,run:s,runMemory:Object.fromEntries(this._runMemory)})),{response:{status:"awaiting_user_guidance"},done:!0,isMetaTool:!0}}handleSaveToMemory(e){this.log("info","RunMemory","handleSaveToMemory:entry",{rawArgs:e.args,argsType:typeof e.args,argKeys:e.args?Object.keys(e.args):[],hasUpdateCallback:!!this._onRunMemoryUpdate,currentKeys:[...this._runMemory.keys()]});let t=String(e.args?.key??"").trim(),n=String(e.args?.value??"");if(!t)return this.log("warn","RunMemory","save_to_memory rejected: missing key",{rawArgs:e.args,valueGiven:n}),{response:{status:"error",error:"key is required"},isMetaTool:!0};this._runMemory.set(t,n);let s=Object.fromEntries(this._runMemory);return this._onRunMemoryUpdate&&this._onRunMemoryUpdate(s),this.log("info","RunMemory","save_to_memory:saved",{key:t,value:n,totalKeys:this._runMemory.size}),{response:{status:"ok",saved:t},isMetaTool:!0}}async blockMissingRunMemoryReferences(e,t,n){let s=n.map(f=>f.key),o=[...this._runMemory.keys()],a=s.length===1?"key":"keys",i=o.length>0?` Available run memory keys: ${wc(o)}.`:" Run memory is empty.",l=`Missing run memory ${a}: ${wc(s)}.`+i,c=`The test plan references missing run memory ${a}. Run the prerequisite plan that saves the value before retrying, or provide the value in run memory.`,u=n[0];this._currentStepIndex=u?.stepIndex??1,this._currentStepText=u?.stepText??null;let h={sessionId:e.id,id:pe("msg"),role:"model",text:c,timestamp:Date.now(),actionName:"exploration_blocked",actionArgs:{stepIndex:this._currentStepIndex,attempted:`Use run memory ${a}: ${wc(s)}`,obstacle:l,question:c},runId:t.id};await this.baseDeps.chatRepo.addMessage(h),this.emit("message:added",{sessionId:e.id,message:h}),t.status="blocked",t.summary=l,t.terminationReason="supervisor_halted",t.endedAt=Date.now(),t.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(t),this.emit("run:completed",{sessionId:e.id,run:t,runMemory:Object.fromEntries(this._runMemory)})}async startRun(e,t,n){if(this.deps.authService.isAuthRequired()&&!await this.deps.authService.ensureAuthenticated()){this.emit("auth:required",{sessionId:this.sessionId,action:"start_run"});return}if(this._isRunning){this.emit("session:error",{sessionId:this.sessionId,error:"Already running"});return}if(!await(this.baseDeps.llmAccessService?.hasApiKey()??Promise.resolve(!0))){this.emit("session:error",{sessionId:this.sessionId,error:"Gemini API key not set"});return}this.beginRun(),this._runMemory=new Map(Object.entries(n?.initialMemory??{})),this._onRunMemoryUpdate=n?.onMemoryUpdate??null;let{url:o,source:a}=BA(e.config?.initialUrl,t);if(o&&o!==e.config?.initialUrl){let f=e.config?.initialUrl;e.config={...e.config,initialUrl:o},this.log("info","RunnerRuntime","startRun:resolvedInitialUrl",{source:a,resolvedInitialUrl:o,originalInitialUrl:f})}this.log("info","RunMemory","startRun:options",{hasInitialMemoryOption:n?.initialMemory!==void 0,hasUpdateCallbackOption:typeof n?.onMemoryUpdate=="function",initialKeys:[...this._runMemory.keys()],initialEntryCount:this._runMemory.size}),this.baseDeps.sink.emit({kind:"user_action",ts:Date.now(),sessionId:e.id,action:"run_test_plan",targetId:t.id,metadata:{title:t.title,stepCount:t.steps.length,steps:t.steps.map(f=>f.text)}});let i={id:pe("run"),testPlanId:t.id,projectId:t.projectId,sessionId:e.id,status:"running",createdAt:Date.now(),updatedAt:Date.now(),stepResults:[],batchRunId:n?.batchRunId,batchSeq:n?.batchSeq};await this.deps.testPlanV2RunRepo.upsert(i),this._currentRunId=i.id,this._activeRun=i,this._activeTestPlan=t,this._currentStepIndex=null,this._currentStepText=null,this._screenshots=[],this._verifyEvidenceStepIndexes.clear(),this._autoVerifyEvidenceStepIndexes.clear(),this._suppressNotifications=n?.suppressNotifications??!1,this._editOnly=!1,this.emit("run:started",{sessionId:e.id,runId:i.id,startedAt:i.createdAt});let l={id:pe("msg"),sessionId:e.id,role:"user",actionName:"run_test_plan",text:"Run test plan",timestamp:Date.now(),runId:i.id};await this.baseDeps.chatRepo.addMessage(l),this.emit("message:added",{sessionId:e.id,message:l});let c=Date.now(),u=null,h=!1;try{let f=tR(t,this._runMemory);if(f.length>0){await this.blockMissingRunMemoryReferences(e,i,f);return}await Bt(this.deps.computerUseService.cleanupSession(this.sessionId),c,"browser cleanup"),h=!0;let p=(e.config?.platform||"web")==="mobile",m=p?e.config?.mobileConfig?.platform||"android":void 0,d=m==="ios",y=p&&mn(e.config?.mobileConfig),v=!p&&(e.config?.snapshotOnly??!1),_=await Bt(this.deps.memoryRepo.list(t.projectId),c,"memory load"),b=await Bt(this.deps.secretsService.listProjectCredentials(t.projectId),c,"credential metadata load");await Bt(Xr(e.id,t.projectId,this.deps),c,"credential seeding"),this._lastSeededSessionId=e.id;let S=await Bt(this.deps.issuesRepo.list(t.projectId,{status:["confirmed","dismissed"]}),c,"known issue load");this.baseDeps.sink.emit({kind:"session_start",ts:Date.now(),sessionId:e.id,sessionMeta:{...un(e,this.baseDeps.sessionMetaExtras),memoryItems:_.map(A=>A.text),credentialNames:b.map(A=>A.name)}}),this.conversationTrace=[],await Bt(this.baseDeps.chatRepo.upsertSession({...e,conversationTrace:[],updatedAt:Date.now()}),c,"conversation reset");let w=await Bt(this.ensureConversationTraceLoaded(e),c,"conversation trace load"),k=Object.fromEntries(this._runMemory);this.log("info","RunMemory","buildRunnerPrompt:calling",{runMemoryKeys:Object.keys(k)}),this.systemPromptText=await Bt(Jg(t,"run",_,b,S,p,v,y,this.deps,m,k,wt(e.config)),c,"runner prompt build"),this.log("info","RunMemory","buildRunnerPrompt:result",{promptLength:this.systemPromptText.length,hasRunMemorySection:this.systemPromptText.includes("RUN MEMORY"),hasToolMention:this.systemPromptText.includes("save_to_memory")}),w.push({role:"user",parts:[{text:this.systemPromptText}]});let x,I;if(p){let A=e.config?.mobileConfig,{screenSize:F,screenshot:W,initWarnings:Y}=await Bt(this.baseDeps.mobileMcpService.initializeSession(e.id,{deviceType:m,deviceMode:A.deviceMode,avdName:A?.avdName,deviceId:A?.deviceId,simulatorUdid:A?.simulatorUdid,deviceUdid:A?.deviceUdid,apkPath:A?.apkPath,appPath:A?.appPath,appIdentifier:A?.appIdentifier,shouldReinstallApp:A?.shouldReinstallApp??!0,appLoadWaitSeconds:A?.appLoadWaitSeconds??5}),c,"mobile session initialization");this.mobileActionExecutor.setScreenSize(F),x=W.base64,I=`Execute the test plan now.
838
+ ${a}`}async handleRunComplete(e,t){let n=this._activeRun,s=this._activeTestPlan,{session:o}=t;if(!n)return{response:{status:"ok",note:"No active run \u2014 stopping loop"},done:!0,isMetaTool:!0};let a=e.args.status==="passed"?"passed":"failed",i=String(e.args.summary??""),l=String(e.args.reflection??"").trim(),c=(e.args.stepResults??[]).map((h,f)=>{let p=h.stepIndex??f+1,m=p-1;return{stepIndex:p,status:h.status??"passed",note:h.note,step:s.steps[m],criteriaResults:(h.criteriaResults??[]).map(d=>({check:d.check,strict:s.steps[m]?.criteria?.find(y=>y.check===d.check)?.strict??!0,passed:d.passed,note:d.note}))}});n.status=a,n.summary=i,n.stepResults=c,n.terminationReason="completed",n.endedAt=Date.now(),n.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(n);let u={id:pe("msg"),sessionId:o.id,role:"model",text:`Test ${a}. ${i}`,timestamp:Date.now(),actionName:"run_complete",actionArgs:{status:a,stepResults:c,screenshots:this._screenshots,reflection:l},runId:n.id};return await this.baseDeps.chatRepo.addMessage(u),this.emit("message:added",{sessionId:o.id,message:u}),this.baseDeps.sink.emit({kind:"user_action",ts:Date.now(),sessionId:o.id,action:"test_plan_run_complete",targetId:n.id,metadata:{testPlanId:n.testPlanId,status:n.status,summary:n.summary,stepResults:n.stepResults,testPlanTitle:s?.title}}),this.emit("run:completed",{sessionId:o.id,run:n,runMemory:Object.fromEntries(this._runMemory)}),this._suppressNotifications||this.deps.notificationService?.showTestRunComplete(o.id,s.title,n.status,{projectId:o.projectId,testPlanId:s.id}),{response:{status:"ok"},done:!0,isMetaTool:!0}}handleSignalStep(e,t){let n=e.args.stepIndex,s=this.findUnverifiedVerifyStepBefore(n);return s!==null?(this._currentStepIndex=s,this._currentStepText=this._activeTestPlan.steps[s-1]?.text??null,Promise.resolve(this.buildVerifyEvidenceRequiredResult(s))):(this._currentStepIndex=n,this._currentStepText=this._activeTestPlan.steps[n-1]?.text??null,Promise.resolve({response:{status:"ok",stepIndex:n},isMetaTool:!0,resetLoopDetector:!0}))}async handleProposeUpdate(e,t){let{session:n}=t,s=this._activeRun,o={id:pe("msg"),sessionId:n.id,role:"model",text:"",timestamp:Date.now(),actionName:"propose_update",actionArgs:e.args,runId:s?.id};if(await this.baseDeps.chatRepo.addMessage(o),this.emit("message:added",{sessionId:n.id,message:o}),s){let a=typeof e.args?.reason=="string"&&e.args.reason?`Proposed test plan update: ${e.args.reason}`:"Agent proposed a test plan update";s.status="blocked",s.summary=a,s.terminationReason="supervisor_halted",s.endedAt=Date.now(),s.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(s),this.emit("run:completed",{sessionId:n.id,run:s,runMemory:Object.fromEntries(this._runMemory)})}return{response:{status:"awaiting_approval"},done:!0,isMetaTool:!0}}async handleReportIssue(e,t){let{session:n}=t,s=this._activeRun,o=this._activeTestPlan,a=fo(this.recentActionsSnapshot(),Ar(e.args??{}));if(a)return{response:{status:"issue_rejected",reason:"disabled_control_prerequisite",instruction:Ha(a)},isMetaTool:!0};let i=await this.deps.computerUseService.invoke({sessionId:n.id,action:"screenshot",args:{},config:n.config});if(Rr(Ar(e.args??{}))&&ps(e.args??{},i.aiSnapshot))return{response:{status:"issue_rejected",reason:"negative_state_recovered",instruction:Sn()},isMetaTool:!0};let l=pe("issue"),c=!1,u;if(i.screenshot)try{let v=await this.baseDeps.imageStorageService?.save({projectId:o.projectId,issueId:l,type:"issue",base64:i.screenshot});c=!0,v&&typeof v=="object"&&v.url&&(u=v.url)}catch(v){this.log("error","RunnerRuntime","Failed to save issue screenshot",{error:v?.message})}let h=Date.now(),f=this.recentActionsSnapshot(),p=f.length>0?{capturedAt:h,actions:f}:void 0,m={id:l,projectId:o.projectId,status:"pending",title:e.args.title,description:e.args.description,severity:e.args.severity,category:e.args.category,confidence:e.args.confidence,reproSteps:e.args.reproSteps??[],hasScreenshot:c,screenshotUrl:u,url:i.url??"",detectedAt:h,detectedInRunId:s?.id,detectedInSessionId:n.id,relatedTestPlanId:o.id,relatedStepIndex:this._currentStepIndex??void 0,evidence:p,createdAt:h,updatedAt:h};await this.deps.issuesRepo.upsert(m);let d=m,y={id:pe("msg"),sessionId:n.id,role:"model",text:"",timestamp:Date.now(),actionName:"report_issue",actionArgs:{issueId:d.id,...e.args,evidence:p,screenshotUrl:u},runId:s?.id};return await this.baseDeps.chatRepo.addMessage(y),this.emit("message:added",{sessionId:n.id,message:y}),{response:{status:"reported",issueId:d.id},isMetaTool:!0}}async handleBlocked(e,t){let{session:n}=t,s=this._activeRun,o=Number(e.args?.stepIndex??this._currentStepIndex??1),a=String(e.args?.attempted??"").trim(),i=String(e.args?.obstacle??"").trim(),l=String(e.args?.question??"").trim(),c={sessionId:n.id,id:pe("msg"),role:"model",text:l,timestamp:Date.now(),actionName:"exploration_blocked",actionArgs:{stepIndex:o,attempted:a,obstacle:i,question:l},runId:s?.id};return await this.baseDeps.chatRepo.addMessage(c),this.emit("message:added",{sessionId:n.id,message:c}),s&&(s.status="blocked",s.summary=i||"Agent blocked",s.terminationReason="supervisor_halted",s.endedAt=Date.now(),s.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(s),this.emit("run:completed",{sessionId:n.id,run:s,runMemory:Object.fromEntries(this._runMemory)})),{response:{status:"awaiting_user_guidance"},done:!0,isMetaTool:!0}}handleSaveToMemory(e){this.log("info","RunMemory","handleSaveToMemory:entry",{rawArgs:e.args,argsType:typeof e.args,argKeys:e.args?Object.keys(e.args):[],hasUpdateCallback:!!this._onRunMemoryUpdate,currentKeys:[...this._runMemory.keys()]});let t=String(e.args?.key??"").trim(),n=String(e.args?.value??"");if(!t)return this.log("warn","RunMemory","save_to_memory rejected: missing key",{rawArgs:e.args,valueGiven:n}),{response:{status:"error",error:"key is required"},isMetaTool:!0};this._runMemory.set(t,n);let s=Object.fromEntries(this._runMemory);return this._onRunMemoryUpdate&&this._onRunMemoryUpdate(s),this.log("info","RunMemory","save_to_memory:saved",{key:t,value:n,totalKeys:this._runMemory.size}),{response:{status:"ok",saved:t},isMetaTool:!0}}async blockMissingRunMemoryReferences(e,t,n){let s=n.map(f=>f.key),o=[...this._runMemory.keys()],a=s.length===1?"key":"keys",i=o.length>0?` Available run memory keys: ${wc(o)}.`:" Run memory is empty.",l=`Missing run memory ${a}: ${wc(s)}.`+i,c=`The test plan references missing run memory ${a}. Run the prerequisite plan that saves the value before retrying, or provide the value in run memory.`,u=n[0];this._currentStepIndex=u?.stepIndex??1,this._currentStepText=u?.stepText??null;let h={sessionId:e.id,id:pe("msg"),role:"model",text:c,timestamp:Date.now(),actionName:"exploration_blocked",actionArgs:{stepIndex:this._currentStepIndex,attempted:`Use run memory ${a}: ${wc(s)}`,obstacle:l,question:c},runId:t.id};await this.baseDeps.chatRepo.addMessage(h),this.emit("message:added",{sessionId:e.id,message:h}),t.status="blocked",t.summary=l,t.terminationReason="supervisor_halted",t.endedAt=Date.now(),t.updatedAt=Date.now(),await this.deps.testPlanV2RunRepo.upsert(t),this.emit("run:completed",{sessionId:e.id,run:t,runMemory:Object.fromEntries(this._runMemory)})}async startRun(e,t,n){if(this.deps.authService.isAuthRequired()&&!await this.deps.authService.ensureAuthenticated()){this.emit("auth:required",{sessionId:this.sessionId,action:"start_run"});return}if(this._isRunning){this.emit("session:error",{sessionId:this.sessionId,error:"Already running"});return}if(!await(this.baseDeps.llmAccessService?.hasApiKey()??Promise.resolve(!0))){this.emit("session:error",{sessionId:this.sessionId,error:"Gemini API key not set"});return}this.beginRun(),e.config&&(e.config.isTestPlanReplay=!0),this._runMemory=new Map(Object.entries(n?.initialMemory??{})),this._onRunMemoryUpdate=n?.onMemoryUpdate??null;let{url:o,source:a}=BA(e.config?.initialUrl,t);if(o&&o!==e.config?.initialUrl){let f=e.config?.initialUrl;e.config={...e.config,initialUrl:o},this.log("info","RunnerRuntime","startRun:resolvedInitialUrl",{source:a,resolvedInitialUrl:o,originalInitialUrl:f})}this.log("info","RunMemory","startRun:options",{hasInitialMemoryOption:n?.initialMemory!==void 0,hasUpdateCallbackOption:typeof n?.onMemoryUpdate=="function",initialKeys:[...this._runMemory.keys()],initialEntryCount:this._runMemory.size}),this.baseDeps.sink.emit({kind:"user_action",ts:Date.now(),sessionId:e.id,action:"run_test_plan",targetId:t.id,metadata:{title:t.title,stepCount:t.steps.length,steps:t.steps.map(f=>f.text)}});let i={id:pe("run"),testPlanId:t.id,projectId:t.projectId,sessionId:e.id,status:"running",createdAt:Date.now(),updatedAt:Date.now(),stepResults:[],batchRunId:n?.batchRunId,batchSeq:n?.batchSeq};await this.deps.testPlanV2RunRepo.upsert(i),this._currentRunId=i.id,this._activeRun=i,this._activeTestPlan=t,this._currentStepIndex=null,this._currentStepText=null,this._screenshots=[],this._verifyEvidenceStepIndexes.clear(),this._autoVerifyEvidenceStepIndexes.clear(),this._suppressNotifications=n?.suppressNotifications??!1,this._editOnly=!1,this.emit("run:started",{sessionId:e.id,runId:i.id,startedAt:i.createdAt});let l={id:pe("msg"),sessionId:e.id,role:"user",actionName:"run_test_plan",text:"Run test plan",timestamp:Date.now(),runId:i.id};await this.baseDeps.chatRepo.addMessage(l),this.emit("message:added",{sessionId:e.id,message:l});let c=Date.now(),u=null,h=!1;try{let f=tR(t,this._runMemory);if(f.length>0){await this.blockMissingRunMemoryReferences(e,i,f);return}await Bt(this.deps.computerUseService.cleanupSession(this.sessionId),c,"browser cleanup"),h=!0;let p=(e.config?.platform||"web")==="mobile",m=p?e.config?.mobileConfig?.platform||"android":void 0,d=m==="ios",y=p&&mn(e.config?.mobileConfig),v=!p&&(e.config?.snapshotOnly??!1),_=await Bt(this.deps.memoryRepo.list(t.projectId),c,"memory load"),b=await Bt(this.deps.secretsService.listProjectCredentials(t.projectId),c,"credential metadata load");await Bt(Xr(e.id,t.projectId,this.deps),c,"credential seeding"),this._lastSeededSessionId=e.id;let S=await Bt(this.deps.issuesRepo.list(t.projectId,{status:["confirmed","dismissed"]}),c,"known issue load");this.baseDeps.sink.emit({kind:"session_start",ts:Date.now(),sessionId:e.id,sessionMeta:{...un(e,this.baseDeps.sessionMetaExtras),memoryItems:_.map(A=>A.text),credentialNames:b.map(A=>A.name)}}),this.conversationTrace=[],await Bt(this.baseDeps.chatRepo.upsertSession({...e,conversationTrace:[],updatedAt:Date.now()}),c,"conversation reset");let w=await Bt(this.ensureConversationTraceLoaded(e),c,"conversation trace load"),k=Object.fromEntries(this._runMemory);this.log("info","RunMemory","buildRunnerPrompt:calling",{runMemoryKeys:Object.keys(k)}),this.systemPromptText=await Bt(Jg(t,"run",_,b,S,p,v,y,this.deps,m,k,wt(e.config)),c,"runner prompt build"),this.log("info","RunMemory","buildRunnerPrompt:result",{promptLength:this.systemPromptText.length,hasRunMemorySection:this.systemPromptText.includes("RUN MEMORY"),hasToolMention:this.systemPromptText.includes("save_to_memory")}),w.push({role:"user",parts:[{text:this.systemPromptText}]});let x,I;if(p){let A=e.config?.mobileConfig,{screenSize:F,screenshot:W,initWarnings:Y}=await Bt(this.baseDeps.mobileMcpService.initializeSession(e.id,{deviceType:m,deviceMode:A.deviceMode,avdName:A?.avdName,deviceId:A?.deviceId,simulatorUdid:A?.simulatorUdid,deviceUdid:A?.deviceUdid,apkPath:A?.apkPath,appPath:A?.appPath,appIdentifier:A?.appIdentifier,shouldReinstallApp:A?.shouldReinstallApp??!0,appLoadWaitSeconds:A?.appLoadWaitSeconds??5}),c,"mobile session initialization");this.mobileActionExecutor.setScreenSize(F),x=W.base64,I=`Execute the test plan now.
839
839
  Platform: mobile (${d?"iOS":"Android"})
840
840
  Device: ${A?.deviceMode==="connected"?A?.deviceId??"unknown":A?.deviceMode==="device"?A?.deviceUdid??"unknown":A?.avdName??"unknown"}`+(Y?.length?`
841
841
 
@@ -1447,8 +1447,9 @@ Mode A login-only plan for this area:
1447
1447
  6. If login fails for ANY reason (wrong password, account not found, "Invalid email or password", captcha, MFA, rate limit, email-verification required) \u2192 assistant_v2_report with summary starting with exactly the marker "login_failed: " followed by the site's error message (e.g. "login_failed: Invalid email or password"). Do NOT sign up, do NOT retry endlessly \u2014 just report the failure so the user can fix the credentials or pick the autonomous path.
1448
1448
  7. NEVER call check_email \u2014 the user owns this inbox.
1449
1449
  8. NEVER submit a signup / registration form in this Explorer.
1450
+ 9. When you report login_ok, ALSO include a draftTestCase in the same assistant_v2_report so the user can save this login as a reusable test plan. Steps: navigate to the login screen \u2192 enter ${N} in the email field \u2192 enter the password via the saved credential "${j}" \u2192 submit \u2192 verify the signed-in state. Use the real login identity exactly as above \u2014 do NOT tokenize or randomize email/password (login reuses the same credentials every run). Omit the draftTestCase only when you report login_failed.
1450
1451
 
1451
- Original spawn instructions follow \u2014 treat them as background; the 8 steps above OVERRIDE any conflicting guidance below.
1452
+ Original spawn instructions follow \u2014 treat them as background; the 9 steps above OVERRIDE any conflicting guidance below.
1452
1453
 
1453
1454
  `+R),d?.length&&(R+=`
1454
1455
 
@@ -1575,7 +1576,7 @@ Reply with ONLY the title, no quotes, no punctuation at the end.`,v=ys(Ko,t);n&&
1575
1576
  })();
1576
1577
  `,su=new WeakMap,mr=class{static script(){return Wv}static async install(e){try{await e.evaluate(Wv)}catch{}}static async reset(e){su.delete(e);try{await e.evaluate(()=>{window.__aqObserver?.reset()})}catch{}}static async flush(e){try{let t=await e.evaluate(()=>window.__aqObserver?.flush()??[]),n=su.get(e)??[],s=yP(t,n),o=t.filter(l=>l.type==="add"),a=t.filter(l=>l.type==="remove"),i=o.filter(l=>!a.find(c=>c.text===l.text&&c.role===l.role));return su.set(e,i),s}catch{return null}}static async waitForQuiescence(e,t={}){let n=t.minQuietMs??100,s=t.maxMs??800;try{return await e.evaluate(async({minQuietMs:o,maxMs:a})=>{let i=window.__aqObserver;if(!i)return{kind:"quiet",quiescedAfterMs:0};let l=Date.now(),c=i.peek();return await new Promise(u=>{let h=()=>{let f=Date.now(),p=i.peek(),m=c.bufferedCount>0||p.bufferedCount>0||p.count>c.count,d=p.lastAt||l,y=f-l;if(m&&f-d>=o){u({kind:"settled",quiescedAfterMs:y});return}if(!m&&y>=a){u({kind:"quiet",quiescedAfterMs:y});return}if(y>=a){u({kind:"timeout",quiescedAfterMs:y});return}requestAnimationFrame(h)};requestAnimationFrame(h)})},{minQuietMs:n,maxMs:s})}catch{return{kind:"quiet",quiescedAfterMs:0}}}};function yP(r,e=[]){if(r.length===0&&e.length===0)return null;let t=[],n=r.filter(a=>a.type==="add"),s=r.filter(a=>a.type==="remove");for(let a of n){let i=s.find(l=>l.text===a.text&&l.role===a.role);i&&t.push(`\u26A1 transient: "${a.text}" (role=${a.role}, appeared T+${(a.t/1e3).toFixed(1)}s, lasted ${i.t-a.t}ms)`)}for(let a of e){let i=s.find(c=>c.text===a.text&&c.role===a.role),l=n.find(c=>c.text===a.text&&c.role===a.role);i&&!l&&t.push(`\u26A1 transient: "${a.text}" (role=${a.role}, appeared in previous screenshot, now gone)`)}let o=r.filter(a=>a.type==="scroll").reduce((a,i)=>a+i.dy,0);Math.abs(o)>10&&t.push(`\u2195 scroll: ${o>0?"+":""}${o}px`);for(let a of r)a.type==="hash"&&t.push(`# hash: #${a.from} \u2192 #${a.to}`),a.type==="nav"&&t.push(`\u2192 nav: ${a.url}`);return t.length===0?null:`[Between screenshots]
1577
1578
  `+t.join(`
1578
- `)}import{promises as Gv}from"node:dns";import{createConnection as vP}from"node:net";var bP=2e3,_P=1e3;async function wP(r,e){let t=Gv.resolve4(r).catch(()=>[]),n=Gv.resolve6(r).catch(()=>[]),s=new Promise(i=>setTimeout(()=>i([]),e)),o=Promise.all([t,n]).then(([i,l])=>[...i,...l]),a=await Promise.race([o,s]);return a.length>0?a:null}async function Yv(r,e,t,n){return new Promise(s=>{let o=!1,a=l=>{if(!o){o=!0;try{i.destroy()}catch{}s(l)}},i=vP({host:r,port:e},()=>a(!0));i.setTimeout(t,()=>a(!1)),i.on("error",()=>a(!1)),i.on("timeout",()=>a(!1)),n&&(n.aborted?a(!1):n.addEventListener("abort",()=>a(!1),{once:!0}))})}function SP(r){return r==="https:"?443:80}async function Jv(r,e={}){let{enableDns:t=!0,enableTcpProbe:n=!0,enableHttpsUpgrade:s=!0,tcpProbeTimeoutMs:o=bP,dnsTimeoutMs:a=_P,signal:i,allowPrivateNetwork:l=!1}=e,c;try{c=new URL(r)}catch{return{ok:!1,reason:"invalid_url",message:kr("invalid_url",r)}}if(c.protocol!=="http:"&&c.protocol!=="https:")return{ok:!1,reason:"invalid_protocol",message:kr("invalid_protocol",c.host)};let u=c.host.split(":")[0].startsWith("[")?c.host.match(/\[[^\]]+\]/)?.[0]??c.hostname:c.hostname;if(!u)return{ok:!1,reason:"invalid_host",message:kr("invalid_host",c.host)};let h=Zr(u),f=h!==null,p=/^\d{1,3}(\.\d{1,3}){3}$/.test(u)||u.startsWith("[")&&u.endsWith("]");if(!l&&h)return{ok:!1,reason:h,message:kr(h,u),detail:{host:u,layer:"static"}};let m=null,d=!1;if(t&&(!l||!f)&&!p){if(m=await wP(u,a),!m)return{ok:!1,reason:"dns_failed",message:kr("dns_failed",u),detail:{host:u,layer:"dns"}};for(let y of m){let v=Zr(y);if(v){if(!l)return{ok:!1,reason:"dns_resolves_private",message:kr("dns_resolves_private",u),detail:{host:u,resolvedIp:y,baseReason:v,layer:"dns"}};d=!0}}}if(n){let y=m?.[0]??u.replace(/^\[|\]$/g,""),v=c.port?parseInt(c.port,10):SP(c.protocol);if(!await Yv(y,v,o,i)){if(s&&c.protocol==="http:"&&!c.port&&await Yv(y,443,o,i)){let S=new URL(r);return S.protocol="https:",{ok:!1,reason:"tcp_unreachable",message:`${c.host} isn't responding on http://, but https:// is \u2014 try ${S.href}.`,suggestedUrl:S.href,detail:{host:u,probedPort:v,httpsAlternative:!0,layer:"tcp-probe"}}}return{ok:!1,reason:"tcp_unreachable",message:l&&(f||d)?`Couldn't open a connection to ${u}. If this is a local target, make sure a service is listening on the port.`:kr("tcp_unreachable",u),detail:{host:u,probedPort:v,layer:"tcp-probe"}}}}return{ok:!0}}var xP=["ERR_CERT_AUTHORITY_INVALID","ERR_CERT_DATE_INVALID","ERR_CERT_COMMON_NAME_INVALID"];function Kv(r){if(!(r instanceof Error))return null;for(let e of xP)if(r.message.includes(e))return e;return null}function Qv(r){let e;try{e=new URL(r)}catch{return null}return e.protocol!=="https:"||e.username||e.password?null:`http://${e.port?`${e.hostname}:${e.port}`:e.hostname}${e.pathname}${e.search}${e.hash}`}typeof process<"u"&&process.env&&(process.env.PW_TEST_SCREENSHOT_NO_FONTS_READY="1");var $o=new WeakMap;function TP(){return{pendingWrites:new Set,rollingConsoleErrors:[],rollingPageErrors:[],rollingFailedRequests:[],rollingRecentWrites:[]}}function IP(r){try{return new URL(r).origin}catch{return null}}function Ci(r){if($o.has(r))return;let e=TP();$o.set(r,e),r.on("request",t=>{let n;try{n=r.url()}catch{return}let s=IP(n);if(!s)return;let o={method:()=>t.method(),url:()=>t.url(),resourceType:()=>t.resourceType(),isMainFrame:t.frame()===r.mainFrame()};Vv(o,s)&&e.pendingWrites.add({request:t,startTs:Date.now(),url:t.url(),method:t.method()})}),r.on("response",t=>{let n=t.request();for(let s of e.pendingWrites)if(s.request===n){e.pendingWrites.delete(s),e.rollingRecentWrites.push({url:s.url,method:s.method,status:t.status(),durationMs:Date.now()-s.startTs});break}}),r.on("requestfailed",t=>{for(let n of e.pendingWrites)if(n.request===t){e.pendingWrites.delete(n);let s=t.failure()?.errorText??"unknown";e.rollingFailedRequests.push({url:n.url,method:n.method,error:s});break}}),r.on("framenavigated",t=>{t===r.mainFrame()&&e.pendingWrites.clear()}),r.on("console",t=>{t.type()==="error"&&(e.rollingConsoleErrors.length>=5||e.rollingConsoleErrors.push({text:t.text().slice(0,500)}))}),r.on("pageerror",t=>{e.rollingPageErrors.length>=5||e.rollingPageErrors.push({name:t.name,message:String(t.message).slice(0,500)})})}async function EP(r,e){let t=e?.seedCookies,n=e?.seedLocalStorage;if(Array.isArray(t)&&t.length>0)try{await r.addCookies(t),console.log(`[BasePlaywright] Seeded ${t.length} cookie(s) into context`)}catch(s){let o=s instanceof Error?s.message:String(s);console.warn(`[BasePlaywright] addCookies failed: ${o}`)}if(Array.isArray(n)&&n.length>0){let s={};for(let o of n)try{let a=new URL(o.url).origin;s[a]={...s[a]??{},...o.items}}catch{}if(Object.keys(s).length===0)return;try{await r.addInitScript(o=>{try{let a=o.byOrigin[location.origin];if(!a)return;for(let i of Object.keys(a))try{localStorage.setItem(i,a[i])}catch{}}catch{}},{byOrigin:s}),console.log(`[BasePlaywright] Seeded localStorage for origins: ${Object.keys(s).join(", ")}`)}catch(o){let a=o instanceof Error?o.message:String(o);console.warn(`[BasePlaywright] addInitScript (seedLocalStorage) failed: ${a}`)}}}function Xv(r){let e=r.closest('button,input,select,textarea,option,[role="button"],[role="menuitem"],[role="checkbox"],[role="radio"],[role="switch"],[role="tab"],a[href]')??r,t=(e.textContent||"").trim().replace(/\s+/g," ").slice(0,80),n=e.getAttribute("aria-label")||e.getAttribute("title")||"",o=(e.getAttribute("aria-labelledby")||"").split(/\s+/).map(m=>document.getElementById(m)?.textContent?.trim()||"").filter(Boolean).join(" "),a="";(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)&&(a=Array.from(e.labels??[]).map(m=>m.textContent?.trim()||"").filter(Boolean).join(" "));let i=(e instanceof HTMLButtonElement||e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement||e instanceof HTMLOptionElement)&&e.disabled,l=e.getAttribute("aria-disabled")==="true"||!!e.closest('[aria-disabled="true"]'),c=!!e.closest("[inert]"),u=i||l||c,h=i?"native-disabled":l?"aria-disabled":c?"inert":void 0,f=e instanceof HTMLButtonElement||e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement?e.form:e.closest("form"),p=f instanceof HTMLFormElement?Array.from(f.querySelectorAll("input,select,textarea")).filter(m=>(m instanceof HTMLInputElement||m instanceof HTMLSelectElement||m instanceof HTMLTextAreaElement)&&m.required&&!m.disabled&&!m.checkValidity()).map(m=>({label:Array.from(m.labels??[]).map(y=>y.textContent?.trim()||"").filter(Boolean).join(" ")||m.getAttribute("aria-label")||m.getAttribute("placeholder")||m.name||m.id||m.type||m.tagName.toLowerCase(),name:m.name||m.id||"",type:m instanceof HTMLInputElement?m.type:m instanceof HTMLSelectElement?"select":"textarea"})):[];return{tag:e.tagName.toLowerCase(),text:t,role:e.getAttribute("role")||"",accessibleName:[n,o,a,t].find(m=>m.trim())||"",disabled:u,nativeDisabled:i,ariaDisabled:l,inert:c,...h?{disabledReason:h}:{},...p.length?{form:{unmetRequiredFields:p}}:{}}}var kP={backspace:"Backspace",tab:"Tab",return:"Enter",enter:"Enter",shift:"Shift",control:"ControlOrMeta",alt:"Alt",escape:"Escape",space:"Space",pageup:"PageUp",pagedown:"PageDown",end:"End",home:"Home",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",insert:"Insert",delete:"Delete",semicolon:";",equals:"=",multiply:"Multiply",add:"Add",separator:"Separator",subtract:"Subtract",decimal:"Decimal",divide:"Divide",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",command:"Meta",meta:"Meta"},ou=new Set(["Shift","Control","ControlOrMeta","Alt","Meta"]),Mi=class extends Error{action;coordinate;received;reason;name="InvalidBrowserActionCoordinatesError";constructor(e,t,n,s){super(`Invalid coordinates for ${e}: ${t} ${s} (received ${AP(n)})`),this.action=e,this.coordinate=t,this.received=n,this.reason=s}};function AP(r){return r===void 0?"missing":r===null?"null":typeof r=="number"?Number.isNaN(r)?"NaN":r===1/0?"Infinity":r===-1/0?"-Infinity":String(r):typeof r=="string"?JSON.stringify(r):`${typeof r}:${String(r)}`}var Oi=class r{browser=null;sessions=new Map;browserShutdownExpected=!1;onBrowserDisconnected;diagLog;requireNormalizedPoint(e,t,n="x",s="y"){return{x:this.requireNormalizedCoordinate(e,t,n),y:this.requireNormalizedCoordinate(e,t,s)}}normalizeTestingEmailForFocusedField(e,t,n){let s={testingEmailPolicy:e.testingEmailPolicy},o=wt(s);return o&&Hr({config:s,text:t,inputType:n.inputType,label:n.label,matchedLabel:n.matchedLabel})?o.canonicalEmail:t}requireNormalizedCoordinate(e,t,n){let s=t[n],o=typeof s=="number"?s:typeof s=="string"&&s.trim()!==""?Number(s):NaN;if(!Number.isFinite(o))throw new Mi(e,n,s,"must be a finite number in normalized 0-1000 coordinates");if(o<0||o>1e3)throw new Mi(e,n,s,"must be between 0 and 1000 in normalized coordinates");return o}async launchBrowser(){let{chromium:e}=await import("playwright");return e.launch({headless:!0,args:["--disable-extensions","--disable-file-system","--disable-plugins","--disable-dev-shm-usage","--disable-background-networking","--disable-default-apps","--disable-sync","--no-sandbox",...Rc]})}async createSession(e,t){let n=t?.initialUrl,s=n&&n!=="about:blank"?Cr(n):null;if(s){let h=await Jv(s,{allowPrivateNetwork:this.preflightAllowsPrivateNetwork()});if(!h.ok)throw new ar(h)}let o=await this.ensureBrowser(),a=t?.screenWidth??1280,i=t?.screenHeight??720,l=await o.newContext({viewport:{width:a,height:i},acceptDownloads:!0,userAgent:Cc(o.version())});await Mc(l),await EP(l,t);let c=await l.newPage();process.env.AQ_NO_DOM_OBSERVER||(await c.addInitScript(mr.script()),await mr.install(c)),Ci(c);let u={sessionId:e,context:l,page:c,viewportWidth:a,viewportHeight:i,needsFullSnapshot:!1,isExtensionSession:!1,tab1:c,activeTab:"tab1",pendingExtensionPopup:!1,extensionId:void 0,browserNavigationScope:Array.isArray(t?.browserNavigationScope)?t.browserNavigationScope.map(String):void 0,allowExternalNavigation:!!t?.allowExternalNavigation,testingEmailPolicy:wt(t)??void 0,lastInvokeAt:Date.now()};if(l.on("page",async h=>{Ci(h);try{if(await h.waitForLoadState("domcontentloaded",{timeout:5e3}).catch(()=>{}),u.tab2&&!u.tab2.isClosed())try{await u.tab2.close()}catch{}u.tab2=h,u.page=h,u.activeTab="tab2",u.needsFullSnapshot=!0,h.on("dialog",f=>f.accept()),h.on("close",()=>{u.tab2===h&&(u.tab2=void 0,u.activeTab==="tab2"&&(u.page=u.tab1,u.activeTab="tab1",u.needsFullSnapshot=!0))})}catch{try{await h.close()}catch{}}}),c.on("dialog",h=>h.accept()),s){let h=null,f=s;try{h=await c.goto(s,{waitUntil:"domcontentloaded"})}catch(p){let m=Kv(p),d=m?Qv(s):null;if(!m||!d)throw p;this.diagLog?.(e,"https_cert_fallback_attempt",{originalUrl:s,fallbackUrl:d,errorCode:m});let y=(()=>{try{return new URL(s)}catch{return null}})();u.httpsCertFallback={originalUrl:s,fallbackUrl:d,host:y?.hostname??"",errorCode:m},await c.waitForURL("chrome-error://**",{timeout:3e3}).catch(()=>{});try{h=await c.goto(d,{waitUntil:"domcontentloaded"}),f=d,this.diagLog?.(e,"https_cert_fallback_success",{originalUrl:u.httpsCertFallback.originalUrl,fallbackUrl:u.httpsCertFallback.fallbackUrl,host:u.httpsCertFallback.host,errorCode:u.httpsCertFallback.errorCode})}catch{throw u.httpsCertFallback=void 0,p}}await this.awaitPageReady(c),await this.assertNoCloudflareBlock(c,h,f)}return u}preflightAllowsPrivateNetwork(){return process.env.AGENTIQA_E2E==="1"}async assertNoCloudflareBlock(e,t,n){if(!this.cloudflareDetectorEnabled())return;let s=t?.headers(),o=t?.status(),a,i;try{a=await e.title()}catch{}try{i=await e.content(),i&&i.length>8192&&(i=i.slice(0,8192))}catch{}let l=Ug({url:n,status:o,headers:s,title:a,html:i});if(l)throw new en(l)}cloudflareDetectorEnabled(){return!0}async dispatchPlatformAction(e,t,n){}async onFilesUploaded(e){return[]}async onBeforeAction(e,t,n){if(!(t==null||n==null))try{await e.page.evaluate(({x:s,y:o})=>{let a=document.getElementById("__agentiqa_cursor");a||(a=document.createElement("div"),a.id="__agentiqa_cursor",a.style.cssText=`
1579
+ `)}import{promises as Gv}from"node:dns";import{createConnection as vP}from"node:net";var bP=2e3,_P=1e3;async function wP(r,e){let t=Gv.resolve4(r).catch(()=>[]),n=Gv.resolve6(r).catch(()=>[]),s=new Promise(i=>setTimeout(()=>i([]),e)),o=Promise.all([t,n]).then(([i,l])=>[...i,...l]),a=await Promise.race([o,s]);return a.length>0?a:null}async function Yv(r,e,t,n){return new Promise(s=>{let o=!1,a=l=>{if(!o){o=!0;try{i.destroy()}catch{}s(l)}},i=vP({host:r,port:e},()=>a(!0));i.setTimeout(t,()=>a(!1)),i.on("error",()=>a(!1)),i.on("timeout",()=>a(!1)),n&&(n.aborted?a(!1):n.addEventListener("abort",()=>a(!1),{once:!0}))})}function SP(r){return r==="https:"?443:80}async function Jv(r,e={}){let{enableDns:t=!0,enableTcpProbe:n=!0,enableHttpsUpgrade:s=!0,tcpProbeTimeoutMs:o=bP,dnsTimeoutMs:a=_P,signal:i,allowPrivateNetwork:l=!1}=e,c;try{c=new URL(r)}catch{return{ok:!1,reason:"invalid_url",message:kr("invalid_url",r)}}if(c.protocol!=="http:"&&c.protocol!=="https:")return{ok:!1,reason:"invalid_protocol",message:kr("invalid_protocol",c.host)};let u=c.host.split(":")[0].startsWith("[")?c.host.match(/\[[^\]]+\]/)?.[0]??c.hostname:c.hostname;if(!u)return{ok:!1,reason:"invalid_host",message:kr("invalid_host",c.host)};let h=Zr(u),f=h!==null,p=/^\d{1,3}(\.\d{1,3}){3}$/.test(u)||u.startsWith("[")&&u.endsWith("]");if(!l&&h)return{ok:!1,reason:h,message:kr(h,u),detail:{host:u,layer:"static"}};let m=null,d=!1;if(t&&(!l||!f)&&!p){if(m=await wP(u,a),!m)return{ok:!1,reason:"dns_failed",message:kr("dns_failed",u),detail:{host:u,layer:"dns"}};for(let y of m){let v=Zr(y);if(v){if(!l)return{ok:!1,reason:"dns_resolves_private",message:kr("dns_resolves_private",u),detail:{host:u,resolvedIp:y,baseReason:v,layer:"dns"}};d=!0}}}if(n){let y=m?.[0]??u.replace(/^\[|\]$/g,""),v=c.port?parseInt(c.port,10):SP(c.protocol);if(!await Yv(y,v,o,i)){if(s&&c.protocol==="http:"&&!c.port&&await Yv(y,443,o,i)){let S=new URL(r);return S.protocol="https:",{ok:!1,reason:"tcp_unreachable",message:`${c.host} isn't responding on http://, but https:// is \u2014 try ${S.href}.`,suggestedUrl:S.href,detail:{host:u,probedPort:v,httpsAlternative:!0,layer:"tcp-probe"}}}return{ok:!1,reason:"tcp_unreachable",message:l&&(f||d)?`Couldn't open a connection to ${u}. If this is a local target, make sure a service is listening on the port.`:kr("tcp_unreachable",u),detail:{host:u,probedPort:v,layer:"tcp-probe"}}}}return{ok:!0}}var xP=["ERR_CERT_AUTHORITY_INVALID","ERR_CERT_DATE_INVALID","ERR_CERT_COMMON_NAME_INVALID"];function Kv(r){if(!(r instanceof Error))return null;for(let e of xP)if(r.message.includes(e))return e;return null}function Qv(r){let e;try{e=new URL(r)}catch{return null}return e.protocol!=="https:"||e.username||e.password?null:`http://${e.port?`${e.hostname}:${e.port}`:e.hostname}${e.pathname}${e.search}${e.hash}`}typeof process<"u"&&process.env&&(process.env.PW_TEST_SCREENSHOT_NO_FONTS_READY="1");var $o=new WeakMap;function TP(){return{pendingWrites:new Set,rollingConsoleErrors:[],rollingPageErrors:[],rollingFailedRequests:[],rollingRecentWrites:[]}}function IP(r){try{return new URL(r).origin}catch{return null}}function Ci(r){if($o.has(r))return;let e=TP();$o.set(r,e),r.on("request",t=>{let n;try{n=r.url()}catch{return}let s=IP(n);if(!s)return;let o={method:()=>t.method(),url:()=>t.url(),resourceType:()=>t.resourceType(),isMainFrame:t.frame()===r.mainFrame()};Vv(o,s)&&e.pendingWrites.add({request:t,startTs:Date.now(),url:t.url(),method:t.method()})}),r.on("response",t=>{let n=t.request();for(let s of e.pendingWrites)if(s.request===n){e.pendingWrites.delete(s),e.rollingRecentWrites.push({url:s.url,method:s.method,status:t.status(),durationMs:Date.now()-s.startTs});break}}),r.on("requestfailed",t=>{for(let n of e.pendingWrites)if(n.request===t){e.pendingWrites.delete(n);let s=t.failure()?.errorText??"unknown";e.rollingFailedRequests.push({url:n.url,method:n.method,error:s});break}}),r.on("framenavigated",t=>{t===r.mainFrame()&&e.pendingWrites.clear()}),r.on("console",t=>{t.type()==="error"&&(e.rollingConsoleErrors.length>=5||e.rollingConsoleErrors.push({text:t.text().slice(0,500)}))}),r.on("pageerror",t=>{e.rollingPageErrors.length>=5||e.rollingPageErrors.push({name:t.name,message:String(t.message).slice(0,500)})})}async function EP(r,e){let t=e?.seedCookies,n=e?.seedLocalStorage;if(Array.isArray(t)&&t.length>0)try{await r.addCookies(t),console.log(`[BasePlaywright] Seeded ${t.length} cookie(s) into context`)}catch(s){let o=s instanceof Error?s.message:String(s);console.warn(`[BasePlaywright] addCookies failed: ${o}`)}if(Array.isArray(n)&&n.length>0){let s={};for(let o of n)try{let a=new URL(o.url).origin;s[a]={...s[a]??{},...o.items}}catch{}if(Object.keys(s).length===0)return;try{await r.addInitScript(o=>{try{let a=o.byOrigin[location.origin];if(!a)return;for(let i of Object.keys(a))try{localStorage.setItem(i,a[i])}catch{}}catch{}},{byOrigin:s}),console.log(`[BasePlaywright] Seeded localStorage for origins: ${Object.keys(s).join(", ")}`)}catch(o){let a=o instanceof Error?o.message:String(o);console.warn(`[BasePlaywright] addInitScript (seedLocalStorage) failed: ${a}`)}}}function Xv(r){let e=r.closest('button,input,select,textarea,option,[role="button"],[role="menuitem"],[role="checkbox"],[role="radio"],[role="switch"],[role="tab"],a[href]')??r,t=(e.textContent||"").trim().replace(/\s+/g," ").slice(0,80),n=e.getAttribute("aria-label")||e.getAttribute("title")||"",o=(e.getAttribute("aria-labelledby")||"").split(/\s+/).map(m=>document.getElementById(m)?.textContent?.trim()||"").filter(Boolean).join(" "),a="";(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)&&(a=Array.from(e.labels??[]).map(m=>m.textContent?.trim()||"").filter(Boolean).join(" "));let i=(e instanceof HTMLButtonElement||e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement||e instanceof HTMLOptionElement)&&e.disabled,l=e.getAttribute("aria-disabled")==="true"||!!e.closest('[aria-disabled="true"]'),c=!!e.closest("[inert]"),u=i||l||c,h=i?"native-disabled":l?"aria-disabled":c?"inert":void 0,f=e instanceof HTMLButtonElement||e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement?e.form:e.closest("form"),p=f instanceof HTMLFormElement?Array.from(f.querySelectorAll("input,select,textarea")).filter(m=>(m instanceof HTMLInputElement||m instanceof HTMLSelectElement||m instanceof HTMLTextAreaElement)&&m.required&&!m.disabled&&!m.checkValidity()).map(m=>({label:Array.from(m.labels??[]).map(y=>y.textContent?.trim()||"").filter(Boolean).join(" ")||m.getAttribute("aria-label")||m.getAttribute("placeholder")||m.name||m.id||m.type||m.tagName.toLowerCase(),name:m.name||m.id||"",type:m instanceof HTMLInputElement?m.type:m instanceof HTMLSelectElement?"select":"textarea"})):[];return{tag:e.tagName.toLowerCase(),text:t,role:e.getAttribute("role")||"",accessibleName:[n,o,a,t].find(m=>m.trim())||"",disabled:u,nativeDisabled:i,ariaDisabled:l,inert:c,...h?{disabledReason:h}:{},...p.length?{form:{unmetRequiredFields:p}}:{}}}var kP={backspace:"Backspace",tab:"Tab",return:"Enter",enter:"Enter",shift:"Shift",control:"ControlOrMeta",alt:"Alt",escape:"Escape",space:"Space",pageup:"PageUp",pagedown:"PageDown",end:"End",home:"Home",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",insert:"Insert",delete:"Delete",semicolon:";",equals:"=",multiply:"Multiply",add:"Add",separator:"Separator",subtract:"Subtract",decimal:"Decimal",divide:"Divide",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",command:"Meta",meta:"Meta"},ou=new Set(["Shift","Control","ControlOrMeta","Alt","Meta"]),Mi=class extends Error{action;coordinate;received;reason;name="InvalidBrowserActionCoordinatesError";constructor(e,t,n,s){super(`Invalid coordinates for ${e}: ${t} ${s} (received ${AP(n)})`),this.action=e,this.coordinate=t,this.received=n,this.reason=s}};function AP(r){return r===void 0?"missing":r===null?"null":typeof r=="number"?Number.isNaN(r)?"NaN":r===1/0?"Infinity":r===-1/0?"-Infinity":String(r):typeof r=="string"?JSON.stringify(r):`${typeof r}:${String(r)}`}var Oi=class r{browser=null;sessions=new Map;browserShutdownExpected=!1;onBrowserDisconnected;diagLog;requireNormalizedPoint(e,t,n="x",s="y"){return{x:this.requireNormalizedCoordinate(e,t,n),y:this.requireNormalizedCoordinate(e,t,s)}}normalizeTestingEmailForFocusedField(e,t,n){let s={testingEmailPolicy:e.testingEmailPolicy,isTestPlanReplay:e.isTestPlanReplay},o=wt(s);return o&&Hr({config:s,text:t,inputType:n.inputType,label:n.label,matchedLabel:n.matchedLabel})?o.canonicalEmail:t}requireNormalizedCoordinate(e,t,n){let s=t[n],o=typeof s=="number"?s:typeof s=="string"&&s.trim()!==""?Number(s):NaN;if(!Number.isFinite(o))throw new Mi(e,n,s,"must be a finite number in normalized 0-1000 coordinates");if(o<0||o>1e3)throw new Mi(e,n,s,"must be between 0 and 1000 in normalized coordinates");return o}async launchBrowser(){let{chromium:e}=await import("playwright");return e.launch({headless:!0,args:["--disable-extensions","--disable-file-system","--disable-plugins","--disable-dev-shm-usage","--disable-background-networking","--disable-default-apps","--disable-sync","--no-sandbox",...Rc]})}async createSession(e,t){let n=t?.initialUrl,s=n&&n!=="about:blank"?Cr(n):null;if(s){let h=await Jv(s,{allowPrivateNetwork:this.preflightAllowsPrivateNetwork()});if(!h.ok)throw new ar(h)}let o=await this.ensureBrowser(),a=t?.screenWidth??1280,i=t?.screenHeight??720,l=await o.newContext({viewport:{width:a,height:i},acceptDownloads:!0,userAgent:Cc(o.version())});await Mc(l),await EP(l,t);let c=await l.newPage();process.env.AQ_NO_DOM_OBSERVER||(await c.addInitScript(mr.script()),await mr.install(c)),Ci(c);let u={sessionId:e,context:l,page:c,viewportWidth:a,viewportHeight:i,needsFullSnapshot:!1,isExtensionSession:!1,tab1:c,activeTab:"tab1",pendingExtensionPopup:!1,extensionId:void 0,browserNavigationScope:Array.isArray(t?.browserNavigationScope)?t.browserNavigationScope.map(String):void 0,allowExternalNavigation:!!t?.allowExternalNavigation,testingEmailPolicy:wt(t)??void 0,lastInvokeAt:Date.now()};if(l.on("page",async h=>{Ci(h);try{if(await h.waitForLoadState("domcontentloaded",{timeout:5e3}).catch(()=>{}),u.tab2&&!u.tab2.isClosed())try{await u.tab2.close()}catch{}u.tab2=h,u.page=h,u.activeTab="tab2",u.needsFullSnapshot=!0,h.on("dialog",f=>f.accept()),h.on("close",()=>{u.tab2===h&&(u.tab2=void 0,u.activeTab==="tab2"&&(u.page=u.tab1,u.activeTab="tab1",u.needsFullSnapshot=!0))})}catch{try{await h.close()}catch{}}}),c.on("dialog",h=>h.accept()),s){let h=null,f=s;try{h=await c.goto(s,{waitUntil:"domcontentloaded"})}catch(p){let m=Kv(p),d=m?Qv(s):null;if(!m||!d)throw p;this.diagLog?.(e,"https_cert_fallback_attempt",{originalUrl:s,fallbackUrl:d,errorCode:m});let y=(()=>{try{return new URL(s)}catch{return null}})();u.httpsCertFallback={originalUrl:s,fallbackUrl:d,host:y?.hostname??"",errorCode:m},await c.waitForURL("chrome-error://**",{timeout:3e3}).catch(()=>{});try{h=await c.goto(d,{waitUntil:"domcontentloaded"}),f=d,this.diagLog?.(e,"https_cert_fallback_success",{originalUrl:u.httpsCertFallback.originalUrl,fallbackUrl:u.httpsCertFallback.fallbackUrl,host:u.httpsCertFallback.host,errorCode:u.httpsCertFallback.errorCode})}catch{throw u.httpsCertFallback=void 0,p}}await this.awaitPageReady(c),await this.assertNoCloudflareBlock(c,h,f)}return u}preflightAllowsPrivateNetwork(){return process.env.AGENTIQA_E2E==="1"}async assertNoCloudflareBlock(e,t,n){if(!this.cloudflareDetectorEnabled())return;let s=t?.headers(),o=t?.status(),a,i;try{a=await e.title()}catch{}try{i=await e.content(),i&&i.length>8192&&(i=i.slice(0,8192))}catch{}let l=Ug({url:n,status:o,headers:s,title:a,html:i});if(l)throw new en(l)}cloudflareDetectorEnabled(){return!0}async dispatchPlatformAction(e,t,n){}async onFilesUploaded(e){return[]}async onBeforeAction(e,t,n){if(!(t==null||n==null))try{await e.page.evaluate(({x:s,y:o})=>{let a=document.getElementById("__agentiqa_cursor");a||(a=document.createElement("div"),a.id="__agentiqa_cursor",a.style.cssText=`
1579
1580
  position: fixed;
1580
1581
  width: 20px;
1581
1582
  height: 20px;
@@ -1586,7 +1587,7 @@ Reply with ONLY the title, no quotes, no punctuation at the end.`,v=ys(Ko,t);n&&
1586
1587
  z-index: 999999;
1587
1588
  transform: translate(-50%, -50%);
1588
1589
  transition: left 0.1s, top 0.1s;
1589
- `,document.body.appendChild(a)),a.style.left=`${s}px`,a.style.top=`${o}px`},{x:t,y:n})}catch{}}getSuggestedSampleFiles(e,t){return[]}async ensureBrowser(){if(!this.browser){console.log("[BasePlaywright] Launching browser");let e=performance.now();this.browser=await this.launchBrowser();let t=Math.round(performance.now()-e);console.log(`[BasePlaywright] Browser launched in ${t}ms`),this.browser.on("disconnected",()=>{console.log("[BasePlaywright] Browser disconnected"),this.browser=null,this.sessions.clear(),this.onBrowserDisconnected?.()})}return this.browser}async ensureSession(e,t){if(this.sessions.has(e))return this.sessions.get(e);e.includes(":child-")||await this.cleanupOtherSessions(e);let n=await this.createSession(e,t);return this.sessions.set(e,n),n}async invoke(e){let t=await this.ensureSession(e.sessionId,e.config);t.lastInvokeAt=Date.now(),t.browserNavigationScope=Array.isArray(e.config?.browserNavigationScope)?e.config.browserNavigationScope.map(String):void 0,t.allowExternalNavigation=!!e.config?.allowExternalNavigation,t.testingEmailPolicy=wt(e.config)??void 0;let n=e.args??{},s=performance.now(),o,a;try{let i=await this.dispatch(t,e.action,n);i=this.withSessionMetadata(t,i);let l=Math.round(performance.now()-s);if(console.log(`[BasePlaywright] ${e.action} completed in ${l}ms`),t.tab2||t.isExtensionSession){let c=t.tab1&&!t.tab1.isClosed(),u=t.tab2&&!t.tab2.isClosed(),h=[];c&&h.push(t.tab1.url()),u&&h.push(t.tab2.url()),i={...i,metadata:{activeTab:t.activeTab,tabCount:(c?1:0)+(u?1:0),tabUrls:h,...t.pendingExtensionPopup?{pendingExtensionPopup:!0}:{},...i.metadata}},t.pendingExtensionPopup=!1}o={screenshot:i.screenshot.toString("base64"),url:i.url,aiSnapshot:i.aiSnapshot,domChanges:i.domChanges,metadata:i.metadata},a=t.page}catch(i){let l=String(i?.message||"");if(l.includes("Execution context was destroyed")||l.includes("most likely because of a navigation")||l.includes("navigation")){console.log(`[BasePlaywright] Navigation detected during ${e.action}, recovering`),t.needsFullSnapshot=!0;try{await t.page.waitForLoadState("load",{timeout:5e3})}catch{}let c=await this.captureState(t),u=this.withSessionMetadata(t,c);o={screenshot:u.screenshot.toString("base64"),url:u.url,aiSnapshot:u.aiSnapshot,metadata:u.metadata},a=t.page}else if(l.includes("Browser session closed")||l.includes("Target closed")||l.includes("has been closed")||l.includes("Page crashed")){console.log(`[BasePlaywright] Session closed for ${e.sessionId}, recreating`),this.sessions.delete(e.sessionId);try{let c=await this.ensureSession(e.sessionId,e.config),u=this.withSessionMetadata(c,await this.dispatch(c,e.action,n));o={screenshot:u.screenshot.toString("base64"),url:u.url,aiSnapshot:u.aiSnapshot,metadata:u.metadata},a=c.page}catch(c){console.error("[BasePlaywright] Retry after session recreation failed:",c);let u=c instanceof Error?c.message:String(c);throw new Error(`Browser session recovery failed: ${u}`)}}else throw i}return o.metadata={...o.metadata??{},events:this.buildAndResetDigest(a)},o}buildAndResetDigest(e){let t=e?$o.get(e):void 0;if(!t)return{consoleErrors:[],pageErrors:[],failedRequests:[],pendingRequests:[],recentWrites:[]};let n=Date.now(),s={consoleErrors:t.rollingConsoleErrors.slice(),pageErrors:t.rollingPageErrors.slice(),failedRequests:t.rollingFailedRequests.slice(),pendingRequests:Array.from(t.pendingWrites).map(o=>({url:o.url,method:o.method,ageMs:n-o.startTs})),recentWrites:t.rollingRecentWrites.slice()};return t.rollingConsoleErrors=[],t.rollingPageErrors=[],t.rollingFailedRequests=[],t.rollingRecentWrites=[],s}async getFocusedFieldName(e){try{return await e.evaluate(()=>{let t=document.activeElement;if(!t||t===document.body)return;let n=u=>{let h=[];for(let f of Array.from(u.childNodes))if(f.nodeType===Node.TEXT_NODE){let p=f.textContent?.trim();p&&h.push(p)}else if(f instanceof HTMLElement&&!s(f)){let p=f.innerText?.trim();p&&h.push(p)}return h.join(" ").replace(/\s+/g," ").trim()},s=u=>u instanceof HTMLInputElement||u instanceof HTMLTextAreaElement||u instanceof HTMLSelectElement||u.isContentEditable,o=t.getAttribute("aria-label");if(o)return o;let a=t.getAttribute("aria-labelledby");if(a){let u=a.split(/\s+/).map(h=>document.getElementById(h)?.textContent?.trim()).filter(Boolean).join(" ");if(u)return u}if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){let u=t.labels?.[0]?.textContent?.trim();if(u)return u}let i=t.id;if(i){let u=document.querySelector(`label[for="${i}"]`);if(u)return u.textContent?.trim()}if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){if(t.placeholder)return t.placeholder;if(t.name)return t.name}let l=t.previousElementSibling;for(;l;){let u=l instanceof HTMLElement?l.innerText?.trim():void 0;if(u)return u;l=l.previousElementSibling}let c=t.parentElement;for(let u=0;c&&u<3;u+=1,c=c.parentElement){let h=n(c);if(h)return h}})}catch{return}}async awaitPageReady(e){await e.waitForLoadState("domcontentloaded",{timeout:5e3}).catch(()=>{})}async screenshotWithSlowSiteRetry(e,t={}){let{page:n}=e,s=(e.screenshotCount??0)===0,o=15e3,a=25e3,l={type:"png",timeout:s?o:5e3};t.fullPage&&(l.fullPage=!0);try{let c=await n.screenshot(l);return e.screenshotCount=(e.screenshotCount??0)+1,c}catch(c){if(!s||!fc(c))throw c;let u=n.url();this.diagLog?.(e.sessionId,"screenshot_first_timeout_retry",{url:u,firstTimeoutMs:o,retryTimeoutMs:a});let h={type:"png",timeout:a};t.fullPage&&(h.fullPage=!0);try{let f=await n.screenshot(h);return e.screenshotCount=(e.screenshotCount??0)+1,this.diagLog?.(e.sessionId,"screenshot_first_retry_success",{url:u}),f}catch(f){throw fc(f)?new tn({url:u,totalTimeoutMs:o+a,attemptCount:2}):f}}}async captureState(e){let{page:t}=e;e.expectDomQuiescence&&!process.env.AQ_NO_DOM_OBSERVER&&!process.env.AQ_NO_DOM_DELAY&&await mr.waitForQuiescence(t,{minQuietMs:100,maxMs:800});let n=await this.screenshotWithSlowSiteRetry(e),s=t.url(),o;try{let i=await t._snapshotForAI({track:e.sessionId+":"+e.activeTab}),l=typeof i=="string"?i:i?.full,c=typeof i=="object"?i?.incremental:void 0;!e.needsFullSnapshot&&c?o=c:(o=l,e.needsFullSnapshot=!1)}catch{o=void 0,e.needsFullSnapshot=!0}let a=process.env.AQ_NO_DOM_OBSERVER?void 0:await mr.flush(t)??void 0;return{screenshot:n,url:s,aiSnapshot:o,domChanges:a}}withSessionMetadata(e,t){return e.httpsCertFallback?{...t,metadata:{...t.metadata??{},httpsCertFallback:e.httpsCertFallback}}:t}shouldResetDomObserverBeforeAction(e){return!new Set(["open_web_browser","screenshot","snapshot","wait","wait_5_seconds","wait_for_element","full_page_screenshot","run_js"]).has(e)}shouldWaitForDomQuiescenceAfterAction(e){return this.shouldResetDomObserverBeforeAction(e)}async dispatch(e,t,n){let s=await this.dispatchPlatformAction(e,t,n);if(s)return s;let{viewportWidth:o,viewportHeight:a}=e,i=h=>Math.floor(h/1e3*o),l=h=>Math.floor(h/1e3*a),c=!process.env.AQ_NO_DOM_OBSERVER&&this.shouldResetDomObserverBeforeAction(t),u=e.expectDomQuiescence;c&&await mr.reset(e.page),e.expectDomQuiescence=this.shouldWaitForDomQuiescenceAfterAction(t);try{switch(t){case"open_web_browser":case"screenshot":return await this.captureState(e);case"snapshot":return e.needsFullSnapshot=!0,await this.captureState(e);case"click_at":{let h=Array.isArray(n.modifiers)?n.modifiers.map(String):[];if(n.ref)return await this.clickByRef(e,String(n.ref),h);let f=this.requireNormalizedPoint(t,n);return await this.clickAt(e,i(f.x),l(f.y),h)}case"right_click_at":{if(n.ref)return await this.rightClickByRef(e,String(n.ref));let h=this.requireNormalizedPoint(t,n);return await this.rightClickAt(e,i(h.x),l(h.y))}case"hover_at":{if(n.ref)return await this.hoverByRef(e,String(n.ref));let h=this.requireNormalizedPoint(t,n);return await this.hoverAt(e,i(h.x),l(h.y))}case"type_text_at":{let h=n.clearBeforeTyping??n.clear_before_typing??!0;if(n.label)return await this.typeByLabel(e,String(n.label),String(n.text??""),!!(n.pressEnter??n.press_enter??!1),h);if(n.ref)return await this.typeByRef(e,String(n.ref),String(n.text??""),!!(n.pressEnter??n.press_enter??!1),h);let f=this.requireNormalizedPoint(t,n);return await this.typeTextAt(e,i(f.x),l(f.y),String(n.text??""),!!(n.pressEnter??n.press_enter??!1),h)}case"scroll_document":return await this.scrollDocument(e,String(n.direction));case"scroll_to_bottom":return await this.scrollToBottom(e);case"scroll_at":{let h=String(n.direction),f=n.magnitude!=null?Number(n.magnitude):800;if(h==="up"||h==="down"?f=l(f):(h==="left"||h==="right")&&(f=i(f)),n.ref){let m=await this.resolveRefCenter(e,String(n.ref));return m?await this.scrollAt(e,m.x,m.y,h,f):await this.refNotFoundError(e,String(n.ref))}let p=this.requireNormalizedPoint(t,n);return await this.scrollAt(e,i(p.x),l(p.y),h,f)}case"wait":return await this.waitSeconds(e,Number(n.seconds||2));case"wait_for_element":return await this.waitForElement(e,String(n.textContent??""),Number(n.timeoutSeconds||5));case"wait_5_seconds":return await this.waitSeconds(e,5);case"full_page_screenshot":return await this.fullPageScreenshot(e);case"switch_layout":{let h=Number(n.width),f=Number(n.height);return e.viewportWidth=h,e.viewportHeight=f,await this.switchLayout(e,h,f)}case"go_back":return await this.goBack(e);case"go_forward":return await this.goForward(e);case"navigate":{let h=String(n.url??n.href??"");if(e.isExtensionSession){if(h.startsWith("chrome-extension://")){if(e.tab1&&!e.tab1.isClosed())await e.tab1.goto(h),await this.awaitPageReady(e.tab1);else{let f=await e.context.newPage();Ci(f),await f.goto(h),await this.awaitPageReady(f)}return e.tab1&&!e.tab1.isClosed()&&(e.page=e.tab1,e.activeTab="tab1",e.needsFullSnapshot=!0,await e.page.bringToFront()),await this.captureState(e)}e.tab2&&!e.tab2.isClosed()&&(e.page=e.tab2,e.activeTab="tab2")}else e.activeTab==="tab2"&&e.tab1&&!e.tab1.isClosed()&&(e.page=e.tab1,e.activeTab="tab1",e.needsFullSnapshot=!0);return await this.navigate(e,h)}case"key_combination":return await this.keyCombination(e,Array.isArray(n.keys)?n.keys.map(String):[]);case"set_focused_input_value":return await this.setFocusedInputValue(e,String(n.value??""));case"drag_and_drop":{let h,f;if(n.ref){let d=await this.resolveRefCenter(e,String(n.ref));if(!d)return await this.refNotFoundError(e,String(n.ref));h=d.x,f=d.y}else{let d=this.requireNormalizedPoint(t,n);h=i(d.x),f=l(d.y)}let p,m;if(n.destinationRef){let d=await this.resolveRefCenter(e,String(n.destinationRef));if(!d)return await this.refNotFoundError(e,String(n.destinationRef));p=d.x,m=d.y}else{let d=this.requireNormalizedPoint(t,n,n.destinationX!==void 0?"destinationX":"destination_x",n.destinationY!==void 0?"destinationY":"destination_y");p=i(d.x),m=l(d.y)}return await this.dragAndDrop(e,h,f,p,m)}case"upload_file":{let h=Array.isArray(n.filePaths)?n.filePaths.map(String):[String(n.filePaths??"")];return await this.uploadFile(e,h)}case"http_request":return await this.httpRequest(e,String(n.url??""),String(n.method??"GET"),n.headers,n.body!=null?String(n.body):void 0);case"run_js":return await this.runJs(e,String(n.code??""));case"switch_tab":{let h=String(n.tab??"tab1"),f=h==="main"?"tab1":h==="extension"?"tab2":h;return await this.switchTab(e,f)}case"close_tab":return await this.closeTab(e);default:return console.warn(`[BasePlaywright] Unsupported action: ${t}`),await this.captureState(e)}}finally{e.expectDomQuiescence=u}}async clickAt(e,t,n,s=[]){let{page:o}=e;try{await o.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}await this.onBeforeAction(e,t,n);let a={isSelect:!1,isMultiple:!1,selectedText:"",options:[],clickedElement:null,clickTarget:null};try{let f=await o.evaluateHandle(d=>document.elementFromPoint(d.x,d.y),{x:t,y:n}),p=f.asElement(),m=p?await p.evaluate(Xv).catch(()=>null):null;await f.dispose().catch(()=>{}),a=await o.evaluate(d=>{let y=document.elementFromPoint(d.x,d.y);if(!y)return{isSelect:!1,isMultiple:!1,selectedText:"",options:[],clickedElement:null,clickTarget:null};let v={tag:y.tagName.toLowerCase(),text:(y.textContent||"").trim().slice(0,80),role:y.getAttribute("role")||""},_=y.closest("a[href], area[href]"),b=null,S=y.closest("select");if(S)b=S;else if(y instanceof HTMLLabelElement&&y.htmlFor){let w=document.getElementById(y.htmlFor);w instanceof HTMLSelectElement&&(b=w)}else{let w=y instanceof HTMLLabelElement?y:y.closest("label");if(w){let k=w.querySelector("select");k&&(b=k)}}if(b){b.focus();let w=b.options[b.selectedIndex]?.textContent?.trim()||"",k=Array.from(b.options).map(I=>I.textContent?.trim()||I.value);return{isSelect:!0,isMultiple:b.multiple,selectedText:w,options:k,clickedElement:null,clickTarget:null}}return{isSelect:!1,isMultiple:!1,selectedText:"",options:[],clickedElement:v,clickTarget:null,linkHref:_?.href||""}},{x:t,y:n}),a.clickTarget=m}catch(f){let p=String(f?.message||"");if(!(p.includes("Execution context was destroyed")||p.includes("navigation")))throw f}if(a.isSelect&&!a.isMultiple)return await this.awaitPageReady(o),{...await this.captureState(e),metadata:{elementType:"select",valueBefore:a.selectedText,valueAfter:a.selectedText,availableOptions:a.options,...a.clickTarget?{clickTarget:a.clickTarget}:{}}};if(a.linkHref){let f=await this.blockScopedNavigationIfNeeded(e,a.linkHref);if(f)return f}let i=o.waitForEvent("filechooser",{timeout:150}).catch(()=>null),l=o.waitForEvent("download",{timeout:500}).catch(()=>null);await mr.reset(o);for(let f of s)await o.keyboard.down(f);await o.mouse.click(t,n);for(let f of s)await o.keyboard.up(f);let c=await i;if(c){let p=await c.element().evaluate(y=>{let v=y;return document.querySelectorAll("[data-agentiqa-file-target]").forEach(_=>_.removeAttribute("data-agentiqa-file-target")),v.setAttribute("data-agentiqa-file-target","true"),v instanceof HTMLInputElement?{accept:v.accept||"*",multiple:v.multiple}:{accept:"*",multiple:!1}}),m=this.getSuggestedSampleFiles(p.accept,p.multiple);return console.log(`[BasePlaywright] FILE CHOOSER INTERCEPTED: accept="${p.accept}", multiple=${p.multiple}`),{...await this.captureState(e),metadata:{elementType:"file",accept:p.accept,multiple:p.multiple,suggestedFiles:m}}}let u=await l;if(u){let f=u.suggestedFilename(),p=u.url();console.log(`[BasePlaywright] DOWNLOAD INTERCEPTED: "${f}" from ${p}`),await u.cancel();try{await o.goBack({waitUntil:"domcontentloaded",timeout:5e3})}catch{}return{...await this.captureState(e),metadata:{elementType:"download",downloadFilename:f,downloadUrl:p,clickedElement:a.clickedElement??void 0,clickTarget:a.clickTarget??void 0}}}await this.awaitPageReady(o);let h=await this.captureState(e);return a.clickedElement||a.clickTarget?{...h,metadata:{...a.clickedElement?{clickedElement:a.clickedElement}:{},...a.clickTarget?{clickTarget:a.clickTarget}:{}}}:h}async clickByRef(e,t,n=[]){let{page:s}=e,o=3e3;try{await s.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let a=s.locator(`aria-ref=${t}`),i=await a.boundingBox({timeout:o});i&&await this.onBeforeAction(e,i.x+i.width/2,i.y+i.height/2);let l=await a.evaluate(v=>({tag:v.tagName.toLowerCase(),text:(v.textContent||"").trim().slice(0,80),role:v.getAttribute("role")||"",linkHref:v.closest("a[href], area[href]")?.href})).catch(()=>null),c=await a.evaluate(Xv).catch(()=>null),u=await a.evaluate(v=>{let _=v instanceof HTMLSelectElement?v:v.closest("select");if(!_)return null;_.focus();let b=_.options[_.selectedIndex]?.textContent?.trim()||"",S=Array.from(_.options).map(w=>w.textContent?.trim()||w.value);return{selectedText:b,options:S,isMultiple:_.multiple}}).catch(()=>null);if(u&&!u.isMultiple)return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:u.selectedText,valueAfter:u.selectedText,availableOptions:u.options,...c?{clickTarget:c}:{}}};if(l?.linkHref){let v=await this.blockScopedNavigationIfNeeded(e,l.linkHref);if(v)return v}let h=s.waitForEvent("filechooser",{timeout:500}).catch(()=>null),f=s.waitForEvent("download",{timeout:500}).catch(()=>null),p=n.map(v=>v).filter(Boolean);await mr.reset(s),await a.click({force:!0,timeout:o,modifiers:p.length?p:void 0});let m=await h;if(m){let _=await m.element().evaluate(w=>{let k=w;return document.querySelectorAll("[data-agentiqa-file-target]").forEach(x=>x.removeAttribute("data-agentiqa-file-target")),k.setAttribute("data-agentiqa-file-target","true"),k instanceof HTMLInputElement?{accept:k.accept||"*",multiple:k.multiple}:{accept:"*",multiple:!1}}),b=this.getSuggestedSampleFiles(_.accept,_.multiple);return console.log(`[BasePlaywright] FILE CHOOSER INTERCEPTED via ref=${t}: accept="${_.accept}"`),{...await this.captureState(e),metadata:{elementType:"file",accept:_.accept,multiple:_.multiple,suggestedFiles:b}}}let d=await f;if(d){let v=d.suggestedFilename(),_=d.url();console.log(`[BasePlaywright] DOWNLOAD INTERCEPTED via ref=${t}: "${v}" from ${_}`),await d.cancel();try{await s.goBack({waitUntil:"domcontentloaded",timeout:5e3})}catch{}return{...await this.captureState(e),metadata:{elementType:"download",downloadFilename:v,downloadUrl:_,clickedElement:l??void 0,clickTarget:c??void 0}}}await this.awaitPageReady(s);let y=await this.captureState(e);return l||c?{...y,metadata:{...l?{clickedElement:l}:{},...c?{clickTarget:c}:{}}}:y}catch(a){console.warn(`[BasePlaywright] clickByRef ref=${t} failed: ${a.message}`);let i=await this.captureState(e),c=(a.message??"").includes("intercepts pointer events")?`Ref "${t}" is covered by another element (overlay/popup). Dismiss the overlay first, or try a different ref.`:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`;return{...i,metadata:{error:c}}}}async rightClickAt(e,t,n){let{page:s}=e;try{await s.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}return await this.onBeforeAction(e,t,n),await s.mouse.click(t,n,{button:"right"}),await this.awaitPageReady(s),await this.captureState(e)}async rightClickByRef(e,t){let{page:n}=e,s=3e3;try{await n.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let o=n.locator(`aria-ref=${t}`),a=await o.boundingBox({timeout:s});return a&&await this.onBeforeAction(e,a.x+a.width/2,a.y+a.height/2),await o.click({button:"right",force:!0,timeout:s}),await this.awaitPageReady(n),await this.captureState(e)}catch(o){console.warn(`[BasePlaywright] rightClickByRef ref=${t} failed: ${o.message}`);let a=await this.captureState(e),l=(o.message??"").includes("intercepts pointer events")?`Ref "${t}" is covered by another element (overlay/popup). Dismiss the overlay first, or try a different ref.`:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`;return{...a,metadata:{error:l}}}}async hoverAt(e,t,n){let{page:s}=e;return await this.onBeforeAction(e,t,n),await s.mouse.move(t,n),await new Promise(o=>setTimeout(o,300)),await this.captureState(e)}async hoverByRef(e,t){let{page:n}=e,s=3e3;try{await n.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let o=n.locator(`aria-ref=${t}`),a=await o.boundingBox({timeout:s});return a&&await this.onBeforeAction(e,a.x+a.width/2,a.y+a.height/2),await o.hover({force:!0,timeout:s}),await new Promise(i=>setTimeout(i,300)),await this.captureState(e)}catch(o){return console.warn(`[BasePlaywright] hoverByRef ref=${t} failed: ${o.message}`),{...await this.captureState(e),metadata:{error:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`}}}}async typeTextAt(e,t,n,s,o,a){let{page:i}=e;await this.onBeforeAction(e,t,n),await i.mouse.click(t,n);let l;try{l=await i.evaluate(()=>{let y=document.activeElement;return y instanceof HTMLInputElement?{type:"input",inputType:y.type}:y instanceof HTMLTextAreaElement?{type:"textarea",inputType:"textarea"}:y instanceof HTMLSelectElement?{type:"select",inputType:"select"}:y.isContentEditable?{type:"contenteditable",inputType:"contenteditable"}:{type:"other",inputType:"none"}})}catch{console.warn("[BasePlaywright] page.evaluate blocked in typeTextAt, falling back to keyboard typing"),l={type:"input",inputType:"text"}}let c=["date","time","datetime-local","month","week"],u=l.type==="input"&&c.includes(l.inputType),f=["text","password","email","search","url","tel","number","textarea","contenteditable"].includes(l.inputType),p=a===!0||a==="true";if(s=this.normalizeTestingEmailForFocusedField(e,s,{inputType:l.inputType}),u){let y=!1;try{y=await i.evaluate(v=>{let _=document.activeElement;if(_ instanceof HTMLInputElement){let b=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;return b?b.call(_,v):_.value=v,_.dispatchEvent(new Event("input",{bubbles:!0})),_.dispatchEvent(new Event("change",{bubbles:!0})),!0}return!1},s)}catch{}y||(p&&f&&(await i.keyboard.press("ControlOrMeta+a"),await i.keyboard.press("Backspace")),await i.keyboard.type(s,{delay:10}))}else p&&f&&(await i.keyboard.press("ControlOrMeta+a"),await i.keyboard.press("Backspace")),await i.keyboard.type(s,{delay:10});o&&(await i.keyboard.press("Enter"),await this.awaitPageReady(i));try{await i.evaluate(()=>new Promise(y=>requestAnimationFrame(()=>setTimeout(y,50))))}catch{}let m=await this.getFocusedFieldName(i),d=await this.captureState(e);return m?{...d,metadata:{...d.metadata,typedIntoField:m}}:d}async typeByRef(e,t,n,s,o){let{page:a}=e,i=3e3;try{await a.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let l=a.locator(`aria-ref=${t}`),c=await l.boundingBox({timeout:i});c&&await this.onBeforeAction(e,c.x+c.width/2,c.y+c.height/2),await l.click({force:!0,timeout:i});let u;try{u=await a.evaluate(()=>{let _=document.activeElement;return _ instanceof HTMLInputElement?{inputType:_.type}:_ instanceof HTMLTextAreaElement?{inputType:"textarea"}:_.isContentEditable?{inputType:"contenteditable"}:{inputType:"none"}})}catch{console.warn(`[BasePlaywright] page.evaluate blocked for typeByRef ref=${t}, falling back to keyboard typing`),u={inputType:"text"}}let f=["text","password","email","search","url","tel","number","textarea","contenteditable"].includes(u.inputType),m=["date","time","datetime-local","month","week"].includes(u.inputType);if(!f&&!m)return{...await this.captureState(e),metadata:{error:`Ref "${t}" resolved to a non-text element (${u.inputType||"unknown"}). Use a different ref that targets the text input directly.`}};let d=o===!0||o==="true";if(n=this.normalizeTestingEmailForFocusedField(e,n,{inputType:u.inputType}),m)try{await a.evaluate(_=>{let b=document.activeElement;if(b instanceof HTMLInputElement){let S=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;S?S.call(b,_):b.value=_,b.dispatchEvent(new Event("input",{bubbles:!0})),b.dispatchEvent(new Event("change",{bubbles:!0}))}},n)}catch{await a.keyboard.type(n,{delay:15})}else d&&f?(await a.keyboard.press("ControlOrMeta+a"),n?await a.keyboard.type(n,{delay:15}):await a.keyboard.press("Backspace")):n&&await a.keyboard.type(n,{delay:15});s&&await a.keyboard.press("Enter"),await this.awaitPageReady(a);try{await a.evaluate(()=>new Promise(_=>requestAnimationFrame(()=>setTimeout(_,50))))}catch{}let y=await this.getFocusedFieldName(a),v=await this.captureState(e);return y?{...v,metadata:{...v.metadata,typedIntoField:y}}:v}catch(l){return console.warn(`[BasePlaywright] typeByRef ref=${t} failed: ${l.message}`),{...await this.captureState(e),metadata:{error:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`}}}}async typeByLabel(e,t,n,s,o){let{page:a}=e,i=3e3,l=await a.evaluate(S=>{let w=L=>L.replace(/\s+/g," ").trim().replace(/:$/,"").toLowerCase(),k=L=>w(L).replace(/[\s:_-]+/g,""),x=w(S),I=k(S),M=L=>{let O=w(L);return O?O===x?0:k(L)===I?1:O.includes(x)||x.includes(O)?2:null:null},R=L=>{let O=window.getComputedStyle(L);if(O.display==="none"||O.visibility==="hidden")return!1;let P=L.getBoundingClientRect();return P.width>0&&P.height>0},N=L=>L instanceof HTMLTextAreaElement?!L.disabled:L instanceof HTMLInputElement?L.disabled||L.type==="hidden"?!1:["text","password","email","search","url","tel","number","date","time","datetime-local","month","week"].includes(L.type):L.isContentEditable,j=L=>L instanceof HTMLInputElement?`input[type=${L.type}]`:L instanceof HTMLTextAreaElement?"textarea":L.isContentEditable?"contenteditable":L.tagName.toLowerCase(),A=L=>L instanceof HTMLInputElement||L instanceof HTMLTextAreaElement?L.value:L.isContentEditable?L.textContent??"":"",F=L=>{let O=[];for(let P of Array.from(L.childNodes))if(P.nodeType===Node.TEXT_NODE){let ae=P.textContent?.trim();ae&&O.push(ae)}else if(P instanceof HTMLElement&&!N(P)){let ae=P.innerText?.trim();ae&&O.push(ae)}return O.join(" ").replace(/\s+/g," ").trim()},W=L=>{let O=[],P=(V,E,T)=>{let U=V?.replace(/\s+/g," ").trim();U&&O.push({label:U,source:E,priority:T})};P(L.getAttribute("aria-label"),"aria-label",0);let ae=L.getAttribute("aria-labelledby");if(ae&&P(ae.split(/\s+/).map(V=>document.getElementById(V)?.textContent?.trim()).filter(Boolean).join(" "),"aria-labelledby",0),L instanceof HTMLInputElement||L instanceof HTMLTextAreaElement)for(let V of Array.from(L.labels??[]))P(V.textContent,"label",0);let te=L.id;te&&P(document.querySelector(`label[for="${te}"]`)?.textContent,"label[for]",0),(L instanceof HTMLInputElement||L instanceof HTMLTextAreaElement)&&(P(L.placeholder,"placeholder",1),P(L.name,"name",2),P(L.id,"id",2));let J=L.previousElementSibling;for(;J;)P(J instanceof HTMLElement?J.innerText:J.textContent,"previous-sibling",3),J=J.previousElementSibling;let G=L.parentElement;for(let V=0;G&&V<3;V+=1,G=G.parentElement)P(F(G),"container-text",4+V);return O},Y=[],H=Array.from(document.querySelectorAll('input:not([type="hidden"]), textarea, [contenteditable="true"]')).filter(L=>N(L)&&R(L));for(let L of H)for(let O of W(L)){let P=M(O.label);P!=null&&Y.push({element:L,label:O.label,source:O.source,priority:O.priority,matchRank:O.priority*10+P,elementType:j(L),valueBefore:A(L)})}if(Y.length===0)return{status:"none",error:`No text input found for label "${S}". Check the latest page snapshot for the field label or use ref/x/y.`};Y.sort((L,O)=>L.matchRank-O.matchRank);let B=Y[0].matchRank,se=Y.filter(L=>L.matchRank===B);if(Array.from(new Set(se.map(L=>L.element))).length>1)return{status:"ambiguous",error:`Multiple text inputs matched label "${S}". Use a more specific label or a direct ref.`,matches:se.map(L=>({label:L.label,source:L.source,elementType:L.elementType}))};let ne=`agentiqa_label_target_${Date.now()}_${Math.random().toString(36).slice(2)}`;return se[0].element.setAttribute("data-agentiqa-label-target",ne),{status:"ok",marker:ne,matchedLabel:se[0].label,labelSource:se[0].source,elementType:se[0].elementType,valueBefore:se[0].valueBefore}},t);if(l.status!=="ok"){let S=await this.captureState(e);return{...S,metadata:{...S.metadata,error:l.error,...l.status==="ambiguous"&&{matches:l.matches}}}}let c=a.locator(`[data-agentiqa-label-target="${l.marker}"]`).first(),u=await c.boundingBox({timeout:i});u&&await this.onBeforeAction(e,u.x+u.width/2,u.y+u.height/2),await c.click({force:!0,timeout:i});let h=await a.evaluate(()=>{let S=document.activeElement;return S instanceof HTMLInputElement?{inputType:S.type}:S instanceof HTMLTextAreaElement?{inputType:"textarea"}:S.isContentEditable?{inputType:"contenteditable"}:{inputType:"none"}}),p=["date","time","datetime-local","month","week"].includes(h.inputType),d=["text","password","email","search","url","tel","number","textarea","contenteditable"].includes(h.inputType);if(!d&&!p){let S=await this.captureState(e);return{...S,metadata:{...S.metadata,error:`Label "${t}" resolved to a non-text element (${h.inputType||"unknown"}). Use a different label or direct ref.`}}}let y=o===!0||o==="true";if(n=this.normalizeTestingEmailForFocusedField(e,n,{inputType:h.inputType,label:t,matchedLabel:l.matchedLabel}),p)try{await a.evaluate(S=>{let w=document.activeElement;if(w instanceof HTMLInputElement){let k=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;k?k.call(w,S):w.value=S,w.dispatchEvent(new Event("input",{bubbles:!0})),w.dispatchEvent(new Event("change",{bubbles:!0}))}},n)}catch{await a.keyboard.type(n,{delay:15})}else y&&d?(await a.keyboard.press("ControlOrMeta+a"),n?await a.keyboard.type(n,{delay:15}):await a.keyboard.press("Backspace")):n&&await a.keyboard.type(n,{delay:15});s&&await a.keyboard.press("Enter"),await this.awaitPageReady(a);try{await a.evaluate(()=>new Promise(S=>requestAnimationFrame(()=>setTimeout(S,50))))}catch{}let v=await this.getFocusedFieldName(a),_=await a.evaluate(()=>{let S=document.activeElement;return S instanceof HTMLInputElement||S instanceof HTMLTextAreaElement?S.value:S instanceof HTMLElement&&S.isContentEditable?S.textContent??"":""}),b=await this.captureState(e);return{...b,metadata:{...b.metadata,typedIntoField:v??l.matchedLabel,matchedLabel:l.matchedLabel,labelSource:l.labelSource,elementType:l.elementType,valueBefore:l.valueBefore,valueAfter:_}}}async scrollDocument(e,t){let{page:n,viewportHeight:s}=e,o=Math.floor(s*.8);return t==="up"?await n.evaluate(a=>window.scrollBy(0,-a),o):t==="down"?await n.evaluate(a=>window.scrollBy(0,a),o):t==="left"?await n.evaluate(a=>window.scrollBy(-a,0),o):t==="right"&&await n.evaluate(a=>window.scrollBy(a,0),o),await new Promise(a=>setTimeout(a,200)),await this.captureState(e)}async scrollToBottom(e){let{page:t}=e;return await t.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await new Promise(n=>setTimeout(n,200)),await this.captureState(e)}async scrollAt(e,t,n,s,o){let{page:a}=e;await a.mouse.move(t,n);let i=0,l=0;switch(s){case"up":l=-o;break;case"down":l=o;break;case"left":i=-o;break;case"right":i=o;break}return await a.mouse.wheel(i,l),await new Promise(c=>setTimeout(c,200)),await this.captureState(e)}async waitSeconds(e,t){let n=Math.min(Math.max(t,1),30);return await new Promise(s=>setTimeout(s,n*1e3)),await this.captureState(e)}async waitForElement(e,t,n){let{page:s}=e,o=Math.min(Math.max(n,1),30);try{return await s.getByText(t,{exact:!1}).first().waitFor({state:"visible",timeout:o*1e3}),await new Promise(i=>setTimeout(i,300)),await this.captureState(e)}catch{return{...await this.captureState(e),metadata:{error:`Text "${t}" not found within ${o}s. Do NOT retry \u2014 the page likely loaded with different text. Inspect the screenshot and proceed with the next action, or report_issue if blocked.`}}}}async fullPageScreenshot(e){let{page:t}=e,n=await this.screenshotWithSlowSiteRetry(e,{fullPage:!0}),s=t.url();return{screenshot:n,url:s}}async switchLayout(e,t,n){let{page:s}=e;return await s.setViewportSize({width:t,height:n}),await this.captureState(e)}async goBack(e){let{page:t}=e;return e.needsFullSnapshot=!0,await t.goBack(),await this.awaitPageReady(t),await this.captureState(e)}async goForward(e){let{page:t}=e;return e.needsFullSnapshot=!0,await t.goForward(),await this.awaitPageReady(t),await this.captureState(e)}async navigate(e,t){let{page:n}=e,s=Cr(t),o=await this.blockScopedNavigationIfNeeded(e,s);if(o)return o;e.needsFullSnapshot=!0;let a=await n.goto(s,{waitUntil:"domcontentloaded"});await this.awaitPageReady(n),await this.assertNoCloudflareBlock(n,a,s);let i=[],l=a?.request().redirectedFrom()??null;for(;l;)i.unshift(l.url()),l=l.redirectedFrom();let c=n.url(),u=sc(s,c,i,(f,p,m,d)=>console.warn(`[BasePlaywright] [${p}] ${m}`,d??"")),h=await this.captureState(e);return{...h,metadata:{...h.metadata??{},navigateMeta:u}}}async blockScopedNavigationIfNeeded(e,t){let n=my({targetUrl:t,currentUrl:e.page.url(),scope:e.browserNavigationScope,allowExternalNavigation:e.allowExternalNavigation,httpsCertFallbackHost:e.httpsCertFallback?.host});if(n.allowed)return null;let s=await this.captureState(e),o=e.browserNavigationScope?.join(", ")||"(none)";return{...s,metadata:{...s.metadata??{},error:`Navigation blocked: ${t} is outside the allowed scope (${o}). Record/report the external link without opening it unless the user explicitly asked to validate external links.`,scopedNavigation:{status:"blocked",targetUrl:t,reason:n.reason}}}}async keyCombination(e,t){let{page:n}=e,s=t.map(a=>kP[a.toLowerCase()]??a),o=s.some(a=>ou.has(a));if(s.length===1)await n.keyboard.press(s[0]);else if(o){let a=s.filter(l=>ou.has(l)),i=s.filter(l=>!ou.has(l));for(let l of a)await n.keyboard.down(l);for(let l of i)await n.keyboard.press(l);for(let l of a.reverse())await n.keyboard.up(l)}else for(let a of s)await n.keyboard.press(a);return await this.awaitPageReady(n),await this.captureState(e)}async setFocusedInputValue(e,t){let{page:n}=e,s={isSelect:!1,inputType:"none"};try{s=await n.evaluate(()=>{let i=document.activeElement;return i instanceof HTMLSelectElement?{isSelect:!0,inputType:"select"}:i instanceof HTMLInputElement?{isSelect:!1,inputType:i.type}:i instanceof HTMLTextAreaElement?{isSelect:!1,inputType:"textarea"}:i?.isContentEditable?{isSelect:!1,inputType:"contenteditable"}:{isSelect:!1,inputType:"none"}})}catch{return console.warn("[BasePlaywright] page.evaluate blocked in setFocusedInputValue, falling back to keyboard typing"),t=this.normalizeTestingEmailForFocusedField(e,t,{}),await n.keyboard.press("ControlOrMeta+a"),await n.keyboard.type(t,{delay:10}),{...await this.captureState(e),metadata:{elementType:"unknown (evaluate blocked)",valueBefore:"",valueAfter:t}}}if(s.isSelect)return await this.setSelectValue(e,t);t=this.normalizeTestingEmailForFocusedField(e,t,{inputType:s.inputType});let o=await n.evaluate(i=>{let l=document.activeElement,c=p=>p instanceof HTMLInputElement?`input[type=${p.type}]`:p instanceof HTMLTextAreaElement?"textarea":p.isContentEditable?"contenteditable":p.tagName.toLowerCase(),u=p=>p instanceof HTMLInputElement||p instanceof HTMLTextAreaElement?p.value:p.isContentEditable&&p.textContent||"";if(!l||l===document.body)return{success:!1,error:"No element is focused",elementType:"none",valueBefore:"",valueAfter:""};let h=c(l),f=u(l);try{if(l instanceof HTMLInputElement){let p=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;p?p.call(l,i):l.value=i,l.dispatchEvent(new Event("input",{bubbles:!0})),l.dispatchEvent(new Event("change",{bubbles:!0}))}else if(l instanceof HTMLTextAreaElement){let p=Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,"value")?.set;p?p.call(l,i):l.value=i,l.dispatchEvent(new Event("input",{bubbles:!0})),l.dispatchEvent(new Event("change",{bubbles:!0}))}else if(l.isContentEditable)l.textContent=i,l.dispatchEvent(new Event("input",{bubbles:!0}));else return{success:!1,error:`Element is not editable: ${h}`,elementType:h,valueBefore:f,valueAfter:f}}catch(p){return{success:!1,error:String(p.message||p),elementType:h,valueBefore:f,valueAfter:u(l)}}return{success:!0,elementType:h,valueBefore:f,valueAfter:u(l)}},t);return{...await this.captureState(e),metadata:{elementType:o.elementType,valueBefore:o.valueBefore,valueAfter:o.valueAfter,...o.error&&{error:o.error}}}}async setSelectValue(e,t){let{page:n}=e,s=await n.evaluate(()=>{let u=document.activeElement;if(!(u instanceof HTMLSelectElement))return null;let h=u.options[u.selectedIndex]?.textContent?.trim()||"",f=Array.from(u.options).map(p=>p.textContent?.trim()||p.value);return{valueBefore:h,options:f}});if(!s)return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:"",valueAfter:"",error:"No select element is focused. Use click_at on the select first."}};let a=(await n.evaluateHandle(()=>document.activeElement)).asElement();if(!a)return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:s.valueBefore,valueAfter:s.valueBefore,error:"Could not get select element handle",availableOptions:s.options}};let i=!1;try{await a.selectOption({label:t}),i=!0}catch{try{await a.selectOption({value:t}),i=!0}catch{}}let l=await n.evaluate(()=>{let u=document.activeElement;return u instanceof HTMLSelectElement?u.options[u.selectedIndex]?.textContent?.trim()||u.value:""});return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:s.valueBefore,valueAfter:l,...!i&&{error:`No option matching "${t}"`},availableOptions:s.options}}}async uploadFile(e,t){let{page:n}=e;console.log(`[BasePlaywright] upload_file called with filePaths=${JSON.stringify(t)}`);let o=(await n.evaluateHandle(()=>document.querySelector('input[type="file"][data-agentiqa-file-target]')||document.activeElement)).asElement();if(!o)return{...await this.captureState(e),metadata:{elementType:"file",error:"No file input found. Use click_at on the file input first."}};let a=await n.evaluate(u=>u instanceof HTMLInputElement&&u.type==="file"?{isFileInput:!0,accept:u.accept||"*",multiple:u.multiple}:{isFileInput:!1,accept:"",multiple:!1},o);if(!a.isFileInput)return{...await this.captureState(e),metadata:{elementType:"not-file-input",error:"No file input found. Use click_at on the file input/upload area first."}};try{await o.setInputFiles(t),console.log(`[BasePlaywright] upload_file setInputFiles succeeded, count=${t.length}`)}catch(u){return console.log(`[BasePlaywright] upload_file setInputFiles failed: ${u.message}`),{...await this.captureState(e),metadata:{elementType:"file",accept:a.accept,multiple:a.multiple,error:`File upload failed: ${u.message}`}}}let i=await this.onFilesUploaded(t),l=await n.evaluate(()=>document.querySelector('input[type="file"][data-agentiqa-file-target]')?.files?.length||0);return console.log(`[BasePlaywright] upload_file result: fileCount=${l}`),await this.awaitPageReady(n),{...await this.captureState(e),metadata:{elementType:"file",accept:a.accept,multiple:a.multiple,fileCount:l,...i.length>0&&{storedAssets:i}}}}async dragAndDrop(e,t,n,s,o){let{page:a}=e;return await a.mouse.move(t,n),await a.mouse.down(),await a.mouse.move(s,o,{steps:10}),await a.mouse.up(),await this.captureState(e)}async resolveRefCenter(e,t){try{let o=await e.page.locator(`aria-ref=${t}`).boundingBox({timeout:3e3});return o?{x:Math.floor(o.x+o.width/2),y:Math.floor(o.y+o.height/2)}:null}catch{return null}}async refNotFoundError(e,t){return{...await this.captureState(e),metadata:{error:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`}}}async switchTab(e,t){if(t==="tab1"){let n=!e.tab1||e.tab1.isClosed();if(this.diagLog?.(e.sessionId,"switchTab tab1 requested",{tab1Closed:n,hasExtId:!!e.extensionId}),n&&e.extensionId){this.diagLog?.(e.sessionId,"switchTab auto-recreating tab1 at popup.html");let s=await e.context.newPage();Ci(s),await s.goto(`chrome-extension://${e.extensionId}/popup.html`,{timeout:5e3}),e.tab1=s}if(!e.tab1||e.tab1.isClosed())return{...await this.captureState(e),metadata:{error:"Tab 1 is not available"}};if(e.page=e.tab1,e.activeTab="tab1",e.extensionId){let s=e.tab1.url();if(!s.startsWith(`chrome-extension://${e.extensionId}`)){this.diagLog?.(e.sessionId,"switchTab navigating to popup.html",{beforeUrl:s});try{await e.tab1.goto(`chrome-extension://${e.extensionId}/popup.html`,{timeout:5e3});let o=e.tab1.url();this.diagLog?.(e.sessionId,"switchTab popup.html loaded",{afterUrl:o})}catch(o){this.diagLog?.(e.sessionId,"switchTab popup.html failed",{error:o?.message})}}}}else{if(!e.tab2||e.tab2.isClosed())return{...await this.captureState(e),metadata:{error:"Tab 2 is not available. No second tab is open."}};e.page=e.tab2,e.activeTab="tab2"}return e.needsFullSnapshot=!0,await e.page.bringToFront(),await this.captureState(e)}async closeTab(e){if(e.activeTab==="tab1")return{...await this.captureState(e),metadata:{error:"Cannot close tab 1"}};if(e.tab2&&!e.tab2.isClosed())try{await e.tab2.close()}catch{}return e.tab2=void 0,e.page=e.tab1,e.activeTab="tab1",e.needsFullSnapshot=!0,await e.page.bringToFront(),await this.captureState(e)}static HTTP_BODY_MAX_LENGTH=5e4;async httpRequest(e,t,n,s,o){let{page:a}=e;try{let i={method:n,timeout:3e4,ignoreHTTPSErrors:!0};s&&(i.headers=s),o&&n!=="GET"&&(i.data=o);let l=await a.request.fetch(t,i),c=await l.text(),u=!1;if(c.length>r.HTTP_BODY_MAX_LENGTH&&(c=c.slice(0,r.HTTP_BODY_MAX_LENGTH),u=!0),(l.headers()["content-type"]||"").includes("application/json")&&!u)try{c=JSON.stringify(JSON.parse(c),null,2),c.length>r.HTTP_BODY_MAX_LENGTH&&(c=c.slice(0,r.HTTP_BODY_MAX_LENGTH),u=!0)}catch{}return{...await this.captureState(e),metadata:{httpResponse:{status:l.status(),statusText:l.statusText(),headers:l.headers(),body:c,...u&&{truncated:!0}}}}}catch(i){return{...await this.captureState(e),metadata:{error:`HTTP request failed: ${i.message}`}}}}static RUN_JS_INPUT_MAX_LENGTH=4e3;static RUN_JS_RESULT_MAX_LENGTH=5e3;static RUN_JS_TIMEOUT_MS=1e4;async runJs(e,t){if(t.length>r.RUN_JS_INPUT_MAX_LENGTH)return{...await this.captureState(e),metadata:{error:`run_js code exceeded ${r.RUN_JS_INPUT_MAX_LENGTH}-char cap (${t.length} chars).`}};let n=`(async () => {
1590
+ `,document.body.appendChild(a)),a.style.left=`${s}px`,a.style.top=`${o}px`},{x:t,y:n})}catch{}}getSuggestedSampleFiles(e,t){return[]}async ensureBrowser(){if(!this.browser){console.log("[BasePlaywright] Launching browser");let e=performance.now();this.browser=await this.launchBrowser();let t=Math.round(performance.now()-e);console.log(`[BasePlaywright] Browser launched in ${t}ms`),this.browser.on("disconnected",()=>{console.log("[BasePlaywright] Browser disconnected"),this.browser=null,this.sessions.clear(),this.onBrowserDisconnected?.()})}return this.browser}async ensureSession(e,t){if(this.sessions.has(e))return this.sessions.get(e);e.includes(":child-")||await this.cleanupOtherSessions(e);let n=await this.createSession(e,t);return this.sessions.set(e,n),n}async invoke(e){let t=await this.ensureSession(e.sessionId,e.config);t.lastInvokeAt=Date.now(),t.browserNavigationScope=Array.isArray(e.config?.browserNavigationScope)?e.config.browserNavigationScope.map(String):void 0,t.allowExternalNavigation=!!e.config?.allowExternalNavigation,t.testingEmailPolicy=wt(e.config)??void 0,t.isTestPlanReplay=!!e.config?.isTestPlanReplay;let n=e.args??{},s=performance.now(),o,a;try{let i=await this.dispatch(t,e.action,n);i=this.withSessionMetadata(t,i);let l=Math.round(performance.now()-s);if(console.log(`[BasePlaywright] ${e.action} completed in ${l}ms`),t.tab2||t.isExtensionSession){let c=t.tab1&&!t.tab1.isClosed(),u=t.tab2&&!t.tab2.isClosed(),h=[];c&&h.push(t.tab1.url()),u&&h.push(t.tab2.url()),i={...i,metadata:{activeTab:t.activeTab,tabCount:(c?1:0)+(u?1:0),tabUrls:h,...t.pendingExtensionPopup?{pendingExtensionPopup:!0}:{},...i.metadata}},t.pendingExtensionPopup=!1}o={screenshot:i.screenshot.toString("base64"),url:i.url,aiSnapshot:i.aiSnapshot,domChanges:i.domChanges,metadata:i.metadata},a=t.page}catch(i){let l=String(i?.message||"");if(l.includes("Execution context was destroyed")||l.includes("most likely because of a navigation")||l.includes("navigation")){console.log(`[BasePlaywright] Navigation detected during ${e.action}, recovering`),t.needsFullSnapshot=!0;try{await t.page.waitForLoadState("load",{timeout:5e3})}catch{}let c=await this.captureState(t),u=this.withSessionMetadata(t,c);o={screenshot:u.screenshot.toString("base64"),url:u.url,aiSnapshot:u.aiSnapshot,metadata:u.metadata},a=t.page}else if(l.includes("Browser session closed")||l.includes("Target closed")||l.includes("has been closed")||l.includes("Page crashed")){console.log(`[BasePlaywright] Session closed for ${e.sessionId}, recreating`),this.sessions.delete(e.sessionId);try{let c=await this.ensureSession(e.sessionId,e.config),u=this.withSessionMetadata(c,await this.dispatch(c,e.action,n));o={screenshot:u.screenshot.toString("base64"),url:u.url,aiSnapshot:u.aiSnapshot,metadata:u.metadata},a=c.page}catch(c){console.error("[BasePlaywright] Retry after session recreation failed:",c);let u=c instanceof Error?c.message:String(c);throw new Error(`Browser session recovery failed: ${u}`)}}else throw i}return o.metadata={...o.metadata??{},events:this.buildAndResetDigest(a)},o}buildAndResetDigest(e){let t=e?$o.get(e):void 0;if(!t)return{consoleErrors:[],pageErrors:[],failedRequests:[],pendingRequests:[],recentWrites:[]};let n=Date.now(),s={consoleErrors:t.rollingConsoleErrors.slice(),pageErrors:t.rollingPageErrors.slice(),failedRequests:t.rollingFailedRequests.slice(),pendingRequests:Array.from(t.pendingWrites).map(o=>({url:o.url,method:o.method,ageMs:n-o.startTs})),recentWrites:t.rollingRecentWrites.slice()};return t.rollingConsoleErrors=[],t.rollingPageErrors=[],t.rollingFailedRequests=[],t.rollingRecentWrites=[],s}async getFocusedFieldName(e){try{return await e.evaluate(()=>{let t=document.activeElement;if(!t||t===document.body)return;let n=u=>{let h=[];for(let f of Array.from(u.childNodes))if(f.nodeType===Node.TEXT_NODE){let p=f.textContent?.trim();p&&h.push(p)}else if(f instanceof HTMLElement&&!s(f)){let p=f.innerText?.trim();p&&h.push(p)}return h.join(" ").replace(/\s+/g," ").trim()},s=u=>u instanceof HTMLInputElement||u instanceof HTMLTextAreaElement||u instanceof HTMLSelectElement||u.isContentEditable,o=t.getAttribute("aria-label");if(o)return o;let a=t.getAttribute("aria-labelledby");if(a){let u=a.split(/\s+/).map(h=>document.getElementById(h)?.textContent?.trim()).filter(Boolean).join(" ");if(u)return u}if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){let u=t.labels?.[0]?.textContent?.trim();if(u)return u}let i=t.id;if(i){let u=document.querySelector(`label[for="${i}"]`);if(u)return u.textContent?.trim()}if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){if(t.placeholder)return t.placeholder;if(t.name)return t.name}let l=t.previousElementSibling;for(;l;){let u=l instanceof HTMLElement?l.innerText?.trim():void 0;if(u)return u;l=l.previousElementSibling}let c=t.parentElement;for(let u=0;c&&u<3;u+=1,c=c.parentElement){let h=n(c);if(h)return h}})}catch{return}}async awaitPageReady(e){await e.waitForLoadState("domcontentloaded",{timeout:5e3}).catch(()=>{})}async screenshotWithSlowSiteRetry(e,t={}){let{page:n}=e,s=(e.screenshotCount??0)===0,o=15e3,a=25e3,l={type:"png",timeout:s?o:5e3};t.fullPage&&(l.fullPage=!0);try{let c=await n.screenshot(l);return e.screenshotCount=(e.screenshotCount??0)+1,c}catch(c){if(!s||!fc(c))throw c;let u=n.url();this.diagLog?.(e.sessionId,"screenshot_first_timeout_retry",{url:u,firstTimeoutMs:o,retryTimeoutMs:a});let h={type:"png",timeout:a};t.fullPage&&(h.fullPage=!0);try{let f=await n.screenshot(h);return e.screenshotCount=(e.screenshotCount??0)+1,this.diagLog?.(e.sessionId,"screenshot_first_retry_success",{url:u}),f}catch(f){throw fc(f)?new tn({url:u,totalTimeoutMs:o+a,attemptCount:2}):f}}}async captureState(e){let{page:t}=e;e.expectDomQuiescence&&!process.env.AQ_NO_DOM_OBSERVER&&!process.env.AQ_NO_DOM_DELAY&&await mr.waitForQuiescence(t,{minQuietMs:100,maxMs:800});let n=await this.screenshotWithSlowSiteRetry(e),s=t.url(),o;try{let i=await t._snapshotForAI({track:e.sessionId+":"+e.activeTab}),l=typeof i=="string"?i:i?.full,c=typeof i=="object"?i?.incremental:void 0;!e.needsFullSnapshot&&c?o=c:(o=l,e.needsFullSnapshot=!1)}catch{o=void 0,e.needsFullSnapshot=!0}let a=process.env.AQ_NO_DOM_OBSERVER?void 0:await mr.flush(t)??void 0;return{screenshot:n,url:s,aiSnapshot:o,domChanges:a}}withSessionMetadata(e,t){return e.httpsCertFallback?{...t,metadata:{...t.metadata??{},httpsCertFallback:e.httpsCertFallback}}:t}shouldResetDomObserverBeforeAction(e){return!new Set(["open_web_browser","screenshot","snapshot","wait","wait_5_seconds","wait_for_element","full_page_screenshot","run_js"]).has(e)}shouldWaitForDomQuiescenceAfterAction(e){return this.shouldResetDomObserverBeforeAction(e)}async dispatch(e,t,n){let s=await this.dispatchPlatformAction(e,t,n);if(s)return s;let{viewportWidth:o,viewportHeight:a}=e,i=h=>Math.floor(h/1e3*o),l=h=>Math.floor(h/1e3*a),c=!process.env.AQ_NO_DOM_OBSERVER&&this.shouldResetDomObserverBeforeAction(t),u=e.expectDomQuiescence;c&&await mr.reset(e.page),e.expectDomQuiescence=this.shouldWaitForDomQuiescenceAfterAction(t);try{switch(t){case"open_web_browser":case"screenshot":return await this.captureState(e);case"snapshot":return e.needsFullSnapshot=!0,await this.captureState(e);case"click_at":{let h=Array.isArray(n.modifiers)?n.modifiers.map(String):[];if(n.ref)return await this.clickByRef(e,String(n.ref),h);let f=this.requireNormalizedPoint(t,n);return await this.clickAt(e,i(f.x),l(f.y),h)}case"right_click_at":{if(n.ref)return await this.rightClickByRef(e,String(n.ref));let h=this.requireNormalizedPoint(t,n);return await this.rightClickAt(e,i(h.x),l(h.y))}case"hover_at":{if(n.ref)return await this.hoverByRef(e,String(n.ref));let h=this.requireNormalizedPoint(t,n);return await this.hoverAt(e,i(h.x),l(h.y))}case"type_text_at":{let h=n.clearBeforeTyping??n.clear_before_typing??!0;if(n.label)return await this.typeByLabel(e,String(n.label),String(n.text??""),!!(n.pressEnter??n.press_enter??!1),h);if(n.ref)return await this.typeByRef(e,String(n.ref),String(n.text??""),!!(n.pressEnter??n.press_enter??!1),h);let f=this.requireNormalizedPoint(t,n);return await this.typeTextAt(e,i(f.x),l(f.y),String(n.text??""),!!(n.pressEnter??n.press_enter??!1),h)}case"scroll_document":return await this.scrollDocument(e,String(n.direction));case"scroll_to_bottom":return await this.scrollToBottom(e);case"scroll_at":{let h=String(n.direction),f=n.magnitude!=null?Number(n.magnitude):800;if(h==="up"||h==="down"?f=l(f):(h==="left"||h==="right")&&(f=i(f)),n.ref){let m=await this.resolveRefCenter(e,String(n.ref));return m?await this.scrollAt(e,m.x,m.y,h,f):await this.refNotFoundError(e,String(n.ref))}let p=this.requireNormalizedPoint(t,n);return await this.scrollAt(e,i(p.x),l(p.y),h,f)}case"wait":return await this.waitSeconds(e,Number(n.seconds||2));case"wait_for_element":return await this.waitForElement(e,String(n.textContent??""),Number(n.timeoutSeconds||5));case"wait_5_seconds":return await this.waitSeconds(e,5);case"full_page_screenshot":return await this.fullPageScreenshot(e);case"switch_layout":{let h=Number(n.width),f=Number(n.height);return e.viewportWidth=h,e.viewportHeight=f,await this.switchLayout(e,h,f)}case"go_back":return await this.goBack(e);case"go_forward":return await this.goForward(e);case"navigate":{let h=String(n.url??n.href??"");if(e.isExtensionSession){if(h.startsWith("chrome-extension://")){if(e.tab1&&!e.tab1.isClosed())await e.tab1.goto(h),await this.awaitPageReady(e.tab1);else{let f=await e.context.newPage();Ci(f),await f.goto(h),await this.awaitPageReady(f)}return e.tab1&&!e.tab1.isClosed()&&(e.page=e.tab1,e.activeTab="tab1",e.needsFullSnapshot=!0,await e.page.bringToFront()),await this.captureState(e)}e.tab2&&!e.tab2.isClosed()&&(e.page=e.tab2,e.activeTab="tab2")}else e.activeTab==="tab2"&&e.tab1&&!e.tab1.isClosed()&&(e.page=e.tab1,e.activeTab="tab1",e.needsFullSnapshot=!0);return await this.navigate(e,h)}case"key_combination":return await this.keyCombination(e,Array.isArray(n.keys)?n.keys.map(String):[]);case"set_focused_input_value":return await this.setFocusedInputValue(e,String(n.value??""));case"drag_and_drop":{let h,f;if(n.ref){let d=await this.resolveRefCenter(e,String(n.ref));if(!d)return await this.refNotFoundError(e,String(n.ref));h=d.x,f=d.y}else{let d=this.requireNormalizedPoint(t,n);h=i(d.x),f=l(d.y)}let p,m;if(n.destinationRef){let d=await this.resolveRefCenter(e,String(n.destinationRef));if(!d)return await this.refNotFoundError(e,String(n.destinationRef));p=d.x,m=d.y}else{let d=this.requireNormalizedPoint(t,n,n.destinationX!==void 0?"destinationX":"destination_x",n.destinationY!==void 0?"destinationY":"destination_y");p=i(d.x),m=l(d.y)}return await this.dragAndDrop(e,h,f,p,m)}case"upload_file":{let h=Array.isArray(n.filePaths)?n.filePaths.map(String):[String(n.filePaths??"")];return await this.uploadFile(e,h)}case"http_request":return await this.httpRequest(e,String(n.url??""),String(n.method??"GET"),n.headers,n.body!=null?String(n.body):void 0);case"run_js":return await this.runJs(e,String(n.code??""));case"switch_tab":{let h=String(n.tab??"tab1"),f=h==="main"?"tab1":h==="extension"?"tab2":h;return await this.switchTab(e,f)}case"close_tab":return await this.closeTab(e);default:return console.warn(`[BasePlaywright] Unsupported action: ${t}`),await this.captureState(e)}}finally{e.expectDomQuiescence=u}}async clickAt(e,t,n,s=[]){let{page:o}=e;try{await o.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}await this.onBeforeAction(e,t,n);let a={isSelect:!1,isMultiple:!1,selectedText:"",options:[],clickedElement:null,clickTarget:null};try{let f=await o.evaluateHandle(d=>document.elementFromPoint(d.x,d.y),{x:t,y:n}),p=f.asElement(),m=p?await p.evaluate(Xv).catch(()=>null):null;await f.dispose().catch(()=>{}),a=await o.evaluate(d=>{let y=document.elementFromPoint(d.x,d.y);if(!y)return{isSelect:!1,isMultiple:!1,selectedText:"",options:[],clickedElement:null,clickTarget:null};let v={tag:y.tagName.toLowerCase(),text:(y.textContent||"").trim().slice(0,80),role:y.getAttribute("role")||""},_=y.closest("a[href], area[href]"),b=null,S=y.closest("select");if(S)b=S;else if(y instanceof HTMLLabelElement&&y.htmlFor){let w=document.getElementById(y.htmlFor);w instanceof HTMLSelectElement&&(b=w)}else{let w=y instanceof HTMLLabelElement?y:y.closest("label");if(w){let k=w.querySelector("select");k&&(b=k)}}if(b){b.focus();let w=b.options[b.selectedIndex]?.textContent?.trim()||"",k=Array.from(b.options).map(I=>I.textContent?.trim()||I.value);return{isSelect:!0,isMultiple:b.multiple,selectedText:w,options:k,clickedElement:null,clickTarget:null}}return{isSelect:!1,isMultiple:!1,selectedText:"",options:[],clickedElement:v,clickTarget:null,linkHref:_?.href||""}},{x:t,y:n}),a.clickTarget=m}catch(f){let p=String(f?.message||"");if(!(p.includes("Execution context was destroyed")||p.includes("navigation")))throw f}if(a.isSelect&&!a.isMultiple)return await this.awaitPageReady(o),{...await this.captureState(e),metadata:{elementType:"select",valueBefore:a.selectedText,valueAfter:a.selectedText,availableOptions:a.options,...a.clickTarget?{clickTarget:a.clickTarget}:{}}};if(a.linkHref){let f=await this.blockScopedNavigationIfNeeded(e,a.linkHref);if(f)return f}let i=o.waitForEvent("filechooser",{timeout:150}).catch(()=>null),l=o.waitForEvent("download",{timeout:500}).catch(()=>null);await mr.reset(o);for(let f of s)await o.keyboard.down(f);await o.mouse.click(t,n);for(let f of s)await o.keyboard.up(f);let c=await i;if(c){let p=await c.element().evaluate(y=>{let v=y;return document.querySelectorAll("[data-agentiqa-file-target]").forEach(_=>_.removeAttribute("data-agentiqa-file-target")),v.setAttribute("data-agentiqa-file-target","true"),v instanceof HTMLInputElement?{accept:v.accept||"*",multiple:v.multiple}:{accept:"*",multiple:!1}}),m=this.getSuggestedSampleFiles(p.accept,p.multiple);return console.log(`[BasePlaywright] FILE CHOOSER INTERCEPTED: accept="${p.accept}", multiple=${p.multiple}`),{...await this.captureState(e),metadata:{elementType:"file",accept:p.accept,multiple:p.multiple,suggestedFiles:m}}}let u=await l;if(u){let f=u.suggestedFilename(),p=u.url();console.log(`[BasePlaywright] DOWNLOAD INTERCEPTED: "${f}" from ${p}`),await u.cancel();try{await o.goBack({waitUntil:"domcontentloaded",timeout:5e3})}catch{}return{...await this.captureState(e),metadata:{elementType:"download",downloadFilename:f,downloadUrl:p,clickedElement:a.clickedElement??void 0,clickTarget:a.clickTarget??void 0}}}await this.awaitPageReady(o);let h=await this.captureState(e);return a.clickedElement||a.clickTarget?{...h,metadata:{...a.clickedElement?{clickedElement:a.clickedElement}:{},...a.clickTarget?{clickTarget:a.clickTarget}:{}}}:h}async clickByRef(e,t,n=[]){let{page:s}=e,o=3e3;try{await s.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let a=s.locator(`aria-ref=${t}`),i=await a.boundingBox({timeout:o});i&&await this.onBeforeAction(e,i.x+i.width/2,i.y+i.height/2);let l=await a.evaluate(v=>({tag:v.tagName.toLowerCase(),text:(v.textContent||"").trim().slice(0,80),role:v.getAttribute("role")||"",linkHref:v.closest("a[href], area[href]")?.href})).catch(()=>null),c=await a.evaluate(Xv).catch(()=>null),u=await a.evaluate(v=>{let _=v instanceof HTMLSelectElement?v:v.closest("select");if(!_)return null;_.focus();let b=_.options[_.selectedIndex]?.textContent?.trim()||"",S=Array.from(_.options).map(w=>w.textContent?.trim()||w.value);return{selectedText:b,options:S,isMultiple:_.multiple}}).catch(()=>null);if(u&&!u.isMultiple)return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:u.selectedText,valueAfter:u.selectedText,availableOptions:u.options,...c?{clickTarget:c}:{}}};if(l?.linkHref){let v=await this.blockScopedNavigationIfNeeded(e,l.linkHref);if(v)return v}let h=s.waitForEvent("filechooser",{timeout:500}).catch(()=>null),f=s.waitForEvent("download",{timeout:500}).catch(()=>null),p=n.map(v=>v).filter(Boolean);await mr.reset(s),await a.click({force:!0,timeout:o,modifiers:p.length?p:void 0});let m=await h;if(m){let _=await m.element().evaluate(w=>{let k=w;return document.querySelectorAll("[data-agentiqa-file-target]").forEach(x=>x.removeAttribute("data-agentiqa-file-target")),k.setAttribute("data-agentiqa-file-target","true"),k instanceof HTMLInputElement?{accept:k.accept||"*",multiple:k.multiple}:{accept:"*",multiple:!1}}),b=this.getSuggestedSampleFiles(_.accept,_.multiple);return console.log(`[BasePlaywright] FILE CHOOSER INTERCEPTED via ref=${t}: accept="${_.accept}"`),{...await this.captureState(e),metadata:{elementType:"file",accept:_.accept,multiple:_.multiple,suggestedFiles:b}}}let d=await f;if(d){let v=d.suggestedFilename(),_=d.url();console.log(`[BasePlaywright] DOWNLOAD INTERCEPTED via ref=${t}: "${v}" from ${_}`),await d.cancel();try{await s.goBack({waitUntil:"domcontentloaded",timeout:5e3})}catch{}return{...await this.captureState(e),metadata:{elementType:"download",downloadFilename:v,downloadUrl:_,clickedElement:l??void 0,clickTarget:c??void 0}}}await this.awaitPageReady(s);let y=await this.captureState(e);return l||c?{...y,metadata:{...l?{clickedElement:l}:{},...c?{clickTarget:c}:{}}}:y}catch(a){console.warn(`[BasePlaywright] clickByRef ref=${t} failed: ${a.message}`);let i=await this.captureState(e),c=(a.message??"").includes("intercepts pointer events")?`Ref "${t}" is covered by another element (overlay/popup). Dismiss the overlay first, or try a different ref.`:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`;return{...i,metadata:{error:c}}}}async rightClickAt(e,t,n){let{page:s}=e;try{await s.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}return await this.onBeforeAction(e,t,n),await s.mouse.click(t,n,{button:"right"}),await this.awaitPageReady(s),await this.captureState(e)}async rightClickByRef(e,t){let{page:n}=e,s=3e3;try{await n.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let o=n.locator(`aria-ref=${t}`),a=await o.boundingBox({timeout:s});return a&&await this.onBeforeAction(e,a.x+a.width/2,a.y+a.height/2),await o.click({button:"right",force:!0,timeout:s}),await this.awaitPageReady(n),await this.captureState(e)}catch(o){console.warn(`[BasePlaywright] rightClickByRef ref=${t} failed: ${o.message}`);let a=await this.captureState(e),l=(o.message??"").includes("intercepts pointer events")?`Ref "${t}" is covered by another element (overlay/popup). Dismiss the overlay first, or try a different ref.`:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`;return{...a,metadata:{error:l}}}}async hoverAt(e,t,n){let{page:s}=e;return await this.onBeforeAction(e,t,n),await s.mouse.move(t,n),await new Promise(o=>setTimeout(o,300)),await this.captureState(e)}async hoverByRef(e,t){let{page:n}=e,s=3e3;try{await n.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let o=n.locator(`aria-ref=${t}`),a=await o.boundingBox({timeout:s});return a&&await this.onBeforeAction(e,a.x+a.width/2,a.y+a.height/2),await o.hover({force:!0,timeout:s}),await new Promise(i=>setTimeout(i,300)),await this.captureState(e)}catch(o){return console.warn(`[BasePlaywright] hoverByRef ref=${t} failed: ${o.message}`),{...await this.captureState(e),metadata:{error:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`}}}}async typeTextAt(e,t,n,s,o,a){let{page:i}=e;await this.onBeforeAction(e,t,n),await i.mouse.click(t,n);let l;try{l=await i.evaluate(()=>{let y=document.activeElement;return y instanceof HTMLInputElement?{type:"input",inputType:y.type}:y instanceof HTMLTextAreaElement?{type:"textarea",inputType:"textarea"}:y instanceof HTMLSelectElement?{type:"select",inputType:"select"}:y.isContentEditable?{type:"contenteditable",inputType:"contenteditable"}:{type:"other",inputType:"none"}})}catch{console.warn("[BasePlaywright] page.evaluate blocked in typeTextAt, falling back to keyboard typing"),l={type:"input",inputType:"text"}}let c=["date","time","datetime-local","month","week"],u=l.type==="input"&&c.includes(l.inputType),f=["text","password","email","search","url","tel","number","textarea","contenteditable"].includes(l.inputType),p=a===!0||a==="true";if(s=this.normalizeTestingEmailForFocusedField(e,s,{inputType:l.inputType}),u){let y=!1;try{y=await i.evaluate(v=>{let _=document.activeElement;if(_ instanceof HTMLInputElement){let b=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;return b?b.call(_,v):_.value=v,_.dispatchEvent(new Event("input",{bubbles:!0})),_.dispatchEvent(new Event("change",{bubbles:!0})),!0}return!1},s)}catch{}y||(p&&f&&(await i.keyboard.press("ControlOrMeta+a"),await i.keyboard.press("Backspace")),await i.keyboard.type(s,{delay:10}))}else p&&f&&(await i.keyboard.press("ControlOrMeta+a"),await i.keyboard.press("Backspace")),await i.keyboard.type(s,{delay:10});o&&(await i.keyboard.press("Enter"),await this.awaitPageReady(i));try{await i.evaluate(()=>new Promise(y=>requestAnimationFrame(()=>setTimeout(y,50))))}catch{}let m=await this.getFocusedFieldName(i),d=await this.captureState(e);return m?{...d,metadata:{...d.metadata,typedIntoField:m}}:d}async typeByRef(e,t,n,s,o){let{page:a}=e,i=3e3;try{await a.evaluate(()=>window.getSelection()?.removeAllRanges())}catch{}try{let l=a.locator(`aria-ref=${t}`),c=await l.boundingBox({timeout:i});c&&await this.onBeforeAction(e,c.x+c.width/2,c.y+c.height/2),await l.click({force:!0,timeout:i});let u;try{u=await a.evaluate(()=>{let _=document.activeElement;return _ instanceof HTMLInputElement?{inputType:_.type}:_ instanceof HTMLTextAreaElement?{inputType:"textarea"}:_.isContentEditable?{inputType:"contenteditable"}:{inputType:"none"}})}catch{console.warn(`[BasePlaywright] page.evaluate blocked for typeByRef ref=${t}, falling back to keyboard typing`),u={inputType:"text"}}let f=["text","password","email","search","url","tel","number","textarea","contenteditable"].includes(u.inputType),m=["date","time","datetime-local","month","week"].includes(u.inputType);if(!f&&!m)return{...await this.captureState(e),metadata:{error:`Ref "${t}" resolved to a non-text element (${u.inputType||"unknown"}). Use a different ref that targets the text input directly.`}};let d=o===!0||o==="true";if(n=this.normalizeTestingEmailForFocusedField(e,n,{inputType:u.inputType}),m)try{await a.evaluate(_=>{let b=document.activeElement;if(b instanceof HTMLInputElement){let S=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;S?S.call(b,_):b.value=_,b.dispatchEvent(new Event("input",{bubbles:!0})),b.dispatchEvent(new Event("change",{bubbles:!0}))}},n)}catch{await a.keyboard.type(n,{delay:15})}else d&&f?(await a.keyboard.press("ControlOrMeta+a"),n?await a.keyboard.type(n,{delay:15}):await a.keyboard.press("Backspace")):n&&await a.keyboard.type(n,{delay:15});s&&await a.keyboard.press("Enter"),await this.awaitPageReady(a);try{await a.evaluate(()=>new Promise(_=>requestAnimationFrame(()=>setTimeout(_,50))))}catch{}let y=await this.getFocusedFieldName(a),v=await this.captureState(e);return y?{...v,metadata:{...v.metadata,typedIntoField:y}}:v}catch(l){return console.warn(`[BasePlaywright] typeByRef ref=${t} failed: ${l.message}`),{...await this.captureState(e),metadata:{error:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`}}}}async typeByLabel(e,t,n,s,o){let{page:a}=e,i=3e3,l=await a.evaluate(S=>{let w=L=>L.replace(/\s+/g," ").trim().replace(/:$/,"").toLowerCase(),k=L=>w(L).replace(/[\s:_-]+/g,""),x=w(S),I=k(S),M=L=>{let O=w(L);return O?O===x?0:k(L)===I?1:O.includes(x)||x.includes(O)?2:null:null},R=L=>{let O=window.getComputedStyle(L);if(O.display==="none"||O.visibility==="hidden")return!1;let P=L.getBoundingClientRect();return P.width>0&&P.height>0},N=L=>L instanceof HTMLTextAreaElement?!L.disabled:L instanceof HTMLInputElement?L.disabled||L.type==="hidden"?!1:["text","password","email","search","url","tel","number","date","time","datetime-local","month","week"].includes(L.type):L.isContentEditable,j=L=>L instanceof HTMLInputElement?`input[type=${L.type}]`:L instanceof HTMLTextAreaElement?"textarea":L.isContentEditable?"contenteditable":L.tagName.toLowerCase(),A=L=>L instanceof HTMLInputElement||L instanceof HTMLTextAreaElement?L.value:L.isContentEditable?L.textContent??"":"",F=L=>{let O=[];for(let P of Array.from(L.childNodes))if(P.nodeType===Node.TEXT_NODE){let ae=P.textContent?.trim();ae&&O.push(ae)}else if(P instanceof HTMLElement&&!N(P)){let ae=P.innerText?.trim();ae&&O.push(ae)}return O.join(" ").replace(/\s+/g," ").trim()},W=L=>{let O=[],P=(V,E,T)=>{let U=V?.replace(/\s+/g," ").trim();U&&O.push({label:U,source:E,priority:T})};P(L.getAttribute("aria-label"),"aria-label",0);let ae=L.getAttribute("aria-labelledby");if(ae&&P(ae.split(/\s+/).map(V=>document.getElementById(V)?.textContent?.trim()).filter(Boolean).join(" "),"aria-labelledby",0),L instanceof HTMLInputElement||L instanceof HTMLTextAreaElement)for(let V of Array.from(L.labels??[]))P(V.textContent,"label",0);let te=L.id;te&&P(document.querySelector(`label[for="${te}"]`)?.textContent,"label[for]",0),(L instanceof HTMLInputElement||L instanceof HTMLTextAreaElement)&&(P(L.placeholder,"placeholder",1),P(L.name,"name",2),P(L.id,"id",2));let J=L.previousElementSibling;for(;J;)P(J instanceof HTMLElement?J.innerText:J.textContent,"previous-sibling",3),J=J.previousElementSibling;let G=L.parentElement;for(let V=0;G&&V<3;V+=1,G=G.parentElement)P(F(G),"container-text",4+V);return O},Y=[],H=Array.from(document.querySelectorAll('input:not([type="hidden"]), textarea, [contenteditable="true"]')).filter(L=>N(L)&&R(L));for(let L of H)for(let O of W(L)){let P=M(O.label);P!=null&&Y.push({element:L,label:O.label,source:O.source,priority:O.priority,matchRank:O.priority*10+P,elementType:j(L),valueBefore:A(L)})}if(Y.length===0)return{status:"none",error:`No text input found for label "${S}". Check the latest page snapshot for the field label or use ref/x/y.`};Y.sort((L,O)=>L.matchRank-O.matchRank);let B=Y[0].matchRank,se=Y.filter(L=>L.matchRank===B);if(Array.from(new Set(se.map(L=>L.element))).length>1)return{status:"ambiguous",error:`Multiple text inputs matched label "${S}". Use a more specific label or a direct ref.`,matches:se.map(L=>({label:L.label,source:L.source,elementType:L.elementType}))};let ne=`agentiqa_label_target_${Date.now()}_${Math.random().toString(36).slice(2)}`;return se[0].element.setAttribute("data-agentiqa-label-target",ne),{status:"ok",marker:ne,matchedLabel:se[0].label,labelSource:se[0].source,elementType:se[0].elementType,valueBefore:se[0].valueBefore}},t);if(l.status!=="ok"){let S=await this.captureState(e);return{...S,metadata:{...S.metadata,error:l.error,...l.status==="ambiguous"&&{matches:l.matches}}}}let c=a.locator(`[data-agentiqa-label-target="${l.marker}"]`).first(),u=await c.boundingBox({timeout:i});u&&await this.onBeforeAction(e,u.x+u.width/2,u.y+u.height/2),await c.click({force:!0,timeout:i});let h=await a.evaluate(()=>{let S=document.activeElement;return S instanceof HTMLInputElement?{inputType:S.type}:S instanceof HTMLTextAreaElement?{inputType:"textarea"}:S.isContentEditable?{inputType:"contenteditable"}:{inputType:"none"}}),p=["date","time","datetime-local","month","week"].includes(h.inputType),d=["text","password","email","search","url","tel","number","textarea","contenteditable"].includes(h.inputType);if(!d&&!p){let S=await this.captureState(e);return{...S,metadata:{...S.metadata,error:`Label "${t}" resolved to a non-text element (${h.inputType||"unknown"}). Use a different label or direct ref.`}}}let y=o===!0||o==="true";if(n=this.normalizeTestingEmailForFocusedField(e,n,{inputType:h.inputType,label:t,matchedLabel:l.matchedLabel}),p)try{await a.evaluate(S=>{let w=document.activeElement;if(w instanceof HTMLInputElement){let k=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;k?k.call(w,S):w.value=S,w.dispatchEvent(new Event("input",{bubbles:!0})),w.dispatchEvent(new Event("change",{bubbles:!0}))}},n)}catch{await a.keyboard.type(n,{delay:15})}else y&&d?(await a.keyboard.press("ControlOrMeta+a"),n?await a.keyboard.type(n,{delay:15}):await a.keyboard.press("Backspace")):n&&await a.keyboard.type(n,{delay:15});s&&await a.keyboard.press("Enter"),await this.awaitPageReady(a);try{await a.evaluate(()=>new Promise(S=>requestAnimationFrame(()=>setTimeout(S,50))))}catch{}let v=await this.getFocusedFieldName(a),_=await a.evaluate(()=>{let S=document.activeElement;return S instanceof HTMLInputElement||S instanceof HTMLTextAreaElement?S.value:S instanceof HTMLElement&&S.isContentEditable?S.textContent??"":""}),b=await this.captureState(e);return{...b,metadata:{...b.metadata,typedIntoField:v??l.matchedLabel,matchedLabel:l.matchedLabel,labelSource:l.labelSource,elementType:l.elementType,valueBefore:l.valueBefore,valueAfter:_}}}async scrollDocument(e,t){let{page:n,viewportHeight:s}=e,o=Math.floor(s*.8);return t==="up"?await n.evaluate(a=>window.scrollBy(0,-a),o):t==="down"?await n.evaluate(a=>window.scrollBy(0,a),o):t==="left"?await n.evaluate(a=>window.scrollBy(-a,0),o):t==="right"&&await n.evaluate(a=>window.scrollBy(a,0),o),await new Promise(a=>setTimeout(a,200)),await this.captureState(e)}async scrollToBottom(e){let{page:t}=e;return await t.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await new Promise(n=>setTimeout(n,200)),await this.captureState(e)}async scrollAt(e,t,n,s,o){let{page:a}=e;await a.mouse.move(t,n);let i=0,l=0;switch(s){case"up":l=-o;break;case"down":l=o;break;case"left":i=-o;break;case"right":i=o;break}return await a.mouse.wheel(i,l),await new Promise(c=>setTimeout(c,200)),await this.captureState(e)}async waitSeconds(e,t){let n=Math.min(Math.max(t,1),30);return await new Promise(s=>setTimeout(s,n*1e3)),await this.captureState(e)}async waitForElement(e,t,n){let{page:s}=e,o=Math.min(Math.max(n,1),30);try{return await s.getByText(t,{exact:!1}).first().waitFor({state:"visible",timeout:o*1e3}),await new Promise(i=>setTimeout(i,300)),await this.captureState(e)}catch{return{...await this.captureState(e),metadata:{error:`Text "${t}" not found within ${o}s. Do NOT retry \u2014 the page likely loaded with different text. Inspect the screenshot and proceed with the next action, or report_issue if blocked.`}}}}async fullPageScreenshot(e){let{page:t}=e,n=await this.screenshotWithSlowSiteRetry(e,{fullPage:!0}),s=t.url();return{screenshot:n,url:s}}async switchLayout(e,t,n){let{page:s}=e;return await s.setViewportSize({width:t,height:n}),await this.captureState(e)}async goBack(e){let{page:t}=e;return e.needsFullSnapshot=!0,await t.goBack(),await this.awaitPageReady(t),await this.captureState(e)}async goForward(e){let{page:t}=e;return e.needsFullSnapshot=!0,await t.goForward(),await this.awaitPageReady(t),await this.captureState(e)}async navigate(e,t){let{page:n}=e,s=Cr(t),o=await this.blockScopedNavigationIfNeeded(e,s);if(o)return o;e.needsFullSnapshot=!0;let a=await n.goto(s,{waitUntil:"domcontentloaded"});await this.awaitPageReady(n),await this.assertNoCloudflareBlock(n,a,s);let i=[],l=a?.request().redirectedFrom()??null;for(;l;)i.unshift(l.url()),l=l.redirectedFrom();let c=n.url(),u=sc(s,c,i,(f,p,m,d)=>console.warn(`[BasePlaywright] [${p}] ${m}`,d??"")),h=await this.captureState(e);return{...h,metadata:{...h.metadata??{},navigateMeta:u}}}async blockScopedNavigationIfNeeded(e,t){let n=my({targetUrl:t,currentUrl:e.page.url(),scope:e.browserNavigationScope,allowExternalNavigation:e.allowExternalNavigation,httpsCertFallbackHost:e.httpsCertFallback?.host});if(n.allowed)return null;let s=await this.captureState(e),o=e.browserNavigationScope?.join(", ")||"(none)";return{...s,metadata:{...s.metadata??{},error:`Navigation blocked: ${t} is outside the allowed scope (${o}). Record/report the external link without opening it unless the user explicitly asked to validate external links.`,scopedNavigation:{status:"blocked",targetUrl:t,reason:n.reason}}}}async keyCombination(e,t){let{page:n}=e,s=t.map(a=>kP[a.toLowerCase()]??a),o=s.some(a=>ou.has(a));if(s.length===1)await n.keyboard.press(s[0]);else if(o){let a=s.filter(l=>ou.has(l)),i=s.filter(l=>!ou.has(l));for(let l of a)await n.keyboard.down(l);for(let l of i)await n.keyboard.press(l);for(let l of a.reverse())await n.keyboard.up(l)}else for(let a of s)await n.keyboard.press(a);return await this.awaitPageReady(n),await this.captureState(e)}async setFocusedInputValue(e,t){let{page:n}=e,s={isSelect:!1,inputType:"none"};try{s=await n.evaluate(()=>{let i=document.activeElement;return i instanceof HTMLSelectElement?{isSelect:!0,inputType:"select"}:i instanceof HTMLInputElement?{isSelect:!1,inputType:i.type}:i instanceof HTMLTextAreaElement?{isSelect:!1,inputType:"textarea"}:i?.isContentEditable?{isSelect:!1,inputType:"contenteditable"}:{isSelect:!1,inputType:"none"}})}catch{return console.warn("[BasePlaywright] page.evaluate blocked in setFocusedInputValue, falling back to keyboard typing"),t=this.normalizeTestingEmailForFocusedField(e,t,{}),await n.keyboard.press("ControlOrMeta+a"),await n.keyboard.type(t,{delay:10}),{...await this.captureState(e),metadata:{elementType:"unknown (evaluate blocked)",valueBefore:"",valueAfter:t}}}if(s.isSelect)return await this.setSelectValue(e,t);t=this.normalizeTestingEmailForFocusedField(e,t,{inputType:s.inputType});let o=await n.evaluate(i=>{let l=document.activeElement,c=p=>p instanceof HTMLInputElement?`input[type=${p.type}]`:p instanceof HTMLTextAreaElement?"textarea":p.isContentEditable?"contenteditable":p.tagName.toLowerCase(),u=p=>p instanceof HTMLInputElement||p instanceof HTMLTextAreaElement?p.value:p.isContentEditable&&p.textContent||"";if(!l||l===document.body)return{success:!1,error:"No element is focused",elementType:"none",valueBefore:"",valueAfter:""};let h=c(l),f=u(l);try{if(l instanceof HTMLInputElement){let p=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;p?p.call(l,i):l.value=i,l.dispatchEvent(new Event("input",{bubbles:!0})),l.dispatchEvent(new Event("change",{bubbles:!0}))}else if(l instanceof HTMLTextAreaElement){let p=Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,"value")?.set;p?p.call(l,i):l.value=i,l.dispatchEvent(new Event("input",{bubbles:!0})),l.dispatchEvent(new Event("change",{bubbles:!0}))}else if(l.isContentEditable)l.textContent=i,l.dispatchEvent(new Event("input",{bubbles:!0}));else return{success:!1,error:`Element is not editable: ${h}`,elementType:h,valueBefore:f,valueAfter:f}}catch(p){return{success:!1,error:String(p.message||p),elementType:h,valueBefore:f,valueAfter:u(l)}}return{success:!0,elementType:h,valueBefore:f,valueAfter:u(l)}},t);return{...await this.captureState(e),metadata:{elementType:o.elementType,valueBefore:o.valueBefore,valueAfter:o.valueAfter,...o.error&&{error:o.error}}}}async setSelectValue(e,t){let{page:n}=e,s=await n.evaluate(()=>{let u=document.activeElement;if(!(u instanceof HTMLSelectElement))return null;let h=u.options[u.selectedIndex]?.textContent?.trim()||"",f=Array.from(u.options).map(p=>p.textContent?.trim()||p.value);return{valueBefore:h,options:f}});if(!s)return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:"",valueAfter:"",error:"No select element is focused. Use click_at on the select first."}};let a=(await n.evaluateHandle(()=>document.activeElement)).asElement();if(!a)return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:s.valueBefore,valueAfter:s.valueBefore,error:"Could not get select element handle",availableOptions:s.options}};let i=!1;try{await a.selectOption({label:t}),i=!0}catch{try{await a.selectOption({value:t}),i=!0}catch{}}let l=await n.evaluate(()=>{let u=document.activeElement;return u instanceof HTMLSelectElement?u.options[u.selectedIndex]?.textContent?.trim()||u.value:""});return{...await this.captureState(e),metadata:{elementType:"select",valueBefore:s.valueBefore,valueAfter:l,...!i&&{error:`No option matching "${t}"`},availableOptions:s.options}}}async uploadFile(e,t){let{page:n}=e;console.log(`[BasePlaywright] upload_file called with filePaths=${JSON.stringify(t)}`);let o=(await n.evaluateHandle(()=>document.querySelector('input[type="file"][data-agentiqa-file-target]')||document.activeElement)).asElement();if(!o)return{...await this.captureState(e),metadata:{elementType:"file",error:"No file input found. Use click_at on the file input first."}};let a=await n.evaluate(u=>u instanceof HTMLInputElement&&u.type==="file"?{isFileInput:!0,accept:u.accept||"*",multiple:u.multiple}:{isFileInput:!1,accept:"",multiple:!1},o);if(!a.isFileInput)return{...await this.captureState(e),metadata:{elementType:"not-file-input",error:"No file input found. Use click_at on the file input/upload area first."}};try{await o.setInputFiles(t),console.log(`[BasePlaywright] upload_file setInputFiles succeeded, count=${t.length}`)}catch(u){return console.log(`[BasePlaywright] upload_file setInputFiles failed: ${u.message}`),{...await this.captureState(e),metadata:{elementType:"file",accept:a.accept,multiple:a.multiple,error:`File upload failed: ${u.message}`}}}let i=await this.onFilesUploaded(t),l=await n.evaluate(()=>document.querySelector('input[type="file"][data-agentiqa-file-target]')?.files?.length||0);return console.log(`[BasePlaywright] upload_file result: fileCount=${l}`),await this.awaitPageReady(n),{...await this.captureState(e),metadata:{elementType:"file",accept:a.accept,multiple:a.multiple,fileCount:l,...i.length>0&&{storedAssets:i}}}}async dragAndDrop(e,t,n,s,o){let{page:a}=e;return await a.mouse.move(t,n),await a.mouse.down(),await a.mouse.move(s,o,{steps:10}),await a.mouse.up(),await this.captureState(e)}async resolveRefCenter(e,t){try{let o=await e.page.locator(`aria-ref=${t}`).boundingBox({timeout:3e3});return o?{x:Math.floor(o.x+o.width/2),y:Math.floor(o.y+o.height/2)}:null}catch{return null}}async refNotFoundError(e,t){return{...await this.captureState(e),metadata:{error:`Ref "${t}" not found \u2014 the page may have changed. Check the latest page snapshot for updated refs.`}}}async switchTab(e,t){if(t==="tab1"){let n=!e.tab1||e.tab1.isClosed();if(this.diagLog?.(e.sessionId,"switchTab tab1 requested",{tab1Closed:n,hasExtId:!!e.extensionId}),n&&e.extensionId){this.diagLog?.(e.sessionId,"switchTab auto-recreating tab1 at popup.html");let s=await e.context.newPage();Ci(s),await s.goto(`chrome-extension://${e.extensionId}/popup.html`,{timeout:5e3}),e.tab1=s}if(!e.tab1||e.tab1.isClosed())return{...await this.captureState(e),metadata:{error:"Tab 1 is not available"}};if(e.page=e.tab1,e.activeTab="tab1",e.extensionId){let s=e.tab1.url();if(!s.startsWith(`chrome-extension://${e.extensionId}`)){this.diagLog?.(e.sessionId,"switchTab navigating to popup.html",{beforeUrl:s});try{await e.tab1.goto(`chrome-extension://${e.extensionId}/popup.html`,{timeout:5e3});let o=e.tab1.url();this.diagLog?.(e.sessionId,"switchTab popup.html loaded",{afterUrl:o})}catch(o){this.diagLog?.(e.sessionId,"switchTab popup.html failed",{error:o?.message})}}}}else{if(!e.tab2||e.tab2.isClosed())return{...await this.captureState(e),metadata:{error:"Tab 2 is not available. No second tab is open."}};e.page=e.tab2,e.activeTab="tab2"}return e.needsFullSnapshot=!0,await e.page.bringToFront(),await this.captureState(e)}async closeTab(e){if(e.activeTab==="tab1")return{...await this.captureState(e),metadata:{error:"Cannot close tab 1"}};if(e.tab2&&!e.tab2.isClosed())try{await e.tab2.close()}catch{}return e.tab2=void 0,e.page=e.tab1,e.activeTab="tab1",e.needsFullSnapshot=!0,await e.page.bringToFront(),await this.captureState(e)}static HTTP_BODY_MAX_LENGTH=5e4;async httpRequest(e,t,n,s,o){let{page:a}=e;try{let i={method:n,timeout:3e4,ignoreHTTPSErrors:!0};s&&(i.headers=s),o&&n!=="GET"&&(i.data=o);let l=await a.request.fetch(t,i),c=await l.text(),u=!1;if(c.length>r.HTTP_BODY_MAX_LENGTH&&(c=c.slice(0,r.HTTP_BODY_MAX_LENGTH),u=!0),(l.headers()["content-type"]||"").includes("application/json")&&!u)try{c=JSON.stringify(JSON.parse(c),null,2),c.length>r.HTTP_BODY_MAX_LENGTH&&(c=c.slice(0,r.HTTP_BODY_MAX_LENGTH),u=!0)}catch{}return{...await this.captureState(e),metadata:{httpResponse:{status:l.status(),statusText:l.statusText(),headers:l.headers(),body:c,...u&&{truncated:!0}}}}}catch(i){return{...await this.captureState(e),metadata:{error:`HTTP request failed: ${i.message}`}}}}static RUN_JS_INPUT_MAX_LENGTH=4e3;static RUN_JS_RESULT_MAX_LENGTH=5e3;static RUN_JS_TIMEOUT_MS=1e4;async runJs(e,t){if(t.length>r.RUN_JS_INPUT_MAX_LENGTH)return{...await this.captureState(e),metadata:{error:`run_js code exceeded ${r.RUN_JS_INPUT_MAX_LENGTH}-char cap (${t.length} chars).`}};let n=`(async () => {
1590
1591
  try {
1591
1592
  const __res = await (async () => { ${t} })();
1592
1593
  return { ok: true, value: __res };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentiqa",
3
- "version": "1.1.7-staging.4883a7e",
3
+ "version": "1.1.7-staging.7150afd",
4
4
  "description": "AI-powered testing for web and mobile apps",
5
5
  "type": "module",
6
6
  "bin": "dist/cli.js",