momentic 2.28.3 → 2.28.4
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 bt=" ".repeat(6);function ER(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 XF from"fetch-retry";import JF from"os";import TR,{multistream as QF}from"pino";import ZF from"pino-pretty";import eU from"pino-std-serializers";var La=new Map,tU=!0,bR="Log throttle exceeded",rU=100,nU=5e3,oU=XF(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}}),hg=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??JF.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=tU?TR(a):TR(a,QF([{stream:ZF({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 oU(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===bR)return!0;let t=Date.now();return t-this.lastWindowStart>nU&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,bR),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<rU?(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(Sl[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=eU.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:sv({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=lv[e]):(this.minLevelValue=Sl[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},Na=({app:r,hostname:e,disableConsoleLogs:t})=>(La.has(r)||La.set(r,new hg({bindings:{app:r},hostname:e,disableConsoleLogs:t})),La.get(r));async function RR(){await Promise.all([...La.values()].map(r=>r.flush()))}import{hostname as iU}from"os";var Y=Na({app:"cli",hostname:iU(),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 SU(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}gU(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as G2}from"crypto";import iO from"body-parser";import _K from"cors";import MK from"dedent";import{Router as EB}from"express";import ur from"fs";import{globSync as TB}from"glob";import Dt from"path";import ud from"fs";import{z as CU}from"zod";var z="v1",Sg="cli",Ci="2.28.
|
|
31
|
+
`)}import XF from"fetch-retry";import JF from"os";import TR,{multistream as QF}from"pino";import ZF from"pino-pretty";import eU from"pino-std-serializers";var La=new Map,tU=!0,bR="Log throttle exceeded",rU=100,nU=5e3,oU=XF(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}}),hg=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??JF.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=tU?TR(a):TR(a,QF([{stream:ZF({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 oU(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===bR)return!0;let t=Date.now();return t-this.lastWindowStart>nU&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,bR),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<rU?(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(Sl[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=eU.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:sv({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=lv[e]):(this.minLevelValue=Sl[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},Na=({app:r,hostname:e,disableConsoleLogs:t})=>(La.has(r)||La.set(r,new hg({bindings:{app:r},hostname:e,disableConsoleLogs:t})),La.get(r));async function RR(){await Promise.all([...La.values()].map(r=>r.flush()))}import{hostname as iU}from"os";var Y=Na({app:"cli",hostname:iU(),disableConsoleLogs:!0}).child({cliVersion:"2.28.4"});var sU=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>sU&&(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 yR(()=>{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=$c[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(`${bt}- Error type: ${wn.dim(t)}`);let i="- Root cause analysis:",a=ER(`${i} ${o}`,`${bt} `,!1),s=a.indexOf(":");E.log(`${bt}${i} ${wn.dim(a.slice(s+1))}`)}else E.log(`${bt}Reason: ${wn.red(t)}`),E.log(`${bt}Description: ${wn.red(n)}`)},bl=({status:r,testLogRef:e,getRunningTestsCount:t,getTotalTestsCount:n,additionalText:o})=>{r=r.toUpperCase();let i=r,a;r.includes("FAIL")?(i=wn.bgRed.white("FAIL"),a=3):r.includes("PASS")?(i=wn.bgGreen.white("PASS"),a=3):r.includes("START")?(i=wn.bgBlue.white("START"),a=2):r.includes("CANCEL")?(i=wn.bgRgb(191,68,11).white("CANCEL"),a=1):r.includes("RETRY")?(i=wn.bgRgb(191,68,11).white("RETRY"),a=2):r.includes("RUN")||r.includes("PROG")?(i=wn.bgMagenta.white("RUNNING"),a=0):(E.warn(`Unknown status tried to be logged in run test locally: ${r}`),a=0),aU||(i=`${i}`),E.log(`${i}${" ".repeat(a)} ${e} ${o?`${o} `:""}(${t()}/${n()})`)};import lU from"fs";import{tmpdir as cU}from"os";import uU from"path";import{registry as vl}from"playwright-core/lib/server";import AR from"proper-lockfile";var wR=uU.join(cU(),"momenticBrowserInstallation");var gg=["chrome","chromium","chrome-for-testing","ffmpeg"],dU={Chromium:"chromium","Google Chrome":"chrome","Chrome for Testing":"chrome-for-testing"},CR={chrome:"chrome",chromium:"chromium","chrome-for-testing":"chromium-headless-shell",ffmpeg:"ffmpeg"};function xR(r){let e=CR[dU[r]??""]??"",t=vl.findExecutable(e);return!t||t.installType==="none"?!1:fg(t)}function fg(r){let e=r.executablePath();return lU.existsSync(e)}function pU(r,e){let t=CR[r];if(!t)throw new Error(`Requested install of unknown browser type ${r}`);let n=vl.findExecutable(t);if(!n||n.installType==="none")throw new Error(`Requested install of unknown browser type ${r}`);if(!(!e&&fg(n)))return n}async function mU({browser:r,force:e}){let t=pU(r,e);if(!t){E.info(`Browser '${r}' is already installed, skipping...`);return}E.info(`Installing browser '${r}'...`);try{await vl.installDeps([t],!1),await vl.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=vl.findExecutable(r),i=5*60*1e3,a=Date.now();for(;Date.now()-a<i&&!fg(o);)E.info("Waiting for browser to finish installing..."),await new Promise(s=>setTimeout(s,5e3))}else throw n}}async function _R({rawBrowsers:r,force:e=!1,all:t=!1}){let n=t?gg:Array.from(new Set(r));try{await AR.lock(wR,{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 mU({browser:i,force:e})}catch(a){o=a,E.error(`Failed to install the ${i} browser: ${a}`)}}finally{await AR.unlock(wR,{realpath:!1})}if(o)throw o}import hU from"blocked-at";import gU from"why-is-node-running";function MR(r){fU(r),SU()}function fU(r){hU((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 SU(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}gU(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as G2}from"crypto";import iO from"body-parser";import _K from"cors";import MK from"dedent";import{Router as EB}from"express";import ur from"fs";import{globSync as TB}from"glob";import Dt from"path";import ud from"fs";import{z as CU}from"zod";var z="v1",Sg="cli",Ci="2.28.4";var Io=3.1783027;function yU(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(yg(r)/Io)}function yg(r){let e=0;if(typeof r=="string"){let t=r;t=t.replaceAll(`
|
|
33
33
|
`,""),t=t.replaceAll(" ","");let n=yU(t);return t.length-n+Io*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+=yg(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*Io:e+=85*Io:n==="source"&&typeof t[n]=="object"&&t[n]?.type==="base64"?e+=1600*Io:e+=yg(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 Po=class extends Error{constructor(e){super(e),this.name="TimeoutError"}};var IR=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 V(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(IR(p));l=()=>c(IR(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 Po(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 EU=9e4,TU=3,bU=1500,vU=15e3,an=class extends Error{status;rawError;constructor(e,t,n,o={}){super(n,o),this.status=e,this.rawError=t}};async function RU(r){return r.text().then(e=>{try{return JSON.parse(e).error}catch{return e}})}var Eg=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),Sg&&(e[hv]=Sg),e}async sendRequest(e,t){let{retries:n=TU,requestTimeoutMs:o=EU,initialRetryDelayMs:i=bU,maxRetryDelayMs:a=vU,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 an&&p.status>=400&&p.status<500)throw p;if(p instanceof Error&&p.name==="AbortError"&&(u=new Po),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 RU(u);throw new an(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 Eg{apiKey;mode;constructor(e){super(e),this.apiKey=e.apiKey,this.mode=e.mode}getHeaders(){return{...super.getHeaders(),Authorization:`Bearer ${this.apiKey}`,[mv]:this.mode??""}}};import{createAnthropic as AU}from"@ai-sdk/anthropic";function wU(r){let{apiKey:e,sessionId:t,extraHeaders:n,loggerTags:o}=r,i={Authorization:`Bearer ${e}`,[Ou]:Ci??"",...t&&{[fv]:t},...n||{}};return o&&(i[gv]=JSON.stringify(o)),i}var Rl=r=>e=>{let t=wU(r);return AU({baseURL:`${r.baseUrl}/v1/llm/anthropic/${e}`,headers:t,apiKey:r.apiKey})(e)};var Kn=class extends zt{agentConfig;constructor(e,t){let n={...hu,...e};super(t),this.agentConfig=n}getAgentConfig(){return this.agentConfig}async rankChunksWithAi(e,t){let n={...e,loggerTags:t.loggerTags},o=await this.sendRequest(`/${z}/web-agent/recommend-chunks-ai`,{method:"POST",body:n,signal:t.abortSignal});return XT.parse(o)}async rankChunksWithRag(e,t){let n=await this.sendRequest(`/${z}/web-agent/recommend-chunks`,{method:"POST",body:{cliVersion:Ci,...e},signal:t.abortSignal});return YT.parse(n)}async getScreenshotFromS3(e){let t=await this.sendRequest(`/${z}/s3/visual-diff-screenshot`,{method:"POST",body:{url:e}});return CU.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(`/${z}/web-agent/locate-element`,{method:"POST",body:n,signal:t.abortSignal});return vv.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(`/${z}/web-agent/assertion`,{method:"POST",body:n,signal:t.abortSignal});return rg.parse(o)}async getLintStepResult(e,t){let n={...e,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${z}/web-agent/lint/step`,{method:"POST",body:n,signal:t.abortSignal});return bv.parse(o)}async getLintMcpCopilotMessageResult(e,t){let n={message:e.message,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${z}/web-agent/lint/mcp-copilot`,{method:"POST",body:n,signal:t.abortSignal});return yv.parse(o)}async getMcpCopilotConversationEvaluation(e,t){let n={messagesAndToolCalls:e.messagesAndToolCalls,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${z}/web-agent/mcp-copilot-conversation-evaluator`,{method:"POST",body:n,signal:t.abortSignal});return Ev.parse(o)}async getMcpCopilotChatSummary(e,t){let n={messagesAndToolCalls:e.messagesAndToolCalls,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${z}/web-agent/mcp-copilot-chat-summary`,{method:"POST",body:n,signal:t.abortSignal});return Tv.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(`/${z}/web-agent/visual-assertion`,{method:"POST",body:n,signal:t.abortSignal});return rg.parse(o)}async getAiActionCommand(e,t){let n=await this.sendRequest(`/${z}/web-agent/next-command-dynamic`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return Sv.parse(n)}async getMultiturnAiActionCommand(e,t){return await this.sendRequest(`/${z}/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(`/${z}/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(`/${z}/web-agent/reverse-mapped-description`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return Rv.parse(n)}async getTextExtraction(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags,agentConfigVersion:this.agentConfig?.["text-extraction"]},o=await this.sendRequest(`/${z}/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(`/${z}/web-agent/page-summary`,{method:"POST",body:n,signal:t.abortSignal});return CT.parse(o)}async getSmartWaitingDecision(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${z}/web-agent/smart-waiting`,{method:"POST",body:n,signal:t.abortSignal});return xT.parse(o)}async getTestResultClassification(e,t){let n=await this.sendRequest(`/${z}/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(`/${z}/web-agent/extract-keywords`,{method:"POST",body:e,signal:t.abortSignal});return ub.parse(n)}async getAutohealingProposal(e,t){let n=await this.sendRequest(`/${z}/web-agent/autoheal-section`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return vT.parse(n)}async getFailureRecoveryProposal(e,t){let n=await this.sendRequest(`/${z}/web-agent/failure-recovery`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return AT.parse(n)}async getFailureRecoveryPlan(e,t){let n=await this.sendRequest(`/${z}/web-agent/failure-recovery-plan`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return RT.parse(n)}async getIframeRegex(e,t){let n=await this.sendRequest(`/${z}/web-agent/iframe-regex`,{method:"POST",body:e,signal:t.abortSignal});return ky.parse(n)}getVercelAnthropicModelFactory({loggerTags:e}){return Rl({baseUrl:this.baseUrl,apiKey:this.apiKey,loggerTags:e})}};import{z as Tg}from"zod";var Ze=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(`/${z}/auth/check`,{method:"GET",retries:10,requestTimeoutMs:5e3,onFailedRequest:t=>{E.warn(`API key check failed: ${t.message}`)}});return kv.parse(e)}async bulkGetRunStatus(e){let t=await this.sendRequest(`/${z}/runs/status`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return Ov.parse(t)}async getTestYAMLExport(e){let t=await this.sendRequest(`/${z}/tests/export`,{method:"POST",body:e,retries:3,requestTimeoutMs:3e4});return wv.parse(t)}async updateStepCaches(e,t){await this.sendRequest(`/${z}/cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getStepCacheForTest(e,t){let n=await this.sendRequest(`/${z}/cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return xv.parse(n)}async updateMobileStepCaches(e,t){await this.sendRequest(`/${z}/mobile-cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getMobileStepCacheForTest(e,t){let n=await this.sendRequest(`/${z}/mobile-cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return _v.parse(n)}async queueTests(e){let t=await this.sendRequest(`/${z}/tests/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return Av.parse(t)}async uploadScreenshot(e){let t=await this.sendRequest(`/${z}/screenshots`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return Dv.parse(t)}async getAllEnvironments(){let e=await this.sendRequest(`/${z}/environments`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Fv.parse(e)}async acquireCacheLock(e,t){let n=await this.sendRequest(`/${z}/result-cache/lock`,{method:"POST",body:e,signal:t,retries:3,requestTimeoutMs:3e4});return Qv.parse(n)}async releaseCacheLock(e){await this.sendRequest(`/${z}/result-cache/lock`,{method:"DELETE",body:{key:e},retries:3,requestTimeoutMs:5e3})}async deleteCacheResult(e){await this.sendRequest(`/${z}/result-cache/entry`,{method:"DELETE",body:e,retries:3,requestTimeoutMs:5e3})}async setCacheResult(e){await this.sendRequest(`/${z}/result-cache/entry`,{method:"PATCH",body:e,retries:3,requestTimeoutMs:5e3})}async getCacheResult(e){try{return await this.sendRequest(`/${z}/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(`/${z}/suites/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return Uv.parse(t)}async bulkGetRunGroupStatus(e){let t={runGroupIds:e},n=await this.sendRequest(`/${z}/run-groups/status`,{method:"POST",body:t,retries:3,requestTimeoutMs:5e3});return VT.array().parse(n)}async uploadProposedSteps(e,t){try{await this.sendRequest(`/${z}/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(`/${z}/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(`/${z}/test-fragments/${e}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Bv.parse(t)}async patchTestFragment(e,t){await this.sendRequest(`/${z}/test-fragments/${e}`,{method:"PATCH",body:t,retries:3,requestTimeoutMs:1e4})}async getPastTestResults(e,t){let n=await this.sendRequest(`/${z}/results/tests/${e}`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return zv.parse(n)}async generateTestResultsUploadUrl(){let e=await this.sendRequest(`/${z}/results/uploads`,{method:"POST",retries:3,requestTimeoutMs:1e4});return Hv.parse(e)}async startProcessingResultsUpload(e,t){let n=await this.sendRequest(`/${z}/results/uploads/${e}/process`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return Gv.parse(n)}async fetchIconKnowledgeBase(e){try{let t=await this.sendRequest(`/${z}/knowledge-base/icons`,{method:"GET",retries:3,requestTimeoutMs:5e3});return nR.parse(t)}catch(t){return e.error({err:t},"Failed to fetch icon knowledge base"),null}}async saveNewIcons(e,t){try{await this.sendRequest(`/${z}/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(`/${z}/git/github/${e}/${t}/merge-base-commit?${i.toString()}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return yl.parse(a)}async getCommitFromGithub(e,t,n){let o=await this.sendRequest(`/${z}/git/github/${e}/${t}/commits/${n}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return yl.parse(o)}async getMergedBranchFromGithub(e,t,n,o){let i=encodeURIComponent(n),a=await this.sendRequest(`/${z}/git/github/${e}/${t}/${i}/${o}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ag.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(`/${z}/git/gitlab/${i}/merge-base-commit?${o.toString()}`,{method:"GET",retries:3,requestTimeoutMs:5e3});return yl.parse(a)}async getCommitFromGitlab(e,t){let n=encodeURIComponent(e),o=await this.sendRequest(`/${z}/git/gitlab/${n}/commits/${t}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return yl.parse(o)}async getMergedBranchFromGitlab(e,t,n){let o=encodeURIComponent(t),i=encodeURIComponent(e),a=await this.sendRequest(`/${z}/git/gitlab/${i}/${o}/${n}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ag.parse(a)}async getAgentConfig(){let e=await this.sendRequest(`/${z}/web-agent/agent-config`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Tg.record(Tg.string(),Tg.string()).parse(e)}async getQuarantinedTests(){let e=await this.sendRequest(`/${z}/quarantine`,{method:"GET"});return jv.parse(e)}async quarantineTest(e,t,n){await this.sendRequest(`/${z}/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(`/${z}/quarantine/${e.id}`,{method:"DELETE",body:{testName:e.name,reason:t,...n??{}},retries:3,requestTimeoutMs:1e4})}async createAndroidEmulator(e){let t=await this.sendRequest(`/${z}/limbar/android`,{method:"POST",retries:3,body:e,requestTimeoutMs:9e4,initialRetryDelayMs:5e3,maxRetryDelayMs:15e3});return Vv.parse(t)}async extendAndroidEmulatorTtl(e){try{await this.sendRequest(`/${z}/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(`/${z}/limbar/android/upload-url`,{method:"POST",retries:3,body:o,requestTimeoutMs:15e3,logResponse:!0});return $v.parse(i)}async deleteAndroidEmulator(e){await this.sendRequest(`/${z}/limbar/android/${e}`,{method:"DELETE",retries:3,requestTimeoutMs:3e4})}async getAndroidAssets(){let e=await this.sendRequest(`/${z}/limbar/assets`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Wv.parse(e)}async deleteAndroidAsset(e,t){await this.sendRequest(`/${z}/limbar/assets/${e}/${t}`,{method:"DELETE",retries:3,requestTimeoutMs:1e4})}};async function bg(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 Oo=class extends zt{generator;constructor(e,t){super(e),this.generator=t}async runTemplateMatching(e,t={}){let n=await this.sendRequest(`/${z}/web-agent/template-matching`,{method:"POST",body:e,signal:t?.signal});return Fy.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 xU,en as _U}from"@faker-js/faker";var Fa="v1",Cn=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 xU({locale:_U}),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 an?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 an?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 an?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 an?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 an?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 an?new Error(t.rawError):new Error(`Failed to fetch latest emails: ${t.message}`)})}};function PR(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 PR(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 et(r,e,t=!1){return r.length<e?r:r.slice(0,e-3)+(t?"...TRUNCATED...":"[...]")}var Yn={EQUALS:"equals",CONTAINS:"contains",STARTS_WITH:"starts with",EXISTS:"exists"},Xn={EQUALS:"does not equal",CONTAINS:"does not contain",STARTS_WITH:"does not start with",EXISTS:"does not exist"},vg={EXISTS:"exists",VISIBLE:"is visible",ENABLED:"is enabled",EDITABLE:"is editable",FOCUSED:"is focused"},Rg={EXISTS:"does not exist",VISIBLE:"is not visible",ENABLED:"is disabled",EDITABLE:"is not editable",FOCUSED:"is not focused"};function OR(r){switch(r.type){case"ELEMENT_CONTENT":return`content ${r.negated?Xn[r.operation]:Yn[r.operation]} '${r.value}'`;case"ELEMENT_ATTRIBUTE":{let t=r.negated?Xn[r.operation]:Yn[r.operation];return r.operation==="EXISTS"?`attribute '${r.attr}' ${t}`:`attribute '${r.attr}' ${t} '${r.value}'`}case"ELEMENT_NAME":{let t=r.negated?Xn[r.operation]:Yn[r.operation];return r.operation==="EXISTS"?`tag name ${t}`:`tag name ${t} '${r.value}'`}case"ELEMENT_STYLE":{let t=r.negated?Xn[r.operation]:Yn[r.operation];return r.operation==="EXISTS"?`style property '${r.property}' ${t}`:`style property '${r.property}' ${t} '${r.value}'`}case"ELEMENT_EXISTENCE":return r.negated?Rg[r.condition]:vg[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 Xce={CONTENT:"The page"};function IU(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 PU(r){return`${r.negated?Xn.CONTAINS:Yn.CONTAINS} '${r.value}'`}function OU(r){switch(r.type){case"CONTENT":return PU(r);default:return r.type,""}}function Jn(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?et(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=IU(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?et(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)} ${OR(r.assertion)}`;case"PAGE_CHECK":return`Check the page ${OU(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 LU(r){return typeof r=="object"&&r!==null}function xn(r){if(Array.isArray(r))return r.map(xn);if(LU(r)){let e={};return Object.entries(r).forEach(([t,n])=>{n!==void 0&&(e[t]=xn(n))}),e}return r}function Al(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 LR(r){return r.type==="ELEMENT_EXISTENCE"&&r.negated&&(r.condition==="EXISTS"||r.condition==="VISIBLE")}function Ua(r){return r.type==="ELEMENT_EXISTENCE"?r.negated?vg[r.condition]:Rg[r.condition]:r.negated?Yn[r.operation]:Xn[r.operation]}import{diff as DU}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 NR(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!!NU([r],t,i).result}function NU(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 DR(r,e){e(r);for(let t in r){let n=r[t];n&&(Array.isArray(n)?Wu(n,e):typeof n=="object"&&DR(n,e))}}function Wu(r,e){for(let t of r)t&&(Array.isArray(t)?Wu(t,e):typeof t=="object"&&DR(t,e))}function Ag(r,e){if(r.length>e.length)return Ag(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 Lo(r,e){return!r&&!e?!1:!r||!e?!0:Object.keys(DU(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=$n.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=kU(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(!Bc.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 kR(r,e){return e?`${e}:${r}`:r}function kU(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 wg(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:kR(r.id,e.join(":")),organizationId:r.orgId,value:r.value,testId:r.testId}),n}function FR(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"&&zc(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 Cl(r,e,t){let n=r.cache&&"memory"in r.cache?r.cache.memory?.traces:void 0;Lo(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 UR({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=kR(o.id,i),s=$n.parse(o);e[a]=s},onSimpleStepContainer:(t,n)=>{},onConditional:(t,n)=>{}}),e}function wl(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 FU(r,e){return Lo(r.memory,e.memory)?{...r,memory:e.memory,updatedAt:e.updatedAt}:r}function Cg(r,e){return r?Lo(r.target.memory,e.target.memory)?{target:{...r.target,memory:e.target.memory},updatedAt:e.updatedAt}:r:{target:wl(e.target),updatedAt:e.updatedAt}}function UU(r,e){let t=qu(r);return t.fromTarget?Lo(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=wl(t.fromTarget),t.updatedAt=e.updatedAt)),t.toTarget?Lo(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=wl(t.toTarget),t.updatedAt=e.updatedAt)),t}function BR({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;Lo(s,a.memory)&&(o.value.cache=FU(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(Lo(s,a.target.memory)){let c=br.safeParse(o.value.cache);o.value.cache=Cg(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};Lo(l,c)&&(o.value.cache=UU(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 zR(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 Ipe}from"lodash-es";import xg 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(!xg.valid(t.toVersion)||!xg.valid(t.fromVersion))throw new Error(`Migration '${t.name}' has invalid version`);if(!xg.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 BU from"diff-lines";import zU,{gte as HU}from"semver";function GU(r){return r.every(e=>e&&typeof e=="object"&&!Array.isArray(e))}async function _g({metadata:r,steps:e,logger:t,toVersion:n,migrations:o}){let i=e,{schemaVersion:a,id:s}=r,c=o.findIndex(d=>zU.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&&HU(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 HR(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=BU(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 HR(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)||GU(i)&&(n[o]=await HR(i,e))}return t}var GR={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 jU=[GR];Xu(ah,jU);var jR={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 VR={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 VU=["target","fromTarget","toTarget"];function $R(r){for(let e of VU){if(r[e]===void 0)continue;let t=r[e];t.elementDescriptor!==void 0?t.type="description":r[e]={type:"description",elementDescriptor:""}}}var WR={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 $R(e.command),e;case"AI_ACTION":{let t=e.commands;for(let n of t??[])$R(n);return e}default:return e}})};import{v4 as $U}from"uuid";var qR={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=$U()),e;default:return e}})};import{v4 as KR}from"uuid";var YR={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??KR(),e}case"AI_ACTION":return e.commands&&(e.steps=e.commands.map(t=>({type:"PRESET_ACTION",command:{...t,id:t.id??KR()}})),delete e.commands),e;default:return e}})};var XR={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 WU}from"uuid";var JR={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=WU()),e))};import{v4 as QR}from"uuid";var ZR={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=QR())}return e.id=QR(),e})};var eA={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 qU}from"uuid";var tA={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=qU()),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 rA={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 nA={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&&oA(t),e})};function oA(r){r&&Object.keys(r).forEach(e=>{if(typeof r[e]=="object"&&r[e]){oA(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 iA={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 aA={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 sA={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 lA={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 cA={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 uA={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 dA={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"]),pA={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 mA={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 hA={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 gA=[dA,mA,hA,pA,jR,VR,WR,qR,YR,XR,JR,ZR,eA,tA,rA,nA,iA,aA,sA,lA,cA,uA];Xu(xe,gA);async function za({metadata:r,steps:e,logger:t,toVersion:n}){return await _g({metadata:r,steps:e,logger:t,toVersion:n,migrations:gA})}import{cloneDeep as jpe}from"lodash-es";import{v4 as Jpe}from"uuid";import{cloneDeep as YU}from"lodash-es";import vA from"truncate-json";import{v4 as SA}from"uuid";import{cloneDeep as dme,unset as pme}from"lodash-es";function fA(r){switch(r.type){case"AI_ACTION":return`AI action: ${et(r.text,100)}`;case"AI_ACTION_DYNAMIC":return`AI action: ${et(r.text,100)}`;case"PRESET_ACTION":return Jn(r.command);case"MODULE":return`Module ${r.moduleName??r.id}`;case"CONDITIONAL":return"Conditional step";case"SECTION":return`Section ${r.description?`with goal: ${et(r.description,100)}`:""}`;default:return(t=>{throw new Error("You missed a case in the switch above")})(r)}}function Qn(r){switch(r.type){case"AI_ACTION":return`AI action: ${et(r.text,100)}`;case"AI_ACTION_DYNAMIC":return`AI action: ${et(r.text,100)}`;case"PRESET_ACTION":return Jn(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: ${et(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 mB(r){let e=pB(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=ln.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=Ur.parse(n)}catch(a){throw new Error(`Test ${r} is missing metadata or has invalid metadata: ${a}`)}let{resolvedTest:i}=await OA({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 eo(c,s)}}});return i}import xB from"@dotenvx/dotenvx";import _B from"fs";import qA from"path";function gd(r,e){return(r.config.environments??[]).map(t=>Li(t.name,r,e))}function KA(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 MB(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=KA(i);s&&(n[o]=s);continue}let a;try{a=_B.readFileSync(qA.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 IB(r){let{project:e,envFile:t,logger:n}=r,o={};if(!t)return o;let i=xB.config({path:qA.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={[vt]:KA(n.baseUrl)},i=MB({envVariables:n.envVariables,project:e});Object.assign(o,i);let a=IB({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 OB,readFileSync as LB,readdirSync as NB,writeFileSync as DB}from"fs";import{glob as kB}from"glob";import Ni,{dirname as YA}from"path";import{cwd as Vg}from"process";import XA from"yaml";import{z as Ke}from"zod";import PB from"zod";var fd=["**/*.test.yaml","**/*.module.yaml"],jg=PB.string().refine(r=>/^[a-zA-Z0-9-]+$/.test(r)),Sd=15;var Ka="momentic.config.yaml",$g="momentic.workspace.yaml",FB=Ke.object({projects:Ke.string().array().describe("list of glob patterns to find project (momentic.config.yaml) files")}),UB=Ke.union([Ke.string(),Ke.object({fromFile:Ke.string(),json:Ke.boolean().optional()})]),BB=Ke.object({name:jg,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(),UB).optional(),inheritFromShell:Ke.boolean().optional().describe("inherit all environment variables from the shell - might be noisy"),browser:gi.optional().describe("NB: most things should use project-level configuration only")}),zB=Ke.object({postSave:Ke.string().optional()}),HB=Ke.object({name:jg,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(BB).optional(),gitMainBranch:Ke.string().optional(),gitProtectedBranches:Ke.string().array().optional(),ai:Zh.optional(),browser:gi.optional(),emulator:Hh.optional(),advanced:eg.optional(),hooks:zB.optional()});function JA(r,e){let t;try{t=LB(r,"utf-8")}catch(o){E.warn(`Could not read possible Momentic ${e} file at ${r}: ${o}`);return}let n;try{if(n=XA.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 Wg(r){let e=JA(r,"project configuration");if(e!==void 0)try{return HB.parse(e)}catch(t){E.warn(`Possible Momentic project configuration file at ${r} does not adhere to the required schema: ${t}`);return}}function GB(r){let e=JA(r,"workspace configuration");if(e!==void 0)try{return FB.parse(e)}catch(t){E.warn(`Possible Momentic workspace configuration file at ${r} does not adhere to the required schema: ${t}`);return}}function jB(){let r=[],e=Vg(),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 NB(e))if(a.endsWith(Ka)){let s=Ni.join(e,a),c=Wg(s);c&&r.push({configFilePath:s,config:c,rootDir:YA(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 qg(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 VB(r){let e=GB(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 kB(t,{absolute:!1,cwd:Vg(),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 ${$g} is misconfigured.`),a}let i=[];for(let a of o){let s=Ni.join(Vg(),a),c=Wg(s);c&&i.push({configFilePath:s,config:c,rootDir:YA(s)})}return i}async function qg(r){if(r){r=Ni.resolve(r);let t=Wg(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(OB($g)){let t=await VB($g);if(t)return t}return jB()}function Fo(r,e){let t=XA.stringify(r);DB(e,t)}import ZA from"fs";import{glob as $B}from"glob";import Dl from"path";import WB from"yaml";import{z as QA}from"zod";var ew=!1,qB=QA.object({fileType:QA.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 $B(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=KB(r.rootDir,s,t,e?An:E);c&&(t.duplicateEntities[c.id]=c.paths)}return ew=!0,t}function KB(r,e,t,n){let o=Dl.join(r,e),i=YB(o,n);if(!i)return;let a=XB(i,o,n);if(!a)return;let s=qB.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=JB(o,n);if(!l)return;let u=QB(e,o,l);switch(c){case ge.TEST:try{return ZB(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 ez(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 rz(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 tz(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 YB(r,e){try{return ZA.readFileSync(r,"utf-8")}catch(t){e.warn(`Could not read possible Momentic file at ${r}, skipping: ${t}`);return}}function XB(r,e,t){try{let n=WB.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 JB(r,e){try{return ZA.statSync(r)}catch(t){e.warn(`Skipping path '${r}' because it could not be stat, skipping: ${t}`);return}}function QB(r,e,t){return{relativePath:r,fullFilePath:e,platformSep:Dl.sep,fullPathSegments:e.split(Dl.sep),relativePathSegments:r.split(Dl.sep),fileName:Dl.basename(e),lastModified:t.mtime,createdAt:t.birthtime}}function ZB(r,e,t,n,o){let i=Ur.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 ez(r,e,t,n,o){let i=hr.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!ew&&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 tz(r,e,t,n,o){let i=Ru.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 rz(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 Kg from"path";import{z as Yg}from"zod";var tw="golden/visual-diff",rw="reports",nw="test-results";var nz=Yg.object({width:Yg.number(),height:Yg.number()}),Xa=class{defaultGoldenScreenshotDir;regenerateGoldenFiles;constructor(e,t){let n=Kg.join(e.rootDir,e.config.goldenFileDir??tw);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=Kg.join(this.defaultGoldenScreenshotDir,`${t.id}.jpg`));let i=`${o}.metadata.json`;if(this.regenerateGoldenFiles)return Ya.mkdirSync(Kg.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=nz.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 oz}from"node:child_process";import{promisify as iz}from"node:util";import az from"simple-git";var Ye=az(),ow=iz(oz);async function sz(r){let e=await tt(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 lz(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 ow("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 ow("gh",o,{timeout:5e3}),a=i?.toString().trim();if(a)return a}catch{}}}async function cz(r,e,t){let n=e?.includes("github.com"),o=e?.includes("gitlab.com");try{if(n)return lz(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 tt(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 uz(){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 dz(r){let[e,t,n]=await Promise.all([tt(r,Ye.show(["--no-patch","--format=%ci"])),tt(r,Ye.show(["-s","--pretty=%B"])),tt(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 pz(r){let[e,t,n]=await Promise.all([tt(r,Ye.listRemote(["--get-url","origin"])),tt(r,Ye.show(["-s","--pretty=%B"])),tt(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 mz(r){let[e,t,n,o]=await Promise.all([tt(r,Ye.show(["--no-patch","--format=%ci"])),tt(r,Ye.listRemote(["--get-url","origin"])),tt(r,Ye.show(["-s","--pretty=%B"])),tt(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 hz(r){let[e,t,n]=await Promise.all([tt(r,Ye.show(["--no-patch","--format=%ci"])),tt(r,Ye.show(["-s","--pretty=%B"])),tt(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 gz(r){let[e,t,n]=await Promise.all([tt(r,Ye.show(["--no-patch","--format=%ci"])),tt(r,Ye.show(["-s","--pretty=%B"])),tt(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 fz(r,e){let[t,n,o,i,a,s,c,l,u]=await Promise.all([tt(r,Ye.revparse(["HEAD"])),tt(r,Ye.revparse(["--short","HEAD"])),tt(r,Ye.revparse(["--abbrev-ref","HEAD"])),tt(r,Ye.listRemote(["--get-url","origin"])),tt(r,Ye.show(["--no-patch","--format=%ci"])),tt(r,Ye.show(["-s","--pretty=%B"])),tt(r,Ye.show(["-s","--pretty=%an"])),e?tt(r,Ye.raw(["merge-base","--fork-point",e])):Promise.resolve(void 0),sz(r)]),d=l?await tt(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 cz(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 Sz(){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 yz(r){let e=r.config.gitProtectedBranches??[];return r.config.gitMainBranch&&e.push(r.config.gitMainBranch),{gitMainBranch:r.config.gitMainBranch,gitProtectedBranches:e}}async function to(r,e){let t=uz();if(!t)return fz(r,e);switch(t){case"GithubActions":return dz(r);case"GitlabCI":return pz(r);case"CircleCI":return mz(r);case"Buildkite":return hz(r);case"AzureDevOps":return gz(r);case"GCPCloudBuild":return Sz()}}async function Ez(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 Tz(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 bz(r,e,t){try{if(t.githubRepository){let[n,o]=t.githubRepository.split("/");return await Tz(r,e,n,o,t)}else if(t.gitlabProjectPath)return await Ez(r,e,t.gitlabProjectPath,t)}catch(n){r.warn({err:n},"Failed to get remote git metadata")}return t}async function zr(r,e,t){let n=await yz(t),o=await to(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 bz(r,e,i);return{...n,...o,...a}}async function iw(){try{return!!(await Ye.show(["--no-patch","--format=%ci"])).trim()}catch{return null}}import{diff as Uye}from"deep-object-diff";import{cloneDeep as zye}from"lodash-es";import{v4 as Qye}from"uuid";import eEe from"yaml";import yEe from"yaml";import TEe from"zod";import{randomUUID as vz}from"crypto";import Uo from"fs";import Ja from"path";var aw=new Set([".DS_Store","__MACOSX"]),sw={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 Rz(r,e,t){if(sw[t]){let i=sw[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 Xg=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 lw(r,e){try{let t=Ja.join(e,"metadata.json");return Nu.parse(JSON.parse(Uo.readFileSync(t,"utf-8")))}catch{throw new Xg(r,e)}}function cw(r,e,t){let n=vz(),o=r.child({runGroupId:n});Uo.rmSync(e,{recursive:!0,force:!0});let i=Uo.readdirSync(t).filter(c=>!aw.has(c)).map(c=>Ja.join(t,c));if(i.length===0)throw new Error(`No run groups found in results path: ${t}`);Uo.mkdirSync(e,{recursive:!0});let a={...lw(t,i[0]),id:n};for(let c of i){let l=Ja.join(c,"runs");if(!Uo.existsSync(l))continue;let u=lw(t,c);o.info({oldRunGroupId:u.id},"Merging run groups");for(let p in u){if(p==="id")continue;let m=p;a[m]=Rz(a,u,m)}let d=Uo.readdirSync(l);for(let p of d){if(aw.has(p))continue;let m=Ja.join(l,p),h=Ja.join(e,"runs",p);Uo.cpSync(m,h,{recursive:!0})}}let s=Ja.join(e,"metadata.json");Uo.writeFileSync(s,JSON.stringify(a,null,2))}import uw from"adm-zip";import Jg from"fs";import Ed from"path";function Az(r){let e=new uw,t=Ed.join(r,"metadata.json"),n=Nu.parse(JSON.parse(Jg.readFileSync(t,"utf-8")));e.addLocalFile(t);for(let o of Jg.readdirSync(Ed.join(r,"runs"))){if(!o.endsWith(".zip"))continue;let i=o.replace(/\.zip$/,""),a=new uw(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(!Jg.existsSync(n)){t.warn("Results path does not exist, skipping upload.");return}let o=new Hu(e);try{let{runGroupId:i,buffer:a}=Az(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 wz from"adm-zip";import Ht from"fs";import Cr from"path";var kl=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(Cr.join(this.filePath,e))}cwd(){return this.filePath}mkdir(e){Ht.mkdirSync(Cr.join(this.filePath,e),{recursive:!0})}readFile(e){let t=Cr.join(this.filePath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}storeFile(e){let{name:t,contents:n}=e,o=Cr.join(this.filePath,t);try{Ht.writeFileSync(o,n)}catch{}}createFileStream(e){let t=Cr.join(this.filePath,e);return Ht.createWriteStream(t)}createRunArchive(e){return new Qg(Cr.join(this.filePath,"runs"),e)}},Qg=class{constructor(e,t){this.filePath=e;this.tempPath=Cr.join(e,`temp-storage-${t}`),this.finalPath=Cr.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=Cr.join(this.tempPath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}mkdir(e){Ht.mkdirSync(Cr.join(this.tempPath,e),{recursive:!0})}cd(e){return new kl(Cr.join(this.tempPath,e))}cwd(){return this.tempPath}storeFile(e){let{name:t,contents:n}=e,o=Cr.join(this.tempPath,t);Ht.writeFileSync(o,n)}createFileStream(e){let t=Cr.join(this.tempPath,e);return Ht.createWriteStream(t)}close(){let e=new wz;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 Cz from"adm-zip";import{randomUUID as xz}from"crypto";import Ot from"fs";import Gt from"path";function hw(r){try{return Ot.existsSync(r)?JSON.parse(Ot.readFileSync(r,"utf-8")):void 0}catch{return}}function dw(r){return Ot.existsSync(r)?Ot.readFileSync(r,"utf-8").split(`
|
|
47
|
-
`).map(t=>t.trim()).filter(t=>t.length>0):[]}function _z(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=hw(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 pw(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}-${xz()}`);Ot.mkdirSync(n,{recursive:!0}),new Cz(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 _z(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=hw(Gt.join(o,"console.json")),a=jh.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 dw(i)){let d=hl.safeParse(mw(u));d.success&&(s[d.data.id]=d.data)}let c={},l=dw(a);for(let u=0;u<l.length;u++){let d=l[u],p=gl.safeParse(mw(d));if(!p.success)continue;let m=`${p.data.startedDateTime}-${u}`;c[m]=p.data}if(Object.keys(c).length!==0)return $h(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=pw(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=pw(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 mw(r){try{return JSON.parse(r)}catch{return}}import{hostname as Mz}from"os";var Iz="2.28.3",Fl=Na({app:"desktop-server",hostname:Mz(),disableConsoleLogs:!0}).child({cliVersion:Iz});(async()=>{try{let r=await to(Fl);r.gitBranchName&&Fl.addBinding("branch",r.gitBranchName)}catch{}})();var gw=Pz();gw.get("/",async(r,e)=>{let t=se(),n=HA();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await zr(Fl,n,t);e.status(200).json(o)});var Zg=gw;import IK from"events";import aO,{Router as PK}from"express";import OK from"http";import LK from"path";import{Server as KW}from"socket.io";var Oz=({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{}}},fw={event:"cancel",createHandler:Oz};var Lz=({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})}}},Sw={event:"fetchA11yTree",createHandler:Lz};var Nz=({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})}}},yw={event:"fetchDom",createHandler:Nz};var Dz=({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)}},Ew={event:"disconnect",createHandler:Dz};function cn(r){let{result:e,nestedResults:t}=r;if(!r.nestedResults.length)return;let{firstMetadata:n,lastMetadata:o}=kz(t);Fz(e,n,o);let i=[...r.asyncTasks];r.asyncTasks.push((async()=>{try{await Uz(i,e,n,o)}catch(a){r.logger.error({result:r.result,err:a},"Error hoisting scalar result metadata")}})())}function kz(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 Fz(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 Uz(r,e,t,n){await Promise.allSettled(r),t&&(e.beforeSnapshot=t.beforeSnapshot),n&&(e.afterSnapshot=n.afterSnapshot)}import{randomUUID as Yz}from"crypto";import{faker as Bz}from"@faker-js/faker";import zz from"assert";import Hz from"axios";import*as Gz from"child_process";import jz from"moment";import*as Vz from"otpauth";import $z from"pg";async function Tw(r){let e;try{e=new URL(r.url).hostname}catch{}let t=[];return r.headers.getSetCookie()?.forEach(n=>{let o=gu(n,e);t.push(...o)}),t}function Wz(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 qz(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 Kz=Object.getPrototypeOf(async function(){}).constructor;async function bw(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=(b,A)=>{o[b]=A,l[b]=A},d={},p=(b,A)=>{o[b]=A,d[b]=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 Kz("axios","moment","faker","assert","pg","Octokit","createAppAuth","OTPAuth","child_process","extractCookiesFromResponse","env","setVariable","setPersistentVariable","sendSms","waitForLatestSms","email","sms","ai","mock",...Object.keys(i??{}),n)(Hz,jz,c.fakerInstance??Bz,zz,$z,m,h,Vz,Gz,Tw,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,Wz(a,s),...Object.values(i??{}))),f=!0,y,S;try{let b=await V(g(),{milliseconds:e.options.timeoutMs,message:`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`,signal:e.signal});y=await qz(e.options.responseSerialization??"RAW",b)}catch(b){t.error({err:b,env:o,evalCode:n},`[${r}] Error executing code: ${b}`),f=!1,b instanceof Po?S=`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`:S=b instanceof Error?b.message:`${b}`}return{result:y,variableUpdates:l,persistentVariableUpdates:d,success:f,error:S}}async function vw({code:r,fragment:e,context:t,localTools:n,logger:o,signal:i,timeoutMs:a=xo,disallowVariableUpdates:s,additionalBindings:c,responseSerialization:l,mock:u}){let d=Yz(),p=await bw(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 Xz,randomUUID as Jz}from"crypto";import Qz from"fetch-retry";var Zz=Qz(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}}),Rw=process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT,Aw=process.env.MOMENTIC_LAMBDA_AUTH_SECRET;async function ww({orgId:r,code:e,fragment:t,context:n,timeoutMs:o=xo,retries:i=2,signal:a,logger:s,additionalBindings:c,disallowVariableUpdates:l,responseSerialization:u,mock:d}){if(!Rw)throw new Error("GCP_JS_EVAL_FUNCTION_ENDPOINT environment variable not set");let p,m,h=0;if(!Aw)throw new Error("Missing lambda auth secret.");let g=Xz("sha256",Aw).update(r).digest("hex");for(;h<=i;){h++,a?.throwIfAborted();let y={id:Jz(),orgId:r,momenticLambdaAuthHash:g,code:e,fragment:t,state:{...n.toObjectCopy(),...d,additionalBindings:c},timeoutMs:o,disallowVariableUpdates:l,responseSerialization:u};try{if(p=await V(Zz(Rw,{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=Ub.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 Bo(r){let e;if(process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT)e=await ww(r);else if(r.localTools)e=await vw({...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 _z(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=hw(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 pw(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}-${xz()}`);Ot.mkdirSync(n,{recursive:!0}),new Cz(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 _z(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=hw(Gt.join(o,"console.json")),a=jh.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 dw(i)){let d=hl.safeParse(mw(u));d.success&&(s[d.data.id]=d.data)}let c={},l=dw(a);for(let u=0;u<l.length;u++){let d=l[u],p=gl.safeParse(mw(d));if(!p.success)continue;let m=`${p.data.startedDateTime}-${u}`;c[m]=p.data}if(Object.keys(c).length!==0)return $h(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=pw(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=pw(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 mw(r){try{return JSON.parse(r)}catch{return}}import{hostname as Mz}from"os";var Iz="2.28.4",Fl=Na({app:"desktop-server",hostname:Mz(),disableConsoleLogs:!0}).child({cliVersion:Iz});(async()=>{try{let r=await to(Fl);r.gitBranchName&&Fl.addBinding("branch",r.gitBranchName)}catch{}})();var gw=Pz();gw.get("/",async(r,e)=>{let t=se(),n=HA();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await zr(Fl,n,t);e.status(200).json(o)});var Zg=gw;import IK from"events";import aO,{Router as PK}from"express";import OK from"http";import LK from"path";import{Server as KW}from"socket.io";var Oz=({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{}}},fw={event:"cancel",createHandler:Oz};var Lz=({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})}}},Sw={event:"fetchA11yTree",createHandler:Lz};var Nz=({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})}}},yw={event:"fetchDom",createHandler:Nz};var Dz=({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)}},Ew={event:"disconnect",createHandler:Dz};function cn(r){let{result:e,nestedResults:t}=r;if(!r.nestedResults.length)return;let{firstMetadata:n,lastMetadata:o}=kz(t);Fz(e,n,o);let i=[...r.asyncTasks];r.asyncTasks.push((async()=>{try{await Uz(i,e,n,o)}catch(a){r.logger.error({result:r.result,err:a},"Error hoisting scalar result metadata")}})())}function kz(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 Fz(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 Uz(r,e,t,n){await Promise.allSettled(r),t&&(e.beforeSnapshot=t.beforeSnapshot),n&&(e.afterSnapshot=n.afterSnapshot)}import{randomUUID as Yz}from"crypto";import{faker as Bz}from"@faker-js/faker";import zz from"assert";import Hz from"axios";import*as Gz from"child_process";import jz from"moment";import*as Vz from"otpauth";import $z from"pg";async function Tw(r){let e;try{e=new URL(r.url).hostname}catch{}let t=[];return r.headers.getSetCookie()?.forEach(n=>{let o=gu(n,e);t.push(...o)}),t}function Wz(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 qz(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 Kz=Object.getPrototypeOf(async function(){}).constructor;async function bw(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=(b,A)=>{o[b]=A,l[b]=A},d={},p=(b,A)=>{o[b]=A,d[b]=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 Kz("axios","moment","faker","assert","pg","Octokit","createAppAuth","OTPAuth","child_process","extractCookiesFromResponse","env","setVariable","setPersistentVariable","sendSms","waitForLatestSms","email","sms","ai","mock",...Object.keys(i??{}),n)(Hz,jz,c.fakerInstance??Bz,zz,$z,m,h,Vz,Gz,Tw,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,Wz(a,s),...Object.values(i??{}))),f=!0,y,S;try{let b=await V(g(),{milliseconds:e.options.timeoutMs,message:`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`,signal:e.signal});y=await qz(e.options.responseSerialization??"RAW",b)}catch(b){t.error({err:b,env:o,evalCode:n},`[${r}] Error executing code: ${b}`),f=!1,b instanceof Po?S=`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`:S=b instanceof Error?b.message:`${b}`}return{result:y,variableUpdates:l,persistentVariableUpdates:d,success:f,error:S}}async function vw({code:r,fragment:e,context:t,localTools:n,logger:o,signal:i,timeoutMs:a=xo,disallowVariableUpdates:s,additionalBindings:c,responseSerialization:l,mock:u}){let d=Yz(),p=await bw(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 Xz,randomUUID as Jz}from"crypto";import Qz from"fetch-retry";var Zz=Qz(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}}),Rw=process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT,Aw=process.env.MOMENTIC_LAMBDA_AUTH_SECRET;async function ww({orgId:r,code:e,fragment:t,context:n,timeoutMs:o=xo,retries:i=2,signal:a,logger:s,additionalBindings:c,disallowVariableUpdates:l,responseSerialization:u,mock:d}){if(!Rw)throw new Error("GCP_JS_EVAL_FUNCTION_ENDPOINT environment variable not set");let p,m,h=0;if(!Aw)throw new Error("Missing lambda auth secret.");let g=Xz("sha256",Aw).update(r).digest("hex");for(;h<=i;){h++,a?.throwIfAborted();let y={id:Jz(),orgId:r,momenticLambdaAuthHash:g,code:e,fragment:t,state:{...n.toObjectCopy(),...d,additionalBindings:c},timeoutMs:o,disallowVariableUpdates:l,responseSerialization:u};try{if(p=await V(Zz(Rw,{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=Ub.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 Bo(r){let e;if(process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT)e=await ww(r);else if(r.localTools)e=await vw({...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 eH}from"lodash-es";async function dr(r){let{orgId:e,s:t,context:n,logger:o,signal:i,retries:a=2,timeoutMs:s=xo,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 Bo({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 Cw(r)}async function Cw({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 Cw({obj:l,bannedKeys:e,context:n,prefixPath:u,replacements:i,allowList:c?void 0:t,...a})}return i}function xw(r,e){for(let{path:t,original:n}of e)eH(r,t,n)}import tH from"fetch-retry";var qbe=process.env.MAILINATOR_API_KEY,Kbe=tH(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 cH}from"os";import{cloneDeep as Mw}from"lodash-es";async function Iw(r){let{command:e,timeoutMs:t,fixtures:n}=r,{abortSignal:o}=n,i=()=>jy(e.cache)?e.cache:void 0,a=i(),s=Mw(a),c=(g=!1)=>{if(a=i(),!!a)if(g){let f=Cg(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 _w({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&&Ic(a.target)){let g=a?.target?.memory?{target:{id:-1,memory:a.target.memory}}:void 0,{result:f}=await _w({cacheToUse:g,params:r});d=f,d.success||c(!0)}let h=i();return d.success&&h?.target&&!m&&(h.target=wl(h.target),h.updatedAt=new Date),d}async function _w({cacheToUse:r,params:e}){let{command:t,disableCache:n,fixtures:o,tracer:i,targetingWrapper:a}=e,{logger:s}=o;if(t.target&&!fo(t.target))throw new Error("Element assertion with x/y is not supported yet");let c=LR(t.assertion),l,u=!1,d=Mw(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=>rH(g.locator,e),options:{...t,allowNotActionableNodesOverride:!0,disableCache:n,memory:d?.target?.memory,disableGlobalLocatorRedirect:!0,source:hi(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 rH(r,{command:e,fixtures:t}){return await t.browser.highlight(r),await nH(r,e.assertion)}async function nH(r,e){let t=!0,n,o;switch(e.type){case"ELEMENT_CONTENT":{let a=await r.textContent()??"";if(o={elementTextContent:et(a,500,!0)},!Al(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:et(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(!Al(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},Sn*1e3);break}case"EDITABLE":{t=await r.isEditable({timeout:Sn*1e3});break}case"EXISTS":{t=!0;break}case"ENABLED":{t=await r.isEnabled({timeout:Sn*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(!Al(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(!Al(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 Pw(r){return r.type==="ELEMENT_EXISTENCE"&&r.negated&&r.condition==="EXISTS"}import{Jimp as oH}from"jimp";async function Ul(r,e){let t=await r.screenshot(e),n=await oH.fromBuffer(t);return{buffer:t,width:Math.ceil(n.bitmap.width??0),height:Math.ceil(n.bitmap.height??0)}}import{Jimp as Ow}from"jimp";import ef from"jpeg-js";import iH from"pixelmatch";async function Lw({ctx:r,tracer:e,command:t,disableCache:n,browser:o,targetingWrapper:i,logger:a,screenshotStorage:s}){if(t.target&&!fo(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 U=>Ul(o,{locator:U.locator,...c}),options:{...t,disableCache:n,disableGlobalLocatorRedirect:!0,memory:t.cache?.target?.memory,targetName:"target"}})).result:l=await Ul(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 B=`${l.width}x${l.height}`,U=`${u.width}x${u.height}`;return{fail:!0,thoughts:`Current screenshot (${B}) does not match saved screenshot dimensions (${U}) - 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 Ow.fromBuffer(l.buffer),p={width:l.width,height:l.height},m=await Ow.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),b=Math.abs(p.width-h.width);if(f>y){let B=d.cover({w:h.width,h:h.height});l.buffer=await B.getBuffer("image/jpeg"),g="current",l.width=h.width,l.height=h.height}else if(y>f){let B=m.cover({w:p.width,h:p.height});u.buffer=await B.getBuffer("image/jpeg"),g="saved"}let A={data:Buffer.alloc(l.width*l.height*4),width:l.width,height:l.height},T=t.threshold??.1,x=iH(ef.decode(u.buffer).data,ef.decode(l.buffer).data,A.data,l.width,l.height,{threshold:T,diffColorAlt:[0,255,0]})/(l.width*l.height)*100,_=x>T*100,D=`Visual diff of ${x.toFixed(2)}% detected, which is ${_?"over":"under"} the threshold of ${T*100}%.`;if(g&&(D+=` The ${g} screenshot was cropped since it was taller by ${S} pixels and wider by ${b} pixels.`),_)throw new M("ActionFailureError",D);return{fail:_,thoughts:D,beforeScreenshotOverride:l.buffer,afterScreenshotOverride:ef.encode(A,75).data,succeedImmediately:!1,urlAfterCommand:o.url()}}var aH=3e4;function sH(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 Nw({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??aH/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 V((async()=>{let h=s?`${l}?${s}`:l;try{let g=sH(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 lH=5e3;async function Rd({timeout:r=Sn,...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 Dw(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),lH);else return i}return i=await Dw(e),i}async function Dw({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(kw,{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(kw,{value:r.value,negated:!!r.negated,returnHtml:!0},"checking page content"));if(!i){let c=r.negated?Yn.CONTAINS:Xn.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 kw({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 tf=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(([b,A])=>`${b}:${A}`)]},n.info({original:f,keyParams:g},"Module cache key params");let S=Date.now();for(;Date.now()-S<uv;){d?.throwIfAborted();let b=await i.getCacheResult(g);if(b){n.info({cacheResult:et(b,1e3,!0)},"Got result from module execution cache"),p=Ad(e,t,"SUCCESS"),p.message="Used cached module result.",p.data=JSON.parse(b),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:${cH()};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 uH(r);else if(e.autoAuth){let f=fu.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 b={type:"CONTENT",value:S.substring},A=await Rd({timeout:Sn,assertion:b,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),tf(r)}}finally{try{h!==void 0&&!m&&p?.status==="SUCCESS"&&await dH({step:e,result:p,browser:s.browser,cacheKeyPrefix:h,logger:n,storage:i})}finally{h!==void 0&&await i.releaseCacheLock(h)}}return p},uH=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,cn({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 Fw({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 Bo({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 dH({step:r,result:e,browser:t,cacheKeyPrefix:n,logger:o,storage:i}){let a=r.cacheConfig?.cacheExpiryMs;(!a||a===Zv)&&(a=r.defaultCacheTtl??eR);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 pH(r,e,t)}async function pH(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 Xj}from"lodash-es";import{randomUUID as Uw}from"crypto";import{diff as mH}from"deep-object-diff";import{cloneDeep as Bw}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?Bw(e.command.cache):{},d=o.browser.url(),p=new Date,m,h=Uw(),g=Uw();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,b=pu();try{let A=await o.executePresetCommand(b,t,e.command,i,s?.advanced.disableAICaching??!1);A.beforeScreenshotOverride&&(m=A.beforeScreenshotOverride),S=A.afterScreenshotOverride;let T=new Date,C=o.browser.url();y={beforeUrl:d,afterUrl:C,startedAt:p,finishedAt:T,viewport:o.browser.getViewport(),status:A.fail?"FAILED":"SUCCESS",elementInteracted:A.elementInteracted},f={...e,message:A.thoughts??"Successfully executed preset action.",beforeUrl:d,afterUrl:C,finishedAt:T,startedAt:p,status:A.fail?"FAILED":"SUCCESS",data:A.data,results:[y],details:b.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 ${Jn(e.command)}`);let T=o.browser.url(),C=new Date,x=A instanceof Error?A.message:`${A}`;y={beforeUrl:d,afterUrl:T,startedAt:p,finishedAt:C,viewport:o.browser.getViewport(),status:A instanceof DOMException&&A.name==="AbortError"?"CANCELLED":"FAILED",message:x},f={...e,startedAt:p,finishedAt:C,beforeUrl:d,afterUrl:T,status:A instanceof DOMException&&A.name==="AbortError"?"CANCELLED":"FAILED",message:x,failureReason:A instanceof M?A.reason:void 0,results:[y],details:b.details}}finally{let A="cache"in e.command&&e.command.cache?Bw(e.command.cache):{},T=mH(u,A);T&&Object.keys(T).length>0&&l.info({diffs:vu(T)},"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 zw(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=pu();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 cn({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 cn({asyncTasks:r.work.asyncTasks,nestedResults:[...l,...m.results],result:g,logger:n}),g}import{randomUUID as Hw}from"crypto";var Gw=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 hH(r);i.finishedAt=new Date,cn({asyncTasks:r.work.asyncTasks,result:i,nestedResults:i.results,logger:r.fixtures.logger});let a=await t.browser.screenshot({}),s=Hw();i.beforeSnapshot=s,e.attachBeforeScreenshot({logger:n,snapshotId:s,screenshot:o});let c=Hw();return i.afterSnapshot=c,e.attachAfterScreenshot({logger:n,snapshotId:c,screenshot:a}),i},hH=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 rf}from"crypto";var jw=15,gH=7,Vw=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 fH(r);i.finishedAt=new Date,cn({asyncTasks:r.work.asyncTasks,result:i,nestedResults:i.results,logger:r.fixtures.logger});let a=await n.browser.screenshot({quality:75}),s=rf();i.beforeSnapshot=s,e.attachBeforeScreenshot({logger:t,snapshotId:s,screenshot:o});let c=rf();return i.afterSnapshot=c,e.attachAfterScreenshot({logger:t,snapshotId:c,screenshot:a}),i},fH=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,b,A;for(;;){if(y>jw)return p.message=`Exceeded the maximum number of commands allowed per AI step (${jw})`,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 T=await i.evaluateAiAction({goal:m,startingScreenshot:y===0?void 0:g,history:f,logger:d,langfuseSessionId:u,lastError:A}),{evaluation:C,reasoning:x,summary:_}=T;d.info(T,"Got AI evaluation");let D=p.results[y-1]?.id;switch(C.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 b=Array.from(g.matchAll(LI)).map(Q=>Q&&Q.length>=3?{tagName:Q[1],id:Q[2]}:void 0).filter(Q=>!!Q),T=Array.from(g.matchAll(aW)).map(Q=>Q&&(Q[2]||Q[4])).filter(Q=>!!Q);T.reverse();let C=g.replace(/ id="[0-9]+"/g,"");u.push(C);for(let Q of b)p.push(Q.id),m.push(Q);for(let Q of T){let K=m[m.length-1];K&&K.tagName===Q&&m.pop()}let x=m.some(Q=>lW.includes(Q.tagName)),_=c[l+1]??"",D=Me(_),U=Array.from(_.matchAll(LI)).map(Q=>Q&&Q.length>2?Q[1]:void 0).filter(Q=>!!Q),L=U.some(Q=>kI.includes(Q)),H=U.some(Q=>sW.includes(Q));d+D>=i&&(h=!0),d>=n&&(L&&!x||T.some(Q=>cW.includes(Q)))&&(h=!0),d>=o&&H&&!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 pW=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>pW)try{let p=Fp({serializedTree:u,options:{minChunkTokenCount:1e4,maxChunkTokenCount:1e5,acceptableChunkTokenCount:5e4,maxLineLength:4e3},logger:i});l=await hW({...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*Io),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:DI,logger:i}),m=dW();l=await V(mW({...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:NI,logger:i});l=await V(gW({...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*Io),u=l.serialize(),i.info("Filtered page using naive truncation")}return u}async function mW({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 hW(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 gW(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 WS(r,e){if(!r.description)throw new M("UserConfigurationError","Cannot locate element with empty description");return $r({action:async()=>fW(r,e),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:e.browser,logger:r.logger})}async function fW(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=yW(y,a));let{serializedTree:b,tree:A}=await Nn(m,{allowNotActionableNodesOverride:u,filterByViewport:o,abortSignal:f,skipWait:i,logger:l}),T,C=Date.now(),x;for(;!T&&Date.now()-C<3e3;){f.throwIfAborted();try{T=await m.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(q){x=q}}if(!T)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 _=b,D=!1,U=`data:image/jpeg;base64,${T.toString("base64")}`;_=await Ki({type:"locator",description:y,screenshot:U,serializedTree:b,options:{aiPageFiltering:c},tree:A,fixtures:{generator:g,signal:f,logger:l,orgId:p}}),_!==b&&(D=!0);let L=await g.getElementLocation({browserState:_,goal:y,screenshot:U,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:U}}var SW=["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:"],FI="<select> element:",UI="text input or contenteditable element:",BI="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:",zI="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:",$S=[FI,UI,BI,zI,...SW];function HI(r,e){if(r===e)return!0;for(let t of $S){if(!r.startsWith(t))continue;let n=r.slice(t.length).trim();if($S.some(o=>e.startsWith(o)&&e.slice(o.length).trim()===n)||n===e.trim())return!0}return!!$S.some(t=>e.startsWith(t)&&e.slice(t.length).trim()===r.trim())}function yW(r,e){if(!r||!e)return r;switch(e){case"SELECT_OPTION":return`${FI} ${r}`;case"TYPE":return`${UI} ${r}`;case"NEGATED_ELEMENT_VISIBLE_CHECK":return`${BI}
|
|
4363
4363
|
${r}`;case"ELEMENT_CHECK":return`${zI}
|
|
4364
|
-
${r}`;default:return r}}var EW=15;async function Bp({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=EW}){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=DA(c),u=0,d=Date.now(),p,m,h;try{await $r({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 $r({action:async()=>{let S=await GI(s,t,n.abortSignal);return m&&m.serializedTree===S.serializedTree&&m.screenshotBuff.equals(S.screenshotBuff)?(f=!0,p):(m=S,jI({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&&Cl(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 $r({action:async()=>jI({command:r,state:await GI(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&&Cl(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 GI(r,e,t){let[n,o]=await Promise.all([Nn(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function jI({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(),b=r.contextChoice??"MULTIMODAL",A=h;b!=="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 T={goal:r.assertion,url:S,memory:o?r.cache?.memory:void 0,browserState:A,screenshot:y,contextChoice:b,source:c},x=await(b==="VISION_ONLY"?(_,D)=>d.getVisualAssertionResult(_,D):(_,D)=>d.getAssertionResult(_,D))(T,{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 TW(x.relevantElements,u,l)),{success:x.result,thoughts:x.thoughts,afterScreenshotOverride:f,updatedMemory:o?x.updatedMemory:void 0}}async function TW(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 V(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 bW=75e4,zp=class extends Error{constructor(){super("The page content exceeds the maximum token limit for AI smart waiting."),this.name="ExceededMaxAISmartWaitingTokensError"}};async function VI(r,e){let{logger:t}=r,{abortSignal:n,browser:o}=e,i=Date.now();try{await vW(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 vW(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 V(RW(r,e,t),{milliseconds:o.smartWaitingTimeout})}async function RW(r,e,t){let{logger:n,iframeUrl:o}=e,{browser:i}=t;for(;Date.now()-r<i.smartWaitingTimeout;)if(await $r({action:async()=>AW(e,t),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function AW(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 Nn(a,{allowNotActionableNodesOverride:i,filterByViewport:o,abortSignal:s,logger:n});if(Me(p)>bW)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 wW=3e4;async function $I({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??wW/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 V((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 Xo=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([Nn(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([Nn(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 Nn(this.browser,e)}async locateElement(e){return await WS({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return $r({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 $r({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 En&&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=WI(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&&!HI(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 b=T=>!!T&&Ic(T),A=!0;if(!b(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 VI({description:o.elementDescriptor,iframeUrl:s.iframeUrl,source:m,logger:h,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride},this.getControllerFixtures(t)),f--;let T;try{T=await WS({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)}T.frameConfig&&this.browser.setActiveFrameConfig(T.frameConfig);let C=s.disableGlobalLocatorRedirect?{locator:T.resolution.locator}:await this.attemptLocatorRedirect(T.resolution.locator,h),x=await a(C);return Ku({cmd:c,key:d,newTarget:T.target,logger:h,updatedWithAI:!0}),p&&(n.recordTargetAutoHeal({healType:"AI"}),T.target.targetSource="AI_HEALED",T.target.targetUpdateTime=new Date().toUTCString(),T.target.targetUpdateLoggerTags=Ge(h)),{result:x,elementInteractedDisplayString:T.resolution.displayString,thoughts:T.thoughts}}try{let T=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(T.locator);let C=s.disableGlobalLocatorRedirect?{locator:T.locator}:await this.attemptLocatorRedirect(T.locator,h),x=await a(C);if(kt.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.3"]),Ku({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let _=T.decisions.filter(D=>D.matched);if(_.length!==1)h.warn({decisions:T.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:T.displayString}}catch(T){this.throwIfClosed();let C="unknown";T instanceof Pr&&T.cacheMissReason&&(C=T.cacheMissReason),kt.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.3",`missReason:${C}`]);let x=!1;if((T instanceof En||Vm(T)||qm(T)||Km(T)||XE(T)||$m(T)||JE(T))&&(x=!0),T instanceof M&&!x)throw h.error({err:T},"Failed to execute action with cached target (fatal)"),T;if(f>0&&o){h.info({err:T},"Failed to execute action with cached target, retrying with AI");let _;return S.memory&&Pc(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",T.message,{errOptions:{cause:T}})}}async attemptLocatorRedirect(e,t){return this.browser.userBrowserSettings.globalLocatorRedirect!==!1?this.browser.performTargetRedirection(e,t):{locator:e}}async screenshotWithDimensions(e){return Ul(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&&pE(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 oM({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{xw(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>SS(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=lR(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&&fn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:b}=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=b}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(fn(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:b=>this.browser.click(b,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(fn(n.fromTarget)&&fn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(fn(n.fromTarget)||fn(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&&fn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,void 0,n.target.pixels);break}let y,S;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:b,thoughts:A}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async T=>this.browser.mouseDrag(h,g,f,T.locator,{force:n.force}),options:{disableCache:i,targetName:"target",...n}});y=b,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(!fo(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:hi(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 Bo({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&&fn(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=WI(n.target),S=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(y){let{elementInteractedDisplayString:A,thoughts:T}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:y,cache:n.cache?.target,action:C=>this.browser.typeIntoTarget(n.value,C,{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:hi(n)}});g=A,f=T}else await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);let b={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return sd(h,b.urlAfterCommand)&&(b.succeedImmediately=!0,b.succeedImmediatelyReason="URL changed"),b}case"HOVER":{if(fn(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(!fo(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&&!fo(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 xW,g=CW(fetch,h),f;try{f=new URL(n.url).hostname}catch{}let y=await Nw({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g});return{data:Gs.parse({...y,cookies:Tb(h,f)}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await $I({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return Lw({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 TM({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 Bo({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=fu.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??Sn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(Pw(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&&Cl(n,y.cache?.memory.traces,a)}}let f=await Iw({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 $r({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 qo(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await vS(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 V(h,{milliseconds:g*1e3,message:`Request listener timed out after ${g} seconds`}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"RECORD_REQUESTS":{let h=new qo(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]=_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 qo(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 qo(n.requestMatcher),async(g,f)=>{let y=await Bo({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=Fb.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 _W}from"lodash-es";var MW={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:_W(MW),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 qI(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(),b=f.toEditorDisplayCopy();JSON.stringify(b)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:b,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=b}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 IW=3;async function KI({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),b=await l(g,e),A=await t(g),{testMetadata:T,baseUrl:C,envName:x,browserConfig:_,aiSettings:D,environmentVariables:B,localCodeEvalTools:U}=await Yi({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:b}),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 H=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:H,event:"connect",args:r.handshake.query},"Websocket event (connect)"),H&&p.getCurrentConnectionsByIp(H)>=IW)throw e.error({clientIp:H,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(H);try{await PW({socket:r,baseUrl:C,envName:x,testMetadata:T,orgId:g,sessionId:m,logger:e,environmentVariables:B,clientIp:H,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:U,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(H),Q}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function PW({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 b={viewport:o.advanced?.viewport??Yt,locale:o.advanced?.locale??vo,timezoneId:o.advanced?.timezone??Ro,geolocation:o.advanced?.geolocation??Ao,colorScheme:o.advanced?.colorScheme};n&&(b.deviceScaleFactor=n);let A=o.id,T=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 C=await Kr.init({baseUrl:e,userBrowserSettings:T,enricher:y,storage:c,logger:s,contextArgs:b,iconKnowledgeBase:null,callbacks:{onTabsChange:(U,L)=>{r.emit("tabs",{tabs:U,activeTab:L})},onScreencastFrame:(U,L)=>{let H=r;Br&&(H=r.compress(!0)),H.emit("screenshot",{buffer:U},()=>{L()})},onSvgsCollected:U=>{r.emit("newIconDetected",{numIcons:U.newSvgs.length}),c.saveNewIcons(U,s)},onNetworkLogs:U=>{r.emit("networkLogs",{harEntries:U})}}});await C.navigate({url:e,initialNavigation:!0});let x=new Xo({browser:C,generator:p,logger:s,orgId:i,options:{scratchPadId:void 0,slowMoMs:T.slowMoMs,autoFollowNewTabs:T.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:c,localCodeEvalTools:d,uploadedFileStorage:l,visualDiffScreenshotStorage:u}),_=qI(r,a,s,S),D=async()=>{_.timers.forEach(U=>clearInterval(U))},B=new sr({baseUrl:e,testName:o.name,currentUrl:x.browser.url(),variablesFromEnvironment:m,envName:t});if(!r.connected)throw await C.cleanup(),new Error("Socket not connected anymore, not proceeding with session setup");r.emit("session",{url:e,userAgent:Kr.USER_AGENT,viewport:x.browser.getViewport(),sessionId:a}),S.registerSession({controller:x,context:B,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 Cn({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?.[vt];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 qS=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 io({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},io=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 qS({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 io({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new io({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new io({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var KS={currentlyExecutingRequests:{}},LW=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=KS.currentlyExecutingRequests[l]??0;KS.currentlyExecutingRequests[l]=u+1,s=await NW({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),KS.currentlyExecutingRequests[l]--}},NW=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:b,sessionId:A,orgId:T}=u,C=A,x=S.getSession(A);if(!x)throw new Error("No active session found");let{controller:_,context:D}=x;_.setOpen(),d=d.child({testId:b,orgId:T,sessionId:A,runId:C}),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 B=h??{},U=async()=>{o&&(await _.browser.reset({newUrl:t}),D.reset({baseUrl:t,currentUrl:_.browser.url(),variablesFromEnvironment:B,envName:p,testName:m}))},L=await s(T),H=await y(T),Q=async()=>{let ae=Date.now();try{await H.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:b,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 _l({promiseGenerator:async()=>Promise.all([U(),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=OW(e),ve={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},q={orgId:T,runId:C,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},at={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,T,b),tr=await bp({fixtures:at,options:ve,callbacks:Oe,inputs:q,testParams:{tracer:ht}}),He={logger:d,cacheStorage:H,orgId:T,testId:b,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 YI={event:"execute",createHandler:LW};import{cloneDeep as DW}from"lodash-es";var kW=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=DW(e),s=wA(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})}}},XI={event:"lintStep",createHandler:kW};var FW=({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=Ei.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let b=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=b.resolution.locator,y={target:b.target,thoughts:b.thoughts}}catch(b){e.warn({err:b},"Failed resolving target with selector"),s({err:`Failed locating element: ${b.message}`,decisions:b instanceof Pr?b.decisions:void 0});return}else try{let b=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:hi(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&Pc(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:b.target,thoughts:b.thoughts},S=b.resolution.locator}catch(b){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:b,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:`${b.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(b){e.warn({err:b},"Failed getting select options"),s({err:`Failed getting select options: ${b.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:b,width:A,height:T}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),C=await g.uploadScreenshot(b);y.screenshot={data:C,width:A,height:T},e.info({width:A,height:T},"Captured screenshot during locate")}catch(b){e.error({err:b},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${b.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(b){e.warn({err:b},"Error highlighting element, continuing...")}}},JI={event:"locate",createHandler:FW};var UW=({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")}}},QI={event:"mouseClickEvent",createHandler:UW};var BW=({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})}},ZI={event:"recordTargetClick",createHandler:BW};var zW=({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}}},eP={event:"keyDownEvent",createHandler:zW};var HW=({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}}},tP={event:"keyUpEvent",createHandler:HW};var GW=({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")}}},rP={event:"mouseMoveEvent",createHandler:GW};var jW=({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}}},nP={event:"recordingStart",createHandler:jW};var VW=({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}},oP={event:"recordingStop",createHandler:VW};var $W=({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()},iP={event:"refresh",createHandler:$W};var WW=({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 b=y.browser.baseUrl;S.reset({baseUrl:b,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),T=Kr.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${b}`),r.emit("session",{url:b,userAgent:T,viewport:A,sessionId:c})},aP={event:"reset",createHandler:WW};var qW=({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})}},sP={event:"switchTab",createHandler:qW};async function lP(r){return KI(r)}var cP=[Ew,YI,JI,aP,iP,fw,sP,XI,ZI,nP,oP,rP,QI,eP,tP,yw,Sw];var uP=r=>{let{logger:e}=r,t=new KW(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 lP({...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}cP.forEach(i=>YW(i,{...r,socket:n,metadata:o,logger:e}))}),t},YW=(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 eq}from"express";import{Router as JW}from"express";import hc from"fs";import mc from"path";import{v4 as QW}from"uuid";import ZW from"yaml";import{hostname as XW}from"os";var pc="2.28.3",rt=Na({app:"desktop-server",hostname:XW(),disableConsoleLogs:!0}).child({cliVersion:pc});(async()=>{try{let r=await to(rt);r.gitBranchName&&rt.addBinding("branch",r.gitBranchName)}catch{}})();var Es=JW();async function YS(r){return(await hd(r,rt)).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 YS(n);e.status(200).json(o)}));Es.post("/",Pe(async(r,e)=>{let t;try{t=Jb.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{To(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=mc.join(n.rootDir,t.folderPath??"");if(!hc.existsSync(i)||!hc.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 sn(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=Xb.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{To(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 sn(i,o,E),s=mc.join(n.rootDir,mc.dirname(i.relativePath));if(!hc.existsSync(s)||!hc.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=mc.join(s,`${c}.module.yaml`),u=QW(),{stepsToSave:d}=await ot({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=ZW.stringify(p);hc.writeFileSync(l,m,"utf-8");let h={relativeFilePath:mc.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=Qb.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=se(),o=await ee(n);VA({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:E,project:n}),e.status(201).json({message:"ok"})}));var dP=Es;var pP=eq();pP.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 YS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var mP=pP;import{Router as tq}from"express";var XS=tq();XS.get("/",Pe((r,e)=>{let t=gd(se(),rt);e.status(200).json(t)}));XS.get("/names",Pe((r,e)=>{let n=se().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var hP=XS;import{Router as rq}from"express";var gP=rq();gP.get("/",Pe((r,e)=>{let t={userId:Do(),orgId:Ct(),cliVersion:pc??"0.0.0"};e.status(200).json(t)}));var fP=gP;import{StreamableHTTPServerTransport as SK}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as yK}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as EK}from"crypto";import{Router as TK}from"express";import{McpServer as gK}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as fK}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as sq}from"ai";import Wp from"dedent";import lq from"path";import{z as Jo}from"zod";import{tool as nq}from"ai";import{z as oq}from"zod";var SP=(r,e)=>({builder:n=>nq({description:r.schema.description,inputSchema:oq.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 EW=15;async function Bp({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=EW}){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=DA(c),u=0,d=Date.now(),p,m,h;try{await $r({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 $r({action:async()=>{let S=await GI(s,t,n.abortSignal);return m&&m.serializedTree===S.serializedTree&&m.screenshotBuff.equals(S.screenshotBuff)?(f=!0,p):(m=S,jI({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&&Cl(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 $r({action:async()=>jI({command:r,state:await GI(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&&Cl(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 GI(r,e,t){let[n,o]=await Promise.all([Nn(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function jI({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(),b=r.contextChoice??"MULTIMODAL",A=h;b!=="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 T={goal:r.assertion,url:S,memory:o?r.cache?.memory:void 0,browserState:A,screenshot:y,contextChoice:b,source:c},x=await(b==="VISION_ONLY"?(_,D)=>d.getVisualAssertionResult(_,D):(_,D)=>d.getAssertionResult(_,D))(T,{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 TW(x.relevantElements,u,l)),{success:x.result,thoughts:x.thoughts,afterScreenshotOverride:f,updatedMemory:o?x.updatedMemory:void 0}}async function TW(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 V(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 bW=75e4,zp=class extends Error{constructor(){super("The page content exceeds the maximum token limit for AI smart waiting."),this.name="ExceededMaxAISmartWaitingTokensError"}};async function VI(r,e){let{logger:t}=r,{abortSignal:n,browser:o}=e,i=Date.now();try{await vW(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 vW(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 V(RW(r,e,t),{milliseconds:o.smartWaitingTimeout})}async function RW(r,e,t){let{logger:n,iframeUrl:o}=e,{browser:i}=t;for(;Date.now()-r<i.smartWaitingTimeout;)if(await $r({action:async()=>AW(e,t),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function AW(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 Nn(a,{allowNotActionableNodesOverride:i,filterByViewport:o,abortSignal:s,logger:n});if(Me(p)>bW)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 wW=3e4;async function $I({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??wW/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 V((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 Xo=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([Nn(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([Nn(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 Nn(this.browser,e)}async locateElement(e){return await WS({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return $r({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 $r({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 En&&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=WI(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&&!HI(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 b=T=>!!T&&Ic(T),A=!0;if(!b(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 VI({description:o.elementDescriptor,iframeUrl:s.iframeUrl,source:m,logger:h,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride},this.getControllerFixtures(t)),f--;let T;try{T=await WS({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)}T.frameConfig&&this.browser.setActiveFrameConfig(T.frameConfig);let C=s.disableGlobalLocatorRedirect?{locator:T.resolution.locator}:await this.attemptLocatorRedirect(T.resolution.locator,h),x=await a(C);return Ku({cmd:c,key:d,newTarget:T.target,logger:h,updatedWithAI:!0}),p&&(n.recordTargetAutoHeal({healType:"AI"}),T.target.targetSource="AI_HEALED",T.target.targetUpdateTime=new Date().toUTCString(),T.target.targetUpdateLoggerTags=Ge(h)),{result:x,elementInteractedDisplayString:T.resolution.displayString,thoughts:T.thoughts}}try{let T=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(T.locator);let C=s.disableGlobalLocatorRedirect?{locator:T.locator}:await this.attemptLocatorRedirect(T.locator,h),x=await a(C);if(kt.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.4"]),Ku({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let _=T.decisions.filter(D=>D.matched);if(_.length!==1)h.warn({decisions:T.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:T.displayString}}catch(T){this.throwIfClosed();let C="unknown";T instanceof Pr&&T.cacheMissReason&&(C=T.cacheMissReason),kt.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.4",`missReason:${C}`]);let x=!1;if((T instanceof En||Vm(T)||qm(T)||Km(T)||XE(T)||$m(T)||JE(T))&&(x=!0),T instanceof M&&!x)throw h.error({err:T},"Failed to execute action with cached target (fatal)"),T;if(f>0&&o){h.info({err:T},"Failed to execute action with cached target, retrying with AI");let _;return S.memory&&Pc(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",T.message,{errOptions:{cause:T}})}}async attemptLocatorRedirect(e,t){return this.browser.userBrowserSettings.globalLocatorRedirect!==!1?this.browser.performTargetRedirection(e,t):{locator:e}}async screenshotWithDimensions(e){return Ul(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&&pE(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 oM({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{xw(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>SS(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=lR(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&&fn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:b}=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=b}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(fn(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:b=>this.browser.click(b,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(fn(n.fromTarget)&&fn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(fn(n.fromTarget)||fn(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&&fn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,void 0,n.target.pixels);break}let y,S;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:b,thoughts:A}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async T=>this.browser.mouseDrag(h,g,f,T.locator,{force:n.force}),options:{disableCache:i,targetName:"target",...n}});y=b,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(!fo(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:hi(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 Bo({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&&fn(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=WI(n.target),S=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(y){let{elementInteractedDisplayString:A,thoughts:T}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:y,cache:n.cache?.target,action:C=>this.browser.typeIntoTarget(n.value,C,{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:hi(n)}});g=A,f=T}else await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);let b={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return sd(h,b.urlAfterCommand)&&(b.succeedImmediately=!0,b.succeedImmediatelyReason="URL changed"),b}case"HOVER":{if(fn(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(!fo(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&&!fo(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 xW,g=CW(fetch,h),f;try{f=new URL(n.url).hostname}catch{}let y=await Nw({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g});return{data:Gs.parse({...y,cookies:Tb(h,f)}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await $I({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return Lw({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 TM({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 Bo({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=fu.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??Sn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(Pw(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&&Cl(n,y.cache?.memory.traces,a)}}let f=await Iw({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 $r({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 qo(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await vS(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 V(h,{milliseconds:g*1e3,message:`Request listener timed out after ${g} seconds`}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"RECORD_REQUESTS":{let h=new qo(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]=_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 qo(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 qo(n.requestMatcher),async(g,f)=>{let y=await Bo({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=Fb.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 _W}from"lodash-es";var MW={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:_W(MW),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 qI(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(),b=f.toEditorDisplayCopy();JSON.stringify(b)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:b,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=b}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 IW=3;async function KI({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),b=await l(g,e),A=await t(g),{testMetadata:T,baseUrl:C,envName:x,browserConfig:_,aiSettings:D,environmentVariables:B,localCodeEvalTools:U}=await Yi({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:b}),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 H=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:H,event:"connect",args:r.handshake.query},"Websocket event (connect)"),H&&p.getCurrentConnectionsByIp(H)>=IW)throw e.error({clientIp:H,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(H);try{await PW({socket:r,baseUrl:C,envName:x,testMetadata:T,orgId:g,sessionId:m,logger:e,environmentVariables:B,clientIp:H,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:U,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(H),Q}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function PW({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 b={viewport:o.advanced?.viewport??Yt,locale:o.advanced?.locale??vo,timezoneId:o.advanced?.timezone??Ro,geolocation:o.advanced?.geolocation??Ao,colorScheme:o.advanced?.colorScheme};n&&(b.deviceScaleFactor=n);let A=o.id,T=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 C=await Kr.init({baseUrl:e,userBrowserSettings:T,enricher:y,storage:c,logger:s,contextArgs:b,iconKnowledgeBase:null,callbacks:{onTabsChange:(U,L)=>{r.emit("tabs",{tabs:U,activeTab:L})},onScreencastFrame:(U,L)=>{let H=r;Br&&(H=r.compress(!0)),H.emit("screenshot",{buffer:U},()=>{L()})},onSvgsCollected:U=>{r.emit("newIconDetected",{numIcons:U.newSvgs.length}),c.saveNewIcons(U,s)},onNetworkLogs:U=>{r.emit("networkLogs",{harEntries:U})}}});await C.navigate({url:e,initialNavigation:!0});let x=new Xo({browser:C,generator:p,logger:s,orgId:i,options:{scratchPadId:void 0,slowMoMs:T.slowMoMs,autoFollowNewTabs:T.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:c,localCodeEvalTools:d,uploadedFileStorage:l,visualDiffScreenshotStorage:u}),_=qI(r,a,s,S),D=async()=>{_.timers.forEach(U=>clearInterval(U))},B=new sr({baseUrl:e,testName:o.name,currentUrl:x.browser.url(),variablesFromEnvironment:m,envName:t});if(!r.connected)throw await C.cleanup(),new Error("Socket not connected anymore, not proceeding with session setup");r.emit("session",{url:e,userAgent:Kr.USER_AGENT,viewport:x.browser.getViewport(),sessionId:a}),S.registerSession({controller:x,context:B,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 Cn({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?.[vt];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 qS=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 io({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},io=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 qS({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 io({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new io({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new io({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var KS={currentlyExecutingRequests:{}},LW=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=KS.currentlyExecutingRequests[l]??0;KS.currentlyExecutingRequests[l]=u+1,s=await NW({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),KS.currentlyExecutingRequests[l]--}},NW=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:b,sessionId:A,orgId:T}=u,C=A,x=S.getSession(A);if(!x)throw new Error("No active session found");let{controller:_,context:D}=x;_.setOpen(),d=d.child({testId:b,orgId:T,sessionId:A,runId:C}),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 B=h??{},U=async()=>{o&&(await _.browser.reset({newUrl:t}),D.reset({baseUrl:t,currentUrl:_.browser.url(),variablesFromEnvironment:B,envName:p,testName:m}))},L=await s(T),H=await y(T),Q=async()=>{let ae=Date.now();try{await H.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:b,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 _l({promiseGenerator:async()=>Promise.all([U(),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=OW(e),ve={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},q={orgId:T,runId:C,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},at={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,T,b),tr=await bp({fixtures:at,options:ve,callbacks:Oe,inputs:q,testParams:{tracer:ht}}),He={logger:d,cacheStorage:H,orgId:T,testId:b,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 YI={event:"execute",createHandler:LW};import{cloneDeep as DW}from"lodash-es";var kW=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=DW(e),s=wA(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})}}},XI={event:"lintStep",createHandler:kW};var FW=({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=Ei.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let b=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=b.resolution.locator,y={target:b.target,thoughts:b.thoughts}}catch(b){e.warn({err:b},"Failed resolving target with selector"),s({err:`Failed locating element: ${b.message}`,decisions:b instanceof Pr?b.decisions:void 0});return}else try{let b=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:hi(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&Pc(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:b.target,thoughts:b.thoughts},S=b.resolution.locator}catch(b){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:b,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:`${b.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(b){e.warn({err:b},"Failed getting select options"),s({err:`Failed getting select options: ${b.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:b,width:A,height:T}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),C=await g.uploadScreenshot(b);y.screenshot={data:C,width:A,height:T},e.info({width:A,height:T},"Captured screenshot during locate")}catch(b){e.error({err:b},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${b.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(b){e.warn({err:b},"Error highlighting element, continuing...")}}},JI={event:"locate",createHandler:FW};var UW=({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")}}},QI={event:"mouseClickEvent",createHandler:UW};var BW=({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})}},ZI={event:"recordTargetClick",createHandler:BW};var zW=({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}}},eP={event:"keyDownEvent",createHandler:zW};var HW=({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}}},tP={event:"keyUpEvent",createHandler:HW};var GW=({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")}}},rP={event:"mouseMoveEvent",createHandler:GW};var jW=({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}}},nP={event:"recordingStart",createHandler:jW};var VW=({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}},oP={event:"recordingStop",createHandler:VW};var $W=({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()},iP={event:"refresh",createHandler:$W};var WW=({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 b=y.browser.baseUrl;S.reset({baseUrl:b,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),T=Kr.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${b}`),r.emit("session",{url:b,userAgent:T,viewport:A,sessionId:c})},aP={event:"reset",createHandler:WW};var qW=({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})}},sP={event:"switchTab",createHandler:qW};async function lP(r){return KI(r)}var cP=[Ew,YI,JI,aP,iP,fw,sP,XI,ZI,nP,oP,rP,QI,eP,tP,yw,Sw];var uP=r=>{let{logger:e}=r,t=new KW(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 lP({...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}cP.forEach(i=>YW(i,{...r,socket:n,metadata:o,logger:e}))}),t},YW=(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 eq}from"express";import{Router as JW}from"express";import hc from"fs";import mc from"path";import{v4 as QW}from"uuid";import ZW from"yaml";import{hostname as XW}from"os";var pc="2.28.4",rt=Na({app:"desktop-server",hostname:XW(),disableConsoleLogs:!0}).child({cliVersion:pc});(async()=>{try{let r=await to(rt);r.gitBranchName&&rt.addBinding("branch",r.gitBranchName)}catch{}})();var Es=JW();async function YS(r){return(await hd(r,rt)).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 YS(n);e.status(200).json(o)}));Es.post("/",Pe(async(r,e)=>{let t;try{t=Jb.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{To(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=mc.join(n.rootDir,t.folderPath??"");if(!hc.existsSync(i)||!hc.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 sn(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=Xb.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{To(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 sn(i,o,E),s=mc.join(n.rootDir,mc.dirname(i.relativePath));if(!hc.existsSync(s)||!hc.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=mc.join(s,`${c}.module.yaml`),u=QW(),{stepsToSave:d}=await ot({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=ZW.stringify(p);hc.writeFileSync(l,m,"utf-8");let h={relativeFilePath:mc.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=Qb.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=se(),o=await ee(n);VA({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:E,project:n}),e.status(201).json({message:"ok"})}));var dP=Es;var pP=eq();pP.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 YS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var mP=pP;import{Router as tq}from"express";var XS=tq();XS.get("/",Pe((r,e)=>{let t=gd(se(),rt);e.status(200).json(t)}));XS.get("/names",Pe((r,e)=>{let n=se().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var hP=XS;import{Router as rq}from"express";var gP=rq();gP.get("/",Pe((r,e)=>{let t={userId:Do(),orgId:Ct(),cliVersion:pc??"0.0.0"};e.status(200).json(t)}));var fP=gP;import{StreamableHTTPServerTransport as SK}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as yK}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as EK}from"crypto";import{Router as TK}from"express";import{McpServer as gK}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as fK}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as sq}from"ai";import Wp from"dedent";import lq from"path";import{z as Jo}from"zod";import{tool as nq}from"ai";import{z as oq}from"zod";var SP=(r,e)=>({builder:n=>nq({description:r.schema.description,inputSchema:oq.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 gc=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=>`${bt}- ${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=wy.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(qK.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:wy.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($K)}function HO({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 GO({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 jO({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 VO({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 $O(r){return r?Be(r):"Unknown suite"}async function WO({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(`${bt}- ${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(b=>!u.some(A=>A.id===b)),y=await r.bulkGetRunGroupStatus(f),S=[];for(let b of y)d(b)?u.push(b):S.push(b);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} ${$O(y.suite?.name)}`)))}),f.every(d))}),m=r.getAppUrl(),g=Da({results:p,startTime:c,onFailed:f=>{let y=$O(f.suite?.name),S=f.runs.filter(A=>A.status==="FAILED").length,b=f.runs.length;E.error(`${y} (${S}/${b} tests failed):`);for(let A of f.runs)if(A.status==="FAILED"){let T=A.testName||A.test?.name;E.error(` ${T?Be(T):"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 qO({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 O2}from"crypto";import L2 from"fs";import{existsSync as s2,mkdirSync as l2,statSync as c2}from"fs";import{randomUUID as Zi}from"crypto";import _s,{writeFileSync as KO}from"fs";import{hostname as KK}from"os";import Hn 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=Hn.join(t,i);return _s.writeFileSync(a,o),i}}}async function YK(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:KK()},{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 Cy(r,e,t.folder,i.steps,n.results);let a=XK(e,o,i.uuid);a.length>0&&(i.attachments=a);let s=`${n.runAttemptId}-result.json`;_s.writeFileSync(Hn.join(o,s),JSON.stringify(i,void 0,2))}async function gm(r,e,t,n){let o={name:fA(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=Hn.join(t,u),m=Hn.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=Hn.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 Cy(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 Cy(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 Cy(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=Hn.join(t,s);KO(c,YO(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=Hn.join(t,s);KO(c,YO(i.afterTestContext.env)),a.attachments.push({name:"Test context after step",source:s,type:"application/json"})}n.push(a)}}async function XO(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 YK(r,i,{folder:t,suiteName:n.suiteName},o)}finally{i.close()}}}function YO(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 XK(r,e,t){let n=r.listVideoAssetPaths();if(n.length===0)return[];let o=[];for(let i of n){let a=Hn.basename(i),s=a,c=Hn.join(e,s);try{_s.copyFileSync(i,c)}catch{continue}let l,u=Hn.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 JK from"junit-report-builder";import Sm from"path";function QK(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=$c[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 ZK(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();QK(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 JO(r,e){let t=JK.newBuilder();ZK(t,e),t.writeTo(Sm.join(r,`${e.suiteName}.xml`))}import e2 from"fs";import t2 from"path";function QO(r){return{title:Qn(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(QO):[]}}async function r2(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 n2(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(QO)||[],startTime:n.lastAttemptStartedAt.toISOString(),attachments:await r2(r,e,t,n)}}async function o2(r,e,t,n){return{expectedStatus:"passed",status:n.status==="PASSED"?"expected":"unexpected",results:[await n2(r,e,t,n)]}}async function i2(r,e,t,n){return{tags:[],title:n.test.name,ok:n.status==="PASSED",tests:[await o2(r,e,t,n)],id:n.runId,file:n.filePath}}function xy(r,e){return r.reduce((t,n)=>e(n)?t+1:t,0)}async function a2(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 ml;try{return await i2(r,i,t,o)}finally{i.close()}}))}],errors:[],stats:{startTime:n.startedAt.toISOString(),duration:n.finishedAt.getTime()-n.startedAt.getTime(),expected:xy(n.runs,o=>o.status==="PASSED"),unexpected:xy(n.runs,o=>o.status!=="PASSED"),flaky:xy(n.runs,o=>!!o.isFlake),skipped:0}}}async function ZO(r,e,t,n){let o=await a2(r,e,t,n);e2.writeFileSync(t2.join(t,`${n.suiteName}.json`),JSON.stringify(o,null,2))}async function eL({logger:r,callbacks:e,format:t,params:n,folder:o}){switch(s2(o)?c2(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...`),l2(o,{recursive:!0})),t){case"junit":JO(o,n);return;case"allure":case"allure-json":await XO(r,e,o,n);return;case"playwright-json":await ZO(r,e,o,n);return;default:throw new Error(`Unknown reporter format requested: '${t}'`)}}import N2 from"wait-on";import{execSync as u2}from"child_process";import{platform as d2}from"os";function _y(){return tL()?(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 tL(){return d2()==="darwin"&&u2("system_profiler SPDisplaysDataType").toString().includes("Retina")}function My(r){tL()&&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 p2 from"@actions/exec";import m2 from"@actions/io";import h2 from"quote";import g2 from"string-argv";async function rL(r,e=!0){let t=g2(r),n=await m2.which(t[0],!0),o=t.slice(1),i=p2.exec(h2(n),o,{delay:100});if(e)return i}import f2 from"csv-parser";import{createReadStream as S2}from"fs";function Iy(r){return new Promise((e,t)=>{let n=[];S2(r).pipe(f2()).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 Mr="2.28.3",y2="https://registry.npmjs.org/momentic",E2=ym.object({versions:ym.record(ym.string(),ym.unknown()).optional()});async function er(r){try{await T2(r)}catch(e){E.warn({err:e},"Failed to check CLI version against NPM servers")}}async function Py(){let r=await V(fetch(y2),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=E2.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=Mr;for(let o of Object.keys(t))Ms.valid(o)&&Ms.major(o)===Ms.major(Mr)&&Ms.gt(o,n)&&Ms.prerelease(o)===null&&(n=o);return n}async function T2(r){let e;for(let t=0;t<2;t++)try{e=await Py()}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(Mr,e)||(E.warn(`Update available: v${Mr} -> 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 lo(){try{await V(Promise.all([RR(),kt.flush()]),{milliseconds:5e3})}catch{}}import{partition as b2}from"lodash-es";function Em(r){return r.length===1?"test":"tests"}function nL(r){return r===1?"1 worker":`${r} workers`}function oL(r){r.length!==0&&(E.info(`Skipping ${r.length} disabled ${Em(r)}:`),r.forEach(e=>{E.info(`${bt}- ${[e.relativeFilePath]}`)}),E.log(""))}function iL(r,e){r.length!==0&&(E.info(`Skipping ${r.length} quarantined ${Em(r)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),E.log(""))}function v2(r,e){r.length!==0&&(E.info(`Running ${r.length} quarantined ${Em(r)} with ${nL(e)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),E.log(""))}function R2(r,e,t){e.length===0&&r.length>0||(E.info(`Running ${e.length} ${Em(e)} with ${nL(t)}:`),e.forEach(n=>{E.info(`${bt}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),E.log(""))}function aL({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]=b2(e,s=>s.quarantined);v2(i,t),R2(i,a,t)}import{randomUUID as A2}from"crypto";import{cloneDeep as Is}from"lodash-es";async function sL({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 lL({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}),b={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:Y,mode:"runner"},A=S.browserType??"Chromium";if(!xR(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 T=await Kr.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new Oo(b,c),contextArgs:{viewport:i.advanced.viewport??Yt,locale:i.advanced.locale??vo,geolocation:i.advanced.geolocation??Ao,timezoneId:i.advanced.timezone??Ro,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}),C=new Xo({browser:T,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:C.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async _=>{let{name:D,defaultValue:B,required:U}=_,L=m?.[D];U&&L===void 0&&(E.error(`Required parameter '${D}' is required by test '${i.name}' but not provided`),process.exit(1));let H=await dr({orgId:l,s:L??B,localTools:s,logger:d,context:sr.dummyContext(x.getEnvName())});x.setMomenticSystemVariable(D,H)})),{controller:C,context:x}}async function cL({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 uL({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 cL({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 dL(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await w2(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 w2(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=No({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}),b=S.steps,A=S.beforeSteps??void 0,T=S.afterSteps??void 0,C=r.envName??x2(e),x,_={};if(C){try{x=Li(C,t,c)}catch(L){let H=`Failed to resolve environment ${C} for test ${e.name}: ${L}`;throw new Error(H)}_=x.variables}let D=e.baseUrl;if(i)D=i;else if(!D){let L=_[vt];typeof L=="string"&&(D=L)}if(!D){let L=`Cannot run test with no base URL and no ${vt} variable defined in its environment`;throw new Error(L)}let B=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:C,schemaVersion:e.schemaVersion,resolvedInputs:p,quarantined:m,quarantinedReason:h}),U=c.child(B.loggerBindings||{});Object.entries(B.envVarBindings||{}).forEach(([L,H])=>{_[L]=H});try{let L=await C2({...r,variables:_,envName:C,resolvedEnv:x,baseUrl:D,storageClient:f,tracer:B,logger:U,cacheStorage:y,stepsWithCaches:b,beforeStepsWithCaches:A,afterStepsWithCaches:T,usageTracker:g});return await B.finish({logger:c,status:L.status,finishedAt:L.finishedAt,failureDetails:L.failureDetails,failureReason:L.failureReason,isFlake:L.isFlake,failureRecoveryDetails:L.failureRecoveryDetails}),{runId:B.runId,...L}}finally{a?.pop()}}async function C2(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:b,logUpdate:A,tracer:T,logger:C,cacheStorage:x,gitMetadata:_,quarantined:D,quarantinedReason:B,usageTracker:U}=r,L=i.config.ai?.aiFailureAnalysis??!1,H=new Date,Q=new Xa(i,a),K={...i.config},ve={envName:p,urlOverride:m,customHeaders:h,testInputs:g},q,at=Math.abs(S??i.config.retries??e.retries??0),Oe=[];C.info({..._,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let ht=0;ht<=at;ht++){let tr=A2(),He=await T.startAttempt(tr),ae=C.child(He.loggerBindings||{}),$e={...e,steps:Is(t),beforeSteps:Is(n),afterSteps:Is(o)};ht!==0&&A("RETRY",`attempt ${ht+1}/${at+1}`);let Jr=new Date,ta=K.advanced?.fakerConstantSeed,Ps=new Cn({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:Qr}=await lL({tracer:He,baseUrl:l,envName:p,testName:$e.name,apiClient:s,devicePixelRatio:b,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 uL({attemptMetadata:{attemptNumber:ht+1,orgId:d,runId:T.runId},attemptFixtures:{logger:ae,storageClient:u,usageTracker:U,codeEvalTools:Ps,apiClient:s,context:Qr,controller:rr,tracer:He},attemptInputs:{test:$e,orgSettings:K}});let ni=new Date,gn={logger:C,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(gn):q?.status==="FAILED"&&ht===at&&await rd(gn),await He.finish({logger:ae,result:q}),Oe.unshift(q.status);let X=await sL({orgId:d,codeEvalTools:Ps,logger:ae,outputDefinitions:e.outputs??[],testContext:Qr}),co=jT(Oe),ra=ht+1;if(q.status!=="FAILED")return{...q,runAttemptId:tr,parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:H,lastAttemptStartedAt:Jr,finishedAt:ni,attempts:ra,baseUrl:l,outputs:X,isFlake:co,quarantined:D,quarantinedReason:B};let na=q.failedStepResult,Gn=na?.message||"Unknown failure",uo=na?.failureReason??YE(Gn)??"UnknownError",Os=ae.child({errResult:na,failureReason:uo,errorMessage:Gn,numAttempts:at+1,name:$e.name});if(ht<at){Os.warn(`Retrying failed execution attempt for run: ${Gn}`);continue}Os.error(`Test failed after all exhausting attempts: ${Gn}`);let oa=new Error(Gn),po={errorMessage:Gn,errorStack:oa.stack},Rm;if(L){let Ls;try{if(q.results&&q.results.length>0){let{classification:Ne,aiFailureReason:Er}=await FA({logger:ae,browserStateStorage:vm,generator:c,fullResults:q,failureReason:uo,error:oa,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Ls=Ne,Rm=Er}}catch(Ne){ae.warn({err:Ne},"Failed to classify test results")}Ls&&(po.classification=Ls,uo=Rm??uo)}return{...q,runAttemptId:tr,parameters:ve,failureDetails:po,failureReason:uo,test:$e,filePath:$e.relativeFilePath,startedAt:H,lastAttemptStartedAt:Jr,finishedAt:ni,attempts:ht+1,baseUrl:l,outputs:X,quarantined:D,quarantinedReason:B}}catch(rr){Ds(rr);let Qr=`Encountered fatal platform error while running test '${$e.name}': ${rr}`,ni=new Date,gn=ht+1;ae.error({err:rr},Qr),E.error(Qr);let X={errorMessage:rr.message,errStack:rr.stack},co={status:"FAILED",failureDetails:X,failureReason:"InternalPlatformError",finishedAt:ni};return await He.finish({logger:ae,result:{status:"FAILED",results:[]}}),{...co,runAttemptId:tr,results:[],parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:H,lastAttemptStartedAt:Jr,finishedAt:new Date,attempts:gn,baseUrl:l,outputs:{},quarantined:D,quarantinedReason:B}}}throw new Error("This code should not be reachable")}function x2(r){for(let e of r.envs??[])if(e.default)return e.name}import I2 from"adm-zip";import P2 from"path";function _2(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 Oy(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:_2(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}};function M2(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var Oy=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:M2(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 Rc=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 P2.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 tL(){return d2()==="darwin"&&u2("system_profiler SPDisplaysDataType").toString().includes("Retina")}function My(r){tL()&&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 p2 from"@actions/exec";import m2 from"@actions/io";import h2 from"quote";import g2 from"string-argv";async function rL(r,e=!0){let t=g2(r),n=await m2.which(t[0],!0),o=t.slice(1),i=p2.exec(h2(n),o,{delay:100});if(e)return i}import f2 from"csv-parser";import{createReadStream as S2}from"fs";function Iy(r){return new Promise((e,t)=>{let n=[];S2(r).pipe(f2()).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 Mr="2.28.4",y2="https://registry.npmjs.org/momentic",E2=ym.object({versions:ym.record(ym.string(),ym.unknown()).optional()});async function er(r){try{await T2(r)}catch(e){E.warn({err:e},"Failed to check CLI version against NPM servers")}}async function Py(){let r=await V(fetch(y2),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=E2.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=Mr;for(let o of Object.keys(t))Ms.valid(o)&&Ms.major(o)===Ms.major(Mr)&&Ms.gt(o,n)&&Ms.prerelease(o)===null&&(n=o);return n}async function T2(r){let e;for(let t=0;t<2;t++)try{e=await Py()}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(Mr,e)||(E.warn(`Update available: v${Mr} -> 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 lo(){try{await V(Promise.all([RR(),kt.flush()]),{milliseconds:5e3})}catch{}}import{partition as b2}from"lodash-es";function Em(r){return r.length===1?"test":"tests"}function nL(r){return r===1?"1 worker":`${r} workers`}function oL(r){r.length!==0&&(E.info(`Skipping ${r.length} disabled ${Em(r)}:`),r.forEach(e=>{E.info(`${bt}- ${[e.relativeFilePath]}`)}),E.log(""))}function iL(r,e){r.length!==0&&(E.info(`Skipping ${r.length} quarantined ${Em(r)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),E.log(""))}function v2(r,e){r.length!==0&&(E.info(`Running ${r.length} quarantined ${Em(r)} with ${nL(e)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),E.log(""))}function R2(r,e,t){e.length===0&&r.length>0||(E.info(`Running ${e.length} ${Em(e)} with ${nL(t)}:`),e.forEach(n=>{E.info(`${bt}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),E.log(""))}function aL({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]=b2(e,s=>s.quarantined);v2(i,t),R2(i,a,t)}import{randomUUID as A2}from"crypto";import{cloneDeep as Is}from"lodash-es";async function sL({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 lL({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}),b={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:Y,mode:"runner"},A=S.browserType??"Chromium";if(!xR(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 T=await Kr.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new Oo(b,c),contextArgs:{viewport:i.advanced.viewport??Yt,locale:i.advanced.locale??vo,geolocation:i.advanced.geolocation??Ao,timezoneId:i.advanced.timezone??Ro,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}),C=new Xo({browser:T,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:C.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async _=>{let{name:D,defaultValue:B,required:U}=_,L=m?.[D];U&&L===void 0&&(E.error(`Required parameter '${D}' is required by test '${i.name}' but not provided`),process.exit(1));let H=await dr({orgId:l,s:L??B,localTools:s,logger:d,context:sr.dummyContext(x.getEnvName())});x.setMomenticSystemVariable(D,H)})),{controller:C,context:x}}async function cL({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 uL({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 cL({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 dL(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await w2(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 w2(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=No({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}),b=S.steps,A=S.beforeSteps??void 0,T=S.afterSteps??void 0,C=r.envName??x2(e),x,_={};if(C){try{x=Li(C,t,c)}catch(L){let H=`Failed to resolve environment ${C} for test ${e.name}: ${L}`;throw new Error(H)}_=x.variables}let D=e.baseUrl;if(i)D=i;else if(!D){let L=_[vt];typeof L=="string"&&(D=L)}if(!D){let L=`Cannot run test with no base URL and no ${vt} variable defined in its environment`;throw new Error(L)}let B=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:C,schemaVersion:e.schemaVersion,resolvedInputs:p,quarantined:m,quarantinedReason:h}),U=c.child(B.loggerBindings||{});Object.entries(B.envVarBindings||{}).forEach(([L,H])=>{_[L]=H});try{let L=await C2({...r,variables:_,envName:C,resolvedEnv:x,baseUrl:D,storageClient:f,tracer:B,logger:U,cacheStorage:y,stepsWithCaches:b,beforeStepsWithCaches:A,afterStepsWithCaches:T,usageTracker:g});return await B.finish({logger:c,status:L.status,finishedAt:L.finishedAt,failureDetails:L.failureDetails,failureReason:L.failureReason,isFlake:L.isFlake,failureRecoveryDetails:L.failureRecoveryDetails}),{runId:B.runId,...L}}finally{a?.pop()}}async function C2(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:b,logUpdate:A,tracer:T,logger:C,cacheStorage:x,gitMetadata:_,quarantined:D,quarantinedReason:B,usageTracker:U}=r,L=i.config.ai?.aiFailureAnalysis??!1,H=new Date,Q=new Xa(i,a),K={...i.config},ve={envName:p,urlOverride:m,customHeaders:h,testInputs:g},q,at=Math.abs(S??i.config.retries??e.retries??0),Oe=[];C.info({..._,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let ht=0;ht<=at;ht++){let tr=A2(),He=await T.startAttempt(tr),ae=C.child(He.loggerBindings||{}),$e={...e,steps:Is(t),beforeSteps:Is(n),afterSteps:Is(o)};ht!==0&&A("RETRY",`attempt ${ht+1}/${at+1}`);let Jr=new Date,ta=K.advanced?.fakerConstantSeed,Ps=new Cn({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:Qr}=await lL({tracer:He,baseUrl:l,envName:p,testName:$e.name,apiClient:s,devicePixelRatio:b,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 uL({attemptMetadata:{attemptNumber:ht+1,orgId:d,runId:T.runId},attemptFixtures:{logger:ae,storageClient:u,usageTracker:U,codeEvalTools:Ps,apiClient:s,context:Qr,controller:rr,tracer:He},attemptInputs:{test:$e,orgSettings:K}});let ni=new Date,gn={logger:C,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(gn):q?.status==="FAILED"&&ht===at&&await rd(gn),await He.finish({logger:ae,result:q}),Oe.unshift(q.status);let X=await sL({orgId:d,codeEvalTools:Ps,logger:ae,outputDefinitions:e.outputs??[],testContext:Qr}),co=jT(Oe),ra=ht+1;if(q.status!=="FAILED")return{...q,runAttemptId:tr,parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:H,lastAttemptStartedAt:Jr,finishedAt:ni,attempts:ra,baseUrl:l,outputs:X,isFlake:co,quarantined:D,quarantinedReason:B};let na=q.failedStepResult,Gn=na?.message||"Unknown failure",uo=na?.failureReason??YE(Gn)??"UnknownError",Os=ae.child({errResult:na,failureReason:uo,errorMessage:Gn,numAttempts:at+1,name:$e.name});if(ht<at){Os.warn(`Retrying failed execution attempt for run: ${Gn}`);continue}Os.error(`Test failed after all exhausting attempts: ${Gn}`);let oa=new Error(Gn),po={errorMessage:Gn,errorStack:oa.stack},Rm;if(L){let Ls;try{if(q.results&&q.results.length>0){let{classification:Ne,aiFailureReason:Er}=await FA({logger:ae,browserStateStorage:vm,generator:c,fullResults:q,failureReason:uo,error:oa,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Ls=Ne,Rm=Er}}catch(Ne){ae.warn({err:Ne},"Failed to classify test results")}Ls&&(po.classification=Ls,uo=Rm??uo)}return{...q,runAttemptId:tr,parameters:ve,failureDetails:po,failureReason:uo,test:$e,filePath:$e.relativeFilePath,startedAt:H,lastAttemptStartedAt:Jr,finishedAt:ni,attempts:ht+1,baseUrl:l,outputs:X,quarantined:D,quarantinedReason:B}}catch(rr){Ds(rr);let Qr=`Encountered fatal platform error while running test '${$e.name}': ${rr}`,ni=new Date,gn=ht+1;ae.error({err:rr},Qr),E.error(Qr);let X={errorMessage:rr.message,errStack:rr.stack},co={status:"FAILED",failureDetails:X,failureReason:"InternalPlatformError",finishedAt:ni};return await He.finish({logger:ae,result:{status:"FAILED",results:[]}}),{...co,runAttemptId:tr,results:[],parameters:ve,test:$e,filePath:$e.relativeFilePath,startedAt:H,lastAttemptStartedAt:Jr,finishedAt:new Date,attempts:gn,baseUrl:l,outputs:{},quarantined:D,quarantinedReason:B}}}throw new Error("This code should not be reachable")}function x2(r){for(let e of r.envs??[])if(e.default)return e.name}import I2 from"adm-zip";import P2 from"path";function _2(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 Oy(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:_2(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}};function M2(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var Oy=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:M2(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 Rc=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 P2.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 I2;i.addLocalFolder(o,void 0,a=>a!==".DS_Store"),this.diskStorage.storeFile({name:`${cr}/${cg}`,contents:i.toBuffer()}),n.info({browserCrashZipName:cg},"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 Ac=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{[iM]: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:uR,startedAt:new Date,status:"RUNNING"};t.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)});let o=new Rc(this.orgId,this.testId,this.testName,e,n,t,this.recordVideo);return this.children.push(o),o}};var wc=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:Dr.CLI,startedAt:new Date,status:"RUNNING",cliVersion:Mr,labels:i??[]},c=new kl(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:Mr,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 Ac(this.orgId,e.testId,e.testName,e.runId,n,t,this.recordVideo);return this.children.push(o),o}};async function pL(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 mL(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:b,reporterDir:A=rw,outputDir:T=nw,uploadResults:C=!1,waitOnTimeout:x=60,parallel:_,shardIndex:D=1,shardCount:B=1,regenerateGoldenFiles:U,gitMetadata:L,cacheOptions:H,ignoreQuarantine:Q,skipQuarantined:K,onlyQuarantined:ve,runGroupId:q,recordVideo:at,timeoutMinutes:Oe}=r;if(o&&(e.info({orgId:p},`Executing start command: ${o}`),await rL(o,!1)),i){e.info({orgId:p},`Waiting for url: ${i} with timeout: ${x} seconds.`);let Ne=a?new URL(a):void 0,Er;Ne&&(Er={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 N2({resources:[i],interval:2500,timeout:x*1e3,headers:{Accept:"*/*"},followRedirect:!0,verbose:!1,log:!0,strictSSL:!1,proxy:Er})}let ht=new Kn(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:b,logger:E}),ae=await pL(e,s,Q),{testsToSkip:$e,quarantinedTestsToSkip:Jr,testsToRun:ta,quarantinedTestsToRun:Ps}=HO({testDefinitions:He,quarantinedTestReasons:ae,onlyQuarantined:ve,skipQuarantined:K});oL($e),iL(Jr,ae);let vm=GO({testsToRun:ta,quarantinedTestsToRun:Ps,quarantinedTestReasons:ae,testInputMatrix:g}),rr=k2({globalTestsToRunWithInputs:vm,shardIndex:D,shardCount:B});aL({logger:e,localTestsToRunWithInputs:rr,parallel:_,shardCount:B,shardIndex:D});let Qr=[],ni=new Date,gn=new Set,X=async()=>{let Ne=s.getAppUrl(),Er=Da({results:Qr,startTime:ni.getTime(),onFailed:Tr=>{Uu(Tr,Tr.filePath)},getDisplayLine:Tr=>{let oi=`${bt}- ${Tr.filePath}${Tr.failureRecoveryDetails?" [recovered] ":""}`;return Tr.runId&&(oi+=` ( link when uploaded: ${Ne}/runs/${Tr.runId} )`),oi},entity:"test"}),Cc=Qr.filter(Tr=>!!Tr.failureRecoveryDetails?.attempts);return Cc.length>0&&E.warn(`Our AI agent automatically prevented ${Cc.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.4",
|
|
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.4",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@actions/exec": "^1.1.1",
|
|
12
12
|
"@actions/io": "^1.1.3",
|