momentic 2.27.2 → 2.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 oR(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 wF from"fetch-retry";import CF from"os";import iR,{multistream as xF}from"pino";import _F from"pino-pretty";import MF from"pino-std-serializers";var _a=new Map,IF=!0,aR="Log throttle exceeded",PF=100,OF=5e3,LF=wF(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}}),tg=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??CF.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=IF?iR(a):iR(a,xF([{stream:_F({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 LF(this.site,{method:"POST",headers:{"Content-Type":"application/json","signoz-access-token":"CumAaTMUcwjt05OddAmefKgshbhfRmWxzxih"},body:Ti(e),signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`Got error status (${t.statusText}) from SigNoz`)}catch{}}shouldAllowLog(e){if(e===aR)return!0;let t=Date.now();return t-this.lastWindowStart>OF&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,aR),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<PF?(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(cl[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=MF.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:KT({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,_a.set("app",this),_a.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=YT[e]):(this.minLevelValue=cl[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},Ma=({app:r,hostname:e,disableConsoleLogs:t})=>(_a.has(r)||_a.set(r,new tg({bindings:{app:r},hostname:e,disableConsoleLogs:t})),_a.get(r));async function lR(){await Promise.all([..._a.values()].map(r=>r.flush()))}import{hostname as NF}from"os";var X=Ma({app:"cli",hostname:NF(),disableConsoleLogs:!0}).child({cliVersion:"2.
|
|
32
|
-
`);console.warn(n),r.warn({stack:n,time:e},"NodeJS event loop blocked")},{threshold:1e3,trimFalsePositives:!0})}function WF(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}VF(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as l2}from"crypto";import FP from"body-parser";import Kq from"cors";import Yq from"dedent";import{Router as KU}from"express";import ar from"fs";import{globSync as YU}from"glob";import Ot from"path";import nd from"fs";import{z as tU}from"zod";var H="v1",og="cli",Ai="2.
|
|
31
|
+
`)}import wF from"fetch-retry";import CF from"os";import iR,{multistream as xF}from"pino";import _F from"pino-pretty";import MF from"pino-std-serializers";var _a=new Map,IF=!0,aR="Log throttle exceeded",PF=100,OF=5e3,LF=wF(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}}),tg=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??CF.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=IF?iR(a):iR(a,xF([{stream:_F({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 LF(this.site,{method:"POST",headers:{"Content-Type":"application/json","signoz-access-token":"CumAaTMUcwjt05OddAmefKgshbhfRmWxzxih"},body:Ti(e),signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`Got error status (${t.statusText}) from SigNoz`)}catch{}}shouldAllowLog(e){if(e===aR)return!0;let t=Date.now();return t-this.lastWindowStart>OF&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,aR),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<PF?(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(cl[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=MF.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:KT({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,_a.set("app",this),_a.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=YT[e]):(this.minLevelValue=cl[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},Ma=({app:r,hostname:e,disableConsoleLogs:t})=>(_a.has(r)||_a.set(r,new tg({bindings:{app:r},hostname:e,disableConsoleLogs:t})),_a.get(r));async function lR(){await Promise.all([..._a.values()].map(r=>r.flush()))}import{hostname as NF}from"os";var X=Ma({app:"cli",hostname:NF(),disableConsoleLogs:!0}).child({cliVersion:"2.28.0"});var kF=5;async function Iu({getResults:r,checkDone:e,name:t,timeoutMs:n=18e5}){let o=Date.now(),i=0;for(;Date.now()-o<n;){let a;i>kF&&(E.error(`Failed to fetch ${t} status too many times.`),process.exit(1));try{a=await r(),i=0}catch(l){i++,X.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 Ia({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 nR(()=>{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 Pu=(r,e)=>{if(!r.failureDetails||!r.failureReason)return;let t=Bc[r.failureDetails?.classification?.reason||r.failureReason],n=r.failureDetails?.classification?.summary||da[r.failureReason],o=r.failureDetails.classification?.rootCause;if(E.error(e),o){E.log(`${bt}- Error type: ${Tn.dim(t)}`);let i="- Root cause analysis:",a=oR(`${i} ${o}`,`${bt} `,!1),s=a.indexOf(":");E.log(`${bt}${i} ${Tn.dim(a.slice(s+1))}`)}else E.log(`${bt}Reason: ${Tn.red(t)}`),E.log(`${bt}Description: ${Tn.red(n)}`)},ml=({status:r,testLogRef:e,getRunningTestsCount:t,getTotalTestsCount:n,additionalText:o})=>{r=r.toUpperCase();let i=r,a;r.includes("FAIL")?(i=Tn.bgRed.white("FAIL"),a=3):r.includes("PASS")?(i=Tn.bgGreen.white("PASS"),a=3):r.includes("START")?(i=Tn.bgBlue.white("START"),a=2):r.includes("CANCEL")?(i=Tn.bgRgb(191,68,11).white("CANCEL"),a=1):r.includes("RETRY")?(i=Tn.bgRgb(191,68,11).white("RETRY"),a=2):r.includes("RUN")||r.includes("PROG")?(i=Tn.bgMagenta.white("RUNNING"),a=0):(E.warn(`Unknown status tried to be logged in run test locally: ${r}`),a=0),DF||(i=`${i}`),E.log(`${i}${" ".repeat(a)} ${e} ${o?`${o} `:""}(${t()}/${n()})`)};import FF from"fs";import{tmpdir as UF}from"os";import BF from"path";import{registry as hl}from"playwright-core/lib/server";import cR from"proper-lockfile";var uR=BF.join(UF(),"momenticBrowserInstallation");var rg=["chrome","chromium","chrome-for-testing","ffmpeg"],HF={Chromium:"chromium","Google Chrome":"chrome","Chrome for Testing":"chrome-for-testing"},dR={chrome:"chrome",chromium:"chromium","chrome-for-testing":"chromium-headless-shell",ffmpeg:"ffmpeg"};function pR(r){let e=dR[HF[r]??""]??"",t=hl.findExecutable(e);return!t||t.installType==="none"?!1:ng(t)}function ng(r){let e=r.executablePath();return FF.existsSync(e)}function zF(r,e){let t=dR[r];if(!t)throw new Error(`Requested install of unknown browser type ${r}`);let n=hl.findExecutable(t);if(!n||n.installType==="none")throw new Error(`Requested install of unknown browser type ${r}`);if(!(!e&&ng(n)))return n}async function GF({browser:r,force:e}){let t=zF(r,e);if(!t){E.info(`Browser '${r}' is already installed, skipping...`);return}E.info(`Installing browser '${r}'...`);try{await hl.installDeps([t],!1),await hl.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=hl.findExecutable(r),i=5*60*1e3,a=Date.now();for(;Date.now()-a<i&&!ng(o);)E.info("Waiting for browser to finish installing..."),await new Promise(s=>setTimeout(s,5e3))}else throw n}}async function mR({rawBrowsers:r,force:e=!1,all:t=!1}){let n=t?rg:Array.from(new Set(r));try{await cR.lock(uR,{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 GF({browser:i,force:e})}catch(a){o=a,E.error(`Failed to install the ${i} browser: ${a}`)}}finally{await cR.unlock(uR,{realpath:!1})}if(o)throw o}import jF from"blocked-at";import VF from"why-is-node-running";function hR(r){$F(r),WF()}function $F(r){jF((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 WF(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}VF(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as l2}from"crypto";import FP from"body-parser";import Kq from"cors";import Yq from"dedent";import{Router as KU}from"express";import ar from"fs";import{globSync as YU}from"glob";import Ot from"path";import nd from"fs";import{z as tU}from"zod";var H="v1",og="cli",Ai="2.28.0";var wo=3.1783027;function qF(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 Pe(r){return Math.ceil(ig(r)/wo)}function ig(r){let e=0;if(typeof r=="string"){let t=r;t=t.replaceAll(`
|
|
33
33
|
`,""),t=t.replaceAll(" ","");let n=qF(t);return t.length-n+wo*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+=ig(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*wo:e+=85*wo:n==="source"&&typeof t[n]=="object"&&t[n]?.type==="base64"?e+=1600*wo:e+=ig(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 Co=class extends Error{constructor(e){super(e),this.name="TimeoutError"}};var gR=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 j(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(gR(p));l=()=>c(gR(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 Co(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 Ou=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 KF=9e4,YF=3,XF=1500,JF=15e3,tn=class extends Error{status;rawError;constructor(e,t,n,o={}){super(n,o),this.status=e,this.rawError=t}};async function QF(r){return r.text().then(e=>{try{return JSON.parse(e).error}catch{return e}})}var ag=class{baseUrl;logger;constructor(e){this.baseUrl=e.baseUrl,this.logger=e.logger}getHeaders(){let e={"Content-Type":"application/json"};return Ai&&(e[wu]=Ai),og&&(e[tv]=og),e}async sendRequest(e,t){let{retries:n=YF,requestTimeoutMs:o=KF,initialRetryDelayMs:i=XF,maxRetryDelayMs:a=JF,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 tn&&p.status>=400&&p.status<500)throw p;if(p instanceof Error&&p.name==="AbortError"&&(u=new Co),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 QF(u);throw new tn(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)}}},Bt=class extends ag{apiKey;mode;constructor(e){super(e),this.apiKey=e.apiKey,this.mode=e.mode}getHeaders(){return{...super.getHeaders(),Authorization:`Bearer ${this.apiKey}`,[ev]:this.mode??""}}};import{createAnthropic as ZF}from"@ai-sdk/anthropic";function eU(r){let{apiKey:e,sessionId:t,extraHeaders:n,loggerTags:o}=r,i={Authorization:`Bearer ${e}`,[wu]:Ai??"",...t&&{[nv]:t},...n||{}};return o&&(i[rv]=JSON.stringify(o)),i}var gl=r=>e=>{let t=eU(r);return ZF({baseURL:`${r.baseUrl}/v1/llm/anthropic/${e}`,headers:t,apiKey:r.apiKey})(e)};var qn=class extends Bt{agentConfig;constructor(e,t){let n={...lu,...e};super(t),this.agentConfig=n}getAgentConfig(){return this.agentConfig}async rankChunksWithAi(e,t){let n={...e,loggerTags:t.loggerTags},o=await this.sendRequest(`/${H}/web-agent/recommend-chunks-ai`,{method:"POST",body:n,signal:t.abortSignal});return Bb.parse(o)}async rankChunksWithRag(e,t){let n=await this.sendRequest(`/${H}/web-agent/recommend-chunks`,{method:"POST",body:{cliVersion:Ai,...e},signal:t.abortSignal});return Ub.parse(n)}async getScreenshotFromS3(e){let t=await this.sendRequest(`/${H}/s3/visual-diff-screenshot`,{method:"POST",body:{url:e}});return tU.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(`/${H}/web-agent/locate-element`,{method:"POST",body:n,signal:t.abortSignal});return sv.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(`/${H}/web-agent/assertion`,{method:"POST",body:n,signal:t.abortSignal});return jh.parse(o)}async getLintStepResult(e,t){let n={...e,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${H}/web-agent/lint/step`,{method:"POST",body:n,signal:t.abortSignal});return av.parse(o)}async getLintMcpCopilotMessageResult(e,t){let n={message:e.message,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${H}/web-agent/lint/mcp-copilot`,{method:"POST",body:n,signal:t.abortSignal});return iv.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(`/${H}/web-agent/visual-assertion`,{method:"POST",body:n,signal:t.abortSignal});return jh.parse(o)}async getAiActionCommand(e,t){let n=await this.sendRequest(`/${H}/web-agent/next-command-dynamic`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return ov.parse(n)}async getMultiturnAiActionCommand(e,t){return await this.sendRequest(`/${H}/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(`/${H}/web-agent/ai-action/evaluate`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return eh.parse(n)}async getReverseMappedDescription(e,t){let n=await this.sendRequest(`/${H}/web-agent/reverse-mapped-description`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return lv.parse(n)}async getTextExtraction(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags,agentConfigVersion:this.agentConfig?.["text-extraction"]},o=await this.sendRequest(`/${H}/web-agent/text-extraction`,{method:"POST",body:n,signal:t.abortSignal});return Jm.parse(o)}async getPageSummary(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${H}/web-agent/page-summary`,{method:"POST",body:n,signal:t.abortSignal});return gb.parse(o)}async getSmartWaitingDecision(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${H}/web-agent/smart-waiting`,{method:"POST",body:n,signal:t.abortSignal});return fb.parse(o)}async getTestResultClassification(e,t){let n=await this.sendRequest(`/${H}/web-agent/result-classification`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return Im.parse(n)}async getExtractedKeywords(e,t){let n=await this.sendRequest(`/${H}/web-agent/extract-keywords`,{method:"POST",body:e,signal:t.abortSignal});return Jb.parse(n)}async getAutohealingProposal(e,t){let n=await this.sendRequest(`/${H}/web-agent/autoheal-section`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return db.parse(n)}async getFailureRecoveryProposal(e,t){let n=await this.sendRequest(`/${H}/web-agent/failure-recovery`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return mb.parse(n)}async getFailureRecoveryPlan(e,t){let n=await this.sendRequest(`/${H}/web-agent/failure-recovery-plan`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return pb.parse(n)}async getIframeRegex(e,t){let n=await this.sendRequest(`/${H}/web-agent/iframe-regex`,{method:"POST",body:e,signal:t.abortSignal});return xy.parse(n)}getVercelAnthropicModelFactory({loggerTags:e}){return gl({baseUrl:this.baseUrl,apiKey:this.apiKey,loggerTags:e})}};import{z as sg}from"zod";var Qe=class extends Bt{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(`/${H}/auth/check`,{method:"GET",retries:10,requestTimeoutMs:5e3,onFailedRequest:t=>{E.warn(`API key check failed: ${t.message}`)}});return Tv.parse(e)}async bulkGetRunStatus(e){let t=await this.sendRequest(`/${H}/runs/status`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return Sv.parse(t)}async getTestYAMLExport(e){let t=await this.sendRequest(`/${H}/tests/export`,{method:"POST",body:e,retries:3,requestTimeoutMs:3e4});return uv.parse(t)}async updateStepCaches(e,t){await this.sendRequest(`/${H}/cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getStepCacheForTest(e,t){let n=await this.sendRequest(`/${H}/cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return pv.parse(n)}async updateMobileStepCaches(e,t){await this.sendRequest(`/${H}/mobile-cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getMobileStepCacheForTest(e,t){let n=await this.sendRequest(`/${H}/mobile-cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return mv.parse(n)}async queueTests(e){let t=await this.sendRequest(`/${H}/tests/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return cv.parse(t)}async uploadScreenshot(e){let t=await this.sendRequest(`/${H}/screenshots`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return bv.parse(t)}async getAllEnvironments(){let e=await this.sendRequest(`/${H}/environments`,{method:"GET",retries:3,requestTimeoutMs:5e3});return vv.parse(e)}async acquireCacheLock(e,t){let n=await this.sendRequest(`/${H}/result-cache/lock`,{method:"POST",body:e,signal:t,retries:3,requestTimeoutMs:3e4});return Fv.parse(n)}async releaseCacheLock(e){await this.sendRequest(`/${H}/result-cache/lock`,{method:"DELETE",body:{key:e},retries:3,requestTimeoutMs:5e3})}async deleteCacheResult(e){await this.sendRequest(`/${H}/result-cache/entry`,{method:"DELETE",body:e,retries:3,requestTimeoutMs:5e3})}async setCacheResult(e){await this.sendRequest(`/${H}/result-cache/entry`,{method:"PATCH",body:e,retries:3,requestTimeoutMs:5e3})}async getCacheResult(e){try{return await this.sendRequest(`/${H}/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(`/${H}/suites/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return Rv.parse(t)}async bulkGetRunGroupStatus(e){let t={runGroupIds:e},n=await this.sendRequest(`/${H}/run-groups/status`,{method:"POST",body:t,retries:3,requestTimeoutMs:5e3});return Lb.array().parse(n)}async uploadProposedSteps(e,t){try{await this.sendRequest(`/${H}/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(`/${H}/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(`/${H}/test-fragments/${e}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Av.parse(t)}async patchTestFragment(e,t){await this.sendRequest(`/${H}/test-fragments/${e}`,{method:"PATCH",body:t,retries:3,requestTimeoutMs:1e4})}async getPastTestResults(e,t){let n=await this.sendRequest(`/${H}/results/tests/${e}`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return wv.parse(n)}async generateTestResultsUploadUrl(){let e=await this.sendRequest(`/${H}/results/uploads`,{method:"POST",retries:3,requestTimeoutMs:1e4});return Cv.parse(e)}async startProcessingResultsUpload(e,t){let n=await this.sendRequest(`/${H}/results/uploads/${e}/process`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return xv.parse(n)}async fetchIconKnowledgeBase(e){try{let t=await this.sendRequest(`/${H}/knowledge-base/icons`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Gv.parse(t)}catch(t){return e.error({err:t},"Failed to fetch icon knowledge base"),null}}async saveNewIcons(e,t){try{await this.sendRequest(`/${H}/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(`/${H}/git/github/${e}/${t}/merge-base-commit?${i.toString()}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ul.parse(a)}async getCommitFromGithub(e,t,n){let o=await this.sendRequest(`/${H}/git/github/${e}/${t}/commits/${n}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ul.parse(o)}async getMergedBranchFromGithub(e,t,n,o){let i=encodeURIComponent(n),a=await this.sendRequest(`/${H}/git/github/${e}/${t}/${i}/${o}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return qh.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(`/${H}/git/gitlab/${i}/merge-base-commit?${o.toString()}`,{method:"GET",retries:3,requestTimeoutMs:5e3});return ul.parse(a)}async getCommitFromGitlab(e,t){let n=encodeURIComponent(e),o=await this.sendRequest(`/${H}/git/gitlab/${n}/commits/${t}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ul.parse(o)}async getMergedBranchFromGitlab(e,t,n){let o=encodeURIComponent(t),i=encodeURIComponent(e),a=await this.sendRequest(`/${H}/git/gitlab/${i}/${o}/${n}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return qh.parse(a)}async getAgentConfig(){let e=await this.sendRequest(`/${H}/web-agent/agent-config`,{method:"GET",retries:3,requestTimeoutMs:5e3});return sg.record(sg.string(),sg.string()).parse(e)}async getQuarantinedTests(){let e=await this.sendRequest(`/${H}/quarantine`,{method:"GET"});return _v.parse(e)}async quarantineTest(e,t,n){await this.sendRequest(`/${H}/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(`/${H}/quarantine/${e.id}`,{method:"DELETE",body:{testName:e.name,reason:t,...n??{}},retries:3,requestTimeoutMs:1e4})}async createAndroidEmulator(e){let t=await this.sendRequest(`/${H}/limbar/android`,{method:"POST",retries:3,body:e,requestTimeoutMs:9e4,initialRetryDelayMs:5e3,maxRetryDelayMs:15e3});return Mv.parse(t)}async extendAndroidEmulatorTtl(e){try{await this.sendRequest(`/${H}/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(`/${H}/limbar/android/upload-url`,{method:"POST",retries:3,body:o,requestTimeoutMs:15e3,logResponse:!0});return Iv.parse(i)}async deleteAndroidEmulator(e){await this.sendRequest(`/${H}/limbar/android/${e}`,{method:"DELETE",retries:3,requestTimeoutMs:3e4})}async getAndroidAssets(){let e=await this.sendRequest(`/${H}/limbar/assets`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Pv.parse(e)}async deleteAndroidAsset(e,t){await this.sendRequest(`/${H}/limbar/assets/${e}/${t}`,{method:"DELETE",retries:3,requestTimeoutMs:1e4})}};async function lg(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 Lu=class{apiClient;constructor(e){this.apiClient=e}async reportBillableEvents(e,t){await this.apiClient.reportBillableEvents(e,t)}};var xo=class extends Bt{generator;constructor(e,t){super(e),this.generator=t}async runTemplateMatching(e,t={}){let n=await this.sendRequest(`/${H}/web-agent/template-matching`,{method:"POST",body:e,signal:t?.signal});return _y.parse(n)}async constructIframeRegex(e,t={}){return this.generator.getIframeRegex(e,{abortSignal:t.signal})}};var Pa=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 rU,en as nU}from"@faker-js/faker";var Oa="v1",vn=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 rU({locale:nU}),this.fakerInstance.seed(e.fakerSeed))}async sendAiGenerate(e){let t=typeof e=="string"?{input:e}:e;return this.httpClient.sendRequest(`/${Oa}/tools/ai/generate`,{method:"POST",body:t}).catch(n=>{throw n instanceof tn?new Error(n.rawError):new Error(`Failed to send AI generation: ${n.message}`)})}async sendSms(e){return this.httpClient.sendRequest(`/${Oa}/tools/sms/send`,{method:"POST",body:e}).then(()=>{}).catch(t=>{throw t instanceof tn?new Error(t.rawError):new Error(`Failed to send sms: ${t.message}`)})}async fetchLatestSms(e){return this.httpClient.sendRequest(`/${Oa}/tools/sms/fetchLatest`,{method:"POST",body:e}).catch(t=>{throw t instanceof tn?new Error(t.rawError):t})}async sendEmail(e){return this.httpClient.sendRequest(`/${Oa}/tools/email/send`,{method:"POST",body:e}).then(()=>{}).catch(t=>{throw t instanceof tn?new Error(t.rawError):new Error(`Failed to send email: ${t.message}`)})}async fetchAllEmails(e){return this.httpClient.sendRequest(`/${Oa}/tools/email/fetchAll`,{method:"POST",body:e}).catch(t=>{throw t instanceof tn?new Error(t.rawError):new Error(`Failed to fetch all emails: ${t.message}`)})}async fetchLatestEmail(e){return this.httpClient.sendRequest(`/${Oa}/tools/email/fetchLatest`,{method:"POST",body:e}).catch(t=>{throw t instanceof tn?new Error(t.rawError):new Error(`Failed to fetch latest emails: ${t.message}`)})}};function fR(r,e,t){return fetch(r,{method:"PUT",body:t,headers:{"Content-Type":e}})}var Nu=class{constructor(e){this.client=e}async uploadResultsArchive(e,t){let{uploadUrl:n,id:o}=await this.client.generateTestResultsUploadUrl(),i=await fR(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 mt(r,e,t=!1){return r.length<e?r:r.slice(0,e-3)+(t?"...TRUNCATED...":"[...]")}var Kn={EQUALS:"equals",CONTAINS:"contains",STARTS_WITH:"starts with",EXISTS:"exists"},Yn={EQUALS:"does not equal",CONTAINS:"does not contain",STARTS_WITH:"does not start with",EXISTS:"does not exist"},cg={EXISTS:"exists",VISIBLE:"is visible",ENABLED:"is enabled",EDITABLE:"is editable",FOCUSED:"is focused"},ug={EXISTS:"does not exist",VISIBLE:"is not visible",ENABLED:"is disabled",EDITABLE:"is not editable",FOCUSED:"is not focused"};function SR(r){switch(r.type){case"ELEMENT_CONTENT":return`content ${r.negated?Yn[r.operation]:Kn[r.operation]} '${r.value}'`;case"ELEMENT_ATTRIBUTE":{let t=r.negated?Yn[r.operation]:Kn[r.operation];return r.operation==="EXISTS"?`attribute '${r.attr}' ${t}`:`attribute '${r.attr}' ${t} '${r.value}'`}case"ELEMENT_NAME":{let t=r.negated?Yn[r.operation]:Kn[r.operation];return r.operation==="EXISTS"?`tag name ${t}`:`tag name ${t} '${r.value}'`}case"ELEMENT_STYLE":{let t=r.negated?Yn[r.operation]:Kn[r.operation];return r.operation==="EXISTS"?`style property '${r.property}' ${t}`:`style property '${r.property}' ${t} '${r.value}'`}case"ELEMENT_EXISTENCE":return r.negated?ug[r.condition]:cg[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 lce={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 ku(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 Du(r){let e="";return r.method&&(e=` with method ${r.method}`),`${ku(r.urlMatcher)}${e}`}function aU(r){return`${r.negated?Yn.CONTAINS:Kn.CONTAINS} '${r.value}'`}function sU(r){switch(r.type){case"CONTENT":return aU(r);default:return r.type,""}}function _o(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?mt(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: ${$t(r.target)}`:""}`;case"SCROLL_UP":return`Scroll up ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${$t(r.target)}`:""}`;case"SCROLL_LEFT":return`Scroll left ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${$t(r.target)}`:""}`;case"SCROLL_RIGHT":return`Scroll right ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${$t(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: ${$t(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 ${$t(r.target)}`;case"BLUR":return`Focus ${$t(r.target)}`;case"DRAG":return`Drag ${$t(r.fromTarget)} onto ${$t(r.toTarget)}`;case"MOUSE_DRAG":return r.target?.type==="description"&&r.target.elementDescriptor?`Click and drag ${$t(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: ${$t(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: ${$t(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: ${$t(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?mt(r.code,30):r.code}`;case"AI_ASSERTION":return`Assertion: '${r.assertion}'`;case"VISUAL_DIFF":return`Visual diff against baseline ${r.target?`for element: ${$t(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 ${$t(r.target)} ${SR(r.assertion)}`;case"PAGE_CHECK":return`Check the page ${sU(r.assertion)}`;case"WAIT_FOR_URL":return`Wait for page URL to ${ku(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 ${Du(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 ${Du(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 ${Du(r.requestMatcher)}`:`Set a ${r.name} header for all requests`:"Set a header";case"MOCK_ROUTE":return r.requestMatcher?`Mock requests that ${Du(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 Rn(r){if(Array.isArray(r))return r.map(Rn);if(lU(r)){let e={};return Object.entries(r).forEach(([t,n])=>{n!==void 0&&(e[t]=Rn(n))}),e}return r}function fl(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 yR(r){return r.type==="ELEMENT_EXISTENCE"&&r.negated&&(r.condition==="EXISTS"||r.condition==="VISIBLE")}function La(r){return r.type==="ELEMENT_EXISTENCE"?r.negated?cg[r.condition]:ug[r.condition]:r.negated?Kn[r.operation]:Yn[r.operation]}import{diff as uU}from"deep-object-diff";import{cloneDeep as Hu}from"lodash-es";function wi(r){let e={parentChain:[]};return Fu(r,e),e}function Fu(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||Fu({...r,steps:c.steps},e)&&i)return!0;if(Fu({...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),Fu({...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 ER(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!!cU([r],t,i).result}function cU(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 wi({steps:r,earlyStop:!0,onPresetAction:i,onConditional:i,onSimpleStepContainer:i}),{result:n,parentChain:o}}function bR(r,e){e(r);for(let t in r){let n=r[t];n&&(Array.isArray(n)?Bu(n,e):typeof n=="object"&&bR(n,e))}}function Bu(r,e){for(let t of r)t&&(Array.isArray(t)?Bu(t,e):typeof t=="object"&&bR(t,e))}function dg(r,e){if(r.length>e.length)return dg(e,r);for(let t=0;t<r.length;t++)if(r[t]!==e[t])return!1;return!0}function Uu(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),Uu({...r,results:e.results});break;case"CONDITIONAL":r.onConditional?.(e),e.assertionResult&&r.onPresetAction(e.assertionResult),Uu({...r,results:e.results});break;default:throw new Error(`Unsupported result type: ${e.type}`)}}function Mo(r,e){return!r&&!e?!1:!r||!e?!0:Object.keys(uU(r,e)).length>0}function Na({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=Vn.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=dU(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}=Na({...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}=Na({...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(!Lc.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}=Na({...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}=Na({...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 TR(r,e){return e?`${e}:${r}`:r}function dU(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 pg(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:TR(r.id,e.join(":")),organizationId:r.orgId,value:r.value,testId:r.testId}),n}function vR(r){let e=new Set;return Bu(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 zu({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"&&Nc(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 yl(r,e,t){let n=r.cache&&"memory"in r.cache?r.cache.memory?.traces:void 0;Mo(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 RR({steps:r}){let e={};return wi({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=TR(o.id,i),s=Vn.parse(o);e[a]=s},onSimpleStepContainer:(t,n)=>{},onConditional:(t,n)=>{}}),e}function Sl(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 pU(r,e){return Mo(r.memory,e.memory)?{...r,memory:e.memory,updatedAt:e.updatedAt}:r}function mg(r,e){return r?Mo(r.target.memory,e.target.memory)?{target:{...r.target,memory:e.target.memory},updatedAt:e.updatedAt}:r:{target:Sl(e.target),updatedAt:e.updatedAt}}function mU(r,e){let t=Hu(r);return t.fromTarget?Mo(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=Sl(t.fromTarget),t.updatedAt=e.updatedAt)),t.toTarget?Mo(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=Sl(t.toTarget),t.updatedAt=e.updatedAt)),t}function AR({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;Mo(s,a.memory)&&(o.value.cache=pU(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(Mo(s,a.target.memory)){let c=Sr.safeParse(o.value.cache);o.value.cache=mg(c.data,a),n.push(o)}}else if("fromTarget"in a||"toTarget"in a){let s=vm.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};Mo(l,c)&&(o.value.cache=mU(s,a),n.push(o))}}return n}async function Gu({cacheStorage:r,logger:e,schemaVersion:t,stepLists:n,testId:o}){let i=Hu(n.steps),a=Hu(n.beforeSteps)??void 0,s=Hu(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 wR(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 Gde}from"lodash-es";import hg from"semver";function ju(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(!hg.valid(t.toVersion)||!hg.valid(t.fromVersion))throw new Error(`Migration '${t.name}' has invalid version`);if(!hg.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 hU from"diff-lines";import gU,{gte as fU}from"semver";function SU(r){return r.every(e=>e&&typeof e=="object"&&!Array.isArray(e))}async function gg({metadata:r,steps:e,logger:t,toVersion:n,migrations:o}){let i=e,{schemaVersion:a,id:s}=r,c=o.findIndex(d=>gU.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&&fU(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 CR(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=hU(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 CR(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)||SU(i)&&(n[o]=await CR(i,e))}return t}var xR={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 yU=[xR];ju(qm,yU);var _R={name:"Migrate to ai step v2",fromVersion:"1.0.4",toVersion:"1.0.5",recursiveKeys:new Set(["results","commands"]),stopOnFailure:!0,execute:async r=>(r=r.filter(e=>!(e.status!==void 0&&e.type==="AI_ACTION")),r=r.map(e=>(e.status===void 0||e.type==="PRESET_ACTION"&&(e.results=e.commands??e.results??[]),e)),r)};var MR={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 EU=["target","fromTarget","toTarget"];function IR(r){for(let e of EU){if(r[e]===void 0)continue;let t=r[e];t.elementDescriptor!==void 0?t.type="description":r[e]={type:"description",elementDescriptor:""}}}var PR={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 IR(e.command),e;case"AI_ACTION":{let t=e.commands;for(let n of t??[])IR(n);return e}default:return e}})};import{v4 as bU}from"uuid";var OR={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=bU()),e;default:return e}})};import{v4 as LR}from"uuid";var NR={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??LR(),e}case"AI_ACTION":return e.commands&&(e.steps=e.commands.map(t=>({type:"PRESET_ACTION",command:{...t,id:t.id??LR()}})),delete e.commands),e;default:return e}})};var DR={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 TU}from"uuid";var kR={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=TU()),e))};import{v4 as FR}from"uuid";var UR={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=FR())}return e.id=FR(),e})};var BR={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 vU}from"uuid";var HR={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=vU()),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 zR={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 GR={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&&jR(t),e})};function jR(r){r&&Object.keys(r).forEach(e=>{if(typeof r[e]=="object"&&r[e]){jR(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 VR={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 $R={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 WR={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 qR={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 KR={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 YR={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 XR={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 Vu=new Set(["CLICK","TYPE","SELECT_OPTION"]),JR={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||Vu.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||Vu.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||Vu.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||Vu.has(m))&&(d.target={elementDescriptor:p??""})})}),e}),stopOnFailure:!0};var QR={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 ZR={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 eA=[XR,QR,ZR,JR,_R,MR,PR,OR,NR,DR,kR,UR,BR,HR,zR,GR,VR,$R,WR,qR,KR,YR];ju(Ce,eA);async function Da({metadata:r,steps:e,logger:t,toVersion:n}){return await gg({metadata:r,steps:e,logger:t,toVersion:n,migrations:eA})}import{cloneDeep as tpe}from"lodash-es";import{v4 as cpe}from"uuid";import{cloneDeep as AU}from"lodash-es";import aA from"truncate-json";import{v4 as tA}from"uuid";import{cloneDeep as Rpe,unset as Ape}from"lodash-es";function rn(r){switch(r.type){case"AI_ACTION":return`AI action: ${mt(r.text,100)}`;case"AI_ACTION_DYNAMIC":return`AI action: ${mt(r.text,100)}`;case"PRESET_ACTION":return _o(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: ${mt(r.description,100)}`:""}`;default:return(t=>{throw new Error("You missed a case in the switch above")})(r)}}function ka(r,e){return r.split(`
|
|
35
35
|
`).map(t=>" ".repeat(e)+t).join(`
|
|
@@ -43,7 +43,7 @@ ${o}`:o)(fg(r))}function xU(r,{unflattenedIndex:e,parentStep:t}){if(!(e===void 0
|
|
|
43
43
|
${n}`}function GU(r){let e=zU(r);return wi({steps:e,earlyStop:!1,onPresetAction:t=>{bg(t);let n;if(Nc(t.command)&&t.command.cache!==void 0){let i=VU(t.command.cache);i&&"target"in i&&(n=i.target)}let o=t.command;return n!==void 0?o.cache=n:delete o.cache,o.thoughts&&delete o.thoughts,delete o.id,"index"in t&&delete t.index,!1},onConditional:t=>(bg(t),!1),onSimpleStepContainer:t=>{if(t.type==="AI_ACTION"){let n=t,o=t.text;return Object.keys(n).forEach(i=>{delete n[i]}),n.type="AI_ACTION_DYNAMIC",n.text=o,!1}if(bg(t),t.type==="RESOLVED_MODULE"){let n=t;delete n.cacheConfig,delete n.enabled,delete n.defaultCacheKey,delete n.defaultCacheTtl,delete n.defaultCacheAllInvocations,delete n.autoAuth,delete n.advanced}return!1}}),e}function bg(r){let e=r;delete e.aiSuggested,delete e.id,delete e.retries,delete e.skipped}function jU(r){return r.selector?r.selector:r.generatedSelectors?.[0]}function Tg(r){let e=jU(r),t=r.nodeOnlySerializedHtml,n={};return e&&(n.selector=e),t&&(n.nodeOnlySerializedHtml=t),Object.keys(n).length?n:void 0}function VU(r){if(!r)return;let e={};if("target"in r)return{target:Tg(r.target)};if("fromTarget"in r||"toTarget"in r){let t=r.fromTarget?Tg(r.fromTarget):void 0,n=r.toTarget?Tg(r.toTarget):void 0;return t&&(e.fromTarget=t),n&&(e.toTarget=n),Object.keys(e).length?e:void 0}}function Io({orgId:r,client:e,gitMetadata:t,regenerateCache:n,alwaysSaveCache:o,noCache:i,bustOldestCachePercentage:a}){return i?new Cu:new vg(r,e,t,{regenerateCache:n,alwaysSaveCache:o,bustOldestCachePercentage:a})}var vg=class{constructor(e,t,n,o){this.orgId=e;this.client=t;let{regenerateCache:i,alwaysSaveCache:a,bustOldestCachePercentage:s}=o,{gitBranchName:c,gitProtectedBranches:l}=n;this.cacheHeaders=Vh(n),this.readCaches=!i;let u=c&&l.includes(c);a||!u?this.writeCaches=!0:this.writeCaches=!1,u||(this.bustOldestCachePercentage=s)}cacheHeaders;readCaches;writeCaches;bustOldestCachePercentage;async saveStepCacheEntries({entries:e,testId:t,logger:n}){if(!this.writeCaches){n.debug("Skipping cache storage because branch is protected");return}try{await this.client.updateStepCaches({entries:e,testId:t},this.cacheHeaders)}catch(o){n.error({err:o},"Failed to save step cache entries")}}async resolveStepCacheEntries(e){if(!this.readCaches){e.logger.debug("Skipping cache resolution because of regenerate flag");return}let{steps:t,beforeSteps:n,afterSteps:o}=e.stepLists,i=await this.client.getStepCacheForTest({testId:e.testId},this.cacheHeaders);if(!this.writeCaches){e.logger.debug("Skipping cache last used at update because branch is protected");return}if(this.bustOldestCachePercentage!==void 0){let s=Object.entries(i).map(([u,d])=>({key:u,time:d.value.cache?.updatedAt?.getTime()??0}));s.sort((u,d)=>u.time-d.time);let c=s.length,l=Math.max(1,Math.floor(c*this.bustOldestCachePercentage/100));s.slice(0,l).forEach(({key:u})=>{delete i[u]}),e.logger.info({nCachesToBust:l,bustOldestCachePercentage:this.bustOldestCachePercentage,totalCaches:c},"Busted oldest caches")}for(let s of[t,n,o])s&&Na({steps:s,stepCacheEntries:i,logger:e.logger});let{cachesToSave:a}=await nt({stepLists:e.stepLists,cacheCreationParams:{testId:e.testId,orgId:this.orgId}});this.client.updateStepCaches({entries:a,testId:e.testId},this.cacheHeaders)}};import $U from"path";var WU=new Ou(30,60*1e3),Cg="https://api.momentic.ai",Ag,AA=r=>{Cg=r},Er=()=>Cg,wA=()=>Ag;var za,wg,od,CA=async r=>{if(Ag&&za&&od)return za;let e=new Qe({baseUrl:Cg,apiKey:r,logger:E});Ag=e;try{let t=await e.getAuthInfo();return za=t.orgId,wg=t.userId,od=r,za}catch(t){throw new Error(`Error checking API key against server: ${t}`)}},wt=()=>{if(!za)throw new Error("Your organization ID is invalid.");return za},Po=()=>{if(!wg)throw new Error("Your user ID is invalid.");return wg},br=()=>{if(!od)throw new Error("Your API key is invalid.");return od},xg,Rg,id=(r,e)=>{xg=r,Rg?.abort(),Rg=new AbortController;let t=Rg.signal,n=[r.configFilePath];r.config.environments?.forEach(o=>{if(!o.envFile)return;let i=$U.resolve(r.rootDir,o.envFile);try{if(nd.lstatSync(i).isSymbolicLink())return;nd.existsSync(i)&&n.push(i)}catch(a){E.warn({err:a},`Failed to check if env file ${i} exists`)}});try{qU({filesToWatch:n,revalidator:e,signal:t,project:r})}catch(o){E.error({err:o},"Failed to start config file watchers")}},se=()=>xg;function qU({filesToWatch:r,revalidator:e,signal:t,project:n}){E.debug("Starting watch on the following files:"),r.forEach(o=>{E.debug(`- ${o}`)}),r.forEach(o=>{let i=async(s,c)=>{s.mtime.getTime()!==c.mtime.getTime()&&(WU.increment("setLocalProject")&&E.warn(`A file change under the ${n.rootDir} directory has caused Momentic to reload its configuration more than 30 times in the last minute. Rapid changes to files may indicate your momentic.config.yaml 'include' glob is incorrect. Please ensure temporary, library, and auto-generated files are not included in Momentic's context.`),xg=await Promise.resolve(e(n.configFilePath)))};nd.watchFile(o,{persistent:!1},i);let a=()=>{nd.unwatchFile(o,i),t.removeEventListener("abort",a)};t.addEventListener("abort",a),process.once("SIGUSR2",()=>{a(),process.kill(process.pid,"SIGUSR2")})})}function Me(r){return function(...e){let t=e[e.length-1],n=r(...e);Promise.resolve(n).catch(t)}}var Rl=KU();function vl(r){let e=se(),t=Ot.dirname(e.configFilePath);return Ot.join(t,...r)}function XU(r){let e=se(),t=Ot.dirname(e.configFilePath),n=Ot.relative(t,r);return n?n.split(Ot.sep):[]}function JU(r,e){let t=ar.statSync(r),n=XU(r);return kh.parse({name:e,absolutePath:r,relativePath:n.join(Ot.sep),pathSegments:n,isDirectory:t.isDirectory(),size:t.size,createdAt:t.birthtime,modifiedAt:t.mtime,accessedAt:t.atime})}Rl.post("/",Me(async(r,e,t)=>{let n;try{n=GT.parse(r.body).pathSegments}catch(d){e.status(400).json({error:`Failed to parse folder read body: ${d}`});return}let o=vl(n);if(!ar.existsSync(o)){e.status(404).json({error:`Path not found: ${n.join(Ot.sep)}`});return}if(!ar.statSync(o).isDirectory()){e.status(400).json({error:`Path is not a directory: ${n.join(Ot.sep)}`});return}let a=se(),s=Array.from(a.config.exclude??[]).concat(Tu),l=YU("*",{absolute:!1,cwd:o,ignore:s,dotRelative:!1,maxDepth:1,nodir:!1}).map(d=>{let p=Ot.join(o,d);return JU(p,d)}),u={absolutePath:o,pathSegments:n,contents:l};e.status(200).json(u)}));Rl.put("/",Me(async(r,e,t)=>{let n;try{n=jT.parse(r.body).pathSegments}catch(a){e.status(400).json({error:`Failed to parse folder create body: ${a}`});return}let o=vl(n);if(ar.existsSync(o)){e.status(200).json({success:!0,message:`Folder already exists: ${n.join(Ot.sep)}`,pathSegments:n});return}ar.mkdirSync(o,{recursive:!0});let i={success:!0,message:`Folder created: ${n.join(Ot.sep)}`,pathSegments:n};e.status(201).json(i)}));Rl.patch("/",Me(async(r,e,t)=>{let n,o;try{let l=VT.parse(r.body);n=l.pathSegments,o=l.newPathSegments}catch(l){e.status(400).json({error:`Failed to parse folder update body: ${l}`});return}let i=vl(n),a=vl(o);if(!ar.existsSync(i)){e.status(400).json({error:`Folder not found: ${n.join(Ot.sep)}`});return}if(ar.existsSync(a)){e.status(400).json({error:`Destination already exists: ${o.join(Ot.sep)}`});return}let s=Ot.dirname(a);ar.existsSync(s)||ar.mkdirSync(s,{recursive:!0}),ar.renameSync(i,a);let c={success:!0,message:`Folder moved from ${n.join(Ot.sep)} to ${o.join(Ot.sep)}`,pathSegments:o};e.status(200).json(c)}));Rl.delete("/",Me(async(r,e,t)=>{let n,o=!0;try{let c=$T.parse(r.body);n=c.pathSegments,o=c.recursive??!0}catch(c){e.status(400).json({error:`Failed to parse folder delete body: ${c}`});return}let i=vl(n);if(!ar.existsSync(i)){e.status(200).json({success:!0,message:`Folder not found: ${n.join(Ot.sep)}`,pathSegments:n});return}if(!ar.statSync(i).isDirectory()){e.status(400).json({error:`Path is not a directory: ${n.join(Ot.sep)}`});return}if(o)ar.rmSync(i,{recursive:!0,force:!0});else{if(ar.readdirSync(i).length>0){e.status(409).json({error:`Cannot delete non-empty directory without recursive flag: ${n.join("/")}`});return}ar.rmdirSync(i)}let s={success:!0,message:`Folder deleted: ${n.join("/")}`,pathSegments:n};e.status(200).json(s)}));var _g=Rl;import{Router as rH}from"express";import{diff as tB}from"deep-object-diff";import on from"fs";import Ii from"path";import Ga from"yaml";import{z as MA}from"zod";import{execSync as QU}from"child_process";function Xn(r,e){let t=e.hooks?.postSave;if(!t)return;let n;t.includes("$1")?n=t.replaceAll("$1",r):n=`${t} ${r}`,E.debug({postSaveCommand:n},"Executing post-save hook command");try{QU(n,{encoding:"utf-8"})}catch(o){E.warn({err:o,postSaveCommand:n},"Failed to execute post-save hook command, continuing...")}}import{diff as xA}from"deep-object-diff";import An from"fs";import{cloneDeep as ZU}from"lodash-es";import Al from"path";import{v4 as eB}from"uuid";import wl from"yaml";function Tr({content:r,schemaVersion:e,momenticFiles:t,project:n,forceSaveOnNoDiffs:o}){let i=t.modules[r.moduleId]?.fullFilePath;if(!i||!An.existsSync(i))throw new Error(`Tried to update module ${r.moduleId} that could not be found on disk`);let a=An.readFileSync(i,"utf-8"),s=wl.parse(a),c;if(r.name&&r.name!==s.name){let m=`${Ue(r.name)}.module.yaml`;if(c=Al.join(Al.dirname(i),m),An.existsSync(c))throw new Error(`A conflicting file '${r.name}' already exists at path '${c}'`)}let l={...r,schemaVersion:e},u=Rn({fileType:he.MODULE,...Bh.parse(l),steps:Je.array().parse(r.steps)}),d=xA(u,s);if(d&&Object.keys(d).length===0&&!o){E.debug(`Skipping save for module ${r.moduleId} since there are no changes`);return}let p=wl.stringify(u);An.writeFileSync(i,p,"utf-8"),c&&An.renameSync(i,c),Xn(c||i,n.config)}function _A({moduleId:r,content:e,momenticFiles:t,project:n,logger:o}){let i=t.modules[r]?.fullFilePath;if(!i)throw new Error(`Tried to update module ${r} that could not be found on disk`);let a=Jn(i,o),s={...a,...e},c=Rn({fileType:he.MODULE,...Bh.parse(s),steps:a.steps}),l=xA(c,a);if(l&&Object.keys(l).length===0){E.debug(`Skipping save for module ${r} since there are no changes`);return}let u=wl.stringify(c);An.writeFileSync(i,u,"utf-8");let d;if(e.name){let p=`${Ue(e.name)}.module.yaml`;if(d=Al.join(Al.dirname(i),p),An.existsSync(d))throw new Error(`Module with name '${e.name}' already exists at path '${d}'`);An.renameSync(i,d)}Xn(d||i,n.config)}async function ad({name:r,description:e,enabled:t,steps:n,folder:o,project:i}){let a=Ue(r),s=Al.join(o,`${a}.module.yaml`),c=eB(),{stepsToSave:l}=await nt({stepLists:{steps:n}}),u={fileType:he.MODULE,schemaVersion:Ce,moduleId:c,name:r,description:e,enabled:t,steps:l.steps},d=wl.stringify(u);return An.writeFileSync(s,d,"utf-8"),Xn(s,i.config),{moduleId:c,name:r,description:e,enabled:t,steps:n}}function Jn(r,e){let t=An.readFileSync(r,"utf-8"),n=wl.parse(t);try{return wh.parse(n)}catch(o){throw e.error({err:o,moduleFilePath:r,moduleContents:t},`${r} does not parse as a valid Momentic module`),o}}async function nn(r,e,t,n){let o=Jn(r.fullFilePath,t),{resolvedSteps:i}=await Xu({rawSteps:o.steps,migrationMetadata:{id:o.moduleId,schemaVersion:o.schemaVersion},resolvedModuleCache:n,logger:t,callbacks:{onFetchModule:async({id:s})=>{let c=e.modules[s]?.fullFilePath;if(c)return Jn(c,t)}}}),a={...o,steps:i};return n&&(n[r.id]=ZU(a)),a}async function sd(r,e){let t={};return await Promise.all(Object.values(r.modules).map(async n=>{await nn(n,r,e,t)})),Array.from(Object.values(t))}async function IA({test:r,name:e,folder:t}){let n=await yA({test:r});if(Object.keys(n.modules).length)throw new Error("A brand new test should not contain any modules in it");let i=`${Ue(e)}.test.yaml`,a=Ii.join(t,i);return on.writeFileSync(a,n.test,"utf-8"),a}function Mg(r,e,t){let n=Ii.join(t.rootDir,r);if(!on.existsSync(n))throw new Error(`Test not found at path '${r}' in project '${t.rootDir}'`);let o=on.readFileSync(n,"utf-8"),i=Ga.parse(o),a,s;if(e.name&&e.name!==i.name){let p=`${Ue(e.name)}.test.yaml`;if(a=Ii.join(Ii.dirname(r),p),s=Ii.join(t.rootDir,a),on.existsSync(s))throw new Error(`Test with name '${e.name}' already exists at path '${s}'`)}let c={...i,...e},l=Dr.parse(c),u={fileType:he.TEST,...Dr.parse(l),beforeSteps:i.beforeSteps??void 0,steps:i.steps,afterSteps:i.afterSteps??void 0},d=Ga.stringify(u);return on.writeFileSync(n,d,"utf-8"),s&&on.renameSync(n,s),Xn(n,t.config),{newRelativeTestPath:a}}function mr({relativeTestPath:r,steps:e,schemaVersion:t,project:n,forceSaveOnNoDiffs:o}){let i=Ii.join(n.rootDir,r);if(!on.existsSync(i))throw new Error(`Test not found at path '${r}' in project '${n.rootDir}'`);let a=on.readFileSync(i,"utf-8"),s=Ga.parse(a),c=Dr.parse({...s,schemaVersion:t}),l=Je.array().or(MA.undefined()).parse(e.beforeSteps),u=Je.array().parse(e.steps),d=Je.array().or(MA.undefined()).parse(e.afterSteps),p=Rn({fileType:he.TEST,...c,beforeSteps:l&&l.length>0?l:void 0,steps:u,afterSteps:d&&d.length>0?d:void 0}),m=tB(p,s);if(m&&Object.keys(m).length===0&&!o){E.debug(`Skipping save for test ${c.name} since there are no changes`);return}let h=Ga.stringify(p);on.writeFileSync(i,h,"utf-8"),E.debug(`Saving test ${c.name} to ${i}`),Xn(i,n.config)}function Cl(r,e){let t=Ii.join(e.rootDir,r);if(!t)throw new Error(`Could not find test with path ${r} in Momentic project (${e.rootDir})`);let n;try{n=on.readFileSync(t,"utf8"),n=n.replace(/\r\n|\r/g,`
|
|
44
44
|
`)}catch(i){throw new Error(`Could not read test file ${t}: ${i}`)}let o;try{o=Ga.parse(n)}catch(i){throw new Error(`Could not parse test file ${t} as YAML: ${i}`)}return Yt.parse(o)}function Pi(r,e,t){let n=t.project.rootDir,o;try{o=on.readFileSync(r,"utf-8")}catch(a){throw e.error({err:a,projectRoot:n},a.message),new Error(a.message)}let i=Ga.parse(o);if(!i.steps||!Array.isArray(i.steps))throw new Error(`Test ${r} is missing steps`);return i}async function ut(r,e,t){let n=Pi(r,e,t),o;try{o=Dr.parse(n)}catch(a){throw new Error(`Test ${r} is missing metadata or has invalid metadata: ${a}`)}let{resolvedTest:i}=await fA({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 Jn(c,s)}}});return i}import rB from"@dotenvx/dotenvx";import nB from"fs";import PA from"path";function ld(r,e){return(r.config.environments??[]).map(t=>Oi(t.name,r,e))}function OA(r){return r.includes("${")?r.replace(/\$\{([^}]+)\}/g,(e,t)=>{let[n,o]=t.split(/:-|-/,2),i=process.env[n];return t.includes(":-")?i&&i!==""?i:o||"":t.includes("-")?i!==void 0?i:o||"":i||""}):r}function oB(r){let{envVariables:e,project:t}=r;if(!e)return{};let n={};for(let[o,i]of Object.entries(e)){if(typeof i=="string"){let s=OA(i);s&&(n[o]=s);continue}let a;try{a=nB.readFileSync(PA.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=rB.config({path:PA.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 Oi(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={[Tt]:OA(n.baseUrl)},i=oB({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 yB,readFileSync as EB,readdirSync as bB,writeFileSync as TB}from"fs";import{glob as vB}from"glob";import Li,{dirname as DA}from"path";import{cwd as Ng}from"process";import kA from"yaml";import{z as We}from"zod";import LA from"fs";import{glob as aB}from"glob";import xl from"path";import sB from"yaml";import{z as Ig}from"zod";var NA=!1,Pg=["**/*.test.yaml","**/*.module.yaml"],Og=Ig.string().refine(r=>/^[a-zA-Z0-9-]+$/.test(r)),Lg=15,lB=Ig.object({fileType:Ig.nativeEnum(he)});async function Z(r,e=!1){let t={project:r,tests:{},modules:{},mobileTests:{},mobileModules:{},duplicateEntities:{}},n=r.config.include??Pg,o=Array.from(r.config.exclude??[]).concat(Tu),i=AbortSignal.timeout(5e3),a;try{a=await aB(n,{absolute:!1,cwd:r.rootDir,ignore:o,dotRelative:!1,maxDepth:Lg,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=cB(r.rootDir,s,t,e?bn:E);c&&(t.duplicateEntities[c.id]=c.paths)}return NA=!0,t}function cB(r,e,t,n){let o=xl.join(r,e),i=uB(o,n);if(!i)return;let a=dB(i,o,n);if(!a)return;let s=lB.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=pB(o,n);if(!l)return;let u=mB(e,o,l);switch(c){case he.TEST:try{return hB(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic test metadata: ${d}`);return}case he.MODULE:try{return gB(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic module metadata: ${d}`);return}case he.MOBILE_TEST:try{return SB(a,t,u,o,n)}catch(d){n.warn(`Skipping file '${o}' because it is missing Momentic mobile test metadata: ${d}`);return}case he.MOBILE_MODULE:try{return fB(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 uB(r,e){try{return LA.readFileSync(r,"utf-8")}catch(t){e.warn(`Could not read possible Momentic file at ${r}, skipping: ${t}`);return}}function dB(r,e,t){try{let n=sB.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 pB(r,e){try{return LA.statSync(r)}catch(t){e.warn(`Skipping path '${r}' because it could not be stat, skipping: ${t}`);return}}function mB(r,e,t){return{relativePath:r,fullFilePath:e,platformSep:xl.sep,fullPathSegments:e.split(xl.sep),relativePathSegments:r.split(xl.sep),fileName:xl.basename(e),lastModified:t.mtime,createdAt:t.birthtime}}function hB(r,e,t,n,o){let i=Dr.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:he.TEST,name:i.name,id:i.id,description:i.description??void 0,labels:i.labels,...t},a}function gB(r,e,t,n,o){let i=ur.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:he.MODULE,name:i.name,id:i.moduleId,description:i.description??void 0,...t};let s=t.fileName.replace(".module.yaml","");return!NA&&Ue(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 fB(r,e,t,n,o){let i=fu.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:he.MOBILE_MODULE,name:s,id:i.moduleId,description:i.description??void 0,...t},a}function SB(r,e,t,n,o){let i=wa.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:he.MOBILE_TEST,name:s,id:i.id,description:i.description??void 0,...t},a}var ja="momentic.config.yaml",Dg="momentic.workspace.yaml",RB=We.object({projects:We.string().array().describe("list of glob patterns to find project (momentic.config.yaml) files")}),AB=We.union([We.string(),We.object({fromFile:We.string(),json:We.boolean().optional()})]),wB=We.object({name:Og,baseUrl:We.string().optional().describe("Optional for mobile tests"),envFile:We.string().optional().describe("path to a file on disk to read environment variables from. can be relative to project root or absolute."),envVariables:We.record(We.string(),AB).optional(),inheritFromShell:We.boolean().optional().describe("inherit all environment variables from the shell - might be noisy"),browser:pi.optional().describe("NB: most things should use project-level configuration only")}),CB=We.object({postSave:We.string().optional()}),xB=We.object({name:Og,include:We.string().array().optional().describe("list of glob patterns that match momentic files (optional)"),exclude:We.string().array().optional().describe("opposite of include, takes precedence over include"),goldenFileDir:We.string().optional(),reporterDir:We.string().optional(),outputDir:We.string().optional(),recordVideo:We.boolean().optional(),retries:We.number().optional().describe("number of retries per test"),parallel:We.number().optional().describe("degree of parallelism"),environments:We.array(wB).optional(),gitMainBranch:We.string().optional(),gitProtectedBranches:We.string().array().optional(),ai:Hh.optional(),browser:pi.optional(),emulator:_h.optional(),advanced:zh.optional(),hooks:CB.optional()});function FA(r,e){let t;try{t=EB(r,"utf-8")}catch(o){E.warn(`Could not read possible Momentic ${e} file at ${r}: ${o}`);return}let n;try{if(n=kA.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 kg(r){let e=FA(r,"project configuration");if(e!==void 0)try{return xB.parse(e)}catch(t){E.warn(`Possible Momentic project configuration file at ${r} does not adhere to the required schema: ${t}`);return}}function _B(r){let e=FA(r,"workspace configuration");if(e!==void 0)try{return RB.parse(e)}catch(t){E.warn(`Possible Momentic workspace configuration file at ${r} does not adhere to the required schema: ${t}`);return}}function MB(){let r=[],e=Ng(),t=Li.parse(e).root,n=15,o=0;for(;o<n;){o++;let i=Li.basename(e);if(bu.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 bB(e))if(a.endsWith(ja)){let s=Li.join(e,a),c=kg(s);c&&r.push({configFilePath:s,config:c,rootDir:DA(s)})}if(r.length)return r;if(e=Li.dirname(e),e===t)break}return r}async function Ct(r={}){let{configFilePath:e,nameFilter:t}=r,n=await Fg(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 IB(r){let e=_B(r);if(!e||!e.projects||!e.projects.length)return;let t=e.projects.map(a=>(a.endsWith("/")||(a+="/"),`${a}*${ja}`)),n=AbortSignal.timeout(2e3),o;try{o=await vB(t,{absolute:!1,cwd:Ng(),dotRelative:!1,maxDepth:Lg,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 ${Dg} is misconfigured.`),a}let i=[];for(let a of o){let s=Li.join(Ng(),a),c=kg(s);c&&i.push({configFilePath:s,config:c,rootDir:DA(s)})}return i}async function Fg(r){if(r){r=Li.resolve(r);let t=kg(r);return t||(console.error(`No valid Momentic project file found at ${r}.`),process.exit(1)),[{config:t,configFilePath:r,rootDir:Li.dirname(r)}]}if(yB(Dg)){let t=await IB(Dg);if(t)return t}return MB()}function Oo(r,e){let t=kA.stringify(r);TB(e,t)}import Va from"fs";import Ug from"path";import{z as Bg}from"zod";var UA="golden/visual-diff",BA="reports",HA="test-results";var PB=Bg.object({width:Bg.number(),height:Bg.number()}),$a=class{defaultGoldenScreenshotDir;regenerateGoldenFiles;constructor(e,t){let n=Ug.join(e.rootDir,e.config.goldenFileDir??UA);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=Ug.join(this.defaultGoldenScreenshotDir,`${t.id}.jpg`));let i=`${o}.metadata.json`;if(this.regenerateGoldenFiles)return Va.mkdirSync(Ug.dirname(o),{recursive:!0}),Va.writeFileSync(o,n.buffer),Va.writeFileSync(i,JSON.stringify({width:n.width,height:n.height})),{buffer:Buffer.from(n.buffer),width:n.width,height:n.height};if(Va.existsSync(o)){let a=Va.readFileSync(o),s=PB.parse(JSON.parse(Va.readFileSync(i,"utf-8")));return{buffer:a,width:s.width,height:s.height}}else throw new _("UserConfigurationError",`Cannot execute visual diff without a saved baseline screenshot at ${o}`)}};import{execFile as OB}from"node:child_process";import{promisify as LB}from"node:util";import NB from"simple-git";var qe=NB(),zA=LB(OB);async function DB(r){let e=await Ze(r,qe.raw(["config","--list"])),t={};if(!e)return t;for(let n of e.split(`
|
|
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 kB(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 zA("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 zA("gh",o,{timeout:5e3}),a=i?.toString().trim();if(a)return a}catch{}}}async function FB(r,e,t){let n=e?.includes("github.com"),o=e?.includes("gitlab.com");try{if(n)return kB(r,e,t);if(o)return}catch{}}function cd(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 Ze(r,e){try{return(await e).trim()}catch(t){r.error({err:t},"Failed to run git command");return}}function UB(){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 BB(r){let[e,t,n]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.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 HB(r){let[e,t,n]=await Promise.all([Ze(r,qe.listRemote(["--get-url","origin"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.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 zB(r){let[e,t,n,o]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.listRemote(["--get-url","origin"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"]))]),i=process.env.CIRCLE_REPOSITORY_URL??t,a=i?.includes("github.com"),s=i?.includes("gitlab.com"),c=i?cd(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 GB(r){let[e,t,n]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"]))]),o=process.env.BUILDKITE_REPO,i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?cd(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 jB(r){let[e,t,n]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"]))]),o=process.env["Build.Repository.Uri"],i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?cd(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 VB(r,e){let[t,n,o,i,a,s,c,l,u]=await Promise.all([Ze(r,qe.revparse(["HEAD"])),Ze(r,qe.revparse(["--short","HEAD"])),Ze(r,qe.revparse(["--abbrev-ref","HEAD"])),Ze(r,qe.listRemote(["--get-url","origin"])),Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"])),e?Ze(r,qe.raw(["merge-base","--fork-point",e])):Promise.resolve(void 0),DB(r)]),d=l?await Ze(r,qe.show(["--no-patch","--format=%ci",l])):void 0,p=i?.includes("github.com"),m=i?.includes("gitlab.com"),h=i?cd(i):void 0,g=u["user.email"]||void 0,f=u["user.name"]||void 0,y=u["user.username"]||void 0,S=await FB(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 $B(){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 WB(r){let e=r.config.gitProtectedBranches??[];return r.config.gitMainBranch&&e.push(r.config.gitMainBranch),{gitMainBranch:r.config.gitMainBranch,gitProtectedBranches:e}}async function Qn(r,e){let t=UB();if(!t)return VB(r,e);switch(t){case"GithubActions":return BB(r);case"GitlabCI":return HB(r);case"CircleCI":return zB(r);case"Buildkite":return GB(r);case"AzureDevOps":return jB(r);case"GCPCloudBuild":return $B()}}async function qB(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 KB(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 YB(r,e,t){try{if(t.githubRepository){let[n,o]=t.githubRepository.split("/");return await KB(r,e,n,o,t)}else if(t.gitlabProjectPath)return await qB(r,e,t.gitlabProjectPath,t)}catch(n){r.warn({err:n},"Failed to get remote git metadata")}return t}async function Fr(r,e,t){let n=await WB(t),o=await Qn(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 YB(r,e,i);return{...n,...o,...a}}async function GA(){try{return!!(await qe.show(["--no-patch","--format=%ci"])).trim()}catch{return null}}import{diff as WSe}from"deep-object-diff";import{cloneDeep as KSe}from"lodash-es";import{v4 as aye}from"uuid";import lye from"yaml";import Cye from"yaml";import _ye from"zod";import{randomUUID as XB}from"crypto";import Lo from"fs";import Wa from"path";var jA=new Set([".DS_Store","__MACOSX"]),VA={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 JB(r,e,t){if(VA[t]){let i=VA[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 Hg=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 $A(r,e){try{let t=Wa.join(e,"metadata.json");return xu.parse(JSON.parse(Lo.readFileSync(t,"utf-8")))}catch{throw new Hg(r,e)}}function WA(r,e,t){let n=XB(),o=r.child({runGroupId:n});Lo.rmSync(e,{recursive:!0,force:!0});let i=Lo.readdirSync(t).filter(c=>!jA.has(c)).map(c=>Wa.join(t,c));if(i.length===0)throw new Error(`No run groups found in results path: ${t}`);Lo.mkdirSync(e,{recursive:!0});let a={...$A(t,i[0]),id:n};for(let c of i){let l=Wa.join(c,"runs");if(!Lo.existsSync(l))continue;let u=$A(t,c);o.info({oldRunGroupId:u.id},"Merging run groups");for(let p in u){if(p==="id")continue;let m=p;a[m]=JB(a,u,m)}let d=Lo.readdirSync(l);for(let p of d){if(jA.has(p))continue;let m=Wa.join(l,p),h=Wa.join(e,"runs",p);Lo.cpSync(m,h,{recursive:!0})}}let s=Wa.join(e,"metadata.json");Lo.writeFileSync(s,JSON.stringify(a,null,2))}import qA from"adm-zip";import zg from"fs";import ud from"path";function QB(r){let e=new qA,t=ud.join(r,"metadata.json"),n=xu.parse(JSON.parse(zg.readFileSync(t,"utf-8")));e.addLocalFile(t);for(let o of zg.readdirSync(ud.join(r,"runs"))){if(!o.endsWith(".zip"))continue;let i=o.replace(/\.zip$/,""),a=new qA(ud.join(r,"runs",o));for(let s of a.getEntries())s.isDirectory||e.addFile(ud.join("runs",i,s.entryName),s.getData())}return{runGroupId:n.id,buffer:e.toBuffer()}}async function dd(r){let{client:e,consoleLogger:t,resultsPath:n}=r;if(!zg.existsSync(n)){t.warn("Results path does not exist, skipping upload.");return}let o=new Nu(e);try{let{runGroupId:i,buffer:a}=QB(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 ZB from"adm-zip";import Ht from"fs";import vr from"path";var _l=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(vr.join(this.filePath,e))}cwd(){return this.filePath}mkdir(e){Ht.mkdirSync(vr.join(this.filePath,e),{recursive:!0})}readFile(e){let t=vr.join(this.filePath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}storeFile(e){let{name:t,contents:n}=e,o=vr.join(this.filePath,t);try{Ht.writeFileSync(o,n)}catch{}}createFileStream(e){let t=vr.join(this.filePath,e);return Ht.createWriteStream(t)}createRunArchive(e){return new Gg(vr.join(this.filePath,"runs"),e)}},Gg=class{constructor(e,t){this.filePath=e;this.tempPath=vr.join(e,`.${t}`),this.finalPath=vr.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=vr.join(this.tempPath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}mkdir(e){Ht.mkdirSync(vr.join(this.tempPath,e),{recursive:!0})}cd(e){return new _l(vr.join(this.tempPath,e))}cwd(){return this.tempPath}storeFile(e){let{name:t,contents:n}=e,o=vr.join(this.tempPath,t);Ht.writeFileSync(o,n)}createFileStream(e){let t=vr.join(this.tempPath,e);return Ht.createWriteStream(t)}close(){let e=new ZB;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{hostname as eH}from"os";var tH="2.27.2",Ml=Ma({app:"desktop-server",hostname:eH(),disableConsoleLogs:!0}).child({cliVersion:tH});(async()=>{try{let r=await Qn(Ml);r.gitBranchName&&Ml.addBinding("branch",r.gitBranchName)}catch{}})();var KA=rH();KA.get("/",async(r,e)=>{let t=se(),n=wA();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Fr(Ml,n,t);e.status(200).json(o)});var jg=KA;import Xq from"events";import UP,{Router as Jq}from"express";import Qq from"http";import Zq from"path";import{Server as yW}from"socket.io";var nH=({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{}}},YA={event:"cancel",createHandler:nH};var oH=({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})}}},XA={event:"fetchA11yTree",createHandler:oH};var iH=({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})}}},JA={event:"fetchDom",createHandler:iH};var aH=({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)}},QA={event:"disconnect",createHandler:aH};function an(r){let{result:e,nestedResults:t}=r;if(!r.nestedResults.length)return;let{firstMetadata:n,lastMetadata:o}=sH(t);lH(e,n,o);let i=[...r.asyncTasks];r.asyncTasks.push((async()=>{try{await cH(i,e,n,o)}catch(a){r.logger.error({result:r.result,err:a},"Error hoisting scalar result metadata")}})())}function sH(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 lH(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 cH(r,e,t,n){await Promise.allSettled(r),t&&(e.beforeSnapshot=t.beforeSnapshot),n&&(e.afterSnapshot=n.afterSnapshot)}import{randomUUID as bH}from"crypto";import{faker as uH}from"@faker-js/faker";import dH from"assert";import pH from"axios";import*as mH from"child_process";import hH from"moment";import*as gH from"otpauth";import fH from"pg";async function ZA(r){let e;try{e=new URL(r.url).hostname}catch{}let t=[];return r.headers.getSetCookie()?.forEach(n=>{let o=cu(n,e);t.push(...o)}),t}function SH(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 yH(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 EH=Object.getPrototypeOf(async function(){}).constructor;async function ew(r,e,t){let n=e.code;e.options.fragment&&(n=`return ${e.code}`);let{env:o,additionalBindings:i,request:a,response:s}=e.bindings,c=e.tools,l={},u=(T,A)=>{o[T]=A,l[T]=A},d={},p=(T,A)=>{o[T]=A,d[T]=A},m;n.includes("Octokit")&&(m=(await import("@octokit/rest")).Octokit);let h;n.includes("createAppAuth")&&(h=(await import("@octokit/auth-app")).createAppAuth);let g=async()=>await Promise.resolve(new EH("axios","moment","faker","assert","pg","Octokit","createAppAuth","OTPAuth","child_process","extractCookiesFromResponse","env","setVariable","setPersistentVariable","sendSms","waitForLatestSms","email","sms","ai","mock",...Object.keys(i??{}),n)(pH,hH,c.fakerInstance??uH,dH,fH,m,h,gH,mH,ZA,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,SH(a,s),...Object.values(i??{}))),f=!0,y,S;try{let T=await j(g(),{milliseconds:e.options.timeoutMs,message:`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`,signal:e.signal});y=await yH(e.options.responseSerialization??"RAW",T)}catch(T){t.error({err:T,env:o,evalCode:n},`[${r}] Error executing code: ${T}`),f=!1,T instanceof Co?S=`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`:S=T instanceof Error?T.message:`${T}`}return{result:y,variableUpdates:l,persistentVariableUpdates:d,success:f,error:S}}async function tw({code:r,fragment:e,context:t,localTools:n,logger:o,signal:i,timeoutMs:a=vo,disallowVariableUpdates:s,additionalBindings:c,responseSerialization:l,mock:u}){let d=bH(),p=await ew(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 TH,randomUUID as vH}from"crypto";import RH from"fetch-retry";var AH=RH(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,nw=process.env.MOMENTIC_LAMBDA_AUTH_SECRET;async function ow({orgId:r,code:e,fragment:t,context:n,timeoutMs:o=vo,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(!nw)throw new Error("Missing lambda auth secret.");let g=TH("sha256",nw).update(r).digest("hex");for(;h<=i;){h++,a?.throwIfAborted();let y={id:vH(),orgId:r,momenticLambdaAuthHash:g,code:e,fragment:t,state:{...n.toObjectCopy(),...d,additionalBindings:c},timeoutMs:o,disallowVariableUpdates:l,responseSerialization:u};try{if(p=await j(AH(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=wT.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 No(r){let e;if(process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT)e=await ow(r);else if(r.localTools)e=await tw({...r,localTools:r.localTools});else throw new Error("No code evaluation environment available");if(e.error){let t=`Failed to evaluate code:
|
|
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 kB(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 zA("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 zA("gh",o,{timeout:5e3}),a=i?.toString().trim();if(a)return a}catch{}}}async function FB(r,e,t){let n=e?.includes("github.com"),o=e?.includes("gitlab.com");try{if(n)return kB(r,e,t);if(o)return}catch{}}function cd(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 Ze(r,e){try{return(await e).trim()}catch(t){r.error({err:t},"Failed to run git command");return}}function UB(){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 BB(r){let[e,t,n]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.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 HB(r){let[e,t,n]=await Promise.all([Ze(r,qe.listRemote(["--get-url","origin"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.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 zB(r){let[e,t,n,o]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.listRemote(["--get-url","origin"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"]))]),i=process.env.CIRCLE_REPOSITORY_URL??t,a=i?.includes("github.com"),s=i?.includes("gitlab.com"),c=i?cd(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 GB(r){let[e,t,n]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"]))]),o=process.env.BUILDKITE_REPO,i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?cd(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 jB(r){let[e,t,n]=await Promise.all([Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"]))]),o=process.env["Build.Repository.Uri"],i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?cd(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 VB(r,e){let[t,n,o,i,a,s,c,l,u]=await Promise.all([Ze(r,qe.revparse(["HEAD"])),Ze(r,qe.revparse(["--short","HEAD"])),Ze(r,qe.revparse(["--abbrev-ref","HEAD"])),Ze(r,qe.listRemote(["--get-url","origin"])),Ze(r,qe.show(["--no-patch","--format=%ci"])),Ze(r,qe.show(["-s","--pretty=%B"])),Ze(r,qe.show(["-s","--pretty=%an"])),e?Ze(r,qe.raw(["merge-base","--fork-point",e])):Promise.resolve(void 0),DB(r)]),d=l?await Ze(r,qe.show(["--no-patch","--format=%ci",l])):void 0,p=i?.includes("github.com"),m=i?.includes("gitlab.com"),h=i?cd(i):void 0,g=u["user.email"]||void 0,f=u["user.name"]||void 0,y=u["user.username"]||void 0,S=await FB(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 $B(){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 WB(r){let e=r.config.gitProtectedBranches??[];return r.config.gitMainBranch&&e.push(r.config.gitMainBranch),{gitMainBranch:r.config.gitMainBranch,gitProtectedBranches:e}}async function Qn(r,e){let t=UB();if(!t)return VB(r,e);switch(t){case"GithubActions":return BB(r);case"GitlabCI":return HB(r);case"CircleCI":return zB(r);case"Buildkite":return GB(r);case"AzureDevOps":return jB(r);case"GCPCloudBuild":return $B()}}async function qB(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 KB(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 YB(r,e,t){try{if(t.githubRepository){let[n,o]=t.githubRepository.split("/");return await KB(r,e,n,o,t)}else if(t.gitlabProjectPath)return await qB(r,e,t.gitlabProjectPath,t)}catch(n){r.warn({err:n},"Failed to get remote git metadata")}return t}async function Fr(r,e,t){let n=await WB(t),o=await Qn(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 YB(r,e,i);return{...n,...o,...a}}async function GA(){try{return!!(await qe.show(["--no-patch","--format=%ci"])).trim()}catch{return null}}import{diff as WSe}from"deep-object-diff";import{cloneDeep as KSe}from"lodash-es";import{v4 as aye}from"uuid";import lye from"yaml";import Cye from"yaml";import _ye from"zod";import{randomUUID as XB}from"crypto";import Lo from"fs";import Wa from"path";var jA=new Set([".DS_Store","__MACOSX"]),VA={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 JB(r,e,t){if(VA[t]){let i=VA[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 Hg=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 $A(r,e){try{let t=Wa.join(e,"metadata.json");return xu.parse(JSON.parse(Lo.readFileSync(t,"utf-8")))}catch{throw new Hg(r,e)}}function WA(r,e,t){let n=XB(),o=r.child({runGroupId:n});Lo.rmSync(e,{recursive:!0,force:!0});let i=Lo.readdirSync(t).filter(c=>!jA.has(c)).map(c=>Wa.join(t,c));if(i.length===0)throw new Error(`No run groups found in results path: ${t}`);Lo.mkdirSync(e,{recursive:!0});let a={...$A(t,i[0]),id:n};for(let c of i){let l=Wa.join(c,"runs");if(!Lo.existsSync(l))continue;let u=$A(t,c);o.info({oldRunGroupId:u.id},"Merging run groups");for(let p in u){if(p==="id")continue;let m=p;a[m]=JB(a,u,m)}let d=Lo.readdirSync(l);for(let p of d){if(jA.has(p))continue;let m=Wa.join(l,p),h=Wa.join(e,"runs",p);Lo.cpSync(m,h,{recursive:!0})}}let s=Wa.join(e,"metadata.json");Lo.writeFileSync(s,JSON.stringify(a,null,2))}import qA from"adm-zip";import zg from"fs";import ud from"path";function QB(r){let e=new qA,t=ud.join(r,"metadata.json"),n=xu.parse(JSON.parse(zg.readFileSync(t,"utf-8")));e.addLocalFile(t);for(let o of zg.readdirSync(ud.join(r,"runs"))){if(!o.endsWith(".zip"))continue;let i=o.replace(/\.zip$/,""),a=new qA(ud.join(r,"runs",o));for(let s of a.getEntries())s.isDirectory||e.addFile(ud.join("runs",i,s.entryName),s.getData())}return{runGroupId:n.id,buffer:e.toBuffer()}}async function dd(r){let{client:e,consoleLogger:t,resultsPath:n}=r;if(!zg.existsSync(n)){t.warn("Results path does not exist, skipping upload.");return}let o=new Nu(e);try{let{runGroupId:i,buffer:a}=QB(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 ZB from"adm-zip";import Ht from"fs";import vr from"path";var _l=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(vr.join(this.filePath,e))}cwd(){return this.filePath}mkdir(e){Ht.mkdirSync(vr.join(this.filePath,e),{recursive:!0})}readFile(e){let t=vr.join(this.filePath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}storeFile(e){let{name:t,contents:n}=e,o=vr.join(this.filePath,t);try{Ht.writeFileSync(o,n)}catch{}}createFileStream(e){let t=vr.join(this.filePath,e);return Ht.createWriteStream(t)}createRunArchive(e){return new Gg(vr.join(this.filePath,"runs"),e)}},Gg=class{constructor(e,t){this.filePath=e;this.tempPath=vr.join(e,`.${t}`),this.finalPath=vr.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=vr.join(this.tempPath,e);if(Ht.existsSync(t))return Ht.readFileSync(t)}mkdir(e){Ht.mkdirSync(vr.join(this.tempPath,e),{recursive:!0})}cd(e){return new _l(vr.join(this.tempPath,e))}cwd(){return this.tempPath}storeFile(e){let{name:t,contents:n}=e,o=vr.join(this.tempPath,t);Ht.writeFileSync(o,n)}createFileStream(e){let t=vr.join(this.tempPath,e);return Ht.createWriteStream(t)}close(){let e=new ZB;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{hostname as eH}from"os";var tH="2.28.0",Ml=Ma({app:"desktop-server",hostname:eH(),disableConsoleLogs:!0}).child({cliVersion:tH});(async()=>{try{let r=await Qn(Ml);r.gitBranchName&&Ml.addBinding("branch",r.gitBranchName)}catch{}})();var KA=rH();KA.get("/",async(r,e)=>{let t=se(),n=wA();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Fr(Ml,n,t);e.status(200).json(o)});var jg=KA;import Xq from"events";import UP,{Router as Jq}from"express";import Qq from"http";import Zq from"path";import{Server as yW}from"socket.io";var nH=({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{}}},YA={event:"cancel",createHandler:nH};var oH=({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})}}},XA={event:"fetchA11yTree",createHandler:oH};var iH=({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})}}},JA={event:"fetchDom",createHandler:iH};var aH=({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)}},QA={event:"disconnect",createHandler:aH};function an(r){let{result:e,nestedResults:t}=r;if(!r.nestedResults.length)return;let{firstMetadata:n,lastMetadata:o}=sH(t);lH(e,n,o);let i=[...r.asyncTasks];r.asyncTasks.push((async()=>{try{await cH(i,e,n,o)}catch(a){r.logger.error({result:r.result,err:a},"Error hoisting scalar result metadata")}})())}function sH(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 lH(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 cH(r,e,t,n){await Promise.allSettled(r),t&&(e.beforeSnapshot=t.beforeSnapshot),n&&(e.afterSnapshot=n.afterSnapshot)}import{randomUUID as bH}from"crypto";import{faker as uH}from"@faker-js/faker";import dH from"assert";import pH from"axios";import*as mH from"child_process";import hH from"moment";import*as gH from"otpauth";import fH from"pg";async function ZA(r){let e;try{e=new URL(r.url).hostname}catch{}let t=[];return r.headers.getSetCookie()?.forEach(n=>{let o=cu(n,e);t.push(...o)}),t}function SH(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 yH(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 EH=Object.getPrototypeOf(async function(){}).constructor;async function ew(r,e,t){let n=e.code;e.options.fragment&&(n=`return ${e.code}`);let{env:o,additionalBindings:i,request:a,response:s}=e.bindings,c=e.tools,l={},u=(T,A)=>{o[T]=A,l[T]=A},d={},p=(T,A)=>{o[T]=A,d[T]=A},m;n.includes("Octokit")&&(m=(await import("@octokit/rest")).Octokit);let h;n.includes("createAppAuth")&&(h=(await import("@octokit/auth-app")).createAppAuth);let g=async()=>await Promise.resolve(new EH("axios","moment","faker","assert","pg","Octokit","createAppAuth","OTPAuth","child_process","extractCookiesFromResponse","env","setVariable","setPersistentVariable","sendSms","waitForLatestSms","email","sms","ai","mock",...Object.keys(i??{}),n)(pH,hH,c.fakerInstance??uH,dH,fH,m,h,gH,mH,ZA,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,SH(a,s),...Object.values(i??{}))),f=!0,y,S;try{let T=await j(g(),{milliseconds:e.options.timeoutMs,message:`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`,signal:e.signal});y=await yH(e.options.responseSerialization??"RAW",T)}catch(T){t.error({err:T,env:o,evalCode:n},`[${r}] Error executing code: ${T}`),f=!1,T instanceof Co?S=`Timeout of ${e.options.timeoutMs}ms exceeded for code execution`:S=T instanceof Error?T.message:`${T}`}return{result:y,variableUpdates:l,persistentVariableUpdates:d,success:f,error:S}}async function tw({code:r,fragment:e,context:t,localTools:n,logger:o,signal:i,timeoutMs:a=vo,disallowVariableUpdates:s,additionalBindings:c,responseSerialization:l,mock:u}){let d=bH(),p=await ew(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 TH,randomUUID as vH}from"crypto";import RH from"fetch-retry";var AH=RH(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,nw=process.env.MOMENTIC_LAMBDA_AUTH_SECRET;async function ow({orgId:r,code:e,fragment:t,context:n,timeoutMs:o=vo,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(!nw)throw new Error("Missing lambda auth secret.");let g=TH("sha256",nw).update(r).digest("hex");for(;h<=i;){h++,a?.throwIfAborted();let y={id:vH(),orgId:r,momenticLambdaAuthHash:g,code:e,fragment:t,state:{...n.toObjectCopy(),...d,additionalBindings:c},timeoutMs:o,disallowVariableUpdates:l,responseSerialization:u};try{if(p=await j(AH(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=wT.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 No(r){let e;if(process.env.GCP_JS_EVAL_FUNCTION_ENDPOINT)e=await ow(r);else if(r.localTools)e=await tw({...r,localTools:r.localTools});else throw new Error("No code evaluation environment available");if(e.error){let t=`Failed to evaluate code:
|
|
47
47
|
${e.error}
|
|
48
48
|
Code received:
|
|
49
49
|
${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 wH}from"lodash-es";async function sr(r){let{orgId:e,s:t,context:n,logger:o,signal:i,retries:a=2,timeoutMs:s=vo,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 No({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 _("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 pd(r){return iw(r)}async function iw({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 sr({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 iw({obj:l,bannedKeys:e,context:n,prefixPath:u,replacements:i,allowList:c?void 0:t,...a})}return i}function aw(r,e){for(let{path:t,original:n}of e)wH(r,t,n)}import CH from"fetch-retry";var zbe=process.env.MAILINATOR_API_KEY,Gbe=CH(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 NH}from"os";import{cloneDeep as lw}from"lodash-es";async function cw(r){let{command:e,timeoutMs:t,fixtures:n}=r,{abortSignal:o}=n,i=()=>Ny(e.cache)?e.cache:void 0,a=i(),s=lw(a),c=(g=!1)=>{if(a=i(),!!a)if(g){let f=mg(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 ae(p,o),o?.throwIfAborted(),a=i();let{result:g,elementWasFound:f}=await sw({cacheToUse:a,params:r});if(d=g,m=f,g.success)break;c(),p=Math.min(p*2,1e4)}if(!d)throw new _("InternalPlatformError",`Failed to evaluate manual element assertion in ${t}ms.`);if(o?.throwIfAborted(),!d.success&&a?.target&&Ac(a.target)){let g=a?.target?.memory?{target:{id:-1,memory:a.target.memory}}:void 0,{result:f}=await sw({cacheToUse:g,params:r});d=f,d.success||c(!0)}let h=i();return d.success&&h?.target&&!m&&(h.target=Sl(h.target),h.updatedAt=new Date),d}async function sw({cacheToUse:r,params:e}){let{command:t,disableCache:n,fixtures:o,tracer:i,targetingWrapper:a}=e,{logger:s}=o;if(t.target&&!po(t.target))throw new Error("Element assertion with x/y is not supported yet");let c=yR(t.assertion),l,u=!1,d=lw(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=>xH(g.locator,e),options:{...t,allowNotActionableNodesOverride:!0,disableCache:n,memory:d?.target?.memory,disableGlobalLocatorRedirect:!0,source:di(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 _)||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 xH(r,{command:e,fixtures:t}){return await t.browser.highlight(r),await _H(r,e.assertion)}async function _H(r,e){let t=!0,n,o;switch(e.type){case"ELEMENT_CONTENT":{let a=await r.textContent()??"";if(o={elementTextContent:mt(a,500,!0)},!fl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!1})){let s=La(e);t=!1,n=new _("AssertionFailureError",`The content ${s} '${e.value}': ${a}`)}break}case"ELEMENT_ATTRIBUTE":{o={elementOuterHtml:mt(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 _("AssertionFailureError",`The element does not have an attribute named ${e.attr}: ${s}`),t=!1;break}if(!fl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!1})){let s=La(e);t=!1,e.operation==="EXISTS"?n=new _("AssertionFailureError",`The attribute ${e.attr} ${s}`):n=new _("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},hn*1e3);break}case"EDITABLE":{t=await r.isEditable({timeout:hn*1e3});break}case"EXISTS":{t=!0;break}case"ENABLED":{t=await r.isEnabled({timeout:hn*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=La(e);n=new _("AssertionFailureError",`The element ${a}`)}break}case"ELEMENT_NAME":{let a=await r.evaluate(s=>s.tagName);if(!fl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!0})){let s=La(e);t=!1,n=new _("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(!fl(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:!1})){let s=La(e);t=!1,e.operation==="EXISTS"?n=new _("AssertionFailureError",`The style property ${e.property} ${s}`):n=new _("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 uw(r){return r.type==="ELEMENT_EXISTENCE"&&r.negated&&r.condition==="EXISTS"}import{Jimp as MH}from"jimp";async function Il(r,e){let t=await r.screenshot(e),n=await MH.fromBuffer(t);return{buffer:t,width:Math.ceil(n.bitmap.width??0),height:Math.ceil(n.bitmap.height??0)}}import{Jimp as dw}from"jimp";import Vg from"jpeg-js";import IH from"pixelmatch";async function pw({ctx:r,tracer:e,command:t,disableCache:n,browser:o,targetingWrapper:i,logger:a,screenshotStorage:s}){if(t.target&&!po(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 V=>Il(o,{locator:V.locator,...c}),options:{...t,disableCache:n,disableGlobalLocatorRedirect:!0,memory:t.cache?.target?.memory,targetName:"target"}})).result:l=await Il(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 U=`${l.width}x${l.height}`,V=`${u.width}x${u.height}`;return{fail:!0,thoughts:`Current screenshot (${U}) does not match saved screenshot dimensions (${V}) - 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 dw.fromBuffer(l.buffer),p={width:l.width,height:l.height},m=await dw.fromBuffer(u.buffer),h={width:u.width,height:u.height},g,f=p.width*p.height,y=h.width*h.height,S=Math.abs(p.height-h.height),T=Math.abs(p.width-h.width);if(f>y){let U=d.cover({w:h.width,h:h.height});l.buffer=await U.getBuffer("image/jpeg"),g="current",l.width=h.width,l.height=h.height}else if(y>f){let U=m.cover({w:p.width,h:p.height});u.buffer=await U.getBuffer("image/jpeg"),g="saved"}let A={data:Buffer.alloc(l.width*l.height*4),width:l.width,height:l.height},b=t.threshold??.1,x=IH(Vg.decode(u.buffer).data,Vg.decode(l.buffer).data,A.data,l.width,l.height,{threshold:b,diffColorAlt:[0,255,0]})/(l.width*l.height)*100,M=x>b*100,P=`Visual diff of ${x.toFixed(2)}% detected, which is ${M?"over":"under"} the threshold of ${b*100}%.`;if(g&&(P+=` The ${g} screenshot was cropped since it was taller by ${S} pixels and wider by ${T} pixels.`),M)throw new _("ActionFailureError",P);return{fail:M,thoughts:P,beforeScreenshotOverride:l.buffer,afterScreenshotOverride:Vg.encode(A,75).data,succeedImmediately:!1,urlAfterCommand:o.url()}}var PH=3e4;function OH(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 mw({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??PH/1e3,i=Object.fromEntries(Object.entries(r.headers||{}).filter(([m,h])=>m&&h)),a=new URLSearchParams;Object.entries(r.params||{}).filter(([m,h])=>m&&h).forEach(([m,h])=>{a.append(m,h)});let s=a.toString(),c;if(Ba(r.url)&&(c=r.url),t&&Ha(r.url,t)&&(c=new URL(r.url,t).toString()),!c)throw new _("ActionFailureError",`Invalid URL: ${r.url}`);e.info({url:c,searchParams:s,headers:i,body:r.body,method:r.method},"Making HTTP request");let u=await j((async()=>{let m=s?`${c}?${s}`:c;try{let h=OH(r);return await n(m,{headers:{...h.contentType?{"Content-Type":h.contentType}:{},...i},method:r.method,body:h.content})}catch(h){throw e.error({err:h},"Failed to make HTTP request"),new Error(`Failed to make HTTP request: ${h}`)}})(),{milliseconds:o*1e3,fallback:()=>{throw new _("ActionFailureError",`Fetch request timed out after ${o} seconds`)}});if(!u.ok){let m;try{m=await u.text()}catch(h){m=`Failed to read response body: ${h}`}throw new _("ActionFailureError",`Fetch request failed with status ${u.status}: ${m}`)}let d={};u.headers.forEach((m,h)=>{d[h]=m});let p={status:u.status,headers:d};if(u.headers.get("content-type")?.includes("json"))try{p.json=await u.json()}catch{}else u.headers.get("content-type")?.includes("text")&&(p.text=await u.text());return p}var LH=5e3;async function md({timeout:r=hn,...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 hw(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 ae(s,e.signal),s=Math.min(Math.floor(s*1.5),LH);else return i}return i=await hw(e),i}async function hw({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(gw,{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(gw,{value:r.value,negated:!!r.negated,returnHtml:!0},"checking page content"));if(!i){let c=r.negated?Kn.CONTAINS:Yn.CONTAINS;a=new _("AssertionFailureError",`The page ${c} '${r.value}'.`),o=s}}catch(s){a=new _("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 gw({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 $g=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(Ua({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 sr({orgId:l,s:f,context:o,logger:n,localTools:a,signal:d});g={orgId:l,cacheKeys:[y,...Object.entries(t).map(([T,A])=>`${T}:${A}`)]},n.info({original:f,keyParams:g},"Module cache key params");let S=Date.now();for(;Date.now()-S<JT;){d?.throwIfAborted();let T=await i.getCacheResult(g);if(T){n.info({cacheResult:mt(T,1e3,!0)},"Got result from module execution cache"),p=hd(e,t,"SUCCESS"),p.message="Used cached module result.",p.data=JSON.parse(T),m=!0;break}else n.info({cacheKey:f,keyParams:g},"No cache result found, continuing with lock acquisition");let A=await i.acquireCacheLock({keyParams:g,clientMetadata:`hostName:${NH()};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 ae(2500+Math.random()*1e4,d)}}try{if(!p)p=await DH(r);else if(e.autoAuth){let f=uu.safeParse(p.data);if(!f.success)throw new _("UserConfigurationError",`Cached authentication module result is not a valid storage state: ${f.error.message}`);n.debug("Automatically loading auth state after cached module result"),await c.loadAuthState(f.data);let y=!1,S=e.advanced?.cacheInvalidation;if(S&&S.type==="PAGE_CHECK"){let T={type:"CONTENT",value:S.substring},A=await md({timeout:hn,assertion:T,browser:c,logger:n,signal:d,autoExpandIframes:!!c.userBrowserSettings.autoExpandIframes});A.success?n.debug({invalResult:A},"Cached result still valid after page check, continuing..."):(n.info({invalResult:A},"Invalidating cached result due to page check failure"),y=!0)}if(g&&y)return await i.deleteCacheResult(g),$g(r)}}finally{try{h!==void 0&&!m&&p?.status==="SUCCESS"&&await kH({step:e,result:p,browser:s.browser,cacheKeyPrefix:h,logger:n,storage:i})}finally{h!==void 0&&await i.releaseCacheLock(h)}}return p},DH=async r=>{let{step:e,tracer:t}=r.moduleParams,n=hd(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,an({asyncTasks:r.work.asyncTasks,nestedResults:a,result:n,logger:r.fixtures.logger}),n};function hd(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 No({orgId:r,code:c,fragment:!0,context:t,logger:n,localTools:o,signal:i})}return a}catch(s){throw i?.throwIfAborted(),new _("UserConfigurationError",`Failed to evaluate module inputs: ${s}`)}}async function kH({step:r,result:e,browser:t,cacheKeyPrefix:n,logger:o,storage:i}){let a=r.cacheConfig?.cacheExpiryMs;(!a||a===Uv)&&(a=r.defaultCacheTtl??Bv);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:Ua({json:s,maxJsonStringSize:1e4})},"Setting module cache result"),await i.setCacheResult({result:s,keyPrefix:n,ttlMs:a})}async function Ni(r,e,t){return FH(r,e,t)}async function FH(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 _?s=`${o}`:s=`An unexpected error occurred: ${o.message}`,r.type==="RESOLVED_MODULE"){let c=hd(r,{},"FAILED");return c.message=s,c.startedAt=n,c.finishedAt=i,c}return{...Qu(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 Tj}from"lodash-es";import{randomUUID as Sw}from"crypto";import{diff as UH}from"deep-object-diff";import{cloneDeep as yw}from"lodash-es";var gd=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?yw(e.command.cache):{},d=o.browser.url(),p=new Date,m,h=Sw(),g=Sw();if(a)try{if(m=await o.browser.screenshot({retries:1,clearHighlights:!0,quality:75}),!o.browser.userBrowserSettings.disableHtmlSnapshots){let A=await o.browser.getRawCondensedHtml();t.attachBeforeHtmlSnapshot({logger:l,snapshotId:h,html:A})}}catch(A){l.debug({err:A},"Failed to take before screenshot, continuing...")}let f,y,S,T=au();try{let A=await o.executePresetCommand(T,t,e.command,i,s?.advanced.disableAICaching??!1);A.beforeScreenshotOverride&&(m=A.beforeScreenshotOverride),S=A.afterScreenshotOverride;let b=new Date,C=o.browser.url();y={beforeUrl:d,afterUrl:C,startedAt:p,finishedAt:b,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:b,startedAt:p,status:A.fail?"FAILED":"SUCCESS",data:A.data,results:[y],details:T.details},"assertion"in e.command&&(f.message=A.thoughts||"Assertion passed.")}catch(A){l.error({message:A.message,stack:A.stack},`Failed executing preset step ${_o(e.command)}`);let b=o.browser.url(),C=new Date,x=A instanceof Error?A.message:`${A}`;y={beforeUrl:d,afterUrl:b,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:b,status:A instanceof DOMException&&A.name==="AbortError"?"CANCELLED":"FAILED",message:x,failureReason:A instanceof _?A.reason:void 0,results:[y],details:T.details}}finally{let A="cache"in e.command&&e.command.cache?yw(e.command.cache):{},b=UH(u,A);b&&Object.keys(b).length>0&&l.info({diffs:b},"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 Ew(r){let{step:e,tracer:t}=r.conditionalParams,{logger:n,controller:o}=r.fixtures,i=new Date,a=Qu(e),s=e.elseSteps,c=!0,l=[],u,d=au();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 gd({...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 an({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 an({asyncTasks:r.work.asyncTasks,nestedResults:[...l,...m.results],result:g,logger:n}),g}import{randomUUID as bw}from"crypto";var Tw=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 BH(r);i.finishedAt=new Date,an({asyncTasks:r.work.asyncTasks,result:i,nestedResults:i.results,logger:r.fixtures.logger});let a=await t.browser.screenshot({}),s=bw();i.beforeSnapshot=s,e.attachBeforeScreenshot({logger:n,snapshotId:s,screenshot:o});let c=bw();return i.afterSnapshot=c,e.attachAfterScreenshot({logger:n,snapshotId:c,screenshot:a}),i},BH=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 _("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 Wg}from"crypto";var vw=15,HH=7,Rw=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 zH(r);i.finishedAt=new Date,an({asyncTasks:r.work.asyncTasks,result:i,nestedResults:i.results,logger:r.fixtures.logger});let a=await n.browser.screenshot({quality:75}),s=Wg();i.beforeSnapshot=s,e.attachBeforeScreenshot({logger:t,snapshotId:s,screenshot:o});let c=Wg();return i.afterSnapshot=c,e.attachAfterScreenshot({logger:t,snapshotId:c,screenshot:a}),i},zH=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 sr({orgId:o,s:e.text,context:a,logger:d,localTools:c});await i.browser.waitForDOMStability({logger:d});let g=`data:image/jpeg;base64,${(await i.browser.screenshot({clearHighlights:!0,retries:2})).toString("base64")}`,f=[],y=0,S=0,T,A;for(;;){if(y>vw)return p.message=`Exceeded the maximum number of commands allowed per AI step (${vw})`,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 b=await i.evaluateAiAction({goal:m,startingScreenshot:y===0?void 0:g,history:f,logger:d,langfuseSessionId:u,lastError:A}),{evaluation:C,reasoning:x,summary:M}=b;d.info(b,"Got AI evaluation");let P=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",P&&l.onDynamicAIActionEvaluatingEvent?.({stepId:P,status:"SUCCESS",message:`${M}
|
|
@@ -4360,7 +4360,7 @@ Available pages:${JSON.stringify(n.map(i=>i.url))}`);if(!_i(o.url,this.logger)){
|
|
|
4360
4360
|
`),tokenLength:d}),u=[],d=0,p=m.length?[m[m.length-1].id]:[],h=!1);let g=c[l],f=Pe(g);d+=f,g.length>a&&(g=g.slice(0,a));let T=Array.from(g.matchAll(mI)).map(Q=>Q&&Q.length>=3?{tagName:Q[1],id:Q[2]}:void 0).filter(Q=>!!Q),b=Array.from(g.matchAll(I$)).map(Q=>Q&&(Q[2]||Q[4])).filter(Q=>!!Q);b.reverse();let C=g.replace(/ id="[0-9]+"/g,"");u.push(C);for(let Q of T)p.push(Q.id),m.push(Q);for(let Q of b){let Y=m[m.length-1];Y&&Y.tagName===Q&&m.pop()}let x=m.some(Q=>O$.includes(Q.tagName)),M=c[l+1]??"",P=Pe(M),V=Array.from(M.matchAll(mI)).map(Q=>Q&&Q.length>2?Q[1]:void 0).filter(Q=>!!Q),k=V.some(Q=>fI.includes(Q)),z=V.some(Q=>P$.includes(Q));d+P>=i&&(h=!0),d>=n&&(k&&!x||b.some(Q=>L$.includes(Q)))&&(h=!0),d>=o&&z&&!x&&(h=!0),l++}return u.length&&s.push({ids:p,content:u.join(`
|
|
4361
4361
|
`),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 k$=75e4,_p=3e5;async function qi(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=Pe(u);if(d>k$)try{let p=xp({serializedTree:u,options:{minChunkTokenCount:1e4,maxChunkTokenCount:1e5,acceptableChunkTokenCount:5e4,maxLineLength:4e3},logger:i});l=await U$({...r,tokenLimit:_p-1e4,chunks:p.chunks}),u=l.serialize();let m=Pe(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(_p*wo),u=l.serialize();let m=Pe(u);i.info({oldTokens:d,newTokens:m},"Filtered page using naive truncation"),d=m}if(d>_p)try{if(o){let p=xp({serializedTree:u,options:gI,logger:i}),m=D$();l=await j(F$({...r,chunks:p.chunks,callId:m}),{milliseconds:12e3,signal:c}),u=l.serialize();let h=Pe(u);i.info({oldTokens:d,newTokens:h,langfuseCallId:m},"Filtered page using AI chunk ranking"),d=h}else{let p=xp({serializedTree:u,options:hI,logger:i});l=await j(B$({...r,chunkResult:p,tokenLimit:4e4}),{milliseconds:12e3,signal:c}),u=l.serialize();let m=Pe(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(_p*wo),u=l.serialize(),i.info("Filtered page using naive truncation")}return u}async function F$({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:He(c)}),u=[];return t.forEach((p,m)=>{l.indices.includes(m)&&(u=u.concat(p.ids))}),i.pruneUsingRelevantIds(new Set(u))}async function U$(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:He(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 B$(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:He(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 kS(r,e){if(!r.description)throw new _("UserConfigurationError","Cannot locate element with empty description");return Gr({action:async()=>H$(r,e),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:e.browser,logger:r.logger})}async function H$(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 sr({orgId:p,s:y,context:n,localTools:h,signal:f,logger:l})),a&&(y=G$(y,a));let{serializedTree:T,tree:A}=await In(m,{allowNotActionableNodesOverride:u,filterByViewport:o,abortSignal:f,skipWait:i,logger:l}),b,C=Date.now(),x;for(;!b&&Date.now()-C<3e3;){f.throwIfAborted();try{b=await m.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(q){x=q}}if(!b)throw new _("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 M=T,P=!1,V=`data:image/jpeg;base64,${b.toString("base64")}`;M=await qi({type:"locator",description:y,screenshot:V,serializedTree:T,options:{aiPageFiltering:c},tree:A,fixtures:{generator:g,signal:f,logger:l,orgId:p}}),M!==T&&(P=!0);let k=await g.getElementLocation({browserState:M,goal:y,screenshot:V,source:a,memory:S?s:void 0},{disableCache:t,abortSignal:f,loggerTags:He(l),useMemory:S});l.debug({usedRag:P,result:k},"Got locator result");let z=k.id>0;if(d?.details?.push({type:"AI_LOCATION",matched:z,pageState:M,ragUsed:P,thoughts:k.thoughts}),!z)throw new pa(`Could not find any relevant element: ${k.thoughts}`,k.updatedMemory?{type:"GCS_TRACES",traces:k.updatedMemory}:void 0);let{resolution:Q,target:Y,frameConfig:Te}=await m.createTargetFromA11yId({id:k.id,requirements:k.requirements,additionalElements:k.additionalElements,description:y,targetSource:"AI",logger:l});if(Q.a11yNode?.properties?.hidden&&Q.a11yNode?.properties?.hidden!=="false")throw new _("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&&(k.updatedMemory?Y.memory={type:"GCS_TRACES",traces:k.updatedMemory}:s&&(Y.memory=s)),{thoughts:k.thoughts,target:Y,resolution:Q,frameConfig:Te,screenshot:V}}var z$=["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:"],SI="<select> element:",yI="text input or contenteditable element:",EI="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:",bI="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:",DS=[SI,yI,EI,bI,...z$];function TI(r,e){if(r===e)return!0;for(let t of DS){if(!r.startsWith(t))continue;let n=r.slice(t.length).trim();if(DS.some(o=>e.startsWith(o)&&e.slice(o.length).trim()===n)||n===e.trim())return!0}return!!DS.some(t=>e.startsWith(t)&&e.slice(t.length).trim()===r.trim())}function G$(r,e){if(!r||!e)return r;switch(e){case"SELECT_OPTION":return`${SI} ${r}`;case"TYPE":return`${yI} ${r}`;case"NEGATED_ELEMENT_VISIBLE_CHECK":return`${EI}
|
|
4362
4362
|
${r}`;case"ELEMENT_CHECK":return`${bI}
|
|
4363
|
-
${r}`;default:return r}}var j$=15;async function Mp({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=j$}){if(!r.assertion.trim())throw new _("ActionFailureError","Assertion command is missing the assertion content");let{browser:s}=n,c=r.timeout?r.timeout*1e3:s.smartWaitingTimeout,l=EA(c),u=0,d=Date.now(),p,m,h;try{await Gr({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 ae(l,n.abortSignal),g=Date.now();let f=!1;try{if(p=await Gr({action:async()=>{let S=await vI(s,t,n.abortSignal);return m&&m.serializedTree===S.serializedTree&&m.screenshotBuff.equals(S.screenshotBuff)?(f=!0,p):(m=S,RI({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&&yl(r,p.updatedMemory,t);break}else throw p?.thoughts?new _("AssertionFailureError",p.thoughts):new _("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 Gr({action:async()=>RI({command:r,state:await vI(s,t,n.abortSignal),fixtures:n,useMemory:i,useConsensus:!0,highlightElementsOnFailure:!0,attemptNumber:u,aiPageFiltering:e,logger:t}),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,logger:t,browser:s})}catch(f){n.abortSignal.throwIfAborted(),h=f instanceof Error?f:new Error(`${f}`)}finally{u++}if(p?.updatedMemory&&yl(r,p.updatedMemory,t),!p?.success){let f=`AI check still failing after ${u} attempts.`;throw h&&(f+=` Latest result: ${h.message}`),new _("AssertionFailureError",f)}return{...p,succeedImmediately:!1,urlAfterCommand:s.url()}}async function vI(r,e,t){let[n,o]=await Promise.all([In(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function RI({command:r,state:e,fixtures:t,useConsensus:n,useMemory:o,highlightElementsOnFailure:i,aiPageFiltering:a,attemptNumber:s,source:c,logger:l}){let{browser:u,generator:d,abortSignal:p}=t,m={type:"ASSERTION"},{serializedTree:h,tree:g}=e,f=e.screenshotBuff,y=f.toString("base64"),S=u.url(),T=r.contextChoice??"MULTIMODAL",A=h;T!=="VISION_ONLY"&&(A=await qi({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 b={goal:r.assertion,url:S,memory:o?r.cache?.memory:void 0,browserState:A,screenshot:y,contextChoice:T,source:c},x=await(T==="VISION_ONLY"?(M,P)=>d.getVisualAssertionResult(M,P):(M,P)=>d.getAssertionResult(M,P))(b,{useConsensus:n,attemptNumber:s,useMemory:o,disableCache:!!r.disableCache,abortSignal:p,logger:l,loggerTags:He(l)});return(x.result||i)&&x.relevantElements&&(m.relevantElementsSerialized=x.relevantElements.map(M=>u.getSerializedFormFromA11yId(M)).filter(M=>!!M),await V$(x.relevantElements,u,l)),{success:x.result,thoughts:x.thoughts,afterScreenshotOverride:f,updatedMemory:o?x.updatedMemory:void 0}}async function V$(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 j(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 $$=75e4,Ip=class extends Error{constructor(){super("The page content exceeds the maximum token limit for AI smart waiting."),this.name="ExceededMaxAISmartWaitingTokensError"}};async function AI(r,e){let{logger:t}=r,{abortSignal:n,browser:o}=e,i=Date.now();try{await W$(i,r,e)}catch(a){if(a instanceof Error&&(a.name==="AbortError"||a.name==="TimeoutError")||n.aborted)return;a instanceof Ip?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 ae(s,n)}finally{t.debug({durationMs:Date.now()-i},"AI smart waiting complete")}}async function W$(r,e,t){let{abortSignal:n,browser:o}=t;if(o.smartWaitingTimeout<3e3){await ae(o.smartWaitingTimeout,n);return}if(!e.description)throw new _("UserConfigurationError","Cannot locate element with empty description");await j(q$(r,e,t),{milliseconds:o.smartWaitingTimeout})}async function q$(r,e,t){let{logger:n,iframeUrl:o}=e,{browser:i}=t;for(;Date.now()-r<i.smartWaitingTimeout;)if(await Gr({action:async()=>K$(e,t),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function K$(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 sr({orgId:l,s:d,context:t,localTools:c,signal:s,logger:n}));let{serializedTree:p}=await In(a,{allowNotActionableNodesOverride:i,filterByViewport:o,abortSignal:s,logger:n});if(Pe(p)>$$)throw new Ip;s.throwIfAborted();let h;try{h=await a.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(S){throw new _("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:He(n)});return n.debug({result:y},"Got smart waiting result"),y.isPageReady}var Y$=3e4;async function wI({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??Y$/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(r.headers||{}).filter(([d,p])=>d&&p));a["Content-Type"]="application/json";let s;if(Ba(r.url)&&(s=r.url),t&&Ha(r.url,t)&&(s=new URL(r.url,t).toString()),!s)throw new _("ActionFailureError",`Invalid URL: ${r.url}`);let l=await j((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 _("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 _("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}throw d?.errors?.length&&d?.errors[0]?.message?new _("ActionFailureError",`GraphQL request failed with status ${l.status}: ${d.errors[0].message}`):new _("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 $o=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([In(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 qi({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:{...He(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([In(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 qi({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:{...He(a)},langfuseSessionId:s})}catch(h){throw new _("InternalWebAgentError",`Error generating command: ${h instanceof Error?h.message:h}`,{errOptions:{cause:h}})}}async getBrowserState(e){return In(this.browser,e)}async locateElement(e){return await kS({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return Gr({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 _("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 Gr({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&&Pm(i)){t.warn({err:i},"Invalid mpath error, retrying element targeting command");continue}if(!this.browser.userBrowserSettings.visualActions&&(Nm(i)||Om(i))){t.warn({err:i},"Invalid momentic id error, retrying element targeting command");continue}if(Dm(i)){t.warn({err:i},"Invalid backend node id error, retrying element targeting command");continue}if(i instanceof fn&&i.retryableWithAI){t.warn({err:i},"Element cache disqualification error, retrying element targeting command");continue}throw i}throw n instanceof _?n:new _("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 _("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 ae(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=CI(e.cache);if((!S||l)&&!fm(o))throw new _("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&&!TI(o.elementDescriptor,S.inputDescription)&&(h.warn({old:S.inputDescription,new:o.elementDescriptor},"Target cache was generated with a different description, clearing it automatically"),y=!0,S=void 0);let T=b=>!!b&&Ac(b),A=!0;if(!T(S)){A=!1,h.info({description:o.elementDescriptor,targetHealingInProgress:p,cacheBustedBeforeAction:y,memory:s.memory,useMemory:g},"Prompting AI for an updated element location"),(y||!i)&&await AI({description:o.elementDescriptor,iframeUrl:s.iframeUrl,source:m,logger:h,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride},this.getControllerFixtures(t)),f--;let b;try{b=await kS({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(M){if(M instanceof pa&&M.updatedLocatorMemory){let P={id:-1,...i,memory:M.updatedLocatorMemory};zu({cmd:c,key:d,newTarget:P,logger:h,updatedWithAI:!0})}throw new _("ActionFailureError",M.message)}b.frameConfig&&this.browser.setActiveFrameConfig(b.frameConfig);let C=s.disableGlobalLocatorRedirect?{locator:b.resolution.locator}:await this.attemptLocatorRedirect(b.resolution.locator,h),x=await a(C);return zu({cmd:c,key:d,newTarget:b.target,logger:h,updatedWithAI:!0}),p&&(n.recordTargetAutoHeal({healType:"AI"}),b.target.targetSource="AI_HEALED",b.target.targetUpdateTime=new Date().toUTCString(),b.target.targetUpdateLoggerTags=He(h)),{result:x,elementInteractedDisplayString:b.resolution.displayString,thoughts:b.thoughts}}try{let b=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(b.locator);let C=s.disableGlobalLocatorRedirect?{locator:b.locator}:await this.attemptLocatorRedirect(b.locator,h),x=await a(C);if(Lt.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.27.2"]),zu({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let M=b.decisions.filter(P=>P.matched);if(M.length!==1)h.warn({decisions:b.decisions},"Expected exactly 1 matching method for element location, got more or less");else{let P=M[0].type;n.recordTargetAutoHeal({healType:P})}}return{result:x,elementInteractedDisplayString:b.displayString}}catch(b){this.throwIfClosed();let C="unknown";b instanceof _r&&b.cacheMissReason&&(C=b.cacheMissReason),Lt.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.27.2",`missReason:${C}`]);let x=!1;if((b instanceof fn||Pm(b)||Nm(b)||Dm(b)||zE(b)||Om(b)||GE(b))&&(x=!0),b instanceof _&&!x)throw h.error({err:b},"Failed to execute action with cached target (fatal)"),b;if(f>0&&o){h.info({err:b},"Failed to execute action with cached target, retrying with AI");let M;return S.memory&&wc(S.memory)&&(M=S.memory),this.wrapElementTargetingCommand({ctx:t,tracer:n,command:c,target:o,cache:void 0,originalCache:i,action:a,options:{...s,memory:M,retriesWithAI:f,targetHealingInProgress:!0}})}throw new _("ActionFailureError",b.message,{errOptions:{cause:b}})}}async attemptLocatorRedirect(e,t){return this.browser.userBrowserSettings.globalLocatorRedirect!==!1?this.browser.performTargetRedirection(e,t):{locator:e}}async screenshotWithDimensions(e){return Il(this.browser,e)}async executePresetCommand(e,t,n,o,i){this.options?.slowMoMs&&await ae(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 _("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&&nE(n)?await this.browser.waitForDOMStability({timeout:Oe}):!this.browser.userBrowserSettings.visualActions&&["PRESS","TYPE"].includes(n.type)&&await this.browser.waitForDOMStability({timeout:ce}),this.options?.autoFollowNewTabs&&await F_({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{aw(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>sS(e)}}async resolveCommandTemplateStrings(e,t){return pd({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()?Mp({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 _("ActionFailureError","Missing assertion");if(n.timeout&&n.timeout>1800)throw new _("AssertionFailureError",`AI check timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);return Mp({command:n,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a})}case"AI_EXTRACT":{if(!n.goal.trim())throw new _("ActionFailureError","Cannot perform AI extraction without goal");if(n.schema){let f=qv(n.schema);if(f)throw new _("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:He(a)});if(f.result==="NOT_FOUND")throw new _("ActionFailureError","No relevant data found for extraction goal on this page");if(f.thoughts?.includes("MaxGenerationLengthExceededError"))throw new _("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 _("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 _("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(!Ba(n.url)&&!Ha(n.url,this.browser.baseUrl))throw new _("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&&mn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:T}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:A=>this.browser.hover(A),options:{...n,targetName:"target",disableGlobalLocatorRedirect:!0,disableCache:i}});h=S,g=T}let f=this.browser.getViewport()?.height??Kt.height,y=this.browser.getViewport()?.width??Kt.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 _("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 _("UserConfigurationError",`Wait timeout of ${n.delay} seconds exceeds the maximum allowed value of 30 minutes`);let l=n.delay*1e3;await ae(l,this.executeAbortController.signal);break;case"REFRESH":await this.browser.refresh({loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"CLICK":{if(mn(n.target)){await this.browser.clickUsingVisualCoordinates(n.target.pixels,n);break}let h=this.browser.url(),{elementInteractedDisplayString:g,result:f,thoughts:y}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,target:n.target,command:n,cache:n.cache?.target,action:T=>this.browser.click(T,this.createCallbacksForBrowser(this.orgId),n),options:{disableCache:i,targetName:"target",...n}}),S={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:y,data:f.downloadedFile?{downloadedFile:f.downloadedFile}:void 0};return ed(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(mn(n.fromTarget)&&mn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(mn(n.fromTarget)||mn(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 _("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${n.deltaX}, ${n.deltaY})`);if(n.target&&mn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,void 0,n.target.pixels);break}let y,S;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:T,thoughts:A}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async b=>this.browser.mouseDrag(h,g,f,b.locator,{force:n.force}),options:{disableCache:i,targetName:"target",...n}});y=T,S=A}else await this.browser.mouseDrag(h,g,f,void 0,{force:n.force});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:y,thoughts:S}}case"SELECT_OPTION":{if(!po(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:di(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 No({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 _("ActionFailureError",g instanceof Error?g.message:`${g}`,{errOptions:{cause:g}})}try{JSON.stringify(h)}catch(g){throw new _("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&&mn(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=CI(n.target),S=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(y){let{elementInteractedDisplayString:A,thoughts:b}=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:di(n)}});g=A,f=b}else await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);let T={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return ed(h,T.urlAfterCommand)&&(T.succeedImmediately=!0,T.succeedImmediatelyReason="URL changed"),T}case"HOVER":{if(mn(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(!po(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&&!po(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 ed(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 J$,g=X$(fetch,h),f;try{f=new URL(n.url).hostname}catch{}return{data:{...await mw({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g}),cookies:sT(h,f)},succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await wI({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return pw({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 Z_({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 _("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 No({orgId:this.orgId,code:n.storageState,fragment:!1,context:o,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof h!="object")throw new _("ActionFailureError",`Credentials must evaluate to an object (received ${typeof h} instead)`);let g;try{g=uu.optional().parse(h)}catch(f){throw new _("ActionFailureError",`Credentials provided do not follow the required format: ${f}`)}await this.browser.loadAuthState(g);break}case"ELEMENT_CHECK":{let h=(n.timeout??hn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(uw(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 Mp({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&&yl(n,y.cache?.memory.traces,a)}}let f=await cw({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 Gr({action:async()=>md({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 Go(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await pS(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 _("ActionFailureError",`No listener registered with key: ${n.key}`);let g=n.timeout??10;return{data:await j(h,{milliseconds:g*1e3,message:`Request listener timed out after ${g} seconds`}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"RECORD_REQUESTS":{let h=new Go(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]=yp(f)},onRequestComplete:(g,f)=>{this.recordedRequests[n.key][g]=yp(f)}}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GET_RECORDED_REQUESTS":{let h=this.recordedRequests[n.key];if(!h)throw new _("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 Go(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 Go(n.requestMatcher),async(g,f)=>{let y=await No({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=AT.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:He(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 Ap({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:He(this.logger)})}async getFailureRecoveryPlan(e){return this.generator.getFailureRecoveryPlan(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:He(this.logger)})}};import{cloneDeep as Q$}from"lodash-es";var Z$={showOverlay:!1},Pp=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:Q$(Z$),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 xI(r,e,t,n){let o=Date.now(),i=Date.now(),a,s,c,l,u=!1,d=async(g,f)=>{if(!g.closed&&!g.isInPageLoad)try{let y=c;c=void 0;let S=g.url(),T=f.toEditorDisplayCopy();JSON.stringify(T)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:T,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=T}catch(y){if(!r.connected)return;let S=y instanceof Error?y.message:`${y}`;if(S.includes("Frame was detached")||S.includes("Not attached to an active page")||S.includes("browser has been closed")||S.includes("UserInfrastructureError"))return;t.error({err:y,sessionId:e},"Error grabbing browser state")}},p=setInterval(()=>{let g=n.getSession(e),f=g?.controller?.browser;if(!f||f.closed){t.debug("Clearing browser state socket cron due to the browser being closed"),clearInterval(p);return}d(f,g.context)},1e3),m=(g,f)=>!!(JSON.stringify(g)!==JSON.stringify(s)||f.logsPerPage.some(y=>y.length>0)),h=setInterval(async()=>{let f=n.getSession(e)?.controller?.browser;if(!f||f.closed){clearInterval(h);return}else if(u)return;u=!0;try{let y=await f.getAllFrameUrls(),S=f.retrieveAndClearDebugData();m(y,S)&&(s=y,c=S,i=Date.now())}catch(y){t.warn({err:y},"Failed to fetch extended details")}finally{u=!1}},2500);return{timers:[p,h]}}var eW=3;async function _I({socket:r,logger:e,storageFactory:t,uploadedFileStorage:n,visualDiffScreenshotStorage:o,devicePixelRatio:i,generatorFactory:a,enricherFactory:s,authorization:c,settingsFactory:l,getOrgId:u,branchGetter:d,globalE2eStateManager:p}){let m=r.id,h=r.handshake.query.testId;if(!h)throw new Error("Socket connection request is missing testId");let g=await u({type:"e2e",testId:h}),f=await d?.();e=e.child({testId:h,orgId:g,sessionId:m,branch:f});let y=await a(g,e),S=await s(g,e),T=await l(g,e),A=await t(g),{testMetadata:b,baseUrl:C,envName:x,browserConfig:M,aiSettings:P,environmentVariables:U,localCodeEvalTools:V}=await Ki({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:T}),k=p.getSession(m);if(k)return e.info("Associating connection with existing session (likely reconnect)"),await k.controller.browser.clearAllCdpHighlights(),{type:"e2e",sessionId:m,orgId:g,testId:h};let z=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:z,event:"connect",args:r.handshake.query},"Websocket event (connect)"),z&&p.getCurrentConnectionsByIp(z)>=eW)throw e.error({clientIp:z,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(z);try{await tW({socket:r,baseUrl:C,envName:x,testMetadata:b,orgId:g,sessionId:m,logger:e,environmentVariables:U,clientIp:z,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:V,generator:y,enricher:S,browserConfig:M,aiSettings:P,globalE2eStateManager:p})}catch(Q){throw e.warn({err:Q},"Error setting up socket session, possibly due to client closing the connection"),p.releaseCapacityByIp(z),Q}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function tW({socket:r,baseUrl:e,envName:t,devicePixelRatio:n,testMetadata:o,orgId:i,sessionId:a,logger:s,storage:c,uploadedFileStorage:l,visualDiffScreenshotStorage:u,localCodeEvalTools:d,generator:p,environmentVariables:m,browserConfig:h,aiSettings:g,clientIp:f,enricher:y,globalE2eStateManager:S}){let T={viewport:o.advanced?.viewport??Kt,locale:o.advanced?.locale??So,timezoneId:o.advanced?.timezone??yo,geolocation:o.advanced?.geolocation??Eo,colorScheme:o.advanced?.colorScheme};n&&(T.deviceScaleFactor=n);let A=o.id,b=await pp({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 $r.init({baseUrl:e,userBrowserSettings:b,enricher:y,storage:c,logger:s,contextArgs:T,iconKnowledgeBase:null,callbacks:{onTabsChange:(V,k)=>{r.emit("tabs",{tabs:V,activeTab:k})},onScreencastFrame:(V,k)=>{let z=r;kr&&(z=r.compress(!0)),z.emit("screenshot",{buffer:V},()=>{k()})},onSvgsCollected:V=>{r.emit("newIconDetected",{numIcons:V.newSvgs.length}),c.saveNewIcons(V,s)},onNetworkLogs:V=>{r.emit("networkLogs",{harEntries:V})}}});await C.navigate({url:e,initialNavigation:!0});let x=new $o({browser:C,generator:p,logger:s,orgId:i,options:{scratchPadId:void 0,slowMoMs:b.slowMoMs,autoFollowNewTabs:b.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:c,localCodeEvalTools:d,uploadedFileStorage:l,visualDiffScreenshotStorage:u}),M=xI(r,a,s,S),P=async()=>{M.timers.forEach(V=>clearInterval(V))},U=new or({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:$r.USER_AGENT,viewport:x.browser.getViewport(),sessionId:a}),S.registerSession({controller:x,context:U,sessionId:a,cleanup:P,clientIp:f,socket:r})}async function Ki({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 vn({httpClient:new Bt({...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?.[Tt];if(!p)throw new Error("Base URL is empty in both test options and the configured environment");let m={...l?.variables};m=await mp({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 FS=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;Lt.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 ro({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},ro=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))Lt.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 FS({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId})}async finish(){this.sendFinalizedStepStats()}},Op=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 ro({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new ro({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new ro({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var US={currentlyExecutingRequests:{}},nW=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 Ki({testId:n,orgId:o,logger:r.logger,storage:a,authorization:r.authorization,settings:i}),l=`${n}|${c.baseUrl}`;try{let u=US.currentlyExecutingRequests[l]??0;US.currentlyExecutingRequests[l]=u+1,s=await oW({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),US.currentlyExecutingRequests[l]--}},oW=async({socket:r,steps:e,baseUrl:t,testMetadata:n,reInitialize:o,toStep:i,fromStep:a,storageFactory:s,aiSettings:c,browserConfig:l,metadata:u,logger:d,envName:p,testName:m,environmentVariables:h,localCodeEvalTools:g,done:f,cacheStorageFactory:y,globalE2eStateManager:S})=>{let{testId:T,sessionId:A,orgId:b}=u,C=A,x=S.getSession(A);if(!x)throw new Error("No active session found");let{controller:M,context:P}=x;M.setOpen(),d=d.child({testId:T,orgId:b,sessionId:A,runId:C}),d.info({steps:e.map(oe=>`${oe.type}${"command"in oe?` - ${oe.command.type}`:""}`),toStep:i,fromStep:a,reInitialize:o,envName:p,testName:m,baseUrl:t,context:P,browserConfig:l,aiSettings:c},"Socket execution parameters");let U=h??{},V=async()=>{o&&(await M.browser.reset({newUrl:t}),P.reset({baseUrl:t,currentUrl:M.browser.url(),variablesFromEnvironment:U,envName:p,testName:m}))},k=await s(b),z=await y(b),Q=async()=>{let oe=Date.now();try{await z.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:T,stepLists:{steps:e},logger:d})}catch(jt){d.error({err:jt},"Failed to fetch step cache entries from Momentic server. This can drastically reduce test reliability and performance.")}finally{Lt.distribution("cache-resolution",Date.now()-oe,["executor:editor"])}};try{await bl({promiseGenerator:async()=>Promise.all([V(),Q()]),signal:M.executeAbortController.signal,codePath:"resolveStepCacheAndInitBrowser"}),M.setOpen()}catch(oe){if(r.emit("finished"),oe.name!=="AbortError")throw new Error(`Failed to setup browser for execution: ${oe}`)}let Y=rW(e),Te={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},q={orgId:b,runId:C,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},it={controller:M,context:P,storage:k,codeEvalTools:g,usageTracker:new Ta,logger:d},Ge={test:{},step:{onDynamicAIActionStatusUpdateEvent:oe=>{r.emit("dynamicCommandStatusUpdate",oe)},onDynamicAIActionEvaluatingEvent:oe=>{r.emit("dynamicCommandEvaluating",oe)},onDynamicCommandGenerated:oe=>{r.emit("dynamicCommandGenerated",oe)},onDynamicCommandExecuted:oe=>{r.emit("dynamicCommandExecuted",oe)}}},Ye=new Op(r,k,b,T),Nt=await dp({fixtures:it,options:Te,callbacks:Ge,inputs:q,testParams:{tracer:Ye}}),Ie={logger:d,cacheStorage:z,orgId:b,testId:T,originalStepsWithCaches:{steps:Y},updatedStepsWithCaches:{steps:e}};return Nt?.status==="PASSED"?await Ku(Ie):Nt?.status==="FAILED"&&await Yu(Ie),await Ye.finish(),f?.(Nt),Nt.status};var MI={event:"execute",createHandler:nW};import{cloneDeep as iW}from"lodash-es";var aW=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=iW(e),s=cA(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})}}},II={event:"lintStep",createHandler:aW};var sW=({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=fi.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let T=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=T.resolution.locator,y={target:T.target,thoughts:T.thoughts}}catch(T){e.warn({err:T},"Failed resolving target with selector"),s({err:`Failed locating element: ${T.message}`,decisions:T instanceof _r?T.decisions:void 0});return}else try{let T=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:di(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&wc(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:T.target,thoughts:T.thoughts},S=T.resolution.locator}catch(T){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:T,html:A.slice(0,1e5)},"Failed locating element with AI")}catch(A){e.warn({err:A},"Failed grabbing HTML after trying to locate element with AI")}})(),s({err:`${T.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(T){e.warn({err:T},"Failed getting select options"),s({err:`Failed getting select options: ${T.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:T,width:A,height:b}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),C=await g.uploadScreenshot(T);y.screenshot={data:C,width:A,height:b},e.info({width:A,height:b},"Captured screenshot during locate")}catch(T){e.error({err:T},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${T.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(T){e.warn({err:T},"Error highlighting element, continuing...")}}},PI={event:"locate",createHandler:sW};var lW=({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")}}},OI={event:"mouseClickEvent",createHandler:lW};var cW=({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})}},LI={event:"recordTargetClick",createHandler:cW};var uW=({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}}},NI={event:"keyDownEvent",createHandler:uW};var dW=({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}}},DI={event:"keyUpEvent",createHandler:dW};var pW=({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")}}},kI={event:"mouseMoveEvent",createHandler:pW};var mW=({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}}},FI={event:"recordingStart",createHandler:mW};var hW=({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}},UI={event:"recordingStop",createHandler:hW};var gW=({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 Ki({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()},BI={event:"refresh",createHandler:gW};var fW=({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 Ki({testId:s,orgId:l,logger:t,storage:d,authorization:o,settings:u}),f=a.getSession(c);if(!f){r.emit("error",{message:"No session to reset"});return}let{controller:y,context:S}=f;await y.browser.reset({newUrl:p});let T=y.browser.baseUrl;S.reset({baseUrl:T,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),b=$r.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${T}`),r.emit("session",{url:T,userAgent:b,viewport:A,sessionId:c})},HI={event:"reset",createHandler:fW};var SW=({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})}},zI={event:"switchTab",createHandler:SW};async function GI(r){return _I(r)}var jI=[QA,MI,PI,HI,BI,YA,zI,II,LI,FI,UI,kI,OI,NI,DI,JA,XA];var VI=r=>{let{logger:e}=r,t=new yW(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 GI({...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}jI.forEach(i=>EW(i,{...r,socket:n,metadata:o,logger:e}))}),t},EW=(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 AW}from"express";import{Router as TW}from"express";import ac from"fs";import ic from"path";import{v4 as vW}from"uuid";import RW from"yaml";import{hostname as bW}from"os";var oc="2.27.2",et=Ma({app:"desktop-server",hostname:bW(),disableConsoleLogs:!0}).child({cliVersion:oc});(async()=>{try{let r=await Qn(et);r.gitBranchName&&et.addBinding("branch",r.gitBranchName)}catch{}})();var hs=TW();async function BS(r){return(await sd(r,et)).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)}hs.get("/",Me(async(r,e)=>{let t=se(),n=await Z(t),o=await BS(n);e.status(200).json(o)}));hs.post("/",Me(async(r,e)=>{let t;try{t=UT.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{go(t.name)}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=se(),o=(await Z(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=ic.join(n.rootDir,t.folderPath??"");if(!ac.existsSync(i)||!ac.statSync(i).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${i}' does not exist.`});return}let a=await ad({...t,folder:i,project:n});e.status(201).json(a)}));hs.get("/:moduleId",Me(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=await Z(se()),n=t.modules[r.params.moduleId];if(!n){e.status(404).json({error:"Module not found."});return}try{let o=await nn(n,t,E);e.json(o)}catch(o){e.status(400).json({err:o})}}));hs.post("/:moduleId/duplicate",Me(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=FT.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{go(t.name)}catch(g){e.status(400).json({error:g.message});return}let n=se(),o=await Z(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 nn(i,o,E),s=ic.join(n.rootDir,ic.dirname(i.relativePath));if(!ac.existsSync(s)||!ac.statSync(s).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${s}' does not exist.`});return}let c=Ue(t.name),l=ic.join(s,`${c}.module.yaml`),u=vW(),{stepsToSave:d}=await nt({stepLists:{steps:a.steps},createNewCacheIds:!0,cacheCreationParams:{orgId:wt()}}),p={fileType:he.MODULE,schemaVersion:Ce,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=RW.stringify(p);ac.writeFileSync(l,m,"utf-8");let h={relativeFilePath:ic.relative(n.rootDir,l)};e.status(201).json(h)}));hs.patch("/:moduleId/metadata",Me(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=BT.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=se(),o=await Z(n);_A({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:E,project:n}),e.status(201).json({message:"ok"})}));var $I=hs;var WI=AW();WI.get("/",Me(async(r,e)=>{let t=se(),n=await Z(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 BS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var qI=WI;import{Router as wW}from"express";var HS=wW();HS.get("/",Me((r,e)=>{let t=ld(se(),et);e.status(200).json(t)}));HS.get("/names",Me((r,e)=>{let n=se().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var KI=HS;import{Router as CW}from"express";var YI=CW();YI.get("/",Me((r,e)=>{let t={userId:Po(),orgId:wt(),cliVersion:oc??"0.0.0"};e.status(200).json(t)}));var XI=YI;import{StreamableHTTPServerTransport as kq}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as Fq}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as Uq}from"crypto";import{Router as Bq}from"express";import{McpServer as Nq}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as Dq}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as PW}from"ai";import Dp from"dedent";import{z as Wo}from"zod";import{tool as xW}from"ai";import{z as _W}from"zod";var JI=(r,e)=>({builder:n=>xW({description:r.schema.description,inputSchema:_W.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(`
|
|
4363
|
+
${r}`;default:return r}}var j$=15;async function Mp({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=j$}){if(!r.assertion.trim())throw new _("ActionFailureError","Assertion command is missing the assertion content");let{browser:s}=n,c=r.timeout?r.timeout*1e3:s.smartWaitingTimeout,l=EA(c),u=0,d=Date.now(),p,m,h;try{await Gr({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 ae(l,n.abortSignal),g=Date.now();let f=!1;try{if(p=await Gr({action:async()=>{let S=await vI(s,t,n.abortSignal);return m&&m.serializedTree===S.serializedTree&&m.screenshotBuff.equals(S.screenshotBuff)?(f=!0,p):(m=S,RI({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&&yl(r,p.updatedMemory,t);break}else throw p?.thoughts?new _("AssertionFailureError",p.thoughts):new _("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 Gr({action:async()=>RI({command:r,state:await vI(s,t,n.abortSignal),fixtures:n,useMemory:i,useConsensus:!0,highlightElementsOnFailure:!0,attemptNumber:u,aiPageFiltering:e,logger:t}),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,logger:t,browser:s})}catch(f){n.abortSignal.throwIfAborted(),h=f instanceof Error?f:new Error(`${f}`)}finally{u++}if(p?.updatedMemory&&yl(r,p.updatedMemory,t),!p?.success){let f=`AI check still failing after ${u} attempts.`;throw h&&(f+=` Latest result: ${h.message}`),new _("AssertionFailureError",f)}return{...p,succeedImmediately:!1,urlAfterCommand:s.url()}}async function vI(r,e,t){let[n,o]=await Promise.all([In(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function RI({command:r,state:e,fixtures:t,useConsensus:n,useMemory:o,highlightElementsOnFailure:i,aiPageFiltering:a,attemptNumber:s,source:c,logger:l}){let{browser:u,generator:d,abortSignal:p}=t,m={type:"ASSERTION"},{serializedTree:h,tree:g}=e,f=e.screenshotBuff,y=f.toString("base64"),S=u.url(),T=r.contextChoice??"MULTIMODAL",A=h;T!=="VISION_ONLY"&&(A=await qi({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 b={goal:r.assertion,url:S,memory:o?r.cache?.memory:void 0,browserState:A,screenshot:y,contextChoice:T,source:c},x=await(T==="VISION_ONLY"?(M,P)=>d.getVisualAssertionResult(M,P):(M,P)=>d.getAssertionResult(M,P))(b,{useConsensus:n,attemptNumber:s,useMemory:o,disableCache:!!r.disableCache,abortSignal:p,logger:l,loggerTags:He(l)});return(x.result||i)&&x.relevantElements&&(m.relevantElementsSerialized=x.relevantElements.map(M=>u.getSerializedFormFromA11yId(M)).filter(M=>!!M),await V$(x.relevantElements,u,l)),{success:x.result,thoughts:x.thoughts,afterScreenshotOverride:f,updatedMemory:o?x.updatedMemory:void 0}}async function V$(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 j(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 $$=75e4,Ip=class extends Error{constructor(){super("The page content exceeds the maximum token limit for AI smart waiting."),this.name="ExceededMaxAISmartWaitingTokensError"}};async function AI(r,e){let{logger:t}=r,{abortSignal:n,browser:o}=e,i=Date.now();try{await W$(i,r,e)}catch(a){if(a instanceof Error&&(a.name==="AbortError"||a.name==="TimeoutError")||n.aborted)return;a instanceof Ip?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 ae(s,n)}finally{t.debug({durationMs:Date.now()-i},"AI smart waiting complete")}}async function W$(r,e,t){let{abortSignal:n,browser:o}=t;if(o.smartWaitingTimeout<3e3){await ae(o.smartWaitingTimeout,n);return}if(!e.description)throw new _("UserConfigurationError","Cannot locate element with empty description");await j(q$(r,e,t),{milliseconds:o.smartWaitingTimeout})}async function q$(r,e,t){let{logger:n,iframeUrl:o}=e,{browser:i}=t;for(;Date.now()-r<i.smartWaitingTimeout;)if(await Gr({action:async()=>K$(e,t),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function K$(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 sr({orgId:l,s:d,context:t,localTools:c,signal:s,logger:n}));let{serializedTree:p}=await In(a,{allowNotActionableNodesOverride:i,filterByViewport:o,abortSignal:s,logger:n});if(Pe(p)>$$)throw new Ip;s.throwIfAborted();let h;try{h=await a.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(S){throw new _("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:He(n)});return n.debug({result:y},"Got smart waiting result"),y.isPageReady}var Y$=3e4;async function wI({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??Y$/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(r.headers||{}).filter(([d,p])=>d&&p));a["Content-Type"]="application/json";let s;if(Ba(r.url)&&(s=r.url),t&&Ha(r.url,t)&&(s=new URL(r.url,t).toString()),!s)throw new _("ActionFailureError",`Invalid URL: ${r.url}`);let l=await j((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 _("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 _("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}throw d?.errors?.length&&d?.errors[0]?.message?new _("ActionFailureError",`GraphQL request failed with status ${l.status}: ${d.errors[0].message}`):new _("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 $o=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([In(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 qi({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:{...He(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([In(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 qi({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:{...He(a)},langfuseSessionId:s})}catch(h){throw new _("InternalWebAgentError",`Error generating command: ${h instanceof Error?h.message:h}`,{errOptions:{cause:h}})}}async getBrowserState(e){return In(this.browser,e)}async locateElement(e){return await kS({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return Gr({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 _("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 Gr({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&&Pm(i)){t.warn({err:i},"Invalid mpath error, retrying element targeting command");continue}if(!this.browser.userBrowserSettings.visualActions&&(Nm(i)||Om(i))){t.warn({err:i},"Invalid momentic id error, retrying element targeting command");continue}if(Dm(i)){t.warn({err:i},"Invalid backend node id error, retrying element targeting command");continue}if(i instanceof fn&&i.retryableWithAI){t.warn({err:i},"Element cache disqualification error, retrying element targeting command");continue}throw i}throw n instanceof _?n:new _("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 _("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 ae(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=CI(e.cache);if((!S||l)&&!fm(o))throw new _("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&&!TI(o.elementDescriptor,S.inputDescription)&&(h.warn({old:S.inputDescription,new:o.elementDescriptor},"Target cache was generated with a different description, clearing it automatically"),y=!0,S=void 0);let T=b=>!!b&&Ac(b),A=!0;if(!T(S)){A=!1,h.info({description:o.elementDescriptor,targetHealingInProgress:p,cacheBustedBeforeAction:y,memory:s.memory,useMemory:g},"Prompting AI for an updated element location"),(y||!i)&&await AI({description:o.elementDescriptor,iframeUrl:s.iframeUrl,source:m,logger:h,allowNotActionableNodesOverride:s.allowNotActionableNodesOverride},this.getControllerFixtures(t)),f--;let b;try{b=await kS({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(M){if(M instanceof pa&&M.updatedLocatorMemory){let P={id:-1,...i,memory:M.updatedLocatorMemory};zu({cmd:c,key:d,newTarget:P,logger:h,updatedWithAI:!0})}throw new _("ActionFailureError",M.message)}b.frameConfig&&this.browser.setActiveFrameConfig(b.frameConfig);let C=s.disableGlobalLocatorRedirect?{locator:b.resolution.locator}:await this.attemptLocatorRedirect(b.resolution.locator,h),x=await a(C);return zu({cmd:c,key:d,newTarget:b.target,logger:h,updatedWithAI:!0}),p&&(n.recordTargetAutoHeal({healType:"AI"}),b.target.targetSource="AI_HEALED",b.target.targetUpdateTime=new Date().toUTCString(),b.target.targetUpdateLoggerTags=He(h)),{result:x,elementInteractedDisplayString:b.resolution.displayString,thoughts:b.thoughts}}try{let b=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(b.locator);let C=s.disableGlobalLocatorRedirect?{locator:b.locator}:await this.attemptLocatorRedirect(b.locator,h),x=await a(C);if(Lt.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.0"]),zu({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let M=b.decisions.filter(P=>P.matched);if(M.length!==1)h.warn({decisions:b.decisions},"Expected exactly 1 matching method for element location, got more or less");else{let P=M[0].type;n.recordTargetAutoHeal({healType:P})}}return{result:x,elementInteractedDisplayString:b.displayString}}catch(b){this.throwIfClosed();let C="unknown";b instanceof _r&&b.cacheMissReason&&(C=b.cacheMissReason),Lt.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.28.0",`missReason:${C}`]);let x=!1;if((b instanceof fn||Pm(b)||Nm(b)||Dm(b)||zE(b)||Om(b)||GE(b))&&(x=!0),b instanceof _&&!x)throw h.error({err:b},"Failed to execute action with cached target (fatal)"),b;if(f>0&&o){h.info({err:b},"Failed to execute action with cached target, retrying with AI");let M;return S.memory&&wc(S.memory)&&(M=S.memory),this.wrapElementTargetingCommand({ctx:t,tracer:n,command:c,target:o,cache:void 0,originalCache:i,action:a,options:{...s,memory:M,retriesWithAI:f,targetHealingInProgress:!0}})}throw new _("ActionFailureError",b.message,{errOptions:{cause:b}})}}async attemptLocatorRedirect(e,t){return this.browser.userBrowserSettings.globalLocatorRedirect!==!1?this.browser.performTargetRedirection(e,t):{locator:e}}async screenshotWithDimensions(e){return Il(this.browser,e)}async executePresetCommand(e,t,n,o,i){this.options?.slowMoMs&&await ae(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 _("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&&nE(n)?await this.browser.waitForDOMStability({timeout:Oe}):!this.browser.userBrowserSettings.visualActions&&["PRESS","TYPE"].includes(n.type)&&await this.browser.waitForDOMStability({timeout:ce}),this.options?.autoFollowNewTabs&&await F_({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{aw(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>sS(e)}}async resolveCommandTemplateStrings(e,t){return pd({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()?Mp({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 _("ActionFailureError","Missing assertion");if(n.timeout&&n.timeout>1800)throw new _("AssertionFailureError",`AI check timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);return Mp({command:n,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a})}case"AI_EXTRACT":{if(!n.goal.trim())throw new _("ActionFailureError","Cannot perform AI extraction without goal");if(n.schema){let f=qv(n.schema);if(f)throw new _("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:He(a)});if(f.result==="NOT_FOUND")throw new _("ActionFailureError","No relevant data found for extraction goal on this page");if(f.thoughts?.includes("MaxGenerationLengthExceededError"))throw new _("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 _("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 _("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(!Ba(n.url)&&!Ha(n.url,this.browser.baseUrl))throw new _("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&&mn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:T}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:A=>this.browser.hover(A),options:{...n,targetName:"target",disableGlobalLocatorRedirect:!0,disableCache:i}});h=S,g=T}let f=this.browser.getViewport()?.height??Kt.height,y=this.browser.getViewport()?.width??Kt.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 _("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 _("UserConfigurationError",`Wait timeout of ${n.delay} seconds exceeds the maximum allowed value of 30 minutes`);let l=n.delay*1e3;await ae(l,this.executeAbortController.signal);break;case"REFRESH":await this.browser.refresh({loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"CLICK":{if(mn(n.target)){await this.browser.clickUsingVisualCoordinates(n.target.pixels,n);break}let h=this.browser.url(),{elementInteractedDisplayString:g,result:f,thoughts:y}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,target:n.target,command:n,cache:n.cache?.target,action:T=>this.browser.click(T,this.createCallbacksForBrowser(this.orgId),n),options:{disableCache:i,targetName:"target",...n}}),S={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:y,data:f.downloadedFile?{downloadedFile:f.downloadedFile}:void 0};return ed(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(mn(n.fromTarget)&&mn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(mn(n.fromTarget)||mn(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 _("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${n.deltaX}, ${n.deltaY})`);if(n.target&&mn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,void 0,n.target.pixels);break}let y,S;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:T,thoughts:A}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async b=>this.browser.mouseDrag(h,g,f,b.locator,{force:n.force}),options:{disableCache:i,targetName:"target",...n}});y=T,S=A}else await this.browser.mouseDrag(h,g,f,void 0,{force:n.force});return{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:y,thoughts:S}}case"SELECT_OPTION":{if(!po(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:di(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 No({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 _("ActionFailureError",g instanceof Error?g.message:`${g}`,{errOptions:{cause:g}})}try{JSON.stringify(h)}catch(g){throw new _("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&&mn(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=CI(n.target),S=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(y){let{elementInteractedDisplayString:A,thoughts:b}=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:di(n)}});g=A,f=b}else await this.browser.type(n.value,{force:n.force,clearContent:n.clearContent,forceClearContent:n.forceClearContent,delay:n.delay,pressEnter:n.pressEnter},!0);let T={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return ed(h,T.urlAfterCommand)&&(T.succeedImmediately=!0,T.succeedImmediatelyReason="URL changed"),T}case"HOVER":{if(mn(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(!po(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&&!po(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 ed(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 J$,g=X$(fetch,h),f;try{f=new URL(n.url).hostname}catch{}return{data:{...await mw({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g}),cookies:sT(h,f)},succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await wI({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return pw({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 Z_({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 _("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 No({orgId:this.orgId,code:n.storageState,fragment:!1,context:o,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof h!="object")throw new _("ActionFailureError",`Credentials must evaluate to an object (received ${typeof h} instead)`);let g;try{g=uu.optional().parse(h)}catch(f){throw new _("ActionFailureError",`Credentials provided do not follow the required format: ${f}`)}await this.browser.loadAuthState(g);break}case"ELEMENT_CHECK":{let h=(n.timeout??hn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(uw(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 Mp({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&&yl(n,y.cache?.memory.traces,a)}}let f=await cw({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 Gr({action:async()=>md({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 Go(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await pS(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 _("ActionFailureError",`No listener registered with key: ${n.key}`);let g=n.timeout??10;return{data:await j(h,{milliseconds:g*1e3,message:`Request listener timed out after ${g} seconds`}),succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"RECORD_REQUESTS":{let h=new Go(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]=yp(f)},onRequestComplete:(g,f)=>{this.recordedRequests[n.key][g]=yp(f)}}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GET_RECORDED_REQUESTS":{let h=this.recordedRequests[n.key];if(!h)throw new _("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 Go(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 Go(n.requestMatcher),async(g,f)=>{let y=await No({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=AT.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:He(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 Ap({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:He(this.logger)})}async getFailureRecoveryPlan(e){return this.generator.getFailureRecoveryPlan(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:He(this.logger)})}};import{cloneDeep as Q$}from"lodash-es";var Z$={showOverlay:!1},Pp=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:Q$(Z$),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 xI(r,e,t,n){let o=Date.now(),i=Date.now(),a,s,c,l,u=!1,d=async(g,f)=>{if(!g.closed&&!g.isInPageLoad)try{let y=c;c=void 0;let S=g.url(),T=f.toEditorDisplayCopy();JSON.stringify(T)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:T,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=T}catch(y){if(!r.connected)return;let S=y instanceof Error?y.message:`${y}`;if(S.includes("Frame was detached")||S.includes("Not attached to an active page")||S.includes("browser has been closed")||S.includes("UserInfrastructureError"))return;t.error({err:y,sessionId:e},"Error grabbing browser state")}},p=setInterval(()=>{let g=n.getSession(e),f=g?.controller?.browser;if(!f||f.closed){t.debug("Clearing browser state socket cron due to the browser being closed"),clearInterval(p);return}d(f,g.context)},1e3),m=(g,f)=>!!(JSON.stringify(g)!==JSON.stringify(s)||f.logsPerPage.some(y=>y.length>0)),h=setInterval(async()=>{let f=n.getSession(e)?.controller?.browser;if(!f||f.closed){clearInterval(h);return}else if(u)return;u=!0;try{let y=await f.getAllFrameUrls(),S=f.retrieveAndClearDebugData();m(y,S)&&(s=y,c=S,i=Date.now())}catch(y){t.warn({err:y},"Failed to fetch extended details")}finally{u=!1}},2500);return{timers:[p,h]}}var eW=3;async function _I({socket:r,logger:e,storageFactory:t,uploadedFileStorage:n,visualDiffScreenshotStorage:o,devicePixelRatio:i,generatorFactory:a,enricherFactory:s,authorization:c,settingsFactory:l,getOrgId:u,branchGetter:d,globalE2eStateManager:p}){let m=r.id,h=r.handshake.query.testId;if(!h)throw new Error("Socket connection request is missing testId");let g=await u({type:"e2e",testId:h}),f=await d?.();e=e.child({testId:h,orgId:g,sessionId:m,branch:f});let y=await a(g,e),S=await s(g,e),T=await l(g,e),A=await t(g),{testMetadata:b,baseUrl:C,envName:x,browserConfig:M,aiSettings:P,environmentVariables:U,localCodeEvalTools:V}=await Ki({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:T}),k=p.getSession(m);if(k)return e.info("Associating connection with existing session (likely reconnect)"),await k.controller.browser.clearAllCdpHighlights(),{type:"e2e",sessionId:m,orgId:g,testId:h};let z=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:z,event:"connect",args:r.handshake.query},"Websocket event (connect)"),z&&p.getCurrentConnectionsByIp(z)>=eW)throw e.error({clientIp:z,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(z);try{await tW({socket:r,baseUrl:C,envName:x,testMetadata:b,orgId:g,sessionId:m,logger:e,environmentVariables:U,clientIp:z,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:V,generator:y,enricher:S,browserConfig:M,aiSettings:P,globalE2eStateManager:p})}catch(Q){throw e.warn({err:Q},"Error setting up socket session, possibly due to client closing the connection"),p.releaseCapacityByIp(z),Q}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function tW({socket:r,baseUrl:e,envName:t,devicePixelRatio:n,testMetadata:o,orgId:i,sessionId:a,logger:s,storage:c,uploadedFileStorage:l,visualDiffScreenshotStorage:u,localCodeEvalTools:d,generator:p,environmentVariables:m,browserConfig:h,aiSettings:g,clientIp:f,enricher:y,globalE2eStateManager:S}){let T={viewport:o.advanced?.viewport??Kt,locale:o.advanced?.locale??So,timezoneId:o.advanced?.timezone??yo,geolocation:o.advanced?.geolocation??Eo,colorScheme:o.advanced?.colorScheme};n&&(T.deviceScaleFactor=n);let A=o.id,b=await pp({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 $r.init({baseUrl:e,userBrowserSettings:b,enricher:y,storage:c,logger:s,contextArgs:T,iconKnowledgeBase:null,callbacks:{onTabsChange:(V,k)=>{r.emit("tabs",{tabs:V,activeTab:k})},onScreencastFrame:(V,k)=>{let z=r;kr&&(z=r.compress(!0)),z.emit("screenshot",{buffer:V},()=>{k()})},onSvgsCollected:V=>{r.emit("newIconDetected",{numIcons:V.newSvgs.length}),c.saveNewIcons(V,s)},onNetworkLogs:V=>{r.emit("networkLogs",{harEntries:V})}}});await C.navigate({url:e,initialNavigation:!0});let x=new $o({browser:C,generator:p,logger:s,orgId:i,options:{scratchPadId:void 0,slowMoMs:b.slowMoMs,autoFollowNewTabs:b.autoFollowNewTabs,useMemory:g.useMemory,aiPageFiltering:g.aiPageFiltering},storage:c,localCodeEvalTools:d,uploadedFileStorage:l,visualDiffScreenshotStorage:u}),M=xI(r,a,s,S),P=async()=>{M.timers.forEach(V=>clearInterval(V))},U=new or({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:$r.USER_AGENT,viewport:x.browser.getViewport(),sessionId:a}),S.registerSession({controller:x,context:U,sessionId:a,cleanup:P,clientIp:f,socket:r})}async function Ki({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 vn({httpClient:new Bt({...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?.[Tt];if(!p)throw new Error("Base URL is empty in both test options and the configured environment");let m={...l?.variables};m=await mp({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 FS=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;Lt.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 ro({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},ro=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))Lt.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 FS({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId})}async finish(){this.sendFinalizedStepStats()}},Op=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 ro({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new ro({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new ro({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var US={currentlyExecutingRequests:{}},nW=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 Ki({testId:n,orgId:o,logger:r.logger,storage:a,authorization:r.authorization,settings:i}),l=`${n}|${c.baseUrl}`;try{let u=US.currentlyExecutingRequests[l]??0;US.currentlyExecutingRequests[l]=u+1,s=await oW({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),US.currentlyExecutingRequests[l]--}},oW=async({socket:r,steps:e,baseUrl:t,testMetadata:n,reInitialize:o,toStep:i,fromStep:a,storageFactory:s,aiSettings:c,browserConfig:l,metadata:u,logger:d,envName:p,testName:m,environmentVariables:h,localCodeEvalTools:g,done:f,cacheStorageFactory:y,globalE2eStateManager:S})=>{let{testId:T,sessionId:A,orgId:b}=u,C=A,x=S.getSession(A);if(!x)throw new Error("No active session found");let{controller:M,context:P}=x;M.setOpen(),d=d.child({testId:T,orgId:b,sessionId:A,runId:C}),d.info({steps:e.map(oe=>`${oe.type}${"command"in oe?` - ${oe.command.type}`:""}`),toStep:i,fromStep:a,reInitialize:o,envName:p,testName:m,baseUrl:t,context:P,browserConfig:l,aiSettings:c},"Socket execution parameters");let U=h??{},V=async()=>{o&&(await M.browser.reset({newUrl:t}),P.reset({baseUrl:t,currentUrl:M.browser.url(),variablesFromEnvironment:U,envName:p,testName:m}))},k=await s(b),z=await y(b),Q=async()=>{let oe=Date.now();try{await z.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:T,stepLists:{steps:e},logger:d})}catch(jt){d.error({err:jt},"Failed to fetch step cache entries from Momentic server. This can drastically reduce test reliability and performance.")}finally{Lt.distribution("cache-resolution",Date.now()-oe,["executor:editor"])}};try{await bl({promiseGenerator:async()=>Promise.all([V(),Q()]),signal:M.executeAbortController.signal,codePath:"resolveStepCacheAndInitBrowser"}),M.setOpen()}catch(oe){if(r.emit("finished"),oe.name!=="AbortError")throw new Error(`Failed to setup browser for execution: ${oe}`)}let Y=rW(e),Te={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},q={orgId:b,runId:C,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},it={controller:M,context:P,storage:k,codeEvalTools:g,usageTracker:new Ta,logger:d},Ge={test:{},step:{onDynamicAIActionStatusUpdateEvent:oe=>{r.emit("dynamicCommandStatusUpdate",oe)},onDynamicAIActionEvaluatingEvent:oe=>{r.emit("dynamicCommandEvaluating",oe)},onDynamicCommandGenerated:oe=>{r.emit("dynamicCommandGenerated",oe)},onDynamicCommandExecuted:oe=>{r.emit("dynamicCommandExecuted",oe)}}},Ye=new Op(r,k,b,T),Nt=await dp({fixtures:it,options:Te,callbacks:Ge,inputs:q,testParams:{tracer:Ye}}),Ie={logger:d,cacheStorage:z,orgId:b,testId:T,originalStepsWithCaches:{steps:Y},updatedStepsWithCaches:{steps:e}};return Nt?.status==="PASSED"?await Ku(Ie):Nt?.status==="FAILED"&&await Yu(Ie),await Ye.finish(),f?.(Nt),Nt.status};var MI={event:"execute",createHandler:nW};import{cloneDeep as iW}from"lodash-es";var aW=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=iW(e),s=cA(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})}}},II={event:"lintStep",createHandler:aW};var sW=({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=fi.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let T=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=T.resolution.locator,y={target:T.target,thoughts:T.thoughts}}catch(T){e.warn({err:T},"Failed resolving target with selector"),s({err:`Failed locating element: ${T.message}`,decisions:T instanceof _r?T.decisions:void 0});return}else try{let T=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:di(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&wc(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:T.target,thoughts:T.thoughts},S=T.resolution.locator}catch(T){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:T,html:A.slice(0,1e5)},"Failed locating element with AI")}catch(A){e.warn({err:A},"Failed grabbing HTML after trying to locate element with AI")}})(),s({err:`${T.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(T){e.warn({err:T},"Failed getting select options"),s({err:`Failed getting select options: ${T.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:T,width:A,height:b}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),C=await g.uploadScreenshot(T);y.screenshot={data:C,width:A,height:b},e.info({width:A,height:b},"Captured screenshot during locate")}catch(T){e.error({err:T},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${T.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(T){e.warn({err:T},"Error highlighting element, continuing...")}}},PI={event:"locate",createHandler:sW};var lW=({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")}}},OI={event:"mouseClickEvent",createHandler:lW};var cW=({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})}},LI={event:"recordTargetClick",createHandler:cW};var uW=({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}}},NI={event:"keyDownEvent",createHandler:uW};var dW=({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}}},DI={event:"keyUpEvent",createHandler:dW};var pW=({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")}}},kI={event:"mouseMoveEvent",createHandler:pW};var mW=({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}}},FI={event:"recordingStart",createHandler:mW};var hW=({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}},UI={event:"recordingStop",createHandler:hW};var gW=({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 Ki({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()},BI={event:"refresh",createHandler:gW};var fW=({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 Ki({testId:s,orgId:l,logger:t,storage:d,authorization:o,settings:u}),f=a.getSession(c);if(!f){r.emit("error",{message:"No session to reset"});return}let{controller:y,context:S}=f;await y.browser.reset({newUrl:p});let T=y.browser.baseUrl;S.reset({baseUrl:T,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),b=$r.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${T}`),r.emit("session",{url:T,userAgent:b,viewport:A,sessionId:c})},HI={event:"reset",createHandler:fW};var SW=({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})}},zI={event:"switchTab",createHandler:SW};async function GI(r){return _I(r)}var jI=[QA,MI,PI,HI,BI,YA,zI,II,LI,FI,UI,kI,OI,NI,DI,JA,XA];var VI=r=>{let{logger:e}=r,t=new yW(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 GI({...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}jI.forEach(i=>EW(i,{...r,socket:n,metadata:o,logger:e}))}),t},EW=(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 AW}from"express";import{Router as TW}from"express";import ac from"fs";import ic from"path";import{v4 as vW}from"uuid";import RW from"yaml";import{hostname as bW}from"os";var oc="2.28.0",et=Ma({app:"desktop-server",hostname:bW(),disableConsoleLogs:!0}).child({cliVersion:oc});(async()=>{try{let r=await Qn(et);r.gitBranchName&&et.addBinding("branch",r.gitBranchName)}catch{}})();var hs=TW();async function BS(r){return(await sd(r,et)).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)}hs.get("/",Me(async(r,e)=>{let t=se(),n=await Z(t),o=await BS(n);e.status(200).json(o)}));hs.post("/",Me(async(r,e)=>{let t;try{t=UT.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{go(t.name)}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=se(),o=(await Z(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=ic.join(n.rootDir,t.folderPath??"");if(!ac.existsSync(i)||!ac.statSync(i).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${i}' does not exist.`});return}let a=await ad({...t,folder:i,project:n});e.status(201).json(a)}));hs.get("/:moduleId",Me(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=await Z(se()),n=t.modules[r.params.moduleId];if(!n){e.status(404).json({error:"Module not found."});return}try{let o=await nn(n,t,E);e.json(o)}catch(o){e.status(400).json({err:o})}}));hs.post("/:moduleId/duplicate",Me(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=FT.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{go(t.name)}catch(g){e.status(400).json({error:g.message});return}let n=se(),o=await Z(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 nn(i,o,E),s=ic.join(n.rootDir,ic.dirname(i.relativePath));if(!ac.existsSync(s)||!ac.statSync(s).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${s}' does not exist.`});return}let c=Ue(t.name),l=ic.join(s,`${c}.module.yaml`),u=vW(),{stepsToSave:d}=await nt({stepLists:{steps:a.steps},createNewCacheIds:!0,cacheCreationParams:{orgId:wt()}}),p={fileType:he.MODULE,schemaVersion:Ce,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=RW.stringify(p);ac.writeFileSync(l,m,"utf-8");let h={relativeFilePath:ic.relative(n.rootDir,l)};e.status(201).json(h)}));hs.patch("/:moduleId/metadata",Me(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=BT.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=se(),o=await Z(n);_A({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:E,project:n}),e.status(201).json({message:"ok"})}));var $I=hs;var WI=AW();WI.get("/",Me(async(r,e)=>{let t=se(),n=await Z(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 BS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var qI=WI;import{Router as wW}from"express";var HS=wW();HS.get("/",Me((r,e)=>{let t=ld(se(),et);e.status(200).json(t)}));HS.get("/names",Me((r,e)=>{let n=se().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var KI=HS;import{Router as CW}from"express";var YI=CW();YI.get("/",Me((r,e)=>{let t={userId:Po(),orgId:wt(),cliVersion:oc??"0.0.0"};e.status(200).json(t)}));var XI=YI;import{StreamableHTTPServerTransport as kq}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as Fq}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as Uq}from"crypto";import{Router as Bq}from"express";import{McpServer as Nq}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as Dq}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as PW}from"ai";import Dp from"dedent";import{z as Wo}from"zod";import{tool as xW}from"ai";import{z as _W}from"zod";var JI=(r,e)=>({builder:n=>xW({description:r.schema.description,inputSchema:_W.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
4364
|
`)},"Tool execution resulted in error"):n.logger.info({toolName:r.schema.name,input:o},"Tool execution completed"),a}}),tool:r});var sc=class{results=[];isError;addResult(e){this.results.push(e)}addError(e){this.results.push(`Error: ${e}`),this.isError=!0}getResult(){return this.results.join(`
|
|
4365
4365
|
`)}async serialize(){let e=[];return this.results.length&&(e.push("### Result"),e.push(this.results.join(`
|
|
4366
4366
|
`)),e.push("")),{content:[{type:"text",text:e.join(`
|
|
@@ -4795,7 +4795,7 @@ ${r.map(p=>`${bt}- ${p}`).join(`
|
|
|
4795
4795
|
`)}`),Object.values(e.tests).forEach(p=>{r.some(m=>p.relativePath.includes(m))&&c.add(p.fullFilePath)}))}else{!n&&!await Ut("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=gy.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 ut(u,X,e);if(mK.gt(d.schemaVersion,Ce)&&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:gy.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(dK)}function EO({testDefinitions:r,quarantinedTestReasons:e,onlyQuarantined:t=!1,skipQuarantined:n=!1}){if(t){let[u,d]=rm(r,h=>h.id in e),[p,m]=rm(u,h=>h.disabled||n);return{testsToSkip:p,quarantinedTestsToSkip:[],testsToRun:m,quarantinedTestsToRun:[]}}let[o,i]=rm(r,u=>u.disabled),[a,s]=rm(i,u=>u.id in e);return{testsToSkip:o,testsToRun:s,quarantinedTestsToRun:n?[]:a,quarantinedTestsToSkip:n?a:[]}}function bO({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 TO({project:r,apiClient:e}){let t=await Z(r),n=await vs({tests:[],momenticFiles:t,yes:!0,project:r,logger:new vi(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(`
|
|
4796
4796
|
`))}async function vO({test:r,reason:e,apiClient:t,project:n,identity:o}){let i=(await Z(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 em({prompt:"Select a test to unquarantine.",inputtedTest:r,testOptions:l}),d=await tm({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 RO(r){return r?Ue(r):"Unknown suite"}async function AO({client:r,orgId:e,suitePaths:t,wait:n,waitTimeout:o,...i}){let{suiteRunIds:a,runGroupIds:s}=await r.queueSuiteRuns({paths:t,...i});X.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 Iu({name:"suites",getResults:async()=>{let f=s.filter(T=>!u.some(A=>A.id===T)),y=await r.bulkGetRunGroupStatus(f),S=[];for(let T of y)d(T)?u.push(T):S.push(T);return[...u,...S]},timeoutMs:o?o*1e3:void 0,checkDone:f=>(f.forEach(y=>{y.status==="RUNNING"&&(l.has(y.id)||(l.add(y.id),E.log(`${l.size}/${s.length} ${RO(y.suite?.name)}`)))}),f.every(d))}),m=r.getAppUrl(),g=Ia({results:p,startTime:c,onFailed:f=>{let y=RO(f.suite?.name),S=f.runs.filter(A=>A.status==="FAILED").length,T=f.runs.length;E.error(`${y} (${S}/${T} tests failed):`);for(let A of f.runs)if(A.status==="FAILED"){let b=A.testName||A.test?.name;E.error(` ${b?Ue(b):"Unknown test"} (${m}/runs/${A.id})`)}},entity:"suite",getDisplayLine:f=>` ${f.suite?.name?Ue(f.suite.name):"Unknown suite name"} (${m}/run-groups/${f.id})`});process.exit(g.failed>0?1:0)}async function wO({tests:r,client:e,orgId:t,...n}){!n.yes&&!await Ut(`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(X.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 Iu({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} ${Ue(g)}`)}}),m.every(c))}),p=Ia({results:d,startTime:u,onFailed:m=>{let h=m.testName||m.test?.name;Pu(m,h?Ue(h):"Unknown test")},getDisplayLine:m=>{let h=m.testName||m.test?.name,g=` ${h?Ue(h):"Unknown test"}`;return m.id&&(g+=` (${l}/runs/${m.id})`),g},entity:"test"});process.exit(p.failed>0?1:0)}import{randomUUID as QK}from"crypto";import ZK from"fs";import{existsSync as xK,mkdirSync as _K,statSync as MK}from"fs";import{randomUUID as CO}from"crypto";import fy from"fs";import{hostname as hK}from"os";import Sy from"path";async function nm(r,e,t,n){if(n){let o=await e.getScreenshot(r,n);if(o){let i=`${n}-screenshot.jpeg`,a=Sy.join(t,i);return fy.writeFileSync(a,o),i}}}async function gK(r,e,t,n){let o=n.runId??CO(),i={uuid:o,historyId:o,testCaseId:n.test.id,fullName:n.test.name,name:Ue(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:hK()},{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[s,c]of Object.entries(n.parameters))c!=null&&i.parameters.push({name:s,value:JSON.stringify(c)});n.results&&await fK(r,e,t.folder,i.steps,n.results);let a=`${o}-result.json`;fy.writeFileSync(Sy.join(t.folder,a),JSON.stringify(i,void 0,2))}async function Rs(r,e,t,n){let o={name:rn(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 nm(r,e,t,n.beforeSnapshot);i&&o.attachments.push({name:"Screenshot before step",source:i,type:"image/jpeg"});let a=await nm(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){let s=`${CO()}-attachment.json`,c=Sy.join(t,s);fy.writeFileSync(c,JSON.stringify(n.data,null,2)),o.attachments.push({name:"Step output data",source:s,type:"text/plain"})}return o}async function fK(r,e,t,n,o){for(let i of o)switch(i.type){case"PRESET_ACTION":{n.push(await Rs(r,e,t,i));break}case"CONDITIONAL":{let a=await Rs(r,e,t,i);a.steps=[],i.assertionResult&&a.steps.push(await Rs(r,e,t,i.assertionResult)),a.steps.push(...await Promise.all(i.results.map(s=>Rs(r,e,t,s)))),n.push(a);break}case"AI_ACTION":case"SECTION":case"MODULE":{let a=await Rs(r,e,t,i);if(a.steps=await Promise.all(i.results.map(s=>Rs(r,e,t,s))),i.type==="MODULE"&&i.inputs){a.parameters=[];for(let[s,c]of Object.entries(i.inputs))a.parameters.push({name:s,value:c})}n.push(a)}}}async function xO(r,e,t,n){for(let o of n.runs)await gK(r,e,{folder:t,suiteName:n.suiteName},o)}import SK from"junit-report-builder";import om from"path";function yK(r,e){if(e.name(r.test.name).className(r.test.name).file(om.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=Bc[r.failureDetails?.classification?.reason||r.failureReason],n=r.failureDetails?.classification?.summary||da[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 EK(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();yK(u,d)}for(let u of a){let d=l.testCase();d.name(u.name).className(u.name).file(om.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(om.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 _O(r,e){let t=SK.newBuilder();EK(t,e),t.writeTo(om.join(r,`${e.suiteName}.xml`))}import bK from"fs";import TK from"path";function MO(r){return{title:rn(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(MO):[]}}async function vK(r,e,t,n){if(n.results?.length){let o=await nm(r,e,t,n.results[n.results.length-1].afterSnapshot);return o?[{name:"Final state screenshot",path:o,contentType:"image/jpeg"}]:[]}return[]}async function RK(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||da[n.failureReason]}:void 0,retry:n.attempts-1,steps:n.results?.map(MO)||[],startTime:n.lastAttemptStartedAt.toISOString(),attachments:await vK(r,e,t,n)}}async function AK(r,e,t,n){return{expectedStatus:"passed",status:n.status==="PASSED"?"expected":"unexpected",results:[await RK(r,e,t,n)]}}async function wK(r,e,t,n){return{tags:[],title:n.test.name,ok:n.status==="PASSED",tests:[await AK(r,e,t,n)],id:n.runId,file:n.filePath}}function yy(r,e){return r.reduce((t,n)=>e(n)?t+1:t,0)}async function CK(r,e,t,n){return{suites:[{title:n.suiteName,file:n.projectConfigPath,specs:await Promise.all(n.runs.map(o=>wK(r,e,t,o)))}],errors:[],stats:{startTime:n.startedAt.toISOString(),duration:n.finishedAt.getTime()-n.startedAt.getTime(),expected:yy(n.runs,o=>o.status==="PASSED"),unexpected:yy(n.runs,o=>o.status!=="PASSED"),flaky:yy(n.runs,o=>!!o.isFlake),skipped:0}}}async function IO(r,e,t,n){let o=await CK(r,e,t,n);bK.writeFileSync(TK.join(t,`${n.suiteName}.json`),JSON.stringify(o,null,2))}async function PO(r,e,t,n,o){switch(xK(o)?MK(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...`),_K(o,{recursive:!0})),t){case"junit":_O(o,n);return;case"allure":case"allure-json":await xO(r,e,o,n);return;case"playwright-json":await IO(r,e,o,n);return;default:throw new Error(`Unknown reporter format requested: '${t}'`)}}import e2 from"wait-on";import{execSync as IK}from"child_process";import{platform as PK}from"os";function Ey(){return OO()?(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.
|
|
4797
4797
|
`),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.
|
|
4798
|
-
`),1)}function OO(){return PK()==="darwin"&&IK("system_profiler SPDisplaysDataType").toString().includes("Retina")}function by(r){OO()&&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 OK from"@actions/exec";import LK from"@actions/io";import NK from"quote";import DK from"string-argv";async function LO(r,e=!0){let t=DK(r),n=await LK.which(t[0],!0),o=t.slice(1),i=OK.exec(NK(n),o,{delay:100});if(e)return i}import kK from"csv-parser";import{createReadStream as FK}from"fs";function Ty(r){return new Promise((e,t)=>{let n=[];FK(r).pipe(kK()).on("data",o=>n.push(o)).on("end",()=>e(n)).on("error",o=>t(o))})}import As from"semver";import{z as im}from"zod";var wr="2.27.2",UK="https://registry.npmjs.org/momentic",BK=im.object({versions:im.record(im.string(),im.unknown()).optional()});async function Zt(r){try{await HK(r)}catch(e){E.warn({err:e},"Failed to check CLI version against NPM servers")}}async function vy(){let r=await j(fetch(UK),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=BK.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=wr;for(let o of Object.keys(t))As.valid(o)&&As.major(o)===As.major(wr)&&As.gt(o,n)&&As.prerelease(o)===null&&(n=o);return n}async function HK(r){let e;for(let t=0;t<2;t++)try{e=await vy()}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}As.eq(wr,e)||(E.warn(`Update available: v${wr} -> 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 io(){try{await j(Promise.all([lR(),Lt.flush()]),{milliseconds:5e3})}catch{}}import{partition as zK}from"lodash-es";function am(r){return r.length===1?"test":"tests"}function NO(r){return r===1?"1 worker":`${r} workers`}function DO(r){r.length!==0&&(E.info(`Skipping ${r.length} disabled ${am(r)}:`),r.forEach(e=>{E.info(`${bt}- ${[e.relativeFilePath]}`)}),E.log(""))}function kO(r,e){r.length!==0&&(E.info(`Skipping ${r.length} quarantined ${am(r)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),E.log(""))}function GK(r,e){r.length!==0&&(E.info(`Running ${r.length} quarantined ${am(r)} with ${NO(e)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),E.log(""))}function jK(r,e,t){e.length===0&&r.length>0||(E.info(`Running ${e.length} ${am(e)} with ${NO(t)}:`),e.forEach(n=>{E.info(`${bt}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),E.log(""))}function FO({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]=zK(e,s=>s.quarantined);GK(i,t),jK(i,a,t)}import{cloneDeep as ws}from"lodash-es";async function UO({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 sr({orgId:r,s:c,localTools:e,logger:t,context:o})}return i}async function BO({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 pp({settings:h,customHeaders:p,envVariables:u,envName:e,testName:t,baseUrl:r,logger:d,localTools:s,orgId:l}),T={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:X,mode:"runner"},A=S.browserType??"Chromium";if(!pR(A)){let M=`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(M),X.warn(M)}let b=await $r.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new xo(T,c),contextArgs:{viewport:i.advanced.viewport??Kt,locale:i.advanced.locale??So,geolocation:i.advanced.geolocation??Eo,timezoneId:i.advanced.timezone??yo,colorScheme:i.advanced.colorScheme,deviceScaleFactor:n},callbacks:{onNetworkPage:M=>y.onNetworkPage(M),onNetworkLogs:M=>y.onNetworkLogs(M)},iconKnowledgeBase:null,videoOptions:y.videoOutputPath?{videoOutputPath:y.videoOutputPath,onVideoPageChange:({videoName:M})=>{y.setActiveVideo(M)}}:void 0}),C=new $o({browser:b,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 or({baseUrl:r,currentUrl:C.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async M=>{let{name:P,defaultValue:U,required:V}=M,k=m?.[P];V&&k===void 0&&(E.error(`Required parameter '${P}' is required by test '${i.name}' but not provided`),process.exit(1));let z=await sr({orgId:l,s:k??U,localTools:s,logger:d,context:or.dummyContext(x.getEnvName())});x.setMomenticSystemVariable(P,z)})),{controller:C,context:x}}async function HO({testAdvancedSettings:r,orgSettings:e,logger:t}){if(r.failureRecovery===!1||r.failureRecovery===void 0&&!e?.failureRecovery)return!1;if(!Ri){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 zO({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 HO({testAdvancedSettings:p.advanced,orgSettings:m.ai,logger:l})};return await dp({fixtures:h,inputs:g,options:f,callbacks:{step:{},test:{onTestComplete:async()=>{await i.browser.cleanup()}}},testParams:{tracer:d}})}async function GO(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await VK(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 VK(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 Pa(n,o),y=Io({orgId:o,client:n,gitMetadata:l,regenerateCache:u.regenerateCache??!1,alwaysSaveCache:u.alwaysSaveCache??!1,noCache:u.noCache??!1,bustOldestCachePercentage:u.bustOldestCachePercentage}),S=await Gu({cacheStorage:y,logger:c,schemaVersion:e.schemaVersion,stepLists:{steps:e.steps,beforeSteps:e.beforeSteps,afterSteps:e.afterSteps},testId:e.id}),T=S.steps,A=S.beforeSteps??void 0,b=S.afterSteps??void 0,C=r.envName??WK(e),x,M={};if(C){try{x=Oi(C,t,c)}catch(k){let z=`Failed to resolve environment ${C} for test ${e.name}: ${k}`;throw new Error(z)}M=x.variables}let P=e.baseUrl;if(i)P=i;else if(!P){let k=M[Tt];typeof k=="string"&&(P=k)}if(!P){let k=`Cannot run test with no base URL and no ${Tt} variable defined in its environment`;throw new Error(k)}let U=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:P,environmentName:C,schemaVersion:e.schemaVersion,resolvedInputs:p,quarantined:m,quarantinedReason:h}),V=c.child(U.loggerBindings||{});Object.entries(U.envVarBindings||{}).forEach(([k,z])=>{M[k]=z});try{let k=await $K({...r,variables:M,envName:C,resolvedEnv:x,baseUrl:P,storageClient:f,tracer:U,logger:V,cacheStorage:y,stepsWithCaches:T,beforeStepsWithCaches:A,afterStepsWithCaches:b,usageTracker:g});return await U.finish({logger:c,status:k.status,finishedAt:k.finishedAt,failureDetails:k.failureDetails,failureReason:k.failureReason,isFlake:k.isFlake,failureRecoveryDetails:k.failureRecoveryDetails}),{runId:U.runId,...k}}finally{a?.pop()}}async function $K(r){let{testDefinition:e,stepsWithCaches:t,beforeStepsWithCaches:n,afterStepsWithCaches:o,project:i,regenerateGoldenFiles:a,apiClient:s,generator:c,baseUrl:l,storageClient:u,orgId:d,envName:p,urlOverride:m,customHeaders:h,testInputs:g,variables:f,resolvedEnv:y,retriesOverride:S,devicePixelRatio:T,logUpdate:A,tracer:b,logger:C,cacheStorage:x,gitMetadata:M,quarantined:P,quarantinedReason:U,usageTracker:V}=r,k=i.config.ai?.aiFailureAnalysis??!1,z=new Date,Q=new $a(i,a),Y={...i.config},Te={envName:p,urlOverride:m,customHeaders:h,testInputs:g},q,it=Math.abs(S??i.config.retries??e.retries??0),Ge=[];C.info({...M,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let Ye=0;Ye<=it;Ye++){let Nt=await b.startAttempt(),Ie=C.child(Nt.loggerBindings||{}),oe={...e,steps:ws(t),beforeSteps:ws(n),afterSteps:ws(o)};Ye!==0&&A("RETRY",`attempt ${Ye+1}/${it+1}`);let jt=new Date,Fn=Y.advanced?.fakerConstantSeed,Un=new vn({httpClient:new Bt({baseUrl:s.baseUrl,apiKey:s.apiKey,logger:Ie,mode:"runner"}),fakerSeed:Fn?Ca:void 0}),cm=Nt;try{let{controller:Bn,context:Qo}=await BO({tracer:Nt,baseUrl:l,envName:p,testName:oe.name,apiClient:s,devicePixelRatio:T,logger:Ie,storageClient:u,codeEvalTools:Un,test:oe,generator:c,orgId:d,variables:f,customHeaders:h,testInputs:g,localBrowserConfig:{...i.config.browser||{},...y?.browser||{},...oe.advanced},aiSettings:{...i.config.ai||{},...oe.advanced||{}},visualDiffScreenshotStorage:Q});q=await zO({attemptMetadata:{attemptNumber:Ye+1,orgId:d,runId:b.runId},attemptFixtures:{logger:Ie,storageClient:u,usageTracker:V,codeEvalTools:Un,apiClient:s,context:Qo,controller:Bn,tracer:Nt},attemptInputs:{test:oe,orgSettings:Y}});let Cr=new Date,pn={logger:C,cacheStorage:x,orgId:d,testId:e.id,originalStepsWithCaches:{steps:ws(t),beforeSteps:ws(n),afterSteps:ws(o)},updatedStepsWithCaches:{steps:oe.steps,beforeSteps:oe.beforeSteps,afterSteps:oe.afterSteps}};q?.status==="PASSED"?await Ku(pn):q?.status==="FAILED"&&Ye===it&&await Yu(pn),await Nt.finish({logger:Ie,result:q}),Ge.unshift(q.status);let Zo=await UO({orgId:d,codeEvalTools:Un,logger:Ie,outputDefinitions:e.outputs??[],testContext:Qo}),K=Ob(Ge),yc=Ye+1;if(q.status!=="FAILED")return{...q,parameters:Te,test:oe,filePath:oe.relativeFilePath,startedAt:z,lastAttemptStartedAt:jt,finishedAt:Cr,attempts:yc,baseUrl:l,outputs:Zo,isFlake:K,quarantined:P,quarantinedReason:U};let ao=q.failedStepResult,Kr=ao?.message||"Unknown failure",so=ao?.failureReason??HE(Kr)??"UnknownError",Cs=Ie.child({errResult:ao,failureReason:so,errorMessage:Kr,numAttempts:it+1,name:oe.name});if(Ye<it){Cs.warn(`Retrying failed execution attempt for run: ${Kr}`);continue}Cs.error(`Test failed after all exhausting attempts: ${Kr}`);let xs=new Error(Kr),_s={errorMessage:Kr,errorStack:xs.stack},Zi;if(k){let Hn;try{if(q.results&&q.results.length>0){let{classification:Ec,aiFailureReason:um}=await TA({logger:Ie,browserStateStorage:cm,generator:c,fullResults:q,failureReason:so,error:xs,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Hn=Ec,Zi=um}}catch(Ec){Ie.warn({err:Ec},"Failed to classify test results")}Hn&&(_s.classification=Hn,so=Zi??so)}return{...q,parameters:Te,failureDetails:_s,failureReason:so,test:oe,filePath:oe.relativeFilePath,startedAt:z,lastAttemptStartedAt:jt,finishedAt:Cr,attempts:Ye+1,baseUrl:l,outputs:Zo,quarantined:P,quarantinedReason:U}}catch(Bn){Is(Bn);let Qo=`Encountered fatal platform error while running test '${oe.name}': ${Bn}`,Cr=new Date,pn=Ye+1;Ie.error({err:Bn},Qo),E.error(Qo);let Zo={errorMessage:Bn.message,errStack:Bn.stack},K={status:"FAILED",failureDetails:Zo,failureReason:"InternalPlatformError",finishedAt:Cr};return await Nt.finish({logger:Ie,result:{status:"FAILED",results:[]}}),{...K,results:[],parameters:Te,test:oe,filePath:oe.relativeFilePath,startedAt:z,lastAttemptStartedAt:jt,finishedAt:new Date,attempts:pn,baseUrl:l,outputs:{},quarantined:P,quarantinedReason:U}}}throw new Error("This code should not be reachable")}function WK(r){for(let e of r.envs??[])if(e.default)return e.name}import YK from"adm-zip";import XK from"path";var gr="assets";function qK(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 Qi=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(`${gr}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${gr}/${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))Lt.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 Ry(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:qK(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}};function KK(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var Ry=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:`${gr}/${t}.jpeg`,contents:n})}attachAfterScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${gr}/${t}.jpeg`,contents:n})}attachBeforeHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${gr}/${t}.html`,contents:n})}attachAfterHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${gr}/${t}.html`,contents:n})}recordTargetAutoHeal(e){let{healType:t}=e,n=t==="AI"?"ai-target-heal":"cache-heal";Lt.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;Lt.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:KK(e.status),finishedAt:e.finishedAt}))))}async finish(e){await this.finishInternal(e.step)}async startSubSteps(){let e=new Qi(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}};var gc=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(gr),this.harPagesStream=this.diskStorage.createFileStream(`${gr}/har-pages.log`),this.inProgressHarEntries={},this.harEntriesStream=this.diskStorage.createFileStream(`${gr}/har-entries.log`)}finished=!1;children=[];harPagesStream;inProgressHarEntries;harEntriesStream;get loggerBindings(){return{runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return XK.resolve(this.diskStorage.cwd(),"assets")}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)}
|
|
4798
|
+
`),1)}function OO(){return PK()==="darwin"&&IK("system_profiler SPDisplaysDataType").toString().includes("Retina")}function by(r){OO()&&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 OK from"@actions/exec";import LK from"@actions/io";import NK from"quote";import DK from"string-argv";async function LO(r,e=!0){let t=DK(r),n=await LK.which(t[0],!0),o=t.slice(1),i=OK.exec(NK(n),o,{delay:100});if(e)return i}import kK from"csv-parser";import{createReadStream as FK}from"fs";function Ty(r){return new Promise((e,t)=>{let n=[];FK(r).pipe(kK()).on("data",o=>n.push(o)).on("end",()=>e(n)).on("error",o=>t(o))})}import As from"semver";import{z as im}from"zod";var wr="2.28.0",UK="https://registry.npmjs.org/momentic",BK=im.object({versions:im.record(im.string(),im.unknown()).optional()});async function Zt(r){try{await HK(r)}catch(e){E.warn({err:e},"Failed to check CLI version against NPM servers")}}async function vy(){let r=await j(fetch(UK),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=BK.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=wr;for(let o of Object.keys(t))As.valid(o)&&As.major(o)===As.major(wr)&&As.gt(o,n)&&As.prerelease(o)===null&&(n=o);return n}async function HK(r){let e;for(let t=0;t<2;t++)try{e=await vy()}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}As.eq(wr,e)||(E.warn(`Update available: v${wr} -> 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 io(){try{await j(Promise.all([lR(),Lt.flush()]),{milliseconds:5e3})}catch{}}import{partition as zK}from"lodash-es";function am(r){return r.length===1?"test":"tests"}function NO(r){return r===1?"1 worker":`${r} workers`}function DO(r){r.length!==0&&(E.info(`Skipping ${r.length} disabled ${am(r)}:`),r.forEach(e=>{E.info(`${bt}- ${[e.relativeFilePath]}`)}),E.log(""))}function kO(r,e){r.length!==0&&(E.info(`Skipping ${r.length} quarantined ${am(r)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),E.log(""))}function GK(r,e){r.length!==0&&(E.info(`Running ${r.length} quarantined ${am(r)} with ${NO(e)}:`),r.forEach(t=>{E.info(`${bt}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),E.log(""))}function jK(r,e,t){e.length===0&&r.length>0||(E.info(`Running ${e.length} ${am(e)} with ${NO(t)}:`),e.forEach(n=>{E.info(`${bt}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),E.log(""))}function FO({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]=zK(e,s=>s.quarantined);GK(i,t),jK(i,a,t)}import{cloneDeep as ws}from"lodash-es";async function UO({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 sr({orgId:r,s:c,localTools:e,logger:t,context:o})}return i}async function BO({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 pp({settings:h,customHeaders:p,envVariables:u,envName:e,testName:t,baseUrl:r,logger:d,localTools:s,orgId:l}),T={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:X,mode:"runner"},A=S.browserType??"Chromium";if(!pR(A)){let M=`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(M),X.warn(M)}let b=await $r.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new xo(T,c),contextArgs:{viewport:i.advanced.viewport??Kt,locale:i.advanced.locale??So,geolocation:i.advanced.geolocation??Eo,timezoneId:i.advanced.timezone??yo,colorScheme:i.advanced.colorScheme,deviceScaleFactor:n},callbacks:{onNetworkPage:M=>y.onNetworkPage(M),onNetworkLogs:M=>y.onNetworkLogs(M)},iconKnowledgeBase:null,videoOptions:y.videoOutputPath?{videoOutputPath:y.videoOutputPath,onVideoPageChange:({videoName:M})=>{y.setActiveVideo(M)}}:void 0}),C=new $o({browser:b,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 or({baseUrl:r,currentUrl:C.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async M=>{let{name:P,defaultValue:U,required:V}=M,k=m?.[P];V&&k===void 0&&(E.error(`Required parameter '${P}' is required by test '${i.name}' but not provided`),process.exit(1));let z=await sr({orgId:l,s:k??U,localTools:s,logger:d,context:or.dummyContext(x.getEnvName())});x.setMomenticSystemVariable(P,z)})),{controller:C,context:x}}async function HO({testAdvancedSettings:r,orgSettings:e,logger:t}){if(r.failureRecovery===!1||r.failureRecovery===void 0&&!e?.failureRecovery)return!1;if(!Ri){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 zO({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 HO({testAdvancedSettings:p.advanced,orgSettings:m.ai,logger:l})};return await dp({fixtures:h,inputs:g,options:f,callbacks:{step:{},test:{onTestComplete:async()=>{await i.browser.cleanup()}}},testParams:{tracer:d}})}async function GO(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await VK(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 VK(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 Pa(n,o),y=Io({orgId:o,client:n,gitMetadata:l,regenerateCache:u.regenerateCache??!1,alwaysSaveCache:u.alwaysSaveCache??!1,noCache:u.noCache??!1,bustOldestCachePercentage:u.bustOldestCachePercentage}),S=await Gu({cacheStorage:y,logger:c,schemaVersion:e.schemaVersion,stepLists:{steps:e.steps,beforeSteps:e.beforeSteps,afterSteps:e.afterSteps},testId:e.id}),T=S.steps,A=S.beforeSteps??void 0,b=S.afterSteps??void 0,C=r.envName??WK(e),x,M={};if(C){try{x=Oi(C,t,c)}catch(k){let z=`Failed to resolve environment ${C} for test ${e.name}: ${k}`;throw new Error(z)}M=x.variables}let P=e.baseUrl;if(i)P=i;else if(!P){let k=M[Tt];typeof k=="string"&&(P=k)}if(!P){let k=`Cannot run test with no base URL and no ${Tt} variable defined in its environment`;throw new Error(k)}let U=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:P,environmentName:C,schemaVersion:e.schemaVersion,resolvedInputs:p,quarantined:m,quarantinedReason:h}),V=c.child(U.loggerBindings||{});Object.entries(U.envVarBindings||{}).forEach(([k,z])=>{M[k]=z});try{let k=await $K({...r,variables:M,envName:C,resolvedEnv:x,baseUrl:P,storageClient:f,tracer:U,logger:V,cacheStorage:y,stepsWithCaches:T,beforeStepsWithCaches:A,afterStepsWithCaches:b,usageTracker:g});return await U.finish({logger:c,status:k.status,finishedAt:k.finishedAt,failureDetails:k.failureDetails,failureReason:k.failureReason,isFlake:k.isFlake,failureRecoveryDetails:k.failureRecoveryDetails}),{runId:U.runId,...k}}finally{a?.pop()}}async function $K(r){let{testDefinition:e,stepsWithCaches:t,beforeStepsWithCaches:n,afterStepsWithCaches:o,project:i,regenerateGoldenFiles:a,apiClient:s,generator:c,baseUrl:l,storageClient:u,orgId:d,envName:p,urlOverride:m,customHeaders:h,testInputs:g,variables:f,resolvedEnv:y,retriesOverride:S,devicePixelRatio:T,logUpdate:A,tracer:b,logger:C,cacheStorage:x,gitMetadata:M,quarantined:P,quarantinedReason:U,usageTracker:V}=r,k=i.config.ai?.aiFailureAnalysis??!1,z=new Date,Q=new $a(i,a),Y={...i.config},Te={envName:p,urlOverride:m,customHeaders:h,testInputs:g},q,it=Math.abs(S??i.config.retries??e.retries??0),Ge=[];C.info({...M,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let Ye=0;Ye<=it;Ye++){let Nt=await b.startAttempt(),Ie=C.child(Nt.loggerBindings||{}),oe={...e,steps:ws(t),beforeSteps:ws(n),afterSteps:ws(o)};Ye!==0&&A("RETRY",`attempt ${Ye+1}/${it+1}`);let jt=new Date,Fn=Y.advanced?.fakerConstantSeed,Un=new vn({httpClient:new Bt({baseUrl:s.baseUrl,apiKey:s.apiKey,logger:Ie,mode:"runner"}),fakerSeed:Fn?Ca:void 0}),cm=Nt;try{let{controller:Bn,context:Qo}=await BO({tracer:Nt,baseUrl:l,envName:p,testName:oe.name,apiClient:s,devicePixelRatio:T,logger:Ie,storageClient:u,codeEvalTools:Un,test:oe,generator:c,orgId:d,variables:f,customHeaders:h,testInputs:g,localBrowserConfig:{...i.config.browser||{},...y?.browser||{},...oe.advanced},aiSettings:{...i.config.ai||{},...oe.advanced||{}},visualDiffScreenshotStorage:Q});q=await zO({attemptMetadata:{attemptNumber:Ye+1,orgId:d,runId:b.runId},attemptFixtures:{logger:Ie,storageClient:u,usageTracker:V,codeEvalTools:Un,apiClient:s,context:Qo,controller:Bn,tracer:Nt},attemptInputs:{test:oe,orgSettings:Y}});let Cr=new Date,pn={logger:C,cacheStorage:x,orgId:d,testId:e.id,originalStepsWithCaches:{steps:ws(t),beforeSteps:ws(n),afterSteps:ws(o)},updatedStepsWithCaches:{steps:oe.steps,beforeSteps:oe.beforeSteps,afterSteps:oe.afterSteps}};q?.status==="PASSED"?await Ku(pn):q?.status==="FAILED"&&Ye===it&&await Yu(pn),await Nt.finish({logger:Ie,result:q}),Ge.unshift(q.status);let Zo=await UO({orgId:d,codeEvalTools:Un,logger:Ie,outputDefinitions:e.outputs??[],testContext:Qo}),K=Ob(Ge),yc=Ye+1;if(q.status!=="FAILED")return{...q,parameters:Te,test:oe,filePath:oe.relativeFilePath,startedAt:z,lastAttemptStartedAt:jt,finishedAt:Cr,attempts:yc,baseUrl:l,outputs:Zo,isFlake:K,quarantined:P,quarantinedReason:U};let ao=q.failedStepResult,Kr=ao?.message||"Unknown failure",so=ao?.failureReason??HE(Kr)??"UnknownError",Cs=Ie.child({errResult:ao,failureReason:so,errorMessage:Kr,numAttempts:it+1,name:oe.name});if(Ye<it){Cs.warn(`Retrying failed execution attempt for run: ${Kr}`);continue}Cs.error(`Test failed after all exhausting attempts: ${Kr}`);let xs=new Error(Kr),_s={errorMessage:Kr,errorStack:xs.stack},Zi;if(k){let Hn;try{if(q.results&&q.results.length>0){let{classification:Ec,aiFailureReason:um}=await TA({logger:Ie,browserStateStorage:cm,generator:c,fullResults:q,failureReason:so,error:xs,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Hn=Ec,Zi=um}}catch(Ec){Ie.warn({err:Ec},"Failed to classify test results")}Hn&&(_s.classification=Hn,so=Zi??so)}return{...q,parameters:Te,failureDetails:_s,failureReason:so,test:oe,filePath:oe.relativeFilePath,startedAt:z,lastAttemptStartedAt:jt,finishedAt:Cr,attempts:Ye+1,baseUrl:l,outputs:Zo,quarantined:P,quarantinedReason:U}}catch(Bn){Is(Bn);let Qo=`Encountered fatal platform error while running test '${oe.name}': ${Bn}`,Cr=new Date,pn=Ye+1;Ie.error({err:Bn},Qo),E.error(Qo);let Zo={errorMessage:Bn.message,errStack:Bn.stack},K={status:"FAILED",failureDetails:Zo,failureReason:"InternalPlatformError",finishedAt:Cr};return await Nt.finish({logger:Ie,result:{status:"FAILED",results:[]}}),{...K,results:[],parameters:Te,test:oe,filePath:oe.relativeFilePath,startedAt:z,lastAttemptStartedAt:jt,finishedAt:new Date,attempts:pn,baseUrl:l,outputs:{},quarantined:P,quarantinedReason:U}}}throw new Error("This code should not be reachable")}function WK(r){for(let e of r.envs??[])if(e.default)return e.name}import YK from"adm-zip";import XK from"path";var gr="assets";function qK(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 Qi=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(`${gr}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${gr}/${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))Lt.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 Ry(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:qK(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}};function KK(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var Ry=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:`${gr}/${t}.jpeg`,contents:n})}attachAfterScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${gr}/${t}.jpeg`,contents:n})}attachBeforeHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${gr}/${t}.html`,contents:n})}attachAfterHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${gr}/${t}.html`,contents:n})}recordTargetAutoHeal(e){let{healType:t}=e,n=t==="AI"?"ai-target-heal":"cache-heal";Lt.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;Lt.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:KK(e.status),finishedAt:e.finishedAt}))))}async finish(e){await this.finishInternal(e.step)}async startSubSteps(){let e=new Qi(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}};var gc=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(gr),this.harPagesStream=this.diskStorage.createFileStream(`${gr}/har-pages.log`),this.inProgressHarEntries={},this.harEntriesStream=this.diskStorage.createFileStream(`${gr}/har-entries.log`)}finished=!1;children=[];harPagesStream;inProgressHarEntries;harEntriesStream;get loggerBindings(){return{runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return XK.resolve(this.diskStorage.cwd(),"assets")}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)}
|
|
4799
4799
|
`)}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)}
|
|
4800
4800
|
`)):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 YK;i.addLocalFolder(o,void 0,a=>a!==".DS_Store"),this.diskStorage.storeFile({name:`${gr}/${Xh}`,contents:i.toBuffer()}),n.info({browserCrashZipName:Xh},"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:qu(n.results,t),beforeResults:n.beforeResults?qu(n.beforeResults,t):void 0,afterResults:n.afterResults?qu(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)}
|
|
4801
4801
|
`);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 Qi(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startMainStepList(){let e=new Qi(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startAfterStepList(){let e=new Qi(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async getScreenshot(e,t){return this.diskStorage.readFile(`${gr}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${gr}/${t}.html`)?.toString()}};import{randomUUID as JK}from"crypto";var fc=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{[U_]: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(){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 e=this.diskStorage.cd(`attempts/${this.metadata.attempts}`),t=JK(),n={id:t,schemaVersion:Ce,runAttemptSchemaVersion:Yv,startedAt:new Date,status:"RUNNING"};e.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)});let o=new gc(this.orgId,this.testId,this.testName,t,n,e,this.recordVideo);return this.children.push(o),o}};var Sc=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:Or.CLI,startedAt:new Date,status:"RUNNING",cliVersion:wr,labels:i??[]},c=new _l(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:wr,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 fc(this.orgId,e.testId,e.testName,e.runId,n,t,this.recordVideo);return this.children.push(o),o}};async function jO(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 VO(r){let{logger:e,tests:t,yes:n,start:o,waitOn:i,waitOnProxy:a,client:s,debugDataStorage:c,project:l,retriesOverride:u,urlOverride:d,envName:p,orgId:m,devicePixelRatio:h,customHeaders:g,testInputMatrix:f,reporter:y,include:S,exclude:T,labels:A,reporterDir:b=BA,outputDir:C=HA,uploadResults:x=!1,waitOnTimeout:M=60,parallel:P,shardIndex:U=1,shardCount:V=1,regenerateGoldenFiles:k,gitMetadata:z,cacheOptions:Q,ignoreQuarantine:Y,skipQuarantined:Te,onlyQuarantined:q,runGroupId:it,recordVideo:Ge,timeoutMinutes:Ye}=r;if(o&&(e.info({orgId:m},`Executing start command: ${o}`),await LO(o,!1)),i){e.info({orgId:m},`Waiting for url: ${i} with timeout: ${M} seconds.`);let tt=a?new URL(a):void 0,zn;tt&&(zn={host:tt.hostname,port:tt.port?parseInt(tt.port):tt.protocol.startsWith("https")?443:80,auth:tt.username||tt.password?{username:tt.username,password:tt.password}:void 0}),await e2({resources:[i],interval:2500,timeout:M*1e3,headers:{Accept:"*/*"},followRedirect:!0,verbose:!1,log:!0,strictSSL:!1,proxy:zn})}let Nt=new qn(l.config.ai?.agentConfig,{baseUrl:s.baseUrl,apiKey:s.apiKey,logger:e,mode:"runner"}),Ie=await Z(l),oe=await vs({tests:t,momenticFiles:Ie,yes:n,project:l,include:S,exclude:T,labels:A,logger:E}),jt=await jO(e,s,Y),{testsToSkip:Fn,quarantinedTestsToSkip:Un,testsToRun:cm,quarantinedTestsToRun:Bn}=EO({testDefinitions:oe,quarantinedTestReasons:jt,onlyQuarantined:q,skipQuarantined:Te});DO(Fn),kO(Un,jt);let Qo=bO({testsToRun:cm,quarantinedTestsToRun:Bn,quarantinedTestReasons:jt,testInputMatrix:f}),Cr=r2({globalTestsToRunWithInputs:Qo,shardIndex:U,shardCount:V});FO({logger:e,localTestsToRunWithInputs:Cr,parallel:P,shardCount:V,shardIndex:U});let pn=[],Zo=new Date,K=new Set,yc=async()=>{let tt=s.getAppUrl(),zn=Ia({results:pn,startTime:Zo.getTime(),onFailed:fr=>{Pu(fr,fr.filePath)},getDisplayLine:fr=>{let ei=`${bt}- ${fr.filePath}${fr.failureRecoveryDetails?" [recovered] ":""}`;return fr.runId&&(ei+=` ( link when uploaded: ${tt}/runs/${fr.runId} )`),ei},entity:"test"}),bc=pn.filter(fr=>!!fr.failureRecoveryDetails?.attempts);return bc.length>0&&E.warn(`Our AI agent automatically prevented ${bc.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.
|
|
3
|
+
"version": "2.28.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "momentic",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.28.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@actions/exec": "^1.1.1",
|
|
12
12
|
"@actions/io": "^1.1.3",
|