momentic 2.28.6 → 2.28.7
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 +5 -5
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -28,8 +28,8 @@ ${this.decisions.map(e=>e.toString()).join(`
|
|
|
28
28
|
`);process.stderr.write(`${o}
|
|
29
29
|
`),globalThis.console=e}}var vt=" ".repeat(6);function bR(r,e="",t=!1){let n=process.stdout?.columns||process.stderr?.columns||80,o=Math.max(n-e.length,20),i=r.split(`
|
|
30
30
|
`),a=[];for(let s of i)if(t){let c=s;for(;c.length>o;){let u=c.slice(0,o+1).lastIndexOf(" "),d=u>-1?u:o;a.push(e+c.slice(0,d)),c=c.slice(d).trimStart()}a.push(e+c)}else{let c=s.split(" "),l="";for(let u of c){if(!l.length){l=u;continue}let d=`${l} ${u}`;d.length<=o?l=d:(a.push(e+l),l=u)}a.push(e+l)}return a.join(`
|
|
31
|
-
`)}import ZF from"fetch-retry";import eU from"os";import vR,{multistream as tU}from"pino";import rU from"pino-pretty";import nU from"pino-std-serializers";var La=new Map,oU=!0,RR="Log throttle exceeded",iU=100,aU=5e3,sU=ZF(global.fetch,{retries:2,retryOn:function(r,e,t){return!!(e!==null||t&&t.status>=500)},retryDelay:function(r){return Math.pow(2,r)*500}}),gg=class r{consoleLogger;hostname;bindingAttributes;disableConsoleLogs;minLevelValue=20;logsInCurrentWindow=0;droppedLogsInWindow=!1;lastWindowStart=Date.now();site="https://ingest.us.signoz.cloud:443/logs/json";flushIntervalMs;maxBatchSize;buffer=[];flushTimer;constructor({bindings:e,hostname:t,disableConsoleLogs:n,flushIntervalMs:o,maxBatchSize:i}){this.hostname=t??eU.hostname(),this.disableConsoleLogs=n,this.bindingAttributes={...e,env:"production"},this.flushIntervalMs=o??5e3,this.maxBatchSize=i??10;let a={base:this.bindingAttributes,errorKey:"err",level:"debug"};this.consoleLogger=oU?vR(a):vR(a,tU([{stream:rU({colorize:!0})}]))}child(e){return new r({bindings:{...this.bindingAttributes,...e},hostname:this.hostname,disableConsoleLogs:this.disableConsoleLogs,flushIntervalMs:this.flushIntervalMs,maxBatchSize:this.maxBatchSize})}async flush(){await this.flushBuffer(),this.disableConsoleLogs||this.consoleLogger.flush()}scheduleFlush(){this.flushTimer||(this.flushTimer=setTimeout(()=>{this.flushTimer=void 0,this.flushBuffer()},this.flushIntervalMs))}async flushBuffer(){if(this.buffer.length===0)return;let e=this.buffer;this.buffer=[];try{let t=await sU(this.site,{method:"POST",headers:{"Content-Type":"application/json","signoz-access-token":"CumAaTMUcwjt05OddAmefKgshbhfRmWxzxih"},body:Ri(e),signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`Got error status (${t.statusText}) from SigNoz`)}catch{}}shouldAllowLog(e){if(e===RR)return!0;let t=Date.now();return t-this.lastWindowStart>aU&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,RR),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<iU?(this.logsInCurrentWindow++,!0):(this.droppedLogsInWindow=!0,!1)}log(e,t,n,...o){try{this.logHelper(e,t,n,...o)}catch(i){this.consoleLogger.warn(`Failed to log to Signoz: ${i}`)}}logHelper(e,t,n,...o){if(fl[e]<this.minLevelValue||!this.shouldAllowLog(n))return;typeof t=="string"&&!n&&(t={message:t}),typeof t=="object"&&t&&"err"in t&&t.err instanceof Error&&(t.err=nU.err(t.err));let i={...this.bindingAttributes,...t&&typeof t=="object"?t:{},...o.length>0?{args:o}:{}},a={host:this.hostname,env:this.bindingAttributes.env};this.disableConsoleLogs||this.consoleLogger[e](i,n,...o);let s={timestamp:Math.round(Date.now()*1e6),severity_text:e.toUpperCase(),resources:a,attributes:{},body:cv({message:n||"",...i})};this.buffer.push(s),this.buffer.length>=this.maxBatchSize?(this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=void 0),this.flushBuffer()):this.scheduleFlush()}setApp(e){let t=this.bindingAttributes.app;this.bindingAttributes.app=e,La.set("app",this),La.delete(t)}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}addBinding(e,t){this.bindingAttributes[e]=t}setMinLevel(e){typeof e=="number"?(this.minLevelValue=e,this.consoleLogger.level=uv[e]):(this.minLevelValue=fl[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},Na=({app:r,hostname:e,disableConsoleLogs:t})=>(La.has(r)||La.set(r,new gg({bindings:{app:r},hostname:e,disableConsoleLogs:t})),La.get(r));async function wR(){await Promise.all([...La.values()].map(r=>r.flush()))}import{hostname as lU}from"os";var Y=Na({app:"cli",hostname:lU(),disableConsoleLogs:!0}).child({cliVersion:"2.28.
|
|
32
|
-
`);console.warn(n),r.warn({stack:n,time:e},"NodeJS event loop blocked")},{threshold:1e3,trimFalsePositives:!0})}function TU(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}yU(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as $2}from"crypto";import sO from"body-parser";import PK from"cors";import OK from"dedent";import{Router as vB}from"express";import ur from"fs";import{globSync as RB}from"glob";import Dt from"path";import ud from"fs";import{z as MU}from"zod";var G="v1",yg="cli",Ci="2.28.
|
|
31
|
+
`)}import ZF from"fetch-retry";import eU from"os";import vR,{multistream as tU}from"pino";import rU from"pino-pretty";import nU from"pino-std-serializers";var La=new Map,oU=!0,RR="Log throttle exceeded",iU=100,aU=5e3,sU=ZF(global.fetch,{retries:2,retryOn:function(r,e,t){return!!(e!==null||t&&t.status>=500)},retryDelay:function(r){return Math.pow(2,r)*500}}),gg=class r{consoleLogger;hostname;bindingAttributes;disableConsoleLogs;minLevelValue=20;logsInCurrentWindow=0;droppedLogsInWindow=!1;lastWindowStart=Date.now();site="https://ingest.us.signoz.cloud:443/logs/json";flushIntervalMs;maxBatchSize;buffer=[];flushTimer;constructor({bindings:e,hostname:t,disableConsoleLogs:n,flushIntervalMs:o,maxBatchSize:i}){this.hostname=t??eU.hostname(),this.disableConsoleLogs=n,this.bindingAttributes={...e,env:"production"},this.flushIntervalMs=o??5e3,this.maxBatchSize=i??10;let a={base:this.bindingAttributes,errorKey:"err",level:"debug"};this.consoleLogger=oU?vR(a):vR(a,tU([{stream:rU({colorize:!0})}]))}child(e){return new r({bindings:{...this.bindingAttributes,...e},hostname:this.hostname,disableConsoleLogs:this.disableConsoleLogs,flushIntervalMs:this.flushIntervalMs,maxBatchSize:this.maxBatchSize})}async flush(){await this.flushBuffer(),this.disableConsoleLogs||this.consoleLogger.flush()}scheduleFlush(){this.flushTimer||(this.flushTimer=setTimeout(()=>{this.flushTimer=void 0,this.flushBuffer()},this.flushIntervalMs))}async flushBuffer(){if(this.buffer.length===0)return;let e=this.buffer;this.buffer=[];try{let t=await sU(this.site,{method:"POST",headers:{"Content-Type":"application/json","signoz-access-token":"CumAaTMUcwjt05OddAmefKgshbhfRmWxzxih"},body:Ri(e),signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`Got error status (${t.statusText}) from SigNoz`)}catch{}}shouldAllowLog(e){if(e===RR)return!0;let t=Date.now();return t-this.lastWindowStart>aU&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,RR),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<iU?(this.logsInCurrentWindow++,!0):(this.droppedLogsInWindow=!0,!1)}log(e,t,n,...o){try{this.logHelper(e,t,n,...o)}catch(i){this.consoleLogger.warn(`Failed to log to Signoz: ${i}`)}}logHelper(e,t,n,...o){if(fl[e]<this.minLevelValue||!this.shouldAllowLog(n))return;typeof t=="string"&&!n&&(t={message:t}),typeof t=="object"&&t&&"err"in t&&t.err instanceof Error&&(t.err=nU.err(t.err));let i={...this.bindingAttributes,...t&&typeof t=="object"?t:{},...o.length>0?{args:o}:{}},a={host:this.hostname,env:this.bindingAttributes.env};this.disableConsoleLogs||this.consoleLogger[e](i,n,...o);let s={timestamp:Math.round(Date.now()*1e6),severity_text:e.toUpperCase(),resources:a,attributes:{},body:cv({message:n||"",...i})};this.buffer.push(s),this.buffer.length>=this.maxBatchSize?(this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=void 0),this.flushBuffer()):this.scheduleFlush()}setApp(e){let t=this.bindingAttributes.app;this.bindingAttributes.app=e,La.set("app",this),La.delete(t)}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}addBinding(e,t){this.bindingAttributes[e]=t}setMinLevel(e){typeof e=="number"?(this.minLevelValue=e,this.consoleLogger.level=uv[e]):(this.minLevelValue=fl[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},Na=({app:r,hostname:e,disableConsoleLogs:t})=>(La.has(r)||La.set(r,new gg({bindings:{app:r},hostname:e,disableConsoleLogs:t})),La.get(r));async function wR(){await Promise.all([...La.values()].map(r=>r.flush()))}import{hostname as lU}from"os";var Y=Na({app:"cli",hostname:lU(),disableConsoleLogs:!0}).child({cliVersion:"2.28.7"});var uU=5;async function Fu({getResults:r,checkDone:e,name:t,timeoutMs:n=18e5}){let o=Date.now(),i=0;for(;Date.now()-o<n;){let a;i>uU&&(E.error(`Failed to fetch ${t} status too many times.`),process.exit(1));try{a=await r(),i=0}catch(l){i++,Y.warn({err:l},"Failed to fetch run status, retrying..."),E.warn({err:l},"Failed to fetch run status, retrying..."),await new Promise(u=>setTimeout(u,1500*i));continue}if(e(a))return a;let c=Math.max(1e4,Math.floor(n/100));await new Promise(l=>setTimeout(l,c))}E.error(`Timeout elapsed waiting for ${t} to complete (${Math.floor(n/1e3)}s).`),process.exit(1)}function Da({results:r,startTime:e,entity:t,getDisplayLine:n,onFailed:o}){let i=r.filter(u=>u.status==="PASSED"&&u.quarantined),a=r.filter(u=>u.status==="PASSED"&&!u.quarantined),s=r.filter(u=>u.status==="FAILED"&&u.quarantined),c=r.filter(u=>u.status==="FAILED"&&!u.quarantined),l=r.filter(u=>u.status==="CANCELLED");return TR(()=>{if(c.forEach(u=>{E.log(""),o(u)}),c.length){E.log("");let u=c.length===1?"":"s";E.error(`${c.length} ${t}${u} failed:`),c.forEach(d=>{E.dimmed(n(d))})}if(l.length){E.log("");let u=l.length===1?"":"s";E.warn(`${l.length} ${t}${u} cancelled:`),l.forEach(d=>{E.dimmed(n(d))})}if(a.length){E.log("");let u=a.length===1?"":"s";E.success(`${a.length} ${t}${u} passed:`),a.forEach(d=>{E.dimmed(n(d))})}if(s.length){E.log("");let u=s.length===1?"":"s";E.warn(`${s.length} quarantined ${t}${u} failed:`),s.forEach(d=>{E.dimmed(n(d))})}if(i.length){E.log("");let u=i.length===1?"":"s";E.warn(`${i.length} quarantined ${t}${u} passed:`),i.forEach(d=>{E.dimmed(n(d))})}E.log(""),E.dimmed(`Total time: ${Math.round((Date.now()-e)/1e3)}s`)}),{quarantinedPassed:i.length,passed:a.length,quarantinedFailed:s.length,failed:c.length,cancelled:l.length}}var Uu=(r,e)=>{if(!r.failureDetails||!r.failureReason)return;let t=Vc[r.failureDetails?.classification?.reason||r.failureReason],n=r.failureDetails?.classification?.summary||fa[r.failureReason],o=r.failureDetails.classification?.rootCause;if(E.error(e),o){E.log(`${vt}- Error type: ${Cn.dim(t)}`);let i="- Root cause analysis:",a=bR(`${i} ${o}`,`${vt} `,!1),s=a.indexOf(":");E.log(`${vt}${i} ${Cn.dim(a.slice(s+1))}`)}else E.log(`${vt}Reason: ${Cn.red(t)}`),E.log(`${vt}Description: ${Cn.red(n)}`)},Tl=({status:r,testLogRef:e,getRunningTestsCount:t,getTotalTestsCount:n,additionalText:o})=>{r=r.toUpperCase();let i=r,a;r.includes("FAIL")?(i=Cn.bgRed.white("FAIL"),a=3):r.includes("PASS")?(i=Cn.bgGreen.white("PASS"),a=3):r.includes("START")?(i=Cn.bgBlue.white("START"),a=2):r.includes("CANCEL")?(i=Cn.bgRgb(191,68,11).white("CANCEL"),a=1):r.includes("RETRY")?(i=Cn.bgRgb(191,68,11).white("RETRY"),a=2):r.includes("RUN")||r.includes("PROG")?(i=Cn.bgMagenta.white("RUNNING"),a=0):(E.warn(`Unknown status tried to be logged in run test locally: ${r}`),a=0),cU||(i=`${i}`),E.log(`${i}${" ".repeat(a)} ${e} ${o?`${o} `:""}(${t()}/${n()})`)};import dU from"fs";import{tmpdir as pU}from"os";import mU from"path";import{registry as bl}from"playwright-core/lib/server";import CR from"proper-lockfile";var xR=mU.join(pU(),"momenticBrowserInstallation");var fg=["chrome","chromium","chrome-for-testing","ffmpeg"],hU={Chromium:"chromium","Google Chrome":"chrome","Chrome for Testing":"chrome-for-testing"},_R={chrome:"chrome",chromium:"chromium","chrome-for-testing":"chromium-headless-shell",ffmpeg:"ffmpeg"};function MR(r){let e=_R[hU[r]??""]??"",t=bl.findExecutable(e);return!t||t.installType==="none"?!1:Sg(t)}function Sg(r){let e=r.executablePath();return dU.existsSync(e)}function gU(r,e){let t=_R[r];if(!t)throw new Error(`Requested install of unknown browser type ${r}`);let n=bl.findExecutable(t);if(!n||n.installType==="none")throw new Error(`Requested install of unknown browser type ${r}`);if(!(!e&&Sg(n)))return n}async function fU({browser:r,force:e}){let t=gU(r,e);if(!t){E.info(`Browser '${r}' is already installed, skipping...`);return}E.info(`Installing browser '${r}'...`);try{await bl.installDeps([t],!1),await bl.install([t],!1)}catch(n){if(n.message.includes("Lock file is already being held")){E.warn("Another process is installing Playwright browsers. Waiting for completion before proceeding..");let o=bl.findExecutable(r),i=5*60*1e3,a=Date.now();for(;Date.now()-a<i&&!Sg(o);)E.info("Waiting for browser to finish installing..."),await new Promise(s=>setTimeout(s,5e3))}else throw n}}async function IR({rawBrowsers:r,force:e=!1,all:t=!1}){let n=t?fg:Array.from(new Set(r));try{await CR.lock(xR,{stale:1e3*60*5,update:1e3*60,realpath:!1,retries:{retries:30,factor:2,maxTimeout:15e3,minTimeout:500}})}catch(i){E.warn(`Failed to acquire lock to install browsers. Please ensure that any other process installing browsers completes within 5 minutes: ${i}. Continuing without installation...`);return}let o;try{for(let i of n)try{await fU({browser:i,force:e})}catch(a){o=a,E.error(`Failed to install the ${i} browser: ${a}`)}}finally{await CR.unlock(xR,{realpath:!1})}if(o)throw o}import SU from"blocked-at";import yU from"why-is-node-running";function PR(r){EU(r),TU()}function EU(r){SU((e,t)=>{console.warn(`Detected the NodeJS event loop was blocked for ${e.toFixed(0)}ms. This can cause the CLI to hang.`);let n=t.join(`
|
|
32
|
+
`);console.warn(n),r.warn({stack:n,time:e},"NodeJS event loop blocked")},{threshold:1e3,trimFalsePositives:!0})}function TU(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}yU(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as $2}from"crypto";import sO from"body-parser";import PK from"cors";import OK from"dedent";import{Router as vB}from"express";import ur from"fs";import{globSync as RB}from"glob";import Dt from"path";import ud from"fs";import{z as MU}from"zod";var G="v1",yg="cli",Ci="2.28.7";var Po=3.1783027;function bU(r){let e=0;for(let t=0;t<r.length;t++){let n=r.charCodeAt(t);!(n>=48&&n<=57)&&!(n>=65&&n<=90)&&!(n>=97&&n<=122)&&e++}return e}function Me(r){return Math.ceil(Eg(r)/Po)}function Eg(r){let e=0;if(typeof r=="string"){let t=r;t=t.replaceAll(`
|
|
33
33
|
`,""),t=t.replaceAll(" ","");let n=bU(t);return t.length-n+Po*n}if(typeof r>"u"||r===null)return 0;if(typeof r=="number")return String(r).length;if(Array.isArray(r))return r.forEach(t=>{e+=Eg(t)}),e;if(typeof r=="object"){let t=r;return t.type==="image"||t.type==="media"&&"data"in t&&"mediaType"in t&&typeof t.mediaType=="string"&&t.mediaType.includes("jpeg")?1600:(Object.keys(t).forEach(n=>{e+=String(n).length,n==="image_url"?(t[n]??{}).detail==="high"?e+=1105*Po:e+=85*Po:n==="source"&&typeof t[n]=="object"&&t[n]?.type==="base64"?e+=1600*Po:e+=Eg(t[n])}),e)}if(typeof r=="boolean")return r?4:5;throw new Error(`Unsupported type passed to token length calculator '${typeof r}': ${r}`)}var Oo=class extends Error{constructor(e){super(e),this.name="TimeoutError"}};var OR=r=>{let e=r.reason===void 0?new DOMException("This operation was aborted.","AbortError"):r.reason;return e instanceof Error?e:new DOMException(e,"AbortError")};function $(r,e){let{milliseconds:t,fallback:n,message:o,customTimers:i={setTimeout,clearTimeout}}=e,a;if(typeof t!="number"||Math.sign(t)!==1)throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${t}\``);return new Promise((s,c)=>{let l;if(e.signal){let{signal:p}=e;if(p.aborted)return c(OR(p));l=()=>c(OR(p)),p.addEventListener("abort",l,{once:!0})}let u=()=>{if(e.signal&&e.signal.removeEventListener("abort",l),n)try{s(n())}catch(p){c(p)}else{typeof r.cancel=="function"&&Promise.resolve().then(()=>r.cancel()).catch(()=>{});let p=o instanceof Error?o:new Oo(o??`Promise timed out after ${t}ms`);c(p)}};t<1/0&&(a=i.setTimeout(u,t));let d=()=>{i.clearTimeout(a),e.signal&&e.signal.removeEventListener("abort",l)};Promise.resolve(r).then(p=>{d(),s(p)}).catch(p=>{d(),c(p)})})}var Bu=class{limit;windowMs;userActions;constructor(e,t){this.limit=e,this.windowMs=t,this.userActions=new Map}_cleanup(e,t="DEFAULT_USER"){let n=Date.now(),o=`${t}:${e}`;if(this.userActions.has(o)){let a=this.userActions.get(o)?.filter(s=>n-s<=this.windowMs)??[];a.length>0?this.userActions.set(o,a):this.userActions.delete(o)}}increment(e,t="DEFAULT_USER"){let n=Date.now(),o=`${t}:${e}`;this._cleanup(t,e),this.userActions.has(o)||this.userActions.set(o,[]);let i=this.userActions.get(o);return i.length>=this.limit?!0:(i.push(n),!1)}};var vU=9e4,RU=3,AU=1500,wU=15e3,sn=class extends Error{status;rawError;constructor(e,t,n,o={}){super(n,o),this.status=e,this.rawError=t}};async function CU(r){return r.text().then(e=>{try{return JSON.parse(e).error}catch{return e}})}var Tg=class{baseUrl;logger;constructor(e){this.baseUrl=e.baseUrl,this.logger=e.logger}getHeaders(){let e={"Content-Type":"application/json"};return Ci&&(e[Ou]=Ci),yg&&(e[fv]=yg),e}async sendRequest(e,t){let{retries:n=RU,requestTimeoutMs:o=vU,initialRetryDelayMs:i=AU,maxRetryDelayMs:a=wU,onFailedRequest:s}=t,c=n,l=n,u,d={path:e,baseUrl:this.baseUrl,method:t.method};for(;c>0;)try{return c--,await this.sendSingleRequestHelper(e,t,o)}catch(p){u=p;try{s?.(u)}catch{}if(p instanceof sn&&p.status>=400&&p.status<500)throw p;if(p instanceof Error&&p.name==="AbortError"&&(u=new Oo),c===0)throw u;let m=l-c,h=Math.min(i*Math.pow(2,m-1),a);await new Promise(g=>setTimeout(g,h))}throw this.logger.warn({...d,err:u},"Got fatal error response from Momentic server"),u}async sendSingleRequestHelper(e,t,n){let o={path:e,baseUrl:this.baseUrl,method:t.method},i=new AbortController,a=setTimeout(()=>i.abort(),n),s=()=>i.abort();t.signal&&t.signal.addEventListener("abort",s,{once:!0});let c=Date.now(),l={...this.getHeaders(),...t.extraHeaders};try{let u=await fetch(`${this.baseUrl}${e}`,{method:t.method,body:t.body?JSON.stringify(t.body):void 0,headers:l,signal:i.signal});if(!u.ok){let p=await CU(u);throw new sn(u.status,p,`Request to ${t.method} ${e} failed with status ${u.status}: ${p}`)}let d;if(u.status===204)d={};else{let p=await u.text();try{d=JSON.parse(p)}catch{d=p}}return this.logger&&t.logResponse===!0&&d&&this.logger.debug({result:d,status:u.status,durationMs:Date.now()-c,...o},"Got response from Momentic server"),d}finally{clearTimeout(a),t.signal&&t.signal.removeEventListener("abort",s)}}},zt=class extends Tg{apiKey;mode;constructor(e){super(e),this.apiKey=e.apiKey,this.mode=e.mode}getHeaders(){return{...super.getHeaders(),Authorization:`Bearer ${this.apiKey}`,[gv]:this.mode??""}}};import{createAnthropic as xU}from"@ai-sdk/anthropic";function _U(r){let{apiKey:e,sessionId:t,extraHeaders:n,loggerTags:o}=r,i={Authorization:`Bearer ${e}`,[Ou]:Ci??"",...t&&{[yv]:t},...n||{}};return o&&(i[Sv]=JSON.stringify(o)),i}var vl=r=>e=>{let t=_U(r);return xU({baseURL:`${r.baseUrl}/v1/llm/anthropic/${e}`,headers:t,apiKey:r.apiKey})(e)};var Xn=class extends zt{agentConfig;constructor(e,t){let n={...mu,...e};super(t),this.agentConfig=n}getAgentConfig(){return this.agentConfig}async rankChunksWithAi(e,t){let n={...e,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/recommend-chunks-ai`,{method:"POST",body:n,signal:t.abortSignal});return JT.parse(o)}async rankChunksWithRag(e,t){let n=await this.sendRequest(`/${G}/web-agent/recommend-chunks`,{method:"POST",body:{cliVersion:Ci,...e},signal:t.abortSignal});return XT.parse(n)}async getScreenshotFromS3(e){let t=await this.sendRequest(`/${G}/s3/visual-diff-screenshot`,{method:"POST",body:{url:e}});return MU.string().parse(t)}async getElementLocation(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags,useMemory:t.useMemory,agentConfigVersion:this.agentConfig?.locator},o=await this.sendRequest(`/${G}/web-agent/locate-element`,{method:"POST",body:n,signal:t.abortSignal});return Av.parse(o)}async getAssertionResult(e,t){let n={...e,disableCache:!!t.disableCache,useConsensus:!!t.useConsensus,attemptNumber:t.attemptNumber,loggerTags:t.loggerTags,useMemory:t.useMemory,agentConfigVersion:this.agentConfig?.assertion},o=await this.sendRequest(`/${G}/web-agent/assertion`,{method:"POST",body:n,signal:t.abortSignal});return ng.parse(o)}async getLintStepResult(e,t){let n={...e,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/lint/step`,{method:"POST",body:n,signal:t.abortSignal});return Rv.parse(o)}async getLintMcpCopilotMessageResult(e,t){let n={message:e.message,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/lint/mcp-copilot`,{method:"POST",body:n,signal:t.abortSignal});return Tv.parse(o)}async getMcpCopilotConversationEvaluation(e,t){let n={messagesAndToolCalls:e.messagesAndToolCalls,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/mcp-copilot-conversation-evaluator`,{method:"POST",body:n,signal:t.abortSignal});return bv.parse(o)}async getMcpCopilotChatSummary(e,t){let n={messagesAndToolCalls:e.messagesAndToolCalls,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/mcp-copilot-chat-summary`,{method:"POST",body:n,signal:t.abortSignal});return vv.parse(o)}async getVisualAssertionResult(e,t){let n={...e,disableCache:!!t.disableCache,useConsensus:!!t.useConsensus,attemptNumber:t.attemptNumber,loggerTags:t.loggerTags,useMemory:t.useMemory,agentConfigVersion:this.agentConfig?.["visual-assertion"]},o=await this.sendRequest(`/${G}/web-agent/visual-assertion`,{method:"POST",body:n,signal:t.abortSignal});return ng.parse(o)}async getAiActionCommand(e,t){let n=await this.sendRequest(`/${G}/web-agent/next-command-dynamic`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return Ev.parse(n)}async getMultiturnAiActionCommand(e,t){return await this.sendRequest(`/${G}/web-agent/ai-action/next-command`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal})}async getMultiturnAiActionEvaluation(e,t){let n=await this.sendRequest(`/${G}/web-agent/ai-action/evaluate`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return mh.parse(n)}async getReverseMappedDescription(e,t){let n=await this.sendRequest(`/${G}/web-agent/reverse-mapped-description`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return wv.parse(n)}async getTextExtraction(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags,agentConfigVersion:this.agentConfig?.["text-extraction"]},o=await this.sendRequest(`/${G}/web-agent/text-extraction`,{method:"POST",body:n,signal:t.abortSignal});return uh.parse(o)}async getPageSummary(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/page-summary`,{method:"POST",body:n,signal:t.abortSignal});return xT.parse(o)}async getSmartWaitingDecision(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${G}/web-agent/smart-waiting`,{method:"POST",body:n,signal:t.abortSignal});return _T.parse(o)}async getTestResultClassification(e,t){let n=await this.sendRequest(`/${G}/web-agent/result-classification`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return jm.parse(n)}async getExtractedKeywords(e,t){let n=await this.sendRequest(`/${G}/web-agent/extract-keywords`,{method:"POST",body:e,signal:t.abortSignal});return db.parse(n)}async getAutohealingProposal(e,t){let n=await this.sendRequest(`/${G}/web-agent/autoheal-section`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return RT.parse(n)}async getFailureRecoveryProposal(e,t){let n=await this.sendRequest(`/${G}/web-agent/failure-recovery`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return wT.parse(n)}async getFailureRecoveryPlan(e,t){let n=await this.sendRequest(`/${G}/web-agent/failure-recovery-plan`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return AT.parse(n)}async getIframeRegex(e,t){let n=await this.sendRequest(`/${G}/web-agent/iframe-regex`,{method:"POST",body:e,signal:t.abortSignal});return Fy.parse(n)}getVercelAnthropicModelFactory({loggerTags:e}){return vl({baseUrl:this.baseUrl,apiKey:this.apiKey,loggerTags:e})}};import{z as bg}from"zod";var et=class extends zt{constructor(e){super({...e,mode:void 0})}getAppUrl(){return this.baseUrl==="http://localhost:8000"?"http://localhost:3000":this.baseUrl.replace(/\/\/api/,"//app")}async getAuthInfo(){let e=await this.sendRequest(`/${G}/auth/check`,{method:"GET",retries:10,requestTimeoutMs:5e3,onFailedRequest:t=>{E.warn(`API key check failed: ${t.message}`)}});return Uv.parse(e)}async bulkGetRunStatus(e){let t=await this.sendRequest(`/${G}/runs/status`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return Nv.parse(t)}async getTestYAMLExport(e){let t=await this.sendRequest(`/${G}/tests/export`,{method:"POST",body:e,retries:3,requestTimeoutMs:3e4});return xv.parse(t)}async updateStepCaches(e,t){await this.sendRequest(`/${G}/cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getStepCacheForTest(e,t){let n=await this.sendRequest(`/${G}/cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return Mv.parse(n)}async updateMobileStepCaches(e,t){await this.sendRequest(`/${G}/mobile-cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getMobileStepCacheForTest(e,t){let n=await this.sendRequest(`/${G}/mobile-cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return Iv.parse(n)}async queueTests(e){let t=await this.sendRequest(`/${G}/tests/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return Cv.parse(t)}async uploadScreenshot(e){let t=await this.sendRequest(`/${G}/screenshots`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return Fv.parse(t)}async getAllEnvironments(){let e=await this.sendRequest(`/${G}/environments`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Bv.parse(e)}async acquireCacheLock(e,t){let n=await this.sendRequest(`/${G}/result-cache/lock`,{method:"POST",body:e,signal:t,retries:3,requestTimeoutMs:3e4});return eR.parse(n)}async releaseCacheLock(e){await this.sendRequest(`/${G}/result-cache/lock`,{method:"DELETE",body:{key:e},retries:3,requestTimeoutMs:5e3})}async deleteCacheResult(e){await this.sendRequest(`/${G}/result-cache/entry`,{method:"DELETE",body:e,retries:3,requestTimeoutMs:5e3})}async setCacheResult(e){await this.sendRequest(`/${G}/result-cache/entry`,{method:"PATCH",body:e,retries:3,requestTimeoutMs:5e3})}async getCacheResult(e){try{return await this.sendRequest(`/${G}/result-cache/entry`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3})}catch(t){if(t instanceof Error&&t.message.includes("404"))return null;throw t}}async queueSuiteRuns(e){let t=await this.sendRequest(`/${G}/suites/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return zv.parse(t)}async bulkGetRunGroupStatus(e){let t={runGroupIds:e},n=await this.sendRequest(`/${G}/run-groups/status`,{method:"POST",body:t,retries:3,requestTimeoutMs:5e3});return $T.array().parse(n)}async uploadProposedSteps(e,t){try{await this.sendRequest(`/${G}/test-fragments/`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4})}catch(n){t.error({err:n},"Failed to upload proposed steps")}}async reportBillableEvents(e,t){try{await this.sendRequest(`/${G}/billing/events`,{method:"POST",body:t,retries:10,requestTimeoutMs:1e4})}catch(n){e.error({err:n},"Failed to report billable event")}}async fetchTestFragment(e){let t=await this.sendRequest(`/${G}/test-fragments/${e}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Hv.parse(t)}async patchTestFragment(e,t){await this.sendRequest(`/${G}/test-fragments/${e}`,{method:"PATCH",body:t,retries:3,requestTimeoutMs:1e4})}async getPastTestResults(e,t){let n=await this.sendRequest(`/${G}/results/tests/${e}`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return Gv.parse(n)}async generateTestResultsUploadUrl(){let e=await this.sendRequest(`/${G}/results/uploads`,{method:"POST",retries:3,requestTimeoutMs:1e4});return jv.parse(e)}async startProcessingResultsUpload(e,t){let n=await this.sendRequest(`/${G}/results/uploads/${e}/process`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return Vv.parse(n)}async fetchIconKnowledgeBase(e){try{let t=await this.sendRequest(`/${G}/knowledge-base/icons`,{method:"GET",retries:3,requestTimeoutMs:5e3});return iR.parse(t)}catch(t){return e.error({err:t},"Failed to fetch icon knowledge base"),null}}async saveNewIcons(e,t){try{await this.sendRequest(`/${G}/knowledge-base/icons`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3})}catch(n){t.error({err:n},"Failed to save new icons to icon knowledge base")}}async getMergeBaseCommitFromGithub(e,t,n,o){let i=new URLSearchParams;i.set("base",n),i.set("head",o);let a=await this.sendRequest(`/${G}/git/github/${e}/${t}/merge-base-commit?${i.toString()}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Sl.parse(a)}async getCommitFromGithub(e,t,n){let o=await this.sendRequest(`/${G}/git/github/${e}/${t}/commits/${n}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Sl.parse(o)}async getMergedBranchFromGithub(e,t,n,o){let i=encodeURIComponent(n),a=await this.sendRequest(`/${G}/git/github/${e}/${t}/${i}/${o}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return sg.parse(a)}async getMergeBaseCommitFromGitlab(e,t,n){let o=new URLSearchParams;o.set("base",t),o.set("head",n);let i=encodeURIComponent(e),a=await this.sendRequest(`/${G}/git/gitlab/${i}/merge-base-commit?${o.toString()}`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Sl.parse(a)}async getCommitFromGitlab(e,t){let n=encodeURIComponent(e),o=await this.sendRequest(`/${G}/git/gitlab/${n}/commits/${t}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Sl.parse(o)}async getMergedBranchFromGitlab(e,t,n){let o=encodeURIComponent(t),i=encodeURIComponent(e),a=await this.sendRequest(`/${G}/git/gitlab/${i}/${o}/${n}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return sg.parse(a)}async getAgentConfig(){let e=await this.sendRequest(`/${G}/web-agent/agent-config`,{method:"GET",retries:3,requestTimeoutMs:5e3});return bg.record(bg.string(),bg.string()).parse(e)}async getQuarantinedTests(){let e=await this.sendRequest(`/${G}/quarantine`,{method:"GET"});return $v.parse(e)}async quarantineTest(e,t,n){await this.sendRequest(`/${G}/quarantine`,{method:"POST",body:{testId:e.id,testName:e.name,reason:t,...n??{}},retries:3,requestTimeoutMs:1e4})}async unquarantineTest(e,t,n){await this.sendRequest(`/${G}/quarantine/${e.id}`,{method:"DELETE",body:{testName:e.name,reason:t,...n??{}},retries:3,requestTimeoutMs:1e4})}async createAndroidEmulator(e){let t=await this.sendRequest(`/${G}/limbar/android`,{method:"POST",retries:3,body:e,requestTimeoutMs:9e4,initialRetryDelayMs:5e3,maxRetryDelayMs:15e3});return Wv.parse(t)}async extendAndroidEmulatorTtl(e){try{await this.sendRequest(`/${G}/limbar/android/${e}/keepalive`,{method:"POST",retries:3,requestTimeoutMs:15e3})}catch{}}async generateAndroidAssetUrls({channel:e,tag:t,md5:n}){let o={channel:e,tag:t,md5:n},i=await this.sendRequest(`/${G}/limbar/android/upload-url`,{method:"POST",retries:3,body:o,requestTimeoutMs:15e3,logResponse:!0});return qv.parse(i)}async deleteAndroidEmulator(e){await this.sendRequest(`/${G}/limbar/android/${e}`,{method:"DELETE",retries:3,requestTimeoutMs:3e4})}async getAndroidAssets(){let e=await this.sendRequest(`/${G}/limbar/assets`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Kv.parse(e)}async deleteAndroidAsset(e,t){await this.sendRequest(`/${G}/limbar/assets/${e}/${t}`,{method:"DELETE",retries:3,requestTimeoutMs:1e4})}};async function vg(r){let e=process.versions.node,t=parseInt(e.split(".")[0]);(isNaN(t)||t<18)&&(E.error(`Node.js version 20 or higher is required to run the CLI. Detected: ${process.versions.node}.`),process.exit(1)),E.debug(`Identified node version ${e}`);let n=await r.client.getAuthInfo();return E.debug("Got auth info from API"),n}var zu=class{apiClient;constructor(e){this.apiClient=e}async reportBillableEvents(e,t){await this.apiClient.reportBillableEvents(e,t)}};var Lo=class extends zt{generator;constructor(e,t){super(e),this.generator=t}async runTemplateMatching(e,t={}){let n=await this.sendRequest(`/${G}/web-agent/template-matching`,{method:"POST",body:e,signal:t?.signal});return Uy.parse(n)}async constructIframeRegex(e,t={}){return this.generator.getIframeRegex(e,{abortSignal:t.signal})}};var ka=class{constructor(e,t){this.client=e;this.orgId=t}async acquireCacheLock(e,t){return this.client.acquireCacheLock(e,t)}async uploadScreenshot(e){return(await this.client.uploadScreenshot({screenshot:e.toString("base64")})).key}async releaseCacheLock(e){return this.client.releaseCacheLock(e)}async deleteCacheResult(e){return this.client.deleteCacheResult(e)}async setCacheResult(e){return this.client.setCacheResult(e)}async getCacheResult(e){return this.client.getCacheResult(e)}fetchIconKnowledgeBase(e){return this.client.fetchIconKnowledgeBase(e)}saveNewIcons(e,t){return this.client.saveNewIcons(e,t)}};import{Faker as IU,en as PU}from"@faker-js/faker";var Fa="v1",xn=class{httpClient;fakerInstance;type="API_CLIENT";sms={send:this.sendSms.bind(this),fetchLatest:this.fetchLatestSms.bind(this)};email={send:this.sendEmail.bind(this),fetchLatest:this.fetchLatestEmail.bind(this),fetchAll:this.fetchAllEmails.bind(this)};ai={generate:this.sendAiGenerate.bind(this)};constructor(e){this.httpClient=e.httpClient,e.fakerSeed&&(this.fakerInstance=new IU({locale:PU}),this.fakerInstance.seed(e.fakerSeed))}async sendAiGenerate(e){let t=typeof e=="string"?{input:e}:e;return this.httpClient.sendRequest(`/${Fa}/tools/ai/generate`,{method:"POST",body:t}).catch(n=>{throw n instanceof sn?new Error(n.rawError):new Error(`Failed to send AI generation: ${n.message}`)})}async sendSms(e){return this.httpClient.sendRequest(`/${Fa}/tools/sms/send`,{method:"POST",body:e}).then(()=>{}).catch(t=>{throw t instanceof sn?new Error(t.rawError):new Error(`Failed to send sms: ${t.message}`)})}async fetchLatestSms(e){return this.httpClient.sendRequest(`/${Fa}/tools/sms/fetchLatest`,{method:"POST",body:e}).catch(t=>{throw t instanceof sn?new Error(t.rawError):t})}async sendEmail(e){return this.httpClient.sendRequest(`/${Fa}/tools/email/send`,{method:"POST",body:e}).then(()=>{}).catch(t=>{throw t instanceof sn?new Error(t.rawError):new Error(`Failed to send email: ${t.message}`)})}async fetchAllEmails(e){return this.httpClient.sendRequest(`/${Fa}/tools/email/fetchAll`,{method:"POST",body:e}).catch(t=>{throw t instanceof sn?new Error(t.rawError):new Error(`Failed to fetch all emails: ${t.message}`)})}async fetchLatestEmail(e){return this.httpClient.sendRequest(`/${Fa}/tools/email/fetchLatest`,{method:"POST",body:e}).catch(t=>{throw t instanceof sn?new Error(t.rawError):new Error(`Failed to fetch latest emails: ${t.message}`)})}};function LR(r,e,t){return fetch(r,{method:"PUT",body:t,headers:{"Content-Type":e}})}var Hu=class{constructor(e){this.client=e}async uploadResultsArchive(e,t){let{uploadUrl:n,id:o}=await this.client.generateTestResultsUploadUrl(),i=await LR(n,"application/zip",t);if(!i.ok)throw new Error(`Failed to upload test results: ${await i.text()}`);let{runGroupId:a}=await this.client.startProcessingResultsUpload(o,{runGroupId:e});return a}};function tt(r,e,t=!1){return r.length<e?r:r.slice(0,e-3)+(t?"...TRUNCATED...":"[...]")}var Jn={EQUALS:"equals",CONTAINS:"contains",STARTS_WITH:"starts with",EXISTS:"exists"},Qn={EQUALS:"does not equal",CONTAINS:"does not contain",STARTS_WITH:"does not start with",EXISTS:"does not exist"},Rg={EXISTS:"exists",VISIBLE:"is visible",ENABLED:"is enabled",EDITABLE:"is editable",FOCUSED:"is focused"},Ag={EXISTS:"does not exist",VISIBLE:"is not visible",ENABLED:"is disabled",EDITABLE:"is not editable",FOCUSED:"is not focused"};function NR(r){switch(r.type){case"ELEMENT_CONTENT":return`content ${r.negated?Qn[r.operation]:Jn[r.operation]} '${r.value}'`;case"ELEMENT_ATTRIBUTE":{let t=r.negated?Qn[r.operation]:Jn[r.operation];return r.operation==="EXISTS"?`attribute '${r.attr}' ${t}`:`attribute '${r.attr}' ${t} '${r.value}'`}case"ELEMENT_NAME":{let t=r.negated?Qn[r.operation]:Jn[r.operation];return r.operation==="EXISTS"?`tag name ${t}`:`tag name ${t} '${r.value}'`}case"ELEMENT_STYLE":{let t=r.negated?Qn[r.operation]:Jn[r.operation];return r.operation==="EXISTS"?`style property '${r.property}' ${t}`:`style property '${r.property}' ${t} '${r.value}'`}case"ELEMENT_EXISTENCE":return r.negated?Ag[r.condition]:Rg[r.condition];default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}var tue={CONTENT:"The page"};function LU(r){switch(r.type){case"VALUE":return`the option with value ${r.value}`;case"LABEL":return`the option with label ${r.label}`;case"INDEX":return`the option at index ${r.index}`;default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}function ju(r){switch(r.type){case"SUBSTRING":return`match substring '${r.url}'`;case"REGEX":return`match regex '${r.regex}'`;case"GLOB":return`match glob '${r.glob}'`;case"DOMAIN":return`match domain '${r.domain}'`;default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}function Gu(r){let e="";return r.method&&(e=` with method ${r.method}`),`${ju(r.urlMatcher)}${e}`}function NU(r){return`${r.negated?Qn.CONTAINS:Jn.CONTAINS} '${r.value}'`}function DU(r){switch(r.type){case"CONTENT":return NU(r);default:return r.type,""}}function Zn(r,e=!0){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: ${e?tt(r.url,30):r.url}`;case"DIALOG":return`Automatically ${r.action.toLowerCase()} the next dialog`;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: ${Wt(r.target)}`:""}`;case"SCROLL_UP":return`Scroll up ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${Wt(r.target)}`:""}`;case"SCROLL_LEFT":return`Scroll left ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${Wt(r.target)}`:""}`;case"SCROLL_RIGHT":return`Scroll right ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${Wt(r.target)}`:""}`;case"WAIT":return`Wait for ${r.delay} seconds`;case"REFRESH":return"Refresh the page";case"CLICK":{if(r.target?.type==="coordinates")return`Click at coordinates: ${Wt(r.target)}`;let n="";return r.target?.elementDescriptor.length?n=` on element: '${r.target.elementDescriptor}'`:r.cache?.target.nodeOnlySerializedHtml&&(n=` on element: '${r.cache?.target.nodeOnlySerializedHtml}'`),`Click${n}`}case"FOCUS":return`Focus ${Wt(r.target)}`;case"BLUR":return`Focus ${Wt(r.target)}`;case"DRAG":return`Drag ${Wt(r.fromTarget)} onto ${Wt(r.toTarget)}`;case"MOUSE_DRAG":return r.target?.type==="description"&&r.target.elementDescriptor?`Click and drag ${Wt(r.target)} by ${r.deltaX}px horizontally, ${r.deltaY}px vertically`:`Click and drag mouse by ${r.deltaX}px horizontally, ${r.deltaY}px vertically`;case"TYPE":{let n="";return r.target?.type==="coordinates"?n=` in element at coordinates: ${Wt(r.target)}`:r.target?.elementDescriptor.length?n=` in element: '${r.target.elementDescriptor}'`:r.cache?.target.nodeOnlySerializedHtml&&(n=` in element: '${r.cache?.target.nodeOnlySerializedHtml}'`),`Type '${r.value}'${n||""}`}case"HOVER":{let n="";return r.target.type==="coordinates"?n=` over coordinates: ${Wt(r.target)}`:r.target.elementDescriptor.length>0?n=` over element: '${r.target.elementDescriptor}'`:r.cache?.target.nodeOnlySerializedHtml&&(n=` over element: '${r.cache?.target.nodeOnlySerializedHtml}'`),`Hover${n}`}case"PRESS":return`Press ${r.value}`;case"KEY_DOWN":return`Hold down ${r.value} on the keyboard`;case"KEY_UP":return`Release ${r.value} on the keyboard`;case"SELECT_OPTION":{let n="",o=LU(r.choice);return r.target.type==="coordinates"?n=` from element at coordinates: ${Wt(r.target)}`:r.target.elementDescriptor.length>0?n=` from: '${r.target.elementDescriptor}'`:r.cache?.target.nodeOnlySerializedHtml&&(n=` from: '${r.cache?.target.nodeOnlySerializedHtml}'`),`Select option '${o}'${n}`}case"TAB":switch(r.action.type){case"SUBSTRING":return`Switch to tab with substring: ${r.action.substring}`;case"REGEX":return`Switch to tab matching regex: ${r.action.pattern}`;case"INDEX":return`Switch to tab at index: ${r.action.index}`;default:return(o=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r.action)}return"Switch to unknown tab";case"NEW_TAB":return`Open new tab to: ${r.url}`;case"REQUEST":return`Send ${r.method} request to ${r.url}`;case"GRAPHQL_REQUEST":return`Send GraphQL 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: ${e?tt(r.code,30):r.code}`;case"AI_ASSERTION":return`Assertion: '${r.assertion}'`;case"VISUAL_DIFF":return`Visual diff against baseline ${r.target?`for element: ${Wt(r.target)}`:"for entire page"}`;case"FILE_UPLOAD":return r.fileSource.type==="URL"?`Upload file: ${r.fileSource.url}`:`Upload file: ${r.fileSource.name}`;case"AUTH_LOAD":return"Load auth state";case"AUTH_SAVE":return"Save auth state";case"ELEMENT_CHECK":return`Check the element ${Wt(r.target)} ${NR(r.assertion)}`;case"PAGE_CHECK":return`Check the page ${DU(r.assertion)}`;case"WAIT_FOR_URL":return`Wait for page URL to ${ju(r.matcher)}`;case"COPY":return"Copy to clipboard";case"PASTE":return"Paste clipboard contents";case"REGISTER_REQUEST_LISTENER":return r.requestMatcher?`Register a listener for network requests that ${Gu(r.requestMatcher)}`:"Register a listener for network requests";case"AWAIT_LISTENER":return r.key?`Wait for the listener ${r.key} to resolve`:"Wait for a listener to resolve";case"RECORD_REQUESTS":return r.requestMatcher?`Start recording requests that match ${Gu(r.requestMatcher)}`:"Start recording network requests";case"GET_RECORDED_REQUESTS":return r.key?`Get the requests that were recorded for ${r.key}`:"Get the requests that were recorded";case"SET_HEADER":return r.name?r.requestMatcher?`Set a ${r.name} header for requests that match ${Gu(r.requestMatcher)}`:`Set a ${r.name} header for all requests`:"Set a header";case"MOCK_ROUTE":return r.requestMatcher?`Mock requests that ${Gu(r.requestMatcher)}`:"Mock a network route";case"REMOVE_ROUTE_MOCK":return r.key?`Remove the mock with key ${r.key}`:"Remove all route mocks";case"OFFLINE_MODE":return r.enable?"Enable offline mode":"Disable offline mode";default:return(n=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}function kU(r){return typeof r=="object"&&r!==null}function _n(r){if(Array.isArray(r))return r.map(_n);if(kU(r)){let e={};return Object.entries(r).forEach(([t,n])=>{n!==void 0&&(e[t]=_n(n))}),e}return r}function Rl(r,e,t,n){let{negated:o,ignoreCase:i}=n,a=r.trim(),s=e.trim();i&&(a=a.toLowerCase(),s=s.toLowerCase());let c;switch(t){case"CONTAINS":{c=a.includes(s);break}case"EQUALS":{c=a===s;break}case"STARTS_WITH":{c=a.startsWith(s);break}case"EXISTS":{c=a.length>0;break}default:throw new Error(`Unrecognized content assertion type: ${t}`)}return o?!c:c}function DR(r){return r.type==="ELEMENT_EXISTENCE"&&r.negated&&(r.condition==="EXISTS"||r.condition==="VISIBLE")}function Ua(r){return r.type==="ELEMENT_EXISTENCE"?r.negated?Rg[r.condition]:Ag[r.condition]:r.negated?Jn[r.operation]:Qn[r.operation]}import{diff as UU}from"deep-object-diff";import{cloneDeep as qu}from"lodash-es";function xi(r){let e={parentChain:[]};return Vu(r,e),e}function Vu(r,e){let{onPresetAction:t,onSimpleStepContainer:n,onConditional:o,earlyStop:i}=r;for(let a of r.steps)switch(a.type){case"PRESET_ACTION":if(t(a,e)&&i)return!0;break;case"CONDITIONAL":if(o?.(a,e)&&i)return!0;e.parentChain.push(a);for(let c of a.blocks)if(t(c.assertion,e)&&i||Vu({...r,steps:c.steps},e)&&i)return!0;if(Vu({...r,steps:a.elseSteps??[]},e)&&i)return!0;e.parentChain.pop();break;case"RESOLVED_MODULE":case"SECTION":case"AI_ACTION":if(n?.(a,e)&&i)return!0;if(a.steps){if(e.parentChain.push(a),Vu({...r,steps:a.steps},e)&&i)return!0;e.parentChain.pop()}break;case"AI_ACTION_DYNAMIC":{if(n?.(a,e)&&i)return!0;break}default:return(c=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(a)}}function kR(r,e,t,n){let o=Array.from(e),i=Array.from(n);for(let s=0;s<o.length;s++){if(o[s]!==n[s])return!1;i.shift()}return!!FU([r],t,i).result}function FU(r,e,t=[]){let n,o=[],i=(a,s)=>{let c=JSON.stringify(s.parentChain.map(u=>u.id)),l=t.length===0?!0:JSON.stringify(t)===c;return a.id===e&&l?(n=a,o=s.parentChain,!0):!1};return xi({steps:r,earlyStop:!0,onPresetAction:i,onConditional:i,onSimpleStepContainer:i}),{result:n,parentChain:o}}function FR(r,e){e(r);for(let t in r){let n=r[t];n&&(Array.isArray(n)?Wu(n,e):typeof n=="object"&&FR(n,e))}}function Wu(r,e){for(let t of r)t&&(Array.isArray(t)?Wu(t,e):typeof t=="object"&&FR(t,e))}function wg(r,e){if(r.length>e.length)return wg(e,r);for(let t=0;t<r.length;t++)if(r[t]!==e[t])return!1;return!0}function $u(r){for(let e of r.results)switch(e.type){case"PRESET_ACTION":r.onPresetAction(e);break;case"AI_ACTION":case"AI_ACTION_DYNAMIC":case"MODULE":r.onSimpleStepContainer?.(e),$u({...r,results:e.results});break;case"CONDITIONAL":r.onConditional?.(e),e.assertionResult&&r.onPresetAction(e.assertionResult),$u({...r,results:e.results});break;default:throw new Error(`Unsupported result type: ${e.type}`)}}function No(r,e){return!r&&!e?!1:!r||!e?!0:Object.keys(UU(r,e)).length>0}function Ba({steps:r,topLevel:e=!0,...t}){let{stepCacheEntries:n,logger:o,keyPrefix:i}=t,a=[],s=[],c=[],l=0,u=(p,m)=>{try{let h=Wn.parse(m.value);if(h.type!==p.type){o.warn({parsedCacheEntry:h,command:p},"Not using step cache due to type mismatch"),s.push(m.key);return}p.cache=h.cache,a.push(m.key),c.push(m.uniqueKey)}catch(h){s.push(m.key),o.error({err:h,cacheEntry:m},"Not using step cache due to parsing error")}},d=(p,m)=>{let h=BU(p.id,m),g=h.find(f=>!!n[f]);if(g)u(p,n[g]);else{if(p.type==="AI_ASSERTION")return;s.push(h[0])}};for(let p of r)switch(p.type){case"RESOLVED_MODULE":{l+=p.steps.length;let{cacheKeysHit:m,cacheKeysMissed:h,uniqueKeysHit:g}=Ba({...t,steps:p.steps,keyPrefix:i?`${i}:${p.id}`:p.id,topLevel:!1});a.push(...m),s.push(...h),c.push(...g);break}case"SECTION":case"AI_ACTION":{if(l+=p.steps?.length??0,!p.steps?.length)break;let{cacheKeysHit:m,cacheKeysMissed:h,uniqueKeysHit:g}=Ba({...t,steps:p.steps,topLevel:!1});a.push(...m),s.push(...h),c.push(...g);break}case"AI_ACTION_DYNAMIC":continue;case"PRESET_ACTION":{if(!Uc.includes(p.command.type)||(p.command.type==="TYPE"||p.command.type==="MOUSE_DRAG"||p.command.type==="VISUAL_DIFF"||p.command.type==="SCROLL_DOWN"||p.command.type==="SCROLL_UP"||p.command.type==="SCROLL_LEFT"||p.command.type==="SCROLL_RIGHT")&&!p.command.target||"cache"in p.command&&p.command.cache)continue;l++,d(p.command,i);break}case"CONDITIONAL":{for(let m of p.blocks){l++,d(m.assertion.command,i),l+=m.steps.length;let{cacheKeysHit:h,cacheKeysMissed:g,uniqueKeysHit:f}=Ba({...t,steps:m.steps,topLevel:!1});a.push(...h),s.push(...g),c.push(...f)}if(p.elseSteps){l+=p.elseSteps.length;let{cacheKeysHit:m,cacheKeysMissed:h,uniqueKeysHit:g}=Ba({...t,steps:p.elseSteps,topLevel:!1});a.push(...m),s.push(...h),c.push(...g)}break}default:return(h=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(p)}return e&&l&&s.length>0&&o.warn({totalSteps:l,cacheKeysMissed:s,cacheKeysHit:a,uniqueKeysHit:c,cacheEntriesKeys:Object.values(n).map(p=>p.uniqueKey)},"Step cache did not fully resolve"),{cacheKeysHit:a,cacheKeysMissed:s,uniqueKeysHit:c}}function UR(r,e){return e?`${e}:${r}`:r}function BU(r,e){let t=[],n=e?.split(":")??[];for(let o=n.length;o>=0;o--){let i=[...n.slice(o),r];t.push(i.join(":"))}return t.reverse(),t}function Cg(r){let{moduleStepParents:e=[],moduleIdParents:t=[]}=r;if(e.length!==t.length)throw new Error(`Invalid cache entry parent length: ${JSON.stringify(e)}
|
|
34
34
|
${JSON.stringify(t)}`);let n=[];return n.push({key:UR(r.id,e.join(":")),organizationId:r.orgId,value:r.value,testId:r.testId}),n}function BR(r){let e=new Set;return Wu(r,t=>{if("type"in t&&t.type==="RESOLVED_MODULE"&&"moduleId"in t){let n=t.moduleId;typeof n=="string"&&!e.has(n)&&e.add(n)}}),e}function Ku({cmd:r,newTarget:e,key:t,logger:n,updatedWithAI:o}){if(r.type==="DRAG")if(t!=="fromTarget"&&t!=="toTarget")n.error({cmd:r,newTarget:e,key:t},"Attempted to apply invalid cache to DRAG command");else{let i=r.cache?.updatedAt;r.cache={...r.cache,[t]:e,updatedAt:i&&!o?i:new Date}}else if(t==="target"&&Bc(r)){let i=r.cache?.updatedAt;r.cache={...r.cache,target:e,updatedAt:i&&!o?i:new Date}}else n.error({cmd:r,newTarget:e,key:t},"Invalid target cache application")}function wl(r,e,t){let n=r.cache&&"memory"in r.cache?r.cache.memory?.traces:void 0;No(n,e)&&(t.info({updatedTraces:e,oldCmd:r},"Wrote new memory to assertion command"),r.cache={...r.cache,memory:{type:"GCS_TRACES",traces:e},updatedAt:new Date})}function zR({steps:r}){let e={};return xi({steps:r,onPresetAction:(t,n)=>{let o=t.command;if(!("cache"in o)||!o.cache)return;let i=n.parentChain.filter(c=>c.type==="RESOLVED_MODULE").map(c=>c.id).join(":"),a=UR(o.id,i),s=Wn.parse(o);e[a]=s},onSimpleStepContainer:(t,n)=>{},onConditional:(t,n)=>{}}),e}function Al(r){return{...r,serializedHtml:void 0,nodeOnlySerializedHtml:void 0,screenshotUrl:void 0,boundingBox:void 0,selector:void 0,hybridSelector:void 0,generatedSelectors:void 0,id:-1}}function zU(r,e){return No(r.memory,e.memory)?{...r,memory:e.memory,updatedAt:e.updatedAt}:r}function xg(r,e){return r?No(r.target.memory,e.target.memory)?{target:{...r.target,memory:e.target.memory},updatedAt:e.updatedAt}:r:{target:Al(e.target),updatedAt:e.updatedAt}}function HU(r,e){let t=qu(r);return t.fromTarget?No(r.fromTarget?.memory,e.fromTarget?.memory)&&(t.fromTarget={...t.fromTarget,memory:e.fromTarget?.memory},t.updatedAt=e.updatedAt):(t.fromTarget=e.fromTarget,t.fromTarget&&(t.fromTarget=Al(t.fromTarget),t.updatedAt=e.updatedAt)),t.toTarget?No(r.toTarget?.memory,e.toTarget?.memory)&&(t.toTarget={...t.toTarget,memory:e.toTarget?.memory},t.updatedAt=e.updatedAt):(t.toTarget=e.toTarget,t.toTarget&&(t.toTarget=Al(t.toTarget),t.updatedAt=e.updatedAt)),t}function HR({newEntries:r,originalCachesMap:e,logger:t}){let n=[];for(let o of r){let i=e[o.key];if(!i||!i.cache){n.push(o);continue}if(o.value.type!==i.type){n.push(o);continue}let a=o.value.cache;if(o.value={...i},!a){n.push(o);continue}if("memory"in a&&a.memory){let s=i.cache&&"memory"in i.cache?i.cache.memory:void 0;No(s,a.memory)&&(o.value.cache=zU(i.cache,a),n.push(o))}else if("target"in a&&a.target.memory){let s=i.cache&&"memory"in i.cache?i.cache.memory:void 0;if(No(s,a.target.memory)){let c=vr.safeParse(o.value.cache);o.value.cache=xg(c.data,a),n.push(o)}}else if("fromTarget"in a||"toTarget"in a){let s=Dm.optional().parse(o.value.cache);if(!s)continue;let c={from:s.fromTarget?.memory,to:s.toTarget?.memory},l={from:i.cache&&"fromTarget"in i.cache?i.cache.fromTarget?.memory:void 0,to:i.cache&&"toTarget"in i.cache?i.cache.toTarget?.memory:void 0};No(l,c)&&(o.value.cache=HU(s,a),n.push(o))}}return n}async function Yu({cacheStorage:r,logger:e,schemaVersion:t,stepLists:n,testId:o}){let i=qu(n.steps),a=qu(n.beforeSteps)??void 0,s=qu(n.afterSteps)??void 0,c={steps:i,beforeSteps:a,afterSteps:s};try{await r.resolveStepCacheEntries({testId:o,stepLists:c,schemaVersion:t,logger:e})}catch(l){throw e.error({err:l},"Failed to resolve step cache entries"),new Error(`Failed to resolve step cache entries. Please ensure you are running using a supported version of Momentic. If you believe this is a Momentic issue, please contact Support with the following error: ${l}`)}return c}function GR(r){let e=[];for(let t of r){t.sort((a,s)=>a.timestamp-s.timestamp);let n=[],o,i=1;for(let a of t)o&&o.text===a.text&&o.type===a.type&&JSON.stringify(o.args??null)===JSON.stringify(a.args??null)?i++:(o&&(i>1?o.args&&o.args.length?o.args.push(`(repeated ${i} times)`):o.text+=` (repeated ${i} times)`:n.push(o)),o=a,i=1);o&&n.push(o),e.push(n)}return e}import{cloneDeep as Dpe}from"lodash-es";import _g from"semver";function Xu(r,e){if(r!=="0.0.1"&&r!==e[e.length-1].toVersion)throw new Error("Please bump latestSchemaVersion in types package after adding a migration");e.forEach((t,n)=>{if(!_g.valid(t.toVersion)||!_g.valid(t.fromVersion))throw new Error(`Migration '${t.name}' has invalid version`);if(!_g.gt(t.toVersion,t.fromVersion))throw new Error(`Migration '${t.name}' has toVersion <= fromVersion`);if(n===0)return;if(e[n-1].toVersion!==t.fromVersion)throw new Error(`Migration '${t.name}' at index ${n} is not contiguous with previous migration`)})}import GU from"diff-lines";import jU,{gte as VU}from"semver";function $U(r){return r.every(e=>e&&typeof e=="object"&&!Array.isArray(e))}async function Mg({metadata:r,steps:e,logger:t,toVersion:n,migrations:o}){let i=e,{schemaVersion:a,id:s}=r,c=o.findIndex(d=>jU.gt(d.toVersion,a));if(c===-1)return{steps:i,newVersion:a};let l=a;for(let d=c;d<o.length;d++){if(n&&VU(l,n)){t.debug("Stopping migration early because toVersion was reached");break}let p=o[d],m={id:s,migration:p.name,toVersion:p.toVersion};try{i=await jR(i,p),l=p.toVersion}catch(h){throw t.error({err:h,...m},"Migration failed"),new Error(`Step migration ${p.name} failed: ${h}`)}}let u=GU(JSON.stringify(e,void 0,2),JSON.stringify(i,void 0,2),{n_surrounding:1});return u.trim()&&t.debug({diffs:u,id:s},"Migration diffs"),{newVersion:l,steps:i}}async function jR(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 i=n[o];!i||!Array.isArray(i)||$U(i)&&(n[o]=await jR(i,e))}return t}var VR={name:"Migrate API request body types",fromVersion:"0.0.1",toVersion:"0.0.2",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!1,execute:async r=>r.map(e=>{if(e.type!=="MOBILE_PRESET_STEP")return e;let t=e.command;if(!t||t.type!=="REQUEST")return e;let n=typeof t.body=="string"&&t.body.length>0?{type:"json",content:t.body}:void 0;return t.body=n,e})};var WU=[VR];Xu(ah,WU);var $R={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 WR={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 qU=["target","fromTarget","toTarget"];function qR(r){for(let e of qU){if(r[e]===void 0)continue;let t=r[e];t.elementDescriptor!==void 0?t.type="description":r[e]={type:"description",elementDescriptor:""}}}var KR={name:"Migrate element target to discriminated union",fromVersion:"1.0.6",toVersion:"1.0.7",recursiveKeys:new Set(["results","steps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{switch(e.type){case"PRESET_ACTION":return qR(e.command),e;case"AI_ACTION":{let t=e.commands;for(let n of t??[])qR(n);return e}default:return e}})};import{v4 as KU}from"uuid";var YR={name:"Ensure module steps have ids",fromVersion:"1.0.7",toVersion:"1.0.8",recursiveKeys:new Set(["results","steps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{switch(e.type){case"MODULE":return e.id||(e.id=KU()),e;default:return e}})};import{v4 as XR}from"uuid";var JR={name:"Ensure module steps have ids",fromVersion:"1.0.8",toVersion:"1.0.9",recursiveKeys:new Set(["results","steps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{switch(e.type){case"PRESET_ACTION":{if(!e.command)return e;let t=e.command;return t.id=t.id??XR(),e}case"AI_ACTION":return e.commands&&(e.steps=e.commands.map(t=>({type:"PRESET_ACTION",command:{...t,id:t.id??XR()}})),delete e.commands),e;default:return e}})};var QR={name:"Migrate ai waits to checks",fromVersion:"1.0.9",toVersion:"1.0.10",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{switch(e.type){case"PRESET_ACTION":{if(!e.command)return e;let t=e.command;return typeof t.type!="string"||t.type!=="AI_WAIT"||(t.type="AI_ASSERTION",t.timeout||(t.timeout=10)),e}default:return e}})};import{v4 as YU}from"uuid";var ZR={name:"Add ids to all steps",fromVersion:"1.0.10",toVersion:"1.0.11",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>("id"in e&&typeof e.id=="string"||(e.id=YU()),e))};import{v4 as eA}from"uuid";var tA={name:"Add ids to all steps",fromVersion:"1.0.11",toVersion:"1.0.12",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if("id"in e&&typeof e.id=="string")return e;if("condition"in e&&typeof e.condition=="object"&&e.condition){let t=e.condition;t.id||(t.id=eA())}return e.id=eA(),e})};var rA={name:"Move env key to steps",fromVersion:"1.0.12",toVersion:"1.0.13",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||typeof t.envKey!="string"||(e.envKey=t.envKey,delete t.envKey),e})};import{v4 as XU}from"uuid";var nA={name:"Redo last two migrations",fromVersion:"1.0.13",toVersion:"1.0.14",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if((!("id"in e)||typeof e.id!="string")&&(e.id=XU()),e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||typeof t.envKey!="string"||(e.envKey=t.envKey,delete t.envKey),e})};var oA={name:"Migrate select choice",fromVersion:"1.0.14",toVersion:"1.0.15",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||t.type!=="SELECT_OPTION"||e.option===void 0||(e.choice={type:"VALUE",value:t.option},e.option=void 0),e})};var iA={name:"Migrate select choice",fromVersion:"1.0.15",toVersion:"1.0.16",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return t&&aA(t),e})};function aA(r){r&&Object.keys(r).forEach(e=>{if(typeof r[e]=="object"&&r[e]){aA(r[e]);return}if(typeof r[e]!="string")return;let t=r[e];e==="code"?r[e]=t.replace(/inputs\./g,"env."):t.includes("{{")&&t.includes("}}")&&(r[e]=t.replace(/inputs\./g,"env."))})}var sA={name:"Migrate switch tab choice",fromVersion:"1.0.16",toVersion:"1.0.17",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||t.type!=="TAB"||t.url===void 0||(t.action={type:"SUBSTRING",substring:t.url},t.url=void 0),e})};var lA={name:"Remove press keys sequentially",fromVersion:"1.0.17",toVersion:"1.0.18",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!1,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||t.type!=="TYPE"?e:t.pressKeysSequentially===void 0?(t.delay=0,e):(t.pressKeysSequentially&&(t.pressKeysSequentially=void 0,t.delay=50),e)})};var cA={name:"Migrate wait for URL to matcher",fromVersion:"1.0.18",toVersion:"1.0.19",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!1,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||t.type!=="WAIT_FOR_URL"||t.url===void 0||(t.matcher={type:"GLOB",glob:t.url},t.url=void 0),e})};var uA={name:"Migrate select choice round 2",fromVersion:"1.0.19",toVersion:"1.0.20",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!0,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;if(!t)return e;if(t.type==="SELECT_OPTION"){if(t.option===void 0)return e;t.choice={type:"VALUE",value:t.option},t.option=void 0}else if(t.type==="TAB"){if(t.url===void 0)return e;t.action={type:"SUBSTRING",substring:t.url},t.url=void 0}else if(t.type==="WAIT_FOR_URL"){if(t.url===void 0)return e;t.matcher={type:"GLOB",glob:t.url},t.url=void 0}else t.type==="AI_WAIT"&&(t.type="AI_ASSERTION",t.timeout||(t.timeout=10));return e})};var dA={name:"Migrate ",fromVersion:"1.0.20",toVersion:"1.0.21",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!1,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;return!t||t.type!=="MOCK_ROUTE"&&t.type!=="SET_HEADER"&&t.type!=="RECORD_REQUESTS"&&t.type!=="REGISTER_REQUEST_LISTENER"||(t.type==="REGISTER_REQUEST_LISTENER"||t.type==="RECORD_REQUESTS"?t.requestMatcher={urlMatcher:{type:"REGEX",regex:t.pattern}}:(t.type==="SET_HEADER"||t.type==="MOCK_ROUTE")&&t.urlPattern&&(t.requestMatcher={urlMatcher:{type:"REGEX",regex:t.urlPattern}})),e})};var pA={name:"Migrate API request body types",fromVersion:"1.0.21",toVersion:"1.0.22",recursiveKeys:new Set(["results","steps","blocks","elseSteps"]),stopOnFailure:!1,execute:async r=>r.map(e=>{if(e.type!=="PRESET_ACTION")return e;let t=e.command;if(!t||t.type!=="REQUEST")return e;let n=typeof t.body=="string"&&t.body.length>0?{type:"json",content:t.body}:void 0;return t.body=n,e})};var mA={name:"Migrate AI checks 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 Ju=new Set(["CLICK","TYPE","SELECT_OPTION"]),hA={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||Ju.has(n))&&(t.target={elementDescriptor:o??""}),e.commands&&Array.isArray(e.commands)&&e.commands.forEach(a=>{let s=a?.elementDescriptor,c=a?.type;(s!==void 0||Ju.has(c))&&(a.target={elementDescriptor:s??""})}),e.results&&Array.isArray(e.results)&&e.results.forEach(a=>{let s=a.command,c=s?.elementDescriptor,l=s?.type;(c!==void 0||Ju.has(l))&&(s.target={elementDescriptor:c??""}),a.commands&&Array.isArray(a.commands)&&a.commands.forEach(d=>{let p=d?.elementDescriptor,m=d?.type;(p!==void 0||Ju.has(m))&&(d.target={elementDescriptor:p??""})})}),e}),stopOnFailure:!0};var gA={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 fA={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(i=>{let a=i.type;a?.startsWith("PRESET_")&&(i.type=a.slice(7))}),e.results&&Array.isArray(e.results)&&e.results.forEach(i=>{let a=i.command,s=a?.type;s?.startsWith("PRESET_")&&(a.type=s.slice(7)),i.commands&&Array.isArray(i.commands)&&i.commands.forEach(l=>{let u=l.type;u?.startsWith("PRESET_")&&(l.type=u.slice(7))})}),e}),stopOnFailure:!0};var SA=[mA,gA,fA,hA,$R,WR,KR,YR,JR,QR,ZR,tA,rA,nA,oA,iA,sA,lA,cA,uA,dA,pA];Xu(xe,SA);async function za({metadata:r,steps:e,logger:t,toVersion:n}){return await Mg({metadata:r,steps:e,logger:t,toVersion:n,migrations:SA})}import{cloneDeep as Kpe}from"lodash-es";import{v4 as rme}from"uuid";import{cloneDeep as QU}from"lodash-es";import AA from"truncate-json";import{v4 as EA}from"uuid";import{cloneDeep as fme,unset as Sme}from"lodash-es";function yA(r){switch(r.type){case"AI_ACTION":return`AI action: ${tt(r.text,100)}`;case"AI_ACTION_DYNAMIC":return`AI action: ${tt(r.text,100)}`;case"PRESET_ACTION":return Zn(r.command);case"MODULE":return`Module ${r.moduleName??r.id}`;case"CONDITIONAL":return"Conditional step";case"SECTION":return`Section ${r.description?`with goal: ${tt(r.description,100)}`:""}`;default:return(t=>{throw new Error("You missed a case in the switch above")})(r)}}function eo(r){switch(r.type){case"AI_ACTION":return`AI action: ${tt(r.text,100)}`;case"AI_ACTION_DYNAMIC":return`AI action: ${tt(r.text,100)}`;case"PRESET_ACTION":return Zn(r.command);case"MODULE":return`Module: ${r.id}`;case"RESOLVED_MODULE":return`Module: ${r.name}`;case"CONDITIONAL":return"Conditional step";case"SECTION":return`Section${r.description?`with goal: ${tt(r.description,100)}`:""}`;default:return(t=>{throw new Error("You missed a case in the switch above")})(r)}}function Ha(r,e){return r.split(`
|
|
35
35
|
`).map(t=>" ".repeat(e)+t).join(`
|
|
@@ -44,7 +44,7 @@ ${n}`}function fB(r){let e=gB(r);return xi({steps:e,earlyStop:!1,onPresetAction:
|
|
|
44
44
|
`)}catch(i){throw new Error(`Could not read test file ${t}: ${i}`)}let o;try{o=qa.parse(n)}catch(i){throw new Error(`Could not parse test file ${t} as YAML: ${i}`)}return Xt.parse(o)}function Oi(r,e,t){let n=t.project.rootDir,o;try{o=cn.readFileSync(r,"utf-8")}catch(a){throw e.error({err:a,projectRoot:n},a.message),new Error(a.message)}let i=qa.parse(o);if(!i.steps||!Array.isArray(i.steps))throw new Error(`Test ${r} is missing steps`);return i}async function dt(r,e,t){let n=Oi(r,e,t),o;try{o=Br.parse(n)}catch(a){throw new Error(`Test ${r} is missing metadata or has invalid metadata: ${a}`)}let{resolvedTest:i}=await NA({rawSteps:{steps:n.steps,beforeSteps:n.beforeSteps,afterSteps:n.afterSteps},metadata:o,logger:e,callbacks:{onFetchModule:async({id:a,logger:s})=>{let c=t.modules[a]?.fullFilePath;if(c)return ro(c,s)}}});return i}import IB from"@dotenvx/dotenvx";import PB from"fs";import YA from"path";function gd(r,e){return(r.config.environments??[]).map(t=>Li(t.name,r,e))}function XA(r){return r.includes("${")?r.replace(/\$\{([^}]+)\}/g,(e,t)=>{let[n,o]=t.split(/:-|-/,2),i=process.env[n];return t.includes(":-")?i&&i!==""?i:o||"":t.includes("-")?i!==void 0?i:o||"":i||""}):r}function OB(r){let{envVariables:e,project:t}=r;if(!e)return{};let n={};for(let[o,i]of Object.entries(e)){if(typeof i=="string"){let s=XA(i);s&&(n[o]=s);continue}let a;try{a=PB.readFileSync(YA.resolve(t.rootDir,i.fromFile),"utf-8")}catch(s){throw new Error(`Failed to read environment variable '${o}' from file '${i.fromFile}': ${s}`)}if(i.json)try{n[o]=JSON.parse(a)}catch(s){throw new Error(`Failed to parse environment variable '${o}' from file '${i.fromFile}' as JSON: ${s}`)}else n[o]=a}return Object.keys(n).length>0&&E.debug(n,"Set environment variables with interpolation from project configuration"),n}function LB(r){let{project:e,envFile:t,logger:n}=r,o={};if(!t)return o;let i=IB.config({path:YA.resolve(e.rootDir,t),processEnv:o,logLevel:"error",quiet:!0});if(i.error)throw new Error(`Failed to load .env file: ${i.error.message}`);return n.debug(o,"Set environment variables from .env file"),o}function Li(r,e,t){let n=(e.config.environments??[]).find(c=>c.name===r);if(!n)throw new Error(`Environment ${r} not found in local project configuration file`);if(!n.baseUrl)throw new Error(`Browser environment ${r} does not have a baseUrl configured`);let o={[Rt]:XA(n.baseUrl)},i=OB({envVariables:n.envVariables,project:e});Object.assign(o,i);let a=LB({project:e,envFile:n.envFile,logger:t});return Object.assign(o,a),n.inheritFromShell&&(t.debug(process.env,"Inheriting environment variables from shell"),Object.assign(o,process.env)),{name:r,variables:o,browser:n.browser}}import{existsSync as DB,readFileSync as kB,readdirSync as FB,writeFileSync as UB}from"fs";import{glob as BB}from"glob";import Ni,{dirname as JA}from"path";import{cwd as $g}from"process";import QA from"yaml";import{z as Ke}from"zod";import NB from"zod";var fd=["**/*.test.yaml","**/*.module.yaml"],Vg=NB.string().refine(r=>/^[a-zA-Z0-9-]+$/.test(r)),Sd=15;var Ka="momentic.config.yaml",Wg="momentic.workspace.yaml",zB=Ke.object({projects:Ke.string().array().describe("list of glob patterns to find project (momentic.config.yaml) files")}),HB=Ke.union([Ke.string(),Ke.object({fromFile:Ke.string(),json:Ke.boolean().optional()})]),GB=Ke.object({name:Vg,baseUrl:Ke.string().optional().describe("Optional for mobile tests"),envFile:Ke.string().optional().describe("path to a file on disk to read environment variables from. can be relative to project root or absolute."),envVariables:Ke.record(Ke.string(),HB).optional(),inheritFromShell:Ke.boolean().optional().describe("inherit all environment variables from the shell - might be noisy"),browser:fi.optional().describe("NB: most things should use project-level configuration only")}),jB=Ke.object({postSave:Ke.string().optional()}),VB=Ke.object({name:Vg,include:Ke.string().array().optional().describe("list of glob patterns that match momentic files (optional)"),exclude:Ke.string().array().optional().describe("opposite of include, takes precedence over include"),goldenFileDir:Ke.string().optional(),reporterDir:Ke.string().optional(),outputDir:Ke.string().optional(),recordVideo:Ke.boolean().optional(),retries:Ke.number().optional().describe("number of retries per test"),parallel:Ke.number().optional().describe("degree of parallelism"),environments:Ke.array(GB).optional(),gitMainBranch:Ke.string().optional(),gitProtectedBranches:Ke.string().array().optional(),ai:eg.optional(),browser:fi.optional(),emulator:Gh.optional(),advanced:tg.optional(),hooks:jB.optional()});function ZA(r,e){let t;try{t=kB(r,"utf-8")}catch(o){E.warn(`Could not read possible Momentic ${e} file at ${r}: ${o}`);return}let n;try{if(n=QA.parse(t),typeof n!="object"||n===null)throw new Error(`The ${e} file should parse as a map with key-value pairs, but is type ${typeof n} instead`)}catch(o){E.warn(`Possible Momentic ${e} file at ${r} does not parse as valid YAML: ${o}`);return}return n}function qg(r){let e=ZA(r,"project configuration");if(e!==void 0)try{return VB.parse(e)}catch(t){E.warn(`Possible Momentic project configuration file at ${r} does not adhere to the required schema: ${t}`);return}}function $B(r){let e=ZA(r,"workspace configuration");if(e!==void 0)try{return zB.parse(e)}catch(t){E.warn(`Possible Momentic workspace configuration file at ${r} does not adhere to the required schema: ${t}`);return}}function WB(){let r=[],e=$g(),t=Ni.parse(e).root,n=15,o=0;for(;o<n;){o++;let i=Ni.basename(e);if(xu.includes(i))return E.warn(`Stopping search for Momentic projects since the current directory name (${i}) is likely a system artifact folder.`),r;for(let a of FB(e))if(a.endsWith(Ka)){let s=Ni.join(e,a),c=qg(s);c&&r.push({configFilePath:s,config:c,rootDir:JA(s)})}if(r.length)return r;if(e=Ni.dirname(e),e===t)break}return r}async function xt(r={}){let{configFilePath:e,nameFilter:t}=r,n=await Kg(e);if(t&&(n=n.filter(o=>o.config.name===t)),n.length>1)throw new Error(`Multiple valid projects were found in the same directory. Please use the '-c / --config' flag to disambiguate:
|
|
45
45
|
${n.map(o=>o.configFilePath)}`);if(n.length===0)throw new Error("No valid Momentic project file available.");return E.debug(`Found valid project configuration at ${n[0].configFilePath}`),n[0]}async function qB(r){let e=$B(r);if(!e||!e.projects||!e.projects.length)return;let t=e.projects.map(a=>(a.endsWith("/")||(a+="/"),`${a}*${Ka}`)),n=AbortSignal.timeout(2e3),o;try{o=await BB(t,{absolute:!1,cwd:$g(),dotRelative:!1,maxDepth:Sd,nodir:!0,signal:n})}catch(a){throw E.error({err:a},`Failed to list the available Momentic projects in the current directory. This usually indicates the 'include' or 'exclude' option in your ${Wg} is misconfigured.`),a}let i=[];for(let a of o){let s=Ni.join($g(),a),c=qg(s);c&&i.push({configFilePath:s,config:c,rootDir:JA(s)})}return i}async function Kg(r){if(r){r=Ni.resolve(r);let t=qg(r);return t||(console.error(`No valid Momentic project file found at ${r}.`),process.exit(1)),[{config:t,configFilePath:r,rootDir:Ni.dirname(r)}]}if(DB(Wg)){let t=await qB(Wg);if(t)return t}return WB()}function Uo(r,e){let t=QA.stringify(r);UB(e,t)}import tw from"fs";import{glob as KB}from"glob";import Nl from"path";import YB from"yaml";import{z as ew}from"zod";var rw=!1,XB=ew.object({fileType:ew.nativeEnum(ge)});async function ee(r,e=!1){let t={project:r,tests:{},modules:{},mobileTests:{},mobileModules:{},duplicateEntities:{}},n=r.config.include??fd,o=Array.from(r.config.exclude??[]).concat(_u),i=AbortSignal.timeout(5e3),a;try{a=await KB(n,{absolute:!1,cwd:r.rootDir,ignore:o,dotRelative:!1,maxDepth:Sd,nodir:!0,signal:i})}catch(s){throw E.error({err:s},"Failed to list all Momentic files in the current directory. This usually indicates the 'include' and 'exclude' globs are misconfigured in your momentic.config.yaml, or that your machine is severely resource constrained."),new Error("Listing Momentic files timed out after 5 seconds.",{cause:s})}for(let s of a){let c=JB(r.rootDir,s,t,e?wn:E);c&&(t.duplicateEntities[c.id]=c.paths)}return rw=!0,t}function JB(r,e,t,n){let o=Nl.join(r,e),i=QB(o,n);if(!i)return;let a=ZB(i,o,n);if(!a)return;let s=XB.safeParse(a);if(s.success===!1){n.warn(`Possible Momentic file at ${o} does not have a 'fileType', skipping: ${s.error}`);return}let c=s.data.fileType,l=ez(o,n);if(!l)return;let u=tz(e,o,l);switch(c){case ge.TEST:try{return rz(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic test metadata: ${d}`);return}case ge.MODULE:try{return nz(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic module metadata: ${d}`);return}case ge.MOBILE_TEST:try{return iz(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic mobile test metadata: ${d}`);return}case ge.MOBILE_MODULE:try{return oz(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic mobile module metadata: ${d}`);return}default:{let d=c;return}}}function QB(r,e){try{return tw.readFileSync(r,"utf-8")}catch(t){e.warn(`Could not read possible Momentic file at ${r}, skipping: ${t}`);return}}function ZB(r,e,t){try{let n=YB.parse(r);if(typeof n!="object"||n===null)throw new Error("The YAML document should parse as a map with key-value pairs");return n}catch(n){t.warn(`Could not parse possible Momentic file at ${e}, skipping: ${n}`);return}}function ez(r,e){try{return tw.statSync(r)}catch(t){e.warn(`Skipping path '${r}' because it could not be stat, skipping: ${t}`);return}}function tz(r,e,t){return{relativePath:r,fullFilePath:e,platformSep:Nl.sep,fullPathSegments:e.split(Nl.sep),relativePathSegments:r.split(Nl.sep),fileName:Nl.basename(e),lastModified:t.mtime,createdAt:t.birthtime}}function rz(r,e,t,n,o){let i=Br.parse(r),a;if(e.tests[i.id]){let s=e.tests[i.id].fullFilePath;a={id:i.id,paths:[s,n]}}return e.tests[i.id]={type:ge.TEST,name:i.name,id:i.id,description:i.description??void 0,labels:i.labels,...t},a}function nz(r,e,t,n,o){let i=gr.parse(r),a;if(e.modules[i.moduleId]){let c=e.modules[i.moduleId].fullFilePath;a={id:i.moduleId,paths:[c,n]}}e.modules[i.moduleId]={type:ge.MODULE,name:i.name,id:i.moduleId,description:i.description??void 0,...t};let s=t.fileName.replace(".module.yaml","");return!rw&&Be(i.name)!==s&&o.warn(`The module with ID ${i.moduleId} has a name (${i.name}) that does not match its file name (${s}). We recommend renaming the module or the file to be consistent to avoid confusion and issues with module resolution.`),a}function oz(r,e,t,n,o){let i=Au.parse(r),a;if(e.mobileModules[i.moduleId]){let c=e.mobileModules[i.moduleId].fullFilePath;a={id:i.moduleId,paths:[c,n]}}let s=t.fileName.replace(".module.yaml","");return e.mobileModules[i.moduleId]={type:ge.MOBILE_MODULE,name:s,id:i.moduleId,description:i.description??void 0,...t},a}function iz(r,e,t,n,o){let i=Ia.parse(r),a;if(e.mobileTests[i.id]){let c=e.mobileTests[i.id].fullFilePath;a={id:i.id,paths:[c,n]}}let s=t.fileName.replace(".test.yaml","");return e.mobileTests[i.id]={type:ge.MOBILE_TEST,name:s,id:i.id,description:i.description??void 0,...t},a}import Ya from"fs";import Yg from"path";import{z as Xg}from"zod";var nw="golden/visual-diff",ow="reports",iw="test-results";var az=Xg.object({width:Xg.number(),height:Xg.number()}),Xa=class{defaultGoldenScreenshotDir;regenerateGoldenFiles;constructor(e,t){let n=Yg.join(e.rootDir,e.config.goldenFileDir??nw);this.defaultGoldenScreenshotDir=n,this.regenerateGoldenFiles=t}async prepareGoldenScreenshotForComparison(e,t,n){if(t.screenshot?.data?.startsWith("https://")){let a=await fetch(t.screenshot.data);return{buffer:Buffer.from(await a.arrayBuffer()),width:t.screenshot.width,height:t.screenshot.height}}let o=t.screenshot?.data;o||(o=Yg.join(this.defaultGoldenScreenshotDir,`${t.id}.jpg`));let i=`${o}.metadata.json`;if(this.regenerateGoldenFiles)return Ya.mkdirSync(Yg.dirname(o),{recursive:!0}),Ya.writeFileSync(o,n.buffer),Ya.writeFileSync(i,JSON.stringify({width:n.width,height:n.height})),{buffer:Buffer.from(n.buffer),width:n.width,height:n.height};if(Ya.existsSync(o)){let a=Ya.readFileSync(o),s=az.parse(JSON.parse(Ya.readFileSync(i,"utf-8")));return{buffer:a,width:s.width,height:s.height}}else throw new M("UserConfigurationError",`Cannot execute visual diff without a saved baseline screenshot at ${o}`)}};import{execFile as sz}from"node:child_process";import{promisify as lz}from"node:util";import cz from"simple-git";var Ye=cz(),aw=lz(sz);async function uz(r){let e=await rt(r,Ye.raw(["config","--list"])),t={};if(!e)return t;for(let n of e.split(`
|
|
46
46
|
`)){let o=n.indexOf("=");if(o===-1)continue;let i=n.slice(0,o),a=n.slice(o+1).trim();t[i]=a}return t}async function dz(r,e,t){try{let o=t["github.user"]||void 0;if(o)return o}catch{}let n;try{if(e?.startsWith("http://")||e?.startsWith("https://"))n=new URL(e).host;else if(e?.startsWith("git@")){let o=e.indexOf("@"),i=e.indexOf(":",o+1);o!==-1&&i!==-1&&(n=e.slice(o+1,i))}}catch{}if(n=n?.toLowerCase(),!!n){try{if(e?.startsWith("git@")&&n?.includes("github")){let{stdout:o,stderr:i}=await aw("ssh",["-T","-o","BatchMode=yes",`git@${n}`],{timeout:5e3}),s=`${o??""}${i??""}`.trim().match(/Hi\s+([A-Za-z0-9_-]+)!/);if(s?.[1])return s[1]}}catch{}try{let o=n&&n!=="github.com"?["api","--hostname",n,"user","-q",".login"]:["api","user","-q",".login"],{stdout:i}=await aw("gh",o,{timeout:5e3}),a=i?.toString().trim();if(a)return a}catch{}}}async function pz(r,e,t){let n=e?.includes("github.com"),o=e?.includes("gitlab.com");try{if(n)return dz(r,e,t);if(o)return}catch{}}function yd(r){if(r.startsWith("git@")){let e=r.split(":");if(e.length===2){let t=e[1].replace(".git","").split("/");if(t.length===2){let n=t[0],o=t[1];return`${n}/${o}`}}}else if(r.startsWith("http")||r.startsWith("https")){let t=new URL(r).pathname.split("/").filter(Boolean);if(t.length>=2){let n=t[0],o=t[1].replace(".git","");return`${n}/${o}`}}}async function rt(r,e){try{return(await e).trim()}catch(t){if(t instanceof Error&&t.message.includes("not a git repository"))return;r.error({err:t},"Failed to run git command");return}}function mz(){if(process.env.GITHUB_ACTION)return"GithubActions";if(process.env.GITLAB_CI)return"GitlabCI";if(process.env.CIRCLECI)return"CircleCI";if(process.env.BUILDKITE)return"Buildkite";if(process.env["System.CollectionUri"]?.includes("azure"))return"AzureDevOps";if(process.env.PROJECT_ID&&process.env.BUILD_ID)return"GCPCloudBuild"}async function hz(r){let[e,t,n]=await Promise.all([rt(r,Ye.show(["--no-patch","--format=%ci"])),rt(r,Ye.show(["-s","--pretty=%B"])),rt(r,Ye.show(["-s","--pretty=%an"]))]),o=process.env.GITHUB_SERVER_URL&&process.env.GITHUB_REPOSITORY?`${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}`:void 0;return{ciProvider:"GithubActions",gitCommitSha:process.env.GITHUB_SHA,gitCommitShaShort:process.env.GITHUB_SHA?.slice(0,6),gitCommitTimestamp:e?new Date(e):void 0,gitBranchName:process.env.GITHUB_HEAD_REF||process.env.GITHUB_REF_NAME,gitOriginUrl:o,gitCommitMessage:t,gitCommitAuthorName:n,githubRepository:process.env.GITHUB_REPOSITORY,pipelineId:process.env.GITHUB_RUN_ID}}async function gz(r){let[e,t,n]=await Promise.all([rt(r,Ye.listRemote(["--get-url","origin"])),rt(r,Ye.show(["-s","--pretty=%B"])),rt(r,Ye.show(["-s","--pretty=%an"]))]);return{ciProvider:"GitlabCI",gitCommitSha:process.env.CI_COMMIT_SHA,gitCommitShaShort:process.env.CI_COMMIT_SHORT_SHA,gitCommitTimestamp:process.env.CI_COMMIT_TIMESTAMP?new Date(process.env.CI_COMMIT_TIMESTAMP):void 0,gitBranchName:process.env.CI_COMMIT_BRANCH||process.env.CI_COMMIT_REF_NAME,gitOriginUrl:e,gitCommitMessage:t,gitCommitAuthorName:n,gitlabProjectPath:process.env.CI_PROJECT_PATH,pipelineId:`${process.env.CI_PIPELINE_ID}:${process.env.CI_JOB_ID}`}}async function fz(r){let[e,t,n,o]=await Promise.all([rt(r,Ye.show(["--no-patch","--format=%ci"])),rt(r,Ye.listRemote(["--get-url","origin"])),rt(r,Ye.show(["-s","--pretty=%B"])),rt(r,Ye.show(["-s","--pretty=%an"]))]),i=process.env.CIRCLE_REPOSITORY_URL??t,a=i?.includes("github.com"),s=i?.includes("gitlab.com"),c=i?yd(i):void 0;return{ciProvider:"CircleCI",gitCommitSha:process.env.CIRCLE_SHA1,gitCommitShaShort:process.env.CIRCLE_SHA1?.slice(0,6),gitCommitTimestamp:e?new Date(e):void 0,gitBranchName:process.env.CIRCLE_BRANCH,gitOriginUrl:i,gitCommitMessage:n,gitCommitAuthorName:o,githubRepository:a?c:void 0,gitlabProjectPath:s?c:void 0,pipelineId:process.env.CIRCLE_PIPELINE_ID}}async function Sz(r){let[e,t,n]=await Promise.all([rt(r,Ye.show(["--no-patch","--format=%ci"])),rt(r,Ye.show(["-s","--pretty=%B"])),rt(r,Ye.show(["-s","--pretty=%an"]))]),o=process.env.BUILDKITE_REPO,i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?yd(o):void 0;return{ciProvider:"Buildkite",gitCommitSha:process.env.BUILDKITE_COMMIT,gitCommitShaShort:process.env.BUILDKITE_COMMIT?.slice(0,6),gitCommitTimestamp:e?new Date(e):void 0,gitBranchName:process.env.BUILDKITE_BRANCH,gitOriginUrl:o,gitCommitMessage:t,gitCommitAuthorName:n,githubRepository:i?s:void 0,gitlabProjectPath:a?s:void 0,pipelineId:`${process.env.BUILDKITE_PIPELINE_ID}:${process.env.BUILDKITE_BUILD_ID}:${process.env.BUILDKITE_JOB_ID}`}}async function yz(r){let[e,t,n]=await Promise.all([rt(r,Ye.show(["--no-patch","--format=%ci"])),rt(r,Ye.show(["-s","--pretty=%B"])),rt(r,Ye.show(["-s","--pretty=%an"]))]),o=process.env["Build.Repository.Uri"],i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?yd(o):void 0;return{ciProvider:"AzureDevOps",gitCommitSha:process.env["Build.SourceVersion"],gitCommitShaShort:process.env["Build.SourceVersion"]?.slice(0,6),gitCommitTimestamp:e?new Date(e):void 0,gitBranchName:process.env["System.PullRequest.SourceBranch"]??process.env["Build.SourceBranchName"],gitOriginUrl:o,gitCommitMessage:t,gitCommitAuthorName:n,githubRepository:i?s:void 0,gitlabProjectPath:a?s:void 0,pipelineId:`${process.env["System.JobId"]}:${process.env["System.JobAttempt"]}`}}async function Ez(r,e){let[t,n,o,i,a,s,c,l,u]=await Promise.all([rt(r,Ye.revparse(["HEAD"])),rt(r,Ye.revparse(["--short","HEAD"])),rt(r,Ye.revparse(["--abbrev-ref","HEAD"])),rt(r,Ye.listRemote(["--get-url","origin"])),rt(r,Ye.show(["--no-patch","--format=%ci"])),rt(r,Ye.show(["-s","--pretty=%B"])),rt(r,Ye.show(["-s","--pretty=%an"])),e?rt(r,Ye.raw(["merge-base","--fork-point",e])):Promise.resolve(void 0),uz(r)]),d=l?await rt(r,Ye.show(["--no-patch","--format=%ci",l])):void 0,p=i?.includes("github.com"),m=i?.includes("gitlab.com"),h=i?yd(i):void 0,g=u["user.email"]||void 0,f=u["user.name"]||void 0,y=u["user.username"]||void 0,S=await pz(r,i,u)??y??void 0;return{ciProvider:"none",gitCommitSha:t,gitCommitShaShort:n,gitBranchName:o,gitOriginUrl:i,gitCommitTimestamp:a?new Date(a):void 0,gitCommitMessage:s,gitCommitAuthorName:c,gitLocalUsername:S,gitLocalEmail:g,gitLocalName:f,lastCommitOnMainSha:l,lastCommitOnMainTimestamp:d?new Date(d):void 0,githubRepository:p?h:void 0,gitlabProjectPath:m?h:void 0,pipelineId:void 0}}async function Tz(){let r=process.env._HEAD_REPO_URL;return{ciProvider:"GCPCloudBuild",gitCommitSha:process.env.COMMIT_SHA,gitCommitShaShort:process.env.COMMIT_SHA?.slice(0,6),gitBranchName:process.env.BRANCH_NAME,gitOriginUrl:r?process.env._HEAD_REPO_URL:void 0,gitCommitTimestamp:void 0,gitCommitMessage:void 0,gitCommitAuthorName:void 0,githubRepository:r?process.env.REPO_FULL_NAME:void 0,pipelineId:`${process.env.PROJECT_ID}:${process.env.BUILD_ID}`}}async function bz(r){let e=r.config.gitProtectedBranches??[];return r.config.gitMainBranch&&e.push(r.config.gitMainBranch),{gitMainBranch:r.config.gitMainBranch,gitProtectedBranches:e}}async function no(r,e){let t=mz();if(!t)return Ez(r,e);switch(t){case"GithubActions":return hz(r);case"GitlabCI":return gz(r);case"CircleCI":return fz(r);case"Buildkite":return Sz(r);case"AzureDevOps":return yz(r);case"GCPCloudBuild":return Tz()}}async function vz(r,e,t,n){let o=n;if(!n.gitCommitSha)return o;if(n.gitMainBranch&&(!o.lastCommitOnMainSha||!o.lastCommitOnMainTimestamp))try{let i=await e.getMergeBaseCommitFromGitlab(t,n.gitMainBranch,n.gitCommitSha);o={...o,lastCommitOnMainSha:i.sha,lastCommitOnMainTimestamp:i.committer.date}}catch(i){r.warn({err:i},"Failed to get merge base commit from Gitlab")}if(!o.gitCommitTimestamp||!o.gitCommitAuthorName||!o.gitCommitMessage||!o.gitCommitAuthorName)try{let i=await e.getCommitFromGitlab(t,n.gitCommitSha);i&&(o={...o,gitCommitTimestamp:o.gitCommitTimestamp??i.committer.date,gitCommitAuthorName:o.gitCommitAuthorName??i.author.name,gitCommitMessage:o.gitCommitMessage??i.message})}catch(i){r.warn({err:i},"Failed to get commit from Gitlab")}if(n.gitBranchName&&n.gitBranchName===n.gitMainBranch&&!o.mergedGitBranchName)try{let i=await e.getMergedBranchFromGitlab(t,n.gitBranchName??"",n.gitCommitSha);i.mergedBranch&&(o={...o,mergedGitBranchName:i.mergedBranch})}catch(i){r.warn({err:i},"Failed to get merged branch from Gitlab")}return o}async function Rz(r,e,t,n,o){let i=o;if(!o.gitCommitSha)return i;if(o.gitMainBranch&&(!i.lastCommitOnMainSha||!i.lastCommitOnMainTimestamp))try{let a=await e.getMergeBaseCommitFromGithub(t,n,o.gitMainBranch,o.gitCommitSha);i={...i,lastCommitOnMainSha:a.sha,lastCommitOnMainTimestamp:a.committer.date}}catch(a){r.warn({err:a},"Failed to get merge base commit from GitHub")}if(!i.gitCommitTimestamp||!i.gitCommitAuthorName||!i.gitCommitMessage||!i.gitCommitAuthorName)try{let a=await e.getCommitFromGithub(t,n,o.gitCommitSha);a&&(i={...i,gitCommitTimestamp:i.gitCommitTimestamp??a.committer.date,gitCommitAuthorName:i.gitCommitAuthorName??a.author.name,gitCommitMessage:i.gitCommitMessage??a.message})}catch(a){r.warn({err:a},"Failed to get commit from GitHub")}if(o.gitBranchName&&o.gitBranchName===o.gitMainBranch&&!i.mergedGitBranchName)try{let a=await e.getMergedBranchFromGithub(t,n,o.gitBranchName??"",o.gitCommitSha);a.mergedBranch&&(i={...i,mergedGitBranchName:a.mergedBranch})}catch(a){r.warn({err:a},"Failed to get merged branch from GitHub")}return i}async function Az(r,e,t){try{if(t.githubRepository){let[n,o]=t.githubRepository.split("/");return await Rz(r,e,n,o,t)}else if(t.gitlabProjectPath)return await vz(r,e,t.gitlabProjectPath,t)}catch(n){r.warn({err:n},"Failed to get remote git metadata")}return t}async function Hr(r,e,t){let n=await bz(t),o=await no(r,n.gitMainBranch),i={...n,...o};(!i.lastCommitOnMainSha||!i.lastCommitOnMainTimestamp)&&i.gitBranchName===n.gitMainBranch&&(i.lastCommitOnMainSha=i.gitCommitSha,i.lastCommitOnMainTimestamp=i.gitCommitTimestamp);let a=await Az(r,e,i);return{...n,...o,...a}}async function sw(){try{return!!(await Ye.show(["--no-patch","--format=%ci"])).trim()}catch{return null}}import{diff as jye}from"deep-object-diff";import{cloneDeep as $ye}from"lodash-es";import{v4 as nEe}from"uuid";import iEe from"yaml";import REe from"yaml";import wEe from"zod";import{randomUUID as wz}from"crypto";import Bo from"fs";import Ja from"path";var lw=new Set([".DS_Store","__MACOSX"]),cw={status:(r,e)=>{if(r.status===e.status)return r.status;if(r.status==="FAILED"||e.status==="FAILED")return"FAILED";if(r.status==="CANCELLED"||e.status==="CANCELLED")return"CANCELLED";if(r.status==="RETRYING"||e.status==="RETRYING")return"RETRYING";if(r.status==="RUNNING"||e.status==="RUNNING")return"RUNNING";if(r.status==="PENDING"||e.status==="PENDING")return"PENDING";throw new Error(`Invalid run status merge: ${r.status} and ${e.status}`)},startedAt:(r,e)=>r.startedAt<e.startedAt?r.startedAt:e.startedAt,updatedAt:(r,e)=>r.updatedAt>e.updatedAt?r.updatedAt:e.updatedAt,finishedAt:(r,e)=>!r.finishedAt||!e.finishedAt?new Date:r.finishedAt>e.finishedAt?r.finishedAt:e.finishedAt,gitCommitTimestamp:(r,e)=>{if(!(!r&&!e)){if(!r.gitCommitTimestamp||!e.gitCommitTimestamp||r.gitCommitTimestamp.getTime()!==e.gitCommitTimestamp.getTime())throw new Error(`Git commit timestamps must match to be merged: ${r.gitCommitTimestamp} and ${e.gitCommitTimestamp}`);return r.gitCommitTimestamp}},pipelineId:(r,e)=>r.pipelineId===e.pipelineId?r.pipelineId:!r.pipelineId&&e.pipelineId?e.pipelineId:!e.pipelineId&&r.pipelineId?r.pipelineId:r.startedAt<e.startedAt?e.pipelineId:r.pipelineId,labels:(r,e)=>{let t=new Set([...r.labels??[],...e.labels??[]]);return Array.from(t)}};function Cz(r,e,t){if(cw[t]){let i=cw[t];return i(r,e)}let n=r[t],o=e[t];if(n!==o)throw new Error(`Metadata values for key "${t}" do not match: "${n}" vs "${o}"`);return n}var Jg=class extends Error{constructor(e,t){let n=`${e} contains invalid Momentic results: ${t}. Please ensure that the path points to a folder containing only valid results. If you passed \`--output-dir test-results/results-1\` to the \`run\` command, your results path for merging should be \`test-results\`.`;super(n),this.name="InvalidMomenticResultsPathError"}};function uw(r,e){try{let t=Ja.join(e,"metadata.json");return Nu.parse(JSON.parse(Bo.readFileSync(t,"utf-8")))}catch{throw new Jg(r,e)}}function dw(r,e,t){let n=wz(),o=r.child({runGroupId:n});Bo.rmSync(e,{recursive:!0,force:!0});let i=Bo.readdirSync(t).filter(c=>!lw.has(c)).map(c=>Ja.join(t,c));if(i.length===0)throw new Error(`No run groups found in results path: ${t}`);Bo.mkdirSync(e,{recursive:!0});let a={...uw(t,i[0]),id:n};for(let c of i){let l=Ja.join(c,"runs");if(!Bo.existsSync(l))continue;let u=uw(t,c);o.info({oldRunGroupId:u.id},"Merging run groups");for(let p in u){if(p==="id")continue;let m=p;a[m]=Cz(a,u,m)}let d=Bo.readdirSync(l);for(let p of d){if(lw.has(p))continue;let m=Ja.join(l,p),h=Ja.join(e,"runs",p);Bo.cpSync(m,h,{recursive:!0})}}let s=Ja.join(e,"metadata.json");Bo.writeFileSync(s,JSON.stringify(a,null,2))}import pw from"adm-zip";import Qg from"fs";import Ed from"path";function xz(r){let e=new pw,t=Ed.join(r,"metadata.json"),n=Nu.parse(JSON.parse(Qg.readFileSync(t,"utf-8")));e.addLocalFile(t);for(let o of Qg.readdirSync(Ed.join(r,"runs"))){if(!o.endsWith(".zip"))continue;let i=o.replace(/\.zip$/,""),a=new pw(Ed.join(r,"runs",o));for(let s of a.getEntries())s.isDirectory||e.addFile(Ed.join("runs",i,s.entryName),s.getData())}return{runGroupId:n.id,buffer:e.toBuffer()}}async function Td(r){let{client:e,consoleLogger:t,resultsPath:n}=r;if(!Qg.existsSync(n)){t.warn("Results path does not exist, skipping upload.");return}let o=new Hu(e);try{let{runGroupId:i,buffer:a}=xz(n),s=await o.uploadResultsArchive(i,a),c=`${e.getAppUrl()}/run-groups/${s}`;t.success(`Successfully uploaded test results. Once processed, your results can be found at ${c}`);return}catch(i){let a;i instanceof Error?a=i.message:typeof i=="string"?a=i:a="Unknown error",t.error(`Failed to upload test results: ${a}.`);return}}import _z from"adm-zip";import Ht from"fs";import xr from"path";var Dl=class r{constructor(e){this.filePath=e;Ht.rmSync(this.filePath,{recursive:!0,force:!0}),Ht.mkdirSync(this.filePath,{recursive:!0})}cd(e){return new r(xr.join(this.filePath,e))}cwd(){return this.filePath}mkdir(e){Ht.mkdirSync(xr.join(this.filePath,e),{recursive:!0})}readFile(e){let t=xr.join(this.filePath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}storeFile(e){let{name:t,contents:n}=e,o=xr.join(this.filePath,t);try{Ht.writeFileSync(o,n)}catch{}}createFileStream(e){let t=xr.join(this.filePath,e);return Ht.createWriteStream(t)}createRunArchive(e){return new Zg(xr.join(this.filePath,"runs"),e)}},Zg=class{constructor(e,t){this.filePath=e;this.tempPath=xr.join(e,`temp-storage-${t}`),this.finalPath=xr.join(e,`${t}.zip`),Ht.rmSync(this.tempPath,{recursive:!0,force:!0}),Ht.rmSync(this.finalPath,{recursive:!0,force:!0}),Ht.mkdirSync(this.tempPath,{recursive:!0})}tempPath;finalPath;readFile(e){let t=xr.join(this.tempPath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}mkdir(e){Ht.mkdirSync(xr.join(this.tempPath,e),{recursive:!0})}cd(e){return new Dl(xr.join(this.tempPath,e))}cwd(){return this.tempPath}storeFile(e){let{name:t,contents:n}=e,o=xr.join(this.tempPath,t);Ht.writeFileSync(o,n)}createFileStream(e){let t=xr.join(this.tempPath,e);return Ht.createWriteStream(t)}close(){let e=new _z;e.addLocalFolder(this.tempPath,void 0,n=>n!==".DS_Store");let t=e.toBuffer();Ht.writeFileSync(this.finalPath,t),Ht.rmSync(this.tempPath,{recursive:!0,force:!0})}};import Mz from"adm-zip";import{randomUUID as Iz}from"crypto";import Ot from"fs";import Gt from"path";function fw(r){try{return Ot.existsSync(r)?JSON.parse(Ot.readFileSync(r,"utf-8")):void 0}catch{return}}function mw(r){return Ot.existsSync(r)?Ot.readFileSync(r,"utf-8").split(`
|
|
47
|
-
`).map(t=>t.trim()).filter(t=>t.length>0):[]}function Pz(r,e){let t=r.attemptIdToAttemptNumber.get(e);if(t)return Gt.join(r.inflatedPath,"attempts",t);let n=Gt.join(r.inflatedPath,"attempts");if(!Ot.existsSync(n))return;let o=Ot.readdirSync(n,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of o){let a=Gt.join(n,i,"metadata.json"),s=fw(a);if(typeof s!="object"||s===null)continue;let c=s.id;if(typeof c=="string"&&c===e)return r.attemptIdToAttemptNumber.set(e,i),Gt.join(n,i)}}function hw(r,e,t){let n=Gt.join(r,"attempts");if(!Ot.existsSync(n))return;let o=Ot.readdirSync(n,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of o){let a=Gt.join(n,i,"assets",`${e}.${t}`);if(Ot.existsSync(a))return a}}var bd=class{constructor(e,t,n){this.outputDir=e;this.runId=t;this.runAttemptId=n;this.runsDir=Gt.join(e,"runs"),this.zipPath=Gt.join(this.runsDir,`${t}.zip`)}inflatedByRunId=new Map;zipPath;runsDir;ensureInflatedRun(e){let t=this.inflatedByRunId.get(e);if(t)return t;if(e!==this.runId||!Ot.existsSync(this.zipPath))return;let n=Gt.join(this.runsDir,`temp-unzipped-${e}-${Iz()}`);Ot.mkdirSync(n,{recursive:!0}),new Mz(this.zipPath).extractAllTo(n,!0);let i={runId:e,zipPath:this.zipPath,inflatedPath:n,attemptIdToAttemptNumber:new Map};return this.inflatedByRunId.set(e,i),i}close(){for(let e of this.inflatedByRunId.values())Ot.rmSync(e.inflatedPath,{recursive:!0,force:!0});this.inflatedByRunId.clear()}getAttemptDir(){let e=this.ensureInflatedRun(this.runId);if(e)return Pz(e,this.runAttemptId)}listVideoAssetPaths(){let e=this.getAttemptDir();if(!e)return[];let t=Gt.join(e,"assets");return Ot.existsSync(t)?Ot.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isFile()).map(o=>Gt.join(t,o.name)).filter(o=>{let i=Gt.extname(o).toLowerCase();return i===".webm"||i===".mp4"}):[]}readAttemptAssetText(e,t){let n=this.getAttemptDir();if(!n)return;let o=Gt.join(n,"assets",`${e}.${t}`);if(Ot.existsSync(o))try{return Ot.readFileSync(o,"utf-8")}catch{return}}async getConsoleLogsForRunAttempt(e,t,n){if(t!==this.runId||n!==this.runAttemptId)return;let o=this.getAttemptDir();if(!o)return;let i=fw(Gt.join(o,"console.json")),a=Vh.safeParse(i);return a.success?a.data:void 0}async getNetworkLogsForRunAttempt(e,t,n){if(t!==this.runId||n!==this.runAttemptId)return;let o=this.getAttemptDir();if(!o)return;let i=Gt.join(o,"assets","har-pages.log"),a=Gt.join(o,"assets","har-entries.log"),s={};for(let u of mw(i)){let d=ml.safeParse(gw(u));d.success&&(s[d.data.id]=d.data)}let c={},l=mw(a);for(let u=0;u<l.length;u++){let d=l[u],p=hl.safeParse(gw(d));if(!p.success)continue;let m=`${p.data.startedDateTime}-${u}`;c[m]=p.data}if(Object.keys(c).length!==0)return Wh(s,c)}async getHtmlSnapshot(e,t){let n=this.readAttemptAssetText(t,"html");if(n)return n;let o=this.ensureInflatedRun(this.runId);if(!o)return;let i=hw(o.inflatedPath,t,"html");if(i)try{return Ot.readFileSync(i,"utf-8")}catch{return}}async getA11yTreeSnapshot(e,t){let n=this.readAttemptAssetText(t,"xml");if(n)return n;let o=this.ensureInflatedRun(this.runId);if(!o)return;let i=hw(o.inflatedPath,t,"xml");if(i)try{return Ot.readFileSync(i,"utf-8")}catch{return}}async getScreenshot(e,t){if(!this.ensureInflatedRun(this.runId))return;let o=this.getAttemptDir(),i=o?Gt.join(o,"assets",`${t}.jpeg`):void 0;if(i)try{return Ot.readFileSync(i)}catch{return}}};function gw(r){try{return JSON.parse(r)}catch{return}}import{hostname as Oz}from"os";var Lz="2.28.6",kl=Na({app:"desktop-server",hostname:Oz(),disableConsoleLogs:!0}).child({cliVersion:Lz});(async()=>{try{let r=await no(kl);r.gitBranchName&&kl.addBinding("branch",r.gitBranchName)}catch{}})();var Sw=Nz();Sw.get("/",async(r,e)=>{let t=se(),n=jA();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Hr(kl,n,t);e.status(200).json(o)});var ef=Sw;import LK from"events";import lO,{Router as NK}from"express";import DK from"http";import kK from"path";import{Server as JW}from"socket.io";var Dz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async()=>{e.info({sessionId:n},"Cancel event received");let o=t.getSession(n);if(!o)throw new Error("No active session found");try{o.controller.setClosed()}catch{}}},yw={event:"cancel",createHandler:Dz};var kz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async(o,i)=>{let a=t.getSession(n);if(!a)throw new Error("No active session found");a.controller.setOpen();let s=a.controller.browser;try{let l=(await s.getBrowserState({skipWait:!0})).serialize();e.debug({a11yTree:l},"Fetched a11y tree from the browser"),i({a11yTree:l})}catch(c){e.error({err:c},"Error fetching a11y tree from the browser"),i({err:c.message})}}},Ew={event:"fetchA11yTree",createHandler:kz};var Fz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async(o,i)=>{let a=t.getSession(n);if(!a)throw new Error("No active session found");a.controller.setOpen();let s=a.controller.browser;try{let c=await s.html();i({html:c})}catch(c){e.error({err:c},"Error fetching DOM from the browser"),c.name==="TimeoutError"?i({err:"Timed out fetching DOM tree. This page may be too large for Momentic to process."}):i({err:c.message})}}},Tw={event:"fetchDom",createHandler:Fz};var Uz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return o=>{e.info({sessionId:n,reason:o},`Disconnect event received (${o})`),t.removeSession(n,e)}},bw={event:"disconnect",createHandler:Uz};function un(r){let{result:e,nestedResults:t}=r;if(!r.nestedResults.length)return;let{firstMetadata:n,lastMetadata:o}=Bz(t);zz(e,n,o);let i=[...r.asyncTasks];r.asyncTasks.push((async()=>{try{await Hz(i,e,n,o)}catch(a){r.logger.error({result:r.result,err:a},"Error hoisting scalar result metadata")}})())}function Bz(r){let e=r[0],t;for(;;){switch(e.type){case"PRESET_ACTION":{t=e;break}case"CONDITIONAL":t=r[0];break;case"AI_ACTION_DYNAMIC":case"AI_ACTION":case"MODULE":case"SECTION":if(!e.results.length){t=e;break}e=e.results[0];break;default:return(a=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}if(t)break}let n=r[r.length-1],o;for(;;){switch(n.type){case"PRESET_ACTION":{o=n;break}case"AI_ACTION_DYNAMIC":case"CONDITIONAL":case"AI_ACTION":case"MODULE":case"SECTION":if(!n.results.length){o=n;break}n=n.results[n.results.length-1];break;default:return(a=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(n)}if(o)break}return{firstMetadata:t,lastMetadata:o}}function zz(r,e,t){e&&(r.beforeUrl=e.beforeUrl),t&&(r.afterUrl=t.afterUrl,r.data=t.data,t.status!=="SUCCESS"&&(r.message=t.message))}async function Hz(r,e,t,n){await Promise.allSettled(r),t&&(e.beforeSnapshot=t.beforeSnapshot),n&&(e.afterSnapshot=n.afterSnapshot)}import{randomUUID as Qz}from"crypto";import{faker as Gz}from"@faker-js/faker";import jz from"assert";import Vz from"axios";import*as $z from"child_process";import Wz from"moment";import*as qz from"otpauth";import Kz from"pg";async function vw(r){let e;try{e=new URL(r.url).hostname}catch{}let t=[];return r.headers.getSetCookie()?.forEach(n=>{let o=hu(n,e);t.push(...o)}),t}function Yz(r,e){if(!r&&!e)return;let t;if(r){let{url:o,options:i}=r;t=new Request(o,i)}let n;if(e){let{body:o,options:i}=e;n=new Response(o??null,i)}return{request:t,response:n}}async function Xz(r,e){switch(r){case"RAW":return e;case"RESPONSE":if(e instanceof Response){let t=[];return e.headers.forEach((o,i)=>{t.push([i,o])}),{status:e.status,headers:t,body:await e.text()}}else throw new Error("Result is not a Response object")}}var Jz=Object.getPrototypeOf(async function(){}).constructor;async function Rw(r,e,t){let n=e.code;e.options.fragment&&(n=`return ${e.code}`);let{env:o,additionalBindings:i,request:a,response:s}=e.bindings,c=e.tools,l={},u=(T,A)=>{o[T]=A,l[T]=A},d={},p=(T,A)=>{o[T]=A,d[T]=A},m;n.includes("Octokit")&&(m=(await import("@octokit/rest")).Octokit);let h;n.includes("createAppAuth")&&(h=(await import("@octokit/auth-app")).createAppAuth);let g=async()=>await Promise.resolve(new Jz("axios","moment","faker","assert","pg","Octokit","createAppAuth","OTPAuth","child_process","extractCookiesFromResponse","env","setVariable","setPersistentVariable","sendSms","waitForLatestSms","email","sms","ai","mock",...Object.keys(i??{}),n)(Vz,Wz,c.fakerInstance??Gz,jz,Kz,m,h,qz,$z,vw,o,e.options.disallowVariableUpdates?void 0:u,e.options.disallowVariableUpdates?void 0:p,A=>c.sms.send(A),A=>c.sms.fetchLatest(A),c.email,c.sms,c.ai,Yz(a,s),...Object.values(i??{}))),f=!0,y,S;try{let T=await $(g(),{milliseconds:e.options.timeoutMs,message:`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`,signal:e.signal});y=await Xz(e.options.responseSerialization??"RAW",T)}catch(T){t.error({err:T,env:o,evalCode:n},`[${r}] Error executing code: ${T}`),f=!1,T instanceof Oo?S=`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`:S=T instanceof Error?T.message:`${T}`}return{result:y,variableUpdates:l,persistentVariableUpdates:d,success:f,error:S}}async function Aw({code:r,fragment:e,context:t,localTools:n,logger:o,signal:i,timeoutMs:a=_o,disallowVariableUpdates:s,additionalBindings:c,responseSerialization:l,mock:u}){let d=Qz(),p=await Rw(d,{code:r,options:{fragment:e,timeoutMs:a,disallowVariableUpdates:s,responseSerialization:l},bindings:{...t.toObjectCopy(),...u,additionalBindings:c},tools:n,signal:i},o);return E.debug(`[${d}] Got execution result: ${JSON.stringify(p)}`),p}import{createHmac as Zz,randomUUID as eH}from"crypto";import tH from"fetch-retry";var rH=tH(global.fetch,{retries:3,retryOn:function(r,e,t){return!!(e!==null||t&&t.status>=500)},retryDelay:function(r){return Math.pow(2,r)*500}}),ww=process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT,Cw=process.env.MOMENTIC_LAMBDA_AUTH_SECRET;async function xw({orgId:r,code:e,fragment:t,context:n,timeoutMs:o=_o,retries:i=2,signal:a,logger:s,additionalBindings:c,disallowVariableUpdates:l,responseSerialization:u,mock:d}){if(!ww)throw new Error("GCP_JS_EVAL_FUNCTION_ENDPOINT environment variable not set");let p,m,h=0;if(!Cw)throw new Error("Missing lambda auth secret.");let g=Zz("sha256",Cw).update(r).digest("hex");for(;h<=i;){h++,a?.throwIfAborted();let y={id:eH(),orgId:r,momenticLambdaAuthHash:g,code:e,fragment:t,state:{...n.toObjectCopy(),...d,additionalBindings:c},timeoutMs:o,disallowVariableUpdates:l,responseSerialization:u};try{if(p=await $(rH(ww,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(y)}),{milliseconds:o,message:`Timeout of ${o}ms exceeded for code execution`,signal:a}),!p)throw new Error("Got empty response from code evaluation server");if(!p.ok)throw new Error(`Code evaluation server returned error code ${p.status}`);m=void 0;break}catch(S){m=S}}if(m)throw s.error({err:m},"Failed to evaluate code remotely"),m;if(!p)throw new Error(`An unexpected code evaluation error occurred${m?`: ${m}`:""}`);let f;try{f=zb.parse(await p.json())}catch(y){throw new Error(`Code evaluation server returned invalid response: ${y}`)}if(f.error)throw new Error(`Code evaluation error: ${f.error}`);return f}async function zo(r){let e;if(process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT)e=await xw(r);else if(r.localTools)e=await Aw({...r,localTools:r.localTools});else throw new Error("No code evaluation environment available");if(e.error){let t=`Failed to evaluate code:
|
|
47
|
+
`).map(t=>t.trim()).filter(t=>t.length>0):[]}function Pz(r,e){let t=r.attemptIdToAttemptNumber.get(e);if(t)return Gt.join(r.inflatedPath,"attempts",t);let n=Gt.join(r.inflatedPath,"attempts");if(!Ot.existsSync(n))return;let o=Ot.readdirSync(n,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of o){let a=Gt.join(n,i,"metadata.json"),s=fw(a);if(typeof s!="object"||s===null)continue;let c=s.id;if(typeof c=="string"&&c===e)return r.attemptIdToAttemptNumber.set(e,i),Gt.join(n,i)}}function hw(r,e,t){let n=Gt.join(r,"attempts");if(!Ot.existsSync(n))return;let o=Ot.readdirSync(n,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of o){let a=Gt.join(n,i,"assets",`${e}.${t}`);if(Ot.existsSync(a))return a}}var bd=class{constructor(e,t,n){this.outputDir=e;this.runId=t;this.runAttemptId=n;this.runsDir=Gt.join(e,"runs"),this.zipPath=Gt.join(this.runsDir,`${t}.zip`)}inflatedByRunId=new Map;zipPath;runsDir;ensureInflatedRun(e){let t=this.inflatedByRunId.get(e);if(t)return t;if(e!==this.runId||!Ot.existsSync(this.zipPath))return;let n=Gt.join(this.runsDir,`temp-unzipped-${e}-${Iz()}`);Ot.mkdirSync(n,{recursive:!0}),new Mz(this.zipPath).extractAllTo(n,!0);let i={runId:e,zipPath:this.zipPath,inflatedPath:n,attemptIdToAttemptNumber:new Map};return this.inflatedByRunId.set(e,i),i}close(){for(let e of this.inflatedByRunId.values())Ot.rmSync(e.inflatedPath,{recursive:!0,force:!0});this.inflatedByRunId.clear()}getAttemptDir(){let e=this.ensureInflatedRun(this.runId);if(e)return Pz(e,this.runAttemptId)}listVideoAssetPaths(){let e=this.getAttemptDir();if(!e)return[];let t=Gt.join(e,"assets");return Ot.existsSync(t)?Ot.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isFile()).map(o=>Gt.join(t,o.name)).filter(o=>{let i=Gt.extname(o).toLowerCase();return i===".webm"||i===".mp4"}):[]}readAttemptAssetText(e,t){let n=this.getAttemptDir();if(!n)return;let o=Gt.join(n,"assets",`${e}.${t}`);if(Ot.existsSync(o))try{return Ot.readFileSync(o,"utf-8")}catch{return}}async getConsoleLogsForRunAttempt(e,t,n){if(t!==this.runId||n!==this.runAttemptId)return;let o=this.getAttemptDir();if(!o)return;let i=fw(Gt.join(o,"console.json")),a=Vh.safeParse(i);return a.success?a.data:void 0}async getNetworkLogsForRunAttempt(e,t,n){if(t!==this.runId||n!==this.runAttemptId)return;let o=this.getAttemptDir();if(!o)return;let i=Gt.join(o,"assets","har-pages.log"),a=Gt.join(o,"assets","har-entries.log"),s={};for(let u of mw(i)){let d=ml.safeParse(gw(u));d.success&&(s[d.data.id]=d.data)}let c={},l=mw(a);for(let u=0;u<l.length;u++){let d=l[u],p=hl.safeParse(gw(d));if(!p.success)continue;let m=`${p.data.startedDateTime}-${u}`;c[m]=p.data}if(Object.keys(c).length!==0)return Wh(s,c)}async getHtmlSnapshot(e,t){let n=this.readAttemptAssetText(t,"html");if(n)return n;let o=this.ensureInflatedRun(this.runId);if(!o)return;let i=hw(o.inflatedPath,t,"html");if(i)try{return Ot.readFileSync(i,"utf-8")}catch{return}}async getA11yTreeSnapshot(e,t){let n=this.readAttemptAssetText(t,"xml");if(n)return n;let o=this.ensureInflatedRun(this.runId);if(!o)return;let i=hw(o.inflatedPath,t,"xml");if(i)try{return Ot.readFileSync(i,"utf-8")}catch{return}}async getScreenshot(e,t){if(!this.ensureInflatedRun(this.runId))return;let o=this.getAttemptDir(),i=o?Gt.join(o,"assets",`${t}.jpeg`):void 0;if(i)try{return Ot.readFileSync(i)}catch{return}}};function gw(r){try{return JSON.parse(r)}catch{return}}import{hostname as Oz}from"os";var Lz="2.28.7",kl=Na({app:"desktop-server",hostname:Oz(),disableConsoleLogs:!0}).child({cliVersion:Lz});(async()=>{try{let r=await no(kl);r.gitBranchName&&kl.addBinding("branch",r.gitBranchName)}catch{}})();var Sw=Nz();Sw.get("/",async(r,e)=>{let t=se(),n=jA();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Hr(kl,n,t);e.status(200).json(o)});var ef=Sw;import LK from"events";import lO,{Router as NK}from"express";import DK from"http";import kK from"path";import{Server as JW}from"socket.io";var Dz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async()=>{e.info({sessionId:n},"Cancel event received");let o=t.getSession(n);if(!o)throw new Error("No active session found");try{o.controller.setClosed()}catch{}}},yw={event:"cancel",createHandler:Dz};var kz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async(o,i)=>{let a=t.getSession(n);if(!a)throw new Error("No active session found");a.controller.setOpen();let s=a.controller.browser;try{let l=(await s.getBrowserState({skipWait:!0})).serialize();e.debug({a11yTree:l},"Fetched a11y tree from the browser"),i({a11yTree:l})}catch(c){e.error({err:c},"Error fetching a11y tree from the browser"),i({err:c.message})}}},Ew={event:"fetchA11yTree",createHandler:kz};var Fz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async(o,i)=>{let a=t.getSession(n);if(!a)throw new Error("No active session found");a.controller.setOpen();let s=a.controller.browser;try{let c=await s.html();i({html:c})}catch(c){e.error({err:c},"Error fetching DOM from the browser"),c.name==="TimeoutError"?i({err:"Timed out fetching DOM tree. This page may be too large for Momentic to process."}):i({err:c.message})}}},Tw={event:"fetchDom",createHandler:Fz};var Uz=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return o=>{e.info({sessionId:n,reason:o},`Disconnect event received (${o})`),t.removeSession(n,e)}},bw={event:"disconnect",createHandler:Uz};function un(r){let{result:e,nestedResults:t}=r;if(!r.nestedResults.length)return;let{firstMetadata:n,lastMetadata:o}=Bz(t);zz(e,n,o);let i=[...r.asyncTasks];r.asyncTasks.push((async()=>{try{await Hz(i,e,n,o)}catch(a){r.logger.error({result:r.result,err:a},"Error hoisting scalar result metadata")}})())}function Bz(r){let e=r[0],t;for(;;){switch(e.type){case"PRESET_ACTION":{t=e;break}case"CONDITIONAL":t=r[0];break;case"AI_ACTION_DYNAMIC":case"AI_ACTION":case"MODULE":case"SECTION":if(!e.results.length){t=e;break}e=e.results[0];break;default:return(a=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}if(t)break}let n=r[r.length-1],o;for(;;){switch(n.type){case"PRESET_ACTION":{o=n;break}case"AI_ACTION_DYNAMIC":case"CONDITIONAL":case"AI_ACTION":case"MODULE":case"SECTION":if(!n.results.length){o=n;break}n=n.results[n.results.length-1];break;default:return(a=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(n)}if(o)break}return{firstMetadata:t,lastMetadata:o}}function zz(r,e,t){e&&(r.beforeUrl=e.beforeUrl),t&&(r.afterUrl=t.afterUrl,r.data=t.data,t.status!=="SUCCESS"&&(r.message=t.message))}async function Hz(r,e,t,n){await Promise.allSettled(r),t&&(e.beforeSnapshot=t.beforeSnapshot),n&&(e.afterSnapshot=n.afterSnapshot)}import{randomUUID as Qz}from"crypto";import{faker as Gz}from"@faker-js/faker";import jz from"assert";import Vz from"axios";import*as $z from"child_process";import Wz from"moment";import*as qz from"otpauth";import Kz from"pg";async function vw(r){let e;try{e=new URL(r.url).hostname}catch{}let t=[];return r.headers.getSetCookie()?.forEach(n=>{let o=hu(n,e);t.push(...o)}),t}function Yz(r,e){if(!r&&!e)return;let t;if(r){let{url:o,options:i}=r;t=new Request(o,i)}let n;if(e){let{body:o,options:i}=e;n=new Response(o??null,i)}return{request:t,response:n}}async function Xz(r,e){switch(r){case"RAW":return e;case"RESPONSE":if(e instanceof Response){let t=[];return e.headers.forEach((o,i)=>{t.push([i,o])}),{status:e.status,headers:t,body:await e.text()}}else throw new Error("Result is not a Response object")}}var Jz=Object.getPrototypeOf(async function(){}).constructor;async function Rw(r,e,t){let n=e.code;e.options.fragment&&(n=`return ${e.code}`);let{env:o,additionalBindings:i,request:a,response:s}=e.bindings,c=e.tools,l={},u=(T,A)=>{o[T]=A,l[T]=A},d={},p=(T,A)=>{o[T]=A,d[T]=A},m;n.includes("Octokit")&&(m=(await import("@octokit/rest")).Octokit);let h;n.includes("createAppAuth")&&(h=(await import("@octokit/auth-app")).createAppAuth);let g=async()=>await Promise.resolve(new Jz("axios","moment","faker","assert","pg","Octokit","createAppAuth","OTPAuth","child_process","extractCookiesFromResponse","env","setVariable","setPersistentVariable","sendSms","waitForLatestSms","email","sms","ai","mock",...Object.keys(i??{}),n)(Vz,Wz,c.fakerInstance??Gz,jz,Kz,m,h,qz,$z,vw,o,e.options.disallowVariableUpdates?void 0:u,e.options.disallowVariableUpdates?void 0:p,A=>c.sms.send(A),A=>c.sms.fetchLatest(A),c.email,c.sms,c.ai,Yz(a,s),...Object.values(i??{}))),f=!0,y,S;try{let T=await $(g(),{milliseconds:e.options.timeoutMs,message:`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`,signal:e.signal});y=await Xz(e.options.responseSerialization??"RAW",T)}catch(T){t.error({err:T,env:o,evalCode:n},`[${r}] Error executing code: ${T}`),f=!1,T instanceof Oo?S=`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`:S=T instanceof Error?T.message:`${T}`}return{result:y,variableUpdates:l,persistentVariableUpdates:d,success:f,error:S}}async function Aw({code:r,fragment:e,context:t,localTools:n,logger:o,signal:i,timeoutMs:a=_o,disallowVariableUpdates:s,additionalBindings:c,responseSerialization:l,mock:u}){let d=Qz(),p=await Rw(d,{code:r,options:{fragment:e,timeoutMs:a,disallowVariableUpdates:s,responseSerialization:l},bindings:{...t.toObjectCopy(),...u,additionalBindings:c},tools:n,signal:i},o);return E.debug(`[${d}] Got execution result: ${JSON.stringify(p)}`),p}import{createHmac as Zz,randomUUID as eH}from"crypto";import tH from"fetch-retry";var rH=tH(global.fetch,{retries:3,retryOn:function(r,e,t){return!!(e!==null||t&&t.status>=500)},retryDelay:function(r){return Math.pow(2,r)*500}}),ww=process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT,Cw=process.env.MOMENTIC_LAMBDA_AUTH_SECRET;async function xw({orgId:r,code:e,fragment:t,context:n,timeoutMs:o=_o,retries:i=2,signal:a,logger:s,additionalBindings:c,disallowVariableUpdates:l,responseSerialization:u,mock:d}){if(!ww)throw new Error("GCP_JS_EVAL_FUNCTION_ENDPOINT environment variable not set");let p,m,h=0;if(!Cw)throw new Error("Missing lambda auth secret.");let g=Zz("sha256",Cw).update(r).digest("hex");for(;h<=i;){h++,a?.throwIfAborted();let y={id:eH(),orgId:r,momenticLambdaAuthHash:g,code:e,fragment:t,state:{...n.toObjectCopy(),...d,additionalBindings:c},timeoutMs:o,disallowVariableUpdates:l,responseSerialization:u};try{if(p=await $(rH(ww,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(y)}),{milliseconds:o,message:`Timeout of ${o}ms exceeded for code execution`,signal:a}),!p)throw new Error("Got empty response from code evaluation server");if(!p.ok)throw new Error(`Code evaluation server returned error code ${p.status}`);m=void 0;break}catch(S){m=S}}if(m)throw s.error({err:m},"Failed to evaluate code remotely"),m;if(!p)throw new Error(`An unexpected code evaluation error occurred${m?`: ${m}`:""}`);let f;try{f=zb.parse(await p.json())}catch(y){throw new Error(`Code evaluation server returned invalid response: ${y}`)}if(f.error)throw new Error(`Code evaluation error: ${f.error}`);return f}async function zo(r){let e;if(process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT)e=await xw(r);else if(r.localTools)e=await Aw({...r,localTools:r.localTools});else throw new Error("No code evaluation environment available");if(e.error){let t=`Failed to evaluate code:
|
|
48
48
|
${e.error}
|
|
49
49
|
Code received:
|
|
50
50
|
${r.code}`;throw r.logger.error({err:e.error,code:r.code,env:r.context.toObjectCopy()},t),new Error(t)}if(e.variableUpdates)for(let[t,n]of Object.entries(e.variableUpdates))r.context.setVariable(t,n);if(e.persistentVariableUpdates&&Object.keys(e.persistentVariableUpdates).length>0){await r.callbacks?.onPersistentVariableUpdates?.(e.persistentVariableUpdates);for(let[t,n]of Object.entries(e.persistentVariableUpdates))r.context.setVariable(t,n)}return e.result}import{set as nH}from"lodash-es";async function dr(r){let{orgId:e,s:t,context:n,logger:o,signal:i,retries:a=2,timeoutMs:s=_o,allowUndefined:c=!1}=r,l=/{{(.*?)}}/g,u=t.matchAll(l),d=t;for(let p of u){if(p.length<2)continue;let m=p[1].trim(),h;try{h=await zo({orgId:e,code:m,fragment:!0,context:n,timeoutMs:s,logger:o,retries:a,localTools:r.localTools,signal:i})}catch(f){throw o.error({err:f,value:t},"Error evaluating template string"),f}if(h===void 0&&!c)throw new M("UserConfigurationError",`Template fragment '${m}' evaluated to undefined. Please ensure that the variable name is spelled correctly and it is only referenced after being assigned a value.`);let g=typeof h=="string"?h:`${h}`;g=g.replaceAll(/\$/g,"$$$$"),d=d.replace(p[0],g)}return d}async function vd(r){return _w(r)}async function _w({obj:r,bannedKeys:e,allowList:t,context:n,prefixPath:o=[],replacements:i=[],...a}){for(let s in r){if(e.includes(s))continue;let c=!1;if(t)if(t.includes(s))c=!0;else continue;let l=r[s],u=[...o,s];if(typeof l=="string"&&l.includes("{{")){let d=await dr({s:l,context:n,...a});if(l===d)continue;i.push({path:u,original:l}),r[s]=d}else typeof l=="object"&&l!==null&&!Array.isArray(l)&&await _w({obj:l,bannedKeys:e,context:n,prefixPath:u,replacements:i,allowList:c?void 0:t,...a})}return i}function Mw(r,e){for(let{path:t,original:n}of e)nH(r,t,n)}import oH from"fetch-retry";var Qbe=process.env.MAILINATOR_API_KEY,Zbe=oH(global.fetch,{retryOn:function(r,e,t){return r>3?!1:!!(e!==null||t&&t.status>=400)},retryDelay:function(r){return 500}});import{hostname as pH}from"os";import{cloneDeep as Pw}from"lodash-es";async function Ow(r){let{command:e,timeoutMs:t,fixtures:n}=r,{abortSignal:o}=n,i=()=>Vy(e.cache)?e.cache:void 0,a=i(),s=Pw(a),c=(g=!1)=>{if(a=i(),!!a)if(g){let f=xg(s,a);a.target=f.target,a.updatedAt=f.updatedAt}else{if(!s){a=void 0;return}a.target=s.target,a.updatedAt=s.updatedAt}},l=Date.now(),u=0,d,p=500,m=!1;for(;u<2||Date.now()-l<t;){u++,u>1&&await ie(p,o),o?.throwIfAborted(),a=i();let{result:g,elementWasFound:f}=await Iw({cacheToUse:a,params:r});if(d=g,m=f,g.success)break;c(),p=Math.min(p*2,1e4)}if(!d)throw new M("InternalPlatformError",`Failed to evaluate manual element assertion in ${t}ms.`);if(o?.throwIfAborted(),!d.success&&a?.target&&Mc(a.target)){let g=a?.target?.memory?{target:{id:-1,memory:a.target.memory}}:void 0,{result:f}=await Iw({cacheToUse:g,params:r});d=f,d.success||c(!0)}let h=i();return d.success&&h?.target&&!m&&(h.target=Al(h.target),h.updatedAt=new Date),d}async function Iw({cacheToUse:r,params:e}){let{command:t,disableCache:n,fixtures:o,tracer:i,targetingWrapper:a}=e,{logger:s}=o;if(t.target&&!So(t.target))throw new Error("Element assertion with x/y is not supported yet");let c=DR(t.assertion),l,u=!1,d=Pw(r);try{let{elementInteractedDisplayString:p,result:m,thoughts:h}=await a({ctx:o.ctx,tracer:i,command:t,target:t.target,cache:d?.target,action:async g=>iH(g.locator,e),options:{...t,allowNotActionableNodesOverride:!0,disableCache:n,memory:d?.target?.memory,disableGlobalLocatorRedirect:!0,source:gi(t),targetName:"target"}});return l={success:m.success,data:m.data,err:m.err,elementInteractedDisplayString:p,thoughts:h},u=!0,m.success||(s.warn({aiThoughts:h,elementString:p,err:m.err},"Element check found an element but failed"),l={...m,thoughts:h}),{result:l,elementWasFound:u}}catch(p){if(c)return l={success:!0,thoughts:`The element described does not exist on the page: ${p.message}`,err:void 0,data:void 0},{result:l,elementWasFound:u};if(!(p instanceof M)||p.reason!="ActionFailureError")throw p;return l={success:!1,err:p,data:void 0,thoughts:void 0},s.warn({err:p},"Element check did not find an element and failed"),{result:l,elementWasFound:u}}}async function iH(r,{command:e,fixtures:t}){return await t.browser.highlight(r),await aH(r,e.assertion)}async function aH(r,e){let t=!0,n,o;switch(e.type){case"ELEMENT_CONTENT":{let a=await r.textContent()??"";if(o={elementTextContent:tt(a,500,!0)},!Rl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!1})){let s=Ua(e);t=!1,n=new M("AssertionFailureError",`The content ${s} '${e.value}': ${a}`)}break}case"ELEMENT_ATTRIBUTE":{o={elementOuterHtml:tt(await r.evaluate(s=>s.cloneNode(!1).outerHTML),500,!0)};let a;try{a=await r.getAttribute(e.attr,{timeout:3e3})??""}catch(s){n=new M("AssertionFailureError",`The element does not have an attribute named ${e.attr}: ${s}`),t=!1;break}if(!Rl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!1})){let s=Ua(e);t=!1,e.operation==="EXISTS"?n=new M("AssertionFailureError",`The attribute ${e.attr} ${s}`):n=new M("AssertionFailureError",`The attribute ${e.attr} ${s} '${e.value}': ${a}`)}break}case"ELEMENT_EXISTENCE":{switch(e.condition){case"VISIBLE":{t=await r.evaluate(async(s,c)=>{let l=Date.now();for(;Date.now()-l<c;){await new Promise(d=>setTimeout(d,250));let u=s.getBoundingClientRect();if(!(u.width===0||u.height===0)&&window.getComputedStyle(s).visibility!=="hidden"&&window.getComputedStyle(s).display!=="none")return!0}return!1},yn*1e3);break}case"EDITABLE":{t=await r.isEditable({timeout:yn*1e3});break}case"EXISTS":{t=!0;break}case"ENABLED":{t=await r.isEnabled({timeout:yn*1e3});break}case"FOCUSED":{t=await r.evaluate(s=>s===document.activeElement);break}default:return(s=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e.condition)}if(t=e.negated?!t:t,!t){let a=Ua(e);n=new M("AssertionFailureError",`The element ${a}`)}break}case"ELEMENT_NAME":{let a=await r.evaluate(s=>s.tagName);if(!Rl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!0})){let s=Ua(e);t=!1,n=new M("AssertionFailureError",`The element tag name ${s} '${e.value}': ${a}`)}break}case"ELEMENT_STYLE":{let a=await r.evaluate((s,c)=>window.getComputedStyle(s).getPropertyValue(c),e.property);if(!Rl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!1})){let s=Ua(e);t=!1,e.operation==="EXISTS"?n=new M("AssertionFailureError",`The style property ${e.property} ${s}`):n=new M("AssertionFailureError",`The style property ${e.property} ${s} '${e.value}': ${a}`)}break}default:return(a=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(e)}return{thoughts:void 0,success:t,data:o,err:n}}function Lw(r){return r.type==="ELEMENT_EXISTENCE"&&r.negated&&r.condition==="EXISTS"}import{Jimp as sH}from"jimp";async function Fl(r,e){let t=await r.screenshot(e),n=await sH.fromBuffer(t);return{buffer:t,width:Math.ceil(n.bitmap.width??0),height:Math.ceil(n.bitmap.height??0)}}import{Jimp as Nw}from"jimp";import tf from"jpeg-js";import lH from"pixelmatch";async function Dw({ctx:r,tracer:e,command:t,disableCache:n,browser:o,targetingWrapper:i,logger:a,screenshotStorage:s}){if(t.target&&!So(t.target))throw new Error("Visual Diff with x/y is not supported yet");await o.waitForDOMStability({logger:a});let c={clearHighlights:!0,hideCaret:!0},l;t.target?.elementDescriptor?l=(await i({ctx:r,tracer:e,command:t,target:t.target,cache:t.cache?.target,action:async B=>Fl(o,{locator:B.locator,...c}),options:{...t,disableCache:n,disableGlobalLocatorRedirect:!0,memory:t.cache?.target?.memory,targetName:"target"}})).result:l=await Fl(o,c);let u=await s.prepareGoldenScreenshotForComparison(a,t,l);if((l.height!==u.height||l.width!==u.width)&&a.warn({currHeight:l.height,currWidth:l.width,savedHeight:u.height,savedWidth:u.width},"Mismatched before and after visual diff screenshot sizes"),Math.abs(l.height-u.height)>10||Math.abs(l.width-u.width)>10){let z=`${l.width}x${l.height}`,B=`${u.width}x${u.height}`;return{fail:!0,thoughts:`Current screenshot (${z}) does not match saved screenshot dimensions (${B}) - did you change the size of the target or the viewport?`,beforeScreenshotOverride:u.buffer,afterScreenshotOverride:l.buffer,succeedImmediately:!1,urlAfterCommand:o.url()}}let d=await Nw.fromBuffer(l.buffer),p={width:l.width,height:l.height},m=await Nw.fromBuffer(u.buffer),h={width:u.width,height:u.height},g,f=p.width*p.height,y=h.width*h.height,S=Math.abs(p.height-h.height),T=Math.abs(p.width-h.width);if(f>y){let z=d.cover({w:h.width,h:h.height});l.buffer=await z.getBuffer("image/jpeg"),g="current",l.width=h.width,l.height=h.height}else if(y>f){let z=m.cover({w:p.width,h:p.height});u.buffer=await z.getBuffer("image/jpeg"),g="saved"}let A={data:Buffer.alloc(l.width*l.height*4),width:l.width,height:l.height},v=t.threshold??.1,x=lH(tf.decode(u.buffer).data,tf.decode(l.buffer).data,A.data,l.width,l.height,{threshold:v,diffColorAlt:[0,255,0]})/(l.width*l.height)*100,_=x>v*100,D=`Visual diff of ${x.toFixed(2)}% detected, which is ${_?"over":"under"} the threshold of ${v*100}%.`;if(g&&(D+=` The ${g} screenshot was cropped since it was taller by ${S} pixels and wider by ${T} pixels.`),_)throw new M("ActionFailureError",D);return{fail:_,thoughts:D,beforeScreenshotOverride:l.buffer,afterScreenshotOverride:tf.encode(A,75).data,succeedImmediately:!1,urlAfterCommand:o.url()}}var cH=3e4;function uH(r){if(!r.body)return{};switch(r.body.type){case"json":return{content:r.body.content,contentType:"application/json"};case"form-urlencoded":{let e=new URLSearchParams;return Object.entries(r.body.content).forEach(([t,n])=>{e.append(t,n)}),{content:e.toString(),contentType:"application/x-www-form-urlencoded;charset=UTF-8"}}}}async function kw({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??cH/1e3,i=Object.fromEntries(Object.entries(r.headers||{}).filter(([h,g])=>h&&g)),a=new URLSearchParams;Object.entries(r.params||{}).filter(([h,g])=>h&&g).forEach(([h,g])=>{a.append(h,g)});let s=a.toString(),c;if(Va(r.url)&&(c=r.url),t&&$a(r.url,t)&&(c=new URL(r.url,t).toString()),!c)throw new M("ActionFailureError",`Invalid URL: ${r.url}`);let l=c;e.info({url:l,searchParams:s,headers:i,body:r.body,method:r.method},"Making HTTP request");let d=await $((async()=>{let h=s?`${l}?${s}`:l;try{let g=uH(r),f=new Headers(i);return g.contentType&&!f.has("Content-Type")&&f.set("Content-Type",g.contentType),await n(h,{headers:f,method:r.method,body:g.content})}catch(g){throw e.error({err:g},"Failed to make HTTP request"),new Error(`Failed to make HTTP request: ${g}`)}})(),{milliseconds:o*1e3,fallback:()=>{throw new M("ActionFailureError",`Fetch request timed out after ${o} seconds`)}});if(!d.ok){let h;try{h=await d.text()}catch(g){h=`Failed to read response body: ${g}`}throw new M("ActionFailureError",`Fetch request failed with status ${d.status}: ${h}`)}let p={};d.headers.forEach((h,g)=>{p[g]=h});let m={status:d.status,headers:p,request:{url:d.url,method:r.method,headers:i}};if(r.body?.type==="json"&&r.body.content)try{m.request.json=JSON.parse(r.body.content)}catch{}if(d.headers.get("content-type")?.includes("json"))try{m.json=await d.json()}catch{}else d.headers.get("content-type")?.includes("text")&&(m.text=await d.text());return m}var dH=5e3;async function Rd({timeout:r=yn,...e}){let t=Date.now(),n=r*1e3,o=n+1e4,i,a=0,s=500;for(;a-t<n;){if(Date.now()-t>o){e.logger.warn("Exceeded max system timeout for page assertion, exiting...");break}e.signal?.throwIfAborted();let c=Date.now();i=await Fw(e),a=Date.now();let l=a-c;if(l>1e3&&e.logger.warn({pageAssertDuration:l},"Page assertion took longer than expected"),!i.success)await ie(s,e.signal),s=Math.min(Math.floor(s*1.5),dH);else return i}return i=await Fw(e),i}async function Fw({assertion:r,browser:e,autoExpandIframes:t}){switch(r.type){case"CONTENT":case"CONTENT":{let o,i=!1,a;try{let s;if(t){let c=await e.evaluateFunctionInAllFrames(Uw,{value:r.value,negated:!!r.negated,returnHtml:!1});i=r.negated?c.every(l=>l.evaluation):c.some(l=>l.evaluation),s=c.find(l=>l.pageHtml)?.pageHtml}else({evaluation:i,pageHtml:s}=await e.evaluateFunctionInPage(Uw,{value:r.value,negated:!!r.negated,returnHtml:!0},"checking page content"));if(!i){let c=r.negated?Jn.CONTAINS:Qn.CONTAINS;a=new M("AssertionFailureError",`The page ${c} '${r.value}'.`),o=s}}catch(s){a=new M("AssertionFailureError",`Failed to evaluate page content assertion: ${s instanceof Error?s.message:`${s}`}`)}return{success:i,err:a,data:i||!o?void 0:{pageContent:o}}}default:return(o=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r)}}function Uw({value:r,negated:e,returnHtml:t}){let n=document.documentElement.outerHTML,o=n.includes(r)===!e;return n.length>1e4&&(n=n.slice(0,1e4)+"...TRUNCATED"),{evaluation:o,pageHtml:!o&&t?n:void 0}}var rf=async r=>{let{step:e,resolvedInputs:t}=r.moduleParams,{logger:n,context:o,storage:i,codeEvalTools:a,controller:s}=r.fixtures,c=s.browser,{orgId:l,runId:u}=r.inputs,d=s.executeAbortController.signal;Object.keys(t).length>0&&(o.setInputs(t),n.info(ja({json:{inputs:t,moduleId:e.moduleId},maxJsonStringSize:1e3}),"Set module inputs"));let p,m=!1,h,g;if(e.cacheConfig||e.defaultCacheAllInvocations){let f=e.cacheConfig?.cacheKey||e.defaultCacheKey||"",y=await dr({orgId:l,s:f,context:o,logger:n,localTools:a,signal:d});g={orgId:l,cacheKeys:[y,...Object.entries(t).map(([T,A])=>`${T}:${A}`)]},n.info({original:f,keyParams:g},"Module cache key params");let S=Date.now();for(;Date.now()-S<pv;){d?.throwIfAborted();let T=await i.getCacheResult(g);if(T){n.info({cacheResult:tt(T,1e3,!0)},"Got result from module execution cache"),p=Ad(e,t,"SUCCESS"),p.message="Used cached module result.",p.data=JSON.parse(T),m=!0;break}else n.info({cacheKey:f,keyParams:g},"No cache result found, continuing with lock acquisition");let A=await i.acquireCacheLock({keyParams:g,clientMetadata:`hostName:${pH()};runId:${u}`},d);if(A.acquired){h=A.keyPrefix,n.info({cacheKeyPrefixIfLockAcquired:h,cacheKey:f,keyParams:g},"Acquired cache lock and proceeding with module execution");break}else n.debug({cacheKeyPrefixIfLockAcquired:h,cacheKey:f,keyParams:g},"Failed to acquire cache lock, retrying...");await ie(2500+Math.random()*1e4,d)}}try{if(!p)p=await mH(r);else if(e.autoAuth){let f=gu.safeParse(p.data);if(!f.success)throw new M("UserConfigurationError",`Cached authentication module result is not a valid storage state: ${f.error.message}`);n.debug("Automatically loading auth state after cached module result"),await c.loadAuthState(f.data);let y=!1,S=e.advanced?.cacheInvalidation;if(S&&S.type==="PAGE_CHECK"){let T={type:"CONTENT",value:S.substring},A=await Rd({timeout:yn,assertion:T,browser:c,logger:n,signal:d,autoExpandIframes:!!c.userBrowserSettings.autoExpandIframes});A.success?n.debug({invalResult:A},"Cached result still valid after page check, continuing..."):(n.info({invalResult:A},"Invalidating cached result due to page check failure"),y=!0)}if(g&&y)return await i.deleteCacheResult(g),rf(r)}}finally{try{h!==void 0&&!m&&p?.status==="SUCCESS"&&await hH({step:e,result:p,browser:s.browser,cacheKeyPrefix:h,logger:n,storage:i})}finally{h!==void 0&&await i.releaseCacheLock(h)}}return p},mH=async r=>{let{step:e,tracer:t}=r.moduleParams,n=Ad(e,r.moduleParams.resolvedInputs,"SUCCESS"),o=await t.startSubSteps(),{status:i,results:a}=await r.executeStepList({...r,listParams:{steps:e.steps,containerName:`module ('${e.name}')`,tracer:o}});return n.results=a,n.status=i,n.finishedAt=new Date,un({asyncTasks:r.work.asyncTasks,nestedResults:a,result:n,logger:r.fixtures.logger}),n};function Ad(r,e,t){let n={};return Object.entries(e).forEach(([i,a])=>{n[i]=JSON.stringify(a)}),{type:"MODULE",id:r.id,moduleId:r.moduleId,moduleName:r.name,startedAt:new Date,cacheConfig:r.cacheConfig,inputs:n,results:[],finishedAt:new Date,status:t}}async function Bw({orgId:r,step:e,context:t,logger:n,codeEvalTools:o,signal:i}){let a={};try{for(let s of e.parameters??[]){let c=e.inputs?.[s]??e.defaultParameters?.[s];if(!c){n.warn(`No value or default found for parameter '${s}' that is required by module '${e.name}'`);continue}a[s]=await zo({orgId:r,code:c,fragment:!0,context:t,logger:n,localTools:o,signal:i})}return a}catch(s){throw i?.throwIfAborted(),new M("UserConfigurationError",`Failed to evaluate module inputs: ${s}`)}}async function hH({step:r,result:e,browser:t,cacheKeyPrefix:n,logger:o,storage:i}){let a=r.cacheConfig?.cacheExpiryMs;(!a||a===tR)&&(a=r.defaultCacheTtl??rR);let s;r.autoAuth?s=JSON.stringify(await t.saveAuthState()):e.data!==void 0?s=JSON.stringify(e.data):s='""',o.debug({cacheKeyPrefix:n,ttlMs:a,truncatedCacheResultJson:ja({json:s,maxJsonStringSize:1e4})},"Setting module cache result"),await i.setCacheResult({result:s,keyPrefix:n,ttlMs:a})}async function Di(r,e,t){return gH(r,e,t)}async function gH(r,e,t){let n=new Date;try{return t.throwIfAborted(),await e()}catch(o){let i=new Date,a="FAILED",s;if(t.aborted||o instanceof DOMException&&o.name==="AbortError"?(s="Step aborted by user.",a="CANCELLED"):o instanceof M?s=`${o}`:s=`An unexpected error occurred: ${o.message}`,r.type==="RESOLVED_MODULE"){let c=Ad(r,{},"FAILED");return c.message=s,c.startedAt=n,c.finishedAt=i,c}return{...id(r),startedAt:n,finishedAt:i,status:a,data:null,message:s,results:[]}}}async function Qa(r,e){let t=!1;try{return r&&!r.state.failureRecoveryDisabled&&(r.state.failureRecoveryDisabled=!0,t=!0),await e()}finally{r&&t&&(r.state.failureRecoveryDisabled=void 0)}}import{cloneDeep as Zj}from"lodash-es";import{randomUUID as zw}from"crypto";import{diff as fH}from"deep-object-diff";import{cloneDeep as Hw}from"lodash-es";var wd=async r=>{let{step:e,tracer:t}=r.presetParams,{logger:n,controller:o,context:i}=r.fixtures,{collectDebugData:a}=r.options,{testMetadata:s}=r.inputs,c=e.command.type,l=n.child({commandType:c,stepId:e.id,commandId:e.command.id}),u="cache"in e.command&&e.command.cache?Hw(e.command.cache):{},d=o.browser.url(),p=new Date,m,h=zw(),g=zw();if(a)try{if(m=await o.browser.screenshot({retries:1,clearHighlights:!0,quality:75}),!o.browser.userBrowserSettings.disableHtmlSnapshots){let A=await o.browser.getRawCondensedHtml();t.attachBeforeHtmlSnapshot({logger:l,snapshotId:h,html:A})}}catch(A){l.debug({err:A},"Failed to take before screenshot, continuing...")}let f,y,S,T=du();try{let A=await o.executePresetCommand(T,t,e.command,i,s?.advanced.disableAICaching??!1);A.beforeScreenshotOverride&&(m=A.beforeScreenshotOverride),S=A.afterScreenshotOverride;let v=new Date,w=o.browser.url();y={beforeUrl:d,afterUrl:w,startedAt:p,finishedAt:v,viewport:o.browser.getViewport(),status:A.fail?"FAILED":"SUCCESS",elementInteracted:A.elementInteracted},f={...e,message:A.thoughts??"Successfully executed preset action.",beforeUrl:d,afterUrl:w,finishedAt:v,startedAt:p,status:A.fail?"FAILED":"SUCCESS",data:A.data,results:[y],details:T.details},"assertion"in e.command&&(f.message=A.thoughts||"Assertion passed.")}catch(A){l.error({message:A.message,stack:A.stack},`Failed executing preset step ${Zn(e.command)}`);let v=o.browser.url(),w=new Date,x=A instanceof Error?A.message:`${A}`;y={beforeUrl:d,afterUrl:v,startedAt:p,finishedAt:w,viewport:o.browser.getViewport(),status:A instanceof DOMException&&A.name==="AbortError"?"CANCELLED":"FAILED",message:x},f={...e,startedAt:p,finishedAt:w,beforeUrl:d,afterUrl:v,status:A instanceof DOMException&&A.name==="AbortError"?"CANCELLED":"FAILED",message:x,failureReason:A instanceof M?A.reason:void 0,results:[y],details:T.details}}finally{let A="cache"in e.command&&e.command.cache?Hw(e.command.cache):{},v=fH(u,A);v&&Object.keys(v).length>0&&l.info({diffs:bu(v)},"Updated cache")}if(a)try{if(S||(S=await o.browser.screenshot({retries:1,quality:75})),!o.browser.userBrowserSettings.disableHtmlSnapshots){let A=await o.browser.getRawCondensedHtml();t.attachAfterHtmlSnapshot({logger:l,snapshotId:g,html:A})}}catch(A){l.debug({err:A},"Failed to store debug data after step, likely because the page is still loading. This is non-fatal and does not affect the test.")}return y.beforeSnapshot=h,f.beforeSnapshot=h,y.afterSnapshot=g,f.afterSnapshot=g,m&&t.attachBeforeScreenshot({logger:l,snapshotId:h,screenshot:m}),S&&t.attachAfterScreenshot({logger:l,snapshotId:g,screenshot:S}),f};async function Gw(r){let{step:e,tracer:t}=r.conditionalParams,{logger:n,controller:o}=r.fixtures,i=new Date,a=id(e),s=e.elseSteps,c=!0,l=[],u,d=du();for(let f=0;f<e.blocks.length;f++){n.info(`Evaluating condition ${f} in conditional step`);let y=e.blocks[f];try{let S=await wd({...r,presetParams:{tracer:t,step:y.assertion}});l.push(S),u=S,S.status==="SUCCESS"?(n.info(`Condition ${f} resolved to true, executing the corresponding ${y.steps.length} steps`),c=!1,s=y.steps):n.info(S.message,`Condition ${f} resolved to false`)}catch(S){n.info({err:S},`Condition ${f} resolved to false`)}finally{o.throwIfClosed()}}if(s)c&&n.info("No conditions resolved to true, executing the else block steps");else{n.warn("No conditions resolved to true and no else block was provided, causing the entire conditional step to be skipped");let f={...a,assertionResult:u,status:"SUCCESS",startedAt:i,data:l[l.length-1]?.data,message:l[l.length-1]?.message,results:[],finishedAt:new Date,details:d.details};return un({asyncTasks:r.work.asyncTasks,nestedResults:[...l],result:f,logger:n}),f}n.info(`Executing ${s.length} steps in the selected conditional block`);let p=await r.conditionalParams.tracer.startSubSteps(),m=await r.executeStepList({...r,listParams:{steps:s,containerName:"conditional block",tracer:p}}),g={...a,assertionResult:u,...m,startedAt:i,finishedAt:new Date};return un({asyncTasks:r.work.asyncTasks,nestedResults:[...l,...m.results],result:g,logger:n}),g}import{randomUUID as jw}from"crypto";var Vw=async r=>{let{tracer:e}=r.aiStepParams,{controller:t,logger:n}=r.fixtures;await t.browser.waitForDOMStability();let o=await t.browser.screenshot({}),i=await SH(r);i.finishedAt=new Date,un({asyncTasks:r.work.asyncTasks,result:i,nestedResults:i.results,logger:r.fixtures.logger});let a=await t.browser.screenshot({}),s=jw();i.beforeSnapshot=s,e.attachBeforeScreenshot({logger:n,snapshotId:s,screenshot:o});let c=jw();return i.afterSnapshot=c,e.attachAfterScreenshot({logger:n,snapshotId:c,screenshot:a}),i},SH=async r=>{let{step:e,tracer:t}=r.aiStepParams,{controller:n,context:o,logger:i}=r.fixtures,a={...e,startedAt:new Date,beforeTestContext:o.toRedactedDisplayCopy(),finishedAt:new Date,results:[],status:"SUCCESS"};if(!("steps"in e&&e.steps&&e.steps.length>0&&e.steps[e.steps.length-1]?.command.type==="SUCCESS"))throw new M("UserConfigurationError","AI action has been fully deprecated. Please delete this step and transition to Dynamic AI Action.");try{let c=await t.startSubSteps(),{status:l}=await r.executeStepList({...r,listParams:{steps:e.steps,containerName:"AI action",results:a.results,tracer:c}});return a.finishedAt=new Date,a.status=l,a}catch(c){i.warn({err:c},"Failed executing saved deprecated AI action steps");let l=n.executeAbortController.signal.aborted;a.message=c instanceof Error?c.message:`${c}`,a.status=l?"CANCELLED":"FAILED"}return a};import{randomUUID as nf}from"crypto";var $w=15,yH=7,Ww=async r=>{let{tracer:e}=r.aiStepParams,{logger:t,controller:n}=r.fixtures;await n.browser.waitForDOMStability();let o=await n.browser.screenshot({quality:75}),i=await EH(r);i.finishedAt=new Date,un({asyncTasks:r.work.asyncTasks,result:i,nestedResults:i.results,logger:r.fixtures.logger});let a=await n.browser.screenshot({quality:75}),s=nf();i.beforeSnapshot=s,e.attachBeforeScreenshot({logger:t,snapshotId:s,screenshot:o});let c=nf();return i.afterSnapshot=c,e.attachAfterScreenshot({logger:t,snapshotId:c,screenshot:a}),i},EH=async r=>{let{step:e,tracer:t}=r.aiStepParams,{testMetadata:n,orgId:o}=r.inputs,{controller:i,context:a,logger:s,codeEvalTools:c}=r.fixtures,{step:l}=r.callbacks,u=`${e.id}-${Date.now()}`,d=s.child({stepId:e.id,langfuseSessionId:u}),p={...e,startedAt:new Date,beforeTestContext:a.toRedactedDisplayCopy(),results:[],finishedAt:new Date,status:"SUCCESS"},m=await dr({orgId:o,s:e.text,context:a,logger:d,localTools:c});await i.browser.waitForDOMStability({logger:d});let g=`data:image/jpeg;base64,${(await i.browser.screenshot({clearHighlights:!0,retries:2})).toString("base64")}`,f=[],y=0,S=0,T,A;for(;;){if(y>$w)return p.message=`Exceeded the maximum number of commands allowed per AI step (${$w})`,p.status="FAILED",p;if(i.executeAbortController.signal.aborted)return p.message="Test execution was cancelled",p.status="CANCELLED",p;l.onDynamicAIActionStatusUpdateEvent?.({parentStepId:e.id,message:"Evaluating current state..."});let v=await i.evaluateAiAction({goal:m,startingScreenshot:y===0?void 0:g,history:f,logger:d,langfuseSessionId:u,lastError:A}),{evaluation:w,reasoning:x,summary:_}=v;d.info(v,"Got AI evaluation");let D=p.results[y-1]?.id;switch(w.type){case"DONE":return p.message=`Our AI evaluator confirmed all tasks are complete: ${x}`,p.status="SUCCESS",D&&l.onDynamicAIActionEvaluatingEvent?.({stepId:D,status:"SUCCESS",message:`${_}
|
|
@@ -4361,7 +4361,7 @@ Available pages:${JSON.stringify(n.map(i=>i.url))}`);if(!Ii(o.url,this.logger)){
|
|
|
4361
4361
|
`),tokenLength:d}),u=[],d=0,p=m.length?[m[m.length-1].id]:[],h=!1);let g=c[l],f=Me(g);d+=f,g.length>a&&(g=g.slice(0,a));let T=Array.from(g.matchAll(DI)).map(Q=>Q&&Q.length>=3?{tagName:Q[1],id:Q[2]}:void 0).filter(Q=>!!Q),v=Array.from(g.matchAll(cW)).map(Q=>Q&&(Q[2]||Q[4])).filter(Q=>!!Q);v.reverse();let w=g.replace(/ id="[0-9]+"/g,"");u.push(w);for(let Q of T)p.push(Q.id),m.push(Q);for(let Q of v){let K=m[m.length-1];K&&K.tagName===Q&&m.pop()}let x=m.some(Q=>dW.includes(Q.tagName)),_=c[l+1]??"",D=Me(_),B=Array.from(_.matchAll(DI)).map(Q=>Q&&Q.length>2?Q[1]:void 0).filter(Q=>!!Q),L=B.some(Q=>UI.includes(Q)),j=B.some(Q=>uW.includes(Q));d+D>=i&&(h=!0),d>=n&&(L&&!x||v.some(Q=>pW.includes(Q)))&&(h=!0),d>=o&&j&&!x&&(h=!0),l++}return u.length&&s.push({ids:p,content:u.join(`
|
|
4362
4362
|
`),tokenLength:d}),s.forEach((g,f)=>{let y=g.ids[0],S=g.ids[g.ids.length-1];r.debug({tokenLength:g.tokenLength,minId:y,maxId:S},`Chunk for page filtering (index ${f+1}/${s.length})`)}),{chunks:s}}var gW=75e4,Up=3e5;async function Ki(r){let{options:e,fixtures:t,screenshot:n}=r,{aiPageFiltering:o}=e,{logger:i,generator:a,orgId:s,signal:c}=t,l=r.tree,u=r.serializedTree,d=Me(u);if(d>gW)try{let p=Fp({serializedTree:u,options:{minChunkTokenCount:1e4,maxChunkTokenCount:1e5,acceptableChunkTokenCount:5e4,maxLineLength:4e3},logger:i});l=await SW({...r,tokenLimit:Up-1e4,chunks:p.chunks}),u=l.serialize();let m=Me(u);i.info({oldTokens:d,newTokens:m},"Filtered page using keywords"),d=m}catch(p){i.warn({err:p},"Error filtering page using keyword matching, using naive truncation"),l=l.pruneToSerializedCharLimit(Up*Po),u=l.serialize();let m=Me(u);i.info({oldTokens:d,newTokens:m},"Filtered page using naive truncation"),d=m}if(d>Up)try{if(o){let p=Fp({serializedTree:u,options:FI,logger:i}),m=hW();l=await $(fW({...r,chunks:p.chunks,callId:m}),{milliseconds:12e3,signal:c}),u=l.serialize();let h=Me(u);i.info({oldTokens:d,newTokens:h,langfuseCallId:m},"Filtered page using AI chunk ranking"),d=h}else{let p=Fp({serializedTree:u,options:kI,logger:i});l=await $(yW({...r,chunkResult:p,tokenLimit:4e4}),{milliseconds:12e3,signal:c}),u=l.serialize();let m=Me(u);i.info({oldTokens:d,newTokens:m},"Filtered page using RAG"),d=m}}catch(p){i.warn({err:p},"Error filtering page using RAG/AI, using naive truncation"),l=l.pruneToSerializedCharLimit(Up*Po),u=l.serialize(),i.info("Filtered page using naive truncation")}return u}async function fW({type:r,callId:e,chunks:t,description:n,fixtures:o,tree:i}){let{generator:a,signal:s,logger:c}=o,l=await a.rankChunksWithAi({chunks:t,description:n,type:r,softTokenLimit:4e4,hardTokenLimit:8e4,callId:e},{abortSignal:s,logger:c,loggerTags:Ge(c)}),u=[];return t.forEach((p,m)=>{l.indices.includes(m)&&(u=u.concat(p.ids))}),i.pruneUsingRelevantIds(new Set(u))}async function SW(r){let{description:e,fixtures:t,tree:n}=r,{generator:o,logger:i,signal:a}=t;if(!e.trim())throw new Error("Empty description passed to page filtering");let s=await o.getExtractedKeywords({goal:e},{logger:i,loggerTags:Ge(i),abortSignal:a});i.info({keywordsResult:s},"Got keywords for page filtering");for(let c of s.keywords){let l=r.chunks.filter(m=>m.content.toLowerCase().includes(c.toLowerCase()));if(!l.length||l.reduce((m,h)=>m+h.tokenLength,0)>r.tokenLimit&&l.length>1)continue;let d=l.flatMap(m=>m.ids);return n.pruneUsingRelevantIds(new Set(d))}throw new Error("No keywords were unique enough for page filtering")}async function yW(r){let{description:e,fixtures:t,chunkResult:n,tokenLimit:o,tree:i}=r,{generator:a,logger:s,signal:c}=t,l=await a.rankChunksWithRag({description:e,chunks:n.chunks,tokenLimit:o},{abortSignal:c,logger:s,loggerTags:Ge(s)});if(l.ids.length===0)throw new Error("RAG returned no important ids");return i.pruneUsingRelevantIds(new Set(l.ids.map(d=>`${d}`)))}async function qS(r,e){if(!r.description)throw new M("UserConfigurationError","Cannot locate element with empty description");return Wr({action:async()=>EW(r,e),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:e.browser,logger:r.logger})}async function EW(r,e){let{disableCache:t,testContext:n,filterByViewport:o,skipWait:i,source:a,memory:s,aiPageFiltering:c,logger:l,allowNotActionableNodesOverride:u}=r,{ctx:d,orgId:p,browser:m,localCodeEvalTools:h,generator:g,abortSignal:f}=e,y=r.description,S=r.useMemory&&!t;n&&(y=await dr({orgId:p,s:y,context:n,localTools:h,signal:f,logger:l})),a&&(y=bW(y,a));let{serializedTree:T,tree:A}=await Dn(m,{allowNotActionableNodesOverride:u,filterByViewport:o,abortSignal:f,skipWait:i,logger:l}),v,w=Date.now(),x;for(;!v&&Date.now()-w<3e3;){f.throwIfAborted();try{v=await m.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(q){x=q}}if(!v)throw new M("ActionFailureError",`Failed to take screenshot of page to locate element. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${x?.message}`);let _=T,D=!1,B=`data:image/jpeg;base64,${v.toString("base64")}`;_=await Ki({type:"locator",description:y,screenshot:B,serializedTree:T,options:{aiPageFiltering:c},tree:A,fixtures:{generator:g,signal:f,logger:l,orgId:p}}),_!==T&&(D=!0);let L=await g.getElementLocation({browserState:_,goal:y,screenshot:B,source:a,memory:S?s:void 0},{disableCache:t,abortSignal:f,loggerTags:Ge(l),useMemory:S});if(l.debug({usedRag:D,result:L},"Got locator result"),!(L.id>0))throw new Sa(`Could not find any relevant element: ${L.thoughts}`,L.updatedMemory?{type:"GCS_TRACES",traces:L.updatedMemory}:void 0);let{resolution:Q,target:K,frameConfig:ve}=await m.createTargetFromA11yId({id:L.id,requirements:L.requirements,additionalElements:L.additionalElements,description:y,targetSource:"AI",logger:l});if(Q.a11yNode?.properties?.hidden&&Q.a11yNode?.properties?.hidden!=="false")throw new M("ActionFailureError",`Momentic's AI found a relevant element to interact with, but it is explicitly marked with an 'aria-hidden' attribute. Please remove this attribute or adjust the element description to locate a different element. Element chosen: ${Q.displayString}`);return S&&(L.updatedMemory?K.memory={type:"GCS_TRACES",traces:L.updatedMemory}:s&&(K.memory=s)),{thoughts:L.thoughts,target:K,resolution:Q,frameConfig:ve,screenshot:B}}var TW=["Element exactly matching the description below. Interpret the description narrowly and do not assume there are any typos or errors. Err on the side of returning -1 unless there is a perfect match. Description:","Element closely matching the description below. Interpret the description narrowly and do not return elements that are merely loosely related. Description:","Element matching the description below. This element is being located as part of a negative check step (i.e. we are trying to verify the element does not exist). Therefore, interpret the description narrowly, do not assume there are typos, and err on the side of returning -1 unless there is a perfect match. Description:"],BI="<select> element:",zI="text input or contenteditable element:",HI="Element matching the description below. It is possible the element is hidden or doesn't exist. Interpret the description narrowly and do not assume there are typos. Return -1 unless there is an straightforward match. Description:",GI="Element matching the description below. This element is being located as part of a check step (i.e. we are trying to verify certain properties about the element). Interpret the description narrowly and do not return elements that are merely loosely related. Description:",WS=[BI,zI,HI,GI,...TW];function jI(r,e){if(r===e)return!0;for(let t of WS){if(!r.startsWith(t))continue;let n=r.slice(t.length).trim();if(WS.some(o=>e.startsWith(o)&&e.slice(o.length).trim()===n)||n===e.trim())return!0}return!!WS.some(t=>e.startsWith(t)&&e.slice(t.length).trim()===r.trim())}function bW(r,e){if(!r||!e)return r;switch(e){case"SELECT_OPTION":return`${BI} ${r}`;case"TYPE":return`${zI} ${r}`;case"NEGATED_ELEMENT_VISIBLE_CHECK":return`${HI}
|
|
4363
4363
|
${r}`;case"ELEMENT_CHECK":return`${GI}
|
|
4364
|
-
${r}`;default:return r}}var vW=15;async function Bp({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=vW}){if(!r.assertion.trim())throw new M("ActionFailureError","Assertion command is missing the assertion content");let{browser:s}=n,c=r.timeout?r.timeout*1e3:s.smartWaitingTimeout,l=FA(c),u=0,d=Date.now(),p,m,h;try{await Wr({action:()=>s.clearHighlights(),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:s,logger:t})}catch(f){t.warn({err:f},"Failed to clear highlights before AI check, continuing...")}let g;for(;u<a&&(!g||g-d<c);){n.abortSignal.throwIfAborted(),u!==0&&await ie(l,n.abortSignal),g=Date.now();let f=!1;try{if(p=await Wr({action:async()=>{let S=await VI(s,t,n.abortSignal);return m&&m.serializedTree===S.serializedTree&&m.screenshotBuff.equals(S.screenshotBuff)?(f=!0,p):(m=S,$I({command:r,state:S,fixtures:n,useMemory:i,useConsensus:!1,highlightElementsOnFailure:!1,attemptNumber:u,aiPageFiltering:e,logger:t,source:o}))},frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,logger:t,browser:s}),p?.success){p?.updatedMemory&&wl(r,p.updatedMemory,t);break}else throw p?.thoughts?new M("AssertionFailureError",p.thoughts):new M("InternalPlatformError","No thoughts were provided for AI assertion failure")}catch(y){n.abortSignal.throwIfAborted(),h=y instanceof Error?y:new Error(`${y}`),f?t.info(`AI check attempt ${u} failed (re-used previous result)`):t.info({err:y},`AI check assert attempt ${u} failed, retrying...`)}finally{u++}}if(!p?.success)try{p=await Wr({action:async()=>$I({command:r,state:await VI(s,t,n.abortSignal),fixtures:n,useMemory:i,useConsensus:!0,highlightElementsOnFailure:!0,attemptNumber:u,aiPageFiltering:e,logger:t}),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,logger:t,browser:s})}catch(f){n.abortSignal.throwIfAborted(),h=f instanceof Error?f:new Error(`${f}`)}finally{u++}if(p?.updatedMemory&&wl(r,p.updatedMemory,t),!p?.success){let f=`AI check still failing after ${u} attempts.`;throw h&&(f+=` Latest result: ${h.message}`),new M("AssertionFailureError",f)}return{...p,succeedImmediately:!1,urlAfterCommand:s.url()}}async function VI(r,e,t){let[n,o]=await Promise.all([Dn(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function $I({command:r,state:e,fixtures:t,useConsensus:n,useMemory:o,highlightElementsOnFailure:i,aiPageFiltering:a,attemptNumber:s,source:c,logger:l}){let{browser:u,generator:d,abortSignal:p}=t,m={type:"ASSERTION"},{serializedTree:h,tree:g}=e,f=e.screenshotBuff,y=f.toString("base64"),S=u.url(),T=r.contextChoice??"MULTIMODAL",A=h;T!=="VISION_ONLY"&&(A=await Ki({type:"assertion",serializedTree:h,tree:g,description:r.assertion,screenshot:y,options:{aiPageFiltering:a},fixtures:{generator:d,signal:p,logger:l,orgId:t.orgId}}),A!==h&&(m.ragUsed=!0),m.pageState=A);let v={goal:r.assertion,url:S,memory:o?r.cache?.memory:void 0,browserState:A,screenshot:y,contextChoice:T,source:c},x=await(T==="VISION_ONLY"?(_,D)=>d.getVisualAssertionResult(_,D):(_,D)=>d.getAssertionResult(_,D))(v,{useConsensus:n,attemptNumber:s,useMemory:o,disableCache:!!r.disableCache,abortSignal:p,logger:l,loggerTags:Ge(l)});return(x.result||i)&&x.relevantElements&&(m.relevantElementsSerialized=x.relevantElements.map(_=>u.getSerializedFormFromA11yId(_)).filter(_=>!!_),await RW(x.relevantElements,u,l)),{success:x.result,thoughts:x.thoughts,afterScreenshotOverride:f,updatedMemory:o?x.updatedMemory:void 0}}async function RW(r,e,t){let n=Date.now();for(let o of r){if(Date.now()-n>2e3){t.debug("Highlighting relevant elements took over 2s, aborting...");return}try{let i=new AbortController;await $(e.highlightA11yId(o),{milliseconds:1e3,fallback:()=>{throw i.abort(),new Error("Timed out waiting for highlighting to complete")}})}catch(i){t.debug({err:i},"Failed to highlight relevant element after assertion, continuing...");return}}}var AW=75e4,zp=class extends Error{constructor(){super("The page content exceeds the maximum token limit for AI smart waiting."),this.name="ExceededMaxAISmartWaitingTokensError"}};async function WI(r,e){let{logger:t}=r,{abortSignal:n,browser:o}=e,i=Date.now();try{await wW(i,r,e)}catch(a){if(a instanceof Error&&(a.name==="AbortError"||a.name==="TimeoutError")||n.aborted)return;a instanceof zp?t.warn("Skipping AI smart waiting due to excessive page size - falling back to naive waiting"):t.warn({err:a},"Unexpected error occurred during AI smart waiting");let s=o.smartWaitingTimeout-(Date.now()-i);s>0&&await ie(s,n)}finally{t.debug({durationMs:Date.now()-i},"AI smart waiting complete")}}async function wW(r,e,t){let{abortSignal:n,browser:o}=t;if(o.smartWaitingTimeout<3e3){await ie(o.smartWaitingTimeout,n);return}if(!e.description)throw new M("UserConfigurationError","Cannot locate element with empty description");await $(CW(r,e,t),{milliseconds:o.smartWaitingTimeout})}async function CW(r,e,t){let{logger:n,iframeUrl:o}=e,{browser:i}=t;for(;Date.now()-r<i.smartWaitingTimeout;)if(await Wr({action:async()=>xW(e,t),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function xW(r,e){let{testContext:t,logger:n,filterByViewport:o,allowNotActionableNodesOverride:i}=r,{browser:a,abortSignal:s,localCodeEvalTools:c,orgId:l,generator:u}=e,d=r.description;t&&(d=await dr({orgId:l,s:d,context:t,localTools:c,signal:s,logger:n}));let{serializedTree:p}=await Dn(a,{allowNotActionableNodesOverride:i,filterByViewport:o,abortSignal:s,logger:n});if(Me(p)>AW)throw new zp;s.throwIfAborted();let h;try{h=await a.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(S){throw new M("ActionFailureError",`Failed to take screenshot of page to perform smart waiting. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${S instanceof Error?S.message:S}`)}let f=`data:image/jpeg;base64,${h.toString("base64")}`;s.throwIfAborted();let y=await u.getSmartWaitingDecision({browserState:p,description:d,screenshot:f},{abortSignal:s,loggerTags:Ge(n)});return n.debug({result:y},"Got smart waiting result"),y.isPageReady}var _W=3e4;async function qI({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??_W/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(r.headers||{}).filter(([d,p])=>d&&p));a["Content-Type"]="application/json";let s;if(Va(r.url)&&(s=r.url),t&&$a(r.url,t)&&(s=new URL(r.url,t).toString()),!s)throw new M("ActionFailureError",`Invalid URL: ${r.url}`);let l=await $((async()=>{try{return await n(s,{headers:a,method:"POST",body:JSON.stringify({query:r.query,variables:r.variables?JSON.parse(r.variables):void 0}),signal:i.signal})}catch(d){e.error({err:d},"Failed to make HTTP request")}})(),{milliseconds:o*1e3});if(!l)throw new M("ActionFailureError",`GraphQL request timed out after ${o} seconds`);if(!l.ok){let d,p=await l.text();try{d=JSON.parse(p)}catch{throw new M("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}throw d?.errors?.length&&d?.errors[0]?.message?new M("ActionFailureError",`GraphQL request failed with status ${l.status}: ${d.errors[0].message}`):new M("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}let u={};return l.headers.forEach((d,p)=>{u[p]=d}),{status:l.status,headers:u,json:await l.json()}}var Jo=class{orgId;options;storage;localCodeEvalTools;uploadedFileStorage;visualDiffScreenshotStorage;browser;generator;executeAbortController=new AbortController;logger;recordAbortController=null;registeredListeners={};recordedRequests={};constructor({browser:e,generator:t,logger:n,storage:o,orgId:i,localCodeEvalTools:a,uploadedFileStorage:s,visualDiffScreenshotStorage:c,options:l}){this.orgId=i,this.options=l,this.browser=e,this.browser.registerAbortSignal(this.executeAbortController.signal),this.storage=o,this.uploadedFileStorage=s,this.visualDiffScreenshotStorage=c,this.localCodeEvalTools=a,this.generator=t,this.logger=n}setOpen(){this.executeAbortController=new AbortController,this.browser.registerAbortSignal(this.executeAbortController.signal)}setClosed(){this.executeAbortController.abort()}throwIfClosed(){this.executeAbortController.signal.throwIfAborted()}get closed(){return this.executeAbortController.signal.aborted}async evaluateAiAction({goal:e,startingScreenshot:t,history:n,disableCache:o,langfuseSessionId:i,lastError:a,logger:s=this.logger}){let[c,l]=await Promise.all([Dn(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:!0,skipWaitForPageLoad:!0,logger:s}),this.browser.screenshot({retries:1,clearHighlights:!0})]),u=`data:image/jpeg;base64,${l.toString("base64")}`,d=await Ki({type:"ai-action",description:e,screenshot:u,serializedTree:c.serializedTree,tree:c.tree,options:{aiPageFiltering:!!this.options?.aiPageFiltering},fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:s,orgId:this.orgId}}),p={url:this.browser.url(),browserState:d,startingScreenshot:t,history:n,goal:e,screenshot:u,lastError:a};return await this.generator.getMultiturnAiActionEvaluation(p,{disableCache:o,abortSignal:this.executeAbortController.signal,loggerTags:{...Ge(s)},langfuseSessionId:i})}async promptToCommand({goal:e,startingScreenshot:t,history:n,actionHint:o,disableCache:i,logger:a=this.logger,langfuseSessionId:s}){let c=this.browser.url(),[l,u]=await Promise.all([Dn(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:!0,skipWaitForPageLoad:!0,logger:a}),this.browser.screenshot({retries:1,clearHighlights:!0})]),d=`data:image/jpeg;base64,${u.toString("base64")}`,p=await Ki({type:"ai-action",description:e,screenshot:d,serializedTree:l.serializedTree,tree:l.tree,options:{aiPageFiltering:!!this.options?.aiPageFiltering},fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:a,orgId:this.orgId}}),m={url:c,browserState:p,startingScreenshot:t,history:n,goal:e,actionHint:o,screenshot:d};try{return await this.generator.getMultiturnAiActionCommand(m,{disableCache:i,abortSignal:this.executeAbortController.signal,loggerTags:{...Ge(a)},langfuseSessionId:s})}catch(h){throw new M("InternalWebAgentError",`Error generating command: ${h instanceof Error?h.message:h}`,{errOptions:{cause:h}})}}async getBrowserState(e){return Dn(this.browser,e)}async locateElement(e){return await qS({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return Wr({action:async()=>{let n=await this.browser.resolveHardcodedCssSelector({ctx:null,selector:e,timeoutMs:2e3,logger:this.logger});return{thoughts:"Located element with selector",target:{id:-1,selector:e,targetSource:"USER_CSS_SELECTOR",targetUpdateTime:new Date().toUTCString()},resolution:n}},frameConfig:t?{type:"url",url:t}:void 0,browser:this.browser,logger:this.logger})}getControllerFixtures(e){return{ctx:e??null,browser:this.browser,generator:this.generator,logger:this.logger,orgId:this.orgId,storage:this.storage,localCodeEvalTools:this.localCodeEvalTools,abortSignal:this.executeAbortController.signal}}shouldUseMemory(){return this.options?.useMemory??(this.orgId==="org_01HMSCJQBCCG51M2ZF65YC5B8W"||this.orgId==="org_01HMJTX4GT1KG94KZRCT8MZ6YB")}async wrapMultiElementTargetingCommand({ctx:e,tracer:t,command:n,targetNames:o,descriptions:i,caches:a,action:s,options:c,retriesWithAI:l=1}){let u=[];for(let d=0;d<i.length;d++){let p=i[d],m=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:p,cache:a[d],action:async h=>h,options:{...c,targetName:o[d]}});u.push(m)}try{let d=await s(...u.map(h=>h.result)),p=h=>h==="fromTarget"?"From Target":h==="toTarget"?"To Target":"Target",m=u.map((h,g)=>h.thoughts?`${p(o[g])}: ${h.thoughts}`:void 0).filter(h=>!!h).join(" -------------- ")||void 0;return{result:d,elementInteractedDisplayStrings:u.map(h=>h.elementInteractedDisplayString),thoughts:m}}catch(d){if(this.throwIfClosed(),l>0)return this.logger.warn({err:d},"Failed to execute action with multiple cached targets, retrying with AI"),this.wrapMultiElementTargetingCommand({ctx:e,tracer:t,command:n,targetNames:o,descriptions:i,caches:i.map(()=>{}),action:s,options:c,retriesWithAI:l-1});throw new M("ActionFailureError",d.message,{errOptions:{cause:d}})}}async wrapElementTargetingCommand(e){let t=this.logger.child({commandId:e.command.id}),n;for(let o=0;o<2;o++)try{return await Wr({action:()=>this.wrapElementTargetingCommandHelper({...e,originalCache:e.originalCache??e.cache}),frameConfig:e.options.iframeUrl?{type:"url",url:e.options.iframeUrl}:void 0,browser:this.browser,logger:t})}catch(i){if(n=i,this.browser.userBrowserSettings.visualActions&&Vm(i)){t.warn({err:i},"Invalid mpath error, retrying element targeting command");continue}if(!this.browser.userBrowserSettings.visualActions&&(qm(i)||$m(i))){t.warn({err:i},"Invalid momentic id error, retrying element targeting command");continue}if(Km(i)){t.warn({err:i},"Invalid backend node id error, retrying element targeting command");continue}if(i instanceof Tn&&i.retryableWithAI){t.warn({err:i},"Element cache disqualification error, retrying element targeting command");continue}throw i}throw n instanceof M?n:new M("ActionFailureError",n?.message??"An unknown error occurred during element targeting")}async wrapHardcodedCssTargetingCommandHelper({ctx:e,target:t,action:n,options:o,command:i}){let a=this.logger.child({commandId:i.id}),{targetName:s}=o;if(t.type!=="description")throw new M("ActionFailureError","Cannot use selector with non-description target");let c,l=Date.now(),u=Date.now();for(;Date.now()-u<this.browser.smartWaitingTimeout;){l=Date.now();try{let d=await this.browser.resolveHardcodedCssSelector({ctx:e,selector:t.elementDescriptor,targetName:s,logger:a});return{result:await n({locator:d.locator}),elementInteractedDisplayString:d.displayString}}catch(d){if(d.name==="AbortError")throw d;c=d,a.warn({err:d},"Failed to action on hardcoded css selector"),Date.now()-l<500&&await ie(500)}}throw c}async wrapElementTargetingCommandHelper(e){let{ctx:t,tracer:n,target:o,originalCache:i,action:a,options:s,command:c}=e,{disableCache:l,useSelector:u,targetName:d,targetHealingInProgress:p,source:m}=s,h=this.logger.child({commandId:c.id}),g=this.shouldUseMemory(),f=s.retriesWithAI??1,y=!1,S=KI(e.cache);if((!S||l)&&!Mm(o))throw new M("ActionFailureError","Cannot target element with no cached data or element descriptor");if(u)return this.wrapHardcodedCssTargetingCommandHelper(e);l&&(h.info("Cache explicitly disabled for this step"),y=!0,S=void 0),S&&this.browser.userBrowserSettings.disableSecondaryCacheResolution&&S.targetSource==="HEURISTIC_HEALED"&&(y=!0,S=void 0),S?.inputDescription&&!jI(o.elementDescriptor,S.inputDescription)&&(h.warn({old:S.inputDescription,new:o.elementDescriptor},"Target cache was generated with a different description, clearing it automatically"),y=!0,S=void 0);let T=v=>!!v&&Mc(v),A=!0;if(!T(S)){A=!1,h.info({description:o.elementDescriptor,targetHealingInProgress:p,cacheBustedBeforeAction:y,memory:s.memory,useMemory:g},"Prompting AI for an updated element location"),(y||!i)&&await WI({description:o.elementDescriptor,iframeUrl:s.iframeUrl,source:m,logger:h,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride},this.getControllerFixtures(t)),f--;let v;try{v=await qS({description:o.elementDescriptor,disableCache:!!s.disableCache,iframeUrl:s.iframeUrl,source:m,useMemory:g,memory:g?s.memory:void 0,aiPageFiltering:!!this.options?.aiPageFiltering,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride,logger:h},this.getControllerFixtures(t))}catch(_){if(_ instanceof Sa&&_.updatedLocatorMemory){let D={id:-1,...i,memory:_.updatedLocatorMemory};Ku({cmd:c,key:d,newTarget:D,logger:h,updatedWithAI:!0})}throw new M("ActionFailureError",_.message)}v.frameConfig&&this.browser.setActiveFrameConfig(v.frameConfig);let w=s.disableGlobalLocatorRedirect?{locator:v.resolution.locator}:await this.attemptLocatorRedirect(v.resolution.locator,h),x=await a(w);return Ku({cmd:c,key:d,newTarget:v.target,logger:h,updatedWithAI:!0}),p&&(n.recordTargetAutoHeal({healType:"AI"}),v.target.targetSource="AI_HEALED",v.target.targetUpdateTime=new Date().toUTCString(),v.target.targetUpdateLoggerTags=Ge(h)),{result:x,elementInteractedDisplayString:v.resolution.displayString,thoughts:v.thoughts}}try{let v=await this.browser.resolveTarget(t,S,{allowNotActionableNodesOverride:s.allowNotActionableNodesOverride,targetName:d,logger:h,signal:this.executeAbortController.signal});(this.browser.userBrowserSettings.visualActions||this.browser.userBrowserSettings.globalLocatorRedirect!==!1)&&await this.browser.scrollIntoViewIfNeeded(v.locator);let w=s.disableGlobalLocatorRedirect?{locator:v.locator}:await this.attemptLocatorRedirect(v.locator,h),x=await a(w);if(kt.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.6"]),Ku({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let _=v.decisions.filter(D=>D.matched);if(_.length!==1)h.warn({decisions:v.decisions},"Expected exactly 1 matching method for element location, got more or less");else{let D=_[0].type;n.recordTargetAutoHeal({healType:D})}}return{result:x,elementInteractedDisplayString:v.displayString}}catch(v){this.throwIfClosed();let w="unknown";v instanceof Or&&v.cacheMissReason&&(w=v.cacheMissReason),kt.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.6",`missReason:${w}`]);let x=!1;if((v instanceof Tn||Vm(v)||qm(v)||Km(v)||JE(v)||$m(v)||QE(v))&&(x=!0),v instanceof M&&!x)throw h.error({err:v},"Failed to execute action with cached target (fatal)"),v;if(f>0&&o){h.info({err:v},"Failed to execute action with cached target, retrying with AI");let _;return S.memory&&Ic(S.memory)&&(_=S.memory),this.wrapElementTargetingCommand({ctx:t,tracer:n,command:c,target:o,cache:void 0,originalCache:i,action:a,options:{...s,memory:_,retriesWithAI:f,targetHealingInProgress:!0}})}throw new M("ActionFailureError",v.message,{errOptions:{cause:v}})}}async attemptLocatorRedirect(e,t){return this.browser.userBrowserSettings.globalLocatorRedirect!==!1?this.browser.performTargetRedirection(e,t):{locator:e}}async screenshotWithDimensions(e){return Fl(this.browser,e)}async executePresetCommand(e,t,n,o,i){this.options?.slowMoMs&&await ie(this.options.slowMoMs);let a=await this.browser.getOpenPages(),s=this.browser.url(),c;try{c=await this.resolveCommandTemplateStrings(n,o)}catch(l){throw this.throwIfClosed(),new M("ActionFailureError",`Failed to substitute template strings in command: ${l.message}`,{errOptions:{cause:l}})}try{let l=await this.executePresetCommandHelper(e,t,n,o,i);return this.browser.userBrowserSettings.visualActions&&mE(n)?await this.browser.waitForDOMStability({timeout:Le}):!this.browser.userBrowserSettings.visualActions&&["PRESS","TYPE"].includes(n.type)&&await this.browser.waitForDOMStability({timeout:ce}),this.options?.autoFollowNewTabs&&await aM({beforeUrl:s,command:n,beforePages:a.map(u=>u.url),browser:this.browser,logger:this.logger}),l}catch(l){throw l.name!=="AbortError"&&this.logger.error({err:l},"Error thrown in action controller"),l}finally{Mw(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>yS(e)}}async resolveCommandTemplateStrings(e,t){return vd({obj:e,context:t,bannedKeys:["type","a11yData","thoughts","cache","code"],orgId:this.orgId,logger:this.logger,signal:this.executeAbortController.signal,localTools:this.localCodeEvalTools})}async executePresetCommandHelper(e,t,n,o,i){i=i||"disableCache"in n&&!!n.disableCache;let a=this.logger.child({commandId:n.id});switch(n.type){case"SUCCESS":let s=n.condition;return s?.assertion.trim()?Bp({command:s,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a}):{succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"AI_ASSERTION":{if(!n.assertion.trim())throw new M("ActionFailureError","Missing assertion");if(n.timeout&&n.timeout>1800)throw new M("AssertionFailureError",`AI check timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);return Bp({command:n,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a})}case"AI_EXTRACT":{if(!n.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(n.schema){let f=uR(n.schema);if(f)throw new M("UserConfigurationError",f)}let h=await this.browser.getCondensedHtml(),g=await this.browser.screenshot({retries:2});try{let f=await this.generator.getTextExtraction({goal:n.goal,browserState:h,returnSchema:n.schema,screenshot:`data:image/jpeg;base64,${g.toString("base64")}`},{disableCache:i,abortSignal:this.executeAbortController.signal,loggerTags:Ge(a)});if(f.result==="NOT_FOUND")throw new M("ActionFailureError","No relevant data found for extraction goal on this page");if(f.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",f.thoughts);return{thoughts:f.thoughts||void 0,data:f.result,succeedImmediately:!1,urlAfterCommand:this.browser.url()}}catch(f){let y=f.message;throw y.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step in the browser instead."):y.includes("AIProviderError")&&y.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:f}}):f}}case"NAVIGATE":if(!Va(n.url)&&!$a(n.url,this.browser.baseUrl))throw new M("ActionFailureError",`Invalid URL provided to navigate command: ${n.url}`);await this.browser.navigate({url:n.url,loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"DIALOG":this.browser.registerDialogHandler(n.action);break;case"CAPTCHA":if(!this.browser.canSolveCaptchas())break;let c=await this.browser.solveCaptcha();c&&(await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:{type:"description",elementDescriptor:"the captcha image solution input"},cache:void 0,action:h=>this.browser.click(h,this.createCallbacksForBrowser(this.orgId),{}),options:{...n,targetName:"target",disableCache:i}}),await this.browser.type(c,{clearContent:!0,pressEnter:!0},!0));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 h,g;if(n.target&&Sn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:T}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:A=>this.browser.hover(A),options:{...n,targetName:"target",disableGlobalLocatorRedirect:!0,disableCache:i}});h=S,g=T}let f=this.browser.getViewport()?.height??Yt.height,y=this.browser.getViewport()?.width??Yt.width;switch(n.type){case"SCROLL_UP":await this.browser.scrollVertical(-(n.deltaY??f));break;case"SCROLL_DOWN":await this.browser.scrollVertical(n.deltaY??f);break;case"SCROLL_LEFT":await this.browser.scrollHorizontal(-(n.deltaX??y));break;case"SCROLL_RIGHT":await this.browser.scrollHorizontal(n.deltaX??y);break}return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"WAIT_FOR_URL":{if(n.timeout&&n.timeout>1800)throw new M("UserConfigurationError",`Wait for URL timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);let h=n.matcher;await this.browser.waitForUrl({beforeUrl:this.browser.url(),matcher:h},{timeout:n.timeout?n.timeout*1e3:void 0,negated:n.negated,caseInsensitive:n.caseInsensitive});break}case"WAIT":if(n.delay>1800)throw new M("UserConfigurationError",`Wait timeout of ${n.delay} seconds exceeds the maximum allowed value of 30 minutes`);let l=n.delay*1e3;await ie(l,this.executeAbortController.signal);break;case"REFRESH":await this.browser.refresh({loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"CLICK":{if(Sn(n.target)){await this.browser.clickUsingVisualCoordinates(n.target.pixels,n);break}let h=this.browser.url(),{elementInteractedDisplayString:g,result:f,thoughts:y}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,target:n.target,command:n,cache:n.cache?.target,action:T=>this.browser.click(T,this.createCallbacksForBrowser(this.orgId),n),options:{disableCache:i,targetName:"target",...n}}),S={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:y,data:f.downloadedFile?{downloadedFile:f.downloadedFile}:void 0};return sd(h,S.urlAfterCommand)&&(S.succeedImmediately=!0,S.succeedImmediatelyReason="URL changed"),S}case"COPY":return await this.browser.copy(n.value),{succeedImmediately:!1,data:n.value,urlAfterCommand:this.browser.url()};case"PASTE":{await this.browser.paste();break}case"DRAG":{if(Sn(n.fromTarget)&&Sn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(Sn(n.fromTarget)||Sn(n.toTarget))throw new Error("Drag and drop targets must be both coordinates or both descriptions");let{elementInteractedDisplayStrings:h,thoughts:g}=await this.wrapMultiElementTargetingCommand({ctx:e,tracer:t,command:n,targetNames:["fromTarget","toTarget"],descriptions:[n.fromTarget,n.toTarget],caches:[n.cache?.fromTarget,n.cache?.toTarget],action:(f,y)=>this.browser.dragAndDrop(f.locator,y.locator,{hoverSeconds:n.hoverSeconds,steps:n.steps}),options:{useSelector:!!n.useSelector,disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h[0],thoughts:g}}case"MOUSE_DRAG":{let h=parseInt(n.deltaX),g=parseInt(n.deltaY),f=n.steps??5;if(isNaN(h)||isNaN(g))throw new M("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${n.deltaX}, ${n.deltaY})`);if(n.target&&Sn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,void 0,n.target.pixels);break}let y,S;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:T,thoughts:A}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async v=>this.browser.mouseDrag(h,g,f,v.locator,{force:n.force}),options:{disableCache:i,targetName:"target",...n}});y=T,S=A}else await this.browser.mouseDrag(h,g,f,void 0,{force:n.force});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:y,thoughts:S}}case"SELECT_OPTION":{if(!So(n.target))throw new Error("Select with x/y is not supported yet");let h=n.target.elementDescriptor,g=n.choice,{elementInteractedDisplayString:f,thoughts:y}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:{type:"description",elementDescriptor:h},cache:n.cache?.target,action:S=>this.browser.selectOption(S,g,n.force),options:{...n,targetName:"target",disableCache:i,source:gi(n)}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:f,thoughts:y}}case"TAB":{let h={loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0,retry:!0};await this.browser.switchToPage(n.action,h);break}case"NEW_TAB":await this.browser.createNewTab(n.url,{loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"COOKIE":if(!n.value)break;let u=await this.browser.setCookie(n.value);a.debug({results:u},"Set cookies");break;case"LOCAL_STORAGE":if(!n.value||!n.key)break;await this.browser.setLocalStorage(n.key,n.value);break;case"JAVASCRIPT":{let h;try{n.environment==="BROWSER"?(h=await this.browser.evaluateCodeInPage({code:n.code,fragment:n.fragment??!1,context:o.toObjectCopy(),timeoutMs:n.timeout?n.timeout*1e3:void 0}),a.info({result:h},"Executed JavaScript in browser")):h=await zo({orgId:this.orgId,code:n.code,fragment:!!n.fragment,context:o,timeoutMs:n.timeout?n.timeout*1e3:void 0,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal,callbacks:{onPersistentVariableUpdates:async g=>{if(!this.options?.scratchPadId){a.warn({updates:g},"Got persistent variable updates but scratch pad is not available");return}await this.storage.savePersistentVariables?.({scratchPadId:this.options?.scratchPadId,orgId:this.orgId,updates:g,logger:a})}}})}catch(g){throw this.throwIfClosed(),new M("ActionFailureError",g instanceof Error?g.message:`${g}`,{errOptions:{cause:g}})}try{JSON.stringify(h)}catch(g){throw new M("ActionFailureError",`Return value is not serializable: ${g instanceof Error?g.message:`${g}`}`,{errOptions:{cause:g}})}return{urlAfterCommand:this.browser.url(),succeedImmediately:!1,data:h}}case"TYPE":{if(n.target&&Sn(n.target)){await this.browser.clickUsingVisualCoordinates(n.target.pixels,n),await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);break}let h=this.browser.url(),g,f,y=KI(n.target),S=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(y){let{elementInteractedDisplayString:A,thoughts:v}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:y,cache:n.cache?.target,action:w=>this.browser.typeIntoTarget(n.value,w,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter,relativePosition:n.relativePosition}),options:{...n,targetName:"target",disableCache:i,disableGlobalLocatorRedirect:!S,source:gi(n)}});g=A,f=v}else await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);let T={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return sd(h,T.urlAfterCommand)&&(T.succeedImmediately=!0,T.succeedImmediatelyReason="URL changed"),T}case"HOVER":{if(Sn(n.target)){await this.browser.hoverUsingVisualCoordinates(n.target.pixels);break}let{elementInteractedDisplayString:h,thoughts:g}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:f=>this.browser.hover(f),options:{...n,targetName:"target",disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"FOCUS":{if(!So(n.target))throw new Error("Focus with x/y is not supported yet");let{elementInteractedDisplayString:h,thoughts:g}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:f=>this.browser.focus(f),options:{...n,targetName:"target",disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"BLUR":{if(n.target&&!So(n.target))throw new Error("Blur with x/y is not supported yet");if(!n.target||!n.target.elementDescriptor)return await this.browser.blur(null),{succeedImmediately:!1,urlAfterCommand:this.browser.url()};let{elementInteractedDisplayString:h,thoughts:g}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,target:n.target,command:n,cache:n.cache?.target,action:f=>this.browser.blur(f),options:{...n,targetName:"target",disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"PRESS":let d=this.browser.url();await this.browser.press(n.value,{repeat:n.repeat,convertMeta:n.convertMeta??!0,delayMs:n.delayMs});let p={urlAfterCommand:this.browser.url(),succeedImmediately:!1};return sd(d,p.urlAfterCommand)&&(p.succeedImmediately=!0,p.succeedImmediatelyReason="URL changed"),p;case"KEY_DOWN":return await this.browser.keyDown(n.value,{convertMeta:n.convertMeta??!0}),{urlAfterCommand:this.browser.url(),succeedImmediately:!1};case"KEY_UP":return await this.browser.keyUp(n.value,{convertMeta:n.convertMeta??!0}),{urlAfterCommand:this.browser.url(),succeedImmediately:!1};case"REQUEST":{let h=new IW,g=MW(fetch,h),f;try{f=new URL(n.url).hostname}catch{}let y=await kw({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g});return{data:Gs.parse({...y,cookies:bb(h,f)}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await qI({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return Dw({ctx:e,tracer:t,command:n,disableCache:i,browser:this.browser,logger:a,storage:this.storage,screenshotStorage:this.visualDiffScreenshotStorage,targetingWrapper:h=>this.wrapElementTargetingCommand(h)});case"FILE_UPLOAD":{let h,g;if(n.fileSource.type==="URL"?(g=n.fileSource.url,h=await vM({uri:n.fileSource.url,logger:a,orgId:this.orgId})):n.fileSource.type==="USER_FILE"&&(g=n.fileSource.name,h=await this.uploadedFileStorage?.getFileForUpload(n.fileSource.name,this.orgId)),!h)throw new M("UserConfigurationError",`Attempted to use non-existent file for upload step: ${g}`);await this.browser.setFileChooserHandler({...h,filename:n.filename});break}case"AUTH_SAVE":return{data:await this.browser.saveAuthState(),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"AUTH_LOAD":{let h;if(!n.storageState.trim())h=void 0;else if(h=await zo({orgId:this.orgId,code:n.storageState,fragment:!1,context:o,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof h!="object")throw new M("ActionFailureError",`Credentials must evaluate to an object (received ${typeof h} instead)`);let g;try{g=gu.optional().parse(h)}catch(f){throw new M("ActionFailureError",`Credentials provided do not follow the required format: ${f}`)}await this.browser.loadAuthState(g);break}case"ELEMENT_CHECK":{let h=(n.timeout??yn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(Lw(n.assertion)&&!n.useSelector&&n.target.type==="description"&&g&&g!=="v1"){let y={id:n.id,type:"AI_ASSERTION",assertion:`There is no element on the page closely matches the following description. If the description has single quotes, remember that requires an exact text substring match. Description: ${n.target.elementDescriptor}`,iframeUrl:n.iframeUrl,timeout:n.timeout,cache:n.cache&&"memory"in n.cache?{memory:n.cache?.memory}:void 0};try{let S=await Bp({command:y,logger:a,aiPageFiltering:!!this.options?.aiPageFiltering,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),source:"NEGATED_CHECK"});return{succeedImmediately:!1,thoughts:`The element described does not exist on the page: ${S.thoughts}`,urlAfterCommand:this.browser.url(),afterScreenshotOverride:S.afterScreenshotOverride}}finally{y.cache?.memory&&wl(n,y.cache?.memory.traces,a)}}let f=await Ow({command:n,tracer:t,timeoutMs:h,targetingWrapper:y=>this.wrapElementTargetingCommand(y),fixtures:this.getControllerFixtures(e),disableCache:i});return{fail:!f.success,data:f.data,elementInteracted:f.elementInteractedDisplayString,thoughts:f.err?.message??f.thoughts??`Element assertion ${f.success?"succeeded":"failed"}.`,succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"PAGE_CHECK":{let h=await Wr({action:async()=>Rd({assertion:n.assertion,browser:this.browser,logger:a,timeout:n.timeout,signal:this.executeAbortController.signal,autoExpandIframes:!!this.browser.userBrowserSettings.autoExpandIframes}),frameConfig:n.iframeUrl?{type:"url",url:n.iframeUrl}:void 0,browser:this.browser,logger:a});return{fail:!h.success,data:h.data,thoughts:h.success?"Page assertion passed.":h.err?.message??`Page assertion still failing after ${n.timeout} seconds.`,urlAfterCommand:this.browser.url(),succeedImmediately:!1}}case"REGISTER_REQUEST_LISTENER":{let h=new Ko(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await RS(f)).catch(f=>{a.error({err:f},"Failed to get request listener response")}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"AWAIT_LISTENER":{let h=this.registeredListeners[n.key];if(!h)throw new M("ActionFailureError",`No listener registered with key: ${n.key}`);let g=n.timeout??10;return{data:await $(h,{milliseconds:g*1e3,message:`Request listener timed out after ${g} seconds`}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"RECORD_REQUESTS":{let h=new Ko(n.requestMatcher);return this.recordedRequests[n.key]={},this.browser.registerRequestRecorder(n.key,{matches:g=>h.matches({url:g.request.url,method:g.request.method}),onRequestStart:(g,f)=>{this.recordedRequests[n.key][g]=_p(f)},onRequestComplete:(g,f)=>{this.recordedRequests[n.key]?.[g]&&(this.recordedRequests[n.key][g]=_p(f))}}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GET_RECORDED_REQUESTS":{let h=this.recordedRequests[n.key];if(!h)throw new M("ActionFailureError",`No recorder registered with key: ${n.key}`);return delete this.recordedRequests[n.key],{data:Object.values(h),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"SET_HEADER":{let h;return n.requestMatcher&&(h=new Ko(n.requestMatcher)),this.browser.setHeader(n.name,n.value,h),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"MOCK_ROUTE":return{data:{key:this.browser.registerMock(n.key,new Ko(n.requestMatcher),async(g,f)=>{let y=await zo({orgId:this.orgId,code:n.responseGenerator,fragment:!1,context:o,timeoutMs:void 0,logger:a,localTools:this.localCodeEvalTools,mock:{request:g,response:f},disallowVariableUpdates:!0,responseSerialization:"RESPONSE"}),S=Bb.parse(y);return new Response(S.body,{status:S.status,headers:S.headers})},n.fetchOriginalResponse??!1)},succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"REMOVE_ROUTE_MOCK":return this.browser.removeMock(n.key),{succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"OFFLINE_MODE":return await this.browser.setOfflineMode(n.enable),{succeedImmediately:!1,urlAfterCommand:this.browser.url()};default:return(h=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(n)}return{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}async getReverseMappedDescription({browserState:e,targetId:t,disableCache:n,screenshot:o}){return(await this.generator.getReverseMappedDescription({browserState:e,target:t,screenshot:o},{disableCache:n,abortSignal:this.executeAbortController.signal,loggerTags:Ge(this.logger)})).phrase}async stopRecordMode(){this.recordAbortController?.abort(),await this.browser.clearAllCdpHighlights()}async startRecordMode({params:e,abortController:t,isClickToRecord:n}){this.recordAbortController=t;let o=new Np({signal:t.signal,...e});return await this.browser.startRecording(this.recordAbortController.signal,o,n),o}async runSectionAutohealing(e){return this.generator.getAutohealingProposal(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:Ge(this.logger)})}async getFailureRecoveryPlan(e){return this.generator.getFailureRecoveryPlan(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:Ge(this.logger)})}};import{cloneDeep as PW}from"lodash-es";var OW={showOverlay:!1},Hp=class{sessions=new Map;sessionCountByIp=new Map;getCurrentConnectionsByIp(e){return this.sessionCountByIp.get(e)??0}getCurrentSessionsByIp(){return Object.fromEntries(this.sessionCountByIp)}reserveCapacityByIp(e){e&&this.sessionCountByIp.set(e,(this.sessionCountByIp.get(e)??0)+1)}releaseCapacityByIp(e){e&&this.sessionCountByIp.set(e,Math.max(this.getCurrentConnectionsByIp(e)-1,0))}registerSession({controller:e,context:t,cleanup:n,clientIp:o,sessionId:i,socket:a}){return this.sessions.set(i,{controller:e,context:t,cleanup:n,clientIp:o,browserBehavior:PW(OW),socket:a}),i}removeSession(e,t){(async()=>{let o=this.sessions.get(e);if(!o)return;this.releaseCapacityByIp(o.clientIp);let{controller:i}=o;try{i.setClosed(),await i.browser.cleanup()}catch(a){t.error({err:a},"Error cleaning up browser in global state manager")}try{await o.cleanup?.()}catch(a){t.error({err:a},"Error running cleanup function in global state manager")}this.sessions.delete(e)})()}getSession(e){return this.sessions.get(e)}};function YI(r,e,t,n){let o=Date.now(),i=Date.now(),a,s,c,l,u=!1,d=async(g,f)=>{if(!g.closed&&!g.isInPageLoad)try{let y=c;c=void 0;let S=g.url(),T=f.toEditorDisplayCopy();JSON.stringify(T)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:T,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=T}catch(y){if(!r.connected)return;let S=y instanceof Error?y.message:`${y}`;if(S.includes("Frame was detached")||S.includes("Not attached to an active page")||S.includes("browser has been closed")||S.includes("UserInfrastructureError"))return;t.error({err:y,sessionId:e},"Error grabbing browser state")}},p=setInterval(()=>{let g=n.getSession(e),f=g?.controller?.browser;if(!f||f.closed){t.debug("Clearing browser state socket cron due to the browser being closed"),clearInterval(p);return}d(f,g.context)},1e3),m=(g,f)=>!!(JSON.stringify(g)!==JSON.stringify(s)||f.logsPerPage.some(y=>y.length>0)),h=setInterval(async()=>{let f=n.getSession(e)?.controller?.browser;if(!f||f.closed){clearInterval(h);return}else if(u)return;u=!0;try{let y=await f.getAllFrameUrls(),S=f.retrieveAndClearDebugData();m(y,S)&&(s=y,c=S,i=Date.now())}catch(y){t.warn({err:y},"Failed to fetch extended details")}finally{u=!1}},2500);return{timers:[p,h]}}var LW=3;async function XI({socket:r,logger:e,storageFactory:t,uploadedFileStorage:n,visualDiffScreenshotStorage:o,devicePixelRatio:i,generatorFactory:a,enricherFactory:s,authorization:c,settingsFactory:l,getOrgId:u,branchGetter:d,globalE2eStateManager:p}){let m=r.id,h=r.handshake.query.testId;if(!h)throw new Error("Socket connection request is missing testId");let g=await u({type:"e2e",testId:h}),f=await d?.();e=e.child({testId:h,orgId:g,sessionId:m,branch:f});let y=await a(g,e),S=await s(g,e),T=await l(g,e),A=await t(g),{testMetadata:v,baseUrl:w,envName:x,browserConfig:_,aiSettings:D,environmentVariables:z,localCodeEvalTools:B}=await Yi({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:T}),L=p.getSession(m);if(L)return e.info("Associating connection with existing session (likely reconnect)"),await L.controller.browser.clearAllCdpHighlights(),{type:"e2e",sessionId:m,orgId:g,testId:h};let j=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:j,event:"connect",args:r.handshake.query},"Websocket event (connect)"),j&&p.getCurrentConnectionsByIp(j)>=LW)throw e.error({clientIp:j,sessions:p.getCurrentSessionsByIp(),...r.handshake.query},"Socket connection browser creation rate limit triggered"),new Error("You have exceeded the maximum number of connections allowed. Momentic limits the number of simultaneously open tabs to uphold browser reliability. Please close duplicate tabs and try again later.");p.reserveCapacityByIp(j);try{await NW({socket:r,baseUrl:w,envName:x,testMetadata:v,orgId:g,sessionId:m,logger:e,environmentVariables:z,clientIp:j,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:B,generator:y,enricher:S,browserConfig:_,aiSettings:D,globalE2eStateManager:p})}catch(Q){throw e.warn({err:Q},"Error setting up socket session, possibly due to client closing the connection"),p.releaseCapacityByIp(j),Q}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function NW({socket:r,baseUrl:e,envName:t,devicePixelRatio:n,testMetadata:o,orgId:i,sessionId:a,logger:s,storage:c,uploadedFileStorage:l,visualDiffScreenshotStorage:u,localCodeEvalTools:d,generator:p,environmentVariables:m,browserConfig:h,aiSettings:g,clientIp:f,enricher:y,globalE2eStateManager:S}){let T={viewport:o.advanced?.viewport??Yt,locale:o.advanced?.locale??Ro,timezoneId:o.advanced?.timezone??Ao,geolocation:o.advanced?.geolocation??wo,colorScheme:o.advanced?.colorScheme};n&&(T.deviceScaleFactor=n);let A=o.id,v=await vp({settings:h,orgId:i,baseUrl:e,envName:t,testName:o.name,localTools:d,envVariables:m,logger:s,customHeaders:void 0});s=s.child({orgId:i,sessionId:a,testId:A});let w=await Yr.init({baseUrl:e,userBrowserSettings:v,enricher:y,storage:c,logger:s,contextArgs:T,iconKnowledgeBase:null,callbacks:{onTabsChange:(B,L)=>{r.emit("tabs",{tabs:B,activeTab:L})},onScreencastFrame:(B,L)=>{let j=r;zr&&(j=r.compress(!0)),j.emit("screenshot",{buffer:B},()=>{L()})},onSvgsCollected:B=>{r.emit("newIconDetected",{numIcons:B.newSvgs.length}),c.saveNewIcons(B,s)},onNetworkLogs:B=>{r.emit("networkLogs",{harEntries:B})}}});await w.navigate({url:e,initialNavigation:!0});let x=new Jo({browser:w,generator:p,logger:s,orgId:i,options:{scratchPadId:void 0,slowMoMs:v.slowMoMs,autoFollowNewTabs:v.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:c,localCodeEvalTools:d,uploadedFileStorage:l,visualDiffScreenshotStorage:u}),_=YI(r,a,s,S),D=async()=>{_.timers.forEach(B=>clearInterval(B))},z=new sr({baseUrl:e,testName:o.name,currentUrl:x.browser.url(),variablesFromEnvironment:m,envName:t});if(!r.connected)throw await w.cleanup(),new Error("Socket not connected anymore, not proceeding with session setup");r.emit("session",{url:e,userAgent:Yr.USER_AGENT,viewport:x.browser.getViewport(),sessionId:a}),S.registerSession({controller:x,context:z,sessionId:a,cleanup:D,clientIp:f,socket:r})}async function Yi({testId:r,orgId:e,logger:t,storage:n,authorization:o,settings:i}){let a=await n.fetchTestMetadata(r,t);if(!a)throw new Error(`Test metadata could not found for test ${r}`);let s;o?.type==="API_KEY"&&(s=new xn({httpClient:new zt({...o,logger:t,mode:"interactive"}),fakerSeed:void 0}));let c=a.envs?.find(g=>g.default),l;c&&(l=await n.fetchEnvironment(c.name,t));let u=l&&"browser"in l?l.browser:void 0,d={...i.browser,...u,...a.advanced},p=a.baseUrl||l?.variables?.[Rt];if(!p)throw new Error("Base URL is empty in both test options and the configured environment");let m={...l?.variables};m=await Rp({orgId:e,testName:a.name,envName:l?.name,baseEnvVariables:m,parameters:a.parameters,logger:t,localTools:s});let h={...i.ai,...a.advanced};return{localCodeEvalTools:s,baseUrl:p,envName:l?.name,testName:a.name,browserConfig:d,environmentVariables:m,testMetadata:a,aiSettings:h}}var KS=class{parentTracer=null;socket;step;orgId;constructor({step:e,socket:t,parentTracer:n,orgId:o}){this.socket=t,this.parentTracer=n,this.step=e,this.orgId=o}getParentStepIdChain(){return this.parentTracer?this.parentTracer?.getParentStepIdChain()??[]:[]}recordStepDuration(e){let t=e.step.type!=="PRESET_ACTION"?e.step.type:e.step.command.type;kt.distribution("test_step_duration",e.durationMs,[`type:${t}`,"platform:browser","executor:editor",`orgId:${this.orgId}`])}attachBeforeScreenshot(){}attachAfterScreenshot(){}attachBeforeHtmlSnapshot(){}attachAfterHtmlSnapshot(){}recordTargetAutoHeal(){}async finish(e){switch(e.step.status){case"SUCCESS":this.socket.emit("success",{...e,parentStepIdChain:this.getParentStepIdChain()});return;case"FAILED":this.socket.emit("failure",{...e,parentStepIdChain:this.getParentStepIdChain()});return;case"CANCELLED":this.socket.emit("cancelled",{...e,parentStepIdChain:this.getParentStepIdChain()});return}}async startSubSteps(){return new so({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},so=class{stepFrequenciesByType={};parentTracer;parentStep;socket;orgId;recordStepStat(e){e.type!=="PRESET_ACTION"?this.stepFrequenciesByType[e.type]=(this.stepFrequenciesByType[e.type]||0)+1:this.stepFrequenciesByType[e.command.type]=(this.stepFrequenciesByType[e.command.type]||0)+1}sendFinalizedStepStats(){for(let[e,t]of Object.entries(this.stepFrequenciesByType))kt.increment("test_step_execution",t,[`type:${e}`,"platform:browser","executor:editor",`orgId:${this.orgId}`])}constructor({parentStep:e,socket:t,parentTracer:n,orgId:o}){this.parentTracer=n,this.parentStep=e,this.socket=t,this.orgId=o}async getScreenshot(){throw new Error("getScreenshot is not supported in the editor")}async getHtmlSnapshot(){throw new Error("getHtmlSnapshot is not supported in the editor")}getParentStepIdChain(){return this.parentStep?[...this.parentTracer?.getParentStepIdChain()??[],this.parentStep.id]:[]}async startStep(e){return this.recordStepStat(e.step),this.socket.emit("started",{stepId:e.step.id,parentStepIdChain:this.getParentStepIdChain(),attempt:e.attempt}),new KS({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId})}async finish(){this.sendFinalizedStepStats()}},Gp=class{constructor(e,t,n,o){this.socket=e;this.storage=t;this.orgId=n;this.testId=o}children=[];loggerBindings;setActiveVideo(){}async getScreenshot(){throw new Error("getScreenshot is not supported in the editor")}async getHtmlSnapshot(){throw new Error("getHtmlSnapshot is not supported in the editor")}onNetworkPage(){}onNetworkLogs(){}attachConsoleLogs(){}attachBrowserCrashDump(){}async finish(){this.socket.emit("finished"),await Promise.all(this.children.map(e=>e.finish()))}async startBeforeStepList(){let e=new so({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new so({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new so({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var YS={currentlyExecutingRequests:{}},kW=r=>async(e,t)=>{let{testId:n,orgId:o}=r.metadata,i=await r.settingsFactory(o,r.logger),a=await r.storageFactory(o),s,c=await Yi({testId:n,orgId:o,logger:r.logger,storage:a,authorization:r.authorization,settings:i}),l=`${n}|${c.baseUrl}`;try{let u=YS.currentlyExecutingRequests[l]??0;YS.currentlyExecutingRequests[l]=u+1,s=await FW({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),YS.currentlyExecutingRequests[l]--}},FW=async({socket:r,steps:e,baseUrl:t,testMetadata:n,reInitialize:o,toStep:i,fromStep:a,storageFactory:s,aiSettings:c,browserConfig:l,metadata:u,logger:d,envName:p,testName:m,environmentVariables:h,localCodeEvalTools:g,done:f,cacheStorageFactory:y,globalE2eStateManager:S})=>{let{testId:T,sessionId:A,orgId:v}=u,w=A,x=S.getSession(A);if(!x)throw new Error("No active session found");let{controller:_,context:D}=x;_.setOpen(),d=d.child({testId:T,orgId:v,sessionId:A,runId:w}),d.info({steps:e.map(ae=>`${ae.type}${"command"in ae?` - ${ae.command.type}`:""}`),toStep:i,fromStep:a,reInitialize:o,envName:p,testName:m,baseUrl:t,context:D,browserConfig:l,aiSettings:c},"Socket execution parameters");let z=h??{},B=async()=>{o&&(await _.browser.reset({newUrl:t}),D.reset({baseUrl:t,currentUrl:_.browser.url(),variablesFromEnvironment:z,envName:p,testName:m}))},L=await s(v),j=await y(v),Q=async()=>{let ae=Date.now();try{await j.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:T,stepLists:{steps:e},logger:d})}catch($e){d.error({err:$e},"Failed to fetch step cache entries from Momentic server. This can drastically reduce test reliability and performance.")}finally{kt.distribution("cache-resolution",Date.now()-ae,["executor:editor"])}};try{await xl({promiseGenerator:async()=>Promise.all([B(),Q()]),signal:_.executeAbortController.signal,codePath:"resolveStepCacheAndInitBrowser"}),_.setOpen()}catch(ae){if(r.emit("finished"),ae.name!=="AbortError")throw new Error(`Failed to setup browser for execution: ${ae}`)}let K=DW(e),ve={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},q={orgId:v,runId:w,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},st={controller:_,context:D,storage:L,codeEvalTools:g,usageTracker:new Ca,logger:d},Oe={test:{},step:{onDynamicAIActionStatusUpdateEvent:ae=>{r.emit("dynamicCommandStatusUpdate",ae)},onDynamicAIActionEvaluatingEvent:ae=>{r.emit("dynamicCommandEvaluating",ae)},onDynamicCommandGenerated:ae=>{r.emit("dynamicCommandGenerated",ae)},onDynamicCommandExecuted:ae=>{r.emit("dynamicCommandExecuted",ae)}}},ht=new Gp(r,L,v,T),tr=await bp({fixtures:st,options:ve,callbacks:Oe,inputs:q,testParams:{tracer:ht}}),He={logger:d,cacheStorage:j,orgId:v,testId:T,originalStepsWithCaches:{steps:K},updatedStepsWithCaches:{steps:e}};return tr?.status==="PASSED"?await td(He):tr?.status==="FAILED"&&await rd(He),await ht.finish(),f?.(tr),tr.status};var JI={event:"execute",createHandler:kW};import{cloneDeep as UW}from"lodash-es";var BW=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=UW(e),s=xA(a);if(s.category!=="NO_DESCRIPTION_PROVIDED"){if(s.category!=="NONE"){t?.({result:s});return}"cache"in a&&(a.cache=void 0);try{let l=await(await o(i.orgId,n)).getLintStepResult({command:a},{logger:n});t?.({result:l})}catch(c){n.error({event:"lint",err:c},"Failed to lint step"),t?.({result:void 0})}}},QI={event:"lintStep",createHandler:BW};var zW=({metadata:r,logger:e,storageFactory:t,globalE2eStateManager:n})=>{let{sessionId:o,orgId:i}=r;return async(a,s)=>{let{description:c,command:l,testMetadata:u,returnScreenshot:d}=a;e.info({params:a},`Locate handler called - ${c}`);let p=n.getSession(o);if(!p)throw new Error("No active session found");let{controller:m,context:h}=p;m.setOpen();let g=await t(i),f=Ti.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let T=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=T.resolution.locator,y={target:T.target,thoughts:T.thoughts}}catch(T){e.warn({err:T},"Failed resolving target with selector"),s({err:`Failed locating element: ${T.message}`,decisions:T instanceof Or?T.decisions:void 0});return}else try{let T=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:gi(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&Ic(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:T.target,thoughts:T.thoughts},S=T.resolution.locator}catch(T){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:T,html:A.slice(0,1e5)},"Failed locating element with AI")}catch(A){e.warn({err:A},"Failed grabbing HTML after trying to locate element with AI")}})(),s({err:`${T.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(T){e.warn({err:T},"Failed getting select options"),s({err:`Failed getting select options: ${T.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:T,width:A,height:v}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),w=await g.uploadScreenshot(T);y.screenshot={data:w,width:A,height:v},e.info({width:A,height:v},"Captured screenshot during locate")}catch(T){e.error({err:T},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${T.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(T){e.warn({err:T},"Error highlighting element, continuing...")}}},ZI={event:"locate",createHandler:zW};var HW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async({event:o,percentX:i,percentY:a})=>{let s=t.getSession(n);if(!s)throw new Error("No active session found");let c=s.controller.browser;if(c.closed||c.getActivePage().isClosed()){e.warn("Ignoring mouse move because the browser is closed");return}try{await c.clickMouseFromPositionPercentages(o,i,a)}catch(l){e.error({err:l},"Error performing click during cloud recording in control mode")}}},eP={event:"mouseClickEvent",createHandler:HW};var GW=({metadata:r,generatorFactory:e,logger:t,socket:n,globalE2eStateManager:o})=>{let{sessionId:i,orgId:a,testId:s}=r;return async({stepId:c,parentStepIdChain:l,attribute:u})=>{let d=o.getSession(i);if(!d)throw new Error("No active session found");let{controller:p}=d,m=await e(a,t);p.setOpen(),d.browserBehavior.showOverlay=!0;let h=new AbortController;h.signal.addEventListener("abort",async()=>{try{d.browserBehavior.showOverlay=!1,await p.stopRecordMode()}catch(y){t.warn({err:y},"Failed to stop record mode in target click socket handler")}},{once:!0});let g=!1,f=(y,S)=>{S.type!=="PRESET_ACTION"||S.command.type!=="CLICK"||(n.emit("targetRecordingUpdate",{type:y,stepId:c,parentStepIdChain:l,command:S.command,attribute:u}),h.abort(),g=!0)};setTimeout(()=>{g||(h.abort(),n.emit("targetRecordingUpdate",{type:"error",err:"Timed out waiting for click event",stepId:c,parentStepIdChain:l,attribute:u}))},1e4),await p.startRecordMode({params:{generator:m,logger:t,testId:s,orgId:a,callbacks:{onActionReceived:y=>f("clickReceived",y),onStepRecorded:y=>f("descriptionGenerated",y)}},abortController:h,isClickToRecord:!0}),n.emit("targetRecordingUpdate",{type:"listenersInitialized",stepId:c,parentStepIdChain:l,attribute:u})}},tP={event:"recordTargetClick",createHandler:GW};var jW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async({key:o})=>{let i=t.getSession(n);if(!i)throw new Error("No active session found");if(o==="Dead")return;let{controller:a}=i;if(a.browser.closed||a.browser.getActivePage().isClosed()){e.debug({sessionId:n},"Browser is closed, ignoring keyboard press socket event");return}try{a.setOpen(),await a.browser.keyDown(o,{})}catch(s){if(s.message.includes("has been closed")){e.debug({sessionId:n,err:s},"Browser is closed, ignoring key down socket event error");return}throw s}}},rP={event:"keyDownEvent",createHandler:jW};var VW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async({key:o})=>{let i=t.getSession(n);if(!i)throw new Error("No active session found");if(o==="Dead")return;let{controller:a}=i;if(a.browser.closed||a.browser.getActivePage().isClosed()){e.debug({sessionId:n},"Browser is closed, ignoring keyboard press socket event");return}try{a.setOpen(),await a.browser.keyUp(o,{})}catch(s){if(s.message.includes("has been closed")){e.debug({sessionId:n,err:s},"Browser is closed, ignoring key up socket event error");return}throw s}}},nP={event:"keyUpEvent",createHandler:VW};var $W=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r,o,i=0,a=(l,u)=>{let d=async()=>{o=void 0};clearTimeout(o),o=setTimeout(d,Math.min(1e3,250*(i+1)))},s,c=0;return async l=>{let u=t.getSession(n);if(!u)throw new Error("No active session found");let{controller:d,browserBehavior:p}=u,m=d.browser;if(m.closed||m.getActivePage().isClosed()){e.warn("Ignoring mouse move because the page is closed");return}if(l.event==="scroll"){let h=await m.scrollFromPositionPercentages(l.percentX,l.percentY,s?.x??0,s?.y??0),g=u.browserBehavior.recordingState?.transformer;g&&h&&g.recordScroll(h);return}p.showOverlay&&a(m,l);try{let h=await m.moveMouseFromPositionPercentages(l.percentX,l.percentY);c=0,s=h}catch(h){c++,c%5===0&&e.warn({err:h,mouseErrors:c},"Error in socket mouse move handler")}}},oP={event:"mouseMoveEvent",createHandler:$W};var WW=({metadata:r,generatorFactory:e,socket:t,logger:n,globalE2eStateManager:o})=>{let{sessionId:i,orgId:a,testId:s}=r;return async({stepId:c})=>{let l=o.getSession(i);if(!l)throw new Error("No active session found");let{controller:u,browserBehavior:d}=l,p=await e(a,n);n.info("Starting cloud recording");let m=new AbortController,h=await u.startRecordMode({params:{generator:p,logger:n,testId:s,orgId:a,callbacks:{onActionReceived:(g,f)=>{t.emit("stepRecorded",{stepId:c,step:g,offset:f})},onStepRecorded:(g,f)=>{t.emit("stepRecorded",{stepId:c,step:g,offset:f})}}},abortController:m,isClickToRecord:!1});d.recordingState={transformer:h}}},iP={event:"recordingStart",createHandler:WW};var qW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async()=>{let o=t.getSession(n);if(!o)throw new Error("No active session found");e.info("Stopping cloud recording"),await o.controller.stopRecordMode(),o.browserBehavior.recordingState=void 0,o.browserBehavior.showOverlay=!1}},aP={event:"recordingStop",createHandler:qW};var KW=({socket:r,metadata:e,logger:t,storageFactory:n,authorization:o,settingsFactory:i,globalE2eStateManager:a})=>async(s,c)=>{let{testId:l,sessionId:u,orgId:d}=e;t.info({testId:l,sessionId:u},"Refresh event received");let p=await i(d,t),m=await n(d),{baseUrl:h}=await Yi({testId:l,orgId:d,logger:t,storage:m,authorization:o,settings:p}),g=a.getSession(u);if(!g){r.emit("error",{message:"No session to refresh"});return}let{controller:f}=g;f.setOpen(),await f.browser.refresh();let y=f.browser.getViewport();t.info({baseUrl:h,viewport:y},`Session refreshed for test ${l} at ${h}`),c()},sP={event:"refresh",createHandler:KW};var YW=({socket:r,metadata:e,logger:t,storageFactory:n,authorization:o,settingsFactory:i,globalE2eStateManager:a})=>async()=>{let{testId:s,sessionId:c,orgId:l}=e;t.info({testId:s,sessionId:c},"Reset event received");let u=await i(l,t),d=await n(l),{baseUrl:p,envName:m,testName:h,environmentVariables:g}=await Yi({testId:s,orgId:l,logger:t,storage:d,authorization:o,settings:u}),f=a.getSession(c);if(!f){r.emit("error",{message:"No session to reset"});return}let{controller:y,context:S}=f;await y.browser.reset({newUrl:p});let T=y.browser.baseUrl;S.reset({baseUrl:T,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),v=Yr.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${T}`),r.emit("session",{url:T,userAgent:v,viewport:A,sessionId:c})},lP={event:"reset",createHandler:YW};var XW=({metadata:r,globalE2eStateManager:e})=>{let{sessionId:t}=r;return async({url:n})=>{let o=e.getSession(t);if(!o)throw new Error("No active session found");await o.controller.browser.switchToPage({type:"SUBSTRING",substring:n})}},cP={event:"switchTab",createHandler:XW};async function uP(r){return XI(r)}var dP=[bw,JI,ZI,lP,sP,yw,cP,QI,tP,iP,aP,oP,eP,rP,nP,Tw,Ew];var pP=r=>{let{logger:e}=r,t=new JW(r.baseServer,{cors:{origin:"*",methods:["GET","POST"]},pingTimeout:15*60*1e3,pingInterval:15*60*1e3,maxHttpBufferSize:1e7,perMessageDeflate:!0});return t.on("connection",async n=>{let o;try{e.info({event:"connection",transport:n.conn.transport.name},"Websocket connection established"),o=await uP({...r,socket:n,logger:e}),e=e.child(o)}catch(i){e.error({event:"connection",type:"websocket",err:i},"Failed to setup connection"),n.emit("error",{message:i instanceof Error?i.message:`${i}`}),n.disconnect(!0);return}dP.forEach(i=>QW(i,{...r,socket:n,metadata:o,logger:e}))}),t},QW=(r,e)=>{let t=r.createHandler(e),n=(...o)=>{["mouseMoveEvent","keyDownEvent","keyUpEvent","mouseClickEvent","lintStep"].includes(r.event)||e.logger.debug({...e.metadata,event:r.event},`Websocket event (${r.event})`);let i=a=>{e.logger.error({event:r.event,type:"websocket",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(i)}catch(a){i(a)}};e.socket.on(r.event,n)};import{Router as nq}from"express";import{Router as eq}from"express";import mc from"fs";import pc from"path";import{v4 as tq}from"uuid";import rq from"yaml";import{hostname as ZW}from"os";var dc="2.28.6",nt=Na({app:"desktop-server",hostname:ZW(),disableConsoleLogs:!0}).child({cliVersion:dc});(async()=>{try{let r=await no(nt);r.gitBranchName&&nt.addBinding("branch",r.gitBranchName)}catch{}})();var Es=eq();async function XS(r){return(await hd(r,nt)).map(n=>{let o=r.modules[n.moduleId];if(!o){E.warn(`Found a dangling module with ID ${n.moduleId} that could not be found on disk.`);return}return{...o,content:n}}).filter(n=>n!==void 0)}Es.get("/",Pe(async(r,e)=>{let t=se(),n=await ee(t),o=await XS(n);e.status(200).json(o)}));Es.post("/",Pe(async(r,e)=>{let t;try{t=Zb.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{bo(t.name)}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=se(),o=(await ee(n)).modules;if(Object.values(o).find(s=>s.name===t.name)){e.status(400).send(`A module with the name "${t.name}" already exists. Please choose a different name.`);return}let i=pc.join(n.rootDir,t.folderPath??"");if(!mc.existsSync(i)||!mc.statSync(i).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${i}' does not exist.`});return}let a=await md({...t,folder:i,project:n});e.status(201).json(a)}));Es.get("/:moduleId",Pe(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=await ee(se()),n=t.modules[r.params.moduleId];if(!n){e.status(404).json({error:"Module not found."});return}try{let o=await ln(n,t,E);e.json(o)}catch(o){e.status(400).json({err:o})}}));Es.post("/:moduleId/duplicate",Pe(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=Qb.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{bo(t.name)}catch(g){e.status(400).json({error:g.message});return}let n=se(),o=await ee(n),i=o.modules[r.params.moduleId];if(!i){e.status(404).json({error:"Module not found."});return}if(Object.values(o.modules).find(g=>g.name===t.name)){e.status(400).send(`A module with the name "${t.name}" already exists. Please choose a different name.`);return}let a=await ln(i,o,E),s=pc.join(n.rootDir,pc.dirname(i.relativePath));if(!mc.existsSync(s)||!mc.statSync(s).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${s}' does not exist.`});return}let c=Be(t.name),l=pc.join(s,`${c}.module.yaml`),u=tq(),{stepsToSave:d}=await it({stepLists:{steps:a.steps},createNewCacheIds:!0,cacheCreationParams:{orgId:Ct()}}),p={fileType:ge.MODULE,schemaVersion:xe,moduleId:u,name:t.name,description:"",enabled:!0,steps:d.steps,parameters:a.parameters,defaultParameters:a.defaultParameters,parameterEnums:a.parameterEnums,defaultCacheKey:a.defaultCacheKey,defaultCacheTtl:a.defaultCacheTtl,defaultCacheAllInvocations:a.defaultCacheAllInvocations,autoAuth:a.autoAuth,advanced:a.advanced},m=rq.stringify(p);mc.writeFileSync(l,m,"utf-8");let h={relativeFilePath:pc.relative(n.rootDir,l)};e.status(201).json(h)}));Es.patch("/:moduleId/metadata",Pe(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=ev.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=se(),o=await ee(n);WA({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:E,project:n}),e.status(201).json({message:"ok"})}));var mP=Es;var hP=nq();hP.get("/",Pe(async(r,e)=>{let t=se(),n=await ee(t),o=new Set;n?.tests&&Object.values(n.tests).forEach(l=>{l.labels?.forEach(u=>o.add(u))});let i=Array.from(o).sort(),a=Object.values(n.tests),s=await XS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var gP=hP;import{Router as oq}from"express";var JS=oq();JS.get("/",Pe((r,e)=>{let t=gd(se(),nt);e.status(200).json(t)}));JS.get("/names",Pe((r,e)=>{let n=se().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var fP=JS;import{Router as iq}from"express";var SP=iq();SP.get("/",Pe((r,e)=>{let t={userId:ko(),orgId:Ct(),cliVersion:dc??"0.0.0"};e.status(200).json(t)}));var yP=SP;import{StreamableHTTPServerTransport as TK}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as bK}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as vK}from"crypto";import{Router as RK}from"express";import{McpServer as yK}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as EK}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as uq}from"ai";import Wp from"dedent";import dq from"path";import{z as Qo}from"zod";import{tool as aq}from"ai";import{z as sq}from"zod";var EP=(r,e)=>({builder:n=>aq({description:r.schema.description,inputSchema:sq.object(r.schema.inputSchema),execute:async o=>{let i=e(n);n.logger.info({input:o},`Executing tool ${r.schema.name}`);try{await r.handle(n,o,i,void 0)}catch(s){i.addError(String(s))}let a=await i.serialize();return a.isError?n.logger.error({toolName:r.schema.name,input:o,err:a.content.map(s=>s.text).join(`
|
|
4364
|
+
${r}`;default:return r}}var vW=15;async function Bp({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=vW}){if(!r.assertion.trim())throw new M("ActionFailureError","Assertion command is missing the assertion content");let{browser:s}=n,c=r.timeout?r.timeout*1e3:s.smartWaitingTimeout,l=FA(c),u=0,d=Date.now(),p,m,h;try{await Wr({action:()=>s.clearHighlights(),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:s,logger:t})}catch(f){t.warn({err:f},"Failed to clear highlights before AI check, continuing...")}let g;for(;u<a&&(!g||g-d<c);){n.abortSignal.throwIfAborted(),u!==0&&await ie(l,n.abortSignal),g=Date.now();let f=!1;try{if(p=await Wr({action:async()=>{let S=await VI(s,t,n.abortSignal);return m&&m.serializedTree===S.serializedTree&&m.screenshotBuff.equals(S.screenshotBuff)?(f=!0,p):(m=S,$I({command:r,state:S,fixtures:n,useMemory:i,useConsensus:!1,highlightElementsOnFailure:!1,attemptNumber:u,aiPageFiltering:e,logger:t,source:o}))},frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,logger:t,browser:s}),p?.success){p?.updatedMemory&&wl(r,p.updatedMemory,t);break}else throw p?.thoughts?new M("AssertionFailureError",p.thoughts):new M("InternalPlatformError","No thoughts were provided for AI assertion failure")}catch(y){n.abortSignal.throwIfAborted(),h=y instanceof Error?y:new Error(`${y}`),f?t.info(`AI check attempt ${u} failed (re-used previous result)`):t.info({err:y},`AI check assert attempt ${u} failed, retrying...`)}finally{u++}}if(!p?.success)try{p=await Wr({action:async()=>$I({command:r,state:await VI(s,t,n.abortSignal),fixtures:n,useMemory:i,useConsensus:!0,highlightElementsOnFailure:!0,attemptNumber:u,aiPageFiltering:e,logger:t}),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,logger:t,browser:s})}catch(f){n.abortSignal.throwIfAborted(),h=f instanceof Error?f:new Error(`${f}`)}finally{u++}if(p?.updatedMemory&&wl(r,p.updatedMemory,t),!p?.success){let f=`AI check still failing after ${u} attempts.`;throw h&&(f+=` Latest result: ${h.message}`),new M("AssertionFailureError",f)}return{...p,succeedImmediately:!1,urlAfterCommand:s.url()}}async function VI(r,e,t){let[n,o]=await Promise.all([Dn(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function $I({command:r,state:e,fixtures:t,useConsensus:n,useMemory:o,highlightElementsOnFailure:i,aiPageFiltering:a,attemptNumber:s,source:c,logger:l}){let{browser:u,generator:d,abortSignal:p}=t,m={type:"ASSERTION"},{serializedTree:h,tree:g}=e,f=e.screenshotBuff,y=f.toString("base64"),S=u.url(),T=r.contextChoice??"MULTIMODAL",A=h;T!=="VISION_ONLY"&&(A=await Ki({type:"assertion",serializedTree:h,tree:g,description:r.assertion,screenshot:y,options:{aiPageFiltering:a},fixtures:{generator:d,signal:p,logger:l,orgId:t.orgId}}),A!==h&&(m.ragUsed=!0),m.pageState=A);let v={goal:r.assertion,url:S,memory:o?r.cache?.memory:void 0,browserState:A,screenshot:y,contextChoice:T,source:c},x=await(T==="VISION_ONLY"?(_,D)=>d.getVisualAssertionResult(_,D):(_,D)=>d.getAssertionResult(_,D))(v,{useConsensus:n,attemptNumber:s,useMemory:o,disableCache:!!r.disableCache,abortSignal:p,logger:l,loggerTags:Ge(l)});return(x.result||i)&&x.relevantElements&&(m.relevantElementsSerialized=x.relevantElements.map(_=>u.getSerializedFormFromA11yId(_)).filter(_=>!!_),await RW(x.relevantElements,u,l)),{success:x.result,thoughts:x.thoughts,afterScreenshotOverride:f,updatedMemory:o?x.updatedMemory:void 0}}async function RW(r,e,t){let n=Date.now();for(let o of r){if(Date.now()-n>2e3){t.debug("Highlighting relevant elements took over 2s, aborting...");return}try{let i=new AbortController;await $(e.highlightA11yId(o),{milliseconds:1e3,fallback:()=>{throw i.abort(),new Error("Timed out waiting for highlighting to complete")}})}catch(i){t.debug({err:i},"Failed to highlight relevant element after assertion, continuing...");return}}}var AW=75e4,zp=class extends Error{constructor(){super("The page content exceeds the maximum token limit for AI smart waiting."),this.name="ExceededMaxAISmartWaitingTokensError"}};async function WI(r,e){let{logger:t}=r,{abortSignal:n,browser:o}=e,i=Date.now();try{await wW(i,r,e)}catch(a){if(a instanceof Error&&(a.name==="AbortError"||a.name==="TimeoutError")||n.aborted)return;a instanceof zp?t.warn("Skipping AI smart waiting due to excessive page size - falling back to naive waiting"):t.warn({err:a},"Unexpected error occurred during AI smart waiting");let s=o.smartWaitingTimeout-(Date.now()-i);s>0&&await ie(s,n)}finally{t.debug({durationMs:Date.now()-i},"AI smart waiting complete")}}async function wW(r,e,t){let{abortSignal:n,browser:o}=t;if(o.smartWaitingTimeout<3e3){await ie(o.smartWaitingTimeout,n);return}if(!e.description)throw new M("UserConfigurationError","Cannot locate element with empty description");await $(CW(r,e,t),{milliseconds:o.smartWaitingTimeout})}async function CW(r,e,t){let{logger:n,iframeUrl:o}=e,{browser:i}=t;for(;Date.now()-r<i.smartWaitingTimeout;)if(await Wr({action:async()=>xW(e,t),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function xW(r,e){let{testContext:t,logger:n,filterByViewport:o,allowNotActionableNodesOverride:i}=r,{browser:a,abortSignal:s,localCodeEvalTools:c,orgId:l,generator:u}=e,d=r.description;t&&(d=await dr({orgId:l,s:d,context:t,localTools:c,signal:s,logger:n}));let{serializedTree:p}=await Dn(a,{allowNotActionableNodesOverride:i,filterByViewport:o,abortSignal:s,logger:n});if(Me(p)>AW)throw new zp;s.throwIfAborted();let h;try{h=await a.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(S){throw new M("ActionFailureError",`Failed to take screenshot of page to perform smart waiting. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${S instanceof Error?S.message:S}`)}let f=`data:image/jpeg;base64,${h.toString("base64")}`;s.throwIfAborted();let y=await u.getSmartWaitingDecision({browserState:p,description:d,screenshot:f},{abortSignal:s,loggerTags:Ge(n)});return n.debug({result:y},"Got smart waiting result"),y.isPageReady}var _W=3e4;async function qI({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??_W/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(r.headers||{}).filter(([d,p])=>d&&p));a["Content-Type"]="application/json";let s;if(Va(r.url)&&(s=r.url),t&&$a(r.url,t)&&(s=new URL(r.url,t).toString()),!s)throw new M("ActionFailureError",`Invalid URL: ${r.url}`);let l=await $((async()=>{try{return await n(s,{headers:a,method:"POST",body:JSON.stringify({query:r.query,variables:r.variables?JSON.parse(r.variables):void 0}),signal:i.signal})}catch(d){e.error({err:d},"Failed to make HTTP request")}})(),{milliseconds:o*1e3});if(!l)throw new M("ActionFailureError",`GraphQL request timed out after ${o} seconds`);if(!l.ok){let d,p=await l.text();try{d=JSON.parse(p)}catch{throw new M("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}throw d?.errors?.length&&d?.errors[0]?.message?new M("ActionFailureError",`GraphQL request failed with status ${l.status}: ${d.errors[0].message}`):new M("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}let u={};return l.headers.forEach((d,p)=>{u[p]=d}),{status:l.status,headers:u,json:await l.json()}}var Jo=class{orgId;options;storage;localCodeEvalTools;uploadedFileStorage;visualDiffScreenshotStorage;browser;generator;executeAbortController=new AbortController;logger;recordAbortController=null;registeredListeners={};recordedRequests={};constructor({browser:e,generator:t,logger:n,storage:o,orgId:i,localCodeEvalTools:a,uploadedFileStorage:s,visualDiffScreenshotStorage:c,options:l}){this.orgId=i,this.options=l,this.browser=e,this.browser.registerAbortSignal(this.executeAbortController.signal),this.storage=o,this.uploadedFileStorage=s,this.visualDiffScreenshotStorage=c,this.localCodeEvalTools=a,this.generator=t,this.logger=n}setOpen(){this.executeAbortController=new AbortController,this.browser.registerAbortSignal(this.executeAbortController.signal)}setClosed(){this.executeAbortController.abort()}throwIfClosed(){this.executeAbortController.signal.throwIfAborted()}get closed(){return this.executeAbortController.signal.aborted}async evaluateAiAction({goal:e,startingScreenshot:t,history:n,disableCache:o,langfuseSessionId:i,lastError:a,logger:s=this.logger}){let[c,l]=await Promise.all([Dn(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:!0,skipWaitForPageLoad:!0,logger:s}),this.browser.screenshot({retries:1,clearHighlights:!0})]),u=`data:image/jpeg;base64,${l.toString("base64")}`,d=await Ki({type:"ai-action",description:e,screenshot:u,serializedTree:c.serializedTree,tree:c.tree,options:{aiPageFiltering:!!this.options?.aiPageFiltering},fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:s,orgId:this.orgId}}),p={url:this.browser.url(),browserState:d,startingScreenshot:t,history:n,goal:e,screenshot:u,lastError:a};return await this.generator.getMultiturnAiActionEvaluation(p,{disableCache:o,abortSignal:this.executeAbortController.signal,loggerTags:{...Ge(s)},langfuseSessionId:i})}async promptToCommand({goal:e,startingScreenshot:t,history:n,actionHint:o,disableCache:i,logger:a=this.logger,langfuseSessionId:s}){let c=this.browser.url(),[l,u]=await Promise.all([Dn(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:!0,skipWaitForPageLoad:!0,logger:a}),this.browser.screenshot({retries:1,clearHighlights:!0})]),d=`data:image/jpeg;base64,${u.toString("base64")}`,p=await Ki({type:"ai-action",description:e,screenshot:d,serializedTree:l.serializedTree,tree:l.tree,options:{aiPageFiltering:!!this.options?.aiPageFiltering},fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:a,orgId:this.orgId}}),m={url:c,browserState:p,startingScreenshot:t,history:n,goal:e,actionHint:o,screenshot:d};try{return await this.generator.getMultiturnAiActionCommand(m,{disableCache:i,abortSignal:this.executeAbortController.signal,loggerTags:{...Ge(a)},langfuseSessionId:s})}catch(h){throw new M("InternalWebAgentError",`Error generating command: ${h instanceof Error?h.message:h}`,{errOptions:{cause:h}})}}async getBrowserState(e){return Dn(this.browser,e)}async locateElement(e){return await qS({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return Wr({action:async()=>{let n=await this.browser.resolveHardcodedCssSelector({ctx:null,selector:e,timeoutMs:2e3,logger:this.logger});return{thoughts:"Located element with selector",target:{id:-1,selector:e,targetSource:"USER_CSS_SELECTOR",targetUpdateTime:new Date().toUTCString()},resolution:n}},frameConfig:t?{type:"url",url:t}:void 0,browser:this.browser,logger:this.logger})}getControllerFixtures(e){return{ctx:e??null,browser:this.browser,generator:this.generator,logger:this.logger,orgId:this.orgId,storage:this.storage,localCodeEvalTools:this.localCodeEvalTools,abortSignal:this.executeAbortController.signal}}shouldUseMemory(){return this.options?.useMemory??(this.orgId==="org_01HMSCJQBCCG51M2ZF65YC5B8W"||this.orgId==="org_01HMJTX4GT1KG94KZRCT8MZ6YB")}async wrapMultiElementTargetingCommand({ctx:e,tracer:t,command:n,targetNames:o,descriptions:i,caches:a,action:s,options:c,retriesWithAI:l=1}){let u=[];for(let d=0;d<i.length;d++){let p=i[d],m=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:p,cache:a[d],action:async h=>h,options:{...c,targetName:o[d]}});u.push(m)}try{let d=await s(...u.map(h=>h.result)),p=h=>h==="fromTarget"?"From Target":h==="toTarget"?"To Target":"Target",m=u.map((h,g)=>h.thoughts?`${p(o[g])}: ${h.thoughts}`:void 0).filter(h=>!!h).join(" -------------- ")||void 0;return{result:d,elementInteractedDisplayStrings:u.map(h=>h.elementInteractedDisplayString),thoughts:m}}catch(d){if(this.throwIfClosed(),l>0)return this.logger.warn({err:d},"Failed to execute action with multiple cached targets, retrying with AI"),this.wrapMultiElementTargetingCommand({ctx:e,tracer:t,command:n,targetNames:o,descriptions:i,caches:i.map(()=>{}),action:s,options:c,retriesWithAI:l-1});throw new M("ActionFailureError",d.message,{errOptions:{cause:d}})}}async wrapElementTargetingCommand(e){let t=this.logger.child({commandId:e.command.id}),n;for(let o=0;o<2;o++)try{return await Wr({action:()=>this.wrapElementTargetingCommandHelper({...e,originalCache:e.originalCache??e.cache}),frameConfig:e.options.iframeUrl?{type:"url",url:e.options.iframeUrl}:void 0,browser:this.browser,logger:t})}catch(i){if(n=i,this.browser.userBrowserSettings.visualActions&&Vm(i)){t.warn({err:i},"Invalid mpath error, retrying element targeting command");continue}if(!this.browser.userBrowserSettings.visualActions&&(qm(i)||$m(i))){t.warn({err:i},"Invalid momentic id error, retrying element targeting command");continue}if(Km(i)){t.warn({err:i},"Invalid backend node id error, retrying element targeting command");continue}if(i instanceof Tn&&i.retryableWithAI){t.warn({err:i},"Element cache disqualification error, retrying element targeting command");continue}throw i}throw n instanceof M?n:new M("ActionFailureError",n?.message??"An unknown error occurred during element targeting")}async wrapHardcodedCssTargetingCommandHelper({ctx:e,target:t,action:n,options:o,command:i}){let a=this.logger.child({commandId:i.id}),{targetName:s}=o;if(t.type!=="description")throw new M("ActionFailureError","Cannot use selector with non-description target");let c,l=Date.now(),u=Date.now();for(;Date.now()-u<this.browser.smartWaitingTimeout;){l=Date.now();try{let d=await this.browser.resolveHardcodedCssSelector({ctx:e,selector:t.elementDescriptor,targetName:s,logger:a});return{result:await n({locator:d.locator}),elementInteractedDisplayString:d.displayString}}catch(d){if(d.name==="AbortError")throw d;c=d,a.warn({err:d},"Failed to action on hardcoded css selector"),Date.now()-l<500&&await ie(500)}}throw c}async wrapElementTargetingCommandHelper(e){let{ctx:t,tracer:n,target:o,originalCache:i,action:a,options:s,command:c}=e,{disableCache:l,useSelector:u,targetName:d,targetHealingInProgress:p,source:m}=s,h=this.logger.child({commandId:c.id}),g=this.shouldUseMemory(),f=s.retriesWithAI??1,y=!1,S=KI(e.cache);if((!S||l)&&!Mm(o))throw new M("ActionFailureError","Cannot target element with no cached data or element descriptor");if(u)return this.wrapHardcodedCssTargetingCommandHelper(e);l&&(h.info("Cache explicitly disabled for this step"),y=!0,S=void 0),S&&this.browser.userBrowserSettings.disableSecondaryCacheResolution&&S.targetSource==="HEURISTIC_HEALED"&&(y=!0,S=void 0),S?.inputDescription&&!jI(o.elementDescriptor,S.inputDescription)&&(h.warn({old:S.inputDescription,new:o.elementDescriptor},"Target cache was generated with a different description, clearing it automatically"),y=!0,S=void 0);let T=v=>!!v&&Mc(v),A=!0;if(!T(S)){A=!1,h.info({description:o.elementDescriptor,targetHealingInProgress:p,cacheBustedBeforeAction:y,memory:s.memory,useMemory:g},"Prompting AI for an updated element location"),(y||!i)&&await WI({description:o.elementDescriptor,iframeUrl:s.iframeUrl,source:m,logger:h,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride},this.getControllerFixtures(t)),f--;let v;try{v=await qS({description:o.elementDescriptor,disableCache:!!s.disableCache,iframeUrl:s.iframeUrl,source:m,useMemory:g,memory:g?s.memory:void 0,aiPageFiltering:!!this.options?.aiPageFiltering,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride,logger:h},this.getControllerFixtures(t))}catch(_){if(_ instanceof Sa&&_.updatedLocatorMemory){let D={id:-1,...i,memory:_.updatedLocatorMemory};Ku({cmd:c,key:d,newTarget:D,logger:h,updatedWithAI:!0})}throw new M("ActionFailureError",_.message)}v.frameConfig&&this.browser.setActiveFrameConfig(v.frameConfig);let w=s.disableGlobalLocatorRedirect?{locator:v.resolution.locator}:await this.attemptLocatorRedirect(v.resolution.locator,h),x=await a(w);return Ku({cmd:c,key:d,newTarget:v.target,logger:h,updatedWithAI:!0}),p&&(n.recordTargetAutoHeal({healType:"AI"}),v.target.targetSource="AI_HEALED",v.target.targetUpdateTime=new Date().toUTCString(),v.target.targetUpdateLoggerTags=Ge(h)),{result:x,elementInteractedDisplayString:v.resolution.displayString,thoughts:v.thoughts}}try{let v=await this.browser.resolveTarget(t,S,{allowNotActionableNodesOverride:s.allowNotActionableNodesOverride,targetName:d,logger:h,signal:this.executeAbortController.signal});(this.browser.userBrowserSettings.visualActions||this.browser.userBrowserSettings.globalLocatorRedirect!==!1)&&await this.browser.scrollIntoViewIfNeeded(v.locator);let w=s.disableGlobalLocatorRedirect?{locator:v.locator}:await this.attemptLocatorRedirect(v.locator,h),x=await a(w);if(kt.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.7"]),Ku({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let _=v.decisions.filter(D=>D.matched);if(_.length!==1)h.warn({decisions:v.decisions},"Expected exactly 1 matching method for element location, got more or less");else{let D=_[0].type;n.recordTargetAutoHeal({healType:D})}}return{result:x,elementInteractedDisplayString:v.displayString}}catch(v){this.throwIfClosed();let w="unknown";v instanceof Or&&v.cacheMissReason&&(w=v.cacheMissReason),kt.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.7",`missReason:${w}`]);let x=!1;if((v instanceof Tn||Vm(v)||qm(v)||Km(v)||JE(v)||$m(v)||QE(v))&&(x=!0),v instanceof M&&!x)throw h.error({err:v},"Failed to execute action with cached target (fatal)"),v;if(f>0&&o){h.info({err:v},"Failed to execute action with cached target, retrying with AI");let _;return S.memory&&Ic(S.memory)&&(_=S.memory),this.wrapElementTargetingCommand({ctx:t,tracer:n,command:c,target:o,cache:void 0,originalCache:i,action:a,options:{...s,memory:_,retriesWithAI:f,targetHealingInProgress:!0}})}throw new M("ActionFailureError",v.message,{errOptions:{cause:v}})}}async attemptLocatorRedirect(e,t){return this.browser.userBrowserSettings.globalLocatorRedirect!==!1?this.browser.performTargetRedirection(e,t):{locator:e}}async screenshotWithDimensions(e){return Fl(this.browser,e)}async executePresetCommand(e,t,n,o,i){this.options?.slowMoMs&&await ie(this.options.slowMoMs);let a=await this.browser.getOpenPages(),s=this.browser.url(),c;try{c=await this.resolveCommandTemplateStrings(n,o)}catch(l){throw this.throwIfClosed(),new M("ActionFailureError",`Failed to substitute template strings in command: ${l.message}`,{errOptions:{cause:l}})}try{let l=await this.executePresetCommandHelper(e,t,n,o,i);return this.browser.userBrowserSettings.visualActions&&mE(n)?await this.browser.waitForDOMStability({timeout:Le}):!this.browser.userBrowserSettings.visualActions&&["PRESS","TYPE"].includes(n.type)&&await this.browser.waitForDOMStability({timeout:ce}),this.options?.autoFollowNewTabs&&await aM({beforeUrl:s,command:n,beforePages:a.map(u=>u.url),browser:this.browser,logger:this.logger}),l}catch(l){throw l.name!=="AbortError"&&this.logger.error({err:l},"Error thrown in action controller"),l}finally{Mw(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>yS(e)}}async resolveCommandTemplateStrings(e,t){return vd({obj:e,context:t,bannedKeys:["type","a11yData","thoughts","cache","code"],orgId:this.orgId,logger:this.logger,signal:this.executeAbortController.signal,localTools:this.localCodeEvalTools})}async executePresetCommandHelper(e,t,n,o,i){i=i||"disableCache"in n&&!!n.disableCache;let a=this.logger.child({commandId:n.id});switch(n.type){case"SUCCESS":let s=n.condition;return s?.assertion.trim()?Bp({command:s,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a}):{succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"AI_ASSERTION":{if(!n.assertion.trim())throw new M("ActionFailureError","Missing assertion");if(n.timeout&&n.timeout>1800)throw new M("AssertionFailureError",`AI check timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);return Bp({command:n,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a})}case"AI_EXTRACT":{if(!n.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(n.schema){let f=uR(n.schema);if(f)throw new M("UserConfigurationError",f)}let h=await this.browser.getCondensedHtml(),g=await this.browser.screenshot({retries:2});try{let f=await this.generator.getTextExtraction({goal:n.goal,browserState:h,returnSchema:n.schema,screenshot:`data:image/jpeg;base64,${g.toString("base64")}`},{disableCache:i,abortSignal:this.executeAbortController.signal,loggerTags:Ge(a)});if(f.result==="NOT_FOUND")throw new M("ActionFailureError","No relevant data found for extraction goal on this page");if(f.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",f.thoughts);return{thoughts:f.thoughts||void 0,data:f.result,succeedImmediately:!1,urlAfterCommand:this.browser.url()}}catch(f){let y=f.message;throw y.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step in the browser instead."):y.includes("AIProviderError")&&y.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:f}}):f}}case"NAVIGATE":if(!Va(n.url)&&!$a(n.url,this.browser.baseUrl))throw new M("ActionFailureError",`Invalid URL provided to navigate command: ${n.url}`);await this.browser.navigate({url:n.url,loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"DIALOG":this.browser.registerDialogHandler(n.action);break;case"CAPTCHA":if(!this.browser.canSolveCaptchas())break;let c=await this.browser.solveCaptcha();c&&(await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:{type:"description",elementDescriptor:"the captcha image solution input"},cache:void 0,action:h=>this.browser.click(h,this.createCallbacksForBrowser(this.orgId),{}),options:{...n,targetName:"target",disableCache:i}}),await this.browser.type(c,{clearContent:!0,pressEnter:!0},!0));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 h,g;if(n.target&&Sn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:T}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:A=>this.browser.hover(A),options:{...n,targetName:"target",disableGlobalLocatorRedirect:!0,disableCache:i}});h=S,g=T}let f=this.browser.getViewport()?.height??Yt.height,y=this.browser.getViewport()?.width??Yt.width;switch(n.type){case"SCROLL_UP":await this.browser.scrollVertical(-(n.deltaY??f));break;case"SCROLL_DOWN":await this.browser.scrollVertical(n.deltaY??f);break;case"SCROLL_LEFT":await this.browser.scrollHorizontal(-(n.deltaX??y));break;case"SCROLL_RIGHT":await this.browser.scrollHorizontal(n.deltaX??y);break}return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"WAIT_FOR_URL":{if(n.timeout&&n.timeout>1800)throw new M("UserConfigurationError",`Wait for URL timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);let h=n.matcher;await this.browser.waitForUrl({beforeUrl:this.browser.url(),matcher:h},{timeout:n.timeout?n.timeout*1e3:void 0,negated:n.negated,caseInsensitive:n.caseInsensitive});break}case"WAIT":if(n.delay>1800)throw new M("UserConfigurationError",`Wait timeout of ${n.delay} seconds exceeds the maximum allowed value of 30 minutes`);let l=n.delay*1e3;await ie(l,this.executeAbortController.signal);break;case"REFRESH":await this.browser.refresh({loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"CLICK":{if(Sn(n.target)){await this.browser.clickUsingVisualCoordinates(n.target.pixels,n);break}let h=this.browser.url(),{elementInteractedDisplayString:g,result:f,thoughts:y}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,target:n.target,command:n,cache:n.cache?.target,action:T=>this.browser.click(T,this.createCallbacksForBrowser(this.orgId),n),options:{disableCache:i,targetName:"target",...n}}),S={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:y,data:f.downloadedFile?{downloadedFile:f.downloadedFile}:void 0};return sd(h,S.urlAfterCommand)&&(S.succeedImmediately=!0,S.succeedImmediatelyReason="URL changed"),S}case"COPY":return await this.browser.copy(n.value),{succeedImmediately:!1,data:n.value,urlAfterCommand:this.browser.url()};case"PASTE":{await this.browser.paste();break}case"DRAG":{if(Sn(n.fromTarget)&&Sn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(Sn(n.fromTarget)||Sn(n.toTarget))throw new Error("Drag and drop targets must be both coordinates or both descriptions");let{elementInteractedDisplayStrings:h,thoughts:g}=await this.wrapMultiElementTargetingCommand({ctx:e,tracer:t,command:n,targetNames:["fromTarget","toTarget"],descriptions:[n.fromTarget,n.toTarget],caches:[n.cache?.fromTarget,n.cache?.toTarget],action:(f,y)=>this.browser.dragAndDrop(f.locator,y.locator,{hoverSeconds:n.hoverSeconds,steps:n.steps}),options:{useSelector:!!n.useSelector,disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h[0],thoughts:g}}case"MOUSE_DRAG":{let h=parseInt(n.deltaX),g=parseInt(n.deltaY),f=n.steps??5;if(isNaN(h)||isNaN(g))throw new M("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${n.deltaX}, ${n.deltaY})`);if(n.target&&Sn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,void 0,n.target.pixels);break}let y,S;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:T,thoughts:A}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async v=>this.browser.mouseDrag(h,g,f,v.locator,{force:n.force}),options:{disableCache:i,targetName:"target",...n}});y=T,S=A}else await this.browser.mouseDrag(h,g,f,void 0,{force:n.force});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:y,thoughts:S}}case"SELECT_OPTION":{if(!So(n.target))throw new Error("Select with x/y is not supported yet");let h=n.target.elementDescriptor,g=n.choice,{elementInteractedDisplayString:f,thoughts:y}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:{type:"description",elementDescriptor:h},cache:n.cache?.target,action:S=>this.browser.selectOption(S,g,n.force),options:{...n,targetName:"target",disableCache:i,source:gi(n)}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:f,thoughts:y}}case"TAB":{let h={loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0,retry:!0};await this.browser.switchToPage(n.action,h);break}case"NEW_TAB":await this.browser.createNewTab(n.url,{loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"COOKIE":if(!n.value)break;let u=await this.browser.setCookie(n.value);a.debug({results:u},"Set cookies");break;case"LOCAL_STORAGE":if(!n.value||!n.key)break;await this.browser.setLocalStorage(n.key,n.value);break;case"JAVASCRIPT":{let h;try{n.environment==="BROWSER"?(h=await this.browser.evaluateCodeInPage({code:n.code,fragment:n.fragment??!1,context:o.toObjectCopy(),timeoutMs:n.timeout?n.timeout*1e3:void 0}),a.info({result:h},"Executed JavaScript in browser")):h=await zo({orgId:this.orgId,code:n.code,fragment:!!n.fragment,context:o,timeoutMs:n.timeout?n.timeout*1e3:void 0,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal,callbacks:{onPersistentVariableUpdates:async g=>{if(!this.options?.scratchPadId){a.warn({updates:g},"Got persistent variable updates but scratch pad is not available");return}await this.storage.savePersistentVariables?.({scratchPadId:this.options?.scratchPadId,orgId:this.orgId,updates:g,logger:a})}}})}catch(g){throw this.throwIfClosed(),new M("ActionFailureError",g instanceof Error?g.message:`${g}`,{errOptions:{cause:g}})}try{JSON.stringify(h)}catch(g){throw new M("ActionFailureError",`Return value is not serializable: ${g instanceof Error?g.message:`${g}`}`,{errOptions:{cause:g}})}return{urlAfterCommand:this.browser.url(),succeedImmediately:!1,data:h}}case"TYPE":{if(n.target&&Sn(n.target)){await this.browser.clickUsingVisualCoordinates(n.target.pixels,n),await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);break}let h=this.browser.url(),g,f,y=KI(n.target),S=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(y){let{elementInteractedDisplayString:A,thoughts:v}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:y,cache:n.cache?.target,action:w=>this.browser.typeIntoTarget(n.value,w,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter,relativePosition:n.relativePosition}),options:{...n,targetName:"target",disableCache:i,disableGlobalLocatorRedirect:!S,source:gi(n)}});g=A,f=v}else await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);let T={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return sd(h,T.urlAfterCommand)&&(T.succeedImmediately=!0,T.succeedImmediatelyReason="URL changed"),T}case"HOVER":{if(Sn(n.target)){await this.browser.hoverUsingVisualCoordinates(n.target.pixels);break}let{elementInteractedDisplayString:h,thoughts:g}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:f=>this.browser.hover(f),options:{...n,targetName:"target",disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"FOCUS":{if(!So(n.target))throw new Error("Focus with x/y is not supported yet");let{elementInteractedDisplayString:h,thoughts:g}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:f=>this.browser.focus(f),options:{...n,targetName:"target",disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"BLUR":{if(n.target&&!So(n.target))throw new Error("Blur with x/y is not supported yet");if(!n.target||!n.target.elementDescriptor)return await this.browser.blur(null),{succeedImmediately:!1,urlAfterCommand:this.browser.url()};let{elementInteractedDisplayString:h,thoughts:g}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,target:n.target,command:n,cache:n.cache?.target,action:f=>this.browser.blur(f),options:{...n,targetName:"target",disableCache:i}});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:h,thoughts:g}}case"PRESS":let d=this.browser.url();await this.browser.press(n.value,{repeat:n.repeat,convertMeta:n.convertMeta??!0,delayMs:n.delayMs});let p={urlAfterCommand:this.browser.url(),succeedImmediately:!1};return sd(d,p.urlAfterCommand)&&(p.succeedImmediately=!0,p.succeedImmediatelyReason="URL changed"),p;case"KEY_DOWN":return await this.browser.keyDown(n.value,{convertMeta:n.convertMeta??!0}),{urlAfterCommand:this.browser.url(),succeedImmediately:!1};case"KEY_UP":return await this.browser.keyUp(n.value,{convertMeta:n.convertMeta??!0}),{urlAfterCommand:this.browser.url(),succeedImmediately:!1};case"REQUEST":{let h=new IW,g=MW(fetch,h),f;try{f=new URL(n.url).hostname}catch{}let y=await kw({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g});return{data:Gs.parse({...y,cookies:bb(h,f)}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await qI({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return Dw({ctx:e,tracer:t,command:n,disableCache:i,browser:this.browser,logger:a,storage:this.storage,screenshotStorage:this.visualDiffScreenshotStorage,targetingWrapper:h=>this.wrapElementTargetingCommand(h)});case"FILE_UPLOAD":{let h,g;if(n.fileSource.type==="URL"?(g=n.fileSource.url,h=await vM({uri:n.fileSource.url,logger:a,orgId:this.orgId})):n.fileSource.type==="USER_FILE"&&(g=n.fileSource.name,h=await this.uploadedFileStorage?.getFileForUpload(n.fileSource.name,this.orgId)),!h)throw new M("UserConfigurationError",`Attempted to use non-existent file for upload step: ${g}`);await this.browser.setFileChooserHandler({...h,filename:n.filename});break}case"AUTH_SAVE":return{data:await this.browser.saveAuthState(),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"AUTH_LOAD":{let h;if(!n.storageState.trim())h=void 0;else if(h=await zo({orgId:this.orgId,code:n.storageState,fragment:!1,context:o,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof h!="object")throw new M("ActionFailureError",`Credentials must evaluate to an object (received ${typeof h} instead)`);let g;try{g=gu.optional().parse(h)}catch(f){throw new M("ActionFailureError",`Credentials provided do not follow the required format: ${f}`)}await this.browser.loadAuthState(g);break}case"ELEMENT_CHECK":{let h=(n.timeout??yn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(Lw(n.assertion)&&!n.useSelector&&n.target.type==="description"&&g&&g!=="v1"){let y={id:n.id,type:"AI_ASSERTION",assertion:`There is no element on the page closely matches the following description. If the description has single quotes, remember that requires an exact text substring match. Description: ${n.target.elementDescriptor}`,iframeUrl:n.iframeUrl,timeout:n.timeout,cache:n.cache&&"memory"in n.cache?{memory:n.cache?.memory}:void 0};try{let S=await Bp({command:y,logger:a,aiPageFiltering:!!this.options?.aiPageFiltering,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),source:"NEGATED_CHECK"});return{succeedImmediately:!1,thoughts:`The element described does not exist on the page: ${S.thoughts}`,urlAfterCommand:this.browser.url(),afterScreenshotOverride:S.afterScreenshotOverride}}finally{y.cache?.memory&&wl(n,y.cache?.memory.traces,a)}}let f=await Ow({command:n,tracer:t,timeoutMs:h,targetingWrapper:y=>this.wrapElementTargetingCommand(y),fixtures:this.getControllerFixtures(e),disableCache:i});return{fail:!f.success,data:f.data,elementInteracted:f.elementInteractedDisplayString,thoughts:f.err?.message??f.thoughts??`Element assertion ${f.success?"succeeded":"failed"}.`,succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"PAGE_CHECK":{let h=await Wr({action:async()=>Rd({assertion:n.assertion,browser:this.browser,logger:a,timeout:n.timeout,signal:this.executeAbortController.signal,autoExpandIframes:!!this.browser.userBrowserSettings.autoExpandIframes}),frameConfig:n.iframeUrl?{type:"url",url:n.iframeUrl}:void 0,browser:this.browser,logger:a});return{fail:!h.success,data:h.data,thoughts:h.success?"Page assertion passed.":h.err?.message??`Page assertion still failing after ${n.timeout} seconds.`,urlAfterCommand:this.browser.url(),succeedImmediately:!1}}case"REGISTER_REQUEST_LISTENER":{let h=new Ko(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await RS(f)).catch(f=>{a.error({err:f},"Failed to get request listener response")}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"AWAIT_LISTENER":{let h=this.registeredListeners[n.key];if(!h)throw new M("ActionFailureError",`No listener registered with key: ${n.key}`);let g=n.timeout??10;return{data:await $(h,{milliseconds:g*1e3,message:`Request listener timed out after ${g} seconds`}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"RECORD_REQUESTS":{let h=new Ko(n.requestMatcher);return this.recordedRequests[n.key]={},this.browser.registerRequestRecorder(n.key,{matches:g=>h.matches({url:g.request.url,method:g.request.method}),onRequestStart:(g,f)=>{this.recordedRequests[n.key][g]=_p(f)},onRequestComplete:(g,f)=>{this.recordedRequests[n.key]?.[g]&&(this.recordedRequests[n.key][g]=_p(f))}}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GET_RECORDED_REQUESTS":{let h=this.recordedRequests[n.key];if(!h)throw new M("ActionFailureError",`No recorder registered with key: ${n.key}`);return delete this.recordedRequests[n.key],{data:Object.values(h),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"SET_HEADER":{let h;return n.requestMatcher&&(h=new Ko(n.requestMatcher)),this.browser.setHeader(n.name,n.value,h),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"MOCK_ROUTE":return{data:{key:this.browser.registerMock(n.key,new Ko(n.requestMatcher),async(g,f)=>{let y=await zo({orgId:this.orgId,code:n.responseGenerator,fragment:!1,context:o,timeoutMs:void 0,logger:a,localTools:this.localCodeEvalTools,mock:{request:g,response:f},disallowVariableUpdates:!0,responseSerialization:"RESPONSE"}),S=Bb.parse(y);return new Response(S.body,{status:S.status,headers:S.headers})},n.fetchOriginalResponse??!1)},succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"REMOVE_ROUTE_MOCK":return this.browser.removeMock(n.key),{succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"OFFLINE_MODE":return await this.browser.setOfflineMode(n.enable),{succeedImmediately:!1,urlAfterCommand:this.browser.url()};default:return(h=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(n)}return{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}async getReverseMappedDescription({browserState:e,targetId:t,disableCache:n,screenshot:o}){return(await this.generator.getReverseMappedDescription({browserState:e,target:t,screenshot:o},{disableCache:n,abortSignal:this.executeAbortController.signal,loggerTags:Ge(this.logger)})).phrase}async stopRecordMode(){this.recordAbortController?.abort(),await this.browser.clearAllCdpHighlights()}async startRecordMode({params:e,abortController:t,isClickToRecord:n}){this.recordAbortController=t;let o=new Np({signal:t.signal,...e});return await this.browser.startRecording(this.recordAbortController.signal,o,n),o}async runSectionAutohealing(e){return this.generator.getAutohealingProposal(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:Ge(this.logger)})}async getFailureRecoveryPlan(e){return this.generator.getFailureRecoveryPlan(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:Ge(this.logger)})}};import{cloneDeep as PW}from"lodash-es";var OW={showOverlay:!1},Hp=class{sessions=new Map;sessionCountByIp=new Map;getCurrentConnectionsByIp(e){return this.sessionCountByIp.get(e)??0}getCurrentSessionsByIp(){return Object.fromEntries(this.sessionCountByIp)}reserveCapacityByIp(e){e&&this.sessionCountByIp.set(e,(this.sessionCountByIp.get(e)??0)+1)}releaseCapacityByIp(e){e&&this.sessionCountByIp.set(e,Math.max(this.getCurrentConnectionsByIp(e)-1,0))}registerSession({controller:e,context:t,cleanup:n,clientIp:o,sessionId:i,socket:a}){return this.sessions.set(i,{controller:e,context:t,cleanup:n,clientIp:o,browserBehavior:PW(OW),socket:a}),i}removeSession(e,t){(async()=>{let o=this.sessions.get(e);if(!o)return;this.releaseCapacityByIp(o.clientIp);let{controller:i}=o;try{i.setClosed(),await i.browser.cleanup()}catch(a){t.error({err:a},"Error cleaning up browser in global state manager")}try{await o.cleanup?.()}catch(a){t.error({err:a},"Error running cleanup function in global state manager")}this.sessions.delete(e)})()}getSession(e){return this.sessions.get(e)}};function YI(r,e,t,n){let o=Date.now(),i=Date.now(),a,s,c,l,u=!1,d=async(g,f)=>{if(!g.closed&&!g.isInPageLoad)try{let y=c;c=void 0;let S=g.url(),T=f.toEditorDisplayCopy();JSON.stringify(T)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:T,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=T}catch(y){if(!r.connected)return;let S=y instanceof Error?y.message:`${y}`;if(S.includes("Frame was detached")||S.includes("Not attached to an active page")||S.includes("browser has been closed")||S.includes("UserInfrastructureError"))return;t.error({err:y,sessionId:e},"Error grabbing browser state")}},p=setInterval(()=>{let g=n.getSession(e),f=g?.controller?.browser;if(!f||f.closed){t.debug("Clearing browser state socket cron due to the browser being closed"),clearInterval(p);return}d(f,g.context)},1e3),m=(g,f)=>!!(JSON.stringify(g)!==JSON.stringify(s)||f.logsPerPage.some(y=>y.length>0)),h=setInterval(async()=>{let f=n.getSession(e)?.controller?.browser;if(!f||f.closed){clearInterval(h);return}else if(u)return;u=!0;try{let y=await f.getAllFrameUrls(),S=f.retrieveAndClearDebugData();m(y,S)&&(s=y,c=S,i=Date.now())}catch(y){t.warn({err:y},"Failed to fetch extended details")}finally{u=!1}},2500);return{timers:[p,h]}}var LW=3;async function XI({socket:r,logger:e,storageFactory:t,uploadedFileStorage:n,visualDiffScreenshotStorage:o,devicePixelRatio:i,generatorFactory:a,enricherFactory:s,authorization:c,settingsFactory:l,getOrgId:u,branchGetter:d,globalE2eStateManager:p}){let m=r.id,h=r.handshake.query.testId;if(!h)throw new Error("Socket connection request is missing testId");let g=await u({type:"e2e",testId:h}),f=await d?.();e=e.child({testId:h,orgId:g,sessionId:m,branch:f});let y=await a(g,e),S=await s(g,e),T=await l(g,e),A=await t(g),{testMetadata:v,baseUrl:w,envName:x,browserConfig:_,aiSettings:D,environmentVariables:z,localCodeEvalTools:B}=await Yi({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:T}),L=p.getSession(m);if(L)return e.info("Associating connection with existing session (likely reconnect)"),await L.controller.browser.clearAllCdpHighlights(),{type:"e2e",sessionId:m,orgId:g,testId:h};let j=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:j,event:"connect",args:r.handshake.query},"Websocket event (connect)"),j&&p.getCurrentConnectionsByIp(j)>=LW)throw e.error({clientIp:j,sessions:p.getCurrentSessionsByIp(),...r.handshake.query},"Socket connection browser creation rate limit triggered"),new Error("You have exceeded the maximum number of connections allowed. Momentic limits the number of simultaneously open tabs to uphold browser reliability. Please close duplicate tabs and try again later.");p.reserveCapacityByIp(j);try{await NW({socket:r,baseUrl:w,envName:x,testMetadata:v,orgId:g,sessionId:m,logger:e,environmentVariables:z,clientIp:j,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:B,generator:y,enricher:S,browserConfig:_,aiSettings:D,globalE2eStateManager:p})}catch(Q){throw e.warn({err:Q},"Error setting up socket session, possibly due to client closing the connection"),p.releaseCapacityByIp(j),Q}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function NW({socket:r,baseUrl:e,envName:t,devicePixelRatio:n,testMetadata:o,orgId:i,sessionId:a,logger:s,storage:c,uploadedFileStorage:l,visualDiffScreenshotStorage:u,localCodeEvalTools:d,generator:p,environmentVariables:m,browserConfig:h,aiSettings:g,clientIp:f,enricher:y,globalE2eStateManager:S}){let T={viewport:o.advanced?.viewport??Yt,locale:o.advanced?.locale??Ro,timezoneId:o.advanced?.timezone??Ao,geolocation:o.advanced?.geolocation??wo,colorScheme:o.advanced?.colorScheme};n&&(T.deviceScaleFactor=n);let A=o.id,v=await vp({settings:h,orgId:i,baseUrl:e,envName:t,testName:o.name,localTools:d,envVariables:m,logger:s,customHeaders:void 0});s=s.child({orgId:i,sessionId:a,testId:A});let w=await Yr.init({baseUrl:e,userBrowserSettings:v,enricher:y,storage:c,logger:s,contextArgs:T,iconKnowledgeBase:null,callbacks:{onTabsChange:(B,L)=>{r.emit("tabs",{tabs:B,activeTab:L})},onScreencastFrame:(B,L)=>{let j=r;zr&&(j=r.compress(!0)),j.emit("screenshot",{buffer:B},()=>{L()})},onSvgsCollected:B=>{r.emit("newIconDetected",{numIcons:B.newSvgs.length}),c.saveNewIcons(B,s)},onNetworkLogs:B=>{r.emit("networkLogs",{harEntries:B})}}});await w.navigate({url:e,initialNavigation:!0});let x=new Jo({browser:w,generator:p,logger:s,orgId:i,options:{scratchPadId:void 0,slowMoMs:v.slowMoMs,autoFollowNewTabs:v.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:c,localCodeEvalTools:d,uploadedFileStorage:l,visualDiffScreenshotStorage:u}),_=YI(r,a,s,S),D=async()=>{_.timers.forEach(B=>clearInterval(B))},z=new sr({baseUrl:e,testName:o.name,currentUrl:x.browser.url(),variablesFromEnvironment:m,envName:t});if(!r.connected)throw await w.cleanup(),new Error("Socket not connected anymore, not proceeding with session setup");r.emit("session",{url:e,userAgent:Yr.USER_AGENT,viewport:x.browser.getViewport(),sessionId:a}),S.registerSession({controller:x,context:z,sessionId:a,cleanup:D,clientIp:f,socket:r})}async function Yi({testId:r,orgId:e,logger:t,storage:n,authorization:o,settings:i}){let a=await n.fetchTestMetadata(r,t);if(!a)throw new Error(`Test metadata could not found for test ${r}`);let s;o?.type==="API_KEY"&&(s=new xn({httpClient:new zt({...o,logger:t,mode:"interactive"}),fakerSeed:void 0}));let c=a.envs?.find(g=>g.default),l;c&&(l=await n.fetchEnvironment(c.name,t));let u=l&&"browser"in l?l.browser:void 0,d={...i.browser,...u,...a.advanced},p=a.baseUrl||l?.variables?.[Rt];if(!p)throw new Error("Base URL is empty in both test options and the configured environment");let m={...l?.variables};m=await Rp({orgId:e,testName:a.name,envName:l?.name,baseEnvVariables:m,parameters:a.parameters,logger:t,localTools:s});let h={...i.ai,...a.advanced};return{localCodeEvalTools:s,baseUrl:p,envName:l?.name,testName:a.name,browserConfig:d,environmentVariables:m,testMetadata:a,aiSettings:h}}var KS=class{parentTracer=null;socket;step;orgId;constructor({step:e,socket:t,parentTracer:n,orgId:o}){this.socket=t,this.parentTracer=n,this.step=e,this.orgId=o}getParentStepIdChain(){return this.parentTracer?this.parentTracer?.getParentStepIdChain()??[]:[]}recordStepDuration(e){let t=e.step.type!=="PRESET_ACTION"?e.step.type:e.step.command.type;kt.distribution("test_step_duration",e.durationMs,[`type:${t}`,"platform:browser","executor:editor",`orgId:${this.orgId}`])}attachBeforeScreenshot(){}attachAfterScreenshot(){}attachBeforeHtmlSnapshot(){}attachAfterHtmlSnapshot(){}recordTargetAutoHeal(){}async finish(e){switch(e.step.status){case"SUCCESS":this.socket.emit("success",{...e,parentStepIdChain:this.getParentStepIdChain()});return;case"FAILED":this.socket.emit("failure",{...e,parentStepIdChain:this.getParentStepIdChain()});return;case"CANCELLED":this.socket.emit("cancelled",{...e,parentStepIdChain:this.getParentStepIdChain()});return}}async startSubSteps(){return new so({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},so=class{stepFrequenciesByType={};parentTracer;parentStep;socket;orgId;recordStepStat(e){e.type!=="PRESET_ACTION"?this.stepFrequenciesByType[e.type]=(this.stepFrequenciesByType[e.type]||0)+1:this.stepFrequenciesByType[e.command.type]=(this.stepFrequenciesByType[e.command.type]||0)+1}sendFinalizedStepStats(){for(let[e,t]of Object.entries(this.stepFrequenciesByType))kt.increment("test_step_execution",t,[`type:${e}`,"platform:browser","executor:editor",`orgId:${this.orgId}`])}constructor({parentStep:e,socket:t,parentTracer:n,orgId:o}){this.parentTracer=n,this.parentStep=e,this.socket=t,this.orgId=o}async getScreenshot(){throw new Error("getScreenshot is not supported in the editor")}async getHtmlSnapshot(){throw new Error("getHtmlSnapshot is not supported in the editor")}getParentStepIdChain(){return this.parentStep?[...this.parentTracer?.getParentStepIdChain()??[],this.parentStep.id]:[]}async startStep(e){return this.recordStepStat(e.step),this.socket.emit("started",{stepId:e.step.id,parentStepIdChain:this.getParentStepIdChain(),attempt:e.attempt}),new KS({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId})}async finish(){this.sendFinalizedStepStats()}},Gp=class{constructor(e,t,n,o){this.socket=e;this.storage=t;this.orgId=n;this.testId=o}children=[];loggerBindings;setActiveVideo(){}async getScreenshot(){throw new Error("getScreenshot is not supported in the editor")}async getHtmlSnapshot(){throw new Error("getHtmlSnapshot is not supported in the editor")}onNetworkPage(){}onNetworkLogs(){}attachConsoleLogs(){}attachBrowserCrashDump(){}async finish(){this.socket.emit("finished"),await Promise.all(this.children.map(e=>e.finish()))}async startBeforeStepList(){let e=new so({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new so({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new so({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var YS={currentlyExecutingRequests:{}},kW=r=>async(e,t)=>{let{testId:n,orgId:o}=r.metadata,i=await r.settingsFactory(o,r.logger),a=await r.storageFactory(o),s,c=await Yi({testId:n,orgId:o,logger:r.logger,storage:a,authorization:r.authorization,settings:i}),l=`${n}|${c.baseUrl}`;try{let u=YS.currentlyExecutingRequests[l]??0;YS.currentlyExecutingRequests[l]=u+1,s=await FW({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),YS.currentlyExecutingRequests[l]--}},FW=async({socket:r,steps:e,baseUrl:t,testMetadata:n,reInitialize:o,toStep:i,fromStep:a,storageFactory:s,aiSettings:c,browserConfig:l,metadata:u,logger:d,envName:p,testName:m,environmentVariables:h,localCodeEvalTools:g,done:f,cacheStorageFactory:y,globalE2eStateManager:S})=>{let{testId:T,sessionId:A,orgId:v}=u,w=A,x=S.getSession(A);if(!x)throw new Error("No active session found");let{controller:_,context:D}=x;_.setOpen(),d=d.child({testId:T,orgId:v,sessionId:A,runId:w}),d.info({steps:e.map(ae=>`${ae.type}${"command"in ae?` - ${ae.command.type}`:""}`),toStep:i,fromStep:a,reInitialize:o,envName:p,testName:m,baseUrl:t,context:D,browserConfig:l,aiSettings:c},"Socket execution parameters");let z=h??{},B=async()=>{o&&(await _.browser.reset({newUrl:t}),D.reset({baseUrl:t,currentUrl:_.browser.url(),variablesFromEnvironment:z,envName:p,testName:m}))},L=await s(v),j=await y(v),Q=async()=>{let ae=Date.now();try{await j.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:T,stepLists:{steps:e},logger:d})}catch($e){d.error({err:$e},"Failed to fetch step cache entries from Momentic server. This can drastically reduce test reliability and performance.")}finally{kt.distribution("cache-resolution",Date.now()-ae,["executor:editor"])}};try{await xl({promiseGenerator:async()=>Promise.all([B(),Q()]),signal:_.executeAbortController.signal,codePath:"resolveStepCacheAndInitBrowser"}),_.setOpen()}catch(ae){if(r.emit("finished"),ae.name!=="AbortError")throw new Error(`Failed to setup browser for execution: ${ae}`)}let K=DW(e),ve={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},q={orgId:v,runId:w,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},st={controller:_,context:D,storage:L,codeEvalTools:g,usageTracker:new Ca,logger:d},Oe={test:{},step:{onDynamicAIActionStatusUpdateEvent:ae=>{r.emit("dynamicCommandStatusUpdate",ae)},onDynamicAIActionEvaluatingEvent:ae=>{r.emit("dynamicCommandEvaluating",ae)},onDynamicCommandGenerated:ae=>{r.emit("dynamicCommandGenerated",ae)},onDynamicCommandExecuted:ae=>{r.emit("dynamicCommandExecuted",ae)}}},ht=new Gp(r,L,v,T),tr=await bp({fixtures:st,options:ve,callbacks:Oe,inputs:q,testParams:{tracer:ht}}),He={logger:d,cacheStorage:j,orgId:v,testId:T,originalStepsWithCaches:{steps:K},updatedStepsWithCaches:{steps:e}};return tr?.status==="PASSED"?await td(He):tr?.status==="FAILED"&&await rd(He),await ht.finish(),f?.(tr),tr.status};var JI={event:"execute",createHandler:kW};import{cloneDeep as UW}from"lodash-es";var BW=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=UW(e),s=xA(a);if(s.category!=="NO_DESCRIPTION_PROVIDED"){if(s.category!=="NONE"){t?.({result:s});return}"cache"in a&&(a.cache=void 0);try{let l=await(await o(i.orgId,n)).getLintStepResult({command:a},{logger:n});t?.({result:l})}catch(c){n.error({event:"lint",err:c},"Failed to lint step"),t?.({result:void 0})}}},QI={event:"lintStep",createHandler:BW};var zW=({metadata:r,logger:e,storageFactory:t,globalE2eStateManager:n})=>{let{sessionId:o,orgId:i}=r;return async(a,s)=>{let{description:c,command:l,testMetadata:u,returnScreenshot:d}=a;e.info({params:a},`Locate handler called - ${c}`);let p=n.getSession(o);if(!p)throw new Error("No active session found");let{controller:m,context:h}=p;m.setOpen();let g=await t(i),f=Ti.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let T=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=T.resolution.locator,y={target:T.target,thoughts:T.thoughts}}catch(T){e.warn({err:T},"Failed resolving target with selector"),s({err:`Failed locating element: ${T.message}`,decisions:T instanceof Or?T.decisions:void 0});return}else try{let T=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:gi(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&Ic(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:T.target,thoughts:T.thoughts},S=T.resolution.locator}catch(T){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:T,html:A.slice(0,1e5)},"Failed locating element with AI")}catch(A){e.warn({err:A},"Failed grabbing HTML after trying to locate element with AI")}})(),s({err:`${T.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(T){e.warn({err:T},"Failed getting select options"),s({err:`Failed getting select options: ${T.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:T,width:A,height:v}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),w=await g.uploadScreenshot(T);y.screenshot={data:w,width:A,height:v},e.info({width:A,height:v},"Captured screenshot during locate")}catch(T){e.error({err:T},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${T.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(T){e.warn({err:T},"Error highlighting element, continuing...")}}},ZI={event:"locate",createHandler:zW};var HW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async({event:o,percentX:i,percentY:a})=>{let s=t.getSession(n);if(!s)throw new Error("No active session found");let c=s.controller.browser;if(c.closed||c.getActivePage().isClosed()){e.warn("Ignoring mouse move because the browser is closed");return}try{await c.clickMouseFromPositionPercentages(o,i,a)}catch(l){e.error({err:l},"Error performing click during cloud recording in control mode")}}},eP={event:"mouseClickEvent",createHandler:HW};var GW=({metadata:r,generatorFactory:e,logger:t,socket:n,globalE2eStateManager:o})=>{let{sessionId:i,orgId:a,testId:s}=r;return async({stepId:c,parentStepIdChain:l,attribute:u})=>{let d=o.getSession(i);if(!d)throw new Error("No active session found");let{controller:p}=d,m=await e(a,t);p.setOpen(),d.browserBehavior.showOverlay=!0;let h=new AbortController;h.signal.addEventListener("abort",async()=>{try{d.browserBehavior.showOverlay=!1,await p.stopRecordMode()}catch(y){t.warn({err:y},"Failed to stop record mode in target click socket handler")}},{once:!0});let g=!1,f=(y,S)=>{S.type!=="PRESET_ACTION"||S.command.type!=="CLICK"||(n.emit("targetRecordingUpdate",{type:y,stepId:c,parentStepIdChain:l,command:S.command,attribute:u}),h.abort(),g=!0)};setTimeout(()=>{g||(h.abort(),n.emit("targetRecordingUpdate",{type:"error",err:"Timed out waiting for click event",stepId:c,parentStepIdChain:l,attribute:u}))},1e4),await p.startRecordMode({params:{generator:m,logger:t,testId:s,orgId:a,callbacks:{onActionReceived:y=>f("clickReceived",y),onStepRecorded:y=>f("descriptionGenerated",y)}},abortController:h,isClickToRecord:!0}),n.emit("targetRecordingUpdate",{type:"listenersInitialized",stepId:c,parentStepIdChain:l,attribute:u})}},tP={event:"recordTargetClick",createHandler:GW};var jW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async({key:o})=>{let i=t.getSession(n);if(!i)throw new Error("No active session found");if(o==="Dead")return;let{controller:a}=i;if(a.browser.closed||a.browser.getActivePage().isClosed()){e.debug({sessionId:n},"Browser is closed, ignoring keyboard press socket event");return}try{a.setOpen(),await a.browser.keyDown(o,{})}catch(s){if(s.message.includes("has been closed")){e.debug({sessionId:n,err:s},"Browser is closed, ignoring key down socket event error");return}throw s}}},rP={event:"keyDownEvent",createHandler:jW};var VW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async({key:o})=>{let i=t.getSession(n);if(!i)throw new Error("No active session found");if(o==="Dead")return;let{controller:a}=i;if(a.browser.closed||a.browser.getActivePage().isClosed()){e.debug({sessionId:n},"Browser is closed, ignoring keyboard press socket event");return}try{a.setOpen(),await a.browser.keyUp(o,{})}catch(s){if(s.message.includes("has been closed")){e.debug({sessionId:n,err:s},"Browser is closed, ignoring key up socket event error");return}throw s}}},nP={event:"keyUpEvent",createHandler:VW};var $W=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r,o,i=0,a=(l,u)=>{let d=async()=>{o=void 0};clearTimeout(o),o=setTimeout(d,Math.min(1e3,250*(i+1)))},s,c=0;return async l=>{let u=t.getSession(n);if(!u)throw new Error("No active session found");let{controller:d,browserBehavior:p}=u,m=d.browser;if(m.closed||m.getActivePage().isClosed()){e.warn("Ignoring mouse move because the page is closed");return}if(l.event==="scroll"){let h=await m.scrollFromPositionPercentages(l.percentX,l.percentY,s?.x??0,s?.y??0),g=u.browserBehavior.recordingState?.transformer;g&&h&&g.recordScroll(h);return}p.showOverlay&&a(m,l);try{let h=await m.moveMouseFromPositionPercentages(l.percentX,l.percentY);c=0,s=h}catch(h){c++,c%5===0&&e.warn({err:h,mouseErrors:c},"Error in socket mouse move handler")}}},oP={event:"mouseMoveEvent",createHandler:$W};var WW=({metadata:r,generatorFactory:e,socket:t,logger:n,globalE2eStateManager:o})=>{let{sessionId:i,orgId:a,testId:s}=r;return async({stepId:c})=>{let l=o.getSession(i);if(!l)throw new Error("No active session found");let{controller:u,browserBehavior:d}=l,p=await e(a,n);n.info("Starting cloud recording");let m=new AbortController,h=await u.startRecordMode({params:{generator:p,logger:n,testId:s,orgId:a,callbacks:{onActionReceived:(g,f)=>{t.emit("stepRecorded",{stepId:c,step:g,offset:f})},onStepRecorded:(g,f)=>{t.emit("stepRecorded",{stepId:c,step:g,offset:f})}}},abortController:m,isClickToRecord:!1});d.recordingState={transformer:h}}},iP={event:"recordingStart",createHandler:WW};var qW=({metadata:r,logger:e,globalE2eStateManager:t})=>{let{sessionId:n}=r;return async()=>{let o=t.getSession(n);if(!o)throw new Error("No active session found");e.info("Stopping cloud recording"),await o.controller.stopRecordMode(),o.browserBehavior.recordingState=void 0,o.browserBehavior.showOverlay=!1}},aP={event:"recordingStop",createHandler:qW};var KW=({socket:r,metadata:e,logger:t,storageFactory:n,authorization:o,settingsFactory:i,globalE2eStateManager:a})=>async(s,c)=>{let{testId:l,sessionId:u,orgId:d}=e;t.info({testId:l,sessionId:u},"Refresh event received");let p=await i(d,t),m=await n(d),{baseUrl:h}=await Yi({testId:l,orgId:d,logger:t,storage:m,authorization:o,settings:p}),g=a.getSession(u);if(!g){r.emit("error",{message:"No session to refresh"});return}let{controller:f}=g;f.setOpen(),await f.browser.refresh();let y=f.browser.getViewport();t.info({baseUrl:h,viewport:y},`Session refreshed for test ${l} at ${h}`),c()},sP={event:"refresh",createHandler:KW};var YW=({socket:r,metadata:e,logger:t,storageFactory:n,authorization:o,settingsFactory:i,globalE2eStateManager:a})=>async()=>{let{testId:s,sessionId:c,orgId:l}=e;t.info({testId:s,sessionId:c},"Reset event received");let u=await i(l,t),d=await n(l),{baseUrl:p,envName:m,testName:h,environmentVariables:g}=await Yi({testId:s,orgId:l,logger:t,storage:d,authorization:o,settings:u}),f=a.getSession(c);if(!f){r.emit("error",{message:"No session to reset"});return}let{controller:y,context:S}=f;await y.browser.reset({newUrl:p});let T=y.browser.baseUrl;S.reset({baseUrl:T,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),v=Yr.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${T}`),r.emit("session",{url:T,userAgent:v,viewport:A,sessionId:c})},lP={event:"reset",createHandler:YW};var XW=({metadata:r,globalE2eStateManager:e})=>{let{sessionId:t}=r;return async({url:n})=>{let o=e.getSession(t);if(!o)throw new Error("No active session found");await o.controller.browser.switchToPage({type:"SUBSTRING",substring:n})}},cP={event:"switchTab",createHandler:XW};async function uP(r){return XI(r)}var dP=[bw,JI,ZI,lP,sP,yw,cP,QI,tP,iP,aP,oP,eP,rP,nP,Tw,Ew];var pP=r=>{let{logger:e}=r,t=new JW(r.baseServer,{cors:{origin:"*",methods:["GET","POST"]},pingTimeout:15*60*1e3,pingInterval:15*60*1e3,maxHttpBufferSize:1e7,perMessageDeflate:!0});return t.on("connection",async n=>{let o;try{e.info({event:"connection",transport:n.conn.transport.name},"Websocket connection established"),o=await uP({...r,socket:n,logger:e}),e=e.child(o)}catch(i){e.error({event:"connection",type:"websocket",err:i},"Failed to setup connection"),n.emit("error",{message:i instanceof Error?i.message:`${i}`}),n.disconnect(!0);return}dP.forEach(i=>QW(i,{...r,socket:n,metadata:o,logger:e}))}),t},QW=(r,e)=>{let t=r.createHandler(e),n=(...o)=>{["mouseMoveEvent","keyDownEvent","keyUpEvent","mouseClickEvent","lintStep"].includes(r.event)||e.logger.debug({...e.metadata,event:r.event},`Websocket event (${r.event})`);let i=a=>{e.logger.error({event:r.event,type:"websocket",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(i)}catch(a){i(a)}};e.socket.on(r.event,n)};import{Router as nq}from"express";import{Router as eq}from"express";import mc from"fs";import pc from"path";import{v4 as tq}from"uuid";import rq from"yaml";import{hostname as ZW}from"os";var dc="2.28.7",nt=Na({app:"desktop-server",hostname:ZW(),disableConsoleLogs:!0}).child({cliVersion:dc});(async()=>{try{let r=await no(nt);r.gitBranchName&&nt.addBinding("branch",r.gitBranchName)}catch{}})();var Es=eq();async function XS(r){return(await hd(r,nt)).map(n=>{let o=r.modules[n.moduleId];if(!o){E.warn(`Found a dangling module with ID ${n.moduleId} that could not be found on disk.`);return}return{...o,content:n}}).filter(n=>n!==void 0)}Es.get("/",Pe(async(r,e)=>{let t=se(),n=await ee(t),o=await XS(n);e.status(200).json(o)}));Es.post("/",Pe(async(r,e)=>{let t;try{t=Zb.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{bo(t.name)}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=se(),o=(await ee(n)).modules;if(Object.values(o).find(s=>s.name===t.name)){e.status(400).send(`A module with the name "${t.name}" already exists. Please choose a different name.`);return}let i=pc.join(n.rootDir,t.folderPath??"");if(!mc.existsSync(i)||!mc.statSync(i).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${i}' does not exist.`});return}let a=await md({...t,folder:i,project:n});e.status(201).json(a)}));Es.get("/:moduleId",Pe(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=await ee(se()),n=t.modules[r.params.moduleId];if(!n){e.status(404).json({error:"Module not found."});return}try{let o=await ln(n,t,E);e.json(o)}catch(o){e.status(400).json({err:o})}}));Es.post("/:moduleId/duplicate",Pe(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=Qb.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{bo(t.name)}catch(g){e.status(400).json({error:g.message});return}let n=se(),o=await ee(n),i=o.modules[r.params.moduleId];if(!i){e.status(404).json({error:"Module not found."});return}if(Object.values(o.modules).find(g=>g.name===t.name)){e.status(400).send(`A module with the name "${t.name}" already exists. Please choose a different name.`);return}let a=await ln(i,o,E),s=pc.join(n.rootDir,pc.dirname(i.relativePath));if(!mc.existsSync(s)||!mc.statSync(s).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${s}' does not exist.`});return}let c=Be(t.name),l=pc.join(s,`${c}.module.yaml`),u=tq(),{stepsToSave:d}=await it({stepLists:{steps:a.steps},createNewCacheIds:!0,cacheCreationParams:{orgId:Ct()}}),p={fileType:ge.MODULE,schemaVersion:xe,moduleId:u,name:t.name,description:"",enabled:!0,steps:d.steps,parameters:a.parameters,defaultParameters:a.defaultParameters,parameterEnums:a.parameterEnums,defaultCacheKey:a.defaultCacheKey,defaultCacheTtl:a.defaultCacheTtl,defaultCacheAllInvocations:a.defaultCacheAllInvocations,autoAuth:a.autoAuth,advanced:a.advanced},m=rq.stringify(p);mc.writeFileSync(l,m,"utf-8");let h={relativeFilePath:pc.relative(n.rootDir,l)};e.status(201).json(h)}));Es.patch("/:moduleId/metadata",Pe(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=ev.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=se(),o=await ee(n);WA({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:E,project:n}),e.status(201).json({message:"ok"})}));var mP=Es;var hP=nq();hP.get("/",Pe(async(r,e)=>{let t=se(),n=await ee(t),o=new Set;n?.tests&&Object.values(n.tests).forEach(l=>{l.labels?.forEach(u=>o.add(u))});let i=Array.from(o).sort(),a=Object.values(n.tests),s=await XS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var gP=hP;import{Router as oq}from"express";var JS=oq();JS.get("/",Pe((r,e)=>{let t=gd(se(),nt);e.status(200).json(t)}));JS.get("/names",Pe((r,e)=>{let n=se().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var fP=JS;import{Router as iq}from"express";var SP=iq();SP.get("/",Pe((r,e)=>{let t={userId:ko(),orgId:Ct(),cliVersion:dc??"0.0.0"};e.status(200).json(t)}));var yP=SP;import{StreamableHTTPServerTransport as TK}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as bK}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as vK}from"crypto";import{Router as RK}from"express";import{McpServer as yK}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as EK}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as uq}from"ai";import Wp from"dedent";import dq from"path";import{z as Qo}from"zod";import{tool as aq}from"ai";import{z as sq}from"zod";var EP=(r,e)=>({builder:n=>aq({description:r.schema.description,inputSchema:sq.object(r.schema.inputSchema),execute:async o=>{let i=e(n);n.logger.info({input:o},`Executing tool ${r.schema.name}`);try{await r.handle(n,o,i,void 0)}catch(s){i.addError(String(s))}let a=await i.serialize();return a.isError?n.logger.error({toolName:r.schema.name,input:o,err:a.content.map(s=>s.text).join(`
|
|
4365
4365
|
`)},"Tool execution resulted in error"):n.logger.info({toolName:r.schema.name,input:o},"Tool execution completed"),a}}),tool:r});var hc=class{results=[];isError;addResult(e){this.results.push(e)}addError(e){this.results.push(`Error: ${e}`),this.isError=!0}getResult(){return this.results.join(`
|
|
4366
4366
|
`)}async serialize(){let e=[];return this.results.length&&(e.push("### Result"),e.push(this.results.join(`
|
|
4367
4367
|
`)),e.push("")),{content:[{type:"text",text:e.join(`
|
|
@@ -4821,7 +4821,7 @@ ${r.map(p=>`${vt}- ${p}`).join(`
|
|
|
4821
4821
|
`)}`),Object.values(e.tests).forEach(p=>{r.some(m=>p.relativePath.includes(m))&&c.add(p.fullFilePath)}))}else{!n&&!await Bt("No test paths or substrings were provided. Do you want to run all tests?")&&(s.error("Cancelled by user."),process.exit(1));let u=Object.values(e.tests);s.info(`Reading all ${u.length} tests in the project from local disk.`),u.forEach(d=>{c.add(d.fullFilePath)})}for(let u of c){let d=Cy.relative(t.rootDir,u);o&&!o.some(p=>new RegExp(p).test(d))&&c.delete(u),i&&i.some(p=>new RegExp(p).test(d))&&c.delete(u)}let l=Array.from(c).map(async u=>{try{let d=await dt(u,Y,e);if(XK.gt(d.schemaVersion,xe)&&s.warn(`Test ${u} has schema version ${d.schemaVersion}, which is greater than what is currently supported by this SDK. Please update your momentic package version to avoid unexpected behavior.`),a&&a.length>0){let p=d.labels||[];if(!a.some(h=>p.includes(h)))return null}return{...d,fullFilePath:u,relativeFilePath:Cy.relative(t.rootDir,u)}}catch(d){s.error(`Failed to read and resolve test at '${u}': ${d}`),process.exit(1)}});return Promise.all(l).then(KK)}function jO({testDefinitions:r,quarantinedTestReasons:e,onlyQuarantined:t=!1,skipQuarantined:n=!1}){if(t){let[u,d]=mm(r,h=>h.id in e),[p,m]=mm(u,h=>h.disabled||n);return{testsToSkip:p,quarantinedTestsToSkip:[],testsToRun:m,quarantinedTestsToRun:[]}}let[o,i]=mm(r,u=>u.disabled),[a,s]=mm(i,u=>u.id in e);return{testsToSkip:o,testsToRun:s,quarantinedTestsToRun:n?[]:a,quarantinedTestsToSkip:n?a:[]}}function VO({testsToRun:r,quarantinedTestsToRun:e,quarantinedTestReasons:t,testInputMatrix:n}){let o=[],i=(a,s,c)=>{n?n.forEach((l,u)=>{o.push({inputs:l,inputIndex:u,testDefinition:a,quarantined:s,quarantinedReason:c})}):o.push({inputs:void 0,testDefinition:a,quarantined:s,quarantinedReason:c})};return r.forEach(a=>i(a,!1)),e.forEach(a=>i(a,!0,t[a.id])),o}async function $O({project:r,apiClient:e}){let t=await ee(r),n=await xs({tests:[],momenticFiles:t,yes:!0,project:r,logger:new Ai(40,{})}),o=(await e.getQuarantinedTests()).quarantined,i=new Set(o.map(s=>s.testId)),a=n.filter(s=>i.has(s.id));E.info(a.map(s=>s.relativeFilePath).join(`
|
|
4822
4822
|
`))}async function WO({test:r,reason:e,apiClient:t,project:n,identity:o}){let i=(await ee(n)).tests,a=Object.values(i),s=(await t.getQuarantinedTests()).quarantined,c=new Set(s.map(p=>p.testId)),l=a.filter(p=>c.has(p.id)),u=await dm({prompt:"Select a test to unquarantine.",inputtedTest:r,testOptions:l}),d=await pm({prompt:"Enter a reason for unquarantining the test.",inputtedReason:e});await t.unquarantineTest(u,d,o),E.success(`Test ${u.name} has been successfully removed from quarantine.`)}function qO(r){return r?Be(r):"Unknown suite"}async function KO({client:r,orgId:e,suitePaths:t,wait:n,waitTimeout:o,...i}){let{suiteRunIds:a,runGroupIds:s}=await r.queueSuiteRuns({paths:t,...i});Y.info({orgId:e,suiteRunIds:a,runGroupIds:s,suitePaths:t},"Queued suites remotely"),E.dimmed(`Queued ${t.length} suites.`),n||process.exit(0);let c=Date.now();E.dimmed(`Waiting for ${t.length} suites to finish. You can view results upon completion at:`);for(let f of s)E.dimmed(`${vt}- ${r.getAppUrl()}/run-groups/${f}`);let l=new Set,u=[],d=f=>(f.status==="FAILED"||f.status==="PASSED"||f.status==="CANCELLED")&&f.runs.every(S=>S.status==="FAILED"&&(S.failureReason||S.finishedAt&&Date.now()-S.finishedAt.getTime()>30*1e3)||S.status==="PASSED"||S.status==="CANCELLED"),p=await Fu({name:"suites",getResults:async()=>{let f=s.filter(T=>!u.some(A=>A.id===T)),y=await r.bulkGetRunGroupStatus(f),S=[];for(let T of y)d(T)?u.push(T):S.push(T);return[...u,...S]},timeoutMs:o?o*1e3:void 0,checkDone:f=>(f.forEach(y=>{y.status==="RUNNING"&&(l.has(y.id)||(l.add(y.id),E.log(`${l.size}/${s.length} ${qO(y.suite?.name)}`)))}),f.every(d))}),m=r.getAppUrl(),g=Da({results:p,startTime:c,onFailed:f=>{let y=qO(f.suite?.name),S=f.runs.filter(A=>A.status==="FAILED").length,T=f.runs.length;E.error(`${y} (${S}/${T} tests failed):`);for(let A of f.runs)if(A.status==="FAILED"){let v=A.testName||A.test?.name;E.error(` ${v?Be(v):"Unknown test"} (${m}/runs/${A.id})`)}},entity:"suite",getDisplayLine:f=>` ${f.suite?.name?Be(f.suite.name):"Unknown suite name"} (${m}/run-groups/${f.id})`});process.exit(g.failed>0?1:0)}async function YO({tests:r,client:e,orgId:t,...n}){!n.yes&&!await Bt(`This command will queue ${r.length} tests to run remotely on Momentic's infrastructure. Results will be available on ${e.getAppUrl()}. Continue?`)&&process.exit(1);let{queuedTests:o,runIds:i}=await e.queueTests({testPaths:r,...n});if(Y.info({queuedTests:o,runIds:i,orgId:t},"Queued tests remotely"),E.dimmed(`Queued ${o.length} tests. Processing time may depend on a variety of factors, including how many tests have already been queued from your organization.`),n.wait||process.exit(0),!i.length)return;E.dimmed(`Waiting for ${o.length} tests to complete.`);let a=new Set,s=[],c=m=>m.status==="FAILED"&&m.failureReason||m.status==="PASSED"||m.status==="CANCELLED",l=e.getAppUrl(),u=Date.now(),d=await Fu({name:"runs",getResults:async()=>{let m=i.filter(f=>!s.some(y=>y.id===f)),h=await e.bulkGetRunStatus(m),g=[];for(let f of h)c(f)?s.push(f):g.push(f);return[...s,...g]},timeoutMs:n.waitTimeout?n.waitTimeout*1e3:void 0,checkDone:m=>(m.forEach(h=>{if(h.status==="RUNNING"&&!a.has(h.id)){a.add(h.id);let g=h.testName||h.test?.name;g&&E.log(`${a.size}/${o.length} ${Be(g)}`)}}),m.every(c))}),p=Da({results:d,startTime:u,onFailed:m=>{let h=m.testName||m.test?.name;Uu(m,h?Be(h):"Unknown test")},getDisplayLine:m=>{let h=m.testName||m.test?.name,g=` ${h?Be(h):"Unknown test"}`;return m.id&&(g+=` (${l}/runs/${m.id})`),g},entity:"test"});process.exit(p.failed>0?1:0)}import{randomUUID as D2}from"crypto";import k2 from"fs";import{existsSync as u2,mkdirSync as d2,statSync as p2}from"fs";import{randomUUID as Zi}from"crypto";import _s,{writeFileSync as XO}from"fs";import{hostname as JK}from"os";import Gn from"path";import{z as hm}from"zod";async function fm(r,e,t,n){if(n){let o=await e.getScreenshot(r,n);if(o){let i=`screenshot-${n}.jpeg`,a=Gn.join(t,i);return _s.writeFileSync(a,o),i}}}async function QK(r,e,t,n){let o=t.folder,i={uuid:n.runAttemptId??Zi(),historyId:n.runId??Zi(),testCaseId:n.test.id,fullName:n.test.name,name:Be(n.test.name),status:n.status==="PASSED"?"passed":n.status==="CANCELLED"?"skipped":"failed",start:n.lastAttemptStartedAt.getTime(),stop:n.finishedAt.getTime(),parameters:[],labels:[{name:"suite",value:t.suiteName},{name:"host",value:JK()},{name:"platform",value:"momentic"},{name:"attempts",value:n.attempts.toString()}],steps:[]};n.runId&&i.labels?.push({name:"runUrl",value:`https://app.momentic.ai/runs/${n.runId}`});for(let[c,l]of Object.entries(n.parameters))l!=null&&i.parameters.push({name:c,value:JSON.stringify(l)});n.results&&await xy(r,e,t.folder,i.steps,n.results);let a=ZK(e,o,i.uuid);a.length>0&&(i.attachments=a);let s=`${n.runAttemptId}-result.json`;_s.writeFileSync(Gn.join(o,s),JSON.stringify(i,void 0,2))}async function gm(r,e,t,n){let o={name:yA(n),start:n.startedAt.getTime(),stop:n.finishedAt.getTime(),status:n.status==="SUCCESS"?"passed":n.status==="CANCELLED"?"skipped":"failed",labels:[],steps:[],attachments:[]};n.beforeUrl&&o.labels?.push({name:"URL before step",value:n.beforeUrl}),n.afterUrl&&o.labels?.push({name:"URL after step",value:n.afterUrl});let i=await fm(r,e,t,n.beforeSnapshot);i&&o.attachments.push({name:"Screenshot before step",source:i,type:"image/jpeg"});let a=await fm(r,e,t,n.afterSnapshot);if(a&&o.attachments.push({name:"Screenshot after step",source:a,type:"image/jpeg"}),n.message&&(o.statusDetails={message:n.message}),n.data)if(Gs.safeParse(n.data).success){let s=Gs.parse(n.data),c=s.request,l={...s,request:void 0},u=`output-attachment-api-request-${Zi()}.json`,d=`output-attachment-api-response-${Zi()}.json`,p=Gn.join(t,u),m=Gn.join(t,d);_s.writeFileSync(p,JSON.stringify(c,null,2)),_s.writeFileSync(m,JSON.stringify(l,null,2)),o.attachments.push({name:"API request details",source:u,type:"application/json"}),o.attachments.push({name:"API response details",source:d,type:"application/json"})}else{let s=hm.union([hm.object({}).passthrough(),hm.array(hm.any())]).safeParse(n.data).success,c=`output-attachment-${Zi()}.json`,l=Gn.join(t,c);_s.writeFileSync(l,JSON.stringify(n.data,null,2)),o.attachments.push({name:"Step output data",source:c,type:s?"application/json":"text/plain"})}return o}async function xy(r,e,t,n,o){for(let i of o){let a;switch(i.type){case"PRESET_ACTION":{a=await gm(r,e,t,i);break}case"CONDITIONAL":{a=await gm(r,e,t,i),a.steps=[],i.assertionResult&&a.steps.push(await gm(r,e,t,i.assertionResult)),await xy(r,e,t,a.steps,i.results);break}case"AI_ACTION_DYNAMIC":case"AI_ACTION":case"SECTION":case"MODULE":{if(a=await gm(r,e,t,i),await xy(r,e,t,a.steps,i.results),i.type==="MODULE"&&i.inputs){a.parameters=[];for(let[s,c]of Object.entries(i.inputs))a.parameters.push({name:s,value:c})}break}default:{let s=i}}if(!a){r.warn({result:i},"Failed to convert Momentic result to Allure step");continue}if(a.attachments||(a.attachments=[]),i.beforeTestContext){let s=`before-context-${Zi()}.json`,c=Gn.join(t,s);XO(c,JO(i.beforeTestContext.env)),a.attachments.push({name:"Test context before step",source:s,type:"application/json"})}if(i.afterTestContext){let s=`after-context-${Zi()}.json`,c=Gn.join(t,s);XO(c,JO(i.afterTestContext.env)),a.attachments.push({name:"Test context after step",source:s,type:"application/json"})}n.push(a)}}async function QO(r,e,t,n){for(let o of n.runs){if(!o.runId||!o.runAttemptId)throw new Error(`Missing runId/runAttemptId for Allure report generation for test '${o.test.name}'`);let i=e.createDebugDataReaderForRunAttempt(o.runId,o.runAttemptId);try{await QK(r,i,{folder:t,suiteName:n.suiteName},o)}finally{i.close()}}}function JO(r){try{return JSON.stringify(r,void 0,2)??JSON.stringify({value:null},void 0,2)}catch(e){let t=e instanceof Error?e.message:"unknown error";return JSON.stringify({error:t},void 0,2)}}function ZK(r,e,t){let n=r.listVideoAssetPaths();if(n.length===0)return[];let o=[];for(let i of n){let a=Gn.basename(i),s=a,c=Gn.join(e,s);try{_s.copyFileSync(i,c)}catch{continue}let l,u=Gn.extname(i).toLowerCase();u===".webm"?l="video/webm":u===".mp4"?l="video/mp4":l="application/octet-stream",o.push({name:a,source:s,type:l})}return o}import e2 from"junit-report-builder";import Sm from"path";function t2(r,e){if(e.name(r.test.name).className(r.test.name).file(Sm.relative(".",r.filePath)).property("id",r.test.id).property("dd_tags[id]",r.test.id),r.test.labels&&(e.property("labels",r.test.labels.join(",")),r.test.labels.forEach(t=>{e.property("dd_tags[label]",t)})),r.baseUrl&&(e.property("base_url",r.baseUrl),e.property("dd_tags[base_url]",r.baseUrl)),r.runId&&(e.property("run_url",`https://app.momentic.ai/runs/${r.runId}`),e.property("dd_tags[run_url]",`https://app.momentic.ai/runs/${r.runId}`)),r.quarantined&&(e.property("quarantined","true"),e.property("dd_tags[quarantined]","true"),r.quarantinedReason&&(e.property("quarantined_reason",r.quarantinedReason),e.property("dd_tags[quarantined_reason]",r.quarantinedReason))),r.beforeResults?.some(t=>t.status==="FAILED")&&(e.property("setup_failed","true"),e.property("dd_tags[setup_failed]","true")),r.results?.some(t=>t.status==="FAILED")&&(e.property("main_failed","true"),e.property("dd_tags[main_failed]","true")),r.afterResults?.some(t=>t.status==="FAILED")&&(e.property("teardown_failed","true"),e.property("dd_tags[teardown_failed]","true")),r.status==="FAILED"){if(r.failureReason){let t=Vc[r.failureDetails?.classification?.reason||r.failureReason],n=r.failureDetails?.classification?.summary||fa[r.failureReason];r.runId&&(n+=` Visit https://app.momentic.ai/runs/${r.runId} for more details.`),e.failure(n,t)}r.failureDetails?.errorStack&&e.stacktrace(r.failureDetails.errorStack)}else r.status==="CANCELLED"&&e.skipped();return e.time((r.finishedAt.getTime()-r.lastAttemptStartedAt.getTime())/1e3).property("started_at",r.lastAttemptStartedAt.toISOString()).property("dd_tags[started_at]",r.lastAttemptStartedAt.toISOString()).property("finished_at",r.finishedAt.toISOString()).property("dd_tags[finished_at]",r.finishedAt.toISOString()),e.property("attempts",r.attempts.toString()).property("dd_tags[attempts]",r.attempts.toString()),r.parameters.envName&&(e.property("environment",r.parameters.envName),e.property("dd_tags[environment]",r.parameters.envName)),r.parameters.urlOverride&&e.property("url_override",r.parameters.urlOverride),e}function r2(r,{suiteId:e,suiteName:t,startedAt:n,finishedAt:o,runs:i,testsToSkip:a,quarantinedTestsToSkip:s,quarantinedTestReasons:c}){let l=r.testSuite().name(t);e&&l.property("id",e),l.timestamp(n).property("startedAt",n.toISOString()).property("finishedAt",o.toISOString()).time((o.getTime()-n.getTime())/1e3);for(let u of i){let d=l.testCase();t2(u,d)}for(let u of a){let d=l.testCase();d.name(u.name).className(u.name).file(Sm.relative(".",u.relativeFilePath)).property("id",u.id),u.baseUrl&&d.property("baseUrl",u.baseUrl),u.labels&&(d.property("labels",u.labels.join(",")),u.labels.forEach(p=>{d.property("dd_tags[label]",p)})),d.skipped()}for(let u of s){let d=l.testCase();d.name(u.name).className(u.name).file(Sm.relative(".",u.relativeFilePath)).property("id",u.id).property("quarantined","true");let p=c[u.id];p&&d.property("quarantinedReason",p),u.baseUrl&&d.property("baseUrl",u.baseUrl),u.labels&&(d.property("labels",u.labels.join(",")),u.labels.forEach(m=>{d.property("dd_tags[label]",m)})),d.skipped()}return l}function ZO(r,e){let t=e2.newBuilder();r2(t,e),t.writeTo(Sm.join(r,`${e.suiteName}.xml`))}import n2 from"fs";import o2 from"path";function eL(r){return{title:eo(r),duration:r.finishedAt.getTime()-r.startedAt.getTime(),error:r.status==="FAILED"?{value:r.failureReason}:void 0,steps:r.results&&r.type!=="PRESET_ACTION"?r.results.map(eL):[]}}async function i2(r,e,t,n){if(n.results?.length){let o=await fm(r,e,t,n.results[n.results.length-1].afterSnapshot);return o?[{name:"Final state screenshot",path:o,contentType:"image/jpeg"}]:[]}return[]}async function a2(r,e,t,n){return{status:n.status==="PASSED"?"passed":n.status==="CANCELLED"?"interrupted":"failed",duration:n.finishedAt.getTime()-n.lastAttemptStartedAt.getTime(),error:n.status==="FAILED"&&n.failureReason?{value:n.failureDetails?.classification?.reason||n.failureReason,message:n.failureDetails?.classification?.summary||fa[n.failureReason]}:void 0,retry:n.attempts-1,steps:n.results?.map(eL)||[],startTime:n.lastAttemptStartedAt.toISOString(),attachments:await i2(r,e,t,n)}}async function s2(r,e,t,n){return{expectedStatus:"passed",status:n.status==="PASSED"?"expected":"unexpected",results:[await a2(r,e,t,n)]}}async function l2(r,e,t,n){return{tags:[],title:n.test.name,ok:n.status==="PASSED",tests:[await s2(r,e,t,n)],id:n.runId,file:n.filePath}}function _y(r,e){return r.reduce((t,n)=>e(n)?t+1:t,0)}async function c2(r,e,t,n){return{suites:[{title:n.suiteName,file:n.projectConfigPath,specs:await Promise.all(n.runs.map(async o=>{let i=o.runId&&o.runAttemptId?e.createDebugDataReaderForRunAttempt(o.runId,o.runAttemptId):new pl;try{return await l2(r,i,t,o)}finally{i.close()}}))}],errors:[],stats:{startTime:n.startedAt.toISOString(),duration:n.finishedAt.getTime()-n.startedAt.getTime(),expected:_y(n.runs,o=>o.status==="PASSED"),unexpected:_y(n.runs,o=>o.status!=="PASSED"),flaky:_y(n.runs,o=>!!o.isFlake),skipped:0}}}async function tL(r,e,t,n){let o=await c2(r,e,t,n);n2.writeFileSync(o2.join(t,`${n.suiteName}.json`),JSON.stringify(o,null,2))}async function rL({logger:r,callbacks:e,format:t,params:n,folder:o}){switch(u2(o)?p2(o).isDirectory()||(E.error(`The specified reporter output directory '${o}' exists on disk but is not a folder. Please move or delete the existing object or specify a different reporter path.`),process.exit(1)):(E.info(`Reporter output directory '${o}' does not exist on disk, creating it now...`),d2(o,{recursive:!0})),t){case"junit":ZO(o,n);return;case"allure":case"allure-json":await QO(r,e,o,n);return;case"playwright-json":await tL(r,e,o,n);return;default:throw new Error(`Unknown reporter format requested: '${t}'`)}}import F2 from"wait-on";import{execSync as m2}from"child_process";import{platform as h2}from"os";function My(){return nL()?(E.dimmed("Setting device pixel ratio to 2 automatically since a Mac OS Retina screen was detected."),E.dimmed(`If you are using a low pixel-density monitor, you should manually set --pixel-ratio to 1 to avoid incorrect viewport calculations. Confirm your device's pixel-ratio at https://www.mydevice.io.
|
|
4823
4823
|
`),2):(E.dimmed("Setting device pixel ratio to 1."),E.dimmed(`If you are using Momentic on a high-pixel density (HiDPI) monitor, relaunch with the --pixel-ratio option to avoid incorrect viewport calculations. Confirm your device's pixel-ratio at https://www.mydevice.io.
|
|
4824
|
-
`),1)}function nL(){return h2()==="darwin"&&m2("system_profiler SPDisplaysDataType").toString().includes("Retina")}function Iy(r){nL()&&r===1&&(E.warn("If you are using Momentic on a Retina screen, relaunch with the --pixel-ratio option to avoid incorrect viewport calculations."),E.warn("Confirm your device's pixel-ratio at https://www.mydevice.io."))}import g2 from"@actions/exec";import f2 from"@actions/io";import S2 from"quote";import y2 from"string-argv";async function oL(r,e=!0){let t=y2(r),n=await f2.which(t[0],!0),o=t.slice(1),i=g2.exec(S2(n),o,{delay:100});if(e)return i}import E2 from"csv-parser";import{createReadStream as T2}from"fs";function Py(r){return new Promise((e,t)=>{let n=[];T2(r).pipe(E2()).on("data",o=>n.push(o)).on("end",()=>e(n)).on("error",o=>t(o))})}import Ms from"semver";import{z as ym}from"zod";var Ir="2.28.6",b2="https://registry.npmjs.org/momentic",v2=ym.object({versions:ym.record(ym.string(),ym.unknown()).optional()});async function er(r){try{await R2(r)}catch(e){E.warn({err:e},"Failed to check CLI version against NPM servers")}}async function Oy(){let r=await $(fetch(b2),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=v2.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=Ir;for(let o of Object.keys(t))Ms.valid(o)&&Ms.major(o)===Ms.major(Ir)&&Ms.gt(o,n)&&Ms.prerelease(o)===null&&(n=o);return n}async function R2(r){let e;for(let t=0;t<2;t++)try{e=await Oy()}catch(n){r.warn({err:n},"Failed to fetch latest version from npm registry")}if(!e){r.warn("Failed to fetch npm registry data. Skipping version check.");return}Ms.eq(Ir,e)||(E.warn(`Update available: v${Ir} -> v${e}`),E.warn("This version may be missing critical fixes, features, and security updates."),E.warn('Run "npx momentic@latest upgrade" to update'))}async function uo(){try{await $(Promise.all([wR(),kt.flush()]),{milliseconds:5e3})}catch{}}import{partition as A2}from"lodash-es";function Em(r){return r.length===1?"test":"tests"}function iL(r){return r===1?"1 worker":`${r} workers`}function aL(r){r.length!==0&&(E.info(`Skipping ${r.length} disabled ${Em(r)}:`),r.forEach(e=>{E.info(`${vt}- ${[e.relativeFilePath]}`)}),E.log(""))}function sL(r,e){r.length!==0&&(E.info(`Skipping ${r.length} quarantined ${Em(r)}:`),r.forEach(t=>{E.info(`${vt}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),E.log(""))}function w2(r,e){r.length!==0&&(E.info(`Running ${r.length} quarantined ${Em(r)} with ${iL(e)}:`),r.forEach(t=>{E.info(`${vt}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),E.log(""))}function C2(r,e,t){e.length===0&&r.length>0||(E.info(`Running ${e.length} ${Em(e)} with ${iL(t)}:`),e.forEach(n=>{E.info(`${vt}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),E.log(""))}function lL({logger:r,localTestsToRunWithInputs:e,parallel:t,shardCount:n,shardIndex:o}){r.info({tests:e.length,shardCount:n,shardIndex:o,parallel:t},"Running local tests");let[i,a]=A2(e,s=>s.quarantined);w2(i,t),C2(i,a,t)}import{randomUUID as x2}from"crypto";import{cloneDeep as Is}from"lodash-es";async function cL({orgId:r,codeEvalTools:e,logger:t,outputDefinitions:n,testContext:o}){let i={};for(let a of n){let{name:s,value:c}=a;i[s]=await dr({orgId:r,s:c,localTools:e,logger:t,context:o})}return i}async function uL({baseUrl:r,envName:e,testName:t,devicePixelRatio:n,apiClient:o,test:i,storageClient:a,codeEvalTools:s,generator:c,orgId:l,variables:u,logger:d,customHeaders:p,testInputs:m,localBrowserConfig:h,aiSettings:g,visualDiffScreenshotStorage:f,tracer:y}){let S=await vp({settings:h,customHeaders:p,envVariables:u,envName:e,testName:t,baseUrl:r,logger:d,localTools:s,orgId:l}),T={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:Y,mode:"runner"},A=S.browserType??"Chromium";if(!MR(A)){let _=`Browser ${A} is required by the test named ${i.name} but does not appear to be installed on this machine. Please install it using 'momentic install-browsers' before running tests. Attempting to continue...`;E.warn(_),Y.warn(_)}let v=await Yr.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new Lo(T,c),contextArgs:{viewport:i.advanced.viewport??Yt,locale:i.advanced.locale??Ro,geolocation:i.advanced.geolocation??wo,timezoneId:i.advanced.timezone??Ao,colorScheme:i.advanced.colorScheme,deviceScaleFactor:n},callbacks:{onNetworkPage:_=>y.onNetworkPage(_),onNetworkLogs:_=>y.onNetworkLogs(_)},iconKnowledgeBase:null,videoOptions:y.videoOutputPath?{videoOutputPath:y.videoOutputPath,onVideoPageChange:({videoName:_})=>{y.setActiveVideo(_)}}:void 0}),w=new Jo({browser:v,generator:c,logger:d,orgId:l,options:{scratchPadId:void 0,slowMoMs:S.slowMoMs,autoFollowNewTabs:S.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:a,localCodeEvalTools:s,visualDiffScreenshotStorage:f}),x=new sr({baseUrl:r,currentUrl:w.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async _=>{let{name:D,defaultValue:z,required:B}=_,L=m?.[D];B&&L===void 0&&(E.error(`Required parameter '${D}' is required by test '${i.name}' but not provided`),process.exit(1));let j=await dr({orgId:l,s:L??z,localTools:s,logger:d,context:sr.dummyContext(x.getEnvName())});x.setMomenticSystemVariable(D,j)})),{controller:w,context:x}}async function dL({testAdvancedSettings:r,orgSettings:e,logger:t}){if(r.failureRecovery===!1||r.failureRecovery===void 0&&!e?.failureRecovery)return!1;if(!wi){let n="This test is ineligible for failure recovery since this does not appear to be a CI environment";return t.warn(n),E.warn(n),!1}return!0}async function pL({attemptInputs:r,attemptFixtures:e,attemptMetadata:t}){let{orgId:n,runId:o}=t,{controller:i,context:a,codeEvalTools:s,storageClient:c,logger:l,usageTracker:u,tracer:d}=e,{test:p,orgSettings:m}=r;l.info(`Running test '${p.name}' locally (run link: https://app.momentic.ai/runs/${o})`);let h={controller:i,storage:c,usageTracker:u,context:a,logger:l,codeEvalTools:s},g={orgId:n,runId:o,testMetadata:p,steps:p.steps,beforeSteps:p.beforeSteps,afterSteps:p.afterSteps,orgSettings:m},f={collectDebugData:!0,reinitializeBrowser:!0,disableHealing:!await dL({testAdvancedSettings:p.advanced,orgSettings:m.ai,logger:l})};return await bp({fixtures:h,inputs:g,options:f,callbacks:{step:{},test:{onTestComplete:async()=>{await i.browser.cleanup()}}},testParams:{tracer:d}})}async function mL(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await _2(r)}catch(o){let i="Fatal error running test";return E.error(`${i}: ${o.message}`),t.error({err:o},i),{results:[],parameters:r,failureReason:"UnknownError",failureDetails:{errorMessage:o.message,errorStack:o.stack},status:"FAILED",attempts:0,test:e,filePath:e.relativeFilePath,startedAt:n,lastAttemptStartedAt:n,finishedAt:new Date,outputs:{}}}}async function _2(r){let{testDefinition:e,project:t,apiClient:n,orgId:o,urlOverride:i,runSigIntHandlers:a,runGroupTracer:s,logger:c,gitMetadata:l,cacheOptions:u,runId:d,testInputs:p,quarantined:m,quarantinedReason:h,usageTracker:g}=r,f=new ka(n,o),y=Do({orgId:o,client:n,gitMetadata:l,regenerateCache:u.regenerateCache??!1,alwaysSaveCache:u.alwaysSaveCache??!1,noCache:u.noCache??!1,bustOldestCachePercentage:u.bustOldestCachePercentage}),S=await Yu({cacheStorage:y,logger:c,schemaVersion:e.schemaVersion,stepLists:{steps:e.steps,beforeSteps:e.beforeSteps,afterSteps:e.afterSteps},testId:e.id}),T=S.steps,A=S.beforeSteps??void 0,v=S.afterSteps??void 0,w=r.envName??I2(e),x,_={};if(w){try{x=Li(w,t,c)}catch(L){let j=`Failed to resolve environment ${w} for test ${e.name}: ${L}`;throw new Error(j)}_=x.variables}let D=e.baseUrl;if(i)D=i;else if(!D){let L=_[Rt];typeof L=="string"&&(D=L)}if(!D){let L=`Cannot run test with no base URL and no ${Rt} variable defined in its environment`;throw new Error(L)}let z=await s.startRun({logger:c,runId:d,originalSteps:{beforeSteps:e.beforeSteps,steps:e.steps,afterSteps:e.afterSteps},testId:e.id,testName:e.name,testDescription:e.description??void 0,testLabels:e.labels,baseUrl:D,environmentName:w,schemaVersion:e.schemaVersion,resolvedInputs:p,quarantined:m,quarantinedReason:h}),B=c.child(z.loggerBindings||{});Object.entries(z.envVarBindings||{}).forEach(([L,j])=>{_[L]=j});try{let L=await M2({...r,variables:_,envName:w,resolvedEnv:x,baseUrl:D,storageClient:f,tracer:z,logger:B,cacheStorage:y,stepsWithCaches:T,beforeStepsWithCaches:A,afterStepsWithCaches:v,usageTracker:g});return await z.finish({logger:c,status:L.status,finishedAt:L.finishedAt,failureDetails:L.failureDetails,failureReason:L.failureReason,isFlake:L.isFlake,failureRecoveryDetails:L.failureRecoveryDetails}),{runId:z.runId,...L}}finally{a?.pop()}}async function M2(r){let{testDefinition:e,stepsWithCaches:t,beforeStepsWithCaches:n,afterStepsWithCaches:o,project:i,regenerateGoldenFiles:a,apiClient:s,generator:c,baseUrl:l,storageClient:u,orgId:d,envName:p,urlOverride:m,customHeaders:h,testInputs:g,variables:f,resolvedEnv:y,retriesOverride:S,devicePixelRatio:T,logUpdate:A,tracer:v,logger:w,cacheStorage:x,gitMetadata:_,quarantined:D,quarantinedReason:z,usageTracker:B}=r,L=i.config.ai?.aiFailureAnalysis??!1,j=new Date,Q=new Xa(i,a),K={...i.config},ve={envName:p,urlOverride:m,customHeaders:h,testInputs:g},q,st=Math.abs(S??i.config.retries??e.retries??0),Oe=[];w.info({..._,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let ht=0;ht<=st;ht++){let tr=x2(),He=await v.startAttempt(tr),ae=w.child(He.loggerBindings||{}),$e={...e,steps:Is(t),beforeSteps:Is(n),afterSteps:Is(o)};ht!==0&&A("RETRY",`attempt ${ht+1}/${st+1}`);let Qr=new Date,ta=K.advanced?.fakerConstantSeed,Ps=new xn({httpClient:new zt({baseUrl:s.baseUrl,apiKey:s.apiKey,logger:ae,mode:"runner"}),fakerSeed:ta?Pa:void 0}),vm=He;try{let{controller:rr,context:Zr}=await uL({tracer:He,baseUrl:l,envName:p,testName:$e.name,apiClient:s,devicePixelRatio:T,logger:ae,storageClient:u,codeEvalTools:Ps,test:$e,generator:c,orgId:d,variables:f,customHeaders:h,testInputs:g,localBrowserConfig:{...i.config.browser||{},...y?.browser||{},...$e.advanced},aiSettings:{...i.config.ai||{},...$e.advanced||{}},visualDiffScreenshotStorage:Q});q=await pL({attemptMetadata:{attemptNumber:ht+1,orgId:d,runId:v.runId},attemptFixtures:{logger:ae,storageClient:u,usageTracker:B,codeEvalTools:Ps,apiClient:s,context:Zr,controller:rr,tracer:He},attemptInputs:{test:$e,orgSettings:K}});let oi=new Date,fn={logger:w,cacheStorage:x,orgId:d,testId:e.id,originalStepsWithCaches:{steps:Is(t),beforeSteps:Is(n),afterSteps:Is(o)},updatedStepsWithCaches:{steps:$e.steps,beforeSteps:$e.beforeSteps,afterSteps:$e.afterSteps}};q?.status==="PASSED"?await td(fn):q?.status==="FAILED"&&ht===st&&await rd(fn),await He.finish({logger:ae,result:q}),Oe.unshift(q.status);let X=await cL({orgId:d,codeEvalTools:Ps,logger:ae,outputDefinitions:e.outputs??[],testContext:Zr}),po=VT(Oe),ra=ht+1;if(q.status!=="FAILED")return{...q,runAttemptId:tr,parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:j,lastAttemptStartedAt:Qr,finishedAt:oi,attempts:ra,baseUrl:l,outputs:X,isFlake:po,quarantined:D,quarantinedReason:z};let na=q.failedStepResult,jn=na?.message||"Unknown failure",mo=na?.failureReason??XE(jn)??"UnknownError",Os=ae.child({errResult:na,failureReason:mo,errorMessage:jn,numAttempts:st+1,name:$e.name});if(ht<st){Os.warn(`Retrying failed execution attempt for run: ${jn}`);continue}Os.error(`Test failed after all exhausting attempts: ${jn}`);let oa=new Error(jn),ho={errorMessage:jn,errorStack:oa.stack},Rm;if(L){let Ls;try{if(q.results&&q.results.length>0){let{classification:Ne,aiFailureReason:Tr}=await BA({logger:ae,browserStateStorage:vm,generator:c,fullResults:q,failureReason:mo,error:oa,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Ls=Ne,Rm=Tr}}catch(Ne){ae.warn({err:Ne},"Failed to classify test results")}Ls&&(ho.classification=Ls,mo=Rm??mo)}return{...q,runAttemptId:tr,parameters:ve,failureDetails:ho,failureReason:mo,test:$e,filePath:$e.relativeFilePath,startedAt:j,lastAttemptStartedAt:Qr,finishedAt:oi,attempts:ht+1,baseUrl:l,outputs:X,quarantined:D,quarantinedReason:z}}catch(rr){Ds(rr);let Zr=`Encountered fatal platform error while running test '${$e.name}': ${rr}`,oi=new Date,fn=ht+1;ae.error({err:rr},Zr),E.error(Zr);let X={errorMessage:rr.message,errStack:rr.stack},po={status:"FAILED",failureDetails:X,failureReason:"InternalPlatformError",finishedAt:oi};return await He.finish({logger:ae,result:{status:"FAILED",results:[]}}),{...po,runAttemptId:tr,results:[],parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:j,lastAttemptStartedAt:Qr,finishedAt:new Date,attempts:fn,baseUrl:l,outputs:{},quarantined:D,quarantinedReason:z}}}throw new Error("This code should not be reachable")}function I2(r){for(let e of r.envs??[])if(e.default)return e.name}import L2 from"adm-zip";import N2 from"path";function P2(r){switch(r){case"PASSED":return"SUCCESS";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":case"PENDING":case"RETRYING":case"WAITING_FOR_USER":return"RUNNING"}}var ea=class{constructor(e,t,n,o){this.orgId=e;this.testId=t;this.testName=n;this.diskStorage=o}children=[];finished=!1;stepFrequenciesByType={};async getScreenshot(e,t){return this.diskStorage.readFile(`${cr}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${cr}/${t}.html`)?.toString()}getParentStepIdChain(){return[]}recordStepStat(e){e.type!=="PRESET_ACTION"?this.stepFrequenciesByType[e.type]=(this.stepFrequenciesByType[e.type]||0)+1:this.stepFrequenciesByType[e.command.type]=(this.stepFrequenciesByType[e.command.type]||0)+1}sendFinalizedStepStats(){for(let[e,t]of Object.entries(this.stepFrequenciesByType))kt.increment("test_step_execution",t,[`type:${e}`,"platform:browser","executor:cli",`orgId:${this.orgId}`])}async startStep(e){let{step:t}=e;this.recordStepStat(t);let n={step:t,status:"RUNNING",startedAt:new Date},o=new Ly(this.orgId,this.testId,this.testName,n,this.diskStorage);return this.children.push(o),o}async finish(e){this.finished||(this.finished=!0,await Promise.all(this.children.map(t=>t.finishInternal({status:P2(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}};function O2(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var Ly=class{constructor(e,t,n,o,i){this.orgId=e;this.testId=t;this.testName=n;this.metadata=o;this.diskStorage=i}children=[];finished=!1;getParentStepIdChain(){return[]}attachBeforeScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.jpeg`,contents:n})}attachAfterScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.jpeg`,contents:n})}attachBeforeHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.html`,contents:n})}attachAfterHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.html`,contents:n})}recordTargetAutoHeal(e){let{healType:t}=e,n=t==="AI"?"ai-target-heal":"cache-heal";kt.increment("test_event",1,[`name:${n}`,`orgId:${this.orgId}`]),this.metadata.healMetadata={healType:t,healedAt:new Date}}recordStepDuration(e){let t=e.step.type!=="PRESET_ACTION"?e.step.type:e.step.command.type;kt.distribution("test_step_duration",e.durationMs,[`type:${t}`,"platform:browser","executor:cli",`orgId:${this.orgId}`])}async finishInternal(e){this.finished||(this.finished=!0,await Promise.all(this.children.map(t=>t.finish({status:O2(e.status),finishedAt:e.finishedAt}))))}async finish(e){await this.finishInternal(e.step)}async startSubSteps(){let e=new ea(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}};var vc=class{constructor(e,t,n,o,i,a,s){this.orgId=e;this.testId=t;this.testName=n;this.runAttemptId=o;this.metadata=i;this.diskStorage=a;this.recordVideo=s;this.diskStorage.mkdir(cr),this.harPagesStream=this.diskStorage.createFileStream(`${cr}/har-pages.log`),this.inProgressHarEntries={},this.harEntriesStream=this.diskStorage.createFileStream(`${cr}/har-entries.log`)}finished=!1;children=[];harPagesStream;inProgressHarEntries;harEntriesStream;get loggerBindings(){return{runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return N2.resolve(this.diskStorage.cwd(),cr)}setActiveVideo(e){this.recordVideo&&(this.metadata.activeVideos=this.metadata.activeVideos||[],this.metadata.activeVideos.push({videoName:e,timestamp:new Date}))}onNetworkPage(e){this.finished||this.harPagesStream.write(`${JSON.stringify(e)}
|
|
4824
|
+
`),1)}function nL(){return h2()==="darwin"&&m2("system_profiler SPDisplaysDataType").toString().includes("Retina")}function Iy(r){nL()&&r===1&&(E.warn("If you are using Momentic on a Retina screen, relaunch with the --pixel-ratio option to avoid incorrect viewport calculations."),E.warn("Confirm your device's pixel-ratio at https://www.mydevice.io."))}import g2 from"@actions/exec";import f2 from"@actions/io";import S2 from"quote";import y2 from"string-argv";async function oL(r,e=!0){let t=y2(r),n=await f2.which(t[0],!0),o=t.slice(1),i=g2.exec(S2(n),o,{delay:100});if(e)return i}import E2 from"csv-parser";import{createReadStream as T2}from"fs";function Py(r){return new Promise((e,t)=>{let n=[];T2(r).pipe(E2()).on("data",o=>n.push(o)).on("end",()=>e(n)).on("error",o=>t(o))})}import Ms from"semver";import{z as ym}from"zod";var Ir="2.28.7",b2="https://registry.npmjs.org/momentic",v2=ym.object({versions:ym.record(ym.string(),ym.unknown()).optional()});async function er(r){try{await R2(r)}catch(e){E.warn({err:e},"Failed to check CLI version against NPM servers")}}async function Oy(){let r=await $(fetch(b2),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=v2.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=Ir;for(let o of Object.keys(t))Ms.valid(o)&&Ms.major(o)===Ms.major(Ir)&&Ms.gt(o,n)&&Ms.prerelease(o)===null&&(n=o);return n}async function R2(r){let e;for(let t=0;t<2;t++)try{e=await Oy()}catch(n){r.warn({err:n},"Failed to fetch latest version from npm registry")}if(!e){r.warn("Failed to fetch npm registry data. Skipping version check.");return}Ms.eq(Ir,e)||(E.warn(`Update available: v${Ir} -> v${e}`),E.warn("This version may be missing critical fixes, features, and security updates."),E.warn('Run "npx momentic@latest upgrade" to update'))}async function uo(){try{await $(Promise.all([wR(),kt.flush()]),{milliseconds:5e3})}catch{}}import{partition as A2}from"lodash-es";function Em(r){return r.length===1?"test":"tests"}function iL(r){return r===1?"1 worker":`${r} workers`}function aL(r){r.length!==0&&(E.info(`Skipping ${r.length} disabled ${Em(r)}:`),r.forEach(e=>{E.info(`${vt}- ${[e.relativeFilePath]}`)}),E.log(""))}function sL(r,e){r.length!==0&&(E.info(`Skipping ${r.length} quarantined ${Em(r)}:`),r.forEach(t=>{E.info(`${vt}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),E.log(""))}function w2(r,e){r.length!==0&&(E.info(`Running ${r.length} quarantined ${Em(r)} with ${iL(e)}:`),r.forEach(t=>{E.info(`${vt}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),E.log(""))}function C2(r,e,t){e.length===0&&r.length>0||(E.info(`Running ${e.length} ${Em(e)} with ${iL(t)}:`),e.forEach(n=>{E.info(`${vt}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),E.log(""))}function lL({logger:r,localTestsToRunWithInputs:e,parallel:t,shardCount:n,shardIndex:o}){r.info({tests:e.length,shardCount:n,shardIndex:o,parallel:t},"Running local tests");let[i,a]=A2(e,s=>s.quarantined);w2(i,t),C2(i,a,t)}import{randomUUID as x2}from"crypto";import{cloneDeep as Is}from"lodash-es";async function cL({orgId:r,codeEvalTools:e,logger:t,outputDefinitions:n,testContext:o}){let i={};for(let a of n){let{name:s,value:c}=a;i[s]=await dr({orgId:r,s:c,localTools:e,logger:t,context:o})}return i}async function uL({baseUrl:r,envName:e,testName:t,devicePixelRatio:n,apiClient:o,test:i,storageClient:a,codeEvalTools:s,generator:c,orgId:l,variables:u,logger:d,customHeaders:p,testInputs:m,localBrowserConfig:h,aiSettings:g,visualDiffScreenshotStorage:f,tracer:y}){let S=await vp({settings:h,customHeaders:p,envVariables:u,envName:e,testName:t,baseUrl:r,logger:d,localTools:s,orgId:l}),T={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:Y,mode:"runner"},A=S.browserType??"Chromium";if(!MR(A)){let _=`Browser ${A} is required by the test named ${i.name} but does not appear to be installed on this machine. Please install it using 'momentic install-browsers' before running tests. Attempting to continue...`;E.warn(_),Y.warn(_)}let v=await Yr.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new Lo(T,c),contextArgs:{viewport:i.advanced.viewport??Yt,locale:i.advanced.locale??Ro,geolocation:i.advanced.geolocation??wo,timezoneId:i.advanced.timezone??Ao,colorScheme:i.advanced.colorScheme,deviceScaleFactor:n},callbacks:{onNetworkPage:_=>y.onNetworkPage(_),onNetworkLogs:_=>y.onNetworkLogs(_)},iconKnowledgeBase:null,videoOptions:y.videoOutputPath?{videoOutputPath:y.videoOutputPath,onVideoPageChange:({videoName:_})=>{y.setActiveVideo(_)}}:void 0}),w=new Jo({browser:v,generator:c,logger:d,orgId:l,options:{scratchPadId:void 0,slowMoMs:S.slowMoMs,autoFollowNewTabs:S.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:a,localCodeEvalTools:s,visualDiffScreenshotStorage:f}),x=new sr({baseUrl:r,currentUrl:w.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async _=>{let{name:D,defaultValue:z,required:B}=_,L=m?.[D];B&&L===void 0&&(E.error(`Required parameter '${D}' is required by test '${i.name}' but not provided`),process.exit(1));let j=await dr({orgId:l,s:L??z,localTools:s,logger:d,context:sr.dummyContext(x.getEnvName())});x.setMomenticSystemVariable(D,j)})),{controller:w,context:x}}async function dL({testAdvancedSettings:r,orgSettings:e,logger:t}){if(r.failureRecovery===!1||r.failureRecovery===void 0&&!e?.failureRecovery)return!1;if(!wi){let n="This test is ineligible for failure recovery since this does not appear to be a CI environment";return t.warn(n),E.warn(n),!1}return!0}async function pL({attemptInputs:r,attemptFixtures:e,attemptMetadata:t}){let{orgId:n,runId:o}=t,{controller:i,context:a,codeEvalTools:s,storageClient:c,logger:l,usageTracker:u,tracer:d}=e,{test:p,orgSettings:m}=r;l.info(`Running test '${p.name}' locally (run link: https://app.momentic.ai/runs/${o})`);let h={controller:i,storage:c,usageTracker:u,context:a,logger:l,codeEvalTools:s},g={orgId:n,runId:o,testMetadata:p,steps:p.steps,beforeSteps:p.beforeSteps,afterSteps:p.afterSteps,orgSettings:m},f={collectDebugData:!0,reinitializeBrowser:!0,disableHealing:!await dL({testAdvancedSettings:p.advanced,orgSettings:m.ai,logger:l})};return await bp({fixtures:h,inputs:g,options:f,callbacks:{step:{},test:{onTestComplete:async()=>{await i.browser.cleanup()}}},testParams:{tracer:d}})}async function mL(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await _2(r)}catch(o){let i="Fatal error running test";return E.error(`${i}: ${o.message}`),t.error({err:o},i),{results:[],parameters:r,failureReason:"UnknownError",failureDetails:{errorMessage:o.message,errorStack:o.stack},status:"FAILED",attempts:0,test:e,filePath:e.relativeFilePath,startedAt:n,lastAttemptStartedAt:n,finishedAt:new Date,outputs:{}}}}async function _2(r){let{testDefinition:e,project:t,apiClient:n,orgId:o,urlOverride:i,runSigIntHandlers:a,runGroupTracer:s,logger:c,gitMetadata:l,cacheOptions:u,runId:d,testInputs:p,quarantined:m,quarantinedReason:h,usageTracker:g}=r,f=new ka(n,o),y=Do({orgId:o,client:n,gitMetadata:l,regenerateCache:u.regenerateCache??!1,alwaysSaveCache:u.alwaysSaveCache??!1,noCache:u.noCache??!1,bustOldestCachePercentage:u.bustOldestCachePercentage}),S=await Yu({cacheStorage:y,logger:c,schemaVersion:e.schemaVersion,stepLists:{steps:e.steps,beforeSteps:e.beforeSteps,afterSteps:e.afterSteps},testId:e.id}),T=S.steps,A=S.beforeSteps??void 0,v=S.afterSteps??void 0,w=r.envName??I2(e),x,_={};if(w){try{x=Li(w,t,c)}catch(L){let j=`Failed to resolve environment ${w} for test ${e.name}: ${L}`;throw new Error(j)}_=x.variables}let D=e.baseUrl;if(i)D=i;else if(!D){let L=_[Rt];typeof L=="string"&&(D=L)}if(!D){let L=`Cannot run test with no base URL and no ${Rt} variable defined in its environment`;throw new Error(L)}let z=await s.startRun({logger:c,runId:d,originalSteps:{beforeSteps:e.beforeSteps,steps:e.steps,afterSteps:e.afterSteps},testId:e.id,testName:e.name,testDescription:e.description??void 0,testLabels:e.labels,baseUrl:D,environmentName:w,schemaVersion:e.schemaVersion,resolvedInputs:p,quarantined:m,quarantinedReason:h}),B=c.child(z.loggerBindings||{});Object.entries(z.envVarBindings||{}).forEach(([L,j])=>{_[L]=j});try{let L=await M2({...r,variables:_,envName:w,resolvedEnv:x,baseUrl:D,storageClient:f,tracer:z,logger:B,cacheStorage:y,stepsWithCaches:T,beforeStepsWithCaches:A,afterStepsWithCaches:v,usageTracker:g});return await z.finish({logger:c,status:L.status,finishedAt:L.finishedAt,failureDetails:L.failureDetails,failureReason:L.failureReason,isFlake:L.isFlake,failureRecoveryDetails:L.failureRecoveryDetails}),{runId:z.runId,...L}}finally{a?.pop()}}async function M2(r){let{testDefinition:e,stepsWithCaches:t,beforeStepsWithCaches:n,afterStepsWithCaches:o,project:i,regenerateGoldenFiles:a,apiClient:s,generator:c,baseUrl:l,storageClient:u,orgId:d,envName:p,urlOverride:m,customHeaders:h,testInputs:g,variables:f,resolvedEnv:y,retriesOverride:S,devicePixelRatio:T,logUpdate:A,tracer:v,logger:w,cacheStorage:x,gitMetadata:_,quarantined:D,quarantinedReason:z,usageTracker:B}=r,L=i.config.ai?.aiFailureAnalysis??!1,j=new Date,Q=new Xa(i,a),K={...i.config},ve={envName:p,urlOverride:m,customHeaders:h,testInputs:g},q,st=Math.abs(S??i.config.retries??e.retries??0),Oe=[];w.info({..._,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let ht=0;ht<=st;ht++){let tr=x2(),He=await v.startAttempt(tr),ae=w.child(He.loggerBindings||{}),$e={...e,steps:Is(t),beforeSteps:Is(n),afterSteps:Is(o)};ht!==0&&A("RETRY",`attempt ${ht+1}/${st+1}`);let Qr=new Date,ta=K.advanced?.fakerConstantSeed,Ps=new xn({httpClient:new zt({baseUrl:s.baseUrl,apiKey:s.apiKey,logger:ae,mode:"runner"}),fakerSeed:ta?Pa:void 0}),vm=He;try{let{controller:rr,context:Zr}=await uL({tracer:He,baseUrl:l,envName:p,testName:$e.name,apiClient:s,devicePixelRatio:T,logger:ae,storageClient:u,codeEvalTools:Ps,test:$e,generator:c,orgId:d,variables:f,customHeaders:h,testInputs:g,localBrowserConfig:{...i.config.browser||{},...y?.browser||{},...$e.advanced},aiSettings:{...i.config.ai||{},...$e.advanced||{}},visualDiffScreenshotStorage:Q});q=await pL({attemptMetadata:{attemptNumber:ht+1,orgId:d,runId:v.runId},attemptFixtures:{logger:ae,storageClient:u,usageTracker:B,codeEvalTools:Ps,apiClient:s,context:Zr,controller:rr,tracer:He},attemptInputs:{test:$e,orgSettings:K}});let oi=new Date,fn={logger:w,cacheStorage:x,orgId:d,testId:e.id,originalStepsWithCaches:{steps:Is(t),beforeSteps:Is(n),afterSteps:Is(o)},updatedStepsWithCaches:{steps:$e.steps,beforeSteps:$e.beforeSteps,afterSteps:$e.afterSteps}};q?.status==="PASSED"?await td(fn):q?.status==="FAILED"&&ht===st&&await rd(fn),await He.finish({logger:ae,result:q}),Oe.unshift(q.status);let X=await cL({orgId:d,codeEvalTools:Ps,logger:ae,outputDefinitions:e.outputs??[],testContext:Zr}),po=VT(Oe),ra=ht+1;if(q.status!=="FAILED")return{...q,runAttemptId:tr,parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:j,lastAttemptStartedAt:Qr,finishedAt:oi,attempts:ra,baseUrl:l,outputs:X,isFlake:po,quarantined:D,quarantinedReason:z};let na=q.failedStepResult,jn=na?.message||"Unknown failure",mo=na?.failureReason??XE(jn)??"UnknownError",Os=ae.child({errResult:na,failureReason:mo,errorMessage:jn,numAttempts:st+1,name:$e.name});if(ht<st){Os.warn(`Retrying failed execution attempt for run: ${jn}`);continue}Os.error(`Test failed after all exhausting attempts: ${jn}`);let oa=new Error(jn),ho={errorMessage:jn,errorStack:oa.stack},Rm;if(L){let Ls;try{if(q.results&&q.results.length>0){let{classification:Ne,aiFailureReason:Tr}=await BA({logger:ae,browserStateStorage:vm,generator:c,fullResults:q,failureReason:mo,error:oa,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Ls=Ne,Rm=Tr}}catch(Ne){ae.warn({err:Ne},"Failed to classify test results")}Ls&&(ho.classification=Ls,mo=Rm??mo)}return{...q,runAttemptId:tr,parameters:ve,failureDetails:ho,failureReason:mo,test:$e,filePath:$e.relativeFilePath,startedAt:j,lastAttemptStartedAt:Qr,finishedAt:oi,attempts:ht+1,baseUrl:l,outputs:X,quarantined:D,quarantinedReason:z}}catch(rr){Ds(rr);let Zr=`Encountered fatal platform error while running test '${$e.name}': ${rr}`,oi=new Date,fn=ht+1;ae.error({err:rr},Zr),E.error(Zr);let X={errorMessage:rr.message,errStack:rr.stack},po={status:"FAILED",failureDetails:X,failureReason:"InternalPlatformError",finishedAt:oi};return await He.finish({logger:ae,result:{status:"FAILED",results:[]}}),{...po,runAttemptId:tr,results:[],parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:j,lastAttemptStartedAt:Qr,finishedAt:new Date,attempts:fn,baseUrl:l,outputs:{},quarantined:D,quarantinedReason:z}}}throw new Error("This code should not be reachable")}function I2(r){for(let e of r.envs??[])if(e.default)return e.name}import L2 from"adm-zip";import N2 from"path";function P2(r){switch(r){case"PASSED":return"SUCCESS";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":case"PENDING":case"RETRYING":case"WAITING_FOR_USER":return"RUNNING"}}var ea=class{constructor(e,t,n,o){this.orgId=e;this.testId=t;this.testName=n;this.diskStorage=o}children=[];finished=!1;stepFrequenciesByType={};async getScreenshot(e,t){return this.diskStorage.readFile(`${cr}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${cr}/${t}.html`)?.toString()}getParentStepIdChain(){return[]}recordStepStat(e){e.type!=="PRESET_ACTION"?this.stepFrequenciesByType[e.type]=(this.stepFrequenciesByType[e.type]||0)+1:this.stepFrequenciesByType[e.command.type]=(this.stepFrequenciesByType[e.command.type]||0)+1}sendFinalizedStepStats(){for(let[e,t]of Object.entries(this.stepFrequenciesByType))kt.increment("test_step_execution",t,[`type:${e}`,"platform:browser","executor:cli",`orgId:${this.orgId}`])}async startStep(e){let{step:t}=e;this.recordStepStat(t);let n={step:t,status:"RUNNING",startedAt:new Date},o=new Ly(this.orgId,this.testId,this.testName,n,this.diskStorage);return this.children.push(o),o}async finish(e){this.finished||(this.finished=!0,await Promise.all(this.children.map(t=>t.finishInternal({status:P2(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}};function O2(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var Ly=class{constructor(e,t,n,o,i){this.orgId=e;this.testId=t;this.testName=n;this.metadata=o;this.diskStorage=i}children=[];finished=!1;getParentStepIdChain(){return[]}attachBeforeScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.jpeg`,contents:n})}attachAfterScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.jpeg`,contents:n})}attachBeforeHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.html`,contents:n})}attachAfterHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${cr}/${t}.html`,contents:n})}recordTargetAutoHeal(e){let{healType:t}=e,n=t==="AI"?"ai-target-heal":"cache-heal";kt.increment("test_event",1,[`name:${n}`,`orgId:${this.orgId}`]),this.metadata.healMetadata={healType:t,healedAt:new Date}}recordStepDuration(e){let t=e.step.type!=="PRESET_ACTION"?e.step.type:e.step.command.type;kt.distribution("test_step_duration",e.durationMs,[`type:${t}`,"platform:browser","executor:cli",`orgId:${this.orgId}`])}async finishInternal(e){this.finished||(this.finished=!0,await Promise.all(this.children.map(t=>t.finish({status:O2(e.status),finishedAt:e.finishedAt}))))}async finish(e){await this.finishInternal(e.step)}async startSubSteps(){let e=new ea(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}};var vc=class{constructor(e,t,n,o,i,a,s){this.orgId=e;this.testId=t;this.testName=n;this.runAttemptId=o;this.metadata=i;this.diskStorage=a;this.recordVideo=s;this.diskStorage.mkdir(cr),this.harPagesStream=this.diskStorage.createFileStream(`${cr}/har-pages.log`),this.inProgressHarEntries={},this.harEntriesStream=this.diskStorage.createFileStream(`${cr}/har-entries.log`)}finished=!1;children=[];harPagesStream;inProgressHarEntries;harEntriesStream;get loggerBindings(){return{runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return N2.resolve(this.diskStorage.cwd(),cr)}setActiveVideo(e){this.recordVideo&&(this.metadata.activeVideos=this.metadata.activeVideos||[],this.metadata.activeVideos.push({videoName:e,timestamp:new Date}))}onNetworkPage(e){this.finished||this.harPagesStream.write(`${JSON.stringify(e)}
|
|
4825
4825
|
`)}onNetworkLogs(e){if(!this.finished)for(let[t,n]of Object.entries(e))n.response?(delete this.inProgressHarEntries[t],this.harEntriesStream.write(`${JSON.stringify(n)}
|
|
4826
4826
|
`)):this.inProgressHarEntries[t]=n}attachConsoleLogs(e){let{logs:t}=e;this.diskStorage.storeFile({name:"console.json",contents:JSON.stringify(t,null,2)})}attachBrowserCrashDump(e){let{crashReportDirFetcher:t,logger:n}=e,o=t();if(!o)return;let i=new L2;i.addLocalFolder(o,void 0,a=>a!==".DS_Store"),this.diskStorage.storeFile({name:`${cr}/${ug}`,contents:i.toBuffer()}),n.info({browserCrashZipName:ug},"Attached browser crash ZIP")}async finish(e){if(this.finished)return;this.finished=!0;let{logger:t,result:n}=e,o={...this.metadata,status:n.status,finishedAt:new Date,results:ed(n.results,t),beforeResults:n.beforeResults?ed(n.beforeResults,t):void 0,afterResults:n.afterResults?ed(n.afterResults,t):void 0};await Promise.all(this.children.map(i=>i.finish({status:o.status,finishedAt:o.finishedAt})));for(let i of Object.values(this.inProgressHarEntries))this.harEntriesStream.write(`${JSON.stringify(i)}
|
|
4827
4827
|
`);try{this.harEntriesStream.end()}catch{}try{this.harPagesStream.end()}catch{}this.diskStorage.storeFile({name:"metadata.json",contents:JSON.stringify(o,null,2)})}async startBeforeStepList(){let e=new ea(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startMainStepList(){let e=new ea(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startAfterStepList(){let e=new ea(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async getScreenshot(e,t){return this.diskStorage.readFile(`${cr}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${cr}/${t}.html`)?.toString()}};var Rc=class{constructor(e,t,n,o,i,a,s){this.orgId=e;this.testId=t;this.testName=n;this.runId=o;this.metadata=i;this.diskStorage=a;this.recordVideo=s}children=[];finished=!1;get loggerBindings(){return{runId:this.runId}}get envVarBindings(){return{[sM]:this.runId}}async finish(e){if(this.finished)return;this.finished=!0;let t={...this.metadata,finishedAt:e.finishedAt||new Date,status:e.status,failureDetails:e.failureDetails,failureReason:e.failureReason,flake:e.isFlake||!1,failureRecoveryDetails:e.failureRecoveryDetails};await Promise.all(this.children.map(n=>n.finish({logger:e.logger,result:{status:t.status,results:[],beforeResults:[],afterResults:[]}}))),this.diskStorage.storeFile({name:"metadata.json",contents:JSON.stringify(t,null,2)}),this.diskStorage.close()}async startAttempt(e){this.metadata.attempts=this.metadata.attempts+1,this.metadata.status="RUNNING",this.diskStorage.storeFile({name:"metadata.json",contents:JSON.stringify(this.metadata,null,2)});let t=this.diskStorage.cd(`attempts/${this.metadata.attempts}`),n={id:e,schemaVersion:xe,runAttemptSchemaVersion:pR,startedAt:new Date,status:"RUNNING"};t.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)});let o=new vc(this.orgId,this.testId,this.testName,e,n,t,this.recordVideo);return this.children.push(o),o}};var Ac=class r{constructor(e,t,n,o,i){this.orgId=e;this.runGroupId=t;this.metadata=n;this.diskStorage=o;this.recordVideo=i}children=[];finished=!1;get loggerBindings(){return{orgId:this.orgId,runGroupId:this.runGroupId,branch:this.metadata.gitBranchName}}static async start({orgId:e,runGroupId:t,outputDir:n,gitMetadata:o,labels:i,recordVideo:a}){let s={...o,id:t,trigger:kr.CLI,startedAt:new Date,status:"RUNNING",cliVersion:Ir,labels:i??[]},c=new Dl(n);return c.storeFile({name:"metadata.json",contents:JSON.stringify(s,null,2)}),new r(e,t,s,c,a??!1)}async finish(e){if(this.finished)return;this.finished=!0;let{status:t}=e,n={...this.metadata,status:t,updatedAt:new Date,finishedAt:new Date};await Promise.all(this.children.map(o=>o.finish({logger:e.logger,status:n.status,finishedAt:n.finishedAt}))),this.diskStorage.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)})}async startRun(e){let t=this.diskStorage.createRunArchive(e.runId),n={stepsSnapshot:e.originalSteps.steps,runGroupId:this.runGroupId,testId:e.testId,testName:e.testName,testDescription:e.testDescription,labels:e.testLabels,trigger:"CLI",status:"RUNNING",resolvedBaseUrl:e.baseUrl,environmentName:e.environmentName,resolvedInputs:e.resolvedInputs,cliVersion:Ir,schemaVersion:e.schemaVersion,startedAt:new Date,attempts:0,quarantined:e.quarantined??!1,quarantinedReason:e.quarantinedReason,executionType:"WEB"};t.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)});let o=new Rc(this.orgId,e.testId,e.testName,e.runId,n,t,this.recordVideo);return this.children.push(o),o}};async function hL(r,e,t){if(t)return{};try{return(await e.getQuarantinedTests()).quarantined.reduce((o,i)=>(o[i.testId]=i.quarantinedReason,o),{})}catch(n){return r.warn({err:n},"Failed to fetch quarantined tests, proceeding without them."),{}}}async function gL(r){let{logger:e,tests:t,yes:n,start:o,waitOn:i,waitOnProxy:a,client:s,project:c,retriesOverride:l,urlOverride:u,envName:d,orgId:p,devicePixelRatio:m,customHeaders:h,testInputMatrix:g,reporter:f,include:y,exclude:S,labels:T,reporterDir:A=ow,outputDir:v=iw,uploadResults:w=!1,waitOnTimeout:x=60,parallel:_,shardIndex:D=1,shardCount:z=1,regenerateGoldenFiles:B,gitMetadata:L,cacheOptions:j,ignoreQuarantine:Q,skipQuarantined:K,onlyQuarantined:ve,runGroupId:q,recordVideo:st,timeoutMinutes:Oe}=r;if(o&&(e.info({orgId:p},`Executing start command: ${o}`),await oL(o,!1)),i){e.info({orgId:p},`Waiting for url: ${i} with timeout: ${x} seconds.`);let Ne=a?new URL(a):void 0,Tr;Ne&&(Tr={host:Ne.hostname,port:Ne.port?parseInt(Ne.port):Ne.protocol.startsWith("https")?443:80,auth:Ne.username||Ne.password?{username:Ne.username,password:Ne.password}:void 0}),await F2({resources:[i],interval:2500,timeout:x*1e3,headers:{Accept:"*/*"},followRedirect:!0,verbose:!1,log:!0,strictSSL:!1,proxy:Tr})}let ht=new Xn(c.config.ai?.agentConfig,{baseUrl:s.baseUrl,apiKey:s.apiKey,logger:e,mode:"runner"}),tr=await ee(c),He=await xs({tests:t,momenticFiles:tr,yes:n,project:c,include:y,exclude:S,labels:T,logger:E}),ae=await hL(e,s,Q),{testsToSkip:$e,quarantinedTestsToSkip:Qr,testsToRun:ta,quarantinedTestsToRun:Ps}=jO({testDefinitions:He,quarantinedTestReasons:ae,onlyQuarantined:ve,skipQuarantined:K});aL($e),sL(Qr,ae);let vm=VO({testsToRun:ta,quarantinedTestsToRun:Ps,quarantinedTestReasons:ae,testInputMatrix:g}),rr=B2({globalTestsToRunWithInputs:vm,shardIndex:D,shardCount:z});lL({logger:e,localTestsToRunWithInputs:rr,parallel:_,shardCount:z,shardIndex:D});let Zr=[],oi=new Date,fn=new Set,X=async()=>{let Ne=s.getAppUrl(),Tr=Da({results:Zr,startTime:oi.getTime(),onFailed:br=>{Uu(br,br.filePath)},getDisplayLine:br=>{let ii=`${vt}- ${br.filePath}${br.failureRecoveryDetails?" [recovered] ":""}`;return br.runId&&(ii+=` ( link when uploaded: ${Ne}/runs/${br.runId} )`),ii},entity:"test"}),wc=Zr.filter(br=>!!br.failureRecoveryDetails?.attempts);return wc.length>0&&E.warn(`Our AI agent automatically prevented ${wc.length} tests from failing due to transient issues. Use the run links above to review the additional steps that were executed.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "momentic",
|
|
3
|
-
"version": "2.28.
|
|
3
|
+
"version": "2.28.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "momentic",
|
|
9
|
-
"version": "2.28.
|
|
9
|
+
"version": "2.28.7",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@actions/exec": "^1.1.1",
|
|
12
12
|
"@actions/io": "^1.1.3",
|