momentic 0.0.41 → 0.0.42
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.
- package/bin/cli.js +19 -19
- package/dist/index.js +16 -16
- package/package.json +1 -1
- package/static/assets/index-9OiucgOW.js +204 -0
- package/static/assets/index-dLnz0DFS.css +1 -0
- package/static/index.html +2 -2
- package/static/assets/index-CBt7niJj.css +0 -1
- package/static/assets/index-dSsErvnW.js +0 -196
package/bin/cli.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
2
|
+
import{Command as Dl,Option as ye}from"commander";import _l from"dedent";import Ka from"body-parser";import qa from"cors";import Nr from"express";import{existsSync as Ya,statSync as Xa}from"fs";import Ja from"http";import Qa from"open";import Za,{join as el}from"path";import{Server as Ea}from"socket.io";import{v4 as gs}from"uuid";var Ft=class{sessions=new Map;registerSession(e,t,n=gs()){return this.sessions.set(n,{controller:e,context:t}),n}async removeSession(e){let t=this.sessions.get(e);if(!t)return;let{controller:n}=t;await n.browser.cleanup(),this.sessions.delete(e)}getSession(e){return this.sessions.get(e)}},H=new Ft;function Vr(r,e,t){let n=async()=>{let s=H.getSession(e)?.controller;if(!s)return;let a=await s.browser.screenshot({});r.emit("screenshot",{viewport:await s.browser.getViewport(),buffer:a,url:await s.browser.url()})},o=setInterval(()=>{(async()=>{let a=H.getSession(e)?.controller?.browser;if(!a||a.closed){clearInterval(o);return}try{await n()}catch(i){clearInterval(o),t.error(i,"Error taking screenshot")}})()},1e3);return o}var ys=({metadata:r,rootState:e,logger:t})=>{let{sessionId:n}=r,o=async()=>{e||await H.removeSession(n)};return s=>{t.info({sessionId:n,reason:s},"Disconnect event received"),o().catch(a=>{t.error({err:a},"Error during disconnect cleanup.")})}},jr={event:"disconnect",createHandler:ys};import ir,{readFileSync as No,readdirSync as yi}from"fs";import Ke from"path";import fi from"diff-lines";import Tt from"semver";import*as q from"zod";var dt=q.object({id:q.number().int(),role:q.string().optional(),name:q.string().optional(),numChildren:q.number().optional(),content:q.string().optional(),pathFromRoot:q.string().optional(),serializedForm:q.string().optional(),nodeOnlySerializedForm:q.string().optional()});function mt(r){return r.name||r.role||r.content||r.serializedForm}import{z as Je}from"zod";var Gr=Je.object({thoughts:Je.string(),result:Je.boolean(),relevantElements:Je.array(Je.number()).optional()});import mc from"string-argv";import{z as F}from"zod";import Ss from"dedent";import*as u from"zod";var ne=(x=>(x.AI_EXTRACT="AI_EXTRACT",x.AI_ASSERTION="AI_ASSERTION",x.AI_WAIT="AI_WAIT",x.CAPTCHA="CAPTCHA",x.CLICK="CLICK",x.COOKIE="COOKIE",x.DRAG="DRAG",x.GO_BACK="GO_BACK",x.GO_FORWARD="GO_FORWARD",x.HOVER="HOVER",x.JAVASCRIPT="JAVASCRIPT",x.LOCAL_STORAGE="LOCAL_STORAGE",x.NAVIGATE="NAVIGATE",x.PRESS="PRESS",x.REFRESH="REFRESH",x.REQUEST="REQUEST",x.SCROLL_DOWN="SCROLL_DOWN",x.SCROLL_UP="SCROLL_UP",x.SCROLL_LEFT="SCROLL_LEFT",x.SCROLL_RIGHT="SCROLL_RIGHT",x.SELECT_OPTION="SELECT_OPTION",x.TAB="TAB",x.TYPE="TYPE",x.VISUAL_DIFF="VISUAL_DIFF",x.WAIT="WAIT",x.SUCCESS="SUCCESS",x))(ne||{}),Z=u.object({elementDescriptor:u.string(),a11yData:dt.optional()}),L=u.object({thoughts:u.string().optional()}),ws=L.merge(u.object({type:u.literal("NAVIGATE"),url:u.string()})).describe("NAVIGATE <URL> - Go to the specified URL. Only navigate to URLs relevant to the user goal."),bs=L.merge(u.object({target:Z.optional(),type:u.literal("SCROLL_UP"),useVision:u.boolean().default(!1),deltaY:u.number().optional()})).describe("SCROLL_UP [id] - Scroll up while hovering over the element with the specified id. If no id is provided, scroll the entire page."),vs=L.merge(u.object({target:Z.optional(),type:u.literal("SCROLL_DOWN"),useVision:u.boolean().default(!1),deltaY:u.number().optional()})).describe("SCROLL_DOWN [id] - Scroll down while hovering over the element with the specified id. If no id is provided, scroll a single page height."),As=L.merge(u.object({target:Z.optional(),type:u.literal("SCROLL_LEFT"),useVision:u.boolean().default(!1),deltaX:u.number().optional()})).describe("SCROLL_LEFT [id] - Scroll leftwards while hovering over the element with the specified id. If no id is provided, scroll a single page width."),Es=L.merge(u.object({target:Z.optional(),type:u.literal("SCROLL_RIGHT"),useVision:u.boolean().default(!1),deltaX:u.number().optional()})).describe("SCROLL_RIGHT [id] - Scroll rightwards while hovering over the element with the specified id. If no id is provided, scroll a single page width."),Ts=L.merge(u.object({type:u.literal("WAIT"),delay:u.number()})),Cs=L.merge(u.object({type:u.literal("REFRESH")})),Rs=L.merge(u.object({type:u.literal("GO_BACK")})),xs=L.merge(u.object({type:u.literal("GO_FORWARD")})),Is=L.merge(u.object({type:u.literal("CAPTCHA"),useVision:u.boolean().default(!1)})),Ls=L.merge(u.object({type:u.literal("JAVASCRIPT"),code:u.string(),fragment:u.boolean().default(!1),timeout:u.number().int().max(10).optional().describe("Max seconds for the code to complete")})),Os=L.merge(u.object({type:u.literal("CLICK"),target:Z,doubleClick:u.boolean().default(!1),rightClick:u.boolean().default(!1),useVision:u.boolean().default(!1),force:u.boolean().default(!1)})).describe(Ss`CLICK <id> - click on the element that has the specified id.
|
|
3
3
|
You are NOT allowed to click on disabled or hidden elements.
|
|
4
4
|
Only click on elements on the Current Page.
|
|
5
5
|
You should try to click on relevant elements with the following tag names: button, input, link, image.
|
|
6
6
|
As a last resort, you may click on relevant generic elements.
|
|
7
7
|
`.replaceAll(`
|
|
8
|
-
`," ")),
|
|
8
|
+
`," ")),Ms=L.merge(u.object({type:u.literal("DRAG"),fromTarget:Z,toTarget:Z,useVision:u.boolean().default(!1),force:u.boolean().default(!1)})),Ns=L.merge(u.object({type:u.literal("HOVER"),target:Z,useVision:u.boolean().default(!1),force:u.boolean().default(!1)})),Ps=L.merge(u.object({type:u.literal("SELECT_OPTION"),target:Z,option:u.string()})).describe(`SELECT_OPTION <id> "<option>" - select an option from a dropdown-type element on the page. Provide the "id" of the dropdown element in the <id> argument and the "name" of the option to be selected in the <option> argument enclosed by single quotes. ONLY use this command to interact with combobox, listbox, or menu elements. For other element types, use CLICK. For example, to select Option 2 from <combobox id="24">
|
|
9
9
|
<menuitem name="Option 1" />
|
|
10
10
|
<menuitem id="26" name="Option 2" />
|
|
11
|
-
</combobox>, output SELECT_OPTION 24 'Option 2'`),_t=L.merge(u.object({type:u.literal("AI_ASSERTION"),assertion:u.string(),useVision:u.boolean().default(!1),disableCache:u.boolean().default(!1),cancelOnFailure:u.boolean().default(!1)})),Ls=_t.merge(u.object({type:u.literal("AI_WAIT"),timeout:u.number().int().optional().describe("Max seconds to wait for assertion to be true")})),Os=L.merge(u.object({type:u.literal("AI_EXTRACT"),goal:u.string(),schema:u.string().optional(),disableCache:u.boolean().default(!1)})),Ms=u.object({clearContent:u.boolean().default(!0),pressKeysSequentially:u.boolean().default(!1)}),Ns=L.merge(u.object({type:u.literal("TYPE"),target:Z.optional(),value:u.string(),pressEnter:u.boolean().default(!1),useVision:u.boolean().default(!1),force:u.boolean().default(!1)})).merge(Ms).describe('TYPE <id> "<text>" - type the specified text into the input with the specified id. The text should be specified by the user - do not use text from the EXAMPLES or generate text yourself. Make sure to include quotes around the text.'),Ps=L.merge(u.object({type:u.literal("PRESS"),value:u.string()})).describe('PRESS <key> - press the specified key, such as "ArrowLeft", "Enter", or "a". You must specify at least one key. Do not provide key codes; only use key names supported by the Playwright press method.'),Ds=L.merge(u.object({type:u.literal("TAB"),url:u.string()})),_s=L.merge(u.object({type:u.literal("COOKIE"),value:u.string()})),ks=L.merge(u.object({type:u.literal("LOCAL_STORAGE"),key:u.string(),value:u.string()})),Fs=L.merge(u.object({type:u.literal("REQUEST"),url:u.string(),method:u.union([u.literal("GET"),u.literal("POST"),u.literal("PUT"),u.literal("DELETE"),u.literal("PATCH")]),headers:u.record(u.string(),u.string()).optional(),params:u.record(u.string(),u.string()).optional(),body:u.string().optional(),timeout:u.number().int().optional().describe("Max seconds to wait for the request to complete")})),zs=L.merge(u.object({type:u.literal("SUCCESS"),condition:_t.optional()})).describe("SUCCESS - the user goal has been successfully achieved"),Us=u.object({data:u.string().describe("s3 url to a jpg"),width:u.number(),height:u.number()}),$s=L.merge(u.object({type:u.literal("VISUAL_DIFF"),threshold:u.number().default(.1),target:Z.optional(),screenshot:Us.optional(),useVision:u.boolean().default(!1)})),Be=u.discriminatedUnion("type",[Cs,Ns,Ps,Is,hs,gs,fs,zs]),Hs=u.discriminatedUnion("type",[_t,Ls,Es,_s,Os,Rs,vs,As,xs,Ts,ks,bs,Fs,ys,Ss,Ds,$s,ws]),Br=u.discriminatedUnion("type",[...Be.options,...Hs.options]),Bs=L.merge(u.object({type:u.literal("FAILURE")})).describe("FAILURE - there are no commands to suggest that could make progress that have not already been tried before"),kt=u.discriminatedUnion("type",[...Be.options,Bs]),dt=r=>{switch(r){case"AI_EXTRACT":return{type:r,goal:"",disableCache:!1};case"NAVIGATE":return{type:"NAVIGATE",url:""};case"CAPTCHA":return{type:r,useVision:!1};case"DRAG":return{type:r,fromTarget:{elementDescriptor:""},toTarget:{elementDescriptor:""},useVision:!1,force:!1};case"GO_BACK":case"GO_FORWARD":case"REFRESH":return{type:r};case"SCROLL_DOWN":case"SCROLL_UP":case"SCROLL_LEFT":case"SCROLL_RIGHT":return{type:r,useVision:!1};case"WAIT":return{type:r,delay:1};case"CLICK":return{type:r,target:{elementDescriptor:""},doubleClick:!1,rightClick:!1,useVision:!1,force:!1};case"HOVER":return{type:r,target:{elementDescriptor:""},useVision:!1,force:!1};case"TYPE":return{type:r,target:void 0,value:"",clearContent:!0,pressEnter:!1,pressKeysSequentially:!1,useVision:!1,force:!1};case"PRESS":return{type:r,value:""};case"SELECT_OPTION":return{type:r,target:{elementDescriptor:""},option:""};case"TAB":return{type:r,url:""};case"REQUEST":return{type:r,url:"",method:"GET"};case"COOKIE":return{type:r,value:""};case"LOCAL_STORAGE":return{type:r,key:"",value:""};case"JAVASCRIPT":return{type:r,code:"",fragment:!1};case"AI_WAIT":case"AI_ASSERTION":return{type:r,assertion:"",disableCache:!1,useVision:!1,cancelOnFailure:!1};case"SUCCESS":return{type:r};case"VISUAL_DIFF":return{type:r,threshold:.1,useVision:!1};default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}};var Ae=(a=>(a.AI_PROVIDER="AIProviderError",a.AI_TIMEOUT="AITimeoutError",a.JOB_TIMEOUT="JobTimeoutError",a.ACTION_FAILURE="ActionFailureError",a.ASSERTION_FAILURE="AssertionFailureError",a.WEB_AGENT_PLATFORM="InternalWebAgentError",a.UNKNOWN_PLATFORM="InternalPlatformError",a))(Ae||{});var mt=class extends Error{constructor(e={}){super("Got empty a11y tree",e),this.name="EmptyA11yTreeError"}};var T=class extends Error{reason;emitToUser;constructor(e,t,n={},o=!1){let s=!1;for(let i of Object.values(Ae))if(t.startsWith(i)){s=!0,e=i;break}s?super(t,n):super(`${e}${t?`: ${t}`:""}`,n),this.name="TestFailureError",this.stack=this.stack?.slice(this.name.length+2),this.reason=e,this.emitToUser=o}toString(){return this.message}toJSON(){return{message:this.message}}};var lc=k.object({command:k.string(),thoughts:k.string()}),cc=k.string().pipe(k.coerce.number());var jr=k.object({phrase:k.string()}),Ft=k.object({result:k.union([k.literal("NOT_FOUND"),k.string(),k.number(),k.array(k.unknown()),k.record(k.unknown(),k.unknown())])});import js from"lodash.unset";import*as D from"zod";var G="1.0.6",U=(n=>(n.AI_ACTION="AI_ACTION",n.PRESET_ACTION="PRESET_ACTION",n.MODULE="MODULE",n))(U||{}),Xe=D.object({type:D.literal("AI_ACTION"),text:D.string(),commands:D.array(Be).optional()}),Je=D.object({type:D.literal("PRESET_ACTION"),command:Br}),zt=D.object({type:D.literal("MODULE"),moduleId:D.string().uuid()}),Ee=D.union([Xe,Je]),Qe=D.object({type:D.literal("RESOLVED_MODULE"),moduleId:D.string().uuid(),name:D.string(),steps:Ee.array()}),Te=D.union([Xe,Je,zt]),Ce=D.union([Xe,Je,Qe]);var Gs=["command.screenshot"];function j(r){let e=JSON.parse(JSON.stringify(r));return Gs.forEach(t=>{js(e,t)}),e}var yc=new Set(Object.values(oe));var Ut={AI_ACTION:"AI action",MODULE:"Module",AI_ASSERTION:"AI check",AI_WAIT:"AI wait",AI_EXTRACT:"AI extract",CLICK:"Click",TYPE:"Type",JAVASCRIPT:"JavaScript",SELECT_OPTION:"Select",PRESS:"Press",NAVIGATE:"Navigate",SCROLL_UP:"Scroll up",SCROLL_DOWN:"Scroll down",SCROLL_LEFT:"Scroll left",SCROLL_RIGHT:"Scroll right",HOVER:"Hover",GO_BACK:"Go back",GO_FORWARD:"Go forward",WAIT:"Wait",REFRESH:"Refresh",TAB:"Switch tab",COOKIE:"Cookie",LOCAL_STORAGE:"Local storage",REQUEST:"Request",CAPTCHA:"CAPTCHA",DRAG:"Drag & drop",VISUAL_DIFF:"Visual diff",SUCCESS:"Done"},Sc={AI_ACTION:"Ask AI to plan and execute something on the page.",MODULE:"A list of steps that can be reused in multiple tests.",AI_ASSERTION:"Ask AI whether something is true on the page.",AI_WAIT:"Wait until AI considers a condition to be true.",CLICK:"Click on an element on the page based on a description.",AI_EXTRACT:"Ask AI to extract data from the page based on a description.",HOVER:"Hover over an element on the page based on a description.",SELECT_OPTION:"Select an option from a dropdown based on a description.",TYPE:"Type the specified text into an element.",PRESS:"Press the specified keys using the keyboard. (e.g. Ctrl+A)",NAVIGATE:"Navigate to the specified URL.",SCROLL_UP:"Scroll up by a specified height.",SCROLL_DOWN:"Scroll down by a specified height.",SCROLL_LEFT:"Scroll left by a specified width.",SCROLL_RIGHT:"Scroll right by a specified width.",GO_BACK:"Go back in browser history.",GO_FORWARD:"Go forward in browser history.",WAIT:"Wait for the specified number of seconds.",REFRESH:"Refresh the page. This will not clear cookies or session data.",TAB:"Switch to different tab in the browser.",COOKIE:"Set a cookie that will persist throughout the browser session",LOCAL_STORAGE:"Set a local storage value that will persist throughout the browser session",CAPTCHA:"Solve CAPTCHAs on the page. This may take 10-60 seconds.",REQUEST:"Make an API request to a URL.",JAVASCRIPT:"Run JavaScript code in an isolated context.",DRAG:"Click and drag an element to another location.",VISUAL_DIFF:"Compare a screenshot of the page or a specific element to a baseline image.",SUCCESS:"Indicate the entire AI action has succeeded, optionally based on a condition."};import*as C from"zod";import*as _ from"zod";import{z as je}from"zod";var Gr=(t=>(t.PROD="production",t.DEV="development",t))(Gr||{}),vc=Object.values(Gr),Re="BASE_URL",Ac={[Re]:"https://www.google.com"},Vr=je.string().describe("Name of the fixture (must be available locally in the fixtures directory)."),ee=je.object({name:je.string(),variables:je.record(je.string().describe("variable name"),je.string().describe("variable value"))});import*as xe from"zod";var Wr=xe.object({type:xe.nativeEnum(U),generatedStep:Be.optional(),serializedCommand:xe.string().optional(),elementInteracted:xe.string().optional()});var le=_.object({goal:_.string(),url:_.string(),browserState:_.string(),history:_.string(),numPrevious:_.number(),lastCommand:Wr.or(_.null()),returnSchema:_.string().optional()}),$t=_.object({env:_.record(_.unknown()),results:_.array(_.unknown()),steps:_.array(Ce)}),q=class{env={};steps;results;constructor(e,t){this.env[Re]=e,this.steps=t.map(j),this.results=[]}setSteps(e){this.steps=e.map(j)}setResult(e,t){this.results[e]=t||null}clearResults(){this.results=[]}getVariable(e){return this.env[e]}setVariable(e,t){this.env[e]=t}toObjectRef(){return{steps:this.steps,results:this.results,env:this.env}}toObjectCopy(){return JSON.parse(JSON.stringify(this.toObjectRef()))}reset(e){this.env={},this.steps=[],this.results=[],e&&(this.env[Re]=e)}};var Ie=(s=>(s.SUCCESS="SUCCESS",s.FAILED="FAILED",s.RUNNING="RUNNING",s.IDLE="IDLE",s.CANCELLED="CANCELLED",s))(Ie||{}),ut=(n=>(n.SUCCESS="SUCCESS",n.FAILED="FAILED",n.CANCELLED="CANCELLED",n))(ut||{}),Vs=C.object({beforeUrl:C.string(),beforeScreenshot:C.string().or(C.any()).optional(),afterUrl:C.string().optional(),afterScreenshot:C.string().or(C.any()).optional(),startedAt:C.coerce.date(),finishedAt:C.coerce.date(),viewport:C.object({height:C.number(),width:C.number()}),status:C.nativeEnum(ut),message:C.string().optional(),elementInteracted:C.string().optional()}),pt=C.object({startedAt:C.coerce.date(),finishedAt:C.coerce.date(),status:C.nativeEnum(Ie),message:C.string().optional(),data:C.unknown().optional(),userAgent:C.string().optional(),beforeTestContext:$t.optional(),afterTestContext:$t.optional()}),Ht=Je.merge(pt).merge(C.object({results:Vs.array()})),Kr=Xe.merge(pt).merge(C.object({results:Ht.array()})),Ws=zt.merge(pt).merge(C.object({results:C.union([Kr,Ht]).array()})),ht=C.discriminatedUnion("type",[Kr,Ht,Ws]),ce=pt.pick({startedAt:!0,finishedAt:!0,status:!0,message:!0,data:!0});function qr(r,e){return r.length<e?r:r.slice(0,e-3)+"[...]"}function Ge(r){switch(r.type){case"SUCCESS":return r.condition?.assertion?`Check success condition: ${r.condition.assertion}`:"All commands completed";case"AI_EXTRACT":return`Extract data from page: ${r.goal}`;case"NAVIGATE":return`Go to URL: ${qr(r.url,30)}`;case"CAPTCHA":return"Solve captchas on the page";case"GO_BACK":return"Go back to the previous page";case"GO_FORWARD":return"Go forward to the next page";case"SCROLL_DOWN":return`Scroll down ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"SCROLL_UP":return`Scroll up ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"SCROLL_LEFT":return`Scroll left ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"SCROLL_RIGHT":return`Scroll right ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"WAIT":return`Wait for ${r.delay} seconds`;case"REFRESH":return"Refresh the page";case"CLICK":return`Click on '${r.target.elementDescriptor}'`;case"DRAG":return`Drag '${r.fromTarget.elementDescriptor}' onto '${r.toTarget.elementDescriptor}'`;case"TYPE":{let t="";return r.target?.elementDescriptor.length?t=` in element: ${r.target.elementDescriptor}`:r.target?.a11yData?.nodeOnlySerializedForm&&(t=` in element: ${r.target.a11yData.nodeOnlySerializedForm}`),`Type '${r.value}'${t||""}`}case"HOVER":{let t="";return r.target.a11yData?.serializedForm?t=` over element: ${r.target.a11yData.serializedForm}`:r.target.elementDescriptor.length>0&&(t=` over element: ${r.target.elementDescriptor}`),`Hover${t}`}case"PRESS":return`Press ${r.value}`;case"SELECT_OPTION":return`Select option '${r.option}' in '${r.target.elementDescriptor}'`;case"TAB":return`Switch to tab: ${r.url}`;case"REQUEST":return`Send ${r.method} request to ${r.url}`;case"COOKIE":return`Set cookie: ${r.value}`;case"LOCAL_STORAGE":return`Set local storage: ${r.key}: ${r.value}`;case"JAVASCRIPT":return`Run JavaScript: ${qr(r.code,30)}`;case"AI_ASSERTION":return`${r.useVision?"Visual assertion":"Assertion"}: '${r.assertion}'`;case"AI_WAIT":return`Wait until ${r.useVision?"visual assertion":"assertion"} is true: '${r.assertion}'`;case"VISUAL_DIFF":return`Visual diff with baseline${r.target?` for element: ${r.target.elementDescriptor}`:""}`;default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}import{parseString as Ks}from"set-cookie-parser";function Yr(r){let e=Ks(r);if(!e.name)throw new Error("Name missing from cookie");if(!e.value)throw new Error("Value missing from cookie");let t;if(e.sameSite){let o=e.sameSite.trim().toLowerCase();if(o==="strict")t="Strict";else if(o==="lax")t="Lax";else if(o==="none")t="None";else throw new Error(`Invalid sameSite setting in cookie: ${o}`)}return!e.path&&e.domain&&(e.path="/"),{...e,expires:e.expires?e.expires.getTime()/1e3:void 0,sameSite:t}}import{z as Y}from"zod";var qs="1.0.0",Xr=Y.object({run:Y.string().describe("Run a single command in the shell. The working directory will be set to where the CLI was invoked from."),waitForCompletion:Y.boolean().optional().describe("Defaults to true")}),Jr=Y.object({type:Y.literal("momentic/fixture"),schemaVersion:Y.string(),name:Y.string(),description:Y.string().optional(),setup:Y.object({steps:Xr.array(),timeout:Y.number().optional().describe("Timeout for all steps in seconds")}).optional(),teardown:Y.object({steps:Xr.array(),timeout:Y.number().optional().describe("Timeout for all steps in seconds")}).optional()}),Hc={type:"momentic/fixture",schemaVersion:qs,name:"example",description:"An example fixture",setup:{steps:[{run:"./scripts/seed_db.sh",waitForCompletion:!0},{run:"npm run start",waitForCompletion:!1}],timeout:30},teardown:{steps:[{run:"./scripts/shutdown_db.sh"}]}};import{z as Ys}from"zod";var Gc=Ys.string().array();import{z as O}from"zod";import{z as N}from"zod";var fe="momentic",ne="modules",jt="fixtures",Ze="environments",Gt="chromium",ft=[ne,jt,Ze,Gt],Vt="momentic-frame",gt=`${Vt}-0`;import{isValidCron as Xs}from"cron-validator";import{z as X}from"zod";var ge=X.object({availableAsModule:X.boolean().default(!1),disableAICaching:X.boolean().default(!1)}),Qr=X.object({cron:X.string().refine(r=>Xs(r),{message:"Invalid cron expression."}).default("0 0 */1 * *"),enabled:X.boolean().default(!1),env:X.string().optional(),timeZone:X.string().default("America/Los_Angeles"),jobKey:X.string().optional()}),Zr=X.object({onSuccess:X.boolean().default(!1),onFailure:X.boolean().default(!0)});var Js=N.string().min(1).max(255).superRefine((r,e)=>{try{et(r)}catch(t){return e.addIssue({code:N.ZodIssueCode.custom,message:t.message,fatal:!0}),N.NEVER}}),Qs=N.object({name:N.string(),defaultOnCloud:N.boolean().optional(),defaultOnLocal:N.boolean().optional(),fixtures:Vr.array().optional()}),de=N.object({id:N.string(),name:Js,baseUrl:N.string().optional(),schemaVersion:N.string(),advanced:ge,retries:N.number(),envs:N.array(Qs).optional()}),td=de.pick({name:!0,baseUrl:!0,retries:!0,advanced:!0}),Zs=N.object({createdAt:N.coerce.date(),updatedAt:N.coerce.date(),schedule:Qr,notification:Zr,createdBy:N.string(),organizationId:N.string()}),eo=de.merge(Zs).merge(N.object({steps:N.array(Ce)})),yt=de.merge(N.object({steps:N.array(Ce)})),rd=de.merge(N.object({steps:Te.array()})),ei=/^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/;function et(r){if(r=r.toLowerCase().trim(),r.length===0||r.length>255)throw new Error("Name must be between 1 and 255 characters long");if(/[<>:"\/\\|?*\x00]/.test(r))throw new Error("Name can only contain alphanumeric characters, dashes, and underscores.");if(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i.test(r))throw new Error(`"${r}" is a reserved name on Windows and cannot be used as a filename.`);if(/^\.+$/.test(r)||/^\s|\s$/.test(r))throw new Error("Name cannot start or end with a space or dot.");if(r.endsWith(".yaml"))throw new Error('Name cannot end with ".yaml".');if(ft.includes(r))throw new Error("'modules' is a reserved folder name in Momentic. Please choose a different name.");if(r.match(ei))throw new Error("Name cannot be a UUID. Please choose a different name.")}var ld=O.array(O.object({id:O.string(),name:O.string(),fullFilePath:O.string(),testPath:O.string().describe("path relative to the root test directory, i.e. my-folder/my-test.yaml"),fileName:O.string(),lastModified:O.coerce.date(),createdAt:O.coerce.date()}));var to=O.object({steps:Ce.array()}),ro=O.object({name:O.string(),baseUrl:O.string().url().optional(),environment:O.string().optional()}),cd=yt.merge(O.object({testPath:O.string()})),oo=O.object({name:O.string(),steps:Ee.array()});var dd=O.array(Qe),md=O.array(O.object({name:O.string(),moduleId:O.string().uuid(),numSteps:O.number()})),ud=O.array(ee);import*as me from"zod";var no=me.object({thoughts:me.string(),id:me.number().int(),options:me.array(me.string()).optional()});var ti={0:"DEBUG",1:"INFO",2:"WARN",3:"ERROR"},ri={0:"\x1B[90m",1:"\x1B[32m",2:"\x1B[33m",3:"\x1B[31m"},Wt=class r{minLogLevel;logBindings;constructor(e,t){this.minLogLevel=e,this.logBindings=t}logWithLevel(e,...t){let n=ti[e],o;Array.isArray(t[0])?(o=t[0],t=t.slice(1)):typeof t[0]=="object"&&!(t[0]instanceof Error)&&(o={...t[0],...this.logBindings},t=t.slice(1));let s=ri[e],i=[`${s}[${new Date().toTimeString().slice(0,8)}][${n}]`];if(e!==0&&i.push("\x1B[39m"),i.push(...t),console.log(...i),o&&!Array.isArray(o))for(let[a,l]of Object.entries(o)){let c=l;l instanceof Error?c=l.message:typeof l=="object"&&(c=JSON.stringify(l,void 0,2),c=c.split(`
|
|
11
|
+
</combobox>, output SELECT_OPTION 24 'Option 2'`),zt=L.merge(u.object({type:u.literal("AI_ASSERTION"),assertion:u.string(),useVision:u.boolean().default(!1),disableCache:u.boolean().default(!1),cancelOnFailure:u.boolean().default(!1)})),Ds=zt.merge(u.object({type:u.literal("AI_WAIT"),timeout:u.number().int().optional().describe("Max seconds to wait for assertion to be true")})),_s=L.merge(u.object({type:u.literal("AI_EXTRACT"),goal:u.string(),schema:u.string().optional(),disableCache:u.boolean().default(!1)})),ks=u.object({clearContent:u.boolean().default(!0),pressKeysSequentially:u.boolean().default(!1)}),Fs=L.merge(u.object({type:u.literal("TYPE"),target:Z.optional(),value:u.string(),pressEnter:u.boolean().default(!1),useVision:u.boolean().default(!1),force:u.boolean().default(!1)})).merge(ks).describe('TYPE <id> "<text>" - type the specified text into the input with the specified id. The text should be specified by the user - do not use text from the EXAMPLES or generate text yourself. Make sure to include quotes around the text.'),zs=L.merge(u.object({type:u.literal("PRESS"),value:u.string()})).describe('PRESS <key> - press the specified key, such as "ArrowLeft", "Enter", or "a". You must specify at least one key. Do not provide key codes; only use key names supported by the Playwright press method.'),Us=L.merge(u.object({type:u.literal("TAB"),url:u.string()})),$s=L.merge(u.object({type:u.literal("COOKIE"),value:u.string()})),Hs=L.merge(u.object({type:u.literal("LOCAL_STORAGE"),key:u.string(),value:u.string()})),Bs=L.merge(u.object({type:u.literal("REQUEST"),url:u.string(),method:u.union([u.literal("GET"),u.literal("POST"),u.literal("PUT"),u.literal("DELETE"),u.literal("PATCH")]),headers:u.record(u.string(),u.string()).optional(),params:u.record(u.string(),u.string()).optional(),body:u.string().optional(),timeout:u.number().int().optional().describe("Max seconds to wait for the request to complete")})),Vs=L.merge(u.object({type:u.literal("SUCCESS"),condition:zt.optional()})).describe("SUCCESS - the user goal has been successfully achieved"),js=u.object({data:u.string().describe("s3 url to a jpg"),width:u.number(),height:u.number()}),Gs=L.merge(u.object({type:u.literal("VISUAL_DIFF"),threshold:u.number().default(.1),target:Z.optional(),screenshot:js.optional(),useVision:u.boolean().default(!1)})),je=u.discriminatedUnion("type",[Os,Fs,zs,Ps,ws,vs,bs,Vs]),Ws=u.discriminatedUnion("type",[zt,Ds,Is,$s,_s,Ms,Rs,xs,Ns,Ls,Hs,Cs,Bs,As,Es,Us,Gs,Ts]),Wr=u.discriminatedUnion("type",[...je.options,...Ws.options]),Ks=L.merge(u.object({type:u.literal("FAILURE")})).describe("FAILURE - there are no commands to suggest that could make progress that have not already been tried before"),Ut=u.discriminatedUnion("type",[...je.options,Ks]),ut=r=>{switch(r){case"AI_EXTRACT":return{type:r,goal:"",disableCache:!1};case"NAVIGATE":return{type:"NAVIGATE",url:""};case"CAPTCHA":return{type:r,useVision:!1};case"DRAG":return{type:r,fromTarget:{elementDescriptor:""},toTarget:{elementDescriptor:""},useVision:!1,force:!1};case"GO_BACK":case"GO_FORWARD":case"REFRESH":return{type:r};case"SCROLL_DOWN":case"SCROLL_UP":case"SCROLL_LEFT":case"SCROLL_RIGHT":return{type:r,useVision:!1};case"WAIT":return{type:r,delay:1};case"CLICK":return{type:r,target:{elementDescriptor:""},doubleClick:!1,rightClick:!1,useVision:!1,force:!1};case"HOVER":return{type:r,target:{elementDescriptor:""},useVision:!1,force:!1};case"TYPE":return{type:r,target:void 0,value:"",clearContent:!0,pressEnter:!1,pressKeysSequentially:!1,useVision:!1,force:!1};case"PRESS":return{type:r,value:""};case"SELECT_OPTION":return{type:r,target:{elementDescriptor:""},option:""};case"TAB":return{type:r,url:""};case"REQUEST":return{type:r,url:"",method:"GET"};case"COOKIE":return{type:r,value:""};case"LOCAL_STORAGE":return{type:r,key:"",value:""};case"JAVASCRIPT":return{type:r,code:"",fragment:!1};case"AI_WAIT":case"AI_ASSERTION":return{type:r,assertion:"",disableCache:!1,useVision:!1,cancelOnFailure:!1};case"SUCCESS":return{type:r};case"VISUAL_DIFF":return{type:r,threshold:.1,useVision:!1};default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}};var Te=(i=>(i.AI_PROVIDER="AIProviderError",i.AI_TIMEOUT="AITimeoutError",i.JOB_TIMEOUT="JobTimeoutError",i.ACTION_FAILURE="ActionFailureError",i.ASSERTION_FAILURE="AssertionFailureError",i.WEB_AGENT_PLATFORM="InternalWebAgentError",i.UNKNOWN_PLATFORM="InternalPlatformError",i))(Te||{});var pt=class extends Error{constructor(e={}){super("Got empty a11y tree",e),this.name="EmptyA11yTreeError"}};var T=class extends Error{reason;emitToUser;constructor(e,t,n={},o=!1){let s=!1;for(let a of Object.values(Te))if(t.startsWith(a)){s=!0,e=a;break}s?super(t,n):super(`${e}${t?`: ${t}`:""}`,n),this.name="TestFailureError",this.stack=this.stack?.slice(this.name.length+2),this.reason=e,this.emitToUser=o}toString(){return this.message}toJSON(){return{message:this.message}}};var fc=F.object({command:F.string(),thoughts:F.string()}),gc=F.string().pipe(F.coerce.number());var Kr=F.object({phrase:F.string()}),$t=F.object({result:F.union([F.literal("NOT_FOUND"),F.string(),F.number(),F.array(F.unknown()),F.record(F.unknown(),F.unknown())])});import{z as Ht}from"zod";var ht=Ht.object({width:Ht.number().min(200).max(1e4),height:Ht.number().min(200).max(1e4)}),qr={"Desktop Large":{width:1920,height:1080},"Desktop Small":{width:1280,height:800},iPad:{width:768,height:1024},"Pixel 8":{width:448,height:998},"iPhone 15":{width:393,height:852}},wc=Object.keys(qr);var de=qr["Desktop Large"];import qs from"lodash.unset";import*as D from"zod";var V="1.0.6",U=(n=>(n.AI_ACTION="AI_ACTION",n.PRESET_ACTION="PRESET_ACTION",n.MODULE="MODULE",n))(U||{}),Qe=D.object({type:D.literal("AI_ACTION"),text:D.string(),commands:D.array(je).optional()}),Ze=D.object({type:D.literal("PRESET_ACTION"),command:Wr}),Bt=D.object({type:D.literal("MODULE"),moduleId:D.string().uuid()}),Ce=D.union([Qe,Ze]),et=D.object({type:D.literal("RESOLVED_MODULE"),moduleId:D.string().uuid(),name:D.string(),steps:Ce.array()}),Re=D.union([Qe,Ze,Bt]),xe=D.union([Qe,Ze,et]);var Ys=["command.screenshot","command.target.a11yData","command.fromTarget.a11yData","command.toTarget.a11yData"];function j(r){let e=JSON.parse(JSON.stringify(r));return Ys.forEach(t=>{qs(e,t)}),e}var xc=new Set(Object.values(ne));var Vt={AI_ACTION:"AI action",MODULE:"Module",AI_ASSERTION:"AI check",AI_WAIT:"AI wait",AI_EXTRACT:"AI extract",CLICK:"Click",TYPE:"Type",JAVASCRIPT:"JavaScript",SELECT_OPTION:"Select",PRESS:"Press",NAVIGATE:"Navigate",SCROLL_UP:"Scroll up",SCROLL_DOWN:"Scroll down",SCROLL_LEFT:"Scroll left",SCROLL_RIGHT:"Scroll right",HOVER:"Hover",GO_BACK:"Go back",GO_FORWARD:"Go forward",WAIT:"Wait",REFRESH:"Refresh",TAB:"Switch tab",COOKIE:"Cookie",LOCAL_STORAGE:"Local storage",REQUEST:"Request",CAPTCHA:"CAPTCHA",DRAG:"Drag & drop",VISUAL_DIFF:"Visual diff",SUCCESS:"Done"},Ic={AI_ACTION:"Ask AI to plan and execute something on the page.",MODULE:"A list of steps that can be reused in multiple tests.",AI_ASSERTION:"Ask AI whether something is true on the page.",AI_WAIT:"Wait until AI considers a condition to be true.",CLICK:"Click on an element on the page based on a description.",AI_EXTRACT:"Ask AI to extract data from the page based on a description.",HOVER:"Hover over an element on the page based on a description.",SELECT_OPTION:"Select an option from a dropdown based on a description.",TYPE:"Type the specified text into an element.",PRESS:"Press the specified keys using the keyboard. (e.g. Ctrl+A)",NAVIGATE:"Navigate to the specified URL.",SCROLL_UP:"Scroll up by a specified height.",SCROLL_DOWN:"Scroll down by a specified height.",SCROLL_LEFT:"Scroll left by a specified width.",SCROLL_RIGHT:"Scroll right by a specified width.",GO_BACK:"Go back in browser history.",GO_FORWARD:"Go forward in browser history.",WAIT:"Wait for the specified number of seconds.",REFRESH:"Refresh the page. This will not clear cookies or session data.",TAB:"Switch to different tab in the browser.",COOKIE:"Set a cookie that will persist throughout the browser session",LOCAL_STORAGE:"Set a local storage value that will persist throughout the browser session",CAPTCHA:"Solve CAPTCHAs on the page. This may take 10-60 seconds.",REQUEST:"Make an API request to a URL.",JAVASCRIPT:"Run JavaScript code in an isolated context.",DRAG:"Click and drag an element to another location.",VISUAL_DIFF:"Compare a screenshot of the page or a specific element to a baseline image.",SUCCESS:"Indicate the entire AI action has succeeded, optionally based on a condition."};import*as C from"zod";import*as _ from"zod";import{z as Ge}from"zod";var Yr=(t=>(t.PROD="production",t.DEV="development",t))(Yr||{}),Mc=Object.values(Yr),Ie="BASE_URL",Nc={[Ie]:"https://www.google.com"},Xr=Ge.string().describe("Name of the fixture (must be available locally in the fixtures directory)."),ee=Ge.object({name:Ge.string(),variables:Ge.record(Ge.string().describe("variable name"),Ge.string().describe("variable value"))});import*as Le from"zod";var Jr=Le.object({type:Le.nativeEnum(U),generatedStep:je.optional(),serializedCommand:Le.string().optional(),elementInteracted:Le.string().optional()});var me=_.object({goal:_.string(),url:_.string(),browserState:_.string(),history:_.string(),numPrevious:_.number(),lastCommand:Jr.or(_.null()),returnSchema:_.string().optional()}),jt=_.object({env:_.record(_.unknown()),results:_.array(_.unknown()),steps:_.array(xe)}),Y=class{env={};steps;results;constructor(e,t){this.env[Ie]=e,this.steps=t.map(j),this.results=[]}setSteps(e){this.steps=e.map(j)}setResult(e,t){this.results[e]=t||null}clearResults(){this.results=[]}getVariable(e){return this.env[e]}setVariable(e,t){this.env[e]=t}toObjectRef(){return{steps:this.steps,results:this.results,env:this.env}}toObjectCopy(){return JSON.parse(JSON.stringify(this.toObjectRef()))}reset(e){this.env={},this.steps=[],this.results=[],e&&(this.env[Ie]=e)}};var Oe=(s=>(s.SUCCESS="SUCCESS",s.FAILED="FAILED",s.RUNNING="RUNNING",s.IDLE="IDLE",s.CANCELLED="CANCELLED",s))(Oe||{}),ft=(n=>(n.SUCCESS="SUCCESS",n.FAILED="FAILED",n.CANCELLED="CANCELLED",n))(ft||{}),Xs=C.object({beforeUrl:C.string(),beforeScreenshot:C.string().or(C.any()).optional(),afterUrl:C.string().optional(),afterScreenshot:C.string().or(C.any()).optional(),startedAt:C.coerce.date(),finishedAt:C.coerce.date(),viewport:C.object({height:C.number(),width:C.number()}),status:C.nativeEnum(ft),message:C.string().optional(),elementInteracted:C.string().optional()}),gt=C.object({startedAt:C.coerce.date(),finishedAt:C.coerce.date(),status:C.nativeEnum(Oe),message:C.string().optional(),data:C.unknown().optional(),userAgent:C.string().optional(),beforeTestContext:jt.optional(),afterTestContext:jt.optional()}),Gt=Ze.merge(gt).merge(C.object({results:Xs.array()})),Qr=Qe.merge(gt).merge(C.object({results:Gt.array()})),Js=Bt.merge(gt).merge(C.object({results:C.union([Qr,Gt]).array()})),yt=C.discriminatedUnion("type",[Qr,Gt,Js]),ue=gt.pick({startedAt:!0,finishedAt:!0,status:!0,message:!0,data:!0});function Zr(r,e){return r.length<e?r:r.slice(0,e-3)+"[...]"}function We(r){switch(r.type){case"SUCCESS":return r.condition?.assertion?`Check success condition: ${r.condition.assertion}`:"All commands completed";case"AI_EXTRACT":return`Extract data from page: ${r.goal}`;case"NAVIGATE":return`Go to URL: ${Zr(r.url,30)}`;case"CAPTCHA":return"Solve captchas on the page";case"GO_BACK":return"Go back to the previous page";case"GO_FORWARD":return"Go forward to the next page";case"SCROLL_DOWN":return`Scroll down ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"SCROLL_UP":return`Scroll up ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"SCROLL_LEFT":return`Scroll left ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"SCROLL_RIGHT":return`Scroll right ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${r.target.elementDescriptor}`:""}`;case"WAIT":return`Wait for ${r.delay} seconds`;case"REFRESH":return"Refresh the page";case"CLICK":return`Click on '${r.target.elementDescriptor}'`;case"DRAG":return`Drag '${r.fromTarget.elementDescriptor}' onto '${r.toTarget.elementDescriptor}'`;case"TYPE":{let t="";return r.target?.elementDescriptor.length?t=` in element: ${r.target.elementDescriptor}`:r.target?.a11yData?.nodeOnlySerializedForm&&(t=` in element: ${r.target.a11yData.nodeOnlySerializedForm}`),`Type '${r.value}'${t||""}`}case"HOVER":{let t="";return r.target.a11yData?.serializedForm?t=` over element: ${r.target.a11yData.serializedForm}`:r.target.elementDescriptor.length>0&&(t=` over element: ${r.target.elementDescriptor}`),`Hover${t}`}case"PRESS":return`Press ${r.value}`;case"SELECT_OPTION":return`Select option '${r.option}' in '${r.target.elementDescriptor}'`;case"TAB":return`Switch to tab: ${r.url}`;case"REQUEST":return`Send ${r.method} request to ${r.url}`;case"COOKIE":return`Set cookie: ${r.value}`;case"LOCAL_STORAGE":return`Set local storage: ${r.key}: ${r.value}`;case"JAVASCRIPT":return`Run JavaScript: ${Zr(r.code,30)}`;case"AI_ASSERTION":return`${r.useVision?"Visual assertion":"Assertion"}: '${r.assertion}'`;case"AI_WAIT":return`Wait until ${r.useVision?"visual assertion":"assertion"} is true: '${r.assertion}'`;case"VISUAL_DIFF":return`Visual diff with baseline${r.target?` for element: ${r.target.elementDescriptor}`:""}`;default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}import{parseString as Qs,splitCookiesString as Zs}from"set-cookie-parser";import{z as G}from"zod";var ei=G.object({name:G.string(),value:G.string(),url:G.string().optional(),domain:G.string().optional(),path:G.string().optional(),expires:G.number().optional(),httpOnly:G.boolean().optional(),secure:G.boolean().optional(),sameSite:G.union([G.literal("Strict"),G.literal("Lax"),G.literal("None")])});function eo(r){let e=[],t=Zs(r);for(let n of t){let o=Qs(n);if(!o.name)throw new Error("Name missing from cookie");if(!o.value)throw new Error("Value missing from cookie");let s;if(o.sameSite){let c=o.sameSite.trim().toLowerCase();if(c==="strict")s="Strict";else if(c==="lax")s="Lax";else if(c==="none")s="None";else throw new Error(`Invalid sameSite setting in cookie: ${c}`)}!o.path&&o.domain&&(o.path="/");let a=ei.parse({...o,expires:o.expires?o.expires.getTime()/1e3:void 0,sameSite:s});e.push(a);let i=[a.name,...Object.keys(a)].map(c=>c.toLowerCase()),l=n.match(/\b(\w+)=([^;]*)/g);if(l)for(let c of l){let[d,m]=c.split("=");if(console.log(d,m),!d||!m)throw new Error(`Invalid key-value pair in cookie: ${c}`);i.includes(d.toLowerCase())||e.push({...a,name:d,value:m})}}return e}import{z as X}from"zod";var ti="1.0.0",to=X.object({run:X.string().describe("Run a single command in the shell. The working directory will be set to where the CLI was invoked from."),waitForCompletion:X.boolean().optional().describe("Defaults to true")}),ro=X.object({type:X.literal("momentic/fixture"),schemaVersion:X.string(),name:X.string(),description:X.string().optional(),setup:X.object({steps:to.array(),timeout:X.number().optional().describe("Timeout for all steps in seconds")}).optional(),teardown:X.object({steps:to.array(),timeout:X.number().optional().describe("Timeout for all steps in seconds")}).optional()}),Qc={type:"momentic/fixture",schemaVersion:ti,name:"example",description:"An example fixture",setup:{steps:[{run:"./scripts/seed_db.sh",waitForCompletion:!0},{run:"npm run start",waitForCompletion:!1}],timeout:30},teardown:{steps:[{run:"./scripts/shutdown_db.sh"}]}};import{z as ri}from"zod";var td=ri.string().array();import{z as O}from"zod";import{z as M}from"zod";var Se="momentic",se="modules",Kt="fixtures",tt="environments",qt="chromium",St=[se,Kt,tt,qt],Yt="momentic-frame",wt=`${Yt}-0`;import{isValidCron as oi}from"cron-validator";import{z as te}from"zod";var ie=te.object({disableAICaching:te.boolean().default(!1),viewport:ht.optional()}),oo=te.object({cron:te.string().refine(r=>oi(r),{message:"Invalid cron expression."}).default("0 0 */1 * *"),enabled:te.boolean().default(!1),env:te.string().optional(),timeZone:te.string().default("America/Los_Angeles"),jobKey:te.string().optional()}),no=te.object({onSuccess:te.boolean().default(!1),onFailure:te.boolean().default(!0)});var ni=M.string().min(1).max(255).superRefine((r,e)=>{try{rt(r)}catch(t){return e.addIssue({code:M.ZodIssueCode.custom,message:t.message,fatal:!0}),M.NEVER}}),si=M.object({name:M.string(),defaultOnCloud:M.boolean().optional(),defaultOnLocal:M.boolean().optional(),fixtures:Xr.array().optional()}),pe=M.object({id:M.string(),name:ni,baseUrl:M.string().optional(),schemaVersion:M.string(),advanced:ie,retries:M.number(),envs:M.array(si).optional()}),pd=pe.pick({name:!0,baseUrl:!0,retries:!0,advanced:!0}),ii=M.object({createdAt:M.coerce.date(),updatedAt:M.coerce.date(),schedule:oo,notification:no,createdBy:M.string(),organizationId:M.string()}),so=pe.merge(ii).merge(M.object({steps:M.array(xe)})),bt=pe.merge(M.object({steps:M.array(xe)})),hd=pe.merge(M.object({steps:Re.array()})),ai=/^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/;function rt(r){if(r=r.toLowerCase().trim(),r.length===0||r.length>255)throw new Error("Name must be between 1 and 255 characters long");if(/[<>:"\/\\|?*\x00]/.test(r))throw new Error("Name can only contain alphanumeric characters, dashes, and underscores.");if(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i.test(r))throw new Error(`"${r}" is a reserved name on Windows and cannot be used as a filename.`);if(/^\.+$/.test(r)||/^\s|\s$/.test(r))throw new Error("Name cannot start or end with a space or dot.");if(r.endsWith(".yaml"))throw new Error('Name cannot end with ".yaml".');if(St.includes(r))throw new Error("'modules' is a reserved folder name in Momentic. Please choose a different name.");if(r.match(ai))throw new Error("Name cannot be a UUID. Please choose a different name.")}var vd=O.array(O.object({id:O.string(),name:O.string(),fullFilePath:O.string(),testPath:O.string().describe("path relative to the root test directory, i.e. my-folder/my-test.yaml"),fileName:O.string(),lastModified:O.coerce.date(),createdAt:O.coerce.date()}));var io=O.object({steps:xe.array()}),ao=O.object({name:O.string(),baseUrl:O.string().url().optional(),environment:O.string().optional(),viewport:ht.optional()}),Ad=bt.merge(O.object({testPath:O.string()})),lo=O.object({name:O.string(),steps:Ce.array()});var Ed=O.array(et),Td=O.array(O.object({name:O.string(),moduleId:O.string().uuid(),numSteps:O.number()})),Cd=O.array(ee);import*as he from"zod";var co=he.object({thoughts:he.string(),id:he.number().int(),options:he.array(he.string()).optional()});var li={0:"DEBUG",1:"INFO",2:"WARN",3:"ERROR"},ci={0:"\x1B[90m",1:"\x1B[32m",2:"\x1B[33m",3:"\x1B[31m"},Xt=class r{minLogLevel;logBindings;constructor(e,t){this.minLogLevel=e,this.logBindings=t}logWithLevel(e,...t){let n=li[e],o;Array.isArray(t[0])?(o=t[0],t=t.slice(1)):typeof t[0]=="object"&&!(t[0]instanceof Error)&&(o={...t[0],...this.logBindings},t=t.slice(1));let s=ci[e],a=[`${s}[${new Date().toTimeString().slice(0,8)}][${n}]`];if(e!==0&&a.push("\x1B[39m"),a.push(...t),console.log(...a),o&&!Array.isArray(o))for(let[i,l]of Object.entries(o)){let c=l;l instanceof Error?c=l.message:typeof l=="object"&&(c=JSON.stringify(l,void 0,2),c=c.split(`
|
|
12
12
|
`).map((d,m)=>m>0?` ${d}`:d).join(`
|
|
13
|
-
`)),console.log(e===0?`${s} ${
|
|
13
|
+
`)),console.log(e===0?`${s} ${i}:`:` ${i}:`,c)}else if(o)for(let i of o){let l=i;typeof i=="object"&&(l=JSON.stringify(i,void 0,2),l=l.split(`
|
|
14
14
|
`).map((c,d)=>d>0?` ${c}`:c).join(`
|
|
15
|
-
`)),console.log(e===0?`${s} `:" ",l)}e===0&&process.stdout.write("\x1B[39m")}setMinLevel(e){this.minLogLevel=e}log(...e){this.info(...e)}info(...e){1<this.minLogLevel||this.logWithLevel(1,...e)}debug(...e){0<this.minLogLevel||this.logWithLevel(0,...e)}warn(...e){2<this.minLogLevel||this.logWithLevel(2,...e)}error(...e){3<this.minLogLevel||this.logWithLevel(3,...e)}child(e){return new r(this.minLogLevel,{...this.logBindings,...e})}flush(){}bindings(){return this.logBindings}},V=new Wt(1,{});import{z as ue}from"zod";var oi=ue.object({id:ue.string(),createdAt:ue.coerce.date(),createdBy:ue.string(),organizationId:ue.string(),name:ue.string(),schemaVersion:ue.string(),numSteps:ue.number()}),Sd=ue.object({steps:Ee.array()}).merge(oi.omit({numSteps:!0}));var Le=r=>{let e=r.trim().toLowerCase().replace(/[^a-z0-9]/g,"-");for(;e.includes("--");)e=e.replaceAll("--","-");return e.startsWith("-")&&(e=e.slice(1)),e.endsWith("-")&&(e=e.slice(0,e.length-1)),e};import*as b from"zod";import{z as x}from"zod";var Kt={WEBHOOK:"WEBHOOK",CRON:"CRON",MANUAL:"MANUAL",CLI:"CLI"},qt={PENDING:"PENDING",RUNNING:"RUNNING",PASSED:"PASSED",FAILED:"FAILED",CANCELLED:"CANCELLED"},ni={PASSED:"PASSED",FAILED:"FAILED"},St=x.string().pipe(x.coerce.date()).or(x.date()),si=x.object({id:x.string(),createdAt:St,createdBy:x.string(),organizationId:x.string(),scheduledAt:St.or(x.null()),startedAt:St.or(x.null()),finishedAt:St.or(x.null()),testId:x.string().or(x.null()),status:x.nativeEnum(qt),expectedStatus:x.nativeEnum(ni).or(x.null()),runKey:x.string(),trigger:x.nativeEnum(Kt),attempts:x.number(),test:x.object({name:x.string(),id:x.string()}).or(x.null())}),Yt=si.merge(x.object({results:ht.array(),test:x.object({name:x.string(),id:x.string(),baseUrl:x.string()}).or(x.null())}));var ye=b.object({disableCache:b.boolean()}),Dd=b.object({error:b.boolean(),reason:b.string(),message:b.string()}),_d=le.merge(ye),so=kt,kd=b.discriminatedUnion("vision",[le.merge(ye).merge(b.object({vision:b.literal(!1)})),le.pick({goal:!0,url:!0}).merge(ye).merge(b.object({screenshot:b.string(),vision:b.literal(!0)}))]),Xt=Hr,Fd=le.pick({browserState:!0,goal:!0}).merge(ye),zd=le.pick({goal:!0}).merge(ye).merge(b.object({screenshot:b.string().describe("base64 encoded image"),hintActivatedScreenshot:b.string().describe("base64 encoded image")})),Jt=no,Ud=le.pick({goal:!0,url:!0}).merge(ye),io=b.string().array(),$d=le.pick({goal:!0,browserState:!0}).merge(ye),ao=jr,Hd=le.pick({goal:!0,browserState:!0,returnSchema:!0}).merge(ye);var Bd=b.object({testPaths:b.string().array().describe("can be either hyphenated, lowercase test names or UUIDs"),env:b.string().optional(),all:b.boolean().optional()}),lo=b.object({message:b.string(),queuedTests:b.object({name:b.string(),id:b.string()}).array()}),co=eo,mo=b.string().array(),jd=b.union([b.object({paths:b.string().array().describe("run specific test paths (e.g. todo-test)"),all:b.boolean().describe("run all tests").optional()}),b.object({path:b.string().describe("deprecated; present for backcompat")})]),uo=b.object({tests:b.record(b.string().describe("Test name"),b.string().describe("Test YAML")),modules:b.record(b.string().describe("Module name"),b.string().describe("Module YAML"))}),ii=b.object({test:b.string().describe("test YAML"),modules:b.record(b.string().describe("moduleId"),b.string().describe("module YAML"))}),Gd=ii.array();var Vd=b.object({testPath:b.string(),testId:b.string()}).partial().merge(b.object({trigger:b.nativeEnum(Kt)})),po=Yt,ho=Yt,Wd=b.object({startedAt:b.coerce.date(),finishedAt:b.coerce.date(),results:ht.array(),status:b.nativeEnum(qt)}).partial(),Kd=b.object({screenshot:b.string()}),fo=b.object({key:b.string()}),go=b.object({orgId:b.string()}),yo=b.array(ee),qd=b.array(ee);function wt(r){switch(r.type){case"AI_ACTION":return`AI action: ${r.text}`;case"PRESET_ACTION":return Ge(r.command);case"RESOLVED_MODULE":return`Module: ${r.moduleId}`}}import{stringify as Qt}from"yaml";import{z as P}from"zod";var lm=P.object({test:P.string().describe("YAML for the test, including metadata and steps"),modules:P.record(P.string(),P.string()).describe("Map of module name to YAML for the module")}),cm=de.merge(P.object({steps:Te.array(),fileType:P.literal("momentic/test")})),Zt=Qe.omit({type:!0}).merge(P.object({schemaVersion:P.string(),fileType:P.literal("momentic/module")})),dm=de.merge(P.object({steps:P.array(P.record(P.string(),P.unknown()))})),mm=P.object({moduleId:P.string().uuid(),name:P.string(),schemaVersion:P.string(),steps:P.array(P.record(P.string(),P.unknown()))});function So(r,e=new Set){let t={id:r.id,name:r.name,baseUrl:r.baseUrl,schemaVersion:r.schemaVersion,advanced:r.advanced,retries:r.retries,envs:r.envs},n={},o=wo(r.steps,r.schemaVersion,n,e),s={fileType:"momentic/test",...t,steps:o};return{test:Qt(s),modules:n}}function wo(r,e,t,n){let o=[];for(let s of r)switch(s.type){case"PRESET_ACTION":o.push(s);break;case"AI_ACTION":let i=(s.commands??[]).map(l=>({...l,thoughts:void 0}));o.push({...s,commands:i});break;case"RESOLVED_MODULE":n.has(s.name)||(t[s.name]=ai(s,e),n.add(s.name)),o.push({type:"MODULE",moduleId:s.moduleId});break;default:return(l=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(s)}return o}function ai(r,e){let t={fileType:"momentic/module",moduleId:r.moduleId,name:r.name,steps:wo(r.steps,e,{},new Set),schemaVersion:e};return Qt(t)}function er(r){return Qt({fileType:"momentic/environment",...r})}import{validator as fm}from"@exodus/schemasafe";var bo={name:"Migrate to ai step v2",fromVersion:"1.0.4",toVersion:"1.0.5",recursiveKeys:new Set(["results","commands"]),stopOnFailure:!0,execute:async r=>(r=r.filter(e=>!(e.status!==void 0&&e.type==="AI_ACTION")),r=r.map(e=>(e.status===void 0||e.type==="PRESET_ACTION"&&(e.results=e.commands??e.results??[]),e)),r)};var vo={name:"Make sure ai step v2 has done command",fromVersion:"1.0.5",toVersion:"1.0.6",recursiveKeys:new Set(["results","commands"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="AI_ACTION"||e.status!==void 0||!e.commands||!e.commands.length)return e;let t=e.commands,n=t[t.length-1];return n&&n.type!=="SUCCESS"&&t.push({type:"SUCCESS"}),e})};var Ao={name:"Migrate AI assertions to preset actions",fromVersion:"1.0.0",toVersion:"1.0.1",recursiveKeys:new Set,execute:async r=>r.map(e=>{if(e.type!=="AI_ASSERTION")return e;let n={type:"PRESET_ACTION",command:{type:"AI_ASSERTION",assertion:e.text,useVision:!1,disableCache:!0}},o={...e,...n};return delete o.text,o}),stopOnFailure:!0};var bt=new Set(["CLICK","TYPE","SELECT_OPTION"]),Eo={name:"Migrate element descriptor to live in a target object",fromVersion:"1.0.3",toVersion:"1.0.4",recursiveKeys:new Set,execute:async r=>r.map(e=>{let t=e.command,n=t?.type,o=t?.elementDescriptor;return(o!==void 0||bt.has(n))&&(t.target={elementDescriptor:o??""}),e.commands&&Array.isArray(e.commands)&&e.commands.forEach(i=>{let a=i?.elementDescriptor,l=i?.type;(a!==void 0||bt.has(l))&&(i.target={elementDescriptor:a??""})}),e.results&&Array.isArray(e.results)&&e.results.forEach(i=>{let a=i.command,l=a?.elementDescriptor,c=a?.type;(l!==void 0||bt.has(c))&&(a.target={elementDescriptor:l??""}),i.commands&&Array.isArray(i.commands)&&i.commands.forEach(m=>{let p=m?.elementDescriptor,h=m?.type;(p!==void 0||bt.has(h))&&(m.target={elementDescriptor:p??""})})}),e}),stopOnFailure:!0};var To={name:"Migrate FAILURE status to FAILED",fromVersion:"1.0.1",toVersion:"1.0.2",recursiveKeys:new Set,execute:async r=>r.map(e=>{let t=e;return t.status==="FAILURE"&&(t.status="FAILED"),typeof t.commands=="object"&&Array.isArray(t.commands)&&t.commands.forEach(n=>{if(n&&typeof n=="object"){let o=n;o?.status==="FAILURE"&&(o.status="FAILED")}}),t}),stopOnFailure:!0};var Co={name:"Migrate preset step types to use the same",fromVersion:"1.0.2",toVersion:"1.0.3",recursiveKeys:new Set,execute:async r=>r.map(e=>{let t=e.command,n=t?.type;return n?.startsWith("PRESET_")&&(t.type=n.slice(7)),e.commands&&Array.isArray(e.commands)&&e.commands.forEach(s=>{let i=s.type;i?.startsWith("PRESET_")&&(s.type=i.slice(7))}),e.results&&Array.isArray(e.results)&&e.results.forEach(s=>{let i=s.command,a=i?.type;a?.startsWith("PRESET_")&&(i.type=a.slice(7)),s.commands&&Array.isArray(s.commands)&&s.commands.forEach(c=>{let d=c.type;d?.startsWith("PRESET_")&&(c.type=d.slice(7))})}),e}),stopOnFailure:!0};var Oe=[Ao,To,Co,Eo,bo,vo];if(G!==Oe[Oe.length-1].toVersion)throw new Error("Please bump LATEST_VERSION in types package after adding a migration");Oe.forEach((r,e)=>{if(!vt.valid(r.toVersion)||!vt.valid(r.fromVersion))throw new Error(`Migration '${r.name}' has invalid version`);if(!vt.gt(r.toVersion,r.fromVersion))throw new Error(`Migration '${r.name}' has toVersion <= fromVersion`);if(e===0)return;if(Oe[e-1].toVersion!==r.fromVersion)throw new Error(`Migration '${r.name}' at index ${e} is not contiguous with previous migration`)});function ci(r){return r.every(e=>e&&typeof e=="object"&&!Array.isArray(e))}var tr=async({metadata:r,steps:e,logger:t})=>{let n=e,{schemaVersion:o,id:s}=r,i=Oe.findIndex(c=>vt.gt(c.toVersion,o));if(i===-1)return t.debug({id:s},"Step migrations up to date"),{steps:n,newVersion:o};let a=o;for(let c=i;c<Oe.length;c++){let d=Oe[c],m={id:s,migration:d.name,toVersion:d.toVersion};t.debug(m,"Starting migration");try{n=await Ro(n,d),a=d.toVersion}catch(p){throw t.error({err:p,...m},"Migration failed"),new Error(`Step migration ${d.name} failed: ${p}`)}}let l=li(JSON.stringify(e,void 0,2),JSON.stringify(n,void 0,2),{n_surrounding:1});return t.debug({diffs:l,id:s},"Migration diffs"),{newVersion:a,steps:n}};async function Ro(r,e){let t=await e.execute(r);for(let n of t)for(let o of Object.keys(n)){if(!e.recursiveKeys.has(o))continue;let s=n[o];!s||!Array.isArray(s)||ci(s)&&(n[o]=await Ro(s,e))}return t}import{parse as or}from"yaml";var Io=ft,mi=new Set([...Io,"node_modules","dist","bin",".git","logs",".npm",".next","out",".yarn","__pycache__","build",".env",".venv","venv","env","wheels"]);function tt(r,e,t=r){let n=r.split(Ve.sep).pop()??"";if(mi.has(n))return Io.includes(n)||e.warn(`Skipping directory '${r}' because it is likely an artifact folder.`),[];let o=rr.readdirSync(r),s=[];return o.forEach(i=>{let a=Ve.join(r,i),l;try{l=rr.statSync(a)}catch(c){e.warn({err:c},`Skipping path '${a}' because it could not be read.`);return}if(l.isDirectory())s=s.concat(tt(a,e,r));else if(i.endsWith(".yaml")){let c=rr.readFileSync(a,"utf-8");try{let d=or(c),m=de.parse(d);s.push({id:m.id,name:m.name,fullFilePath:a,testPath:Ve.relative(Ve.resolve(t),Ve.resolve(a)),fileName:i,lastModified:l.mtime,createdAt:l.ctime})}catch{e.warn(`Skipping file '${a}' because it does not parse as a valid Momentic test.`)}}}),s}function nr(r,e){let t;try{t=xo(r,"utf8"),t=t.replace(/\r\n|\r/g,`
|
|
16
|
-
`)}catch(a){throw new Error(`Could not read test file ${r}: ${a}`)}let n=new Set,o=/moduleId: (.*)/g,s;for(;(s=o.exec(t))!==null;)n.add(s[1].trim());let i={};return n.size>0&&n.forEach(a=>{i[a]||(i[a]=At(e,a).content)}),{test:t,modules:i}}function At(r,e){let t=di(r);for(let n of t){let o=Ve.join(r,n),s=xo(o,"utf8");if(s.includes(e))return{path:o,content:s}}throw new Error(`Could not find module file for module ${e} in ${r}`)}async function Et(r,e){let{test:t,modules:n}=nr(r,e),o=or(t);if(!o.steps||!Array.isArray(o.steps))throw new Error(`Test ${r} is missing steps`);if(!o.schemaVersion||!o.id)throw new Error(`Test ${r} is missing an ID or schema version`);let s;if(o.schemaVersion<G){V.warn(`Test ${r} has schema version ${o.schemaVersion}, which is lower than the version used by this SDK, ${G}. Your test will be migrated to the latest version before execution.`);let{steps:l}=await tr({metadata:o,steps:o.steps,logger:V});s=Te.array().parse(l)}else s=Te.array().parse(o.steps);let i={};for(let[l,c]of Object.entries(n)){let d=or(c);if(!d.schemaVersion||!d.moduleId)throw new Error(`Module ${l} is missing an ID or schema version`);if(!d.steps||!Array.isArray(d.steps))throw new Error(`Module ${l} is missing steps`);if(d.schemaVersion<G){V.warn(`Module ${l} has schema version ${d.schemaVersion}, which is lower than the version used by this SDK, ${G}. Your module will be migrated to the latest version before execution.`);let{steps:m}=await tr({metadata:{id:d.moduleId,schemaVersion:d.schemaVersion},steps:d.steps,logger:V});i[l]={...d,steps:Ee.array().parse(m)}}else i[l]=d}let a=s.map(l=>{if(l.type!=="MODULE")return l;let c=i[l.moduleId];if(!c)throw new Error(`Could not resolve module ${l.moduleId} required in test ${r}`);return{type:"RESOLVED_MODULE",moduleId:l.moduleId,name:c.name,steps:c.steps}});return yt.parse({...o,steps:a})}import{spawn as ui}from"child_process";async function Lo(r){return new Promise((e,t)=>{let n={stdio:"inherit",env:process.env,detached:!0},o=ui("bash",["-c",r],n),s=!1;process.on("exit",()=>o.pid!==void 0&&!s&&process.kill(-o.pid)),o.on("close",i=>{if(s=!0,i===0){e();return}t(`command exited with code ${i}`)})})}import{distance as _i}from"fastest-levenshtein";import ki from"js-beautify";import{homedir as Fi}from"os";import{join as zi}from"path";import{chromium as Ui,devices as Jo}from"playwright";import{addExtra as $i}from"playwright-extra";import Hi from"puppeteer-extra-plugin-recaptcha";import Bi from"puppeteer-extra-plugin-stealth";var Tt={js:'var K=Object.defineProperty;var P=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,B=Object.prototype.propertyIsEnumerable;var H=(t,e,n)=>e in t?K(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,D=(t,e)=>{for(var n in e||(e={}))z.call(e,n)&&H(t,n,e[n]);if(P)for(var n of P(e))B.call(e,n)&&H(t,n,e[n]);return t};var g=(t,e,n)=>(H(t,typeof e!="symbol"?e+"":e,n),n);var _=(t,e,n)=>new Promise((o,r)=>{var i=s=>{try{d(n.next(s))}catch(l){r(l)}},a=s=>{try{d(n.throw(s))}catch(l){r(l)}},d=s=>s.done?o(s.value):Promise.resolve(s.value).then(i,a);d((n=n.apply(t,e)).next())});var E=t=>function(e){return e&&e.isTrusted?t.apply(this,arguments):!0};globalThis.forTrusted==null&&(globalThis.forTrusted=E);var k={create(t,e,n,o){return{bottom:o,top:e,left:t,right:n,width:n-t,height:o-e}},copy(t){return{bottom:t.bottom,top:t.top,left:t.left,right:t.right,width:t.width,height:t.height}},translate(t,e,n){return e==null&&(e=0),n==null&&(n=0),{bottom:t.bottom+n,top:t.top+n,left:t.left+e,right:t.right+e,width:t.width,height:t.height}},subtract(t,e){return e=this.create(Math.max(t.left,e.left),Math.max(t.top,e.top),Math.min(t.right,e.right),Math.min(t.bottom,e.bottom)),e.width<0||e.height<0?[k.copy(t)]:[this.create(t.left,t.top,e.left,e.top),this.create(e.left,t.top,e.right,e.top),this.create(e.right,t.top,t.right,e.top),this.create(t.left,e.top,e.left,e.bottom),this.create(e.right,e.top,t.right,e.bottom),this.create(t.left,e.bottom,e.left,t.bottom),this.create(e.left,e.bottom,e.right,t.bottom),this.create(e.right,e.bottom,t.right,t.bottom)].filter(o=>o.height>0&&o.width>0)},intersects(t,e){return t.right>e.left&&t.left<e.right&&t.bottom>e.top&&t.top<e.bottom},intersectsStrict(t,e){return t.right>=e.left&&t.left<=e.right&&t.bottom>=e.top&&t.top<=e.bottom},equals(t,e){for(let n of["top","bottom","left","right","width","height"])if(t[n]!==e[n])return!1;return!0},intersect(t,e){return this.create(Math.max(t.left,e.left),Math.max(t.top,e.top),Math.min(t.right,e.right),Math.min(t.bottom,e.bottom))}};var N={_browserInfoLoaded:!0,_firefoxVersion:null,_isFirefox:!1,isFirefox(){if(!this._browserInfoLoaded)throw Error("browserInfo has not yet loaded.");return this._isFirefox},firefoxVersion(){if(!this._browserInfoLoaded)throw Error("browserInfo has not yet loaded.");return this._firefoxVersion},isString(t){return typeof t=="string"||t instanceof String}};var f={isReady(){return document.readyState!=="loading"},documentReady:function(){let t=document.readyState!=="loading",e=[];if(!t){let n;globalThis.addEventListener("DOMContentLoaded",n=E(function(){globalThis.removeEventListener("DOMContentLoaded",n,!0),t=!0;for(let o of e)o();e=null}),!0)}return function(n){if(t)return n();e.push(n)}}(),documentComplete:function(){let t=document.readyState==="complete",e=[];if(!t){let n;globalThis.addEventListener("load",n=E(function(o){if(o.target===document){globalThis.removeEventListener("load",n,!0),t=!0;for(let r of e)r();e=null}}),!0)}return function(n){t?n():e.push(n)}}(),createElement(t){let e=document.createElement(t);return e instanceof HTMLElement?(this.createElement=n=>document.createElement(n),e):(this.createElement=n=>document.createElementNS("http://www.w3.org/1999/xhtml",n),this.createElement(t))},addElementsToPage(t,e){let n=this.createElement("div");e.id!=null&&(n.id=e.id),e.className!=null&&(n.className=e.className);for(let o of t)n.appendChild(o);return document.body.appendChild(n),n},removeElement(t){return t.parentNode.removeChild(t)},isTopFrame(){return globalThis.top===globalThis.self},makeXPath(t){let e=[];for(let n of t)e.push(".//"+n,".//xhtml:"+n);return e.join(" | ")},evaluateXPath(t,e){let n=document.webkitIsFullScreen?document.webkitFullscreenElement:document.documentElement,o=function(r){return r==="xhtml"?"http://www.w3.org/1999/xhtml":null};return document.evaluate(t,n,o,e,null)},getVisibleClientRect(t,e){let n;e==null&&(e=!1);let o=(()=>{let i=[];for(n of t.getClientRects())i.push(k.copy(n));return i})(),r=function(){let i=window.getComputedStyle(t,null),a=i.getPropertyValue("display").indexOf("inline")===0&&i.getPropertyValue("font-size")==="0px";return r=()=>a,a};for(n of o){let i;if((n.width===0||n.height===0)&&e)for(let a of Array.from(t.children)){i=window.getComputedStyle(a,null);let d=i.getPropertyValue("position");if(i.getPropertyValue("float")==="none"&&!["absolute","fixed"].includes(d)&&!(n.height===0&&r()&&i.getPropertyValue("display").indexOf("inline")===0))continue;let s=this.getVisibleClientRect(a,!0);if(!(s===null||s.width<3||s.height<3))return s}else{if(n=this.cropRectToVisible(n),n===null||n.width<3||n.height<3||(i=window.getComputedStyle(t,null),i.getPropertyValue("visibility")!=="visible"))continue;return n}}return null},cropRectToVisible(t){let e=k.create(Math.max(t.left,0),Math.max(t.top,0),t.right,t.bottom);return e.top>=window.innerHeight-4||e.left>=window.innerWidth-4?null:e},getClientRectsForAreas(t,e){let n=[];for(let o of e){let r,i,a,d,s=o.coords.split(",").map(p=>parseInt(p,10)),l=o.shape.toLowerCase();if(["rect","rectangle"].includes(l))s.length==4&&([r,a,i,d]=s);else if(["circle","circ"].includes(l)){if(s.length==3){let[p,w,v]=s,u=v/Math.sqrt(2);r=p-u,i=p+u,a=w-u,d=w+u}}else l==="default"?s.length==2&&([r,a,i,d]=[0,0,t.width,t.height]):s.length>=4&&([r,a,i,d]=s);let c=k.translate(k.create(r,a,i,d),t.left,t.top);c=this.cropRectToVisible(c),c&&!isNaN(c.top)&&!isNaN(c.left)&&!isNaN(c.width)&&!isNaN(c.height)&&n.push({element:o,rect:c})}return n},isSelectable(t){if(!(t instanceof Element))return!1;let e=["button","checkbox","color","file","hidden","image","radio","reset","submit"];return t.nodeName.toLowerCase()==="input"&&e.indexOf(t.type)===-1||t.nodeName.toLowerCase()==="textarea"||t.isContentEditable},isEditable(t){return this.isSelectable(t)||(t.nodeName!=null?t.nodeName.toLowerCase():void 0)==="select"},isEmbed(t){let e=t.nodeName!=null?t.nodeName.toLowerCase():null;return["embed","object"].includes(e)},isFocusable(t){return t&&(this.isEditable(t)||this.isEmbed(t))},isDOMDescendant(t,e){let n=e;for(;n!==null;){if(n===t)return!0;n=n.parentNode}return!1},isSelected(t){let e=document.getSelection();if(t.isContentEditable){let n=e.anchorNode;return n&&this.isDOMDescendant(t,n)}else if(f.getSelectionType(e)==="Range"&&e.isCollapsed){let n=e.anchorNode.childNodes[e.anchorOffset];return t===n}else return!1},simulateSelect(t){if(t===document.activeElement&&f.isEditable(document.activeElement))return handlerStack.bubbleEvent("click",{target:t});if(t.focus(),t.tagName.toLowerCase()!=="textarea"||t.value.indexOf(`\n`)<0)try{if(t.selectionStart===0&&t.selectionEnd===0)return t.setSelectionRange(t.value.length,t.value.length)}catch(e){}},simulateClick(t,e){e==null&&(e={});let n=["mouseover","mousedown","mouseup","click"],o=[];for(let r of n){let i=this.simulateMouseEvent(r,t,e);o.push(i)}return o},simulateMouseEvent(t,e,n){if(n==null&&(n={}),t==="mouseout"){if(e==null&&(e=this.lastHoveredElement),this.lastHoveredElement=void 0,e==null)return}else t==="mouseover"&&(this.simulateMouseEvent("mouseout",void 0,n),this.lastHoveredElement=e);let o=new MouseEvent(t,{bubbles:!0,cancelable:!0,composed:!0,view:window,detail:1,ctrlKey:n.ctrlKey,altKey:n.altKey,shiftKey:n.shiftKey,metaKey:n.metaKey});return e.dispatchEvent(o)},simulateClickDefaultAction(t,e){let n;if(e==null&&(e={}),(t.tagName!=null?t.tagName.toLowerCase():void 0)!=="a"||!t.href)return;let{ctrlKey:o,shiftKey:r,metaKey:i,altKey:a}=e;KeyboardUtils.platform==="Mac"?n=i===!0&&o===!1:n=i===!1&&o===!0,n?chrome.runtime.sendMessage({handler:"openUrlInNewTab",url:t.href,active:r===!0}):r===!0&&i===!1&&o===!1&&a===!1?chrome.runtime.sendMessage({handler:"openUrlInNewWindow",url:t.href}):t.target==="_blank"&&chrome.runtime.sendMessage({handler:"openUrlInNewTab",url:t.href,active:!0})},simulateHover(t,e){return e==null&&(e={}),this.simulateMouseEvent("mouseover",t,e)},simulateUnhover(t,e){return e==null&&(e={}),this.simulateMouseEvent("mouseout",t,e)},addFlashRect(t){let e=this.createElement("div");return e.classList.add("vimiumReset"),e.classList.add("vimiumFlash"),e.style.left=t.left+"px",e.style.top=t.top+"px",e.style.width=t.width+"px",e.style.height=t.height+"px",document.documentElement.appendChild(e),e},getViewportTopLeft(){let t=document.documentElement,e=getComputedStyle(t),n=t.getBoundingClientRect();if(e.position==="static"&&!/content|paint|strict/.test(e.contain||"")){let o=parseInt(e.marginTop),r=parseInt(e.marginLeft);return{top:-n.top+o,left:-n.left+r}}else{let o,r;return N.isFirefox()?(r=parseInt(e.borderTopWidth),o=parseInt(e.borderLeftWidth)):{clientTop:r,clientLeft:o}=t,{top:-n.top-r,left:-n.left-o}}},suppressPropagation(t){t.stopImmediatePropagation()},suppressEvent(t){t.preventDefault(),this.suppressPropagation(t)},consumeKeyup:function(){let t=null;return function(e,n=null,o){if(!e.repeat){t!=null&&handlerStack.remove(t);let{code:r}=e;t=handlerStack.push({_name:"dom_utils/consumeKeyup",keyup(i){return i.code!==r||(this.remove(),o?f.suppressPropagation(i):f.suppressEvent(i)),handlerStack.continueBubbling},blur(i){return i.target===window&&this.remove(),handlerStack.continueBubbling}})}return typeof n=="function"&&n(),o?(f.suppressPropagation(e),handlerStack.suppressPropagation):(f.suppressEvent(e),handlerStack.suppressEvent)}}(),getSelectionType(t){return t==null&&(t=document.getSelection()),t.type?t.type:t.rangeCount===0?"None":t.isCollapsed?"Caret":"Range"},getElementWithFocus(t,e){let n,o=n=t.getRangeAt(0);f.getSelectionType(t)==="Range"&&(o=n.cloneRange(),o.collapse(e)),n=o.startContainer,n.nodeType===1&&(n=n.childNodes[o.startOffset]);let r=n;for(;r&&r.nodeType!==1;)r=r.previousSibling;return n=r||(n!=null?n.parentNode:void 0),n},getSelectionFocusElement(){let t=window.getSelection(),e=t.focusNode;return e==null?null:(e===t.anchorNode&&t.focusOffset===t.anchorOffset&&(e=e.childNodes[t.focusOffset]||e),e.nodeType!==Node.ELEMENT_NODE?e.parentElement:e)},getContainingElement(t){return(typeof t.getDestinationInsertionPoints=="function"?t.getDestinationInsertionPoints()[0]:void 0)||t.parentElement},windowIsTooSmall(){return window.innerWidth<3||window.innerHeight<3},injectUserCss(){let t=document.createElement("style");t.type="text/css",t.textContent=Settings.get("userDefinedLinkHintCss"),document.head.appendChild(t)}};var O={MAX_CONTENT_LENGTH:1e3,MAX_ATTRIBUTE_LENGTH:500,MAX_NUM_DATA_ATTRIBUTES:10,commonAttributes:["id","className","title","aria-label","aria-labelledby"],attributeNamesMapping:new Map([["a",["href","title","rel","target"]],["label",["for"]],["input",["type","name","placeholder","checked","maximumLength"]],["textarea",["placeholder","maximumLength"]],["button",["type"]],["select",["name","multiple"]],["div",["role"]],["iframe",["src"]],["img",["src","alt"]]]),describe(t){var r,i;let e={};this.addAttributes(t,this.commonAttributes,e);let n=((i=(r=t.tagName).toLowerCase)==null?void 0:i.call(r))||"";this.attributeNamesMapping.has(n)&&this.addAttributes(t,this.attributeNamesMapping.get(n),e),this.addDataAttrs(t,e);let o=this.getContent(t);return this.additionalHandling(t,D({tag:n,attributes:e},o&&{content:o}))},getContent(t){var n,o;let e=((o=(n=t.tagName).toLowerCase)==null?void 0:o.call(n))||"";return["input","textarea"].includes(e)?t.value:["div","iframe","img","body"].includes(e)?null:(["a","button","select","label"].includes(e),t.innerText)},additionalHandling(t,e){var o,r;if((((r=(o=t.tagName).toLowerCase)==null?void 0:r.call(o))||"")=="label"&&t.hasAttribute("for")){let i=t.getAttribute("for"),a=document.getElementById(i);a&&(e.target=this.describe(a))}return e},addAttributes(t,e,n){n||(n={});for(let o of e)t.hasAttribute(o)&&(n[o]=t.getAttribute(o).substring(0,this.MAX_ATTRIBUTE_LENGTH));return n},addDataAttrs(t,e){let n=0;for(let o in t.dataset)if(e[`data-${o}`]=t.dataset[o].substring(0,this.MAX_ATTRIBUTE_LENGTH),n++,n>this.MAX_NUM_DATA_ATTRIBUTES)return e;return e}};var x=null,C=()=>G()||document.scrollingElement||document.body,W=function(t){return t?t<0?-1:1:0},U={x:{axisName:"scrollLeft",max:"scrollWidth",viewSize:"clientWidth"},y:{axisName:"scrollTop",max:"scrollHeight",viewSize:"clientHeight"}},X=function(t,e,n){if(N.isString(n)){let o=n;return o==="viewSize"&&t===C()?e==="x"?window.innerWidth:window.innerHeight:t[U[e][o]]}else return n},V=function(t,e,n){let o=U[e].axisName,r=t[o];if(t.scrollBy){let i={behavior:"instant"};i[e==="x"?"left":"top"]=n,t.scrollBy(i)}else t[o]+=n;return t[o]!==r},q=function(t,e){let n=window.getComputedStyle(t);return!(n.getPropertyValue(`overflow-${e}`)==="hidden"||["hidden","collapse"].includes(n.getPropertyValue("visibility"))||n.getPropertyValue("display")==="none")},T=function(t,e,n,o){let r=o*X(t,e,n)||-1;return r=W(r),V(t,e,r)&&V(t,e,-r)},$=function(t,e,n,o){return e==null&&(e="y"),n==null&&(n=1),o==null&&(o=1),T(t,e,n,o)&&q(t,e)},j=function(t=null){let e;if(!t){let n=C();if(T(n,"y",1,1)||T(n,"y",-1,1))return n;t=document.body||C()}if(T(t,"y",1,1)||T(t,"y",-1,1))return t;{let n=Array.from(t.children).map(o=>({element:o,rect:f.getVisibleClientRect(o)})).filter(o=>o.rect);n.map(o=>o.area=o.rect.width*o.rect.height);for(e of n.sort((o,r)=>r.area-o.area)){let o=j(e.element);if(o)return o}return null}},L={init(){x=null},isScrollableElement(t){return x||(x=C()&&j()||C()),t!==x&&$(t)}},G=function(){let t=J[window.location.host];if(t)return document.querySelector(t)},J={"twitter.com":"div.permalink-container div.permalink[role=main]","reddit.com":"#overlayScrollContainer","new.reddit.com":"#overlayScrollContainer","www.reddit.com":"#overlayScrollContainer","web.telegram.org":".MessageList"};window.Scroller=L;var A=function(){let t=null;return f.documentReady(()=>t=document.hasFocus()),globalThis.addEventListener("focus",E(function(e){return e.target===window&&(t=!0),!0}),!0),globalThis.addEventListener("blur",E(function(e){return e.target===window&&(t=!1),!0}),!0),()=>t}();Object.assign(globalThis,{windowIsFocused:A});var R=class{constructor(e){g(this,"element");g(this,"image");g(this,"rect");g(this,"linkText");g(this,"showLinkText");g(this,"reason");g(this,"secondClassCitizen");g(this,"possibleFalsePositive");Object.seal(this),e&&Object.assign(this,e)}},M={getLocalHintsForElement(t){var p,w,v;let e=((w=(p=t.tagName).toLowerCase)==null?void 0:w.call(p))||"",n=!1,o=!1,r=!1,i=[],a=[],d=null;if(e==="img"){let u=t.getAttribute("usemap");if(u){let h=t.getClientRects();u=u.replace(/^#/,"").replace(\'"\',\'\\\\"\');let m=document.querySelector(`map[name="${u}"]`);if(m&&h.length>0){n=!0;let y=m.getElementsByTagName("area"),S=f.getClientRectsForAreas(h[0],y);S=S.map(F=>Object.assign(F,{image:t})),a.push(...S)}}}let s=t.getAttribute("aria-disabled");if(s&&["","true"].includes(s.toLowerCase()))return[];if(this.checkForAngularJs||(this.checkForAngularJs=function(){if(document.getElementsByClassName("ng-scope").length===0)return()=>!1;{let h=[];for(let m of["","data-","x-"])for(let y of["-",":","_"])h.push(`${m}ng${y}click`);return function(m){for(let y of h)if(m.hasAttribute(y))return!0;return!1}}}()),n||(n=this.checkForAngularJs(t)),t.hasAttribute("onclick"))n=!0;else{let u=t.getAttribute("role"),h=["button","tab","link","checkbox","menuitem","menuitemcheckbox","menuitemradio","radio"];if(u!=null&&h.includes(u.toLowerCase()))n=!0;else{let m=t.getAttribute("contentEditable");m!=null&&["","contenteditable","true","plaintext-only"].includes(m.toLowerCase())&&(n=!0)}}if(!n&&t.hasAttribute("jsaction")){let u=t.getAttribute("jsaction").split(";");for(let h of u){let m=h.trim().split(":");if(m.length>=1&&m.length<=2){let[y,S,F]=m.length===1?["click",...m[0].trim().split("."),"_"]:[m[0],...m[1].trim().split("."),"_"];n||(n=y==="click"&&S!=="none"&&F!=="_")}}}switch(e){case"a":n=!0;break;case"textarea":n||(n=!t.disabled&&!t.readOnly);break;case"input":n||(n=!(((v=t.getAttribute("type"))==null?void 0:v.toLowerCase())=="hidden"||t.disabled||t.readOnly&&f.isSelectable(t)));break;case"button":case"select":n||(n=!t.disabled);break;case"object":case"embed":n=!0;break;case"label":n||(n=t.control!=null&&!t.control.disabled&&this.getLocalHintsForElement(t.control).length===0);break;case"body":n||(n=t===document.body&&!A()&&window.innerWidth>3&&window.innerHeight>3&&(document.body!=null?document.body.tagName.toLowerCase():void 0)!=="frameset"?d="Frame.":void 0),n||(n=t===document.body&&A()&&L.isScrollableElement(t)?d="Scroll.":void 0);break;case"img":n||(n=["zoom-in","zoom-out"].includes(t.style.cursor));break;case"div":case"ol":case"ul":n||(n=t.clientHeight<t.scrollHeight&&L.isScrollableElement(t)?d="Scroll.":void 0);break;case"details":n=!0,d="Open.";break}let l=t.getAttribute("class");!n&&(l!=null&&l.toLowerCase().includes("button"))&&(n=!0,r=!0);let c=t.getAttribute("tabindex"),b=c?parseInt(c):-1;if(!n&&!(b<0)&&!isNaN(b)&&(n=!0,o=!0),n)if(a.length>0){let u=a.map(h=>new R({element:h.element,image:t,rect:h.rect,secondClassCitizen:o,possibleFalsePositive:r,reason:d}));i.push(...u)}else{let u=f.getVisibleClientRect(t,!0);if(u!==null){let h=new R({element:t,rect:u,secondClassCitizen:o,possibleFalsePositive:r,reason:d});i.push(h)}}return i},getElementFromPoint(t,e,n,o){n==null&&(n=document),o==null&&(o=[]);let r=n.elementsFromPoint?n.elementsFromPoint(t,e)[0]:n.elementFromPoint(t,e);return o.includes(r)?r:(o.push(r),r&&r.shadowRoot?M.getElementFromPoint(t,e,r.shadowRoot,o):r)},getLocalHints(t){if(!document.body)return[];let e=(s,l)=>{l==null&&(l=[]);for(let c of Array.from(s.querySelectorAll("*")))l.push(c),c.shadowRoot&&e(c.shadowRoot,l);return l},n=e(document.body),o=[];for(let s of Array.from(n))if(!t||s.href){let l=this.getLocalHintsForElement(s);o.push(...l)}o=o.reverse();let r=[1,2,3];o=o.filter((s,l)=>{if(!s.possibleFalsePositive)return!0;let b=Math.max(0,l-6);for(;b<l;){let p=o[b].element;for(let w of r)if(p=p==null?void 0:p.parentElement,p===s.element)return!1;b+=1}return!0});let i=o.filter(s=>{if(s.secondClassCitizen)return!1;let l=s.rect,c=M.getElementFromPoint(l.left+l.width*.5,l.top+l.height*.5);if(c&&(s.element.contains(c)||c.contains(s.element))||s.element.localName=="area"&&c==s.image)return!0;let p=[l.top+.1,l.bottom-.1],w=[l.left+.1,l.right-.1];for(let v of p)for(let u of w){let h=M.getElementFromPoint(u,v);if(h&&(s.element.contains(h)||h.contains(s.element)))return!0}});i.reverse();let{top:a,left:d}=f.getViewportTopLeft();for(let s of i)s.rect.top+=a,s.rect.left+=d;return i}};var I=class{constructor(){this.hints=null;this.hintMarkers=null;this.markersDiv=null;this.enrichedMarkers=null}reset(){this.removeMarkers(),this.hints=null,this.hintMarkers=null,this.markersDiv=null}capture(){return _(this,null,function*(){this.reset(),this.createMarkers(),this.displayMarkers()})}createMarkers(){this.hints=M.getLocalHints(),this.hintMarkers=new Map,this.hints.forEach((e,n)=>{var i,a;let o=f.createElement("div"),r=(a=(i=e.element.attributes["data-momentic-id"])==null?void 0:i.value)!=null?a:void 0;if(!r){console.warn(`[Momentic] No data-momentic-id found for interactive element ${e.element.outerHTML}`);return}o.style.left=e.rect.left+"px",o.style.top=e.rect.top+"px",o.style.zIndex=214e7+n,o.className="vimiumReset internalVimiumHintMarker vimiumHintMarker",Z(o,r),this.hintMarkers.set(r,{hint:e,marker:o})})}enrichMarkers(){if(this.hintMarkers){this.enrichedMarkers=[];for(let[e,n]of this.hintMarkers)this.enrichedMarkers.push(Object.assign(O.describe(n.hint.element),{hintString:e}))}}displayMarkers(){this.hintMarkers&&(this.markersDiv||(this.markersDiv=f.addElementsToPage(Array.from(this.hintMarkers.values()).map(e=>e.marker),{id:"vimiumHintMarkerContainer",className:"vimiumReset"})))}removeMarkers(){this.markersDiv&&(f.removeElement(this.markersDiv),this.markersDiv=null)}toggleMarkers(){this.markersDiv?this.removeMarkers():this.displayMarkers()}},Z=(t,e)=>{for(let n of e){let o=document.createElement("span");o.className="vimiumReset",o.textContent=n,t.appendChild(o)}};window.HintManager=I;\n',css:'.vimiumReset,a.vimiumReset,a:hover.vimiumReset,a:link.vimiumReset,a:visited.vimiumReset,div.vimiumReset,span.vimiumReset,table.vimiumReset,td.vimiumReset,tr.vimiumReset{background:none;border:none;bottom:auto;box-shadow:none;color:#000;cursor:auto;display:inline;float:none;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:inherit;font-style:normal;font-variant:normal;font-weight:400;height:auto;left:auto;letter-spacing:0;line-height:100%;margin:0;max-height:none;max-width:none;min-height:0;min-width:0;opacity:1;padding:0;position:static;right:auto;text-align:left;text-decoration:none;text-indent:0;text-shadow:none;text-transform:none;top:auto;vertical-align:baseline;white-space:normal;width:auto;z-index:2140000000}tbody.vimiumReset,thead.vimiumReset{display:table-header-group}tbody.vimiumReset{display:table-row-group}div.internalVimiumHintMarker{background:linear-gradient(180deg,#fff785 0,#ffc542);border:1px solid #c38a22;border-radius:3px;box-shadow:0 3px 7px 0 rgba(0,0,0,.3);display:block;font-size:11px;left:-1px;overflow:hidden;padding:1px 3px 0;position:absolute;top:-1px;white-space:nowrap}div.internalVimiumHintMarker span{color:#302505;font-family:Helvetica,Arial,sans-serif;font-size:11px;font-weight:700;text-shadow:0 1px 0 hsla(0,0%,100%,.6)}div.internalVimiumHintMarker>.matchingCharacter{color:#d4ac3a}div>.vimiumActiveHintMarker span{color:#a07555!important}div.internalVimiumInputHint{background-color:rgba(255,247,133,.3);border:1px solid #c38a22;display:block;pointer-events:none;position:absolute}div.internalVimiumSelectedInputHint{background-color:hsla(0,100%,70%,.3);border:1px solid #933!important}div.internalVimiumSelectedInputHint span{color:#fff!important}div.vimiumHighlightedFrame{border:5px solid #ff0;box-sizing:border-box;margin:0;pointer-events:none}div.vimiumHighlightedFrame,iframe.vimiumHelpDialogFrame{height:100%;left:0;padding:0;position:fixed;top:0;width:100%}iframe.vimiumHelpDialogFrame{background-color:hsla(0,0%,4%,.6);border:none;display:block;z-index:2139999997}div#vimiumHelpDialogContainer{background-color:#fff;border:2px solid #b3b3b3;border-radius:6px;margin:50px auto;max-height:calc(100% - 100px);max-width:calc(100% - 100px);opacity:1;overflow-x:auto;overflow-y:auto;width:840px}div#vimiumHelpDialog{min-width:600px;padding:8px 12px}span#vimiumTitle,span#vimiumTitle *,span#vimiumTitle span{font-size:20px}#vimiumTitle{display:block;line-height:130%;white-space:nowrap}td.vimiumHelpDialogTopButtons{text-align:right;width:100%}#helpDialogOptionsPage,#helpDialogWikiPage{font-size:14px;padding-left:5px;padding-right:5px}div.vimiumColumn{float:left;font-size:11px;line-height:130%;width:50%}div.vimiumColumn tr{display:table-row}div.vimiumColumn td{display:table-cell;font-size:11px;line-height:130%}div.vimiumColumn table,div.vimiumColumn td,div.vimiumColumn tr{margin:0;padding:0}div.vimiumColumn table{table-layout:auto;width:100%}div.vimiumColumn td{padding:1px;vertical-align:top}div#vimiumHelpDialog div.vimiumColumn tr>td:first-of-type{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;text-align:right;white-space:nowrap}span.vimiumHelpDialogKey{background-color:#f3f3f3;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#212121;font-family:monospace;font-size:11px;margin-left:2px;padding:1px 4px}div#vimiumHelpDialog div.vimiumColumn tr>td:nth-of-type(3){width:100%}div#vimiumHelpDialog div.vimiumDivider{background-color:#9a9a9a;display:block;height:1px;margin:10px auto;width:100%}div#vimiumHelpDialog td.vimiumHelpSectionTitle{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:16px;font-weight:700;padding-top:3px}div#vimiumHelpDialog td.vimiumHelpDescription{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px}div#vimiumHelpDialog span.vimiumCopyCommandNameName{cursor:pointer;font-size:12px;font-style:italic}div#vimiumHelpDialog tr.advanced{display:none}div#vimiumHelpDialog.showAdvanced tr.advanced{display:table-row}div#vimiumHelpDialog div.advanced td:nth-of-type(3){color:#555}div#vimiumHelpDialog a.closeButton{color:#555;cursor:pointer;font-family:courier new;font-size:24px;font-weight:700;padding-left:5px;position:relative;text-decoration:none;top:3px}div#vimiumHelpDialog a{text-decoration:underline}div#vimiumHelpDialog a.closeButton:hover{color:#000;-webkit-user-select:none}div#vimiumHelpDialogFooter{display:block;margin-bottom:37px;position:relative}table.helpDialogBottom{width:100%}td.helpDialogBottomRight{float:right;text-align:right;width:100%}td.helpDialogBottomLeft,td.helpDialogBottomRight{padding:0}div#vimiumHelpDialogFooter *{font-size:10px}a#toggleAdvancedCommands,span#help-dialog-tip{font-size:10px;position:relative;top:19px;white-space:nowrap}a#toggleAdvancedCommands,a:active.vimiumHelDialogLink,a:hover.vimiumHelDialogLink,a:link.vimiumHelDialogLink,a:visited.vimiumHelDialogLink{color:#2f508e;cursor:pointer;text-decoration:underline}div.vimiumHUD{background:#f1f1f1;border:1px solid #aaa;border-radius:4px;bottom:8px;box-shadow:0 2px 10px rgba(0,0,0,.8);display:block;left:8px;position:fixed;text-align:left;width:calc(100% - 20px);z-index:2139999999}iframe.vimiumHUDFrame{background-color:transparent;border:none;bottom:-14px;display:block;height:58px;margin:0 0 0 -40%;min-width:300px;opacity:0;overflow:hidden;padding:0;position:fixed;right:20px;width:20%;z-index:2139999998}div.vimiumHUD .vimiumHUDSearchArea{background-color:#f1f1f1;border-radius:4px 4px 0 0;display:block;padding:3px}div.vimiumHUD .vimiumHUDSearchAreaInner{border-radius:3px;box-sizing:border-box;color:#777;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;height:30px;line-height:20px;margin-bottom:0;outline:none;padding:2px 4px;width:100%}div.vimiumHUD .hud-find{background:#fff;border:1px solid #ccc}div.vimiumHUD span#hud-find-input,div.vimiumHUD span#hud-match-count{color:#000;display:inline;outline:none;overflow-y:hidden;white-space:nowrap}div.vimiumHUD span#hud-find-input:before{content:"/"}div.vimiumHUD span#hud-match-count{color:#aaa;font-size:12px}div.vimiumHUD span#hud-find-input br{display:none}div.vimiumHUD span#hud-find-input *{display:inline;white-space:nowrap}body.vimiumFindMode ::selection{background:#ff9632}iframe.vomnibarFrame{background-color:transparent;border:none;display:block;font-family:sans-serif;height:calc(100% - 70px);left:50%;margin:0 0 0 -40%;min-width:400px;overflow:hidden;padding:0;position:fixed;top:70px;width:calc(80% + 20px);z-index:2139999998}div.vimiumFlash{background-color:transparent;box-shadow:0 0 4px 2px #4183c4;padding:1px;position:absolute;z-index:2140000000}iframe.vimiumUIComponentHidden{display:none}iframe.vimiumUIComponentVisible{color-scheme:light dark;display:block}iframe.vimiumUIComponentReactivated{border:5px solid #ff0}iframe.vimiumNonClickable{pointer-events:none}@media (prefers-color-scheme:dark){iframe.reverseDarkReaderFilter{-webkit-filter:invert(100%) hue-rotate(180deg)!important;filter:invert(100%) hue-rotate(180deg)!important}body.vimiumBody{background-color:#292a2d;color:#fff}body.vimiumBody a,body.vimiumBody a:visited{color:#8ab4f8}body.vimiumBody input,body.vimiumBody textarea{background-color:#1d1d1f;border-color:#1d1d1f;color:#e8eaed}body.vimiumBody div.example{color:#9aa0a6}body.vimiumBody div#footer,body.vimiumBody div#state,div#vimiumHelpDialogContainer{background-color:#202124;border-color:hsla(0,0%,100%,.1)}div#vimiumHelpDialog{background-color:#292a2d;color:#fff}div#vimiumHelpDialog td.vimiumHelpDescription{color:#c9cccf}div#vimiumHelpDialog td.vimiumHelpSectionTitle,span#vimiumTitle{color:#fff}#vimiumTitle>span:first-child{color:#8ab4f8!important}div#vimiumHelpDialog a{color:#8ab4f8}div#vimiumHelpDialog div.vimiumDivider{background-color:hsla(0,0%,100%,.1)}span.vimiumHelpDialogKey{background-color:#1d1d1f;border:1px solid #000;box-shadow:none;color:#fff}}',htmlJs:'var c=["html","head","title","meta","iframe","script","style","path","svg","br","::marker","noscript"],u=["data-momentic-id","aria-keyshortcuts"],d=[/data-.*/,/aria-.*/],f=["name","id","text","value","type","class","focusable","height","width","placeholder","target","aria-label","type","title","href","src","alt","role","headers","scope"],m=["relative","flex","center","justify","auto","sticky","absolute","top","right","left","bottom"];function h(e){let t=document.createElement("textarea");return t.innerHTML=e,t.value}function g(e){let t=e.trim().split(" ");for(let r of t)if(!(r.length<=4)&&!m.some(s=>r.includes(s)))return r;return""}function o(e){var t;return!!(e.nodeType!==Node.ELEMENT_NODE||(t=e.textContent)!=null&&t.trim()||e.getAttributeNames().length>1||e.getAttributeNames().length===1&&!e.getAttribute("class"))}function b(e){return c.includes(e.tagName.toLowerCase())?!0:!o(e)&&e.childNodes.length===0}function N(e){let t=e.getAttributeNames();for(let r of t){if(u.includes(r)){e.removeAttribute(r);continue}switch(r){case"class":{let s=g(e.getAttribute("class"));s?e.setAttribute(r,s):e.removeAttribute(r);break}case"src":{let s=e.getAttribute(r);s!=null&&s.startsWith("data:")&&e.setAttribute(r,`${s.split(";")[0]};TRUNCATED`);break}default:{!f.includes(r)&&!d.some(n=>r.match(n))&&e.removeAttribute(r);let s=e.getAttribute(r);s!=null&&s.includes("&")&&e.setAttribute(r,h(s))}}}return e}function a(e){if(e.nodeType===Node.TEXT_NODE)return e;if(e.nodeType!==Node.ELEMENT_NODE)return!1;let t=N(e);if(b(t))return!1;let r=[...t.childNodes];for(let n=0;n<r.length;n++){let i=r[n],l=a(i);l?t.replaceChild(l,i):(t.removeChild(i),i.remove())}let s=o(t);return!s&&t.childNodes.length===0?!1:!s&&t.childNodes.length===1?t.childNodes[0]:t}function E(){let e=document.body.cloneNode(!0),t=a(e);if(!t)return"";let r=[];for(let s=0;s<t.childNodes.length;s++){let n=t.childNodes[s];n.parentNode||r.push(n)}for(let s=0;s<r.length;s++)t.removeChild(r[s]);return t.outerHTML}window.getHTMLBodyString=E;\n'};var Me=(r,e)=>{let{hostname:t,pathname:n}=new URL(r),{hostname:o,pathname:s}=new URL(e);return t!==o||n!==s},sr=r=>{try{return new URL(r),!0}catch{return!1}},ir=(r,e)=>{try{return new URL(r,e),!0}catch{return!1}};import{distance as lr}from"fastest-levenshtein";var Oo=new Set(["about:blank","chrome-error://chromewebdata/"]),Mo=3,We="data-momentic-id";var hi=["focusable","keyshortcuts","controls"],fi=["textbox","checkbox","combobox","button","link","list","listitem","tablist","tabpanel","tab","searchbox","menu","menubar","form","dialog","alertdialog","banner","navigation","main","menuitem","menuitemcheckbox","menuitemradio","option","radio","progressbar","switch"],gi=["notRendered","notVisible","ariaHiddenElement","ariaHiddenSubtree"],yi=80,Si={paragraph:"p",searchbox:"input",LineBreak:"br"},mr=["paragraph","StaticText","ListMarker","RootWebArea","LineBreak"],Po={indentLevel:0,noID:!1,noChildren:!1,noProperties:!1,maxLevel:void 0,neighbors:void 0},cr=class{id;role;name;content;properties;dataMomenticId;pathFromRoot;parent;children;backendNodeID;ignoredByCDP;constructor(e){this.id=e.id,this.role=e.role,this.name=e.name,this.content=e.content,this.properties={},this.pathFromRoot=e.pathFromRoot,this.children=e.children,this.backendNodeID=e.backendNodeID,this.ignoredByCDP=e.ignoredByCDP,e.properties&&e.properties.forEach(t=>{t.name==="keyshortcuts"?this.dataMomenticId=parseInt(t.value.value):this.properties[t.name]=t.value.value})}getLogForm(){return JSON.stringify({id:this.id,name:this.name??"",role:this.role??"",backendNodeId:this.backendNodeID})}isInteresting(){return fi.includes(this.role)||this.properties.focusable||this.properties.settable||this.children.some(e=>e.role==="StaticText")?!0:!!this.name.trim()||!!this.content}serialize(e=Po){let{indentLevel:t,noChildren:n,noProperties:o,noID:s}=Object.assign({},Po,e),i=" ".repeat(t),a=Si[this.role]||this.role,l=this.name,c={...this.properties};a==="heading"&&l==="heading"&&(l="");let d=!mr.includes(this.role);if(this.role==="StaticText")return`${i}${l}
|
|
17
|
-
`;let m=`${
|
|
18
|
-
`;else{let h="";for(let
|
|
19
|
-
`)?m+=`>${
|
|
15
|
+
`)),console.log(e===0?`${s} `:" ",l)}e===0&&process.stdout.write("\x1B[39m")}setMinLevel(e){this.minLogLevel=e}log(...e){this.info(...e)}info(...e){1<this.minLogLevel||this.logWithLevel(1,...e)}debug(...e){0<this.minLogLevel||this.logWithLevel(0,...e)}warn(...e){2<this.minLogLevel||this.logWithLevel(2,...e)}error(...e){3<this.minLogLevel||this.logWithLevel(3,...e)}child(e){return new r(this.minLogLevel,{...this.logBindings,...e})}flush(){}bindings(){return this.logBindings}},W=new Xt(1,{});import{z as fe}from"zod";var di=fe.object({id:fe.string(),createdAt:fe.coerce.date(),createdBy:fe.string(),organizationId:fe.string(),name:fe.string(),schemaVersion:fe.string(),numSteps:fe.number()}),Md=fe.object({steps:Ce.array()}).merge(di.omit({numSteps:!0}));var Me=r=>{let e=r.trim().toLowerCase().replace(/[^a-z0-9]/g,"-");for(;e.includes("--");)e=e.replaceAll("--","-");return e.startsWith("-")&&(e=e.slice(1)),e.endsWith("-")&&(e=e.slice(0,e.length-1)),e};import*as v from"zod";import{z as I}from"zod";var Jt={WEBHOOK:"WEBHOOK",CRON:"CRON",MANUAL:"MANUAL",CLI:"CLI"},Qt={PENDING:"PENDING",RUNNING:"RUNNING",PASSED:"PASSED",FAILED:"FAILED",CANCELLED:"CANCELLED"},mi={PASSED:"PASSED",FAILED:"FAILED"},vt=I.string().pipe(I.coerce.date()).or(I.date()),ui=I.object({id:I.string(),createdAt:vt,createdBy:I.string(),organizationId:I.string(),scheduledAt:vt.or(I.null()),startedAt:vt.or(I.null()),finishedAt:vt.or(I.null()),testId:I.string().or(I.null()),status:I.nativeEnum(Qt),expectedStatus:I.nativeEnum(mi).or(I.null()),runKey:I.string(),trigger:I.nativeEnum(Jt),attempts:I.number(),test:I.object({name:I.string(),id:I.string()}).or(I.null())}),Zt=ui.merge(I.object({results:yt.array(),test:I.object({name:I.string(),id:I.string(),baseUrl:I.string(),advanced:ie.optional()}).or(I.null())}));var we=v.object({disableCache:v.boolean()}),qd=v.object({error:v.boolean(),reason:v.string(),message:v.string()}),Yd=me.merge(we),mo=Ut,Xd=v.discriminatedUnion("vision",[me.merge(we).merge(v.object({vision:v.literal(!1)})),me.pick({goal:!0,url:!0}).merge(we).merge(v.object({screenshot:v.string(),vision:v.literal(!0)}))]),er=Gr,Jd=me.pick({browserState:!0,goal:!0}).merge(we),Qd=me.pick({goal:!0}).merge(we).merge(v.object({screenshot:v.string().describe("base64 encoded image"),hintActivatedScreenshot:v.string().describe("base64 encoded image")})),tr=co,Zd=me.pick({goal:!0,url:!0}).merge(we),uo=v.string().array(),em=me.pick({goal:!0,browserState:!0}).merge(we),po=Kr,tm=me.pick({goal:!0,browserState:!0,returnSchema:!0}).merge(we);var rm=v.object({testPaths:v.string().array().describe("can be either hyphenated, lowercase test names or UUIDs"),env:v.string().optional(),all:v.boolean().optional()}),ho=v.object({message:v.string(),queuedTests:v.object({name:v.string(),id:v.string()}).array()}),fo=so,go=v.string().array(),om=v.union([v.object({paths:v.string().array().describe("run specific test paths (e.g. todo-test)"),all:v.boolean().describe("run all tests").optional()}),v.object({path:v.string().describe("deprecated; present for backcompat")})]),yo=v.object({tests:v.record(v.string().describe("Test name"),v.string().describe("Test YAML")),modules:v.record(v.string().describe("Module name"),v.string().describe("Module YAML"))}),pi=v.object({test:v.string().describe("test YAML"),modules:v.record(v.string().describe("moduleId"),v.string().describe("module YAML"))}),nm=pi.array();var sm=v.object({testPath:v.string(),testId:v.string()}).partial().merge(v.object({trigger:v.nativeEnum(Jt)})),So=Zt,wo=Zt,im=v.object({startedAt:v.coerce.date(),finishedAt:v.coerce.date(),results:yt.array(),status:v.nativeEnum(Qt)}).partial(),am=v.object({screenshot:v.string()}),bo=v.object({key:v.string()}),vo=v.object({orgId:v.string()}),Ao=v.array(ee),lm=v.array(ee);function At(r){switch(r.type){case"AI_ACTION":return`AI action: ${r.text}`;case"PRESET_ACTION":return We(r.command);case"RESOLVED_MODULE":return`Module: ${r.moduleId}`}}import{stringify as rr}from"yaml";import{z as N}from"zod";var Am=N.object({test:N.string().describe("YAML for the test, including metadata and steps"),modules:N.record(N.string(),N.string()).describe("Map of module name to YAML for the module")}),Em=pe.merge(N.object({steps:Re.array(),fileType:N.literal("momentic/test")})),or=et.omit({type:!0}).merge(N.object({schemaVersion:N.string(),fileType:N.literal("momentic/module")})),Tm=pe.merge(N.object({steps:N.array(N.record(N.string(),N.unknown()))})),Cm=N.object({moduleId:N.string().uuid(),name:N.string(),schemaVersion:N.string(),steps:N.array(N.record(N.string(),N.unknown()))});function Eo(r,e=new Set){let t={id:r.id,name:r.name,baseUrl:r.baseUrl,schemaVersion:r.schemaVersion,advanced:r.advanced,retries:r.retries,envs:r.envs},n={},o=To(r.steps,r.schemaVersion,n,e),s={fileType:"momentic/test",...t,steps:o};return{test:rr(s),modules:n}}function To(r,e,t,n){let o=[];for(let s of r)switch(s.type){case"PRESET_ACTION":o.push(s);break;case"AI_ACTION":let a=(s.commands??[]).map(l=>({...l,thoughts:void 0}));o.push({...s,commands:a});break;case"RESOLVED_MODULE":n.has(s.name)||(t[s.name]=hi(s,e),n.add(s.name)),o.push({type:"MODULE",moduleId:s.moduleId});break;default:return(l=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(s)}return o}function hi(r,e){let t={fileType:"momentic/module",moduleId:r.moduleId,name:r.name,steps:To(r.steps,e,{},new Set),schemaVersion:e};return rr(t)}function nr(r){return rr({fileType:"momentic/environment",...r})}import{validator as Lm}from"@exodus/schemasafe";var Co={name:"Migrate to ai step v2",fromVersion:"1.0.4",toVersion:"1.0.5",recursiveKeys:new Set(["results","commands"]),stopOnFailure:!0,execute:async r=>(r=r.filter(e=>!(e.status!==void 0&&e.type==="AI_ACTION")),r=r.map(e=>(e.status===void 0||e.type==="PRESET_ACTION"&&(e.results=e.commands??e.results??[]),e)),r)};var Ro={name:"Make sure ai step v2 has done command",fromVersion:"1.0.5",toVersion:"1.0.6",recursiveKeys:new Set(["results","commands"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="AI_ACTION"||e.status!==void 0||!e.commands||!e.commands.length)return e;let t=e.commands,n=t[t.length-1];return n&&n.type!=="SUCCESS"&&t.push({type:"SUCCESS"}),e})};var xo={name:"Migrate AI assertions to preset actions",fromVersion:"1.0.0",toVersion:"1.0.1",recursiveKeys:new Set,execute:async r=>r.map(e=>{if(e.type!=="AI_ASSERTION")return e;let n={type:"PRESET_ACTION",command:{type:"AI_ASSERTION",assertion:e.text,useVision:!1,disableCache:!0}},o={...e,...n};return delete o.text,o}),stopOnFailure:!0};var Et=new Set(["CLICK","TYPE","SELECT_OPTION"]),Io={name:"Migrate element descriptor to live in a target object",fromVersion:"1.0.3",toVersion:"1.0.4",recursiveKeys:new Set,execute:async r=>r.map(e=>{let t=e.command,n=t?.type,o=t?.elementDescriptor;return(o!==void 0||Et.has(n))&&(t.target={elementDescriptor:o??""}),e.commands&&Array.isArray(e.commands)&&e.commands.forEach(a=>{let i=a?.elementDescriptor,l=a?.type;(i!==void 0||Et.has(l))&&(a.target={elementDescriptor:i??""})}),e.results&&Array.isArray(e.results)&&e.results.forEach(a=>{let i=a.command,l=i?.elementDescriptor,c=i?.type;(l!==void 0||Et.has(c))&&(i.target={elementDescriptor:l??""}),a.commands&&Array.isArray(a.commands)&&a.commands.forEach(m=>{let f=m?.elementDescriptor,h=m?.type;(f!==void 0||Et.has(h))&&(m.target={elementDescriptor:f??""})})}),e}),stopOnFailure:!0};var Lo={name:"Migrate FAILURE status to FAILED",fromVersion:"1.0.1",toVersion:"1.0.2",recursiveKeys:new Set,execute:async r=>r.map(e=>{let t=e;return t.status==="FAILURE"&&(t.status="FAILED"),typeof t.commands=="object"&&Array.isArray(t.commands)&&t.commands.forEach(n=>{if(n&&typeof n=="object"){let o=n;o?.status==="FAILURE"&&(o.status="FAILED")}}),t}),stopOnFailure:!0};var Oo={name:"Migrate preset step types to use the same",fromVersion:"1.0.2",toVersion:"1.0.3",recursiveKeys:new Set,execute:async r=>r.map(e=>{let t=e.command,n=t?.type;return n?.startsWith("PRESET_")&&(t.type=n.slice(7)),e.commands&&Array.isArray(e.commands)&&e.commands.forEach(s=>{let a=s.type;a?.startsWith("PRESET_")&&(s.type=a.slice(7))}),e.results&&Array.isArray(e.results)&&e.results.forEach(s=>{let a=s.command,i=a?.type;i?.startsWith("PRESET_")&&(a.type=i.slice(7)),s.commands&&Array.isArray(s.commands)&&s.commands.forEach(c=>{let d=c.type;d?.startsWith("PRESET_")&&(c.type=d.slice(7))})}),e}),stopOnFailure:!0};var Ne=[xo,Lo,Oo,Io,Co,Ro];if(V!==Ne[Ne.length-1].toVersion)throw new Error("Please bump LATEST_VERSION in types package after adding a migration");Ne.forEach((r,e)=>{if(!Tt.valid(r.toVersion)||!Tt.valid(r.fromVersion))throw new Error(`Migration '${r.name}' has invalid version`);if(!Tt.gt(r.toVersion,r.fromVersion))throw new Error(`Migration '${r.name}' has toVersion <= fromVersion`);if(e===0)return;if(Ne[e-1].toVersion!==r.fromVersion)throw new Error(`Migration '${r.name}' at index ${e} is not contiguous with previous migration`)});function gi(r){return r.every(e=>e&&typeof e=="object"&&!Array.isArray(e))}var sr=async({metadata:r,steps:e,logger:t})=>{let n=e,{schemaVersion:o,id:s}=r,a=Ne.findIndex(c=>Tt.gt(c.toVersion,o));if(a===-1)return t.debug({id:s},"Step migrations up to date"),{steps:n,newVersion:o};let i=o;for(let c=a;c<Ne.length;c++){let d=Ne[c],m={id:s,migration:d.name,toVersion:d.toVersion};t.debug(m,"Starting migration");try{n=await Mo(n,d),i=d.toVersion}catch(f){throw t.error({err:f,...m},"Migration failed"),new Error(`Step migration ${d.name} failed: ${f}`)}}let l=fi(JSON.stringify(e,void 0,2),JSON.stringify(n,void 0,2),{n_surrounding:1});return t.debug({diffs:l,id:s},"Migration diffs"),{newVersion:i,steps:n}};async function Mo(r,e){let t=await e.execute(r);for(let n of t)for(let o of Object.keys(n)){if(!e.recursiveKeys.has(o))continue;let s=n[o];!s||!Array.isArray(s)||gi(s)&&(n[o]=await Mo(s,e))}return t}import{parse as ar}from"yaml";var Po=St,Si=new Set([...Po,"node_modules","dist","bin",".git","logs",".npm",".next","out",".yarn","__pycache__","build",".env",".venv","venv","env","wheels"]);function ot(r,e,t=r){let n=r.split(Ke.sep).pop()??"";if(Si.has(n))return Po.includes(n)||e.warn(`Skipping directory '${r}' because it is likely an artifact folder.`),[];let o=ir.readdirSync(r),s=[];return o.forEach(a=>{let i=Ke.join(r,a),l;try{l=ir.statSync(i)}catch(c){e.warn({err:c},`Skipping path '${i}' because it could not be read.`);return}if(l.isDirectory())s=s.concat(ot(i,e,r));else if(a.endsWith(".yaml")){let c=ir.readFileSync(i,"utf-8");try{let d=ar(c),m=pe.parse(d);s.push({id:m.id,name:m.name,fullFilePath:i,testPath:Ke.relative(Ke.resolve(t),Ke.resolve(i)),fileName:a,lastModified:l.mtime,createdAt:l.ctime})}catch{e.warn(`Skipping file '${i}' because it does not parse as a valid Momentic test.`)}}}),s}function lr(r,e){let t;try{t=No(r,"utf8"),t=t.replace(/\r\n|\r/g,`
|
|
16
|
+
`)}catch(i){throw new Error(`Could not read test file ${r}: ${i}`)}let n=new Set,o=/moduleId: (.*)/g,s;for(;(s=o.exec(t))!==null;)n.add(s[1].trim());let a={};return n.size>0&&n.forEach(i=>{a[i]||(a[i]=Ct(e,i).content)}),{test:t,modules:a}}function Ct(r,e){let t=yi(r);for(let n of t){let o=Ke.join(r,n),s=No(o,"utf8");if(s.includes(e))return{path:o,content:s}}throw new Error(`Could not find module file for module ${e} in ${r}`)}async function Rt(r,e){let{test:t,modules:n}=lr(r,e),o=ar(t);if(!o.steps||!Array.isArray(o.steps))throw new Error(`Test ${r} is missing steps`);if(!o.schemaVersion||!o.id)throw new Error(`Test ${r} is missing an ID or schema version`);let s;if(o.schemaVersion<V){W.warn(`Test ${r} has schema version ${o.schemaVersion}, which is lower than the version used by this SDK, ${V}. Your test will be migrated to the latest version before execution.`);let{steps:l}=await sr({metadata:o,steps:o.steps,logger:W});s=Re.array().parse(l)}else s=Re.array().parse(o.steps);let a={};for(let[l,c]of Object.entries(n)){let d=ar(c);if(!d.schemaVersion||!d.moduleId)throw new Error(`Module ${l} is missing an ID or schema version`);if(!d.steps||!Array.isArray(d.steps))throw new Error(`Module ${l} is missing steps`);if(d.schemaVersion<V){W.warn(`Module ${l} has schema version ${d.schemaVersion}, which is lower than the version used by this SDK, ${V}. Your module will be migrated to the latest version before execution.`);let{steps:m}=await sr({metadata:{id:d.moduleId,schemaVersion:d.schemaVersion},steps:d.steps,logger:W});a[l]={...d,steps:Ce.array().parse(m)}}else a[l]=d}let i=s.map(l=>{if(l.type!=="MODULE")return l;let c=a[l.moduleId];if(!c)throw new Error(`Could not resolve module ${l.moduleId} required in test ${r}`);return{type:"RESOLVED_MODULE",moduleId:l.moduleId,name:c.name,steps:c.steps}});return bt.parse({...o,steps:i})}import{spawn as wi}from"child_process";async function Do(r){return new Promise((e,t)=>{let n={stdio:"inherit",env:process.env,detached:!0},o=wi("bash",["-c",r],n),s=!1;process.on("exit",()=>o.pid!==void 0&&!s&&process.kill(-o.pid)),o.on("close",a=>{if(s=!0,a===0){e();return}t(`command exited with code ${a}`)})})}import{distance as Bi}from"fastest-levenshtein";import Vi from"js-beautify";import{homedir as ji}from"os";import{join as Gi}from"path";import{chromium as Wi,devices as rn}from"playwright";import{addExtra as Ki}from"playwright-extra";import qi from"puppeteer-extra-plugin-recaptcha";import Yi from"puppeteer-extra-plugin-stealth";var xt={js:'var K=Object.defineProperty;var P=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,B=Object.prototype.propertyIsEnumerable;var H=(t,e,n)=>e in t?K(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,D=(t,e)=>{for(var n in e||(e={}))z.call(e,n)&&H(t,n,e[n]);if(P)for(var n of P(e))B.call(e,n)&&H(t,n,e[n]);return t};var g=(t,e,n)=>(H(t,typeof e!="symbol"?e+"":e,n),n);var _=(t,e,n)=>new Promise((o,r)=>{var i=s=>{try{d(n.next(s))}catch(l){r(l)}},a=s=>{try{d(n.throw(s))}catch(l){r(l)}},d=s=>s.done?o(s.value):Promise.resolve(s.value).then(i,a);d((n=n.apply(t,e)).next())});var E=t=>function(e){return e&&e.isTrusted?t.apply(this,arguments):!0};globalThis.forTrusted==null&&(globalThis.forTrusted=E);var k={create(t,e,n,o){return{bottom:o,top:e,left:t,right:n,width:n-t,height:o-e}},copy(t){return{bottom:t.bottom,top:t.top,left:t.left,right:t.right,width:t.width,height:t.height}},translate(t,e,n){return e==null&&(e=0),n==null&&(n=0),{bottom:t.bottom+n,top:t.top+n,left:t.left+e,right:t.right+e,width:t.width,height:t.height}},subtract(t,e){return e=this.create(Math.max(t.left,e.left),Math.max(t.top,e.top),Math.min(t.right,e.right),Math.min(t.bottom,e.bottom)),e.width<0||e.height<0?[k.copy(t)]:[this.create(t.left,t.top,e.left,e.top),this.create(e.left,t.top,e.right,e.top),this.create(e.right,t.top,t.right,e.top),this.create(t.left,e.top,e.left,e.bottom),this.create(e.right,e.top,t.right,e.bottom),this.create(t.left,e.bottom,e.left,t.bottom),this.create(e.left,e.bottom,e.right,t.bottom),this.create(e.right,e.bottom,t.right,t.bottom)].filter(o=>o.height>0&&o.width>0)},intersects(t,e){return t.right>e.left&&t.left<e.right&&t.bottom>e.top&&t.top<e.bottom},intersectsStrict(t,e){return t.right>=e.left&&t.left<=e.right&&t.bottom>=e.top&&t.top<=e.bottom},equals(t,e){for(let n of["top","bottom","left","right","width","height"])if(t[n]!==e[n])return!1;return!0},intersect(t,e){return this.create(Math.max(t.left,e.left),Math.max(t.top,e.top),Math.min(t.right,e.right),Math.min(t.bottom,e.bottom))}};var N={_browserInfoLoaded:!0,_firefoxVersion:null,_isFirefox:!1,isFirefox(){if(!this._browserInfoLoaded)throw Error("browserInfo has not yet loaded.");return this._isFirefox},firefoxVersion(){if(!this._browserInfoLoaded)throw Error("browserInfo has not yet loaded.");return this._firefoxVersion},isString(t){return typeof t=="string"||t instanceof String}};var f={isReady(){return document.readyState!=="loading"},documentReady:function(){let t=document.readyState!=="loading",e=[];if(!t){let n;globalThis.addEventListener("DOMContentLoaded",n=E(function(){globalThis.removeEventListener("DOMContentLoaded",n,!0),t=!0;for(let o of e)o();e=null}),!0)}return function(n){if(t)return n();e.push(n)}}(),documentComplete:function(){let t=document.readyState==="complete",e=[];if(!t){let n;globalThis.addEventListener("load",n=E(function(o){if(o.target===document){globalThis.removeEventListener("load",n,!0),t=!0;for(let r of e)r();e=null}}),!0)}return function(n){t?n():e.push(n)}}(),createElement(t){let e=document.createElement(t);return e instanceof HTMLElement?(this.createElement=n=>document.createElement(n),e):(this.createElement=n=>document.createElementNS("http://www.w3.org/1999/xhtml",n),this.createElement(t))},addElementsToPage(t,e){let n=this.createElement("div");e.id!=null&&(n.id=e.id),e.className!=null&&(n.className=e.className);for(let o of t)n.appendChild(o);return document.body.appendChild(n),n},removeElement(t){return t.parentNode.removeChild(t)},isTopFrame(){return globalThis.top===globalThis.self},makeXPath(t){let e=[];for(let n of t)e.push(".//"+n,".//xhtml:"+n);return e.join(" | ")},evaluateXPath(t,e){let n=document.webkitIsFullScreen?document.webkitFullscreenElement:document.documentElement,o=function(r){return r==="xhtml"?"http://www.w3.org/1999/xhtml":null};return document.evaluate(t,n,o,e,null)},getVisibleClientRect(t,e){let n;e==null&&(e=!1);let o=(()=>{let i=[];for(n of t.getClientRects())i.push(k.copy(n));return i})(),r=function(){let i=window.getComputedStyle(t,null),a=i.getPropertyValue("display").indexOf("inline")===0&&i.getPropertyValue("font-size")==="0px";return r=()=>a,a};for(n of o){let i;if((n.width===0||n.height===0)&&e)for(let a of Array.from(t.children)){i=window.getComputedStyle(a,null);let d=i.getPropertyValue("position");if(i.getPropertyValue("float")==="none"&&!["absolute","fixed"].includes(d)&&!(n.height===0&&r()&&i.getPropertyValue("display").indexOf("inline")===0))continue;let s=this.getVisibleClientRect(a,!0);if(!(s===null||s.width<3||s.height<3))return s}else{if(n=this.cropRectToVisible(n),n===null||n.width<3||n.height<3||(i=window.getComputedStyle(t,null),i.getPropertyValue("visibility")!=="visible"))continue;return n}}return null},cropRectToVisible(t){let e=k.create(Math.max(t.left,0),Math.max(t.top,0),t.right,t.bottom);return e.top>=window.innerHeight-4||e.left>=window.innerWidth-4?null:e},getClientRectsForAreas(t,e){let n=[];for(let o of e){let r,i,a,d,s=o.coords.split(",").map(p=>parseInt(p,10)),l=o.shape.toLowerCase();if(["rect","rectangle"].includes(l))s.length==4&&([r,a,i,d]=s);else if(["circle","circ"].includes(l)){if(s.length==3){let[p,w,v]=s,u=v/Math.sqrt(2);r=p-u,i=p+u,a=w-u,d=w+u}}else l==="default"?s.length==2&&([r,a,i,d]=[0,0,t.width,t.height]):s.length>=4&&([r,a,i,d]=s);let c=k.translate(k.create(r,a,i,d),t.left,t.top);c=this.cropRectToVisible(c),c&&!isNaN(c.top)&&!isNaN(c.left)&&!isNaN(c.width)&&!isNaN(c.height)&&n.push({element:o,rect:c})}return n},isSelectable(t){if(!(t instanceof Element))return!1;let e=["button","checkbox","color","file","hidden","image","radio","reset","submit"];return t.nodeName.toLowerCase()==="input"&&e.indexOf(t.type)===-1||t.nodeName.toLowerCase()==="textarea"||t.isContentEditable},isEditable(t){return this.isSelectable(t)||(t.nodeName!=null?t.nodeName.toLowerCase():void 0)==="select"},isEmbed(t){let e=t.nodeName!=null?t.nodeName.toLowerCase():null;return["embed","object"].includes(e)},isFocusable(t){return t&&(this.isEditable(t)||this.isEmbed(t))},isDOMDescendant(t,e){let n=e;for(;n!==null;){if(n===t)return!0;n=n.parentNode}return!1},isSelected(t){let e=document.getSelection();if(t.isContentEditable){let n=e.anchorNode;return n&&this.isDOMDescendant(t,n)}else if(f.getSelectionType(e)==="Range"&&e.isCollapsed){let n=e.anchorNode.childNodes[e.anchorOffset];return t===n}else return!1},simulateSelect(t){if(t===document.activeElement&&f.isEditable(document.activeElement))return handlerStack.bubbleEvent("click",{target:t});if(t.focus(),t.tagName.toLowerCase()!=="textarea"||t.value.indexOf(`\n`)<0)try{if(t.selectionStart===0&&t.selectionEnd===0)return t.setSelectionRange(t.value.length,t.value.length)}catch(e){}},simulateClick(t,e){e==null&&(e={});let n=["mouseover","mousedown","mouseup","click"],o=[];for(let r of n){let i=this.simulateMouseEvent(r,t,e);o.push(i)}return o},simulateMouseEvent(t,e,n){if(n==null&&(n={}),t==="mouseout"){if(e==null&&(e=this.lastHoveredElement),this.lastHoveredElement=void 0,e==null)return}else t==="mouseover"&&(this.simulateMouseEvent("mouseout",void 0,n),this.lastHoveredElement=e);let o=new MouseEvent(t,{bubbles:!0,cancelable:!0,composed:!0,view:window,detail:1,ctrlKey:n.ctrlKey,altKey:n.altKey,shiftKey:n.shiftKey,metaKey:n.metaKey});return e.dispatchEvent(o)},simulateClickDefaultAction(t,e){let n;if(e==null&&(e={}),(t.tagName!=null?t.tagName.toLowerCase():void 0)!=="a"||!t.href)return;let{ctrlKey:o,shiftKey:r,metaKey:i,altKey:a}=e;KeyboardUtils.platform==="Mac"?n=i===!0&&o===!1:n=i===!1&&o===!0,n?chrome.runtime.sendMessage({handler:"openUrlInNewTab",url:t.href,active:r===!0}):r===!0&&i===!1&&o===!1&&a===!1?chrome.runtime.sendMessage({handler:"openUrlInNewWindow",url:t.href}):t.target==="_blank"&&chrome.runtime.sendMessage({handler:"openUrlInNewTab",url:t.href,active:!0})},simulateHover(t,e){return e==null&&(e={}),this.simulateMouseEvent("mouseover",t,e)},simulateUnhover(t,e){return e==null&&(e={}),this.simulateMouseEvent("mouseout",t,e)},addFlashRect(t){let e=this.createElement("div");return e.classList.add("vimiumReset"),e.classList.add("vimiumFlash"),e.style.left=t.left+"px",e.style.top=t.top+"px",e.style.width=t.width+"px",e.style.height=t.height+"px",document.documentElement.appendChild(e),e},getViewportTopLeft(){let t=document.documentElement,e=getComputedStyle(t),n=t.getBoundingClientRect();if(e.position==="static"&&!/content|paint|strict/.test(e.contain||"")){let o=parseInt(e.marginTop),r=parseInt(e.marginLeft);return{top:-n.top+o,left:-n.left+r}}else{let o,r;return N.isFirefox()?(r=parseInt(e.borderTopWidth),o=parseInt(e.borderLeftWidth)):{clientTop:r,clientLeft:o}=t,{top:-n.top-r,left:-n.left-o}}},suppressPropagation(t){t.stopImmediatePropagation()},suppressEvent(t){t.preventDefault(),this.suppressPropagation(t)},consumeKeyup:function(){let t=null;return function(e,n=null,o){if(!e.repeat){t!=null&&handlerStack.remove(t);let{code:r}=e;t=handlerStack.push({_name:"dom_utils/consumeKeyup",keyup(i){return i.code!==r||(this.remove(),o?f.suppressPropagation(i):f.suppressEvent(i)),handlerStack.continueBubbling},blur(i){return i.target===window&&this.remove(),handlerStack.continueBubbling}})}return typeof n=="function"&&n(),o?(f.suppressPropagation(e),handlerStack.suppressPropagation):(f.suppressEvent(e),handlerStack.suppressEvent)}}(),getSelectionType(t){return t==null&&(t=document.getSelection()),t.type?t.type:t.rangeCount===0?"None":t.isCollapsed?"Caret":"Range"},getElementWithFocus(t,e){let n,o=n=t.getRangeAt(0);f.getSelectionType(t)==="Range"&&(o=n.cloneRange(),o.collapse(e)),n=o.startContainer,n.nodeType===1&&(n=n.childNodes[o.startOffset]);let r=n;for(;r&&r.nodeType!==1;)r=r.previousSibling;return n=r||(n!=null?n.parentNode:void 0),n},getSelectionFocusElement(){let t=window.getSelection(),e=t.focusNode;return e==null?null:(e===t.anchorNode&&t.focusOffset===t.anchorOffset&&(e=e.childNodes[t.focusOffset]||e),e.nodeType!==Node.ELEMENT_NODE?e.parentElement:e)},getContainingElement(t){return(typeof t.getDestinationInsertionPoints=="function"?t.getDestinationInsertionPoints()[0]:void 0)||t.parentElement},windowIsTooSmall(){return window.innerWidth<3||window.innerHeight<3},injectUserCss(){let t=document.createElement("style");t.type="text/css",t.textContent=Settings.get("userDefinedLinkHintCss"),document.head.appendChild(t)}};var O={MAX_CONTENT_LENGTH:1e3,MAX_ATTRIBUTE_LENGTH:500,MAX_NUM_DATA_ATTRIBUTES:10,commonAttributes:["id","className","title","aria-label","aria-labelledby"],attributeNamesMapping:new Map([["a",["href","title","rel","target"]],["label",["for"]],["input",["type","name","placeholder","checked","maximumLength"]],["textarea",["placeholder","maximumLength"]],["button",["type"]],["select",["name","multiple"]],["div",["role"]],["iframe",["src"]],["img",["src","alt"]]]),describe(t){var r,i;let e={};this.addAttributes(t,this.commonAttributes,e);let n=((i=(r=t.tagName).toLowerCase)==null?void 0:i.call(r))||"";this.attributeNamesMapping.has(n)&&this.addAttributes(t,this.attributeNamesMapping.get(n),e),this.addDataAttrs(t,e);let o=this.getContent(t);return this.additionalHandling(t,D({tag:n,attributes:e},o&&{content:o}))},getContent(t){var n,o;let e=((o=(n=t.tagName).toLowerCase)==null?void 0:o.call(n))||"";return["input","textarea"].includes(e)?t.value:["div","iframe","img","body"].includes(e)?null:(["a","button","select","label"].includes(e),t.innerText)},additionalHandling(t,e){var o,r;if((((r=(o=t.tagName).toLowerCase)==null?void 0:r.call(o))||"")=="label"&&t.hasAttribute("for")){let i=t.getAttribute("for"),a=document.getElementById(i);a&&(e.target=this.describe(a))}return e},addAttributes(t,e,n){n||(n={});for(let o of e)t.hasAttribute(o)&&(n[o]=t.getAttribute(o).substring(0,this.MAX_ATTRIBUTE_LENGTH));return n},addDataAttrs(t,e){let n=0;for(let o in t.dataset)if(e[`data-${o}`]=t.dataset[o].substring(0,this.MAX_ATTRIBUTE_LENGTH),n++,n>this.MAX_NUM_DATA_ATTRIBUTES)return e;return e}};var x=null,C=()=>G()||document.scrollingElement||document.body,W=function(t){return t?t<0?-1:1:0},U={x:{axisName:"scrollLeft",max:"scrollWidth",viewSize:"clientWidth"},y:{axisName:"scrollTop",max:"scrollHeight",viewSize:"clientHeight"}},X=function(t,e,n){if(N.isString(n)){let o=n;return o==="viewSize"&&t===C()?e==="x"?window.innerWidth:window.innerHeight:t[U[e][o]]}else return n},V=function(t,e,n){let o=U[e].axisName,r=t[o];if(t.scrollBy){let i={behavior:"instant"};i[e==="x"?"left":"top"]=n,t.scrollBy(i)}else t[o]+=n;return t[o]!==r},q=function(t,e){let n=window.getComputedStyle(t);return!(n.getPropertyValue(`overflow-${e}`)==="hidden"||["hidden","collapse"].includes(n.getPropertyValue("visibility"))||n.getPropertyValue("display")==="none")},T=function(t,e,n,o){let r=o*X(t,e,n)||-1;return r=W(r),V(t,e,r)&&V(t,e,-r)},$=function(t,e,n,o){return e==null&&(e="y"),n==null&&(n=1),o==null&&(o=1),T(t,e,n,o)&&q(t,e)},j=function(t=null){let e;if(!t){let n=C();if(T(n,"y",1,1)||T(n,"y",-1,1))return n;t=document.body||C()}if(T(t,"y",1,1)||T(t,"y",-1,1))return t;{let n=Array.from(t.children).map(o=>({element:o,rect:f.getVisibleClientRect(o)})).filter(o=>o.rect);n.map(o=>o.area=o.rect.width*o.rect.height);for(e of n.sort((o,r)=>r.area-o.area)){let o=j(e.element);if(o)return o}return null}},L={init(){x=null},isScrollableElement(t){return x||(x=C()&&j()||C()),t!==x&&$(t)}},G=function(){let t=J[window.location.host];if(t)return document.querySelector(t)},J={"twitter.com":"div.permalink-container div.permalink[role=main]","reddit.com":"#overlayScrollContainer","new.reddit.com":"#overlayScrollContainer","www.reddit.com":"#overlayScrollContainer","web.telegram.org":".MessageList"};window.Scroller=L;var A=function(){let t=null;return f.documentReady(()=>t=document.hasFocus()),globalThis.addEventListener("focus",E(function(e){return e.target===window&&(t=!0),!0}),!0),globalThis.addEventListener("blur",E(function(e){return e.target===window&&(t=!1),!0}),!0),()=>t}();Object.assign(globalThis,{windowIsFocused:A});var R=class{constructor(e){g(this,"element");g(this,"image");g(this,"rect");g(this,"linkText");g(this,"showLinkText");g(this,"reason");g(this,"secondClassCitizen");g(this,"possibleFalsePositive");Object.seal(this),e&&Object.assign(this,e)}},M={getLocalHintsForElement(t){var p,w,v;let e=((w=(p=t.tagName).toLowerCase)==null?void 0:w.call(p))||"",n=!1,o=!1,r=!1,i=[],a=[],d=null;if(e==="img"){let u=t.getAttribute("usemap");if(u){let h=t.getClientRects();u=u.replace(/^#/,"").replace(\'"\',\'\\\\"\');let m=document.querySelector(`map[name="${u}"]`);if(m&&h.length>0){n=!0;let y=m.getElementsByTagName("area"),S=f.getClientRectsForAreas(h[0],y);S=S.map(F=>Object.assign(F,{image:t})),a.push(...S)}}}let s=t.getAttribute("aria-disabled");if(s&&["","true"].includes(s.toLowerCase()))return[];if(this.checkForAngularJs||(this.checkForAngularJs=function(){if(document.getElementsByClassName("ng-scope").length===0)return()=>!1;{let h=[];for(let m of["","data-","x-"])for(let y of["-",":","_"])h.push(`${m}ng${y}click`);return function(m){for(let y of h)if(m.hasAttribute(y))return!0;return!1}}}()),n||(n=this.checkForAngularJs(t)),t.hasAttribute("onclick"))n=!0;else{let u=t.getAttribute("role"),h=["button","tab","link","checkbox","menuitem","menuitemcheckbox","menuitemradio","radio"];if(u!=null&&h.includes(u.toLowerCase()))n=!0;else{let m=t.getAttribute("contentEditable");m!=null&&["","contenteditable","true","plaintext-only"].includes(m.toLowerCase())&&(n=!0)}}if(!n&&t.hasAttribute("jsaction")){let u=t.getAttribute("jsaction").split(";");for(let h of u){let m=h.trim().split(":");if(m.length>=1&&m.length<=2){let[y,S,F]=m.length===1?["click",...m[0].trim().split("."),"_"]:[m[0],...m[1].trim().split("."),"_"];n||(n=y==="click"&&S!=="none"&&F!=="_")}}}switch(e){case"a":n=!0;break;case"textarea":n||(n=!t.disabled&&!t.readOnly);break;case"input":n||(n=!(((v=t.getAttribute("type"))==null?void 0:v.toLowerCase())=="hidden"||t.disabled||t.readOnly&&f.isSelectable(t)));break;case"button":case"select":n||(n=!t.disabled);break;case"object":case"embed":n=!0;break;case"label":n||(n=t.control!=null&&!t.control.disabled&&this.getLocalHintsForElement(t.control).length===0);break;case"body":n||(n=t===document.body&&!A()&&window.innerWidth>3&&window.innerHeight>3&&(document.body!=null?document.body.tagName.toLowerCase():void 0)!=="frameset"?d="Frame.":void 0),n||(n=t===document.body&&A()&&L.isScrollableElement(t)?d="Scroll.":void 0);break;case"img":n||(n=["zoom-in","zoom-out"].includes(t.style.cursor));break;case"div":case"ol":case"ul":n||(n=t.clientHeight<t.scrollHeight&&L.isScrollableElement(t)?d="Scroll.":void 0);break;case"details":n=!0,d="Open.";break}let l=t.getAttribute("class");!n&&(l!=null&&l.toLowerCase().includes("button"))&&(n=!0,r=!0);let c=t.getAttribute("tabindex"),b=c?parseInt(c):-1;if(!n&&!(b<0)&&!isNaN(b)&&(n=!0,o=!0),n)if(a.length>0){let u=a.map(h=>new R({element:h.element,image:t,rect:h.rect,secondClassCitizen:o,possibleFalsePositive:r,reason:d}));i.push(...u)}else{let u=f.getVisibleClientRect(t,!0);if(u!==null){let h=new R({element:t,rect:u,secondClassCitizen:o,possibleFalsePositive:r,reason:d});i.push(h)}}return i},getElementFromPoint(t,e,n,o){n==null&&(n=document),o==null&&(o=[]);let r=n.elementsFromPoint?n.elementsFromPoint(t,e)[0]:n.elementFromPoint(t,e);return o.includes(r)?r:(o.push(r),r&&r.shadowRoot?M.getElementFromPoint(t,e,r.shadowRoot,o):r)},getLocalHints(t){if(!document.body)return[];let e=(s,l)=>{l==null&&(l=[]);for(let c of Array.from(s.querySelectorAll("*")))l.push(c),c.shadowRoot&&e(c.shadowRoot,l);return l},n=e(document.body),o=[];for(let s of Array.from(n))if(!t||s.href){let l=this.getLocalHintsForElement(s);o.push(...l)}o=o.reverse();let r=[1,2,3];o=o.filter((s,l)=>{if(!s.possibleFalsePositive)return!0;let b=Math.max(0,l-6);for(;b<l;){let p=o[b].element;for(let w of r)if(p=p==null?void 0:p.parentElement,p===s.element)return!1;b+=1}return!0});let i=o.filter(s=>{if(s.secondClassCitizen)return!1;let l=s.rect,c=M.getElementFromPoint(l.left+l.width*.5,l.top+l.height*.5);if(c&&(s.element.contains(c)||c.contains(s.element))||s.element.localName=="area"&&c==s.image)return!0;let p=[l.top+.1,l.bottom-.1],w=[l.left+.1,l.right-.1];for(let v of p)for(let u of w){let h=M.getElementFromPoint(u,v);if(h&&(s.element.contains(h)||h.contains(s.element)))return!0}});i.reverse();let{top:a,left:d}=f.getViewportTopLeft();for(let s of i)s.rect.top+=a,s.rect.left+=d;return i}};var I=class{constructor(){this.hints=null;this.hintMarkers=null;this.markersDiv=null;this.enrichedMarkers=null}reset(){this.removeMarkers(),this.hints=null,this.hintMarkers=null,this.markersDiv=null}capture(){return _(this,null,function*(){this.reset(),this.createMarkers(),this.displayMarkers()})}createMarkers(){this.hints=M.getLocalHints(),this.hintMarkers=new Map,this.hints.forEach((e,n)=>{var i,a;let o=f.createElement("div"),r=(a=(i=e.element.attributes["data-momentic-id"])==null?void 0:i.value)!=null?a:void 0;if(!r){console.warn(`[Momentic] No data-momentic-id found for interactive element ${e.element.outerHTML}`);return}o.style.left=e.rect.left+"px",o.style.top=e.rect.top+"px",o.style.zIndex=214e7+n,o.className="vimiumReset internalVimiumHintMarker vimiumHintMarker",Z(o,r),this.hintMarkers.set(r,{hint:e,marker:o})})}enrichMarkers(){if(this.hintMarkers){this.enrichedMarkers=[];for(let[e,n]of this.hintMarkers)this.enrichedMarkers.push(Object.assign(O.describe(n.hint.element),{hintString:e}))}}displayMarkers(){this.hintMarkers&&(this.markersDiv||(this.markersDiv=f.addElementsToPage(Array.from(this.hintMarkers.values()).map(e=>e.marker),{id:"vimiumHintMarkerContainer",className:"vimiumReset"})))}removeMarkers(){this.markersDiv&&(f.removeElement(this.markersDiv),this.markersDiv=null)}toggleMarkers(){this.markersDiv?this.removeMarkers():this.displayMarkers()}},Z=(t,e)=>{for(let n of e){let o=document.createElement("span");o.className="vimiumReset",o.textContent=n,t.appendChild(o)}};window.HintManager=I;\n',css:'.vimiumReset,a.vimiumReset,a:hover.vimiumReset,a:link.vimiumReset,a:visited.vimiumReset,div.vimiumReset,span.vimiumReset,table.vimiumReset,td.vimiumReset,tr.vimiumReset{background:none;border:none;bottom:auto;box-shadow:none;color:#000;cursor:auto;display:inline;float:none;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:inherit;font-style:normal;font-variant:normal;font-weight:400;height:auto;left:auto;letter-spacing:0;line-height:100%;margin:0;max-height:none;max-width:none;min-height:0;min-width:0;opacity:1;padding:0;position:static;right:auto;text-align:left;text-decoration:none;text-indent:0;text-shadow:none;text-transform:none;top:auto;vertical-align:baseline;white-space:normal;width:auto;z-index:2140000000}tbody.vimiumReset,thead.vimiumReset{display:table-header-group}tbody.vimiumReset{display:table-row-group}div.internalVimiumHintMarker{background:linear-gradient(180deg,#fff785 0,#ffc542);border:1px solid #c38a22;border-radius:3px;box-shadow:0 3px 7px 0 rgba(0,0,0,.3);display:block;font-size:11px;left:-1px;overflow:hidden;padding:1px 3px 0;position:absolute;top:-1px;white-space:nowrap}div.internalVimiumHintMarker span{color:#302505;font-family:Helvetica,Arial,sans-serif;font-size:11px;font-weight:700;text-shadow:0 1px 0 hsla(0,0%,100%,.6)}div.internalVimiumHintMarker>.matchingCharacter{color:#d4ac3a}div>.vimiumActiveHintMarker span{color:#a07555!important}div.internalVimiumInputHint{background-color:rgba(255,247,133,.3);border:1px solid #c38a22;display:block;pointer-events:none;position:absolute}div.internalVimiumSelectedInputHint{background-color:hsla(0,100%,70%,.3);border:1px solid #933!important}div.internalVimiumSelectedInputHint span{color:#fff!important}div.vimiumHighlightedFrame{border:5px solid #ff0;box-sizing:border-box;margin:0;pointer-events:none}div.vimiumHighlightedFrame,iframe.vimiumHelpDialogFrame{height:100%;left:0;padding:0;position:fixed;top:0;width:100%}iframe.vimiumHelpDialogFrame{background-color:hsla(0,0%,4%,.6);border:none;display:block;z-index:2139999997}div#vimiumHelpDialogContainer{background-color:#fff;border:2px solid #b3b3b3;border-radius:6px;margin:50px auto;max-height:calc(100% - 100px);max-width:calc(100% - 100px);opacity:1;overflow-x:auto;overflow-y:auto;width:840px}div#vimiumHelpDialog{min-width:600px;padding:8px 12px}span#vimiumTitle,span#vimiumTitle *,span#vimiumTitle span{font-size:20px}#vimiumTitle{display:block;line-height:130%;white-space:nowrap}td.vimiumHelpDialogTopButtons{text-align:right;width:100%}#helpDialogOptionsPage,#helpDialogWikiPage{font-size:14px;padding-left:5px;padding-right:5px}div.vimiumColumn{float:left;font-size:11px;line-height:130%;width:50%}div.vimiumColumn tr{display:table-row}div.vimiumColumn td{display:table-cell;font-size:11px;line-height:130%}div.vimiumColumn table,div.vimiumColumn td,div.vimiumColumn tr{margin:0;padding:0}div.vimiumColumn table{table-layout:auto;width:100%}div.vimiumColumn td{padding:1px;vertical-align:top}div#vimiumHelpDialog div.vimiumColumn tr>td:first-of-type{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;text-align:right;white-space:nowrap}span.vimiumHelpDialogKey{background-color:#f3f3f3;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#212121;font-family:monospace;font-size:11px;margin-left:2px;padding:1px 4px}div#vimiumHelpDialog div.vimiumColumn tr>td:nth-of-type(3){width:100%}div#vimiumHelpDialog div.vimiumDivider{background-color:#9a9a9a;display:block;height:1px;margin:10px auto;width:100%}div#vimiumHelpDialog td.vimiumHelpSectionTitle{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:16px;font-weight:700;padding-top:3px}div#vimiumHelpDialog td.vimiumHelpDescription{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px}div#vimiumHelpDialog span.vimiumCopyCommandNameName{cursor:pointer;font-size:12px;font-style:italic}div#vimiumHelpDialog tr.advanced{display:none}div#vimiumHelpDialog.showAdvanced tr.advanced{display:table-row}div#vimiumHelpDialog div.advanced td:nth-of-type(3){color:#555}div#vimiumHelpDialog a.closeButton{color:#555;cursor:pointer;font-family:courier new;font-size:24px;font-weight:700;padding-left:5px;position:relative;text-decoration:none;top:3px}div#vimiumHelpDialog a{text-decoration:underline}div#vimiumHelpDialog a.closeButton:hover{color:#000;-webkit-user-select:none}div#vimiumHelpDialogFooter{display:block;margin-bottom:37px;position:relative}table.helpDialogBottom{width:100%}td.helpDialogBottomRight{float:right;text-align:right;width:100%}td.helpDialogBottomLeft,td.helpDialogBottomRight{padding:0}div#vimiumHelpDialogFooter *{font-size:10px}a#toggleAdvancedCommands,span#help-dialog-tip{font-size:10px;position:relative;top:19px;white-space:nowrap}a#toggleAdvancedCommands,a:active.vimiumHelDialogLink,a:hover.vimiumHelDialogLink,a:link.vimiumHelDialogLink,a:visited.vimiumHelDialogLink{color:#2f508e;cursor:pointer;text-decoration:underline}div.vimiumHUD{background:#f1f1f1;border:1px solid #aaa;border-radius:4px;bottom:8px;box-shadow:0 2px 10px rgba(0,0,0,.8);display:block;left:8px;position:fixed;text-align:left;width:calc(100% - 20px);z-index:2139999999}iframe.vimiumHUDFrame{background-color:transparent;border:none;bottom:-14px;display:block;height:58px;margin:0 0 0 -40%;min-width:300px;opacity:0;overflow:hidden;padding:0;position:fixed;right:20px;width:20%;z-index:2139999998}div.vimiumHUD .vimiumHUDSearchArea{background-color:#f1f1f1;border-radius:4px 4px 0 0;display:block;padding:3px}div.vimiumHUD .vimiumHUDSearchAreaInner{border-radius:3px;box-sizing:border-box;color:#777;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;height:30px;line-height:20px;margin-bottom:0;outline:none;padding:2px 4px;width:100%}div.vimiumHUD .hud-find{background:#fff;border:1px solid #ccc}div.vimiumHUD span#hud-find-input,div.vimiumHUD span#hud-match-count{color:#000;display:inline;outline:none;overflow-y:hidden;white-space:nowrap}div.vimiumHUD span#hud-find-input:before{content:"/"}div.vimiumHUD span#hud-match-count{color:#aaa;font-size:12px}div.vimiumHUD span#hud-find-input br{display:none}div.vimiumHUD span#hud-find-input *{display:inline;white-space:nowrap}body.vimiumFindMode ::selection{background:#ff9632}iframe.vomnibarFrame{background-color:transparent;border:none;display:block;font-family:sans-serif;height:calc(100% - 70px);left:50%;margin:0 0 0 -40%;min-width:400px;overflow:hidden;padding:0;position:fixed;top:70px;width:calc(80% + 20px);z-index:2139999998}div.vimiumFlash{background-color:transparent;box-shadow:0 0 4px 2px #4183c4;padding:1px;position:absolute;z-index:2140000000}iframe.vimiumUIComponentHidden{display:none}iframe.vimiumUIComponentVisible{color-scheme:light dark;display:block}iframe.vimiumUIComponentReactivated{border:5px solid #ff0}iframe.vimiumNonClickable{pointer-events:none}@media (prefers-color-scheme:dark){iframe.reverseDarkReaderFilter{-webkit-filter:invert(100%) hue-rotate(180deg)!important;filter:invert(100%) hue-rotate(180deg)!important}body.vimiumBody{background-color:#292a2d;color:#fff}body.vimiumBody a,body.vimiumBody a:visited{color:#8ab4f8}body.vimiumBody input,body.vimiumBody textarea{background-color:#1d1d1f;border-color:#1d1d1f;color:#e8eaed}body.vimiumBody div.example{color:#9aa0a6}body.vimiumBody div#footer,body.vimiumBody div#state,div#vimiumHelpDialogContainer{background-color:#202124;border-color:hsla(0,0%,100%,.1)}div#vimiumHelpDialog{background-color:#292a2d;color:#fff}div#vimiumHelpDialog td.vimiumHelpDescription{color:#c9cccf}div#vimiumHelpDialog td.vimiumHelpSectionTitle,span#vimiumTitle{color:#fff}#vimiumTitle>span:first-child{color:#8ab4f8!important}div#vimiumHelpDialog a{color:#8ab4f8}div#vimiumHelpDialog div.vimiumDivider{background-color:hsla(0,0%,100%,.1)}span.vimiumHelpDialogKey{background-color:#1d1d1f;border:1px solid #000;box-shadow:none;color:#fff}}',htmlJs:'var c=["html","head","title","meta","iframe","script","style","path","svg","br","::marker","noscript"],u=["data-momentic-id","aria-keyshortcuts"],d=[/data-.*/,/aria-.*/],f=["name","id","text","value","type","class","focusable","height","width","placeholder","target","aria-label","type","title","href","src","alt","role","headers","scope"],m=["relative","flex","center","justify","auto","sticky","absolute","top","right","left","bottom"];function h(e){let t=document.createElement("textarea");return t.innerHTML=e,t.value}function g(e){let t=e.trim().split(" ");for(let r of t)if(!(r.length<=4)&&!m.some(s=>r.includes(s)))return r;return""}function o(e){var t;return!!(e.nodeType!==Node.ELEMENT_NODE||(t=e.textContent)!=null&&t.trim()||e.getAttributeNames().length>1||e.getAttributeNames().length===1&&!e.getAttribute("class"))}function b(e){return c.includes(e.tagName.toLowerCase())?!0:!o(e)&&e.childNodes.length===0}function N(e){let t=e.getAttributeNames();for(let r of t){if(u.includes(r)){e.removeAttribute(r);continue}switch(r){case"class":{let s=g(e.getAttribute("class"));s?e.setAttribute(r,s):e.removeAttribute(r);break}case"src":{let s=e.getAttribute(r);s!=null&&s.startsWith("data:")&&e.setAttribute(r,`${s.split(";")[0]};TRUNCATED`);break}default:{!f.includes(r)&&!d.some(n=>r.match(n))&&e.removeAttribute(r);let s=e.getAttribute(r);s!=null&&s.includes("&")&&e.setAttribute(r,h(s))}}}return e}function a(e){if(e.nodeType===Node.TEXT_NODE)return e;if(e.nodeType!==Node.ELEMENT_NODE)return!1;let t=N(e);if(b(t))return!1;let r=[...t.childNodes];for(let n=0;n<r.length;n++){let i=r[n],l=a(i);l?t.replaceChild(l,i):(t.removeChild(i),i.remove())}let s=o(t);return!s&&t.childNodes.length===0?!1:!s&&t.childNodes.length===1?t.childNodes[0]:t}function E(){let e=document.body.cloneNode(!0),t=a(e);if(!t)return"";let r=[];for(let s=0;s<t.childNodes.length;s++){let n=t.childNodes[s];n.parentNode||r.push(n)}for(let s=0;s<r.length;s++)t.removeChild(r[s]);return t.outerHTML}window.getHTMLBodyString=E;\n'};var Pe=(r,e)=>{let{hostname:t,pathname:n}=new URL(r),{hostname:o,pathname:s}=new URL(e);return t!==o||n!==s},cr=r=>{try{return new URL(r),!0}catch{return!1}},dr=(r,e)=>{try{return new URL(r,e),!0}catch{return!1}};import{distance as ur}from"fastest-levenshtein";var _o=new Set(["about:blank","chrome-error://chromewebdata/"]),ko=3,qe="data-momentic-id";var vi=["focusable","keyshortcuts","controls"],Ai=["textbox","checkbox","combobox","button","link","list","listitem","tablist","tabpanel","tab","searchbox","menu","menubar","form","dialog","alertdialog","banner","navigation","main","menuitem","menuitemcheckbox","menuitemradio","option","radio","progressbar","switch"],Ei=["notRendered","notVisible","ariaHiddenElement","ariaHiddenSubtree"],Ti=80,Ci={paragraph:"p",searchbox:"input",LineBreak:"br"},fr=["paragraph","StaticText","ListMarker","RootWebArea","LineBreak"],zo={indentLevel:0,noID:!1,noChildren:!1,noProperties:!1,maxLevel:void 0,neighbors:void 0},pr=class{id;role;name;content;properties;dataMomenticId;pathFromRoot;parent;children;backendNodeID;ignoredByCDP;constructor(e){this.id=e.id,this.role=e.role,this.name=e.name,this.content=e.content,this.properties={},this.pathFromRoot=e.pathFromRoot,this.children=e.children,this.backendNodeID=e.backendNodeID,this.ignoredByCDP=e.ignoredByCDP,e.properties&&e.properties.forEach(t=>{t.name==="keyshortcuts"?this.dataMomenticId=parseInt(t.value.value):this.properties[t.name]=t.value.value})}getLogForm(){return JSON.stringify({id:this.id,name:this.name??"",role:this.role??"",backendNodeId:this.backendNodeID})}isInteresting(){return Ai.includes(this.role)||this.properties.focusable||this.properties.settable||this.children.some(e=>e.role==="StaticText")?!0:!!this.name.trim()||!!this.content}serialize(e=zo){let{indentLevel:t,noChildren:n,noProperties:o,noID:s}=Object.assign({},zo,e),a=" ".repeat(t),i=Ci[this.role]||this.role,l=this.name,c={...this.properties};i==="heading"&&l==="heading"&&(l="");let d=!fr.includes(this.role);if(this.role==="StaticText")return`${a}${l}
|
|
17
|
+
`;let m=`${a}<${i}`;!s&&d&&(m+=` id="${this.id}"`),l&&(m+=` name=${JSON.stringify(l)}`),this.content&&(m+=` content=${JSON.stringify(this.content)}`),Object.keys(this.properties).length>0&&!o&&Object.entries(this.properties).forEach(([h,p])=>{vi.includes(h)||(typeof p=="string"?m+=` ${h}="${p}"`:typeof p=="boolean"?p?m+=` ${h}`:m+=` ${h}={false}`:typeof p<"u"&&(m+=` ${h}={${JSON.stringify(p)}}`))});let f=e.maxLevel!==void 0&&t/2>=e.maxLevel;if(this.children.length===0||n||f)m+=` />
|
|
18
|
+
`;else{let h="";for(let y of this.children)h+=y.serialize({...e,indentLevel:t+2,neighbors:0});let p=h.trim();p.length<=Ti&&!p.includes(`
|
|
19
|
+
`)?m+=`>${p}</${i}>
|
|
20
20
|
`:m+=`>
|
|
21
|
-
${h}${
|
|
22
|
-
`}if(e.neighbors!==void 0&&e.neighbors>0&&this.parent){let h=this.parent.children.findIndex(
|
|
21
|
+
${h}${a}</${i}>
|
|
22
|
+
`}if(e.neighbors!==void 0&&e.neighbors>0&&this.parent){let h=this.parent.children.findIndex(S=>S.id===this.id),p=h>0?this.parent.children[h-1]?.serialize({...e,neighbors:0}):"",y=h<this.parent.children.length-1?this.parent.children[h+1]?.serialize({...e,neighbors:0}):"";return`${p||""}
|
|
23
23
|
${m}
|
|
24
|
-
${g||""}`}return m}},dr=class{constructor(e,t,n){this.root=e;this.a11yIdNodeMap=t;this.dataMomenticIdMap=n}serialize(){return this.root?this.root.serialize():""}};function wi(r){return r.name?.value?`"${r.name.value}"`:r.role?.value&&r.role.value!=="none"&&r.role.value!=="generic"?`"${r.role.value}"`:`"${r.nodeId}"`}function Do(r,e,t){if(!e&&r.parentId)throw new Error(`Got no parent for accessibility node ${r.nodeId}: ${JSON.stringify(r)}`);let n=new cr({id:parseInt(r.nodeId),role:r.role?.value||"",name:r.name?.value?typeof r.name.value=="string"?r.name.value:`${r.name.value}`:"",content:r.value?.value?typeof r.value.value=="string"?r.value.value:`${r.value.value}`:"",properties:r.properties,children:[],pathFromRoot:(e?`${e.pathFromRoot} `:"")+wi(r),backendNodeID:r.backendDOMNodeId,ignoredByCDP:r.ignored}),o=r.childIds??[];for(let a of o){if(!a)continue;let l=t.get(parseInt(a));if(!l)continue;let c=Do(l,n,t);c.length&&(n.children=n.children.concat(c))}if(n.role==="StaticText"&&(n.children=[]),n.children.length===1&&n.children[0].role==="StaticText"){let a=n.name,l=n.children[0]?.name;(a===l||!l)&&(n.children=[])}let s=[];for(let a=n.children.length-1;a>=0;a--){let l=n.children[a];if(l.role!=="StaticText"){s.push(l);continue}if(a===0||n.children[a-1].role!=="StaticText"){s.push(l);continue}n.children[a-1].name+=` ${l.name}`}if(n.children=s.reverse(),n.role==="generic"&&n.children.length===1){let a=n.children[0];if(n.name&&!mr.includes(a.role)&&n.name===a.name)return n.children}if(!n.isInteresting()&&r.parentId)return n.children;for(let a of n.children)a.parent=n;return[n]}function _o(r,e,t,n,o=1){r.id=o,o+=1,e.set(r.id,r),r.dataMomenticId?t.set(r.dataMomenticId,r):mr.includes(r.role)||n.debug({node:r.serialize({neighbors:1,maxLevel:1})},"Node has no data-momentic-id");for(let s of r.children)o=_o(s,e,t,n,o);return o}function ko(r,e){if(!r.root)throw new Error("a11y tree has null root");r.allNodes=r.allNodes.filter(i=>i.ignored?!i.ignoredReasons?.find(l=>gi.includes(l.name)):!0);let t=new Map;for(let i of r.allNodes)t.set(parseInt(i.nodeId),i);let n=Do(r.root,null,t);if(n.length>1)throw new Error(`Something went horribly wrong processing the a11y tree, we got: ${JSON.stringify(n)}`);if(n.length===0)throw new mt;let o=new Map,s=new Map;return _o(n[0],o,s,e),new dr(n[0],o,s)}var rt=(r,e)=>{e.id=r.id,e.content=r.content,e.name=r.name,e.role=r.role,e.numChildren=r.children.length,e.serializedForm=r.serialize({noID:!0,maxLevel:1,neighbors:1}),e.nodeOnlySerializedForm=r.serialize({noID:!0,noChildren:!0,noProperties:!0})},ur=(r,e)=>{let t=1;r.role===e.role&&t++;let n=["name","content"];for(let o of n){let s=r[o];if(typeof s!="string"||!s.trim())continue;let i=lr(s,e[o])/Math.min(s.length,e[o].length);i===0?t+=2:i<=.1&&t++}if(e.numChildren!==void 0&&(r.children.length===e.numChildren&&e.numChildren>0?t++:(e.numChildren>0&&r.children.length===0||Math.abs(r.children.length-e.numChildren)>2)&&t--),e.nodeOnlySerializedForm){let o=r.serialize({noID:!0,noChildren:!0,noProperties:!0});lr(o,e.nodeOnlySerializedForm)/Math.min(o.length,e.nodeOnlySerializedForm.length)<=.1&&t++}if(e.serializedForm){let o=r.serialize({noID:!0,maxLevel:1,neighbors:1}),s=lr(o,e.serializedForm)/Math.min(o.length,e.serializedForm.length);s===0?t+=2:s<=.1&&t++}return t};var Ne={r:147,g:196,b:125,a:.55},Fo={showInfo:!1,showRulers:!1,showStyles:!1,showAccessibilityInfo:!1,showExtensionLines:!1,contrastAlgorithm:"aa",contentColor:Ne,paddingColor:Ne,borderColor:Ne,marginColor:Ne,eventTargetColor:Ne,shapeColor:Ne,shapeMarginColor:Ne};var B=(r=1e3)=>new Promise(e=>setTimeout(()=>e(),r));function zo(){window.cursor||(window.cursor=document.createElement("img"),window.cursor.setAttribute("src","data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjMyIiB2aWV3Qm94PSIwIDAgMzIgMzIiIHdpZHRoPSIzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEwIDcpIj48cGF0aCBkPSJtNi4xNDggMTguNDczIDEuODYzLTEuMDAzIDEuNjE1LS44MzktMi41NjgtNC44MTZoNC4zMzJsLTExLjM3OS0xMS40MDh2MTYuMDE1bDMuMzE2LTMuMjIxeiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Im02LjQzMSAxNyAxLjc2NS0uOTQxLTIuNzc1LTUuMjAyaDMuNjA0bC04LjAyNS04LjA0M3YxMS4xODhsMi41My0yLjQ0MnoiIGZpbGw9IiMwMDAiLz48L2c+PC9zdmc+"),window.cursor.setAttribute("id","momentic_cursor"),window.cursor.setAttribute("style","position: absolute; z-index: 99999999999; pointer-events: none; left:0; top:0; height:4%;"),window.cursor.style.filter="invert(0%) sepia(6%) saturate(24%) hue-rotate(315deg) brightness(89%) contrast(110%)",document.body.appendChild(cursor),document.onmousemove=function(r){r=r||window.event,document.getElementById("momentic_cursor").style.left=r.pageX+"px",document.getElementById("momentic_cursor").style.top=r.pageY+"px"})}function Uo(){window.globalHintManager||(window.globalHintManager=new window.HintManager),window.globalHintManager.capture()}function $o(){window.globalHintManager&&window.globalHintManager.reset()}function Ho(){let r=document.body.getElementsByTagName("*"),e=1;for(let t=0;t<r.length;t++){let n=e.toString();for(;[6].some(s=>n.includes(s.toString()));)e++,n=e.toString();let o=r[t];o?.setAttribute("data-momentic-id",`${e}`),o?.setAttribute("aria-keyshortcuts",`${e}`),e++}}var bi=new Set(["document","script","XMLHttpRequest","fetch","xhr"]),vi=new Set(["script","document"]),Ai=["intercom.io","googletagmanager.com","google-analytics.com","www.gstatic.com","gstatic.com","apis.google.com","sentry.io","newrelic.com","p.retool.com","m.stripe.com","m.stripe.network","js.stripe.com","assets.trybento.co","udon.trybento.co","cdn.lr-in-prod.com","r.lr-in-prod.com","content.product-usage.assembledhq.com","data.product-usage.assembledhq.com","static.zdassets.com","o.clarity.ms/collect"],Ei=["api.stripe.com","supabase.co"],Ti=[];async function jo(r){for(let e of Ti)await r.route(e,t=>t.abort())}function pr(r){return`${r.resourceType()} ${r.method()} ${r.url()}`}function Bo(r){return r=r.replace(/^www\./,""),r}function Go(r){return Ei.some(e=>r.includes(e))}function Vo(r,e){if(!bi.has(r.resourceType()))return!1;let t=new URL(e),n=new URL(r.url());return Ai.some(o=>n.hostname.includes(o))?!1:vi.has(r.resourceType())||r.method()!=="GET"?!0:Bo(n.hostname).includes(Bo(t.hostname))}var Wo=()=>{window.clickListener&&document.removeEventListener("click",window.clickListener,{capture:!0}),window.clickListener=async r=>{console.log("[Momentic] Window click listener fired",r.target),await window.captureClick(r.target)},document.addEventListener("click",window.clickListener,{capture:!0})};var Ko=()=>{window.pressListener&&document.removeEventListener("keydown",window.pressListener,{capture:!0}),window.pressListener=async r=>{console.log("[Momentic] Window press listener fired"),await window.captureKeystroke({key:r.key})},document.addEventListener("keydown",window.pressListener,{capture:!0})};var Rt=$i(Ui);Rt.use(Bi());Rt.use(Hi({provider:{id:"2captcha",token:process.env.TWO_CAPTCHA_KEY},visualFeedback:!0}));var M=class r{browser;context;page;a11yIdToNodeMap=new Map;dataMomenticIdToNodeMap=new Map;cdpClient;logger;localMode;activeFrame;transformer;mostRecentBrowserState;baseURL;constructor({browser:e,context:t,page:n,baseUrl:o,logger:s,localMode:i,cdpClient:a}){this.browser=e,this.context=t,this.cdpClient=a,this.page=n,this.baseURL=o,this.logger=s,this.localMode=!!i}static USER_AGENT=Jo["Desktop Chrome"].userAgent;static VIEWPORT={width:1920,height:1080};static async init({baseUrl:e,logger:t,browserArgs:n,contextArgs:o,takeScreenshots:s,onScreenshot:i,onClose:a,waitForLoad:l,localMode:c,localAppUrl:d,extensionPath:m,skipPageSetup:p,timeout:h=8e3}){let f={headless:!0,handleSIGTERM:!1,chromiumSandbox:!1,...n??{}},g={viewport:r.VIEWPORT,deviceScaleFactor:process.platform==="darwin"?2:1,userAgent:Jo["Desktop Chrome"].userAgent,geolocation:{latitude:37.7749,longitude:-122.4194},locale:"en-US",timezoneId:"America/Los_Angeles",...o??{}},A=null,w,y;if(c){let F=zi(Fi(),"momentic","chromium");w=await Rt.launchPersistentContext(F,{...f,...g,ignoreDefaultArgs:["--enable-automation","--enable-strict-mixed-content-checking"],ignoreHTTPSErrors:!0,bypassCSP:!0,args:["--allow-insecure-localhost","--disable-site-isolation-for-policy","--disable-site-isolation-trials",`--unsafely-treat-insecure-origin-as-secure=${d}`,`--load-extension=${m}`,"--test-type=browser"],baseURL:e}),y=w.pages()[0],a&&y.on("close",()=>{a()})}else A=await Rt.launch(f),w=await A.newContext({...g,baseURL:e}),y=await w.newPage();await jo(w);let I=new r({browser:A,context:w,page:y,baseUrl:e,logger:t,localMode:c,cdpClient:await w.newCDPSession(y)}),v=!1,E=async()=>{try{await I.navigate({url:e,wrapPossibleNavigation:!1,initialNavigation:!p,timeout:h})}catch(F){if(t.error({err:F},"Failed to initialize chrome browser"),l)throw F}finally{v=!0}};if(l?await E():E(),i){let F=async()=>{if(s)try{i({viewport:await I.viewport(),buffer:await I.screenshot({})})}catch(He){t.error({err:He},"Failed to take screenshot")}};F();let $e=setInterval(()=>{F()},400),z=Date.now();for(;!v&&Date.now()-z<(h??1/0);)await B(250);clearInterval($e)}return I}async getUserPageOrFrame(){if(this.localMode&&this.activeFrame){let e=null,t=0;for(;!e&&t<5;)e=this.page.frame(this.activeFrame),await B(100),t++;if(!e)throw new T("InternalWebAgentError",`Failed to find frame ${this.activeFrame} on page ${this.page.url()}`);return e}return this.page}async initCDPSession(e=3e3){let t=!1,n=e===null?1/0:2,o=async()=>{try{this.cdpClient=await this.context.newCDPSession(this.page),await this.cdpClient.send("Accessibility.enable"),await this.cdpClient.send("DOM.enable"),await this.cdpClient.send("Overlay.enable"),t=!0}catch(s){if(n>0)return this.logger.warn({err:s},"Failed to initialize CDP session, re-creating CDP client"),await B(250),n--,o();throw s}};return e===null?await o():await Promise.race([o(),B(e)]),t}setLogger(e){this.logger=e}ping(){if(this.closed)throw new Error("Page has been closed");if(this.browser&&!this.browser.isConnected())throw new Error("Browser is not connected")}setActiveFrame(e){this.activeFrame=e}async reset(e){this.a11yIdToNodeMap.clear(),this.dataMomenticIdToNodeMap.clear();let t=this.context.pages();this.page=t[0];for(let n=1;n<t.length;n++)await t[n].close();if(e.clearCookies&&await this.context.clearCookies(),!this.page.isClosed()){if(e.clearStorage)try{await(await this.getUserPageOrFrame()).evaluate(async()=>{window.localStorage.clear(),window.sessionStorage.clear(),await indexedDB.databases().then(n=>{n.forEach(o=>{o.name&&indexedDB.deleteDatabase(o.name)})})})}catch(n){this.logger.warn({err:n},"Failed clearing site data, continuing...")}await this.navigate({url:e.url??this.baseURL,wrapPossibleNavigation:!1,initialNavigation:!0,timeout:e.timeout})}}async pageSetup(){try{this.localMode||await this.page.evaluate(zo)}catch{}}async wait(e){await B(e)}async toggleHints(e){let t=await this.getUserPageOrFrame();e.state==="on"?(await t.addStyleTag({content:Tt.css}),await t.addScriptTag({content:Tt.js}),await t.evaluate(Uo)):await t.evaluate($o)}async showHints(){await this.toggleHints({state:"on"});let e=async()=>{try{await this.toggleHints({state:"off"})}catch(t){this.logger.debug({err:t},"Failed to remove vision hints")}};setTimeout(()=>{e()},3e3)}async cleanup(){await this.page.close(),await this.context.close(),this.browser&&await this.browser.close()}get closed(){return this.page.isClosed()||!!this.browser&&!this.browser.isConnected()}async html(){return(await this.getUserPageOrFrame()).content()}async url(){return(await this.getUserPageOrFrame()).url()}async screenshotWithHints({target:e,quality:t=100,scale:n="device",saveToDiskPath:o}){let s=o?.split("."),i=s?.slice(0,-1).join("."),a=s?.slice(-1)[0],l=Buffer.from("");await this.showHints();let c=await this.screenshot({target:e,quality:t,scale:n,saveToDiskPath:o?`${i}-after-hint.${a}`:void 0});return{before:l,after:c}}async screenshot({target:e,quality:t,scale:n,saveToDiskPath:o,hideCaret:s}){let i={fullPage:!1,quality:t,scale:n,type:"jpeg",caret:s?"hide":"initial",path:o};if(e){let a=await this.resolveCachedTargetToNode(e);return(await this.getLocatorFromA11yNode(a)).screenshot(i)}else return!this.localMode||!this.activeFrame?this.page.screenshot(i):this.page.locator(`iframe[name="${this.activeFrame}"]`).screenshot(i)}async viewport(){if(this.localMode&&this.activeFrame){let t=await this.page.locator(`iframe[name="${this.activeFrame}"]`).boundingBox();if(!t)throw new Error(`Failed to get bounding box for frame: ${this.activeFrame}`);return t}let e=this.page.viewportSize();if(!e)throw new Error("failed to get viewport");return e}async navigate({url:e,wrapPossibleNavigation:t=!0,initialNavigation:n=!1,timeout:o=8e3}){this.logger.debug(`Navigating to ${e}`);let s=Date.now(),i=async()=>{try{await(await this.getUserPageOrFrame()).goto(e,{waitUntil:"load",timeout:o??void 0}),this.logger.debug({url:e},`Got load event in ${Math.floor(Date.now()-s)}ms`)}catch(l){if(l instanceof Error&&l.message.includes("ERR_ABORTED"))return;this.logger.warn({url:e,err:l},"Timeout elapsed waiting for page to fire load event. Are you sure this page is accessible?")}};t?await this.wrapPossibleNavigation(i):await i();let a=await this.url();if(Oo.has(a)&&process.env.NODE_ENV==="production")throw new T("ActionFailureError",`${e} took too long to load \u{1F61E}. Please ensure the site and your internet are working.`,{},!0);if(n){if(!await this.initCDPSession(o))throw new T("ActionFailureError",`Initializing libraries timed out on ${e} \u{1F61E}. Please ensure the site and your internet are working.`,{},!0);if(await this.pageSetup(),await this.attachPageLoadListeners(),this.localMode)try{await this.exposeRecordingBindings()}catch(c){c instanceof Error&&c.message.includes("already registered")||this.logger.error({err:c},"Failed to expose recording bindings during navigation")}}this.logger.info({url:e},"Navigation complete")}async type(e,t={}){let{clearContent:n=!0,pressKeysSequentially:o=!1}=t;n&&(process.platform==="darwin"?await this.page.keyboard.press("Meta+A"):await this.page.keyboard.press("Control+A"),await this.page.keyboard.press("Backspace")),o?await this.page.keyboard.type(e):await this.page.keyboard.insertText(e)}async clickByA11yID(e,t={}){let n=this.a11yIdToNodeMap.get(e);if(!n)throw new Error(`Could not find DOM node during click: ${e}`);let o=await this.clickUsingCDP(n,t);return await this.highlightNode(o.id),n.serialize({noChildren:!0,noID:!0})}async selectOptionByA11yId(e,t){let n=this.a11yIdToNodeMap.get(e);if(!n)throw new Error(`Could not find DOM node while selecting option: ${e}`);return await(await this.getLocatorFromA11yNode(n)).selectOption(t,{timeout:8e3}),await this.highlightNode(n.id),n.serialize({noChildren:!0,noID:!0})}async scrollIntoView(e){let t=await this.resolveCachedTargetToNode(e);await(await this.getLocatorFromA11yNode(t)).scrollIntoViewIfNeeded({timeout:8e3})}async highlight(e){try{let t=await this.resolveCachedTargetToNode(e);await this.highlightNode(t.id)}catch(t){this.logger.warn({err:t,target:e},"Failed to highlight target")}}async highlightNode(e){let t;try{if(t=this.a11yIdToNodeMap.get(e),!t)throw new Error(`Could not find DOM node during highlight: ${e}`);await this.cdpClient.send("Overlay.highlightNode",{highlightConfig:Fo,backendNodeId:t.backendNodeID})}catch{this.logger.warn("Failed to add node highlight, a page navigation likely occurred. This is non-fatal for tests.");return}let n=async()=>{try{await this.cdpClient.send("Overlay.hideHighlight",{backendNodeId:t.backendNodeID})}catch(o){this.logger.debug({err:o},"Failed to remove node highlight")}};setTimeout(()=>{n()},3e3)}async wrapPossibleNavigation(e,t=8e3,n=!0){let o=Date.now(),s=await this.url(),i=Date.now(),a=new Map,l=new Map,c=v=>{let E=pr(v.request());l.set(E,(l.get(E)??0)+1);let F=v.status();F>=500&&this.logger.warn({request:E,status:F},"Received 500 level response")},d=v=>{if(!Vo(v,s))return;let E=pr(v);a.set(E,(a.get(E)??0)+1),i=Date.now()};this.page.on("response",c),this.page.on("request",d);let m=[];n&&(m=this.context.pages().map(v=>v.url()));let p=!1,h=e().catch(v=>(p=!0,v instanceof Error?v:new Error(`${v}`)));await B(250);let f=async v=>{let E=await v;if(E instanceof Error)throw E;return E},g=new Set,A=!1,y=await(async()=>{for(;!p&&!(!A&&Date.now()-o>t);){if(await B(250),A=!1,g=new Set,Date.now()-i<=1250)continue;let v=!1;for(let E of a.keys())a.get(E)!==l.get(E)&&(Go(E)&&(A=!0),v=!0,g.add(E));if(!v)return this.logger.debug({url:await this.url(),requests:JSON.stringify(Array.from(a.entries()))},`Network idle in ${Math.floor(Date.now()-o)}ms`),!0}return!p&&g.size>0&&this.logger.warn({url:await this.url(),unfinishedRequests:JSON.stringify(Array.from(g.entries()))},"Timeout elapsed waiting for network idle, continuing anyways..."),!1})();if(this.page.off("response",c),this.page.off("request",d),!y)return f(h);let I=await this.url();if(!p&&Me(I,s)){this.logger.debug({startUrl:s,newUrl:I},"Detected url change in wrapPossibleNavigation, waiting for load state");let v=Math.max(t-(Date.now()-o),0);if(v>0)try{await(await this.getUserPageOrFrame()).waitForLoadState("load",{timeout:v})}catch{this.logger.warn({url:await this.url()},"Timeout elapsed waiting for load state, continuing anyways...")}}if(n){let v=this.context.pages().map(E=>E.url());if(v.length>m.length)for(let E of v)E!==I&&await this.switchToPage(E)}return f(h)}async resolveCachedTargetToNode(e){if(!ct(e)){let a=this.a11yIdToNodeMap.get(e.id);if(!a)throw new Error(`Resolving target failed, fresh value did not exist in node map: ${e.id}`);return rt(a,e),a}let t=(await this.getA11yTree()).serialize();this.logger.debug({tree:t},"Refreshed a11y tree before resolving target");let n=this.a11yIdToNodeMap.get(e.id);if(n){let a=ur(n,e);if(a>=5)return this.logger.debug({target:e,proposedNode:n.getLogForm(),comparisonScore:a},"Resolved cached a11y target to node with exact same id"),rt(n,e),n}let o=1/0,s=1/0,i;for(let a of this.a11yIdToNodeMap.values()){let l=ur(a,e);if(l>=5)return this.logger.debug({newNode:a.getLogForm(),target:e,comparisonScore:l},"Resolved cached a11y target to new node with field comparison"),rt(a,e),a;if(!e.serializedForm)continue;let c=a.serialize({noID:!0,maxLevel:1,neighbors:1});if(Math.abs(c.length-e.serializedForm.length)>15)continue;let d=_i(e.serializedForm,c),m=d/Math.min(e.serializedForm.length,c.length);d<o&&m<.2&&(o=d,s=m,i=a)}if(i&&o<15)return this.logger.debug({newNode:i.getLogForm(),target:e,distance:o,ratio:s},"Resolved cached a11y target to new node with pure levenshtein distance"),rt(i,e),i;throw new Error(`Could not find any relevant node given cached target: ${JSON.stringify({target:e,closestLevenshteinDistance:o,closestNode:i})}`)}async click(e,t={}){let n=await this.resolveCachedTargetToNode(e);return await this.wrapPossibleNavigation(()=>this.clickByA11yID(n.id,t))}async dragAndDrop(e,t,n={}){let o=await this.resolveCachedTargetToNode(e),s=await this.getLocatorFromA11yNode(o),i=await this.resolveCachedTargetToNode(t),a=await this.getLocatorFromA11yNode(i);return await s.hover(n),await this.page.mouse.down(),await a.hover(n),await B(250),await this.page.mouse.up(),o.serialize({noChildren:!0,noID:!0})}async hover(e){let t=await this.resolveCachedTargetToNode(e);return await(await this.getLocatorFromA11yNode(t)).hover({timeout:8e3}),await this.highlightNode(t.id),t.serialize({noChildren:!0,noID:!0})}async selectOption(e,t){let n=await this.resolveCachedTargetToNode(e);return this.selectOptionByA11yId(n.id,t)}async press(e){await this.wrapPossibleNavigation(()=>this.page.keyboard.press(e))}async refresh(){if(this.localMode&&this.activeFrame){let t=(await this.getUserPageOrFrame()).url();await this.navigate({url:t,wrapPossibleNavigation:!0})}else try{await this.page.reload({timeout:3e3})}catch{this.logger.warn({url:await this.url()},"Timeout elapsed waiting for page on reload, continuing anyways...")}}async getA11yTree(e=!1){let t=null,n=async()=>{let o=0,s=await this.url();for(;!t&&o<3;)try{let i=await this.getRawA11yTree(e);if(!i.root||i.allNodes.length<=1)throw new Error("No a11y tree found on page");t=ko(i,this.logger)}catch(i){if(this.logger.error({err:i,url:s},"Error fetching a11y tree"),o===0)await B(1e3),o++;else throw new Error(`Max retries exceeded fetching a11y tree: ${i}`)}if(!t||!t.root)throw new Error("Accessibility tree appears empty");this.a11yIdToNodeMap=t.a11yIdNodeMap,this.dataMomenticIdToNodeMap=t.dataMomenticIdMap};if(await Promise.race([n(),B(8e3)]),t)return t;throw new T("ActionFailureError",`Getting accessibility tree timed out after ${8e3}ms`)}getA11yIdFromDataMomenticId(e){return this.dataMomenticIdToNodeMap.get(e)?.id}async getRawA11yTree(e=!1){let t=await this.url(),n=Date.now(),o=()=>{n=Date.now()};this.cdpClient.addListener("Accessibility.nodesUpdated",o);let s=!1,i=()=>{this.logger.info({url:t},"Load event fired on page"),s=!0,n=Date.now()};this.cdpClient.addListener("Accessibility.loadComplete",i);let a=Date.now(),l=!e;for(;!e&&Date.now()-a<3e3;){if(await B(250),!s&&Date.now()-a<1e3){process.env.NODE_ENV!=="production"&&this.logger.debug({url:t},"A11y tree not loaded yet, waiting...");continue}if(Date.now()-n>=1250){l=!1;break}this.logger.debug({url:t},"A11y tree not stable yet, waiting...")}this.logger.debug({duration:Date.now()-a,eventReceived:s,timeoutTriggered:l,skipWait:e},"A11y wait phase completed"),await(await this.getUserPageOrFrame()).evaluate(Ho);let c;if(this.localMode&&this.activeFrame){let{result:{objectId:m}}=await this.cdpClient.send("Runtime.evaluate",{expression:`document.querySelector("#${this.activeFrame}")`}),p=await this.cdpClient.send("DOM.describeNode",{objectId:m});c=(await this.cdpClient.send("Accessibility.getRootAXNode",{frameId:p.node.frameId})).node.backendDOMNodeId}else{let{node:m}=await this.cdpClient.send("Accessibility.getRootAXNode");c=m.backendDOMNodeId}let{nodes:d}=await this.cdpClient.send("Accessibility.queryAXTree",{backendNodeId:c});return this.cdpClient.removeListener("Accessibility.loadComplete",i),this.cdpClient.removeListener("Accessibility.nodesUpdated",o),{root:d[0],allNodes:d}}async clickUsingVisualCoordinates(e){let t=await this.getElementLocation(e);if(!t)throw new Error(`Could not find element location with backend node id: ${e}`);this.logger.debug({location:t},"Executing mouse click"),await this.page.mouse.click(t.centerX,t.centerY)}async getIDAttributeUsingCDP(e){await this.cdpClient.send("DOM.getDocument",{depth:0});let t=await this.cdpClient.send("DOM.requestNode",{objectId:e}),o=(await this.cdpClient.send("DOM.getAttributes",{nodeId:t.nodeId})).attributes,s=o.findIndex(i=>i===We);if(s===-1||!o[s+1])throw new Error(`Could not find ${We} for object ${e}`);return o[s+1]}async getLocatorFromA11yNode(e){if(!e.backendNodeID)throw new Error(`Node with a11y id ${e.id} has no backend node ID`);return this.getLocatorFromBackendID(e.backendNodeID)}async getLocatorFromBackendID(e){let t=await this.cdpClient.send("DOM.resolveNode",{backendNodeId:e});if(!t||!t.object.objectId)throw new Error(`Could not resolve backend node ${e}`);let n;try{n=await this.getIDAttributeUsingCDP(t.object.objectId)}catch(o){throw this.logger.error({err:o,object:JSON.stringify(t.object)},"Failed to get ID attribute"),o}return(await this.getUserPageOrFrame()).locator(`[${We}="${n}"]`)}async clickUsingCDP(e,t={}){let n=0,o=e,s;for(;n<Mo;){if(!o||o.role==="RootWebArea")throw new T("ActionFailureError",s??`Attempted to click node with no clickable surrounding elements: ${e.getLogForm()}`);if(o.role==="StaticText"){o=o.parent;continue}let i=o.backendNodeID;if(!i){this.logger.warn({node:o.getLogForm()},"Click candidate had no backend node ID"),o=o.parent;continue}try{let a=await this.getLocatorFromBackendID(i);return t.doubleClick?await a.dblclick({timeout:8e3}):await a.click({timeout:8e3,button:t.rightClick?"right":"left",force:t.force}),o.id!==e.id&&this.logger.info({oldNode:e.getLogForm(),newNode:o.getLogForm()},"Redirected click successfully to new element"),o}catch(a){let l=`Failed to click '${o.getLogForm()}' - are you sure the element is currently visible and not obscured on the page?`;this.logger.error({err:a},l),s||(s=l),n++,o=o.parent}}throw new Error(`Max click redirection attempts exhausted on original element: ${e.getLogForm()}`)}async getElementLocation(e){let t=await this.cdpClient.send("DOMSnapshot.captureSnapshot",{computedStyles:[],includeDOMRects:!0,includePaintOrder:!0}),n=await this.page.evaluate(()=>window.devicePixelRatio);process.platform==="darwin"&&n===1&&(n=2);let o=t.documents[0],s=o.layout,i=o.nodes,a=i.nodeName||[],l=i.backendNodeId||[],c=s.nodeIndex,d=s.bounds,m=-1;for(let y=0;y<a.length;y++)if(l[y]===e){m=c.indexOf(y);break}if(m===-1)throw new Error(`Could not find any backend node with ID ${e}`);let[p=0,h=0,f=0,g=0]=d[m];p/=n,h/=n,f/=n,g/=n;let A=p+f/2,w=h+g/2;return{centerX:A,centerY:w}}async scroll(e,t,n,o){let s=t==="left"?-1:1,i=o==="up"?-1:1;this.activeFrame?await(await this.getUserPageOrFrame()).evaluate(([l,c,d,m])=>window.scrollTo(window.scrollX+(l??window.innerWidth)*d,window.scrollY+(c??window.innerHeight)*m),[e,n,s,i]):await this.page.mouse.wheel((e??r.VIEWPORT.width)*s,(n??r.VIEWPORT.height)*i)}async scrollUp(e){await this.scroll(0,null,e??null,"up")}async scrollDown(e){await this.scroll(0,null,e??null,"down")}async scrollLeft(e){await this.scroll(e??null,"left",0,null)}async scrollRight(e){await this.scroll(e??null,"right",0,null)}async goForward(){await this.wrapPossibleNavigation(async()=>this.localMode&&this.activeFrame?(await this.getUserPageOrFrame()).evaluate(e=>{let t=e().contentWindow;t?t.history.forward():console.error("Failed to get content window for frame")},()=>document.querySelector(`iframe[name="${this.activeFrame}"]`)):this.page.goForward({timeout:8e3}))}async goBack(){await this.wrapPossibleNavigation(async()=>this.localMode&&this.activeFrame?(await this.getUserPageOrFrame()).evaluate(e=>{let t=e().contentWindow;t?t.history.back():console.error("Failed to get content window for frame")},()=>document.querySelector(`iframe[name="${this.activeFrame}"]`)):this.page.goBack({timeout:8e3}))}async switchToPage(e){let t=this.context.pages();for(let n=0;n<t.length;n++){let o=t[n];if(o.url().includes(e)){this.logger.info(`Switching to tab ${n} with url ${o.url()}`),this.page=o,await this.pageSetup(),await this.attachPageLoadListeners();try{await o.waitForLoadState("load",{timeout:3e3})}catch{this.logger.warn({url:await this.url()},"Timeout elapsed waiting for load state during tab switch, continuing anyways...")}if(!await this.initCDPSession())throw new T("ActionFailureError",`Initializing libraries timed out on ${o.url()} \u{1F61E}. Please ensure the site and your internet are working.`);return}}throw new Error(`Could not find page with url containing ${e}`)}async attachPageLoadListeners(){if(this.localMode)return;let e=async t=>{t.parentFrame()||await this.pageSetup()};this.page.off("framenavigated",e),this.page.on("framenavigated",e)}async setCookie(e){let t=Yr(e);await this.context.addCookies([t])}async setLocalStorage(e,t){await(await this.getUserPageOrFrame()).evaluate(([o,s])=>{o&&localStorage.setItem(o,s||"")},[e,t])}async solveCaptcha(){await this.getA11yTree();let e;for(let a of this.a11yIdToNodeMap.values())if(a.role==="image"&&a.name.toLowerCase().includes("captcha")){if(!a.backendNodeID)continue;e=await this.getLocatorFromBackendID(a.backendNodeID);break}if(!e){let a=await(await this.getUserPageOrFrame()).solveRecaptchas();if(!a.captchas||!a.captchas.length)throw new Error("No captchas found on the page");return}let t=await e.screenshot({type:"jpeg",animations:"allow",caret:"hide",quality:100}),n=await fetch("https://api.2captcha.com/createTask",{method:"POST",body:JSON.stringify({clientKey:process.env.TWO_CAPTCHA_KEY,task:{type:"ImageToTextTask",body:t.toString("base64"),case:!0},languagePool:"en"})});if(!n.ok){let a=`Captcha solver API returned error response: ${n.statusText}`;throw this.logger.error({text:await n.text()},a),new Error(a)}let{taskId:o}=await n.json(),s=Date.now(),i="";for(;Date.now()-s<6e4;){await B(2500);let a=await fetch("https://api.2captcha.com/getTaskResult",{method:"POST",body:JSON.stringify({clientKey:process.env.TWO_CAPTCHA_KEY,taskId:o})});if(!a.ok){let c=`Captcha solution API returned error response: ${a.statusText}`;throw this.logger.error({text:await a.text()},c),new Error(c)}let l=await a.json();if(l.errorId){let c=`Captcha solution API returned error ID ${l.errorId}`;throw this.logger.error(c),new Error(c)}if(l.status==="ready"){i=l.solution.text;break}}if(!i)throw new Error("Captcha solution timed out");return i}getActiveFrame(){return this.activeFrame}async exposeRecordingBindings(){await this.context.exposeBinding("captureClick",async(e,t)=>{if(!this.transformer){this.logger.warn("Click captured without transformer");return}let n,o;try{n=await t.getAttribute("id"),o=await t.getAttribute(We)}catch(l){throw this.logger.error({err:l},"Failed to get element attributes for click processing"),l}if(this.logger.info({id:n,dataMomenticId:o},"Click captured on element"),!o){this.logger.error({url:await this.url(),element:await t.evaluate(l=>l.outerHTML)},`Could not find ${We} for recorded click`);return}let s=this.getA11yIdFromDataMomenticId(parseInt(o));if(!s){this.logger.warn({url:await this.url(),element:await t.evaluate(l=>l.outerHTML)},"Could not find a11y id for recorded click");return}let i={id:s};await this.resolveCachedTargetToNode(i),(async()=>{try{let l=this.mostRecentBrowserState??(await this.getA11yTree(!0)).serialize();await this.transformer?.recordClick(i,l)}catch(l){this.logger.error({err:l},"Failed transforming captured click")}})()},{handle:!0}),await this.context.exposeBinding("captureKeystroke",async({},{key:e})=>{this.transformer&&(this.logger.info({key:e},"Captured keypress"),this.transformer.recordKeystroke(e))})}async startRecording(e,t){this.transformer=t;let n=await this.getA11yTree(!0);this.mostRecentBrowserState=n.serialize();let o=null,s=[async()=>{this.transformer=void 0}],i=async l=>{o&&clearTimeout(o),o=setInterval(()=>{if(!this.transformer||e.aborted)return;(async()=>{let d=0;for(;d<2;)try{let m=await this.getA11yTree(!0);this.mostRecentBrowserState=m.serialize();break}catch(m){this.logger.error({err:m},"Failed to get a11y tree in frame navigation listener"),d++}})()},250),s.push(async()=>{o&&(clearInterval(o),o=null)}),await l.evaluate(Wo),s.push(async()=>{await l.evaluate(()=>{document.removeEventListener("click",window.clickListener,{capture:!0})})}),await l.evaluate(Ko),s.push(async()=>{await l.evaluate(()=>{document.removeEventListener("keydown",window.pressListener,{capture:!0})})})};await i(await this.getUserPageOrFrame());let a=async l=>{l.name().startsWith(Vt)&&(e.aborted||!this.transformer||(this.logger.info("Re-adding window recording event listeners on navigation"),await i(l)))};this.page.on("framenavigated",a),s.push(async()=>{this.page.off("framenavigated",a)}),e.addEventListener("abort",async()=>{for(let l of s)try{await l()}catch(c){this.logger.warn({err:c},"Recording cleanup function failed, continuing...")}})}async getSelectOptions(e){let t=this.a11yIdToNodeMap.get(e);return await(await this.getLocatorFromA11yNode(t)).evaluate(s=>Array.from(s.querySelectorAll("option")).map(a=>a.value))}async getHTML(){let e=await this.getUserPageOrFrame();await e.addScriptTag({content:Tt.htmlJs});let t=await e.evaluate(()=>window.getHTMLBodyString());if(!t)throw new T("InternalWebAgentError","Empty HTML tree");return ki.html(t,{indent_size:1,indent_with_tabs:!1,preserve_newlines:!1,wrap_line_length:80})}};var Ke=async({controller:r,context:e,step:t,logger:n,advanced:o,...s})=>{s.onStarted?.(),r.resetHistory();let i={...t,startedAt:new Date,userAgent:M.USER_AGENT,finishedAt:new Date,results:[],status:"SUCCESS"};try{let a=0;t.commands=t.commands||[];let l=t.commands&&t.commands.length>0;for(;;){if(a>12)throw new Error(`Exceeded max number of commands per step (${12})`);if(r.isClosed())throw new Error("Cancelling remaining steps in AI action because the controller is now closed");let c,d=new Date,m;if(s.onSaveScreenshot){let h=await r.browser.screenshot({});m=await s.onSaveScreenshot(h)}if(l){if(c=t.commands[a],!c)throw new Error(`Saved command at index ${a} is undefined.`)}else{n.info(`Generating new sub-command ${a} within AI step`);let h;try{h=await r.promptToCommand(t.type,t.text,o.disableAICaching),c=h.command}catch(g){c={type:"FAILURE",thoughts:g instanceof Error?g.message:`${g}`}}finally{if(c.type==="FAILURE")if(a===0){i.finishedAt=new Date,i.status="FAILED",i.message=c.thoughts;break}else{let g="Stopping command generation prematurely since no progress can be made";n.warn({command:c},g),c={type:"SUCCESS",thoughts:g}}}(async()=>{let g=a,A=t,w=c;if("target"in w&&w.target){await new Promise(y=>setTimeout(()=>y(),250));try{let y=await ji(r,h.context,w.target);w.target.elementDescriptor=y,A.commands[a]=w,s.onCommandExecuted?.({commandIndex:g,command:w})}catch(y){n.error({err:y,currentIndex:g,currentStep:A},"Failed to generate element description, continuing...")}}})()}s.onCommandGenerated?.({commandIndex:a,message:Ut[c.type]||`Unknown command (${c.type})`});let p={beforeScreenshot:m,beforeUrl:await r.browser.url(),startedAt:d,viewport:await r.browser.viewport(),finishedAt:new Date,status:"SUCCESS"};n.info(`Executing sub-command ${a} within AI step: ${Ge(c)}`);try{let h=await r.executeCommand(c,e,o.disableAICaching,l);n.info(`AI sub-command ${a} completed successfully`),p.elementInteracted=h.elementInteracted;let f;if(s.onSaveScreenshot){let A=await r.browser.screenshot({});f=await s.onSaveScreenshot(A)}p.afterScreenshot=f,p.afterUrl=await r.browser.url(),p.finishedAt=new Date;let g={status:"SUCCESS",startedAt:p.startedAt,finishedAt:p.finishedAt,type:"PRESET_ACTION",data:h.data,command:c,results:[p]};if(i.results.push(j(g)),t.commands[a]=c,s.onCommandExecuted?.({commandIndex:a,output:{...g,message:c.thoughts??h.thoughts??"Successfully executed preset action."},command:c}),c.type==="SUCCESS"){i.finishedAt=new Date,i.status="SUCCESS",i.message=h.thoughts??"All commands completed.";break}if(h.succeedImmediately&&!l){i.finishedAt=new Date,i.status="SUCCESS",i.message=h.succeedImmediatelyReason,c={type:"SUCCESS",thoughts:h.succeedImmediatelyReason},t.commands.push(c),s.onCommandExecuted?.({commandIndex:a+1,output:{...g,message:i.message},command:c}),i.results.push(j({...g,command:c}));break}}catch(h){if(l){l=!1,a=0,i.results=[];continue}let f=h instanceof Error?h.message:`${h}`;p.status="FAILED",p.message=f,p.finishedAt=new Date,p.afterUrl=await r.browser.url();let g;try{g=await r.browser.screenshot({})}catch(A){n.warn({err:A},"Failed to take screenshot after error, skipping")}p.afterScreenshot=g,i.results.push(j({status:"FAILED",startedAt:p.startedAt,finishedAt:p.finishedAt,type:"PRESET_ACTION",command:c,results:[p],message:f})),i.status="FAILED",i.finishedAt=new Date,i.message=f;break}a++}}catch(a){i.message=a instanceof Error?a.message:`${a}`,i.finishedAt=new Date,i.status="FAILED"}return i.status==="SUCCESS"?(i.data=i.results[i.results.length-1]?.data,s.onSuccess?.({message:i.message||"AI step succeeded.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i})):s.onFailure?.({message:i.message||"AI step errored.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i}),i};async function ji(r,e,t){let n=t.a11yData?.id;if(!n)throw new Error("Attempted to get reverse mapping for command with no a11y id target");return r.getReverseMappedTarget(e,n,!0)}var qe=async({controller:r,context:e,step:t,advanced:n,...o})=>{o.onStarted?.();let s=new Date,i=await r.browser.url(),a;if(o.onSaveScreenshot){let c=await r.browser.screenshot({});a=await o.onSaveScreenshot(c)}let l;try{let c=await r.executePresetStep(t.command,e,n.disableAICaching),d=c.screenshotOverride;if(o.onSaveScreenshot&&(d||(d=await r.browser.screenshot({})),l=await o.onSaveScreenshot(d)),c.fail)throw new T("ActionFailureError",c.thoughts||"Preset action failed.");let m=new Date,p={...t,startedAt:s,finishedAt:m,status:"SUCCESS",data:c.data,results:[]},h="Successfully executed preset action.";"assertion"in t.command&&(h=c.thoughts||"Assertion passed.");let f={beforeUrl:i,beforeScreenshot:a,afterUrl:await r.browser.url(),afterScreenshot:l,startedAt:s,finishedAt:m,viewport:await r.browser.viewport(),status:"SUCCESS"};return p.status="SUCCESS",p.results=[f],p.message=h,o.onSuccess?.({message:h,startedAt:s.getTime(),durationMs:m.getTime()-s.getTime(),command:t.command,output:p}),p}catch(c){o.logger.error({err:c},`Failed executing preset step ${t.command.type}`);let d=new Date,m=c instanceof Error?c.message:`${c}`;if(o.onSaveScreenshot&&!l&&(l=await o.onSaveScreenshot(await r.browser.screenshot({}))),"cancelOnFailure"in t.command&&t.command.cancelOnFailure){let h={...t,startedAt:s,finishedAt:d,status:"CANCELLED",message:m,results:[{beforeUrl:i,beforeScreenshot:a,afterUrl:await r.browser.url(),afterScreenshot:l,startedAt:s,finishedAt:d,viewport:await r.browser.viewport(),status:"CANCELLED",message:m}]};return o.onCancelled?.({message:m,startedAt:s.getTime(),durationMs:d.getTime()-s.getTime(),output:h}),h}let p={...t,startedAt:s,finishedAt:d,status:"FAILED",message:m,results:[{beforeUrl:i,beforeScreenshot:a,afterUrl:await r.browser.url(),afterScreenshot:l,startedAt:s,finishedAt:d,viewport:await r.browser.viewport(),status:"FAILED",message:m}]};return o.onFailure?.({message:m,startedAt:s.getTime(),durationMs:d.getTime()-s.getTime(),output:p}),p}};var xt=async({controller:r,context:e,step:t,advanced:n,logger:o,...s})=>{s.onStarted?.();let i={type:"MODULE",moduleId:t.moduleId,startedAt:new Date,userAgent:M.USER_AGENT,results:[],finishedAt:new Date,status:"SUCCESS"};for(let a=0;a<t.steps.length;a++){let l=t.steps[a];if(r.isClosed())throw i.status="CANCELLED",new Error("Cancelling remaining steps in module because the controller is now closed");o.debug({i:a,moduleStep:l},"Starting module step"),o.info(`Starting module sub-step ${a+1}/${t.steps.length}: ${wt(l)}`);let c;switch(l.type){case"PRESET_ACTION":c=await qe({controller:r,context:e,step:l,advanced:n,logger:o,onSaveScreenshot:s.onSaveScreenshot,onStarted(){s.onStepStarted?.({index:a})},onSuccess({message:m,startedAt:p,durationMs:h,output:f}){s.onStepSuccess?.({index:a,message:m,startedAt:p,durationMs:h,output:f})},onFailure({message:m,startedAt:p,durationMs:h,output:f}){s.onStepFailure?.({index:a,message:m,startedAt:p,durationMs:h,output:f})},onCancelled({message:m,startedAt:p,durationMs:h,output:f}){s.onStepCancelled?.({index:a,message:m,startedAt:p,durationMs:h,output:f})}});break;case"AI_ACTION":c=await Ke({controller:r,context:e,step:l,advanced:n,logger:o,onSaveScreenshot:s.onSaveScreenshot,onStarted(){s.onStepStarted?.({index:a})},onSuccess({message:m,startedAt:p,durationMs:h,output:f}){s.onStepSuccess?.({index:a,message:m,startedAt:p,durationMs:h,output:f})},onFailure({message:m,startedAt:p,durationMs:h,output:f}){s.onStepFailure?.({index:a,message:m,startedAt:p,durationMs:h,output:f})},onCommandGenerated({commandIndex:m,message:p}){s.onCommandGenerated?.({index:a,commandIndex:m,message:p})},onCommandExecuted({commandIndex:m,command:p,output:h}){s.onCommandExecuted?.({index:a,commandIndex:m,command:p,output:h})}});break;default:return(m=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(l)}if(i.results.push(j(c)),c.status==="FAILED"||c.status==="CANCELLED"){i.status=c.status,i.finishedAt=new Date,i.message=c.message;for(let d=a+1;d<t.steps.length;d++){let p={...t.steps[d],status:"CANCELLED",startedAt:new Date,finishedAt:new Date,userAgent:M.USER_AGENT,results:[],message:"Cancelled due to previous failure."};i.results.push(j(p))}break}}return i.status==="SUCCESS"?(i.data=i.results[i.results.length-1]?.data,s.onSuccess?.({message:"Executed module step.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i})):i.status==="FAILED"?s.onFailure?.({message:"Failed to execute module step.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i}):i.status==="CANCELLED"&&s.onCancelled?.({message:"Module step cancelled.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i}),i};var Zo=async({test:r,runId:e,controller:t,context:n,logger:o,onUpdateRun:s,onSaveScreenshot:i,onTestSuccess:a})=>{try{let l=await Gi({test:r,runId:e,controller:t,context:n,logger:o,onUpdateRun:s,onSaveScreenshot:i});if(l==="PASSED"||l==="CANCELLED")return await a?.(r),l;throw new T("ActionFailureError",l.message||"An unknown error occurred")}catch(l){throw l instanceof T||(l=new T("InternalPlatformError",l instanceof Error?l.message:`${l}`,{cause:l})),l}finally{await t.browser.cleanup()}},Gi=async({test:r,runId:e,controller:t,context:n,logger:o,onUpdateRun:s,onSaveScreenshot:i})=>{let a=ge.parse(r.advanced),l=o.child({runId:e,testId:r.id});l.info("Starting test run"),await s({status:"RUNNING",startedAt:new Date});let c,d="PASSED",m=[];for(let p=0;p<r.steps.length;p++){let h=r.steps[p];l.info(`Starting step ${p+1}/${r.steps.length}: ${wt(h)}`);let f=n.toObjectCopy(),g;switch(h.type){case"PRESET_ACTION":g=await qe({controller:t,context:n,step:h,advanced:a,logger:l,onSaveScreenshot:i});break;case"AI_ACTION":g=await Ke({controller:t,context:n,step:h,advanced:a,logger:l,onSaveScreenshot:i});break;case"RESOLVED_MODULE":g=await xt({controller:t,context:new q(await t.browser.url(),h.steps),step:h,advanced:a,logger:l,onSaveScreenshot:i});break;default:return(w=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(h)}if(m.push({...j(g),beforeTestContext:f,afterTestContext:n.toObjectCopy()}),n.setResult(p,g.data),await s({results:m}),g.status==="SUCCESS"){l.info(`Step ${p+1}/${r.steps.length} succeeded`);continue}if(g.status!=="FAILED"&&g.status!=="CANCELLED")throw new T("InternalPlatformError",`Received unexpected non-terminal status from step: ${g.status}`);l.info({message:m[m.length-1]?.message},`Step ${p+1}/${r.steps.length} ended with status: ${g.status}`),c=g,d=g.status;for(let A=p+1;A<r.steps.length;A++){let w=r.steps[A];if(w.type==="RESOLVED_MODULE"){let y={type:"MODULE",moduleId:w.moduleId,startedAt:new Date,userAgent:M.USER_AGENT,results:w.steps.map(I=>({...I,status:"CANCELLED",startedAt:new Date,finishedAt:new Date,userAgent:M.USER_AGENT,results:[]})),finishedAt:new Date,status:"CANCELLED"};m.push(j(y))}else{let y={...w,status:"CANCELLED",startedAt:new Date,finishedAt:new Date,userAgent:M.USER_AGENT,results:[]};m.push(j(y))}}break}return await s({status:d,finishedAt:new Date,results:m}),d==="FAILED"?c:d};var en={currentlyExecutingRequests:0},Vi=r=>async e=>{let t=!1;try{en.currentlyExecutingRequests++,t=await Wi({...r,...e})}finally{r.logger.info({success:t,sessionId:r.metadata.sessionId},"Test execution complete"),en.currentlyExecutingRequests--}},Wi=async({socket:r,steps:e,baseUrl:t,testMetadata:n,reInitialize:o,indicesFilter:s,metadata:i,logger:a,rootState:l,localApp:c})=>{let{testId:d,sessionId:m,orgId:p}=i,h={testId:d,orgId:p,baseUrl:t},f=a.child(h),g=a.child({package:"web-agent",...h}),A=!0,w=!0;c==="iframe"&&(w=!1);let y=ge.parse(n.advanced??{}),I=H.getSession(m);if(!I)throw new Error("No active session found");let{controller:v,context:E}=I;v.setOpen();let F=M.USER_AGENT;f.info({reInitialize:o,context:E,steps:e.map(z=>`${z.type}${"command"in z?` - ${z.command.type}`:""}`),indicesFilter:s},"Starting execution");let $e={url:t,clearCookies:!0,clearStorage:!0};if(o&&(l?(v.browser.baseURL=t,v.browser.setActiveFrame(gt),await v.resetState($e),v.setLogger(g),v.browser.setLogger(g)):await v.resetState($e),v.setOpen(),E.reset(t)),f.info(`Session restarted for test ${d} at ${t}`),r.emit("session",{url:t,userAgent:F,viewport:await v.browser.viewport(),localApp:c}),E.setSteps(e),s?.length){let z=qi(e,s);return f.info({indices:s,stepType:z.type,commandType:"command"in z?z.command.type:void 0},"Starting individual step"),r.emit("started",{indices:s}),A=await tn({indices:s,step:z,controller:v,context:E,advanced:y,socket:r,logger:f,takeScreenshots:w}),r.emit("testContext",{state:E.toObjectRef()}),r.emit("finished"),A}else E.clearResults(),r.emit("testContext",{state:E.toObjectRef()});for(let z=0;z<e.length&&!(v.browser.closed||v.isClosed()||r.disconnected);z++){let He=e[z];f.info({index:z,type:He.type,commandType:"command"in He?He.command.type:void 0},"Starting step");let R=await tn({indices:[z],step:He,controller:v,context:E,advanced:y,socket:r,logger:f,takeScreenshots:w});if(r.emit("testContext",{state:E.toObjectRef()}),!R){A=!1;break}}return r.emit("finished"),A},Ki=(r,e)=>{switch(r.type){case"RESOLVED_MODULE":return r.steps[e];case"AI_ACTION":let t=r.commands[e];return{type:"PRESET_ACTION",command:t};case"PRESET_ACTION":default:throw new Error(`Cannot get a child step from step type ${r.type}`)}},qi=(r,e)=>{let t=r[e[0]];for(let n=1;n<e.length;n++)t=Ki(t,e[n]);return t},fr=async r=>r,tn=async r=>{try{return await Yi(r)}catch(e){throw e instanceof T&&e.emitToUser&&r.socket.emit("error",{message:e.message}),e}},Yi=async({indices:r,step:e,controller:t,context:n,advanced:o,socket:s,logger:i,takeScreenshots:a})=>{let l=()=>{s.emit("started",{indices:r})},c=({message:h,startedAt:f,durationMs:g,command:A,output:w})=>{s.emit("success",{indices:r,message:h,startedAt:f,durationMs:g,command:A,output:ce.parse(w)})},d=({message:h,startedAt:f,durationMs:g,output:A})=>{s.emit("failure",{indices:r,message:h,startedAt:f,durationMs:g,output:ce.parse(A)})},m=({message:h,startedAt:f,durationMs:g,output:A})=>{s.emit("cancelled",{indices:r,message:h,startedAt:f,durationMs:g,output:ce.parse(A)})},p;switch(e.type){case"PRESET_ACTION":{p=await qe({controller:t,context:n,step:e,advanced:o,logger:i,onSaveScreenshot:a?fr:void 0,onStarted:l,onSuccess:c,onFailure:d,onCancelled:m});break}case"AI_ACTION":{p=await Ke({controller:t,context:n,step:e,advanced:o,logger:i,onSaveScreenshot:a?fr:void 0,onStarted:l,onSuccess:c,onFailure:d,onCommandGenerated({commandIndex:f,message:g}){s.emit("commandGenerated",{indices:[...r,f],message:g})},onCommandExecuted({commandIndex:f,command:g,output:A}){s.emit("commandExecuted",{indices:[...r,f],command:g,output:ce.parse(A)})}});break}case"RESOLVED_MODULE":{p=await xt({controller:t,context:new q(t.browser.baseURL,e.steps),step:e,advanced:o,logger:i,onSaveScreenshot:a?fr:void 0,onStarted:l,onSuccess:c,onFailure:d,onCancelled:m,onStepStarted({index:f}){s.emit("started",{indices:[...r,f]})},onStepSuccess({index:f,message:g,startedAt:A,durationMs:w,output:y}){s.emit("success",{indices:[...r,f],message:g,startedAt:A,durationMs:w,output:ce.parse(y)})},onStepFailure({index:f,message:g,startedAt:A,durationMs:w,output:y}){s.emit("failure",{indices:[...r,f],message:g,startedAt:A,durationMs:w,output:ce.parse(y)})},onStepCancelled({index:f,message:g,startedAt:A,durationMs:w,output:y}){s.emit("cancelled",{indices:[...r,f],message:g,startedAt:A,durationMs:w,output:ce.parse(y)})},onCommandGenerated({commandIndex:f,index:g,message:A}){s.emit("commandGenerated",{indices:[...r,g,f],message:A})},onCommandExecuted({index:f,commandIndex:g,command:A,output:w}){s.emit("commandExecuted",{indices:[...r,f,g],command:A,output:ce.parse(w)})}});break}default:return(f=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}return n.setResult(r[0],p.data),p.status==="SUCCESS"};var rn={event:"execute",createHandler:Vi};var Xi=({metadata:r,logger:e,socket:t})=>{let{sessionId:n}=r;return async(o,s)=>{let{description:i,useVision:a,testMetadata:l,isSelect:c,returnScreenshot:d}=o;e.info({description:i,useVision:a},"Locate handler called");let m=H.getSession(n);if(!m)throw new Error("No active session found");let{controller:p,context:h}=m,f=ge.parse(l.advanced??{}),g,A;if(i)try{if(g=await p.locateElement(i,a,f.disableAICaching,h),A={id:g.id},await p.browser.resolveCachedTargetToNode(A),c)try{g.options=await p.browser.getSelectOptions(g.id)}catch(y){e.warn({err:y},"Failed getting select options"),t.emit("error",{message:`Failed getting select options: ${y}`})}e.info({locator:g,a11yData:A},"Located element result")}catch(y){e.error({err:y},"Error locating element"),t.emit("error",{message:y instanceof Error?y.message:`${y}`}),s({found:!1});return}let w;if(d){let{buffer:y,width:I,height:v}=await p.screenshotWithDimensions({target:A,hideCaret:!0});w={data:y.toString("base64"),width:I,height:v}}if(g)try{await p.browser.scrollIntoView({id:g.id}),await p.browser.highlight({id:g.id})}catch(y){e.warn({err:y,locator:g},"Error highlighting element")}s({found:!0,locator:g,a11yData:A,screenshot:w})}},on={event:"locate",createHandler:Xi};var Ji=({socket:r,metadata:e,logger:t})=>{let{sessionId:n}=e;return async({action:o,indices:s},i)=>{try{let a=H.getSession(n);if(!a)throw new Error("No active session found");let{controller:l}=a;o==="START"&&t.info({sessionId:n},"Starting record mode"),await l.toggleRecordMode({action:o,indices:s,onStepRecord:(c,d)=>{r.emit("stepRecorded",{step:c,indices:d})}}),i()}catch(a){t.error({err:a},"Error in record socket handler"),i(a instanceof Error?a.message:`${a}`)}}},nn={event:"record",createHandler:Ji};var Qi=({socket:r,metadata:e,rootState:t,logger:n,localApp:o})=>async({baseUrl:s})=>{let{testId:i,sessionId:a}=e;n.info({testId:i,sessionId:a,baseUrl:s},"Reset event received");let l;if(t?.controller){let{controller:d,context:m}=t;await d.resetState({clearCookies:!0,clearStorage:!0,url:s}),l=d.browser.baseURL,m.reset(l)}else{let d=H.getSession(a);if(!d){r.emit("error",{message:"No session to reset"});return}let{controller:m,context:p}=d;await m.browser.reset({clearCookies:!0,clearStorage:!0,url:s}),l=m.browser.baseURL,p.reset(l)}let c=M.USER_AGENT;n.info(`Session reset for test ${i} at ${l}`),r.emit("session",{url:l,userAgent:c,viewport:M.VIEWPORT,localApp:o})},sn={event:"reset",createHandler:Qi};import{v4 as fa}from"uuid";var Zi={type:"a11y",version:"1.0.0",useHistory:"diff",useGoalSplitter:!0},_e=Zi;import da from"buffer-image-size";import{existsSync as aa}from"fs";import{faker as ea}from"@faker-js/faker";import ta from"assert";import ra from"axios";import oa from"moment";import na from"p-timeout";var sa=Object.getPrototypeOf(async function(){}).constructor;async function an({code:r,fragment:e,state:t,timeoutMs:n=1e4}){let o=r;e&&(o=`return ${r}`);let s=JSON.parse(JSON.stringify(t)),i=(c,d)=>{s.env[c]=d,t.env[c]=d},a;return await na((async()=>{a=await Promise.resolve(new sa("axios","moment","faker","assert","env","steps","results","setVariable",o)(ra,oa,ea,ta,s.env,s.steps,s.results,i))})(),{milliseconds:n,message:`Timeout of ${n}ms exceeded for code execution`}),a}import{z as ke}from"zod";var ln=process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT,ia=ke.object({result:ke.unknown(),variableUpdates:ke.record(ke.string(),ke.unknown()).optional(),error:ke.string().optional(),success:ke.boolean()});async function cn({code:r,fragment:e,state:t,logger:n,timeoutMs:o=1e4}){let s=new AbortController;if(!ln)throw new Error("GCP_JS_EVAL_FUNCTION_ENDPOINT environment variable not set");let i=setTimeout(()=>{s.abort()},o),a=await fetch(ln,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:r,fragment:e,state:t}),signal:s.signal});if(!a.ok)throw new Error(`Code evaluation server returned error code: ${a.status}`);clearTimeout(i);let l;try{l=ia.parse(await a.json()),n.debug({response:l},"Response from code evaluation server")}catch(c){throw new Error(`Code evaluation server returned invalid response: ${c}`)}if(l.error)throw new Error(`Code evaluation server returned error: ${l.error}`);if(l.variableUpdates)for(let[c,d]of Object.entries(l.variableUpdates))t.env[c]=d;return l.result}var la=ca();function ca(){if(process.env.NODE_ENV!=="production")return!1;if(process.env.NAMESPACE)return!0;try{if(aa("/var/run/secrets/kubernetes.io/serviceaccount/token"))return!0}catch{}return!1}async function gr(r){let e;return la?(r.logger.info({code:r.code,fragment:r.fragment,state:r.state},"Running code remotely"),e=cn):(r.logger.info({code:r.code,fragment:r.fragment,state:r.state},"Running code locally"),e=an),e(r)}async function yr({s:r,state:e,logger:t,timeoutMs:n=1e3}){let o=/{{(.*?)}}/g,s=r.matchAll(o),i=r;for(let a of s){if(a.length<2)continue;let l=a[1].trim(),c=await gr({code:l,fragment:!0,state:e,timeoutMs:n,logger:t}),d=typeof c=="string"?c:`${c}`;i=i.replace(a[0],d)}return i}import ma from"dedent";import ua from"diff-lines";import wr from"jpeg-js";import pa from"pixelmatch";var It=class r{static ACTION_DEBOUNCE_DELAY=1e3;onStepRecord;signal;generator;indices;keyBuffer=[];timer=null;keyBufferMode="normal";lastStep=null;constructor({signal:e,onStepRecord:t,generator:n,initialIndices:o}){this.signal=e,this.onStepRecord=(s,i)=>{this.lastStep={step:s,indices:i},t(s,i)},this.generator=n,this.indices=o}async recordClick(e,t){if(this.signal.aborted)return;let n=dt("CLICK"),o={type:"PRESET_ACTION",command:{...n,target:{elementDescriptor:`Generating description for: ${e.nodeOnlySerializedForm?.trim()??`element with id ${e.id}`}`,a11yData:e}}},s=Array.from(this.indices);this.indices[this.indices.length-1]++,this.onStepRecord(o,s);let i=await this.generator.getReverseMappedDescription({goal:`${e.id}`,browserState:t},!1);o.command.target.elementDescriptor=i.phrase,this.onStepRecord(o,s)}flushKeyBufferToCommand(){let e;if(this.keyBufferMode==="normal"){let o=dt("TYPE");e={type:"PRESET_ACTION",command:{...o,target:void 0,value:this.keyBuffer.join("")}}}else{let o=dt("PRESS");e={type:"PRESET_ACTION",command:{...o,value:this.keyBuffer.join("+")}}}let t,n=this.lastStep?.step.command;if(n?.type===e.command.type){let o=n.value,s=e.command.value;e={type:"PRESET_ACTION",command:{...n,value:e.command.type==="PRESS"?`${o}+${s}`:`${o}${s}`}},t=this.lastStep.indices}else n?.type==="CLICK"&&e.command.type==="TYPE"?(this.lastStep.step.command={...e.command,target:n.target},e=this.lastStep.step,t=this.lastStep.indices):(t=Array.from(this.indices),this.indices[this.indices.length-1]++);this.onStepRecord(e,t),this.keyBuffer=[],this.timer=null}recordKeystroke(e){if(e==="Shift"||e==="CapsLock"||this.signal.aborted)return;this.timer!==null&&clearTimeout(this.timer);let t="normal";e.length>1&&(t="special"),this.keyBuffer.length!==0&&t!==this.keyBufferMode&&this.flushKeyBufferToCommand(),this.keyBufferMode=t,this.keyBuffer.push(e),this.timer=setTimeout(()=>{this.flushKeyBufferToCommand()},r.ACTION_DEBOUNCE_DELAY)}};var Sr=(r,e,t)=>{let[n,...o]=e.split("."),s=n;return o.length>=1?Sr(r[s],o.join("."),t):r[s]=t,r};var ha=1e4,pe=class{browser;pendingInstructions;generator;commandHistory;config;closed=!1;logger;recordAbortController=null;constructor({browser:e,config:t,generator:n,logger:o}){this.browser=e,this.generator=n,this.config=t,this.logger=o,this.pendingInstructions=[],this.commandHistory=[]}get history(){return this.commandHistory.filter(e=>e.state==="DONE")}get lastExecutedCommand(){let e=this.history;return e.length===0?null:e[e.length-1]}setOpen(){this.closed=!1}isClosed(){return this.closed}setLogger(e){this.logger=e}resetHistory(){this.commandHistory=[],this.pendingInstructions=[]}async resetState(e){this.resetHistory(),this.closed=!0,await this.browser.reset(e)}async getBrowserState(){let t=await(await this.browser.getA11yTree()).serialize();return this.logger.debug({tree:t,activeFrame:this.browser.getActiveFrame()},"Got a11y tree"),t}getSerializedHistory(e,t){let n;return this.config.useHistory==="diff"?n=this.getDiffHistory(e,t):n=this.getListHistory(),n}async splitUserGoal(e,t,n){if(e==="AI_ACTION"&&t.match(/[,!;.]|(?:and)|(?:then)/)&&this.config.useGoalSplitter){let o=await this.generator.getGranularGoals({goal:t,url:await this.browser.url()},n);this.pendingInstructions=o.reverse()}else this.pendingInstructions=[t]}async promptToCommand(e,t,n){try{return await this.promptToCommandHelper(e,t,n)}catch(o){throw o instanceof T?o:new T("InternalWebAgentError",o instanceof Error?o.message:`${o}`,{cause:o})}}async promptToCommandHelper(e,t,n){if(this.pendingInstructions.length===0){if(!t.trim())throw new Error("Cannot generate commands for empty goal");await this.splitUserGoal(e,t,n)}let o=this.pendingInstructions[this.pendingInstructions.length-1];this.logger.info({goal:o},"Starting prompt translation");let s=Date.now(),i=await this.browser.url(),a=await this.getBrowserState();this.logger.info({duration:Date.now()-s,url:i},"Got browser state");let l=this.commandHistory.length;this.commandHistory.push({state:"PENDING",browserStateBeforeCommand:a,urlBeforeCommand:i,type:e});let c=this.getSerializedHistory(i,a),d={url:i,numPrevious:l,browserState:a,history:c,goal:o,lastCommand:this.lastExecutedCommand},m=await this.generator.getProposedCommand(d,n);if(this.logger.info({type:m.type,thoughts:m.thoughts},"Got proposed command"),m.type==="SUCCESS"){let p=this.pendingInstructions.pop();if(this.logger.info({finishedInstruction:p,remainingInstructions:this.pendingInstructions},"Removing pending instruction due to SUCCESS"),this.pendingInstructions.length!==0)return this.commandHistory=[],this.promptToCommand(e,"",n)}else m.type==="FAILURE"&&(this.logger.info({remainingInstructions:this.pendingInstructions},"Removing pending instructions due to FAILURE"),this.pendingInstructions=[]);return{context:d,command:m}}async locateElement(e,t,n,o){if(!e)throw new T("ActionFailureError","Cannot locate element with empty description");o&&(e=await yr({s:e,state:o.toObjectRef(),logger:this.logger}));let s=await this.getBrowserState(),i;if(t){let{before:a,after:l}=await this.browser.screenshotWithHints({});if(i=await this.generator.getElementLocationWithVision({goal:e,screenshot:a,hintActivatedScreenshot:l},n),i.id>0){let c=this.browser.getA11yIdFromDataMomenticId(i.id);if(!c)throw new T("InternalWebAgentError",`Unable to find corresponding DOM node for id ${i.id}`);i.id=c}}else i=await this.generator.getElementLocation({browserState:s,goal:e},n);if(i.id<0)throw new T("ActionFailureError",`Unable to locate element: ${i.thoughts?i.thoughts:"please ensure the element is visible and conforms to Accessibility guidelines"}`);return i}getDiffHistory(e,t){let n=this.history.filter(s=>s.type==="AI_ACTION");if(n.length===0)return"<NONE/>";let o=[`
|
|
25
|
-
You have already executed the following commands successfully (most recent listed first)`,"-".repeat(10)];return n.reverse().forEach((s,
|
|
24
|
+
${y||""}`}return m}},hr=class{constructor(e,t,n){this.root=e;this.a11yIdNodeMap=t;this.dataMomenticIdMap=n}serialize(){return this.root?this.root.serialize():""}};function Ri(r){return r.name?.value?`"${r.name.value}"`:r.role?.value&&r.role.value!=="none"&&r.role.value!=="generic"?`"${r.role.value}"`:`"${r.nodeId}"`}function Uo(r,e,t){if(!e&&r.parentId)throw new Error(`Got no parent for accessibility node ${r.nodeId}: ${JSON.stringify(r)}`);let n=new pr({id:parseInt(r.nodeId),role:r.role?.value||"",name:r.name?.value?typeof r.name.value=="string"?r.name.value:`${r.name.value}`:"",content:r.value?.value?typeof r.value.value=="string"?r.value.value:`${r.value.value}`:"",properties:r.properties,children:[],pathFromRoot:(e?`${e.pathFromRoot} `:"")+Ri(r),backendNodeID:r.backendDOMNodeId,ignoredByCDP:r.ignored}),o=r.childIds??[];for(let i of o){if(!i)continue;let l=t.get(parseInt(i));if(!l)continue;let c=Uo(l,n,t);c.length&&(n.children=n.children.concat(c))}if(n.role==="StaticText"&&(n.children=[]),n.children.length===1&&n.children[0].role==="StaticText"){let i=n.name,l=n.children[0]?.name;(i===l||!l)&&(n.children=[])}let s=[];for(let i=n.children.length-1;i>=0;i--){let l=n.children[i];if(l.role!=="StaticText"){s.push(l);continue}if(i===0||n.children[i-1].role!=="StaticText"){s.push(l);continue}n.children[i-1].name+=` ${l.name}`}if(n.children=s.reverse(),n.role==="generic"&&n.children.length===1){let i=n.children[0];if(n.name&&!fr.includes(i.role)&&n.name===i.name)return n.children}if(!n.isInteresting()&&r.parentId)return n.children;for(let i of n.children)i.parent=n;return[n]}function $o(r,e,t,n,o=1){r.id=o,o+=1,e.set(r.id,r),r.dataMomenticId?t.set(r.dataMomenticId,r):fr.includes(r.role)||n.debug({node:r.serialize({neighbors:1,maxLevel:1})},"Node has no data-momentic-id");for(let s of r.children)o=$o(s,e,t,n,o);return o}function Ho(r,e){if(!r.root)throw new Error("a11y tree has null root");r.allNodes=r.allNodes.filter(a=>a.ignored?!a.ignoredReasons?.find(l=>Ei.includes(l.name)):!0);let t=new Map;for(let a of r.allNodes)t.set(parseInt(a.nodeId),a);let n=Uo(r.root,null,t);if(n.length>1)throw new Error(`Something went horribly wrong processing the a11y tree, we got: ${JSON.stringify(n)}`);if(n.length===0)throw new pt;let o=new Map,s=new Map;return $o(n[0],o,s,e),new hr(n[0],o,s)}var nt=(r,e)=>{e.id=r.id,e.content=r.content,e.name=r.name,e.role=r.role,e.numChildren=r.children.length,e.serializedForm=r.serialize({noID:!0,maxLevel:1,neighbors:1}),e.nodeOnlySerializedForm=r.serialize({noID:!0,noChildren:!0,noProperties:!0})},gr=(r,e)=>{let t=1;r.role===e.role&&t++;let n=["name","content"];for(let o of n){let s=r[o];if(typeof s!="string"||!s.trim())continue;let a=ur(s,e[o])/Math.min(s.length,e[o].length);a===0?t+=2:a<=.1&&t++}if(e.numChildren!==void 0&&(r.children.length===e.numChildren&&e.numChildren>0?t++:(e.numChildren>0&&r.children.length===0||Math.abs(r.children.length-e.numChildren)>2)&&t--),e.nodeOnlySerializedForm){let o=r.serialize({noID:!0,noChildren:!0,noProperties:!0});ur(o,e.nodeOnlySerializedForm)/Math.min(o.length,e.nodeOnlySerializedForm.length)<=.1&&t++}if(e.serializedForm){let o=r.serialize({noID:!0,maxLevel:1,neighbors:1}),s=ur(o,e.serializedForm)/Math.min(o.length,e.serializedForm.length);s===0?t+=2:s<=.1&&t++}return t};var De={r:147,g:196,b:125,a:.55},Bo={showInfo:!1,showRulers:!1,showStyles:!1,showAccessibilityInfo:!1,showExtensionLines:!1,contrastAlgorithm:"aa",contentColor:De,paddingColor:De,borderColor:De,marginColor:De,eventTargetColor:De,shapeColor:De,shapeMarginColor:De};var B=(r=1e3)=>new Promise(e=>setTimeout(()=>e(),r));function Vo(){window.cursor||(window.cursor=document.createElement("img"),window.cursor.setAttribute("src","data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjMyIiB2aWV3Qm94PSIwIDAgMzIgMzIiIHdpZHRoPSIzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEwIDcpIj48cGF0aCBkPSJtNi4xNDggMTguNDczIDEuODYzLTEuMDAzIDEuNjE1LS44MzktMi41NjgtNC44MTZoNC4zMzJsLTExLjM3OS0xMS40MDh2MTYuMDE1bDMuMzE2LTMuMjIxeiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Im02LjQzMSAxNyAxLjc2NS0uOTQxLTIuNzc1LTUuMjAyaDMuNjA0bC04LjAyNS04LjA0M3YxMS4xODhsMi41My0yLjQ0MnoiIGZpbGw9IiMwMDAiLz48L2c+PC9zdmc+"),window.cursor.setAttribute("id","momentic_cursor"),window.cursor.setAttribute("style","position: absolute; z-index: 99999999999; pointer-events: none; left:0; top:0; height:4%;"),window.cursor.style.filter="invert(0%) sepia(6%) saturate(24%) hue-rotate(315deg) brightness(89%) contrast(110%)",document.body.appendChild(cursor),document.onmousemove=function(r){r=r||window.event,document.getElementById("momentic_cursor").style.left=r.pageX+"px",document.getElementById("momentic_cursor").style.top=r.pageY+"px"})}function jo(){window.globalHintManager||(window.globalHintManager=new window.HintManager),window.globalHintManager.capture()}function Go(){window.globalHintManager&&window.globalHintManager.reset()}function Wo(){let r=document.body.getElementsByTagName("*"),e=1;for(let t=0;t<r.length;t++){let n=e.toString();for(;[6].some(s=>n.includes(s.toString()));)e++,n=e.toString();let o=r[t];o?.setAttribute("data-momentic-id",`${e}`),o?.setAttribute("aria-keyshortcuts",`${e}`),e++}}var xi=new Set(["document","script","XMLHttpRequest","fetch","xhr"]),Ii=new Set(["script","document"]),Li=["intercom.io","googletagmanager.com","google-analytics.com","www.gstatic.com","gstatic.com","apis.google.com","sentry.io","newrelic.com","p.retool.com","m.stripe.com","m.stripe.network","js.stripe.com","px.ads.linkedin.com","www.clarity.ms","assets.trybento.co","udon.trybento.co","cdn.lr-in-prod.com","r.lr-in-prod.com","content.product-usage.assembledhq.com","data.product-usage.assembledhq.com","static.zdassets.com","o.clarity.ms/collect"],Oi=["api.stripe.com","supabase.co"],Mi=[];async function qo(r){for(let e of Mi)await r.route(e,t=>t.abort())}function yr(r){return`${r.resourceType()} ${r.method()} ${r.url()}`}function Ko(r){return r=r.replace(/^www\./,""),r}function Yo(r){return r.startsWith("document GET")?!0:Oi.some(e=>r.includes(e))}function Xo(r,e){if(!xi.has(r.resourceType()))return!1;let t=new URL(e),n=new URL(r.url());return Li.some(o=>n.hostname.includes(o))?!1:Ii.has(r.resourceType())||r.method()!=="GET"?!0:Ko(n.hostname).includes(Ko(t.hostname))}var Jo=()=>{window.clickListener&&document.removeEventListener("click",window.clickListener,{capture:!0}),window.clickListener=async r=>{console.log("[Momentic] Window click listener fired",r.target),await window.captureClick(r.target)},document.addEventListener("click",window.clickListener,{capture:!0})};var Qo=()=>{window.pressListener&&document.removeEventListener("keydown",window.pressListener,{capture:!0}),window.pressListener=async r=>{console.log("[Momentic] Window press listener fired"),await window.captureKeystroke({key:r.key})},document.addEventListener("keydown",window.pressListener,{capture:!0})};var Lt=Ki(Wi);Lt.use(Yi());Lt.use(qi({provider:{id:"2captcha",token:process.env.TWO_CAPTCHA_KEY},visualFeedback:!0}));var P=class r{browser;context;page;a11yIdToNodeMap=new Map;dataMomenticIdToNodeMap=new Map;cdpClient;logger;localMode;activeFrame;transformer;mostRecentBrowserState;baseURL;constructor({browser:e,context:t,page:n,baseUrl:o,logger:s,localMode:a,cdpClient:i}){this.browser=e,this.context=t,this.cdpClient=i,this.page=n,this.baseURL=o,this.logger=s,this.localMode=!!a}static USER_AGENT=rn["Desktop Chrome"].userAgent;static async init({baseUrl:e,logger:t,browserArgs:n,contextArgs:o,takeScreenshots:s,onScreenshot:a,onClose:i,waitForLoad:l,localMode:c,localAppUrl:d,extensionPath:m,skipPageSetup:f,timeout:h=8e3}){let p={headless:!0,handleSIGTERM:!1,chromiumSandbox:!1,...n??{}},y={viewport:de,deviceScaleFactor:process.platform==="darwin"?2:1,userAgent:rn["Desktop Chrome"].userAgent,geolocation:{latitude:37.7749,longitude:-122.4194},locale:"en-US",timezoneId:"America/Los_Angeles",...o??{}},S=null,b,g;if(c){let k=Gi(ji(),"momentic","chromium");b=await Lt.launchPersistentContext(k,{...p,...y,ignoreDefaultArgs:["--enable-automation","--enable-strict-mixed-content-checking"],ignoreHTTPSErrors:!0,bypassCSP:!0,args:["--allow-insecure-localhost","--disable-site-isolation-for-policy","--disable-site-isolation-trials",`--unsafely-treat-insecure-origin-as-secure=${d}`,`--load-extension=${m}`,"--test-type=browser"],baseURL:e}),g=b.pages()[0],i&&g.on("close",()=>{i()})}else S=await Lt.launch(p),b=await S.newContext({...y,baseURL:e}),g=await b.newPage();await qo(b);let R=new r({browser:S,context:b,page:g,baseUrl:e,logger:t,localMode:c,cdpClient:await b.newCDPSession(g)}),A=!1,E=async()=>{try{await R.navigate({url:e,wrapPossibleNavigation:!1,initialNavigation:!f,timeout:h})}catch(k){if(t.error({err:k},"Failed to initialize chrome browser"),l)throw k}finally{A=!0}};if(l?await E():E(),a){let k=async()=>{if(s)try{a({viewport:await R.getViewport(),buffer:await R.screenshot({})})}catch(Ve){t.error({err:Ve},"Failed to take screenshot")}};k();let Be=setInterval(()=>{k()},400),z=Date.now();for(;!A&&Date.now()-z<(h??1/0);)await B(250);clearInterval(Be)}return R}async getUserPageOrFrame(){if(this.localMode&&this.activeFrame){let e=null,t=0;for(;!e&&t<5;)e=this.page.frame(this.activeFrame),await B(100),t++;if(!e)throw new T("InternalWebAgentError",`Failed to find frame ${this.activeFrame} on page ${this.page.url()}`);return e}return this.page}async initCDPSession(e=3e3){let t=!1,n=e===null?1/0:2,o=async()=>{try{this.cdpClient=await this.context.newCDPSession(this.page),await this.cdpClient.send("Accessibility.enable"),await this.cdpClient.send("DOM.enable"),await this.cdpClient.send("Overlay.enable"),t=!0}catch(s){if(n>0)return this.logger.warn({err:s},"Failed to initialize CDP session, re-creating CDP client"),await B(250),n--,o();throw s}};return e===null?await o():await Promise.race([o(),B(e)]),t}setLogger(e){this.logger=e}ping(){if(this.closed)throw new Error("Page has been closed");if(this.browser&&!this.browser.isConnected())throw new Error("Browser is not connected")}setActiveFrame(e){this.activeFrame=e}async reset(e){this.a11yIdToNodeMap.clear(),this.dataMomenticIdToNodeMap.clear();let t=this.context.pages();this.page=t[0];for(let n=1;n<t.length;n++)await t[n].close();if(e.clearCookies&&await this.context.clearCookies(),!this.page.isClosed()){if(e.clearStorage)try{await(await this.getUserPageOrFrame()).evaluate(async()=>{window.localStorage.clear(),window.sessionStorage.clear(),await indexedDB.databases().then(n=>{n.forEach(o=>{o.name&&indexedDB.deleteDatabase(o.name)})})})}catch(n){this.logger.debug({err:n},"Failed clearing site data, continuing...")}await this.navigate({url:e.url??this.baseURL,wrapPossibleNavigation:!1,initialNavigation:!0,timeout:e.timeout})}}async pageSetup(){try{this.localMode||await this.page.evaluate(Vo)}catch{}}async wait(e){await B(e)}async toggleHints(e){let t=await this.getUserPageOrFrame();e.state==="on"?(await t.addStyleTag({content:xt.css}),await t.addScriptTag({content:xt.js}),await t.evaluate(jo)):await t.evaluate(Go)}async showHints(){await this.toggleHints({state:"on"});let e=async()=>{try{await this.toggleHints({state:"off"})}catch(t){this.logger.debug({err:t},"Failed to remove vision hints")}};setTimeout(()=>{e()},3e3)}async cleanup(){await this.page.close(),await this.context.close(),this.browser&&await this.browser.close()}get closed(){return this.page.isClosed()||!!this.browser&&!this.browser.isConnected()}async html(){return(await this.getUserPageOrFrame()).content()}async url(){return(await this.getUserPageOrFrame()).url()}async screenshotWithHints({target:e,quality:t=100,scale:n="device",saveToDiskPath:o}){let s=o?.split("."),a=s?.slice(0,-1).join("."),i=s?.slice(-1)[0],l=Buffer.from("");await this.showHints();let c=await this.screenshot({target:e,quality:t,scale:n,saveToDiskPath:o?`${a}-after-hint.${i}`:void 0});return{before:l,after:c}}async screenshot({target:e,quality:t,scale:n,saveToDiskPath:o,hideCaret:s}){let a={fullPage:!1,quality:t,scale:n,type:"jpeg",caret:s?"hide":"initial",path:o};if(e){let i=await this.resolveCachedTargetToNode(e);return(await this.getLocatorFromA11yNode(i)).screenshot(a)}else return!this.localMode||!this.activeFrame?this.page.screenshot(a):this.page.locator(`iframe[name="${this.activeFrame}"]`).screenshot(a)}async getViewport(){if(this.localMode&&this.activeFrame){let t=await this.page.locator(`iframe[name="${this.activeFrame}"]`).boundingBox();if(!t)throw new Error(`Failed to get bounding box for frame: ${this.activeFrame}`);return t}let e=this.page.viewportSize();if(!e)throw new Error("failed to get viewport");return e}async navigate({url:e,wrapPossibleNavigation:t=!0,initialNavigation:n=!1,timeout:o=8e3}){this.logger.debug(`Navigating to ${e}`);let s=Date.now(),a=async()=>{try{await(await this.getUserPageOrFrame()).goto(e,{waitUntil:"load",timeout:o??void 0}),this.logger.debug({url:e},`Got load event in ${Math.floor(Date.now()-s)}ms`)}catch(l){if(l instanceof Error&&l.message.includes("ERR_ABORTED"))return;this.logger.warn({url:e,err:l},"Timeout elapsed waiting for page to fire load event. Are you sure this page is accessible?")}};t?await this.wrapPossibleNavigation(a):await a();let i=await this.url();if(_o.has(i)&&process.env.NODE_ENV==="production")throw new T("ActionFailureError",`${e} took too long to load \u{1F61E}. Please ensure the site and your internet are working.`,{},!0);if(n){if(!await this.initCDPSession(o))throw new T("ActionFailureError",`Initializing libraries timed out on ${e} \u{1F61E}. Please ensure the site and your internet are working.`,{},!0);if(await this.pageSetup(),await this.attachPageLoadListeners(),this.localMode)try{await this.exposeRecordingBindings()}catch(c){c instanceof Error&&c.message.includes("already registered")||this.logger.error({err:c},"Failed to expose recording bindings during navigation")}}this.logger.info({url:e},"Navigation complete")}async type(e,t={}){let{clearContent:n=!0,pressKeysSequentially:o=!1}=t;n&&(process.platform==="darwin"?await this.page.keyboard.press("Meta+A"):await this.page.keyboard.press("Control+A"),await this.page.keyboard.press("Backspace")),o?await this.page.keyboard.type(e):await this.page.keyboard.insertText(e)}async clickByA11yID(e,t={}){let n=this.a11yIdToNodeMap.get(e);if(!n)throw new Error(`Could not find DOM node during click: ${e}`);let o=await this.clickUsingCDP(n,t);return await this.highlightNode(o.id),n.serialize({noChildren:!0,noID:!0})}async selectOptionByA11yId(e,t){let n=this.a11yIdToNodeMap.get(e);if(!n)throw new Error(`Could not find DOM node while selecting option: ${e}`);return await(await this.getLocatorFromA11yNode(n)).selectOption(t,{timeout:8e3}),await this.highlightNode(n.id),n.serialize({noChildren:!0,noID:!0})}async scrollIntoView(e){let t=await this.resolveCachedTargetToNode(e);await(await this.getLocatorFromA11yNode(t)).scrollIntoViewIfNeeded({timeout:8e3})}async highlight(e){try{let t=await this.resolveCachedTargetToNode(e);await this.highlightNode(t.id)}catch(t){this.logger.warn({err:t,target:e},"Failed to highlight target")}}async highlightNode(e){let t;try{if(t=this.a11yIdToNodeMap.get(e),!t)throw new Error(`Could not find DOM node during highlight: ${e}`);await this.cdpClient.send("Overlay.highlightNode",{highlightConfig:Bo,backendNodeId:t.backendNodeID})}catch{this.logger.warn("Failed to add node highlight, a page navigation likely occurred. This is non-fatal for tests.");return}let n=async()=>{try{await this.cdpClient.send("Overlay.hideHighlight",{backendNodeId:t.backendNodeID})}catch(o){this.logger.debug({err:o},"Failed to remove node highlight")}};setTimeout(()=>{n()},3e3)}async wrapPossibleNavigation(e,t=8e3,n=!0){let o=Date.now(),s=await this.url(),a=Date.now(),i=new Map,l=new Map,c=A=>{let E=yr(A.request());l.set(E,(l.get(E)??0)+1);let k=A.status();k>=500&&this.logger.warn({request:E,status:k},"Received 500 level response")},d=A=>{if(!Xo(A,s))return;let E=yr(A);i.set(E,(i.get(E)??0)+1),a=Date.now()};this.page.on("response",c),this.page.on("request",d);let m=[];n&&(m=this.context.pages().map(A=>A.url()));let f=!1,h=e().catch(A=>(f=!0,A instanceof Error?A:new Error(`${A}`)));await B(250);let p=async A=>{let E=await A;if(E instanceof Error)throw E;return E},y=new Set,S=!1,g=await(async()=>{for(;!f&&!(!S&&Date.now()-o>t);){if(await B(250),S=!1,y=new Set,Date.now()-a<=1250)continue;let A=!1;for(let E of i.keys())i.get(E)!==l.get(E)&&(Yo(E)&&(S=!0),A=!0,y.add(E));if(!A)return this.logger.debug({url:await this.url(),requests:JSON.stringify(Array.from(i.entries()))},`Network idle in ${Math.floor(Date.now()-o)}ms`),!0}return!f&&y.size>0&&this.logger.warn({url:await this.url(),unfinishedRequests:JSON.stringify(Array.from(y.entries()))},"Timeout elapsed waiting for network idle, continuing anyways..."),!1})();if(this.page.off("response",c),this.page.off("request",d),!g)return p(h);let R=await this.url();if(!f&&Pe(R,s)){this.logger.debug({startUrl:s,newUrl:R},"Detected url change in wrapPossibleNavigation, waiting for load state");let A=Math.max(t-(Date.now()-o),0);if(A>0)try{await(await this.getUserPageOrFrame()).waitForLoadState("load",{timeout:A})}catch{this.logger.warn({url:await this.url()},"Timeout elapsed waiting for load state, continuing anyways...")}}if(n){let A=this.context.pages().map(E=>E.url());if(A.length>m.length)for(let E=0;E<A.length;E++){let k=A[E];k!==R&&await this.switchToPage(k,E)}}return p(h)}async resolveCachedTargetToNode(e){if(!mt(e)){let i=this.a11yIdToNodeMap.get(e.id);if(!i)throw new Error(`Resolving target failed, fresh value did not exist in node map: ${e.id}`);return nt(i,e),i}let t=(await this.getA11yTree()).serialize();this.logger.debug({tree:t},"Refreshed a11y tree before resolving target");let n=this.a11yIdToNodeMap.get(e.id);if(n){let i=gr(n,e);if(i>=5)return this.logger.debug({target:e,proposedNode:n.getLogForm(),comparisonScore:i},"Resolved cached a11y target to node with exact same id"),nt(n,e),n}let o=1/0,s=1/0,a;for(let i of this.a11yIdToNodeMap.values()){let l=gr(i,e);if(l>=5)return this.logger.debug({newNode:i.getLogForm(),target:e,comparisonScore:l},"Resolved cached a11y target to new node with field comparison"),nt(i,e),i;if(!e.serializedForm)continue;let c=i.serialize({noID:!0,maxLevel:1,neighbors:1});if(Math.abs(c.length-e.serializedForm.length)>15)continue;let d=Bi(e.serializedForm,c),m=d/Math.min(e.serializedForm.length,c.length);d<o&&m<.2&&(o=d,s=m,a=i)}if(a&&o<15)return this.logger.debug({newNode:a.getLogForm(),target:e,distance:o,ratio:s},"Resolved cached a11y target to new node with pure levenshtein distance"),nt(a,e),a;throw new Error(`Could not find any relevant node given cached target: ${JSON.stringify({target:e,closestLevenshteinDistance:o,closestNode:a?.getLogForm()})}`)}async click(e,t={}){let n=await this.resolveCachedTargetToNode(e);return await this.wrapPossibleNavigation(()=>this.clickByA11yID(n.id,t))}async dragAndDrop(e,t,n={}){let o=await this.resolveCachedTargetToNode(e),s=await this.getLocatorFromA11yNode(o),a=await this.resolveCachedTargetToNode(t),i=await this.getLocatorFromA11yNode(a);return await s.hover(n),await this.page.mouse.down(),await i.hover(n),await B(250),await this.page.mouse.up(),o.serialize({noChildren:!0,noID:!0})}async hover(e){let t=await this.resolveCachedTargetToNode(e);return await(await this.getLocatorFromA11yNode(t)).hover({timeout:8e3}),await this.highlightNode(t.id),t.serialize({noChildren:!0,noID:!0})}async selectOption(e,t){let n=await this.resolveCachedTargetToNode(e);return this.selectOptionByA11yId(n.id,t)}async press(e){if(this.localMode&&this.activeFrame){let t=(await this.getUserPageOrFrame()).locator("html");await t.click(),await t.press(e);return}await this.wrapPossibleNavigation(()=>this.page.keyboard.press(e))}async refresh(){if(this.localMode&&this.activeFrame){let t=(await this.getUserPageOrFrame()).url();await this.navigate({url:t,wrapPossibleNavigation:!0})}else try{await this.page.reload({timeout:3e3})}catch{this.logger.warn({url:await this.url()},"Timeout elapsed waiting for page on reload, continuing anyways...")}}async getA11yTree(e=!1){let t=null,n=async()=>{let o=0,s=await this.url();for(;!t&&o<3;)try{let a=await this.getRawA11yTree(e);if(!a.root||a.allNodes.length<=1)throw new Error("No a11y tree found on page");t=Ho(a,this.logger)}catch(a){if(this.logger.error({err:a,url:s},"Error fetching a11y tree"),o===0)await B(1e3),o++;else throw new Error(`Max retries exceeded fetching a11y tree: ${a}`)}if(!t||!t.root)throw new Error("Accessibility tree appears empty");this.a11yIdToNodeMap=t.a11yIdNodeMap,this.dataMomenticIdToNodeMap=t.dataMomenticIdMap};if(await Promise.race([n(),B(8e3)]),t)return t;throw new T("ActionFailureError",`Getting accessibility tree timed out after ${8e3}ms`)}getA11yIdFromDataMomenticId(e){return this.dataMomenticIdToNodeMap.get(e)?.id}async getRawA11yTree(e=!1){let t=await this.url(),n=Date.now(),o=()=>{n=Date.now()};this.cdpClient.addListener("Accessibility.nodesUpdated",o);let s=!1,a=()=>{this.logger.info({url:t},"Load event fired on page"),s=!0,n=Date.now()};this.cdpClient.addListener("Accessibility.loadComplete",a);let i=Date.now(),l=!e;for(;!e&&Date.now()-i<3e3;){if(await B(250),!s&&Date.now()-i<1e3){process.env.NODE_ENV!=="production"&&this.logger.debug({url:t},"A11y tree not loaded yet, waiting...");continue}if(Date.now()-n>=1250){l=!1;break}this.logger.debug({url:t},"A11y tree not stable yet, waiting...")}this.logger.debug({duration:Date.now()-i,eventReceived:s,timeoutTriggered:l,skipWait:e},"A11y wait phase completed"),await(await this.getUserPageOrFrame()).evaluate(Wo);let c;if(this.localMode&&this.activeFrame){let{result:{objectId:m}}=await this.cdpClient.send("Runtime.evaluate",{expression:`document.querySelector("#${this.activeFrame}")`}),f=await this.cdpClient.send("DOM.describeNode",{objectId:m});c=(await this.cdpClient.send("Accessibility.getRootAXNode",{frameId:f.node.frameId})).node.backendDOMNodeId}else{let{node:m}=await this.cdpClient.send("Accessibility.getRootAXNode");c=m.backendDOMNodeId}let{nodes:d}=await this.cdpClient.send("Accessibility.queryAXTree",{backendNodeId:c});return this.cdpClient.removeListener("Accessibility.loadComplete",a),this.cdpClient.removeListener("Accessibility.nodesUpdated",o),{root:d[0],allNodes:d}}async clickUsingVisualCoordinates(e){let t=await this.getElementLocation(e);if(!t)throw new Error(`Could not find element location with backend node id: ${e}`);this.logger.debug({location:t},"Executing mouse click"),await this.page.mouse.click(t.centerX,t.centerY)}async getIDAttributeUsingCDP(e){await this.cdpClient.send("DOM.getDocument",{depth:0});let t=await this.cdpClient.send("DOM.requestNode",{objectId:e}),o=(await this.cdpClient.send("DOM.getAttributes",{nodeId:t.nodeId})).attributes,s=o.findIndex(a=>a===qe);if(s===-1||!o[s+1])throw new Error(`Could not find ${qe} for object ${e}`);return o[s+1]}async getLocatorFromA11yNode(e){if(!e.backendNodeID)throw new Error(`Node with a11y id ${e.id} has no backend node ID`);return this.getLocatorFromBackendID(e.backendNodeID)}async getLocatorFromBackendID(e){let t=await this.cdpClient.send("DOM.resolveNode",{backendNodeId:e});if(!t||!t.object.objectId)throw new Error(`Could not resolve backend node ${e}`);let n;try{n=await this.getIDAttributeUsingCDP(t.object.objectId)}catch(o){throw this.logger.error({err:o,object:JSON.stringify(t.object)},"Failed to get ID attribute"),o}return(await this.getUserPageOrFrame()).locator(`[${qe}="${n}"]`)}async clickUsingCDP(e,t={}){let n=0,o=e,s;for(;n<ko;){if(!o||o.role==="RootWebArea")throw new T("ActionFailureError",s??`Attempted to click node with no clickable surrounding elements: ${e.getLogForm()}`);if(o.role==="StaticText"){o=o.parent;continue}let a=o.backendNodeID;if(!a){this.logger.warn({node:o.getLogForm()},"Click candidate had no backend node ID"),o=o.parent;continue}try{let i=await this.getLocatorFromBackendID(a);return t.doubleClick?await i.dblclick({timeout:8e3}):await i.click({timeout:8e3,button:t.rightClick?"right":"left",force:t.force}),o.id!==e.id&&this.logger.info({oldNode:e.getLogForm(),newNode:o.getLogForm()},"Redirected click successfully to new element"),o}catch(i){let l=`Failed to click '${o.getLogForm()}' - are you sure the element is currently visible and not obscured on the page?`;this.logger.error({err:i},l),s||(s=l),n++,o=o.parent}}throw new Error(`Max click redirection attempts exhausted on original element: ${e.getLogForm()}`)}async getElementLocation(e){let t=await this.cdpClient.send("DOMSnapshot.captureSnapshot",{computedStyles:[],includeDOMRects:!0,includePaintOrder:!0}),n=await this.page.evaluate(()=>window.devicePixelRatio);process.platform==="darwin"&&n===1&&(n=2);let o=t.documents[0],s=o.layout,a=o.nodes,i=a.nodeName||[],l=a.backendNodeId||[],c=s.nodeIndex,d=s.bounds,m=-1;for(let g=0;g<i.length;g++)if(l[g]===e){m=c.indexOf(g);break}if(m===-1)throw new Error(`Could not find any backend node with ID ${e}`);let[f=0,h=0,p=0,y=0]=d[m];f/=n,h/=n,p/=n,y/=n;let S=f+p/2,b=h+y/2;return{centerX:S,centerY:b}}async scroll(e,t,n,o){let s=t==="left"?-1:1,a=o==="up"?-1:1;if(this.activeFrame)await(await this.getUserPageOrFrame()).evaluate(([l,c,d,m])=>window.scrollTo(window.scrollX+(l??window.innerWidth)*d,window.scrollY+(c??window.innerHeight)*m),[e,n,s,a]);else{let i=this.page.viewportSize()||de;await this.page.mouse.wheel((e??i.width)*s,(n??i.height)*a)}}async scrollUp(e){await this.scroll(0,null,e??null,"up")}async scrollDown(e){await this.scroll(0,null,e??null,"down")}async scrollLeft(e){await this.scroll(e??null,"left",0,null)}async scrollRight(e){await this.scroll(e??null,"right",0,null)}async goForward(){await this.wrapPossibleNavigation(async()=>this.localMode&&this.activeFrame?(await this.getUserPageOrFrame()).evaluate(e=>{let t=e().contentWindow;t?t.history.forward():console.error("Failed to get content window for frame")},()=>document.querySelector(`iframe[name="${this.activeFrame}"]`)):this.page.goForward({timeout:8e3}))}async goBack(){await this.wrapPossibleNavigation(async()=>this.localMode&&this.activeFrame?(await this.getUserPageOrFrame()).evaluate(e=>{let t=e().contentWindow;t?t.history.back():console.error("Failed to get content window for frame")},()=>document.querySelector(`iframe[name="${this.activeFrame}"]`)):this.page.goBack({timeout:8e3}))}async switchToPage(e,t){let n=async(s,a)=>{this.logger.info(`Switching to tab ${a} with url ${s.url()}`),this.page=s,await this.pageSetup(),await this.attachPageLoadListeners();try{await s.waitForLoadState("load",{timeout:3e3})}catch{this.logger.warn({url:await this.url()},"Timeout elapsed waiting for load state during tab switch, continuing anyways...")}if(!await this.initCDPSession())throw new T("ActionFailureError",`Initializing libraries timed out on ${s.url()} \u{1F61E}. Please ensure the site and your internet are working.`)},o=this.context.pages();if(t){await n(o[t],t);return}for(let s=0;s<o.length;s++){let a=o[s];a.url().includes(e)&&await n(a,s)}throw new Error(`Could not find page with url containing ${e}`)}async attachPageLoadListeners(){if(this.localMode)return;let e=async t=>{t.parentFrame()||await this.pageSetup()};this.page.off("framenavigated",e),this.page.on("framenavigated",e)}async setCookie(e){let t=eo(e);this.logger.debug({cookieSettings:t},"Adding cookies to session"),await this.context.addCookies(t)}async setLocalStorage(e,t){await(await this.getUserPageOrFrame()).evaluate(([o,s])=>{o&&localStorage.setItem(o,s||"")},[e,t])}async solveCaptcha(){await this.getA11yTree();let e;for(let i of this.a11yIdToNodeMap.values())if(i.role==="image"&&i.name.toLowerCase().includes("captcha")){if(!i.backendNodeID)continue;e=await this.getLocatorFromBackendID(i.backendNodeID);break}if(!e){let i=await(await this.getUserPageOrFrame()).solveRecaptchas();if(!i.captchas||!i.captchas.length)throw new Error("No captchas found on the page");return}let t=await e.screenshot({type:"jpeg",animations:"allow",caret:"hide",quality:100}),n=await fetch("https://api.2captcha.com/createTask",{method:"POST",body:JSON.stringify({clientKey:process.env.TWO_CAPTCHA_KEY,task:{type:"ImageToTextTask",body:t.toString("base64"),case:!0},languagePool:"en"})});if(!n.ok){let i=`Captcha solver API returned error response: ${n.statusText}`;throw this.logger.error({text:await n.text()},i),new Error(i)}let{taskId:o}=await n.json(),s=Date.now(),a="";for(;Date.now()-s<6e4;){await B(2500);let i=await fetch("https://api.2captcha.com/getTaskResult",{method:"POST",body:JSON.stringify({clientKey:process.env.TWO_CAPTCHA_KEY,taskId:o})});if(!i.ok){let c=`Captcha solution API returned error response: ${i.statusText}`;throw this.logger.error({text:await i.text()},c),new Error(c)}let l=await i.json();if(l.errorId){let c=`Captcha solution API returned error ID ${l.errorId}`;throw this.logger.error(c),new Error(c)}if(l.status==="ready"){a=l.solution.text;break}}if(!a)throw new Error("Captcha solution timed out");return a}getActiveFrame(){return this.activeFrame}async exposeRecordingBindings(){await this.context.exposeBinding("captureClick",async(e,t)=>{if(!this.transformer){this.logger.warn("Click captured without transformer");return}let n,o;try{n=await t.getAttribute("id"),o=await t.getAttribute(qe)}catch(l){throw this.logger.error({err:l},"Failed to get element attributes for click processing"),l}if(this.logger.info({id:n,dataMomenticId:o},"Click captured on element"),!o){this.logger.error({url:await this.url(),element:await t.evaluate(l=>l.outerHTML)},`Could not find ${qe} for recorded click`);return}let s=this.getA11yIdFromDataMomenticId(parseInt(o));if(!s){this.logger.warn({url:await this.url(),element:await t.evaluate(l=>l.outerHTML)},"Could not find a11y id for recorded click");return}let a={id:s};await this.resolveCachedTargetToNode(a),(async()=>{try{let l=this.mostRecentBrowserState??(await this.getA11yTree(!0)).serialize();await this.transformer?.recordClick(a,l)}catch(l){this.logger.error({err:l},"Failed transforming captured click")}})()},{handle:!0}),await this.context.exposeBinding("captureKeystroke",async({},{key:e})=>{this.transformer&&(this.logger.info({key:e},"Captured keypress"),this.transformer.recordKeystroke(e))})}async startRecording(e,t){this.transformer=t;let n=await this.getA11yTree(!0);this.mostRecentBrowserState=n.serialize();let o=null,s=[async()=>{this.transformer=void 0}],a=async l=>{o&&clearTimeout(o),o=setInterval(()=>{if(!this.transformer||e.aborted)return;(async()=>{let d=0;for(;d<2;)try{let m=await this.getA11yTree(!0);this.mostRecentBrowserState=m.serialize();break}catch(m){this.logger.error({err:m},"Failed to get a11y tree in frame navigation listener"),d++}})()},250),s.push(async()=>{o&&(clearInterval(o),o=null)}),await l.evaluate(Jo),s.push(async()=>{await l.evaluate(()=>{document.removeEventListener("click",window.clickListener,{capture:!0})})}),await l.evaluate(Qo),s.push(async()=>{await l.evaluate(()=>{document.removeEventListener("keydown",window.pressListener,{capture:!0})})})};await a(await this.getUserPageOrFrame());let i=async l=>{l.name().startsWith(Yt)&&(e.aborted||!this.transformer||(this.logger.info("Re-adding window recording event listeners on navigation"),await a(l)))};this.page.on("framenavigated",i),s.push(async()=>{this.page.off("framenavigated",i)}),e.addEventListener("abort",async()=>{for(let l of s)try{await l()}catch(c){this.logger.warn({err:c},"Recording cleanup function failed, continuing...")}})}async getSelectOptions(e){let t=this.a11yIdToNodeMap.get(e);return await(await this.getLocatorFromA11yNode(t)).evaluate(s=>Array.from(s.querySelectorAll("option")).map(i=>i.value))}async getHTML(){let e=await this.getUserPageOrFrame();await e.addScriptTag({content:xt.htmlJs});let t=await e.evaluate(()=>window.getHTMLBodyString());if(!t)throw new T("InternalWebAgentError","Empty HTML tree");return Vi.html(t,{indent_size:1,indent_with_tabs:!1,preserve_newlines:!1,wrap_line_length:80})}};var Ye=async({controller:r,context:e,step:t,logger:n,advanced:o,takeScreenshots:s,...a})=>{a.onStarted?.(),r.resetHistory();let i={...t,startedAt:new Date,userAgent:P.USER_AGENT,finishedAt:new Date,results:[],status:"SUCCESS"};try{let l=0;t.commands=t.commands||[];let c=t.commands&&t.commands.length>0;for(;;){if(l>12)throw new Error(`Exceeded max number of commands per step (${12})`);if(r.isClosed())throw new Error("Cancelling remaining steps in AI action because the controller is now closed");let d,m=new Date,f;if(s){let p=await r.browser.screenshot({});f=await a.onSaveScreenshot(p)}if(c){if(d=t.commands[l],!d)throw new Error(`Saved command at index ${l} is undefined.`)}else{n.info(`Generating new sub-command ${l} within AI step`);let p;try{p=await r.promptToCommand(t.type,t.text,o.disableAICaching),d=p.command}catch(S){d={type:"FAILURE",thoughts:S instanceof Error?S.message:`${S}`}}finally{if(d.type==="FAILURE")if(l===0){i.finishedAt=new Date,i.status="FAILED",i.message=d.thoughts;break}else{let S="Stopping command generation prematurely since no progress can be made";n.warn({command:d},S),d={type:"SUCCESS",thoughts:S}}}(async()=>{let S=l,b=t,g=d;if("target"in g&&g.target){await new Promise(R=>setTimeout(()=>R(),250));try{let R=await Xi(r,p.context,g.target);g.target.elementDescriptor=R,b.commands[l]=g,a.onCommandExecuted?.({commandIndex:S,command:g})}catch(R){n.error({err:R,currentIndex:S,currentStep:b},"Failed to generate element description, continuing...")}}})()}a.onCommandGenerated?.({commandIndex:l,message:Vt[d.type]||`Unknown command (${d.type})`});let h={beforeScreenshot:f,beforeUrl:await r.browser.url(),startedAt:m,viewport:await r.browser.getViewport(),finishedAt:new Date,status:"SUCCESS"};n.info(`Executing sub-command ${l} within AI step: ${We(d)}`);try{let p=await r.executeCommand(d,e,o.disableAICaching,c);n.info(`AI sub-command ${l} completed successfully`),h.elementInteracted=p.elementInteracted;let y;if(s){let b=await r.browser.screenshot({});y=await a.onSaveScreenshot(b)}h.afterScreenshot=y,h.afterUrl=await r.browser.url(),h.finishedAt=new Date;let S={status:"SUCCESS",startedAt:h.startedAt,finishedAt:h.finishedAt,type:"PRESET_ACTION",data:p.data,command:d,results:[h]};if(i.results.push(j(S)),t.commands[l]=d,a.onCommandExecuted?.({commandIndex:l,output:{...S,message:d.thoughts??p.thoughts??"Successfully executed preset action."},command:d}),d.type==="SUCCESS"){i.finishedAt=new Date,i.status="SUCCESS",i.message=p.thoughts??"All commands completed.";break}if(p.succeedImmediately&&!c){i.finishedAt=new Date,i.status="SUCCESS",i.message=p.succeedImmediatelyReason,d={type:"SUCCESS",thoughts:p.succeedImmediatelyReason},t.commands.push(d),a.onCommandExecuted?.({commandIndex:l+1,output:{...S,message:i.message},command:d}),i.results.push(j({...S,command:d}));break}}catch(p){if(c){c=!1,l=0,i.results=[];continue}let y=p instanceof Error?p.message:`${p}`;h.status="FAILED",h.message=y,h.finishedAt=new Date,h.afterUrl=await r.browser.url();let S;try{S=await r.browser.screenshot({})}catch(b){n.warn({err:b},"Failed to take screenshot after error, skipping")}h.afterScreenshot=S,i.results.push(j({status:"FAILED",startedAt:h.startedAt,finishedAt:h.finishedAt,type:"PRESET_ACTION",command:d,results:[h],message:y})),i.status="FAILED",i.finishedAt=new Date,i.message=y;break}l++}}catch(l){i.message=l instanceof Error?l.message:`${l}`,i.finishedAt=new Date,i.status="FAILED"}return i.status==="SUCCESS"?(i.data=i.results[i.results.length-1]?.data,a.onSuccess?.({message:i.message||"AI step succeeded.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i})):a.onFailure?.({message:i.message||"AI step errored.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i}),i};async function Xi(r,e,t){let n=t.a11yData?.id;if(!n)throw new Error("Attempted to get reverse mapping for command with no a11y id target");return r.getReverseMappedTarget(e,n,!0)}var Xe=async({controller:r,context:e,step:t,advanced:n,takeScreenshots:o,...s})=>{s.onStarted?.();let a=new Date,i=await r.browser.url(),l;if(o){let d=await r.browser.screenshot({});l=await s.onSaveScreenshot(d)}let c;try{let d=await r.executePresetStep(t.command,e,n.disableAICaching),m=d.screenshotOverride;if(o&&(m||(m=await r.browser.screenshot({})),c=await s.onSaveScreenshot(m)),d.fail)throw new T("ActionFailureError",d.thoughts||"Preset action failed.");let f=new Date,h={...t,startedAt:a,finishedAt:f,status:"SUCCESS",data:d.data,results:[]},p="Successfully executed preset action.";"assertion"in t.command&&(p=d.thoughts||"Assertion passed.");let y={beforeUrl:i,beforeScreenshot:l,afterUrl:await r.browser.url(),afterScreenshot:c,startedAt:a,finishedAt:f,viewport:await r.browser.getViewport(),status:"SUCCESS"};return h.status="SUCCESS",h.results=[y],h.message=p,s.onSuccess?.({message:p,startedAt:a.getTime(),durationMs:f.getTime()-a.getTime(),command:t.command,output:h}),h}catch(d){s.logger.error({err:d},`Failed executing preset step ${t.command.type}`);let m=new Date,f=d instanceof Error?d.message:`${d}`;if(o&&!c&&(c=await s.onSaveScreenshot(await r.browser.screenshot({}))),"cancelOnFailure"in t.command&&t.command.cancelOnFailure){let p={...t,startedAt:a,finishedAt:m,status:"CANCELLED",message:f,results:[{beforeUrl:i,beforeScreenshot:l,afterUrl:await r.browser.url(),afterScreenshot:c,startedAt:a,finishedAt:m,viewport:await r.browser.getViewport(),status:"CANCELLED",message:f}]};return s.onCancelled?.({message:f,startedAt:a.getTime(),durationMs:m.getTime()-a.getTime(),output:p}),p}let h={...t,startedAt:a,finishedAt:m,status:"FAILED",message:f,results:[{beforeUrl:i,beforeScreenshot:l,afterUrl:await r.browser.url(),afterScreenshot:c,startedAt:a,finishedAt:m,viewport:await r.browser.getViewport(),status:"FAILED",message:f}]};return s.onFailure?.({message:f,startedAt:a.getTime(),durationMs:m.getTime()-a.getTime(),output:h}),h}};var Ot=async({controller:r,context:e,step:t,advanced:n,logger:o,takeScreenshots:s,...a})=>{a.onStarted?.();let i={type:"MODULE",moduleId:t.moduleId,startedAt:new Date,userAgent:P.USER_AGENT,results:[],finishedAt:new Date,status:"SUCCESS"};for(let l=0;l<t.steps.length;l++){let c=t.steps[l];if(r.isClosed())throw i.status="CANCELLED",new Error("Cancelling remaining steps in module because the controller is now closed");o.debug({i:l,moduleStep:c},"Starting module step"),o.info(`Starting module sub-step ${l+1}/${t.steps.length}: ${At(c)}`);let d;switch(c.type){case"PRESET_ACTION":d=await Xe({controller:r,context:e,step:c,advanced:n,logger:o,takeScreenshots:s,onSaveScreenshot:a.onSaveScreenshot,onStarted(){a.onStepStarted?.({index:l})},onSuccess({message:f,startedAt:h,durationMs:p,output:y}){a.onStepSuccess?.({index:l,message:f,startedAt:h,durationMs:p,output:y})},onFailure({message:f,startedAt:h,durationMs:p,output:y}){a.onStepFailure?.({index:l,message:f,startedAt:h,durationMs:p,output:y})},onCancelled({message:f,startedAt:h,durationMs:p,output:y}){a.onStepCancelled?.({index:l,message:f,startedAt:h,durationMs:p,output:y})}});break;case"AI_ACTION":d=await Ye({controller:r,context:e,step:c,advanced:n,logger:o,takeScreenshots:s,onSaveScreenshot:a.onSaveScreenshot,onStarted(){a.onStepStarted?.({index:l})},onSuccess({message:f,startedAt:h,durationMs:p,output:y}){a.onStepSuccess?.({index:l,message:f,startedAt:h,durationMs:p,output:y})},onFailure({message:f,startedAt:h,durationMs:p,output:y}){a.onStepFailure?.({index:l,message:f,startedAt:h,durationMs:p,output:y})},onCommandGenerated({commandIndex:f,message:h}){a.onCommandGenerated?.({index:l,commandIndex:f,message:h})},onCommandExecuted({commandIndex:f,command:h,output:p}){a.onCommandExecuted?.({index:l,commandIndex:f,command:h,output:p})}});break;default:return(f=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(c)}if(i.results.push(j(d)),d.status==="FAILED"||d.status==="CANCELLED"){i.status=d.status,i.finishedAt=new Date,i.message=d.message;for(let m=l+1;m<t.steps.length;m++){let h={...t.steps[m],status:"CANCELLED",startedAt:new Date,finishedAt:new Date,userAgent:P.USER_AGENT,results:[],message:"Cancelled due to previous failure."};i.results.push(j(h))}break}}return i.status==="SUCCESS"?(i.data=i.results[i.results.length-1]?.data,a.onSuccess?.({message:"Executed module step.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i})):i.status==="FAILED"?a.onFailure?.({message:"Failed to execute module step.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i}):i.status==="CANCELLED"&&a.onCancelled?.({message:"Module step cancelled.",startedAt:i.startedAt.getTime(),durationMs:i.finishedAt.getTime()-i.startedAt.getTime(),output:i}),i};var nn=async({test:r,runId:e,controller:t,context:n,logger:o,takeScreenshots:s,onUpdateRun:a,onSaveScreenshot:i,onTestSuccess:l})=>{try{let c=await Ji({test:r,runId:e,controller:t,context:n,logger:o,takeScreenshots:s,onUpdateRun:a,onSaveScreenshot:i});if(c==="PASSED"||c==="CANCELLED")return await l?.(r),c;throw new T("ActionFailureError",c.message||"An unknown error occurred")}catch(c){throw c instanceof T||(c=new T("InternalPlatformError",c instanceof Error?c.message:`${c}`,{cause:c})),c}finally{await t.browser.cleanup()}},Ji=async({test:r,runId:e,controller:t,context:n,logger:o,takeScreenshots:s,onUpdateRun:a,onSaveScreenshot:i})=>{let l=ie.parse(r.advanced),c=o.child({runId:e,testId:r.id});c.info("Starting test run"),await a({status:"RUNNING",startedAt:new Date});let d,m="PASSED",f=[];for(let h=0;h<r.steps.length;h++){let p=r.steps[h];c.info(`Starting step ${h+1}/${r.steps.length}: ${At(p)}`);let y=n.toObjectCopy(),S;switch(p.type){case"PRESET_ACTION":S=await Xe({controller:t,context:n,step:p,advanced:l,logger:c,takeScreenshots:s,onSaveScreenshot:i});break;case"AI_ACTION":S=await Ye({controller:t,context:n,step:p,advanced:l,logger:c,takeScreenshots:s,onSaveScreenshot:i});break;case"RESOLVED_MODULE":S=await Ot({controller:t,context:new Y(await t.browser.url(),p.steps),step:p,advanced:l,logger:c,takeScreenshots:s,onSaveScreenshot:i});break;default:return(g=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(p)}if(f.push({...j(S),beforeTestContext:y,afterTestContext:n.toObjectCopy()}),n.setResult(h,S.data),n.setVariable("CURRENT_URL",await t.browser.url()),await a({results:f}),S.status==="SUCCESS"){c.info(`Step ${h+1}/${r.steps.length} succeeded`);continue}if(S.status!=="FAILED"&&S.status!=="CANCELLED")throw new T("InternalPlatformError",`Received unexpected non-terminal status from step: ${S.status}`);c.info({message:f[f.length-1]?.message},`Step ${h+1}/${r.steps.length} ended with status: ${S.status}`),d=S,m=S.status;for(let b=h+1;b<r.steps.length;b++){let g=j(r.steps[b]);if(g.type==="RESOLVED_MODULE"){let R={type:"MODULE",moduleId:g.moduleId,startedAt:new Date,userAgent:P.USER_AGENT,results:g.steps.map(A=>({...A,status:"CANCELLED",startedAt:new Date,finishedAt:new Date,userAgent:P.USER_AGENT,results:[]})),finishedAt:new Date,status:"CANCELLED"};f.push(R)}else{let R={...g,status:"CANCELLED",startedAt:new Date,finishedAt:new Date,userAgent:P.USER_AGENT,results:[]};f.push(R)}}break}return await a({status:m,finishedAt:new Date,results:f}),m==="FAILED"?d:m};var sn={currentlyExecutingRequests:0},Qi=r=>async e=>{let t=!1;try{sn.currentlyExecutingRequests++,t=await Zi({...r,...e})}finally{r.logger.info({success:t,sessionId:r.metadata.sessionId},"Test execution complete"),sn.currentlyExecutingRequests--}},Zi=async({socket:r,steps:e,baseUrl:t,testMetadata:n,reInitialize:o,indicesFilter:s,metadata:a,logger:i,rootState:l,localApp:c})=>{let{testId:d,sessionId:m,orgId:f}=a,h={testId:d,orgId:f,baseUrl:t},p=i.child(h),y=i.child({package:"web-agent",...h}),S=!0,b=!0;c==="iframe"&&(b=!1);let g=ie.parse(n.advanced??{}),R=H.getSession(m);if(!R)throw new Error("No active session found");let{controller:A,context:E}=R;A.setOpen();let k=P.USER_AGENT;p.info({reInitialize:o,context:E,steps:e.map(z=>`${z.type}${"command"in z?` - ${z.command.type}`:""}`),indicesFilter:s},"Starting execution");let Be={url:t,clearCookies:!0,clearStorage:!0};if(o&&(l?(A.browser.baseURL=t,A.browser.setActiveFrame(wt),await A.resetState(Be),A.setLogger(y),A.browser.setLogger(y)):await A.resetState(Be),A.setOpen(),E.reset(t)),p.info(`Session restarted for test ${d} at ${t}`),r.emit("session",{url:t,userAgent:k,viewport:await A.browser.getViewport(),localApp:c}),E.setSteps(e),s?.length){let z=ta(e,s);return p.info({indices:s,stepType:z.type,commandType:"command"in z?z.command.type:void 0},"Starting individual step"),r.emit("started",{indices:s}),S=await an({indices:s,step:z,controller:A,context:E,advanced:g,socket:r,logger:p,takeScreenshots:b}),r.emit("testContext",{state:E.toObjectRef()}),r.emit("finished"),S}else E.clearResults(),r.emit("testContext",{state:E.toObjectRef()});for(let z=0;z<e.length&&!(A.browser.closed||A.isClosed()||r.disconnected);z++){let Ve=e[z];p.info({index:z,type:Ve.type,commandType:"command"in Ve?Ve.command.type:void 0},"Starting step");let x=await an({indices:[z],step:Ve,controller:A,context:E,advanced:g,socket:r,logger:p,takeScreenshots:b});if(r.emit("testContext",{state:E.toObjectRef()}),!x){S=!1;break}}return r.emit("finished"),S},ea=(r,e)=>{switch(r.type){case"RESOLVED_MODULE":return r.steps[e];case"AI_ACTION":let t=r.commands[e];return{type:"PRESET_ACTION",command:t};case"PRESET_ACTION":default:throw new Error(`Cannot get a child step from step type ${r.type}`)}},ta=(r,e)=>{let t=r[e[0]];for(let n=1;n<e.length;n++)t=ea(t,e[n]);return t},wr=async r=>r,an=async r=>{try{return await ra(r)}catch(e){throw e instanceof T&&e.emitToUser&&r.socket.emit("error",{message:e.message}),e}},ra=async({indices:r,step:e,controller:t,context:n,advanced:o,socket:s,logger:a,takeScreenshots:i})=>{let l=()=>{s.emit("started",{indices:r})},c=({message:h,startedAt:p,durationMs:y,command:S,output:b})=>{s.emit("success",{indices:r,message:h,startedAt:p,durationMs:y,command:S,output:ue.parse(b)})},d=({message:h,startedAt:p,durationMs:y,output:S})=>{s.emit("failure",{indices:r,message:h,startedAt:p,durationMs:y,output:ue.parse(S)})},m=({message:h,startedAt:p,durationMs:y,output:S})=>{s.emit("cancelled",{indices:r,message:h,startedAt:p,durationMs:y,output:ue.parse(S)})},f;switch(e.type){case"PRESET_ACTION":{f=await Xe({controller:t,context:n,step:e,advanced:o,logger:a,takeScreenshots:i,onSaveScreenshot:wr,onStarted:l,onSuccess:c,onFailure:d,onCancelled:m});break}case"AI_ACTION":{f=await Ye({controller:t,context:n,step:e,advanced:o,logger:a,takeScreenshots:i,onSaveScreenshot:wr,onStarted:l,onSuccess:c,onFailure:d,onCommandGenerated({commandIndex:p,message:y}){s.emit("commandGenerated",{indices:[...r,p],message:y})},onCommandExecuted({commandIndex:p,command:y,output:S}){s.emit("commandExecuted",{indices:[...r,p],command:y,output:ue.parse(S)})}});break}case"RESOLVED_MODULE":{f=await Ot({controller:t,context:new Y(t.browser.baseURL,e.steps),step:e,advanced:o,logger:a,takeScreenshots:i,onSaveScreenshot:wr,onStarted:l,onSuccess:c,onFailure:d,onCancelled:m,onStepStarted({index:p}){s.emit("started",{indices:[...r,p]})},onStepSuccess({index:p,message:y,startedAt:S,durationMs:b,output:g}){s.emit("success",{indices:[...r,p],message:y,startedAt:S,durationMs:b,output:ue.parse(g)})},onStepFailure({index:p,message:y,startedAt:S,durationMs:b,output:g}){s.emit("failure",{indices:[...r,p],message:y,startedAt:S,durationMs:b,output:ue.parse(g)})},onStepCancelled({index:p,message:y,startedAt:S,durationMs:b,output:g}){s.emit("cancelled",{indices:[...r,p],message:y,startedAt:S,durationMs:b,output:ue.parse(g)})},onCommandGenerated({commandIndex:p,index:y,message:S}){s.emit("commandGenerated",{indices:[...r,y,p],message:S})},onCommandExecuted({index:p,commandIndex:y,command:S,output:b}){s.emit("commandExecuted",{indices:[...r,p,y],command:S,output:ue.parse(b)})}});break}default:return(p=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}return n.setResult(r[0],f.data),n.setVariable("CURRENT_URL",await t.browser.url()),f.status==="SUCCESS"};var ln={event:"execute",createHandler:Qi};var oa=({metadata:r,logger:e,socket:t})=>{let{sessionId:n}=r;return async(o,s)=>{let{description:a,useVision:i,testMetadata:l,isSelect:c,returnScreenshot:d}=o;e.info({description:a,useVision:i},"Locate handler called");let m=H.getSession(n);if(!m)throw new Error("No active session found");let{controller:f,context:h}=m,p=ie.parse(l.advanced??{}),y,S;if(a)try{if(y=await f.locateElement(a,i,p.disableAICaching,h),S={id:y.id},await f.browser.resolveCachedTargetToNode(S),c)try{y.options=await f.browser.getSelectOptions(y.id)}catch(g){e.warn({err:g},"Failed getting select options"),t.emit("error",{message:`Failed getting select options: ${g}`})}e.info({locator:y,a11yData:S},"Located element result")}catch(g){e.error({err:g},"Error locating element"),t.emit("error",{message:g instanceof Error?g.message:`${g}`}),s({found:!1});return}let b;if(d){let{buffer:g,width:R,height:A}=await f.screenshotWithDimensions({target:S,hideCaret:!0});b={data:g.toString("base64"),width:R,height:A}}if(y)try{await f.browser.scrollIntoView({id:y.id}),await f.browser.highlight({id:y.id})}catch(g){e.warn({err:g,locator:y},"Error highlighting element")}s({found:!0,locator:y,a11yData:S,screenshot:b})}},cn={event:"locate",createHandler:oa};var na=({socket:r,metadata:e,logger:t})=>{let{sessionId:n}=e;return async({action:o,indices:s},a)=>{try{let i=H.getSession(n);if(!i)throw new Error("No active session found");let{controller:l}=i;o==="START"&&t.info({sessionId:n},"Starting record mode"),await l.toggleRecordMode({action:o,indices:s,onStepRecord:(c,d)=>{r.emit("stepRecorded",{step:c,indices:d})}}),a()}catch(i){t.error({err:i},"Error in record socket handler"),a(i instanceof Error?i.message:`${i}`)}}},dn={event:"record",createHandler:na};var sa=({socket:r,metadata:e,rootState:t,logger:n,localApp:o})=>async({baseUrl:s})=>{let{testId:a,sessionId:i}=e;n.info({testId:a,sessionId:i,baseUrl:s},"Reset event received");let l,c=null;if(t?.controller){let{controller:m,context:f}=t;await m.resetState({clearCookies:!0,clearStorage:!0,url:s}),l=m.browser.baseURL,f.reset(l)}else{let m=H.getSession(i);if(!m){r.emit("error",{message:"No session to reset"});return}let{controller:f,context:h}=m;await f.browser.reset({clearCookies:!0,clearStorage:!0,url:s}),l=f.browser.baseURL,h.reset(l),c=await f.browser.getViewport()}let d=P.USER_AGENT;n.info(`Session reset for test ${a} at ${l}`),r.emit("session",{url:l,userAgent:d,viewport:c,localApp:o})},mn={event:"reset",createHandler:sa};import{v4 as Aa}from"uuid";var ia={type:"a11y",version:"1.0.0",useHistory:"diff",useGoalSplitter:!0},Fe=ia;import ya from"buffer-image-size";import{existsSync as ha}from"fs";import{faker as aa}from"@faker-js/faker";import la from"assert";import ca from"axios";import da from"moment";import ma from"p-timeout";var ua=Object.getPrototypeOf(async function(){}).constructor;async function un({code:r,fragment:e,state:t,timeoutMs:n=1e4}){let o=r;e&&(o=`return ${r}`);let s=JSON.parse(JSON.stringify(t)),a=(c,d)=>{s.env[c]=d,t.env[c]=d},i;return await ma((async()=>{i=await Promise.resolve(new ua("axios","moment","faker","assert","env","steps","results","setVariable",o)(ca,da,aa,la,s.env,s.steps,s.results,a))})(),{milliseconds:n,message:`Timeout of ${n}ms exceeded for code execution`}),i}import{z as ze}from"zod";var pn=process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT,pa=ze.object({result:ze.unknown(),variableUpdates:ze.record(ze.string(),ze.unknown()).optional(),error:ze.string().optional(),success:ze.boolean()});async function hn({code:r,fragment:e,state:t,logger:n,timeoutMs:o=1e4}){let s=new AbortController;if(!pn)throw new Error("GCP_JS_EVAL_FUNCTION_ENDPOINT environment variable not set");let a=setTimeout(()=>{s.abort()},o),i=await fetch(pn,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:r,fragment:e,state:t}),signal:s.signal});if(!i.ok)throw new Error(`Code evaluation server returned error code: ${i.status}`);clearTimeout(a);let l;try{l=pa.parse(await i.json()),n.debug({response:l},"Response from code evaluation server")}catch(c){throw new Error(`Code evaluation server returned invalid response: ${c}`)}if(l.error)throw new Error(`Code evaluation server returned error: ${l.error}`);if(l.variableUpdates)for(let[c,d]of Object.entries(l.variableUpdates))t.env[c]=d;return l.result}var fa=ga();function ga(){if(process.env.NODE_ENV!=="production")return!1;if(process.env.NAMESPACE)return!0;try{if(ha("/var/run/secrets/kubernetes.io/serviceaccount/token"))return!0}catch{}return!1}async function br(r){let e;return fa?(r.logger.info({code:r.code,fragment:r.fragment,state:r.state},"Running code remotely"),e=hn):(r.logger.info({code:r.code,fragment:r.fragment},"Running code locally"),e=un),e(r)}async function vr({s:r,state:e,logger:t,timeoutMs:n=2e3}){let o=/{{(.*?)}}/g,s=r.matchAll(o),a=r;for(let i of s){if(i.length<2)continue;let l=i[1].trim(),c=await br({code:l,fragment:!0,state:e,timeoutMs:n,logger:t}),d=typeof c=="string"?c:`${c}`;a=a.replace(i[0],d)}return a}import Sa from"dedent";import wa from"diff-lines";import Er from"jpeg-js";import ba from"pixelmatch";var Mt=class r{static ACTION_DEBOUNCE_DELAY=1e3;onStepRecord;signal;generator;indices;keyBuffer=[];timer=null;keyBufferMode="normal";lastStep=null;constructor({signal:e,onStepRecord:t,generator:n,initialIndices:o}){this.signal=e,this.onStepRecord=(s,a)=>{this.lastStep={step:s,indices:a},t(s,a)},this.generator=n,this.indices=o}async recordClick(e,t){if(this.signal.aborted)return;let n=ut("CLICK"),o={type:"PRESET_ACTION",command:{...n,target:{elementDescriptor:`Generating description for: ${e.nodeOnlySerializedForm?.trim()??`element with id ${e.id}`}`,a11yData:e}}},s=Array.from(this.indices);this.indices[this.indices.length-1]++,this.onStepRecord(o,s);let a=await this.generator.getReverseMappedDescription({goal:`${e.id}`,browserState:t},!1);o.command.target.elementDescriptor=a.phrase,this.onStepRecord(o,s)}flushKeyBufferToCommand(){let e;if(this.keyBufferMode==="normal"){let o=ut("TYPE");e={type:"PRESET_ACTION",command:{...o,target:void 0,value:this.keyBuffer.join("")}}}else{let o=ut("PRESS");e={type:"PRESET_ACTION",command:{...o,value:this.keyBuffer.join("+")}}}let t,n=this.lastStep?.step.command;if(n?.type===e.command.type){let o=n.value,s=e.command.value;e={type:"PRESET_ACTION",command:{...n,value:e.command.type==="PRESS"?`${o}+${s}`:`${o}${s}`}},t=this.lastStep.indices}else n?.type==="CLICK"&&e.command.type==="TYPE"?(this.lastStep.step.command={...e.command,target:n.target},e=this.lastStep.step,t=this.lastStep.indices):(t=Array.from(this.indices),this.indices[this.indices.length-1]++);this.onStepRecord(e,t),this.keyBuffer=[],this.timer=null}recordKeystroke(e){if(e==="Shift"||e==="CapsLock"||this.signal.aborted)return;this.timer!==null&&clearTimeout(this.timer);let t="normal";e.length>1&&(t="special"),this.keyBuffer.length!==0&&t!==this.keyBufferMode&&this.flushKeyBufferToCommand(),this.keyBufferMode=t,this.keyBuffer.push(e),this.timer=setTimeout(()=>{this.flushKeyBufferToCommand()},r.ACTION_DEBOUNCE_DELAY)}};var Ar=(r,e,t)=>{let[n,...o]=e.split("."),s=n;return o.length>=1?Ar(r[s],o.join("."),t):r[s]=t,r};var va=1e4,ge=class{browser;pendingInstructions;generator;commandHistory;config;closed=!1;logger;recordAbortController=null;constructor({browser:e,config:t,generator:n,logger:o}){this.browser=e,this.generator=n,this.config=t,this.logger=o,this.pendingInstructions=[],this.commandHistory=[]}get history(){return this.commandHistory.filter(e=>e.state==="DONE")}get lastExecutedCommand(){let e=this.history;return e.length===0?null:e[e.length-1]}setOpen(){this.closed=!1}isClosed(){return this.closed}setLogger(e){this.logger=e}resetHistory(){this.commandHistory=[],this.pendingInstructions=[]}async resetState(e){this.resetHistory(),this.closed=!0,await this.browser.reset(e)}async getBrowserState(){let t=await(await this.browser.getA11yTree()).serialize();return this.logger.debug({tree:t,activeFrame:this.browser.getActiveFrame()},"Got a11y tree"),t}getSerializedHistory(e,t){let n;return this.config.useHistory==="diff"?n=this.getDiffHistory(e,t):n=this.getListHistory(),n}async splitUserGoal(e,t,n){if(e==="AI_ACTION"&&t.match(/[,!;.]|(?:and)|(?:then)/)&&this.config.useGoalSplitter){let o=await this.generator.getGranularGoals({goal:t,url:await this.browser.url()},n);this.pendingInstructions=o.reverse()}else this.pendingInstructions=[t]}async promptToCommand(e,t,n){try{return await this.promptToCommandHelper(e,t,n)}catch(o){throw o instanceof T?o:new T("InternalWebAgentError",o instanceof Error?o.message:`${o}`,{cause:o})}}async promptToCommandHelper(e,t,n){if(this.pendingInstructions.length===0){if(!t.trim())throw new Error("Cannot generate commands for empty goal");await this.splitUserGoal(e,t,n)}let o=this.pendingInstructions[this.pendingInstructions.length-1];this.logger.info({goal:o},"Starting prompt translation");let s=Date.now(),a=await this.browser.url(),i=await this.getBrowserState();this.logger.info({duration:Date.now()-s,url:a},"Got browser state");let l=this.commandHistory.length;this.commandHistory.push({state:"PENDING",browserStateBeforeCommand:i,urlBeforeCommand:a,type:e});let c=this.getSerializedHistory(a,i),d={url:a,numPrevious:l,browserState:i,history:c,goal:o,lastCommand:this.lastExecutedCommand},m=await this.generator.getProposedCommand(d,n);if(this.logger.info({type:m.type,thoughts:m.thoughts},"Got proposed command"),m.type==="SUCCESS"){let f=this.pendingInstructions.pop();if(this.logger.info({finishedInstruction:f,remainingInstructions:this.pendingInstructions},"Removing pending instruction due to SUCCESS"),this.pendingInstructions.length!==0)return this.commandHistory=[],this.promptToCommand(e,"",n)}else m.type==="FAILURE"&&(this.logger.info({remainingInstructions:this.pendingInstructions},"Removing pending instructions due to FAILURE"),this.pendingInstructions=[]);return{context:d,command:m}}async locateElement(e,t,n,o){if(!e)throw new T("ActionFailureError","Cannot locate element with empty description");o&&(e=await vr({s:e,state:o.toObjectRef(),logger:this.logger}));let s=await this.getBrowserState(),a;if(t){let{before:i,after:l}=await this.browser.screenshotWithHints({});if(a=await this.generator.getElementLocationWithVision({goal:e,screenshot:i,hintActivatedScreenshot:l},n),a.id>0){let c=this.browser.getA11yIdFromDataMomenticId(a.id);if(!c)throw new T("InternalWebAgentError",`Unable to find corresponding DOM node for id ${a.id}`);a.id=c}}else a=await this.generator.getElementLocation({browserState:s,goal:e},n);if(a.id<0)throw new T("ActionFailureError",`Unable to locate element: ${a.thoughts?a.thoughts:"please ensure the element is visible and conforms to Accessibility guidelines"}`);return a}getDiffHistory(e,t){let n=this.history.filter(s=>s.type==="AI_ACTION");if(n.length===0)return"<NONE/>";let o=[`
|
|
25
|
+
You have already executed the following commands successfully (most recent listed first)`,"-".repeat(10)];return n.reverse().forEach((s,a)=>{if(o.push(`COMMAND ${n.length-a}${a===0?" (command just executed)":""}: ${s.serializedCommand}`),a===0)if(Pe(s.urlBeforeCommand,e))o.push(` URL CHANGE: '${s.urlBeforeCommand}' -> '${e}'`);else{let i=wa(s.browserStateBeforeCommand,t,{n_surrounding:1});i?i.length<va?(o.push("PAGE CONTENT CHANGE:"),i.split(`
|
|
26
26
|
`).forEach(l=>o.push(` ${l}`))):o.push("PAGE CONTENT CHANGE: <TOO_LONG_TO_DISPLAY/>"):o.push("PAGE CONTENT CHANGE: <NONE/>")}o.push("-".repeat(10))}),o.push(`STARTING URL: ${this.browser.baseURL}`),o.join(`
|
|
27
|
-
`)}getListHistory(){return
|
|
27
|
+
`)}getListHistory(){return Sa`Here are the commands that you have successfully executed:
|
|
28
28
|
${this.commandHistory.filter(e=>e.type==="AI_ACTION").map(e=>`- ${e.serializedCommand}`).join(`
|
|
29
|
-
`)}`}async executeCommand(e,t,n,o=!1){let s=this.commandHistory[this.commandHistory.length-1];if(!o&&(!s||s.state!=="PENDING"))throw new T("InternalWebAgentError","Executing command but there is no pending entry in the history");if(this.closed)throw new Error("Attempting to execute command on a closed controller");let i=Date.now(),a=await this.executePresetStep(e,t,n),l=Date.now()-i;return this.logger.debug({result:a,duration:l},"Got execution result"),a.succeedImmediately&&!o&&(this.pendingInstructions.pop(),this.pendingInstructions.length>0&&(a.succeedImmediately=!1)),a.elementInteracted&&"target"in e&&e.target&&!e.target.elementDescriptor&&(e.target.elementDescriptor=a.elementInteracted.trim()),o||(s.generatedStep=e,s.serializedCommand=Ge(e),s.state="DONE"),a}async executeAssertion(e){let t=await this.getBrowserState(),n=await this.browser.url(),o;if(e.useVision)o={goal:e.assertion,url:n,screenshot:await this.browser.screenshot({}),browserState:"",history:"",numPrevious:-1,lastCommand:null};else{let i=this.getSerializedHistory(n,t);o={goal:e.assertion,url:n,browserState:t,history:i,lastCommand:this.lastExecutedCommand,numPrevious:this.commandHistory.length}}let s=await this.generator.getAssertionResult(o,e.useVision,e.disableCache);if(s.relevantElements&&Promise.all(s.relevantElements.map(i=>this.browser.highlight({id:i}))),!s.result)throw new T("AssertionFailureError",s.thoughts);return{succeedImmediately:!1,thoughts:s.thoughts,urlAfterCommand:n}}async wrapMultiElementTargetingCommand(e,t,n,...o){let s=await Promise.all(o.map(i=>this.wrapElementTargetingCommand(i,t.useVision,t.disableCache,async a=>a)));try{return await e(...s)}catch(i){if(n>0)return this.logger.warn({err:i},"Failed to execute action with multiple cached targets, retrying with AI"),o.forEach(a=>a.a11yData=void 0),this.wrapMultiElementTargetingCommand(e,t,n-1,...o);throw new T("ActionFailureError","",{cause:i})}}async wrapElementTargetingCommand(e,t,n,o,s=1){if(!e.a11yData&&!e.elementDescriptor)throw new T("ActionFailureError","Cannot target element with no target data or element descriptor");let i=e.a11yData&&ct(e.a11yData);e.a11yData||(this.logger.info("No cached locator data for target, prompting AI for fresh location"),s--,e.a11yData=lt.parse(await this.locateElement(e.elementDescriptor,t,n)));try{let a=await o(e.a11yData);return i?this.logger.info({target:e},"Successfully used cached target to perform action"):this.logger.debug({target:e},"Successfully generated and used new a11y target information"),a}catch(a){if(s>0&&e.elementDescriptor)return this.logger.warn({err:a,target:e},"Failed to execute action with cached target, retrying with AI"),e.a11yData=void 0,this.wrapElementTargetingCommand(e,t,n,o,s);if(a instanceof T)throw a;let l=`Failed to find ${e.elementDescriptor?`${e.elementDescriptor}`:"element"}: ${a instanceof Error?a.message:a}`;throw this.logger.error({err:a,target:e},l),new T("ActionFailureError",l,{cause:a})}}async screenshotWithDimensions(e){let t=await this.browser.screenshot(e),n=da(t);return{buffer:t,...n}}async executePresetStep(e,t,n){let o;try{o=await this.resolveCommandTemplateStrings(e,t)}catch(s){throw new T("ActionFailureError",s.message,{cause:s})}try{return await this.executePresetStepHelper(e,t,n)}catch(s){throw s instanceof T?s:new T("InternalWebAgentError",s instanceof Error?s.message:`${s}`,{cause:s})}finally{this.restoreCommandTemplateReplacements(e,o)}}restoreCommandTemplateReplacements(e,t={}){for(let[n,o]of Object.entries(t))Sr(e,n,o)}async resolveCommandTemplateStrings(e,t,n="",o={}){let s=["type","a11yData","thoughts"];for(let i in e){if(s.includes(i))continue;let a=e[i],l=n?`${n}.${i}`:i;if(typeof a=="string"&&a.includes("{{")){let c=await yr({s:a,state:t.toObjectRef(),logger:this.logger});if(a===c)continue;o[l]=a,e[i]=c}else typeof a=="object"&&a!==null&&!Array.isArray(a)&&await this.resolveCommandTemplateStrings(a,t,l,o)}return o}async executePresetStepHelper(e,t,n){switch(e.type){case"SUCCESS":return e.condition?.assertion.trim()?this.executeAssertion(e.condition):{succeedImmediately:!1,urlAfterCommand:await this.browser.url()};case"AI_ASSERTION":{if(!e.assertion.trim())throw new T("ActionFailureError","Missing assertion");return this.executeAssertion(e)}case"AI_WAIT":{if(!e.assertion.trim())throw new T("ActionFailureError","Missing assertion");let c=Date.now();if(e.timeout&&e.timeout>30)throw new T("AssertionFailureError",`AI wait timeout of ${e.timeout} exceeds the maximum allowed timeout of 30s`);let d=(e.timeout??10)*1e3,m,p,h=0;for(;Date.now()-c<d;)try{m=await this.executeAssertion({...e,type:"AI_ASSERTION"});break}catch(f){p=f instanceof Error?f:new Error(`${f}`),this.logger.warn({err:f},`AI_WAIT assert attempt ${h} failed, retrying...`),h++,await B(d/10)}if(!m){let f=`AI wait still failing after ${d}ms.`;throw p&&(f+=` Latest result: ${p.message}`),new T("AssertionFailureError",f)}return m}case"AI_EXTRACT":{if(!e.goal.trim())throw new T("ActionFailureError","Cannot perform AI extraction without goal");let c=await this.browser.getHTML(),d=await this.generator.getTextExtraction({goal:e.goal,browserState:c,returnSchema:e.schema},e.disableCache);if(d.result==="NOT_FOUND")throw new T("ActionFailureError","No relevant data found for extraction goal on this page");return{data:d.result,succeedImmediately:!1,urlAfterCommand:await this.browser.url()}}case"NAVIGATE":if(!sr(e.url)&&!ir(e.url,this.browser.baseURL))throw new T("ActionFailureError",`Invalid URL: ${e.url}`);await this.browser.navigate({url:e.url});break;case"CAPTCHA":let o=await this.browser.solveCaptcha();o&&(await this.wrapElementTargetingCommand({elementDescriptor:"the captcha image solution input"},e.useVision,n,c=>this.browser.click(c)),await this.browser.type(o,{clearContent:!0,pressKeysSequentially:!1}));break;case"GO_BACK":await this.browser.goBack();break;case"GO_FORWARD":await this.browser.goForward();break;case"SCROLL_LEFT":case"SCROLL_RIGHT":case"SCROLL_DOWN":case"SCROLL_UP":let s;switch(e.target&&(e.target.elementDescriptor.trim()||e.target.a11yData)&&(s=await this.wrapElementTargetingCommand(e.target,e.useVision,n,c=>this.browser.hover(c))),e.type){case"SCROLL_UP":await this.browser.scrollUp(e.deltaY);break;case"SCROLL_DOWN":await this.browser.scrollDown(e.deltaY);break;case"SCROLL_LEFT":await this.browser.scrollLeft(e.deltaX);break;case"SCROLL_RIGHT":await this.browser.scrollRight(e.deltaX);break}return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:s};case"WAIT":await this.browser.wait(e.delay*1e3);break;case"REFRESH":await this.browser.refresh();break;case"CLICK":{let c=await this.browser.url(),d=await this.wrapElementTargetingCommand(e.target,e.useVision,n,p=>this.browser.click(p,{doubleClick:e.doubleClick,rightClick:e.rightClick,force:e.force})),m={urlAfterCommand:await this.browser.url(),succeedImmediately:!1,elementInteracted:d};return Me(c,m.urlAfterCommand)&&(m.succeedImmediately=!0,m.succeedImmediatelyReason="URL changed"),m}case"DRAG":{let c=await this.wrapMultiElementTargetingCommand((d,m)=>this.browser.dragAndDrop(d,m,{force:e.force}),{useVision:e.useVision,disableCache:n},1,e.fromTarget,e.toTarget);return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:c}}case"SELECT_OPTION":{let c=await this.wrapElementTargetingCommand(e.target,!1,n,d=>this.browser.selectOption(d,e.option));return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:c}}case"TAB":await this.browser.switchToPage(e.url);break;case"COOKIE":if(!e.value)break;await this.browser.setCookie(e.value);break;case"LOCAL_STORAGE":if(!e.value||!e.key)break;await this.browser.setLocalStorage(e.key,e.value);break;case"JAVASCRIPT":{let c;try{c=await gr({code:e.code,fragment:!!e.fragment,state:t.toObjectRef(),timeoutMs:e.timeout?e.timeout*1e3:void 0,logger:this.logger})}catch(d){throw new T("ActionFailureError",d instanceof Error?d.message:`${d}`,{cause:d})}try{c=c===void 0?void 0:JSON.parse(JSON.stringify(c))}catch(d){throw new T("ActionFailureError",`Return value is not serializable: ${d instanceof Error?d.message:`${d}`}`,{cause:d})}return{urlAfterCommand:await this.browser.url(),succeedImmediately:!1,data:c}}case"TYPE":{let c=await this.browser.url(),d;e.target&&(d=await this.wrapElementTargetingCommand(e.target,e.useVision,n,p=>this.browser.click(p,{force:e.force}))),await this.browser.type(e.value,{clearContent:e.clearContent,pressKeysSequentially:e.pressKeysSequentially}),e.pressEnter&&await this.browser.press("Enter");let m={urlAfterCommand:await this.browser.url(),succeedImmediately:!1,elementInteracted:d};return Me(c,m.urlAfterCommand)&&(m.succeedImmediately=!0,m.succeedImmediatelyReason="URL changed"),m}case"HOVER":{let c=await this.wrapElementTargetingCommand(e.target,e.useVision,n,d=>this.browser.hover(d));return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:c}}case"PRESS":let i=await this.browser.url();await this.browser.press(e.value);let a={urlAfterCommand:await this.browser.url(),succeedImmediately:!1};return Me(i,a.urlAfterCommand)&&(a.succeedImmediately=!0,a.succeedImmediatelyReason="URL changed"),a;case"REQUEST":{let c=e.timeout??30,d=null,m=new AbortController,p=Object.fromEntries(Object.entries(e.headers||{}).filter(([v,E])=>v&&E)),h=new URLSearchParams;Object.entries(e.params||{}).filter(([v,E])=>v&&E).forEach(([v,E])=>{h.append(v,E)});let f;if(sr(e.url)&&(f=e.url),ir(e.url,this.browser.baseURL)&&(f=new URL(e.url,this.browser.baseURL).toString()),!f)throw new T("ActionFailureError",`Invalid URL: ${e.url}`);let g=async()=>{try{d=await fetch(`${f}?${h.toString()}`,{headers:p,method:e.method,body:e.body,signal:m.signal})}catch(v){this.logger.error({err:v},"Failed to make fetch request")}},A=async()=>{await new Promise(v=>setTimeout(v,c*1e3)),m.abort()};await Promise.race([A(),g()]);let w=d;if(!w)throw new T("ActionFailureError",`Fetch request timed out after ${c} seconds`);if(!w.ok)throw new T("ActionFailureError",`Fetch request failed with status ${w.status}`);let y={};w.headers.forEach((v,E)=>{y[E]=v});let I={status:w.status,headers:y};return w.headers.get("content-type")?.includes("json")?I.json=await w.json():w.headers.get("content-type")?.includes("text")&&(I.text=await w.text()),{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),data:I}}case"VISUAL_DIFF":{if(!e.screenshot)throw new T("ActionFailureError","Cannot execute visual diff without saved screenshot");let c=await this.screenshotWithDimensions({target:e.target?.a11yData,hideCaret:!0});if(c.height!==e.screenshot.height||c.width!==e.screenshot.width)throw new T("ActionFailureError","Current screenshot does not match saved screenshot dimensions - did you change the size of the target or the viewport?");let d={data:Buffer.alloc(c.width*c.height*4),width:c.width,height:c.height},p=pa(wr.decode(Buffer.from(e.screenshot.data,"base64")).data,wr.decode(c.buffer).data,d.data,c.width,c.height,{threshold:e.threshold,diffColorAlt:[0,255,0]})/(c.width*c.height)*100,h=p>e.threshold;return{fail:h,thoughts:h?`Visual diff of ${p.toFixed(2)}% detected`:void 0,screenshotOverride:wr.encode(d,75).data,succeedImmediately:!1,urlAfterCommand:await this.browser.url()}}default:return(c=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}return{succeedImmediately:!1,urlAfterCommand:await this.browser.url()}}async getReverseMappedTarget(e,t,n){return(await this.generator.getReverseMappedDescription({browserState:e.browserState,goal:`${t}`},n)).phrase}async toggleRecordMode({action:e,indices:t,onStepRecord:n}){if(e==="STOP"){this.recordAbortController?.abort();return}if(!t||!n)throw new Error("Indices or step recording callback not provided to toggleRecordMode");this.recordAbortController=new AbortController;let o=new It({signal:this.recordAbortController.signal,initialIndices:t,generator:this.generator,onStepRecord:n});await this.browser.startRecording(this.recordAbortController.signal,o)}};async function dn({socket:r,generator:e,logger:t,rootState:n,localApp:o}){let s=t.child({package:"web-agent"}),i=!0;o==="iframe"&&(i=!1);let a=r.handshake.query.testId,l=r.handshake.query.baseUrl;if(!a)throw new Error("Socket connection is missing testID");let c=r.handshake.query.orgId,d=fa(),m=g=>{r.emit("screenshot",{...g,url:l})},p=n?.controller;if(p)p.browser.setActiveFrame(gt),p.browser.baseURL=l,await p.resetState({clearCookies:!0,clearStorage:!0,timeout:null}),p.setOpen(),n?.context.reset(l);else{let g=await M.init({baseUrl:l,logger:s,takeScreenshots:i,onScreenshot:m});p=new pe({browser:g,generator:e,config:_e,logger:s})}i&&Ur(r,d,t);let h=new q(l,[]);r.emit("testContext",{state:h.toObjectRef()}),H.registerSession(p,h,d);let f=M.USER_AGENT;return r.emit("session",{url:l,userAgent:f,viewport:await p.browser.viewport(),localApp:o}),{sessionId:d,testId:a,orgId:c}}var mn=[$r,rn,on,nn,sn];var un=r=>{let{logger:e}=r,t=new ga(r.baseServer,{cors:{origin:"*",methods:["GET","POST"]},maxHttpBufferSize:1e7});return t.on("connection",async n=>{let o;try{o=await dn({...r,socket:n})}catch(s){e.error({event:"connection",type:"websocket",err:s},"Failed to setup connection"),n.emit("error",{message:s instanceof Error?s.message:`${s}`});return}mn.forEach(s=>ya(s,{socket:n,metadata:o,...r}))}),t},ya=(r,e)=>{let t=r.createHandler(e),n=(...o)=>{e.logger.debug({event:r.event,metadata:e.metadata,args:o},"Websocket event");let s=i=>{e.logger.error({event:r.event,type:"websocket",args:o,err:i instanceof Error?i:new Error(`${i}`)},"Unhandled exception in socket handler"),e.socket.emit("error",{message:i instanceof Error?i.message:`${i}`})};try{let i=t.apply(void 0,o);i&&typeof i.catch=="function"&&i.catch(s)}catch(i){s(i)}};e.socket.on(r.event,n)};import{z as ba}from"zod";import Sa from"fetch-retry";var wa=Sa(global.fetch),W=class{static API_VERSION="v1";baseURL;apiKey;constructor(e){this.baseURL=e.baseURL,this.apiKey=e.apiKey}async sendRequest(e,t){let n=await wa(`${this.baseURL}${e}`,{retries:1,retryDelay:1e3,method:"POST",body:JSON.stringify(t),headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}});if(!n.ok)throw new Error(`Request to ${e} failed with status ${n.status}: ${await n.text()}`);return n.json()}};var Fe=class extends W{constructor(e){super(e)}async getScreenshotFromS3(e){let t=await this.sendRequest(`/${W.API_VERSION}/s3/visual-diff-screenshot`,{url:e});return ba.string().parse(t)}async getElementLocation(e,t){let n=await this.sendRequest(`/${W.API_VERSION}/web-agent/locate-element`,{browserState:e.browserState,goal:e.goal,disableCache:t});return Jt.parse(n)}async getElementLocationWithVision(e,t){let n=await this.sendRequest(`/${W.API_VERSION}/web-agent/visual-locate`,{goal:e.goal,screenshot:e.screenshot?.toString("base64"),hintActivatedScreenshot:e.hintActivatedScreenshot?.toString("base64"),disableCache:t});return Jt.parse(n)}async getAssertionResult(e,t,n){if(t){let s=await this.sendRequest(`/${W.API_VERSION}/web-agent/assertion`,{url:e.url,goal:e.goal,screenshot:e.screenshot?.toString("base64"),disableCache:n,vision:!0});return Xt.parse(s)}let o=await this.sendRequest(`/${W.API_VERSION}/web-agent/assertion`,{url:e.url,browserState:e.browserState,goal:e.goal,history:e.history,numPrevious:e.numPrevious,lastCommand:e.lastCommand,disableCache:n,vision:!1});return Xt.parse(o)}async getProposedCommand(e,t){let n=await this.sendRequest(`/${W.API_VERSION}/web-agent/next-command`,{url:e.url,browserState:e.browserState,goal:e.goal,history:e.history,numPrevious:e.numPrevious,lastCommand:e.lastCommand,disableCache:t});return so.parse(n)}async getGranularGoals(e,t){let n=await this.sendRequest(`/${W.API_VERSION}/web-agent/split-goal`,{url:e.url,goal:e.goal,disableCache:t});return io.parse(n)}async getReverseMappedDescription(e,t){let n=await this.sendRequest(`/${W.API_VERSION}/web-agent/reverse-mapped-description`,{goal:e.goal,browserState:e.browserState,disableCache:t});return ao.parse(n)}async getTextExtraction(e,t){let n={goal:e.goal,browserState:e.browserState,returnSchema:e.returnSchema,disableCache:t},o=await this.sendRequest(`/${W.API_VERSION}/web-agent/text-extraction`,n);return Ft.parse(o)}};import{existsSync as va,readFileSync as Aa,writeFileSync as br}from"fs";import vr from"path";import{parse as Ea,stringify as Ta}from"yaml";var $=process.env.MOMENTIC_DIR??fe;function pn(r,e){let t=So(r);for(let[s,i]of Object.entries(t.modules)){let a=Le(s);br(vr.join($,ne,`${a}.yaml`),i,"utf-8")}let n=Le(e),o=vr.join($,`${n}.yaml`);return br(o,t.test,"utf-8"),`${n}.yaml`}function hn(r,e){if(!va(e))throw new Error(`Test not found at path: ${vr}`);let t=Aa(e,"utf-8"),o={...Ea(t),...r},s=Ta(o);br(e,s,"utf-8")}import{readFileSync as Lt,readdirSync as fn,writeFileSync as gn}from"fs";import{join as Ar}from"path";import{v4 as Ca}from"uuid";import{parse as Ot,stringify as yn}from"yaml";var ot=Ar($,ne);function Sn(r,e){let t=At(ot,e).path,n=Lt(t,"utf-8"),s={...Ot(n),...r},i=yn(s);gn(t,i,"utf-8")}function wn(r,e){let t=Le(r),n=Ar(ot,`${t}.yaml`),o={fileType:"momentic/module",schemaVersion:G,moduleId:Ca(),name:r,steps:e},s=yn(o);return gn(n,s,"utf-8"),{type:"RESOLVED_MODULE",moduleId:o.moduleId,name:o.name,steps:o.steps}}function bn(){let r=[];for(let e in fn(ot)){if(!e.endsWith(".yaml"))continue;let t=Lt(e,"utf-8"),n=Ot(t),o={name:n.name,moduleId:n.moduleId,numSteps:n.steps.length};r.push(o)}return r}function vn(){let r=[];for(let e of fn(ot)){if(!e.endsWith(".yaml"))continue;let t=Ar(ot,e),n=Lt(t,"utf-8"),o=Ot(n);try{let s=Zt.parse(o);r.push(s)}catch(s){V.warn({err:s},"Error parsing module, skipping...")}}return r}function An(r){let e=At(ne,r).path,t=Lt(e,"utf-8"),n=Ot(t);return Zt.parse(n)}import{Router as Oa}from"express";import{existsSync as Ra,readFileSync as xa,readdirSync as Ia}from"fs";import{join as En}from"path";import{parse as La}from"yaml";var Er=En($,Ze);function Tn(){let r=[];if(!Ra(Er))return[];for(let e of Ia(Er)){if(!e.endsWith(".yaml"))continue;let t=En(Er,e),n=xa(t,"utf-8"),o=La(n);try{let s=ee.parse(o);r.push(s)}catch(s){V.warn({err:s},"Error parsing environment, skipping...")}}return r}function J(r){return function(...e){let t=e[e.length-1],n=r(...e);Promise.resolve(n).catch(t)}}var Cn=Oa();Cn.get("/",J((r,e)=>{let t=Tn();e.status(200).json(t)}));var Rn=Cn;import{Router as Ma}from"express";var nt=Ma();nt.get("/",J((r,e)=>{let n=vn().map(o=>({...o,type:"RESOLVED_MODULE"}));e.status(200).json(n)}));nt.get("/metadata",J((r,e)=>{let t=bn();e.status(200).json(t)}));nt.post("/",J((r,e)=>{let t;try{t=oo.parse(r.body)}catch(o){e.status(400).json({error:`Invalid request body: ${o}`});return}try{et(t.name)}catch(o){e.status(400).json({error:`Invalid module name: ${o}`});return}let n=wn(t.name,t.steps);e.status(201).json(n)}));nt.get("/:moduleId",J((r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=An(r.params.moduleId);e.json(t)}));var xn=nt;import{Router as ka}from"express";import{existsSync as Fa}from"fs";import{join as Rr}from"path";import{v4 as za}from"uuid";import In,{multistream as Na}from"pino";import Pa from"pino-pretty";var Tr=new Map,Da=process.env.NODE_ENV==="production",Cr=class r{consoleLogger;ddClientToken;hostname;bindingAttributes;site="https://http-intake.logs.us5.datadoghq.com/api/v2/logs";constructor({bindings:e,clientToken:t,hostname:n}){this.ddClientToken=t,this.hostname=n,this.bindingAttributes={...e,env:process.env.NODE_ENV};let o={base:this.bindingAttributes,errorKey:"err",level:"debug"};this.consoleLogger=Da?In(o):In(o,Na([{stream:Pa({colorize:!0})}]))}child(e){return new r({clientToken:this.ddClientToken,bindings:{...this.bindingAttributes,...e},hostname:this.hostname})}flush(e){this.consoleLogger.flush(e)}log(e,t,n,...o){t&&n===void 0&&(n=`${t}`,t={}),this.consoleLogger[e](t,n,...o);let s=Object.assign({},this.bindingAttributes,t&&typeof t=="object"?t:{});o.length>0&&(s.args=o),(async()=>{try{let i=await fetch(this.site,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","DD-API-KEY":this.ddClientToken},body:JSON.stringify([{ddsource:this.bindingAttributes.app,hostname:this.hostname??"vercel",service:"momentic",message:{message:n||"",...s}}])});if(!i.ok)throw new Error(`Failed to log to Datadog: ${i.statusText})}`)}catch(i){this.consoleLogger.warn({obj:t,msg:n,args:o,err:i},"Failed to log to Datadog")}})()}debug(e,t,...n){this.log("debug",e,t,...n)}info(e,t,...n){this.log("info",e,t,...n)}warn(e,t,...n){this.log("warn",e,t,...n)}error(e,t,...n){this.log("error",e,t,...n)}bindings(){return this.bindingAttributes}setMinLevel(e){this.consoleLogger.level=e}},Mt=({app:r,clientToken:e,hostname:t})=>{if(!process.env.DD_CLIENT_TOKEN&&!process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN&&!e)throw new Error("Missing DD_CLIENT_TOKEN");return Tr.has(r)||Tr.set(r,new Cr({bindings:{app:r},hostname:t,clientToken:e||process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN||process.env.DD_CLIENT_TOKEN})),Tr.get(r)};import{hostname as _a}from"os";var Q=Mt({app:"desktop-server",clientToken:"pubcfd7516a5c0ba852b42675cd97bee027",hostname:_a()});var st=ka();st.get("/",J((r,e)=>{let t=tt($,Q);e.status(200).json(t)}));st.post("/",J((r,e)=>{let t;try{t=ro.parse(r.body)}catch(a){e.status(400).json({error:`Invalid request body: ${a}`});return}try{et(t.name)}catch(a){e.status(400).json({error:a.message});return}let o={id:za(),name:t.name,baseUrl:t.baseUrl,schemaVersion:G,advanced:{disableAICaching:!1,availableAsModule:!0},retries:0,steps:[]};t.environment&&(o.envs=[{name:t.environment,defaultOnLocal:!0}]);let s=pn(o,t.name),i={...o,testPath:s};e.status(201).json(i)}));st.get("/:testPath",J(async(r,e)=>{if(!r.params.testPath){e.status(400).json({error:"Missing testPath in url path."});return}let t=Rr($,r.params.testPath);if(!Fa(t)){e.status(400).json({error:`Test not found at path: ${t}`});return}let n=await Et(t,Rr($,ne));e.status(200).json(n)}));st.patch("/:testPath",J((r,e)=>{if(!r.params.testPath){e.status(400).json({error:"Missing testPath in url path."});return}let t;try{t=to.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}let n=[],o={};for(let s of t.steps){if(s.type!=="RESOLVED_MODULE"){n.push(s);continue}n.push({type:"MODULE",moduleId:s.moduleId}),o[s.moduleId]=s.steps}for(let[s,i]of Object.entries(o))Sn({steps:i},s);hn({steps:n},Rr($,r.params.testPath)),e.status(201).json({message:"ok"})}));var Ln=st;var xr="https://api.momentic.ai",Mn=r=>{xr=r},Nn=()=>xr,Ua,Pn=r=>{Ua=r};var On,Dn=async r=>{if(On)return;let e=await fetch(`${xr}/v1/auth/check`,{headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`}});if(!e.ok)throw new Error(`Error checking API key with server (code ${e.status}): ${await e.text()}`);let t=await e.json(),{orgId:n}=go.parse(t);On=n};async function kn({momenticServerUrl:r,apiKey:e,mode:t,serverPort:n,appPort:o,staticDir:s,assetsDir:i}){if(!Ba($)||!ja($).isDirectory()){let h=Wa.isAbsolute($);throw new Error(`Root folder ${$} does not exist${h?"":` in the current directory ("${process.cwd()}")`}. Please run \`npx momentic init\` if you wish to setup Momentic here for the first time.`)}r&&Mn(r),V.info("Checking API key"),await Dn(e);let l=`http://localhost:${n}`;o&&(l=`http://localhost:${o}`);let c=qa(s);await new Promise(h=>{c.listen(n,()=>{V.info(`Server is running at http://localhost:${n}`),h()})});let m=new Fe({baseURL:Nn(),apiKey:e});if(t==="web"){await _n("web",c,m,Q),await Va(l);return}let p=await Ya({appUrl:l,apiGenerator:m,extensionPath:Ka(i,"extension"),onClose:async()=>{V.info("Browser closed, closing app."),await p.browser.cleanup(),c.close(()=>{process.exit(0)})}});await _n("iframe",c,m,Q,{controller:p,context:new q("",[])}),process.on("uncaughtException",h=>{Q.error({err:h},"Uncaught exception in desktop-server")}),process.on("unhandledRejection",h=>{Q.error({err:h},"Unhandled rejection in desktop-server")})}function qa(r){let e=Ir();e.use(Ha()),e.use($a.json({limit:"50mb"}));let t=Ir.Router();if(t.use("/tests",Ln),t.use("/modules",xn),t.use("/environments",Rn),e.use("/api",t),e.use((o,s,i)=>{o.path!=="/healthcheck"&&Q.debug({url:o.url,path:o.path,query:o.query,method:o.method,body:o.body,headers:o.rawHeaders,client:o.ip},"Received desktop-server request"),s.on("close",()=>{s.statusCode>=400&&Q.error({url:o.url,method:o.method,statusCode:s.statusCode},"Request completed in error")}),i()}),e.use((o,s,i,a)=>{Q.error({stack:o.stack,msg:o.message,url:s.url,method:s.method},"Unhandled exception leading to 500 on desktop-server"),i.status(500).send("Internal Server Error"),a(o)}),r){let o=Ir.static(r);e.use("/",o),e.use("*",o)}return Ga.createServer(e)}async function Ya({appUrl:r,apiGenerator:e,extensionPath:t,onClose:n}){let o=await M.init({baseUrl:r,logger:Q,browserArgs:{headless:!1,handleSIGTERM:!0},contextArgs:{bypassCSP:!0,viewport:null,deviceScaleFactor:void 0},waitForLoad:!0,localMode:!0,localAppUrl:r,extensionPath:t,skipPageSetup:!0,timeout:null,onClose:n}),s=new pe({browser:o,config:_e,generator:e,logger:Q});return Pn(s),s}async function _n(r,e,t,n,o){un({baseServer:e,generator:t,logger:n,localApp:r,rootState:o})}import{existsSync as Ll}from"fs";import cs,{dirname as Ol}from"path";import{fileURLToPath as Ml}from"url";var Fn="0.0.41";var te="v1",se=class{baseURL;apiKey;constructor(e){this.baseURL=e.baseURL,this.apiKey=e.apiKey}async getRun(e){let t=await this.sendRequest(`/${te}/runs/${e}`,{method:"GET"});return ho.parse(t)}async createRun(e){let t=await this.sendRequest(`/${te}/runs`,{method:"POST",body:e});return po.parse(t)}async updateRun(e,t){await this.sendRequest(`/${te}/runs/${e}`,{method:"PATCH",body:t})}async getTest(e){let t=await this.sendRequest(`/${te}/tests/${e}`,{method:"GET"});return co.parse(t)}async getAllTestIds(){let e=await this.sendRequest(`/${te}/tests`,{method:"GET"});return mo.parse(e)}async getTestYAMLExport(e){let t=await this.sendRequest(`/${te}/tests/export`,{method:"POST",body:e});return uo.parse(t)}async updateTestWithYAML(e){await this.sendRequest(`/${te}/tests/update`,{method:"POST",body:e})}async queueTests(e){let t=await this.sendRequest(`/${te}/tests/queue`,{method:"POST",body:e});return lo.parse(t)}async uploadScreenshot(e){let t=await this.sendRequest(`/${te}/screenshots`,{method:"POST",body:e});return fo.parse(t)}async getAllEnvironments(){let e=await this.sendRequest(`/${te}/environments`,{method:"GET"});return yo.parse(e)}async updateEnvironments(e){await this.sendRequest(`/${te}/environments`,{method:"POST",body:e})}async sendRequest(e,t){let n=await fetch(`${this.baseURL}${e}`,{method:t.method,body:t.body?JSON.stringify(t.body):void 0,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}});if(!n.ok)throw new Error(`Request to ${e} failed with status ${n.status}: ${await n.text()}`);return n.status===204?n.text():n.json()}};import{hostname as Ja}from"os";var S=Mt({app:"cli",clientToken:"pub7eb923f18fb3f1d42ac5eba8c5ea13a5",hostname:Ja()});import{createHash as Hn}from"crypto";import{existsSync as Bn,mkdirSync as nl,readFileSync as Pr,writeFileSync as jn}from"fs";import{join as Gn}from"path";import{parse as sl}from"yaml";import{existsSync as Lr,mkdirSync as el,readdirSync as Un,statSync as Or}from"fs";import{homedir as $n}from"os";import{join as it,resolve as tl}from"path";import Qa from"chalk";import Za from"readline/promises";async function re(r,e){if(process.env.CI)return!0;let t=Za.createInterface({input:process.stdin,output:process.stdout});r=`${r} (y/N) `;let n=e?Qa.bold.yellow(r):r,o=await t.question(n);return t.close(),o.toLowerCase()==="y"}var Mr=fe,ze=it(fe,ne),Nr=it(fe,jt),ie=it(fe,Ze),rl=it($n(),"momentic",Gt),ol=[rl,ze,Nr,ie];function zn(r){try{return Lr(r)&&Or(r).isDirectory()}catch(e){return S.error({err:e},`Error reading path ${r} during directory exists check`),!1}}async function Se(r,e=!1){$n()||(S.error("Your home directory could not be found. Please ensure the HOME environment variable is set for POSIX systems, and the USERPROFILE environment variable is set for Windows systems."),process.exit(1)),zn(Mr)||!e&&!await re(`A '${fe}' folder was not found in the current directory. Proceed with creation here? You will need to invoke the Momentic CLI from this directory in the future.`)&&(S.error("Setup cancelled"),process.exit(1));for(let t of ol)zn(t)||(!e&&!await re(`'${t}' folder was not found in the current directory. Create it now?`)&&(S.error("Setup cancelled"),process.exit(1)),el(t,{recursive:!0}));Un(ie).length===0&&(!e&&!await re("You do not appear to have any environments configured locally. Pull environments from Momentic Cloud?")&&(S.error("Setup cancelled"),process.exit(1)),await Nt({client:r,all:!0,skipPrompts:e})),S.info("CLI initialization complete")}function at(r,e,t=new Set){for(let n of r){let o=tl(n),s=!1;try{s=Lr(o)&&Or(o).isDirectory()}catch(i){S.error({err:i},`Error reading path ${o} during collect paths`)}if(o&&s){let i=Un(o).map(a=>it(o,a));at(i,e,t);continue}if(o.endsWith(".yaml")){try{if(!Lr(o)||!Or(o).isFile()){S.error(`File not found or unreadable: ${o}`);continue}}catch(i){S.error({err:i},`Error reading file ${o} during collect paths`);continue}if(!e(o))continue;t.add(o)}}return t}async function Nt({envNames:r,client:e,all:t,skipPrompts:n}){let o=await e.getAllEnvironments();r&&!t&&(o=o.filter(a=>r?.includes(a.name))),Bn(ie)||nl(ie);let s=0,i=0;for(let a of o){let l=Gn(ie,`${a.name}.yaml`);if(!Bn(l))jn(l,er(a)),s++;else{let c=Hn("sha256").update(Pr(l)).digest("hex"),d=er(a),m=Hn("sha256").update(d).digest("hex");if(c!==m){if(!n&&!await re(`Environment ${a.name} already exists on disk but needs to be updated. Overwrite?`)){S.error("Pull cancelled");return}jn(l,d),i++}}}S.info(`Pulled ${s} new environments and updated ${i} existing environments`)}function il(r){return r.endsWith(".yaml")?Pr(r,"utf8").includes("momentic/environment")?!0:(S.warn(`Skipping YAML that is not a Momentic environment: ${r}`),!1):!1}async function Vn({client:r,names:e,all:t,yes:n}){let o;t?o=[ie]:o=e.map(a=>Gn(ie,`${a.toLowerCase()}.yaml`));let s=at(o,il);S.info(`Found ${s.size} environments(s) to push:`),s.forEach(a=>S.info(` - ${a}`)),S.info("Loading file contents");let i=[];for(let a of s){let l=sl(Pr(a,"utf-8"));try{let c=ee.parse(l);i.push(c)}catch(c){S.error({err:c},`${a} failed to parse as a valid environment file`),process.exit(1)}}if(!n&&!await re("Pushing environments can overwrite variables on cloud and instantly affect scheduled runs. Continue?",!0)){S.error("Push cancelled");return}S.info(`Pushing ${s.size} environment(s)`),await r.updateEnvironments(i),S.info("Push successful!")}import{registry as Dr}from"playwright-core/lib/server";function al(r){let e=[],t=[];for(let n of r){let o=Dr.findExecutable(n);!o||o.installType==="none"?e.push(n):t.push(o)}return t}async function Wn(){let r=al(["chromium"]);await Dr.installDeps(r,!1),await Dr.install(r,!1)}import{Argument as Pt,Option as Ue}from"commander";var we=new Ue("--api-key <key>","API key for authentication. If not supplied, attempts to read the MOMENTIC_API_KEY env var.").env("MOMENTIC_API_KEY").makeOptionMandatory(!0),be=new Ue("--server <server>","Momentic server to use. Leave unchanged unless using Momentic on-premise.").default("https://api.momentic.ai"),ve=new Ue("-y, --yes","Skip confirmation prompts.").env("CI").default(!1),Kn=new Ue("--no-report","Skip reporting test results to Momentic Cloud when running with the --local flag.").default(!0),qn=new Ue("--env <env>","Name of the environment to use when running tests."),_r=new Ue("-a, --all","Select all tests in your organization from Momentic Cloud. Cannot be used together with <tests> arguments."),kr=new Ue("-a, --all","Select all environments in your organization from Momentic Cloud. Cannot be used together with <paths> arguments."),Yn=new Pt("<tests...>",`One or more test paths to pull from Momentic Cloud.
|
|
29
|
+
`)}`}async executeCommand(e,t,n,o=!1){let s=this.commandHistory[this.commandHistory.length-1];if(!o&&(!s||s.state!=="PENDING"))throw new T("InternalWebAgentError","Executing command but there is no pending entry in the history");if(this.closed)throw new Error("Attempting to execute command on a closed controller");let a=Date.now(),i=await this.executePresetStep(e,t,n),l=Date.now()-a;return this.logger.debug({result:i,duration:l},"Got execution result"),i.succeedImmediately&&!o&&(this.pendingInstructions.pop(),this.pendingInstructions.length>0&&(i.succeedImmediately=!1)),i.elementInteracted&&"target"in e&&e.target&&!e.target.elementDescriptor&&(e.target.elementDescriptor=i.elementInteracted.trim()),o||(s.generatedStep=e,s.serializedCommand=We(e),s.state="DONE"),i}async executeAssertion(e){let t=await this.getBrowserState(),n=await this.browser.url(),o;if(e.useVision)o={goal:e.assertion,url:n,screenshot:await this.browser.screenshot({}),browserState:"",history:"",numPrevious:-1,lastCommand:null};else{let a=this.getSerializedHistory(n,t);o={goal:e.assertion,url:n,browserState:t,history:a,lastCommand:this.lastExecutedCommand,numPrevious:this.commandHistory.length}}let s=await this.generator.getAssertionResult(o,e.useVision,e.disableCache);if(s.relevantElements&&Promise.all(s.relevantElements.map(a=>this.browser.highlight({id:a}))),!s.result)throw new T("AssertionFailureError",s.thoughts);return{succeedImmediately:!1,thoughts:s.thoughts,urlAfterCommand:n}}async wrapMultiElementTargetingCommand(e,t,n,...o){let s=await Promise.all(o.map(a=>this.wrapElementTargetingCommand(a,t.useVision,t.disableCache,async i=>i)));try{return await e(...s)}catch(a){if(n>0)return this.logger.warn({err:a},"Failed to execute action with multiple cached targets, retrying with AI"),o.forEach(i=>i.a11yData=void 0),this.wrapMultiElementTargetingCommand(e,t,n-1,...o);throw new T("ActionFailureError","",{cause:a})}}async wrapElementTargetingCommand(e,t,n,o,s=1){if(!e.a11yData&&!e.elementDescriptor)throw new T("ActionFailureError","Cannot target element with no target data or element descriptor");let a=e.a11yData&&mt(e.a11yData);e.a11yData||(this.logger.info("No cached locator data for target, prompting AI for fresh location"),s--,e.a11yData=dt.parse(await this.locateElement(e.elementDescriptor,t,n)));try{let i=await o(e.a11yData);return a?this.logger.info({target:e},"Successfully used cached target to perform action"):this.logger.debug({target:e},"Successfully generated and used new a11y target information"),i}catch(i){if(s>0&&e.elementDescriptor)return this.logger.warn({err:i,target:e},"Failed to execute action with cached target, retrying with AI"),e.a11yData=void 0,this.wrapElementTargetingCommand(e,t,n,o,s);if(i instanceof T)throw i;let l=`Failed to find ${e.elementDescriptor?`${e.elementDescriptor}`:"element"}: ${i instanceof Error?i.message:i}`;throw this.logger.error({err:i,target:e},l),new T("ActionFailureError",l,{cause:i})}}async screenshotWithDimensions(e){let t=await this.browser.screenshot(e),n=ya(t);return{buffer:t,...n}}async executePresetStep(e,t,n){let o;try{o=await this.resolveCommandTemplateStrings(e,t)}catch(s){throw new T("ActionFailureError",s.message,{cause:s})}try{return await this.executePresetStepHelper(e,t,n)}catch(s){throw s instanceof T?s:new T("InternalWebAgentError",s instanceof Error?s.message:`${s}`,{cause:s})}finally{this.restoreCommandTemplateReplacements(e,o)}}restoreCommandTemplateReplacements(e,t={}){for(let[n,o]of Object.entries(t))Ar(e,n,o)}async resolveCommandTemplateStrings(e,t,n="",o={}){let s=["type","a11yData","thoughts"];for(let a in e){if(s.includes(a))continue;let i=e[a],l=n?`${n}.${a}`:a;if(typeof i=="string"&&i.includes("{{")){let c=await vr({s:i,state:t.toObjectRef(),logger:this.logger});if(i===c)continue;o[l]=i,e[a]=c}else typeof i=="object"&&i!==null&&!Array.isArray(i)&&await this.resolveCommandTemplateStrings(i,t,l,o)}return o}async executePresetStepHelper(e,t,n){switch(e.type){case"SUCCESS":return e.condition?.assertion.trim()?this.executeAssertion(e.condition):{succeedImmediately:!1,urlAfterCommand:await this.browser.url()};case"AI_ASSERTION":{if(!e.assertion.trim())throw new T("ActionFailureError","Missing assertion");return this.executeAssertion(e)}case"AI_WAIT":{if(!e.assertion.trim())throw new T("ActionFailureError","Missing assertion");let c=Date.now();if(e.timeout&&e.timeout>30)throw new T("AssertionFailureError",`AI wait timeout of ${e.timeout} exceeds the maximum allowed timeout of 30s`);let d=(e.timeout??10)*1e3,m,f,h=0;for(;Date.now()-c<d;)try{m=await this.executeAssertion({...e,type:"AI_ASSERTION"});break}catch(p){f=p instanceof Error?p:new Error(`${p}`),this.logger.warn({err:p},`AI_WAIT assert attempt ${h} failed, retrying...`),h++,await B(d/10)}if(!m){let p=`AI wait still failing after ${d}ms.`;throw f&&(p+=` Latest result: ${f.message}`),new T("AssertionFailureError",p)}return m}case"AI_EXTRACT":{if(!e.goal.trim())throw new T("ActionFailureError","Cannot perform AI extraction without goal");let c=await this.browser.getHTML(),d=await this.generator.getTextExtraction({goal:e.goal,browserState:c,returnSchema:e.schema},e.disableCache);if(d.result==="NOT_FOUND")throw new T("ActionFailureError","No relevant data found for extraction goal on this page");return{data:d.result,succeedImmediately:!1,urlAfterCommand:await this.browser.url()}}case"NAVIGATE":if(!cr(e.url)&&!dr(e.url,this.browser.baseURL))throw new T("ActionFailureError",`Invalid URL: ${e.url}`);await this.browser.navigate({url:e.url});break;case"CAPTCHA":let o=await this.browser.solveCaptcha();o&&(await this.wrapElementTargetingCommand({elementDescriptor:"the captcha image solution input"},e.useVision,n,c=>this.browser.click(c)),await this.browser.type(o,{clearContent:!0,pressKeysSequentially:!1}));break;case"GO_BACK":await this.browser.goBack();break;case"GO_FORWARD":await this.browser.goForward();break;case"SCROLL_LEFT":case"SCROLL_RIGHT":case"SCROLL_DOWN":case"SCROLL_UP":let s;switch(e.target&&(e.target.elementDescriptor.trim()||e.target.a11yData)&&(s=await this.wrapElementTargetingCommand(e.target,e.useVision,n,c=>this.browser.hover(c))),e.type){case"SCROLL_UP":await this.browser.scrollUp(e.deltaY);break;case"SCROLL_DOWN":await this.browser.scrollDown(e.deltaY);break;case"SCROLL_LEFT":await this.browser.scrollLeft(e.deltaX);break;case"SCROLL_RIGHT":await this.browser.scrollRight(e.deltaX);break}return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:s};case"WAIT":await this.browser.wait(e.delay*1e3);break;case"REFRESH":await this.browser.refresh();break;case"CLICK":{let c=await this.browser.url(),d=await this.wrapElementTargetingCommand(e.target,e.useVision,n,f=>this.browser.click(f,{doubleClick:e.doubleClick,rightClick:e.rightClick,force:e.force})),m={urlAfterCommand:await this.browser.url(),succeedImmediately:!1,elementInteracted:d};return Pe(c,m.urlAfterCommand)&&(m.succeedImmediately=!0,m.succeedImmediatelyReason="URL changed"),m}case"DRAG":{let c=await this.wrapMultiElementTargetingCommand((d,m)=>this.browser.dragAndDrop(d,m,{force:e.force}),{useVision:e.useVision,disableCache:n},1,e.fromTarget,e.toTarget);return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:c}}case"SELECT_OPTION":{let c=await this.wrapElementTargetingCommand(e.target,!1,n,d=>this.browser.selectOption(d,e.option));return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:c}}case"TAB":await this.browser.switchToPage(e.url);break;case"COOKIE":if(!e.value)break;await this.browser.setCookie(e.value);break;case"LOCAL_STORAGE":if(!e.value||!e.key)break;await this.browser.setLocalStorage(e.key,e.value);break;case"JAVASCRIPT":{let c;try{c=await br({code:e.code,fragment:!!e.fragment,state:t.toObjectRef(),timeoutMs:e.timeout?e.timeout*1e3:void 0,logger:this.logger})}catch(d){throw new T("ActionFailureError",d instanceof Error?d.message:`${d}`,{cause:d})}try{c=c===void 0?void 0:JSON.parse(JSON.stringify(c))}catch(d){throw new T("ActionFailureError",`Return value is not serializable: ${d instanceof Error?d.message:`${d}`}`,{cause:d})}return{urlAfterCommand:await this.browser.url(),succeedImmediately:!1,data:c}}case"TYPE":{let c=await this.browser.url(),d;e.target&&(d=await this.wrapElementTargetingCommand(e.target,e.useVision,n,f=>this.browser.click(f,{force:e.force}))),await this.browser.type(e.value,{clearContent:e.clearContent,pressKeysSequentially:e.pressKeysSequentially}),e.pressEnter&&await this.browser.press("Enter");let m={urlAfterCommand:await this.browser.url(),succeedImmediately:!1,elementInteracted:d};return Pe(c,m.urlAfterCommand)&&(m.succeedImmediately=!0,m.succeedImmediatelyReason="URL changed"),m}case"HOVER":{let c=await this.wrapElementTargetingCommand(e.target,e.useVision,n,d=>this.browser.hover(d));return{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),elementInteracted:c}}case"PRESS":let a=await this.browser.url();await this.browser.press(e.value);let i={urlAfterCommand:await this.browser.url(),succeedImmediately:!1};return Pe(a,i.urlAfterCommand)&&(i.succeedImmediately=!0,i.succeedImmediatelyReason="URL changed"),i;case"REQUEST":{let c=e.timeout??30,d=null,m=new AbortController,f=Object.fromEntries(Object.entries(e.headers||{}).filter(([A,E])=>A&&E)),h=new URLSearchParams;Object.entries(e.params||{}).filter(([A,E])=>A&&E).forEach(([A,E])=>{h.append(A,E)});let p;if(cr(e.url)&&(p=e.url),dr(e.url,this.browser.baseURL)&&(p=new URL(e.url,this.browser.baseURL).toString()),!p)throw new T("ActionFailureError",`Invalid URL: ${e.url}`);let y=async()=>{try{d=await fetch(`${p}?${h.toString()}`,{headers:f,method:e.method,body:e.body,signal:m.signal})}catch(A){this.logger.error({err:A},"Failed to make fetch request")}},S=async()=>{await new Promise(A=>setTimeout(A,c*1e3)),m.abort()};await Promise.race([S(),y()]);let b=d;if(!b)throw new T("ActionFailureError",`Fetch request timed out after ${c} seconds`);if(!b.ok)throw new T("ActionFailureError",`Fetch request failed with status ${b.status}`);let g={};b.headers.forEach((A,E)=>{g[E]=A});let R={status:b.status,headers:g};return b.headers.get("content-type")?.includes("json")?R.json=await b.json():b.headers.get("content-type")?.includes("text")&&(R.text=await b.text()),{succeedImmediately:!1,urlAfterCommand:await this.browser.url(),data:R}}case"VISUAL_DIFF":{if(!e.screenshot)throw new T("ActionFailureError","Cannot execute visual diff without saved screenshot");let c=await this.screenshotWithDimensions({target:e.target?.a11yData,hideCaret:!0});if(c.height!==e.screenshot.height||c.width!==e.screenshot.width)throw new T("ActionFailureError","Current screenshot does not match saved screenshot dimensions - did you change the size of the target or the viewport?");let d={data:Buffer.alloc(c.width*c.height*4),width:c.width,height:c.height},f=ba(Er.decode(Buffer.from(e.screenshot.data,"base64")).data,Er.decode(c.buffer).data,d.data,c.width,c.height,{threshold:e.threshold,diffColorAlt:[0,255,0]})/(c.width*c.height)*100,h=f>e.threshold;return{fail:h,thoughts:h?`Visual diff of ${f.toFixed(2)}% detected`:void 0,screenshotOverride:Er.encode(d,75).data,succeedImmediately:!1,urlAfterCommand:await this.browser.url()}}default:return(c=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}return{succeedImmediately:!1,urlAfterCommand:await this.browser.url()}}async getReverseMappedTarget(e,t,n){return(await this.generator.getReverseMappedDescription({browserState:e.browserState,goal:`${t}`},n)).phrase}async toggleRecordMode({action:e,indices:t,onStepRecord:n}){if(e==="STOP"){this.recordAbortController?.abort();return}if(!t||!n)throw new Error("Indices or step recording callback not provided to toggleRecordMode");this.recordAbortController=new AbortController;let o=new Mt({signal:this.recordAbortController.signal,initialIndices:t,generator:this.generator,onStepRecord:n});await this.browser.startRecording(this.recordAbortController.signal,o)}};async function fn({socket:r,generator:e,logger:t,rootState:n,localApp:o}){let s=t.child({package:"web-agent"}),a=!0;o==="iframe"&&(a=!1);let i=r.handshake.query.testId,l=r.handshake.query.baseUrl,c=r.handshake.query.viewport?JSON.parse(decodeURIComponent(r.handshake.query.viewport)):void 0;if(!i||!l)throw new Error("Socket connection request is missing testId or baseUrl");let d=r.handshake.query.orgId,m=Aa(),f=S=>{a&&r.emit("screenshot",{...S,url:l})},h=n?.controller;if(h)h.browser.setActiveFrame(wt),h.browser.baseURL=l,await h.resetState({clearCookies:!0,clearStorage:!0,timeout:null}),h.setOpen(),n?.context.reset(l);else{let S=await P.init({baseUrl:l,logger:s,takeScreenshots:a,onScreenshot:f,contextArgs:{viewport:c??de}});h=new ge({browser:S,generator:e,config:Fe,logger:s})}a&&Vr(r,m,t);let p=new Y(l,[]);r.emit("testContext",{state:p.toObjectRef()}),H.registerSession(h,p,m);let y=P.USER_AGENT;return r.emit("session",{url:l,userAgent:y,viewport:await h.browser.getViewport(),localApp:o}),{sessionId:m,testId:i,orgId:d}}var gn=[jr,ln,cn,dn,mn];var yn=r=>{let{logger:e}=r,t=new Ea(r.baseServer,{cors:{origin:"*",methods:["GET","POST"]},maxHttpBufferSize:1e7});return t.on("connection",async n=>{let o;try{o=await fn({...r,socket:n})}catch(s){e.error({event:"connection",type:"websocket",err:s},"Failed to setup connection"),n.emit("error",{message:s instanceof Error?s.message:`${s}`});return}gn.forEach(s=>Ta(s,{socket:n,metadata:o,...r}))}),t},Ta=(r,e)=>{let t=r.createHandler(e),n=(...o)=>{e.logger.debug({event:r.event,metadata:e.metadata,args:o},"Websocket event");let s=a=>{e.logger.error({event:r.event,type:"websocket",args:o,err:a instanceof Error?a:new Error(`${a}`)},"Unhandled exception in socket handler"),e.socket.emit("error",{message:a instanceof Error?a.message:`${a}`})};try{let a=t.apply(void 0,o);a&&typeof a.catch=="function"&&a.catch(s)}catch(a){s(a)}};e.socket.on(r.event,n)};import{z as xa}from"zod";import Ca from"fetch-retry";var Ra=Ca(global.fetch),K=class{static API_VERSION="v1";baseURL;apiKey;constructor(e){this.baseURL=e.baseURL,this.apiKey=e.apiKey}async sendRequest(e,t){let n=await Ra(`${this.baseURL}${e}`,{retries:1,retryDelay:1e3,method:"POST",body:JSON.stringify(t),headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}});if(!n.ok)throw new Error(`Request to ${e} failed with status ${n.status}: ${await n.text()}`);return n.json()}};var Ue=class extends K{constructor(e){super(e)}async getScreenshotFromS3(e){let t=await this.sendRequest(`/${K.API_VERSION}/s3/visual-diff-screenshot`,{url:e});return xa.string().parse(t)}async getElementLocation(e,t){let n=await this.sendRequest(`/${K.API_VERSION}/web-agent/locate-element`,{browserState:e.browserState,goal:e.goal,disableCache:t});return tr.parse(n)}async getElementLocationWithVision(e,t){let n=await this.sendRequest(`/${K.API_VERSION}/web-agent/visual-locate`,{goal:e.goal,screenshot:e.screenshot?.toString("base64"),hintActivatedScreenshot:e.hintActivatedScreenshot?.toString("base64"),disableCache:t});return tr.parse(n)}async getAssertionResult(e,t,n){if(t){let s=await this.sendRequest(`/${K.API_VERSION}/web-agent/assertion`,{url:e.url,goal:e.goal,screenshot:e.screenshot?.toString("base64"),disableCache:n,vision:!0});return er.parse(s)}let o=await this.sendRequest(`/${K.API_VERSION}/web-agent/assertion`,{url:e.url,browserState:e.browserState,goal:e.goal,history:e.history,numPrevious:e.numPrevious,lastCommand:e.lastCommand,disableCache:n,vision:!1});return er.parse(o)}async getProposedCommand(e,t){let n=await this.sendRequest(`/${K.API_VERSION}/web-agent/next-command`,{url:e.url,browserState:e.browserState,goal:e.goal,history:e.history,numPrevious:e.numPrevious,lastCommand:e.lastCommand,disableCache:t});return mo.parse(n)}async getGranularGoals(e,t){let n=await this.sendRequest(`/${K.API_VERSION}/web-agent/split-goal`,{url:e.url,goal:e.goal,disableCache:t});return uo.parse(n)}async getReverseMappedDescription(e,t){let n=await this.sendRequest(`/${K.API_VERSION}/web-agent/reverse-mapped-description`,{goal:e.goal,browserState:e.browserState,disableCache:t});return po.parse(n)}async getTextExtraction(e,t){let n={goal:e.goal,browserState:e.browserState,returnSchema:e.returnSchema,disableCache:t},o=await this.sendRequest(`/${K.API_VERSION}/web-agent/text-extraction`,n);return $t.parse(o)}};import{existsSync as Ia,readFileSync as La,writeFileSync as Tr}from"fs";import Cr from"path";import{parse as Oa,stringify as Ma}from"yaml";var $=process.env.MOMENTIC_DIR??Se;function Sn(r,e){let t=Eo(r);for(let[s,a]of Object.entries(t.modules)){let i=Me(s);Tr(Cr.join($,se,`${i}.yaml`),a,"utf-8")}let n=Me(e),o=Cr.join($,`${n}.yaml`);return Tr(o,t.test,"utf-8"),`${n}.yaml`}function wn(r,e){if(!Ia(e))throw new Error(`Test not found at path: ${Cr}`);let t=La(e,"utf-8"),o={...Oa(t),...r},s=Ma(o);Tr(e,s,"utf-8")}import{readFileSync as Nt,readdirSync as bn,writeFileSync as vn}from"fs";import{join as Rr}from"path";import{v4 as Na}from"uuid";import{parse as Pt,stringify as An}from"yaml";var st=Rr($,se);function En(r,e){let t=Ct(st,e).path,n=Nt(t,"utf-8"),s={...Pt(n),...r},a=An(s);vn(t,a,"utf-8")}function Tn(r,e){let t=Me(r),n=Rr(st,`${t}.yaml`),o={fileType:"momentic/module",schemaVersion:V,moduleId:Na(),name:r,steps:e},s=An(o);return vn(n,s,"utf-8"),{type:"RESOLVED_MODULE",moduleId:o.moduleId,name:o.name,steps:o.steps}}function Cn(){let r=[];for(let e in bn(st)){if(!e.endsWith(".yaml"))continue;let t=Nt(e,"utf-8"),n=Pt(t),o={name:n.name,moduleId:n.moduleId,numSteps:n.steps.length};r.push(o)}return r}function Rn(){let r=[];for(let e of bn(st)){if(!e.endsWith(".yaml"))continue;let t=Rr(st,e),n=Nt(t,"utf-8"),o=Pt(n);try{let s=or.parse(o);r.push(s)}catch(s){W.warn({err:s},"Error parsing module, skipping...")}}return r}function xn(r){let e=Ct(se,r).path,t=Nt(e,"utf-8"),n=Pt(t);return or.parse(n)}import{Router as Fa}from"express";import{existsSync as Pa,readFileSync as Da,readdirSync as _a}from"fs";import{join as In}from"path";import{parse as ka}from"yaml";var xr=In($,tt);function Ln(){let r=[];if(!Pa(xr))return[];for(let e of _a(xr)){if(!e.endsWith(".yaml"))continue;let t=In(xr,e),n=Da(t,"utf-8"),o=ka(n);try{let s=ee.parse(o);r.push(s)}catch(s){W.warn({err:s},"Error parsing environment, skipping...")}}return r}function J(r){return function(...e){let t=e[e.length-1],n=r(...e);Promise.resolve(n).catch(t)}}var On=Fa();On.get("/",J((r,e)=>{let t=Ln();e.status(200).json(t)}));var Mn=On;import{Router as za}from"express";var it=za();it.get("/",J((r,e)=>{let n=Rn().map(o=>({...o,type:"RESOLVED_MODULE"}));e.status(200).json(n)}));it.get("/metadata",J((r,e)=>{let t=Cn();e.status(200).json(t)}));it.post("/",J((r,e)=>{let t;try{t=lo.parse(r.body)}catch(o){e.status(400).json({error:`Invalid request body: ${o}`});return}try{rt(t.name)}catch(o){e.status(400).json({error:`Invalid module name: ${o}`});return}let n=Tn(t.name,t.steps);e.status(201).json(n)}));it.get("/:moduleId",J((r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=xn(r.params.moduleId);e.json(t)}));var Nn=it;import{Router as Va}from"express";import{existsSync as ja}from"fs";import{join as Or}from"path";import{v4 as Ga}from"uuid";import Pn,{multistream as Ua}from"pino";import $a from"pino-pretty";var Ir=new Map,Ha=process.env.NODE_ENV==="production",Lr=class r{consoleLogger;ddClientToken;hostname;bindingAttributes;site="https://http-intake.logs.us5.datadoghq.com/api/v2/logs";constructor({bindings:e,clientToken:t,hostname:n}){this.ddClientToken=t,this.hostname=n,this.bindingAttributes={...e,env:process.env.NODE_ENV};let o={base:this.bindingAttributes,errorKey:"err",level:"debug"};this.consoleLogger=Ha?Pn(o):Pn(o,Ua([{stream:$a({colorize:!0})}]))}child(e){return new r({clientToken:this.ddClientToken,bindings:{...this.bindingAttributes,...e},hostname:this.hostname})}flush(e){this.consoleLogger.flush(e)}log(e,t,n,...o){t&&n===void 0&&(n=`${t}`,t={}),this.consoleLogger[e](t,n,...o);let s=Object.assign({},this.bindingAttributes,t&&typeof t=="object"?t:{});o.length>0&&(s.args=o),(async()=>{try{let a=await fetch(this.site,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","DD-API-KEY":this.ddClientToken},body:JSON.stringify([{ddsource:this.bindingAttributes.app,hostname:this.hostname??"vercel",service:"momentic",message:{message:n||"",...s,level:e}}])});if(!a.ok)throw new Error(`Failed to log to Datadog: ${a.statusText})}`)}catch(a){this.consoleLogger.warn({obj:t,msg:n,args:o,err:a},"Failed to log to Datadog")}})()}debug(e,t,...n){this.log("debug",e,t,...n)}info(e,t,...n){this.log("info",e,t,...n)}warn(e,t,...n){this.log("warn",e,t,...n)}error(e,t,...n){this.log("error",e,t,...n)}bindings(){return this.bindingAttributes}setMinLevel(e){this.consoleLogger.level=e}},Dt=({app:r,clientToken:e,hostname:t})=>{if(!process.env.DD_CLIENT_TOKEN&&!process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN&&!e)throw new Error("Missing DD_CLIENT_TOKEN");return Ir.has(r)||Ir.set(r,new Lr({bindings:{app:r},hostname:t,clientToken:e||process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN||process.env.DD_CLIENT_TOKEN})),Ir.get(r)};import{hostname as Ba}from"os";var Q=Dt({app:"desktop-server",clientToken:"pubcfd7516a5c0ba852b42675cd97bee027",hostname:Ba()});var at=Va();at.get("/",J((r,e)=>{let t=ot($,Q);e.status(200).json(t)}));at.post("/",J((r,e)=>{let t;try{t=ao.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}try{rt(t.name)}catch(i){e.status(400).json({error:i.message});return}let o={id:Ga(),name:t.name,baseUrl:t.baseUrl,schemaVersion:V,advanced:{disableAICaching:!1,viewport:t.viewport??de},retries:0,steps:[]};t.environment&&(o.envs=[{name:t.environment,defaultOnLocal:!0}]);let s=Sn(o,t.name),a={...o,testPath:s};e.status(201).json(a)}));at.get("/:testPath",J(async(r,e)=>{if(!r.params.testPath){e.status(400).json({error:"Missing testPath in url path."});return}let t=Or($,r.params.testPath);if(!ja(t)){e.status(400).json({error:`Test not found at path: ${t}`});return}let n=await Rt(t,Or($,se));e.status(200).json(n)}));at.patch("/:testPath",J((r,e)=>{if(!r.params.testPath){e.status(400).json({error:"Missing testPath in url path."});return}let t;try{t=io.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}let n=[],o={};for(let s of t.steps){if(s.type!=="RESOLVED_MODULE"){n.push(s);continue}n.push({type:"MODULE",moduleId:s.moduleId}),o[s.moduleId]=s.steps}for(let[s,a]of Object.entries(o))En({steps:a},s);wn({steps:n},Or($,r.params.testPath)),e.status(201).json({message:"ok"})}));var Dn=at;var Mr="https://api.momentic.ai",kn=r=>{Mr=r},Fn=()=>Mr,Wa,zn=r=>{Wa=r};var _n,Un=async r=>{if(_n)return;let e=await fetch(`${Mr}/v1/auth/check`,{headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`}});if(!e.ok)throw new Error(`Error checking API key with server (code ${e.status}): ${await e.text()}`);let t=await e.json(),{orgId:n}=vo.parse(t);_n=n};async function Hn({momenticServerUrl:r,apiKey:e,mode:t,serverPort:n,appPort:o,staticDir:s,assetsDir:a}){if(!Ya($)||!Xa($).isDirectory()){let h=Za.isAbsolute($);throw new Error(`Root folder ${$} does not exist${h?"":` in the current directory ("${process.cwd()}")`}. Please run \`npx momentic init\` if you wish to setup Momentic here for the first time.`)}r&&kn(r),W.info("Checking API key"),await Un(e);let l=`http://localhost:${n}`;o&&(l=`http://localhost:${o}`);let c=tl(s);await new Promise(h=>{c.listen(n,()=>{W.info(`Server is running at http://localhost:${n}`),h()})});let m=new Ue({baseURL:Fn(),apiKey:e});if(t==="web"){await $n("web",c,m,Q),await Qa(l);return}let f=await rl({appUrl:l,apiGenerator:m,extensionPath:el(a,"extension"),onClose:async()=>{W.info("Browser closed, closing app."),await f.browser.cleanup(),c.close(()=>{process.exit(0)})}});await $n("iframe",c,m,Q,{controller:f,context:new Y("",[])}),process.on("uncaughtException",h=>{Q.error({err:h},"Uncaught exception in desktop-server")}),process.on("unhandledRejection",h=>{Q.error({err:h},"Unhandled rejection in desktop-server")})}function tl(r){let e=Nr();e.use(qa()),e.use(Ka.json({limit:"50mb"}));let t=Nr.Router();if(t.use("/tests",Dn),t.use("/modules",Nn),t.use("/environments",Mn),e.use("/api",t),e.use((o,s,a)=>{o.path!=="/healthcheck"&&Q.debug({url:o.url,path:o.path,query:o.query,method:o.method,body:o.body,headers:o.rawHeaders,client:o.ip},"Received desktop-server request"),s.on("close",()=>{s.statusCode>=400&&Q.error({url:o.url,method:o.method,statusCode:s.statusCode},"Request completed in error")}),a()}),e.use((o,s,a,i)=>{o instanceof Error&&o.message.includes("BadRequestError: request aborted")||(Q.error({stack:o.stack,msg:o.message,url:s.url,method:s.method},"Unhandled exception leading to 500 on desktop-server"),a.status(500).send("Internal Server Error"),i(o))}),r){let o=Nr.static(r);e.use("/",o),e.use("*",o)}return Ja.createServer(e)}async function rl({appUrl:r,apiGenerator:e,extensionPath:t,onClose:n}){let o=await P.init({baseUrl:r,logger:Q,browserArgs:{headless:!1,handleSIGTERM:!0},contextArgs:{bypassCSP:!0,viewport:null,deviceScaleFactor:void 0},waitForLoad:!0,localMode:!0,localAppUrl:r,extensionPath:t,skipPageSetup:!0,timeout:null,onClose:n}),s=new ge({browser:o,config:Fe,generator:e,logger:Q});return zn(s),s}async function $n(r,e,t,n,o){yn({baseServer:e,generator:t,logger:n,localApp:r,rootState:o})}import{existsSync as kl}from"fs";import hs,{dirname as Fl}from"path";import{fileURLToPath as zl}from"url";var Bn="0.0.42";var re="v1",ae=class{baseURL;apiKey;constructor(e){this.baseURL=e.baseURL,this.apiKey=e.apiKey}async getRun(e){let t=await this.sendRequest(`/${re}/runs/${e}`,{method:"GET"});return wo.parse(t)}async createRun(e){let t=await this.sendRequest(`/${re}/runs`,{method:"POST",body:e});return So.parse(t)}async updateRun(e,t){await this.sendRequest(`/${re}/runs/${e}`,{method:"PATCH",body:t})}async getTest(e){let t=await this.sendRequest(`/${re}/tests/${e}`,{method:"GET"});return fo.parse(t)}async getAllTestIds(){let e=await this.sendRequest(`/${re}/tests`,{method:"GET"});return go.parse(e)}async getTestYAMLExport(e){let t=await this.sendRequest(`/${re}/tests/export`,{method:"POST",body:e});return yo.parse(t)}async updateTestWithYAML(e){await this.sendRequest(`/${re}/tests/update`,{method:"POST",body:e})}async queueTests(e){let t=await this.sendRequest(`/${re}/tests/queue`,{method:"POST",body:e});return ho.parse(t)}async uploadScreenshot(e){let t=await this.sendRequest(`/${re}/screenshots`,{method:"POST",body:e});return bo.parse(t)}async getAllEnvironments(){let e=await this.sendRequest(`/${re}/environments`,{method:"GET"});return Ao.parse(e)}async updateEnvironments(e){await this.sendRequest(`/${re}/environments`,{method:"POST",body:e})}async sendRequest(e,t){let n=await fetch(`${this.baseURL}${e}`,{method:t.method,body:t.body?JSON.stringify(t.body):void 0,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}});if(!n.ok)throw new Error(`Request to ${e} failed with status ${n.status}: ${await n.text()}`);return n.status===204?n.text():n.json()}};import{hostname as nl}from"os";var w=Dt({app:"cli",clientToken:"pub7eb923f18fb3f1d42ac5eba8c5ea13a5",hostname:nl()});import{createHash as Wn}from"crypto";import{existsSync as Kn,mkdirSync as ml,readFileSync as Fr,writeFileSync as qn}from"fs";import{join as Yn}from"path";import{parse as ul}from"yaml";import{existsSync as Pr,mkdirSync as al,readdirSync as jn,statSync as Dr}from"fs";import{homedir as Gn}from"os";import{join as lt,resolve as ll}from"path";import sl from"chalk";import il from"readline/promises";async function oe(r,e){if(process.env.CI)return!0;let t=il.createInterface({input:process.stdin,output:process.stdout});r=`${r} (y/N) `;let n=e?sl.bold.yellow(r):r,o=await t.question(n);return t.close(),o.toLowerCase()==="y"}var _r=Se,$e=lt(Se,se),kr=lt(Se,Kt),le=lt(Se,tt),cl=lt(Gn(),"momentic",qt),dl=[cl,$e,kr,le];function Vn(r){try{return Pr(r)&&Dr(r).isDirectory()}catch(e){return w.error({err:e},`Error reading path ${r} during directory exists check`),!1}}async function be(r,e=!1){Gn()||(w.error("Your home directory could not be found. Please ensure the HOME environment variable is set for POSIX systems, and the USERPROFILE environment variable is set for Windows systems."),process.exit(1)),Vn(_r)||!e&&!await oe(`A '${Se}' folder was not found in the current directory. Proceed with creation here? You will need to invoke the Momentic CLI from this directory in the future.`)&&(w.error("Setup cancelled"),process.exit(1));for(let t of dl)Vn(t)||(!e&&!await oe(`'${t}' folder was not found in the current directory. Create it now?`)&&(w.error("Setup cancelled"),process.exit(1)),al(t,{recursive:!0}));jn(le).length===0&&(!e&&!await oe("You do not appear to have any environments configured locally. Pull environments from Momentic Cloud?")&&(w.error("Setup cancelled"),process.exit(1)),await _t({client:r,all:!0,skipPrompts:e})),w.info("CLI initialization complete")}function ct(r,e,t=new Set){for(let n of r){let o=ll(n),s=!1;try{s=Pr(o)&&Dr(o).isDirectory()}catch(a){w.error({err:a},`Error reading path ${o} during collect paths`)}if(o&&s){let a=jn(o).map(i=>lt(o,i));ct(a,e,t);continue}if(o.endsWith(".yaml")){try{if(!Pr(o)||!Dr(o).isFile()){w.error(`File not found or unreadable: ${o}`);continue}}catch(a){w.error({err:a},`Error reading file ${o} during collect paths`);continue}if(!e(o))continue;t.add(o)}}return t}async function _t({envNames:r,client:e,all:t,skipPrompts:n}){let o=await e.getAllEnvironments();r&&!t&&(o=o.filter(i=>r?.includes(i.name))),Kn(le)||ml(le);let s=0,a=0;for(let i of o){let l=Yn(le,`${i.name}.yaml`);if(!Kn(l))qn(l,nr(i)),s++;else{let c=Wn("sha256").update(Fr(l)).digest("hex"),d=nr(i),m=Wn("sha256").update(d).digest("hex");if(c!==m){if(!n&&!await oe(`Environment ${i.name} already exists on disk but needs to be updated. Overwrite?`)){w.error("Pull cancelled");return}qn(l,d),a++}}}w.info(`Pulled ${s} new environments and updated ${a} existing environments`)}function pl(r){return r.endsWith(".yaml")?Fr(r,"utf8").includes("momentic/environment")?!0:(w.warn(`Skipping YAML that is not a Momentic environment: ${r}`),!1):!1}async function Xn({client:r,names:e,all:t,yes:n}){let o;t?o=[le]:o=e.map(i=>Yn(le,`${i.toLowerCase()}.yaml`));let s=ct(o,pl);w.info(`Found ${s.size} environments(s) to push:`),s.forEach(i=>w.info(` - ${i}`)),w.info("Loading file contents");let a=[];for(let i of s){let l=ul(Fr(i,"utf-8"));try{let c=ee.parse(l);a.push(c)}catch(c){w.error({err:c},`${i} failed to parse as a valid environment file`),process.exit(1)}}if(!n&&!await oe("Pushing environments can overwrite variables on cloud and instantly affect scheduled runs. Continue?",!0)){w.error("Push cancelled");return}w.info(`Pushing ${s.size} environment(s)`),await r.updateEnvironments(a),w.info("Push successful!")}import{registry as zr}from"playwright-core/lib/server";function hl(r){let e=[],t=[];for(let n of r){let o=zr.findExecutable(n);!o||o.installType==="none"?e.push(n):t.push(o)}return t}async function Jn(){let r=hl(["chromium"]);await zr.installDeps(r,!1),await zr.install(r,!1)}import{Argument as kt,Option as He}from"commander";var ve=new He("--api-key <key>","API key for authentication. If not supplied, attempts to read the MOMENTIC_API_KEY env var.").env("MOMENTIC_API_KEY").makeOptionMandatory(!0),Ae=new He("--server <server>","Momentic server to use. Leave unchanged unless using Momentic on-premise.").default("https://api.momentic.ai"),Ee=new He("-y, --yes","Skip confirmation prompts.").env("CI").default(!1),Qn=new He("--no-report","Skip reporting test results to Momentic Cloud when running with the --local flag."),Zn=new He("--env <env>","Name of the environment to use when running tests."),Ur=new He("-a, --all","Select all tests in your organization from Momentic Cloud. Cannot be used together with <tests> arguments."),$r=new He("-a, --all","Select all environments in your organization from Momentic Cloud. Cannot be used together with <paths> arguments."),es=new kt("<tests...>",`One or more test paths to pull from Momentic Cloud.
|
|
30
30
|
|
|
31
|
-
A test path is a lowercased version of your test name where spaces are replaced with underscores: 'npx momentic pull hello-world'.`).argOptional(),
|
|
31
|
+
A test path is a lowercased version of your test name where spaces are replaced with underscores: 'npx momentic pull hello-world'.`).argOptional(),ts=new kt("<tests...>",`One or more test identifiers.
|
|
32
32
|
|
|
33
33
|
To use tests stored on your local file system, pass '--local' and specify file paths to Momentic YAML files or folders that exist locally: 'npx momentic run --local momentic/hello-world.yaml'.
|
|
34
34
|
|
|
35
|
-
To use tests stored remotely on Momentic Cloud, pass '--remote' and specify one or more test paths. A test path is a lowercased version of your test name where spaces are replaced with underscores: 'npx momentic run --remote hello-world'.`).argOptional(),
|
|
36
|
-
`))}catch(o){throw new Error(`Fixture at path ${e} does not parse as valid YAML: ${o}`)}let n;try{n=
|
|
37
|
-
Please supply the --local flag to run tests locally, or specify the test path without its file extension to queue tests remotely (e.g. 'hello-world').`),process.exit(1));await
|
|
35
|
+
To use tests stored remotely on Momentic Cloud, pass '--remote' and specify one or more test paths. A test path is a lowercased version of your test name where spaces are replaced with underscores: 'npx momentic run --remote hello-world'.`).argOptional(),rs=new kt("<paths...>","File paths pointing to one or more Momentic YAML files. Paths to directories are supported as well."),Hr=new kt("<envs...>","One or more environment names to push").argOptional();import{existsSync as gl,writeFileSync as os}from"fs";import{join as ns}from"path";async function as({testsToFetch:r,client:e,all:t}){t&&w.info({url:e.baseURL},"Fetching all tests from the server. This may take a while...");let{tests:n,modules:o}=await e.getTestYAMLExport({paths:r,all:t}),s=Object.keys(n).length;for(let[i,l]of Object.entries(n)){let c=ns(_r,is(i));if(!await ss(c)){w.error("Pull cancelled");return}os(c,l,"utf-8"),w.info(`Wrote '${c}'`)}let a=Object.keys(o).length;for(let[i,l]of Object.entries(o)){let c=ns($e,is(i));if(!await ss(c)){w.error("Pull cancelled");return}os(c,l,"utf-8"),w.info(`Wrote '${c}'`)}s===0?w.info("Pulled zero tests! For onprem deployments, please ensure the --server parameter is set correctly."):w.info(`Pulled ${s} test${s>1?"s":""}${a?` and ${a} module${a>1?"s":""}`:""}!`)}async function ss(r){return gl(r)?oe(`File '${r.replace(/(\s+)/g,"\\$1")}' already exists. Overwrite existing content?`,!0):!0}function is(r){return`${Me(r)}.yaml`}import{existsSync as xS,readFileSync as yl}from"fs";async function ls(r){let e=ct(r.paths,Sl);w.info(`Found ${e.size} test(s) to push:`),e.forEach(o=>w.info(` - ${o}`)),w.info("Loading file contents and resolving dependent modules");let t=Array.from(e).map(o=>lr(o,$e)),n=new Set(t.flatMap(o=>Object.keys(o.modules)));if(w.info(`Resolved ${e.size} test(s) and ${n.size} module(s)`),!r.yes&&!await oe("Pushing tests overwrites tests on production and will instantly affect scheduled runs. Continue?",!0)){w.error("Push cancelled");return}await r.client.updateTestWithYAML(t),w.info("Update successful!")}function Sl(r){return r.endsWith(".yaml")?yl(r,"utf8").includes("momentic/test")?!0:(w.warn(`Skipping YAML that is not a Momentic test: ${r}`),!1):(w.warn(`Skipping file that does not have YAML extension: ${r}`),!1)}import{existsSync as ms,readFileSync as Ll,statSync as Ol}from"fs";import{join as Ml}from"path";import Nl from"wait-on";import{parse as Pl}from"yaml";import wl from"@actions/exec";import bl from"@actions/io";import vl from"quote";import Al from"string-argv";async function cs(r,e=!0){let t=Al(r),n=await bl.which(t[0],!0),o=t.slice(1),s=wl.exec(vl(n),o,{delay:100});if(e)return s}import{v4 as Il}from"uuid";import{existsSync as El,readFileSync as Tl}from"fs";import{join as Cl}from"path";import{parse as Rl}from"yaml";function xl(r){let e=Cl(kr,`${r}.yaml`);if(!El(e))throw new Error(`Fixture '${r}' does not exist at expected path ${e}`);let t;try{t=Rl(Tl(e,"utf-8").replace(/\r\n|\r/g,`
|
|
36
|
+
`))}catch(o){throw new Error(`Fixture at path ${e} does not parse as valid YAML: ${o}`)}let n;try{n=ro.parse(t)}catch(o){throw new Error(`Fixture at path ${e} does not conform to expected schema: ${o}`)}return n}async function Br(r,e){let t=xl(r),n=e==="setup"?t.setup:t.teardown;if(!n){w.warn(`Fixture '${r}' does not have any steps in the ${e} phase, skipping...`);return}let o=n.timeout,s=async function(){for(let c=0;c<n.steps.length;c++){let d=n.steps[c],m=d.run,f=async h=>{try{await Do(`set -ex; ${m}`)}catch(p){if(h){let y=`Fixture '${r}' ${e} step ${c+1} errored in the background. The test will continue, but this may affect test execution and results: ${p}`;w.error(y)}else throw new Error(`Fixture '${r}' ${e} step ${c+1} errored: ${p}`)}};d.waitForCompletion===!1?f(!0):await f(!1)}};if(w.info(`Running ${e} phase of fixture '${r}'`),!o){await s();return}let a,i,l=async function(){return new Promise((c,d)=>{i=c,a=setTimeout(()=>{i=void 0,d(`Fixture '${r}' ${e} phase timed out after ${o} seconds`)},o*1e3)})};try{await Promise.race([s(),l()])}catch(c){throw c}finally{i&&i(),clearTimeout(a)}}async function ds({path:r,apiClient:e,generator:t,useLocalFiles:n,noReport:o,environment:s,newBaseUrl:a}){let i;n?(w.info(`Reading ${r} from local filesystem`),i=await Rt(r,$e)):(w.info(`Fetching ${r} from Momentic Cloud server (${e.baseURL})`),i=await e.getTest(r)),i.schemaVersion>V&&w.warn(`Test ${r} has schema version ${i.schemaVersion}, which is greater than what is currently supported by this SDK. Please update your momentic package version to avoid unexpected behavior.`);let l=[],c={};s&&(l=i.envs?.find(g=>g.name===s.name)?.fixtures??[],c=s.variables);for(let b of l)await Br(b,"setup");let d;if(i.baseUrl){if(d=i.baseUrl,a){let b=new URL(i.baseUrl),g=new URL(a);b.hostname=g.hostname,b.protocol=g.protocol,b.port=g.port,d=b.toString()}}else d=c[Ie],d||(w.error(`Test ${i.name} has no baseURL and the environment has no ${Ie} variable either`),process.exit(1));let m=await P.init({baseUrl:d,logger:w,waitForLoad:!0,contextArgs:{viewport:i.advanced.viewport??de}}),f=new ge({browser:m,generator:t,config:Fe,logger:w}),h=new Y(d,i.steps),p,y;if(o)y=Il();else try{p=await e.createRun({testId:i.id,trigger:"CLI"}),y=p.id}catch(b){throw w.error(b),new Error(`Are you sure test ${i.name} exists on the server?`)}let S="FAILED";try{S=await nn({test:i,context:h,runId:y,controller:f,logger:w,takeScreenshots:!0,onSaveScreenshot:async b=>{if(o)return"";let{key:g}=await e.uploadScreenshot({screenshot:b.toString("base64")});return g},onUpdateRun:async b=>{o||await e.updateRun(y,b)}})}catch(b){throw o||await e.updateRun(y,{status:"FAILED",finishedAt:new Date}),o||w.error(`Test '${i.name}' failed. You can view a playback of this run at ${e.baseURL}/runs/${y}`),b}finally{try{for(let b of l)await Br(b,"teardown")}catch(b){w.error(`Failed to run teardown fixtures: ${b}`)}}return S}async function us({tests:r,start:e,waitOn:t,waitOnTimeout:n,client:o,all:s,report:a,env:i,parallelization:l=1}){e&&(w.info(`Running start command: ${e}`),await cs(e,!1)),t&&(w.info(`Waiting for ${t} to be accessible (timeout: ${n}s)`),await Nl({resources:[t],timeout:n*1e3}));let c;if(i){let g=Ml(le,`${i}.yaml`),R=Pl(Ll(g,"utf-8"));try{c=ee.parse(R),w.info(`Running in the ${i} environment with the following variables:`),w.info(c.variables)}catch(A){w.error({err:A},`${g} failed to parse as a valid environment file`),process.exit(1)}}let d=new Ue({baseURL:o.baseURL,apiKey:o.apiKey}),m=!1;(r.some(g=>g.endsWith(".yaml"))||r.some(g=>ms(g)))&&(m=!0);let f=new Set;if(m)w.info(r,"Reading tests from the following local file paths:"),r.forEach(g=>{if(!ms(g))throw new Error(`Path '${g}' does not exist.`);let R,A;try{R=Ol(g),A=R.isDirectory()}catch(E){w.error({err:E},`Skipping path ${g} because it cannot be read`);return}if(A)ot(g,w).map(E=>E.fullFilePath).forEach(E=>f.add(E));else if(g.endsWith(".yaml"))f.add(g);else throw new Error(`Path '${g}' is not a directory or a .yaml file.`)});else if(w.warn("The paths you specified are not files or directories that exist locally."),w.warn(`Fetching tests from Momentic Cloud (${o.baseURL}) instead...`),s)for(let g of await o.getAllTestIds())f.add(g);else f=new Set(r);let h=Array.from(f);w.info(h,`Identified ${h.length} tests to run locally:`);let p=[];for(let g=0;g<h.length;g+=l){let R=await Promise.all(h.slice(g,g+l).map(async A=>{let E="FAILED";try{E=await ds({useLocalFiles:m,path:A,apiClient:o,generator:d,newBaseUrl:t,environment:c,noReport:!a})}catch(k){let Be=k instanceof Error?k.message:`${k}`;w.error(`Test ${A} failed with error: ${Be}`)}return{runStatus:E,path:A}}));p=p.concat(R)}let y=p.filter(g=>g.runStatus==="PASSED");y.length>0&&(w.info(`Passed ${y.length} out of ${p.length} tests:`),y.forEach(g=>{w.info(`- ${g.path}`)}));let S=p.filter(g=>g.runStatus==="CANCELLED");S.length>0&&(w.warn(`Cancelled ${S.length} out of ${p.length} tests:`),S.forEach(g=>{w.warn(`- ${g.path}`)}));let b=p.filter(g=>g.runStatus==="FAILED");b.length>0&&(w.error(`Failed ${b.length} out of ${p.length} tests:`),b.forEach(g=>{w.error(`- ${g.path}`)}),process.exit(1)),process.exit(0)}async function ps({tests:r,client:e,env:t,all:n}){let{queuedTests:o}=await e.queueTests({testPaths:r,env:t,all:n});w.info(`Successfully queued ${o.length} tests!`)}var ce=new Dl;ce.name("momentic").description("Momentic CLI").version(Bn);ce.command("install-browsers").action(async()=>{await Jn()});ce.addOption(new ye("--log-level <level>").choices(["debug","info","warn","error"]).default("info")).on("option:log-level",r=>{w.setMinLevel(r.toLowerCase())});ce.command("init").addOption(Ee).addOption(ve).addOption(Ae).action(async r=>{let{yes:e,apiKey:t,server:n}=r,o=new ae({baseURL:n,apiKey:t});await be(o,e)});ce.command("app").addOption(ve).addOption(Ae).addOption(Ee).addOption(new ye("--port <port>","Port to run the app on. Defaults to 58888.").default(58888)).addOption(new ye("--mode <mode>","Mode to run the app in. Defaults to iframe.").choices(["iframe","web"]).default("iframe")).action(async r=>{let{apiKey:e,port:t,yes:n,server:o,mode:s}=r,a=new ae({baseURL:o,apiKey:e});await be(a,n);let i=zl(import.meta.url),l=Fl(i),c=hs.resolve(l,"..","static"),d=hs.resolve(l,"..","assets");await Hn({momenticServerUrl:o,mode:s,apiKey:e,serverPort:t,appPort:t,staticDir:c,assetsDir:d})});ce.command("run").alias("run-tests").addOption(ve).addOption(Ae).addOption(Ur).addOption(Ee).addOption(new ye("-r, --remote","Run tests remotely. The production version of this test will be queued for execution.").default(!0).conflicts(["start, waitOn, waitOnTimeout, local"]).implies({local:!1})).addOption(Qn).addOption(new ye("-l, --local","Run tests locally. Useful for accessing apps on localhost. This option does not control where tests are read from (see <tests> argument documentation).").implies({remote:!1,noReport:!0})).addOption(new ye("--start <command>","Arbitrary setup command that will run before Momentic steps begin.")).addOption(new ye("--wait-on <url>","URL to wait to become accessible before Momentic tests begin.")).addOption(Zn).addOption(new ye("--wait-on-timeout <timeout>","Max time to wait for the --wait-on URL to become accessible.").default(60,"one minute")).addOption(new ye("-p, --parallel <parallelization>","When running with the --local flag, the number of tests to run in parallel. Defaults to 1.").default(1)).addArgument(ts).action(async(r,e)=>{let{apiKey:t,server:n,remote:o,local:s,all:a,env:i,yes:l}=e;!a&&(!r||!r.length)&&(w.error("You must pass at least one test path or the --all flag"),process.exit(1));let c=new ae({baseURL:n,apiKey:t});if(await be(c,l),s){try{await us({tests:r,client:c,...e})}catch(d){w.error(d),process.exit(1)}return}if(o){for(let d of r)(d.endsWith(".yaml")||kl(d))&&(w.error(_l`'${d}' looks like a local file or directory, but the --local flag was not supplied.
|
|
37
|
+
Please supply the --local flag to run tests locally, or specify the test path without its file extension to queue tests remotely (e.g. 'hello-world').`),process.exit(1));await ps({tests:r,client:c,all:a,env:i});return}w.error("One of --remote or --local must be specified"),process.exit(1)});ce.command("pull").description("Fetch one or more tests from Momentic Cloud and save it in to local disk in YAML format.").addOption(ve).addOption(Ae).addOption(Ur).addOption(Ee).addArgument(es).action(async(r,e)=>{let{apiKey:t,server:n,all:o,yes:s}=e,a=new ae({baseURL:n,apiKey:t});if(await be(a,s),!o&&!r?.length)throw new Error("At least one test name or --all must be provided");await as({testsToFetch:r??[],client:a,all:o})});ce.command("push").description("Save one or more tests in YAML format to Momentic Cloud.").addOption(Ee).addOption(ve).addOption(Ae).addArgument(rs).action(async(r,e)=>{let{apiKey:t,server:n,yes:o}=e;await be(t,o);let s=new ae({baseURL:n,apiKey:t});await ls({paths:r,client:s,yes:o})});var fs=ce.command("env").description("Perform operations on Momentic environments");fs.command("push").description("Push one or more environments and associated variables to Momentic cloud.").addOption(Ee).addOption(ve).addOption(Ae).addOption($r).addArgument(Hr).action(async(r,e)=>{let{apiKey:t,server:n,yes:o,all:s}=e;!r?.length&&!s&&(w.error("At least one environment name or --all must be provided"),process.exit(1)),await be(t,o);let a=new ae({baseURL:n,apiKey:t});await Xn({names:r,client:a,yes:o,all:s})});fs.command("pull").description("Pull one or more environments and associated variables from Momentic cloud.").addOption(Ee).addOption(ve).addOption(Ae).addOption($r).addArgument(Hr).action(async(r,e)=>{let{apiKey:t,server:n,yes:o,all:s}=e;!r?.length&&!s&&(w.error("At least one environment name or --all must be provided"),process.exit(1)),await be(t,o);let a=new ae({baseURL:n,apiKey:t});await _t({envNames:r,client:a,skipPrompts:o,all:s})});async function Ul(){try{await ce.parseAsync(process.argv)}catch(r){w.error(r)}}Ul();
|