momentic 2.21.0 → 2.21.1
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 +4 -4
- package/npm-shrinkwrap.json +50 -16
- package/package.json +2 -2
package/bin/cli.js
CHANGED
|
@@ -24,8 +24,8 @@ ${this.decisions.map(e=>e.toString()).join(`
|
|
|
24
24
|
`);process.stderr.write(`${o}
|
|
25
25
|
`),globalThis.console=e}}var ht=" ".repeat(6);function qb(r,e="",t=!1){let n=process.stdout?.columns||process.stderr?.columns||80,o=Math.max(n-e.length,20),i=r.split(`
|
|
26
26
|
`),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(`
|
|
27
|
-
`)}import $k from"fetch-retry";import Wk from"os";import Kb,{multistream as qk}from"pino";import Kk from"pino-pretty";import Yk from"pino-std-serializers";var sa=new Map,Xk=!0,Yb="Log throttle exceeded",Jk=100,Qk=5e3,Zk=$k(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}}),Th=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??Wk.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=Xk?Kb(a):Kb(a,qk([{stream:Kk({colorize:!0})}]))}getLevel(){return Yc[this.minLevelValue]}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 Zk(this.site,{method:"POST",headers:{"Content-Type":"application/json","signoz-access-token":"CumAaTMUcwjt05OddAmefKgshbhfRmWxzxih"},body:li(e),signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`Got error status (${t.statusText}) from SigNoz`)}catch(t){this.consoleLogger.warn({err:t},"Failed to log to Momentic's observability provider, continuing...")}}shouldAllowLog(e){if(e===Yb)return!0;let t=Date.now();return t-this.lastWindowStart>Qk&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,Yb),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<Jk?(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(Bs[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=Yk.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:BT({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,sa.set("app",this),sa.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=Yc[e]):(this.minLevelValue=Bs[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},ru=({app:r,hostname:e,disableConsoleLogs:t})=>(sa.has(r)||sa.set(r,new Th({bindings:{app:r},hostname:e,disableConsoleLogs:t})),sa.get(r));async function Jb(){await Promise.all([...sa.values()].map(r=>r.flush()))}import{hostname as e0}from"os";var ne=ru({app:"cli",hostname:e0(),disableConsoleLogs:!0}).child({cliVersion:"2.21.
|
|
28
|
-
`);console.warn(n),r.warn({stack:n,time:e},"NodeJS event loop blocked")},{threshold:1e3,trimFalsePositives:!0})}function p0(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}u0(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as KW}from"crypto";import ZI from"body-parser";import N$ from"cors";import D$ from"dedent";import{Router as nU}from"express";import er from"fs";import{globSync as oU}from"glob";import _t from"path";import Bh from"fs";import{z as T0}from"zod";var B="v1",Rh="cli",di="2.21.
|
|
27
|
+
`)}import $k from"fetch-retry";import Wk from"os";import Kb,{multistream as qk}from"pino";import Kk from"pino-pretty";import Yk from"pino-std-serializers";var sa=new Map,Xk=!0,Yb="Log throttle exceeded",Jk=100,Qk=5e3,Zk=$k(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}}),Th=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??Wk.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=Xk?Kb(a):Kb(a,qk([{stream:Kk({colorize:!0})}]))}getLevel(){return Yc[this.minLevelValue]}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 Zk(this.site,{method:"POST",headers:{"Content-Type":"application/json","signoz-access-token":"CumAaTMUcwjt05OddAmefKgshbhfRmWxzxih"},body:li(e),signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`Got error status (${t.statusText}) from SigNoz`)}catch(t){this.consoleLogger.warn({err:t},"Failed to log to Momentic's observability provider, continuing...")}}shouldAllowLog(e){if(e===Yb)return!0;let t=Date.now();return t-this.lastWindowStart>Qk&&(this.logsInCurrentWindow=0,this.droppedLogsInWindow&&this.log("error",void 0,Yb),this.droppedLogsInWindow=!1,this.lastWindowStart=t),this.logsInCurrentWindow<Jk?(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(Bs[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=Yk.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:BT({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,sa.set("app",this),sa.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=Yc[e]):(this.minLevelValue=Bs[e],this.consoleLogger.level=e)}enableConsoleLogs(){this.disableConsoleLogs=!1}},ru=({app:r,hostname:e,disableConsoleLogs:t})=>(sa.has(r)||sa.set(r,new Th({bindings:{app:r},hostname:e,disableConsoleLogs:t})),sa.get(r));async function Jb(){await Promise.all([...sa.values()].map(r=>r.flush()))}import{hostname as e0}from"os";var ne=ru({app:"cli",hostname:e0(),disableConsoleLogs:!0}).child({cliVersion:"2.21.1"});var r0=5;async function ou({getResults:r,checkDone:e,name:t,timeoutMs:n=18e5}){let o=Date.now(),i=0;for(;Date.now()-o<n;){let a;i>r0&&(T.error(`Failed to fetch ${t} status too many times.`),process.exit(1));try{a=await r(),i=0}catch(l){i++,ne.warn({err:l},"Failed to fetch run status, retrying..."),T.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))}T.error(`Timeout elapsed waiting for ${t} to complete (${Math.floor(n/1e3)}s).`),process.exit(1)}function la({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 Wb(()=>{if(c.forEach(u=>{T.log(""),o(u)}),c.length){T.log("");let u=c.length===1?"":"s";T.error(`${c.length} ${t}${u} failed:`),c.forEach(d=>{T.dimmed(n(d))})}if(l.length){T.log("");let u=l.length===1?"":"s";T.warn(`${l.length} ${t}${u} cancelled:`),l.forEach(d=>{T.dimmed(n(d))})}if(a.length){T.log("");let u=a.length===1?"":"s";T.success(`${a.length} ${t}${u} passed:`),a.forEach(d=>{T.dimmed(n(d))})}if(s.length){T.log("");let u=s.length===1?"":"s";T.warn(`${s.length} quarantined ${t}${u} failed:`),s.forEach(d=>{T.dimmed(n(d))})}if(i.length){T.log("");let u=i.length===1?"":"s";T.warn(`${i.length} quarantined ${t}${u} passed:`),i.forEach(d=>{T.dimmed(n(d))})}T.log(""),T.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 iu=(r,e)=>{if(!r.failureDetails||!r.failureReason)return;let t=mc[r.failureDetails?.classification?.reason||r.failureReason],n=r.failureDetails?.classification?.summary||qi[r.failureReason],o=r.failureDetails.classification?.rootCause;if(T.error(e),o){T.log(`${ht}- Error type: ${pn.dim(t)}`);let i="- Root cause analysis:",a=qb(`${i} ${o}`,`${ht} `,!1),s=a.indexOf(":");T.log(`${ht}${i} ${pn.dim(a.slice(s+1))}`)}else T.log(`${ht}Reason: ${pn.red(t)}`),T.log(`${ht}Description: ${pn.red(n)}`)},js=({status:r,testLogRef:e,getRunningTestsCount:t,getTotalTestsCount:n,additionalText:o})=>{r=r.toUpperCase();let i=r,a;r.includes("FAIL")?(i=pn.bgRed.white("FAIL"),a=3):r.includes("PASS")?(i=pn.bgGreen.white("PASS"),a=3):r.includes("START")?(i=pn.bgBlue.white("START"),a=2):r.includes("CANCEL")?(i=pn.bgRgb(191,68,11).white("CANCEL"),a=1):r.includes("RETRY")?(i=pn.bgRgb(191,68,11).white("RETRY"),a=2):r.includes("RUN")||r.includes("PROG")?(i=pn.bgMagenta.white("RUNNING"),a=0):(T.warn(`Unknown status tried to be logged in run test locally: ${r}`),a=0),t0||(i=`${i}`),T.log(`${i}${" ".repeat(a)} ${e} ${o?`${o} `:""}(${t()}/${n()})`)};import n0 from"fs";import{tmpdir as o0}from"os";import i0 from"path";import{registry as Vs}from"playwright-core/lib/server";import Qb from"proper-lockfile";var Zb=i0.join(o0(),"momenticBrowserInstallation");var bh=["chrome","chromium","chrome-for-testing","ffmpeg"],a0={Chromium:"chromium","Google Chrome":"chrome","Chrome for Testing":"chrome-for-testing"},ev={chrome:"chrome",chromium:"chromium","chrome-for-testing":"chromium-headless-shell",ffmpeg:"ffmpeg"};function tv(r){let e=ev[a0[r]??""]??"",t=Vs.findExecutable(e);return!t||t.installType==="none"?!1:vh(t)}function vh(r){let e=r.executablePath();return n0.existsSync(e)}function s0(r,e){let t=ev[r];if(!t)throw new Error(`Requested install of unknown browser type ${r}`);let n=Vs.findExecutable(t);if(!n||n.installType==="none")throw new Error(`Requested install of unknown browser type ${r}`);if(!(!e&&vh(n)))return n}async function l0({browser:r,force:e}){let t=s0(r,e);if(!t){T.info(`Browser '${r}' is already installed, skipping...`);return}T.info(`Installing browser '${r}'...`);try{await Vs.installDeps([t],!1),await Vs.install([t],!1)}catch(n){if(n.message.includes("Lock file is already being held")){T.warn("Another process is installing Playwright browsers. Waiting for completion before proceeding..");let o=Vs.findExecutable(r),i=5*60*1e3,a=Date.now();for(;Date.now()-a<i&&!vh(o);)T.info("Waiting for browser to finish installing..."),await new Promise(s=>setTimeout(s,5e3))}else throw n}}async function rv({rawBrowsers:r,force:e=!1,all:t=!1}){let n=t?bh:Array.from(new Set(r));try{await Qb.lock(Zb,{stale:1e3*60*5,update:1e3*60,realpath:!1,retries:{retries:30,factor:2,maxTimeout:15e3,minTimeout:500}})}catch(i){T.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 l0({browser:i,force:e})}catch(a){o=a,T.error(`Failed to install the ${i} browser: ${a}`)}}finally{await Qb.unlock(Zb,{realpath:!1})}if(o)throw o}import c0 from"blocked-at";import u0 from"why-is-node-running";function nv(r){d0(r),p0()}function d0(r){c0((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(`
|
|
28
|
+
`);console.warn(n),r.warn({stack:n,time:e},"NodeJS event loop blocked")},{threshold:1e3,trimFalsePositives:!0})}function p0(){process.on("SIGINT",()=>{if("_getActiveHandles"in process){let r=process._getActiveHandles();console.log("Active handles:",r.map(e=>e.constructor?.name))}u0(),setImmediate(()=>{setTimeout(()=>{process.exit(1)},2e3).unref()})})}import{randomUUID as KW}from"crypto";import ZI from"body-parser";import N$ from"cors";import D$ from"dedent";import{Router as nU}from"express";import er from"fs";import{globSync as oU}from"glob";import _t from"path";import Bh from"fs";import{z as T0}from"zod";var B="v1",Rh="cli",di="2.21.1";var ho=3.1783027;function m0(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 Et(r){return Math.ceil(Ah(r)/ho)}function Ah(r){let e=0;if(typeof r=="string"){let t=r;t=t.replaceAll(`
|
|
29
29
|
`,""),t=t.replaceAll(" ","");let n=m0(t);return t.length-n+ho*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+=Ah(t)}),e;if(typeof r=="object"){let t=r;return Object.keys(t).forEach(n=>{e+=String(n).length,n==="image_url"?(t[n]??{}).detail==="high"?e+=1105*ho:e+=85*ho:n==="source"&&typeof t[n]=="object"&&t[n]?.type==="base64"?e+=1600*ho:e+=Ah(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 go=class extends Error{constructor(e){super(e),this.name="TimeoutError"}};var ov=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(ov(p));l=()=>c(ov(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 go(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 au=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 h0=9e4,g0=3,f0=1500,S0=15e3,Wr=class extends Error{status;rawError;constructor(e,t,n,o={}){super(n,o),this.status=e,this.rawError=t}};async function y0(r){return r.text().then(e=>{try{return JSON.parse(e).error}catch{return e}})}var wh=class{baseUrl;logger;constructor(e){this.baseUrl=e.baseUrl,this.logger=e.logger}getHeaders(){let e={"Content-Type":"application/json"};return di&&(e[Qc]=di),Rh&&(e[VT]=Rh),e}async sendRequest(e,t){let{retries:n=g0,requestTimeoutMs:o=h0,initialRetryDelayMs:i=f0,maxRetryDelayMs:a=S0}=t,s=n,c=n,l,u={path:e,baseUrl:this.baseUrl,method:t.method};for(;s>0;)try{return s--,await this.sendSingleRequestHelper(e,t,o)}catch(d){if(l=d,d instanceof Wr&&d.status>=400&&d.status<500)throw d;if(d instanceof Error&&d.name==="AbortError"&&(l=new go),s===0)throw l;let p=c-s,m=Math.min(i*Math.pow(2,p-1),a);await new Promise(h=>setTimeout(h,m))}throw this.logger.warn({...u,err:l},"Got fatal error response from Momentic server"),l}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 y0(u);throw new Wr(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)}}},Nt=class extends wh{apiKey;constructor(e){super(e),this.apiKey=e.apiKey}getHeaders(){return{...super.getHeaders(),Authorization:`Bearer ${this.apiKey}`}}};import{createAnthropic as E0}from"@ai-sdk/anthropic";var $s=({baseUrl:r,apiKey:e,sessionId:t,extraHeaders:n,loggerTags:o})=>i=>{let a={Authorization:`Bearer ${e}`,[Qc]:di??"",...t&&{[WT]:t},...n||{}};return o&&(a[$T]=JSON.stringify(o)),E0({baseURL:`${r}/v1/llm/anthropic/${i}`,headers:a,apiKey:e})(i)};var kn=class extends Nt{agentConfig;constructor(e,t){let n={...kc,...e};super(t),this.agentConfig=n}getAgentConfig(){return this.agentConfig}async rankChunksWithAi(e,t){let n={...e,loggerTags:t.loggerTags},o=await this.sendRequest(`/${B}/web-agent/recommend-chunks-ai`,{method:"POST",body:n,signal:t.abortSignal});return LE.parse(o)}async rankChunksWithRag(e,t){let n=await this.sendRequest(`/${B}/web-agent/recommend-chunks`,{method:"POST",body:{cliVersion:di,...e},signal:t.abortSignal});return OE.parse(n)}async getScreenshotFromS3(e){let t=await this.sendRequest(`/${B}/s3/visual-diff-screenshot`,{method:"POST",body:{url:e}});return T0.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(`/${B}/web-agent/locate-element`,{method:"POST",body:n,signal:t.abortSignal});return XT.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(`/${B}/web-agent/assertion`,{method:"POST",body:n,signal:t.abortSignal});return lh.parse(o)}async getLintStepResult(e,t){let n={...e,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${B}/web-agent/lint/step`,{method:"POST",body:n,signal:t.abortSignal});return YT.parse(o)}async getLintMcpCopilotMessageResult(e,t){let n={message:e.message,disableCache:!!t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${B}/web-agent/lint/mcp-copilot`,{method:"POST",body:n,signal:t.abortSignal});return KT.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(`/${B}/web-agent/visual-assertion`,{method:"POST",body:n,signal:t.abortSignal});return lh.parse(o)}async getAiActionCommand(e,t){let n=await this.sendRequest(`/${B}/web-agent/next-command-dynamic`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return qT.parse(n)}async getMultiturnAiActionCommand(e,t){return await this.sendRequest(`/${B}/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(`/${B}/web-agent/ai-action/evaluate`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return vm.parse(n)}async getReverseMappedDescription(e,t){let n=await this.sendRequest(`/${B}/web-agent/reverse-mapped-description`,{method:"POST",body:{...e,disableCache:t.disableCache,loggerTags:t.loggerTags},signal:t.abortSignal});return JT.parse(n)}async getTextExtraction(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags,agentConfigVersion:this.agentConfig?.["text-extraction"]},o=await this.sendRequest(`/${B}/web-agent/text-extraction`,{method:"POST",body:n,signal:t.abortSignal});return Em.parse(o)}async getPageSummary(e,t){let n={...e,disableCache:t.disableCache,loggerTags:t.loggerTags},o=await this.sendRequest(`/${B}/web-agent/page-summary`,{method:"POST",body:n,signal:t.abortSignal});return uE.parse(o)}async getTestResultClassification(e,t){let n=await this.sendRequest(`/${B}/web-agent/result-classification`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return nm.parse(n)}async getExtractedKeywords(e,t){let n=await this.sendRequest(`/${B}/web-agent/extract-keywords`,{method:"POST",body:e,signal:t.abortSignal});return VE.parse(n)}async getAutohealingProposal(e,t){let n=await this.sendRequest(`/${B}/web-agent/autoheal-section`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return sE.parse(n)}async getFailureRecoveryProposal(e,t){let n=await this.sendRequest(`/${B}/web-agent/failure-recovery`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return cE.parse(n)}async getFailureRecoveryPlan(e,t){let n=await this.sendRequest(`/${B}/web-agent/failure-recovery-plan`,{method:"POST",body:{...e,loggerTags:t.loggerTags},signal:t.abortSignal});return lE.parse(n)}async getIframeRegex(e,t){let n=await this.sendRequest(`/${B}/web-agent/iframe-regex`,{method:"POST",body:e,signal:t.abortSignal});return GS.parse(n)}getVercelAnthropicModelFactory({loggerTags:e}){return $s({baseUrl:this.baseUrl,apiKey:this.apiKey,loggerTags:e})}};import{z as Ch}from"zod";var et=class extends Nt{constructor(e){super(e)}getAppUrl(){return this.baseUrl==="http://localhost:8000"?"http://localhost:3000":this.baseUrl.replace(/\/\/api/,"//app")}async getAuthInfo(){let e=await this.sendRequest(`/${B}/auth/check`,{method:"GET",retries:10,requestTimeoutMs:5e3});return ub.parse(e)}async bulkGetRunStatus(e){let t=await this.sendRequest(`/${B}/runs/status`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return ab.parse(t)}async getTestYAMLExport(e){let t=await this.sendRequest(`/${B}/tests/export`,{method:"POST",body:e,retries:3,requestTimeoutMs:3e4});return ZT.parse(t)}async updateStepCaches(e,t){await this.sendRequest(`/${B}/cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getStepCacheForTest(e,t){let n=await this.sendRequest(`/${B}/cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return tb.parse(n)}async updateMobileStepCaches(e,t){await this.sendRequest(`/${B}/mobile-cache`,{method:"PATCH",body:e,extraHeaders:t,retries:3,requestTimeoutMs:1e4,initialRetryDelayMs:3e3})}async getMobileStepCacheForTest(e,t){let n=await this.sendRequest(`/${B}/mobile-cache`,{method:"POST",body:e,extraHeaders:t,retries:10,requestTimeoutMs:3e4,initialRetryDelayMs:3e3});return rb.parse(n)}async queueTests(e){let t=await this.sendRequest(`/${B}/tests/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:1e4});return QT.parse(t)}async uploadScreenshot(e){let t=await this.sendRequest(`/${B}/screenshots`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return cb.parse(t)}async getAllEnvironments(){let e=await this.sendRequest(`/${B}/environments`,{method:"GET",retries:3,requestTimeoutMs:5e3});return db.parse(e)}async acquireCacheLock(e,t){let n=await this.sendRequest(`/${B}/result-cache/lock`,{method:"POST",body:e,signal:t,retries:3,requestTimeoutMs:3e4});return Cb.parse(n)}async releaseCacheLock(e){await this.sendRequest(`/${B}/result-cache/lock`,{method:"DELETE",body:{key:e},retries:3,requestTimeoutMs:5e3})}async deleteCacheResult(e){await this.sendRequest(`/${B}/result-cache/entry`,{method:"DELETE",body:e,retries:3,requestTimeoutMs:5e3})}async setCacheResult(e){await this.sendRequest(`/${B}/result-cache/entry`,{method:"PATCH",body:e,retries:3,requestTimeoutMs:5e3})}async getCacheResult(e){try{return await this.sendRequest(`/${B}/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(`/${B}/suites/queue`,{method:"POST",body:e,retries:3,requestTimeoutMs:5e3});return pb.parse(t)}async bulkGetRunGroupStatus(e){let t={runGroupIds:e},n=await this.sendRequest(`/${B}/run-groups/status`,{method:"POST",body:t,retries:3,requestTimeoutMs:5e3});return xE.array().parse(n)}async uploadProposedSteps(e,t){try{await this.sendRequest(`/${B}/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(`/${B}/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(`/${B}/test-fragments/${e}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return mb.parse(t)}async patchTestFragment(e,t){await this.sendRequest(`/${B}/test-fragments/${e}`,{method:"PATCH",body:t,retries:3,requestTimeoutMs:1e4})}async getPastTestResults(e,t){let n=await this.sendRequest(`/${B}/results/tests/${e}`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return hb.parse(n)}async generateTestResultsUploadUrl(){let e=await this.sendRequest(`/${B}/results/uploads`,{method:"POST",retries:3,requestTimeoutMs:1e4});return gb.parse(e)}async startProcessingResultsUpload(e,t){let n=await this.sendRequest(`/${B}/results/uploads/${e}/process`,{method:"POST",body:t,retries:3,requestTimeoutMs:1e4});return fb.parse(n)}async fetchIconKnowledgeBase(e){try{let t=await this.sendRequest(`/${B}/knowledge-base/icons`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Pb.parse(t)}catch(t){return e.error({err:t},"Failed to fetch icon knowledge base"),null}}async saveNewIcons(e,t){try{await this.sendRequest(`/${B}/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(`/${B}/git/github/${e}/${t}/merge-base-commit?${i.toString()}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Hs.parse(a)}async getCommitFromGithub(e,t,n){let o=await this.sendRequest(`/${B}/git/github/${e}/${t}/commits/${n}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Hs.parse(o)}async getMergedBranchFromGithub(e,t,n,o){let i=encodeURIComponent(n),a=await this.sendRequest(`/${B}/git/github/${e}/${t}/${i}/${o}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ph.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(`/${B}/git/gitlab/${i}/merge-base-commit?${o.toString()}`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Hs.parse(a)}async getCommitFromGitlab(e,t){let n=encodeURIComponent(e),o=await this.sendRequest(`/${B}/git/gitlab/${n}/commits/${t}`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Hs.parse(o)}async getMergedBranchFromGitlab(e,t,n){let o=encodeURIComponent(t),i=encodeURIComponent(e),a=await this.sendRequest(`/${B}/git/gitlab/${i}/${o}/${n}/merged-branch`,{method:"GET",retries:3,requestTimeoutMs:1e4});return ph.parse(a)}async getAgentConfig(){let e=await this.sendRequest(`/${B}/web-agent/agent-config`,{method:"GET",retries:3,requestTimeoutMs:5e3});return Ch.record(Ch.string(),Ch.string()).parse(e)}async getQuarantinedTests(){let e=await this.sendRequest(`/${B}/quarantine`,{method:"GET"});return Sb.parse(e)}async quarantineTest(e,t,n){await this.sendRequest(`/${B}/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(`/${B}/quarantine/${e.id}`,{method:"DELETE",body:{testName:e.name,reason:t,...n??{}},retries:3,requestTimeoutMs:1e4})}async createAndroidEmulator(e){let t=await this.sendRequest(`/${B}/limbar/android`,{method:"POST",retries:3,body:e,requestTimeoutMs:9e4,initialRetryDelayMs:5e3,maxRetryDelayMs:15e3});return yb.parse(t)}async extendAndroidEmulatorTtl(e){try{await this.sendRequest(`/${B}/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(`/${B}/limbar/android/upload-url`,{method:"POST",retries:3,body:o,requestTimeoutMs:15e3,logResponse:!0});return Eb.parse(i)}async deleteAndroidEmulator(e){await this.sendRequest(`/${B}/limbar/android/${e}`,{method:"DELETE",retries:3,requestTimeoutMs:3e4})}async getAndroidAssets(){let e=await this.sendRequest(`/${B}/limbar/assets`,{method:"GET",retries:3,requestTimeoutMs:1e4});return Tb.parse(e)}async deleteAndroidAsset(e,t){await this.sendRequest(`/${B}/limbar/assets/${e}/${t}`,{method:"DELETE",retries:3,requestTimeoutMs:1e4})}};async function xh(r){let e=process.versions.node,t=parseInt(e.split(".")[0]);(isNaN(t)||t<18)&&(T.error(`Node.js version 20 or higher is required to run the CLI. Detected: ${process.versions.node}.`),process.exit(1)),T.debug(`Identified node version ${e}`);let n=await r.client.getAuthInfo();return T.debug("Got auth info from API"),n}var su=class{apiClient;constructor(e){this.apiClient=e}async reportBillableEvents(e,t){await this.apiClient.reportBillableEvents(e,t)}};var fo=class extends Nt{generator;constructor(e,t){super(e),this.generator=t}async runTemplateMatching(e,t={}){let n=await this.sendRequest(`/${B}/web-agent/template-matching`,{method:"POST",body:e,signal:t?.signal});return jS.parse(n)}async constructIframeRegex(e,t={}){return this.generator.getIframeRegex(e,{abortSignal:t.signal})}};var ca=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 b0,en as v0}from"@faker-js/faker";var ua="v1",mn=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 b0({locale:v0}),this.fakerInstance.seed(e.fakerSeed))}async sendAiGenerate(e){let t=typeof e=="string"?{input:e}:e;return this.httpClient.sendRequest(`/${ua}/tools/ai/generate`,{method:"POST",body:t}).catch(n=>{throw n instanceof Wr?new Error(n.rawError):new Error(`Failed to send AI generation: ${n.message}`)})}async sendSms(e){return this.httpClient.sendRequest(`/${ua}/tools/sms/send`,{method:"POST",body:e}).then(()=>{}).catch(t=>{throw t instanceof Wr?new Error(t.rawError):new Error(`Failed to send sms: ${t.message}`)})}async fetchLatestSms(e){return this.httpClient.sendRequest(`/${ua}/tools/sms/fetchLatest`,{method:"POST",body:e}).catch(t=>{throw t instanceof Wr?new Error(t.rawError):t})}async sendEmail(e){return this.httpClient.sendRequest(`/${ua}/tools/email/send`,{method:"POST",body:e}).then(()=>{}).catch(t=>{throw t instanceof Wr?new Error(t.rawError):new Error(`Failed to send email: ${t.message}`)})}async fetchAllEmails(e){return this.httpClient.sendRequest(`/${ua}/tools/email/fetchAll`,{method:"POST",body:e}).catch(t=>{throw t instanceof Wr?new Error(t.rawError):new Error(`Failed to fetch all emails: ${t.message}`)})}async fetchLatestEmail(e){return this.httpClient.sendRequest(`/${ua}/tools/email/fetchLatest`,{method:"POST",body:e}).catch(t=>{throw t instanceof Wr?new Error(t.rawError):new Error(`Failed to fetch latest emails: ${t.message}`)})}};function iv(r,e,t){return fetch(r,{method:"PUT",body:t,headers:{"Content-Type":e}})}var lu=class{constructor(e){this.client=e}async uploadResultsArchive(e,t){let{uploadUrl:n,id:o}=await this.client.generateTestResultsUploadUrl(),i=await iv(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}};import{diff as A0}from"deep-object-diff";import{cloneDeep as w0}from"lodash-es";function Ws(r){let e={parentChain:[]};return cu(r,e),e}function cu(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||cu({...r,steps:c.steps},e)&&i)return!0;if(cu({...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),cu({...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 av(r,e,t,n){let o=Array.from(e),i=Array.from(n);for(let s=0;s<o.length;s++){if(o[s]!==i[s])return!1;i.shift()}return!!R0([r],t,i).result}function R0(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 Ws({steps:r,earlyStop:!0,onPresetAction:i,onConditional:i,onSimpleStepContainer:i}),{result:n,parentChain:o}}function sv(r,e){e(r);for(let t in r){let n=r[t];n&&(Array.isArray(n)?du(n,e):typeof n=="object"&&sv(n,e))}}function du(r,e){for(let t of r)t&&(Array.isArray(t)?du(t,e):typeof t=="object"&&sv(t,e))}function _h(r,e){if(r.length>e.length)return _h(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 qs(r,e){return!r&&!e?!1:!r||!e?!0:Object.keys(A0(r,e)).length>0}function da({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=Ln.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=C0(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}=da({...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}=da({...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}=da({...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}=da({...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,cacheEntries:n.length},"Step cache did not fully resolve"),{cacheKeysHit:a,cacheKeysMissed:s,uniqueKeysHit:c}}function lv(r,e){return e?`${e}:${r}`:r}function C0(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 Ih(r){let{moduleStepParents:e=[],moduleIdParents:t=[]}=r;if(e.length!==t.length)throw new Error(`Invalid cache entry parent length: ${JSON.stringify(e)}
|
|
30
30
|
${JSON.stringify(t)}`);let n=[];return n.push({key:lv(r.id,e.join(":")),organizationId:r.orgId,value:r.value,testId:r.testId}),n}function cv(r){let e=new Set;return du(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 pu({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"&&py(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 mu(r,e,t){let n=r.cache&&"memory"in r.cache?r.cache.memory?.traces:void 0;return qs(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},{changed:!0}):{changed:!1}}function uv({steps:r}){let e={};return Ws({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=lv(t.id,i),s=Ln.parse(o);e[a]=s},onSimpleStepContainer:(t,n)=>{},onConditional:(t,n)=>{}}),e}function Ks(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 x0(r,e){return qs(r.memory,e.memory)?{...r,memory:e.memory,updatedAt:e.updatedAt}:r}function Mh(r,e){return r?qs(r.target.memory,e.target.memory)?{target:{...r.target,memory:e.target.memory},updatedAt:e.updatedAt}:r:{target:Ks(e.target),updatedAt:e.updatedAt}}function _0(r,e){let t=w0(r);return t.fromTarget?qs(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=Ks(t.fromTarget),t.updatedAt=e.updatedAt)),t.toTarget?qs(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=Ks(t.toTarget),t.updatedAt=e.updatedAt)),t}function dv({newEntries:r,originalCachesMap:e,logger:t}){let n=[];for(let o of r){let i=e[o.key];if(!i||!i.cache||o.value.type!==i.type)continue;let a=o.value.cache;if(o.value={...i},!a){n.push(o);continue}if("memory"in a&&a.memory)t.debug({cacheKey:o.key,newCacheMemory:a.memory,originalCache:i},"Overwriting assertion cache memory"),o.value.cache=x0(i.cache,a);else if("target"in a&&a.target.memory){t.debug({cacheKey:o.key,newCacheMemory:a.target.memory,originalCache:i},"Overwriting target cache memory");let s=pr.safeParse(o.value.cache);o.value.cache=Mh(s.data,a)}else if("fromTarget"in a||"toTarget"in a){let s=qp.optional().parse(o.value.cache);if(!s)continue;t.debug({cacheKey:o.key,fromTargetMemory:a.fromTarget?.memory,toTargetMemory:a.toTarget?.memory,originalCache:i},"Overwriting drag cache memory"),o.value.cache=_0(s,a)}n.push(o)}return n}function ot(r,e,t=!1){return r.length<e?r:r.slice(0,e-3)+(t?"...TRUNCATED...":"[...]")}var Mr={EQUALS:"equals",CONTAINS:"contains",STARTS_WITH:"starts with",EXISTS:"exists"},Pr={EQUALS:"does not equal",CONTAINS:"does not contain",STARTS_WITH:"does not start with",EXISTS:"does not exist"},Ph={EXISTS:"exists",VISIBLE:"is visible",ENABLED:"is enabled",EDITABLE:"is editable",FOCUSED:"is focused"},Oh={EXISTS:"does not exist",VISIBLE:"is not visible",ENABLED:"is disabled",EDITABLE:"is not editable",FOCUSED:"is not focused"};function I0(r){switch(r.type){case"ELEMENT_CONTENT":return`content ${r.negated?Pr[r.operation]:Mr[r.operation]} '${r.value}'`;case"ELEMENT_ATTRIBUTE":{let t=r.negated?Pr[r.operation]:Mr[r.operation];return r.operation==="EXISTS"?`attribute '${r.attr}' ${t}`:`attribute '${r.attr}' ${t} '${r.value}'`}case"ELEMENT_NAME":{let t=r.negated?Pr[r.operation]:Mr[r.operation];return r.operation==="EXISTS"?`tag name ${t}`:`tag name ${t} '${r.value}'`}case"ELEMENT_STYLE":{let t=r.negated?Pr[r.operation]:Mr[r.operation];return r.operation==="EXISTS"?`style property '${r.property}' ${t}`:`style property '${r.property}' ${t} '${r.value}'`}case"ELEMENT_EXISTENCE":return r.negated?Oh[r.condition]:Ph[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 Ise={CONTENT:"The page"};function M0(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 gu(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 hu(r){let e="";return r.method&&(e=` with method ${r.method}`),`${gu(r.urlMatcher)}${e}`}function P0(r){switch(r.type){case"CONTENT":return`${r.negated?Pr.CONTAINS:Mr.CONTAINS} '${r.value}'`;default:return(t=>{throw"If Typescript complains about the line below, you missed a case or break in the switch above"})(r.type)}}function gn(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?ot(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: ${Bt(r.target)}`:""}`;case"SCROLL_UP":return`Scroll up ${r.deltaY?`${r.deltaY}px`:"1 page height"}${r.target?` in the container of: ${Bt(r.target)}`:""}`;case"SCROLL_LEFT":return`Scroll left ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${Bt(r.target)}`:""}`;case"SCROLL_RIGHT":return`Scroll right ${r.deltaX?`${r.deltaX}px`:"1 page width"}${r.target?` in the container of: ${Bt(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: ${Bt(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 ${Bt(r.target)}`;case"BLUR":return`Focus ${Bt(r.target)}`;case"DRAG":return`Drag ${Bt(r.fromTarget)} onto ${Bt(r.toTarget)}`;case"MOUSE_DRAG":return r.target?.type==="description"&&r.target.elementDescriptor?`Click and drag ${Bt(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: ${Bt(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: ${Bt(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=M0(r.choice);return r.target.type==="coordinates"?n=` from element at coordinates: ${Bt(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?ot(r.code,30):r.code}`;case"AI_ASSERTION":return`Assertion: '${r.assertion}'`;case"VISUAL_DIFF":return`Visual diff against baseline ${r.target?`for element: ${Bt(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 ${Bt(r.target)} ${I0(r.assertion)}`;case"PAGE_CHECK":return`Check the page ${P0(r.assertion)}`;case"WAIT_FOR_URL":return`Wait for page URL to ${gu(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 ${hu(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 ${hu(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 ${hu(r.requestMatcher)}`:`Set a ${r.name} header for all requests`:"Set a header";case"MOCK_ROUTE":return r.requestMatcher?`Mock requests that ${hu(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 O0(r){return typeof r=="object"&&r!==null}function hn(r){if(Array.isArray(r))return r.map(hn);if(O0(r)){let e={};return Object.entries(r).forEach(([t,n])=>{n!==void 0&&(e[t]=hn(n))}),e}return r}function pv(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 Bse}from"lodash-es";import{cloneDeep as Xse}from"lodash-es";import{v4 as ole}from"uuid";import{cloneDeep as L0}from"lodash-es";import yv from"truncate-json";import{v4 as mv}from"uuid";import{cloneDeep as yle,unset as Ele}from"lodash-es";function So(r){switch(r.type){case"AI_ACTION":return`AI action: ${ot(r.text,100)}`;case"AI_ACTION_DYNAMIC":return`AI action: ${ot(r.text,100)}`;case"PRESET_ACTION":return gn(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: ${ot(r.description,100)}`:""}`;default:return(t=>{throw new Error("You missed a case in the switch above")})(r)}}function pi(r,e){return r.split(`
|
|
31
31
|
`).map(t=>" ".repeat(e)+t).join(`
|
|
@@ -4139,7 +4139,7 @@ Available pages:${JSON.stringify(n.map(i=>i.url))}`);if(!fi(o.url,this.logger)){
|
|
|
4139
4139
|
`),tokenLength:d}),u=[],d=0,p=m.length?[m[m.length-1].id]:[],h=!1);let g=c[l],f=Et(g);d+=f,g.length>a&&(g=g.slice(0,a));let E=Array.from(g.matchAll(F_)).map(U=>U&&U.length>=3?{tagName:U[1],id:U[2]}:void 0).filter(U=>!!U),b=Array.from(g.matchAll(Aj)).map(U=>U&&(U[2]||U[4])).filter(U=>!!U);b.reverse();let _=g.replace(/ id="[0-9]+"/g,"");u.push(_);for(let U of E)p.push(U.id),m.push(U);for(let U of b){let V=m[m.length-1];V&&V.tagName===U&&m.pop()}let C=m.some(U=>Cj.includes(U.tagName)),I=c[l+1]??"",P=Et(I),K=Array.from(I.matchAll(F_)).map(U=>U&&U.length>2?U[1]:void 0).filter(U=>!!U),z=K.some(U=>z_.includes(U)),G=K.some(U=>wj.includes(U));d+P>=i&&(h=!0),d>=n&&(z&&!C||b.some(U=>xj.includes(U)))&&(h=!0),d>=o&&G&&!C&&(h=!0),l++}return u.length&&s.push({ids:p,content:u.join(`
|
|
4140
4140
|
`),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 Mj=75e4,Jd=3e5,Pj=5e3;async function Li(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=Et(u);if(d>Mj)try{let p=Xd({serializedTree:u,options:{minChunkTokenCount:1e4,maxChunkTokenCount:1e5,acceptableChunkTokenCount:5e4,maxLineLength:4e3},logger:i});l=await Lj({...r,tokenLimit:Jd-1e4,chunks:p.chunks}),u=l.serialize();let m=Et(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(Jd*ho),u=l.serialize();let m=Et(u);i.info({oldTokens:d,newTokens:m},"Filtered page using naive truncation"),d=m}if(d>Jd)try{if(o){let p=Xd({serializedTree:u,options:H_,logger:i}),m=Ij();l=await j(Oj({...r,chunks:p.chunks,callId:m}),{milliseconds:12e3,signal:c}),u=l.serialize();let h=Et(u);i.info({oldTokens:d,newTokens:h,langfuseCallId:m},"Filtered page using AI chunk ranking"),d=h}else{let p=Xd({serializedTree:u,options:B_,logger:i});l=await j(Nj({...r,chunkResult:p,tokenLimit:4e4}),{milliseconds:12e3,signal:c}),u=l.serialize();let m=Et(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(Jd*ho),u=l.serialize(),i.info("Filtered page using naive truncation")}if(o&&d>Pj&&r.type==="locator"&&(s==="org_01HMSCJQBCCG51M2ZF65YC5B8W"||s==="org_01HMJTX4GT1KG94KZRCT8MZ6YB"))try{let p=await a.getPageSummary({browserContext:u,currentStep:r.description,screenshot:n,type:r.type},{logger:i,loggerTags:$e(i),abortSignal:c});if(i.info(p,"Got AI summaries"),p.category!=="OTHER"){let m=new Set;for(let g of p.relevantSections){let f=Math.min(g.startId,g.endId),y=Math.max(g.startId,g.endId);for(let S=f;S<=y;S++)m.add(S.toString())}l=l.pruneUsingRelevantIds(m),u=l.serialize();let h=Et(u);i.info({newTokens:h,oldTokens:d},"Filtered page using AI summary"),d=h}}catch(p){i.warn({err:p},"Error filtering page using AI summary, continuing...")}return u}async function Oj({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:$e(c)}),u=[];return t.forEach((p,m)=>{l.indices.includes(m)&&(u=u.concat(p.ids))}),i.pruneUsingRelevantIds(new Set(u))}async function Lj(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:$e(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 Nj(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:$e(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 Jf(r,e){if(!r.description)throw new x("UserConfigurationError","Cannot locate element with empty description");return Rn({action:async()=>Dj(r,e),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:e.browser,logger:r.logger})}async function Dj(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 fr({orgId:p,s:y,context:n,localTools:h,signal:f,logger:l})),a&&(y=Uj(y,a));let{serializedTree:E,tree:A}=await Io(m,{allowNotActionableNodesOverride:u,filterByViewport:o,abortSignal:f,skipWait:i,logger:l}),b,_=Date.now(),C;for(;!b&&Date.now()-_<3e3;){f.throwIfAborted();try{b=await m.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2})}catch(W){C=W}}if(!b)throw new x("ActionFailureError",`Failed to take screenshot of page to locate element. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${C?.message}`);let I=E,P=!1,K=`data:image/jpeg;base64,${b.toString("base64")}`;I=await Li({type:"locator",description:y,screenshot:K,serializedTree:E,options:{aiPageFiltering:c},tree:A,fixtures:{generator:g,signal:f,logger:l,orgId:p}}),I!==E&&(P=!0);let z=await g.getElementLocation({browserState:I,goal:y,screenshot:K,source:a,memory:S?s:void 0},{disableCache:t,abortSignal:f,loggerTags:$e(l),useMemory:S});l.debug({usedRag:P,result:z},"Got locator result");let G=z.id>0;if(d?.details?.push({type:"AI_LOCATION",matched:G,pageState:I,ragUsed:P,thoughts:z.thoughts}),!G)throw new Ki(`Could not find any relevant element: ${z.thoughts}`,z.updatedMemory?{type:"GCS_TRACES",traces:z.updatedMemory}:void 0);let{resolution:U,target:V,frameConfig:me}=await m.createTargetFromA11yId({id:z.id,requirements:z.requirements,additionalElements:z.additionalElements,description:y,targetSource:"AI",logger:l});if(U.a11yNode?.properties?.hidden&&U.a11yNode?.properties?.hidden!=="false")throw new x("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: ${U.displayString}`);return S&&(z.updatedMemory?V.memory={type:"GCS_TRACES",traces:z.updatedMemory}:s&&(V.memory=s)),{thoughts:z.thoughts,target:V,resolution:U,frameConfig:me,screenshot:K}}var kj=["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:"],G_="<select> element:",j_="text input or contenteditable element:",V_="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:",$_="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:",Xf=[G_,j_,V_,$_,...kj];function W_(r,e){if(r===e)return!0;for(let t of Xf){if(!r.startsWith(t))continue;let n=r.slice(t.length).trim();if(Xf.some(o=>e.startsWith(o)&&e.slice(o.length).trim()===n)||n===e.trim())return!0}return!!Xf.some(t=>e.startsWith(t)&&e.slice(t.length).trim()===r.trim())}function Uj(r,e){if(!r||!e)return r;switch(e){case"SELECT_OPTION":return`${G_} ${r}`;case"TYPE":return`${j_} ${r}`;case"NEGATED_ELEMENT_VISIBLE_CHECK":return`${V_}
|
|
4141
4141
|
${r}`;case"ELEMENT_CHECK":return`${$_}
|
|
4142
|
-
${r}`;default:return r}}var Fj=15;async function Qd({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=Fj}){if(!r.assertion.trim())throw new x("ActionFailureError","Assertion command is missing the assertion content");let{browser:s}=n,c=r.timeout?r.timeout*1e3:s.smartWaitingTimeout,l=eR(c),u=0,d=Date.now(),p,m,h;try{await Rn({action:()=>s.clearHighlights(),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:s,logger:t})}catch(f){t.warn({err:f},"Failed to clear highlights before AI check, continuing...")}let g;for(;u<a&&(!g||g-d<c);){n.abortSignal.throwIfAborted(),u!==0&&await ie(l,n.abortSignal),g=Date.now();try{if(p=await Rn({action:async()=>{let y=await q_(s,t,n.abortSignal);return m&&m.serializedTree===y.serializedTree&&m.screenshotBuff.equals(y.screenshotBuff)?p:(m=y,K_({command:r,state:y,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?.updatedMemory&&mu(r,p.updatedMemory,t),p?.success)break;throw p?.thoughts?new x("AssertionFailureError",p.thoughts):new x("InternalPlatformError","No thoughts were provided for AI assertion failure")}catch(f){n.abortSignal.throwIfAborted(),h=f instanceof Error?f:new Error(`${f}`),t.info({err:f},`AI check assert attempt ${u} failed, retrying...`)}finally{u++}}if(!p?.success)try{p=await Rn({action:async()=>K_({command:r,state:await q_(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?.success){let f=`AI check still failing after ${u} attempts.`;throw h&&(f+=` Latest result: ${h.message}`),new x("AssertionFailureError",f)}return{...p,succeedImmediately:!1,urlAfterCommand:s.url()}}async function q_(r,e,t){let[n,o]=await Promise.all([Io(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function K_({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(),E=r.contextChoice??"MULTIMODAL",A=h;E!=="VISION_ONLY"&&(A=await Li({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:E,source:c},C=await(E==="VISION_ONLY"?(I,P)=>d.getVisualAssertionResult(I,P):(I,P)=>d.getAssertionResult(I,P))(b,{useConsensus:n,attemptNumber:s,useMemory:o,disableCache:!!r.disableCache,abortSignal:p,logger:l,loggerTags:$e(l)});return(C.result||i)&&C.relevantElements&&(m.relevantElementsSerialized=C.relevantElements.map(I=>u.getSerializedFormFromA11yId(I)).filter(I=>!!I),await Bj(C.relevantElements,u,l)),{success:C.result,thoughts:C.thoughts,afterScreenshotOverride:f,updatedMemory:o?C.updatedMemory:void 0}}async function Bj(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 Hj=3e4;async function Y_({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??Hj/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(r.headers||{}).filter(([d,p])=>d&&p));a["Content-Type"]="application/json";let s;if(ha(r.url)&&(s=r.url),t&&ga(r.url,t)&&(s=new URL(r.url,t).toString()),!s)throw new x("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 x("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 x("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}throw d?.errors?.length&&d?.errors[0]?.message?new x("ActionFailureError",`GraphQL request failed with status ${l.status}: ${d.errors[0].message}`):new x("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 No=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([Io(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 Li({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:{...$e(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([Io(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 Li({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:{...$e(a)},langfuseSessionId:s})}catch(h){throw new x("InternalWebAgentError",`Error generating command: ${h instanceof Error?h.message:h}`,{errOptions:{cause:h}})}}async getBrowserState(e){return Io(this.browser,e)}async locateElement(e){return await Jf({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return Rn({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 x("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 Rn({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&&om(i)){t.warn({err:i},"Invalid mpath error, retrying element targeting command");continue}if(!this.browser.userBrowserSettings.visualActions&&(am(i)||im(i))){t.warn({err:i},"Invalid momentic id error, retrying element targeting command");continue}if(sm(i)){t.warn({err:i},"Invalid backend node id error, retrying element targeting command");continue}if(i instanceof sn&&i.retryableWithAI){t.warn({err:i},"Element cache disqualification error, retrying element targeting command");continue}throw i}throw n instanceof x?n:new x("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 x("ActionFailureError","Cannot use selector with non-description target");let c,l=Date.now(),u=Date.now();for(;Date.now()-u<this.browser.smartWaitingTimeout;){l=Date.now();try{let d=await this.browser.resolveHardcodedCssSelector({ctx:e,selector:t.elementDescriptor,targetName:s,logger:a});return{result:await n({locator:d.locator}),elementInteractedDisplayString:d.displayString}}catch(d){if(d.name==="AbortError")throw d;c=d,a.warn({err:d},"Failed to action on hardcoded css selector"),Date.now()-l<500&&await ie(500)}}throw c}async wrapElementTargetingCommandHelper(e){let{ctx:t,tracer:n,target:o,originalCache:i,action:a,options:s,command:c}=e,{disableCache:l,useSelector:u,targetName:d,targetHealingInProgress:p,source:m}=s,h=this.logger.child({commandId:c.id}),g=this.shouldUseMemory(),f=s.retriesWithAI??1,y=!1,S=X_(e.cache);if((!S||l)&&!zp(o))throw new x("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&&!W_(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 E=b=>!!b&&Zl(b),A=!0;if(!E(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&&await ie(this.browser.smartWaitingTimeout,this.executeAbortController.signal),f--;let b;try{b=await Jf({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(I){if(I instanceof Ki&&I.updatedLocatorMemory){let P={id:-1,...i,memory:I.updatedLocatorMemory};pu({cmd:c,key:d,newTarget:P,logger:h,updatedWithAI:!0})}throw new x("ActionFailureError",I.message)}b.frameConfig&&this.browser.setActiveFrameConfig(b.frameConfig);let _=s.disableGlobalLocatorRedirect?{locator:b.resolution.locator}:await this.attemptLocatorRedirect(b.resolution.locator,h),C=await a(_);return pu({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=$e(h)),{result:C,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 _=s.disableGlobalLocatorRedirect?{locator:b.locator}:await this.attemptLocatorRedirect(b.locator,h),C=await a(_);if(tr.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.21.0"]),pu({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let I=b.decisions.filter(P=>P.matched);if(I.length!==1)h.warn({decisions:b.decisions},"Expected exactly 1 matching method for element location, got more or less");else{let P=I[0].type;n.recordTargetAutoHeal({healType:P})}}return{result:C,elementInteractedDisplayString:b.displayString}}catch(b){this.throwIfClosed(),tr.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.21.0"]);let _=!1;if((b instanceof sn||om(b)||am(b)||sm(b)||Yy(b)||im(b))&&(_=!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 C;return S.memory&&ec(S.memory)&&(C=S.memory),this.wrapElementTargetingCommand({ctx:t,tracer:n,command:c,target:o,cache:void 0,originalCache:i,action:a,options:{...s,memory:C,retriesWithAI:f,targetHealingInProgress:!0}})}throw new x("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 ll(this.browser,e)}async executePresetCommand(e,t,n,o,i){this.options?.slowMoMs&&await ie(this.options.slowMoMs);let a=await this.browser.getOpenPages(),s=this.browser.url(),c;try{c=await this.resolveCommandTemplateStrings(n,o)}catch(l){throw this.throwIfClosed(),new x("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&&uy(n)?await this.browser.waitForDOMStability({timeout:Ae}):!this.browser.userBrowserSettings.visualActions&&["PRESS","TYPE"].includes(n.type)&&await this.browser.waitForDOMStability({timeout:ae}),this.options?.autoFollowNewTabs&&await gx({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{HR(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>Rf(e)}}async resolveCommandTemplateStrings(e,t){return Uu({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()?Qd({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 x("ActionFailureError","Missing assertion");if(n.timeout&&n.timeout>1800)throw new x("AssertionFailureError",`AI check timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);return Qd({command:n,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a})}case"AI_EXTRACT":{if(!n.goal.trim())throw new x("ActionFailureError","Cannot perform AI extraction without goal");if(n.schema){let f=kb(n.schema);if(f)throw new x("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:$e(a)});if(f.result==="NOT_FOUND")throw new x("ActionFailureError","No relevant data found for extraction goal on this page");if(f.thoughts?.includes("MaxGenerationLengthExceededError"))throw new x("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 x("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 x("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(!ha(n.url)&&!ga(n.url,this.browser.baseUrl))throw new x("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&&rn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:E}=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=E}let f=this.browser.getViewport()?.height??Gt.height,y=this.browser.getViewport()?.width??Gt.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 x("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 x("UserConfigurationError",`Wait timeout of ${n.delay} seconds exceeds the maximum allowed value of 30 minutes`);let l=n.delay*1e3;await ie(l,this.executeAbortController.signal);break;case"REFRESH":await this.browser.refresh({loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"CLICK":{if(rn(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:E=>this.browser.click(E,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 xu(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(rn(n.fromTarget)&&rn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(rn(n.fromTarget)||rn(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 x("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${n.deltaX}, ${n.deltaY})`);if(n.target&&rn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,n.target.pixels,{force:n.force});break}let y,S,E;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:A,result:b,thoughts:_}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async C=>C.locator,options:{disableCache:i,targetName:"target",...n}});y=b,S=A,E=_}return await this.browser.mouseDrag(h,g,f,y,{force:n.force}),{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:S,thoughts:E}}case"SELECT_OPTION":{if(!eo(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:Qo(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 vo({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 x("ActionFailureError",g instanceof Error?g.message:`${g}`,{errOptions:{cause:g}})}try{JSON.stringify(h)}catch(g){throw new x("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&&rn(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=X_(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:_=>this.browser.typeIntoTarget(n.value,_,{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:Qo(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 E={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return xu(h,E.urlAfterCommand)&&(E.succeedImmediately=!0,E.succeedImmediatelyReason="URL changed"),E}case"HOVER":{if(rn(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(!eo(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&&!eo(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 xu(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 Gj,g=zj(fetch,h),f;try{f=new URL(n.url).hostname}catch{}return{data:{...await qR({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g}),cookies:eT(h,f)},succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await Y_({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return WR({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 Px({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 x("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 vo({orgId:this.orgId,code:n.storageState,fragment:!1,context:o,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof h!="object")throw new x("ActionFailureError",`Credentials must evaluate to an object (received ${typeof h} instead)`);let g;try{g=Fc.optional().parse(h)}catch(f){throw new x("ActionFailureError",`Credentials provided do not follow the required format: ${f}`)}await this.browser.loadAuthState(g);break}case"ELEMENT_CHECK":{let h=(n.timeout??nn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(VR(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 Qd({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&&mu(n,y.cache?.memory.traces,a)}}let f=await jR({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 Rn({action:async()=>Bu({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 Po(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await If(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 x("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 Po(n.requestMatcher);return this.recordedRequests[n.key]={},this.browser.registerRequestRecorder(n.key,h,{onRequestStart:(g,f)=>{this.recordedRequests[n.key][g]=zd(f)},onRequestComplete:(g,f)=>{this.recordedRequests[n.key][g]=zd(f)}}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GET_RECORDED_REQUESTS":{let h=this.recordedRequests[n.key];if(!h)throw new x("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 Po(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 Po(n.requestMatcher),async(g,f)=>{let y=await vo({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=dT.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:$e(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 qd({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:$e(this.logger)})}async getFailureRecoveryPlan(e){return this.generator.getFailureRecoveryPlan(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:$e(this.logger)})}};import{cloneDeep as jj}from"lodash-es";var Vj={showOverlay:!1},Zd=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:jj(Vj),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 J_(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(),E=f.toEditorDisplayCopy();JSON.stringify(E)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,harPages:y?.harPages,harEntries:y?.harEntries,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:E,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=E}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)||f.harPages&&Object.keys(f.harPages).length>0||f.harEntries&&Object.keys(f.harEntries).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 $j=4;async function Q_({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),E=await l(g,e),A=await t(g),{testMetadata:b,baseUrl:_,envName:C,browserConfig:I,aiSettings:P,environmentVariables:X,localCodeEvalTools:K}=await Ni({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:E}),z=p.getSession(m);if(z)return e.info("Associating connection with existing session (likely reconnect)"),await z.controller.browser.clearAllCdpHighlights(),{type:"e2e",sessionId:m,orgId:g,testId:h};let G=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:G,event:"connect",args:r.handshake.query},"Websocket event (connect)"),G&&p.getCurrentConnectionsByIp(G)>=$j)throw e.error({clientIp:G,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(G);try{await Wj({socket:r,baseUrl:_,envName:C,testMetadata:b,orgId:g,sessionId:m,logger:e,environmentVariables:X,clientIp:G,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:K,generator:y,enricher:S,browserConfig:I,aiSettings:P,globalE2eStateManager:p})}catch(U){throw e.warn({err:U},"Error setting up socket session, possibly due to client closing the connection"),p.releaseCapacityByIp(G),U}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function Wj({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 E={viewport:o.advanced?.viewport??Gt,locale:o.advanced?.locale??io,timezoneId:o.advanced?.timezone??ao,geolocation:o.advanced?.geolocation??so,colorScheme:o.advanced?.colorScheme};n&&(E.deviceScaleFactor=n);let A=o.id,b=await Fd({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 _=await Fr.init({baseUrl:e,userBrowserSettings:b,enricher:y,storage:c,logger:s,contextArgs:E,iconKnowledgeBase:null,callbacks:{onTabsChange:(K,z)=>{r.emit("tabs",{tabs:K,activeTab:z})},onScreencastFrame:(K,z)=>{let G=r;cn&&(G=r.compress(!0)),G.emit("screenshot",{buffer:K},()=>{z()})},onSvgsCollected:K=>{r.emit("newIconDetected",{numIcons:K.newSvgs.length}),c.saveNewIcons(K,s)}}});await _.navigate({url:e,initialNavigation:!0});let C=new No({browser:_,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}),I=J_(r,a,s,S),P=async()=>{I.timers.forEach(K=>clearInterval(K))},X=new ir({baseUrl:e,testName:o.name,currentUrl:C.browser.url(),variablesFromEnvironment:m,envName:t});if(!r.connected)throw await _.cleanup(),new Error("Socket not connected anymore, not proceeding with session setup");r.emit("session",{url:e,userAgent:Fr.USER_AGENT,viewport:C.browser.getViewport(),sessionId:a}),S.registerSession({controller:C,context:X,sessionId:a,cleanup:P,clientIp:f,socket:r})}async function Ni({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 mn({httpClient:new Nt({...o,logger:t}),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?.[wt];if(!p)throw new Error("Base URL is empty in both test options and the configured environment");let m={...l?.variables};await Promise.all((a.parameters??[]).map(async g=>{let f=await fr({orgId:e,s:g.defaultValue,context:ir.dummyContext(a.name,l?.name,m),logger:t,localTools:s});m[g.name]=f}));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 Qf=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;tr.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 jn({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},jn=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))tr.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 Qf({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId})}async finish(){this.sendFinalizedStepStats()}},ep=class{constructor(e,t,n,o,i){this.socket=e;this.storage=t;this.orgId=n;this.testId=o;this.stepsBeforeRun=i}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")}attachConsoleLogs(){}attachNetworkLogs(){}attachBrowserCrashDump(){}async finish(){this.socket.emit("finished"),await Promise.all(this.children.map(e=>e.finish()))}async startBeforeStepList(){let e=new jn({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new jn({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new jn({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var Zf={currentlyExecutingRequests:{}},Kj=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 Ni({testId:n,orgId:o,logger:r.logger,storage:a,authorization:r.authorization,settings:i}),l=`${n}|${c.baseUrl}`;try{let u=Zf.currentlyExecutingRequests[l]??0;Zf.currentlyExecutingRequests[l]=u+1,s=await Yj({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),Zf.currentlyExecutingRequests[l]--}},Yj=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:E,sessionId:A,orgId:b}=u,_=A,C=S.getSession(A);if(!C)throw new Error("No active session found");let{controller:I,context:P}=C;I.setOpen(),d=d.child({testId:E,orgId:b,sessionId:A,runId:_}),d.info({steps:e.map(te=>`${te.type}${"command"in te?` - ${te.command.type}`:""}`),toStep:i,fromStep:a,reInitialize:o,envName:p,testName:m,baseUrl:t,context:P,browserConfig:l,aiSettings:c},"Socket execution parameters");let X=h??{},K=async()=>{o&&(await I.browser.reset({newUrl:t}),P.reset({baseUrl:t,currentUrl:I.browser.url(),variablesFromEnvironment:X,envName:p,testName:m}))},z=await s(b),G=await y(b),U=async()=>{try{await G.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:E,stepLists:{steps:e},logger:d})}catch(te){d.error({err:te},"Failed to fetch step cache entries from Momentic server. This can drastically reduce test reliability and performance.")}};try{await Js({promiseGenerator:async()=>Promise.all([K(),U()]),signal:I.executeAbortController.signal,codePath:"resolveStepCacheAndInitBrowser"}),I.setOpen()}catch(te){if(r.emit("finished"),te.name!=="AbortError")throw new Error(`Failed to setup browser for execution: ${te}`)}let V=qj(e),me={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},W={orgId:b,runId:_,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},tt={controller:I,context:P,storage:z,codeEvalTools:g,usageTracker:new na,logger:d},De={test:{},step:{onDynamicAIActionStatusUpdateEvent:te=>{r.emit("dynamicCommandStatusUpdate",te)},onDynamicAIActionEvaluatingEvent:te=>{r.emit("dynamicCommandEvaluating",te)},onDynamicCommandGenerated:te=>{r.emit("dynamicCommandGenerated",te)},onDynamicCommandExecuted:te=>{r.emit("dynamicCommandExecuted",te)}}},ut=new ep(r,z,b,E,V),Mt=await Ud({fixtures:tt,options:me,callbacks:De,inputs:W,testParams:{tracer:ut}});return Mt?.status==="PASSED"?await vu({logger:d,cacheStorage:G,orgId:b,testId:E,originalSteps:{steps:V},updatedSteps:{steps:e}}):Mt?.status==="FAILED"&&await Ru({logger:d,cacheStorage:G,orgId:b,testId:E,originalSteps:{steps:V},updatedSteps:{steps:e}}),await ut.finish(),f?.(Mt),Mt.status};var Z_={event:"execute",createHandler:Kj};import{cloneDeep as Xj}from"lodash-es";var Jj=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=Xj(e),s=Tv(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})}}},eI={event:"lintStep",createHandler:Jj};var Qj=({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=ni.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let E=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=E.resolution.locator,y={target:E.target,thoughts:E.thoughts}}catch(E){e.warn({err:E},"Failed resolving target with selector"),s({err:`Failed locating element: ${E.message}`,decisions:E instanceof an?E.decisions:void 0});return}else try{let E=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:Qo(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&ec(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:E.target,thoughts:E.thoughts},S=E.resolution.locator}catch(E){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:E,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:`${E.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(E){e.warn({err:E},"Failed getting select options"),s({err:`Failed getting select options: ${E.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:E,width:A,height:b}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),_=await g.uploadScreenshot(E);y.screenshot={data:_,width:A,height:b},e.info({width:A,height:b},"Captured screenshot during locate")}catch(E){e.error({err:E},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${E.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(E){e.warn({err:E},"Error highlighting element, continuing...")}}},tI={event:"locate",createHandler:Qj};var Zj=({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")}}},rI={event:"mouseClickEvent",createHandler:Zj};var eV=({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})}},nI={event:"recordTargetClick",createHandler:eV};var tV=({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}}},oI={event:"keyDownEvent",createHandler:tV};var rV=({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}}},iI={event:"keyUpEvent",createHandler:rV};var nV=({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")}}},aI={event:"mouseMoveEvent",createHandler:nV};var oV=({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}}},sI={event:"recordingStart",createHandler:oV};var iV=({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}},lI={event:"recordingStop",createHandler:iV};var aV=({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 Ni({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()},cI={event:"refresh",createHandler:aV};var sV=({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 Ni({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 E=y.browser.baseUrl;S.reset({baseUrl:E,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),b=Fr.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${E}`),r.emit("session",{url:E,userAgent:b,viewport:A,sessionId:c})},uI={event:"reset",createHandler:sV};var lV=({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})}},dI={event:"switchTab",createHandler:lV};async function pI(r){return Q_(r)}var mI=[OR,Z_,tI,uI,cI,IR,dI,eI,nI,sI,lI,aI,rI,oI,iI,PR,MR];var hI=r=>{let{logger:e}=r,t=new cV(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 pI({...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}mI.forEach(i=>uV(i,{...r,socket:n,metadata:o,logger:e}))}),t},uV=(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 gV}from"express";import{Router as pV}from"express";import Fl from"fs";import Ul from"path";import{v4 as mV}from"uuid";import hV from"yaml";import{hostname as dV}from"os";var eS="2.21.0",it=ru({app:"desktop-server",hostname:dV(),disableConsoleLogs:!0}).child({cliVersion:eS});(async()=>{try{let r=await al(it);r.gitBranchName&&it.addBinding("branch",r.gitBranchName)}catch{}})();var Va=pV();async function tS(r){return(await Ou(r,it)).map(n=>{let o=r.modules[n.moduleId];if(!o){T.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)}Va.get("/",Re(async(r,e)=>{let t=ce(),n=await Q(t),o=await tS(n);e.status(200).json(o)}));Va.post("/",Re(async(r,e)=>{let t;try{t=IT.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{no(t.name)}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=ce(),o=(await Q(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=Ul.join(n.rootDir,t.folderPath??"");if(!Fl.existsSync(i)||!Fl.statSync(i).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${i}' does not exist.`});return}let a=await Pu({...t,folder:i,project:n});e.status(201).json(a)}));Va.get("/:moduleId",Re(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=await Q(ce()),n=t.modules[r.params.moduleId];if(!n){e.status(404).json({error:"Module not found."});return}try{let o=await Yr(n,t,T);e.json(o)}catch(o){e.status(400).json({err:o})}}));Va.post("/:moduleId/duplicate",Re(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=_T.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{no(t.name)}catch(g){e.status(400).json({error:g.message});return}let n=ce(),o=await Q(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 Yr(i,o,T),s=Ul.join(n.rootDir,Ul.dirname(i.relativePath));if(!Fl.existsSync(s)||!Fl.statSync(s).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${s}' does not exist.`});return}let c=Oe(t.name),l=Ul.join(s,`${c}.module.yaml`),u=mV(),{stepsToSave:d}=await lt({stepLists:{steps:a.steps},createNewCacheIds:!0,cacheCreationParams:{orgId:xt()}}),p={fileType:de.MODULE,schemaVersion:Ee,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=hV.stringify(p);Fl.writeFileSync(l,m,"utf-8");let h={relativeFilePath:Ul.relative(n.rootDir,l)};e.status(201).json(h)}));Va.patch("/:moduleId/metadata",Re(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=MT.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=ce(),o=await Q(n);cR({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:T,project:n}),e.status(201).json({message:"ok"})}));var gI=Va;var fI=gV();fI.get("/",Re(async(r,e)=>{let t=ce(),n=await Q(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 tS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var SI=fI;import{Router as fV}from"express";var rS=fV();rS.get("/",Re((r,e)=>{let t=Lu(ce(),it);e.status(200).json(t)}));rS.get("/names",Re((r,e)=>{let n=ce().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var yI=rS;import{Router as SV}from"express";var EI=SV();EI.get("/",Re((r,e)=>{let t={userId:yo(),orgId:xt()};e.status(200).json(t)}));var TI=EI;import{StreamableHTTPServerTransport as v$}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as R$}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as A$}from"crypto";import{Router as w$}from"express";import{McpServer as T$}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as b$}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as vV}from"ai";import op from"dedent";import{z as Do}from"zod";import{tool as yV}from"ai";import{z as EV}from"zod";var tp=(r,e)=>({builder:n=>yV({description:r.schema.description,inputSchema:EV.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(`
|
|
4142
|
+
${r}`;default:return r}}var Fj=15;async function Qd({command:r,aiPageFiltering:e,logger:t,fixtures:n,source:o,useMemory:i,maxRetries:a=Fj}){if(!r.assertion.trim())throw new x("ActionFailureError","Assertion command is missing the assertion content");let{browser:s}=n,c=r.timeout?r.timeout*1e3:s.smartWaitingTimeout,l=eR(c),u=0,d=Date.now(),p,m,h;try{await Rn({action:()=>s.clearHighlights(),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:s,logger:t})}catch(f){t.warn({err:f},"Failed to clear highlights before AI check, continuing...")}let g;for(;u<a&&(!g||g-d<c);){n.abortSignal.throwIfAborted(),u!==0&&await ie(l,n.abortSignal),g=Date.now();try{if(p=await Rn({action:async()=>{let y=await q_(s,t,n.abortSignal);return m&&m.serializedTree===y.serializedTree&&m.screenshotBuff.equals(y.screenshotBuff)?p:(m=y,K_({command:r,state:y,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?.updatedMemory&&mu(r,p.updatedMemory,t),p?.success)break;throw p?.thoughts?new x("AssertionFailureError",p.thoughts):new x("InternalPlatformError","No thoughts were provided for AI assertion failure")}catch(f){n.abortSignal.throwIfAborted(),h=f instanceof Error?f:new Error(`${f}`),t.info({err:f},`AI check assert attempt ${u} failed, retrying...`)}finally{u++}}if(!p?.success)try{p=await Rn({action:async()=>K_({command:r,state:await q_(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?.success){let f=`AI check still failing after ${u} attempts.`;throw h&&(f+=` Latest result: ${h.message}`),new x("AssertionFailureError",f)}return{...p,succeedImmediately:!1,urlAfterCommand:s.url()}}async function q_(r,e,t){let[n,o]=await Promise.all([Io(r,{abortSignal:t,skipWait:!0,skipWaitForPageLoad:!0,logger:e}),r.screenshot({retries:1,respectActiveFrame:!0})]);return{...n,screenshotBuff:o}}async function K_({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(),E=r.contextChoice??"MULTIMODAL",A=h;E!=="VISION_ONLY"&&(A=await Li({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:E,source:c},C=await(E==="VISION_ONLY"?(I,P)=>d.getVisualAssertionResult(I,P):(I,P)=>d.getAssertionResult(I,P))(b,{useConsensus:n,attemptNumber:s,useMemory:o,disableCache:!!r.disableCache,abortSignal:p,logger:l,loggerTags:$e(l)});return(C.result||i)&&C.relevantElements&&(m.relevantElementsSerialized=C.relevantElements.map(I=>u.getSerializedFormFromA11yId(I)).filter(I=>!!I),await Bj(C.relevantElements,u,l)),{success:C.result,thoughts:C.thoughts,afterScreenshotOverride:f,updatedMemory:o?C.updatedMemory:void 0}}async function Bj(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 Hj=3e4;async function Y_({command:r,logger:e,baseUrl:t,fetchImplementation:n=fetch}){let o=r.timeout??Hj/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(r.headers||{}).filter(([d,p])=>d&&p));a["Content-Type"]="application/json";let s;if(ha(r.url)&&(s=r.url),t&&ga(r.url,t)&&(s=new URL(r.url,t).toString()),!s)throw new x("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 x("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 x("ActionFailureError",`GraphQL request failed with status ${l.status}: ${p}`)}throw d?.errors?.length&&d?.errors[0]?.message?new x("ActionFailureError",`GraphQL request failed with status ${l.status}: ${d.errors[0].message}`):new x("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 No=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([Io(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 Li({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:{...$e(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([Io(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 Li({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:{...$e(a)},langfuseSessionId:s})}catch(h){throw new x("InternalWebAgentError",`Error generating command: ${h instanceof Error?h.message:h}`,{errOptions:{cause:h}})}}async getBrowserState(e){return Io(this.browser,e)}async locateElement(e){return await Jf({...e,aiPageFiltering:!!this.options?.aiPageFiltering},this.getControllerFixtures())}async locateElementWithSelector(e,t){return Rn({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 x("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 Rn({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&&om(i)){t.warn({err:i},"Invalid mpath error, retrying element targeting command");continue}if(!this.browser.userBrowserSettings.visualActions&&(am(i)||im(i))){t.warn({err:i},"Invalid momentic id error, retrying element targeting command");continue}if(sm(i)){t.warn({err:i},"Invalid backend node id error, retrying element targeting command");continue}if(i instanceof sn&&i.retryableWithAI){t.warn({err:i},"Element cache disqualification error, retrying element targeting command");continue}throw i}throw n instanceof x?n:new x("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 x("ActionFailureError","Cannot use selector with non-description target");let c,l=Date.now(),u=Date.now();for(;Date.now()-u<this.browser.smartWaitingTimeout;){l=Date.now();try{let d=await this.browser.resolveHardcodedCssSelector({ctx:e,selector:t.elementDescriptor,targetName:s,logger:a});return{result:await n({locator:d.locator}),elementInteractedDisplayString:d.displayString}}catch(d){if(d.name==="AbortError")throw d;c=d,a.warn({err:d},"Failed to action on hardcoded css selector"),Date.now()-l<500&&await ie(500)}}throw c}async wrapElementTargetingCommandHelper(e){let{ctx:t,tracer:n,target:o,originalCache:i,action:a,options:s,command:c}=e,{disableCache:l,useSelector:u,targetName:d,targetHealingInProgress:p,source:m}=s,h=this.logger.child({commandId:c.id}),g=this.shouldUseMemory(),f=s.retriesWithAI??1,y=!1,S=X_(e.cache);if((!S||l)&&!zp(o))throw new x("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&&!W_(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 E=b=>!!b&&Zl(b),A=!0;if(!E(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&&await ie(this.browser.smartWaitingTimeout,this.executeAbortController.signal),f--;let b;try{b=await Jf({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(I){if(I instanceof Ki&&I.updatedLocatorMemory){let P={id:-1,...i,memory:I.updatedLocatorMemory};pu({cmd:c,key:d,newTarget:P,logger:h,updatedWithAI:!0})}throw new x("ActionFailureError",I.message)}b.frameConfig&&this.browser.setActiveFrameConfig(b.frameConfig);let _=s.disableGlobalLocatorRedirect?{locator:b.resolution.locator}:await this.attemptLocatorRedirect(b.resolution.locator,h),C=await a(_);return pu({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=$e(h)),{result:C,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 _=s.disableGlobalLocatorRedirect?{locator:b.locator}:await this.attemptLocatorRedirect(b.locator,h),C=await a(_);if(tr.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.21.1"]),pu({cmd:c,key:d,newTarget:S,logger:h,updatedWithAI:!1}),A){let I=b.decisions.filter(P=>P.matched);if(I.length!==1)h.warn({decisions:b.decisions},"Expected exactly 1 matching method for element location, got more or less");else{let P=I[0].type;n.recordTargetAutoHeal({healType:P})}}return{result:C,elementInteractedDisplayString:b.displayString}}catch(b){this.throwIfClosed(),tr.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!S.requirements}`,`hasAdditionalElements:${!!S.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:2.21.1"]);let _=!1;if((b instanceof sn||om(b)||am(b)||sm(b)||Yy(b)||im(b))&&(_=!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 C;return S.memory&&ec(S.memory)&&(C=S.memory),this.wrapElementTargetingCommand({ctx:t,tracer:n,command:c,target:o,cache:void 0,originalCache:i,action:a,options:{...s,memory:C,retriesWithAI:f,targetHealingInProgress:!0}})}throw new x("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 ll(this.browser,e)}async executePresetCommand(e,t,n,o,i){this.options?.slowMoMs&&await ie(this.options.slowMoMs);let a=await this.browser.getOpenPages(),s=this.browser.url(),c;try{c=await this.resolveCommandTemplateStrings(n,o)}catch(l){throw this.throwIfClosed(),new x("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&&uy(n)?await this.browser.waitForDOMStability({timeout:Ae}):!this.browser.userBrowserSettings.visualActions&&["PRESS","TYPE"].includes(n.type)&&await this.browser.waitForDOMStability({timeout:ae}),this.options?.autoFollowNewTabs&&await gx({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{HR(n,c)}}createCallbacksForBrowser(e){return{createIsolatedFolder:()=>Rf(e)}}async resolveCommandTemplateStrings(e,t){return Uu({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()?Qd({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 x("ActionFailureError","Missing assertion");if(n.timeout&&n.timeout>1800)throw new x("AssertionFailureError",`AI check timeout of ${n.timeout} exceeds the maximum allowed value of 30 minutes.`);return Qd({command:n,fixtures:this.getControllerFixtures(e),useMemory:this.shouldUseMemory(),aiPageFiltering:!!this.options?.aiPageFiltering,logger:a})}case"AI_EXTRACT":{if(!n.goal.trim())throw new x("ActionFailureError","Cannot perform AI extraction without goal");if(n.schema){let f=kb(n.schema);if(f)throw new x("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:$e(a)});if(f.result==="NOT_FOUND")throw new x("ActionFailureError","No relevant data found for extraction goal on this page");if(f.thoughts?.includes("MaxGenerationLengthExceededError"))throw new x("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 x("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 x("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(!ha(n.url)&&!ga(n.url,this.browser.baseUrl))throw new x("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&&rn(n.target))await this.browser.hoverUsingVisualCoordinates(n.target.pixels);else if(n.target&&n.target.elementDescriptor.trim()){let{elementInteractedDisplayString:S,thoughts:E}=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=E}let f=this.browser.getViewport()?.height??Gt.height,y=this.browser.getViewport()?.width??Gt.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 x("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 x("UserConfigurationError",`Wait timeout of ${n.delay} seconds exceeds the maximum allowed value of 30 minutes`);let l=n.delay*1e3;await ie(l,this.executeAbortController.signal);break;case"REFRESH":await this.browser.refresh({loadTimeoutMs:n.loadTimeout?n.loadTimeout*1e3:void 0});break;case"CLICK":{if(rn(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:E=>this.browser.click(E,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 xu(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(rn(n.fromTarget)&&rn(n.toTarget)){await this.browser.dragAndDropUsingVisualCoordinates(n.fromTarget.pixels,n.toTarget.pixels,{hoverSeconds:n.hoverSeconds});break}if(rn(n.fromTarget)||rn(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 x("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${n.deltaX}, ${n.deltaY})`);if(n.target&&rn(n.target)){await this.browser.mouseDragUsingVisualCoordinates(h,g,f,n.target.pixels,{force:n.force});break}let y,S,E;if(n.target?.elementDescriptor){let{elementInteractedDisplayString:A,result:b,thoughts:_}=await this.wrapElementTargetingCommand({ctx:e,tracer:t,command:n,target:n.target,cache:n.cache?.target,action:async C=>C.locator,options:{disableCache:i,targetName:"target",...n}});y=b,S=A,E=_}return await this.browser.mouseDrag(h,g,f,y,{force:n.force}),{succeedImmediately:!1,urlAfterCommand:this.browser.url(),elementInteracted:S,thoughts:E}}case"SELECT_OPTION":{if(!eo(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:Qo(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 vo({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 x("ActionFailureError",g instanceof Error?g.message:`${g}`,{errOptions:{cause:g}})}try{JSON.stringify(h)}catch(g){throw new x("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&&rn(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=X_(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:_=>this.browser.typeIntoTarget(n.value,_,{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:Qo(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 E={urlAfterCommand:this.browser.url(),succeedImmediately:!1,elementInteracted:g,thoughts:f};return xu(h,E.urlAfterCommand)&&(E.succeedImmediately=!0,E.succeedImmediatelyReason="URL changed"),E}case"HOVER":{if(rn(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(!eo(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&&!eo(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 xu(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 Gj,g=zj(fetch,h),f;try{f=new URL(n.url).hostname}catch{}return{data:{...await qR({command:n,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:g}),cookies:eT(h,f)},succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GRAPHQL_REQUEST":return{data:await Y_({command:n,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:!1,urlAfterCommand:this.browser.url()};case"VISUAL_DIFF":return WR({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 Px({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 x("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 vo({orgId:this.orgId,code:n.storageState,fragment:!1,context:o,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof h!="object")throw new x("ActionFailureError",`Credentials must evaluate to an object (received ${typeof h} instead)`);let g;try{g=Fc.optional().parse(h)}catch(f){throw new x("ActionFailureError",`Credentials provided do not follow the required format: ${f}`)}await this.browser.loadAuthState(g);break}case"ELEMENT_CHECK":{let h=(n.timeout??nn)*1e3,g=this.generator.getAgentConfig()?.assertion;if(VR(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 Qd({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&&mu(n,y.cache?.memory.traces,a)}}let f=await jR({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 Rn({action:async()=>Bu({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 Po(n.requestMatcher),g=this.browser.registerRequestListener(h);return this.registeredListeners[n.key]=g.then(async f=>await If(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 x("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 Po(n.requestMatcher);return this.recordedRequests[n.key]={},this.browser.registerRequestRecorder(n.key,h,{onRequestStart:(g,f)=>{this.recordedRequests[n.key][g]=zd(f)},onRequestComplete:(g,f)=>{this.recordedRequests[n.key][g]=zd(f)}}),{succeedImmediately:!1,urlAfterCommand:this.browser.url()}}case"GET_RECORDED_REQUESTS":{let h=this.recordedRequests[n.key];if(!h)throw new x("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 Po(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 Po(n.requestMatcher),async(g,f)=>{let y=await vo({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=dT.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:$e(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 qd({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:$e(this.logger)})}async getFailureRecoveryPlan(e){return this.generator.getFailureRecoveryPlan(e,{disableCache:!0,abortSignal:this.executeAbortController.signal,loggerTags:$e(this.logger)})}};import{cloneDeep as jj}from"lodash-es";var Vj={showOverlay:!1},Zd=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:jj(Vj),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 J_(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(),E=f.toEditorDisplayCopy();JSON.stringify(E)===JSON.stringify(a)&&S===l&&o>i||(r.emit("browserState",{logsPerPage:y?.logsPerPage,harPages:y?.harPages,harEntries:y?.harEntries,viewport:g.getViewport(),url:S,iframeSrcUrls:s??[],context:E,isInPageLoad:g.isInPageLoad}),o=Date.now()),l=S,a=E}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)||f.harPages&&Object.keys(f.harPages).length>0||f.harEntries&&Object.keys(f.harEntries).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 $j=4;async function Q_({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),E=await l(g,e),A=await t(g),{testMetadata:b,baseUrl:_,envName:C,browserConfig:I,aiSettings:P,environmentVariables:X,localCodeEvalTools:K}=await Ni({testId:h,orgId:g,logger:e,storage:A,authorization:c,settings:E}),z=p.getSession(m);if(z)return e.info("Associating connection with existing session (likely reconnect)"),await z.controller.browser.clearAllCdpHighlights(),{type:"e2e",sessionId:m,orgId:g,testId:h};let G=r.handshake.headers["x-forwarded-for"]?.split(",")[0];if(e.info({clientIp:G,event:"connect",args:r.handshake.query},"Websocket event (connect)"),G&&p.getCurrentConnectionsByIp(G)>=$j)throw e.error({clientIp:G,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(G);try{await Wj({socket:r,baseUrl:_,envName:C,testMetadata:b,orgId:g,sessionId:m,logger:e,environmentVariables:X,clientIp:G,devicePixelRatio:i,storage:A,uploadedFileStorage:n,visualDiffScreenshotStorage:o,localCodeEvalTools:K,generator:y,enricher:S,browserConfig:I,aiSettings:P,globalE2eStateManager:p})}catch(U){throw e.warn({err:U},"Error setting up socket session, possibly due to client closing the connection"),p.releaseCapacityByIp(G),U}return{type:"e2e",sessionId:m,testId:h,orgId:g}}async function Wj({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 E={viewport:o.advanced?.viewport??Gt,locale:o.advanced?.locale??io,timezoneId:o.advanced?.timezone??ao,geolocation:o.advanced?.geolocation??so,colorScheme:o.advanced?.colorScheme};n&&(E.deviceScaleFactor=n);let A=o.id,b=await Fd({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 _=await Fr.init({baseUrl:e,userBrowserSettings:b,enricher:y,storage:c,logger:s,contextArgs:E,iconKnowledgeBase:null,callbacks:{onTabsChange:(K,z)=>{r.emit("tabs",{tabs:K,activeTab:z})},onScreencastFrame:(K,z)=>{let G=r;cn&&(G=r.compress(!0)),G.emit("screenshot",{buffer:K},()=>{z()})},onSvgsCollected:K=>{r.emit("newIconDetected",{numIcons:K.newSvgs.length}),c.saveNewIcons(K,s)}}});await _.navigate({url:e,initialNavigation:!0});let C=new No({browser:_,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}),I=J_(r,a,s,S),P=async()=>{I.timers.forEach(K=>clearInterval(K))},X=new ir({baseUrl:e,testName:o.name,currentUrl:C.browser.url(),variablesFromEnvironment:m,envName:t});if(!r.connected)throw await _.cleanup(),new Error("Socket not connected anymore, not proceeding with session setup");r.emit("session",{url:e,userAgent:Fr.USER_AGENT,viewport:C.browser.getViewport(),sessionId:a}),S.registerSession({controller:C,context:X,sessionId:a,cleanup:P,clientIp:f,socket:r})}async function Ni({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 mn({httpClient:new Nt({...o,logger:t}),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?.[wt];if(!p)throw new Error("Base URL is empty in both test options and the configured environment");let m={...l?.variables};await Promise.all((a.parameters??[]).map(async g=>{let f=await fr({orgId:e,s:g.defaultValue,context:ir.dummyContext(a.name,l?.name,m),logger:t,localTools:s});m[g.name]=f}));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 Qf=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;tr.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 jn({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId})}},jn=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))tr.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 Qf({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId})}async finish(){this.sendFinalizedStepStats()}},ep=class{constructor(e,t,n,o,i){this.socket=e;this.storage=t;this.orgId=n;this.testId=o;this.stepsBeforeRun=i}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")}attachConsoleLogs(){}attachNetworkLogs(){}attachBrowserCrashDump(){}async finish(){this.socket.emit("finished"),await Promise.all(this.children.map(e=>e.finish()))}async startBeforeStepList(){let e=new jn({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startMainStepList(){let e=new jn({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}async startAfterStepList(){let e=new jn({orgId:this.orgId,parentStep:null,parentTracer:null,socket:this.socket});return this.children.push(e),e}};var Zf={currentlyExecutingRequests:{}},Kj=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 Ni({testId:n,orgId:o,logger:r.logger,storage:a,authorization:r.authorization,settings:i}),l=`${n}|${c.baseUrl}`;try{let u=Zf.currentlyExecutingRequests[l]??0;Zf.currentlyExecutingRequests[l]=u+1,s=await Yj({...r,...e,...c,done:t})}finally{r.logger.info({result:s,sessionId:r.metadata.sessionId},"Test execution complete"),Zf.currentlyExecutingRequests[l]--}},Yj=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:E,sessionId:A,orgId:b}=u,_=A,C=S.getSession(A);if(!C)throw new Error("No active session found");let{controller:I,context:P}=C;I.setOpen(),d=d.child({testId:E,orgId:b,sessionId:A,runId:_}),d.info({steps:e.map(te=>`${te.type}${"command"in te?` - ${te.command.type}`:""}`),toStep:i,fromStep:a,reInitialize:o,envName:p,testName:m,baseUrl:t,context:P,browserConfig:l,aiSettings:c},"Socket execution parameters");let X=h??{},K=async()=>{o&&(await I.browser.reset({newUrl:t}),P.reset({baseUrl:t,currentUrl:I.browser.url(),variablesFromEnvironment:X,envName:p,testName:m}))},z=await s(b),G=await y(b),U=async()=>{try{await G.resolveStepCacheEntries({schemaVersion:n.schemaVersion,testId:E,stepLists:{steps:e},logger:d})}catch(te){d.error({err:te},"Failed to fetch step cache entries from Momentic server. This can drastically reduce test reliability and performance.")}};try{await Js({promiseGenerator:async()=>Promise.all([K(),U()]),signal:I.executeAbortController.signal,codePath:"resolveStepCacheAndInitBrowser"}),I.setOpen()}catch(te){if(r.emit("finished"),te.name!=="AbortError")throw new Error(`Failed to setup browser for execution: ${te}`)}let V=qj(e),me={collectDebugData:!1,reinitializeBrowser:!1,disableHealing:!0},W={orgId:b,runId:_,testMetadata:n,steps:e,fromStep:a,toStep:i,orgSettings:{ai:c,browser:l}},tt={controller:I,context:P,storage:z,codeEvalTools:g,usageTracker:new na,logger:d},De={test:{},step:{onDynamicAIActionStatusUpdateEvent:te=>{r.emit("dynamicCommandStatusUpdate",te)},onDynamicAIActionEvaluatingEvent:te=>{r.emit("dynamicCommandEvaluating",te)},onDynamicCommandGenerated:te=>{r.emit("dynamicCommandGenerated",te)},onDynamicCommandExecuted:te=>{r.emit("dynamicCommandExecuted",te)}}},ut=new ep(r,z,b,E,V),Mt=await Ud({fixtures:tt,options:me,callbacks:De,inputs:W,testParams:{tracer:ut}});return Mt?.status==="PASSED"?await vu({logger:d,cacheStorage:G,orgId:b,testId:E,originalSteps:{steps:V},updatedSteps:{steps:e}}):Mt?.status==="FAILED"&&await Ru({logger:d,cacheStorage:G,orgId:b,testId:E,originalSteps:{steps:V},updatedSteps:{steps:e}}),await ut.finish(),f?.(Mt),Mt.status};var Z_={event:"execute",createHandler:Kj};import{cloneDeep as Xj}from"lodash-es";var Jj=r=>async({command:e},t)=>{let{logger:n,generatorFactory:o,metadata:i}=r,a=Xj(e),s=Tv(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})}}},eI={event:"lintStep",createHandler:Jj};var Qj=({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=ni.parse(u.advanced??{}),y={},S;if(c){if("useSelector"in l&&l.useSelector)try{let E=await m.locateElementWithSelector(c,"iframeUrl"in l?l.iframeUrl:void 0);S=E.resolution.locator,y={target:E.target,thoughts:E.thoughts}}catch(E){e.warn({err:E},"Failed resolving target with selector"),s({err:`Failed locating element: ${E.message}`,decisions:E instanceof an?E.decisions:void 0});return}else try{let E=await m.locateElement({description:c,disableCache:f.disableAICaching??!1,skipWait:!0,testContext:h,source:Qo(l),iframeUrl:"iframeUrl"in l?l.iframeUrl:void 0,memory:"cache"in l&&l.cache&&"target"in l.cache&&ec(l.cache.target.memory)?l.cache.target.memory:void 0,logger:e});y={target:E.target,thoughts:E.thoughts},S=E.resolution.locator}catch(E){(async()=>{try{let A=await m.browser.getCondensedHtml({skipWait:!0});e.warn({err:E,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:`${E.message}`});return}if(l.type==="SELECT_OPTION"&&S)try{y.options=await m.browser.getSelectOptions(S)}catch(E){e.warn({err:E},"Failed getting select options"),s({err:`Failed getting select options: ${E.message}`});return}e.info({result:y},"Locate handler result")}if(d)try{let{buffer:E,width:A,height:b}=await m.screenshotWithDimensions({clearHighlights:!0,locator:S}),_=await g.uploadScreenshot(E);y.screenshot={data:_,width:A,height:b},e.info({width:A,height:b},"Captured screenshot during locate")}catch(E){e.error({err:E},"Error capturing screenshot during locate"),s({err:`Error taking screenshot: ${E.message}`});return}if(s({result:y}),S)try{await Promise.all([m.browser.scrollIntoViewIfNeeded(S),m.browser.highlight(S)])}catch(E){e.warn({err:E},"Error highlighting element, continuing...")}}},tI={event:"locate",createHandler:Qj};var Zj=({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")}}},rI={event:"mouseClickEvent",createHandler:Zj};var eV=({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})}},nI={event:"recordTargetClick",createHandler:eV};var tV=({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}}},oI={event:"keyDownEvent",createHandler:tV};var rV=({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}}},iI={event:"keyUpEvent",createHandler:rV};var nV=({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")}}},aI={event:"mouseMoveEvent",createHandler:nV};var oV=({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}}},sI={event:"recordingStart",createHandler:oV};var iV=({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}},lI={event:"recordingStop",createHandler:iV};var aV=({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 Ni({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()},cI={event:"refresh",createHandler:aV};var sV=({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 Ni({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 E=y.browser.baseUrl;S.reset({baseUrl:E,currentUrl:y.browser.url(),variablesFromEnvironment:g,envName:m,testName:h});let A=y.browser.getViewport(),b=Fr.USER_AGENT;t.info({baseUrl:p,viewport:A},`Session reset for test ${s} at ${E}`),r.emit("session",{url:E,userAgent:b,viewport:A,sessionId:c})},uI={event:"reset",createHandler:sV};var lV=({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})}},dI={event:"switchTab",createHandler:lV};async function pI(r){return Q_(r)}var mI=[OR,Z_,tI,uI,cI,IR,dI,eI,nI,sI,lI,aI,rI,oI,iI,PR,MR];var hI=r=>{let{logger:e}=r,t=new cV(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 pI({...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}mI.forEach(i=>uV(i,{...r,socket:n,metadata:o,logger:e}))}),t},uV=(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 gV}from"express";import{Router as pV}from"express";import Fl from"fs";import Ul from"path";import{v4 as mV}from"uuid";import hV from"yaml";import{hostname as dV}from"os";var eS="2.21.1",it=ru({app:"desktop-server",hostname:dV(),disableConsoleLogs:!0}).child({cliVersion:eS});(async()=>{try{let r=await al(it);r.gitBranchName&&it.addBinding("branch",r.gitBranchName)}catch{}})();var Va=pV();async function tS(r){return(await Ou(r,it)).map(n=>{let o=r.modules[n.moduleId];if(!o){T.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)}Va.get("/",Re(async(r,e)=>{let t=ce(),n=await Q(t),o=await tS(n);e.status(200).json(o)}));Va.post("/",Re(async(r,e)=>{let t;try{t=IT.parse(r.body)}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{no(t.name)}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=ce(),o=(await Q(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=Ul.join(n.rootDir,t.folderPath??"");if(!Fl.existsSync(i)||!Fl.statSync(i).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${i}' does not exist.`});return}let a=await Pu({...t,folder:i,project:n});e.status(201).json(a)}));Va.get("/:moduleId",Re(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t=await Q(ce()),n=t.modules[r.params.moduleId];if(!n){e.status(404).json({error:"Module not found."});return}try{let o=await Yr(n,t,T);e.json(o)}catch(o){e.status(400).json({err:o})}}));Va.post("/:moduleId/duplicate",Re(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=_T.parse(r.body)}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}try{no(t.name)}catch(g){e.status(400).json({error:g.message});return}let n=ce(),o=await Q(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 Yr(i,o,T),s=Ul.join(n.rootDir,Ul.dirname(i.relativePath));if(!Fl.existsSync(s)||!Fl.statSync(s).isDirectory()){e.status(400).json({error:`The folder configured for module creation '${s}' does not exist.`});return}let c=Oe(t.name),l=Ul.join(s,`${c}.module.yaml`),u=mV(),{stepsToSave:d}=await lt({stepLists:{steps:a.steps},createNewCacheIds:!0,cacheCreationParams:{orgId:xt()}}),p={fileType:de.MODULE,schemaVersion:Ee,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=hV.stringify(p);Fl.writeFileSync(l,m,"utf-8");let h={relativeFilePath:Ul.relative(n.rootDir,l)};e.status(201).json(h)}));Va.patch("/:moduleId/metadata",Re(async(r,e)=>{if(!r.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let t;try{t=MT.parse(r.body)}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=ce(),o=await Q(n);cR({moduleId:r.params.moduleId,content:t,momenticFiles:o,logger:T,project:n}),e.status(201).json({message:"ok"})}));var gI=Va;var fI=gV();fI.get("/",Re(async(r,e)=>{let t=ce(),n=await Q(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 tS(n),c={labels:i,tests:a,modules:s};e.status(200).json(c)}));var SI=fI;import{Router as fV}from"express";var rS=fV();rS.get("/",Re((r,e)=>{let t=Lu(ce(),it);e.status(200).json(t)}));rS.get("/names",Re((r,e)=>{let n=ce().config.environments?.map(o=>o.name)??[];e.status(200).json(n)}));var yI=rS;import{Router as SV}from"express";var EI=SV();EI.get("/",Re((r,e)=>{let t={userId:yo(),orgId:xt()};e.status(200).json(t)}));var TI=EI;import{StreamableHTTPServerTransport as v$}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as R$}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as A$}from"crypto";import{Router as w$}from"express";import{McpServer as T$}from"@modelcontextprotocol/sdk/server/mcp.js";import{SSEServerTransport as b$}from"@modelcontextprotocol/sdk/server/sse.js";import{streamObject as vV}from"ai";import op from"dedent";import{z as Do}from"zod";import{tool as yV}from"ai";import{z as EV}from"zod";var tp=(r,e)=>({builder:n=>yV({description:r.schema.description,inputSchema:EV.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(`
|
|
4143
4143
|
`)},"Tool execution resulted in error"):n.logger.info({toolName:r.schema.name,input:o},"Tool execution completed"),a}}),tool:r});var Bl=class{results=[];isError;addResult(e){this.results.push(e)}addError(e){this.results.push(`Error: ${e}`),this.isError=!0}getResult(){return this.results.join(`
|
|
4144
4144
|
`)}async serialize(){let e=[];return this.results.length&&(e.push("### Result"),e.push(this.results.join(`
|
|
4145
4145
|
`)),e.push("")),{content:[{type:"text",text:e.join(`
|
|
@@ -4536,7 +4536,7 @@ ${r.map(p=>`${ht}- ${p}`).join(`
|
|
|
4536
4536
|
`)}`),Object.values(e.tests).forEach(p=>{r.some(m=>p.relativePath.includes(m))&&c.add(p.fullFilePath)}))}else{!n&&!await Lt("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=CS.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 ct(u,ne,e);if(Z$.gt(d.schemaVersion,Ee)&&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:CS.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(J$)}function LM({testDefinitions:r,quarantinedTestReasons:e,onlyQuarantined:t=!1,skipQuarantined:n=!1}){if(t){let[u,d]=xp(r,h=>h.id in e),[p,m]=xp(u,h=>h.disabled||n);return{testsToSkip:p,quarantinedTestsToSkip:[],testsToRun:m,quarantinedTestsToRun:[]}}let[o,i]=xp(r,u=>u.disabled),[a,s]=xp(i,u=>u.id in e);return{testsToSkip:o,testsToRun:s,quarantinedTestsToRun:n?[]:a,quarantinedTestsToSkip:n?a:[]}}function NM({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 DM({project:r,apiClient:e}){let t=await Q(r),n=await Ya({tests:[],momenticFiles:t,yes:!0,project:r,logger:new ci(40,{})}),o=(await e.getQuarantinedTests()).quarantined,i=new Set(o.map(s=>s.testId)),a=n.filter(s=>i.has(s.id));T.info(a.map(s=>s.relativeFilePath).join(`
|
|
4537
4537
|
`))}async function kM({test:r,reason:e,apiClient:t,project:n,identity:o}){let i=(await Q(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 wp({prompt:"Select a test to unquarantine.",inputtedTest:r,testOptions:l}),d=await Cp({prompt:"Enter a reason for unquarantining the test.",inputtedReason:e});await t.unquarantineTest(u,d,o),T.success(`Test ${u.name} has been successfully removed from quarantine.`)}function UM(r){return r?Oe(r):"Unknown suite"}async function FM({client:r,orgId:e,suitePaths:t,wait:n,waitTimeout:o,...i}){let{suiteRunIds:a,runGroupIds:s}=await r.queueSuiteRuns({paths:t,...i});ne.info({orgId:e,suiteRunIds:a,runGroupIds:s,suitePaths:t},"Queued suites remotely"),T.dimmed(`Queued ${t.length} suites.`),n||process.exit(0);let c=Date.now();T.dimmed(`Waiting for ${t.length} suites to finish. You can view results upon completion at:`);for(let f of s)T.dimmed(`${ht}- ${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 ou({name:"suites",getResults:async()=>{let f=s.filter(E=>!u.some(A=>A.id===E)),y=await r.bulkGetRunGroupStatus(f),S=[];for(let E of y)d(E)?u.push(E):S.push(E);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),T.log(`${l.size}/${s.length} ${UM(y.suite?.name)}`)))}),f.every(d))}),m=r.getAppUrl(),g=la({results:p,startTime:c,onFailed:f=>{let y=UM(f.suite?.name),S=f.runs.filter(A=>A.status==="FAILED").length,E=f.runs.length;T.error(`${y} (${S}/${E} tests failed):`);for(let A of f.runs)if(A.status==="FAILED"){let b=A.testName||A.test?.name;T.error(` ${b?Oe(b):"Unknown test"} (${m}/runs/${A.id})`)}},entity:"suite",getDisplayLine:f=>` ${f.suite?.name?Oe(f.suite.name):"Unknown suite name"} (${m}/run-groups/${f.id})`});process.exit(g.failed>0?1:0)}async function BM({tests:r,client:e,orgId:t,...n}){!n.yes&&!await Lt(`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(ne.info({queuedTests:o,runIds:i,orgId:t},"Queued tests remotely"),T.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;T.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 ou({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&&T.log(`${a.size}/${o.length} ${Oe(g)}`)}}),m.every(c))}),p=la({results:d,startTime:u,onFailed:m=>{let h=m.testName||m.test?.name;iu(m,h?Oe(h):"Unknown test")},getDisplayLine:m=>{let h=m.testName||m.test?.name,g=` ${h?Oe(h):"Unknown test"}`;return m.id&&(g+=` (${l}/runs/${m.id})`),g},entity:"test"});process.exit(p.failed>0?1:0)}import{randomUUID as FW}from"crypto";import BW from"fs";import{existsSync as mW,mkdirSync as hW,statSync as gW}from"fs";import{randomUUID as HM}from"crypto";import xS from"fs";import{hostname as eW}from"os";import _S from"path";async function _p(r,e,t,n){if(n){let o=await e.getScreenshot(r,n);if(o){let i=`${n}-screenshot.jpeg`,a=_S.join(t,i);return xS.writeFileSync(a,o),i}}}async function tW(r,e,t,n){let o=n.runId??HM(),i={uuid:o,historyId:o,testCaseId:n.test.id,fullName:n.test.name,name:Oe(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:eW()},{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 rW(r,e,t.folder,i.steps,n.results);let a=`${o}-result.json`;xS.writeFileSync(_S.join(t.folder,a),JSON.stringify(i,void 0,2))}async function Xa(r,e,t,n){let o={name:So(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 _p(r,e,t,n.beforeSnapshot);i&&o.attachments.push({name:"Screenshot before step",source:i,type:"image/jpeg"});let a=await _p(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=`${HM()}-attachment.json`,c=_S.join(t,s);xS.writeFileSync(c,JSON.stringify(n.data,null,2)),o.attachments.push({name:"Step output data",source:s,type:"text/plain"})}return o}async function rW(r,e,t,n,o){for(let i of o)switch(i.type){case"PRESET_ACTION":{n.push(await Xa(r,e,t,i));break}case"CONDITIONAL":{let a=await Xa(r,e,t,i);a.steps=[],i.assertionResult&&a.steps.push(await Xa(r,e,t,i.assertionResult)),a.steps.push(...await Promise.all(i.results.map(s=>Xa(r,e,t,s)))),n.push(a);break}case"AI_ACTION":case"SECTION":case"MODULE":{let a=await Xa(r,e,t,i);if(a.steps=await Promise.all(i.results.map(s=>Xa(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 zM(r,e,t,n){for(let o of n.runs)await tW(r,e,{folder:t,suiteName:n.suiteName},o)}import nW from"junit-report-builder";import Ip from"path";function oW(r,e){if(e.name(r.test.name).className(r.test.name).file(Ip.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=mc[r.failureDetails?.classification?.reason||r.failureReason],n=r.failureDetails?.classification?.summary||qi[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 iW(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();oW(u,d)}for(let u of a){let d=l.testCase();d.name(u.name).className(u.name).file(Ip.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(Ip.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 GM(r,e){let t=nW.newBuilder();iW(t,e),t.writeTo(Ip.join(r,`${e.suiteName}.xml`))}import aW from"fs";import sW from"path";function jM(r){return{title:So(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(jM):[]}}async function lW(r,e,t,n){if(n.results?.length){let o=await _p(r,e,t,n.results[n.results.length-1].afterSnapshot);return o?[{name:"Final state screenshot",path:o,contentType:"image/jpeg"}]:[]}return[]}async function cW(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||qi[n.failureReason]}:void 0,retry:n.attempts-1,steps:n.results?.map(jM)||[],startTime:n.lastAttemptStartedAt.toISOString(),attachments:await lW(r,e,t,n)}}async function uW(r,e,t,n){return{expectedStatus:"passed",status:n.status==="PASSED"?"expected":"unexpected",results:[await cW(r,e,t,n)]}}async function dW(r,e,t,n){return{tags:[],title:n.test.name,ok:n.status==="PASSED",tests:[await uW(r,e,t,n)],id:n.runId,file:n.filePath}}function IS(r,e){return r.reduce((t,n)=>e(n)?t+1:t,0)}async function pW(r,e,t,n){return{suites:[{title:n.suiteName,file:n.projectConfigPath,specs:await Promise.all(n.runs.map(o=>dW(r,e,t,o)))}],errors:[],stats:{startTime:n.startedAt.toISOString(),duration:n.finishedAt.getTime()-n.startedAt.getTime(),expected:IS(n.runs,o=>o.status==="PASSED"),unexpected:IS(n.runs,o=>o.status!=="PASSED"),flaky:IS(n.runs,o=>!!o.isFlake),skipped:0}}}async function VM(r,e,t,n){let o=await pW(r,e,t,n);aW.writeFileSync(sW.join(t,`${n.suiteName}.json`),JSON.stringify(o,null,2))}async function $M(r,e,t,n,o){switch(mW(o)?gW(o).isDirectory()||(T.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)):(T.info(`Reporter output directory '${o}' does not exist on disk, creating it now...`),hW(o,{recursive:!0})),t){case"junit":GM(o,n);return;case"allure":case"allure-json":await zM(r,e,o,n);return;case"playwright-json":await VM(r,e,o,n);return;default:throw new Error(`Unknown reporter format requested: '${t}'`)}}import HW from"wait-on";import{execSync as fW}from"child_process";import{platform as SW}from"os";function MS(){return WM()?(T.dimmed("Setting device pixel ratio to 2 automatically since a Mac OS Retina screen was detected."),T.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.
|
|
4538
4538
|
`),2):(T.dimmed("Setting device pixel ratio to 1."),T.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.
|
|
4539
|
-
`),1)}function WM(){return SW()==="darwin"&&fW("system_profiler SPDisplaysDataType").toString().includes("Retina")}function PS(r){WM()&&r===1&&(T.warn("If you are using Momentic on a Retina screen, relaunch with the --pixel-ratio option to avoid incorrect viewport calculations."),T.warn("Confirm your device's pixel-ratio at https://www.mydevice.io."))}import yW from"@actions/exec";import EW from"@actions/io";import TW from"quote";import bW from"string-argv";async function qM(r,e=!0){let t=bW(r),n=await EW.which(t[0],!0),o=t.slice(1),i=yW.exec(TW(n),o,{delay:100});if(e)return i}import vW from"csv-parser";import{createReadStream as RW}from"fs";function OS(r){return new Promise((e,t)=>{let n=[];RW(r).pipe(vW()).on("data",o=>n.push(o)).on("end",()=>e(n)).on("error",o=>t(o))})}import Ja from"semver";import{z as Mp}from"zod";var Er="2.21.0",AW="https://registry.npmjs.org/momentic",wW=Mp.object({versions:Mp.record(Mp.string(),Mp.unknown()).optional()});async function KM(r){try{await CW(r)}catch(e){T.warn({err:e},"Failed to check CLI version against NPM servers")}}async function LS(){let r=await j(fetch(AW),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=wW.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=Er;for(let o of Object.keys(t))Ja.valid(o)&&Ja.major(o)===Ja.major(Er)&&Ja.gt(o,n)&&Ja.prerelease(o)===null&&(n=o);return n}async function CW(r){let e;for(let t=0;t<2;t++)try{e=await LS()}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}Ja.eq(Er,e)||(T.warn(`Update available: v${Er} -> v${e}`),T.warn("This version may be missing critical fixes, features, and security updates."),T.warn(`Run "npx momentic@${e} -V" to update`))}async function $n(){try{await j(Promise.all([Jb(),tr.flush()]),{milliseconds:5e3})}catch{}}import{partition as xW}from"lodash-es";function Pp(r){return r.length===1?"test":"tests"}function YM(r){return r===1?"1 worker":`${r} workers`}function XM(r){r.length!==0&&(T.info(`Skipping ${r.length} disabled ${Pp(r)}:`),r.forEach(e=>{T.info(`${ht}- ${[e.relativeFilePath]}`)}),T.log(""))}function JM(r,e){r.length!==0&&(T.info(`Skipping ${r.length} quarantined ${Pp(r)}:`),r.forEach(t=>{T.info(`${ht}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),T.log(""))}function _W(r,e){r.length!==0&&(T.info(`Running ${r.length} quarantined ${Pp(r)} with ${YM(e)}:`),r.forEach(t=>{T.info(`${ht}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),T.log(""))}function IW(r,e,t){e.length===0&&r.length>0||(T.info(`Running ${e.length} ${Pp(e)} with ${YM(t)}:`),e.forEach(n=>{T.info(`${ht}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),T.log(""))}function QM({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]=xW(e,s=>s.quarantined);_W(i,t),IW(i,a,t)}import{cloneDeep as Qa}from"lodash-es";async function ZM({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 fr({orgId:r,s:c,localTools:e,logger:t,context:o})}return i}async function eP({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 Fd({settings:h,customHeaders:p,envVariables:u,envName:e,testName:t,baseUrl:r,logger:d,localTools:s,orgId:l}),E={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:ne},A=S.browserType??"Chromium";if(!tv(A)){let I=`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...`;T.warn(I),ne.warn(I)}let b=await Fr.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new fo(E,c),contextArgs:{viewport:i.advanced.viewport??Gt,locale:i.advanced.locale??io,geolocation:i.advanced.geolocation??so,timezoneId:i.advanced.timezone??ao,colorScheme:i.advanced.colorScheme,deviceScaleFactor:n},iconKnowledgeBase:null,videoOptions:y.videoOutputPath?{videoOutputPath:y.videoOutputPath,onVideoPageChange:({videoName:I})=>{y.setActiveVideo(I)}}:void 0}),_=new No({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}),C=new ir({baseUrl:r,currentUrl:_.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async I=>{let{name:P,defaultValue:X,required:K}=I,z=m?.[P];K&&z===void 0&&(T.error(`Required parameter '${P}' is required by test '${i.name}' but not provided`),process.exit(1));let G=await fr({orgId:l,s:z??X,localTools:s,logger:d,context:ir.dummyContext(C.getEnvName())});C.setMomenticSystemVariable(P,G)})),{controller:_,context:C}}async function tP({testAdvancedSettings:r,orgSettings:e,logger:t}){if(r.failureRecovery===!1||r.failureRecovery===void 0&&!e?.failureRecovery)return!1;if(!ui){let n="This test is ineligible for failure recovery since this does not appear to be a CI environment";return t.warn(n),T.warn(n),!1}return!0}async function rP({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 tP({testAdvancedSettings:p.advanced,orgSettings:m.ai,logger:l})};return await Ud({fixtures:h,inputs:g,options:f,callbacks:{step:{},test:{onTestComplete:async()=>{await i.browser.cleanup()}}},testParams:{tracer:d}})}async function nP(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await MW(r)}catch(o){let i="Fatal error running test";return T.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 MW(r){let{testDefinition:e,project:t,apiClient:n,orgId:o,urlOverride:i,runSigIntHandlers:a,runGroupTracer:s,logger:c,gitMetadata:l,regenerateCache:u,alwaysSaveCache:d,noCache:p,runId:m,testInputs:h,quarantined:g,quarantinedReason:f,usageTracker:y}=r,S=new ca(n,o),E=fa({orgId:o,client:n,gitMetadata:l,regenerateCache:u??!1,alwaysSaveCache:d??!1,noCache:p??!1}),A=Qa(e.steps),b=Qa(e.beforeSteps)??void 0,_=Qa(e.afterSteps)??void 0;try{await E.resolveStepCacheEntries({testId:e.id,stepLists:{steps:A,beforeSteps:b,afterSteps:_},schemaVersion:e.schemaVersion,logger:c})}catch(G){throw c.error({err:G},"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: ${G}`)}let C=r.envName??OW(e),I,P={};if(C){try{I=ol(C,t,c)}catch(G){let U=`Failed to resolve environment ${C} for test ${e.name}: ${G}`;throw new Error(U)}P=I.variables}let X=e.baseUrl;if(i)X=i;else if(!X){let G=P[wt];typeof G=="string"&&(X=G)}if(!X){let G=`Cannot run test with no base URL and no ${wt} variable defined in its environment`;throw new Error(G)}let K=await s.startRun({logger:c,runId:m,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:X,environmentName:C,schemaVersion:e.schemaVersion,resolvedInputs:h,quarantined:g,quarantinedReason:f}),z=c.child(K.loggerBindings||{});Object.entries(K.envVarBindings||{}).forEach(([G,U])=>{P[G]=U});try{let G=await PW({...r,variables:P,envName:C,resolvedEnv:I,baseUrl:X,storageClient:S,tracer:K,logger:z,cacheStorage:E,stepsWithCaches:A,beforeStepsWithCaches:b,afterStepsWithCaches:_,usageTracker:y});return await K.finish({logger:c,status:G.status,finishedAt:G.finishedAt,failureDetails:G.failureDetails,failureReason:G.failureReason,isFlake:G.isFlake,failureRecoveryDetails:G.failureRecoveryDetails}),{runId:K.runId,...G}}finally{a?.pop()}}async function PW(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:E,logUpdate:A,tracer:b,logger:_,cacheStorage:C,gitMetadata:I,quarantined:P,quarantinedReason:X,usageTracker:K}=r,z=i.config.ai?.aiFailureAnalysis??!1,G=new Date,U=new ba(i,a),V={...i.config},me={envName:p,urlOverride:m,customHeaders:h,testInputs:g},W,tt=Math.abs(S??i.config.retries??e.retries??0),De=[];_.info({...I,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let ut=0;ut<=tt;ut++){let Mt=await b.startAttempt(),te=_.child(Mt.loggerBindings||{}),we={...e,steps:Qa(t),beforeSteps:Qa(n),afterSteps:Qa(o)};ut!==0&&A("RETRY",`attempt ${ut+1}/${tt+1}`);let nr=new Date,_n=V.advanced?.fakerConstantSeed,In=new mn({httpClient:new Nt({baseUrl:s.baseUrl,apiKey:s.apiKey,logger:te}),fakerSeed:_n?ia:void 0}),Dp=Mt;try{let{controller:Mn,context:zo}=await eP({tracer:Mt,baseUrl:l,envName:p,testName:we.name,apiClient:s,devicePixelRatio:E,logger:te,storageClient:u,codeEvalTools:In,test:we,generator:c,orgId:d,variables:f,customHeaders:h,testInputs:g,localBrowserConfig:{...i.config.browser||{},...y?.browser||{},...we.advanced},aiSettings:{...i.config.ai||{},...we.advanced||{}},visualDiffScreenshotStorage:U});W=await rP({attemptMetadata:{attemptNumber:ut+1,orgId:d,runId:b.runId},attemptFixtures:{logger:te,storageClient:u,usageTracker:K,codeEvalTools:In,apiClient:s,context:zo,controller:Mn,tracer:Mt},attemptInputs:{test:we,orgSettings:V}});let Tr=new Date,tn={logger:_,cacheStorage:C,orgId:d,testId:e.id,originalSteps:{steps:e.steps,beforeSteps:e.beforeSteps,afterSteps:e.afterSteps},updatedSteps:{steps:we.steps,beforeSteps:we.beforeSteps,afterSteps:we.afterSteps}};W?.status==="PASSED"?await vu(tn):W?.status==="FAILED"&&await Ru(tn),await Mt.finish({logger:te,result:W}),De.unshift(W.status);let Go=await ZM({orgId:d,codeEvalTools:In,logger:te,outputDefinitions:e.outputs??[],testContext:zo}),q=CE(De),Kl=ut+1;if(W.status!=="FAILED")return{...W,parameters:me,test:we,filePath:we.relativeFilePath,startedAt:G,lastAttemptStartedAt:nr,finishedAt:Tr,attempts:Kl,baseUrl:l,outputs:Go,isFlake:q,quarantined:P,quarantinedReason:X};let qn=W.failedStepResult,zr=qn?.message||"Unknown failure",Kn=qn?.failureReason??Ky(zr)??"UnknownError",es=te.child({errResult:qn,failureReason:Kn,errorMessage:zr,numAttempts:tt+1,name:we.name});if(ut<tt){es.warn(`Retrying failed execution attempt for run: ${zr}`);continue}es.error(`Test failed after all exhausting attempts: ${zr}`);let Yn=new Error(zr),kp={errorMessage:zr,errorStack:Yn.stack},Yl;if(z){let Pt;try{if(W.results&&W.results.length>0){let{classification:Xn,aiFailureReason:Ui}=await rR({logger:te,browserStateStorage:Dp,generator:c,fullResults:W,failureReason:Kn,error:Yn,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Pt=Xn,Yl=Ui}}catch(Xn){te.warn({err:Xn},"Failed to classify test results")}Pt&&(kp.classification=Pt,Kn=Yl??Kn)}return{...W,parameters:me,failureDetails:kp,failureReason:Kn,test:we,filePath:we.relativeFilePath,startedAt:G,lastAttemptStartedAt:nr,finishedAt:Tr,attempts:ut+1,baseUrl:l,outputs:Go,quarantined:P,quarantinedReason:X}}catch(Mn){rs(Mn);let zo=`Encountered fatal platform error while running test '${we.name}': ${Mn}`,Tr=new Date,tn=ut+1;te.error({err:Mn},zo),T.error(zo);let Go={errorMessage:Mn.message,errStack:Mn.stack},q={status:"FAILED",failureDetails:Go,failureReason:"InternalPlatformError",finishedAt:Tr};return await Mt.finish({logger:te,result:{status:"FAILED",results:[]}}),{...q,results:[],parameters:me,test:we,filePath:we.relativeFilePath,startedAt:G,lastAttemptStartedAt:nr,finishedAt:new Date,attempts:tn,baseUrl:l,outputs:{},quarantined:P,quarantinedReason:X}}}throw new Error("This code should not be reachable")}function OW(r){for(let e of r.envs??[])if(e.default)return e.name}import LW from"adm-zip";import{randomUUID as NW}from"crypto";import DW from"path";var Wn="assets";function kW(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"}}function UW(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var NS=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:`${Wn}/${t}.jpeg`,contents:n})}attachAfterScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${Wn}/${t}.jpeg`,contents:n})}attachBeforeHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${Wn}/${t}.html`,contents:n})}attachAfterHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${Wn}/${t}.html`,contents:n})}recordTargetAutoHeal(e){let{healType:t}=e,n=t==="AI"?"ai-target-heal":"cache-heal";tr.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;tr.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:UW(e.status),finishedAt:e.finishedAt}))))}async finish(e){await this.finishInternal(e.step)}async startSubSteps(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}},Za=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(`${Wn}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${Wn}/${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))tr.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 NS(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:kW(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}},DS=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("assets")}finished=!1;children=[];get loggerBindings(){return{runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return DW.resolve(this.diskStorage.cwd(),"assets")}setActiveVideo(e){this.recordVideo&&(this.metadata.activeVideos=this.metadata.activeVideos||[],this.metadata.activeVideos.push({videoName:e,timestamp:new Date}))}attachNetworkLogs(e){let{logs:t}=e;this.diskStorage.storeFile({name:"network.har",contents:JSON.stringify(t,null,2)})}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 LW;i.addLocalFolder(o,void 0,a=>a!==".DS_Store"),this.diskStorage.storeFile({name:`${Wn}/${gh}`,contents:i.toBuffer()}),n.info({browserCrashZipName:gh},"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:yu(n.results,t),beforeResults:n.beforeResults?yu(n.beforeResults,t):void 0,afterResults:n.afterResults?yu(n.afterResults,t):void 0};await Promise.all(this.children.map(i=>i.finish({status:o.status,finishedAt:o.finishedAt}))),this.diskStorage.storeFile({name:"metadata.json",contents:JSON.stringify(o,null,2)})}async startBeforeStepList(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startMainStepList(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startAfterStepList(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async getScreenshot(e,t){return this.diskStorage.readFile(`${Wn}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${Wn}/${t}.html`)?.toString()}},kS=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{[fx]: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=NW(),n={id:t,schemaVersion:Ee,runAttemptSchemaVersion:Fb,startedAt:new Date,status:"RUNNING"};e.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)});let o=new DS(this.orgId,this.testId,this.testName,t,n,e,this.recordVideo);return this.children.push(o),o}},Op=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:wr.CLI,startedAt:new Date,status:"RUNNING",cliVersion:Er,labels:i??[]},c=new sl(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:Er,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 kS(this.orgId,e.testId,e.testName,e.runId,n,t,this.recordVideo);return this.children.push(o),o}};async function oP(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 iP(r){let{logger:e,tests:t,yes:n,start:o,waitOn:i,client:a,debugDataStorage:s,project:c,retriesOverride:l,urlOverride:u,envName:d,orgId:p,devicePixelRatio:m,customHeaders:h,testInputMatrix:g,reporter:f,include:y,exclude:S,labels:E,reporterDir:A=TR,outputDir:b=bR,uploadResults:_=!1,waitOnTimeout:C=60,parallel:I,shardIndex:P=1,shardCount:X=1,regenerateGoldenFiles:K,gitMetadata:z,regenerateCache:G,alwaysSaveCache:U,noCache:V,ignoreQuarantine:me,skipQuarantined:W,onlyQuarantined:tt,runGroupId:De,recordVideo:ut}=r;o&&(e.info({orgId:p},`Executing start command: ${o}`),await qM(o,!1)),i&&(e.info({orgId:p},`Waiting for url: ${i} with timeout: ${C} seconds.`),await HW({resources:[i],interval:2500,timeout:C*1e3,headers:{Accept:"*/*"},followRedirect:!0,verbose:!1,log:!0,strictSSL:!1}));let Mt=new kn(c.config.ai?.agentConfig,{baseUrl:a.baseUrl,apiKey:a.apiKey,logger:e}),te=await Q(c),we=await Ya({tests:t,momenticFiles:te,yes:n,project:c,include:y,exclude:S,labels:E,logger:T}),nr=await oP(e,a,me),{testsToSkip:_n,quarantinedTestsToSkip:In,testsToRun:Dp,quarantinedTestsToRun:Mn}=LM({testDefinitions:we,quarantinedTestReasons:nr,onlyQuarantined:tt,skipQuarantined:W});XM(_n),JM(In,nr);let zo=NM({testsToRun:Dp,quarantinedTestsToRun:Mn,quarantinedTestReasons:nr,testInputMatrix:g}),Tr=GW({globalTestsToRunWithInputs:zo,shardIndex:P,shardCount:X});QM({logger:e,localTestsToRunWithInputs:Tr,parallel:I,shardCount:X,shardIndex:P});let tn=[],Go=new Date,q=new Set,Kl=async()=>{let Pt=a.getAppUrl(),Xn=la({results:tn,startTime:Go.getTime(),onFailed:dr=>{iu(dr,dr.filePath)},getDisplayLine:dr=>{let jo=`${ht}- ${dr.filePath}${dr.failureRecoveryDetails?" [recovered] ":""}`;return dr.runId&&(jo+=` ( link when uploaded: ${Pt}/runs/${dr.runId} )`),jo},entity:"test"}),Ui=tn.filter(dr=>!!dr.failureRecoveryDetails?.attempts);return Ui.length>0&&T.warn(`Our AI agent automatically prevented ${Ui.length} tests from failing due to transient issues. Use the run links above to review the additional steps that were executed.`),T.log(""),_?(T.success(`Test results have been saved to the folder ${b}. Uploading to Momentic Cloud...`),await ku({client:a,consoleLogger:T,resultsPath:b})):T.success(`Test results have been saved to the folder ${b}. Upload them to Momentic Cloud by running 'npx momentic results upload ${b}'.`),Xn};BW.existsSync(b)&&T.warn(`Output directory ${b} already exists, removing before test execution...`);let qn=await Op.start({orgId:p,runGroupId:De,outputDir:b,gitMetadata:z,labels:E,recordVideo:ut}),zr=e.child(qn.loggerBindings||{}),Kn=[],es=async()=>{T.warn("SIGINT received. Stopping tests and printing latest results..."),await qn.finish({logger:zr,status:"CANCELLED"}),await Kl(),await Promise.allSettled(Kn.map(Pt=>Pt())),await $n(),process.exit(1)};process.once("SIGINT",es);let Yn={};for(let Pt=0;Pt<Tr.length;Pt++){let Xn=Object.values(Yn);Xn.length===I&&await Promise.race(Xn.map(jo=>jo.promise));let Ui=Tr[Pt],dr=`test-${Pt}`;Yn[dr]={done:!1,promise:(async({inputs:jo,quarantined:mP,quarantinedReason:hP,testDefinition:Vo})=>{q.add({inputs:jo});let Xl=Vo.relativeFilePath.includes("..")?Vo.fullFilePath:Vo.relativeFilePath;js({status:"START",testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length});let gP=setInterval(()=>js({status:"RUN",testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length}),5*60*1e3),Up=FW(),Fp=zr.child({testId:Vo.id,runId:Up}),HS=new _u({logger:Fp,reporter:new su(a),runType:"test-run",runId:Up,testMetadata:Vo,suiteMetadata:void 0});try{let ts=await nP({testDefinition:Vo,project:c,testInputs:jo,quarantined:mP,quarantinedReason:hP,orgId:p,runId:Up,devicePixelRatio:m,apiClient:a,runGroupTracer:qn,generator:Mt,retriesOverride:l,urlOverride:u,envName:d,customHeaders:h,regenerateGoldenFiles:K,logUpdate:(Jl,fP)=>js({status:Jl,testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length,additionalText:fP}),runSigIntHandlers:Kn,logger:Fp,gitMetadata:z,regenerateCache:G,alwaysSaveCache:U,noCache:V,usageTracker:HS});js({status:ts.status,testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length}),tn.push(ts)}catch(ts){let Jl=`Encountered unexpected fatal error when running test '${Vo.name}': ${ts.message}`;T.error(Jl),Fp.error({err:ts},Jl)}finally{clearInterval(gP),Yn[dr].done=!0,delete Yn[dr]}await HS.flush(e)})(Ui)}}await Promise.allSettled(Object.values(Yn).map(Pt=>Pt.promise));let Yl=tn.some(Pt=>!Pt.quarantined&&Pt.status==="FAILED")?"FAILED":"PASSED";return await qn.finish({logger:zr,status:Yl}),process.off("SIGINT",es),f&&await $M(zr,s,f,{projectConfigPath:c.configFilePath,suiteName:c.config.name,startedAt:Go,finishedAt:new Date,runs:tn,testsToSkip:_n,quarantinedTestsToSkip:In,quarantinedTestReasons:nr},A),Kl()}function zW(r,e,t){if(t>r.length&&(T.warn(`Shard count ${t} is greater than the number of tests ${r.length}! Some workers won't have any tests to run.`),t=Math.max(t,r.length),e>t))return[];let n=Math.floor((e-1)*(r.length/t)),o=Math.floor(e*(r.length/t));return r.sort().filter((a,s)=>s>=n&&s<o)}function GW({globalTestsToRunWithInputs:r,shardIndex:e,shardCount:t}){return t&&t>1?zW(r,e,t):r}import{installPackage as jW}from"@antfu/install-pkg";import{cloneDeep as VW}from"lodash-es";import $W from"semver";async function aP(){let r=await LS();$W.lt(Er,r)&&T.warn(`The current CLI version (${Er}) is not the latest. It's recommended to run the upgrade command using momentic@latest.`),await jW(`momentic@${r}`,{silent:!0,dev:!0})}function sP(r){let e=VW(r.config),t={...e.ai?.agentConfig,...kc},n={...e.ai,agentConfig:t};e.ai=n,Eo(e,r.configFilePath)}Bp||ne.warn("Sentry is not enabled in this environment due to unsupported node version");cx({serviceName:"cli"});var cP=process.argv.some(r=>r.includes("--log-level"))&&process.argv.some(r=>r.includes("debug")),US=r=>{cP&&T.dimmed(r)};cP&&nv(ne);var Ut=new WW;Ut.name("momentic").description("Momentic CLI").version(Er);Ut.command("install-browsers").description("Install browser executables onto the local machine.").option("-f, --force","Force reinstallation even if the browser executables already exist on disk.").option("-a, --all","Install all browsers types.").argument("[browsers...]",`Browsers to install. Available choices: ${bh.join(", ")}.`).action(async(r,e)=>{!e.all&&r.length===0&&(T.error("No browsers specified"),process.exit(1)),await rv({rawBrowsers:r,force:e.force,all:e.all})});Ut.addOption(new ur("--log-level <level>").choices(["debug","info","warn","error"]).default("info")).on("option:log-level",r=>{r==="debug"&&T.info("Enabling debug logging"),T.setMinLevel(r.toLowerCase())});Ut.addOption(new ur("--verbose","enable verbose logging")).on("option:verbose",()=>{ne.enableConsoleLogs(),T.setMinLevel(20)});var FS=Ut.command("checks").alias("check").description("Perform various project checks");FS.command("config").addOption(rr).action(async r=>{await Tt({configFilePath:r.config})});FS.command("duplicate-ids").description("Checks if any steps in your entire Momentic test repository share the same ID.").addOption(rr).addOption(TM).action(async r=>{let e=await Tt({configFilePath:r.config});await aM({project:e,fix:r.fix})});FS.command("duplicate-names").description("Checks if tests or modules with duplicate names or ids exist").addOption(rr).action(async r=>{let e=await Tt({configFilePath:r.config});await sM({project:e})});var uP=Ut.command("migrate").description("Migrate and upgrade tooling");uP.command("steps").description("Migrate steps in all tests and modules to the latest schema version. Note that this is always done when a test is loaded through the interactive editor, so is generally not needed.").addOption(rr).action(async r=>{let e=await Tt({configFilePath:r.config});await MM(e)});uP.command("v1-v2").description("Migrate from v1 of the Momentic CLI to v2").addOption(Hr).addOption(rr).addOption(Br).addOption(Bo).action(async r=>{!r.yes&&!await Lt("This command will modify your existing Momentic configuration. Please backup your local directory using Git or another version control system before proceeding. Continue?")&&process.exit(1);let e=await Tt({configFilePath:r.config}),t=new et({baseUrl:r.server,apiKey:r.apiKey,logger:ne}),{orgId:n}=await t.getAuthInfo();await PM({project:e,orgId:n,apiClient:t}),process.exit(0)});Ut.command("import").addOption(Br).addOption(Hr).addOption(rr).addOption(Bo).addArgument(CM).action(async(r,e)=>{let{apiKey:t,server:n,config:o,yes:i}=e,a=await Tt({configFilePath:o}),s=new et({baseUrl:n,apiKey:t,logger:ne});!r||r.length===0?await pM({client:s,project:a,skipPrompts:i}):await mM({client:s,project:a,paths:r,skipPrompts:i}),process.exit(0)});Ut.command("init").description("Initialize an empty Momentic project in the current working directory").addOption(new ur("--name <name>","Name of the project")).action(async r=>{T.info(`Welcome to the Momentic project setup wizard! \u{1F680}
|
|
4539
|
+
`),1)}function WM(){return SW()==="darwin"&&fW("system_profiler SPDisplaysDataType").toString().includes("Retina")}function PS(r){WM()&&r===1&&(T.warn("If you are using Momentic on a Retina screen, relaunch with the --pixel-ratio option to avoid incorrect viewport calculations."),T.warn("Confirm your device's pixel-ratio at https://www.mydevice.io."))}import yW from"@actions/exec";import EW from"@actions/io";import TW from"quote";import bW from"string-argv";async function qM(r,e=!0){let t=bW(r),n=await EW.which(t[0],!0),o=t.slice(1),i=yW.exec(TW(n),o,{delay:100});if(e)return i}import vW from"csv-parser";import{createReadStream as RW}from"fs";function OS(r){return new Promise((e,t)=>{let n=[];RW(r).pipe(vW()).on("data",o=>n.push(o)).on("end",()=>e(n)).on("error",o=>t(o))})}import Ja from"semver";import{z as Mp}from"zod";var Er="2.21.1",AW="https://registry.npmjs.org/momentic",wW=Mp.object({versions:Mp.record(Mp.string(),Mp.unknown()).optional()});async function KM(r){try{await CW(r)}catch(e){T.warn({err:e},"Failed to check CLI version against NPM servers")}}async function LS(){let r=await j(fetch(AW),{milliseconds:5e3});if(!r.ok)throw new Error(`Got error status code ${r.statusText}`);let e=await r.json(),t=wW.parse(e).versions;if(!t)throw new Error("Failed to fetch npm registry data. Skipping version check.");let n=Er;for(let o of Object.keys(t))Ja.valid(o)&&Ja.major(o)===Ja.major(Er)&&Ja.gt(o,n)&&Ja.prerelease(o)===null&&(n=o);return n}async function CW(r){let e;for(let t=0;t<2;t++)try{e=await LS()}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}Ja.eq(Er,e)||(T.warn(`Update available: v${Er} -> v${e}`),T.warn("This version may be missing critical fixes, features, and security updates."),T.warn(`Run "npx momentic@${e} -V" to update`))}async function $n(){try{await j(Promise.all([Jb(),tr.flush()]),{milliseconds:5e3})}catch{}}import{partition as xW}from"lodash-es";function Pp(r){return r.length===1?"test":"tests"}function YM(r){return r===1?"1 worker":`${r} workers`}function XM(r){r.length!==0&&(T.info(`Skipping ${r.length} disabled ${Pp(r)}:`),r.forEach(e=>{T.info(`${ht}- ${[e.relativeFilePath]}`)}),T.log(""))}function JM(r,e){r.length!==0&&(T.info(`Skipping ${r.length} quarantined ${Pp(r)}:`),r.forEach(t=>{T.info(`${ht}- ${[t.relativeFilePath]}: ${e[t.id]}`)}),T.log(""))}function _W(r,e){r.length!==0&&(T.info(`Running ${r.length} quarantined ${Pp(r)} with ${YM(e)}:`),r.forEach(t=>{T.info(`${ht}- ${[t.testDefinition.relativeFilePath]}${typeof t.inputIndex=="number"?` with input set ${t.inputIndex}`:""}`)}),T.log(""))}function IW(r,e,t){e.length===0&&r.length>0||(T.info(`Running ${e.length} ${Pp(e)} with ${YM(t)}:`),e.forEach(n=>{T.info(`${ht}- ${[n.testDefinition.relativeFilePath]}${typeof n.inputIndex=="number"?` with input set ${n.inputIndex}`:""}`)}),T.log(""))}function QM({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]=xW(e,s=>s.quarantined);_W(i,t),IW(i,a,t)}import{cloneDeep as Qa}from"lodash-es";async function ZM({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 fr({orgId:r,s:c,localTools:e,logger:t,context:o})}return i}async function eP({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 Fd({settings:h,customHeaders:p,envVariables:u,envName:e,testName:t,baseUrl:r,logger:d,localTools:s,orgId:l}),E={baseUrl:o.baseUrl,apiKey:o.apiKey,logger:ne},A=S.browserType??"Chromium";if(!tv(A)){let I=`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...`;T.warn(I),ne.warn(I)}let b=await Fr.init({baseUrl:r,logger:d,userBrowserSettings:S,storage:a,enricher:new fo(E,c),contextArgs:{viewport:i.advanced.viewport??Gt,locale:i.advanced.locale??io,geolocation:i.advanced.geolocation??so,timezoneId:i.advanced.timezone??ao,colorScheme:i.advanced.colorScheme,deviceScaleFactor:n},iconKnowledgeBase:null,videoOptions:y.videoOutputPath?{videoOutputPath:y.videoOutputPath,onVideoPageChange:({videoName:I})=>{y.setActiveVideo(I)}}:void 0}),_=new No({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}),C=new ir({baseUrl:r,currentUrl:_.browser.url(),variablesFromEnvironment:u,envName:e,testName:t});return i.parameters&&await Promise.all(i.parameters.map(async I=>{let{name:P,defaultValue:X,required:K}=I,z=m?.[P];K&&z===void 0&&(T.error(`Required parameter '${P}' is required by test '${i.name}' but not provided`),process.exit(1));let G=await fr({orgId:l,s:z??X,localTools:s,logger:d,context:ir.dummyContext(C.getEnvName())});C.setMomenticSystemVariable(P,G)})),{controller:_,context:C}}async function tP({testAdvancedSettings:r,orgSettings:e,logger:t}){if(r.failureRecovery===!1||r.failureRecovery===void 0&&!e?.failureRecovery)return!1;if(!ui){let n="This test is ineligible for failure recovery since this does not appear to be a CI environment";return t.warn(n),T.warn(n),!1}return!0}async function rP({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 tP({testAdvancedSettings:p.advanced,orgSettings:m.ai,logger:l})};return await Ud({fixtures:h,inputs:g,options:f,callbacks:{step:{},test:{onTestComplete:async()=>{await i.browser.cleanup()}}},testParams:{tracer:d}})}async function nP(r){let{testDefinition:e,logger:t}=r,n=new Date;try{return await MW(r)}catch(o){let i="Fatal error running test";return T.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 MW(r){let{testDefinition:e,project:t,apiClient:n,orgId:o,urlOverride:i,runSigIntHandlers:a,runGroupTracer:s,logger:c,gitMetadata:l,regenerateCache:u,alwaysSaveCache:d,noCache:p,runId:m,testInputs:h,quarantined:g,quarantinedReason:f,usageTracker:y}=r,S=new ca(n,o),E=fa({orgId:o,client:n,gitMetadata:l,regenerateCache:u??!1,alwaysSaveCache:d??!1,noCache:p??!1}),A=Qa(e.steps),b=Qa(e.beforeSteps)??void 0,_=Qa(e.afterSteps)??void 0;try{await E.resolveStepCacheEntries({testId:e.id,stepLists:{steps:A,beforeSteps:b,afterSteps:_},schemaVersion:e.schemaVersion,logger:c})}catch(G){throw c.error({err:G},"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: ${G}`)}let C=r.envName??OW(e),I,P={};if(C){try{I=ol(C,t,c)}catch(G){let U=`Failed to resolve environment ${C} for test ${e.name}: ${G}`;throw new Error(U)}P=I.variables}let X=e.baseUrl;if(i)X=i;else if(!X){let G=P[wt];typeof G=="string"&&(X=G)}if(!X){let G=`Cannot run test with no base URL and no ${wt} variable defined in its environment`;throw new Error(G)}let K=await s.startRun({logger:c,runId:m,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:X,environmentName:C,schemaVersion:e.schemaVersion,resolvedInputs:h,quarantined:g,quarantinedReason:f}),z=c.child(K.loggerBindings||{});Object.entries(K.envVarBindings||{}).forEach(([G,U])=>{P[G]=U});try{let G=await PW({...r,variables:P,envName:C,resolvedEnv:I,baseUrl:X,storageClient:S,tracer:K,logger:z,cacheStorage:E,stepsWithCaches:A,beforeStepsWithCaches:b,afterStepsWithCaches:_,usageTracker:y});return await K.finish({logger:c,status:G.status,finishedAt:G.finishedAt,failureDetails:G.failureDetails,failureReason:G.failureReason,isFlake:G.isFlake,failureRecoveryDetails:G.failureRecoveryDetails}),{runId:K.runId,...G}}finally{a?.pop()}}async function PW(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:E,logUpdate:A,tracer:b,logger:_,cacheStorage:C,gitMetadata:I,quarantined:P,quarantinedReason:X,usageTracker:K}=r,z=i.config.ai?.aiFailureAnalysis??!1,G=new Date,U=new ba(i,a),V={...i.config},me={envName:p,urlOverride:m,customHeaders:h,testInputs:g},W,tt=Math.abs(S??i.config.retries??e.retries??0),De=[];_.info({...I,labels:e.labels,name:e.name,cwd:process.cwd()},"Starting test run using CLI");for(let ut=0;ut<=tt;ut++){let Mt=await b.startAttempt(),te=_.child(Mt.loggerBindings||{}),we={...e,steps:Qa(t),beforeSteps:Qa(n),afterSteps:Qa(o)};ut!==0&&A("RETRY",`attempt ${ut+1}/${tt+1}`);let nr=new Date,_n=V.advanced?.fakerConstantSeed,In=new mn({httpClient:new Nt({baseUrl:s.baseUrl,apiKey:s.apiKey,logger:te}),fakerSeed:_n?ia:void 0}),Dp=Mt;try{let{controller:Mn,context:zo}=await eP({tracer:Mt,baseUrl:l,envName:p,testName:we.name,apiClient:s,devicePixelRatio:E,logger:te,storageClient:u,codeEvalTools:In,test:we,generator:c,orgId:d,variables:f,customHeaders:h,testInputs:g,localBrowserConfig:{...i.config.browser||{},...y?.browser||{},...we.advanced},aiSettings:{...i.config.ai||{},...we.advanced||{}},visualDiffScreenshotStorage:U});W=await rP({attemptMetadata:{attemptNumber:ut+1,orgId:d,runId:b.runId},attemptFixtures:{logger:te,storageClient:u,usageTracker:K,codeEvalTools:In,apiClient:s,context:zo,controller:Mn,tracer:Mt},attemptInputs:{test:we,orgSettings:V}});let Tr=new Date,tn={logger:_,cacheStorage:C,orgId:d,testId:e.id,originalSteps:{steps:e.steps,beforeSteps:e.beforeSteps,afterSteps:e.afterSteps},updatedSteps:{steps:we.steps,beforeSteps:we.beforeSteps,afterSteps:we.afterSteps}};W?.status==="PASSED"?await vu(tn):W?.status==="FAILED"&&await Ru(tn),await Mt.finish({logger:te,result:W}),De.unshift(W.status);let Go=await ZM({orgId:d,codeEvalTools:In,logger:te,outputDefinitions:e.outputs??[],testContext:zo}),q=CE(De),Kl=ut+1;if(W.status!=="FAILED")return{...W,parameters:me,test:we,filePath:we.relativeFilePath,startedAt:G,lastAttemptStartedAt:nr,finishedAt:Tr,attempts:Kl,baseUrl:l,outputs:Go,isFlake:q,quarantined:P,quarantinedReason:X};let qn=W.failedStepResult,zr=qn?.message||"Unknown failure",Kn=qn?.failureReason??Ky(zr)??"UnknownError",es=te.child({errResult:qn,failureReason:Kn,errorMessage:zr,numAttempts:tt+1,name:we.name});if(ut<tt){es.warn(`Retrying failed execution attempt for run: ${zr}`);continue}es.error(`Test failed after all exhausting attempts: ${zr}`);let Yn=new Error(zr),kp={errorMessage:zr,errorStack:Yn.stack},Yl;if(z){let Pt;try{if(W.results&&W.results.length>0){let{classification:Xn,aiFailureReason:Ui}=await rR({logger:te,browserStateStorage:Dp,generator:c,fullResults:W,failureReason:Kn,error:Yn,maxItemsFromEnd:void 0,numStepsWithScreenshots:void 0,disableCache:!1});Pt=Xn,Yl=Ui}}catch(Xn){te.warn({err:Xn},"Failed to classify test results")}Pt&&(kp.classification=Pt,Kn=Yl??Kn)}return{...W,parameters:me,failureDetails:kp,failureReason:Kn,test:we,filePath:we.relativeFilePath,startedAt:G,lastAttemptStartedAt:nr,finishedAt:Tr,attempts:ut+1,baseUrl:l,outputs:Go,quarantined:P,quarantinedReason:X}}catch(Mn){rs(Mn);let zo=`Encountered fatal platform error while running test '${we.name}': ${Mn}`,Tr=new Date,tn=ut+1;te.error({err:Mn},zo),T.error(zo);let Go={errorMessage:Mn.message,errStack:Mn.stack},q={status:"FAILED",failureDetails:Go,failureReason:"InternalPlatformError",finishedAt:Tr};return await Mt.finish({logger:te,result:{status:"FAILED",results:[]}}),{...q,results:[],parameters:me,test:we,filePath:we.relativeFilePath,startedAt:G,lastAttemptStartedAt:nr,finishedAt:new Date,attempts:tn,baseUrl:l,outputs:{},quarantined:P,quarantinedReason:X}}}throw new Error("This code should not be reachable")}function OW(r){for(let e of r.envs??[])if(e.default)return e.name}import LW from"adm-zip";import{randomUUID as NW}from"crypto";import DW from"path";var Wn="assets";function kW(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"}}function UW(r){switch(r){case"SUCCESS":return"PASSED";case"FAILED":return"FAILED";case"CANCELLED":return"CANCELLED";case"RUNNING":return"RUNNING";case"IDLE":return"PENDING"}}var NS=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:`${Wn}/${t}.jpeg`,contents:n})}attachAfterScreenshot(e){let{snapshotId:t,screenshot:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${Wn}/${t}.jpeg`,contents:n})}attachBeforeHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.beforeSnapshotId=t,this.diskStorage.storeFile({name:`${Wn}/${t}.html`,contents:n})}attachAfterHtmlSnapshot(e){let{snapshotId:t,html:n}=e;this.metadata.afterSnapshotId=t,this.diskStorage.storeFile({name:`${Wn}/${t}.html`,contents:n})}recordTargetAutoHeal(e){let{healType:t}=e,n=t==="AI"?"ai-target-heal":"cache-heal";tr.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;tr.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:UW(e.status),finishedAt:e.finishedAt}))))}async finish(e){await this.finishInternal(e.step)}async startSubSteps(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}},Za=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(`${Wn}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${Wn}/${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))tr.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 NS(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:kW(e.status),finishedAt:e.finishedAt}))),this.sendFinalizedStepStats())}},DS=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("assets")}finished=!1;children=[];get loggerBindings(){return{runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return DW.resolve(this.diskStorage.cwd(),"assets")}setActiveVideo(e){this.recordVideo&&(this.metadata.activeVideos=this.metadata.activeVideos||[],this.metadata.activeVideos.push({videoName:e,timestamp:new Date}))}attachNetworkLogs(e){let{logs:t}=e;this.diskStorage.storeFile({name:"network.har",contents:JSON.stringify(t,null,2)})}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 LW;i.addLocalFolder(o,void 0,a=>a!==".DS_Store"),this.diskStorage.storeFile({name:`${Wn}/${gh}`,contents:i.toBuffer()}),n.info({browserCrashZipName:gh},"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:yu(n.results,t),beforeResults:n.beforeResults?yu(n.beforeResults,t):void 0,afterResults:n.afterResults?yu(n.afterResults,t):void 0};await Promise.all(this.children.map(i=>i.finish({status:o.status,finishedAt:o.finishedAt}))),this.diskStorage.storeFile({name:"metadata.json",contents:JSON.stringify(o,null,2)})}async startBeforeStepList(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startMainStepList(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async startAfterStepList(){let e=new Za(this.orgId,this.testId,this.testName,this.diskStorage);return this.children.push(e),e}async getScreenshot(e,t){return this.diskStorage.readFile(`${Wn}/${t}.jpeg`)}async getHtmlSnapshot(e,t){return this.diskStorage.readFile(`${Wn}/${t}.html`)?.toString()}},kS=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{[fx]: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=NW(),n={id:t,schemaVersion:Ee,runAttemptSchemaVersion:Fb,startedAt:new Date,status:"RUNNING"};e.storeFile({name:"metadata.json",contents:JSON.stringify(n,null,2)});let o=new DS(this.orgId,this.testId,this.testName,t,n,e,this.recordVideo);return this.children.push(o),o}},Op=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:wr.CLI,startedAt:new Date,status:"RUNNING",cliVersion:Er,labels:i??[]},c=new sl(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:Er,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 kS(this.orgId,e.testId,e.testName,e.runId,n,t,this.recordVideo);return this.children.push(o),o}};async function oP(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 iP(r){let{logger:e,tests:t,yes:n,start:o,waitOn:i,client:a,debugDataStorage:s,project:c,retriesOverride:l,urlOverride:u,envName:d,orgId:p,devicePixelRatio:m,customHeaders:h,testInputMatrix:g,reporter:f,include:y,exclude:S,labels:E,reporterDir:A=TR,outputDir:b=bR,uploadResults:_=!1,waitOnTimeout:C=60,parallel:I,shardIndex:P=1,shardCount:X=1,regenerateGoldenFiles:K,gitMetadata:z,regenerateCache:G,alwaysSaveCache:U,noCache:V,ignoreQuarantine:me,skipQuarantined:W,onlyQuarantined:tt,runGroupId:De,recordVideo:ut}=r;o&&(e.info({orgId:p},`Executing start command: ${o}`),await qM(o,!1)),i&&(e.info({orgId:p},`Waiting for url: ${i} with timeout: ${C} seconds.`),await HW({resources:[i],interval:2500,timeout:C*1e3,headers:{Accept:"*/*"},followRedirect:!0,verbose:!1,log:!0,strictSSL:!1}));let Mt=new kn(c.config.ai?.agentConfig,{baseUrl:a.baseUrl,apiKey:a.apiKey,logger:e}),te=await Q(c),we=await Ya({tests:t,momenticFiles:te,yes:n,project:c,include:y,exclude:S,labels:E,logger:T}),nr=await oP(e,a,me),{testsToSkip:_n,quarantinedTestsToSkip:In,testsToRun:Dp,quarantinedTestsToRun:Mn}=LM({testDefinitions:we,quarantinedTestReasons:nr,onlyQuarantined:tt,skipQuarantined:W});XM(_n),JM(In,nr);let zo=NM({testsToRun:Dp,quarantinedTestsToRun:Mn,quarantinedTestReasons:nr,testInputMatrix:g}),Tr=GW({globalTestsToRunWithInputs:zo,shardIndex:P,shardCount:X});QM({logger:e,localTestsToRunWithInputs:Tr,parallel:I,shardCount:X,shardIndex:P});let tn=[],Go=new Date,q=new Set,Kl=async()=>{let Pt=a.getAppUrl(),Xn=la({results:tn,startTime:Go.getTime(),onFailed:dr=>{iu(dr,dr.filePath)},getDisplayLine:dr=>{let jo=`${ht}- ${dr.filePath}${dr.failureRecoveryDetails?" [recovered] ":""}`;return dr.runId&&(jo+=` ( link when uploaded: ${Pt}/runs/${dr.runId} )`),jo},entity:"test"}),Ui=tn.filter(dr=>!!dr.failureRecoveryDetails?.attempts);return Ui.length>0&&T.warn(`Our AI agent automatically prevented ${Ui.length} tests from failing due to transient issues. Use the run links above to review the additional steps that were executed.`),T.log(""),_?(T.success(`Test results have been saved to the folder ${b}. Uploading to Momentic Cloud...`),await ku({client:a,consoleLogger:T,resultsPath:b})):T.success(`Test results have been saved to the folder ${b}. Upload them to Momentic Cloud by running 'npx momentic results upload ${b}'.`),Xn};BW.existsSync(b)&&T.warn(`Output directory ${b} already exists, removing before test execution...`);let qn=await Op.start({orgId:p,runGroupId:De,outputDir:b,gitMetadata:z,labels:E,recordVideo:ut}),zr=e.child(qn.loggerBindings||{}),Kn=[],es=async()=>{T.warn("SIGINT received. Stopping tests and printing latest results..."),await qn.finish({logger:zr,status:"CANCELLED"}),await Kl(),await Promise.allSettled(Kn.map(Pt=>Pt())),await $n(),process.exit(1)};process.once("SIGINT",es);let Yn={};for(let Pt=0;Pt<Tr.length;Pt++){let Xn=Object.values(Yn);Xn.length===I&&await Promise.race(Xn.map(jo=>jo.promise));let Ui=Tr[Pt],dr=`test-${Pt}`;Yn[dr]={done:!1,promise:(async({inputs:jo,quarantined:mP,quarantinedReason:hP,testDefinition:Vo})=>{q.add({inputs:jo});let Xl=Vo.relativeFilePath.includes("..")?Vo.fullFilePath:Vo.relativeFilePath;js({status:"START",testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length});let gP=setInterval(()=>js({status:"RUN",testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length}),5*60*1e3),Up=FW(),Fp=zr.child({testId:Vo.id,runId:Up}),HS=new _u({logger:Fp,reporter:new su(a),runType:"test-run",runId:Up,testMetadata:Vo,suiteMetadata:void 0});try{let ts=await nP({testDefinition:Vo,project:c,testInputs:jo,quarantined:mP,quarantinedReason:hP,orgId:p,runId:Up,devicePixelRatio:m,apiClient:a,runGroupTracer:qn,generator:Mt,retriesOverride:l,urlOverride:u,envName:d,customHeaders:h,regenerateGoldenFiles:K,logUpdate:(Jl,fP)=>js({status:Jl,testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length,additionalText:fP}),runSigIntHandlers:Kn,logger:Fp,gitMetadata:z,regenerateCache:G,alwaysSaveCache:U,noCache:V,usageTracker:HS});js({status:ts.status,testLogRef:Xl,getRunningTestsCount:()=>q.size,getTotalTestsCount:()=>Tr.length}),tn.push(ts)}catch(ts){let Jl=`Encountered unexpected fatal error when running test '${Vo.name}': ${ts.message}`;T.error(Jl),Fp.error({err:ts},Jl)}finally{clearInterval(gP),Yn[dr].done=!0,delete Yn[dr]}await HS.flush(e)})(Ui)}}await Promise.allSettled(Object.values(Yn).map(Pt=>Pt.promise));let Yl=tn.some(Pt=>!Pt.quarantined&&Pt.status==="FAILED")?"FAILED":"PASSED";return await qn.finish({logger:zr,status:Yl}),process.off("SIGINT",es),f&&await $M(zr,s,f,{projectConfigPath:c.configFilePath,suiteName:c.config.name,startedAt:Go,finishedAt:new Date,runs:tn,testsToSkip:_n,quarantinedTestsToSkip:In,quarantinedTestReasons:nr},A),Kl()}function zW(r,e,t){if(t>r.length&&(T.warn(`Shard count ${t} is greater than the number of tests ${r.length}! Some workers won't have any tests to run.`),t=Math.max(t,r.length),e>t))return[];let n=Math.floor((e-1)*(r.length/t)),o=Math.floor(e*(r.length/t));return r.sort().filter((a,s)=>s>=n&&s<o)}function GW({globalTestsToRunWithInputs:r,shardIndex:e,shardCount:t}){return t&&t>1?zW(r,e,t):r}import{installPackage as jW}from"@antfu/install-pkg";import{cloneDeep as VW}from"lodash-es";import $W from"semver";async function aP(){let r=await LS();$W.lt(Er,r)&&T.warn(`The current CLI version (${Er}) is not the latest. It's recommended to run the upgrade command using momentic@latest.`),await jW(`momentic@${r}`,{silent:!0,dev:!0})}function sP(r){let e=VW(r.config),t={...e.ai?.agentConfig,...kc},n={...e.ai,agentConfig:t};e.ai=n,Eo(e,r.configFilePath)}Bp||ne.warn("Sentry is not enabled in this environment due to unsupported node version");cx({serviceName:"cli"});var cP=process.argv.some(r=>r.includes("--log-level"))&&process.argv.some(r=>r.includes("debug")),US=r=>{cP&&T.dimmed(r)};cP&&nv(ne);var Ut=new WW;Ut.name("momentic").description("Momentic CLI").version(Er);Ut.command("install-browsers").description("Install browser executables onto the local machine.").option("-f, --force","Force reinstallation even if the browser executables already exist on disk.").option("-a, --all","Install all browsers types.").argument("[browsers...]",`Browsers to install. Available choices: ${bh.join(", ")}.`).action(async(r,e)=>{!e.all&&r.length===0&&(T.error("No browsers specified"),process.exit(1)),await rv({rawBrowsers:r,force:e.force,all:e.all})});Ut.addOption(new ur("--log-level <level>").choices(["debug","info","warn","error"]).default("info")).on("option:log-level",r=>{r==="debug"&&T.info("Enabling debug logging"),T.setMinLevel(r.toLowerCase())});Ut.addOption(new ur("--verbose","enable verbose logging")).on("option:verbose",()=>{ne.enableConsoleLogs(),T.setMinLevel(20)});var FS=Ut.command("checks").alias("check").description("Perform various project checks");FS.command("config").addOption(rr).action(async r=>{await Tt({configFilePath:r.config})});FS.command("duplicate-ids").description("Checks if any steps in your entire Momentic test repository share the same ID.").addOption(rr).addOption(TM).action(async r=>{let e=await Tt({configFilePath:r.config});await aM({project:e,fix:r.fix})});FS.command("duplicate-names").description("Checks if tests or modules with duplicate names or ids exist").addOption(rr).action(async r=>{let e=await Tt({configFilePath:r.config});await sM({project:e})});var uP=Ut.command("migrate").description("Migrate and upgrade tooling");uP.command("steps").description("Migrate steps in all tests and modules to the latest schema version. Note that this is always done when a test is loaded through the interactive editor, so is generally not needed.").addOption(rr).action(async r=>{let e=await Tt({configFilePath:r.config});await MM(e)});uP.command("v1-v2").description("Migrate from v1 of the Momentic CLI to v2").addOption(Hr).addOption(rr).addOption(Br).addOption(Bo).action(async r=>{!r.yes&&!await Lt("This command will modify your existing Momentic configuration. Please backup your local directory using Git or another version control system before proceeding. Continue?")&&process.exit(1);let e=await Tt({configFilePath:r.config}),t=new et({baseUrl:r.server,apiKey:r.apiKey,logger:ne}),{orgId:n}=await t.getAuthInfo();await PM({project:e,orgId:n,apiClient:t}),process.exit(0)});Ut.command("import").addOption(Br).addOption(Hr).addOption(rr).addOption(Bo).addArgument(CM).action(async(r,e)=>{let{apiKey:t,server:n,config:o,yes:i}=e,a=await Tt({configFilePath:o}),s=new et({baseUrl:n,apiKey:t,logger:ne});!r||r.length===0?await pM({client:s,project:a,skipPrompts:i}):await mM({client:s,project:a,paths:r,skipPrompts:i}),process.exit(0)});Ut.command("init").description("Initialize an empty Momentic project in the current working directory").addOption(new ur("--name <name>","Name of the project")).action(async r=>{T.info(`Welcome to the Momentic project setup wizard! \u{1F680}
|
|
4540
4540
|
`),T.info("This wizard will help you bootstrap a new Momentic project. If you need to import existing assets from Momentic Cloud, you can call the 'import' command after initialization."),Np.existsSync(Ea)&&(T.error("A momentic.config.yaml file already exists in this directory. Please rename or remove it to initialize a new project."),process.exit(1));let e=r.name??await Vb("Choose an identifier for your project, such as a service, product, or team name (default: 'app'):","app");await RR()||await Lt("A Git repository was not detected in the current directory. Momentic highly recommends initializing your project within a Git repository for seamless version control. Continue?")||process.exit(1),Eo({name:e,include:Wh},Ea),T.success(`Initialized Momentic project file at ${Lp.resolve(Ea)}`)});Ut.command("app").addOption(Br).addOption(Hr).addOption(Bo).addOption(SS).addOption(rr).addOption(ES).addOption(TS).addOption(bS).action(async r=>{let{apiKey:e,yes:t,server:n,pixelRatio:o,disableCache:i,saveCache:a,regenerateCache:s}=r,c=await Tt({configFilePath:r.config,nameFilter:void 0}),{errors:l}=await Ep({project:c,fix:!1});l>0&&(T.error(`Found ${l} errors`),T.warn("To fix these errors automatically, run the duplicate-ids check with the --fix flag and then commit the resulting changes"),process.exit(1)),aA(ne);let u=new et({baseUrl:n,apiKey:e,logger:ne});await xh({client:u,skipPrompts:t});let d=JW(import.meta.url),p=Lp.dirname(d),m=Lp.resolve(p,"..","static"),h=Lp.resolve(p,"..","assets"),g=o??MS();PS(g),await rM({momenticServerUrl:n,apiKey:e,serverPort:Tp,appPort:Tp,staticDir:m,assetsDir:h,devicePixelRatio:g,regenerateCache:s,noCache:i,alwaysSaveCache:a,initialProject:c});let f=`http://localhost:${Tp}`;await XW(f)});var dP=Ut.command("queue").description("Queue tests or suites to run on Momentic Cloud");dP.command("suites").description("Run one or more suites on Momentic Cloud").addOption(Br).addOption(Hr).addOption(pS).addOption(mS).addOption(Bo).addArgument(xM).addOption(Ap).addOption(Rp).addOption(vp).action(async(r,e)=>{let{apiKey:t,server:n,wait:o,waitTimeout:i,env:a,urlOverride:s}=e,c=bp(e.customHeaders),l=new et({baseUrl:n,apiKey:t,logger:ne});(!r||!Array.isArray(r)||!r.length)&&(T.error("Must pass at least one suite to run."),process.exit(1));let{orgId:u}=await l.getAuthInfo();await FM({client:l,orgId:u,wait:o,suitePaths:r,waitTimeout:i,env:a,urlOverride:s,customHeaders:c}),await $n()});dP.command("tests").description("Run one or more tests on Momentic Cloud").addOption(Br).addOption(Hr).addOption(Bo).addOption(vp).addOption(yS).addOption(Ap).addOption(Rp).addOption(new ur("--all","Run all tests.").default(!1)).addOption(pS).addOption(mS).addArgument(wM).action(async(r,e)=>{let{all:t,apiKey:n,env:o,server:i,inputCsv:a,urlOverride:s,wait:c,waitTimeout:l,yes:u}=e,d=bp(e.customHeaders);for(let g of r)(g.endsWith(".yaml")||Np.existsSync(g))&&T.warn("Are you trying to run a test on your local machine? If so, please use the 'run' command instead of the 'queue' command");let p=new et({baseUrl:i,apiKey:n,logger:ne}),{orgId:m}=await p.getAuthInfo(),h;a&&(h=await OS(a)),await BM({client:p,orgId:m,tests:r,all:t,customHeaders:d,env:o,urlOverride:s,wait:c,waitTimeout:l,testInputMatrix:h,yes:u}),await $n(),process.exit(0)});var QW=Ut.command("list").description("List test paths");QW.addOption(rr).addOption(Ho).addOption(gS).addOption(fS).addOption(new ur("--labels <labels...>","Only run tests with the specified label(s).")).addArgument(vS).action(async(r,e)=>{let t=await Tt({configFilePath:e.config,nameFilter:e.filter}),n=await Q(t),o=await Ya({tests:r,momenticFiles:n,yes:!0,project:t,include:e.include,exclude:e.exclude,labels:e.labels,logger:new ci(40,{})});T.info(o.map(i=>i.relativeFilePath).join(`
|
|
4541
4541
|
`)),process.exit(0)});var ZW=Ut.command("run").alias("test").description("Run tests on the local machine");ZW.addOption(Br).addOption(Hr).addOption(rr).addOption(Ho).addOption(Bo).addOption(vp).addOption(yS).addOption(ES).addOption(TS).addOption(bS).addOption(AM).addOption(bM).addOption(vM).addOption(RM).addOption(Rp).addOption(Ap).addOption(SS).addOption(new ur("--start <start>","Arbitrary setup command that will run before Momentic steps begin.")).addOption(new ur("--wait-on <waitOn>","URL to wait to become accessible before Momentic tests begin.")).addOption(new ur("--wait-on-timeout <waitOnTimeout>","Max time in seconds to wait for the --wait-on URL to become accessible.").default(60).argParser(Fo)).addOption(new ur("--retries <retries>","Number of retries to attempt when running tests locally. Defaults to each test's own retry configuration.").argParser(Fo)).addOption(new ur("-p, --parallel <parallel>","The number of tests to run in parallel. Defaults to 1.").argParser(Fo)).addOption(new ur("--labels <labels...>","Only run tests with the specified label(s).")).addOption(new ur("--update-golden-files","Update locally stored golden files for steps that this is enabled for.").default(!1)).addOption(gM).addOption(fM).addOption(hS).addOption(SM).addOption(EM).addOption(yM).addOption(gS).addOption(fS).addArgument(vS).action(async(r,e)=>{if(e.shardIndex>e.shardCount)throw new Error("Shard index cannot be greater than shard count");let t=bp(e.customHeaders),n=await Tt({configFilePath:e.config,nameFilter:e.filter}),o=e.parallel??n.config.parallel??1;lP().length<o*2&&T.warn(`You requested to run tests in parallel ${o} at a time on a machine with ${lP().length} cores. This may cause performance issues and test failures as Chrome requires at least 2 cores per browser instance.`),T.debug({projectName:n.config.name},"Identified project config");let{errors:i}=await Ep({project:n,fix:!1});i>0&&(T.error(`Found ${i} errors`),T.warn("To fix these errors automatically, run the duplicate-ids check with the --fix flag and then commit the resulting changes"),process.exit(1));let a=new et({baseUrl:e.server,apiKey:e.apiKey,logger:ne});T.debug("Checking API key and dependencies");let{orgId:s,userId:c}=await xh({client:a,skipPrompts:e.yes});T.debug("API key check and browser installation complete");let l=new Us,u=e.outputDir??n.config.outputDir,d=e.reporterDir??n.config.reporterDir,p=KW(),m=ne.child({cliVersion:Er,orgId:s,userId:c,runGroupId:p}),h=await To(ne,a,n);m.info({gitMetadata:h,config:n.config},"Got local metadata");let g;e.inputCsv&&(g=await OS(e.inputCsv));let f=e.pixelRatio??MS();PS(f);try{let y=await iP({...e,parallel:o,retriesOverride:e.retries,devicePixelRatio:f,tests:r,project:n,client:a,debugDataStorage:l,outputDir:u,uploadResults:e.uploadResults,reporterDir:d,customHeaders:t,envName:e.env,orgId:s,testInputMatrix:g,logger:m,regenerateGoldenFiles:e.updateGoldenFiles,gitMetadata:h,regenerateCache:e.regenerateCache,alwaysSaveCache:e.saveCache,noCache:e.disableCache,recordVideo:e.recordVideo??n.config.recordVideo,runGroupId:p});await $n(),y.failed>0?process.exit(1):process.exit(0)}catch(y){T.error("Failed to run tests locally. Please check the error message below or run with the --verbose flag."),T.error(y),await $n(),process.exit(1)}});var eq=Ut.command("apply").description("Apply an operation to local resources");eq.command("patch").addOption(Br).addOption(Hr).addOption(rr).addOption(Ho).addOption(Bo).addOption(new ur("--from <from>","Name or ID of the patch to apply").makeOptionMandatory()).addOption(new ur("--to <to>","Name or ID of the test to apply the patch to").makeOptionMandatory()).action(async r=>{let{apiKey:e,server:t,config:n,yes:o}=r,i=await Tt({configFilePath:n}),a=ne,s=new et({baseUrl:t,apiKey:e,logger:a}),c=await Q(i),l=c.tests[r.to]??Object.values(c.tests).find(d=>Oe(d.name)===r.to.trim());l||(T.error(`No test matching '${r.to}' could be found in the current project.`),process.exit(1));let u=await s.fetchTestFragment(r.from);await oM({client:s,test:l,fragment:u,yes:o,entities:c,logger:ne}),process.exit(0)});var pP=Ut.command("results").description("Merge and upload test results.");pP.command("merge").description("Merge test results files.").addOption(hS).addArgument(_M).action(async(r,e)=>{let{outputDir:t}=e;t||(T.error("Output directory is required."),process.exit(1)),Np.existsSync(r)||(T.warn("Results path does not exist, skipping merge."),process.exit(0)),Np.existsSync(t)&&T.warn(`Output directory ${t} already exists, removing before merging...`),xR(ne,t,r)});pP.command("upload").description("Upload test results to Momentic cloud.").addOption(Br).addOption(Hr).addArgument(IM).action(async(r,e)=>{let{apiKey:t,server:n}=e,o=ne,i=new et({baseUrl:n,apiKey:t,logger:o});await ku({consoleLogger:T,resultsPath:r,client:i}),process.exit(0)});var BS=Ut.command("quarantine").description("Manage test quarantines");BS.command("add").description("Add a test to the quarantine. This will prevent it from running.").addOption(Br).addOption(Hr).addOption(rr).addOption(Ho).addOption(RS).addArgument(AS).action(async(r,e)=>{let{apiKey:t,server:n,config:o,reason:i}=e,a=ne,s=await Tt({configFilePath:o}),c=new et({baseUrl:n,apiKey:t,logger:a}),l=await To(ne,c,s);await OM({test:r,reason:i,apiClient:c,project:s,logger:a,identity:l})});BS.command("list").description("List quarantined tests.").addOption(Br).addOption(Hr).addOption(rr).addOption(Ho).action(async r=>{let{apiKey:e,server:t,config:n}=r,o=ne,i=await Tt({configFilePath:n}),a=new et({baseUrl:t,apiKey:e,logger:o});await DM({apiClient:a,project:i})});BS.command("remove").description("Remove a test from the quarantine. This will allow it to run again.").addOption(Br).addOption(Hr).addOption(rr).addOption(Ho).addOption(RS).addArgument(AS).action(async(r,e)=>{let{apiKey:t,server:n,config:o,reason:i}=e,a=ne,s=await Tt({configFilePath:o}),c=new et({baseUrl:n,apiKey:t,logger:a}),l=await To(ne,c,s);await kM({test:r,reason:i,apiClient:c,project:s,identity:l})});Ut.command("upgrade").description("Upgrade your configuration to the latest recommended settings").addOption(rr).addOption(Ho).action(async r=>{let e=await Tt({configFilePath:r.config,nameFilter:r.filter});T.info("Updating Momentic version in package.json..."),await aP(),T.info("Updating project configuration..."),sP(e),T.success("Your project configuration was successfully updated to the latest recommended settings."),T.info("You can optionally run tests with the `--regenerate-cache` flag to entirely rebuild caches with the newer configuration. Warning: using this option will cause all steps to run without any cached data, resulting in significantly longer execution times.")});async function tq(){US("Main program started"),await KM(ne),US("CLI version check complete");try{await Ut.parseAsync(process.argv),await $n()}catch(r){let e={};try{e.playwrightVersion=qW("npx playwright --version").toString()}catch(t){ne.error({err:t},"Error fetching debug information")}ne.error({err:r,debugInfo:e},"Uncaught error in CLI"),rs(r,e),T.error(r),await $n(),process.exit(1)}}YW.setMaxListeners(25);process.on("warning",r=>{ne.warn({err:r},`Node warning received on CLI: ${r.message}`)});US("CLI parsing setup complete");tq();
|
|
4542
4542
|
//# sourceMappingURL=cli.js.map
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "momentic",
|
|
3
|
-
"version": "2.21.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "momentic",
|
|
9
|
-
"version": "2.21.
|
|
9
|
+
"version": "2.21.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@actions/exec": "^1.1.1",
|
|
12
12
|
"@actions/io": "^1.1.3",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@octokit/rest": "^22.0.0",
|
|
24
24
|
"@sentry/node": "^9.28.1",
|
|
25
25
|
"adm-zip": "^0.5.16",
|
|
26
|
-
"ai": "
|
|
26
|
+
"ai": "5.0.71",
|
|
27
27
|
"axios": "^1.12.0",
|
|
28
28
|
"blocked-at": "1.2.0",
|
|
29
29
|
"body-parser": "^1.20.2",
|
|
@@ -122,14 +122,31 @@
|
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
124
|
"node_modules/@ai-sdk/gateway": {
|
|
125
|
-
"version": "
|
|
126
|
-
"resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-
|
|
127
|
-
"integrity": "sha512-
|
|
125
|
+
"version": "1.0.40",
|
|
126
|
+
"resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-1.0.40.tgz",
|
|
127
|
+
"integrity": "sha512-zlixM9jac0w0jjYl5gwNq+w9nydvraAmLaZQbbh+QpHU+OPkTIZmyBcKeTq5eGQKQxhi+oquHxzCSKyJx3egGw==",
|
|
128
128
|
"license": "Apache-2.0",
|
|
129
129
|
"dependencies": {
|
|
130
130
|
"@ai-sdk/provider": "2.0.0",
|
|
131
|
-
"@ai-sdk/provider-utils": "3.0.
|
|
132
|
-
"@vercel/oidc": "3.0.
|
|
131
|
+
"@ai-sdk/provider-utils": "3.0.12",
|
|
132
|
+
"@vercel/oidc": "3.0.2"
|
|
133
|
+
},
|
|
134
|
+
"engines": {
|
|
135
|
+
"node": ">=18"
|
|
136
|
+
},
|
|
137
|
+
"peerDependencies": {
|
|
138
|
+
"zod": "^3.25.76 || ^4.1.8"
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"node_modules/@ai-sdk/gateway/node_modules/@ai-sdk/provider-utils": {
|
|
142
|
+
"version": "3.0.12",
|
|
143
|
+
"resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz",
|
|
144
|
+
"integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==",
|
|
145
|
+
"license": "Apache-2.0",
|
|
146
|
+
"dependencies": {
|
|
147
|
+
"@ai-sdk/provider": "2.0.0",
|
|
148
|
+
"@standard-schema/spec": "^1.0.0",
|
|
149
|
+
"eventsource-parser": "^3.0.5"
|
|
133
150
|
},
|
|
134
151
|
"engines": {
|
|
135
152
|
"node": ">=18"
|
|
@@ -2481,9 +2498,9 @@
|
|
|
2481
2498
|
}
|
|
2482
2499
|
},
|
|
2483
2500
|
"node_modules/@vercel/oidc": {
|
|
2484
|
-
"version": "3.0.
|
|
2485
|
-
"resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.
|
|
2486
|
-
"integrity": "sha512-
|
|
2501
|
+
"version": "3.0.2",
|
|
2502
|
+
"resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.2.tgz",
|
|
2503
|
+
"integrity": "sha512-JekxQ0RApo4gS4un/iMGsIL1/k4KUBe3HmnGcDvzHuFBdQdudEJgTqcsJC7y6Ul4Yw5CeykgvQbX2XeEJd0+DA==",
|
|
2487
2504
|
"license": "Apache-2.0",
|
|
2488
2505
|
"engines": {
|
|
2489
2506
|
"node": ">= 20"
|
|
@@ -2589,14 +2606,14 @@
|
|
|
2589
2606
|
"license": "MIT"
|
|
2590
2607
|
},
|
|
2591
2608
|
"node_modules/ai": {
|
|
2592
|
-
"version": "5.0.
|
|
2593
|
-
"resolved": "https://registry.npmjs.org/ai/-/ai-5.0.
|
|
2594
|
-
"integrity": "sha512-
|
|
2609
|
+
"version": "5.0.71",
|
|
2610
|
+
"resolved": "https://registry.npmjs.org/ai/-/ai-5.0.71.tgz",
|
|
2611
|
+
"integrity": "sha512-2c9/cXpF7O1K9xOgcoPCMC7Jj5GxVsPHTBhKcV6bqCVKm21P8AiN+rz9zIGopNMDhlEbQxqi8qSgrwCfsW+KMw==",
|
|
2595
2612
|
"license": "Apache-2.0",
|
|
2596
2613
|
"dependencies": {
|
|
2597
|
-
"@ai-sdk/gateway": "
|
|
2614
|
+
"@ai-sdk/gateway": "1.0.40",
|
|
2598
2615
|
"@ai-sdk/provider": "2.0.0",
|
|
2599
|
-
"@ai-sdk/provider-utils": "3.0.
|
|
2616
|
+
"@ai-sdk/provider-utils": "3.0.12",
|
|
2600
2617
|
"@opentelemetry/api": "1.9.0"
|
|
2601
2618
|
},
|
|
2602
2619
|
"engines": {
|
|
@@ -2606,6 +2623,23 @@
|
|
|
2606
2623
|
"zod": "^3.25.76 || ^4.1.8"
|
|
2607
2624
|
}
|
|
2608
2625
|
},
|
|
2626
|
+
"node_modules/ai/node_modules/@ai-sdk/provider-utils": {
|
|
2627
|
+
"version": "3.0.12",
|
|
2628
|
+
"resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz",
|
|
2629
|
+
"integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==",
|
|
2630
|
+
"license": "Apache-2.0",
|
|
2631
|
+
"dependencies": {
|
|
2632
|
+
"@ai-sdk/provider": "2.0.0",
|
|
2633
|
+
"@standard-schema/spec": "^1.0.0",
|
|
2634
|
+
"eventsource-parser": "^3.0.5"
|
|
2635
|
+
},
|
|
2636
|
+
"engines": {
|
|
2637
|
+
"node": ">=18"
|
|
2638
|
+
},
|
|
2639
|
+
"peerDependencies": {
|
|
2640
|
+
"zod": "^3.25.76 || ^4.1.8"
|
|
2641
|
+
}
|
|
2642
|
+
},
|
|
2609
2643
|
"node_modules/ajv": {
|
|
2610
2644
|
"version": "8.17.1",
|
|
2611
2645
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "momentic",
|
|
3
|
-
"version": "2.21.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"bin": {
|
|
5
5
|
"momentic": "./bin/cli.js"
|
|
6
6
|
},
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@octokit/rest": "^22.0.0",
|
|
24
24
|
"@sentry/node": "^9.28.1",
|
|
25
25
|
"adm-zip": "^0.5.16",
|
|
26
|
-
"ai": "
|
|
26
|
+
"ai": "5.0.71",
|
|
27
27
|
"axios": "^1.12.0",
|
|
28
28
|
"blocked-at": "1.2.0",
|
|
29
29
|
"body-parser": "^1.20.2",
|