momentic-mobile 1.0.1 → 1.0.2
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 +9 -9
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/remote-control-static/assets/{index-DZi84ZW9.css → index-Bi1i3UiB.css} +1 -1
- package/remote-control-static/index.html +2 -2
- package/{static/assets/index-DvK8-1_Y.css → run-viewer-static/assets/index-78BcG7nv.css} +1 -1
- package/run-viewer-static/assets/{index-CwOEKN2p.js → index-ev38hrTS.js} +3 -3
- package/run-viewer-static/index.html +2 -2
- package/{run-viewer-static/assets/index-DvK8-1_Y.css → static/assets/index-78BcG7nv.css} +1 -1
- package/static/assets/{index-Ds_rynX4.js → index-CEbIHt8H.js} +7 -7
- package/static/assets/{vendor-C2K0i6C4.js → vendor-EHBWRwXA.js} +3 -3
- package/static/assets/{vendor-codemirror-Cs7lBdjy.js → vendor-codemirror-DhoPEB09.js} +3 -3
- package/static/assets/{vendor-limrun-BNhWxdH9.js → vendor-limrun-CqAmtz5-.js} +3 -3
- package/static/index.html +5 -5
- /package/remote-control-static/assets/{index-kirjJQi9.js → index-PPlnkmgq.js} +0 -0
package/bin/cli.js
CHANGED
|
@@ -186,7 +186,7 @@ To resolve the conflict:`,BI(c,e))),i=l):PE.diag.warn("A view or instrument with
|
|
|
186
186
|
`);if(r<1||r>n.length)return;let o=Math.max(1,r-qG),i=Math.min(n.length,r+qG),a=String(i).length,s=[];for(let l=o;l<=i;l++){let c=l===r?Ibe:Pbe;s.push(`${c}${String(l).padStart(a)} | ${n[l-1]??""}`);}return s.join(`
|
|
187
187
|
`)}var XG="\r",JG="\x1B[1A",ZG="\x1B[J",Lbe="\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F",Nbe="|/-\\",kbe="#0891b2",Fbe={pass:{glyph:"\u2713",ascii:"v",paint:da.green},fail:{glyph:"\u2718",ascii:"x",paint:da.red},skip:{glyph:"\u2212",ascii:"-",paint:da.dim},cancel:{glyph:"\u2298",ascii:"o",paint:da.yellow},retry:{glyph:"\u21BB",ascii:"~",paint:da.yellow}};function Og(t){let e=t.colorLevel>0&&t.isTTY,r=(n,o)=>e?o(n):n;return {unicode:t.unicode,color:e,bold:n=>r(n,da.bold),dim:n=>r(n,da.gray),code:n=>r(n,da.hex(kbe)),spinner:n=>{let o=t.unicode?Lbe:Nbe,i=(n%o.length+o.length)%o.length;return r(o.charAt(i),da.cyan)},statusGlyph:n=>{let o=Fbe[n],i=t.unicode?o.glyph:o.ascii;return e?o.paint(i):i},separator:t.unicode?" \xB7 ":" | "}}function QG(t,e=""){let r=process.stdout?.columns||process.stderr?.columns||80,n=Math.max(r-e.length,20),o=[];for(let i of t.split(`
|
|
188
188
|
`)){let a="";for(let s of i.split(" ")){if(!a.length){a=s;continue}let l=`${a} ${s}`;if(l.length<=n){a=l;continue}o.push(e+a),a=s;}o.push(e+a);}return o.join(`
|
|
189
|
-
`)}var Bbe={PASS:{glyph:"pass",isTerminal:true},FAIL:{glyph:"fail",isTerminal:true},SKIP:{glyph:"skip",isTerminal:true},CANCEL:{glyph:"cancel",isTerminal:true},RETRY:{glyph:"retry",isTerminal:false}},Ube={PASSED:"PASS",FAILED:"FAIL",CANCELLED:"CANCEL",RETRYING:"RETRY",RUNNING:"RUNNING",SKIP:"SKIP",RUN:"RUNNING",RETRY:"RETRY"};function eq(t,e,r=0){let n=Ube[t];if(!n)return;let o=Og(e);if(n==="RUNNING")return {badge:o.spinner(r),isTerminal:false};let{glyph:i,isTerminal:a}=Bbe[n];return {badge:o.statusGlyph(i),isTerminal:a}}function nc(t,e){return !e.isTTY||e.colorLevel===0?t:`\x1B]8;;${t}\x07${t}\x1B]8;;\x07`}function tq(){let t=EH(),e=[];t.lowMemorySamples>0&&e.push(`memory low ${t.lowMemorySamples}x`),t.highCpuSamples>0&&e.push(`CPU saturated ${t.highCpuSamples}x`),t.highHeapSamples>0&&e.push(`heap near limit ${t.highHeapSamples}x`),e.length!==0&&(P.log(""),P.warn(`Machine was under pressure during this run (${e.join(", ")}). Slowdowns and timeouts may be related.`));}var Lt=qm({app:"cli",hostname:hostname(),disableConsoleLogs:true}).child({cliVersion:"1.0.
|
|
189
|
+
`)}var Bbe={PASS:{glyph:"pass",isTerminal:true},FAIL:{glyph:"fail",isTerminal:true},SKIP:{glyph:"skip",isTerminal:true},CANCEL:{glyph:"cancel",isTerminal:true},RETRY:{glyph:"retry",isTerminal:false}},Ube={PASSED:"PASS",FAILED:"FAIL",CANCELLED:"CANCEL",RETRYING:"RETRY",RUNNING:"RUNNING",SKIP:"SKIP",RUN:"RUNNING",RETRY:"RETRY"};function eq(t,e,r=0){let n=Ube[t];if(!n)return;let o=Og(e);if(n==="RUNNING")return {badge:o.spinner(r),isTerminal:false};let{glyph:i,isTerminal:a}=Bbe[n];return {badge:o.statusGlyph(i),isTerminal:a}}function nc(t,e){return !e.isTTY||e.colorLevel===0?t:`\x1B]8;;${t}\x07${t}\x1B]8;;\x07`}function tq(){let t=EH(),e=[];t.lowMemorySamples>0&&e.push(`memory low ${t.lowMemorySamples}x`),t.highCpuSamples>0&&e.push(`CPU saturated ${t.highCpuSamples}x`),t.highHeapSamples>0&&e.push(`heap near limit ${t.highHeapSamples}x`),e.length!==0&&(P.log(""),P.warn(`Machine was under pressure during this run (${e.join(", ")}). Slowdowns and timeouts may be related.`));}var Lt=qm({app:"cli",hostname:hostname(),disableConsoleLogs:true}).child({cliVersion:"1.0.2"});function n_(t){if(!t)return;t=t.toLowerCase();let e=tT.safeParse(t);if(e.success)return P.setMinLevel(e.data),e.data}var Uu=" ";function rq(t){let e={passed:[],failed:[],cancelled:[],quarantinedPassed:[],quarantinedFailed:[]};for(let r of t)switch(r.status){case "PASSED":(r.quarantined?e.quarantinedPassed:e.passed).push(r);break;case "FAILED":(r.quarantined?e.quarantinedFailed:e.failed).push(r);break;case "CANCELLED":e.cancelled.push(r);break}return e}function nq(t){let e=rq(t),r=e.failed.filter(o=>o.failureDetails?.classification?.action==="heal"),n=e.failed.filter(o=>o.failureDetails?.classification?.action==="warn");return {passed:e.passed.length,failed:e.failed.length,cancelled:e.cancelled.length,quarantinedPassed:e.quarantinedPassed.length,quarantinedFailed:e.quarantinedFailed.length,healElectedFailures:r.length,warnElectedFailures:n.length}}function oq(t,{onlyQuarantined:e=false,overrideExitCode:r=false}={}){let n=r?t.healElectedFailures+t.warnElectedFailures:0,o=t.failed-n,i=e?t.quarantinedFailed:0;return o+i>0||t.cancelled>0}function iq({results:t,startTime:e,getPath:r,getUrl:n,printFailureBody:o,getCancellationReason:i,recoveredCount:a,skippedCount:s,videoRecordingActive:l}){let{passed:c,failed:u,cancelled:d,quarantinedPassed:m,quarantinedFailed:p}=rq(t),f=eo(),h=f.unicode?"\u2500":"-",g=process.stdout?.columns||80,y=(S,E,v,w)=>{let _=` ${E+1}) ${r(S)} `,L=Math.max(3,g-_.length-2);P.log(""),P.log(v(`${_}${h.repeat(L)}`)),P.log(""),w();let I=n(S);I&&(P.log(""),P.log(`${Uu}${nc(I,f)}`));};WG(()=>{u.forEach((I,R)=>{y(I,R,da.red.bold,()=>o?.(I));}),d.forEach((I,R)=>{y(I,u.length+R,da.yellow.bold,()=>{let k=i?.(I)??"Cancelled";P.log(`${Uu}${da.yellow.bold(k)}`);});});let S=(I,R,k)=>{I.length!==0&&(P.log(""),P.log(` ${k(`${I.length} ${R}`)}`),I.forEach(D=>{P.dimmed(`${Uu}${r(D)}`);}));};S(u,"failed",da.red.bold),S(p,"failed",I=>da.red.bold(`${I} (quarantined)`)),S(d,"cancelled",da.yellow.bold),s&&(P.log(""),P.log(` ${da.yellow.bold(`${s} skipped`)}`));let E=c.length+m.length,v=Math.max(1,Math.round((Date.now()-e)/1e3)),w=[];m.length>0&&w.push(`${m.length} quarantined`),a&&a>0&&w.push(`${a} recovered`);let _=w.length>0?` (${w.join(", ")})`:"",L=$be(t,f,l);P.log(""),P.log(` ${da.green.bold(`${E} passed${_} (${v}s)`)}${L}`),tq();});}function $be(t,e,r=false){let n=t.length;if(n===0)return "";let o=t.filter(s=>s.usedRemoteBrowser).length;return o===0?"":`${e.unicode?" \xB7 ":" | "}${o}/${n} ran on remote browser${r?" (video saved async)":""}`}function aq(t){if(!t.failureDetails||!t.failureReason)return;let e=_l({failureReason:t.failureReason,classification:t.failureDetails.classification,manualClassification:t.failureDetails.manualClassification}),r=e.title??t.failureReason,n=t.failureDetails.classification?.rootCause??e.description??e.title??t.failureReason;P.log(`${Uu}${da.red.bold(r)}`),n&&n!==r&&(P.log(""),P.log(QG(n,Uu)));let o=KG({failureDetails:t.failureDetails,filePath:t.filePath,results:t.results,beforeResults:t.beforeResults,afterResults:t.afterResults});o&&(P.log(""),P.log(o));let i=t.failureDetails.classification?.citations;if(i&&i.length>0){P.log(""),P.log(`${Uu}${da.bold("Sources:")}`);for(let a of i)P.log(`${Uu} [${a.refId}] ${a.title}`);}}var sq=" ".repeat(6);var Vbe=(t,e,r,n)=>{if(r==="length"||r==="prototype"||r==="arguments"||r==="caller")return;let o=Object.getOwnPropertyDescriptor(t,r),i=Object.getOwnPropertyDescriptor(e,r);!jbe(o,i)&&n||Object.defineProperty(t,r,i);},jbe=function(t,e){return t===void 0||t.configurable||t.writable===e.writable&&t.enumerable===e.enumerable&&t.configurable===e.configurable&&(t.writable||t.value===e.value)},Hbe=(t,e)=>{let r=Object.getPrototypeOf(e);r!==Object.getPrototypeOf(t)&&Object.setPrototypeOf(t,r);},Wbe=(t,e)=>`/* Wrapped ${t}*/
|
|
190
190
|
${e}`,Gbe=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),qbe=Object.getOwnPropertyDescriptor(Function.prototype.toString,"name"),Kbe=(t,e,r)=>{let n=r===""?"":`with ${r.trim()}() `,o=Wbe.bind(null,n,e.toString());Object.defineProperty(o,"name",qbe);let{writable:i,enumerable:a,configurable:s}=Gbe;Object.defineProperty(t,"toString",{value:o,writable:i,enumerable:a,configurable:s});};function o_(t,e,{ignoreNonConfigurable:r=false}={}){let{name:n}=t;for(let o of Reflect.ownKeys(e))Vbe(t,e,o,r);return Hbe(t,e),Kbe(t,e,n),t}var YE=new WeakMap,lq=(t,e={})=>{if(typeof t!="function")throw new TypeError("Expected a function");let r,n=0,o=t.displayName||t.name||"<anonymous>",i=function(...a){if(YE.set(i,++n),n===1)r=t.apply(this,a),t=void 0;else if(e.throw===true)throw new Error(`Function \`${o}\` can only be called once`);return r};return o_(i,t),YE.set(i,n),i};lq.callCount=t=>{if(!YE.has(t))throw new Error(`The given function \`${t.name}\` is not wrapped by the \`onetime\` package`);return YE.get(t)};var cq=lq;var zu=[];zu.push("SIGHUP","SIGINT","SIGTERM");process.platform!=="win32"&&zu.push("SIGALRM","SIGABRT","SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");process.platform==="linux"&&zu.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT");var XE=t=>!!t&&typeof t=="object"&&typeof t.removeListener=="function"&&typeof t.emit=="function"&&typeof t.reallyExit=="function"&&typeof t.listeners=="function"&&typeof t.kill=="function"&&typeof t.pid=="number"&&typeof t.on=="function",i_=Symbol.for("signal-exit emitter"),a_=globalThis,Ybe=Object.defineProperty.bind(Object),s_=class{emitted={afterExit:false,exit:false};listeners={afterExit:[],exit:[]};count=0;id=Math.random();constructor(){if(a_[i_])return a_[i_];Ybe(a_,i_,{value:this,writable:false,enumerable:false,configurable:false});}on(e,r){this.listeners[e].push(r);}removeListener(e,r){let n=this.listeners[e],o=n.indexOf(r);o!==-1&&(o===0&&n.length===1?n.length=0:n.splice(o,1));}emit(e,r,n){if(this.emitted[e])return false;this.emitted[e]=true;let o=false;for(let i of this.listeners[e])o=i(r,n)===true||o;return e==="exit"&&(o=this.emit("afterExit",r,n)||o),o}},JE=class{},Xbe=t=>({onExit(e,r){return t.onExit(e,r)},load(){return t.load()},unload(){return t.unload()}}),l_=class extends JE{onExit(){return ()=>{}}load(){}unload(){}},c_=class extends JE{#a=u_.platform==="win32"?"SIGINT":"SIGHUP";#r=new s_;#e;#o;#m;#t={};#i=false;constructor(e){super(),this.#e=e,this.#t={};for(let r of zu)this.#t[r]=()=>{let n=this.#e.listeners(r),{count:o}=this.#r,i=e;if(typeof i.__signal_exit_emitter__=="object"&&typeof i.__signal_exit_emitter__.count=="number"&&(o+=i.__signal_exit_emitter__.count),n.length===o){this.unload();let a=this.#r.emit("exit",null,r),s=r==="SIGHUP"?this.#a:r;a||e.kill(e.pid,s);}};this.#m=e.reallyExit,this.#o=e.emit;}onExit(e,r){if(!XE(this.#e))return ()=>{};this.#i===false&&this.load();let n=r?.alwaysLast?"afterExit":"exit";return this.#r.on(n,e),()=>{this.#r.removeListener(n,e),this.#r.listeners.exit.length===0&&this.#r.listeners.afterExit.length===0&&this.unload();}}load(){if(!this.#i){this.#i=true,this.#r.count+=1;for(let e of zu)try{let r=this.#t[e];r&&this.#e.on(e,r);}catch{}this.#e.emit=(e,...r)=>this.#p(e,...r),this.#e.reallyExit=e=>this.#n(e);}}unload(){this.#i&&(this.#i=false,zu.forEach(e=>{let r=this.#t[e];if(!r)throw new Error("Listener not defined for signal: "+e);try{this.#e.removeListener(e,r);}catch{}}),this.#e.emit=this.#o,this.#e.reallyExit=this.#m,this.#r.count-=1);}#n(e){return XE(this.#e)?(this.#e.exitCode=e||0,this.#r.emit("exit",this.#e.exitCode,null),this.#m.call(this.#e,this.#e.exitCode)):0}#p(e,...r){let n=this.#o;if(e==="exit"&&XE(this.#e)){typeof r[0]=="number"&&(this.#e.exitCode=r[0]);let o=n.call(this.#e,e,...r);return this.#r.emit("exit",this.#e.exitCode,null),o}else return n.call(this.#e,e,...r)}},u_=globalThis.process,{onExit:uq}=Xbe(XE(u_)?new c_(u_):new l_);var dq=ya.stderr.isTTY?ya.stderr:ya.stdout.isTTY?ya.stdout:void 0,Jbe=dq?cq(()=>{uq(()=>{dq.write("\x1B[?25h");},{alwaysLast:true});}):()=>{},mq=Jbe;var QE=false,np={};np.show=(t=ya.stderr)=>{t.isTTY&&(QE=false,t.write("\x1B[?25h"));};np.hide=(t=ya.stderr)=>{t.isTTY&&(mq(),QE=true,t.write("\x1B[?25l"));};np.toggle=(t,e)=>{t!==void 0&&(QE=t),QE?np.show(e):np.hide(e);};var d_=np;var Ng=Xf(m_());function p_(){return ya.platform!=="win32"?ya.env.TERM!=="linux":!!ya.env.CI||!!ya.env.WT_SESSION||!!ya.env.TERMINUS_SUBLIME||ya.env.ConEmuTask==="{cmd::Cmder}"||ya.env.TERM_PROGRAM==="Terminus-Sublime"||ya.env.TERM_PROGRAM==="vscode"||ya.env.TERM==="xterm-256color"||ya.env.TERM==="alacritty"||ya.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var Qbe={info:da.blue("\u2139"),success:da.green("\u2714"),warning:da.yellow("\u26A0"),error:da.red("\u2716")},eye={info:da.blue("i"),success:da.green("\u221A"),warning:da.yellow("\u203C"),error:da.red("\xD7")},tye=p_()?Qbe:eye,Dg=tye;function f_({onlyFirst:t=false}={}){let o="(?:\\u001B\\][\\s\\S]*?(?:\\u0007|\\u001B\\u005C|\\u009C))|[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";return new RegExp(o,t?void 0:"g")}var rye=f_();function Lg(t){if(typeof t!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof t}\``);return !t.includes("\x1B")&&!t.includes("\x9B")?t:t.replace(rye,"")}var bq=[161,161,164,164,167,168,170,170,173,174,176,180,182,186,188,191,198,198,208,208,215,216,222,225,230,230,232,234,236,237,240,240,242,243,247,250,252,252,254,254,257,257,273,273,275,275,283,283,294,295,299,299,305,307,312,312,319,322,324,324,328,331,333,333,338,339,358,359,363,363,462,462,464,464,466,466,468,468,470,470,472,472,474,474,476,476,593,593,609,609,708,708,711,711,713,715,717,717,720,720,728,731,733,733,735,735,768,879,913,929,931,937,945,961,963,969,1025,1025,1040,1103,1105,1105,8208,8208,8211,8214,8216,8217,8220,8221,8224,8226,8228,8231,8240,8240,8242,8243,8245,8245,8251,8251,8254,8254,8308,8308,8319,8319,8321,8324,8364,8364,8451,8451,8453,8453,8457,8457,8467,8467,8470,8470,8481,8482,8486,8486,8491,8491,8531,8532,8539,8542,8544,8555,8560,8569,8585,8585,8592,8601,8632,8633,8658,8658,8660,8660,8679,8679,8704,8704,8706,8707,8711,8712,8715,8715,8719,8719,8721,8721,8725,8725,8730,8730,8733,8736,8739,8739,8741,8741,8743,8748,8750,8750,8756,8759,8764,8765,8776,8776,8780,8780,8786,8786,8800,8801,8804,8807,8810,8811,8814,8815,8834,8835,8838,8839,8853,8853,8857,8857,8869,8869,8895,8895,8978,8978,9312,9449,9451,9547,9552,9587,9600,9615,9618,9621,9632,9633,9635,9641,9650,9651,9654,9655,9660,9661,9664,9665,9670,9672,9675,9675,9678,9681,9698,9701,9711,9711,9733,9734,9737,9737,9742,9743,9756,9756,9758,9758,9792,9792,9794,9794,9824,9825,9827,9829,9831,9834,9836,9837,9839,9839,9886,9887,9919,9919,9926,9933,9935,9939,9941,9953,9955,9955,9960,9961,9963,9969,9972,9972,9974,9977,9979,9980,9982,9983,10045,10045,10102,10111,11094,11097,12872,12879,57344,63743,65024,65039,65533,65533,127232,127242,127248,127277,127280,127337,127344,127373,127375,127376,127387,127404,917760,917999,983040,1048573,1048576,1114109],yq=12288,Sq=65510,Tq=[12288,12288,65281,65376,65504,65510];var Eq=4352,vq=262141,h_=[4352,4447,8986,8987,9001,9002,9193,9196,9200,9200,9203,9203,9725,9726,9748,9749,9776,9783,9800,9811,9855,9855,9866,9871,9875,9875,9889,9889,9898,9899,9917,9918,9924,9925,9934,9934,9940,9940,9962,9962,9970,9971,9973,9973,9978,9978,9981,9981,9989,9989,9994,9995,10024,10024,10060,10060,10062,10062,10067,10069,10071,10071,10133,10135,10160,10160,10175,10175,11035,11036,11088,11088,11093,11093,11904,11929,11931,12019,12032,12245,12272,12287,12289,12350,12353,12438,12441,12543,12549,12591,12593,12686,12688,12773,12783,12830,12832,12871,12880,42124,42128,42182,43360,43388,44032,55203,63744,64255,65040,65049,65072,65106,65108,65126,65128,65131,94176,94180,94192,94198,94208,101589,101631,101662,101760,101874,110576,110579,110581,110587,110589,110590,110592,110882,110898,110898,110928,110930,110933,110933,110948,110951,110960,111355,119552,119638,119648,119670,126980,126980,127183,127183,127374,127374,127377,127386,127488,127490,127504,127547,127552,127560,127568,127569,127584,127589,127744,127776,127789,127797,127799,127868,127870,127891,127904,127946,127951,127955,127968,127984,127988,127988,127992,128062,128064,128064,128066,128252,128255,128317,128331,128334,128336,128359,128378,128378,128405,128406,128420,128420,128507,128591,128640,128709,128716,128716,128720,128722,128725,128728,128732,128735,128747,128748,128756,128764,128992,129003,129008,129008,129292,129338,129340,129349,129351,129535,129648,129660,129664,129674,129678,129734,129736,129736,129741,129756,129759,129770,129775,129784,131072,196605,196608,262141];var tv=(t,e)=>{let r=0,n=Math.floor(t.length/2)-1;for(;r<=n;){let o=Math.floor((r+n)/2),i=o*2;if(e<t[i])n=o-1;else if(e>t[i+1])r=o+1;else return true}return false};var Cq=19968,[iye,aye]=sye(h_);function sye(t){let e=t[0],r=t[1];for(let n=0;n<t.length;n+=2){let o=t[n],i=t[n+1];if(Cq>=o&&Cq<=i)return [o,i];i-o>r-e&&(e=o,r=i);}return [e,r]}var wq=t=>t<161||t>1114109?false:tv(bq,t),Aq=t=>t<yq||t>Sq?false:tv(Tq,t);var Rq=t=>t>=iye&&t<=aye?true:t<Eq||t>vq?false:tv(h_,t);function lye(t){if(!Number.isSafeInteger(t))throw new TypeError(`Expected a code point, got \`${typeof t}\`.`)}function xq(t,{ambiguousAsWide:e=false}={}){return lye(t),Aq(t)||Rq(t)||e&&wq(t)?2:1}var Mq=()=>/[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E-\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED8\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])))?))?|\uDD75(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3C-\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE8A\uDE8E-\uDEC2\uDEC6\uDEC8\uDECD-\uDEDC\uDEDF-\uDEEA\uDEEF]|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;var cye=new Intl.Segmenter,uye=/^\p{Default_Ignorable_Code_Point}$/u;function g_(t,e={}){if(typeof t!="string"||t.length===0)return 0;let{ambiguousIsNarrow:r=true,countAnsiEscapeCodes:n=false}=e;if(n||(t=Lg(t)),t.length===0)return 0;let o=0,i={ambiguousAsWide:!r};for(let{segment:a}of cye.segment(t)){let s=a.codePointAt(0);if(!(s<=31||s>=127&&s<=159)&&!(s>=8203&&s<=8207||s===65279)&&!(s>=768&&s<=879||s>=6832&&s<=6911||s>=7616&&s<=7679||s>=8400&&s<=8447||s>=65056&&s<=65071)&&!(s>=55296&&s<=57343)&&!(s>=65024&&s<=65039)&&!uye.test(a)){if(Mq().test(a)){o+=2;continue}o+=xq(s,i);}}return o}function b_({stream:t=process.stdout}={}){return !!(t&&t.isTTY&&process.env.TERM!=="dumb"&&!("CI"in process.env))}function y_(){let{env:t}=ya,{TERM:e,TERM_PROGRAM:r}=t;return ya.platform!=="win32"?e!=="linux":!!t.WT_SESSION||!!t.TERMINUS_SUBLIME||t.ConEmuTask==="{cmd::Cmder}"||r==="Terminus-Sublime"||r==="vscode"||e==="xterm-256color"||e==="alacritty"||e==="rxvt-unicode"||e==="rxvt-unicode-256color"||t.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var dye=3,S_=class{#a=0;start(){this.#a++,this.#a===1&&this.#r();}stop(){if(this.#a<=0)throw new Error("`stop` called more times than `start`");this.#a--,this.#a===0&&this.#e();}#r(){ya.platform==="win32"||!ya.stdin.isTTY||(ya.stdin.setRawMode(true),ya.stdin.on("data",this.#o),ya.stdin.resume());}#e(){ya.stdin.isTTY&&(ya.stdin.off("data",this.#o),ya.stdin.pause(),ya.stdin.setRawMode(false));}#o(e){e[0]===dye&&ya.emit("SIGINT");}},mye=new S_,T_=mye;Xf(m_());var E_=class{#a=0;#r=false;#e=0;#o=-1;#m=0;#t;#i;#n;#p;#h;#c;#u;#d;#g;#s;#l;color;constructor(e){typeof e=="string"&&(e={text:e}),this.#t={color:"cyan",stream:ya.stderr,discardStdin:true,hideCursor:true,...e},this.color=this.#t.color,this.spinner=this.#t.spinner,this.#h=this.#t.interval,this.#n=this.#t.stream,this.#c=typeof this.#t.isEnabled=="boolean"?this.#t.isEnabled:b_({stream:this.#n}),this.#u=typeof this.#t.isSilent=="boolean"?this.#t.isSilent:false,this.text=this.#t.text,this.prefixText=this.#t.prefixText,this.suffixText=this.#t.suffixText,this.indent=this.#t.indent,ya.env.NODE_ENV==="test"&&(this._stream=this.#n,this._isEnabled=this.#c,Object.defineProperty(this,"_linesToClear",{get(){return this.#a},set(r){this.#a=r;}}),Object.defineProperty(this,"_frameIndex",{get(){return this.#o}}),Object.defineProperty(this,"_lineCount",{get(){return this.#e}}));}get indent(){return this.#d}set indent(e=0){if(!(e>=0&&Number.isInteger(e)))throw new Error("The `indent` option must be an integer from 0 and up");this.#d=e,this.#f();}get interval(){return this.#h??this.#i.interval??100}get spinner(){return this.#i}set spinner(e){if(this.#o=-1,this.#h=void 0,typeof e=="object"){if(e.frames===void 0)throw new Error("The given spinner must have a `frames` property");this.#i=e;}else if(!y_())this.#i=Ng.default.line;else if(e===void 0)this.#i=Ng.default.dots;else if(e!=="default"&&Ng.default[e])this.#i=Ng.default[e];else throw new Error(`There is no built-in spinner named '${e}'. See https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json for a full list.`)}get text(){return this.#g}set text(e=""){this.#g=e,this.#f();}get prefixText(){return this.#s}set prefixText(e=""){this.#s=e,this.#f();}get suffixText(){return this.#l}set suffixText(e=""){this.#l=e,this.#f();}get isSpinning(){return this.#p!==void 0}#b(e=this.#s,r=" "){return typeof e=="string"&&e!==""?e+r:typeof e=="function"?e()+r:""}#y(e=this.#l,r=" "){return typeof e=="string"&&e!==""?r+e:typeof e=="function"?r+e():""}#f(){let e=this.#n.columns??80,r=this.#b(this.#s,"-"),n=this.#y(this.#l,"-"),o=" ".repeat(this.#d)+r+"--"+this.#g+"--"+n;this.#e=0;for(let i of Lg(o).split(`
|
|
191
191
|
`))this.#e+=Math.max(1,Math.ceil(g_(i,{countAnsiEscapeCodes:true})/e));}get isEnabled(){return this.#c&&!this.#u}set isEnabled(e){if(typeof e!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#c=e;}get isSilent(){return this.#u}set isSilent(e){if(typeof e!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#u=e;}frame(){let e=Date.now();(this.#o===-1||e-this.#m>=this.interval)&&(this.#o=++this.#o%this.#i.frames.length,this.#m=e);let{frames:r}=this.#i,n=r[this.#o];this.color&&(n=da[this.color](n));let o=typeof this.#s=="string"&&this.#s!==""?this.#s+" ":"",i=typeof this.text=="string"?" "+this.text:"",a=typeof this.#l=="string"&&this.#l!==""?" "+this.#l:"";return o+n+i+a}clear(){if(!this.#c||!this.#n.isTTY)return this;this.#n.cursorTo(0);for(let e=0;e<this.#a;e++)e>0&&this.#n.moveCursor(0,-1),this.#n.clearLine(1);return (this.#d||this.lastIndent!==this.#d)&&this.#n.cursorTo(this.#d),this.lastIndent=this.#d,this.#a=0,this}render(){return this.#u?this:(this.clear(),this.#n.write(this.frame()),this.#a=this.#e,this)}start(e){return e&&(this.text=e),this.#u?this:this.#c?this.isSpinning?this:(this.#t.hideCursor&&d_.hide(this.#n),this.#t.discardStdin&&ya.stdin.isTTY&&(this.#r=true,T_.start()),this.render(),this.#p=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#n.write(`- ${this.text}
|
|
192
192
|
`),this)}stop(){return this.#c?(clearInterval(this.#p),this.#p=void 0,this.#o=0,this.clear(),this.#t.hideCursor&&d_.show(this.#n),this.#t.discardStdin&&ya.stdin.isTTY&&this.#r&&(T_.stop(),this.#r=false),this):this}succeed(e){return this.stopAndPersist({symbol:Dg.success,text:e})}fail(e){return this.stopAndPersist({symbol:Dg.error,text:e})}warn(e){return this.stopAndPersist({symbol:Dg.warning,text:e})}info(e){return this.stopAndPersist({symbol:Dg.info,text:e})}stopAndPersist(e={}){if(this.#u)return this;let r=e.prefixText??this.#s,n=this.#b(r," "),o=e.symbol??" ",i=e.text??this.text,s=typeof i=="string"?(o?" ":"")+i:"",l=e.suffixText??this.#l,c=this.#y(l," "),u=n+o+s+c+`
|
|
@@ -215,7 +215,7 @@ ${r}`:r}var cSe="[FAILED]";async function Mv(t,e,r,{numStepsWithScreenshots:n=5,
|
|
|
215
215
|
`),s;try{s=_g.parse(a);}catch(l){throw l instanceof YAMLParseError?new DS(`Invalid YAML in ${r}: ${l.message}`,{cause:l}):l}return CK.set(r,{mtimeMs:n.mtimeMs,size:n.size,parsed:s}),{parsed:structuredClone(s),stats:n}}var MK=false,KTe=z.object({fileType:z.enum(Ce)});async function vt(t,e=false,r=Xu){return IK({project:t,includeGlobs:t.config.include??gp,disableLogging:e,fileSystem:r})}async function PK(t,e=false){let r=t.config.include??["**/*.module.yaml"];return {mobileModules:(await IK({project:t,includeGlobs:r,disableLogging:e,filePathPredicate:o=>o.endsWith(".module.yaml")})).mobileModules}}async function IK({project:t,includeGlobs:e,disableLogging:r,filePathPredicate:n,fileSystem:o=Xu}){let i={project:t,tests:{},modules:{},mobileTests:{},mobileModules:{},duplicateEntities:{},metadataParseFailures:[]},a=t.config.exclude??[],s=AbortSignal.timeout(5e3),l;try{l=await Yu(e,{cwd:t.rootDir,ignore:a,maxDepth:rb,nodir:!0,signal:s,fs:o});}catch(c){throw P.error({err:c},"Failed to list all Momentic files in the current directory. This usually indicates the 'include' and 'exclude' globs are misconfigured in your momentic.config.yaml, or that your machine is severely resource constrained."),new Error("Listing Momentic files timed out after 5 seconds.",{cause:c})}for(let c of l){if(n&&!n(c))continue;let u=XTe(t.rootDir,c,i,r?fu:P,o);u&&(i.duplicateEntities[u.id]=u.paths);}return MK=true,i}async function _K(t){let e=t.config.exclude??[],r=AbortSignal.timeout(5e3),n;try{n=await Yu(["**"],{cwd:t.rootDir,ignore:e,maxDepth:rb,nodir:!1,onlyDirectories:!0,signal:r});}catch(i){throw r.aborted?(P.error({err:i},"Listing Momentic entity folders timed out after 5s. Check 'include'/'exclude' globs in momentic.config.yaml."),new Error("Listing Momentic entity folders timed out after 5s.",{cause:i})):i}let o=n.map(i=>i.split(fr__default.sep).join("/")).filter(i=>YTe(t,i));return Array.from(new Set(o)).sort()}function YTe(t,e){let r=t.config.exclude??[],n=t.config.include??gp;return ["test.yaml","module.yaml"].some(i=>{let a=e?`${e}/placeholder.${i}`:`placeholder.${i}`;return tb(a,r)?false:tb(a,n)})}function Qv({project:t,relativeFilePath:e}){let r=e.split(fr__default.sep).join("/"),n=t.config.exclude??[];if(tb(r,n))throw new ar(`Cannot create "${r}" because it matches this project's "exclude" patterns (${n.join(", ")}). Choose a folder that is part of the project.`);let o=t.config.include??gp;if(!tb(r,o))throw new ar(`Cannot create "${r}" because it is outside this project's "include" patterns (${o.join(", ")}). Choose a folder that is part of the project.`)}function XTe(t,e,r,n,o){let i=fr__default.join(t,e),a=JTe(i,n,o);if(!a)return;let{entityJs:s,stats:l}=a,c=KTe.safeParse(s);if(c.success===false){n.warn(`Possible Momentic file at ${i} does not have a 'fileType', skipping: ${W(c.error)}`);return}let u=c.data.fileType,d=ZTe(e,i,l);switch(u){case Ce.TEST:try{return wK(s,u,r,d,i,n)}catch(m){n.warn(`Skipping file '${i}' because it is missing Momentic test metadata: ${W(m)}`);return}case Ce.TEST_V2:try{return wK(s,u,r,d,i,n)}catch(m){Zv({err:m,fullPath:i,fsAttributes:d,kind:"test",suffix:"test.yaml",resultsCollector:r,logger:n});return}case Ce.MODULE:try{return AK(s,u,r,d,i,n)}catch(m){n.warn(`Skipping file '${i}' because it is missing Momentic module metadata: ${W(m)}`);return}case Ce.MODULE_V2:try{return AK(s,u,r,d,i,n)}catch(m){Zv({err:m,fullPath:i,fsAttributes:d,kind:"module",suffix:"module.yaml",resultsCollector:r,logger:n});return}case Ce.MOBILE_TEST:try{return xK(s,u,r,d,i,n)}catch(m){n.warn(`Skipping file '${i}' because it is missing Momentic mobile test metadata: ${W(m)}`);return}case Ce.MOBILE_TEST_V2:try{return xK(s,u,r,d,i,n)}catch(m){Zv({err:m,fullPath:i,fsAttributes:d,kind:"test",suffix:"test.yaml",resultsCollector:r,logger:n});return}case Ce.MOBILE_MODULE:try{return RK(s,u,r,d,i,n)}catch(m){n.warn(`Skipping file '${i}' because it is missing Momentic mobile module metadata: ${W(m)}`);return}case Ce.MOBILE_MODULE_V2:try{return RK(s,u,r,d,i,n)}catch(m){Zv({err:m,fullPath:i,fsAttributes:d,kind:"module",suffix:"module.yaml",resultsCollector:r,logger:n});return}default:{return}}}function JTe(t,e,r){try{let{parsed:n,stats:o}=Gi(t,r);if(typeof n!="object"||n===null)throw new Error("The YAML document should parse as a map with key-value pairs");return {entityJs:n,stats:o}}catch(n){e.warn(`Could not parse possible Momentic file at ${t}, skipping: ${W(n)}`);return}}function Zv({err:t,fullPath:e,fsAttributes:r,kind:n,suffix:o,resultsCollector:i,logger:a}){if(t instanceof z.ZodError){i.metadataParseFailures.push({fullPath:e,relativePath:r.relativePath,name:r.fileName.replace(`.${o}`,""),kind:n,issues:t.issues});return}a.warn(`Skipping file '${e}': failed to read Momentic v2 ${n} metadata: ${W(t)}`);}function ZTe(t,e,r){return {relativePath:t,fullFilePath:e,platformSep:fr__default.sep,fullPathSegments:e.split(fr__default.sep),relativePathSegments:t.split(fr__default.sep),fileName:fr__default.basename(e),lastModified:r.mtime,createdAt:r.birthtime}}function wK(t,e,r,n,o,i){let a=n.fileName.replace(".test.yaml",""),s,l;e===Ce.TEST_V2?(s=VP.parse(t),l=a):(s=Nh.parse(t),l=s.name);let c;if(r.tests[s.id]){let u=r.tests[s.id].fullFilePath;c={id:s.id,paths:[u,o]};}return r.tests[s.id]={type:e,name:l,id:s.id,description:s.description??void 0,labels:s.labels,...n},c}function AK(t,e,r,n,o,i){let a,s,l,c=n.fileName.replace(".module.yaml","");if(e===Ce.MODULE_V2){let d=KT.parse(t);a=d.id,s=d.name??c,l=d.description;}else {let d=qa.parse(t);a=d.moduleId,s=d.name,l=d.description;}let u;if(r.modules[a]){let d=r.modules[a].fullFilePath;u={id:a,paths:[d,o]};}return r.modules[a]={type:e,name:s,id:a,description:l??void 0,...n},!MK&&ua(s)!==c&&i.warn(`The module with ID ${a} has a name (${s}) that does not match its file name (${c}). We recommend renaming the module or the file to be consistent to avoid confusion and issues with module resolution.`),u}function RK(t,e,r,n,o,i){let a=n.fileName.replace(".module.yaml",""),s,l,c;if(e===Ce.MOBILE_MODULE_V2){let d=QT.parse(t);s=d.id,l=d.description,c=d.name??a;}else {let d=rs.parse(t);s=d.moduleId,l=d.description,c=a;}let u;if(r.mobileModules[s]){let d=r.mobileModules[s].fullFilePath;u={id:s,paths:[d,o]};}return r.mobileModules[s]={type:e,name:c,id:s,description:l??void 0,...n},u}function xK(t,e,r,n,o,i){let a=e===Ce.MOBILE_TEST_V2?ej.parse(t):Gl.parse(t),s;if(r.mobileTests[a.id]){let c=r.mobileTests[a.id].fullFilePath;s={id:a.id,paths:[c,o]};}let l=n.fileName.replace(".test.yaml","");return r.mobileTests[a.id]={type:e,name:l,id:a.id,description:a.description??void 0,labels:a.labels,...n},s}var OK=100;function sl(t,e){let r=e.hooks?.postSave;if(!r)return;let n;r.includes("$1")?n=r.replaceAll("$1",t):n=`${r} ${t}`,LK(n);}function DK(t,e){let r=e.hooks?.postSave;if(!(!r||t.length===0)){if(r.includes("$1")){for(let n of t)sl(n,e);return}for(let n=0;n<t.length;n+=OK){let o=t.slice(n,n+OK).map(eEe).join(" ");LK(`${r} ${o}`);}}}function LK(t){P.debug({postSaveCommand:t},"Executing post-save hook command");try{execSync(t,{encoding:"utf-8"});}catch(e){P.warn({err:e,postSaveCommand:t},"Post-save hook command failed; continuing.");}}function eEe(t){return `'${t.replaceAll("'","'\\''")}'`}function Zu({sourceFilePath:t,momenticFiles:e}){return rEe({sourceFilePath:t,moduleEntities:e?.mobileModules})}function rEe({sourceFilePath:t,moduleEntities:e}){return {sourceFilePath:t,getModuleReference:r=>{let n=e?.[r]?.fullFilePath;if(!n)return;let o=fr__default.relative(fr__default.dirname(t),n).split(fr__default.sep).join("/");return lO(o)},getRelativeJsonFileReference:r=>{if(!fr__default.isAbsolute(r))return lO(r);let n=fr__default.relative(fr__default.dirname(t),r).split(fr__default.sep).join("/");return lO(n)}}}function Qu({sourceFilePath:t,momenticFiles:e}){return nEe({sourceFilePath:t,moduleEntities:e.mobileModules})}function nEe({sourceFilePath:t,moduleEntities:e}){let r=new Map(Object.values(e).map(n=>[fr__default.resolve(n.fullFilePath),n]));return {sourceFilePath:t,readRelativeFile:n=>$v(n)||fr__default.isAbsolute(n)||iK(n)?readFileSync(fr__default.resolve(fr__default.dirname(t),n),"utf8"):n,resolveRelativeJsonPath:n=>fr__default.isAbsolute(n)?n:fr__default.resolve(fr__default.dirname(t),n),resolveModuleReference:n=>{if(!Vv(n))return;let o=fr__default.resolve(fr__default.dirname(t),n),i=r.get(o);if(!i)throw new Xe(`Could not find module file '${n}' referenced from '${t}'.`);return {moduleId:i.id,moduleName:i.name}}}}function lO(t){return $v(t)||fr__default.isAbsolute(t)?t.split(fr__default.sep).join("/"):`./${t.split(fr__default.sep).join("/")}`}var NK=100;function bp({projectConfig:t,momenticFiles:e,entityType:r}){if(t.fileFormat!=="v2")return v4$1();let n;switch(r){case "test":n=Object.keys(e.tests);break;case "module":n=Object.keys(e.modules);break;case "mobile-test":n=Object.keys(e.mobileTests);break;case "mobile-module":n=Object.keys(e.mobileModules);break}return oEe({existingIds:n})}function oEe({existingIds:t}){let e=new Set(t);for(let r=0;r<NK;r++){let n=Vr.parse(o3(v4$1()));if(!e.has(n))return n}throw new Error(`Failed to generate a unique readable v2 entity ID after ${NK} attempts`)}function eC(t,e){let r=[];for(let n of t.config.environments??[]){if(n.baseUrl)continue;let o=ed(n.name,t,e);o.variables[oM]||r.push(o);}return r}function sEe(t){return t.includes("${")?t.replace(/\$\{([^}]+)\}/g,(e,r)=>{let n=r.match(/^([A-Za-z_][A-Za-z0-9_]*)(?:(:-|-)([\s\S]*))?$/);if(!n)return process.env[r]||"";let o=n[1];if(!o)return "";let i=n[2],a=n[3],s=process.env[o];return i===":-"?s&&s!==""?s:a||"":i==="-"?s!==void 0?s:a||"":s||""}):t}function lEe(t){let{envVariables:e,project:r}=t;if(!e)return {};let n={};for(let[o,i]of Object.entries(e)){if(typeof i=="string"){let s=sEe(i);s&&(n[o]=s);continue}let a;try{a=Sn.readFileSync(fr__default.resolve(r.rootDir,i.fromFile),"utf-8");}catch(s){throw new Error(`Failed to read environment variable '${o}' from file '${i.fromFile}': ${s}`)}if(i.json)try{n[o]=JSON.parse(a);}catch(s){throw new Error(`Failed to parse environment variable '${o}' from file '${i.fromFile}' as JSON: ${s}`)}else n[o]=a;}return Object.keys(n).length>0&&P.debug(n,"Set environment variables with interpolation from project configuration"),n}function cEe(t){let{project:e,envFile:r,logger:n}=t,o={};if(!r)return o;let i=iEe.config({path:fr__default.resolve(e.rootDir,r),processEnv:o,logLevel:"error",quiet:true});if(i.error)throw new Xe(`Failed to load .env file: ${i.error.message}`,{cause:i.error});return n.debug("Set environment variables from .env file"),o}function ed(t,e,r){let n=(e.config.environments??[]).find(l=>l.name===t);if(!n)throw new Xe(`Environment ${t} not found in local project configuration file`);let o={},i=lEe({envVariables:n.envVariables,project:e});Object.assign(o,i);let a=cEe({project:e,envFile:n.envFile,logger:r});return Object.assign(o,a),n.inheritFromShell&&(r.debug(process.env,"Inheriting environment variables from shell"),Object.assign(o,process.env)),{name:t,variables:o}}var mc="momentic.config.yaml",uO="momentic.workspace.yaml",hEe=z.object({projects:z.string().array().describe("list of glob patterns to find project (momentic.config.yaml) files")}),gEe=z.union([z.string(),z.object({fromFile:z.string(),json:z.boolean().optional()})]),bEe=z.object({name:iO,baseUrl:z.string().optional().describe("Optional for mobile tests"),envFile:z.string().optional().describe("path to a file on disk to read environment variables from. can be relative to project root or absolute."),envVariables:z.record(z.string(),gEe).optional(),inheritFromShell:z.boolean().optional().describe("inherit all environment variables from the shell - might be noisy"),browser:Ws.optional().describe("NB: most things should use project-level configuration only")}),yEe=z.object({postSave:z.string().optional()}),SEe=z.union([z.boolean(),z.literal("on-fail")]).describe("Controls video recording for test runs. true records video for all tests, false disables video (default), 'on-fail' records video but removes it for passing tests."),TEe=z.object({name:iO,include:z.string().array().optional().describe("list of glob patterns that match momentic files (optional)"),exclude:z.string().array().optional().describe("opposite of include, takes precedence over include"),fileFormat:j$.optional().describe("file format version to use"),goldenFileDir:z.string().optional(),reporterDir:z.string().optional(),outputDir:z.string().optional(),recordVideo:SEe.optional(),retries:z.number().optional().describe("number of retries per test"),parallel:z.union([z.number(),z.literal("auto")]).optional().describe("degree of parallelism"),environments:z.array(bEe).optional(),gitMainBranch:z.string().optional().readonly(),gitProtectedBranches:z.string().array().optional().readonly(),ai:Ja.optional(),browser:Ws.optional(),emulator:vP.optional(),advanced:gM.optional(),displayRoot:z.string().optional().describe("relative path from project root to use as the Repository root"),hooks:yEe.optional()});function zK(t,e){let r;try{r=readFileSync(t,"utf-8");}catch(o){P.warn(`Could not read possible Momentic ${e} file at ${t}: ${W(o)}`);return}let n;try{if(n=_g.parse(r),typeof n!="object"||n===null)throw new Error(`The ${e} file should parse as a map with key-value pairs, but is type ${typeof n} instead`)}catch(o){P.warn(`Possible Momentic ${e} file at ${t} does not parse as valid YAML: ${W(o)}`);return}return n}function $K(t,e){let r=[];for(let[n,o]of Object.entries(t)){let a=/^\d+$/.test(n)?`${e}[${n}]`:e?`${e}.${n}`:n;o!==null&&typeof o=="object"?r.push(...$K(o,a)):r.push(a);}return r}var EEe=["healing","explore"];function vEe(t){let e=t.ai;if(!e)return [];let r=[];for(let n of EEe)e[n]!==void 0&&(delete e[n],r.push(`ai.${n}`));return r}var CEe=z.object({ai:z.object({classification:z.object({categories:z.unknown()})})});function wEe(t){let e=CEe.safeParse(t);return e.success&&e.data.ai.classification.categories!==void 0}function dO(t){let e=zK(t,"project configuration");if(e===void 0)return;let r;try{r=TEe.parse(e);}catch(a){let s=a instanceof z.ZodError?`
|
|
216
216
|
${z.prettifyError(a)}`:`: ${W(a)}`;P.warn(`Project config at ${t} does not match the required schema${s}`);return}let n=deletedDiff(e,r),o=$K(n,"");o.length>0&&P.warn(`Momentic config file at ${t} contains unrecognized keys: ${o.join(", ")}. These keys will be ignored.`);let i=vEe(r);return wEe(e)&&i.push("ai.classification.categories"),i.length>0&&P.warn(`Momentic config file at ${t} sets cloud-managed AI settings (${i.join(", ")}) that are configured in the Momentic dashboard and ignored locally. Remove them from this file.`),r}function AEe(t){let e=zK(t,"workspace configuration");if(e!==void 0)try{return hEe.parse(e)}catch(r){P.warn(`Possible Momentic workspace configuration file at ${t} does not adhere to the required schema: ${W(r)}`);return}}function REe(){let t=[],e=cwd(),r=fr__default.parse(e).root,n=15,o=0;for(;o<n;){o++;let i=fr__default.basename(e);if(oO.includes(i))return P.warn(`Stopping search for Momentic projects since the current directory name (${i}) is likely a system artifact folder.`),t;for(let a of readdirSync(e))if(a.endsWith(mc)){let s=fr__default.join(e,a),l=dO(s);l&&t.push({configFilePath:s,config:l,rootDir:dirname(s)});}if(t.length)return t;if(e=fr__default.dirname(e),e===r)break}return t}async function hi(t={}){let{configFilePath:e,nameFilter:r,skipExitOnError:n}=t,o=await MEe(e,n);if(r&&(o=o.filter(i=>i.config.name===r)),o.length>1)throw new Error(`Multiple valid projects were found in the same directory. Please use the '-c / --config' flag to disambiguate:
|
|
217
217
|
${o.map(i=>i.configFilePath)}`);if(o.length===0)throw new Error("No valid Momentic project file available.");return P.debug(`Found valid project configuration at ${o[0].configFilePath}`),o[0]}async function xEe(t){let e=AEe(t);if(!e||!e.projects||!e.projects.length)return;let r=e.projects.map(a=>(a.endsWith("/")||(a+="/"),`${a}*${mc}`)),n=AbortSignal.timeout(2e3),o;try{o=await Yu(r,{cwd:cwd(),maxDepth:rb,ignore:[],nodir:!0,signal:n});}catch(a){throw P.error({err:a},`Failed to list the available Momentic projects in the current directory. This usually indicates the 'include' or 'exclude' option in your ${uO} is misconfigured.`),a}let i=[];for(let a of o){let s=fr__default.join(cwd(),a),l=dO(s);l&&i.push({configFilePath:s,config:l,rootDir:dirname(s)});}return i}async function MEe(t,e){if(t){t=fr__default.resolve(t);let n=dO(t);return n?[{config:n,configFilePath:t,rootDir:fr__default.dirname(t)}]:(console.error(`No valid Momentic project file found at ${t}.`),e||process.exit(1),[])}if(existsSync(uO)){let n=await xEe(uO);if(n)return n}return REe()}function rd(t,e){let r=_g.stringify(t);writeFileSync(e,r);}var nb="test-results";var VK=3e3,zt=jK(),_Ee=promisify(execFile);async function qi(t){let{logger:e,operation:r,fn:n,context:o}=t,i=Date.now();try{return await n()}finally{let a=Date.now()-i;a>VK&&!process.env.CI&&e.warn({operation:r,durationMs:a,thresholdMs:VK,...o??{}},"[timing] slow git metadata operation");}}function gs(t){if(t)try{let e=new Date(t);return isNaN(e.getTime())?void 0:e}catch{return}}async function OEe(t){let e=await $t(t,zt.raw(["config","--list"])),r={};if(!e)return r;for(let n of e.split(`
|
|
218
|
-
`)){let o=n.indexOf("=");if(o===-1)continue;let i=n.slice(0,o),a=n.slice(o+1).trim();r[i]=a;}return r}async function DEe(t,e,r){try{let o=r["github.user"]||void 0;if(o)return o}catch{}let n;try{if(e?.startsWith("http://")||e?.startsWith("https://"))n=new URL(e).host;else if(e?.startsWith("git@")){let o=e.indexOf("@"),i=e.indexOf(":",o+1);o!==-1&&i!==-1&&(n=e.slice(o+1,i));}}catch{}if(n=n?.toLowerCase(),!!n&&e?.startsWith("git@")&&n.includes("github"))try{let{stdout:o,stderr:i}=await _Ee("ssh",["-T","-o","BatchMode=yes",`git@${n}`],{timeout:5e3}),s=`${o??""}${i??""}`.trim().match(/Hi\s+([A-Za-z0-9_-]+)!/);if(s?.[1])return s[1]}catch{return}}async function LEe(t,e,r){let n=e?.includes("github.com"),o=e?.includes("gitlab.com");try{if(n)return DEe(t,e,r);if(o)return}catch{}}function ob(t){if(t.startsWith("git@")){let e=t.split(":");if(e.length===2){let r=e[1].replace(".git","").split("/");if(r.length===2){let n=r[0],o=r[1];return `${n}/${o}`}}}else if(t.startsWith("http")||t.startsWith("https")){let r=new URL(t).pathname.split("/").filter(Boolean);if(r.length>=2){let n=r[0],o=r[1].replace(".git","");return `${n}/${o}`}}}function NEe(t){if(!(t instanceof Error))return false;let e=t.message;return e.includes("not a git repository")||e.includes("ENOENT")||e.includes("detected dubious ownership")}async function $t(t,e){try{return (await e).trim()}catch(r){if(NEe(r))return;t.error({err:r},"Failed to run git command");return}}function kEe(){if(process.env.GITHUB_ACTION)return "GithubActions";if(process.env.GITLAB_CI)return "GitlabCI";if(process.env.CIRCLECI)return "CircleCI";if(process.env.BUILDKITE)return "Buildkite";if(process.env["System.CollectionUri"]?.includes("azure"))return "AzureDevOps";if(process.env.PROJECT_ID&&process.env.BUILD_ID)return "GCPCloudBuild";if(process.env.BITRISE_BUILD_SLUG)return "Bitrise";if(process.env.MOMENTIC_GIT_OVERRIDE)return "Custom"}async function FEe(t){let[e,r,n]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),o=process.env.GITHUB_SERVER_URL&&process.env.GITHUB_REPOSITORY?`${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}`:void 0;return {ciProvider:"GithubActions",gitCommitSha:process.env.GITHUB_SHA,gitCommitShaShort:process.env.GITHUB_SHA?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.GITHUB_HEAD_REF||process.env.GITHUB_REF_NAME,gitOriginUrl:o,gitCommitMessage:r,gitCommitAuthorName:n,githubRepository:process.env.GITHUB_REPOSITORY,pipelineId:process.env.GITHUB_RUN_ID}}async function BEe(t){let[e,r,n]=await Promise.all([$t(t,zt.listRemote(["--get-url","origin"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]);return {ciProvider:"GitlabCI",gitCommitSha:process.env.CI_COMMIT_SHA,gitCommitShaShort:process.env.CI_COMMIT_SHORT_SHA,gitCommitTimestamp:process.env.CI_COMMIT_TIMESTAMP?gs(process.env.CI_COMMIT_TIMESTAMP):void 0,gitBranchName:process.env.CI_COMMIT_BRANCH||process.env.CI_COMMIT_REF_NAME,gitOriginUrl:e,gitCommitMessage:r,gitCommitAuthorName:n,gitlabProjectPath:process.env.CI_PROJECT_PATH,pipelineId:`${process.env.CI_PIPELINE_ID}:${process.env.CI_JOB_ID}`}}async function UEe(t){let[e,r,n,o]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.listRemote(["--get-url","origin"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),a=process.env.CIRCLE_REPOSITORY_URL?.trim()||void 0||r||void 0,s=a?.includes("github.com")??false,l=a?.includes("gitlab.com")??false,c=a?ob(a):void 0;return {ciProvider:"CircleCI",gitCommitSha:process.env.CIRCLE_SHA1,gitCommitShaShort:process.env.CIRCLE_SHA1?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.CIRCLE_BRANCH,gitOriginUrl:a,gitCommitMessage:n,gitCommitAuthorName:o,githubRepository:s?c:void 0,gitlabProjectPath:l?c:void 0,pipelineId:process.env.CIRCLE_PIPELINE_ID}}async function zEe(t){let[e,r,n]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),o=process.env.BUILDKITE_REPO,i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?ob(o):void 0;return {ciProvider:"Buildkite",gitCommitSha:process.env.BUILDKITE_COMMIT,gitCommitShaShort:process.env.BUILDKITE_COMMIT?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.BUILDKITE_BRANCH,gitOriginUrl:o,gitCommitMessage:r,gitCommitAuthorName:n,githubRepository:i?s:void 0,gitlabProjectPath:a?s:void 0,pipelineId:`${process.env.BUILDKITE_PIPELINE_ID}:${process.env.BUILDKITE_BUILD_ID}:${process.env.BUILDKITE_JOB_ID}`}}async function $Ee(t){let[e,r,n]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),o=process.env["Build.Repository.Uri"],i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?ob(o):void 0;return {ciProvider:"AzureDevOps",gitCommitSha:process.env["Build.SourceVersion"],gitCommitShaShort:process.env["Build.SourceVersion"]?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env["System.PullRequest.SourceBranch"]??process.env["Build.SourceBranchName"],gitOriginUrl:o,gitCommitMessage:r,gitCommitAuthorName:n,githubRepository:i?s:void 0,gitlabProjectPath:a?s:void 0,pipelineId:`${process.env["System.JobId"]}:${process.env["System.JobAttempt"]}`}}async function VEe(t,e,r){let[n,o,i,a,s,l,c,u,d]=await Promise.all([$t(t,zt.revparse(["HEAD"])),$t(t,zt.revparse(["--short","HEAD"])),$t(t,zt.revparse(["--abbrev-ref","HEAD"])),$t(t,zt.listRemote(["--get-url","origin"])),$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"])),e?$t(t,zt.raw(["merge-base","--fork-point",e])):Promise.resolve(void 0),OEe(t)]),m=u||(e?await $t(t,zt.raw(["merge-base",e,"HEAD"])):void 0),p=m?await $t(t,zt.show(["--no-patch","--format=%ci",m])):void 0,f=a?.includes("github.com"),h=a?.includes("gitlab.com"),g=a?ob(a):void 0,y=d["user.email"]||void 0,S=d["user.name"]||void 0,E=d["user.username"]||void 0,v=d["github.user"]||void 0,L=(r?.includeHostingUsername??true?await LEe(t,a,d):void 0)??E??v??void 0;return {ciProvider:"none",gitCommitSha:n,gitCommitShaShort:o,gitBranchName:i,gitOriginUrl:a,gitCommitTimestamp:s?gs(s):void 0,gitCommitMessage:l,gitCommitAuthorName:c,gitLocalUsername:L,gitLocalEmail:y,gitLocalName:S,lastCommitOnMainSha:m,lastCommitOnMainTimestamp:p?gs(p):void 0,githubRepository:f?g:void 0,gitlabProjectPath:h?g:void 0,pipelineId:void 0}}async function jEe(t){let[e,r]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%an"]))]),n=process.env.GIT_REPOSITORY_URL,o=n?.includes("github.com"),i=n?.includes("gitlab.com"),a=n?ob(n):void 0;return {ciProvider:"Bitrise",gitCommitSha:process.env.BITRISE_GIT_COMMIT,gitCommitShaShort:process.env.BITRISE_GIT_COMMIT?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.BITRISE_GIT_BRANCH,gitOriginUrl:n,gitCommitMessage:process.env.BITRISE_GIT_MESSAGE,gitCommitAuthorName:r,githubRepository:o?a:void 0,gitlabProjectPath:i?a:void 0,pipelineId:`${process.env.BITRISE_APP_SLUG}:${process.env.BITRISE_BUILD_SLUG}`}}async function HEe(){let t=process.env._HEAD_REPO_URL;return {ciProvider:"GCPCloudBuild",gitCommitSha:process.env.COMMIT_SHA,gitCommitShaShort:process.env.COMMIT_SHA?.slice(0,6),gitBranchName:process.env.BRANCH_NAME,gitOriginUrl:t?process.env._HEAD_REPO_URL:void 0,gitCommitTimestamp:void 0,gitCommitMessage:void 0,gitCommitAuthorName:void 0,githubRepository:t?process.env.REPO_FULL_NAME:void 0,pipelineId:`${process.env.PROJECT_ID}:${process.env.BUILD_ID}`}}function WEe(){return {ciProvider:"Custom",gitCommitSha:process.env.GIT_COMMIT_SHA,gitCommitShaShort:process.env.GIT_COMMIT_SHA_SHORT??process.env.GIT_COMMIT_SHA?.slice(0,6),gitCommitTimestamp:gs(process.env.GIT_COMMIT_TIMESTAMP),gitBranchName:process.env.GIT_BRANCH_NAME,gitOriginUrl:process.env.GIT_ORIGIN_URL,gitCommitAuthorName:process.env.GIT_COMMIT_AUTHOR_NAME,gitCommitMessage:process.env.GIT_COMMIT_MESSAGE,lastCommitOnMainSha:process.env.LAST_COMMIT_ON_MAIN_SHA,lastCommitOnMainTimestamp:gs(process.env.LAST_COMMIT_ON_MAIN_TIMESTAMP),mergedGitBranchName:process.env.MERGED_GIT_BRANCH_NAME,githubRepository:process.env.GITHUB_REPOSITORY,gitlabProjectPath:process.env.GITLAB_PROJECT_PATH,gitLocalUsername:process.env.GIT_USERNAME,gitLocalEmail:process.env.GIT_EMAIL,gitLocalName:process.env.GIT_NAME}}async function GEe(t){let e=[...t.config.gitProtectedBranches??[]];return t.config.gitMainBranch&&e.push(t.config.gitMainBranch),{gitMainBranch:t.config.gitMainBranch,gitProtectedBranches:e}}async function ib(t,e,r){let n=kEe();if(!n)return VEe(t,e,r);switch(n){case "GithubActions":return FEe(t);case "GitlabCI":return BEe(t);case "CircleCI":return UEe(t);case "Buildkite":return zEe(t);case "AzureDevOps":return $Ee(t);case "GCPCloudBuild":return HEe();case "Bitrise":return jEe(t);case "Custom":return WEe()}}async function qEe(t,e,r,n){let o=n,i=n.gitCommitSha;if(!i)return o;let a=n.gitMainBranch;if(a&&(!o.lastCommitOnMainSha||!o.lastCommitOnMainTimestamp))try{let s=await qi({logger:t,operation:"getRemoteMetadataFromGitlab.getMergeBaseCommitFromGitlab",fn:()=>e.getMergeBaseCommitFromGitlab(r,a,i),context:{projectPath:r,mainBranch:a}});o={...o,lastCommitOnMainSha:s.sha,lastCommitOnMainTimestamp:s.committer.date};}catch(s){t.warn({err:s},"Failed to get merge base commit from Gitlab");}if(!o.gitCommitTimestamp||!o.gitCommitAuthorName||!o.gitCommitMessage||!o.gitCommitAuthorName)try{let s=await qi({logger:t,operation:"getRemoteMetadataFromGitlab.getCommitFromGitlab",fn:()=>e.getCommitFromGitlab(r,i),context:{projectPath:r,gitCommitSha:i}});s&&(o={...o,gitCommitTimestamp:o.gitCommitTimestamp??s.committer.date,gitCommitAuthorName:o.gitCommitAuthorName??s.author.name,gitCommitMessage:o.gitCommitMessage??s.message});}catch(s){t.warn({err:s},"Failed to get commit from Gitlab");}if(n.gitBranchName&&n.gitBranchName===n.gitMainBranch&&!o.mergedGitBranchName){let s=n.gitBranchName;try{let l=await qi({logger:t,operation:"getRemoteMetadataFromGitlab.getMergedBranchFromGitlab",fn:()=>e.getMergedBranchFromGitlab(r,s,i),context:{projectPath:r,branchName:s,gitCommitSha:i}});l.mergedBranch&&(o={...o,mergedGitBranchName:l.mergedBranch});}catch(l){t.warn({err:l},"Failed to get merged branch from Gitlab");}}return o}async function KEe(t,e,r,n,o){let i=o,a=o.gitCommitSha;if(!a)return i;let s=o.gitMainBranch;if(s&&(!i.lastCommitOnMainSha||!i.lastCommitOnMainTimestamp))try{let l=await qi({logger:t,operation:"getRemoteMetadataFromGitHub.getMergeBaseCommitFromGithub",fn:()=>e.getMergeBaseCommitFromGithub(r,n,s,a),context:{owner:r,repo:n,mainBranch:s}});i={...i,lastCommitOnMainSha:l.sha,lastCommitOnMainTimestamp:l.committer.date};}catch(l){t.warn({err:l},"Failed to get merge base commit from GitHub");}if(!i.gitCommitTimestamp||!i.gitCommitAuthorName||!i.gitCommitMessage||!i.gitCommitAuthorName)try{let l=await qi({logger:t,operation:"getRemoteMetadataFromGitHub.getCommitFromGithub",fn:()=>e.getCommitFromGithub(r,n,a),context:{owner:r,repo:n,gitCommitSha:a}});l&&(i={...i,gitCommitTimestamp:i.gitCommitTimestamp??l.committer.date,gitCommitAuthorName:i.gitCommitAuthorName??l.author.name,gitCommitMessage:i.gitCommitMessage??l.message});}catch(l){t.warn({err:l},"Failed to get commit from GitHub");}if(o.gitBranchName&&o.gitBranchName===o.gitMainBranch&&!i.mergedGitBranchName){let l=o.gitBranchName;try{let c=await qi({logger:t,operation:"getRemoteMetadataFromGitHub.getMergedBranchFromGithub",fn:()=>e.getMergedBranchFromGithub(r,n,l,a),context:{owner:r,repo:n,branchName:l,gitCommitSha:a}});c.mergedBranch&&(i={...i,mergedGitBranchName:c.mergedBranch});}catch(c){t.warn({err:c},"Failed to get merged branch from GitHub");}}return i}async function YEe(t,e,r){try{if(r.githubRepository){let{owner:n,repo:o}=m$(r.githubRepository);return await qi({logger:t,operation:"getRemoteMetadataIfNeeded.getRemoteMetadataFromGitHub",fn:()=>KEe(t,e,n,o,r),context:{githubRepository:r.githubRepository}})}else if(r.gitlabProjectPath){let n=r.gitlabProjectPath;return await qi({logger:t,operation:"getRemoteMetadataIfNeeded.getRemoteMetadataFromGitlab",fn:()=>qEe(t,e,n,r),context:{gitlabProjectPath:n}})}}catch(n){t.warn({err:n},"Failed to get remote git metadata");}return r}async function XEe(t,e,r,n){let o={},i={gitMainBranch:r.config.gitMainBranch};return qi({logger:t,operation:"getGitMetadata.total",fn:async()=>{let[a,s]=await Promise.all([qi({logger:t,operation:"getGitMetadata.getConfiguredGitMetadata",fn:()=>GEe(r),context:{projectConfigPath:r.configFilePath}}),qi({logger:t,operation:"getGitMetadata.getEnvironmentGitMetadata",fn:async()=>{let u=await ib(t,r.config.gitMainBranch,n);return i.ciProvider=u.ciProvider,u},context:i})]),l={...a,...s};o.gitBranchName=l.gitBranchName,o.githubRepository=l.githubRepository,o.gitlabProjectPath=l.gitlabProjectPath,(!l.lastCommitOnMainSha||!l.lastCommitOnMainTimestamp)&&l.gitBranchName===a.gitMainBranch&&(l.lastCommitOnMainSha=l.gitCommitSha,l.lastCommitOnMainTimestamp=l.gitCommitTimestamp);let c=await qi({logger:t,operation:"getGitMetadata.getRemoteMetadataIfNeeded",fn:()=>YEe(t,e,l),context:{githubRepository:l.githubRepository,gitlabProjectPath:l.gitlabProjectPath,gitBranchName:l.gitBranchName}});return {...a,...s,...c}},context:o})}async function HK(t){try{let e=await jK(t).remote(["show","origin"]);return e?e.match(/HEAD branch: (.*)$/m)?.[1]?.trim():void 0}catch{return}}var mO=new Map;async function JEe(t,e,r){let n,o;try{[n,o]=await Promise.all([$t(t,zt.raw(["symbolic-ref","--short","-q","HEAD"]).then(s=>s.trim())),$t(t,zt.revparse(["--verify","HEAD"]).then(s=>s.trim()))]);}catch{return}if(!n||!o)return;let i=`${e.configFilePath}:${e.config.gitMainBranch}:${e.config.gitProtectedBranches?.join(",")}`,a=`${r?.includeHostingUsername}`;return `${n}:${o}:${i}:${a}`}async function Sr(t,e,r,n){let o=await JEe(t,r,n);if(o&&mO.has(o))return t.debug("Using cached git metadata"),mO.get(o);let i=await XEe(t,e,r,n);return o&&mO.set(o,i),i}function eve(t,e){let r=`${ua(e)}.module.yaml`,n=fr__default.join(fr__default.dirname(t),r);if(Sn.existsSync(n))throw new Error(`A conflicting file already exists at the following path: ${n}`);return Sn.renameSync(t,n),n}function bs({content:t,schemaVersion:e,momenticFiles:r,project:n,forceSaveOnNoDiffs:o,forceFileFormat:i}){let a=r.mobileModules[t.moduleId]?.fullFilePath,s=r.mobileModules[t.moduleId]?.name;if(!a||!Sn.existsSync(a))throw new Error(`Tried to update mobile module ${t.moduleId} that could not be found on disk`);let{parsed:l}=Gi(a),c=n.config.fileFormat==="v2";i!==void 0&&(c=i==="v2");let u=!!t.name&&t.name!==s,d={...l,...t,schemaVersion:e},m=rs.parse(d),p=ha(t.platform).array().parse(t.steps),f=c?Jv({metadata:{...m,moduleId:t.moduleId,name:t.name??s??""},steps:p,fileResolver:Zu({sourceFilePath:a,momenticFiles:{mobileModules:r.mobileModules}})}):hn({fileType:Ce.MOBILE_MODULE,...m,steps:p}),h=diff(f,l);if(h&&Object.keys(h).length===0&&!o&&!u)return;Sn.writeFileSync(a,_g.stringify(f),"utf-8");let g=u?eve(a,t.name):void 0;sl(g??a,n.config);}function GK({moduleId:t,patch:e,momenticFiles:r,project:n,logger:o}){let i=r.mobileModules[t]?.fullFilePath;if(!i)throw new Error(`Tried to update mobile module ${t} that could not be found on disk`);let a=pc(i,o),s=fc({module:a,moduleFilePath:i,momenticFiles:r}),l=tP.parse({...s,...e}),c={moduleId:l.moduleId,platform:l.platform,name:e.name??s.name,description:l.description,enabled:l.enabled,parameters:l.parameters,steps:ha(l.platform).array().parse(l.steps)};bs({content:c,schemaVersion:l.schemaVersion,momenticFiles:r,project:n});}async function sb({name:t,description:e,enabled:r,platform:n,steps:o,folder:i,project:a,momenticFiles:s}){let l=ua(t),c=fr__default.join(i,`${l}.module.yaml`);Qv({project:a,relativeFilePath:fr__default.relative(a.rootDir,c)});let u=bp({projectConfig:a.config,momenticFiles:s,entityType:"mobile-module"}),{stepsToSave:{steps:d}}=await An({platform:n,stepLists:{steps:o}}),m={schemaVersion:US,platform:n,moduleId:u,description:e,enabled:r},p=a.config.fileFormat==="v2"?Jv({metadata:{...m,moduleId:u,name:t},steps:d,fileResolver:Zu({sourceFilePath:c,momenticFiles:{mobileModules:s.mobileModules}})}):rP.parse({fileType:Ce.MOBILE_MODULE,...m,steps:d});return Sn.mkdirSync(i,{recursive:true}),Sn.writeFileSync(c,_g.stringify(p),"utf-8"),sl(c,a.config),{moduleId:u,platform:n,name:t,description:e||void 0,steps:o}}function pc(t,e){let{parsed:r}=Gi(t);if(Qg(r))try{return eE.parse(r)}catch(n){throw e.error({err:n,moduleFilePath:t,existingModule:r},`${t} does not parse as a valid V2 Momentic mobile module`),n}try{return rP.parse(r)}catch(n){throw e.error({err:n,moduleFilePath:t,existingModule:r},`${t} does not parse as a valid Momentic mobile module`),n}}function fc({module:t,moduleFilePath:e,momenticFiles:r}){let n=fr__default.basename(e,".module.yaml");if(!Qg(t))return {...t,name:n};let{module:o}=Xv({moduleV2:t,moduleName:n,fileResolver:Qu({sourceFilePath:e,momenticFiles:r})});return o}async function nd(t,e,r,n){let o=pc(t.fullFilePath,r),i=fc({module:o,moduleFilePath:t.fullFilePath,momenticFiles:e}),a=i.platform==="ANDROID"?n?.android:n?.ios,{resolvedSteps:s}=await vv({platform:i.platform,rawSteps:i.steps,resolvedModuleCache:a||{},onFetchModule:async c=>{let u=e.mobileModules[c]?.fullFilePath;if(!u)throw new Error(`Could not find mobile module with id ${c}`);let d=pc(u,r);return fc({module:d,moduleFilePath:u,momenticFiles:e})},logger:r,metadata:{id:i.moduleId,schemaVersion:i.schemaVersion}}),l=i.platform==="ANDROID"?{...i,platform:"ANDROID",name:t.name,description:i.description||void 0,steps:s}:{...i,platform:"IOS",name:t.name,description:i.description||void 0,steps:s};return a&&(a[t.id]=cloneDeep(l)),l}async function qK(t,e){let r={},n={};return await Promise.all(Object.values(t.mobileModules).map(async o=>{await nd(o,t,e,{ios:r,android:n});})),[...Object.values(r),...Object.values(n)]}var Sp=hT.array(),tC=C__default.discriminatedUnion("platform",[OT.extend({beforeSteps:Sp.optional(),steps:Sp,afterSteps:Sp.optional()}),DT.extend({beforeSteps:Sp.optional(),steps:Sp,afterSteps:Sp.optional()})]);function rC({name:t,description:e="",settings:r,folder:n,platform:o,project:i,momenticFiles:a}){try{_i(t);}catch(p){throw new ar(`${p} when validating the test entity name`)}let l=`${ua(t)}.test.yaml`,c=fr__default.join(n,l);if(Sn.existsSync(c))throw new gh({name:t,path:c});Qv({project:i,relativeFilePath:fr__default.relative(i.rootDir,c)});let u=bp({projectConfig:i.config,momenticFiles:a,entityType:"mobile-test"}),d={fileType:Ce.MOBILE_TEST,id:u,description:e,schemaVersion:dn,platform:o,settings:r,steps:[]},m=i.config.fileFormat==="v2"?hp({metadata:d,stepLists:{steps:[]},fileResolver:Zu({sourceFilePath:c,momenticFiles:{mobileModules:a.mobileModules}})}):zz.parse(d);return Sn.mkdirSync(n,{recursive:true}),Sn.writeFileSync(c,_g.stringify(m),"utf-8"),{fullPath:c,testId:u}}function tve(t){if(!Sn.existsSync(t))throw new Error(`Test file not found: ${t}`);let{parsed:e}=Gi(t);if(Zg(e))return e;if(!e.steps||!Array.isArray(e.steps))throw new Error(`Test ${t} is missing steps`);return e}async function dr(t,e,r){let n=tve(t),o,i;if(Zg(n)){let s;try{s=Xl.parse(n);}catch(c){let u=c instanceof C__default.ZodError?C__default.prettifyError(c):W(c);throw new ar(`Mobile test ${t} is missing metadata or has invalid metadata: ${u}`,{cause:c})}o=eb({testV2:s});let l=await Yv({testV2:s,platform:o.platform,fileResolver:Qu({sourceFilePath:t,momenticFiles:{mobileModules:r.mobileModules}})});i={steps:l.stepLists.steps,beforeSteps:l.stepLists.beforeSteps,afterSteps:l.stepLists.afterSteps};}else {try{o=Gl.parse(n);}catch(s){let l=s instanceof C__default.ZodError?C__default.prettifyError(s):W(s);throw new ar(`Mobile test ${t} is missing metadata or has invalid metadata: ${l}`,{cause:s})}i={steps:n.steps,beforeSteps:n.beforeSteps,afterSteps:n.afterSteps};}let a={rawStepLists:i,logger:e,testMetadata:o,onFetchModule:async s=>{let l=r.mobileModules[s]?.fullFilePath;if(!l)throw new Error(`Mobile module ${s} not found`);let c=pc(l,e);return fc({module:c,moduleFilePath:l,momenticFiles:r})}};switch(o.platform){case "ANDROID":{let{resolvedStepLists:s}=await F_({...a,platform:o.platform});return {...o,steps:s.steps,...s.beforeSteps?.length&&{beforeSteps:s.beforeSteps},...s.afterSteps?.length&&{afterSteps:s.afterSteps}}}case "IOS":{let{resolvedStepLists:s}=await F_({...a,platform:o.platform});return {...o,steps:s.steps,...s.beforeSteps?.length&&{beforeSteps:s.beforeSteps},...s.afterSteps?.length&&{afterSteps:s.afterSteps}}}}}async function cl({platform:t,filePath:e,steps:r,beforeSteps:n,afterSteps:o,settings:i,labels:a,folder:s,project:l,momenticFiles:c,schemaVersion:u,forceFileFormat:d}){let m=fr__default.isAbsolute(e)?e:fr__default.join(s,e);if(!Sn.existsSync(m))throw new Error(`Test file not found: ${m}`);let{parsed:p}=Gi(m),f=Zg(p),h,g;if(f?(g=Xl.parse(p),h={...eb({testV2:g}),schemaVersion:u,fileType:Ce.MOBILE_TEST,steps:[]}):h=tC.parse({...p,schemaVersion:u}),h.fileType!==Ce.MOBILE_TEST)throw new Error(`File at '${m}' is not a mobile test (fileType=${h.fileType}).`);if(h.platform!==t)throw new Error(`Platform mismatch. Test at '${m}' is for platform ${h.platform}, but update is for platform ${t}.`);let y=r||n||o,S=y?await An({platform:t,stepLists:{steps:r??[],beforeSteps:n,afterSteps:o}}):void 0,E=S?.moduleUpdates??[],v;f&&g&&!y&&(v={steps:g.steps??[],before:g.before,after:g.after});let w=l.config.fileFormat==="v2"||f;d!==void 0&&(w=d==="v2");for(let I of E)bs({content:I,schemaVersion:dn,momenticFiles:c,project:l,forceFileFormat:d});if(w){let I={...h};a!==void 0&&(I.labels=a),i!==void 0&&(I.settings=i);let R={...I,steps:[]},k;if(y&&S){let D;S.stepsToSave.beforeSteps&&S.stepsToSave.beforeSteps.length>0&&(D=S.stepsToSave.beforeSteps);let V;S.stepsToSave.afterSteps&&S.stepsToSave.afterSteps.length>0&&(V=S.stepsToSave.afterSteps),k={steps:S.stepsToSave.steps,beforeSteps:D,afterSteps:V};let $=Zu({sourceFilePath:m,momenticFiles:{mobileModules:c.mobileModules}}),U=hp({metadata:R,stepLists:k,fileResolver:$});Sn.writeFileSync(m,_g.stringify(U),"utf-8");}else {let D=hp({metadata:R,stepLists:{steps:[]},fileResolver:Zu({sourceFilePath:m,momenticFiles:{mobileModules:c.mobileModules}})}),V=YK({formatted:D,stepLists:v??{steps:[]}});Sn.writeFileSync(m,V,"utf-8");}sl(m,l.config);return}let _={...h,steps:h.steps};if(r&&(_.steps=S?.stepsToSave.steps??[]),a!==void 0&&(_.labels=a),n){let I=S?.stepsToSave.beforeSteps;I&&I.length>0?_.beforeSteps=I:delete _.beforeSteps;}else h.beforeSteps&&h.beforeSteps.length>0&&(_.beforeSteps=h.beforeSteps);if(o){let I=S?.stepsToSave.afterSteps;I&&I.length>0?_.afterSteps=I:delete _.afterSteps;}else h.afterSteps&&h.afterSteps.length>0&&(_.afterSteps=h.afterSteps);i&&(_.settings=i);let L=_g.stringify(tC.parse(_));Sn.writeFileSync(m,L,"utf-8"),sl(m,l.config);}function KK(t,e,r){let n=fr__default.join(r.rootDir,t);if(!Sn.existsSync(n))throw new Xe(`Test not found at path '${t}' in project '${r.rootDir}'`);let{parsed:o}=Gi(n),i=Zg(o),a=fr__default.basename(t,".test.yaml"),s,l;if(e.name&&e.name!==a){let u=`${ua(e.name)}.test.yaml`;if(s=fr__default.join(fr__default.dirname(t),u),l=fr__default.join(r.rootDir,s),Sn.existsSync(l))throw new gh({name:e.name,path:l})}let c=i?rve({existingTestRaw:o,updates:e}):nve({existingTestRaw:o,updates:e});return Sn.writeFileSync(n,c,"utf-8"),l&&l!==n?(Sn.renameSync(n,l),sl(l,r.config)):sl(n,r.config),{newRelativeTestPath:s}}function rve({existingTestRaw:t,updates:e}){let r=Xl.parse(t),n=eb({testV2:r}),o={...n,description:e.description??n.description,disabled:e.disabled??n.disabled,labels:e.labels??n.labels,settings:e.settings??n.settings,fileType:Ce.MOBILE_TEST,steps:[]};return YK({formatted:hp({metadata:o,stepLists:{steps:[]}}),stepLists:{before:r.before,steps:r.steps??[],after:r.after}})}function YK({formatted:t,stepLists:e}){let{steps:r,...n}=t,o=e.before;o&&o.length===0&&(o=void 0);let i=e.after;i&&i.length===0&&(i=void 0);let a=hn({...n,before:o,steps:e.steps,after:i});return _g.stringify(a)}function nve({existingTestRaw:t,updates:e}){let n={...tC.parse(t),...e};if(n.fileType!==Ce.MOBILE_TEST)throw new Error(`Existing legacy mobile test has unexpected fileType=${n.fileType}.`);return _g.stringify(tC.parse(n))}var XK=new Set([".DS_Store","__MACOSX"]),JK={status:(t,e)=>{if(t.status===e.status)return t.status;if(t.status==="FAILED"||e.status==="FAILED")return "FAILED";if(t.status==="CANCELLED"||e.status==="CANCELLED")return "CANCELLED";if(t.status==="RETRYING"||e.status==="RETRYING")return "RETRYING";if(t.status==="RUNNING"||e.status==="RUNNING")return "RUNNING";if(t.status==="PENDING"||e.status==="PENDING")return "PENDING";throw new Error(`Invalid run status merge: ${t.status} and ${e.status}`)},startedAt:(t,e)=>t.startedAt<e.startedAt?t.startedAt:e.startedAt,updatedAt:(t,e)=>t.updatedAt>e.updatedAt?t.updatedAt:e.updatedAt,finishedAt:(t,e)=>!t.finishedAt||!e.finishedAt?new Date:t.finishedAt>e.finishedAt?t.finishedAt:e.finishedAt,gitCommitTimestamp:(t,e)=>{if(!(!t&&!e)){if(!t.gitCommitTimestamp||!e.gitCommitTimestamp||t.gitCommitTimestamp.getTime()!==e.gitCommitTimestamp.getTime())throw new Error(`Git commit timestamps must match to be merged: ${t.gitCommitTimestamp} and ${e.gitCommitTimestamp}`);return t.gitCommitTimestamp}},pipelineId:(t,e)=>t.pipelineId===e.pipelineId?t.pipelineId:!t.pipelineId&&e.pipelineId?e.pipelineId:!e.pipelineId&&t.pipelineId?t.pipelineId:t.startedAt<e.startedAt?e.pipelineId:t.pipelineId,labels:(t,e)=>{let r=new Set([...t.labels??[],...e.labels??[]]);return Array.from(r)},ai:(t,e)=>t.ai??e.ai,browser:(t,e)=>t.browser??e.browser,aiSelect:(t,e)=>{let r=[...t.aiSelect??[],...e.aiSelect??[]];return r.length>0?r:void 0},healRiskSummary:()=>{}};function ive(t,e,r){if(JK[r]){let i=JK[r];return i(t,e)}let n=t[r],o=e[r];if(n===void 0)return o;if(o===void 0)return n;if(n!==o)throw new Error(`Metadata values for key "${r}" do not match: "${n}" vs "${o}"`);return n}var pO=class extends Error{constructor(e,r){let n=`${e} contains invalid Momentic results: ${r}. Please ensure that the path points to a folder containing only valid results. If you passed \`--output-dir test-results/results-1\` to the \`run\` command, your results path for merging should be \`test-results\`.`;super(n),this.name="InvalidMomenticResultsPathError";}};function ZK(t,e){try{let r=fr__default.join(e,fn);return jm.parse(JSON.parse(Sn.readFileSync(r,"utf-8")))}catch{throw new pO(t,e)}}function QK(t,e,r){let n=randomUUID(),o=t.child({runGroupId:n});Sn.rmSync(e,{recursive:true,force:true});let i=Sn.readdirSync(r).filter(l=>!XK.has(l)).map(l=>fr__default.join(r,l));if(i.length===0)throw new Error(`No run groups found in results path: ${r}`);Sn.mkdirSync(e,{recursive:true});let a={...ZK(r,i[0]),id:n,healRiskSummary:void 0,aiSelect:void 0};for(let l of i){let c=fr__default.join(l,vo);if(!Sn.existsSync(c))continue;let u=ZK(r,l);o.info({oldRunGroupId:u.id},"Merging run groups");for(let m in u){if(m==="id")continue;let p=m;a[p]=ive(a,u,p);}let d=Sn.readdirSync(c);for(let m of d){if(XK.has(m))continue;let p=fr__default.join(c,m),f=fr__default.join(e,vo,m);Sn.cpSync(p,f,{recursive:true});}}let s=fr__default.join(e,fn);Sn.writeFileSync(s,JSON.stringify(a,null,2));}var X="v1",fO="mobile-cli",od="1.0.1";var ave=9e4,sve=3,lve=1500,cve=15e3,Pr=class extends Error{status;rawError;constructor(e,r,n,o={}){super(n,o),this.status=e,this.rawError=r;}},hO=class extends Xe{constructor(e,r={}){super(e,r),this.name="PlanLimitExceededError";}};async function uve(t){return t.text().then(e=>{try{return JSON.parse(e).error}catch{return e}})}var gO=class{baseUrl;logger;constructor(e){this.baseUrl=e.baseUrl,this.logger=e.logger;}getHeaders(){let e={"Content-Type":"application/json"};return (e[tE]=od),(e[lj]=fO),e}async sendRequest(e,r){let{retries:n=sve,requestTimeoutMs:o=ave,initialRetryDelayMs:i=lve,maxRetryDelayMs:a=cve,onFailedRequest:s}=r,l=n,c=n,u,d={path:e,baseUrl:this.baseUrl,method:r.method};for(;l>0;)try{return l--,await this.sendSingleRequestWithOTEL(e,r,o)}catch(m){u=m;try{s?.(u);}catch{}if(m instanceof Pr&&m.status>=400&&m.status<500)throw m.status===402?new hO(m.rawError,{cause:m}):m;if(m instanceof Error&&m.name==="AbortError"&&(u=new Zl),l===0)throw u;let p=c-l,f=Math.min(i*Math.pow(2,p-1),a);await new Promise(h=>setTimeout(h,f));}throw this.logger.warn({...d,err:u},"Got fatal error response from Momentic server"),u}async sendSingleRequestWithOTEL(e,r,n){let o=dve(e);return Ne({name:`cli.api.${r.method.toLowerCase()}.${o}`,serviceName:"api-server",attributes:{"http.request.method":r.method,"url.path":o},fn:i=>this.sendSingleRequestHelper(e,r,n,a=>{i?.setAttribute("http.response.status_code",a);})})}async sendSingleRequestHelper(e,r,n,o){let i={path:e,baseUrl:this.baseUrl,method:r.method},a=new AbortController,s=setTimeout(()=>a.abort(),n),l=()=>a.abort();r.signal&&r.signal.addEventListener("abort",l,{once:true});let c=Date.now(),u={...this.getHeaders(),...r.extraHeaders};try{let d=await fetch(`${this.baseUrl}${e}`,{method:r.method,body:r.body?JSON.stringify(r.body):void 0,headers:u,signal:a.signal});if(o?.(d.status),!d.ok){let f=await uve(d);throw new Pr(d.status,f,`Request to ${r.method} ${e} failed with status ${d.status}: ${f}`)}let m;if(d.status===204)m={};else if(r.responseType==="buffer"){let f=await d.arrayBuffer();m=Buffer.from(f);}else {let f=await d.text();try{m=JSON.parse(f);}catch{m=f;}}this.logger&&r.logResponse===!0&&m&&this.logger.debug({result:m,status:d.status,durationMs:Date.now()-c,...i},"Got response from Momentic server");let p=r.responseHeadersObject;return p&&d.headers.forEach((f,h)=>{p[h.toLowerCase()]=f;}),m}finally{clearTimeout(s),r.signal&&r.signal.removeEventListener("abort",l);}}};function dve(t){return (t.split("?")[0]??t).replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,":id")}var ys=class extends gO{apiKey;mode;runner;constructor(e){super(e),this.apiKey=e.apiKey,this.mode=e.mode,this.runner=e.runner;}getHeaders(){return {...super.getHeaders(),Authorization:`Bearer ${this.apiKey}`,[aj]:this.mode??""}}};var M4="vercel.ai.error",mve=Symbol.for(M4),e4,t4,qt=class P4 extends(t4=Error,e4=mve,t4){constructor({name:e,message:r,cause:n}){super(r),this[e4]=true,this.name=e,this.cause=n;}static isInstance(e){return P4.hasMarker(e,M4)}static hasMarker(e,r){let n=Symbol.for(r);return e!=null&&typeof e=="object"&&n in e&&typeof e[n]=="boolean"&&e[n]===true}},I4="AI_APICallError",_4=`vercel.ai.error.${I4}`,pve=Symbol.for(_4),r4,n4,kn=class extends(n4=qt,r4=pve,n4){constructor({message:t,url:e,requestBodyValues:r,statusCode:n,responseHeaders:o,responseBody:i,cause:a,isRetryable:s=n!=null&&(n===408||n===409||n===429||n>=500),data:l}){super({name:I4,message:t,cause:a}),this[r4]=true,this.url=e,this.requestBodyValues=r,this.statusCode=n,this.responseHeaders=o,this.responseBody=i,this.isRetryable=s,this.data=l;}static isInstance(t){return qt.hasMarker(t,_4)}},O4="AI_EmptyResponseBodyError",D4=`vercel.ai.error.${O4}`,fve=Symbol.for(D4),o4,i4,L4=class extends(i4=qt,o4=fve,i4){constructor({message:t="Empty response body"}={}){super({name:O4,message:t}),this[o4]=true;}static isInstance(t){return qt.hasMarker(t,D4)}};function N4(t){return t==null?"unknown error":typeof t=="string"?t:t instanceof Error?t.message:JSON.stringify(t)}var k4="AI_InvalidArgumentError",F4=`vercel.ai.error.${k4}`,hve=Symbol.for(F4),a4,s4,nC=class extends(s4=qt,a4=hve,s4){constructor({message:t,cause:e,argument:r}){super({name:k4,message:t,cause:e}),this[a4]=true,this.argument=r;}static isInstance(t){return qt.hasMarker(t,F4)}},B4="AI_InvalidPromptError",U4=`vercel.ai.error.${B4}`,gve=Symbol.for(U4),l4,c4,z4=class extends(c4=qt,l4=gve,c4){constructor({prompt:t,message:e,cause:r}){super({name:B4,message:`Invalid prompt: ${e}`,cause:r}),this[l4]=true,this.prompt=t;}static isInstance(t){return qt.hasMarker(t,U4)}},$4="AI_InvalidResponseDataError",V4=`vercel.ai.error.${$4}`,bve=Symbol.for(V4),u4,d4,oC=class extends(d4=qt,u4=bve,d4){constructor({data:t,message:e=`Invalid response data: ${JSON.stringify(t)}.`}){super({name:$4,message:e}),this[u4]=true,this.data=t;}static isInstance(t){return qt.hasMarker(t,V4)}},j4="AI_JSONParseError",H4=`vercel.ai.error.${j4}`,yve=Symbol.for(H4),m4,p4,ub=class extends(p4=qt,m4=yve,p4){constructor({text:t,cause:e}){super({name:j4,message:`JSON parsing failed: Text: ${t}.
|
|
218
|
+
`)){let o=n.indexOf("=");if(o===-1)continue;let i=n.slice(0,o),a=n.slice(o+1).trim();r[i]=a;}return r}async function DEe(t,e,r){try{let o=r["github.user"]||void 0;if(o)return o}catch{}let n;try{if(e?.startsWith("http://")||e?.startsWith("https://"))n=new URL(e).host;else if(e?.startsWith("git@")){let o=e.indexOf("@"),i=e.indexOf(":",o+1);o!==-1&&i!==-1&&(n=e.slice(o+1,i));}}catch{}if(n=n?.toLowerCase(),!!n&&e?.startsWith("git@")&&n.includes("github"))try{let{stdout:o,stderr:i}=await _Ee("ssh",["-T","-o","BatchMode=yes",`git@${n}`],{timeout:5e3}),s=`${o??""}${i??""}`.trim().match(/Hi\s+([A-Za-z0-9_-]+)!/);if(s?.[1])return s[1]}catch{return}}async function LEe(t,e,r){let n=e?.includes("github.com"),o=e?.includes("gitlab.com");try{if(n)return DEe(t,e,r);if(o)return}catch{}}function ob(t){if(t.startsWith("git@")){let e=t.split(":");if(e.length===2){let r=e[1].replace(".git","").split("/");if(r.length===2){let n=r[0],o=r[1];return `${n}/${o}`}}}else if(t.startsWith("http")||t.startsWith("https")){let r=new URL(t).pathname.split("/").filter(Boolean);if(r.length>=2){let n=r[0],o=r[1].replace(".git","");return `${n}/${o}`}}}function NEe(t){if(!(t instanceof Error))return false;let e=t.message;return e.includes("not a git repository")||e.includes("ENOENT")||e.includes("detected dubious ownership")}async function $t(t,e){try{return (await e).trim()}catch(r){if(NEe(r))return;t.error({err:r},"Failed to run git command");return}}function kEe(){if(process.env.GITHUB_ACTION)return "GithubActions";if(process.env.GITLAB_CI)return "GitlabCI";if(process.env.CIRCLECI)return "CircleCI";if(process.env.BUILDKITE)return "Buildkite";if(process.env["System.CollectionUri"]?.includes("azure"))return "AzureDevOps";if(process.env.PROJECT_ID&&process.env.BUILD_ID)return "GCPCloudBuild";if(process.env.BITRISE_BUILD_SLUG)return "Bitrise";if(process.env.MOMENTIC_GIT_OVERRIDE)return "Custom"}async function FEe(t){let[e,r,n]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),o=process.env.GITHUB_SERVER_URL&&process.env.GITHUB_REPOSITORY?`${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}`:void 0;return {ciProvider:"GithubActions",gitCommitSha:process.env.GITHUB_SHA,gitCommitShaShort:process.env.GITHUB_SHA?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.GITHUB_HEAD_REF||process.env.GITHUB_REF_NAME,gitOriginUrl:o,gitCommitMessage:r,gitCommitAuthorName:n,githubRepository:process.env.GITHUB_REPOSITORY,pipelineId:process.env.GITHUB_RUN_ID}}async function BEe(t){let[e,r,n]=await Promise.all([$t(t,zt.listRemote(["--get-url","origin"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]);return {ciProvider:"GitlabCI",gitCommitSha:process.env.CI_COMMIT_SHA,gitCommitShaShort:process.env.CI_COMMIT_SHORT_SHA,gitCommitTimestamp:process.env.CI_COMMIT_TIMESTAMP?gs(process.env.CI_COMMIT_TIMESTAMP):void 0,gitBranchName:process.env.CI_COMMIT_BRANCH||process.env.CI_COMMIT_REF_NAME,gitOriginUrl:e,gitCommitMessage:r,gitCommitAuthorName:n,gitlabProjectPath:process.env.CI_PROJECT_PATH,pipelineId:`${process.env.CI_PIPELINE_ID}:${process.env.CI_JOB_ID}`}}async function UEe(t){let[e,r,n,o]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.listRemote(["--get-url","origin"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),a=process.env.CIRCLE_REPOSITORY_URL?.trim()||void 0||r||void 0,s=a?.includes("github.com")??false,l=a?.includes("gitlab.com")??false,c=a?ob(a):void 0;return {ciProvider:"CircleCI",gitCommitSha:process.env.CIRCLE_SHA1,gitCommitShaShort:process.env.CIRCLE_SHA1?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.CIRCLE_BRANCH,gitOriginUrl:a,gitCommitMessage:n,gitCommitAuthorName:o,githubRepository:s?c:void 0,gitlabProjectPath:l?c:void 0,pipelineId:process.env.CIRCLE_PIPELINE_ID}}async function zEe(t){let[e,r,n]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),o=process.env.BUILDKITE_REPO,i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?ob(o):void 0;return {ciProvider:"Buildkite",gitCommitSha:process.env.BUILDKITE_COMMIT,gitCommitShaShort:process.env.BUILDKITE_COMMIT?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.BUILDKITE_BRANCH,gitOriginUrl:o,gitCommitMessage:r,gitCommitAuthorName:n,githubRepository:i?s:void 0,gitlabProjectPath:a?s:void 0,pipelineId:`${process.env.BUILDKITE_PIPELINE_ID}:${process.env.BUILDKITE_BUILD_ID}:${process.env.BUILDKITE_JOB_ID}`}}async function $Ee(t){let[e,r,n]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"]))]),o=process.env["Build.Repository.Uri"],i=o?.includes("github.com"),a=o?.includes("gitlab.com"),s=o?ob(o):void 0;return {ciProvider:"AzureDevOps",gitCommitSha:process.env["Build.SourceVersion"],gitCommitShaShort:process.env["Build.SourceVersion"]?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env["System.PullRequest.SourceBranch"]??process.env["Build.SourceBranchName"],gitOriginUrl:o,gitCommitMessage:r,gitCommitAuthorName:n,githubRepository:i?s:void 0,gitlabProjectPath:a?s:void 0,pipelineId:`${process.env["System.JobId"]}:${process.env["System.JobAttempt"]}`}}async function VEe(t,e,r){let[n,o,i,a,s,l,c,u,d]=await Promise.all([$t(t,zt.revparse(["HEAD"])),$t(t,zt.revparse(["--short","HEAD"])),$t(t,zt.revparse(["--abbrev-ref","HEAD"])),$t(t,zt.listRemote(["--get-url","origin"])),$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%B"])),$t(t,zt.show(["-s","--pretty=%an"])),e?$t(t,zt.raw(["merge-base","--fork-point",e])):Promise.resolve(void 0),OEe(t)]),m=u||(e?await $t(t,zt.raw(["merge-base",e,"HEAD"])):void 0),p=m?await $t(t,zt.show(["--no-patch","--format=%ci",m])):void 0,f=a?.includes("github.com"),h=a?.includes("gitlab.com"),g=a?ob(a):void 0,y=d["user.email"]||void 0,S=d["user.name"]||void 0,E=d["user.username"]||void 0,v=d["github.user"]||void 0,L=(r?.includeHostingUsername??true?await LEe(t,a,d):void 0)??E??v??void 0;return {ciProvider:"none",gitCommitSha:n,gitCommitShaShort:o,gitBranchName:i,gitOriginUrl:a,gitCommitTimestamp:s?gs(s):void 0,gitCommitMessage:l,gitCommitAuthorName:c,gitLocalUsername:L,gitLocalEmail:y,gitLocalName:S,lastCommitOnMainSha:m,lastCommitOnMainTimestamp:p?gs(p):void 0,githubRepository:f?g:void 0,gitlabProjectPath:h?g:void 0,pipelineId:void 0}}async function jEe(t){let[e,r]=await Promise.all([$t(t,zt.show(["--no-patch","--format=%ci"])),$t(t,zt.show(["-s","--pretty=%an"]))]),n=process.env.GIT_REPOSITORY_URL,o=n?.includes("github.com"),i=n?.includes("gitlab.com"),a=n?ob(n):void 0;return {ciProvider:"Bitrise",gitCommitSha:process.env.BITRISE_GIT_COMMIT,gitCommitShaShort:process.env.BITRISE_GIT_COMMIT?.slice(0,6),gitCommitTimestamp:e?gs(e):void 0,gitBranchName:process.env.BITRISE_GIT_BRANCH,gitOriginUrl:n,gitCommitMessage:process.env.BITRISE_GIT_MESSAGE,gitCommitAuthorName:r,githubRepository:o?a:void 0,gitlabProjectPath:i?a:void 0,pipelineId:`${process.env.BITRISE_APP_SLUG}:${process.env.BITRISE_BUILD_SLUG}`}}async function HEe(){let t=process.env._HEAD_REPO_URL;return {ciProvider:"GCPCloudBuild",gitCommitSha:process.env.COMMIT_SHA,gitCommitShaShort:process.env.COMMIT_SHA?.slice(0,6),gitBranchName:process.env.BRANCH_NAME,gitOriginUrl:t?process.env._HEAD_REPO_URL:void 0,gitCommitTimestamp:void 0,gitCommitMessage:void 0,gitCommitAuthorName:void 0,githubRepository:t?process.env.REPO_FULL_NAME:void 0,pipelineId:`${process.env.PROJECT_ID}:${process.env.BUILD_ID}`}}function WEe(){return {ciProvider:"Custom",gitCommitSha:process.env.GIT_COMMIT_SHA,gitCommitShaShort:process.env.GIT_COMMIT_SHA_SHORT??process.env.GIT_COMMIT_SHA?.slice(0,6),gitCommitTimestamp:gs(process.env.GIT_COMMIT_TIMESTAMP),gitBranchName:process.env.GIT_BRANCH_NAME,gitOriginUrl:process.env.GIT_ORIGIN_URL,gitCommitAuthorName:process.env.GIT_COMMIT_AUTHOR_NAME,gitCommitMessage:process.env.GIT_COMMIT_MESSAGE,lastCommitOnMainSha:process.env.LAST_COMMIT_ON_MAIN_SHA,lastCommitOnMainTimestamp:gs(process.env.LAST_COMMIT_ON_MAIN_TIMESTAMP),mergedGitBranchName:process.env.MERGED_GIT_BRANCH_NAME,githubRepository:process.env.GITHUB_REPOSITORY,gitlabProjectPath:process.env.GITLAB_PROJECT_PATH,gitLocalUsername:process.env.GIT_USERNAME,gitLocalEmail:process.env.GIT_EMAIL,gitLocalName:process.env.GIT_NAME}}async function GEe(t){let e=[...t.config.gitProtectedBranches??[]];return t.config.gitMainBranch&&e.push(t.config.gitMainBranch),{gitMainBranch:t.config.gitMainBranch,gitProtectedBranches:e}}async function ib(t,e,r){let n=kEe();if(!n)return VEe(t,e,r);switch(n){case "GithubActions":return FEe(t);case "GitlabCI":return BEe(t);case "CircleCI":return UEe(t);case "Buildkite":return zEe(t);case "AzureDevOps":return $Ee(t);case "GCPCloudBuild":return HEe();case "Bitrise":return jEe(t);case "Custom":return WEe()}}async function qEe(t,e,r,n){let o=n,i=n.gitCommitSha;if(!i)return o;let a=n.gitMainBranch;if(a&&(!o.lastCommitOnMainSha||!o.lastCommitOnMainTimestamp))try{let s=await qi({logger:t,operation:"getRemoteMetadataFromGitlab.getMergeBaseCommitFromGitlab",fn:()=>e.getMergeBaseCommitFromGitlab(r,a,i),context:{projectPath:r,mainBranch:a}});o={...o,lastCommitOnMainSha:s.sha,lastCommitOnMainTimestamp:s.committer.date};}catch(s){t.warn({err:s},"Failed to get merge base commit from Gitlab");}if(!o.gitCommitTimestamp||!o.gitCommitAuthorName||!o.gitCommitMessage||!o.gitCommitAuthorName)try{let s=await qi({logger:t,operation:"getRemoteMetadataFromGitlab.getCommitFromGitlab",fn:()=>e.getCommitFromGitlab(r,i),context:{projectPath:r,gitCommitSha:i}});s&&(o={...o,gitCommitTimestamp:o.gitCommitTimestamp??s.committer.date,gitCommitAuthorName:o.gitCommitAuthorName??s.author.name,gitCommitMessage:o.gitCommitMessage??s.message});}catch(s){t.warn({err:s},"Failed to get commit from Gitlab");}if(n.gitBranchName&&n.gitBranchName===n.gitMainBranch&&!o.mergedGitBranchName){let s=n.gitBranchName;try{let l=await qi({logger:t,operation:"getRemoteMetadataFromGitlab.getMergedBranchFromGitlab",fn:()=>e.getMergedBranchFromGitlab(r,s,i),context:{projectPath:r,branchName:s,gitCommitSha:i}});l.mergedBranch&&(o={...o,mergedGitBranchName:l.mergedBranch});}catch(l){t.warn({err:l},"Failed to get merged branch from Gitlab");}}return o}async function KEe(t,e,r,n,o){let i=o,a=o.gitCommitSha;if(!a)return i;let s=o.gitMainBranch;if(s&&(!i.lastCommitOnMainSha||!i.lastCommitOnMainTimestamp))try{let l=await qi({logger:t,operation:"getRemoteMetadataFromGitHub.getMergeBaseCommitFromGithub",fn:()=>e.getMergeBaseCommitFromGithub(r,n,s,a),context:{owner:r,repo:n,mainBranch:s}});i={...i,lastCommitOnMainSha:l.sha,lastCommitOnMainTimestamp:l.committer.date};}catch(l){t.warn({err:l},"Failed to get merge base commit from GitHub");}if(!i.gitCommitTimestamp||!i.gitCommitAuthorName||!i.gitCommitMessage||!i.gitCommitAuthorName)try{let l=await qi({logger:t,operation:"getRemoteMetadataFromGitHub.getCommitFromGithub",fn:()=>e.getCommitFromGithub(r,n,a),context:{owner:r,repo:n,gitCommitSha:a}});l&&(i={...i,gitCommitTimestamp:i.gitCommitTimestamp??l.committer.date,gitCommitAuthorName:i.gitCommitAuthorName??l.author.name,gitCommitMessage:i.gitCommitMessage??l.message});}catch(l){t.warn({err:l},"Failed to get commit from GitHub");}if(o.gitBranchName&&o.gitBranchName===o.gitMainBranch&&!i.mergedGitBranchName){let l=o.gitBranchName;try{let c=await qi({logger:t,operation:"getRemoteMetadataFromGitHub.getMergedBranchFromGithub",fn:()=>e.getMergedBranchFromGithub(r,n,l,a),context:{owner:r,repo:n,branchName:l,gitCommitSha:a}});c.mergedBranch&&(i={...i,mergedGitBranchName:c.mergedBranch});}catch(c){t.warn({err:c},"Failed to get merged branch from GitHub");}}return i}async function YEe(t,e,r){try{if(r.githubRepository){let{owner:n,repo:o}=m$(r.githubRepository);return await qi({logger:t,operation:"getRemoteMetadataIfNeeded.getRemoteMetadataFromGitHub",fn:()=>KEe(t,e,n,o,r),context:{githubRepository:r.githubRepository}})}else if(r.gitlabProjectPath){let n=r.gitlabProjectPath;return await qi({logger:t,operation:"getRemoteMetadataIfNeeded.getRemoteMetadataFromGitlab",fn:()=>qEe(t,e,n,r),context:{gitlabProjectPath:n}})}}catch(n){t.warn({err:n},"Failed to get remote git metadata");}return r}async function XEe(t,e,r,n){let o={},i={gitMainBranch:r.config.gitMainBranch};return qi({logger:t,operation:"getGitMetadata.total",fn:async()=>{let[a,s]=await Promise.all([qi({logger:t,operation:"getGitMetadata.getConfiguredGitMetadata",fn:()=>GEe(r),context:{projectConfigPath:r.configFilePath}}),qi({logger:t,operation:"getGitMetadata.getEnvironmentGitMetadata",fn:async()=>{let u=await ib(t,r.config.gitMainBranch,n);return i.ciProvider=u.ciProvider,u},context:i})]),l={...a,...s};o.gitBranchName=l.gitBranchName,o.githubRepository=l.githubRepository,o.gitlabProjectPath=l.gitlabProjectPath,(!l.lastCommitOnMainSha||!l.lastCommitOnMainTimestamp)&&l.gitBranchName===a.gitMainBranch&&(l.lastCommitOnMainSha=l.gitCommitSha,l.lastCommitOnMainTimestamp=l.gitCommitTimestamp);let c=await qi({logger:t,operation:"getGitMetadata.getRemoteMetadataIfNeeded",fn:()=>YEe(t,e,l),context:{githubRepository:l.githubRepository,gitlabProjectPath:l.gitlabProjectPath,gitBranchName:l.gitBranchName}});return {...a,...s,...c}},context:o})}async function HK(t){try{let e=await jK(t).remote(["show","origin"]);return e?e.match(/HEAD branch: (.*)$/m)?.[1]?.trim():void 0}catch{return}}var mO=new Map;async function JEe(t,e,r){let n,o;try{[n,o]=await Promise.all([$t(t,zt.raw(["symbolic-ref","--short","-q","HEAD"]).then(s=>s.trim())),$t(t,zt.revparse(["--verify","HEAD"]).then(s=>s.trim()))]);}catch{return}if(!n||!o)return;let i=`${e.configFilePath}:${e.config.gitMainBranch}:${e.config.gitProtectedBranches?.join(",")}`,a=`${r?.includeHostingUsername}`;return `${n}:${o}:${i}:${a}`}async function Sr(t,e,r,n){let o=await JEe(t,r,n);if(o&&mO.has(o))return t.debug("Using cached git metadata"),mO.get(o);let i=await XEe(t,e,r,n);return o&&mO.set(o,i),i}function eve(t,e){let r=`${ua(e)}.module.yaml`,n=fr__default.join(fr__default.dirname(t),r);if(Sn.existsSync(n))throw new Error(`A conflicting file already exists at the following path: ${n}`);return Sn.renameSync(t,n),n}function bs({content:t,schemaVersion:e,momenticFiles:r,project:n,forceSaveOnNoDiffs:o,forceFileFormat:i}){let a=r.mobileModules[t.moduleId]?.fullFilePath,s=r.mobileModules[t.moduleId]?.name;if(!a||!Sn.existsSync(a))throw new Error(`Tried to update mobile module ${t.moduleId} that could not be found on disk`);let{parsed:l}=Gi(a),c=n.config.fileFormat==="v2";i!==void 0&&(c=i==="v2");let u=!!t.name&&t.name!==s,d={...l,...t,schemaVersion:e},m=rs.parse(d),p=ha(t.platform).array().parse(t.steps),f=c?Jv({metadata:{...m,moduleId:t.moduleId,name:t.name??s??""},steps:p,fileResolver:Zu({sourceFilePath:a,momenticFiles:{mobileModules:r.mobileModules}})}):hn({fileType:Ce.MOBILE_MODULE,...m,steps:p}),h=diff(f,l);if(h&&Object.keys(h).length===0&&!o&&!u)return;Sn.writeFileSync(a,_g.stringify(f),"utf-8");let g=u?eve(a,t.name):void 0;sl(g??a,n.config);}function GK({moduleId:t,patch:e,momenticFiles:r,project:n,logger:o}){let i=r.mobileModules[t]?.fullFilePath;if(!i)throw new Error(`Tried to update mobile module ${t} that could not be found on disk`);let a=pc(i,o),s=fc({module:a,moduleFilePath:i,momenticFiles:r}),l=tP.parse({...s,...e}),c={moduleId:l.moduleId,platform:l.platform,name:e.name??s.name,description:l.description,enabled:l.enabled,parameters:l.parameters,steps:ha(l.platform).array().parse(l.steps)};bs({content:c,schemaVersion:l.schemaVersion,momenticFiles:r,project:n});}async function sb({name:t,description:e,enabled:r,platform:n,steps:o,folder:i,project:a,momenticFiles:s}){let l=ua(t),c=fr__default.join(i,`${l}.module.yaml`);Qv({project:a,relativeFilePath:fr__default.relative(a.rootDir,c)});let u=bp({projectConfig:a.config,momenticFiles:s,entityType:"mobile-module"}),{stepsToSave:{steps:d}}=await An({platform:n,stepLists:{steps:o}}),m={schemaVersion:US,platform:n,moduleId:u,description:e,enabled:r},p=a.config.fileFormat==="v2"?Jv({metadata:{...m,moduleId:u,name:t},steps:d,fileResolver:Zu({sourceFilePath:c,momenticFiles:{mobileModules:s.mobileModules}})}):rP.parse({fileType:Ce.MOBILE_MODULE,...m,steps:d});return Sn.mkdirSync(i,{recursive:true}),Sn.writeFileSync(c,_g.stringify(p),"utf-8"),sl(c,a.config),{moduleId:u,platform:n,name:t,description:e||void 0,steps:o}}function pc(t,e){let{parsed:r}=Gi(t);if(Qg(r))try{return eE.parse(r)}catch(n){throw e.error({err:n,moduleFilePath:t,existingModule:r},`${t} does not parse as a valid V2 Momentic mobile module`),n}try{return rP.parse(r)}catch(n){throw e.error({err:n,moduleFilePath:t,existingModule:r},`${t} does not parse as a valid Momentic mobile module`),n}}function fc({module:t,moduleFilePath:e,momenticFiles:r}){let n=fr__default.basename(e,".module.yaml");if(!Qg(t))return {...t,name:n};let{module:o}=Xv({moduleV2:t,moduleName:n,fileResolver:Qu({sourceFilePath:e,momenticFiles:r})});return o}async function nd(t,e,r,n){let o=pc(t.fullFilePath,r),i=fc({module:o,moduleFilePath:t.fullFilePath,momenticFiles:e}),a=i.platform==="ANDROID"?n?.android:n?.ios,{resolvedSteps:s}=await vv({platform:i.platform,rawSteps:i.steps,resolvedModuleCache:a||{},onFetchModule:async c=>{let u=e.mobileModules[c]?.fullFilePath;if(!u)throw new Error(`Could not find mobile module with id ${c}`);let d=pc(u,r);return fc({module:d,moduleFilePath:u,momenticFiles:e})},logger:r,metadata:{id:i.moduleId,schemaVersion:i.schemaVersion}}),l=i.platform==="ANDROID"?{...i,platform:"ANDROID",name:t.name,description:i.description||void 0,steps:s}:{...i,platform:"IOS",name:t.name,description:i.description||void 0,steps:s};return a&&(a[t.id]=cloneDeep(l)),l}async function qK(t,e){let r={},n={};return await Promise.all(Object.values(t.mobileModules).map(async o=>{await nd(o,t,e,{ios:r,android:n});})),[...Object.values(r),...Object.values(n)]}var Sp=hT.array(),tC=C__default.discriminatedUnion("platform",[OT.extend({beforeSteps:Sp.optional(),steps:Sp,afterSteps:Sp.optional()}),DT.extend({beforeSteps:Sp.optional(),steps:Sp,afterSteps:Sp.optional()})]);function rC({name:t,description:e="",settings:r,folder:n,platform:o,project:i,momenticFiles:a}){try{_i(t);}catch(p){throw new ar(`${p} when validating the test entity name`)}let l=`${ua(t)}.test.yaml`,c=fr__default.join(n,l);if(Sn.existsSync(c))throw new gh({name:t,path:c});Qv({project:i,relativeFilePath:fr__default.relative(i.rootDir,c)});let u=bp({projectConfig:i.config,momenticFiles:a,entityType:"mobile-test"}),d={fileType:Ce.MOBILE_TEST,id:u,description:e,schemaVersion:dn,platform:o,settings:r,steps:[]},m=i.config.fileFormat==="v2"?hp({metadata:d,stepLists:{steps:[]},fileResolver:Zu({sourceFilePath:c,momenticFiles:{mobileModules:a.mobileModules}})}):zz.parse(d);return Sn.mkdirSync(n,{recursive:true}),Sn.writeFileSync(c,_g.stringify(m),"utf-8"),{fullPath:c,testId:u}}function tve(t){if(!Sn.existsSync(t))throw new Error(`Test file not found: ${t}`);let{parsed:e}=Gi(t);if(Zg(e))return e;if(!e.steps||!Array.isArray(e.steps))throw new Error(`Test ${t} is missing steps`);return e}async function dr(t,e,r){let n=tve(t),o,i;if(Zg(n)){let s;try{s=Xl.parse(n);}catch(c){let u=c instanceof C__default.ZodError?C__default.prettifyError(c):W(c);throw new ar(`Mobile test ${t} is missing metadata or has invalid metadata: ${u}`,{cause:c})}o=eb({testV2:s});let l=await Yv({testV2:s,platform:o.platform,fileResolver:Qu({sourceFilePath:t,momenticFiles:{mobileModules:r.mobileModules}})});i={steps:l.stepLists.steps,beforeSteps:l.stepLists.beforeSteps,afterSteps:l.stepLists.afterSteps};}else {try{o=Gl.parse(n);}catch(s){let l=s instanceof C__default.ZodError?C__default.prettifyError(s):W(s);throw new ar(`Mobile test ${t} is missing metadata or has invalid metadata: ${l}`,{cause:s})}i={steps:n.steps,beforeSteps:n.beforeSteps,afterSteps:n.afterSteps};}let a={rawStepLists:i,logger:e,testMetadata:o,onFetchModule:async s=>{let l=r.mobileModules[s]?.fullFilePath;if(!l)throw new Error(`Mobile module ${s} not found`);let c=pc(l,e);return fc({module:c,moduleFilePath:l,momenticFiles:r})}};switch(o.platform){case "ANDROID":{let{resolvedStepLists:s}=await F_({...a,platform:o.platform});return {...o,steps:s.steps,...s.beforeSteps?.length&&{beforeSteps:s.beforeSteps},...s.afterSteps?.length&&{afterSteps:s.afterSteps}}}case "IOS":{let{resolvedStepLists:s}=await F_({...a,platform:o.platform});return {...o,steps:s.steps,...s.beforeSteps?.length&&{beforeSteps:s.beforeSteps},...s.afterSteps?.length&&{afterSteps:s.afterSteps}}}}}async function cl({platform:t,filePath:e,steps:r,beforeSteps:n,afterSteps:o,settings:i,labels:a,folder:s,project:l,momenticFiles:c,schemaVersion:u,forceFileFormat:d}){let m=fr__default.isAbsolute(e)?e:fr__default.join(s,e);if(!Sn.existsSync(m))throw new Error(`Test file not found: ${m}`);let{parsed:p}=Gi(m),f=Zg(p),h,g;if(f?(g=Xl.parse(p),h={...eb({testV2:g}),schemaVersion:u,fileType:Ce.MOBILE_TEST,steps:[]}):h=tC.parse({...p,schemaVersion:u}),h.fileType!==Ce.MOBILE_TEST)throw new Error(`File at '${m}' is not a mobile test (fileType=${h.fileType}).`);if(h.platform!==t)throw new Error(`Platform mismatch. Test at '${m}' is for platform ${h.platform}, but update is for platform ${t}.`);let y=r||n||o,S=y?await An({platform:t,stepLists:{steps:r??[],beforeSteps:n,afterSteps:o}}):void 0,E=S?.moduleUpdates??[],v;f&&g&&!y&&(v={steps:g.steps??[],before:g.before,after:g.after});let w=l.config.fileFormat==="v2"||f;d!==void 0&&(w=d==="v2");for(let I of E)bs({content:I,schemaVersion:dn,momenticFiles:c,project:l,forceFileFormat:d});if(w){let I={...h};a!==void 0&&(I.labels=a),i!==void 0&&(I.settings=i);let R={...I,steps:[]},k;if(y&&S){let D;S.stepsToSave.beforeSteps&&S.stepsToSave.beforeSteps.length>0&&(D=S.stepsToSave.beforeSteps);let V;S.stepsToSave.afterSteps&&S.stepsToSave.afterSteps.length>0&&(V=S.stepsToSave.afterSteps),k={steps:S.stepsToSave.steps,beforeSteps:D,afterSteps:V};let $=Zu({sourceFilePath:m,momenticFiles:{mobileModules:c.mobileModules}}),U=hp({metadata:R,stepLists:k,fileResolver:$});Sn.writeFileSync(m,_g.stringify(U),"utf-8");}else {let D=hp({metadata:R,stepLists:{steps:[]},fileResolver:Zu({sourceFilePath:m,momenticFiles:{mobileModules:c.mobileModules}})}),V=YK({formatted:D,stepLists:v??{steps:[]}});Sn.writeFileSync(m,V,"utf-8");}sl(m,l.config);return}let _={...h,steps:h.steps};if(r&&(_.steps=S?.stepsToSave.steps??[]),a!==void 0&&(_.labels=a),n){let I=S?.stepsToSave.beforeSteps;I&&I.length>0?_.beforeSteps=I:delete _.beforeSteps;}else h.beforeSteps&&h.beforeSteps.length>0&&(_.beforeSteps=h.beforeSteps);if(o){let I=S?.stepsToSave.afterSteps;I&&I.length>0?_.afterSteps=I:delete _.afterSteps;}else h.afterSteps&&h.afterSteps.length>0&&(_.afterSteps=h.afterSteps);i&&(_.settings=i);let L=_g.stringify(tC.parse(_));Sn.writeFileSync(m,L,"utf-8"),sl(m,l.config);}function KK(t,e,r){let n=fr__default.join(r.rootDir,t);if(!Sn.existsSync(n))throw new Xe(`Test not found at path '${t}' in project '${r.rootDir}'`);let{parsed:o}=Gi(n),i=Zg(o),a=fr__default.basename(t,".test.yaml"),s,l;if(e.name&&e.name!==a){let u=`${ua(e.name)}.test.yaml`;if(s=fr__default.join(fr__default.dirname(t),u),l=fr__default.join(r.rootDir,s),Sn.existsSync(l))throw new gh({name:e.name,path:l})}let c=i?rve({existingTestRaw:o,updates:e}):nve({existingTestRaw:o,updates:e});return Sn.writeFileSync(n,c,"utf-8"),l&&l!==n?(Sn.renameSync(n,l),sl(l,r.config)):sl(n,r.config),{newRelativeTestPath:s}}function rve({existingTestRaw:t,updates:e}){let r=Xl.parse(t),n=eb({testV2:r}),o={...n,description:e.description??n.description,disabled:e.disabled??n.disabled,labels:e.labels??n.labels,settings:e.settings??n.settings,fileType:Ce.MOBILE_TEST,steps:[]};return YK({formatted:hp({metadata:o,stepLists:{steps:[]}}),stepLists:{before:r.before,steps:r.steps??[],after:r.after}})}function YK({formatted:t,stepLists:e}){let{steps:r,...n}=t,o=e.before;o&&o.length===0&&(o=void 0);let i=e.after;i&&i.length===0&&(i=void 0);let a=hn({...n,before:o,steps:e.steps,after:i});return _g.stringify(a)}function nve({existingTestRaw:t,updates:e}){let n={...tC.parse(t),...e};if(n.fileType!==Ce.MOBILE_TEST)throw new Error(`Existing legacy mobile test has unexpected fileType=${n.fileType}.`);return _g.stringify(tC.parse(n))}var XK=new Set([".DS_Store","__MACOSX"]),JK={status:(t,e)=>{if(t.status===e.status)return t.status;if(t.status==="FAILED"||e.status==="FAILED")return "FAILED";if(t.status==="CANCELLED"||e.status==="CANCELLED")return "CANCELLED";if(t.status==="RETRYING"||e.status==="RETRYING")return "RETRYING";if(t.status==="RUNNING"||e.status==="RUNNING")return "RUNNING";if(t.status==="PENDING"||e.status==="PENDING")return "PENDING";throw new Error(`Invalid run status merge: ${t.status} and ${e.status}`)},startedAt:(t,e)=>t.startedAt<e.startedAt?t.startedAt:e.startedAt,updatedAt:(t,e)=>t.updatedAt>e.updatedAt?t.updatedAt:e.updatedAt,finishedAt:(t,e)=>!t.finishedAt||!e.finishedAt?new Date:t.finishedAt>e.finishedAt?t.finishedAt:e.finishedAt,gitCommitTimestamp:(t,e)=>{if(!(!t&&!e)){if(!t.gitCommitTimestamp||!e.gitCommitTimestamp||t.gitCommitTimestamp.getTime()!==e.gitCommitTimestamp.getTime())throw new Error(`Git commit timestamps must match to be merged: ${t.gitCommitTimestamp} and ${e.gitCommitTimestamp}`);return t.gitCommitTimestamp}},pipelineId:(t,e)=>t.pipelineId===e.pipelineId?t.pipelineId:!t.pipelineId&&e.pipelineId?e.pipelineId:!e.pipelineId&&t.pipelineId?t.pipelineId:t.startedAt<e.startedAt?e.pipelineId:t.pipelineId,labels:(t,e)=>{let r=new Set([...t.labels??[],...e.labels??[]]);return Array.from(r)},ai:(t,e)=>t.ai??e.ai,browser:(t,e)=>t.browser??e.browser,aiSelect:(t,e)=>{let r=[...t.aiSelect??[],...e.aiSelect??[]];return r.length>0?r:void 0},healRiskSummary:()=>{}};function ive(t,e,r){if(JK[r]){let i=JK[r];return i(t,e)}let n=t[r],o=e[r];if(n===void 0)return o;if(o===void 0)return n;if(n!==o)throw new Error(`Metadata values for key "${r}" do not match: "${n}" vs "${o}"`);return n}var pO=class extends Error{constructor(e,r){let n=`${e} contains invalid Momentic results: ${r}. Please ensure that the path points to a folder containing only valid results. If you passed \`--output-dir test-results/results-1\` to the \`run\` command, your results path for merging should be \`test-results\`.`;super(n),this.name="InvalidMomenticResultsPathError";}};function ZK(t,e){try{let r=fr__default.join(e,fn);return jm.parse(JSON.parse(Sn.readFileSync(r,"utf-8")))}catch{throw new pO(t,e)}}function QK(t,e,r){let n=randomUUID(),o=t.child({runGroupId:n});Sn.rmSync(e,{recursive:true,force:true});let i=Sn.readdirSync(r).filter(l=>!XK.has(l)).map(l=>fr__default.join(r,l));if(i.length===0)throw new Error(`No run groups found in results path: ${r}`);Sn.mkdirSync(e,{recursive:true});let a={...ZK(r,i[0]),id:n,healRiskSummary:void 0,aiSelect:void 0};for(let l of i){let c=fr__default.join(l,vo);if(!Sn.existsSync(c))continue;let u=ZK(r,l);o.info({oldRunGroupId:u.id},"Merging run groups");for(let m in u){if(m==="id")continue;let p=m;a[p]=ive(a,u,p);}let d=Sn.readdirSync(c);for(let m of d){if(XK.has(m))continue;let p=fr__default.join(c,m),f=fr__default.join(e,vo,m);Sn.cpSync(p,f,{recursive:true});}}let s=fr__default.join(e,fn);Sn.writeFileSync(s,JSON.stringify(a,null,2));}var X="v1",fO="mobile-cli",od="1.0.2";var ave=9e4,sve=3,lve=1500,cve=15e3,Pr=class extends Error{status;rawError;constructor(e,r,n,o={}){super(n,o),this.status=e,this.rawError=r;}},hO=class extends Xe{constructor(e,r={}){super(e,r),this.name="PlanLimitExceededError";}};async function uve(t){return t.text().then(e=>{try{return JSON.parse(e).error}catch{return e}})}var gO=class{baseUrl;logger;constructor(e){this.baseUrl=e.baseUrl,this.logger=e.logger;}getHeaders(){let e={"Content-Type":"application/json"};return (e[tE]=od),(e[lj]=fO),e}async sendRequest(e,r){let{retries:n=sve,requestTimeoutMs:o=ave,initialRetryDelayMs:i=lve,maxRetryDelayMs:a=cve,onFailedRequest:s}=r,l=n,c=n,u,d={path:e,baseUrl:this.baseUrl,method:r.method};for(;l>0;)try{return l--,await this.sendSingleRequestWithOTEL(e,r,o)}catch(m){u=m;try{s?.(u);}catch{}if(m instanceof Pr&&m.status>=400&&m.status<500)throw m.status===402?new hO(m.rawError,{cause:m}):m;if(m instanceof Error&&m.name==="AbortError"&&(u=new Zl),l===0)throw u;let p=c-l,f=Math.min(i*Math.pow(2,p-1),a);await new Promise(h=>setTimeout(h,f));}throw this.logger.warn({...d,err:u},"Got fatal error response from Momentic server"),u}async sendSingleRequestWithOTEL(e,r,n){let o=dve(e);return Ne({name:`cli.api.${r.method.toLowerCase()}.${o}`,serviceName:"api-server",attributes:{"http.request.method":r.method,"url.path":o},fn:i=>this.sendSingleRequestHelper(e,r,n,a=>{i?.setAttribute("http.response.status_code",a);})})}async sendSingleRequestHelper(e,r,n,o){let i={path:e,baseUrl:this.baseUrl,method:r.method},a=new AbortController,s=setTimeout(()=>a.abort(),n),l=()=>a.abort();r.signal&&r.signal.addEventListener("abort",l,{once:true});let c=Date.now(),u={...this.getHeaders(),...r.extraHeaders};try{let d=await fetch(`${this.baseUrl}${e}`,{method:r.method,body:r.body?JSON.stringify(r.body):void 0,headers:u,signal:a.signal});if(o?.(d.status),!d.ok){let f=await uve(d);throw new Pr(d.status,f,`Request to ${r.method} ${e} failed with status ${d.status}: ${f}`)}let m;if(d.status===204)m={};else if(r.responseType==="buffer"){let f=await d.arrayBuffer();m=Buffer.from(f);}else {let f=await d.text();try{m=JSON.parse(f);}catch{m=f;}}this.logger&&r.logResponse===!0&&m&&this.logger.debug({result:m,status:d.status,durationMs:Date.now()-c,...i},"Got response from Momentic server");let p=r.responseHeadersObject;return p&&d.headers.forEach((f,h)=>{p[h.toLowerCase()]=f;}),m}finally{clearTimeout(s),r.signal&&r.signal.removeEventListener("abort",l);}}};function dve(t){return (t.split("?")[0]??t).replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,":id")}var ys=class extends gO{apiKey;mode;runner;constructor(e){super(e),this.apiKey=e.apiKey,this.mode=e.mode,this.runner=e.runner;}getHeaders(){return {...super.getHeaders(),Authorization:`Bearer ${this.apiKey}`,[aj]:this.mode??""}}};var M4="vercel.ai.error",mve=Symbol.for(M4),e4,t4,qt=class P4 extends(t4=Error,e4=mve,t4){constructor({name:e,message:r,cause:n}){super(r),this[e4]=true,this.name=e,this.cause=n;}static isInstance(e){return P4.hasMarker(e,M4)}static hasMarker(e,r){let n=Symbol.for(r);return e!=null&&typeof e=="object"&&n in e&&typeof e[n]=="boolean"&&e[n]===true}},I4="AI_APICallError",_4=`vercel.ai.error.${I4}`,pve=Symbol.for(_4),r4,n4,kn=class extends(n4=qt,r4=pve,n4){constructor({message:t,url:e,requestBodyValues:r,statusCode:n,responseHeaders:o,responseBody:i,cause:a,isRetryable:s=n!=null&&(n===408||n===409||n===429||n>=500),data:l}){super({name:I4,message:t,cause:a}),this[r4]=true,this.url=e,this.requestBodyValues=r,this.statusCode=n,this.responseHeaders=o,this.responseBody=i,this.isRetryable=s,this.data=l;}static isInstance(t){return qt.hasMarker(t,_4)}},O4="AI_EmptyResponseBodyError",D4=`vercel.ai.error.${O4}`,fve=Symbol.for(D4),o4,i4,L4=class extends(i4=qt,o4=fve,i4){constructor({message:t="Empty response body"}={}){super({name:O4,message:t}),this[o4]=true;}static isInstance(t){return qt.hasMarker(t,D4)}};function N4(t){return t==null?"unknown error":typeof t=="string"?t:t instanceof Error?t.message:JSON.stringify(t)}var k4="AI_InvalidArgumentError",F4=`vercel.ai.error.${k4}`,hve=Symbol.for(F4),a4,s4,nC=class extends(s4=qt,a4=hve,s4){constructor({message:t,cause:e,argument:r}){super({name:k4,message:t,cause:e}),this[a4]=true,this.argument=r;}static isInstance(t){return qt.hasMarker(t,F4)}},B4="AI_InvalidPromptError",U4=`vercel.ai.error.${B4}`,gve=Symbol.for(U4),l4,c4,z4=class extends(c4=qt,l4=gve,c4){constructor({prompt:t,message:e,cause:r}){super({name:B4,message:`Invalid prompt: ${e}`,cause:r}),this[l4]=true,this.prompt=t;}static isInstance(t){return qt.hasMarker(t,U4)}},$4="AI_InvalidResponseDataError",V4=`vercel.ai.error.${$4}`,bve=Symbol.for(V4),u4,d4,oC=class extends(d4=qt,u4=bve,d4){constructor({data:t,message:e=`Invalid response data: ${JSON.stringify(t)}.`}){super({name:$4,message:e}),this[u4]=true,this.data=t;}static isInstance(t){return qt.hasMarker(t,V4)}},j4="AI_JSONParseError",H4=`vercel.ai.error.${j4}`,yve=Symbol.for(H4),m4,p4,ub=class extends(p4=qt,m4=yve,p4){constructor({text:t,cause:e}){super({name:j4,message:`JSON parsing failed: Text: ${t}.
|
|
219
219
|
Error message: ${N4(e)}`,cause:e}),this[m4]=true,this.text=t;}static isInstance(t){return qt.hasMarker(t,H4)}},W4="AI_LoadAPIKeyError",G4=`vercel.ai.error.${W4}`,Sve=Symbol.for(G4),f4,h4,db=class extends(h4=qt,f4=Sve,h4){constructor({message:t}){super({name:W4,message:t}),this[f4]=true;}static isInstance(t){return qt.hasMarker(t,G4)}},Q4="AI_TooManyEmbeddingValuesForCallError",e5=`vercel.ai.error.${Q4}`,Cve=Symbol.for(e5),v4,C4,t5=class extends(C4=qt,v4=Cve,C4){constructor(t){super({name:Q4,message:`Too many values for a single embedding call. The ${t.provider} model "${t.modelId}" can only embed up to ${t.maxEmbeddingsPerCall} values per call, but ${t.values.length} values were provided.`}),this[v4]=true,this.provider=t.provider,this.modelId=t.modelId,this.maxEmbeddingsPerCall=t.maxEmbeddingsPerCall,this.values=t.values;}static isInstance(t){return qt.hasMarker(t,e5)}},r5="AI_TypeValidationError",n5=`vercel.ai.error.${r5}`,wve=Symbol.for(n5),w4,A4,gc=class bO extends(A4=qt,w4=wve,A4){constructor({value:e,cause:r,context:n}){let o="Type validation failed";if(n?.field&&(o+=` for ${n.field}`),n?.entityName||n?.entityId){o+=" (";let i=[];n.entityName&&i.push(n.entityName),n.entityId&&i.push(`id: "${n.entityId}"`),o+=i.join(", "),o+=")";}super({name:r5,message:`${o}: Value: ${JSON.stringify(e)}.
|
|
220
220
|
Error message: ${N4(r)}`,cause:r}),this[w4]=true,this.value=e,this.context=n;}static isInstance(e){return qt.hasMarker(e,n5)}static wrap({value:e,cause:r,context:n}){var o,i,a;return bO.isInstance(r)&&r.value===e&&((o=r.context)==null?void 0:o.field)===n?.field&&((i=r.context)==null?void 0:i.entityName)===n?.entityName&&((a=r.context)==null?void 0:a.entityId)===n?.entityId?r:new bO({value:e,cause:r,context:n})}},o5="AI_UnsupportedFunctionalityError",i5=`vercel.ai.error.${o5}`,Ave=Symbol.for(i5),R4,x4,zo=class extends(x4=qt,R4=Ave,x4){constructor({functionality:t,message:e=`'${t}' functionality not supported.`}){super({name:o5,message:e}),this[R4]=true,this.functionality=t;}static isInstance(t){return qt.hasMarker(t,i5)}};var iC=class extends Error{constructor(e,r){super(e),this.name="ParseError",this.type=r.type,this.field=r.field,this.value=r.value,this.line=r.line;}};function yO(t){}function a5(t){if(typeof t=="function")throw new TypeError("`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?");let{onEvent:e=yO,onError:r=yO,onRetry:n=yO,onComment:o}=t,i="",a=true,s,l="",c="";function u(h){let g=a?h.replace(/^\xEF\xBB\xBF/,""):h,[y,S]=Rve(`${i}${g}`);for(let E of y)d(E);i=S,a=false;}function d(h){if(h===""){p();return}if(h.startsWith(":")){o&&o(h.slice(h.startsWith(": ")?2:1));return}let g=h.indexOf(":");if(g!==-1){let y=h.slice(0,g),S=h[g+1]===" "?2:1,E=h.slice(g+S);m(y,E,h);return}m(h,"",h);}function m(h,g,y){switch(h){case "event":c=g;break;case "data":l=`${l}${g}
|
|
221
221
|
`;break;case "id":s=g.includes("\0")?void 0:g;break;case "retry":/^\d+$/.test(g)?n(parseInt(g,10)):r(new iC(`Invalid \`retry\` value: "${g}"`,{type:"invalid-retry",value:g,line:y}));break;default:r(new iC(`Unknown field "${h.length>20?`${h.slice(0,20)}\u2026`:h}"`,{type:"unknown-field",field:h,value:g,line:y}));break}}function p(){l.length>0&&e({id:s,event:c||void 0,data:l.endsWith(`
|
|
@@ -264,7 +264,7 @@ ${n}
|
|
|
264
264
|
`);}catch(r){t.logger.warn({err:r},"Failed to check CLI version against npm");}}async function NRe(t,e,r){if(!V9){V9=true;try{let n=await t.getCliAnnouncements();for(let{announcement:o,level:i}of n)P.log(`
|
|
265
265
|
${B9({announcement:o,level:i},r)}
|
|
266
266
|
`);}catch(n){e.warn({err:n},"Failed to fetch CLI announcements");}}}var xp=25;function W9(t){return {v2ProjectConfig:{...t.config,fileFormat:"v2"},migratedFilePaths:[]}}function G9(t){return {legacyProjectConfig:{...t.config,fileFormat:"v1"},migratedFilePaths:[]}}function QO({project:t,newProjectConfig:e,fileFormatLabel:r,migratedFilePaths:n}){t.config=e,rd(t.config,t.configFilePath),n.push(t.configFilePath),P.info(`Updated ${t.configFilePath} to use ${r} file format`),e.hooks?.postSave&&(P.info(`Running post-save hook for ${n.length} migrated files`),DK([...new Set(n)],e));}async function Mp(t,e,r){for(let n=0;n<t.length;n+=e)await Promise.all(t.slice(n,n+e).map(r));}function eD(t){return t.upgradedAgents.length>0||t.enabledUseMemory||t.enabledFailureRecovery}function kRe(t){let e=t.ai??={},r=e.agentConfig??={},n=[];for(let[a,s]of Object.entries(im)){let l=r[a];l!==s&&(l?.startsWith(`${s}.`)||(r[a]=s,n.push({type:a,newValue:s})));}let o=e.useMemory!==true;o&&(e.useMemory=true);let i=e.failureRecovery!==true;return i&&(e.failureRecovery=true),{upgradedAgents:n,enabledUseMemory:o,enabledFailureRecovery:i}}async function q9({project:t,dryRun:e,migrate:r}){let n=t.config.fileFormat!=="v2",o=kRe(t.config);return n?{fileFormatChanged:n,aiSettings:o,migration:await r()}:(!e&&eD(o)&&rd(t.config,t.configFilePath),{fileFormatChanged:false,aiSettings:o,migration:tD()})}function tD(){return {migratedTestPaths:[],migratedModulePaths:[],alreadyV2TestCount:0,alreadyV2ModuleCount:0}}function rD({summary:t,fileFormatChanged:e,aiSettings:r,dryRun:n,testNoun:o="test",moduleNoun:i="module"}){let a=n?"Would migrate":"Migrated",s=Hu(o,t.migratedTestPaths.length),l=Hu(i,t.migratedModulePaths.length);P.info(`${a} ${t.migratedTestPaths.length} ${s} and ${t.migratedModulePaths.length} ${l} to v2.`),(t.alreadyV2TestCount>0||t.alreadyV2ModuleCount>0)&&P.dimmed(` Skipped ${t.alreadyV2TestCount} already-v2 ${Hu(o,t.alreadyV2TestCount)} and ${t.alreadyV2ModuleCount} already-v2 ${Hu(i,t.alreadyV2ModuleCount)}.`),e&&P.dimmed(" + fileFormat: v2");for(let c of r.upgradedAgents)P.dimmed(` + ai.agentConfig.${c.type}: ${c.newValue}`);r.enabledUseMemory&&P.dimmed(" + ai.useMemory: true"),r.enabledFailureRecovery&&P.dimmed(" + ai.failureRecovery: true");}var zRe=C__default.string().url();async function xC(t){if(zRe.safeParse(t).success){let e=new AbortController,r=setTimeout(()=>e.abort(),1e4),n;try{n=await fetch(t,{signal:e.signal});}catch(i){throw new M("UserInfrastructureError",`Fetch failed or timed out for URL: ${t}`,{errOptions:{cause:i}})}finally{clearTimeout(r);}if(!n.ok)throw new M("UserInfrastructureError",`Failed to fetch file from URL: ${t}, status: ${n.status}`);let o=await n.arrayBuffer();return Buffer.from(o).toString("base64")}if(!existsSync(t))throw new M("UserInfrastructureError",`File does not exist at path: ${t}`);return readFileSync(t).toString("base64")}var K9=1e3,Y9=5e6,VRe=5*1024*1024;function nD(t,e){for(let r=0;r<t.length;r++){let n=t[r];if(n.type==="MOBILE_PRESET_STEP"&&n.command.type==="VISUAL_DIFF")jRe(n);else try{if(n.data){let{jsonString:o}=Z9(JSON.stringify(n.data),1e3);n.data=JSON.parse(o);}}catch(o){e.error({err:o},"Failed to serialize individual result output data"),n.data=`Result output data could not be serialized: ${o}`;}switch(n.type){case "MOBILE_PRESET_STEP":X9(n);break;case "MOBILE_AI_ACTION_STEP":case "MOBILE_MODULE_STEP":nD(n.steps,e);break;case "MOBILE_CONDITIONAL_STEP":n.assertionResult&&X9(n.assertionResult),nD(n.steps,e);break;default:{throw new Error("If Typescript complains about the line below, you missed a case or break in the switch above")}}}}function X9(t){let e=t.command;"cache"in e&&e.cache&&(e.cache=void 0);}function jRe(t){let e=$M.safeParse(t.data);if(!e.success)return;let r=e.data;t.data={created:r.created,goldenPath:r.goldenPath,threshold:r.threshold,goldenScreenshotSnapshotId:r.goldenScreenshotSnapshotId,currentScreenshotSnapshotId:r.currentScreenshotSnapshotId,diffScreenshotSnapshotId:r.diffScreenshotSnapshotId,diffPercent:r.diffPercent,pass:r.pass,dimensionMismatch:r.dimensionMismatch};}function J9(t,e){let r=JSON.stringify(t),n=r.replaceAll("\\u0000","");if(r.length!==n.length){let o=r.indexOf("\\u0000");e.warn({input:r.slice(Math.max(0,o-500),Math.min(r.length,o+500))},"Database content violation: stripped unicode character from input");}return n}function MC(t,e,r){let n=cloneDeep(t);if(nD(n,r),n.length>K9)return r.error("Database content violation: results too long, truncating before insertion"),n.slice(0,K9);let o=J9(n,r);if(o.length>Y9)for(r.error({serializedLength:o.length,resultsArrayLength:n.length},"Database content violation: results too large, truncating before insertion");o.length>Y9;)n.pop(),o=J9(n,r);let{jsonString:i}=Z9(o,VRe);try{return e.array().parse(JSON.parse(i))}catch(a){throw r.error({serialized:o,err:a},"Could not parse serialized results into JSON structure after processing"),a}}function wc(t,e,r=.01){let n=Buffer.from(t,"base64"),o=Buffer.from(e,"base64"),i=PNG.sync.read(n),a=PNG.sync.read(o);if(i.width!==a.width||i.height!==a.height)return 100;let s=i.width,l=i.height,c=Buffer.alloc(s*l*4);return Q9(i.data,a.data,c,s,l,{threshold:r})/(s*l)*100}function e8(t,e,r){let n=PNG.sync.read(Buffer.from(t,"base64")),o=PNG.sync.read(Buffer.from(e,"base64")),i={width:n.width,height:n.height},a={width:o.width,height:o.height};if(n.width!==o.width||n.height!==o.height)return {diffPercent:100,diffPngBase64:"",dimensionMismatch:true,goldenDimensions:i,currentDimensions:a};let s=n.width,l=n.height,c=new PNG({width:s,height:l});return {diffPercent:Q9(n.data,o.data,c.data,s,l,{threshold:r,diffColorAlt:[0,255,0]})/(s*l)*100,diffPngBase64:PNG.sync.write(c).toString("base64"),dimensionMismatch:false,goldenDimensions:i,currentDimensions:a}}var vs=class{baseDir;updateGoldenFiles;constructor({baseDir:e,updateGoldenFiles:r}){this.baseDir=e,this.updateGoldenFiles=r;}resolveGoldenPath(e){return fr__default.isAbsolute(e)?e:fr__default.join(this.baseDir,e)}compareOrCreate({goldenPath:e,currentScreenshotBase64:r,pixelThreshold:n,updateGoldenFiles:o,logger:i}){let a=this.resolveGoldenPath(e),s=Sn.existsSync(a),l=o??this.updateGoldenFiles;if(!s||l)return Sn.mkdirSync(fr__default.dirname(a),{recursive:true}),Sn.writeFileSync(a,Buffer.from(r,"base64")),i.info({goldenPath:a,updated:s},s?"Updated golden screenshot":"Created golden screenshot"),{created:true,goldenScreenshotBase64:r};let c=Sn.readFileSync(a).toString("base64"),u=e8(c,r,n);return {created:false,goldenScreenshotBase64:c,diffScreenshotBase64:u.diffPngBase64,diffPercent:u.diffPercent,dimensionMismatch:u.dimensionMismatch,goldenDimensions:u.goldenDimensions,currentDimensions:u.currentDimensions}}};var t8=1e4,r8=2e4,qRe=250,KRe=5e3,YRe=2e3,XRe=[/dbug Appium Creating hash file directory/];function JRe(t){return XRe.some(e=>e.test(t))}var ZRe=createRequire(import.meta.url),QRe=ZRe.resolve("appium/build/lib/main.js");function exe(t){let e=(t??"").toLowerCase();return {deviceOffline:e.includes("device offline"),instrumentationCrashed:e.includes("instrumentation process has been unexpectedly terminated"),uiAutomatorCrashed:e.includes("uiautomator2")&&(e.includes("instrumentation")||e.includes("not running")||e.includes("socket hang up")),nodeVersionUnsupported:e.includes("node version must be at least")}}function txe(t,e){let r=`Appium subprocess exited before becoming ready with exit code ${t}`;if(e.nodeVersionUnsupported)return `${r}. The current Node.js version is not supported by Appium; see the Appium log for the required version range.`;let n=e.lastError??e.lastWarn;return n?`${r}. Appium reported: ${n}`:r}async function iD(t){try{let e=await fetch(`http://localhost:${t}/status`,{method:"GET",signal:AbortSignal.timeout(KRe)}),r=await e.text();return {ok:!0,statusCode:e.status,body:r}}catch(e){return {ok:false,error:W(e)}}}async function rxe({appiumPort:t,child:e,appiumLogHints:r,waitForOutputFlush:n}){let o=Date.now();for(;Date.now()-o<r8;){if(e.exitCode!==null)throw await n(),new Error(txe(e.exitCode,r));if((await iD(t)).ok)return;await new Promise(a=>setTimeout(a,qRe));}throw new Error(`Timed out waiting for Appium to become ready after ${r8}ms`)}async function n8({child:t,logger:e}){t.exitCode!==null||t.killed||(t.kill("SIGTERM"),await ee(new Promise(r=>{t.once("exit",()=>r());}),{milliseconds:t8,fallback:()=>{e.warn({timeoutMs:t8},"Appium subprocess close timed out; sending SIGKILL"),t.kill("SIGKILL");}}));}function o8(t,e,r,n){let o=createInterface({input:t,terminal:false}),i=[],a=l=>{let c=exe(l);n.deviceOffline||=c.deviceOffline,n.instrumentationCrashed||=c.instrumentationCrashed,n.uiAutomatorCrashed||=c.uiAutomatorCrashed,n.nodeVersionUnsupported||=c.nodeVersionUnsupported;},s=()=>{if(i.length===0)return;let l=i.join(`
|
|
267
|
-
`);a(l),r==="warn"&&(n.lastWarn=l),e[r]({appium:true,logLine:l},"Appium log"),i.length=0;};return o.on("line",l=>{if(!l.trim()||JRe(l))return;let c;try{c=JSON.parse(l);}catch{}if(c!==void 0){s(),a(l);let u=c.level,d=c.message;typeof d=="string"&&(u==="error"?n.lastError=d:u==="warn"&&(n.lastWarn=d)),e[r]({appium:true,parsed:c},"Appium log");}else !/^\s/.test(l)&&i.length>0&&s(),i.push(l);}),new Promise(l=>{o.on("close",()=>{s(),l();});})}async function aD({logger:t,logLevel:e,appiumPort:r}){let n=Date.now(),o=spawn(process.execPath,[QRe,"--address","127.0.0.1","--port",`${r}`,"--relaxed-security","--log-format","json","--log-level",e],{stdio:["ignore","pipe","pipe"],env:process.env}),i={deviceOffline:false,instrumentationCrashed:false,uiAutomatorCrashed:false,nodeVersionUnsupported:false},a=[];o.stdout&&a.push(o8(o.stdout,t,"info",i)),o.stderr&&a.push(o8(o.stderr,t,"warn",i));let s=()=>ee(Promise.all(a).then(()=>{}),{milliseconds:YRe,fallback:()=>{}});try{await rxe({appiumPort:r,child:o,appiumLogHints:i,waitForOutputFlush:s});}catch(l){throw await n8({child:o,logger:t}),l}return t.info({duration:Date.now()-n},"Started Appium server"),{close:()=>n8({child:o,logger:t}),appiumLogHints:i}}function a8(t){let e=W(t);return e.includes("/session")&&(e.toLowerCase().includes("timeout")||e.toLowerCase().includes("socket hang up"))}function IC(t){return t instanceof Error?t.message.includes("Could not find a driver for automationName")||t.message.includes("Multiple drivers claim support for the same automationName"):false}async function dxe(t,e){let r=new nxe(e);return await r.start(),cxe.createInterface({input:r}).on("line",o=>{t.info({wdio:true,logLine:o},"WebdriverIO log");}),()=>r.quit()}async function mxe(t){let e=fr__default.join(tmpdir(),"momentic","wdio",randomUUID());mkdirSync(e,{recursive:true});let r=new Set,n=[],o=watch(e,async(i,a)=>{if(i!=="rename"||!a||r.has(a))return;r.add(a);let s=fr__default.join(e,a.toString());if(!existsSync(s)){r.delete(a);return}try{let l=await dxe(t,s);n.push(l);}catch(l){r.delete(a),t.warn({err:l,fileName:a},"Failed to start forwarding logs from new WDIO log file");}});return {stop:async()=>{o.close(),await Promise.all(n.map(i=>i().catch(a=>{t.warn({err:a},"Failed to stop forwarding logs from WDIO log file");})));},logDir:e}}async function s8({logger:t,callbacks:e,logLevel:r,wdioOpts:n}){let{onStatusUpdate:o,onFailure:i}=e,a=Math.floor(Math.random()*1e4)+4e4,s=await ic(a,"appium"),{close:l,appiumLogHints:c}=await aD({logger:t,logLevel:r,appiumPort:s}),u=async()=>{try{await l();}catch(p){t.warn({err:p},"Failed to close Appium server");}},{logDir:d,stop:m}=await mxe(t);for(let p=1;p<=2;p++)try{p>1&&o("Retrying Appium session");let f=Date.now(),h=await remote({connectionRetryTimeout:3e4,connectionRetryCount:0,...n,outputDir:d,hostname:"localhost",port:s,path:"/",protocol:"http",logLevel:r});return t.info({duration:Date.now()-f},"Created Wdio driver"),{driver:h,appiumServerClose:async()=>{await m(),await l();}}}catch(f){let h,g;try{let y=i?await i({err:f,attempt:p,appiumPort:s,appiumLogHints:c}):{shouldRetry:!1,recover:void 0};h=y.shouldRetry,g=y.recover;}catch(y){throw await m(),await u(),y}if(!h||p>=2)throw await m(),await u(),f;if(g)try{await g();}catch(y){t.warn({err:y},"Recovery failed before Appium restart");}await u(),{close:l,appiumLogHints:c}=await aD({logger:t,logLevel:r,appiumPort:s});}throw new Error("createWdioDriverWithRecovery: unexpected state")}function l8(t,e){let r=new Map;e.on("command",n=>{r.set(n.command,Date.now());}),e.on("result",n=>{let o=r.get(n.command);if(!o)return;let i=Date.now()-o;n.result instanceof Error?t.warn({err:n.result,command:n.command,args:n.body,durationMs:i},"Appium cmd failed"):i>1e4&&t.warn({command:n.command,args:n.body,durationMs:i},"Appium cmd took very long"),r.delete(n.command);});}var c8=1e4,pxe=15e3,fxe=15e3;function u8(t,e,r,n){let{onHeartbeatFailure:o,onHeartbeatRestored:i}=n||{},a=0,s=false,l,c,u=[];t.on("command",m=>{u.push(m.command);}),t.on("result",m=>{m.result instanceof Error||(c=Date.now());});async function d(){let m=pxe,p=Date.now()-(c??0);if(p>c8)try{await ee(e(),{milliseconds:fxe}),a>0&&(r.info("Driver heartbeat restored"),i?.()),a=0;}catch(f){a++;let h=f instanceof Error?f.message:`${f}`;if(r.warn({attempt:a,error:h,recentCommands:u},"Driver heartbeat failed"),a===3){let g="The driver appears unresponsive, indicating a possible emulator failure";r.error({err:f},g),P.error(g),o?.();}}else a>0&&(r.info("Driver heartbeat restored"),i?.()),a=0,m-=p;u=[],s||(l=setTimeout(()=>void d(),Math.max(m,c8)));}return d(),()=>{s=true,clearTimeout(l);}}async function Ip(t,e,r,n){let{maxAttempts:o=3,signal:i,slowThresholdMs:a=3e3,initialBackoffMs:s=3e3,backoffMultiplier:l=2,attemptTimeoutMs:c=1e4,operationName:u}=r,d;for(let m=0;m<o;m++){i?.throwIfAborted();let p=n?.reconnectingPromise?.();if(p){t.info("Waiting for reconnect to finish before attempt");try{await p;}catch(h){t.error({err:h},"Error while waiting for reconnect");}}else o>1&&m===o-1&&n?.tryReconnect&&(t.info({attempt:m+1,maxAttempts:o},`Attempting reconnect before final attempt ${m+1}`),await n.tryReconnect(t));let f=Date.now();try{let h=await ee(e(),{milliseconds:c,signal:i,message:`${u} timed out after ${c}ms`}),g=Date.now()-f;return g>a&&t.warn({durationMs:g},`${u} took very long`),h}catch(h){if(i?.throwIfAborted(),d=h,m===o-1)throw t.error({err:h,attempt:m+1,maxAttempts:o},`${u} failed on final attempt`),h;if(!hxe(h))throw t.error({err:h,attempt:m+1,maxAttempts:o},`${u} failed and does not look retryable`),h;let g=Math.min(1e4,s*Math.pow(l,m));t.warn({err:h,attempt:m+1,maxAttempts:o,backoffMs:g},`${u} failed, sleeping ${g}ms for recovery`),await pe(g,i);}}throw d}function hxe(t){return t instanceof Error?["socket hang up","read ECONNRESET","timeout","timed out","UND_ERR_HEADERS_TIMEOUT"].some(r=>t.message.includes(r)):false}var gxe="NATIVE_APP",Ac=class t{currentContext;driver;appiumClose;stopHeartbeat;initializationParams;reconnectingPromise;async close(){try{this.stopHeartbeat();}catch{}try{await this.appiumClose();}catch{}}startHeartbeat(e,r){return u8(this.driver,()=>this.healthcheck(),e,{...r,onHeartbeatFailure:()=>{r.onHeartbeatFailure?.(),this.reconnect(e).catch(n=>{e.error({err:n},"Failed to reconnect after heartbeat failure");});}})}constructor({logger:e,driver:r,appiumClose:n,callbacks:o,initializationParams:i}){this.initializationParams=i,this.driver=r,this.appiumClose=n,this.stopHeartbeat=this.startHeartbeat(e,o);}static async connectAppium(e){let{logger:r}=e,{driver:n,appiumServerClose:o}=await s8(e);return l8(r,n),{...e,driver:n,appiumClose:o,initializationParams:e}}async executeInNativeContext(e,r,n){return this.executeInContext(e,gxe,r,n)}async reconnect(e){if(e.info("Attempting to reconnect to Appium"),this.reconnectingPromise)return this.reconnectingPromise;this.reconnectingPromise=(async()=>{try{await this.close();}catch(i){e.error({err:i},"Error while closing Appium during reconnect");}this.initializationParams.callbacks.restartWda&&await this.initializationParams.callbacks.restartWda(e);let{driver:r,appiumClose:n,callbacks:o}=await t.connectAppium(this.initializationParams);this.currentContext=void 0,this.driver=r,this.appiumClose=n,this.stopHeartbeat=this.startHeartbeat(e,o);})();try{await this.reconnectingPromise;}finally{this.reconnectingPromise=void 0;}}async executeInContext(e,r,n,o){return Ip(e,async()=>(this.currentContext!==r&&(e.info({from:this.currentContext,to:r},"Switching Appium context"),this.currentContext=void 0,await this.driver.switchContext(r),this.currentContext=r),await n(this.driver)),o,{reconnectingPromise:()=>this.reconnectingPromise,tryReconnect:async a=>{await this.reconnect(a);}})}};function _p({containerBounds:t,viewport:e,defaultThresholdPercent:r}){let n=e.width*e.height;if(n<=0)return r;let o=d8({start:t.left,size:t.width,maxSize:e.width}),i=d8({start:t.top,size:t.height,maxSize:e.height});if(o<=0||i<=0)return r;let a=Math.min(o*i/n,1);return r*a}function _C({currentPixelDelta:t,baseDirection:e,correctionDirection:r,correctionPixels:n}){let o=Math.abs(t),i;r===e?i=o+n:i=Math.max(0,o-n);let a;return t===0?a=e==="down"?1:-1:a=Math.sign(t),a*i}function Cs({containerBounds:t,containerInsetRatio:e}){let r=t.height*e;return t.height-2*r}function OC({viewportTop:t,viewportBottom:e,elementHeight:r,targetTopRatio:n}){let o=Math.max(1,e-t),i=t+o*n,a=Math.max(t,e-r);return Math.max(t,Math.min(i,a))}function d8({start:t,size:e,maxSize:r}){let n=t+e;return Math.max(0,Math.min(n,r)-Math.max(t,0))}function m8(t){return t?.position?{...t,position:void 0}:t}function bxe(t){return t?.map(e=>({...e,requirements:m8(e.requirements)}))}function DC(t){return {...t,requirements:m8(t.requirements),requiredRelatedElements:bxe(t.requiredRelatedElements)}}function LC(t){let{tracer:e,span:r,screenshot:n,emulatorState:o,logger:i}=t;if(e.storeTraceAsset)try{let a=randomUUID$1();e.storeTraceAsset({snapshotId:a,data:Buffer.from(n,"base64"),extension:"png"}),r.screenshotSnapshotId=a;let s=randomUUID$1();e.storeTraceAsset({snapshotId:s,data:Buffer.from(o),extension:"xml"}),r.emulatorStateSnapshotId=s;}catch(a){i.debug({err:a},"Failed to store extraction trace assets");}}function NC(t){let{tracer:e,goldenScreenshotBase64:r,currentScreenshotBase64:n,diffScreenshotBase64:o,logger:i}=t,a=e.storeTraceAsset;if(!a)return {};let s=l=>{if(!l)return;let c=randomUUID$1();return a({snapshotId:c,data:Buffer.from(l,"base64"),extension:"png"}),c};try{return {goldenScreenshotSnapshotId:s(r),currentScreenshotSnapshotId:s(n),diffScreenshotSnapshotId:s(o)}}catch(l){return i.debug({err:l},"Failed to store visual diff trace assets"),{}}}function kC(t){let{tracer:e}=t;return e.startSpan("VISUAL_DIFF",r=>{let n=Sxe(t);return r.result={created:n.output.created,success:n.success,message:n.message},n})}function Sxe({goldenStorage:t,command:e,currentScreenshotBase64:r,threshold:n,updateGoldenFiles:o,tracer:i,logger:a}){let s=t.compareOrCreate({goldenPath:e.path,currentScreenshotBase64:r,pixelThreshold:n,updateGoldenFiles:o,logger:a}),l=t.resolveGoldenPath(e.path);if(s.created){let d=NC({tracer:i,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,logger:a});return {success:true,message:`Saved golden screenshot to ${l}.`,output:{created:true,goldenPath:l,threshold:n,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,...d}}}if(s.dimensionMismatch){let d=`${s.currentDimensions.width}x${s.currentDimensions.height}`,m=`${s.goldenDimensions.width}x${s.goldenDimensions.height}`,p=NC({tracer:i,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,logger:a});return {success:false,message:`Current screenshot (${d}) does not match golden dimensions (${m}).`,output:{created:false,goldenPath:l,threshold:n,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,diffPercent:s.diffPercent,pass:false,dimensionMismatch:true,...p}}}let c=s.diffPercent<=n*100,u=NC({tracer:i,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,diffScreenshotBase64:s.diffScreenshotBase64,logger:a});return {success:c,message:`Visual diff of ${s.diffPercent.toFixed(2)}% detected, which is ${c?"under":"over"} the threshold of ${n*100}%.`,output:{created:false,goldenPath:l,threshold:n,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,diffScreenshotBase64:s.diffScreenshotBase64,diffPercent:s.diffPercent,pass:c,...u}}}function FC(t,e){return e.length*(t+50)+4e3}var Txe=["WebSocket was closed before the connection was","Intentional disconnect"];function Tb(t){return t instanceof Error&&Txe.some(e=>t.message.includes(e))}var sD=false,f8;try{let t=await import('@sentry/node');t.init({dsn:"https://67a6ef469598f8880478f33863d05873@o4506426201800704.ingest.us.sentry.io/4510914396291072",environment:"production",dist:"production",release:"mobile-cli-1.0.1",tracesSampleRate:0,skipOpenTelemetrySetup:!0,sendDefaultPii:!0,beforeSend(e,r){return Uq(r?.originalException)||zq(r?.originalException)||$q(r?.originalException)||ju(r?.originalException)||Th(r?.originalException,Xe)||Tb(r?.originalException)||Vq(r?.originalException)?null:e}}),VG(t.captureException),f8=e=>{if(!e){t.setUser(null);return}t.setUser({id:e.userId,organizationId:e.orgId,...e.email&&{email:e.email}});},sD=!0;}catch{}var h8=t=>f8?.(t);var Exe="https://api.momentic.ai";function g8(t){let e=process.env.MOMENTIC_API_KEY??TC();if(!e)return;let r=(process.env.MOMENTIC_SERVER??EC()??Exe).replace(/\/+$/,"");return new Tr({apiKey:e,baseUrl:r,logger:t})}function b8({apiClient:t,logger:e}){let r=Router();return r.get("/:id",async(n,o)=>{let{id:i}=n.params;if(!i){o.status(400).json({error:"Missing screenshot ID"});return}if(!t){o.status(401).json({error:"Missing Momentic API key"});return}try{let{data:a,contentType:s}=await t.fetchOnDemandScreenshot(i);o.setHeader("Content-Type",s),o.send(a);}catch(a){e.error({err:a,screenshotId:i},"Failed to proxy on-demand screenshot"),o.status(502).json({error:"Failed to fetch screenshot"});}}),r}function y8(t){let e=Router(),r=fr__default.join(t,vo);return e.get("/",async(n,o)=>{try{let i=Axe(t);if(!i){o.status(404).json({error:"No run group found"});return}if(!Sn.existsSync(r)){o.status(404).json({error:"No runs found for run group"});return}let a=Rxe(r,i),s={...i,id:i.id??"local-run-group",createdAt:i.startedAt,runs:a};o.status(200).json(s);}catch(i){o.status(500).json({error:`Error loading run group: ${i.message}`});}}),e}function Axe(t){let e=fr__default.join(t,fn);if(!Sn.existsSync(e))return P.error("Run group metadata file not found"),null;try{let r=Sn.readFileSync(e,"utf-8");return jm.parse(JSON.parse(r))}catch(r){return P.error({err:r},"Error reading run group metadata"),null}}function Rxe(t,e){let r=Sn.readdirSync(t).filter(o=>o.endsWith(".zip")).sort((o,i)=>{let a=Sn.statSync(fr__default.join(t,o));return Sn.statSync(fr__default.join(t,i)).mtime.getTime()-a.mtime.getTime()}),n=[];for(let o of r){let i=fr__default.join(t,o),a=o.replace(/\.zip$/i,"");n.push(xxe(i,a,e));}return n}function xxe(t,e,r){let n=new u9(t),o=n.getEntry(fn);if(!o)throw new Error(`No entry found for file ${t}/${fn}`);try{let i=o.getData().toString("utf-8"),a=JSON.parse(i),s=cH.parse(a),l=Pxe(n,t);return N3(s,e,{runGroupMetadata:r,runAttempts:l,organizationId:"local"})}catch(i){throw P.error({err:i,zipPath:t},`Error parsing ${fn} for run`),new Error(`Error parsing ${fn} for run ${t}`,{cause:i})}}var Mxe=/^attempts\/(\d+)\/metadata\.json$/;function Pxe(t,e){let r=[];for(let o of t.getEntries()){let i=Mxe.exec(o.entryName);!i||!i[1]||r.push({index:parseInt(i[1],10),entry:o});}r.sort((o,i)=>o.index-i.index);let n=[];for(let{entry:o}of r){let i=Ixe(o,e);!i||!i.id||n.push({id:i.id,status:i.status,startedAt:i.startedAt,finishedAt:i.finishedAt??null});}return n}function Ixe(t,e){try{let r=t.getData().toString("utf-8");return sH.parse(JSON.parse(r))}catch(r){return P.warn({err:r,zipPath:e,entryName:t.entryName},"Skipping attempt metadata that failed to parse"),null}}function T8(t){let e=Router(),r=fr__default.join(t,vo);return e.get("/:filename",(n,o)=>{let i=n.params.filename;if(!i||!i.endsWith(".zip")){o.status(404).send("Not found");return}let a=fr__default.join(r,i),s=fr__default.resolve(a),l=fr__default.resolve(r);if(!s.startsWith(l)){o.status(403).send("Forbidden");return}if(!Sn.existsSync(a)){o.status(404).send("File not found");return}try{o.setHeader("Content-Type","application/zip"),o.setHeader("Content-Disposition",`attachment; filename="${i}"`);let c=Sn.readFileSync(a);o.send(c);}catch(c){o.status(500).send(`Error reading file: ${c.message}`);}}),e}function E8(t){let e=Router();return e.get("*",(r,n)=>{let o=r.path==="/"?fr__default.join(t,"index.html"):fr__default.join(t,r.path),i=fr__default.resolve(o),a=fr__default.resolve(t);if(!i.startsWith(a)){n.status(403).send("Forbidden");return}if(!Sn.existsSync(o)&&(o=fr__default.join(t,"index.html"),!Sn.existsSync(o))){n.status(404).send("File not found");return}try{let s=fr__default.extname(o).toLowerCase(),l=Mu[s]||"application/octet-stream";n.setHeader("Content-Type",l);let c=Sn.readFileSync(o);n.send(c);}catch(s){n.status(500).send(`Error reading file: ${s.message}`);}}),e}async function v8(t,e,r,n){op(t);let o=r??await ic(zT,"local-run-viewer-server"),i=Qoe();i.use((s,l,c)=>{l.setHeader("Access-Control-Allow-Origin","*"),l.setHeader("Cache-Control","no-cache"),c();});let a=g8(t);return i.use("/api/runs",T8(e)),i.use("/api/run-group",y8(e)),i.use("/api/on-demand-screenshots",b8({apiClient:a,logger:t})),n&&i.use("/",E8(n)),new Promise((s,l)=>{let c=i.listen(o,()=>{let u=`http://localhost:${o}`;$u(async()=>{await c.close();}),s({port:o,url:u});});c.on("error",u=>{l(u);});})}async function uD(t){let{logger:e,staticDir:r,resultsPath:n,runId:o,port:i}=t,a=fr__default.resolve(n),s=fr__default.join(a,vo),l;if(o){l=`${o.replace(/\.zip$/i,"")}.zip`;let u=fr__default.join(s,l);if(!Sn.existsSync(u)){let d=[];if(Sn.existsSync(s))for(let m of Sn.readdirSync(s))m.endsWith(".zip")&&d.push(m.replace(/\.zip$/i,""));P.error(`Run not found: ${l} in ${s}`),d.length>0&&P.error(`Available runs: ${d.join(", ")}`),process.exit(1);}}Sn.existsSync(r)||(P.error(`Static frontend files not found at ${r}. Please ensure the CLI is properly built.`),process.exit(1));try{let u=(await v8(e,a,i,r)).url;P.info(`Run viewer running at ${u}`);let d=new URL(u);l&&d.searchParams.set("zipUrl",`${u}/api/runs/${l}`),await _ye(d.toString());}catch(c){P.error(`Failed to start run viewer: ${c.message}`),process.exit(1);}}function Fxe(){let t=process.env.ANDROID_HOME;if(!t)return "adb";let e=process.platform==="win32"?"adb.exe":"adb";return fr__default.join(t,"platform-tools",e)}async function qr(t,e){let{timeoutMs:r=5e3,serial:n,throwOnError:o=false,encoding:i="utf8"}=e,a=Fxe(),s=n?["-s",n,...t]:t;return await new Promise((l,c)=>{execFile$1(a,s,{encoding:i,timeout:r,maxBuffer:1024*1024*20},(u,d)=>{if(u){if(o){c(u);return}l(void 0);return}l(d);});})}var zC=class t extends Ac{get capabilities(){return this.driver.capabilities}get sessionId(){return this.driver.sessionId}get sessionOptions(){let{hostname:e,port:r,protocol:n}=this.driver.options;return {hostname:e,port:r,protocol:n}}static async init(e){let r=await Ac.connectAppium(e);return new t(r)}async healthcheck(){await this.driver.execute("mobile: shell",{command:"echo",args:["ping"]});}};var jxe=12e4,vb=3e5,C8=6e4,Cb=2,Hxe=1e3;async function w8(t){let{apiClient:e,logger:r,creationOpts:n,onStatusUpdate:o,logLevel:i,orgId:a,sessionId:s,onConnectionStateChange:l}=t,{token:c,webRtcUrl:u,adbUrl:d,apiUrl:m,name:p,apkDownloadUrl:f,region:h,resolvedTag:g,playwrightServerUrl:y}=await e.createAndroidEmulator({...n,hostname:hostname(),sessionId:s,playwrightVersion:Lz}),S;try{execSync("adb --version"),S="adb";}catch{if(process.env.ANDROID_HOME)S=fr__default.join(process.env.ANDROID_HOME,"platform-tools","adb");else throw new M("UserInfrastructureError","The ADB binary was not found in PATH and ANDROID_HOME is not set either")}r.info({creationOpts:n,emulatorName:p,apkToInstall:n.apkToInstall,region:h,apkDownloadUrl:f,sessionId:s,playwrightServerUrl:y},"Android instance creation ok");let E=n.apkToInstall?.channel,v=n.apkToInstall?.tag,w=await Ge.recordDuration({fn:async()=>await createInstanceClient$1({adbUrl:d,apiUrl:m,token:c,logLevel:i,adbPath:S}),name:"test_event_duration",tags:["name:limbar-client-creation","clientOs:android",`orgId:${a}`],timeoutMs:C8,timeoutMessage:`Timed out after ${C8}ms creating Limbar Android instance client for emulator ${p} after instance creation succeeded (region: ${h??"unknown"}, channel: ${E??"none"}, tag: ${v??"none"})`}),_;l&&(_=w.onConnectionStateChange(l));let L=["https://storage.googleapis.com/mobile-drivers/appium-uiautomator2-server-v10.2.1.apk","https://storage.googleapis.com/mobile-drivers/appium-uiautomator2-server-debug-androidTest-v10.2.1.apk","https://storage.googleapis.com/mobile-drivers/settings_apk-debug-v7.1.3.apk"];f&&L.push(f),o(`Installing APK${E?` with channel ${E}`:""}${v?` and tag ${v}`:""}`),await Ge.recordDuration({fn:async()=>{await Promise.all(L.map(D=>Wxe({client:w,url:D,logger:r,emulatorName:p})));},name:"test_event_duration",tags:["name:limbar-asset-upload",`orgId:${a}`]}),o("Starting ADB tunnel");let I=await Ge.recordDuration({fn:async()=>await w.startAdbTunnel(),name:"test_event_duration",tags:["name:limbar-tunnel-connect",`orgId:${a}`]}),R=()=>{_?.(),I.close(),w.disconnect();},k;return y&&(o("Opening Playwright connection"),k=await Ge.recordDuration({fn:async()=>{let D=await _android.connect(y,{timeout:3e4});return r.info("Playwright connection opened"),D},name:"test_event_duration",tags:["name:playwright-device-connect",`orgId:${a}`]})),{adbPort:I.address.port,close:R,limbarToken:c,limbarUrl:u,limbarRegion:h,limbarTag:g,limbarOsVersion:n.osVersion,emulatorName:p,playwrightDevice:k,limbarClient:w}}async function Wxe(t){let{client:e,url:r,logger:n,emulatorName:o}=t,i,a=Date.now();for(let s=1;s<=Cb;s++){let l=vb-(Date.now()-a);if(l<=0)break;let c=Math.min(jxe,l);try{await ee(e.sendAsset(r,c),{milliseconds:c,message:`Timed out after ${c}ms sending asset to emulator ${o}: ${r}`});return}catch(u){if(i=u,s===Cb)break;let d=Hxe*2**(s-1);if(vb-(Date.now()-a)-d<=0)break;n.warn({url:r,err:u,emulatorName:o,attempt:s,maxAttempts:Cb,backoffMs:d,attemptTimeoutMs:c,totalTimeoutMs:vb},"Failed to send asset to Limbar client; retrying after backoff"),await pe(d);}}throw n.error({url:r,err:i,emulatorName:o,maxAttempts:Cb,totalTimeoutMs:vb},"Failed to send asset to Limbar client (no more retries)"),new M("InternalPlatformError",`Failed to upload APK asset to emulator ${o} after ${Cb} attempt(s) within ${vb}ms: ${i}`)}var Gxe=["If you see 'device offline' in ADB output, the emulator likely reset or crashed. Please start a new editor session by refreshing the page.","If Appium /status does not respond, the Appium server may not have started correctly. Please inspect the log output above for errors."];function A8(t,e){if(!t||!e)return;let r=t.split(/\r?\n/).map(n=>n.trim()).filter(n=>n.length>0);for(let n of r){if(n.startsWith("List of devices attached")||!n.startsWith(e))continue;let i=n.split(/\s+/)[1]?.toLowerCase();return i==="device"?"device":i==="offline"?"offline":i==="unauthorized"?"unauthorized":"unknown"}}function qxe(t){return t&&(/^\d{1,3}(\.\d{1,3}){3}:\d+$/.test(t)||/^localhost:\d+$/.test(t))?t:null}async function Kxe(t){return {adbSerial:t,devices:await qr(["devices","-l"],{timeoutMs:2500}),state:t?await qr(["get-state"],{serial:t,timeoutMs:5e3}):void 0,bootCompleted:t?await qr(["shell","getprop","sys.boot_completed"],{serial:t,timeoutMs:5e3}):void 0}}async function Yxe({logger:t,adbSerial:e,adbSnapshot:r,appiumLogHints:n,transportMode:o}){let i=A8(r.devices,e);if(!(i==="offline"||n.deviceOffline||n.instrumentationCrashed||n.uiAutomatorCrashed))return;let s=o==="tunneled"?qxe(e):void 0;if(t.warn({adbSerial:e,deviceState:i,appiumLogHints:n,transportMode:o},"Attempting best-effort recovery of Android transport"),o==="tunneled"&&s?(await qr(["start-server"],{timeoutMs:5e3}),await pe(500),await qr(["disconnect",s],{timeoutMs:5e3}),await pe(500),await qr(["connect",s],{timeoutMs:5e3}),await pe(500)):(await qr(["kill-server"],{timeoutMs:5e3}),await pe(500),await qr(["start-server"],{timeoutMs:5e3}),await pe(500),await qr(["reconnect","offline"],{timeoutMs:5e3}),await pe(500)),e){let l=await qr(["get-state"],{serial:e,timeoutMs:5e3});typeof l=="string"&&l.trim()==="device"&&(await qr(["shell","pm","clear","io.appium.uiautomator2.server"],{serial:e,timeoutMs:5e3}),await qr(["shell","pm","clear","io.appium.uiautomator2.server.test"],{serial:e,timeoutMs:5e3}));}}function R8({logger:t,onStatusUpdate:e,adbSerial:r,transportMode:n}){return async({err:o,attempt:i,appiumPort:a,appiumLogHints:s})=>{let l=o instanceof M?o:new M("UserInfrastructureError",W(o),{errOptions:{cause:o}}),c=await iD(a),u=await Kxe(r),d=A8(u.devices,r);t.error({err:o,appiumPort:a,appiumStatus:c,adbSnapshot:u,adbDeviceState:d,appiumLogHints:s},"Failed to create Appium WebDriver session"),e(`Appium session creation failed: ${W(o)}`);let m=i===1&&(a8(o)||IC(o)||d==="offline"||s.instrumentationCrashed||s.deviceOffline);if(!m)throw P.error(`Failed to create Appium WebDriver session. Troubleshooting:
|
|
267
|
+
`);a(l),r==="warn"&&(n.lastWarn=l),e[r]({appium:true,logLine:l},"Appium log"),i.length=0;};return o.on("line",l=>{if(!l.trim()||JRe(l))return;let c;try{c=JSON.parse(l);}catch{}if(c!==void 0){s(),a(l);let u=c.level,d=c.message;typeof d=="string"&&(u==="error"?n.lastError=d:u==="warn"&&(n.lastWarn=d)),e[r]({appium:true,parsed:c},"Appium log");}else !/^\s/.test(l)&&i.length>0&&s(),i.push(l);}),new Promise(l=>{o.on("close",()=>{s(),l();});})}async function aD({logger:t,logLevel:e,appiumPort:r}){let n=Date.now(),o=spawn(process.execPath,[QRe,"--address","127.0.0.1","--port",`${r}`,"--relaxed-security","--log-format","json","--log-level",e],{stdio:["ignore","pipe","pipe"],env:process.env}),i={deviceOffline:false,instrumentationCrashed:false,uiAutomatorCrashed:false,nodeVersionUnsupported:false},a=[];o.stdout&&a.push(o8(o.stdout,t,"info",i)),o.stderr&&a.push(o8(o.stderr,t,"warn",i));let s=()=>ee(Promise.all(a).then(()=>{}),{milliseconds:YRe,fallback:()=>{}});try{await rxe({appiumPort:r,child:o,appiumLogHints:i,waitForOutputFlush:s});}catch(l){throw await n8({child:o,logger:t}),l}return t.info({duration:Date.now()-n},"Started Appium server"),{close:()=>n8({child:o,logger:t}),appiumLogHints:i}}function a8(t){let e=W(t);return e.includes("/session")&&(e.toLowerCase().includes("timeout")||e.toLowerCase().includes("socket hang up"))}function IC(t){return t instanceof Error?t.message.includes("Could not find a driver for automationName")||t.message.includes("Multiple drivers claim support for the same automationName"):false}async function dxe(t,e){let r=new nxe(e);return await r.start(),cxe.createInterface({input:r}).on("line",o=>{t.info({wdio:true,logLine:o},"WebdriverIO log");}),()=>r.quit()}async function mxe(t){let e=fr__default.join(tmpdir(),"momentic","wdio",randomUUID());mkdirSync(e,{recursive:true});let r=new Set,n=[],o=watch(e,async(i,a)=>{if(i!=="rename"||!a||r.has(a))return;r.add(a);let s=fr__default.join(e,a.toString());if(!existsSync(s)){r.delete(a);return}try{let l=await dxe(t,s);n.push(l);}catch(l){r.delete(a),t.warn({err:l,fileName:a},"Failed to start forwarding logs from new WDIO log file");}});return {stop:async()=>{o.close(),await Promise.all(n.map(i=>i().catch(a=>{t.warn({err:a},"Failed to stop forwarding logs from WDIO log file");})));},logDir:e}}async function s8({logger:t,callbacks:e,logLevel:r,wdioOpts:n}){let{onStatusUpdate:o,onFailure:i}=e,a=Math.floor(Math.random()*1e4)+4e4,s=await ic(a,"appium"),{close:l,appiumLogHints:c}=await aD({logger:t,logLevel:r,appiumPort:s}),u=async()=>{try{await l();}catch(p){t.warn({err:p},"Failed to close Appium server");}},{logDir:d,stop:m}=await mxe(t);for(let p=1;p<=2;p++)try{p>1&&o("Retrying Appium session");let f=Date.now(),h=await remote({connectionRetryTimeout:3e4,connectionRetryCount:0,...n,outputDir:d,hostname:"localhost",port:s,path:"/",protocol:"http",logLevel:r});return t.info({duration:Date.now()-f},"Created Wdio driver"),{driver:h,appiumServerClose:async()=>{await m(),await l();}}}catch(f){let h,g;try{let y=i?await i({err:f,attempt:p,appiumPort:s,appiumLogHints:c}):{shouldRetry:!1,recover:void 0};h=y.shouldRetry,g=y.recover;}catch(y){throw await m(),await u(),y}if(!h||p>=2)throw await m(),await u(),f;if(g)try{await g();}catch(y){t.warn({err:y},"Recovery failed before Appium restart");}await u(),{close:l,appiumLogHints:c}=await aD({logger:t,logLevel:r,appiumPort:s});}throw new Error("createWdioDriverWithRecovery: unexpected state")}function l8(t,e){let r=new Map;e.on("command",n=>{r.set(n.command,Date.now());}),e.on("result",n=>{let o=r.get(n.command);if(!o)return;let i=Date.now()-o;n.result instanceof Error?t.warn({err:n.result,command:n.command,args:n.body,durationMs:i},"Appium cmd failed"):i>1e4&&t.warn({command:n.command,args:n.body,durationMs:i},"Appium cmd took very long"),r.delete(n.command);});}var c8=1e4,pxe=15e3,fxe=15e3;function u8(t,e,r,n){let{onHeartbeatFailure:o,onHeartbeatRestored:i}=n||{},a=0,s=false,l,c,u=[];t.on("command",m=>{u.push(m.command);}),t.on("result",m=>{m.result instanceof Error||(c=Date.now());});async function d(){let m=pxe,p=Date.now()-(c??0);if(p>c8)try{await ee(e(),{milliseconds:fxe}),a>0&&(r.info("Driver heartbeat restored"),i?.()),a=0;}catch(f){a++;let h=f instanceof Error?f.message:`${f}`;if(r.warn({attempt:a,error:h,recentCommands:u},"Driver heartbeat failed"),a===3){let g="The driver appears unresponsive, indicating a possible emulator failure";r.error({err:f},g),P.error(g),o?.();}}else a>0&&(r.info("Driver heartbeat restored"),i?.()),a=0,m-=p;u=[],s||(l=setTimeout(()=>void d(),Math.max(m,c8)));}return d(),()=>{s=true,clearTimeout(l);}}async function Ip(t,e,r,n){let{maxAttempts:o=3,signal:i,slowThresholdMs:a=3e3,initialBackoffMs:s=3e3,backoffMultiplier:l=2,attemptTimeoutMs:c=1e4,operationName:u}=r,d;for(let m=0;m<o;m++){i?.throwIfAborted();let p=n?.reconnectingPromise?.();if(p){t.info("Waiting for reconnect to finish before attempt");try{await p;}catch(h){t.error({err:h},"Error while waiting for reconnect");}}else o>1&&m===o-1&&n?.tryReconnect&&(t.info({attempt:m+1,maxAttempts:o},`Attempting reconnect before final attempt ${m+1}`),await n.tryReconnect(t));let f=Date.now();try{let h=await ee(e(),{milliseconds:c,signal:i,message:`${u} timed out after ${c}ms`}),g=Date.now()-f;return g>a&&t.warn({durationMs:g},`${u} took very long`),h}catch(h){if(i?.throwIfAborted(),d=h,m===o-1)throw t.error({err:h,attempt:m+1,maxAttempts:o},`${u} failed on final attempt`),h;if(!hxe(h))throw t.error({err:h,attempt:m+1,maxAttempts:o},`${u} failed and does not look retryable`),h;let g=Math.min(1e4,s*Math.pow(l,m));t.warn({err:h,attempt:m+1,maxAttempts:o,backoffMs:g},`${u} failed, sleeping ${g}ms for recovery`),await pe(g,i);}}throw d}function hxe(t){return t instanceof Error?["socket hang up","read ECONNRESET","timeout","timed out","UND_ERR_HEADERS_TIMEOUT"].some(r=>t.message.includes(r)):false}var gxe="NATIVE_APP",Ac=class t{currentContext;driver;appiumClose;stopHeartbeat;initializationParams;reconnectingPromise;async close(){try{this.stopHeartbeat();}catch{}try{await this.appiumClose();}catch{}}startHeartbeat(e,r){return u8(this.driver,()=>this.healthcheck(),e,{...r,onHeartbeatFailure:()=>{r.onHeartbeatFailure?.(),this.reconnect(e).catch(n=>{e.error({err:n},"Failed to reconnect after heartbeat failure");});}})}constructor({logger:e,driver:r,appiumClose:n,callbacks:o,initializationParams:i}){this.initializationParams=i,this.driver=r,this.appiumClose=n,this.stopHeartbeat=this.startHeartbeat(e,o);}static async connectAppium(e){let{logger:r}=e,{driver:n,appiumServerClose:o}=await s8(e);return l8(r,n),{...e,driver:n,appiumClose:o,initializationParams:e}}async executeInNativeContext(e,r,n){return this.executeInContext(e,gxe,r,n)}async reconnect(e){if(e.info("Attempting to reconnect to Appium"),this.reconnectingPromise)return this.reconnectingPromise;this.reconnectingPromise=(async()=>{try{await this.close();}catch(i){e.error({err:i},"Error while closing Appium during reconnect");}this.initializationParams.callbacks.restartWda&&await this.initializationParams.callbacks.restartWda(e);let{driver:r,appiumClose:n,callbacks:o}=await t.connectAppium(this.initializationParams);this.currentContext=void 0,this.driver=r,this.appiumClose=n,this.stopHeartbeat=this.startHeartbeat(e,o);})();try{await this.reconnectingPromise;}finally{this.reconnectingPromise=void 0;}}async executeInContext(e,r,n,o){return Ip(e,async()=>(this.currentContext!==r&&(e.info({from:this.currentContext,to:r},"Switching Appium context"),this.currentContext=void 0,await this.driver.switchContext(r),this.currentContext=r),await n(this.driver)),o,{reconnectingPromise:()=>this.reconnectingPromise,tryReconnect:async a=>{await this.reconnect(a);}})}};function _p({containerBounds:t,viewport:e,defaultThresholdPercent:r}){let n=e.width*e.height;if(n<=0)return r;let o=d8({start:t.left,size:t.width,maxSize:e.width}),i=d8({start:t.top,size:t.height,maxSize:e.height});if(o<=0||i<=0)return r;let a=Math.min(o*i/n,1);return r*a}function _C({currentPixelDelta:t,baseDirection:e,correctionDirection:r,correctionPixels:n}){let o=Math.abs(t),i;r===e?i=o+n:i=Math.max(0,o-n);let a;return t===0?a=e==="down"?1:-1:a=Math.sign(t),a*i}function Cs({containerBounds:t,containerInsetRatio:e}){let r=t.height*e;return t.height-2*r}function OC({viewportTop:t,viewportBottom:e,elementHeight:r,targetTopRatio:n}){let o=Math.max(1,e-t),i=t+o*n,a=Math.max(t,e-r);return Math.max(t,Math.min(i,a))}function d8({start:t,size:e,maxSize:r}){let n=t+e;return Math.max(0,Math.min(n,r)-Math.max(t,0))}function m8(t){return t?.position?{...t,position:void 0}:t}function bxe(t){return t?.map(e=>({...e,requirements:m8(e.requirements)}))}function DC(t){return {...t,requirements:m8(t.requirements),requiredRelatedElements:bxe(t.requiredRelatedElements)}}function LC(t){let{tracer:e,span:r,screenshot:n,emulatorState:o,logger:i}=t;if(e.storeTraceAsset)try{let a=randomUUID$1();e.storeTraceAsset({snapshotId:a,data:Buffer.from(n,"base64"),extension:"png"}),r.screenshotSnapshotId=a;let s=randomUUID$1();e.storeTraceAsset({snapshotId:s,data:Buffer.from(o),extension:"xml"}),r.emulatorStateSnapshotId=s;}catch(a){i.debug({err:a},"Failed to store extraction trace assets");}}function NC(t){let{tracer:e,goldenScreenshotBase64:r,currentScreenshotBase64:n,diffScreenshotBase64:o,logger:i}=t,a=e.storeTraceAsset;if(!a)return {};let s=l=>{if(!l)return;let c=randomUUID$1();return a({snapshotId:c,data:Buffer.from(l,"base64"),extension:"png"}),c};try{return {goldenScreenshotSnapshotId:s(r),currentScreenshotSnapshotId:s(n),diffScreenshotSnapshotId:s(o)}}catch(l){return i.debug({err:l},"Failed to store visual diff trace assets"),{}}}function kC(t){let{tracer:e}=t;return e.startSpan("VISUAL_DIFF",r=>{let n=Sxe(t);return r.result={created:n.output.created,success:n.success,message:n.message},n})}function Sxe({goldenStorage:t,command:e,currentScreenshotBase64:r,threshold:n,updateGoldenFiles:o,tracer:i,logger:a}){let s=t.compareOrCreate({goldenPath:e.path,currentScreenshotBase64:r,pixelThreshold:n,updateGoldenFiles:o,logger:a}),l=t.resolveGoldenPath(e.path);if(s.created){let d=NC({tracer:i,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,logger:a});return {success:true,message:`Saved golden screenshot to ${l}.`,output:{created:true,goldenPath:l,threshold:n,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,...d}}}if(s.dimensionMismatch){let d=`${s.currentDimensions.width}x${s.currentDimensions.height}`,m=`${s.goldenDimensions.width}x${s.goldenDimensions.height}`,p=NC({tracer:i,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,logger:a});return {success:false,message:`Current screenshot (${d}) does not match golden dimensions (${m}).`,output:{created:false,goldenPath:l,threshold:n,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,diffPercent:s.diffPercent,pass:false,dimensionMismatch:true,...p}}}let c=s.diffPercent<=n*100,u=NC({tracer:i,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,diffScreenshotBase64:s.diffScreenshotBase64,logger:a});return {success:c,message:`Visual diff of ${s.diffPercent.toFixed(2)}% detected, which is ${c?"under":"over"} the threshold of ${n*100}%.`,output:{created:false,goldenPath:l,threshold:n,goldenScreenshotBase64:s.goldenScreenshotBase64,currentScreenshotBase64:r,diffScreenshotBase64:s.diffScreenshotBase64,diffPercent:s.diffPercent,pass:c,...u}}}function FC(t,e){return e.length*(t+50)+4e3}var Txe=["WebSocket was closed before the connection was","Intentional disconnect"];function Tb(t){return t instanceof Error&&Txe.some(e=>t.message.includes(e))}var sD=false,f8;try{let t=await import('@sentry/node');t.init({dsn:"https://67a6ef469598f8880478f33863d05873@o4506426201800704.ingest.us.sentry.io/4510914396291072",environment:"production",dist:"production",release:"mobile-cli-1.0.2",tracesSampleRate:0,skipOpenTelemetrySetup:!0,sendDefaultPii:!0,beforeSend(e,r){return Uq(r?.originalException)||zq(r?.originalException)||$q(r?.originalException)||ju(r?.originalException)||Th(r?.originalException,Xe)||Tb(r?.originalException)||Vq(r?.originalException)?null:e}}),VG(t.captureException),f8=e=>{if(!e){t.setUser(null);return}t.setUser({id:e.userId,organizationId:e.orgId,...e.email&&{email:e.email}});},sD=!0;}catch{}var h8=t=>f8?.(t);var Exe="https://api.momentic.ai";function g8(t){let e=process.env.MOMENTIC_API_KEY??TC();if(!e)return;let r=(process.env.MOMENTIC_SERVER??EC()??Exe).replace(/\/+$/,"");return new Tr({apiKey:e,baseUrl:r,logger:t})}function b8({apiClient:t,logger:e}){let r=Router();return r.get("/:id",async(n,o)=>{let{id:i}=n.params;if(!i){o.status(400).json({error:"Missing screenshot ID"});return}if(!t){o.status(401).json({error:"Missing Momentic API key"});return}try{let{data:a,contentType:s}=await t.fetchOnDemandScreenshot(i);o.setHeader("Content-Type",s),o.send(a);}catch(a){e.error({err:a,screenshotId:i},"Failed to proxy on-demand screenshot"),o.status(502).json({error:"Failed to fetch screenshot"});}}),r}function y8(t){let e=Router(),r=fr__default.join(t,vo);return e.get("/",async(n,o)=>{try{let i=Axe(t);if(!i){o.status(404).json({error:"No run group found"});return}if(!Sn.existsSync(r)){o.status(404).json({error:"No runs found for run group"});return}let a=Rxe(r,i),s={...i,id:i.id??"local-run-group",createdAt:i.startedAt,runs:a};o.status(200).json(s);}catch(i){o.status(500).json({error:`Error loading run group: ${i.message}`});}}),e}function Axe(t){let e=fr__default.join(t,fn);if(!Sn.existsSync(e))return P.error("Run group metadata file not found"),null;try{let r=Sn.readFileSync(e,"utf-8");return jm.parse(JSON.parse(r))}catch(r){return P.error({err:r},"Error reading run group metadata"),null}}function Rxe(t,e){let r=Sn.readdirSync(t).filter(o=>o.endsWith(".zip")).sort((o,i)=>{let a=Sn.statSync(fr__default.join(t,o));return Sn.statSync(fr__default.join(t,i)).mtime.getTime()-a.mtime.getTime()}),n=[];for(let o of r){let i=fr__default.join(t,o),a=o.replace(/\.zip$/i,"");n.push(xxe(i,a,e));}return n}function xxe(t,e,r){let n=new u9(t),o=n.getEntry(fn);if(!o)throw new Error(`No entry found for file ${t}/${fn}`);try{let i=o.getData().toString("utf-8"),a=JSON.parse(i),s=cH.parse(a),l=Pxe(n,t);return N3(s,e,{runGroupMetadata:r,runAttempts:l,organizationId:"local"})}catch(i){throw P.error({err:i,zipPath:t},`Error parsing ${fn} for run`),new Error(`Error parsing ${fn} for run ${t}`,{cause:i})}}var Mxe=/^attempts\/(\d+)\/metadata\.json$/;function Pxe(t,e){let r=[];for(let o of t.getEntries()){let i=Mxe.exec(o.entryName);!i||!i[1]||r.push({index:parseInt(i[1],10),entry:o});}r.sort((o,i)=>o.index-i.index);let n=[];for(let{entry:o}of r){let i=Ixe(o,e);!i||!i.id||n.push({id:i.id,status:i.status,startedAt:i.startedAt,finishedAt:i.finishedAt??null});}return n}function Ixe(t,e){try{let r=t.getData().toString("utf-8");return sH.parse(JSON.parse(r))}catch(r){return P.warn({err:r,zipPath:e,entryName:t.entryName},"Skipping attempt metadata that failed to parse"),null}}function T8(t){let e=Router(),r=fr__default.join(t,vo);return e.get("/:filename",(n,o)=>{let i=n.params.filename;if(!i||!i.endsWith(".zip")){o.status(404).send("Not found");return}let a=fr__default.join(r,i),s=fr__default.resolve(a),l=fr__default.resolve(r);if(!s.startsWith(l)){o.status(403).send("Forbidden");return}if(!Sn.existsSync(a)){o.status(404).send("File not found");return}try{o.setHeader("Content-Type","application/zip"),o.setHeader("Content-Disposition",`attachment; filename="${i}"`);let c=Sn.readFileSync(a);o.send(c);}catch(c){o.status(500).send(`Error reading file: ${c.message}`);}}),e}function E8(t){let e=Router();return e.get("*",(r,n)=>{let o=r.path==="/"?fr__default.join(t,"index.html"):fr__default.join(t,r.path),i=fr__default.resolve(o),a=fr__default.resolve(t);if(!i.startsWith(a)){n.status(403).send("Forbidden");return}if(!Sn.existsSync(o)&&(o=fr__default.join(t,"index.html"),!Sn.existsSync(o))){n.status(404).send("File not found");return}try{let s=fr__default.extname(o).toLowerCase(),l=Mu[s]||"application/octet-stream";n.setHeader("Content-Type",l);let c=Sn.readFileSync(o);n.send(c);}catch(s){n.status(500).send(`Error reading file: ${s.message}`);}}),e}async function v8(t,e,r,n){op(t);let o=r??await ic(zT,"local-run-viewer-server"),i=Qoe();i.use((s,l,c)=>{l.setHeader("Access-Control-Allow-Origin","*"),l.setHeader("Cache-Control","no-cache"),c();});let a=g8(t);return i.use("/api/runs",T8(e)),i.use("/api/run-group",y8(e)),i.use("/api/on-demand-screenshots",b8({apiClient:a,logger:t})),n&&i.use("/",E8(n)),new Promise((s,l)=>{let c=i.listen(o,()=>{let u=`http://localhost:${o}`;$u(async()=>{await c.close();}),s({port:o,url:u});});c.on("error",u=>{l(u);});})}async function uD(t){let{logger:e,staticDir:r,resultsPath:n,runId:o,port:i}=t,a=fr__default.resolve(n),s=fr__default.join(a,vo),l;if(o){l=`${o.replace(/\.zip$/i,"")}.zip`;let u=fr__default.join(s,l);if(!Sn.existsSync(u)){let d=[];if(Sn.existsSync(s))for(let m of Sn.readdirSync(s))m.endsWith(".zip")&&d.push(m.replace(/\.zip$/i,""));P.error(`Run not found: ${l} in ${s}`),d.length>0&&P.error(`Available runs: ${d.join(", ")}`),process.exit(1);}}Sn.existsSync(r)||(P.error(`Static frontend files not found at ${r}. Please ensure the CLI is properly built.`),process.exit(1));try{let u=(await v8(e,a,i,r)).url;P.info(`Run viewer running at ${u}`);let d=new URL(u);l&&d.searchParams.set("zipUrl",`${u}/api/runs/${l}`),await _ye(d.toString());}catch(c){P.error(`Failed to start run viewer: ${c.message}`),process.exit(1);}}function Fxe(){let t=process.env.ANDROID_HOME;if(!t)return "adb";let e=process.platform==="win32"?"adb.exe":"adb";return fr__default.join(t,"platform-tools",e)}async function qr(t,e){let{timeoutMs:r=5e3,serial:n,throwOnError:o=false,encoding:i="utf8"}=e,a=Fxe(),s=n?["-s",n,...t]:t;return await new Promise((l,c)=>{execFile$1(a,s,{encoding:i,timeout:r,maxBuffer:1024*1024*20},(u,d)=>{if(u){if(o){c(u);return}l(void 0);return}l(d);});})}var zC=class t extends Ac{get capabilities(){return this.driver.capabilities}get sessionId(){return this.driver.sessionId}get sessionOptions(){let{hostname:e,port:r,protocol:n}=this.driver.options;return {hostname:e,port:r,protocol:n}}static async init(e){let r=await Ac.connectAppium(e);return new t(r)}async healthcheck(){await this.driver.execute("mobile: shell",{command:"echo",args:["ping"]});}};var jxe=12e4,vb=3e5,C8=6e4,Cb=2,Hxe=1e3;async function w8(t){let{apiClient:e,logger:r,creationOpts:n,onStatusUpdate:o,logLevel:i,orgId:a,sessionId:s,onConnectionStateChange:l}=t,{token:c,webRtcUrl:u,adbUrl:d,apiUrl:m,name:p,apkDownloadUrl:f,region:h,resolvedTag:g,playwrightServerUrl:y}=await e.createAndroidEmulator({...n,hostname:hostname(),sessionId:s,playwrightVersion:Lz}),S;try{execSync("adb --version"),S="adb";}catch{if(process.env.ANDROID_HOME)S=fr__default.join(process.env.ANDROID_HOME,"platform-tools","adb");else throw new M("UserInfrastructureError","The ADB binary was not found in PATH and ANDROID_HOME is not set either")}r.info({creationOpts:n,emulatorName:p,apkToInstall:n.apkToInstall,region:h,apkDownloadUrl:f,sessionId:s,playwrightServerUrl:y},"Android instance creation ok");let E=n.apkToInstall?.channel,v=n.apkToInstall?.tag,w=await Ge.recordDuration({fn:async()=>await createInstanceClient$1({adbUrl:d,apiUrl:m,token:c,logLevel:i,adbPath:S}),name:"test_event_duration",tags:["name:limbar-client-creation","clientOs:android",`orgId:${a}`],timeoutMs:C8,timeoutMessage:`Timed out after ${C8}ms creating Limbar Android instance client for emulator ${p} after instance creation succeeded (region: ${h??"unknown"}, channel: ${E??"none"}, tag: ${v??"none"})`}),_;l&&(_=w.onConnectionStateChange(l));let L=["https://storage.googleapis.com/mobile-drivers/appium-uiautomator2-server-v10.2.1.apk","https://storage.googleapis.com/mobile-drivers/appium-uiautomator2-server-debug-androidTest-v10.2.1.apk","https://storage.googleapis.com/mobile-drivers/settings_apk-debug-v7.1.3.apk"];f&&L.push(f),o(`Installing APK${E?` with channel ${E}`:""}${v?` and tag ${v}`:""}`),await Ge.recordDuration({fn:async()=>{await Promise.all(L.map(D=>Wxe({client:w,url:D,logger:r,emulatorName:p})));},name:"test_event_duration",tags:["name:limbar-asset-upload",`orgId:${a}`]}),o("Starting ADB tunnel");let I=await Ge.recordDuration({fn:async()=>await w.startAdbTunnel(),name:"test_event_duration",tags:["name:limbar-tunnel-connect",`orgId:${a}`]}),R=()=>{_?.(),I.close(),w.disconnect();},k;return y&&(o("Opening Playwright connection"),k=await Ge.recordDuration({fn:async()=>{let D=await _android.connect(y,{timeout:3e4});return r.info("Playwright connection opened"),D},name:"test_event_duration",tags:["name:playwright-device-connect",`orgId:${a}`]})),{adbPort:I.address.port,close:R,limbarToken:c,limbarUrl:u,limbarRegion:h,limbarTag:g,limbarOsVersion:n.osVersion,emulatorName:p,playwrightDevice:k,limbarClient:w}}async function Wxe(t){let{client:e,url:r,logger:n,emulatorName:o}=t,i,a=Date.now();for(let s=1;s<=Cb;s++){let l=vb-(Date.now()-a);if(l<=0)break;let c=Math.min(jxe,l);try{await ee(e.sendAsset(r,c),{milliseconds:c,message:`Timed out after ${c}ms sending asset to emulator ${o}: ${r}`});return}catch(u){if(i=u,s===Cb)break;let d=Hxe*2**(s-1);if(vb-(Date.now()-a)-d<=0)break;n.warn({url:r,err:u,emulatorName:o,attempt:s,maxAttempts:Cb,backoffMs:d,attemptTimeoutMs:c,totalTimeoutMs:vb},"Failed to send asset to Limbar client; retrying after backoff"),await pe(d);}}throw n.error({url:r,err:i,emulatorName:o,maxAttempts:Cb,totalTimeoutMs:vb},"Failed to send asset to Limbar client (no more retries)"),new M("InternalPlatformError",`Failed to upload APK asset to emulator ${o} after ${Cb} attempt(s) within ${vb}ms: ${i}`)}var Gxe=["If you see 'device offline' in ADB output, the emulator likely reset or crashed. Please start a new editor session by refreshing the page.","If Appium /status does not respond, the Appium server may not have started correctly. Please inspect the log output above for errors."];function A8(t,e){if(!t||!e)return;let r=t.split(/\r?\n/).map(n=>n.trim()).filter(n=>n.length>0);for(let n of r){if(n.startsWith("List of devices attached")||!n.startsWith(e))continue;let i=n.split(/\s+/)[1]?.toLowerCase();return i==="device"?"device":i==="offline"?"offline":i==="unauthorized"?"unauthorized":"unknown"}}function qxe(t){return t&&(/^\d{1,3}(\.\d{1,3}){3}:\d+$/.test(t)||/^localhost:\d+$/.test(t))?t:null}async function Kxe(t){return {adbSerial:t,devices:await qr(["devices","-l"],{timeoutMs:2500}),state:t?await qr(["get-state"],{serial:t,timeoutMs:5e3}):void 0,bootCompleted:t?await qr(["shell","getprop","sys.boot_completed"],{serial:t,timeoutMs:5e3}):void 0}}async function Yxe({logger:t,adbSerial:e,adbSnapshot:r,appiumLogHints:n,transportMode:o}){let i=A8(r.devices,e);if(!(i==="offline"||n.deviceOffline||n.instrumentationCrashed||n.uiAutomatorCrashed))return;let s=o==="tunneled"?qxe(e):void 0;if(t.warn({adbSerial:e,deviceState:i,appiumLogHints:n,transportMode:o},"Attempting best-effort recovery of Android transport"),o==="tunneled"&&s?(await qr(["start-server"],{timeoutMs:5e3}),await pe(500),await qr(["disconnect",s],{timeoutMs:5e3}),await pe(500),await qr(["connect",s],{timeoutMs:5e3}),await pe(500)):(await qr(["kill-server"],{timeoutMs:5e3}),await pe(500),await qr(["start-server"],{timeoutMs:5e3}),await pe(500),await qr(["reconnect","offline"],{timeoutMs:5e3}),await pe(500)),e){let l=await qr(["get-state"],{serial:e,timeoutMs:5e3});typeof l=="string"&&l.trim()==="device"&&(await qr(["shell","pm","clear","io.appium.uiautomator2.server"],{serial:e,timeoutMs:5e3}),await qr(["shell","pm","clear","io.appium.uiautomator2.server.test"],{serial:e,timeoutMs:5e3}));}}function R8({logger:t,onStatusUpdate:e,adbSerial:r,transportMode:n}){return async({err:o,attempt:i,appiumPort:a,appiumLogHints:s})=>{let l=o instanceof M?o:new M("UserInfrastructureError",W(o),{errOptions:{cause:o}}),c=await iD(a),u=await Kxe(r),d=A8(u.devices,r);t.error({err:o,appiumPort:a,appiumStatus:c,adbSnapshot:u,adbDeviceState:d,appiumLogHints:s},"Failed to create Appium WebDriver session"),e(`Appium session creation failed: ${W(o)}`);let m=i===1&&(a8(o)||IC(o)||d==="offline"||s.instrumentationCrashed||s.deviceOffline);if(!m)throw P.error(`Failed to create Appium WebDriver session. Troubleshooting:
|
|
268
268
|
- ${Gxe.join(`
|
|
269
269
|
- `)}`),l;return {shouldRetry:m,recover:()=>Yxe({logger:t,adbSerial:r,adbSnapshot:u,appiumLogHints:s,transportMode:n})}}}var x8=5e3;async function Lp({callbacks:t,creationOpts:e,apiClient:r,logger:n,driverLogLevel:o,socket:i,orgId:a,sessionId:s}){let l=Date.now();n.info("Starting android driver creation");let c=[],u,d;if("avdId"in e)d=e;else {d=await w8({apiClient:r,logger:n,creationOpts:e,onStatusUpdate:t.onStatusUpdate,orgId:a,sessionId:s,onConnectionStateChange:t.onLimbarConnectionStateChange});let f=d.emulatorName,h=d.close;u=async()=>r.deleteAndroidEmulator(f),c.push(h),n=n.child({emulatorName:f}),(async()=>{try{let[g,y]=await Promise.allSettled([rp("limserver-1.limrun.net"),rp("125.253.92.199")]);n.info({limserver:g.status==="fulfilled"?g.value:g.reason,ip125:y.status==="fulfilled"?y.value:y.reason},"Limbar network diagnostics");}catch(g){n.warn({err:g},"Failed to run network diagnostics");}})();}let m=async()=>{let f=c.toReversed();u&&(f.push(u),u=void 0);let h=f.map(g=>Promise.resolve(g()).catch(y=>{ju(y)||n.warn({err:y},"Error running cleanup task");}));try{await ee(Promise.allSettled(h),{milliseconds:x8,message:`Android driver cleanup timed out after ${x8}ms`});}catch(g){n.warn({err:g},"Android driver cleanup timed out");}},p=async()=>{if(i&&!i.connected)throw await m(),new M("UserInfrastructureError","Client disconnected before Appium driver could be started, cleaning up...")};await p();try{let f=await Qxe({logger:n,driverLogLevel:o,emulatorStart:l,emulatorCreationParams:d,apiClient:r,callbacks:t,creationOpts:e,orgId:a,sessionId:s}),h=f.driver;return c.push(f.appiumClose),await p(),{...d,...f,driver:h,cleanup:m}}catch(f){throw await m(),new M("UserInfrastructureError",`Failed to start Appium driver: ${f.message}`)}}async function Qxe({logger:t,driverLogLevel:e="error",emulatorCreationParams:r,callbacks:n,creationOpts:o}){let i=[],{adbPort:a,emulatorName:s}=r,l,c="tunneled";if(!a){c="local";let f=0;for(;f<10;){let h=5555+Math.floor(Math.random()*30);if(h%2!==0&&(h=Math.min(h+1,5584)),await sv(h)&&await sv(h+1)){l=h,a=h+1;break}f+=1;}if(!a)throw new M("UserInfrastructureError",`Failed to find an available ADB port after ${f} attempts`)}s||(s=`emulator-${l}`,n.onStatusUpdate("Killing existing emulators"),await M8(t),i.push(()=>M8(t)),n.onStatusUpdate("Starting new emulator"));let u={platformName:"Android","appium:automationName":"UiAutomator2","appium:deviceName":"Android","appium:udid":`127.0.0.1:${a}`,"appium:adbExecTimeout":3e4,"appium:newCommandTimeout":3600,"appium:skipDeviceInitialization":true,"appium:skipServerInstallation":true,"appium:androidInstallTimeout":6e4,"appium:autoWebview":false,"appium:autoWebviewTimeout":0,"appium:clearDeviceLogsOnStart":true,"appium:ensureWebviewsHavePages":true,"appium:noReset":true,"appium:fullReset":false,"appium:dontStopAppOnReset":true,"appium:shouldTerminateApp":false,"appium:forceAppLaunch":false,"appium:skipUnlock":true},d={capabilities:u,connectionRetryTimeout:3e4,connectionRetryCount:3};if("avdId"in r){u["appium:avd"]=r.avdId,u["appium:avdLaunchTimeout"]=18e4,u["appium:avdReadyTimeout"]=18e4,u["appium:skipDeviceInitialization"]=false,u["appium:skipServerInstallation"]=false,u["appium:udid"]=void 0;let f=eMe();u["appium:avdArgs"]=`-port ${l} -memory ${f} -no-snapshot-save -no-boot-anim -noaudio`,d.connectionRetryTimeout=12e4,d.connectionRetryCount=3;}let m=xu in r?s:`127.0.0.1:${a}`,p=await zC.init({logger:t,callbacks:{...n,onFailure:R8({logger:t,onStatusUpdate:n.onStatusUpdate,adbSerial:m,transportMode:c})},logLevel:e,wdioOpts:d});try{if("avdId"in o){let y=o.apkFilePath?.trim();if(y){let S=fr__default.resolve(y);if(!Sn.existsSync(S))throw new M("UserConfigurationError",`APK not found at path: ${S}`);n.onStatusUpdate("Installing local APK");let E=Date.now();try{await p.executeInNativeContext(t,v=>v.installApp(S),{operationName:"installApp"}),t.info({apkFilePath:S,installDurationMs:Date.now()-E},"Installed local APK");}catch(v){throw t.error({err:v,apkFilePath:S},"Failed to install local APK"),new M("UserConfigurationError",`Failed to install APK from ${S}: ${v.message}`)}}}let[f,h]=await Promise.all([qr(["shell","wm","size"],{serial:m,timeoutMs:5e3}),qr(["shell","wm","density"],{serial:m,timeoutMs:5e3}),p.executeInNativeContext(t,y=>y.updateSettings({enableMultiWindows:!0,waitForIdleTimeout:250,simpleBoundsCalculation:!0}),{operationName:"updateSettings"})]);return t.info({capabilities:u,emulatorName:s,viewport:{size:f?.trim(),density:h?.trim()}},"Started Appium driver"),{driver:p,appiumClose:async()=>{await p.close(),await Promise.all(i.map(y=>y()));},emulatorName:s,adbPort:a}}catch(f){throw t.error({err:f},"Failed to initialize emulator"),await p.close(),f}}async function M8(t){let n=(await qr(["devices"],{timeoutMs:5e3})??"").split(`
|
|
270
270
|
`).map(o=>o.trim().split(/\s+/)[0]).filter(o=>!!o?.startsWith("emulator-"));await Promise.all(n.map(async o=>{t.info({emulatorName:o},"Killing emulator");let i=await qr(["emu","kill"],{serial:o,timeoutMs:5e3});i&&t.warn({emulatorName:o,killResult:i},"Failed to kill emulator, continuing...");}));}function eMe(){let t=Math.floor(totalmem()/1024/1024),e=Math.floor(t/4);return Math.max(2048,Math.min(4096,Math.floor(e/256)*256))}var nMe="If you do not have Java installed, please download the JDK 24 from https://www.oracle.com/java/technologies/downloads/, move it to your home directory, and then set the JAVA_HOME environment variable in your shell profile to the JDK path.",oMe="If you do not have Android Studio installed, please download it first from https://developer.android.com/studio and then follow all setup instructions in the Android Studio app.",iMe="Follow the instructions at https://developer.android.com/tools/variables to set the ANDROID_HOME environment variable.",_8="On Mac OS, the SDK is typically installed at /Users/<username>/Library/Android/sdk.",O8="On Windows, the SDK is typically installed at C:\\Users\\<username>\\AppData\\Local\\Android\\Sdk.";function aMe(){if(!process.env.JAVA_HOME)P.warn("JAVA_HOME is not set. Some Appium drivers and Android tools may not work as expected.");else {process.platform==="darwin"&&/\.jdk\/?$/.test(process.env.JAVA_HOME)&&P.warn("JAVA_HOME appears to point at a *.jdk bundle, which is incorrect. The correct path should be formatted like '<bundle>/Contents/Home'.");let e=((r,n)=>join(r,"bin",process.platform==="win32"?`${n}.exe`:n))(process.env.JAVA_HOME,"java");existsSync(e)||P.warn(`JAVA_HOME does not appear to point to a valid Java installation: expected the 'java' binary to exist at ${e}`);}try{execSync("java --version",{stdio:"pipe",encoding:"utf-8"})||P.warn(`Could not find a Java installation. Some Appium drivers and Android tools may not work as expected. ${nMe}`);}catch(t){P.warn(`Got error while checking if the Java JDK is installed: ${W(t)}`);}}function sMe(){process.env.ANDROID_HOME||P.warn(`The ANDROID_HOME environment variable is not set. Some Appium drivers and Android tools may not work as expected. ${iMe} ${platform()==="darwin"?_8:O8}`);}function lMe(){let t=process.env.ANDROID_HOME?`${process.env.ANDROID_HOME}/platform-tools/adb`:"adb";try{execSync(`${t} version`,{stdio:"pipe",encoding:"utf-8"})||P.warn(`Could not find the Android Debug Bridge (ADB) tool locally. Some Appium drivers and Android tools may not work as expected. This tool is included with Android Studio. ${oMe} Finally, ensure that the 'adb' command is available in your shell. ${platform()==="darwin"?_8:O8}`);}catch(e){P.warn(`Got error while checking if ADB is installed: ${W(e)}`);}}function D8(){aMe(),sMe(),lMe();}var pMe=100,fMe=2500,L8=4e3,hMe="\u2026",gMe=1e3;async function $C({driver:t,onLogs:e,logFilePath:r}){await t.execute("mobile: startLogsBroadcast");let n=r?Sn.createWriteStream(r,{flags:"a"}):void 0,o=[],i=()=>{o.length===0||!n||(n.write(o.join(`
|
|
@@ -5712,7 +5712,7 @@ ${t}`;case "ELEMENT_CHECK":return `${zY}
|
|
|
5712
5712
|
${t}`;default:return t}}async function Qi({frameConfig:t,action:e,browser:r}){let n=r.getActiveFrameConfig();t?r.setActiveFrameConfig(t):n?.type==="auto"&&r.setActiveFrameConfig(void 0);try{return await e()}finally{r.setActiveFrameConfig(n);}}var E_e=["NAVIGATE","NEW_TAB","CLOSE_TAB","TAB","REFRESH","WAIT_FOR_URL"];async function jY({beforeUrl:t,beforePages:e,browser:r,command:n,logger:o}){if(E_e.includes(n.type))return;await Ir().startAsyncSpan("AUTO_FOLLOW_NEW_TABS",async a=>{let c=("cache"in n&&n.cache&&"target"in n.cache?n.cache.target:void 0)?.nodeOnlySerializedHtml?.includes("<a")??false?300:3e3,u=Date.now(),d=0;for(o.info({command:n.type,beforePages:e,beforeUrl:t,timeout:c},"Checking for new tabs to auto-follow");d===0||Date.now()-u<c;){await pe(250),d++;let m=(await r.getOpenPages()).map(f=>f.url),p=r.url();if(m.length!==e.length)for(let f=m.length-1;f>=e.length;f--){let h=m[f];if(lc(h,o)&&h!==t&&h!==p){o.info({beforePages:e,afterPages:m,beforeUrl:t},"Auto-following new tab after preset action"),await r.switchToPage({type:"INDEX",index:String(f)}),a.result={followed:true};return}}}a.result={followed:false};});}async function Oc(t,e={}){let r=await t.getBrowserState(e);return {serializedTree:r.serialize(e.serializationOpts),tree:r}}var HY=t=>!!t&&$d(t),WY=t=>{let{cache:e,description:r,disableSecondaryCacheResolution:n,logger:o}=t,i=e,a=false,s;return i&&n&&i.targetSource==="HEURISTIC_HEALED"&&(a=true,s="Heuristic healed cache incompatible",i=void 0),i?.inputDescription&&!$Y(r,i.inputDescription)&&(o.warn({old:i.inputDescription,new:r},"Target cache was generated with a different description, clearing it automatically"),a=true,s="Description changed",i=void 0),{cache:i,cacheBustedBeforeAction:a,cacheBustReason:s}};var qY={minChunkTokenCount:1e4,acceptableChunkTokenCount:25e3,maxChunkTokenCount:5e4,maxLineLength:4e3},GY=/<(\S+) id="(\d+)".*?>/g,v_e=/(<\/(\S+)>)|(<(\S+).*?\/>)/g,KY=["h1","h2","section","footer","nav","aside","form","label","dialog"],C_e=[...KY,"span","div","h3"],w_e=["table","select","form","ul","ol","menu","pre","code","dialog"],A_e=["table","form","dialog","nav","section","ul","select"];function YY(t){return R_e(t)}function R_e({logger:t,serializedTree:e,options:r}){let{minChunkTokenCount:n,acceptableChunkTokenCount:o,maxChunkTokenCount:i,maxLineLength:a}=r,s=[],l=e.split(`
|
|
5713
5713
|
`),c=0,u=[],d=0,m=[],p=[],f=false;for(;c<l.length;){f&&(s.push({ids:m,content:u.join(`
|
|
5714
5714
|
`),tokenLength:d}),u=[],d=0,m=p.length?[p[p.length-1].id]:[],f=false);let h=l[c],g=Ut(h);d+=g,h.length>a&&(h=h.slice(0,a));let E=Array.from(h.matchAll(GY)).map(U=>U&&U.length>=3?{tagName:U[1],id:U[2]}:void 0).filter(U=>!!U),w=Array.from(h.matchAll(v_e)).map(U=>U&&(U[2]||U[4])).filter(U=>!!U);w.reverse();let _=h.replace(/ id="[0-9]+"/g,"");u.push(_);for(let U of E)m.push(U.id),p.push(U);for(let U of w){let fe=p[p.length-1];fe&&fe.tagName===U&&p.pop();}let L=p.some(U=>w_e.includes(U.tagName)),I=l[c+1]??"",R=Ut(I),D=Array.from(I.matchAll(GY)).map(U=>U&&U.length>2?U[1]:void 0).filter(U=>!!U),V=D.some(U=>KY.includes(U)),$=D.some(U=>C_e.includes(U));d+R>=i&&(f=true),d>=n&&(V&&!L||w.some(U=>A_e.includes(U)))&&(f=true),d>=o&&$&&!L&&(f=true),c++;}return u.length&&s.push({ids:m,content:u.join(`
|
|
5715
|
-
`),tokenLength:d}),s.forEach((h,g)=>{let y=h.ids[0],S=h.ids[h.ids.length-1];t.debug({tokenLength:h.tokenLength,minId:y,maxId:S},`Chunk for page filtering (index ${g+1}/${s.length})`);}),{chunks:s}}var XY=5e6,M_e=1e5,P_e=3e4,I_e=6e4,__e=1e5;async function md(t){let{fixtures:e}=t,{logger:r}=e,n=t.tree,o=t.serializedTree,i=Ut(o);if(i>XY)throw new M("UserConfigurationError",`Page accessibility tree is too large for AI page filtering (${i} tokens). Maximum supported size is ${XY} tokens.`);if(i>M_e){let a=YY({serializedTree:o,options:qY,logger:r}),s=randomUUID();n=await O_e({...t,chunks:a.chunks,callId:s}),o=n.serialize();let l=Ut(o);r.info({oldTokens:i,newTokens:l,langfuseCallId:s},"Filtered page using AI chunk ranking");}return o}async function O_e({type:t,callId:e,chunks:r,description:n,fixtures:o,tree:i}){let{generator:a,signal:s,logger:l}=o,c=await a.rankChunksWithAi({chunks:r,description:n,type:t,softTokenLimit:P_e,mediumTokenLimit:I_e,hardTokenLimit:__e,callId:e},{abortSignal:s,logger:l,loggerTags:De(l)}),u=[];return r.forEach((m,p)=>{c.indices.includes(p)&&(u=u.concat(m.ids));}),i.pruneUsingRelevantIds(new Set(u))}async function nL(t,e){if(!t.description)throw new M("UserConfigurationError","Cannot locate element with empty description");return Qi({action:async()=>L_e(t,e),frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,browser:e.browser,logger:t.logger})}async function L_e(t,e){let{disableCache:r,testContext:n,filterByViewport:o,skipWait:i,source:a,memory:s,logger:l,allowNotActionableNodesOverride:c,allowIneligibleTagRedirect:u,showZeroOpacityElementsOverride:d,skipSavingVisualAttributes:m,isAutoHeal:p,cacheBustReason:f,acceptElementMovedError:h}=t,{orgId:g,browser:y,localCodeEvalTools:S,generator:E,abortSignal:v}=e,w=t.description,_=Ir(),L=t.useMemory&&!r;n&&(w=await fl({orgId:g,s:w,context:n,localTools:S,signal:v,logger:l})),a&&(w=VY(w,a));let{serializedTree:I,tree:R}=await _.startAsyncSpan("GET_PAGE_STATE",async()=>Oc(y,{allowNotActionableNodesOverride:c,allowIneligibleTagRedirect:u,showZeroOpacityElementsOverride:d,filterByViewport:o,abortSignal:v,skipWait:i,logger:l}),{}),k=await _.startAsyncSpan("GET_PAGE_SCREENSHOT",async()=>{let j,z=Date.now(),se;for(;!j&&Date.now()-z<3e3;){v.throwIfAborted();try{j=await y.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2});}catch(be){se=be;}}if(!j)throw new M("ActionFailureError",`Failed to take screenshot of page to locate element. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${se?.message}`);return j}),D=I,V=false,U=`data:image/jpeg;base64,${k.toString("base64")}`,fe=De(l);D=await md({type:"locator",description:w,screenshot:U,serializedTree:I,tree:R,fixtures:{generator:E,signal:v,logger:l,orgId:g}}),D!==I&&(V=true);let q=await _.startAsyncSpan("AI_LOCATOR_CALL",async j=>{p&&(j.attributes.isAutoHeal=true),f&&(j.attributes.cacheBustReason=f);let z=await E.getElementLocation({browserState:D,goal:w,screenshot:U,source:a,memory:L?s:void 0},{disableCache:r,abortSignal:v,logger:l,loggerTags:fe,useMemory:L,cacheBustReason:f});if(j.result=z,L&&(j.attributes.useMemory=true,j.attributes.memoryTraces=z.rememberedTraces??[],z.updatedMemory&&(j.attributes.memorySavedNewResult=true)),_.storeTraceAsset){let se=randomUUID();_.storeTraceAsset({snapshotId:se,data:k}),j.screenshotSnapshotId=se;}return z});if(l.debug({usedRag:V,result:q},"Got locator result"),!(q.id>0))throw new Wa(`Could not find any relevant element: ${q.thoughts}`,q.updatedMemory?{type:"GCS_TRACES",traces:q.updatedMemory}:void 0);let{resolution:F,target:B,frameConfig:te}=await _.startAsyncSpan("TARGET_RESOLUTION",async j=>{let z=await y.createTargetFromA11yId({id:q.id,requirements:q.requirements,additionalElements:q.additionalElements,description:w,targetSource:"AI",logger:l,skipSavingVisualAttributes:m,acceptElementMovedError:h});return j.result={serializedElement:z.target.nodeOnlySerializedHtml??"Unknown HTML element"},z});if(F.a11yNode?.properties?.hidden&&F.a11yNode?.properties?.hidden!=="false")throw new M("ActionFailureError",`Momentic's AI found a relevant element to interact with, but it is explicitly marked with an 'aria-hidden' attribute. Please remove this attribute or adjust the element description to locate a different element. Element chosen: ${F.displayString}`);return L&&(q.updatedMemory?B.memory={type:"GCS_TRACES",traces:q.updatedMemory}:s&&(B.memory=s)),{thoughts:q.thoughts,target:B,resolution:F,frameConfig:te,screenshot:U}}var N_e=15;async function sw({command:t,logger:e,fixtures:r,useMemory:n,maxRetries:o=N_e,recoveryHint:i}){if(!t.assertion.trim())throw new M("ActionFailureError","Assertion command is missing the assertion content");let a=EM.optional().catch(void 0).parse(t.source);t.source&&!a&&e.warn(`Invalid source ${t.source} for AI assertion, ignoring...`);let s=Ir();return s.startAsyncSpan("AI_ASSERTION_CALL",async l=>{let{browser:c}=r,u=t.timeout?t.timeout*1e3:c.smartWaitingTimeout,d=D3(u,o-1),m=0,p=Date.now(),f=p+u,h=p,g,y,S;try{await Qi({action:()=>c.clearHighlights(),frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,browser:c,logger:e});}catch(w){e.warn({err:w},"Failed to clear highlights before AI check, continuing...");}for(;m<o;){r.abortSignal.throwIfAborted();let w=Date.now();if(m>0){if(w>=f)break;let I=f-w,R=h-w,k=Math.min(R,I);k>0&&await pe(k,r.abortSignal);}let _=Date.now();if(m>0&&_>=f)break;let L=false;try{if(g=await Qi({action:async()=>{let R=await ZY(c,e,r.abortSignal);return y&&y.serializedTree===R.serializedTree&&y.screenshotBuff.equals(R.screenshotBuff)?(L=!0,g):(y=R,QY({command:t,state:R,fixtures:r,useMemory:n,useConsensus:!1,highlightElementsOnFailure:!1,attemptNumber:m,logger:e,source:a,recoveryHint:i}))},frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,logger:e,browser:c}),g?.aiResult.result){g?.updatedMemory&&Bg(t,g.updatedMemory,e);break}else throw g?.aiResult.thoughts?new M("AssertionFailureError",g.aiResult.thoughts):new M("InternalPlatformError","No thoughts were provided for AI assertion failure")}catch(I){r.abortSignal.throwIfAborted(),S=I instanceof Error?I:new Error(`${I}`),L?e.info(`AI check attempt ${m} failed (re-used previous result)`):e.info({err:I},`AI check assert attempt ${m} failed, retrying...`);}finally{m++,h=_+d;}}if(!g?.aiResult.result){let w=f-Date.now();w>0&&await pe(w,r.abortSignal);}if(!g?.aiResult.result)try{g=await Qi({action:async()=>QY({command:t,state:await ZY(c,e,r.abortSignal),fixtures:r,useMemory:n,useConsensus:!0,highlightElementsOnFailure:!0,attemptNumber:m,logger:e,recoveryHint:i}),frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,logger:e,browser:c});}catch(w){r.abortSignal.throwIfAborted(),S=w instanceof Error?w:new Error(`${w}`);}finally{m++;}g?.updatedMemory&&Bg(t,g.updatedMemory,e);let E=g?.afterScreenshotOverride;if(E&&s.storeTraceAsset){let w=randomUUID();s.storeTraceAsset({snapshotId:w,data:E}),l.screenshotSnapshotId=w;}let v=g?.elementScreenshotOverride;if(v&&s.storeTraceAsset){let w=randomUUID();s.storeTraceAsset({snapshotId:w,data:v}),l.elementScreenshotSnapshotId=w;}if(n&&(l.attributes.useMemory=true,l.attributes.memoryTraces=g?.aiResult.rememberedTraces??[],g?.updatedMemory&&(l.attributes.memorySavedNewResult=true)),!g?.aiResult.result){l.result=g?.aiResult??{thoughts:S?.message??"AI check failed after all attempts",result:false};let w=`AI check still failing after ${m} attempts.`;throw S&&(w+=` Latest result: ${S.message}`),new M("AssertionFailureError",w)}return l.result=g.aiResult,{...g,thoughts:g.aiResult.thoughts,succeedImmediately:false,urlAfterCommand:c.url()}})}async function ZY(t,e,r){await t.waitForPageLoad({signal:r});let[n,o]=await Promise.all([Oc(t,{abortSignal:r,skipWait:true,skipWaitForPageLoad:true,logger:e}),t.screenshot({retries:1,respectActiveFrame:true})]);return {...n,screenshotBuff:o}}async function QY({command:t,state:e,fixtures:r,useConsensus:n,useMemory:o,highlightElementsOnFailure:i,attemptNumber:a,source:s,logger:l,recoveryHint:c}){let {browser:u,generator:d,abortSignal:m}=r,{serializedTree:f,tree:h}=e,g=e.screenshotBuff,y=g.toString("base64"),S=u.url(),E=t.contextChoice??"MULTIMODAL",v=f;E!=="VISION_ONLY"&&(v=await md({type:"assertion",serializedTree:f,tree:h,description:t.assertion,screenshot:y,fixtures:{generator:d,signal:m,logger:l,orgId:r.orgId}}),v);let w={goal:t.assertion,url:S,memory:o?t.cache?.memory:void 0,browserState:v,screenshot:y,contextChoice:E,source:s,recoveryHint:c},L=await(E==="VISION_ONLY"?(R,k)=>d.getVisualAssertionResult(R,k):(R,k)=>d.getAssertionResult(R,k))(w,{useConsensus:n,attemptNumber:a,useMemory:o,disableCache:!!t.disableCache,abortSignal:m,logger:l,loggerTags:De(l)}),I;if((L.result||i)&&L.relevantElements?.length){L.relevantElements.map(R=>u.getSerializedFormFromA11yId(R)).filter(R=>!!R);try{let R=L.relevantElements[0],{resolution:k}=await u.createTargetFromA11yId({id:R,description:null,targetSource:"AI",skipSaveToCache:!0});I=await u.screenshot({locator:k.locator,clearHighlights:!0,respectActiveFrame:!0});}catch(R){l.debug({err:R},"Failed to capture element screenshot for trace, continuing...");}await k_e(L.relevantElements,u,l);}return {aiResult:L,afterScreenshotOverride:g,elementScreenshotOverride:I,updatedMemory:o?L.updatedMemory:void 0}}async function k_e(t,e,r){let n=Date.now();for(let o of t){if(Date.now()-n>2e3){r.debug("Highlighting relevant elements took over 2s, aborting...");return}try{let i=new AbortController;await ee(e.highlightA11yId(o),{milliseconds:1e3,fallback:()=>{throw i.abort(),new Error("Timed out waiting for highlighting to complete")}});}catch(i){r.debug({err:i},"Failed to highlight relevant element after assertion, continuing...");return}}}async function tX(t){let{command:e,logger:r,fixtures:n,disableCache:o}=t,{browser:i,generator:a,abortSignal:s}=n;if(!e.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(e.schema){let d=Vm(e.schema);if(d)throw new M("UserConfigurationError",d)}let l=await i.getCondensedHtml(),c=await i.screenshot({retries:2}),u=Ir();try{return await u.startAsyncSpan("AI_EXTRACTION_CALL",async d=>{let m=await a.getTextExtraction({goal:e.goal,browserState:l,returnSchema:e.schema,screenshot:`data:image/jpeg;base64,${c.toString("base64")}`},{disableCache:o,abortSignal:s,loggerTags:De(r)});if(d.result=m,F_e({tracer:u,span:d,screenshot:c,htmlState:l,logger:r}),m.result==="NOT_FOUND")throw new M("ActionFailureError","No relevant data found for extraction goal on this page");if(m.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",m.thoughts);return {thoughts:m.thoughts||void 0,data:m.result,succeedImmediately:!1,urlAfterCommand:i.url()}})}catch(d){let m=W(d);throw m.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step in the browser instead."):m.includes("AIProviderError")&&m.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:d}}):d}}function F_e(t){let{tracer:e,span:r,screenshot:n,htmlState:o,logger:i}=t;if(e.storeTraceAsset)try{let a=randomUUID();e.storeTraceAsset({snapshotId:a,data:n}),r.screenshotSnapshotId=a;let s=randomUUID();e.storeTraceAsset({snapshotId:s,data:Buffer.from(o),extension:"html"}),r.browserStateSnapshotId=s;}catch(a){i.debug({err:a},"Failed to store extraction trace assets");}}async function rX(t,e){let{logger:r}=t,{abortSignal:n,browser:o}=e,i=Date.now();try{await B_e(i,t,e);}catch(a){if(a instanceof Error&&(a.name==="AbortError"||a.name==="TimeoutError")||n.aborted)return;r.warn({err:a},"Unexpected error occurred during AI smart waiting");let s=o.smartWaitingTimeout-(Date.now()-i);s>0&&await pe(s,n);}finally{r.debug({durationMs:Date.now()-i},"AI smart waiting complete");}}async function B_e(t,e,r){let{abortSignal:n,browser:o}=r;if(o.smartWaitingTimeout<3e3){await pe(o.smartWaitingTimeout,n);return}if(!e.description)throw new M("UserConfigurationError","Cannot locate element with empty description");await ee(U_e(t,e,r),{milliseconds:o.smartWaitingTimeout});}async function U_e(t,e,r){let{logger:n,iframeUrl:o}=e,{browser:i}=r;for(;Date.now()-t<i.smartWaitingTimeout;)if(await Qi({action:async()=>z_e(e,r),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function z_e(t,e){let{testContext:r,logger:n}=t,{browser:o,abortSignal:i,localCodeEvalTools:a,orgId:s,generator:l}=e,c=t.description;r&&(c=await fl({orgId:s,s:c,context:r,localTools:a,signal:i,logger:n})),i.throwIfAborted();let u;try{u=await o.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2});}catch(f){throw new M("ActionFailureError",`Failed to take screenshot of page to perform smart waiting. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${f instanceof Error?f.message:f}`)}let m=`data:image/jpeg;base64,${u.toString("base64")}`;i.throwIfAborted();let p=await l.getSmartWaitingDecision({description:c,screenshot:m},{abortSignal:i,loggerTags:De(n)});return n.debug({result:p},"Got smart waiting result"),p.isPageReady}var $_e=3e4;async function iX(t){return Ir().startAsyncSpan("ELEMENT_ASSERTION",async r=>V_e(t,r),{name:"Element check"})}async function V_e(t,e){let{command:r,timeoutMs:n,fixtures:o,disableCache:i}=t,{abortSignal:a}=o,s=()=>Dx(r.cache)?r.cache:void 0,l=s(),c=!i&&!!l?.target&&$d(l.target),u=cloneDeep(l),d=(v=false)=>{if(l=s(),!!l)if(v){let w=f3(u,l);l.target=w.target,l.updatedAt=w.updatedAt;}else {if(!u){l=void 0;return}l.target=u.target,l.updatedAt=u.updatedAt;}},m=Date.now(),p=c?Math.max(n/10,$_e):0,f=m,h=0,g,y=500,S=false;for(;h<2||Date.now()-m<n;){h++,h>1&&await pe(y,a),a?.throwIfAborted(),l=s();let v=h===1,w=c&&Date.now()-f>=p;w&&(f=Date.now());let{result:_,elementWasFound:L}=await nX({cacheToUse:l,skipAISmartWaiting:!v,useAIIfCacheFails:!c||w,params:t});if(g=_,S=S||L,_.success)break;d(),y=Math.min(y*1.25,1e4);}if(!g)throw new M("InternalPlatformError",`Failed to evaluate manual element assertion in ${n}ms.`);if(a?.throwIfAborted(),!g.success){let v=s(),w=v?.target?.memory?{target:{id:-1,memory:v.target.memory}}:void 0,{result:_,elementWasFound:L}=await nX({cacheToUse:w,skipAISmartWaiting:true,useAIIfCacheFails:true,params:t});g=_,S=S||L,g.success||d(true);}let E=s();return g.success&&E?.target&&!S&&(E.target=L_(E.target),E.updatedAt=new Date),e.result={success:g.success,message:g.err?.message},g}async function nX({cacheToUse:t,skipAISmartWaiting:e,useAIIfCacheFails:r,params:n}){let{command:o,disableCache:i,fixtures:a,tracer:s,targetingWrapper:l}=n,{logger:c}=a;if(o.target&&!zs(o.target))throw new Error("Element assertion with x/y is not supported yet");let u=ap(o.assertion),d=j_e(o.assertion),m,p=false,f=cloneDeep(t);try{let{elementInteractedDisplayString:h,result:g,thoughts:y}=await l({tracer:s,command:o,target:o.target,cache:f?.target,action:async S=>H_e(S.locator,n),options:{...o,allowNotActionableNodesOverride:d,allowIneligibleTagRedirect:d,showZeroOpacityElementsOverride:!0,disableCache:i,memory:f?.target?.memory,disableGlobalLocatorRedirect:!0,source:Ah(o),skipAISmartWaiting:e,targetName:"target"},retriesWithAI:r?1:0});return m={success:g.success,data:g.data,err:g.err,elementInteractedDisplayString:h,thoughts:y},p=!0,g.success||(c.warn({aiThoughts:y,elementString:h,err:g.err},"Element check found an element but failed"),m={...g,thoughts:y}),{result:m,elementWasFound:p}}catch(h){if(u)return m={success:true,thoughts:`The element described does not exist on the page: ${h.message}`,err:void 0,data:void 0},{result:m,elementWasFound:p};if(!(h instanceof M)||h.reason!="ActionFailureError")throw h;return m={success:false,err:h,data:void 0,thoughts:void 0},c.warn({err:h},"Element check did not find an element and failed"),{result:m,elementWasFound:p}}}function j_e(t){return !(t.type==="ELEMENT_EXISTENCE"&&t.condition==="VISIBLE"&&!t.negated)}async function H_e(t,{command:e,fixtures:r}){return await r.browser.highlight(t),await W_e(t,e.assertion)}async function W_e(t,e){let r=true,n,o;switch(e.type){case "ELEMENT_CONTENT":{let a=await t.textContent()??"";if(o={elementTextContent:kr(a,500,true)},!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let s=wn(e);r=false,n=new M("AssertionFailureError",`The content ${s} '${e.value}': ${a}`);}break}case "ELEMENT_ATTRIBUTE":{o={elementOuterHtml:kr(await t.evaluate(s=>s.cloneNode(false).outerHTML),500,true)};let a=null;try{a=await t.getAttribute(e.attr,{timeout:3e3});}catch(s){n=new M("AssertionFailureError",W(s)),r=false;break}if(!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let s=wn(e);r=false,e.operation==="EXISTS"?n=new M("AssertionFailureError",`The attribute ${e.attr} ${s}`):n=new M("AssertionFailureError",`The attribute ${e.attr} ${s} '${e.value}': ${a}`);}break}case "ELEMENT_EXISTENCE":{switch(e.condition){case "VISIBLE":{r=await t.evaluate(async(s,l)=>{let c=Date.now();for(;Date.now()-c<l;){await new Promise(d=>setTimeout(d,250));let u=s.getBoundingClientRect();if(!(u.width===0||u.height===0)&&window.getComputedStyle(s).visibility!=="hidden"&&window.getComputedStyle(s).display!=="none")return true}return false},un*1e3);break}case "EDITABLE":{r=await t.isEditable({timeout:un*1e3});break}case "EXISTS":{r=true;break}case "ENABLED":{r=await t.isEnabled({timeout:un*1e3});break}case "FOCUSED":{r=await t.evaluate(s=>s===document.activeElement);break}default:return (s=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})(e.condition)}if(r=e.negated?!r:r,!r){let a=wn(e);n=new M("AssertionFailureError",`The element ${a}`);}break}case "ELEMENT_NAME":{let a=await t.evaluate(s=>s.tagName);if(!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:true})){let s=wn(e);r=false,n=new M("AssertionFailureError",`The element tag name ${s} '${e.value}': ${a}`);}break}case "ELEMENT_STYLE":{let a=await t.evaluate((s,l)=>window.getComputedStyle(s).getPropertyValue(l),e.property);if(!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let s=wn(e);r=false,e.operation==="EXISTS"?n=new M("AssertionFailureError",`The style property ${e.property} ${s}`):n=new M("AssertionFailureError",`The style property ${e.property} ${s} '${e.value}': ${a}`);}break}default:return (a=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})()}return {thoughts:void 0,success:r,data:o,err:n}}function aX(t){return t.type==="ELEMENT_EXISTENCE"&&t.negated&&t.condition==="EXISTS"}async function Ob(t,e){let r=await t.screenshot(e),{width:n,height:o}=imageSize(r);return {buffer:r,width:Math.ceil(n),height:Math.ceil(o)}}async function lX(t){let{command:e,browser:r,logger:n}=t;if(e.target&&!zs(e.target))throw new Error("Visual Diff with x/y is not supported yet");return await r.waitForStability({logger:n}),Ir().startAsyncSpan("VISUAL_DIFF",async i=>{try{let a=await K_e(t);return i.result={success:!a.fail,message:a.thoughts},a}catch(a){throw a instanceof M&&(i.result={success:false,message:a.message}),a}},{name:"Compare against golden"})}async function K_e({tracer:t,command:e,disableCache:r,browser:n,targetingWrapper:o,logger:i,screenshotStorage:a}){let s={clearHighlights:true,hideCaret:true},l=e.target&&zs(e.target)?e.target:void 0,c;l?.elementDescriptor?c=(await o({tracer:t,command:e,target:l,cache:e.cache?.target,action:async D=>Ob(n,{locator:D.locator,...s}),options:{...e,disableCache:r,disableGlobalLocatorRedirect:true,memory:e.cache?.target?.memory,targetName:"target"}})).result:c=await Ob(n,s);let u=await a.prepareGoldenScreenshotForComparison(i,e,c);if((c.height!==u.height||c.width!==u.width)&&i.warn({currHeight:c.height,currWidth:c.width,savedHeight:u.height,savedWidth:u.width},"Mismatched before and after visual diff screenshot sizes"),Math.abs(c.height-u.height)>10||Math.abs(c.width-u.width)>10){let k=`${c.width}x${c.height}`,D=`${u.width}x${u.height}`;return {fail:true,thoughts:`Current screenshot (${k}) does not match saved screenshot dimensions (${D}) - did you change the size of the target or the viewport?`,beforeScreenshotOverride:u.buffer,afterScreenshotOverride:c.buffer,succeedImmediately:false,urlAfterCommand:n.url()}}let d=await Jimp.fromBuffer(c.buffer),m={width:c.width,height:c.height},p=await Jimp.fromBuffer(u.buffer),f={width:u.width,height:u.height},h,g=m.width*m.height,y=f.width*f.height,S=Math.abs(m.height-f.height),E=Math.abs(m.width-f.width);if(g>y){let k=d.cover({w:f.width,h:f.height});c.buffer=await k.getBuffer("image/jpeg"),h="current",c.width=f.width,c.height=f.height;}else if(y>g){let k=p.cover({w:m.width,h:m.height});u.buffer=await k.getBuffer("image/jpeg"),h="saved";}let v={data:Buffer.alloc(c.width*c.height*4),width:c.width,height:c.height},w=e.threshold??.1,L=Q9(oL.decode(u.buffer).data,oL.decode(c.buffer).data,v.data,c.width,c.height,{threshold:w,diffColorAlt:[0,255,0]})/(c.width*c.height)*100,I=L>w*100,R=`Visual diff of ${L.toFixed(2)}% detected, which is ${I?"over":"under"} the threshold of ${w*100}%.`;if(h&&(R+=` The ${h} screenshot was cropped since it was taller by ${S} pixels and wider by ${E} pixels.`),I)throw new M("ActionFailureError",R);return {fail:I,thoughts:R,beforeScreenshotOverride:c.buffer,afterScreenshotOverride:oL.encode(v,75).data,succeedImmediately:false,urlAfterCommand:n.url()}}var Y_e=3e4;function X_e(t){if(!t.body)return {};switch(t.body.type){case "json":return {content:t.body.content,contentType:"application/json"};case "form-urlencoded":{let e=new URLSearchParams;return Object.entries(t.body.content).forEach(([r,n])=>{e.append(r,n);}),{content:e.toString(),contentType:"application/x-www-form-urlencoded;charset=UTF-8"}}}}async function jp({command:t,logger:e,baseUrl:r,fetchImplementation:n=fetch}){let o=t.timeout??Y_e/1e3,i=Object.fromEntries(Object.entries(t.headers||{}).filter(([f,h])=>f&&h)),a=new URLSearchParams;Object.entries(t.params||{}).filter(([f,h])=>f&&h).forEach(([f,h])=>{a.append(f,h);});let s=a.toString(),l;if(lp(t.url)&&(l=t.url),r&&cp(t.url,r)&&(l=new URL(t.url,r).toString()),!l)throw new M("ActionFailureError",`Invalid URL: ${t.url}`);let c=l;e.info({url:c,searchParams:s,headers:i,body:t.body,method:t.method},"Making HTTP request");let d=await ee((async()=>{let f=s?`${c}?${s}`:c;try{let h=X_e(t),g=new Headers(i);return h.contentType&&!g.has("Content-Type")&&g.set("Content-Type",h.contentType),await n(f,{headers:g,method:t.method,body:h.content})}catch(h){throw new Error(`Failed to make HTTP request: ${h}`,{cause:h})}})(),{milliseconds:o*1e3,fallback:()=>{throw new M("ActionFailureError",`Fetch request timed out after ${o} seconds`)}});if(!d.ok){let f;try{f=await d.text();}catch(h){f=`Failed to read response body: ${h}`;}throw new M("ActionFailureError",`Fetch request failed with status ${d.status}: ${f}`)}let m={};d.headers.forEach((f,h)=>{m[h]=f;});let p={status:d.status,headers:m,request:{url:d.url,method:t.method,headers:i}};if(t.body?.type==="json"&&t.body.content)try{p.request.json=JSON.parse(t.body.content);}catch{}if(d.headers.get("content-type")?.includes("json"))try{p.json=await d.json();}catch{}else d.headers.get("content-type")?.includes("text")&&(p.text=await d.text());return p}var J_e=5e3;async function dX({timeout:t=un,...e}){let r=Date.now(),n=t*1e3,o=n+1e4,i,a=0,s=500;for(;a-r<n;){if(Date.now()-r>o){e.logger.warn("Exceeded max system timeout for page assertion, exiting...");break}e.signal?.throwIfAborted();let l=Date.now();i=await cX(e),a=Date.now();let c=a-l;if(c>1e3&&e.logger.warn({pageAssertDuration:c},"Page assertion took longer than expected"),!i.success)await pe(s,e.signal),s=Math.min(Math.floor(s*1.5),J_e);else return i}return i=await cX(e),i}async function cX(t){return Ir().startAsyncSpan("PAGE_ASSERTION",async r=>{let n=await iL(t);return r.result={success:n.success,message:n.err?.message},n},{name:"Page check"})}async function iL({assertion:t,browser:e,autoExpandIframes:r}){switch(t.type){case "CONTENT":case "CONTENT":{let o,i=false,a;try{let s;if(r){let l=await e.evaluateFunctionInAllFrames(uX,{value:t.value,negated:!!t.negated,returnHtml:!1});i=t.negated?l.every(c=>c.evaluation):l.some(c=>c.evaluation),s=l.find(c=>c.pageHtml)?.pageHtml;}else ({evaluation:i,pageHtml:s}=await e.evaluateFunctionInPage(uX,{value:t.value,negated:!!t.negated,returnHtml:!0},"checking page content"));if(!i){let l=t.negated?nl.CONTAINS:ol.CONTAINS;a=new M("AssertionFailureError",`The page ${l} '${t.value}'.`),o=s;}}catch(s){a=new M("AssertionFailureError",`Failed to evaluate page content assertion: ${s instanceof Error?s.message:`${s}`}`);}return {success:i,err:a,data:i||!o?void 0:{pageContent:o}}}default:return (o=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})()}}function uX({value:t,negated:e,returnHtml:r}){let n=document.body.innerHTML,o=n.includes(t)===!e;return n.length>1e4&&(n=n.slice(0,1e4)+"...TRUNCATED"),{evaluation:o,pageHtml:!o&&r?n:void 0}}var Z_e=3e4;async function mX({command:t,logger:e,baseUrl:r,fetchImplementation:n=fetch}){let o=t.timeout??Z_e/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(t.headers||{}).filter(([d,m])=>d&&m));a["Content-Type"]="application/json";let s;if(lp(t.url)&&(s=t.url),r&&cp(t.url,r)&&(s=new URL(t.url,r).toString()),!s)throw new M("ActionFailureError",`Invalid URL: ${t.url}`);let c=await ee((async()=>{try{return await n(s,{headers:a,method:"POST",body:JSON.stringify({query:t.query,variables:t.variables?JSON.parse(t.variables):void 0}),signal:i.signal})}catch(d){throw new Error(`Failed to make HTTP request: ${d}`,{cause:d})}})(),{milliseconds:o*1e3});if(!c)throw new M("ActionFailureError",`GraphQL request timed out after ${o} seconds`);if(!c.ok){let d,m=await c.text();try{d=JSON.parse(m);}catch{throw new M("ActionFailureError",`GraphQL request failed with status ${c.status}: ${m}`)}throw d?.errors?.length&&d?.errors[0]?.message?new M("ActionFailureError",`GraphQL request failed with status ${c.status}: ${d.errors[0].message}`):new M("ActionFailureError",`GraphQL request failed with status ${c.status}: ${m}`)}let u={};return c.headers.forEach((d,m)=>{u[m]=d;}),{status:c.status,headers:u,json:await c.json()}}var lw=class{orgId;options;storage;localCodeEvalTools;uploadedFileStorage;visualDiffScreenshotStorage;browser;generator;executeAbortController=new AbortController;logger;executionOptionsStack=[];recordAbortController=null;registeredListeners={};recordedRequests={};constructor({browser:e,generator:r,logger:n,storage:o,orgId:i,localCodeEvalTools:a,uploadedFileStorage:s,visualDiffScreenshotStorage:l,options:c}){this.orgId=i,this.options=c,this.browser=e,this.browser.registerAbortSignal(this.executeAbortController.signal),this.storage=o,this.uploadedFileStorage=s,this.visualDiffScreenshotStorage=l,this.localCodeEvalTools=a,this.generator=r,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 withExecutionOptions(e,r){this.executionOptionsStack.push(e);try{return await r()}finally{this.executionOptionsStack.pop();}}getCurrentExecutionOptions(){return this.executionOptionsStack[this.executionOptionsStack.length-1]??{}}async evaluateAiAction({goal:e,startingScreenshot:r,history:n,disableCache:o,langfuseSessionId:i,lastError:a,logger:s=this.logger}){let[l,c]=await Promise.all([Oc(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:true,skipWaitForPageLoad:true,logger:s}),this.browser.screenshot({retries:1,clearHighlights:true})]),u=`data:image/jpeg;base64,${c.toString("base64")}`,d=await md({type:"ai-action",description:e,screenshot:u,serializedTree:l.serializedTree,tree:l.tree,fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:s,orgId:this.orgId}}),m={url:this.browser.url(),browserState:d,startingScreenshot:r,history:n,goal:e,screenshot:u,lastError:a};return await this.generator.getMultiturnAiActionEvaluation(m,{disableCache:o,abortSignal:this.executeAbortController.signal,loggerTags:{...De(s)},langfuseSessionId:i})}async promptToCommand({goal:e,startingScreenshot:r,history:n,actionHint:o,disableCache:i,logger:a=this.logger,langfuseSessionId:s}){let l=this.browser.url(),[c,u]=await Promise.all([Oc(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:true,skipWaitForPageLoad:true,logger:a}),this.browser.screenshot({retries:1,clearHighlights:true})]),d=`data:image/jpeg;base64,${u.toString("base64")}`,m=await md({type:"ai-action",description:e,screenshot:d,serializedTree:c.serializedTree,tree:c.tree,fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:a,orgId:this.orgId}}),p={url:l,browserState:m,startingScreenshot:r,history:n,goal:e,actionHint:o,screenshot:d};try{return await this.generator.getMultiturnAiActionCommand(p,{disableCache:i,abortSignal:this.executeAbortController.signal,loggerTags:{...De(a)},langfuseSessionId:s})}catch(f){throw new M("InternalWebAgentError",`Error generating command: ${f instanceof Error?f.message:f}`,{errOptions:{cause:f}})}}async getBrowserState(e){return Oc(this.browser,e)}async locateElement(e){return await nL(e,this.getControllerFixtures())}async locateElementWithSelector(e,r){return Qi({action:async()=>{let n=await this.browser.resolveHardcodedCssSelector({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:r?{type:"url",url:r}:void 0,browser:this.browser,logger:this.logger})}getControllerFixtures(){return {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??true}async wrapMultiElementTargetingCommand({tracer:e,command:r,targetNames:n,descriptions:o,caches:i,action:a,options:s,retriesWithAI:l=1}){let c=[];for(let u=0;u<o.length;u++){let d=o[u],m=await this.wrapElementTargetingCommand({tracer:e,command:r,target:d,cache:i[u],action:async p=>p,options:{...s,targetName:n[u]}});c.push(m);}try{let u=await a(...c.map(p=>p.result)),d=p=>p==="fromTarget"?"From Target":p==="toTarget"?"To Target":"Target",m=c.map((p,f)=>p.thoughts?`${d(n[f])}: ${p.thoughts}`:void 0).filter(p=>!!p).join(" -------------- ")||void 0;return {result:u,elementInteractedDisplayStrings:c.map(p=>p.elementInteractedDisplayString),thoughts:m}}catch(u){if(this.throwIfClosed(),l>0)return this.logger.warn({err:u},"Failed to execute action with multiple cached targets, retrying with AI"),this.wrapMultiElementTargetingCommand({tracer:e,command:r,targetNames:n,descriptions:o,caches:o.map(()=>{}),action:a,options:s,retriesWithAI:l-1});throw new M("ActionFailureError",u.message,{errOptions:{cause:u}})}}async wrapHardcodedCssTargetingCommandHelper({target:e,action:r,options:n,command:o}){let i=this.logger.child({commandId:o.id}),{targetName:a}=n;if(e.type!=="description")throw new M("ActionFailureError","Cannot use selector with non-description target");let s,l=Date.now(),c=Date.now();for(;Date.now()-c<this.browser.smartWaitingTimeout;){l=Date.now();try{let u=await this.browser.resolveHardcodedCssSelector({selector:e.elementDescriptor,targetName:a,logger:i});return {result:await r({locator:u.locator,originalElementLocationResult:void 0,serverSideBoundingBox:null}),elementInteractedDisplayString:u.displayString}}catch(u){if(u.name==="AbortError")throw u;s=u,i.warn({err:u},"Failed to action on hardcoded css selector"),Date.now()-l<500&&await pe(500);}}throw s}async scrollIntoViewAndResolveFinalTarget(e){let{resolutionResult:r,disableGlobalLocatorRedirect:n,logger:o}=e,i=Ir(),a=!n&&this.browser.userBrowserSettings.globalLocatorRedirect!==false;(this.browser.userBrowserSettings.visualActions||a)&&await i.startAsyncSpan("SCROLL_ELEMENT_INTO_VIEW",async()=>{await this.browser.scrollIntoViewIfNeeded(r.locator);});let s;return a&&(s=await i.startAsyncSpan("LOCATOR_REDIRECT",async l=>{let{targetingResult:c,metadata:u}=await this.browser.performTargetRedirection(r,o);if(l.result=u,u.outcome==="redirected to new element"&&c&&i.storeTraceAsset&&!this.browser.userBrowserSettings.disableBrowserMonitoring){let d=randomUUID();(async()=>{try{let m=await this.browser.screenshot({locator:c.locator,clearHighlights:!0,boundingBoxOverride:c.serverSideBoundingBox??void 0});i.storeTraceAsset?.({snapshotId:d,data:m});}catch(m){o.debug({err:m},"Failed to capture element screenshot for redirect trace");}})(),l.elementScreenshotSnapshotId=d;}return c})),s||(s={locator:r.locator,serverSideBoundingBox:await r.locator.boundingBox({timeout:ke}),originalElementLocationResult:r.originalElementLocationResult}),s}async resolveCachedTargetForAction(e){let{cache:r,options:n,logger:o}=e,a=await Ir().startAsyncSpan("CACHE_RESOLUTION",async l=>{l.targetSource=r.targetSource,l.attributes.smartWaitingTimeoutMs=this.browser.smartWaitingTimeout;try{let c=await this.browser.resolveTarget(r,{allowNotActionableNodesOverride:n.allowNotActionableNodesOverride,logger:o,signal:this.executeAbortController.signal,...n.resolveTargetOptions,acceptElementMovedError:n.force});l.attributes.targetDisplayString=c.displayString,l.attributes.decisions=c.decisions;let u=c.decisions.find(d=>d.matched);return u&&(l.resolutionMethod=u.type),c}catch(c){throw c instanceof Pe&&(l.cacheMissReason=c.cacheMissReason,l.attributes.decisions=c.decisions),c}}),s=await this.scrollIntoViewAndResolveFinalTarget({resolutionResult:a,disableGlobalLocatorRedirect:n.disableGlobalLocatorRedirect,logger:o});return n.force||await a.revalidator?.(),{resolutionResult:a,finalTarget:s}}async wrapElementTargetingCommand(e){return await Qi({action:()=>this.wrapElementTargetingCommandHelper(e),frameConfig:e.options.iframeUrl?{type:"url",url:e.options.iframeUrl}:void 0,browser:this.browser,logger:this.logger})}async wrapElementTargetingCommandHelper(e){let{tracer:r,target:n,action:o,options:i,command:a,finalAttempt:s=false,originalCache:l=e.cache}=e,{retriesWithAI:c=1}=e,{disableCache:u,useSelector:d,targetName:m}=i,p=Ir(),f=this.logger.child({commandId:a.id}),h=this.shouldUseMemory(),g=cloneDeep(e.cache);if((!g||u)&&!QF(n))throw new M("ActionFailureError","Cannot target element with no cached data or element descriptor");if(d)return this.wrapHardcodedCssTargetingCommandHelper(e);let y=false,S;u&&(f.info("Cache explicitly disabled for this step"),y=true,S="Cache explicitly disabled",g=void 0);let E=WY({cache:g,description:n.elementDescriptor,disableSecondaryCacheResolution:!!this.browser.userBrowserSettings.disableSecondaryCacheResolution,logger:f});g=E.cache,y=y||E.cacheBustedBeforeAction,!S&&E.cacheBustReason&&(S=E.cacheBustReason);let v=true;if(!HY(g))return c--,v=false,this.executeTargetingCommandWithAI({tracer:p,stepTracer:r,target:n,options:i,command:a,action:o,originalCache:l,logger:f,useMemory:h,cacheBustedBeforeAction:y,cacheBustReason:S});try{let{resolutionResult:w,finalTarget:_}=await this.resolveCachedTargetForAction({cache:g,options:i,logger:f}),L=await o(_);if(Ge.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!g.requirements}`,`hasAdditionalElements:${!!g.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:1.0.1"]),Sv({cmd:a,key:m,newTarget:g,logger:f,updatedWithAI:!1}),v){let I=w.decisions.filter(R=>R.matched);if(I.length!==1)f.warn({decisions:w.decisions},"Expected exactly 1 matching method for element location, got more or less");else {let R=I[0].type;r.recordTargetAutoHeal({healType:R});}}return {result:L,elementInteractedDisplayString:w.displayString}}catch(w){this.throwIfClosed();let _=Gx(w);if(_&&!s)return f.warn({err:w},"Encountered error that is retryable with cache"),this.wrapElementTargetingCommandHelper({tracer:r,command:a,target:n,action:o,cache:l,originalCache:l,retriesWithAI:c,finalAttempt:true,options:i});if(w instanceof M&&!_)throw f.warn({err:w},"Failed to execute command with target (fatal)"),w;if(c>0&&n){f.info({err:w},"Failed to execute action with cached target, retrying with AI"),Ge.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!g.requirements}`,`hasAdditionalElements:${!!g.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:1.0.1",`missReason:${w instanceof Pe?w.cacheMissReason:"unknown"}`]);let L;g.memory&&eB(g.memory)&&(L=g.memory);let I=w instanceof Pe&&w.cacheMissReason==="failing-ldist";return this.wrapElementTargetingCommandHelper({tracer:r,command:a,target:n,cache:void 0,action:o,originalCache:l,retriesWithAI:c,finalAttempt:true,options:{...i,memory:L,targetHealingInProgress:true},skipInitialLocateWait:I})}throw new M("ActionFailureError",`Failed to execute interactive command: ${w instanceof Error?w.message:`${w}`}`,{errOptions:{cause:w}})}}async executeTargetingCommandWithAI(e){let{tracer:r,stepTracer:n,target:o,options:i,command:a,action:s,originalCache:l,logger:c,useMemory:u,cacheBustedBeforeAction:d,cacheBustReason:m,skipInitialLocateWait:p}=e;c.info({description:o.elementDescriptor,targetHealingInProgress:i.targetHealingInProgress,cacheBustedBeforeAction:d,memory:i.memory,useMemory:u},"Prompting AI for an updated element location");let f=false;(d||!l)&&!this.getCurrentExecutionOptions().skipAISmartWaiting&&!i.skipAISmartWaiting?(await r.startAsyncSpan("SMART_WAITING",async()=>await rX({description:o.elementDescriptor,iframeUrl:i.iframeUrl,source:i.source,logger:c,allowNotActionableNodesOverride:i.allowNotActionableNodesOverride},this.getControllerFixtures())),f=true):(d||!l)&&(i.skipAISmartWaiting?c.debug("Skipping AI smart waiting for this targeting attempt"):c.debug("Skipping AI smart waiting due to controller execution options"));let h=2;for(let g=1;g<=h;g++){let y=false,S=this.browser.getActiveFrameConfig(),E=i.force||g>1;try{let v;try{v=await nL({description:o.elementDescriptor,disableCache:!!i.disableCache,iframeUrl:i.iframeUrl,source:i.source,useMemory:u,memory:u?i.memory:void 0,allowNotActionableNodesOverride:i.allowNotActionableNodesOverride,allowIneligibleTagRedirect:i.allowIneligibleTagRedirect,showZeroOpacityElementsOverride:i.showZeroOpacityElementsOverride,logger:c,skipWait:f||p,isAutoHeal:!!i.targetHealingInProgress,cacheBustReason:m,acceptElementMovedError:E},this.getControllerFixtures());}catch(L){if(L instanceof Wa&&L.updatedLocatorMemory){let I={id:-1,...l,memory:L.updatedLocatorMemory};Sv({cmd:a,key:i.targetName,newTarget:I,logger:c,updatedWithAI:!0});}throw L}v.frameConfig&&(this.browser.setActiveFrameConfig(v.frameConfig),y=!0);let w=await this.scrollIntoViewAndResolveFinalTarget({resolutionResult:v.resolution,disableGlobalLocatorRedirect:i.disableGlobalLocatorRedirect,logger:c}),_=await s(w);return Sv({cmd:a,key:i.targetName,newTarget:v.target,logger:c,updatedWithAI:!0}),i.targetHealingInProgress&&(n.recordTargetAutoHeal({healType:"AI"}),v.target.targetSource="AI_HEALED",v.target.targetUpdateTime=new Date().toUTCString(),v.target.targetUpdateLoggerTags=De(c)),{result:_,elementInteractedDisplayString:v.resolution.displayString,thoughts:v.thoughts}}catch(v){if(y&&this.browser.setActiveFrameConfig(S),this.throwIfClosed(),g<h&&Gx(v)){c.warn({err:v,aiAttempt:g},"Encountered retryable AI targeting error; retrying with AI once");continue}throw v instanceof M?v:new M("ActionFailureError",v.message)}}throw new M("ActionFailureError","Failed to execute AI targeting after retry")}async screenshotWithDimensions(e){return Ob(this.browser,e)}async executePresetCommand(e,r,n,o,i){this.options?.slowMoMs&&await pe(this.options.slowMoMs);let a=await this.browser.getOpenPages(),s=this.browser.url(),l;try{l=await this.resolveCommandTemplateStrings(r,n);}catch(c){throw this.throwIfClosed(),new M("ActionFailureError",`Failed to substitute template strings in command: ${c.message}`,{errOptions:{cause:c}})}try{let c=await Ne({name:`cli.command.${r.type}`,attributes:{"momentic.command_type":r.type,"momentic.command_id":r.id},fn:()=>this.executePresetCommandHelper(e,r,n,o,i)});return this.options?.autoFollowNewTabs&&await jY({beforeUrl:s,command:r,beforePages:a.map(u=>u.url),browser:this.browser,logger:this.logger}),c}catch(c){throw c.name!=="AbortError"&&this.logger.error({err:c},"Error thrown in action controller"),c}finally{Bp(r,l);}}createCallbacksForBrowser(e){return {createIsolatedFolder:()=>DD(e)}}async traceBrowserInteraction(e,r,n){return Ir().startAsyncSpan("BROWSER_INTERACTION",async i=>r(i),{name:e,...n})}async resolveCommandTemplateStrings(e,r){return Fp({obj:e,context:r,bannedKeys:["type","a11yData","thoughts","cache","code"],orgId:this.orgId,logger:this.logger,signal:this.executeAbortController.signal,localTools:this.localCodeEvalTools})}async executePresetCommandHelper(e,r,n,o,i){o=o||"disableCache"in r&&!!r.disableCache;let a=this.logger.child({commandId:r.id});switch(r.type){case "SUCCESS":{let s=r.condition;return s?.assertion.trim()?sw({command:s,fixtures:this.getControllerFixtures(),useMemory:this.shouldUseMemory(),logger:a,recoveryHint:i}):{succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "AI_ASSERTION":{if(!r.assertion.trim())throw new M("ActionFailureError","Missing assertion");if(r.timeout&&r.timeout>1800)throw new M("AssertionFailureError",`AI check timeout of ${r.timeout} exceeds the maximum allowed value of 30 minutes.`);return sw({command:r,fixtures:this.getControllerFixtures(),useMemory:this.shouldUseMemory(),logger:a,recoveryHint:i})}case "AI_EXTRACT":return tX({command:r,logger:a,fixtures:this.getControllerFixtures(),disableCache:o});case "NAVIGATE":if(!lp(r.url)&&!cp(r.url,this.browser.baseUrl))throw new M("ActionFailureError",`Invalid URL provided to navigate command: ${r.url}`);await this.traceBrowserInteraction("Navigate",()=>this.browser.navigate({url:r.url,loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0}));break;case "DIALOG":this.browser.registerDialogHandler(r.action);break;case "CAPTCHA":throw new M("UserConfigurationError","Captcha solving is no longer available on Momentic");case "GO_BACK":await this.traceBrowserInteraction("Go back",()=>this.browser.goBack());break;case "GO_FORWARD":await this.traceBrowserInteraction("Go forward",()=>this.browser.goForward());break;case "SCROLL_LEFT":case "SCROLL_RIGHT":case "SCROLL_DOWN":case "SCROLL_UP":{let s,l;if(r.target&&za(r.target)){let d=er(r.target.pixels);await this.browser.hoverUsingVisualCoordinates(d);}else if(r.target&&r.target.elementDescriptor.trim()){let{elementInteractedDisplayString:d,thoughts:m}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:p=>this.browser.hover(p),options:{...r,targetName:"target",disableGlobalLocatorRedirect:true,disableCache:o}});s=d,l=m;}let c=this.browser.getViewport()?.height??Ol.height,u=this.browser.getViewport()?.width??Ol.width;switch(r.type){case "SCROLL_UP":await this.traceBrowserInteraction("Scroll up",()=>this.browser.scrollVertical(-(r.deltaY??c)));break;case "SCROLL_DOWN":await this.traceBrowserInteraction("Scroll down",()=>this.browser.scrollVertical(r.deltaY??c));break;case "SCROLL_LEFT":await this.traceBrowserInteraction("Scroll left",()=>this.browser.scrollHorizontal(-(r.deltaX??u)));break;case "SCROLL_RIGHT":await this.traceBrowserInteraction("Scroll right",()=>this.browser.scrollHorizontal(r.deltaX??u));break}return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "WAIT_FOR_URL":{if(r.timeout&&r.timeout>1800)throw new M("UserConfigurationError",`Wait for URL timeout of ${r.timeout} exceeds the maximum allowed value of 30 minutes.`);let s=r.matcher;await this.browser.waitForUrl({beforeUrl:this.browser.url(),matcher:s},{timeout:r.timeout?r.timeout*1e3:void 0,negated:r.negated,caseInsensitive:r.caseInsensitive});break}case "WAIT":{if(r.delay>1800)throw new M("UserConfigurationError",`Wait timeout of ${r.delay} seconds exceeds the maximum allowed value of 30 minutes`);let s=r.delay*1e3;await pe(s,this.executeAbortController.signal);break}case "REFRESH":await this.traceBrowserInteraction("Refresh",()=>this.browser.refresh({loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0}));break;case "CLICK":{if(za(r.target)){let m=er(r.target.pixels),p={...r,relativePosition:r.relativePosition?er(r.relativePosition):void 0};await this.traceBrowserInteraction("Click",()=>this.browser.clickUsingVisualCoordinates(m,p),{coordinates:m});break}let s=this.browser.url(),{elementInteractedDisplayString:l,result:c,thoughts:u}=await this.wrapElementTargetingCommand({tracer:e,target:r.target,command:r,cache:r.cache?.target,action:m=>this.traceBrowserInteraction("Click",async p=>{let f={...r,relativePosition:r.relativePosition?er(r.relativePosition):void 0},h=await this.browser.click(m,this.createCallbacksForBrowser(this.orgId),f);return h.coordinates&&(p.coordinates=h.coordinates),h},{selector:m.locator.toString()}),options:{...r,targetName:"target",disableCache:o}}),d={urlAfterCommand:this.browser.url(),succeedImmediately:false,elementInteracted:l,thoughts:u,data:c.downloadedFile?{downloadedFile:c.downloadedFile}:void 0};return _v(s,d.urlAfterCommand)&&(d.succeedImmediately=true,d.succeedImmediatelyReason="URL changed"),d}case "COPY":return await this.browser.copy(r.value),{succeedImmediately:false,data:r.value,urlAfterCommand:this.browser.url()};case "PASTE":{await this.browser.paste();break}case "DRAG":{if(za(r.fromTarget)&&za(r.toTarget)){let c=er(r.fromTarget.pixels),u=er(r.toTarget.pixels);await this.traceBrowserInteraction("Drag",()=>this.browser.dragAndDropUsingVisualCoordinates(c,u,{hoverDurationMs:r.hoverSeconds?r.hoverSeconds*1e3:void 0}),{coordinates:c});break}if(za(r.fromTarget)||za(r.toTarget))throw new Error("Drag and drop targets must be both coordinates or both descriptions");let{elementInteractedDisplayStrings:s,thoughts:l}=await this.wrapMultiElementTargetingCommand({tracer:e,command:r,targetNames:["fromTarget","toTarget"],descriptions:[r.fromTarget,r.toTarget],caches:[r.cache?.fromTarget,r.cache?.toTarget],action:(c,u)=>this.traceBrowserInteraction("Drag",()=>this.browser.dragAndDrop(c,u,{hoverDurationMs:r.hoverSeconds?r.hoverSeconds*1e3:void 0,steps:r.steps})),options:{...r,disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s[0],thoughts:l}}case "MOUSE_DRAG":{let s=parseInt(r.deltaX),l=parseInt(r.deltaY),c=r.steps??5;if(isNaN(s)||isNaN(l))throw new M("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${r.deltaX}, ${r.deltaY})`);if(r.target&&za(r.target)){let m=er(r.target.pixels);await this.traceBrowserInteraction("Mouse drag",()=>this.browser.mouseDragUsingVisualCoordinates({deltaX:s,deltaY:l,steps:c,fromTarget:m}),{coordinates:m});break}let u,d;if(r.target?.elementDescriptor){let{elementInteractedDisplayString:m,thoughts:p}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:async f=>this.traceBrowserInteraction("Mouse drag",()=>this.browser.mouseDrag(s,l,c,f.locator,{force:r.force})),options:{...r,targetName:"target",disableCache:o}});u=m,d=p;}else await this.traceBrowserInteraction("Mouse drag",()=>this.browser.mouseDrag(s,l,c,void 0,{force:r.force}));return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:u,thoughts:d}}case "SELECT_OPTION":{if(!zs(r.target))throw new Error("Select with x/y is not supported yet");let s=r.target.elementDescriptor,l=r.choice,{elementInteractedDisplayString:c,thoughts:u}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:{type:"description",elementDescriptor:s},cache:r.cache?.target,action:d=>this.traceBrowserInteraction("Select option",()=>this.browser.selectOption(d,l,r.force),{value:l.type==="LABEL"?l.label:l.type==="VALUE"?l.value:l.index}),options:{...r,targetName:"target",disableCache:o,source:Ah(r)}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:c,thoughts:u}}case "TAB":{let s={loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0,retry:true};await this.browser.switchToPage(r.action,s);break}case "NEW_TAB":await this.browser.createNewTab(r.url,{loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0});break;case "CLOSE_TAB":await this.browser.closePage(r.action,{retry:true});break;case "COOKIE":{if(!r.value)break;let s=await this.browser.setCookie(r.value);a.debug({results:s},"Set cookies");break}case "LOCAL_STORAGE":if(!r.value||!r.key)break;await this.browser.setLocalStorage(r.key,r.value);break;case "JAVASCRIPT":{let s;try{r.environment==="BROWSER"?(s=await this.browser.evaluateCodeInPage({code:r.code,fragment:r.fragment??!1,context:n.toObjectCopy(),timeoutMs:r.timeout?r.timeout*1e3:void 0}),a.info({result:s},"Executed JavaScript in browser")):s=await Yi({orgId:this.orgId,code:r.code,fragment:!!r.fragment,context:n,timeoutMs:r.timeout?r.timeout*1e3:void 0,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal,callbacks:{onPersistentVariableUpdates:async l=>{if(!this.options?.scratchPadId){a.warn({updates:l},"Got persistent variable updates but scratch pad is not available");return}await this.storage.savePersistentVariables?.({scratchPadId:this.options?.scratchPadId,orgId:this.orgId,updates:l,logger:a});}}});}catch(l){throw this.throwIfClosed(),new M("ActionFailureError",l instanceof Error?l.message:`${l}`,{errOptions:{cause:l}})}try{JSON.stringify(s);}catch(l){throw new M("ActionFailureError",`Return value is not serializable: ${l instanceof Error?l.message:`${l}`}`,{errOptions:{cause:l}})}return {urlAfterCommand:this.browser.url(),succeedImmediately:false,data:s}}case "TYPE":{if(r.target&&za(r.target)){let p=er(r.target.pixels),f={...r,relativePosition:r.relativePosition?er(r.relativePosition):void 0};await this.browser.clickUsingVisualCoordinates(p,f),await this.traceBrowserInteraction("Type",()=>this.browser.type(r.value,{force:r.force,clearContent:r.clearContent,forceClearContent:r.forceClearContent,delay:r.delay,pressEnter:r.pressEnter},true),{value:r.value});break}let s=this.browser.url(),l,c,u=cloneDeep(r.target),d=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(u){let{elementInteractedDisplayString:p,thoughts:f}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:u,cache:r.cache?.target,action:h=>this.traceBrowserInteraction("Type",()=>this.browser.typeIntoTarget(r.value,h,{force:r.force,clearContent:r.clearContent,forceClearContent:r.forceClearContent,delay:r.delay,pressEnter:r.pressEnter,relativePosition:r.relativePosition}),{value:r.value,selector:h.locator.toString()}),options:{...r,targetName:"target",disableCache:o,disableGlobalLocatorRedirect:!d,source:Ah(r)}});l=p,c=f;}else await this.traceBrowserInteraction("Type",()=>this.browser.type(r.value,{force:r.force,clearContent:r.clearContent,forceClearContent:r.forceClearContent,delay:r.delay,pressEnter:r.pressEnter},true),{value:r.value});let m={urlAfterCommand:this.browser.url(),succeedImmediately:false,elementInteracted:l,thoughts:c};return _v(s,m.urlAfterCommand)&&(m.succeedImmediately=true,m.succeedImmediatelyReason="URL changed"),m}case "HOVER":{if(za(r.target)){let c=er(r.target.pixels);await this.traceBrowserInteraction("Hover",()=>this.browser.hoverUsingVisualCoordinates(c),{coordinates:c});break}let{elementInteractedDisplayString:s,thoughts:l}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:c=>this.traceBrowserInteraction("Hover",()=>this.browser.hover(c,{relativePosition:r.relativePosition?er(r.relativePosition):void 0}),{selector:c.locator.toString()}),options:{...r,targetName:"target",disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "FOCUS":{if(!zs(r.target))throw new Error("Focus with x/y is not supported yet");let{elementInteractedDisplayString:s,thoughts:l}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:c=>this.browser.focus(c),options:{...r,targetName:"target",disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "BLUR":{if(r.target&&!zs(r.target))throw new Error("Blur with x/y is not supported yet");if(!r.target||!r.target.elementDescriptor)return await this.browser.blur(null),{succeedImmediately:false,urlAfterCommand:this.browser.url()};let{elementInteractedDisplayString:s,thoughts:l}=await this.wrapElementTargetingCommand({tracer:e,target:r.target,command:r,cache:r.cache?.target,action:c=>this.browser.blur(c),options:{...r,targetName:"target",disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "PRESS":{let s=this.browser.url();await this.traceBrowserInteraction("Press key",()=>this.browser.press(r.value,{repeat:r.repeat,convertMeta:r.convertMeta??true,delayMs:r.delayMs}),{value:r.value});let l={urlAfterCommand:this.browser.url(),succeedImmediately:false};return _v(s,l.urlAfterCommand)&&(l.succeedImmediately=true,l.succeedImmediatelyReason="URL changed"),l}case "KEY_DOWN":return await this.browser.keyDown(r.value,{convertMeta:r.convertMeta??true}),{urlAfterCommand:this.browser.url(),succeedImmediately:false};case "KEY_UP":return await this.browser.keyUp(r.value,{convertMeta:r.convertMeta??true}),{urlAfterCommand:this.browser.url(),succeedImmediately:false};case "REQUEST":{let s=new CookieJar,l=eOe(fetch,s),c;try{c=new URL(r.url).hostname;}catch{}let u=await jp({command:r,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:l});return {data:Wd.parse({...u,cookies:Tm(s,c)}),succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "GRAPHQL_REQUEST":return {data:await mX({command:r,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:false,urlAfterCommand:this.browser.url()};case "VISUAL_DIFF":return lX({tracer:e,command:r,disableCache:o,browser:this.browser,logger:a,screenshotStorage:this.visualDiffScreenshotStorage,targetingWrapper:s=>this.wrapElementTargetingCommand(s)});case "FILE_UPLOAD":{let s,l;if(r.fileSource.type==="URL"?(l=r.fileSource.url,s=await I6({uri:r.fileSource.url,logger:a,orgId:this.orgId})):r.fileSource.type==="USER_FILE"&&(l=r.fileSource.name,s=await this.uploadedFileStorage?.getFileForUpload(r.fileSource.name,this.orgId)),!s)throw new M("UserConfigurationError",`Attempted to use non-existent file for upload step: ${l}`);await this.browser.setFileChooserHandler({...s,filename:r.filename});break}case "AUTH_SAVE":{let s=await this.browser.saveAuthState();if(r.storageState&&q_(r.storageState)){let l=fr__default.resolve(r.storageState);Sn.mkdirSync(fr__default.dirname(l),{recursive:true}),Sn.writeFileSync(l,`${JSON.stringify(s,null,2)}
|
|
5715
|
+
`),tokenLength:d}),s.forEach((h,g)=>{let y=h.ids[0],S=h.ids[h.ids.length-1];t.debug({tokenLength:h.tokenLength,minId:y,maxId:S},`Chunk for page filtering (index ${g+1}/${s.length})`);}),{chunks:s}}var XY=5e6,M_e=1e5,P_e=3e4,I_e=6e4,__e=1e5;async function md(t){let{fixtures:e}=t,{logger:r}=e,n=t.tree,o=t.serializedTree,i=Ut(o);if(i>XY)throw new M("UserConfigurationError",`Page accessibility tree is too large for AI page filtering (${i} tokens). Maximum supported size is ${XY} tokens.`);if(i>M_e){let a=YY({serializedTree:o,options:qY,logger:r}),s=randomUUID();n=await O_e({...t,chunks:a.chunks,callId:s}),o=n.serialize();let l=Ut(o);r.info({oldTokens:i,newTokens:l,langfuseCallId:s},"Filtered page using AI chunk ranking");}return o}async function O_e({type:t,callId:e,chunks:r,description:n,fixtures:o,tree:i}){let{generator:a,signal:s,logger:l}=o,c=await a.rankChunksWithAi({chunks:r,description:n,type:t,softTokenLimit:P_e,mediumTokenLimit:I_e,hardTokenLimit:__e,callId:e},{abortSignal:s,logger:l,loggerTags:De(l)}),u=[];return r.forEach((m,p)=>{c.indices.includes(p)&&(u=u.concat(m.ids));}),i.pruneUsingRelevantIds(new Set(u))}async function nL(t,e){if(!t.description)throw new M("UserConfigurationError","Cannot locate element with empty description");return Qi({action:async()=>L_e(t,e),frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,browser:e.browser,logger:t.logger})}async function L_e(t,e){let{disableCache:r,testContext:n,filterByViewport:o,skipWait:i,source:a,memory:s,logger:l,allowNotActionableNodesOverride:c,allowIneligibleTagRedirect:u,showZeroOpacityElementsOverride:d,skipSavingVisualAttributes:m,isAutoHeal:p,cacheBustReason:f,acceptElementMovedError:h}=t,{orgId:g,browser:y,localCodeEvalTools:S,generator:E,abortSignal:v}=e,w=t.description,_=Ir(),L=t.useMemory&&!r;n&&(w=await fl({orgId:g,s:w,context:n,localTools:S,signal:v,logger:l})),a&&(w=VY(w,a));let{serializedTree:I,tree:R}=await _.startAsyncSpan("GET_PAGE_STATE",async()=>Oc(y,{allowNotActionableNodesOverride:c,allowIneligibleTagRedirect:u,showZeroOpacityElementsOverride:d,filterByViewport:o,abortSignal:v,skipWait:i,logger:l}),{}),k=await _.startAsyncSpan("GET_PAGE_SCREENSHOT",async()=>{let j,z=Date.now(),se;for(;!j&&Date.now()-z<3e3;){v.throwIfAborted();try{j=await y.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2});}catch(be){se=be;}}if(!j)throw new M("ActionFailureError",`Failed to take screenshot of page to locate element. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${se?.message}`);return j}),D=I,V=false,U=`data:image/jpeg;base64,${k.toString("base64")}`,fe=De(l);D=await md({type:"locator",description:w,screenshot:U,serializedTree:I,tree:R,fixtures:{generator:E,signal:v,logger:l,orgId:g}}),D!==I&&(V=true);let q=await _.startAsyncSpan("AI_LOCATOR_CALL",async j=>{p&&(j.attributes.isAutoHeal=true),f&&(j.attributes.cacheBustReason=f);let z=await E.getElementLocation({browserState:D,goal:w,screenshot:U,source:a,memory:L?s:void 0},{disableCache:r,abortSignal:v,logger:l,loggerTags:fe,useMemory:L,cacheBustReason:f});if(j.result=z,L&&(j.attributes.useMemory=true,j.attributes.memoryTraces=z.rememberedTraces??[],z.updatedMemory&&(j.attributes.memorySavedNewResult=true)),_.storeTraceAsset){let se=randomUUID();_.storeTraceAsset({snapshotId:se,data:k}),j.screenshotSnapshotId=se;}return z});if(l.debug({usedRag:V,result:q},"Got locator result"),!(q.id>0))throw new Wa(`Could not find any relevant element: ${q.thoughts}`,q.updatedMemory?{type:"GCS_TRACES",traces:q.updatedMemory}:void 0);let{resolution:F,target:B,frameConfig:te}=await _.startAsyncSpan("TARGET_RESOLUTION",async j=>{let z=await y.createTargetFromA11yId({id:q.id,requirements:q.requirements,additionalElements:q.additionalElements,description:w,targetSource:"AI",logger:l,skipSavingVisualAttributes:m,acceptElementMovedError:h});return j.result={serializedElement:z.target.nodeOnlySerializedHtml??"Unknown HTML element"},z});if(F.a11yNode?.properties?.hidden&&F.a11yNode?.properties?.hidden!=="false")throw new M("ActionFailureError",`Momentic's AI found a relevant element to interact with, but it is explicitly marked with an 'aria-hidden' attribute. Please remove this attribute or adjust the element description to locate a different element. Element chosen: ${F.displayString}`);return L&&(q.updatedMemory?B.memory={type:"GCS_TRACES",traces:q.updatedMemory}:s&&(B.memory=s)),{thoughts:q.thoughts,target:B,resolution:F,frameConfig:te,screenshot:U}}var N_e=15;async function sw({command:t,logger:e,fixtures:r,useMemory:n,maxRetries:o=N_e,recoveryHint:i}){if(!t.assertion.trim())throw new M("ActionFailureError","Assertion command is missing the assertion content");let a=EM.optional().catch(void 0).parse(t.source);t.source&&!a&&e.warn(`Invalid source ${t.source} for AI assertion, ignoring...`);let s=Ir();return s.startAsyncSpan("AI_ASSERTION_CALL",async l=>{let{browser:c}=r,u=t.timeout?t.timeout*1e3:c.smartWaitingTimeout,d=D3(u,o-1),m=0,p=Date.now(),f=p+u,h=p,g,y,S;try{await Qi({action:()=>c.clearHighlights(),frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,browser:c,logger:e});}catch(w){e.warn({err:w},"Failed to clear highlights before AI check, continuing...");}for(;m<o;){r.abortSignal.throwIfAborted();let w=Date.now();if(m>0){if(w>=f)break;let I=f-w,R=h-w,k=Math.min(R,I);k>0&&await pe(k,r.abortSignal);}let _=Date.now();if(m>0&&_>=f)break;let L=false;try{if(g=await Qi({action:async()=>{let R=await ZY(c,e,r.abortSignal);return y&&y.serializedTree===R.serializedTree&&y.screenshotBuff.equals(R.screenshotBuff)?(L=!0,g):(y=R,QY({command:t,state:R,fixtures:r,useMemory:n,useConsensus:!1,highlightElementsOnFailure:!1,attemptNumber:m,logger:e,source:a,recoveryHint:i}))},frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,logger:e,browser:c}),g?.aiResult.result){g?.updatedMemory&&Bg(t,g.updatedMemory,e);break}else throw g?.aiResult.thoughts?new M("AssertionFailureError",g.aiResult.thoughts):new M("InternalPlatformError","No thoughts were provided for AI assertion failure")}catch(I){r.abortSignal.throwIfAborted(),S=I instanceof Error?I:new Error(`${I}`),L?e.info(`AI check attempt ${m} failed (re-used previous result)`):e.info({err:I},`AI check assert attempt ${m} failed, retrying...`);}finally{m++,h=_+d;}}if(!g?.aiResult.result){let w=f-Date.now();w>0&&await pe(w,r.abortSignal);}if(!g?.aiResult.result)try{g=await Qi({action:async()=>QY({command:t,state:await ZY(c,e,r.abortSignal),fixtures:r,useMemory:n,useConsensus:!0,highlightElementsOnFailure:!0,attemptNumber:m,logger:e,recoveryHint:i}),frameConfig:t.iframeUrl?{type:"url",url:t.iframeUrl}:void 0,logger:e,browser:c});}catch(w){r.abortSignal.throwIfAborted(),S=w instanceof Error?w:new Error(`${w}`);}finally{m++;}g?.updatedMemory&&Bg(t,g.updatedMemory,e);let E=g?.afterScreenshotOverride;if(E&&s.storeTraceAsset){let w=randomUUID();s.storeTraceAsset({snapshotId:w,data:E}),l.screenshotSnapshotId=w;}let v=g?.elementScreenshotOverride;if(v&&s.storeTraceAsset){let w=randomUUID();s.storeTraceAsset({snapshotId:w,data:v}),l.elementScreenshotSnapshotId=w;}if(n&&(l.attributes.useMemory=true,l.attributes.memoryTraces=g?.aiResult.rememberedTraces??[],g?.updatedMemory&&(l.attributes.memorySavedNewResult=true)),!g?.aiResult.result){l.result=g?.aiResult??{thoughts:S?.message??"AI check failed after all attempts",result:false};let w=`AI check still failing after ${m} attempts.`;throw S&&(w+=` Latest result: ${S.message}`),new M("AssertionFailureError",w)}return l.result=g.aiResult,{...g,thoughts:g.aiResult.thoughts,succeedImmediately:false,urlAfterCommand:c.url()}})}async function ZY(t,e,r){await t.waitForPageLoad({signal:r});let[n,o]=await Promise.all([Oc(t,{abortSignal:r,skipWait:true,skipWaitForPageLoad:true,logger:e}),t.screenshot({retries:1,respectActiveFrame:true})]);return {...n,screenshotBuff:o}}async function QY({command:t,state:e,fixtures:r,useConsensus:n,useMemory:o,highlightElementsOnFailure:i,attemptNumber:a,source:s,logger:l,recoveryHint:c}){let {browser:u,generator:d,abortSignal:m}=r,{serializedTree:f,tree:h}=e,g=e.screenshotBuff,y=g.toString("base64"),S=u.url(),E=t.contextChoice??"MULTIMODAL",v=f;E!=="VISION_ONLY"&&(v=await md({type:"assertion",serializedTree:f,tree:h,description:t.assertion,screenshot:y,fixtures:{generator:d,signal:m,logger:l,orgId:r.orgId}}),v);let w={goal:t.assertion,url:S,memory:o?t.cache?.memory:void 0,browserState:v,screenshot:y,contextChoice:E,source:s,recoveryHint:c},L=await(E==="VISION_ONLY"?(R,k)=>d.getVisualAssertionResult(R,k):(R,k)=>d.getAssertionResult(R,k))(w,{useConsensus:n,attemptNumber:a,useMemory:o,disableCache:!!t.disableCache,abortSignal:m,logger:l,loggerTags:De(l)}),I;if((L.result||i)&&L.relevantElements?.length){L.relevantElements.map(R=>u.getSerializedFormFromA11yId(R)).filter(R=>!!R);try{let R=L.relevantElements[0],{resolution:k}=await u.createTargetFromA11yId({id:R,description:null,targetSource:"AI",skipSaveToCache:!0});I=await u.screenshot({locator:k.locator,clearHighlights:!0,respectActiveFrame:!0});}catch(R){l.debug({err:R},"Failed to capture element screenshot for trace, continuing...");}await k_e(L.relevantElements,u,l);}return {aiResult:L,afterScreenshotOverride:g,elementScreenshotOverride:I,updatedMemory:o?L.updatedMemory:void 0}}async function k_e(t,e,r){let n=Date.now();for(let o of t){if(Date.now()-n>2e3){r.debug("Highlighting relevant elements took over 2s, aborting...");return}try{let i=new AbortController;await ee(e.highlightA11yId(o),{milliseconds:1e3,fallback:()=>{throw i.abort(),new Error("Timed out waiting for highlighting to complete")}});}catch(i){r.debug({err:i},"Failed to highlight relevant element after assertion, continuing...");return}}}async function tX(t){let{command:e,logger:r,fixtures:n,disableCache:o}=t,{browser:i,generator:a,abortSignal:s}=n;if(!e.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(e.schema){let d=Vm(e.schema);if(d)throw new M("UserConfigurationError",d)}let l=await i.getCondensedHtml(),c=await i.screenshot({retries:2}),u=Ir();try{return await u.startAsyncSpan("AI_EXTRACTION_CALL",async d=>{let m=await a.getTextExtraction({goal:e.goal,browserState:l,returnSchema:e.schema,screenshot:`data:image/jpeg;base64,${c.toString("base64")}`},{disableCache:o,abortSignal:s,loggerTags:De(r)});if(d.result=m,F_e({tracer:u,span:d,screenshot:c,htmlState:l,logger:r}),m.result==="NOT_FOUND")throw new M("ActionFailureError","No relevant data found for extraction goal on this page");if(m.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",m.thoughts);return {thoughts:m.thoughts||void 0,data:m.result,succeedImmediately:!1,urlAfterCommand:i.url()}})}catch(d){let m=W(d);throw m.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step in the browser instead."):m.includes("AIProviderError")&&m.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:d}}):d}}function F_e(t){let{tracer:e,span:r,screenshot:n,htmlState:o,logger:i}=t;if(e.storeTraceAsset)try{let a=randomUUID();e.storeTraceAsset({snapshotId:a,data:n}),r.screenshotSnapshotId=a;let s=randomUUID();e.storeTraceAsset({snapshotId:s,data:Buffer.from(o),extension:"html"}),r.browserStateSnapshotId=s;}catch(a){i.debug({err:a},"Failed to store extraction trace assets");}}async function rX(t,e){let{logger:r}=t,{abortSignal:n,browser:o}=e,i=Date.now();try{await B_e(i,t,e);}catch(a){if(a instanceof Error&&(a.name==="AbortError"||a.name==="TimeoutError")||n.aborted)return;r.warn({err:a},"Unexpected error occurred during AI smart waiting");let s=o.smartWaitingTimeout-(Date.now()-i);s>0&&await pe(s,n);}finally{r.debug({durationMs:Date.now()-i},"AI smart waiting complete");}}async function B_e(t,e,r){let{abortSignal:n,browser:o}=r;if(o.smartWaitingTimeout<3e3){await pe(o.smartWaitingTimeout,n);return}if(!e.description)throw new M("UserConfigurationError","Cannot locate element with empty description");await ee(U_e(t,e,r),{milliseconds:o.smartWaitingTimeout});}async function U_e(t,e,r){let{logger:n,iframeUrl:o}=e,{browser:i}=r;for(;Date.now()-t<i.smartWaitingTimeout;)if(await Qi({action:async()=>z_e(e,r),frameConfig:o?{type:"url",url:o}:void 0,browser:i,logger:n}))return}async function z_e(t,e){let{testContext:r,logger:n}=t,{browser:o,abortSignal:i,localCodeEvalTools:a,orgId:s,generator:l}=e,c=t.description;r&&(c=await fl({orgId:s,s:c,context:r,localTools:a,signal:i,logger:n})),i.throwIfAborted();let u;try{u=await o.screenshot({clearHighlights:!0,respectActiveFrame:!0,retries:2});}catch(f){throw new M("ActionFailureError",`Failed to take screenshot of page to perform smart waiting. The page may be unresponsive, or your machine might be severely resource constrained. Error: ${f instanceof Error?f.message:f}`)}let m=`data:image/jpeg;base64,${u.toString("base64")}`;i.throwIfAborted();let p=await l.getSmartWaitingDecision({description:c,screenshot:m},{abortSignal:i,loggerTags:De(n)});return n.debug({result:p},"Got smart waiting result"),p.isPageReady}var $_e=3e4;async function iX(t){return Ir().startAsyncSpan("ELEMENT_ASSERTION",async r=>V_e(t,r),{name:"Element check"})}async function V_e(t,e){let{command:r,timeoutMs:n,fixtures:o,disableCache:i}=t,{abortSignal:a}=o,s=()=>Dx(r.cache)?r.cache:void 0,l=s(),c=!i&&!!l?.target&&$d(l.target),u=cloneDeep(l),d=(v=false)=>{if(l=s(),!!l)if(v){let w=f3(u,l);l.target=w.target,l.updatedAt=w.updatedAt;}else {if(!u){l=void 0;return}l.target=u.target,l.updatedAt=u.updatedAt;}},m=Date.now(),p=c?Math.max(n/10,$_e):0,f=m,h=0,g,y=500,S=false;for(;h<2||Date.now()-m<n;){h++,h>1&&await pe(y,a),a?.throwIfAborted(),l=s();let v=h===1,w=c&&Date.now()-f>=p;w&&(f=Date.now());let{result:_,elementWasFound:L}=await nX({cacheToUse:l,skipAISmartWaiting:!v,useAIIfCacheFails:!c||w,params:t});if(g=_,S=S||L,_.success)break;d(),y=Math.min(y*1.25,1e4);}if(!g)throw new M("InternalPlatformError",`Failed to evaluate manual element assertion in ${n}ms.`);if(a?.throwIfAborted(),!g.success){let v=s(),w=v?.target?.memory?{target:{id:-1,memory:v.target.memory}}:void 0,{result:_,elementWasFound:L}=await nX({cacheToUse:w,skipAISmartWaiting:true,useAIIfCacheFails:true,params:t});g=_,S=S||L,g.success||d(true);}let E=s();return g.success&&E?.target&&!S&&(E.target=L_(E.target),E.updatedAt=new Date),e.result={success:g.success,message:g.err?.message},g}async function nX({cacheToUse:t,skipAISmartWaiting:e,useAIIfCacheFails:r,params:n}){let{command:o,disableCache:i,fixtures:a,tracer:s,targetingWrapper:l}=n,{logger:c}=a;if(o.target&&!zs(o.target))throw new Error("Element assertion with x/y is not supported yet");let u=ap(o.assertion),d=j_e(o.assertion),m,p=false,f=cloneDeep(t);try{let{elementInteractedDisplayString:h,result:g,thoughts:y}=await l({tracer:s,command:o,target:o.target,cache:f?.target,action:async S=>H_e(S.locator,n),options:{...o,allowNotActionableNodesOverride:d,allowIneligibleTagRedirect:d,showZeroOpacityElementsOverride:!0,disableCache:i,memory:f?.target?.memory,disableGlobalLocatorRedirect:!0,source:Ah(o),skipAISmartWaiting:e,targetName:"target"},retriesWithAI:r?1:0});return m={success:g.success,data:g.data,err:g.err,elementInteractedDisplayString:h,thoughts:y},p=!0,g.success||(c.warn({aiThoughts:y,elementString:h,err:g.err},"Element check found an element but failed"),m={...g,thoughts:y}),{result:m,elementWasFound:p}}catch(h){if(u)return m={success:true,thoughts:`The element described does not exist on the page: ${h.message}`,err:void 0,data:void 0},{result:m,elementWasFound:p};if(!(h instanceof M)||h.reason!="ActionFailureError")throw h;return m={success:false,err:h,data:void 0,thoughts:void 0},c.warn({err:h},"Element check did not find an element and failed"),{result:m,elementWasFound:p}}}function j_e(t){return !(t.type==="ELEMENT_EXISTENCE"&&t.condition==="VISIBLE"&&!t.negated)}async function H_e(t,{command:e,fixtures:r}){return await r.browser.highlight(t),await W_e(t,e.assertion)}async function W_e(t,e){let r=true,n,o;switch(e.type){case "ELEMENT_CONTENT":{let a=await t.textContent()??"";if(o={elementTextContent:kr(a,500,true)},!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let s=wn(e);r=false,n=new M("AssertionFailureError",`The content ${s} '${e.value}': ${a}`);}break}case "ELEMENT_ATTRIBUTE":{o={elementOuterHtml:kr(await t.evaluate(s=>s.cloneNode(false).outerHTML),500,true)};let a=null;try{a=await t.getAttribute(e.attr,{timeout:3e3});}catch(s){n=new M("AssertionFailureError",W(s)),r=false;break}if(!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let s=wn(e);r=false,e.operation==="EXISTS"?n=new M("AssertionFailureError",`The attribute ${e.attr} ${s}`):n=new M("AssertionFailureError",`The attribute ${e.attr} ${s} '${e.value}': ${a}`);}break}case "ELEMENT_EXISTENCE":{switch(e.condition){case "VISIBLE":{r=await t.evaluate(async(s,l)=>{let c=Date.now();for(;Date.now()-c<l;){await new Promise(d=>setTimeout(d,250));let u=s.getBoundingClientRect();if(!(u.width===0||u.height===0)&&window.getComputedStyle(s).visibility!=="hidden"&&window.getComputedStyle(s).display!=="none")return true}return false},un*1e3);break}case "EDITABLE":{r=await t.isEditable({timeout:un*1e3});break}case "EXISTS":{r=true;break}case "ENABLED":{r=await t.isEnabled({timeout:un*1e3});break}case "FOCUSED":{r=await t.evaluate(s=>s===document.activeElement);break}default:return (s=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})(e.condition)}if(r=e.negated?!r:r,!r){let a=wn(e);n=new M("AssertionFailureError",`The element ${a}`);}break}case "ELEMENT_NAME":{let a=await t.evaluate(s=>s.tagName);if(!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:true})){let s=wn(e);r=false,n=new M("AssertionFailureError",`The element tag name ${s} '${e.value}': ${a}`);}break}case "ELEMENT_STYLE":{let a=await t.evaluate((s,l)=>window.getComputedStyle(s).getPropertyValue(l),e.property);if(!Co(a,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let s=wn(e);r=false,e.operation==="EXISTS"?n=new M("AssertionFailureError",`The style property ${e.property} ${s}`):n=new M("AssertionFailureError",`The style property ${e.property} ${s} '${e.value}': ${a}`);}break}default:return (a=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})()}return {thoughts:void 0,success:r,data:o,err:n}}function aX(t){return t.type==="ELEMENT_EXISTENCE"&&t.negated&&t.condition==="EXISTS"}async function Ob(t,e){let r=await t.screenshot(e),{width:n,height:o}=imageSize(r);return {buffer:r,width:Math.ceil(n),height:Math.ceil(o)}}async function lX(t){let{command:e,browser:r,logger:n}=t;if(e.target&&!zs(e.target))throw new Error("Visual Diff with x/y is not supported yet");return await r.waitForStability({logger:n}),Ir().startAsyncSpan("VISUAL_DIFF",async i=>{try{let a=await K_e(t);return i.result={success:!a.fail,message:a.thoughts},a}catch(a){throw a instanceof M&&(i.result={success:false,message:a.message}),a}},{name:"Compare against golden"})}async function K_e({tracer:t,command:e,disableCache:r,browser:n,targetingWrapper:o,logger:i,screenshotStorage:a}){let s={clearHighlights:true,hideCaret:true},l=e.target&&zs(e.target)?e.target:void 0,c;l?.elementDescriptor?c=(await o({tracer:t,command:e,target:l,cache:e.cache?.target,action:async D=>Ob(n,{locator:D.locator,...s}),options:{...e,disableCache:r,disableGlobalLocatorRedirect:true,memory:e.cache?.target?.memory,targetName:"target"}})).result:c=await Ob(n,s);let u=await a.prepareGoldenScreenshotForComparison(i,e,c);if((c.height!==u.height||c.width!==u.width)&&i.warn({currHeight:c.height,currWidth:c.width,savedHeight:u.height,savedWidth:u.width},"Mismatched before and after visual diff screenshot sizes"),Math.abs(c.height-u.height)>10||Math.abs(c.width-u.width)>10){let k=`${c.width}x${c.height}`,D=`${u.width}x${u.height}`;return {fail:true,thoughts:`Current screenshot (${k}) does not match saved screenshot dimensions (${D}) - did you change the size of the target or the viewport?`,beforeScreenshotOverride:u.buffer,afterScreenshotOverride:c.buffer,succeedImmediately:false,urlAfterCommand:n.url()}}let d=await Jimp.fromBuffer(c.buffer),m={width:c.width,height:c.height},p=await Jimp.fromBuffer(u.buffer),f={width:u.width,height:u.height},h,g=m.width*m.height,y=f.width*f.height,S=Math.abs(m.height-f.height),E=Math.abs(m.width-f.width);if(g>y){let k=d.cover({w:f.width,h:f.height});c.buffer=await k.getBuffer("image/jpeg"),h="current",c.width=f.width,c.height=f.height;}else if(y>g){let k=p.cover({w:m.width,h:m.height});u.buffer=await k.getBuffer("image/jpeg"),h="saved";}let v={data:Buffer.alloc(c.width*c.height*4),width:c.width,height:c.height},w=e.threshold??.1,L=Q9(oL.decode(u.buffer).data,oL.decode(c.buffer).data,v.data,c.width,c.height,{threshold:w,diffColorAlt:[0,255,0]})/(c.width*c.height)*100,I=L>w*100,R=`Visual diff of ${L.toFixed(2)}% detected, which is ${I?"over":"under"} the threshold of ${w*100}%.`;if(h&&(R+=` The ${h} screenshot was cropped since it was taller by ${S} pixels and wider by ${E} pixels.`),I)throw new M("ActionFailureError",R);return {fail:I,thoughts:R,beforeScreenshotOverride:c.buffer,afterScreenshotOverride:oL.encode(v,75).data,succeedImmediately:false,urlAfterCommand:n.url()}}var Y_e=3e4;function X_e(t){if(!t.body)return {};switch(t.body.type){case "json":return {content:t.body.content,contentType:"application/json"};case "form-urlencoded":{let e=new URLSearchParams;return Object.entries(t.body.content).forEach(([r,n])=>{e.append(r,n);}),{content:e.toString(),contentType:"application/x-www-form-urlencoded;charset=UTF-8"}}}}async function jp({command:t,logger:e,baseUrl:r,fetchImplementation:n=fetch}){let o=t.timeout??Y_e/1e3,i=Object.fromEntries(Object.entries(t.headers||{}).filter(([f,h])=>f&&h)),a=new URLSearchParams;Object.entries(t.params||{}).filter(([f,h])=>f&&h).forEach(([f,h])=>{a.append(f,h);});let s=a.toString(),l;if(lp(t.url)&&(l=t.url),r&&cp(t.url,r)&&(l=new URL(t.url,r).toString()),!l)throw new M("ActionFailureError",`Invalid URL: ${t.url}`);let c=l;e.info({url:c,searchParams:s,headers:i,body:t.body,method:t.method},"Making HTTP request");let d=await ee((async()=>{let f=s?`${c}?${s}`:c;try{let h=X_e(t),g=new Headers(i);return h.contentType&&!g.has("Content-Type")&&g.set("Content-Type",h.contentType),await n(f,{headers:g,method:t.method,body:h.content})}catch(h){throw new Error(`Failed to make HTTP request: ${h}`,{cause:h})}})(),{milliseconds:o*1e3,fallback:()=>{throw new M("ActionFailureError",`Fetch request timed out after ${o} seconds`)}});if(!d.ok){let f;try{f=await d.text();}catch(h){f=`Failed to read response body: ${h}`;}throw new M("ActionFailureError",`Fetch request failed with status ${d.status}: ${f}`)}let m={};d.headers.forEach((f,h)=>{m[h]=f;});let p={status:d.status,headers:m,request:{url:d.url,method:t.method,headers:i}};if(t.body?.type==="json"&&t.body.content)try{p.request.json=JSON.parse(t.body.content);}catch{}if(d.headers.get("content-type")?.includes("json"))try{p.json=await d.json();}catch{}else d.headers.get("content-type")?.includes("text")&&(p.text=await d.text());return p}var J_e=5e3;async function dX({timeout:t=un,...e}){let r=Date.now(),n=t*1e3,o=n+1e4,i,a=0,s=500;for(;a-r<n;){if(Date.now()-r>o){e.logger.warn("Exceeded max system timeout for page assertion, exiting...");break}e.signal?.throwIfAborted();let l=Date.now();i=await cX(e),a=Date.now();let c=a-l;if(c>1e3&&e.logger.warn({pageAssertDuration:c},"Page assertion took longer than expected"),!i.success)await pe(s,e.signal),s=Math.min(Math.floor(s*1.5),J_e);else return i}return i=await cX(e),i}async function cX(t){return Ir().startAsyncSpan("PAGE_ASSERTION",async r=>{let n=await iL(t);return r.result={success:n.success,message:n.err?.message},n},{name:"Page check"})}async function iL({assertion:t,browser:e,autoExpandIframes:r}){switch(t.type){case "CONTENT":case "CONTENT":{let o,i=false,a;try{let s;if(r){let l=await e.evaluateFunctionInAllFrames(uX,{value:t.value,negated:!!t.negated,returnHtml:!1});i=t.negated?l.every(c=>c.evaluation):l.some(c=>c.evaluation),s=l.find(c=>c.pageHtml)?.pageHtml;}else ({evaluation:i,pageHtml:s}=await e.evaluateFunctionInPage(uX,{value:t.value,negated:!!t.negated,returnHtml:!0},"checking page content"));if(!i){let l=t.negated?nl.CONTAINS:ol.CONTAINS;a=new M("AssertionFailureError",`The page ${l} '${t.value}'.`),o=s;}}catch(s){a=new M("AssertionFailureError",`Failed to evaluate page content assertion: ${s instanceof Error?s.message:`${s}`}`);}return {success:i,err:a,data:i||!o?void 0:{pageContent:o}}}default:return (o=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})()}}function uX({value:t,negated:e,returnHtml:r}){let n=document.body.innerHTML,o=n.includes(t)===!e;return n.length>1e4&&(n=n.slice(0,1e4)+"...TRUNCATED"),{evaluation:o,pageHtml:!o&&r?n:void 0}}var Z_e=3e4;async function mX({command:t,logger:e,baseUrl:r,fetchImplementation:n=fetch}){let o=t.timeout??Z_e/1e3,i=new AbortController,a=Object.fromEntries(Object.entries(t.headers||{}).filter(([d,m])=>d&&m));a["Content-Type"]="application/json";let s;if(lp(t.url)&&(s=t.url),r&&cp(t.url,r)&&(s=new URL(t.url,r).toString()),!s)throw new M("ActionFailureError",`Invalid URL: ${t.url}`);let c=await ee((async()=>{try{return await n(s,{headers:a,method:"POST",body:JSON.stringify({query:t.query,variables:t.variables?JSON.parse(t.variables):void 0}),signal:i.signal})}catch(d){throw new Error(`Failed to make HTTP request: ${d}`,{cause:d})}})(),{milliseconds:o*1e3});if(!c)throw new M("ActionFailureError",`GraphQL request timed out after ${o} seconds`);if(!c.ok){let d,m=await c.text();try{d=JSON.parse(m);}catch{throw new M("ActionFailureError",`GraphQL request failed with status ${c.status}: ${m}`)}throw d?.errors?.length&&d?.errors[0]?.message?new M("ActionFailureError",`GraphQL request failed with status ${c.status}: ${d.errors[0].message}`):new M("ActionFailureError",`GraphQL request failed with status ${c.status}: ${m}`)}let u={};return c.headers.forEach((d,m)=>{u[m]=d;}),{status:c.status,headers:u,json:await c.json()}}var lw=class{orgId;options;storage;localCodeEvalTools;uploadedFileStorage;visualDiffScreenshotStorage;browser;generator;executeAbortController=new AbortController;logger;executionOptionsStack=[];recordAbortController=null;registeredListeners={};recordedRequests={};constructor({browser:e,generator:r,logger:n,storage:o,orgId:i,localCodeEvalTools:a,uploadedFileStorage:s,visualDiffScreenshotStorage:l,options:c}){this.orgId=i,this.options=c,this.browser=e,this.browser.registerAbortSignal(this.executeAbortController.signal),this.storage=o,this.uploadedFileStorage=s,this.visualDiffScreenshotStorage=l,this.localCodeEvalTools=a,this.generator=r,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 withExecutionOptions(e,r){this.executionOptionsStack.push(e);try{return await r()}finally{this.executionOptionsStack.pop();}}getCurrentExecutionOptions(){return this.executionOptionsStack[this.executionOptionsStack.length-1]??{}}async evaluateAiAction({goal:e,startingScreenshot:r,history:n,disableCache:o,langfuseSessionId:i,lastError:a,logger:s=this.logger}){let[l,c]=await Promise.all([Oc(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:true,skipWaitForPageLoad:true,logger:s}),this.browser.screenshot({retries:1,clearHighlights:true})]),u=`data:image/jpeg;base64,${c.toString("base64")}`,d=await md({type:"ai-action",description:e,screenshot:u,serializedTree:l.serializedTree,tree:l.tree,fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:s,orgId:this.orgId}}),m={url:this.browser.url(),browserState:d,startingScreenshot:r,history:n,goal:e,screenshot:u,lastError:a};return await this.generator.getMultiturnAiActionEvaluation(m,{disableCache:o,abortSignal:this.executeAbortController.signal,loggerTags:{...De(s)},langfuseSessionId:i})}async promptToCommand({goal:e,startingScreenshot:r,history:n,actionHint:o,disableCache:i,logger:a=this.logger,langfuseSessionId:s}){let l=this.browser.url(),[c,u]=await Promise.all([Oc(this.browser,{abortSignal:this.executeAbortController.signal,skipWait:true,skipWaitForPageLoad:true,logger:a}),this.browser.screenshot({retries:1,clearHighlights:true})]),d=`data:image/jpeg;base64,${u.toString("base64")}`,m=await md({type:"ai-action",description:e,screenshot:d,serializedTree:c.serializedTree,tree:c.tree,fixtures:{generator:this.generator,signal:this.executeAbortController.signal,logger:a,orgId:this.orgId}}),p={url:l,browserState:m,startingScreenshot:r,history:n,goal:e,actionHint:o,screenshot:d};try{return await this.generator.getMultiturnAiActionCommand(p,{disableCache:i,abortSignal:this.executeAbortController.signal,loggerTags:{...De(a)},langfuseSessionId:s})}catch(f){throw new M("InternalWebAgentError",`Error generating command: ${f instanceof Error?f.message:f}`,{errOptions:{cause:f}})}}async getBrowserState(e){return Oc(this.browser,e)}async locateElement(e){return await nL(e,this.getControllerFixtures())}async locateElementWithSelector(e,r){return Qi({action:async()=>{let n=await this.browser.resolveHardcodedCssSelector({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:r?{type:"url",url:r}:void 0,browser:this.browser,logger:this.logger})}getControllerFixtures(){return {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??true}async wrapMultiElementTargetingCommand({tracer:e,command:r,targetNames:n,descriptions:o,caches:i,action:a,options:s,retriesWithAI:l=1}){let c=[];for(let u=0;u<o.length;u++){let d=o[u],m=await this.wrapElementTargetingCommand({tracer:e,command:r,target:d,cache:i[u],action:async p=>p,options:{...s,targetName:n[u]}});c.push(m);}try{let u=await a(...c.map(p=>p.result)),d=p=>p==="fromTarget"?"From Target":p==="toTarget"?"To Target":"Target",m=c.map((p,f)=>p.thoughts?`${d(n[f])}: ${p.thoughts}`:void 0).filter(p=>!!p).join(" -------------- ")||void 0;return {result:u,elementInteractedDisplayStrings:c.map(p=>p.elementInteractedDisplayString),thoughts:m}}catch(u){if(this.throwIfClosed(),l>0)return this.logger.warn({err:u},"Failed to execute action with multiple cached targets, retrying with AI"),this.wrapMultiElementTargetingCommand({tracer:e,command:r,targetNames:n,descriptions:o,caches:o.map(()=>{}),action:a,options:s,retriesWithAI:l-1});throw new M("ActionFailureError",u.message,{errOptions:{cause:u}})}}async wrapHardcodedCssTargetingCommandHelper({target:e,action:r,options:n,command:o}){let i=this.logger.child({commandId:o.id}),{targetName:a}=n;if(e.type!=="description")throw new M("ActionFailureError","Cannot use selector with non-description target");let s,l=Date.now(),c=Date.now();for(;Date.now()-c<this.browser.smartWaitingTimeout;){l=Date.now();try{let u=await this.browser.resolveHardcodedCssSelector({selector:e.elementDescriptor,targetName:a,logger:i});return {result:await r({locator:u.locator,originalElementLocationResult:void 0,serverSideBoundingBox:null}),elementInteractedDisplayString:u.displayString}}catch(u){if(u.name==="AbortError")throw u;s=u,i.warn({err:u},"Failed to action on hardcoded css selector"),Date.now()-l<500&&await pe(500);}}throw s}async scrollIntoViewAndResolveFinalTarget(e){let{resolutionResult:r,disableGlobalLocatorRedirect:n,logger:o}=e,i=Ir(),a=!n&&this.browser.userBrowserSettings.globalLocatorRedirect!==false;(this.browser.userBrowserSettings.visualActions||a)&&await i.startAsyncSpan("SCROLL_ELEMENT_INTO_VIEW",async()=>{await this.browser.scrollIntoViewIfNeeded(r.locator);});let s;return a&&(s=await i.startAsyncSpan("LOCATOR_REDIRECT",async l=>{let{targetingResult:c,metadata:u}=await this.browser.performTargetRedirection(r,o);if(l.result=u,u.outcome==="redirected to new element"&&c&&i.storeTraceAsset&&!this.browser.userBrowserSettings.disableBrowserMonitoring){let d=randomUUID();(async()=>{try{let m=await this.browser.screenshot({locator:c.locator,clearHighlights:!0,boundingBoxOverride:c.serverSideBoundingBox??void 0});i.storeTraceAsset?.({snapshotId:d,data:m});}catch(m){o.debug({err:m},"Failed to capture element screenshot for redirect trace");}})(),l.elementScreenshotSnapshotId=d;}return c})),s||(s={locator:r.locator,serverSideBoundingBox:await r.locator.boundingBox({timeout:ke}),originalElementLocationResult:r.originalElementLocationResult}),s}async resolveCachedTargetForAction(e){let{cache:r,options:n,logger:o}=e,a=await Ir().startAsyncSpan("CACHE_RESOLUTION",async l=>{l.targetSource=r.targetSource,l.attributes.smartWaitingTimeoutMs=this.browser.smartWaitingTimeout;try{let c=await this.browser.resolveTarget(r,{allowNotActionableNodesOverride:n.allowNotActionableNodesOverride,logger:o,signal:this.executeAbortController.signal,...n.resolveTargetOptions,acceptElementMovedError:n.force});l.attributes.targetDisplayString=c.displayString,l.attributes.decisions=c.decisions;let u=c.decisions.find(d=>d.matched);return u&&(l.resolutionMethod=u.type),c}catch(c){throw c instanceof Pe&&(l.cacheMissReason=c.cacheMissReason,l.attributes.decisions=c.decisions),c}}),s=await this.scrollIntoViewAndResolveFinalTarget({resolutionResult:a,disableGlobalLocatorRedirect:n.disableGlobalLocatorRedirect,logger:o});return n.force||await a.revalidator?.(),{resolutionResult:a,finalTarget:s}}async wrapElementTargetingCommand(e){return await Qi({action:()=>this.wrapElementTargetingCommandHelper(e),frameConfig:e.options.iframeUrl?{type:"url",url:e.options.iframeUrl}:void 0,browser:this.browser,logger:this.logger})}async wrapElementTargetingCommandHelper(e){let{tracer:r,target:n,action:o,options:i,command:a,finalAttempt:s=false,originalCache:l=e.cache}=e,{retriesWithAI:c=1}=e,{disableCache:u,useSelector:d,targetName:m}=i,p=Ir(),f=this.logger.child({commandId:a.id}),h=this.shouldUseMemory(),g=cloneDeep(e.cache);if((!g||u)&&!QF(n))throw new M("ActionFailureError","Cannot target element with no cached data or element descriptor");if(d)return this.wrapHardcodedCssTargetingCommandHelper(e);let y=false,S;u&&(f.info("Cache explicitly disabled for this step"),y=true,S="Cache explicitly disabled",g=void 0);let E=WY({cache:g,description:n.elementDescriptor,disableSecondaryCacheResolution:!!this.browser.userBrowserSettings.disableSecondaryCacheResolution,logger:f});g=E.cache,y=y||E.cacheBustedBeforeAction,!S&&E.cacheBustReason&&(S=E.cacheBustReason);let v=true;if(!HY(g))return c--,v=false,this.executeTargetingCommandWithAI({tracer:p,stepTracer:r,target:n,options:i,command:a,action:o,originalCache:l,logger:f,useMemory:h,cacheBustedBeforeAction:y,cacheBustReason:S});try{let{resolutionResult:w,finalTarget:_}=await this.resolveCachedTargetForAction({cache:g,options:i,logger:f}),L=await o(_);if(Ge.increment("cache_target_resolution_v2",1,["outcome:hit","platform:web",`hasRequirements:${!!g.requirements}`,`hasAdditionalElements:${!!g.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:1.0.2"]),Sv({cmd:a,key:m,newTarget:g,logger:f,updatedWithAI:!1}),v){let I=w.decisions.filter(R=>R.matched);if(I.length!==1)f.warn({decisions:w.decisions},"Expected exactly 1 matching method for element location, got more or less");else {let R=I[0].type;r.recordTargetAutoHeal({healType:R});}}return {result:L,elementInteractedDisplayString:w.displayString}}catch(w){this.throwIfClosed();let _=Gx(w);if(_&&!s)return f.warn({err:w},"Encountered error that is retryable with cache"),this.wrapElementTargetingCommandHelper({tracer:r,command:a,target:n,action:o,cache:l,originalCache:l,retriesWithAI:c,finalAttempt:true,options:i});if(w instanceof M&&!_)throw f.warn({err:w},"Failed to execute command with target (fatal)"),w;if(c>0&&n){f.info({err:w},"Failed to execute action with cached target, retrying with AI"),Ge.increment("cache_target_resolution_v2",1,["outcome:miss","platform:web",`hasRequirements:${!!g.requirements}`,`hasAdditionalElements:${!!g.additionalElements}`,`orgId:${this.orgId}`,"cliVersion:1.0.2",`missReason:${w instanceof Pe?w.cacheMissReason:"unknown"}`]);let L;g.memory&&eB(g.memory)&&(L=g.memory);let I=w instanceof Pe&&w.cacheMissReason==="failing-ldist";return this.wrapElementTargetingCommandHelper({tracer:r,command:a,target:n,cache:void 0,action:o,originalCache:l,retriesWithAI:c,finalAttempt:true,options:{...i,memory:L,targetHealingInProgress:true},skipInitialLocateWait:I})}throw new M("ActionFailureError",`Failed to execute interactive command: ${w instanceof Error?w.message:`${w}`}`,{errOptions:{cause:w}})}}async executeTargetingCommandWithAI(e){let{tracer:r,stepTracer:n,target:o,options:i,command:a,action:s,originalCache:l,logger:c,useMemory:u,cacheBustedBeforeAction:d,cacheBustReason:m,skipInitialLocateWait:p}=e;c.info({description:o.elementDescriptor,targetHealingInProgress:i.targetHealingInProgress,cacheBustedBeforeAction:d,memory:i.memory,useMemory:u},"Prompting AI for an updated element location");let f=false;(d||!l)&&!this.getCurrentExecutionOptions().skipAISmartWaiting&&!i.skipAISmartWaiting?(await r.startAsyncSpan("SMART_WAITING",async()=>await rX({description:o.elementDescriptor,iframeUrl:i.iframeUrl,source:i.source,logger:c,allowNotActionableNodesOverride:i.allowNotActionableNodesOverride},this.getControllerFixtures())),f=true):(d||!l)&&(i.skipAISmartWaiting?c.debug("Skipping AI smart waiting for this targeting attempt"):c.debug("Skipping AI smart waiting due to controller execution options"));let h=2;for(let g=1;g<=h;g++){let y=false,S=this.browser.getActiveFrameConfig(),E=i.force||g>1;try{let v;try{v=await nL({description:o.elementDescriptor,disableCache:!!i.disableCache,iframeUrl:i.iframeUrl,source:i.source,useMemory:u,memory:u?i.memory:void 0,allowNotActionableNodesOverride:i.allowNotActionableNodesOverride,allowIneligibleTagRedirect:i.allowIneligibleTagRedirect,showZeroOpacityElementsOverride:i.showZeroOpacityElementsOverride,logger:c,skipWait:f||p,isAutoHeal:!!i.targetHealingInProgress,cacheBustReason:m,acceptElementMovedError:E},this.getControllerFixtures());}catch(L){if(L instanceof Wa&&L.updatedLocatorMemory){let I={id:-1,...l,memory:L.updatedLocatorMemory};Sv({cmd:a,key:i.targetName,newTarget:I,logger:c,updatedWithAI:!0});}throw L}v.frameConfig&&(this.browser.setActiveFrameConfig(v.frameConfig),y=!0);let w=await this.scrollIntoViewAndResolveFinalTarget({resolutionResult:v.resolution,disableGlobalLocatorRedirect:i.disableGlobalLocatorRedirect,logger:c}),_=await s(w);return Sv({cmd:a,key:i.targetName,newTarget:v.target,logger:c,updatedWithAI:!0}),i.targetHealingInProgress&&(n.recordTargetAutoHeal({healType:"AI"}),v.target.targetSource="AI_HEALED",v.target.targetUpdateTime=new Date().toUTCString(),v.target.targetUpdateLoggerTags=De(c)),{result:_,elementInteractedDisplayString:v.resolution.displayString,thoughts:v.thoughts}}catch(v){if(y&&this.browser.setActiveFrameConfig(S),this.throwIfClosed(),g<h&&Gx(v)){c.warn({err:v,aiAttempt:g},"Encountered retryable AI targeting error; retrying with AI once");continue}throw v instanceof M?v:new M("ActionFailureError",v.message)}}throw new M("ActionFailureError","Failed to execute AI targeting after retry")}async screenshotWithDimensions(e){return Ob(this.browser,e)}async executePresetCommand(e,r,n,o,i){this.options?.slowMoMs&&await pe(this.options.slowMoMs);let a=await this.browser.getOpenPages(),s=this.browser.url(),l;try{l=await this.resolveCommandTemplateStrings(r,n);}catch(c){throw this.throwIfClosed(),new M("ActionFailureError",`Failed to substitute template strings in command: ${c.message}`,{errOptions:{cause:c}})}try{let c=await Ne({name:`cli.command.${r.type}`,attributes:{"momentic.command_type":r.type,"momentic.command_id":r.id},fn:()=>this.executePresetCommandHelper(e,r,n,o,i)});return this.options?.autoFollowNewTabs&&await jY({beforeUrl:s,command:r,beforePages:a.map(u=>u.url),browser:this.browser,logger:this.logger}),c}catch(c){throw c.name!=="AbortError"&&this.logger.error({err:c},"Error thrown in action controller"),c}finally{Bp(r,l);}}createCallbacksForBrowser(e){return {createIsolatedFolder:()=>DD(e)}}async traceBrowserInteraction(e,r,n){return Ir().startAsyncSpan("BROWSER_INTERACTION",async i=>r(i),{name:e,...n})}async resolveCommandTemplateStrings(e,r){return Fp({obj:e,context:r,bannedKeys:["type","a11yData","thoughts","cache","code"],orgId:this.orgId,logger:this.logger,signal:this.executeAbortController.signal,localTools:this.localCodeEvalTools})}async executePresetCommandHelper(e,r,n,o,i){o=o||"disableCache"in r&&!!r.disableCache;let a=this.logger.child({commandId:r.id});switch(r.type){case "SUCCESS":{let s=r.condition;return s?.assertion.trim()?sw({command:s,fixtures:this.getControllerFixtures(),useMemory:this.shouldUseMemory(),logger:a,recoveryHint:i}):{succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "AI_ASSERTION":{if(!r.assertion.trim())throw new M("ActionFailureError","Missing assertion");if(r.timeout&&r.timeout>1800)throw new M("AssertionFailureError",`AI check timeout of ${r.timeout} exceeds the maximum allowed value of 30 minutes.`);return sw({command:r,fixtures:this.getControllerFixtures(),useMemory:this.shouldUseMemory(),logger:a,recoveryHint:i})}case "AI_EXTRACT":return tX({command:r,logger:a,fixtures:this.getControllerFixtures(),disableCache:o});case "NAVIGATE":if(!lp(r.url)&&!cp(r.url,this.browser.baseUrl))throw new M("ActionFailureError",`Invalid URL provided to navigate command: ${r.url}`);await this.traceBrowserInteraction("Navigate",()=>this.browser.navigate({url:r.url,loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0}));break;case "DIALOG":this.browser.registerDialogHandler(r.action);break;case "CAPTCHA":throw new M("UserConfigurationError","Captcha solving is no longer available on Momentic");case "GO_BACK":await this.traceBrowserInteraction("Go back",()=>this.browser.goBack());break;case "GO_FORWARD":await this.traceBrowserInteraction("Go forward",()=>this.browser.goForward());break;case "SCROLL_LEFT":case "SCROLL_RIGHT":case "SCROLL_DOWN":case "SCROLL_UP":{let s,l;if(r.target&&za(r.target)){let d=er(r.target.pixels);await this.browser.hoverUsingVisualCoordinates(d);}else if(r.target&&r.target.elementDescriptor.trim()){let{elementInteractedDisplayString:d,thoughts:m}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:p=>this.browser.hover(p),options:{...r,targetName:"target",disableGlobalLocatorRedirect:true,disableCache:o}});s=d,l=m;}let c=this.browser.getViewport()?.height??Ol.height,u=this.browser.getViewport()?.width??Ol.width;switch(r.type){case "SCROLL_UP":await this.traceBrowserInteraction("Scroll up",()=>this.browser.scrollVertical(-(r.deltaY??c)));break;case "SCROLL_DOWN":await this.traceBrowserInteraction("Scroll down",()=>this.browser.scrollVertical(r.deltaY??c));break;case "SCROLL_LEFT":await this.traceBrowserInteraction("Scroll left",()=>this.browser.scrollHorizontal(-(r.deltaX??u)));break;case "SCROLL_RIGHT":await this.traceBrowserInteraction("Scroll right",()=>this.browser.scrollHorizontal(r.deltaX??u));break}return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "WAIT_FOR_URL":{if(r.timeout&&r.timeout>1800)throw new M("UserConfigurationError",`Wait for URL timeout of ${r.timeout} exceeds the maximum allowed value of 30 minutes.`);let s=r.matcher;await this.browser.waitForUrl({beforeUrl:this.browser.url(),matcher:s},{timeout:r.timeout?r.timeout*1e3:void 0,negated:r.negated,caseInsensitive:r.caseInsensitive});break}case "WAIT":{if(r.delay>1800)throw new M("UserConfigurationError",`Wait timeout of ${r.delay} seconds exceeds the maximum allowed value of 30 minutes`);let s=r.delay*1e3;await pe(s,this.executeAbortController.signal);break}case "REFRESH":await this.traceBrowserInteraction("Refresh",()=>this.browser.refresh({loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0}));break;case "CLICK":{if(za(r.target)){let m=er(r.target.pixels),p={...r,relativePosition:r.relativePosition?er(r.relativePosition):void 0};await this.traceBrowserInteraction("Click",()=>this.browser.clickUsingVisualCoordinates(m,p),{coordinates:m});break}let s=this.browser.url(),{elementInteractedDisplayString:l,result:c,thoughts:u}=await this.wrapElementTargetingCommand({tracer:e,target:r.target,command:r,cache:r.cache?.target,action:m=>this.traceBrowserInteraction("Click",async p=>{let f={...r,relativePosition:r.relativePosition?er(r.relativePosition):void 0},h=await this.browser.click(m,this.createCallbacksForBrowser(this.orgId),f);return h.coordinates&&(p.coordinates=h.coordinates),h},{selector:m.locator.toString()}),options:{...r,targetName:"target",disableCache:o}}),d={urlAfterCommand:this.browser.url(),succeedImmediately:false,elementInteracted:l,thoughts:u,data:c.downloadedFile?{downloadedFile:c.downloadedFile}:void 0};return _v(s,d.urlAfterCommand)&&(d.succeedImmediately=true,d.succeedImmediatelyReason="URL changed"),d}case "COPY":return await this.browser.copy(r.value),{succeedImmediately:false,data:r.value,urlAfterCommand:this.browser.url()};case "PASTE":{await this.browser.paste();break}case "DRAG":{if(za(r.fromTarget)&&za(r.toTarget)){let c=er(r.fromTarget.pixels),u=er(r.toTarget.pixels);await this.traceBrowserInteraction("Drag",()=>this.browser.dragAndDropUsingVisualCoordinates(c,u,{hoverDurationMs:r.hoverSeconds?r.hoverSeconds*1e3:void 0}),{coordinates:c});break}if(za(r.fromTarget)||za(r.toTarget))throw new Error("Drag and drop targets must be both coordinates or both descriptions");let{elementInteractedDisplayStrings:s,thoughts:l}=await this.wrapMultiElementTargetingCommand({tracer:e,command:r,targetNames:["fromTarget","toTarget"],descriptions:[r.fromTarget,r.toTarget],caches:[r.cache?.fromTarget,r.cache?.toTarget],action:(c,u)=>this.traceBrowserInteraction("Drag",()=>this.browser.dragAndDrop(c,u,{hoverDurationMs:r.hoverSeconds?r.hoverSeconds*1e3:void 0,steps:r.steps})),options:{...r,disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s[0],thoughts:l}}case "MOUSE_DRAG":{let s=parseInt(r.deltaX),l=parseInt(r.deltaY),c=r.steps??5;if(isNaN(s)||isNaN(l))throw new M("ActionFailureError",`Invalid pixel values passed to mouse drag command: (${r.deltaX}, ${r.deltaY})`);if(r.target&&za(r.target)){let m=er(r.target.pixels);await this.traceBrowserInteraction("Mouse drag",()=>this.browser.mouseDragUsingVisualCoordinates({deltaX:s,deltaY:l,steps:c,fromTarget:m}),{coordinates:m});break}let u,d;if(r.target?.elementDescriptor){let{elementInteractedDisplayString:m,thoughts:p}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:async f=>this.traceBrowserInteraction("Mouse drag",()=>this.browser.mouseDrag(s,l,c,f.locator,{force:r.force})),options:{...r,targetName:"target",disableCache:o}});u=m,d=p;}else await this.traceBrowserInteraction("Mouse drag",()=>this.browser.mouseDrag(s,l,c,void 0,{force:r.force}));return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:u,thoughts:d}}case "SELECT_OPTION":{if(!zs(r.target))throw new Error("Select with x/y is not supported yet");let s=r.target.elementDescriptor,l=r.choice,{elementInteractedDisplayString:c,thoughts:u}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:{type:"description",elementDescriptor:s},cache:r.cache?.target,action:d=>this.traceBrowserInteraction("Select option",()=>this.browser.selectOption(d,l,r.force),{value:l.type==="LABEL"?l.label:l.type==="VALUE"?l.value:l.index}),options:{...r,targetName:"target",disableCache:o,source:Ah(r)}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:c,thoughts:u}}case "TAB":{let s={loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0,retry:true};await this.browser.switchToPage(r.action,s);break}case "NEW_TAB":await this.browser.createNewTab(r.url,{loadTimeoutMs:r.loadTimeout?r.loadTimeout*1e3:void 0});break;case "CLOSE_TAB":await this.browser.closePage(r.action,{retry:true});break;case "COOKIE":{if(!r.value)break;let s=await this.browser.setCookie(r.value);a.debug({results:s},"Set cookies");break}case "LOCAL_STORAGE":if(!r.value||!r.key)break;await this.browser.setLocalStorage(r.key,r.value);break;case "JAVASCRIPT":{let s;try{r.environment==="BROWSER"?(s=await this.browser.evaluateCodeInPage({code:r.code,fragment:r.fragment??!1,context:n.toObjectCopy(),timeoutMs:r.timeout?r.timeout*1e3:void 0}),a.info({result:s},"Executed JavaScript in browser")):s=await Yi({orgId:this.orgId,code:r.code,fragment:!!r.fragment,context:n,timeoutMs:r.timeout?r.timeout*1e3:void 0,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal,callbacks:{onPersistentVariableUpdates:async l=>{if(!this.options?.scratchPadId){a.warn({updates:l},"Got persistent variable updates but scratch pad is not available");return}await this.storage.savePersistentVariables?.({scratchPadId:this.options?.scratchPadId,orgId:this.orgId,updates:l,logger:a});}}});}catch(l){throw this.throwIfClosed(),new M("ActionFailureError",l instanceof Error?l.message:`${l}`,{errOptions:{cause:l}})}try{JSON.stringify(s);}catch(l){throw new M("ActionFailureError",`Return value is not serializable: ${l instanceof Error?l.message:`${l}`}`,{errOptions:{cause:l}})}return {urlAfterCommand:this.browser.url(),succeedImmediately:false,data:s}}case "TYPE":{if(r.target&&za(r.target)){let p=er(r.target.pixels),f={...r,relativePosition:r.relativePosition?er(r.relativePosition):void 0};await this.browser.clickUsingVisualCoordinates(p,f),await this.traceBrowserInteraction("Type",()=>this.browser.type(r.value,{force:r.force,clearContent:r.clearContent,forceClearContent:r.forceClearContent,delay:r.delay,pressEnter:r.pressEnter},true),{value:r.value});break}let s=this.browser.url(),l,c,u=cloneDeep(r.target),d=this.browser.userBrowserSettings.globalLocatorRedirect===void 0||this.browser.userBrowserSettings.globalLocatorRedirect==="always";if(u){let{elementInteractedDisplayString:p,thoughts:f}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:u,cache:r.cache?.target,action:h=>this.traceBrowserInteraction("Type",()=>this.browser.typeIntoTarget(r.value,h,{force:r.force,clearContent:r.clearContent,forceClearContent:r.forceClearContent,delay:r.delay,pressEnter:r.pressEnter,relativePosition:r.relativePosition}),{value:r.value,selector:h.locator.toString()}),options:{...r,targetName:"target",disableCache:o,disableGlobalLocatorRedirect:!d,source:Ah(r)}});l=p,c=f;}else await this.traceBrowserInteraction("Type",()=>this.browser.type(r.value,{force:r.force,clearContent:r.clearContent,forceClearContent:r.forceClearContent,delay:r.delay,pressEnter:r.pressEnter},true),{value:r.value});let m={urlAfterCommand:this.browser.url(),succeedImmediately:false,elementInteracted:l,thoughts:c};return _v(s,m.urlAfterCommand)&&(m.succeedImmediately=true,m.succeedImmediatelyReason="URL changed"),m}case "HOVER":{if(za(r.target)){let c=er(r.target.pixels);await this.traceBrowserInteraction("Hover",()=>this.browser.hoverUsingVisualCoordinates(c),{coordinates:c});break}let{elementInteractedDisplayString:s,thoughts:l}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:c=>this.traceBrowserInteraction("Hover",()=>this.browser.hover(c,{relativePosition:r.relativePosition?er(r.relativePosition):void 0}),{selector:c.locator.toString()}),options:{...r,targetName:"target",disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "FOCUS":{if(!zs(r.target))throw new Error("Focus with x/y is not supported yet");let{elementInteractedDisplayString:s,thoughts:l}=await this.wrapElementTargetingCommand({tracer:e,command:r,target:r.target,cache:r.cache?.target,action:c=>this.browser.focus(c),options:{...r,targetName:"target",disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "BLUR":{if(r.target&&!zs(r.target))throw new Error("Blur with x/y is not supported yet");if(!r.target||!r.target.elementDescriptor)return await this.browser.blur(null),{succeedImmediately:false,urlAfterCommand:this.browser.url()};let{elementInteractedDisplayString:s,thoughts:l}=await this.wrapElementTargetingCommand({tracer:e,target:r.target,command:r,cache:r.cache?.target,action:c=>this.browser.blur(c),options:{...r,targetName:"target",disableCache:o}});return {succeedImmediately:false,urlAfterCommand:this.browser.url(),elementInteracted:s,thoughts:l}}case "PRESS":{let s=this.browser.url();await this.traceBrowserInteraction("Press key",()=>this.browser.press(r.value,{repeat:r.repeat,convertMeta:r.convertMeta??true,delayMs:r.delayMs}),{value:r.value});let l={urlAfterCommand:this.browser.url(),succeedImmediately:false};return _v(s,l.urlAfterCommand)&&(l.succeedImmediately=true,l.succeedImmediatelyReason="URL changed"),l}case "KEY_DOWN":return await this.browser.keyDown(r.value,{convertMeta:r.convertMeta??true}),{urlAfterCommand:this.browser.url(),succeedImmediately:false};case "KEY_UP":return await this.browser.keyUp(r.value,{convertMeta:r.convertMeta??true}),{urlAfterCommand:this.browser.url(),succeedImmediately:false};case "REQUEST":{let s=new CookieJar,l=eOe(fetch,s),c;try{c=new URL(r.url).hostname;}catch{}let u=await jp({command:r,baseUrl:this.browser.baseUrl,logger:a,fetchImplementation:l});return {data:Wd.parse({...u,cookies:Tm(s,c)}),succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "GRAPHQL_REQUEST":return {data:await mX({command:r,baseUrl:this.browser.baseUrl,logger:a}),succeedImmediately:false,urlAfterCommand:this.browser.url()};case "VISUAL_DIFF":return lX({tracer:e,command:r,disableCache:o,browser:this.browser,logger:a,screenshotStorage:this.visualDiffScreenshotStorage,targetingWrapper:s=>this.wrapElementTargetingCommand(s)});case "FILE_UPLOAD":{let s,l;if(r.fileSource.type==="URL"?(l=r.fileSource.url,s=await I6({uri:r.fileSource.url,logger:a,orgId:this.orgId})):r.fileSource.type==="USER_FILE"&&(l=r.fileSource.name,s=await this.uploadedFileStorage?.getFileForUpload(r.fileSource.name,this.orgId)),!s)throw new M("UserConfigurationError",`Attempted to use non-existent file for upload step: ${l}`);await this.browser.setFileChooserHandler({...s,filename:r.filename});break}case "AUTH_SAVE":{let s=await this.browser.saveAuthState();if(r.storageState&&q_(r.storageState)){let l=fr__default.resolve(r.storageState);Sn.mkdirSync(fr__default.dirname(l),{recursive:true}),Sn.writeFileSync(l,`${JSON.stringify(s,null,2)}
|
|
5716
5716
|
`,"utf8");}return {data:s,succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "AUTH_LOAD":{let s;if(q_(r.storageState))try{s=JSON.parse(Sn.readFileSync(fr__default.resolve(r.storageState),"utf8"));}catch(c){throw new M("UserConfigurationError",`Failed to read auth state from '${r.storageState}': ${W(c)}`,{errOptions:{cause:c}})}else if(!r.storageState.trim())s=void 0;else if(s=await Yi({orgId:this.orgId,code:r.storageState,fragment:false,context:n,logger:a,localTools:this.localCodeEvalTools,signal:this.executeAbortController.signal}),typeof s!="object")throw new M("ActionFailureError",`Credentials must evaluate to an object (received ${typeof s} instead)`);let l;try{l=yz.optional().parse(s);}catch(c){throw new M("ActionFailureError",`Credentials provided do not follow the required format: ${c}`)}await this.browser.loadAuthState(l);break}case "ELEMENT_CHECK":{let s=(r.timeout??un)*1e3,l=this.generator.getAgentConfig()?.assertion;if(aX(r.assertion)&&!r.useSelector&&r.target.type==="description"&&l&&l!=="v1"){let u={id:r.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: ${r.target.elementDescriptor}`,iframeUrl:r.iframeUrl,timeout:r.timeout,source:"NEGATED_CHECK",cache:r.cache&&"memory"in r.cache?{memory:r.cache?.memory}:void 0};try{let d=await sw({command:u,logger:a,fixtures:this.getControllerFixtures(),useMemory:this.shouldUseMemory()});return {succeedImmediately:!1,thoughts:`The element described does not exist on the page: ${d.thoughts}`,urlAfterCommand:this.browser.url(),afterScreenshotOverride:d.afterScreenshotOverride}}finally{u.cache?.memory&&Bg(r,u.cache?.memory.traces,a);}}let c=await iX({command:r,tracer:e,timeoutMs:s,targetingWrapper:u=>this.wrapElementTargetingCommand(u),fixtures:this.getControllerFixtures(),disableCache:o});return {fail:!c.success,data:c.data,elementInteracted:c.elementInteractedDisplayString,thoughts:c.err?.message??c.thoughts??`Element assertion ${c.success?"succeeded":"failed"}.`,succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "PAGE_CHECK":{let s=await Qi({action:async()=>dX({assertion:r.assertion,browser:this.browser,logger:a,timeout:r.timeout,signal:this.executeAbortController.signal,autoExpandIframes:!!this.browser.userBrowserSettings.autoExpandIframes}),frameConfig:r.iframeUrl?{type:"url",url:r.iframeUrl}:void 0,browser:this.browser,logger:a});return {fail:!s.success,data:s.data,thoughts:s.success?"Page assertion passed.":s.err?.message??`Page assertion still failing after ${r.timeout} seconds.`,urlAfterCommand:this.browser.url(),succeedImmediately:false}}case "REGISTER_REQUEST_LISTENER":{let s=new Ic(r.requestMatcher),l=this.browser.registerRequestListener(s);return this.registeredListeners[r.key]=l.then(async c=>await FD(c)).catch(c=>{a.error({err:c},"Failed to get request listener response");}),{succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "AWAIT_LISTENER":{let s=this.registeredListeners[r.key];if(!s)throw new M("ActionFailureError",`No listener registered with key: ${r.key}`);let l=r.timeout??10;return {data:await ee(s,{milliseconds:l*1e3,message:`Request listener timed out after ${l} seconds`}),succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "RECORD_REQUESTS":{let s=new Ic(r.requestMatcher);return this.recordedRequests[r.key]={},this.browser.registerRequestRecorder(r.key,{matches:l=>s.matches({url:l.request.url,method:l.request.method}),onRequestStart:(l,c)=>{this.recordedRequests[r.key][l]=JC(c);},onRequestComplete:(l,c)=>{this.recordedRequests[r.key]?.[l]&&(this.recordedRequests[r.key][l]=JC(c));}}),{succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "GET_RECORDED_REQUESTS":{let s=this.recordedRequests[r.key];if(!s)throw new M("ActionFailureError",`No recorder registered with key: ${r.key}`);return delete this.recordedRequests[r.key],{data:Object.values(s),succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "SET_HEADER":{let s;return r.requestMatcher&&(s=new Ic(r.requestMatcher)),this.browser.setHeader(r.name,r.value,s),{succeedImmediately:false,urlAfterCommand:this.browser.url()}}case "MOCK_ROUTE":return {data:{key:this.browser.registerMock(r.key,new Ic(r.requestMatcher),async(l,c)=>{let u=await Yi({orgId:this.orgId,code:r.responseGenerator,fragment:false,context:n,timeoutMs:void 0,logger:a,localTools:this.localCodeEvalTools,mock:{request:l,response:c},disallowVariableUpdates:true,responseSerialization:"RESPONSE"}),d=Zz.parse(u);return new Response(d.body,{status:d.status,headers:d.headers})},r.fetchOriginalResponse??false)},succeedImmediately:false,urlAfterCommand:this.browser.url()};case "REMOVE_ROUTE_MOCK":return this.browser.removeMock(r.key),{succeedImmediately:false,urlAfterCommand:this.browser.url()};case "OFFLINE_MODE":return await this.browser.setOfflineMode(r.enable),{succeedImmediately:false,urlAfterCommand:this.browser.url()};default:return (l=>{throw "If Typescript complains about the line below, you missed a case or break in the switch above"})()}return {succeedImmediately:false,urlAfterCommand:this.browser.url()}}async getReverseMappedDescription({browserState:e,targetId:r,disableCache:n,screenshot:o}){return (await this.generator.getReverseMappedDescription({browserState:e,target:r,screenshot:o},{disableCache:n,abortSignal:this.executeAbortController.signal,loggerTags:De(this.logger)})).phrase}async stopRecordMode(){this.recordAbortController?.abort(),await this.browser.clearAllCdpHighlights();}async startRecordMode({params:e,abortController:r,isClickToRecord:n}){this.recordAbortController=r;let o=new nw({signal:r.signal,...e});return await this.browser.startRecording(this.recordAbortController.signal,o,n),o}async runSectionAutohealing(e){return this.generator.getAutohealingProposal(e,{disableCache:true,abortSignal:this.executeAbortController.signal,loggerTags:De(this.logger)})}async getFailureRecoveryPlan(e,r){return this.generator.getFailureRecoveryPlan(e,{disableCache:true,abortSignal:this.executeAbortController.signal,loggerTags:De(r??this.logger)})}};function yt({text:t,section:e}){if(!e)return [{type:"text",text:t}];let r=`### ${e}`;return t.length===0?[{type:"text",text:r}]:[{type:"text",text:`${r}
|
|
5717
5717
|
${t}`}]}function cL({base64Data:t,mediaType:e,section:r}){return r?[{type:"text",text:`### ${r}`},{type:"media",data:t,mediaType:e}]:[{type:"media",data:t,mediaType:e}]}function Db(t){if(t.length===0)throw new ar("No content parts provided to construct the tool response content.");return {type:"content",value:t}}function Lb(t){return {type:"content",value:[{type:"text",text:t}]}}function fX({projectRoot:t,filePath:e,pathLabel:r="path"}){if(!e||!fr__default.isAbsolute(e))return e;let n=fr__default.relative(t,e);if(n.startsWith("..")||fr__default.isAbsolute(n))throw new Error(`Error: ${r} "${e}" must be inside project root "${t}".`);return n}function hX(t){return t.map(e=>{switch(e.type){case "text":return e;case "media":return {type:"image",data:e.data,mimeType:e.mediaType};default:return (n=>{throw new Error("Unhandled content part")})()}})}var uL="We are scrolling the device in search of the element described below. Return -1 unless there is a strong match clearly visible in the current viewport. Description:";function cw(t){return `${uL} ${t}`}function Dc(t,e){if(t===e)return true;let r=n=>n.startsWith(uL)?n.slice(uL.length).trim():n;return r(t)===r(e)}var rOe=[400,401,403,404,408,409,413,429,498,500,502,503,504],nOe=["overloaded","service unavailable","bad gateway","too many requests","toomanyrequests","internal server error","gateway timeout","timed out","rate_limit","ratelimit","rate limit","wrong-key","unexpected","capacity","timeout","terminated","other side closed","connection closed","upstream_closed","server_error","websocket unavailable","you can retry your request","429","500","502","503","504"];function gX(t){if(t&&typeof t=="object"&&"statusCode"in t){let r=t.statusCode;if(typeof r=="number"&&(rOe.includes(r)||r>500))return true}let e=bX(t).toLowerCase();return nOe.some(r=>e.includes(r))}function bX(t){if(t instanceof Error){let e="cause"in t?t.cause:void 0,r="code"in t&&typeof t.code=="string"?t.code:"";return `${t.name} ${t.message} ${r} ${bX(e)}`}if(typeof t=="string")return t;if(t&&typeof t=="object")try{return JSON.stringify(t)}catch{return ""}return ""}var oOe="language model provider fallback failed (fatal)";function SX(t){return new dL(t)}var dL=class{specificationVersion="v3";settings;retryAfterOutput;models;constructor(e){if(this.settings=e,this.models=[...e.models],this.retryAfterOutput=e.retryAfterOutput??true,this.models.length===0)throw new Error("No models available in settings")}get supportedUrls(){return this.currentModel.supportedUrls}get modelId(){return this.currentModel.modelId}get provider(){return this.currentModel.provider}doGenerate(e){return this.retry(()=>this.currentModel.doGenerate(e))}doStream(e){return this.retry(async()=>{let r=await this.currentModel.doStream(e);return {...r,stream:this.createRetryingStream({stream:r.stream,options:e})}})}get currentModel(){let e=this.models[0];if(!e)throw new Error("No model available at current fallback index");return e}moveCurrentModelToBack(){let e=this.models.shift();e&&this.models.push(e);}shouldRetry(e){return this.settings.shouldRetryThisError?this.settings.shouldRetryThisError(e):gX(e)}async notifyError(e){await this.settings.onError?.(e,this.modelId);}logFatal(e){this.settings.logger.error({err:e,modelId:this.modelId,provider:this.provider},oOe);}async retry(e){let r=this.models.length;for(let n=0;n<r;n++)try{return await e()}catch(o){if(!this.shouldRetry(o))throw this.logFatal(o),o;await this.notifyError(o);let i=n===r-1;if(i&&this.logFatal(o),this.moveCurrentModelToBack(),i)throw o}throw new Error("No models available in settings")}createRetryingStream(e){let{stream:r,options:n}=e,o={hasStreamedAny:false,hasEmittedClientExecutedToolCall:false,remainingFallbackAttempts:this.models.length-1};return new ReadableStream({start:async i=>{let a;try{a=r.getReader(),await this.pipeStreamToController({reader:a,controller:i,retryState:o}),i.close();}catch(s){await this.retryStreamAfterError({error:s,options:n,controller:i,retryState:o});}finally{yX(a);}}})}async pipeStreamToController(e){let{reader:r,controller:n,retryState:o}=e,i=await r.read();for(;!i.done;){let a=i.value;if(o&&a.type==="error"&&this.shouldRetry(a.error))throw a.error;n.enqueue(a),o&&(o.hasStreamedAny||=a.type!=="stream-start",a.type==="tool-call"&&a.providerExecuted!==true&&(o.hasEmittedClientExecutedToolCall=true)),i=await r.read();}}async retryStreamAfterError(e){let{error:r,options:n,controller:o,retryState:i}=e;if(!this.shouldRetry(r)){this.logFatal(r),o.error(r);return}if(await this.notifyError(r),i.hasEmittedClientExecutedToolCall||i.hasStreamedAny&&!this.retryAfterOutput||i.remainingFallbackAttempts<=0){this.logFatal(r),o.error(r);return}this.moveCurrentModelToBack(),i.remainingFallbackAttempts-=1;let a;try{a=(await this.currentModel.doStream(n)).stream.getReader(),await this.pipeStreamToController({reader:a,controller:o,retryState:i}),o.close();}catch(s){await this.retryStreamAfterError({error:s,options:n,controller:o,retryState:i});}finally{yX(a);}}};function yX(t){try{t?.releaseLock();}catch{}}var aOe=new Set(["itemId","reasoningEncryptedContent"]);function TX({model:t,logger:e,logMessage:r}){return wrapLanguageModel({model:t,middleware:{specificationVersion:"v3",transformParams:async({params:o})=>{let{messages:i,wasPruned:a}=sOe(o.prompt);return a&&e.info({messageCount:i.length,fallbackModel:t.modelId},r),{...o,prompt:i}}}})}function sOe(t){let e=false,r=[];for(let n of t){let{message:o,wasPruned:i}=lOe(n);e=e||i,o&&r.push(o);}return {messages:r,wasPruned:e}}function lOe(t){let e=EX(t.providerOptions),r=e.wasPruned;switch(t.role){case "system":return {message:{...t,providerOptions:e.providerOptions},wasPruned:r};case "assistant":{let n=[];for(let i of t.content){if(i.type==="reasoning"){r=true;continue}n.push(i);}let o=mL(n);return r=r||o.wasPruned,o.parts.length===0?{message:void 0,wasPruned:true}:{message:{...t,content:o.parts,providerOptions:e.providerOptions},wasPruned:r}}case "user":{let n=mL(t.content);return r=r||n.wasPruned,{message:{...t,content:n.parts,providerOptions:e.providerOptions},wasPruned:r}}case "tool":{let n=mL(t.content);return r=r||n.wasPruned,{message:{...t,content:n.parts,providerOptions:e.providerOptions},wasPruned:r}}}}function EX(t){if(!t)return {providerOptions:t,wasPruned:false};let e=false,r={};for(let[n,o]of Object.entries(t)){let i={};for(let[a,s]of Object.entries(o)){if(aOe.has(a)){e=true;continue}s!==void 0&&(i[a]=s);}Object.keys(i).length>0&&(r[n]=i);}return {providerOptions:Object.keys(r).length>0?r:void 0,wasPruned:e}}function mL(t){let e=false;return {parts:t.map(r=>{let n=cOe(r);return e=e||n.wasPruned,n.part}),wasPruned:e}}function cOe(t){let e=EX(t.providerOptions);return e.wasPruned?{part:{...t,providerOptions:e.providerOptions},wasPruned:true}:{part:t,wasPruned:false}}var Nb="openai-websocket",vX={cacheControl:{type:"ephemeral"}};function CX(t){if(!t||typeof t!="object"||!("modelId"in t))return false;let e=t.modelId;return typeof e=="string"&&e.startsWith(`${Nb}/`)}function xX(){let t=new Map;return {get(e){return t.get(e)},set(e,r){t.set(e,r);}}}var pOe=xX(),fOe=createRequire(import.meta.url),wX;function hOe(){try{return fOe("@ai-sdk/devtools").devToolsMiddleware}catch{return}}function gOe(){if(!(process.env.AI_SDK_DEVTOOLS!=="true"||process.env.MOMENTIC_LOCAL_DEV!=="1"))try{return wX??=hOe(),wX?.()}catch{return}}function uw(t){let{providerFallback:e,prepareStep:r,onChunk:n,streamTelemetry:o,streamTextImpl:i=streamText,...a}=t,s=PX(e);return i({...a,prepareStep:EOe(r),onChunk:bOe({logger:e.logger,onChunk:n,telemetry:o}),model:s})}async function MX(t){let{providerFallback:e,schema:r,schemaDescription:n,schemaName:o,...i}=t,a={...e,websocketFirst:void 0},s=PX(a),l=streamText({...i,model:s,output:Output.object({schema:r,name:o,description:n})});return await consumeStream({stream:l.fullStream,onError(c){throw c}}),l.output}function bOe(t){let{logger:e,onChunk:r,telemetry:n}=t;if(!n)return r;let o=new Map;return async i=>{yOe({logger:e,buffers:o,telemetry:n,chunk:i.chunk}),await r?.(i);}}function yOe(t){let{logger:e,buffers:r,telemetry:n,chunk:o}=t;if(o.type==="text-delta"&&n.textDeltas){AX({logger:e,buffers:r,telemetry:n,chunk:o});return}if(o.type==="reasoning-delta"&&n.reasoningDeltas){AX({logger:e,buffers:r,telemetry:n,chunk:o});return}if(o.type==="text-end"||o.type==="reasoning-end"){hL({logger:e,buffers:r,telemetry:n,id:o.id,kind:o.type==="text-end"?"text-delta":"reasoning-delta",flushReason:"end"});return}(o.type==="finish"||o.type==="abort"||o.type==="error")&&TOe({logger:e,buffers:r,telemetry:n,flushReason:o.type});}function AX(t){let{logger:e,buffers:r,telemetry:n,chunk:o}=t,i=`${o.type}:${o.id}`,s=r.get(i)??{id:o.id,kind:o.type,text:"",deltaCount:0,timer:void 0};s.timer&&clearTimeout(s.timer),s.text+=o.text,s.deltaCount+=1,s.timer=setTimeout(()=>{hL({logger:e,buffers:r,telemetry:n,id:o.id,kind:o.type,flushReason:"debounce"});},n.debounceMs??2e3),SOe(s.timer),r.set(i,s);}function SOe(t){if(typeof t!="object"||t===null||!("unref"in t))return;let e=t.unref;typeof e=="function"&&e.call(t);}function hL(t){let{logger:e,buffers:r,telemetry:n,id:o,kind:i,flushReason:a}=t,s=`${i}:${o}`,l=r.get(s);if(!l)return;l.timer&&clearTimeout(l.timer),r.delete(s);let c=n.maxLoggedChars,u=typeof c=="number"&&l.text.length>c?l.text.slice(0,c):l.text;e.info({...n.attributes,chunkId:l.id,chunkType:l.kind,deltaCount:l.deltaCount,flushReason:a,text:u,textLength:l.text.length,truncated:u.length!==l.text.length},`streamText ${i}`);}function TOe(t){let{logger:e,buffers:r,telemetry:n,flushReason:o}=t;for(let i of Array.from(r.values()))hL({logger:e,buffers:r,telemetry:n,id:i.id,kind:i.kind,flushReason:o});}function EOe(t){if(t)return e=>{if(!CX(e.model))return t(e)}}function PX(t){let e=t.scopeKey,r=e?t.state??pOe:xX(),n=vOe({...t,scopeKey:e,state:r});if(n.length===0)throw new Error("No streamText fallback providers configured");let o=SX({models:n.map(a=>a.model),logger:t.logger,retryAfterOutput:true,onError:async(a,s)=>{let l=n.find(c=>c.model.modelId===s)?.id??s;t.logger.warn({err:a,modelId:s,providerId:l},"streamText provider failed, trying next fallback"),await t.onError?.({error:kS(a),failedProviderId:l,failedModelId:s});}}),i=gOe();return i?wrapLanguageModel({model:o,middleware:i}):o}function vOe(t){let e=t.scopeKey?t.state.get(t.scopeKey):void 0;if(t.websocketFirst?.enabled&&(!e||e===t.websocketFirst.provider.id))return [pL({candidate:t.websocketFirst.provider,config:t,pruneProviderState:false}),...t.providers.map(i=>pL({candidate:i,config:t,pruneProviderState:true}))];let r=e?t.providers.findIndex(i=>i.id===e):-1,n=r>=0?r:0;return [...t.providers.slice(n),...t.providers.slice(0,n)].map((i,a)=>pL({candidate:i,config:t,pruneProviderState:a>0}))}function pL(t){let{candidate:e,config:r,pruneProviderState:n}=t,o=AOe({model:e.model,providerId:e.id,scopeKey:r.scopeKey,state:r.state});return n&&(o=TX({model:o,logger:r.logger,logMessage:"Stripped provider-local state from streamText fallback step"})),e.id.includes("anthropic")&&(o=COe({model:o})),{...e,model:o}}function COe(t){return wrapLanguageModel({model:t.model,middleware:{specificationVersion:"v3",transformParams:async({params:e})=>wOe(e)}})}function wOe(t){return t.tools?.some(e=>"strict"in e)?{...t,tools:t.tools.map(e=>{if(!("strict"in e))return e;let{strict:r,...n}=e;return n})}:t}function AOe(t){let{model:e,providerId:r,scopeKey:n,state:o}=t;return wrapLanguageModel({model:e,middleware:{specificationVersion:"v3",overrideModelId:()=>`${r}/${e.modelId}`,wrapGenerate:async({doGenerate:i})=>{let a=await i();return n&&o.set(n,r),a},wrapStream:async({doStream:i})=>{let a=await i();return {...a,stream:ROe({stream:a.stream,providerId:r,scopeKey:n,state:o})}}}})}function ROe(t){let{stream:e,providerId:r,scopeKey:n,state:o}=t,i=false,a,s=false;return new ReadableStream({async start(l){a=e.getReader();try{for(;;){let{done:c,value:u}=await a.read();if(c)break;!i&&u.type!=="stream-start"&&u.type!=="error"&&(i=!0,n&&o.set(n,r)),l.enqueue(u);}s||l.close();}catch(c){s||l.error(c);}finally{a.releaseLock(),a=void 0;}},cancel(l){return s=true,a?.cancel(l)}})}async function xOe(t){let{agentConfig:e,streamResponseMessages:r,userMessage:n,...o}=t,i={role:"user",content:n};return MX({...o,providerFallback:e.providerFallback,system:e.system,providerOptions:e.providerOptions,messages:[...e.messages??[],...r,i]})}async function kb({validate:t,maxAttempts:e,logger:r,...n}){let o;for(let i=1;i<=e;i++){n.abortSignal?.throwIfAborted();try{let a=await xOe(n);return await t(a),a}catch(a){if(n.abortSignal?.aborted||(o=a,i===e))throw a;r.warn({err:a,attempt:i,nextAttempt:i+1},"Failed to validate generated object to repair missing submission tool call, retrying");}}throw o}var IX=500;function gL(t){return !t||typeof t!="object"||!("type"in t)||t.type!=="content"||!("value"in t)||!Array.isArray(t.value)?t:{type:t.type,value:t.value.map(e=>{if(!e||typeof e!="object"||!("type"in e))return e;if(e.type==="text"&&"text"in e){let r=typeof e.text=="string"?e.text:"";return {type:e.type,textLength:r.length,preview:r.slice(0,IX),truncated:r.length>IX}}if(e.type==="media"&&"data"in e){let r=typeof e.data=="string"?e.data:"";return {type:e.type,dataLength:r.length,mediaType:"mediaType"in e?e.mediaType:void 0}}return e})}}var _X=z.looseObject({type:z.literal("tool-call"),toolCallId:z.string(),toolName:z.string(),input:z.unknown().optional()}),dw=z.object({type:z.literal("content"),value:z.array(z.discriminatedUnion("type",[z.object({type:z.literal("text"),text:z.string()}),z.object({type:z.literal("media"),data:z.string(),mediaType:z.string()})]))}),MOe=z.discriminatedUnion("type",[z.object({type:z.literal("text"),value:z.string()}),z.object({type:z.literal("json"),value:z.unknown().optional()}),z.object({type:z.literal("error-text"),value:z.string()}),z.object({type:z.literal("error-json"),value:z.unknown().optional()}),dw]),OX=z.looseObject({type:z.literal("tool-result"),toolCallId:z.string(),toolName:z.string(),output:MOe}),DX=z.looseObject({text:z.string()});var LX=2,POe=1600,IOe=.3,pd="[trimmed: omitted due to context budget]",FX="[screenshot truncated]",BX="[browser state truncated]",UX={_momenticTrimmed:true,summary:pd},zX={type:"text",value:pd},_Oe=z.object({type:z.literal("text"),value:z.literal(pd)}),OOe=["reasoning","tool-result","image","tool-call","text"];function $X(t){let{messages:e,phase1:r,phase2:n,logger:o}=t,i=DOe(e,r.toolResultPruningRules??[],{trimReasoning:r.trimReasoning??false});if(typeof r.numScreenshots=="number"&&(i=LOe(i,r.numScreenshots)),r.browserStateMarkers&&r.browserStateMarkers.length>0&&(typeof r.browserStateTailMessageWindow=="number"&&(i=zOe(i,r.browserStateTailMessageWindow,r.browserStateMarkers)),typeof r.numBrowserStates=="number"&&(i=UOe(i,r.numBrowserStates,r.browserStateMarkers))),!n)return i;let a=Ut(i);return a<=n.tokensThreshold||(o.info({totalTokens:a,threshold:n.tokensThreshold,target:n.targetTokens,messageCount:i.length,breakdown:kX(i)},"Phase 2 triggered \u2014 token breakdown before compaction"),i=rDe(i,n.targetTokens,o),o.info({totalTokens:Ut(i),messageCount:i.length,breakdown:kX(i)},"Phase 2 complete \u2014 token breakdown after compaction")),i}function DOe(t,e,r){let n=t;r.trimReasoning&&(n=n.map((o,i)=>o.role!=="assistant"?o:ZOe(o,i===t.length-1)));for(let o of e)n=HOe(n,o);return n}function LOe(t,e){let r={count:e},n=[...t];for(let o=n.length-1;o>=0;o--)n[o]=NOe(n[o],r);return n}function NOe(t,e){if(t.role==="user"){if(typeof t.content=="string")return t;let r=kOe(t.content,e);return {...t,content:r}}if(t.role==="tool"){let r=FOe(t.content,e);return {...t,content:r}}return t}function kOe(t,e){let r=[...t];for(let n=r.length-1;n>=0;n--)if(r[n].type==="image"){if(e.count>0){e.count--;continue}r[n]={type:"text",text:FX};}return r}function FOe(t,e){let r=[...t];for(let n=r.length-1;n>=0;n--){let o=r[n];if(o.type!=="tool-result")continue;let i=dw.safeParse(o.output);if(!i.success)continue;let a=BOe(i.data.value,e);a!==i.data.value&&(r[n]={...o,output:{...i.data,value:a}});}return r}function BOe(t,e){let r=[...t],n=false;for(let o=r.length-1;o>=0;o--)if(r[o].type==="media"){if(e.count>0){e.count--;continue}r[o]={type:"text",text:FX},n=true;}return n?r:t}function UOe(t,e,r){let n={count:e},o=[...t];for(let i=o.length-1;i>=0;i--)o[i]=VX(o[i],n,r);return o}function zOe(t,e,r){let n=Math.max(0,t.length-e);return t.map((o,i)=>i>=n?o:VX(o,{count:0},r))}function VX(t,e,r){if(t.role==="user"){if(typeof t.content=="string")return t;let n=$Oe(t.content,e,r);return {...t,content:n}}if(t.role==="tool"){let n=VOe(t.content,e,r);return {...t,content:n}}return t}function $Oe(t,e,r){let n=[...t];for(let o=n.length-1;o>=0;o--){let i=n[o];if(!(i.type!=="text"||!jX(i.text,r))){if(e.count>0){e.count--;continue}n[o]={type:"text",text:BX};}}return n}function VOe(t,e,r){let n=[...t];for(let o=n.length-1;o>=0;o--){let i=n[o];if(i.type!=="tool-result")continue;let a=dw.safeParse(i.output);if(!a.success)continue;let s=jOe(a.data.value,e,r);s!==a.data.value&&(n[o]={...i,output:{...a.data,value:s}});}return n}function jOe(t,e,r){let n=[...t],o=false;for(let i=n.length-1;i>=0;i--){let a=n[i];if(!(a.type!=="text"||!jX(a.text,r))){if(e.count>0){e.count--;continue}n[i]={type:"text",text:BX},o=true;}}return o?n:t}function jX(t,e){for(let r of e)if(t.includes(r))return true;return false}function HOe(t,e){let r=new Set;for(let n of t.slice(-e.keepLastMessages))if(typeof n.content!="string")for(let o of n.content)WOe(o)&&e.tools.includes(o.toolName)&&r.add(o.toolCallId);return t.map((n,o)=>o>=t.length-e.keepLastMessages?n:tDe(n,e,r))}function mw(t){return _X.safeParse(t).success}function SL(t){return OX.safeParse(t).success}function WOe(t){return mw(t)||SL(t)}function GOe(t){return DX.safeParse(t).success}function HX(t){return !t||typeof t!="object"||Array.isArray(t)?false:t._momenticTrimmed===true}function WX(t){return _Oe.safeParse(t).success}function yL(t){return t.text===pd?{part:t,trimmedTokens:0}:{part:{...t,text:pd},trimmedTokens:Ut(t.text)}}function qOe(t){return t.input===void 0||HX(t.input)?{part:t,trimmedTokens:0}:{part:{...t,input:UX},trimmedTokens:Ut(t.input)}}function GX(t){return t.output===void 0||WX(t.output)?{part:t,trimmedTokens:0}:{part:{...t,output:zX},trimmedTokens:Ut(t.output)}}function KOe(t,e,r){let n=0,o=[];for(let i of t){if(n>=e){o.push(i);continue}switch(i.role){case "assistant":{let a=YOe(i,e-n,r);n+=a.trimmedTokens,o.push(a.message);continue}case "tool":{let a=JOe(i,e-n,r);n+=a.trimmedTokens,o.push(a.message);continue}case "user":{let a=XOe(i,e-n,r);n+=a.trimmedTokens,o.push(a.message);continue}default:o.push(i);}}return {messages:o,trimmedTokens:n}}function YOe(t,e,r){if(typeof t.content=="string")return {message:t,trimmedTokens:0};let n=[],o=0;for(let i of t.content){if(o>=e){n.push(i);continue}if(r==="image"){n.push(i);continue}if(r==="reasoning"){if(i.type!=="reasoning"){n.push(i);continue}let s=yL(i);o+=s.trimmedTokens,n.push(s.part);continue}if(r==="text"){if(i.type!=="text"){n.push(i);continue}let s=yL(i);o+=s.trimmedTokens,n.push(s.part);continue}if(r==="tool-call"){if(!mw(i)){n.push(i);continue}let s=qOe(i);o+=s.trimmedTokens,n.push(s.part);continue}if(!SL(i)){n.push(i);continue}let a=GX(i);o+=a.trimmedTokens,n.push(a.part);}return {message:{...t,content:n},trimmedTokens:o}}function XOe(t,e,r){if(typeof t.content=="string")return {message:t,trimmedTokens:0};let n=[],o=0;for(let i of t.content){if(o>=e){n.push(i);continue}if(r==="image"){if(i.type!=="image"){n.push(i);continue}o+=POe;continue}if(r!=="text"||!GOe(i)){n.push(i);continue}let a=yL(i);o+=a.trimmedTokens,n.push(a.part);}return {message:{...t,content:n},trimmedTokens:o}}function JOe(t,e,r){if(r!=="tool-result")return {message:t,trimmedTokens:0};let n=[],o=0;for(let i of t.content){if(i.type==="tool-approval-response"){n.push(i);continue}if(o>=e){n.push(i);continue}let a=GX(i);o+=a.trimmedTokens,n.push(a.part);}return {message:{...t,content:n},trimmedTokens:o}}function ZOe(t,e){return e||typeof t.content=="string"?t:{...t,content:t.content.map(r=>r.type!=="reasoning"||r.text===pd?r:{...r,text:pd})}}function QOe(t,e,r){return !e.tools.includes(t.toolName)||r.has(t.toolCallId)||t.input===void 0||HX(t.input)?t:{...t,input:UX}}function qX(t,e,r){return !e.tools.includes(t.toolName)||r.has(t.toolCallId)||t.output===void 0||WX(t.output)?t:{...t,output:zX}}function eDe(t,e,r){return mw(t)?QOe(t,e,r):SL(t)?qX(t,e,r):t}function tDe(t,e,r){return t.role==="assistant"&&typeof t.content!="string"?{...t,content:t.content.map(n=>eDe(n,e,r))}:t.role==="tool"?{...t,content:t.content.map(n=>n.type==="tool-approval-response"?n:qX(n,e,r))}:t}function Fb(t,e,r){let n=[...t];for(let o of OOe){let i=Ut(n);if(i<=e)break;let a=i-e,s=KOe(n,a,o);n=s.messages,s.trimmedTokens>0&&r.debug({contentType:o,trimmedTokens:s.trimmedTokens,newTokenCount:Ut(n)},"Trimmed content");}return n}function KX(t){return t.role!=="assistant"||typeof t.content=="string"?false:t.content.some(e=>mw(e))}function NX(t){if(t.length===0)return;let e=t[0];if(KX(e)){t.shift(),t.length>0&&t[0].role==="tool"&&t.shift();return}t.shift();}function kX(t){let e={};for(let r of t)if(r.role==="system")e.system=(e.system??0)+Ut(r);else if(r.role==="user")e.user=(e.user??0)+Ut(r);else if(r.role==="assistant")if(typeof r.content=="string")e.assistant_text=(e.assistant_text??0)+Ut(r);else for(let n of r.content)if(n.type==="tool-call"){let o=`tool_call:${n.toolName}`;e[o]=(e[o]??0)+Ut(n);}else e.assistant_text=(e.assistant_text??0)+Ut(n);else if(r.role==="tool"){for(let n of r.content)if(n.type==="tool-result"){let o=`tool_result:${n.toolName}`;e[o]=(e[o]??0)+Ut(n);}}return e}function rDe(t,e,r){let n=Ut(t);if(n<=e||t.length<=1)return t;let o=t[0],i=[],a=[];if(t.length>LX+1){let u=t.length-LX;u>1&&t[u]?.role==="tool"&&KX(t[u-1])&&u++,i=t.slice(1,u),a=t.slice(u);}else a=t.slice(1);if(i.length>0){i=Fb(i,e,r);let u=[o,...i,...a];if(n=Ut(u),n<=e)return u}let s=Ut(i),l=s/e;if(l<IOe){if(a.length>1){let u=a[a.length-1],d=[...i,...a.slice(0,-1)],m=Fb(d,e,r),p=[o,...m,u];if(n=Ut(p),n<=e)return p;let f=Fb([...m,u],e,r),h=[o,...f];if(n=Ut(h),n<=e)return h}else if(a.length===1){let u=[...i,...a],d=Fb(u,e,r),m=[o,...d];if(n=Ut(m),n<=e)return m}}else for(r.debug({headBudgetRatio:l,middleMsgTokens:s,targetTokens:e},"Middle exceeds 30% budget, removing messages");i.length>0;){NX(i);let u=[o,...i,...a];if(n=Ut(u),n<=e)return u}a=Fb(a,e,r);let c=[o,...i,...a];if(n=Ut(c),n<=e)return c;for(;a.length>0;)if(NX(a),c=[o,...i,...a],n=Ut(c),n<=e)return c;return n>e&&r.warn({targetTokens:e,finalTokenCount:n,remainingMessages:c.length},"Unable to meet token target after all pruning phases"),c}var TL=5e3,YX=2e4;function ZX(t){let{tool:e,name:r,spanName:n,attributes:o}=t,i=e.execute;return i?{...e,execute:async(a,s)=>Ne({name:n,attributes:{"momentic.tool_name":r,...o},fn:async l=>{l?.setAttribute("momentic.tool_input",XX(a));let c=await i(a,s);return l?.setAttribute("momentic.tool_output",XX(gL(c))),c}})}:e}function XX(t){let e=sc({json:t,maxJsonStringSize:TL});return typeof e=="string"?e:kl(e)??""}function pw(t){let{tool:e,name:r,logger:n,logPrefix:o,agentName:i,createToolSpan:a}=t,s=t.getResultForLogging??gL,l=e.execute;return l?{...e,strict:e.strict??false,execute:async(c,u)=>EL({logger:n,toolName:r,logPrefix:o,agentName:i,createToolSpan:a,input:c,execute:async()=>l(c,u),getResultForLogging:s})}:{...e,strict:e.strict??false}}async function EL(t){let{logger:e,toolName:r,logPrefix:n="",agentName:o,createToolSpan:i,input:a}=t,s=t.getResultForLogging??(d=>d),l=Date.now(),c=i?.({name:r,input:a,metadata:o!=null?{agentName:o}:void 0}),u=JX({logger:e,toolName:r,agentName:o,value:a,label:"input"});e.info({...o!=null&&{agentName:o},...u!==void 0&&{inputTokenCount:u},params:sc({json:a,maxJsonStringSize:TL}),toolName:r},`${n}Tool invoked: ${r}`);try{let d=await t.execute(),m=JX({logger:e,toolName:r,agentName:o,value:d,label:"output"}),p=s(d);return m!==void 0&&m>YX&&e.warn({...o!=null&&{agentName:o},largeToolOutputWarningThresholdTokens:YX,outputTokenCount:m,toolName:r},`${n}Tool output is large: ${r}`),e.info({...o!=null&&{agentName:o},duration:Date.now()-l,...m!==void 0&&{outputTokenCount:m},response:sc({json:p,maxJsonStringSize:TL}),toolName:r},`${n}Tool completed: ${r}`),c?.end({output:d}),d}catch(d){throw e.error({...o!=null&&{agentName:o},duration:Date.now()-l,err:d,toolName:r},`${n}Tool failed: ${r}`),c?.end({level:"ERROR",statusMessage:W(d)}),d}}function JX(t){let{logger:e,toolName:r,agentName:n,value:o,label:i}=t;try{return Ut(o)}catch(a){e.warn({...n!=null&&{agentName:n},err:a,toolName:r},`Failed to calculate tool ${i} token count`);return}}var QX=".momentic-mcp",lDe=30*v$;function CL(t){return t?fr__default.join(t,QX):fr__default.resolve(QX)}function Ms(t){let e=CL(t);mkdirSync(e,{recursive:true});}function cDe(){return `${Date.now()}`}function Ps({rootDir:t,entity:e,ext:r}){return fr__default.join(CL(t),`${e}-${cDe()}.${r}`)}function uDe(t){let e=fr__default.relative(process.cwd(),t);return e.startsWith(".")?e:`./${e}`}function Aa({filePath:t,title:e}){return `- [${e}](${uDe(t)})`}var Ub="All relative paths/links returned by a tool are relative to the server's `cwd`. Use the advertised `cwd` to resolve relative paths, use `projectRootAbsolutePath` to find the project-local `.momentic-mcp` artifacts, and use `projectConfigAbsolutePath` for the active `momentic.config.yaml`.";function e7({projectRootAbsolutePath:t,projectConfigAbsolutePath:e,cwd:r}){return [Ub,"",`- **projectRootAbsolutePath**: \`${t}\``,`- **projectConfigAbsolutePath**: \`${e}\``,`- **cwd**: \`${r}\``].join(`
|
|
5718
5718
|
`)}async function t7({projectRootAbsolutePath:t,projectConfigAbsolutePath:e,cwd:r,stepSchema:n,stepSchemaTitle:o,supportsFileOutput:i}){let a="Step Authoring Guide",s="Read this Step Authoring Guide to understand momentic step input shapes. It explains the CLI-style step arguments accepted by the MCP tools and includes the project context.",l=[s,"","## Project context","",e7({projectRootAbsolutePath:t,projectConfigAbsolutePath:e,cwd:r}),"",`## ${o}`,"",n].join(`
|
|
@@ -5860,19 +5860,19 @@ ${s}`}]}async function o7({rootDir:t,cutoffTime:e}){let r=await readdir$1(t,{wit
|
|
|
5860
5860
|
`),section:"Diffs For Recovery"})),u}return u.push(...yt({text:["",d].join(`
|
|
5861
5861
|
`),section:"Diffs For Recovery"})),u}function nte({moduleName:t,existingModuleNames:e,parameterNames:r,defaultParameters:n,parameterEnums:o,moduleInputs:i,testPath:a,startIndex:s,endIndex:l,availableSteps:c,containsNestedModuleStep:u}){if(e.includes(t))throw new Error(`Error: module with the name "${t}" already exists. Please use a different name.`);let d=r??[],m=[...Object.keys(n??{}),...Object.keys(o??{})];for(let y of m)if(!d.includes(y)){let S=d.length?d.join(", "):"none";throw new Error(`Error: Parameter metadata "${y}" is not defined in parameters. Available parameters: ${S}`)}let p=new Set(d);for(let y of Object.keys(i??{}))if(!p.has(y)){let S=p.size?Array.from(p).join(", "):"none";throw new Error(`Error: Module input "${y}" is not defined in parameters. Available parameters: ${S}`)}let f=s??0,h=l??f+1;if(l!==void 0&&s===void 0)throw new Error("Error: startIndex is required when endIndex is provided for extraction.");if(s===void 0)return {stepsToExtract:[],startIndex:f,endIndex:h};if(!a)throw new Error("Error: testPath is required when extracting steps from the test.");if(!c)throw new Error("Error: resolved steps are required to validate module extraction.");if(f<0||f>=c.length)throw new Error(`Error: startIndex ${f} is out of bounds. Test has ${c.length} steps.`);if(h<=f||h>c.length)throw new Error(`Error: endIndex ${h} is out of bounds. Must be between ${f+1} and ${c.length}.`);let g=c.slice(f,h);for(let y of g)if(u(y))throw new Error("Error: Modules cannot be nested. Please select steps that do not include module references.");return {stepsToExtract:g,startIndex:f,endIndex:h}}var wze=new Set(["android.webkit.webview","com.facebook.react.views.webview.reactwebview","com.tencent.smtt.sdk.webview","com.tencent.smtt.sdk.x5webview","org.xwalk.core.xwalkview","com.uc.webview.export.webview"]);function Aze(t){let e=t.toLowerCase();return e.endsWith("webview")||wze.has(e)}function Uy(t){return !!(Aze(t.tagName)||t.getAttribute("package")==="com.android.chrome"&&t.getAttribute("content-desc")==="Web View"&&ote(t.tagName.toLowerCase()).startsWith("frame"))}function ote(t){let e=["android.widget.","android.view.","android.webkit.","android.app.","android.support.","androidx.","com.android.inputmethod."];for(let r of e)if(t.startsWith(r))return t.substring(r.length);return t}var Rze=new Set(["index","package","a11y-important","screen-reader-focusabl"]),xze=new Set(["selected","checked","checkable","clickable","enabled","focusable","focused","long-clickable","password","scrollable","selected","showing-hint","context-clickable","multiline","text-entry-key","heading","dismissable","screen-reader-focusable","content-invalid","a11y-focused"]),Mze=new Set(["text","hint"]),Pze=new Set(["live-region","drawing-order"]),Ize=new Set(["displayed","enabled"]);function _ze(t,e){let r={};for(let[n,o]of Object.entries(e))Rze.has(n)||n==="class"&&t===o||n==="focusable"&&o==="true"&&e.clickable==="true"||xze.has(n)&&o==="false"||Mze.has(n)&&o===""||Ize.has(n)&&o==="true"||Pze.has(n)&&o==="0"||n!=="id"&&(r[n]=o);return r}function ite(t,e,r){let{prunedDocument:n,idToElement:o,prunedIdToElement:i,idCounter:a,opts:s}=t,l=a.value++;r.setAttribute("id",String(l));let c={};for(let m of e.attributes){let p=m.name,f=m.value;f!=null&&(c[p]=String(f));}let u=_ze(e.tagName,c);for(let[m,p]of Object.entries(u))r.setAttribute(m,p);if(o.set(l,e),i.set(l,r),Uy(e)){let m=s?.injectedWebviewContent??"";if(s?.removeWebviewContent){for(;r.firstChild;)r.removeChild(r.firstChild);return}else if(!s?.disableMomenticAccessibilityTree&&m.trim().length>0){for(;r.firstChild;)r.removeChild(r.firstChild);m.trim().length>0&&r.appendChild(n.createCDATASection(`
|
|
5862
5862
|
${m}
|
|
5863
|
-
`));return}}let d=Array.from(e.childNodes??[]);for(let m of d){let p=m.nodeType;if(p===3){let f=m.nodeValue;f&&f.trim().length>0&&r.appendChild(n.createTextNode(f));continue}if(p===1){let f=m;if(!Lze(f,s?.viewportBounds))continue;let h=n.createElement(ote(f.tagName));ite(t,f,h),r.appendChild(h);}}}function Oze(t,e,r,n){let o=t.parseFromString("<hierarchy/>","text/xml"),i=new Map,a={prunedDocument:o,idToElement:r,prunedIdToElement:i,idCounter:{value:0},opts:n},s=o.documentElement;ite(a,e,s);let l=new XMLSerializer().serializeToString(o);return {prunedDocument:o,prunedIdToElement:i,xml:l}}async function ate(t,e,r){let n=new DOMParser,o=n.parseFromString(t,"text/xml"),i=new Map,a=o.documentElement;if(!a)throw new M("InternalWebAgentError","No root element found in XML");if(a.tagName!=="hierarchy")throw new M("InternalWebAgentError","No hierarchy element found in XML");let{prunedDocument:s,prunedIdToElement:l,xml:c}=Oze(n,a,i,r),u=c;try{u=await Eze.format(c,{parser:"xml",plugins:[Tze],printWidth:120,tabWidth:1,singleAttributePerLine:!1});}catch(d){e.warn({err:d},"Failed to format XML");}return {xml:u,originalXml:t,document:o,idToElement:i,prunedDocument:s,prunedIdToElement:l}}function Dze(t){let e=[],r=t;for(;r;){let n=r.tagName,o=r.parentElement,i=1;if(o){let a=Array.from(o.children).filter(s=>s.tagName===n);for(let s=0;s<a.length;s++)if(a[s]===r){i=s+1;break}}e.unshift(`${n}[${i}]`),r=o;}return `/${e.join("/")}`}function WA(t,e){let r=t.idToElement.get(e);if(r)return Dze(r)}function tk(t,e){let r=t.idToElement.get(e);if(!r)return;let n=r.cloneNode(true);for(let o of Array.from(n.children)){let i=o;for(let a of Array.from(i.children))i.removeChild(a);}return n.outerHTML}function Tl(t){if(!t.hasAttribute("bounds"))return;let e=t.getAttribute("bounds");if(!e)return;let r=e.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/);if(r){let n=parseInt(r[1],10),o=parseInt(r[2],10),i=parseInt(r[3],10),a=parseInt(r[4],10);if(Number.isFinite(n)&&Number.isFinite(o)&&Number.isFinite(i)&&Number.isFinite(a))return [n,o,i,a]}}function Lze(t,e){if(!e)return true;let r=Tl(t);if(!r||r.length<4)return true;let n=r[0],o=r[1],i=r[2],a=r[3];return !(i<=e.left||n>=e.right||a<=e.top||o>=e.bottom)}function ste(t,e){if(t&&!(!e||e.length===0))return Object.fromEntries(e.map(r=>[r,t.getAttribute(r)]).filter(([,r])=>r!==null))}function cte({requirements:t,element:e}){let r;if((t?.positionSpecificity||t?.shapeSpecificity)&&(r=Tl(e),!r))throw new M("ActionFailureError","Element to cache has no bounds or unexpected bounds format");return {requiredText:t?.textRequired&&kp(e)||void 0,requiredAttributes:ste(e,t?.attributesRequired),requiredBounds:t?.boundsRequired,position:t?.positionSpecificity?{x1:r[0],y1:r[1],x2:r[2],y2:r[3],tolerance:t?.positionSpecificity}:void 0,shape:t?.shapeSpecificity?{width:r[2]-r[0],height:r[3]-r[1],tolerance:t?.shapeSpecificity}:void 0}}function dte({aiResponse:t,description:e,emulatorState:r,memory:n,useMemory:o}){let i=r.graph.idToElement.get(t.id);if(!i)throw new M("InternalWebAgentError",`Could not find node with id: ${t.id}`);let a=Tl(i);if(!a)throw new M("InternalWebAgentError",`Node ${t.id} has no bounding box: ${i.outerHTML}`);let s=WA(r.graph,t.id)??"",l=tk(r.graph,t.id)??"",c=cte({requirements:t.requirements,element:i}),u=[];t.additionalElements&&(u=t.additionalElements.map(({id:m,requirements:p})=>{let f=r.graph.idToElement.get(m);if(!f)return;let h=WA(r.graph,m);return h?{xPath:h,requirements:cte({requirements:p,element:f})}:void 0}).filter(m=>!!m));let d;if(Uy(i)&&t.inWebview!==false?d={type:"WEBVIEW",resolvedDescription:e,xPath:s}:d={type:"NATIVE",bounds:a,resolvedDescription:e,xPath:s,elementOnlySerializedXml:l,requirements:c,requiredRelatedElements:u},o)if(t.updatedMemory){let m={type:"GCS_TRACES",traces:t.updatedMemory};d.memory=m;}else n&&(d.memory=n);return {target:d,resolvedNode:i}}function mte(t){return t?.type==="WEBVIEW"?t.browserCache?.memory:void 0}function Nze(t,e){let r=e.x2-e.x1,n=(e.x1+e.x2)/2,o=(t[0]+t[2])/2;if(!ws(e.tolerance,n,o,Math.min(1,r)))return false;let i=e.y2-e.y1,a=(e.y1+e.y2)/2,s=(t[1]+t[3])/2;return ws(e.tolerance,a,s,Math.min(1,i))}function kze(t,e){return ws(e.tolerance,e.width,t[2]-t[0],Math.min(1,e.width))?ws(e.tolerance,e.height,t[3]-t[1],Math.min(1,e.height)):false}var ute=(t,e,r)=>{if(!e)return;let{requiredAttributes:n,requiredText:o,requiredBounds:i,position:a,shape:s}=e;if(o!==void 0&&o.length>0){let l=kp(t);if(l!==o)throw new Pe(`Resolved element text mismatch: expected ${o}, got ${l}`)}if(n)for(let[l,c]of Object.entries(n)){let u=t.getAttribute(l)??void 0;if(u!==c)throw new Pe(`Attribute ${l} mismatch: expected ${c}, got ${u}`)}if(i&&r&&!r.targetBounds.every((c,u)=>c===r.newElementBounds[u]))throw new Pe(`Bounds changed from [${r.targetBounds.join(",")} ] to [${r.newElementBounds.join(",")} ]`);if(a&&r&&!Nze(r.newElementBounds,a))throw new Pe(`Position mismatch: expected ${JSON.stringify(a)}, got ${JSON.stringify(r.newElementBounds)}`);if(s&&r&&!kze(r.newElementBounds,s))throw new Pe(`Shape mismatch: expected ${JSON.stringify(s)}, got ${JSON.stringify(r.newElementBounds)}`)};async function yf(t){let{target:e,domState:r}=t,{graph:n}=r,{document:o}=n,i=ae();if(e.type==="WEBVIEW")return Fze(e,t);if(!e.xPath)throw new M("ActionFailureError","Native element cache has no XPath");let a=lte.evaluateXPathToFirstNode(e.xPath,o,null,null);if(!a)throw new Pe(`Could not resolve cached target via XPath: ${e.xPath}`);if(e.requiredRelatedElements){let m=e.requiredRelatedElements;i.startSection("Validate related elements are similar enough to past runs",()=>{for(let p of m){let f=lte.evaluateXPathToFirstNode(p.xPath,o);if(!f)throw new Pe(`Required related element not found for XPath: ${p.xPath}`);ute(f,p.requirements);}});}let s=Tl(a);if(!s)throw new Pe("Resolved native element has no bounding box");if(!e.bounds)throw new Pe("Native element cache has no bounds");ute(a,e.requirements,{targetBounds:e.bounds,newElementBounds:s});let l;for(let[m,p]of n.idToElement.entries())if(p===a){l=m;break}let c=e.elementOnlySerializedXml,u=e.xPath;return l!==void 0&&(c=tk(n,l)??c,u=WA(n,l)??u),{resolvedTarget:{...e,resolvedNode:a,bounds:s,elementOnlySerializedXml:c,xPath:u}}}async function Fze(t,e){let{stateManager:r,logger:n,signal:o}=e,i=ae(),a=await r.getActiveWebview();if(!a||!a.browserController)throw n.error({webview:a?{...a,browserController:!!a.browserController}:void 0},"resolveTargetCacheInWebView: No browser controller attached"),new Pe("No browser controller is attached to the requested webview");let s=a.browserController;if(!t.browserCache)throw n.error({target:t},"resolveTargetCacheInWebView: No browser target available on cache"),new Pe("No browser target available on cache");let l=t.browserCache,{finalTarget:c}=await i.startAsyncSection("Resolve target in webview",()=>s.resolveCachedTargetForAction({cache:l,options:{resolveTargetOptions:{logger:n,signal:o,skipWaitForPageLoad:true,skipSavingVisualAttributes:true}},logger:n}));return {resolvedTarget:{...t,controller:a.browserController,browserTarget:c}}}function Pd(t){let{command:e,cacheKey:r="cache",targetName:n="target",updatedCache:o}=t;Cm(e)&&(e[r]={...e[r],[n]:cm.parse(o)},t.updatedWithAI&&(e[r].updatedAt=new Date,e[r].updatedAtLoggerTags=De(t.logger)));}function Yc(t){if(t.type==="WEBVIEW")return {type:"WEBVIEW",resolvedDescription:t.resolvedDescription,xPath:t.xPath,browserCache:t.browserCache,memory:t.memory};let{resolvedNode:e,...r}=t;return {...r}}var Yo=.15,Uze=500,Cr=class{driver;generator;stateManager;logger;fixtures;aborter;orgId;aiSettings;options;constructor(e){this.stateManager=e.stateManager,this.generator=e.generator,this.driver=e.driver,this.logger=e.logger,this.fixtures=e.fixtures,this.aborter=e.aborter,this.orgId=e.orgId,this.aiSettings=e.aiSettings,this.options=e.options;}shouldUseMemoryForCommand(e){return this.aiSettings?.useMemory&&!e?.disableCache}async findElement({description:e,tracer:r,skipFetchingFullWebviewContent:n=false,removeWebviewContent:o=false,useMemory:i=false,memory:a,webviewMemory:s,metadata:l,cacheBustReason:c,knownState:u}){let d=this.logger.child({...l}),m=u??await r.startAsyncSection("Get emulator state",async()=>{let S=await this.stateManager.getCurrentScreenshotPngString();return {emulatorState:await this.stateManager.getDomState({skipFetchingFullWebviewContent:n,removeWebviewContent:o}),screenshot:S}}),p;try{p=await r.startAsyncSpan("AI_LOCATOR_CALL",async S=>{c&&(S.attributes.cacheBustReason=c);let E=await this.generator.getAndroidElementLocation({description:e,screenXml:m.emulatorState.graph.xml,screenshot:m.screenshot,source:l?.source==="SCROLL_TO"?"SCROLL_TO":void 0,memory:i?a:void 0},{logger:d,loggerTags:De(d),abortSignal:this.aborter.controller?.signal,useMemory:i,agentConfigVersion:this.aiSettings.agentConfig?.["android-locator"]});return S.result=E,E});}catch(S){throw this.throwIfAborted(),d.error({err:S},"Failed to locate element"),new M("InternalWebAgentError",`Failed to locate element: ${S instanceof Error?S.message:S}`,{errOptions:{cause:S}})}if(p.id===-1){let S=p.updatedMemory?{type:"GCS_TRACES",traces:p.updatedMemory}:void 0;return {success:false,thoughts:p.thoughts??"No matching element found",updatedLocatorMemory:S}}let{target:f,resolvedNode:h}=dte({aiResponse:p,description:e,emulatorState:m.emulatorState,memory:a,useMemory:i});if(f.type==="NATIVE")return r.addSpan({type:"TARGET_RESOLUTION",startTime:Date.now(),endTime:Date.now(),result:{serializedElement:f.elementOnlySerializedXml??"Unknown element"},attributes:{},subSpans:[]}),{success:true,resolvedTarget:{...f,resolvedNode:h},thoughts:p.thoughts};let{browserLocateResult:g,browserController:y}=await r.startWebviewTrace(async()=>{let S=await this.stateManager.getActiveWebview();if(!S||!S.browserController)throw new M("InternalWebAgentError","No browser controller is attached to the requested webview");return {browserLocateResult:await S.browserController.locateElement({description:e,disableCache:false,useMemory:i,memory:i?s:void 0,logger:this.logger,skipWait:true,skipSavingVisualAttributes:true}),browserController:S.browserController}});return r.addSpan({type:"TARGET_RESOLUTION",startTime:Date.now(),endTime:Date.now(),result:{serializedElement:g.target.nodeOnlySerializedHtml??"Unknown HTML element in webview"},attributes:{},subSpans:[]}),{success:true,resolvedTarget:{...f,controller:y,browserTarget:{...g.resolution,serverSideBoundingBox:await g.resolution.locator.boundingBox({timeout:5e3})},browserCache:g.target},thoughts:g.thoughts}}async targetingActionWithAILocator(e){let{action:r,command:n,description:o,tracer:i,cacheKey:a,targetName:s,cache:l,skipFetchingFullWebviewContent:c,removeWebviewContent:u,metadata:d,cacheBustReason:m}=e,p=await this.findElement({description:o,tracer:i,skipFetchingFullWebviewContent:c,removeWebviewContent:u,useMemory:this.shouldUseMemoryForCommand(n),memory:l?.memory,webviewMemory:mte(l),metadata:d,cacheBustReason:m});if(!p.success){if(p.updatedLocatorMemory&&l){let y={...l,memory:p.updatedLocatorMemory};Pd({command:n,cacheKey:a,targetName:s,updatedCache:y,updatedWithAI:true,logger:this.logger});}throw new M("NoMatchingElementError",p.thoughts??"No matching element found")}let f=p.thoughts,{result:h,resolvedTarget:g}=await this.executeActionWithWebviewReconstructRetry({action:r,resolvedTarget:p.resolvedTarget,reason:"webview target closed during AI-located action"});return Pd({command:n,cacheKey:a,targetName:s,updatedCache:Yc(g),updatedWithAI:true,logger:this.logger}),{result:h,thoughts:f}}async wrapTargetingAction(e){let{action:r,description:n,command:o,cacheKey:i="cache",targetName:a="target",cacheIsInvalidAfterResolution:s,tracer:l,skipFetchingFullWebviewContent:c=false,removeWebviewContent:u=false}=e,d,m={commandId:o.id};if(i==="cache"&&"cache"in o&&o.cache){let E=o.cache;a==="target"&&"target"in E?d=E.target:a==="fromTarget"&&"fromTarget"in E?d=E.fromTarget:a==="toTarget"&&"toTarget"in E&&(d=E.toTarget);}let p=false,f,h=cloneDeep(d);if(o.disableCache&&(this.logger.debug({command:o},"Cache explicitly disabled for command"),p=true,f="Cache explicitly disabled",h=void 0),s&&(p=true,f=f??"Cache invalidated after resolution",h=void 0),h&&!Dc(h?.resolvedDescription??"",n)&&(this.logger.info({description:n,cacheDescription:h?.resolvedDescription},"Cache description mismatch, clearing it automatically"),p=true,f="Description mismatch",h=void 0),!h)return this.logger.info({description:n,cacheBustedBeforeAction:p},"Prompting AI for a new element location"),this.targetingActionWithAILocator({action:r,command:o,description:n,tracer:l,cacheKey:i,targetName:a,cache:d,skipFetchingFullWebviewContent:c,removeWebviewContent:u,metadata:m,cacheBustReason:f});let g=h.type==="NATIVE"?!!h.requirements:!!h.browserCache?.requirements,y=h.type==="NATIVE"?!!h.requiredRelatedElements?.length:!!h.browserCache?.additionalElements?.length,S;try{this.options?.emulator?.waitForStability&&await this.stateManager.waitForPageSourceStability({timeoutMs:3e3,signal:this.aborter.controller?.signal,reason:"Waiting for stability before cache resolution"});let{resolvedTarget:E}=await l.startAsyncSpan("CACHE_RESOLUTION",async _=>{let L=Date.now(),I;for(;Date.now()-L<3e3;){S=await this.stateManager.getDomState({skipFetchingFullWebviewContent:h?.type==="NATIVE"});let R;try{R=(await yf({target:h,domState:S,stateManager:this.stateManager,logger:this.logger})).resolvedTarget;}catch(V){if(I=V,V instanceof Pe){this.logger.warn({err:V},"Failed to resolve target cache, retrying"),await ms(100,this.aborter.controller?.signal);continue}throw this.logger.error({err:V},"Failed to resolve target cache"),V}let k=Yc(R),D=diff(h,k);return D&&Object.keys(D).length>0&&this.logger.info({cacheDiffs:D},"Successfully resolved target with cache"),_.attributes.serializedElement=R.type==="WEBVIEW"?R.browserCache?.nodeOnlySerializedHtml??"Unknown HTML element in webview":R.elementOnlySerializedXml??"Unknown element",{resolvedTarget:R,updatedCache:k}}throw I}),{result:v,resolvedTarget:w}=await this.executeActionWithWebviewReconstructRetry({action:r,resolvedTarget:E,reason:"webview target closed during cached action"});return Pd({command:o,cacheKey:i,targetName:a,updatedCache:Yc(w),updatedWithAI:!1,logger:this.logger}),Ge.increment("cache_target_resolution_v2",1,["outcome:hit",`platform:mobile-${h.type.toLowerCase()}`,`hasRequirements:${g}`,`hasAdditionalElements:${y}`,`orgId:${this.orgId}`,"cliVersion:1.0.1"]),{result:v,thoughts:"Successfully executed preset action with cache"}}catch(E){if(this.throwIfAborted(),E instanceof M&&E.reason!=="InternalWebAgentError")throw this.logger.error({err:E},"Failed to execute action with target cache (fatal)"),E;return Ge.increment("cache_target_resolution_v2",1,["outcome:miss",`platform:mobile-${h.type.toLowerCase()}`,`hasRequirements:${g}`,`hasAdditionalElements:${y}`,`orgId:${this.orgId}`,"cliVersion:1.0.1"]),this.logger.warn({err:E},"Failed to execute action with target cache, retrying with AI"),this.targetingActionWithAILocator({action:r,command:o,description:n,tracer:l,cacheKey:i,targetName:a,cache:h,skipFetchingFullWebviewContent:c,removeWebviewContent:u,metadata:m})}}async executeActionWithWebviewReconstructRetry(e){let{action:r,resolvedTarget:n,reason:o}=e;try{return {result:await r(n),resolvedTarget:n}}catch(i){if(this.throwIfAborted(),n.type!=="WEBVIEW"||!this.errorLooksLikeClosedWebviewTarget(i)||(this.logger.warn({err:i},"Webview target appears closed or crashed during action, reconstructing browser and retrying once"),!(await this.stateManager.reconstructActiveWebviewBrowser(o))?.browserController))throw i;let s=await this.stateManager.getDomState({skipFetchingFullWebviewContent:true}),{resolvedTarget:l}=await yf({target:Yc(n),domState:s,stateManager:this.stateManager,logger:this.logger,signal:this.abortSignal});return {result:await r(l),resolvedTarget:l}}}errorLooksLikeClosedWebviewTarget(e){let r=W(e);return ["Target closed","Target crashed","Page crashed","Target page, context or browser has been closed","Session closed. Most likely the page has been closed"].some(n=>r.includes(n))}constructPerformerParams(){return {stateManager:this.stateManager,generator:this.generator,driver:this.driver,logger:this.logger,fixtures:this.fixtures,aborter:this.aborter,orgId:this.orgId,aiSettings:this.aiSettings,options:this.options}}getBoundsFromNativeCache(e){if(!e.bounds)throw new M("ActionFailureError","Native element cache has no bounds");let[r,n,o,i]=e.bounds;if(r===void 0||n===void 0||o===void 0||i===void 0)throw new M("ActionFailureError",`Native element cache has incomplete bounds: [${e.bounds.join(", ")}]`);return {left:r,top:n,width:o-r,height:i-n}}calculateSwipeCoordinates({containerBounds:e,direction:r,desiredDelta:n}){let o=e.left+e.width/2,i=e.top+e.height/2;if(r==="up"||r==="down"){let a=e.height*Yo,s=e.top+a,l=e.top+e.height-a,c=l-s,u=Math.min(Math.abs(n),c),d=c-u,m=r==="down"?l-d/2:s+d/2;return {startX:o,startY:m,actualDelta:u}}else {let a=e.width*Yo,s=e.left+a,l=e.left+e.width-a,c=l-s,u=Math.min(Math.abs(n),c),d=c-u;return {startX:r==="right"?l-d/2:s+d/2,startY:i,actualDelta:u}}}invertDirection(e){if(e==="up")return "down";if(e==="down")return "up";if(e==="left")return "right";if(e==="right")return "left";throw new Error(`Unreachable code: ${e}`)}async performRawSwipe({startX:e,startY:r,deltaPixels:n,direction:o,durationMs:i=300}){let a=Math.abs(n),s=e,l=r;o==="up"||o==="down"?l=o==="up"?r-a:r+a:s=o==="left"?e-a:e+a,await this.driver.executeInNativeContext(this.logger,async c=>{await c.performActions([{type:"pointer",id:"finger1",parameters:{pointerType:"touch"},actions:[{type:"pointerMove",duration:0,x:e,y:r},{type:"pointerDown",button:0},{type:"pause",duration:250},{type:"pointerMove",duration:i,x:s,y:l},{type:"pause",duration:500},{type:"pointerUp",button:0}]}]),await c.releaseActions();},{operationName:"performRawSwipe"}),await pe(Uze,this.abortSignal);}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}get abortSignal(){return this.aborter.controller?.signal}get aiSettingsCopy(){return cloneDeep(this.aiSettings)}get optionsCopy(){return cloneDeep(this.options)}};function Xc(t){if(t.type==="WEBVIEW"){let a=t.browserTarget.serverSideBoundingBox;return a?{left:a.x,top:a.y,width:a.width,height:a.height}:void 0}let{bounds:e}=t;if(!e)return;let[r,n,o,i]=e;if(!(r===void 0||n===void 0||o===void 0||i===void 0))return {left:r,top:n,width:o-r,height:i-n}}function fte(t){return "iterations"in t}function Vze(t){let e={relativePosition:t.relativePosition?er(t.relativePosition):void 0};if(t.iterations!==void 0&&(!Number.isInteger(t.iterations)||t.iterations<1))throw new Error("UserConfigurationError: iterations must be a positive integer");if(t.tapDelayMs!==void 0&&(!Number.isInteger(t.tapDelayMs)||t.tapDelayMs<0))throw new Error("UserConfigurationError: tapDelayMs must be >= 0");if(t.iterations&&t.iterations>1&&t.longPress)throw new Error("UserConfigurationError: Cannot specify both more than one tap iteration and long press at the same time");if(t.tapDelayMs!==void 0&&(!t.iterations||t.iterations<2))throw new Error("UserConfigurationError: tapDelayMs requires iterations >= 2");if(t.longPress){if(t.tapDelayMs!==void 0)throw new Error("UserConfigurationError: tapDelayMs cannot be used with longPress");return {...e,longPress:true,longPressDurationMs:t.longPressDurationMs}}return t.iterations!==void 0?{...e,iterations:t.iterations,tapDelayMs:t.tapDelayMs}:e}var Sf=class extends Cr{async tapOnNativeCoordinates(e){let r=e.x,n=e.y;if(this.logger.info({x:r,y:n},"Tap at coordinates"),"longPress"in e&&e.longPress)return await this.driver.executeInNativeContext(this.logger,o=>o.executeScript("mobile: longClickGesture",[{x:r,y:n,duration:e.longPressDurationMs??2e3}]),{operationName:"longPress"});if(fte(e)){let o=e.tapDelayMs??100;for(let i=0;i<e.iterations;i++)await this.driver.executeInNativeContext(this.logger,a=>a.tap({x:r,y:n}),{operationName:"tap"}),i<e.iterations-1&&await new Promise(a=>setTimeout(a,o));return}await this.driver.executeInNativeContext(this.logger,o=>o.tap({x:r,y:n}),{operationName:"tap"});}async tapOnNativeTarget(e,r){let[n,o,i,a]=e.bounds,s=i-n,l=a-o,c=r?.relativePosition?.x??s/2,u=r?.relativePosition?.y??l/2;c=Math.max(0,Math.min(c,s)),u=Math.max(0,Math.min(u,l));let d=n+c,m=o+u;return await this.tapOnNativeCoordinates({x:d,y:m,...r}),{x:d,y:m}}async tapOnWebviewTarget(e,r){let{controller:n}=e,o,i=1;return r&&fte(r)?(o=r.tapDelayMs,i=r.iterations):r&&"longPress"in r&&(o=r.longPressDurationMs),(await n.browser.click(e.browserTarget,{createIsolatedFolder:()=>{let s=Math.random().toString(36).substring(4),l=fr__default.join(tmpdir(),"momentic","downloads"),c=fr__default.join(l,this.orgId,s);return mkdirSync(c,{recursive:true}),c}},{delayMs:o,relativePosition:r?.relativePosition,iterations:i})).coordinates}async tapOnTarget({target:e,options:r}){return await ae().startAsyncSpan("EMULATOR_INTERACTION",async o=>{if(o.attributes.options=r,"type"in e&&e.type==="NATIVE"){let i=await this.tapOnNativeTarget(e,r);o.attributes.point=i,o.targetBounds=Xc(e);}else {o.withinWebview=true;let i=await this.tapOnWebviewTarget(e,r);o.attributes.point=i,o.targetBounds=Xc(e);}},{name:"Tap on target"})}async executeTap({command:e}){let r=ae(),n=Vze(e);if(e.target.type==="coordinates"||e.target.type==="absolute_percent"){let a=await this.driver.executeInNativeContext(this.logger,c=>c.getWindowSize(),{operationName:"getTapWindowSize"}),s,l;return e.target.type==="coordinates"?(s=e.target.xPercent*a.width,l=e.target.yPercent*a.height):(s=e.target.x/100*a.width,l=e.target.y/100*a.height),await r.startAsyncSpan("EMULATOR_INTERACTION",async c=>{await this.tapOnNativeCoordinates({...n,x:s,y:l}),c.attributes.point={x:s,y:l};},{name:`Tap at coordinates ${s}, ${l}`}),{success:true,message:`Tapped at ${s}, ${l}`}}let o=e.target.description,{thoughts:i}=await this.wrapTargetingAction({command:e,tracer:r,action:a=>this.tapOnTarget({target:a,options:n}),description:o});return {success:true,message:i}}};var Jc=class extends Cr{async doPress({keycode:e,repeat:r=1,keyPressDelayMs:n=0}){await ae().startAsyncSpan("EMULATOR_INTERACTION",async()=>{let i=jze({keycode:e,repeat:r,keyPressDelayMs:n});return this.driver.executeInNativeContext(this.logger,a=>a.execute("mobile: shell",i),{operationName:"pressKey"})},{name:r>1?`Send ${r} key event(s) to emulator`:"Send key events to emulator"});}};function jze({keycode:t,repeat:e,keyPressDelayMs:r}){if(e<=1)return {command:"input",args:["keyevent",`${t}`]};if(r<=0)return {command:"input",args:["keyevent",...Array(e).fill(`${t}`)]};let n=r/1e3;return {command:"sh",args:["-c",Array(e).fill(`input keyevent ${t}`).join(`; sleep ${n}; `)]}}var Id=25,gte=150,bte=67,Wze=123,Gze=100,qze=24,Kze=4,yte=1e3,KA=class extends Cr{async doType(e){let r=ae();if(!e.target){if(e.clearContent)throw new M("UserConfigurationError","Clearing content is only supported when a target is provided to the Type step");return await this.stateManager.waitForPageSourceStability({timeoutMs:2e3,signal:this.aborter.controller?.signal,reason:"Waiting for page to stabilize before typing"}),await this.sendKeys(e),{success:true,message:"Successfully executed type action"}}if(e.target.type!=="description")throw new M("UserConfigurationError","x/y targets are not supported for the Type step");let{thoughts:n}=await this.wrapTargetingAction({command:e,tracer:r,action:async o=>{"type"in o&&o.type==="NATIVE"?await this.doNativeType(e,o):await this.doWebviewType(e,o);},description:e.target.description});return {success:true,message:n}}async doWebviewType(e,r){await ae().startAsyncSpan("EMULATOR_INTERACTION",async o=>{o.withinWebview=true;let i={clearContent:e.clearContent,forceClearContent:e.forceClearContent,delay:e.keyPressDelayMs??Id};o.attributes.options=i;let{controller:a,browserTarget:s}=r;await a.browser.typeIntoTarget(e.text,s,i);},{name:"Typing within web view"});}async doNativeType(e,r){e.clearContent?await this.clearNativeContent(e,r):await this.tapNativeTargetForType(r),await this.stateManager.waitForPageSourceStability({timeoutMs:2e3,signal:this.aborter.controller?.signal,reason:"Waiting for keyboard to appear before typing"}),await this.sendKeys(e);}async tapNativeTargetForType(e,r){let n=ae(),o=new Sf(this.constructPerformerParams());await n.startAsyncSpan("EMULATOR_INTERACTION",async i=>{i.attributes.options=r??{};let a=await o.tapOnNativeTarget(e,r);i.attributes.point=a,i.targetBounds=Xc(e);},{name:"Tap on target"});}async sendKeys(e){let r=ae(),n=e.keyPressDelayMs??Id;await r.startAsyncSection("Waiting for system keyboard to open",async(o,i)=>{let a=Date.now();for(;Date.now()-a<2e3;){this.throwIfAborted();let s=Date.now();if(await this.driver.executeInNativeContext(this.logger,c=>c.isKeyboardShown(),{operationName:"isKeyboardShown"}))return;let l=Date.now()-s;l<100&&await new Promise(c=>setTimeout(c,100-l));}i.attributes.timedOut=true;}),await r.startAsyncSpan("EMULATOR_INTERACTION",async()=>{try{n!==Id&&await this.driver.executeInNativeContext(this.logger,async i=>i.updateSettings({keyInjectionDelay:n}),{operationName:"updateKeyInjectionDelay"});let o=[];for(let i=0;i<e.text.length;i+=gte)o.push(e.text.slice(i,i+gte));for(let i of o)await this.driver.executeInNativeContext(this.logger,async a=>a.keys(i),{operationName:"typeWithCustomKeyDelay",attemptTimeoutMs:FC(n,i),maxAttempts:1});}finally{n!==Id&&await this.driver.executeInNativeContext(this.logger,async o=>o.updateSettings({keyInjectionDelay:Id}),{operationName:"updateKeyInjectionDelay"});}},{name:`Typing with a ${n}ms delay`});}async clearNativeContent(e,r){let n=e.replaceStrategy??"auto";switch(this.logger.info({strategy:n,command:{targetDescription:e.target?.type==="description"?e.target.description:e.target?.type,textLength:e.text.length,clearContent:e.clearContent,forceClearContent:e.forceClearContent,replaceStrategy:e.replaceStrategy},target:sa(r)},"Preparing to clear native input content"),n){case "auto":await this.clearNativeContentAutomatically(r);return;case "programmatic":await this.clearContentWithAppium(r,{verify:false});return;case "long-press":await this.clearContentWithSelectAll(r);return;case "backspace":await this.clearContentWithBackspace(r);return}}async clearNativeContentAutomatically(e){let r=Ste(e),n=Yze(e);if(r===""&&n){this.logger.info({target:sa(e)},"Skipping native clear because target text is already empty");return}n&&await this.clearContentWithAppium(e,{verify:true})||await this.clearContentWithSelectAll(e)||await this.clearContentWithBackspace(e);}async clearContentWithSelectAll(e){await this.tapNativeTargetForType(e,{longPress:true});let r=ae();try{return await r.startAsyncSection("Clearing any content from the focused field",()=>this.clearContentHelper()),!0}catch(n){return this.logger.warn({err:n},"Failed to find select all button, continuing..."),false}}async clearContentWithAppium(e,r){let n=e.xPath,o=ok(e);if(!n||o)return this.logger.info({rejectionReason:n?o:"missing_xpath",target:sa(e)},"Skipping Appium clear for native target"),false;let i=ae();try{await i.startAsyncSection("Clearing content programmatically",()=>this.driver.executeInNativeContext(this.logger,async s=>{await(await s.$(n)).clearValue();},{operationName:"clearNativeTextInput",maxAttempts:1}));let a=r.verify?await this.waitForNativeTargetTextToClear(n):!0;return this.logger.info({target:sa(e),verified:r.verify,cleared:a},"Finished Appium clear for native target"),a?(await this.focusNativeTargetAfterClear(e),!0):!1}catch(a){return this.logger.warn({err:a},"Failed to clear native input with Appium, falling back..."),false}}async focusNativeTargetAfterClear(e){let r=e.xPath;if(!r){await this.tapNativeTargetForType(e);return}let n=await this.resolveNativeTargetFocusAfterClear(r);if(n.resolved&&n.focused){this.logger.info({target:sa(e)},"Target already focused after clear, skipping focus tap");return}if(n.resolved){let i=n.bounds;this.logger.info({target:sa(e),bounds:i},"Tapping native target to focus after clear"),await this.tapNativeTargetForType(i?{...e,bounds:i}:e);return}if(await this.driver.executeInNativeContext(this.logger,i=>i.isKeyboardShown(),{operationName:"isKeyboardShown"})){this.logger.info({target:sa(e)},"Target xPath no longer resolves but keyboard is open, skipping focus tap");return}this.logger.info({target:sa(e)},"Target xPath no longer resolves and keyboard is closed, tapping cached bounds"),await this.tapNativeTargetForType(e);}async resolveNativeTargetFocusAfterClear(e){try{let r=await this.stateManager.getDomState({skipFetchingFullWebviewContent:!0,removeWebviewContent:!0}),n=lte.evaluateXPathToFirstNode(e,r.graph.document,null,null);return n instanceof Element?{resolved:!0,focused:n.getAttribute("focused")==="true",bounds:Tl(n)}:{resolved:!1}}catch(r){return this.logger.debug({err:r},"Failed to resolve native target focus state after clear"),{resolved:false}}}async clearContentWithBackspace(e){let r=await this.readNativeTargetText(e.xPath);if(r===void 0)return this.logger.debug({target:sa(e)},"Skipping native backspace clear because the target text is not readable"),false;if(r==="")return true;await this.tapNativeTargetForType(e);let o=await ae().startAsyncSection("Clearing content with bounded backspaces",async(i,a)=>{let s=r.length,l=1,c=0,u=0;for(let d=0;d<qze;d++){let m=Gze-c;if(m<=0)break;let f=d===0||u>0?1:Math.max(1,Math.min(Math.ceil(s/2),Math.floor(s/l),m));this.logger.info({target:sa(e),round:d,lengthBefore:s,keysToIssue:f,maxUnitsPerKey:l},"Issuing bounded backspaces"),await this.driver.executeInNativeContext(this.logger,y=>y.execute("mobile: shell",{command:"sh",args:["-c",`input keyevent ${Wze}; i=0; while [ $i -lt ${f} ]; do input keyevent ${bte}; i=$((i+1)); done`]}),{operationName:"backspaceClearNativeTextInput",maxAttempts:1}),c+=f;let h=await this.readRemainingNativeTextLength(e.xPath);if(h===void 0)return false;let g=s-h;if(this.logger.info({target:sa(e),round:d,lengthAfter:h,deleted:g,totalKeys:c},"Bounded backspace iteration result"),h===0)return a.attributes.totalKeys=c,true;if(g<=0){if(u+=1,u>=2)return false;s=h;continue}u=0,l=Math.max(l,Math.ceil(g/f)),s=h;}return a.attributes.totalKeys=c,false});return this.logger.info({target:sa(e),cleared:o},"Finished native backspace clear"),o}async readNativeTargetText(e){let r=await this.readNativeTargetTextResult(e);if(r.status==="readable")return r.text}async readRemainingNativeTextLength(e){for(let r=0;r<Kze;r++){let n=await this.readNativeTargetTextResult(e);if(n.status==="readable")return n.text?.length??0}}async readNativeTargetTextResult(e){if(!e)return {status:"unreadable"};try{return {status:"readable",text:await ee(this.readNativeTargetTextFromXml(e),{milliseconds:yte,signal:this.aborter.controller?.signal,message:`readNativeTextInputValueFromXml timed out after ${yte}ms`})}}catch(r){return this.logger.debug({err:r},"Failed to read native input text from XML for clear verification"),{status:"unreadable"}}}async readNativeTargetTextFromXml(e){let r=await this.stateManager.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true}),n=lte.evaluateXPathToFirstNode(e,r.graph.document,null,null);if(!n)throw new Error(`Could not resolve native input via XPath: ${e}`);return Tte({text:n.getAttribute("text"),hint:n.getAttribute("hint"),showingHint:n.getAttribute("showing-hint"),password:n.getAttribute("password")})}async waitForNativeTargetTextToClear(e){return await ae().startAsyncSection("Verifying programmatic clear result",async(n,o)=>{let i=[],a=Date.now(),s=false,l=0;for(;Date.now()-a<2e3;){this.throwIfAborted(),l+=1;let c=await this.readNativeTargetTextResult(e);if(c.status==="unreadable"){i.push({attempt:l,status:"unreadable"});break}if(c.text===void 0||c.text==="")return i.push({attempt:l,status:"cleared"}),o.attributes.observations=i,o.attributes.result="cleared",true;s=true,i.push({attempt:l,status:"non_empty",textLength:c.text.length}),await new Promise(u=>setTimeout(u,100));}return o.attributes.observations=i,s?(o.attributes.result="still_non_empty",false):(o.attributes.result="unverifiable",true)})}async clearContentHelper(){await this.driver.executeInNativeContext(this.logger,async r=>{let n=r.$('//android.widget.LinearLayout[@content-desc="Select all" and @clickable="true"]');await n.waitForExist({timeout:750}),await n.click();},{operationName:"selectAllText",maxAttempts:1}),await new Jc(this.constructPerformerParams()).doPress({keycode:bte});}};function Ste(t){return Tte({text:t.resolvedNode.getAttribute("text"),hint:t.resolvedNode.getAttribute("hint"),showingHint:t.resolvedNode.getAttribute("showing-hint"),password:t.resolvedNode.getAttribute("password")})}function Tte({text:t,hint:e,showingHint:r,password:n}){if(!(t===null||r==="true"||n==="true")&&!(e!==null&&t.trim()!==""&&t.trim()===e.trim()))return t}function Yze(t){return ok(t)===void 0}function ok(t){if(!t.xPath)return "missing_xpath";if(t.resolvedNode.getAttribute("enabled")==="false")return "disabled";let e=t.resolvedNode.tagName.toLowerCase(),r=t.resolvedNode.getAttribute("class")?.toLowerCase();if(e.endsWith("edittext")||r?.endsWith("edittext"))return;let n=t.resolvedNode.getAttribute("input-type");if(!n||n==="0")return "not_text_input"}function sa(t){let e=Ste(t);return {xPath:t.xPath,tagName:t.resolvedNode.tagName,className:t.resolvedNode.getAttribute("class"),resourceId:t.resolvedNode.getAttribute("resource-id"),contentDescription:t.resolvedNode.getAttribute("content-desc"),hint:t.resolvedNode.getAttribute("hint"),inputType:t.resolvedNode.getAttribute("input-type"),enabled:t.resolvedNode.getAttribute("enabled"),focused:t.resolvedNode.getAttribute("focused"),showingHint:t.resolvedNode.getAttribute("showing-hint"),password:t.resolvedNode.getAttribute("password"),readableText:e===void 0?"unreadable":{length:e.length},appiumClearRejectionReason:ok(t)}}var Ete=.8,Xze=C__default.object({navigationBar:C__default.object({visible:C__default.boolean(),x:C__default.number(),y:C__default.number(),width:C__default.number(),height:C__default.number()}),statusBar:C__default.object({visible:C__default.boolean(),x:C__default.number(),y:C__default.number(),width:C__default.number(),height:C__default.number()})});function ik(t,e){t.attributes.scrollableElementType=e.type,t.attributes.scrollableElementDisplay=Ks(e),e.type==="CUSTOM"&&(t.attributes.scrollableElementDescription=e.target.description);}var Tf=class extends Cr{async getHardcodedScrollableElementBounds(e,r){let n;switch(e.type){case "SCREEN":n=this.getContainerBoundsFromViewport(r);break;case "OPEN_APP":try{let o=Xze.parse(await this.driver.executeInNativeContext(this.logger,i=>i.executeScript("mobile: getSystemBars",[]),{operationName:"getSystemBars"}));n=this.getContainerBoundsFromViewport(r),o.navigationBar.visible&&(n.height=Math.max(1,n.height-o.navigationBar.height)),o.statusBar.visible&&(n.top+=o.statusBar.height,n.height=Math.max(1,n.height-o.statusBar.height));}catch(o){this.logger.warn({err:o},"Failed to get system bars, using hardcoded bounds"),n=this.getContainerBoundsFromViewport(r);}break;case "OPEN_WEBVIEW":{let o=await this.stateManager.getActiveWebviewNodes();if(o.length===0&&(await this.stateManager.refreshWebviewsManually("get active webview nodes"),o=await this.stateManager.getActiveWebviewNodes()),o.length===0)throw new Error("No active webviews found");if(o.length>1){let a=o.map(s=>({id:s.id,ele:s.originalElement.outerHTML,bounds:s.bounds}));throw new Error(`Multiple active webviews found. Momentic currently only supports a single active webview at a time. Discovered nodes: ${JSON.stringify(a)}`)}let i=o[0]?.bounds;if(!i)throw new Error("No bounds found for active webview");n=this.getContainerBoundsFromBounds(i);break}default:{throw new Error("If Typescript complains about the line above, you missed a switch case")}}return n}getContainerBoundsFromViewport(e){return {left:e.x,top:e.y,width:Math.max(1,e.width),height:Math.max(1,e.height)}}getContainerBoundsFromBounds(e){let r=e[0],n=e[1],o=e[2],i=e[3],a=o-r,s=i-n;return {left:r,top:n,width:Math.max(1,a),height:Math.max(1,s)}}async executeSwipe(e){let r=ae(),n=Ks(e.scrollableElement);if(e.scrollableElement.type==="CUSTOM_COORDINATES"){let{startX:i,startY:a,deltaPixels:s}=e.scrollableElement;return await r.startAsyncSpan("EMULATOR_INTERACTION",async l=>{ik(l,e.scrollableElement),l.attributes.startX=i,l.attributes.startY=a,l.attributes.deltaPixels=s,l.attributes.direction=e.direction,await this.performRawSwipe({startX:i,startY:a,deltaPixels:s,direction:e.direction,durationMs:e.durationMs});},{name:`Swipe ${e.direction} in ${n}`}),{success:true,message:"Successfully executed swipe action"}}if(e.scrollableElement.type!=="CUSTOM"){let i=await this.driver.executeInNativeContext(this.logger,s=>s.getWindowRect(),{operationName:"getSwipeViewportRect"}),a=await this.getHardcodedScrollableElementBounds(e.scrollableElement,i);return await r.startAsyncSpan("EMULATOR_INTERACTION",async s=>{ik(s,e.scrollableElement),await this.swipeByAbsoluteCoordinates({span:s,direction:e.direction,percent:e.viewportPercent,durationMs:e.durationMs,containerBounds:a,relativePosition:e.relativePosition?er(e.relativePosition):void 0});},{name:`Swipe ${e.direction} in ${n}`}),{success:true,message:"Successfully executed swipe action"}}let{thoughts:o}=await this.wrapTargetingAction({command:e,description:e.scrollableElement.target.description,action:async i=>ae().startAsyncSpan("EMULATOR_INTERACTION",async s=>(ik(s,e.scrollableElement),"type"in i&&i.type==="NATIVE"?this.scrollInNativeContainer({span:s,cmd:e,target:i}):(s.withinWebview=true,this.swipeInWebview({span:s,cmd:e,target:i}))),{name:`Swipe ${e.direction} in ${n}`}),tracer:r});return {success:true,message:o}}async scrollInNativeContainer({span:e,cmd:r,target:n}){if(!n.bounds||n.bounds.length<4)throw new M("ActionFailureError","Native container cache has no bounds");let o=n.bounds,i=o[2]-o[0],a=o[3]-o[1];await this.swipeByAbsoluteCoordinates({span:e,direction:r.direction,percent:r.viewportPercent,durationMs:r.durationMs,containerBounds:{left:o[0],top:o[1],width:Math.max(1,i),height:Math.max(1,a)},relativePosition:r.relativePosition?er(r.relativePosition):void 0});}async swipeInWebview({span:e,cmd:r,target:n}){let{controller:o,browserTarget:i}=n;if(!o.browser.getViewport())throw new Error("Failed to get viewport size from webview");let s=r.direction==="down"||r.direction==="up",l=await i.locator.boundingBox();if(!l)throw new Error("Failed to get bounds for webview container");let c=Math.floor(l.width*Yo),u=Math.floor(l.height*Yo),d=Math.max(1,l.width-c*2),m=Math.max(1,l.height-u*2),p,f;if(r.relativePosition){let y=er(r.relativePosition);p=l.x+y.x,f=l.y+y.y;}else p=l.x+l.width/2,f=l.y+l.height/2;let h={x:p,y:f},g=(s?m:d)*(r.viewportPercent??Ete)*(s?r.direction==="down"?1:-1:r.direction==="right"?1:-1);e.attributes.startPoint=h,e.attributes.scrollPixelAmount=g,await o.browser.mouseDragUsingVisualCoordinates({deltaX:s?0:g,deltaY:s?g:0,steps:10,dragDurationMs:r.durationMs,fromTarget:h});}async swipeByAbsoluteCoordinates({span:e,direction:r,percent:n=Ete,durationMs:o=500,containerBounds:i,relativePosition:a}){e.attributes.containerBounds=i;let s=i.width*Yo,l=i.height*Yo,c,u;if(r==="up"||r==="down"?(c=(i.height-2*l)*n,u=Math.floor(c/(o/1e3))):(c=(i.width-2*s)*n,u=Math.floor(c/(o/1e3))),e.attributes.pixelDelta=c,e.attributes.pixelsPerSecond=u,a){let d=i.left+a.x,m=i.top+a.y;await this.performRawSwipe({startX:d,startY:m,deltaPixels:c,direction:r,durationMs:o});}else {let d=i.width*Yo,m=i.height*Yo,p={left:i.left+d,top:i.top+m,width:Math.max(1,i.width-2*d),height:Math.max(1,i.height-2*m)};await this.driver.executeInNativeContext(this.logger,f=>f.executeScript("mobile: swipeGesture",[{...p,direction:r,percent:n,speed:u}]),{operationName:"swipeGesture"});}}};var vte=20,ak=.9,Jze=2,Ef=.5,sk=.2;var YA=class extends Tf{async executeScrollTo(e){let r=e.target.description,n=e.scrollStepPercent??ak,o=await this.tryUseCachedScrollPosition(e,r);return o||this.searchForElement({cmd:e,description:r,scrollStepPercent:n})}async resolveContainer({scrollableElement:e,containerCache:r,aiMetadata:n}){let o=await this.stateManager.getViewportBounds(),i={x:o.left,y:o.top,width:o.right-o.left,height:o.bottom-o.top};if(e.type==="CUSTOM_COORDINATES")return {bounds:{left:0,top:0,width:i.width,height:i.height},diffThresholdPercent:Ef};if(e.type!=="CUSTOM")return {bounds:await this.getHardcodedScrollableElementBounds(e,i),diffThresholdPercent:Ef};let a=ae(),s=e.target.description;if(r){let d=this.getBoundsFromNativeCache(r);return this.logger.info({bounds:d},"Got container bounds from native cache"),{bounds:d,cache:r,diffThresholdPercent:_p({containerBounds:d,viewport:i,defaultThresholdPercent:Ef})}}let l=await this.findElement({description:s,tracer:a,metadata:n});if(!l.success)throw new M("NoMatchingElementError",l.thoughts??"No matching element found");let{resolvedTarget:c}=l;if(c.type!=="NATIVE")throw new Error(`ActionFailureError: Custom scroll container "${s}" resolved to a webview element. Custom containers must be native elements.`);let u=this.getBoundsFromNativeCache(c);return this.logger.info({bounds:u},"Got container bounds from AI"),{bounds:u,cache:c,diffThresholdPercent:_p({containerBounds:u,viewport:i,defaultThresholdPercent:Ef})}}async tryUseCachedScrollPosition(e,r){let n=e.cache?.target;return n?n.type==="WEBVIEW"?this.tryUseWebviewCache(e,r):n.scrollDetails?this.tryUseNativeScrollCache(e,r,n):null:null}async tryUseWebviewCache(e,r){let n=ae();try{let{thoughts:o}=await this.wrapTargetingAction({command:e,tracer:n,description:r,action:async i=>{if(i.type==="NATIVE")throw new Error("Expected WEBVIEW target but got NATIVE");await this.scrollWebviewTargetIntoView(i);}});return {success:!0,message:o}}catch(o){return this.logger.warn({err:o},"Failed to use webview cache, falling back to search"),null}}async tryUseNativeScrollCache(e,r,n){let o=n.scrollDetails,i=ae(),a=e.scrollStepPercent??ak,s=o.scrollableElement.type==="CUSTOM"?o.scrollableElement.cache:void 0,l=await this.resolveContainer({scrollableElement:e.scrollableElement,containerCache:s,aiMetadata:{commandId:e.id}}),c=l.bounds,u=l.diffThresholdPercent,d=e.scrollableElement.type==="CUSTOM_COORDINATES"?e.scrollableElement:void 0,m=d?Math.abs(d.deltaPixels):this.calculateSwipeCoordinates({containerBounds:c,direction:e.direction,desiredDelta:Cs({containerBounds:c,containerInsetRatio:Yo})*a}).actualDelta,p=await this.stateManager.getLastObservedState();if(p){let v=await this.tryFindElement({cmd:e,description:r,tracer:i,scrollDetails:this.buildScrollDetails(e,0,l.cache),knownState:p,useAIIfCacheFails:false});if(v)return this.logger.info("Element resolved from last observed state without scrolling"),v}else this.logger.debug("Skipping scroll-to preflight because no last observed state is available");let f=Math.abs(o.pixelDelta),h=0,g=m*Jze,y=0;for(;y<f;){this.throwIfAborted();let v=f-y,w=Math.min(v,g),_=await this.scrollByPixelDelta({pixelDelta:w,scrollableElement:e.scrollableElement,containerCache:l.cache,direction:e.direction,scrollStepPercent:a,aiMetadata:{commandId:e.id},useVisualDiff:false});if(_===0)break;y+=_,h+=e.direction==="down"?_:-_;let L=await this.tryFindElement({cmd:e,description:r,tracer:i,scrollDetails:this.buildScrollDetails(e,h,l.cache),useAIIfCacheFails:false});if(L)return this.logger.info({cumulativePixelDelta:h},"Element resolved during cache replay"),L}let S=Math.max(0,Math.min(e.maxScrollAttempts??vte,2)),E=true;for(let v=0;v<S&&E;v++){this.throwIfAborted(),E=await this.scrollByPage({direction:e.direction,containerBounds:c,scrollStepPercent:a,diffThresholdPercent:u,rawCoordinates:d}),E&&(h+=e.direction==="down"?m:-m);let w=await this.tryFindElement({cmd:e,description:r,tracer:i,scrollDetails:this.buildScrollDetails(e,h,l.cache),useAIIfCacheFails:false});if(w)return this.logger.info({attempt:v,cumulativePixelDelta:h},"Element resolved during cache buffer scroll"),w}if(h!==0){let v=e.direction==="down"?"up":"down";this.logger.info({cumulativePixelDelta:h,originalDirection:e.direction,undoDirection:v,scrollableElementType:e.scrollableElement.type},"Cache replay did not resolve target; undoing scroll"),await this.scrollByPixelDelta({pixelDelta:Math.abs(h),scrollableElement:e.scrollableElement,containerCache:l.cache,direction:v,scrollStepPercent:a,aiMetadata:{commandId:e.id}});}return null}async tryFindElement({cmd:e,description:r,tracer:n,scrollDetails:o,useAIIfCacheFails:i=true,knownState:a}){let s,l,c=false,u=o,d=lk(e.cache?.target);if(d&&d.resolvedDescription!==void 0&&Dc(d.resolvedDescription,r)&&!e.disableCache){let f=a?.emulatorState??await this.stateManager.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true});try{let{resolvedTarget:h}=await yf({target:d,domState:f,stateManager:this.stateManager,logger:this.logger});s=h,c=!0,l="Successfully resolved scroll to target with cache.",this.logger.info("Successfully resolved scroll to target from cache");}catch(h){this.logger.warn({err:h},"Failed to resolve target from cache");}}if(s&&c&&s.type==="NATIVE"&&o){let f=await this.correctNativeTargetIntoView({cmd:e,resolvedTarget:s,scrollDetails:o});u=f.scrollDetails,f.resolvedTarget?s=f.resolvedTarget:(s=void 0,c=false);}if(!s&&!i)return null;if(!s)try{let f=cw(r),h=await this.findElement({description:f,tracer:n,knownState:a,metadata:{commandId:e.id,source:"SCROLL_TO"}});if(!h.success)return null;s=h.resolvedTarget,l=h.thoughts;}catch(f){if(f instanceof M&&f.reason==="NoMatchingElementError")return null;throw this.logger.warn({err:f},"Failed to find scroll-to target with AI"),f}if(s&&!c&&s.type==="NATIVE"&&o)try{let f=await this.correctNativeTargetIntoView({cmd:e,resolvedTarget:s,scrollDetails:o});u=f.scrollDetails,f.resolvedTarget&&(s=f.resolvedTarget);}catch(f){this.logger.warn({err:f},"Failed to reposition AI-resolved scroll-to target for stable cache generation");}if(s.type==="WEBVIEW"){await this.scrollWebviewTargetIntoView(s);let f=lk(Yc(s));return Pd({command:e,updatedCache:f,updatedWithAI:!c,logger:this.logger}),{success:true,message:l}}let p=Yc(s);if(p.type!=="NATIVE")throw new Error("Expected native target cache for scroll-to");return Pd({command:e,updatedCache:lk({...p,scrollDetails:u}),updatedWithAI:!c,logger:this.logger}),{success:true,message:l}}async correctNativeTargetIntoView({cmd:e,resolvedTarget:r,scrollDetails:n}){let o=await this.getCorrectiveScrollForTarget({resolvedTarget:r});if(!o)return {resolvedTarget:r,scrollDetails:n};this.logger.info({bounds:r.bounds,correction:o},"Repositioning scroll-to target to the preferred viewport anchor");let i=n.scrollableElement.type==="CUSTOM"?n.scrollableElement.cache:void 0,a=await this.scrollByPixelDelta({pixelDelta:o.pixelDelta,scrollableElement:n.scrollableElement,containerCache:i,direction:o.direction,scrollStepPercent:e.scrollStepPercent??ak,aiMetadata:{commandId:e.id},useVisualDiff:true});if(a===0)return this.logger.info({bounds:r.bounds,correction:o},"Skipping corrective scroll update because the viewport did not move"),{resolvedTarget:r,scrollDetails:n};let s=await this.stateManager.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true}),l;try{({resolvedTarget:l}=await yf({target:r,domState:s,stateManager:this.stateManager,logger:this.logger}));}catch(f){return this.logger.warn({err:f},"Failed to re-resolve scroll-to target after corrective scroll"),{resolvedTarget:r,scrollDetails:n}}if(l.type!=="NATIVE")return {resolvedTarget:r,scrollDetails:n};let c=r.bounds,u=l.bounds;if(c!==void 0&&u!==void 0&&c.length===u.length&&c.every((f,h)=>f===u[h]))return this.logger.info({bounds:r.bounds,correction:o,appliedCorrectionPixels:a},"Skipping corrective scroll update because the target did not move (viewport at scroll extent)"),{resolvedTarget:l,scrollDetails:n};let m={...n,pixelDelta:_C({currentPixelDelta:n.pixelDelta,baseDirection:n.direction,correctionDirection:o.direction,correctionPixels:a})},p=await this.getCorrectiveScrollForTarget({resolvedTarget:l});return p?(this.logger.warn({bounds:l.bounds,correction:p},"Corrective scroll still did not bring the scroll-to target into the preferred viewport anchor"),{resolvedTarget:l,scrollDetails:m}):{resolvedTarget:l,scrollDetails:m}}async searchForElement({cmd:e,description:r,scrollStepPercent:n}){let o=ae(),i=await this.resolveContainer({scrollableElement:e.scrollableElement,aiMetadata:{commandId:e.id}});return this.scrollAndSearch({cmd:e,description:r,tracer:o,scrollStepPercent:n,resolvedContainer:i})}async scrollAndSearch({cmd:e,description:r,tracer:n,scrollStepPercent:o,resolvedContainer:i}){let a=0,s=i.bounds,l=i.diffThresholdPercent,c=e.scrollableElement.type==="CUSTOM_COORDINATES"?e.scrollableElement:void 0,u;c?u=Math.abs(c.deltaPixels):u=this.calculateSwipeCoordinates({containerBounds:s,direction:e.direction,desiredDelta:Cs({containerBounds:s,containerInsetRatio:Yo})*o}).actualDelta;let d=true,m=e.maxScrollAttempts??vte;for(let h=0;h<m;h++){this.throwIfAborted();let g=this.buildScrollDetails(e,a,i.cache),y=await this.tryFindElement({cmd:e,description:r,tracer:n,scrollDetails:g});if(y)return y;if(!d)throw new Error(`ActionFailureError: Could not find element "${r}" after scrolling to the end`);this.logger.debug({attempt:h,cumulativePixelDelta:a},"Element not found, scrolling further"),d=await this.scrollByPage({direction:e.direction,containerBounds:s,scrollStepPercent:o,diffThresholdPercent:l,rawCoordinates:c}),a+=e.direction==="down"?u:-u;}let p=this.buildScrollDetails(e,a,i.cache),f=await this.tryFindElement({cmd:e,description:r,tracer:n,scrollDetails:p});if(f)return f;throw new Error(`ActionFailureError: Could not find element "${r}" after ${m} scroll attempts`)}buildScrollDetails(e,r,n){return e.scrollableElement.type==="CUSTOM"?{pixelDelta:r,scrollableElement:{type:"CUSTOM",target:e.scrollableElement.target,cache:n},direction:e.direction}:e.scrollableElement.type==="CUSTOM_COORDINATES"?{pixelDelta:r,scrollableElement:e.scrollableElement,direction:e.direction}:{pixelDelta:r,scrollableElement:e.scrollableElement,direction:e.direction}}async scrollWebviewTargetIntoView(e){let{controller:r,browserTarget:n}=e;await r.browser.hover(n);}async scrollByPage({direction:e,containerBounds:r,scrollStepPercent:n,diffThresholdPercent:o,rawCoordinates:i}){return ae().startAsyncSpan("EMULATOR_INTERACTION",async s=>(s.attributes.containerBounds=r,s.attributes.direction=e,(await this.executeScrollGesture({direction:e,containerBounds:r,scrollStepPercent:n,diffThresholdPercent:o,rawCoordinates:i})).canScrollMore),{name:`Scroll ${e} by one page`})}async scrollByPixelDelta({pixelDelta:e,scrollableElement:r,containerCache:n,direction:o,scrollStepPercent:i,aiMetadata:a,useVisualDiff:s=false}){if(e===0)return 0;let l=ae(),c,u=Ef,d,m,p;if(r.type==="CUSTOM_COORDINATES")d=r.startX,m=r.startY,p=r.deltaPixels;else {c=await this.resolveContainer({scrollableElement:r,containerCache:n,aiMetadata:a});let h=c.bounds;u=c.diffThresholdPercent;let g=Cs({containerBounds:h,containerInsetRatio:Yo})*i,y=this.calculateSwipeCoordinates({containerBounds:h,direction:o,desiredDelta:g});d=y.startX,m=y.startY,p=y.actualDelta;}let f=Math.ceil(Math.abs(e)/p);return this.logger.debug({pixelDelta:e,direction:o,scrollableElementType:r.type,startX:d,startY:m,maxScrollPerStep:p,numScrolls:f},"scrollByPixelDelta calculated parameters"),l.startAsyncSpan("EMULATOR_INTERACTION",async h=>{h.attributes.pixelDelta=e,h.attributes.numScrolls=f,h.attributes.maxScrollPerStep=p,h.attributes.startX=d,h.attributes.startY=m;let g=this.invertDirection(o),y=0;for(let S=0;S<f;S++){this.throwIfAborted();let E=Math.abs(e)-y,v=Math.min(p,E);if(s){let w=await this.executeScrollGesture({direction:o,containerBounds:c?.bounds,scrollStepPercent:i,diffThresholdPercent:u,rawCoordinates:{type:"CUSTOM_COORDINATES",startX:d,startY:m,deltaPixels:v}});if(w.didScroll&&(y+=v),!w.canScrollMore)break}else await this.performRawSwipe({startX:d,startY:m,deltaPixels:v,direction:g}),y+=v;}return h.attributes.appliedPixels=y,y},{name:`Scroll ${o} by ${Math.abs(e)}px`})}async executeScrollGesture({direction:e,containerBounds:r,scrollStepPercent:n,diffThresholdPercent:o=Ef,rawCoordinates:i}){let a=await this.stateManager.getRawScreenshotBase64(),s,l,c;if(i)s=i.startX,l=i.startY,c=i.deltaPixels;else {if(!r)throw new Error("Expected container bounds for scroll gesture");let f=Cs({containerBounds:r,containerInsetRatio:Yo})*n,h=this.calculateSwipeCoordinates({containerBounds:r,direction:e,desiredDelta:f});s=h.startX,l=h.startY,c=h.actualDelta;}await this.performRawSwipe({startX:s,startY:l,deltaPixels:c,direction:this.invertDirection(e)});let u=await this.stateManager.getRawScreenshotBase64(),d=wc(a,u),m=d>o,p=d>o;return this.logger.debug({diffPercent:d,didScroll:m,diffThresholdPercent:o,canScrollMore:p,direction:e,actualDelta:c,rawCoordinates:i},"Scroll gesture visual diff result"),{didScroll:m,canScrollMore:p}}async getCorrectiveScrollForTarget({resolvedTarget:e}){let r=e.bounds;if(!r||r.length<4)return;let n=await this.stateManager.getViewportBounds(),o=Math.max(1,n.bottom-n.top),i=r[1],a=r[3],s=OC({viewportTop:n.top,viewportBottom:n.bottom,elementHeight:a-r[1],targetTopRatio:sk}),l=n.top+o*sk,c=n.bottom-o*sk,u=i>=n.top&&a<=n.bottom,d=i<l||a>c,m=e.resolvedNode.getAttribute("displayed")!=="false"&&e.resolvedNode.getAttribute("visible")!=="false",p=s-i;if(!(u&&m&&!d)){if(p>0)return {direction:"up",pixelDelta:p};if(p<0)return {direction:"down",pixelDelta:Math.abs(p)}}}};function lk(t){return !t||t.type!=="NATIVE"?t:DC(t)}var XA=class extends Cr{async doInstallApk(e){return await this.installApkFromUri(e.uri),{success:true,message:"Installed APK."}}async installApkFromUri(e){let r=await this.resolveUriToLocalApk(e);try{await this.stateManager.executeRawADBCommand(`install -r ${fr__default.resolve(r.localPath)}`),this.logger.info({uri:e,localPath:r.localPath},"Installed APK on device");}finally{r.cleanup();}}async resolveUriToLocalApk(e){try{let r=new URL(e);if(r.protocol==="file:"){let n=r.href.slice(7),o;if(Sn.existsSync(n))o=n;else if(Sn.existsSync(fr__default.join("/",n)))o=fr__default.join("/",n);else throw new M("UserConfigurationError",`APK not found at path: ${n}`);return this.assertFileExists(o),{localPath:o,cleanup:()=>{}}}if(r.protocol==="http:"||r.protocol==="https:"){let n=await this.fetchWithTimeout(r);if(!n.ok)throw new M("UserInfrastructureError",`Failed to download APK from ${e} (status ${n.status})`);let o=await n.arrayBuffer(),i=Buffer.from(o),a=await this.writeBufferToTempFile(i,r.pathname);return {localPath:a,cleanup:()=>{try{Sn.unlinkSync(a);}catch(s){this.logger.warn({err:s,path:a},"Failed to remove temporary APK file");}}}}throw new M("UserConfigurationError",`Unsupported URI scheme for APK installation: ${r.protocol}`)}catch(r){if(r instanceof TypeError){let n=fr__default.resolve(e);return this.assertFileExists(n),{localPath:n,cleanup:()=>{}}}throw r}}assertFileExists(e){try{Sn.accessSync(e);}catch{throw new M("UserConfigurationError",`APK not found at path: ${e}`)}}async fetchWithTimeout(e){let r=AbortSignal.timeout(9e4);return await fetch(e,{signal:r})}async writeBufferToTempFile(e,r){let n=fr__default.extname(r)||".apk",o=fr__default.join(tmpdir(),`momentic-apk-${randomUUID()}${n}`);return Sn.writeFileSync(o,e),o}};async function Cte({command:t,logger:e,generator:r,aiSettings:n,getEmulatorDomState:o,getScreenshotBase64:i,abortSignal:a}){let s=ae();if(!t.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(t.schema){let u=Vm(t.schema);if(u)throw new M("UserConfigurationError",u)}let l="",c="";return await s.startAsyncSpan("EMULATOR_READ_STATE",async()=>{l=await o(),c=await i();},{name:"Get emulator state"}),await s.startAsyncSpan("AI_EXTRACTION_CALL",async u=>{try{let d=await r.getAndroidTextExtraction({goal:t.goal,emulatorState:l,returnSchema:t.schema,screenshot:`data:image/png;base64,${c}`},{disableCache:!!t.disableCache,abortSignal:a,loggerTags:De(e),agentConfigVersion:n.agentConfig?.["android-text-extraction"]});if(u.result=d,LC({tracer:s,span:u,screenshot:c,emulatorState:l,logger:e}),d.result==="NOT_FOUND")return {success:!1,message:"No relevant data found for extraction goal on this page"};if(d.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",d.thoughts);return {success:!0,output:d.result,message:d.thoughts}}catch(d){let m=W(d);throw m.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step instead."):m.includes("AIProviderError")&&m.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:d}}):d}})}var JA=class extends Cr{async dragNative(e,r,n){let{left:o,top:i,width:a,height:s}=this.getBoundsFromNativeCache(e),{left:l,top:c,width:u,height:d}=this.getBoundsFromNativeCache(r),m=o+a/2,p=i+s/2,f=l+u/2,h=c+d/2,g=n?.hoverDuration??500,y=n?.dragDuration??1e3;await this.driver.executeInNativeContext(this.logger,async S=>{await S.performActions([{type:"pointer",id:"finger1",parameters:{pointerType:"touch"},actions:[{type:"pointerMove",duration:0,x:m,y:p},{type:"pointerDown",button:0},{type:"pause",duration:g},{type:"pointerMove",duration:y,x:f,y:h},{type:"pointerUp",button:0}]}]),await S.releaseActions();},{operationName:"dragAndDrop"});}async dragWebview(e,r,n){let{controller:o}=e;if(e.controller!==r.controller)throw new M("UserConfigurationError","Cannot drag and drop between different webviews");let i=n?.dragDuration??1e3,a=n?.hoverDuration??1e3,s;n?.dragDuration&&(s=Math.max(1,Math.floor(i/200))),await o.browser.dragAndDrop(e.browserTarget,r.browserTarget,{hoverDurationMs:a,steps:s,dragDurationMs:i});}async executeDragAndDrop({command:e}){let r=ae();if(e.fromTarget.type!=="description"||e.toTarget.type!=="description")throw new M("UserConfigurationError","Drag and drop only supports description targets for now");let n=e.fromTarget.description,{result:o,thoughts:i}=await this.wrapTargetingAction({command:e,tracer:r,description:n,cacheKey:"cache",targetName:"fromTarget",action:async c=>c}),a=e.toTarget.description,{result:s,thoughts:l}=await this.wrapTargetingAction({command:e,tracer:r,description:a,cacheKey:"cache",targetName:"toTarget",action:async c=>c});if(o.type!==s.type)throw new M("UserConfigurationError",`Drag and drop targets must be in the same context (both native or both webview). Found: From=${o.type}, To=${s.type}`);return await r.startAsyncSpan("EMULATOR_INTERACTION",async c=>{o.type==="NATIVE"&&s.type==="NATIVE"?await this.dragNative(o,s,{hoverDuration:e.hoverDuration,dragDuration:e.dragDuration}):o.type==="WEBVIEW"&&s.type==="WEBVIEW"&&(c.withinWebview=true,await this.dragWebview(o,s,{hoverDuration:e.hoverDuration,dragDuration:e.dragDuration}));},{name:"Drag and drop"}),{success:true,message:`${i}
|
|
5863
|
+
`));return}}let d=Array.from(e.childNodes??[]);for(let m of d){let p=m.nodeType;if(p===3){let f=m.nodeValue;f&&f.trim().length>0&&r.appendChild(n.createTextNode(f));continue}if(p===1){let f=m;if(!Lze(f,s?.viewportBounds))continue;let h=n.createElement(ote(f.tagName));ite(t,f,h),r.appendChild(h);}}}function Oze(t,e,r,n){let o=t.parseFromString("<hierarchy/>","text/xml"),i=new Map,a={prunedDocument:o,idToElement:r,prunedIdToElement:i,idCounter:{value:0},opts:n},s=o.documentElement;ite(a,e,s);let l=new XMLSerializer().serializeToString(o);return {prunedDocument:o,prunedIdToElement:i,xml:l}}async function ate(t,e,r){let n=new DOMParser,o=n.parseFromString(t,"text/xml"),i=new Map,a=o.documentElement;if(!a)throw new M("InternalWebAgentError","No root element found in XML");if(a.tagName!=="hierarchy")throw new M("InternalWebAgentError","No hierarchy element found in XML");let{prunedDocument:s,prunedIdToElement:l,xml:c}=Oze(n,a,i,r),u=c;try{u=await Eze.format(c,{parser:"xml",plugins:[Tze],printWidth:120,tabWidth:1,singleAttributePerLine:!1});}catch(d){e.warn({err:d},"Failed to format XML");}return {xml:u,originalXml:t,document:o,idToElement:i,prunedDocument:s,prunedIdToElement:l}}function Dze(t){let e=[],r=t;for(;r;){let n=r.tagName,o=r.parentElement,i=1;if(o){let a=Array.from(o.children).filter(s=>s.tagName===n);for(let s=0;s<a.length;s++)if(a[s]===r){i=s+1;break}}e.unshift(`${n}[${i}]`),r=o;}return `/${e.join("/")}`}function WA(t,e){let r=t.idToElement.get(e);if(r)return Dze(r)}function tk(t,e){let r=t.idToElement.get(e);if(!r)return;let n=r.cloneNode(true);for(let o of Array.from(n.children)){let i=o;for(let a of Array.from(i.children))i.removeChild(a);}return n.outerHTML}function Tl(t){if(!t.hasAttribute("bounds"))return;let e=t.getAttribute("bounds");if(!e)return;let r=e.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/);if(r){let n=parseInt(r[1],10),o=parseInt(r[2],10),i=parseInt(r[3],10),a=parseInt(r[4],10);if(Number.isFinite(n)&&Number.isFinite(o)&&Number.isFinite(i)&&Number.isFinite(a))return [n,o,i,a]}}function Lze(t,e){if(!e)return true;let r=Tl(t);if(!r||r.length<4)return true;let n=r[0],o=r[1],i=r[2],a=r[3];return !(i<=e.left||n>=e.right||a<=e.top||o>=e.bottom)}function ste(t,e){if(t&&!(!e||e.length===0))return Object.fromEntries(e.map(r=>[r,t.getAttribute(r)]).filter(([,r])=>r!==null))}function cte({requirements:t,element:e}){let r;if((t?.positionSpecificity||t?.shapeSpecificity)&&(r=Tl(e),!r))throw new M("ActionFailureError","Element to cache has no bounds or unexpected bounds format");return {requiredText:t?.textRequired&&kp(e)||void 0,requiredAttributes:ste(e,t?.attributesRequired),requiredBounds:t?.boundsRequired,position:t?.positionSpecificity?{x1:r[0],y1:r[1],x2:r[2],y2:r[3],tolerance:t?.positionSpecificity}:void 0,shape:t?.shapeSpecificity?{width:r[2]-r[0],height:r[3]-r[1],tolerance:t?.shapeSpecificity}:void 0}}function dte({aiResponse:t,description:e,emulatorState:r,memory:n,useMemory:o}){let i=r.graph.idToElement.get(t.id);if(!i)throw new M("InternalWebAgentError",`Could not find node with id: ${t.id}`);let a=Tl(i);if(!a)throw new M("InternalWebAgentError",`Node ${t.id} has no bounding box: ${i.outerHTML}`);let s=WA(r.graph,t.id)??"",l=tk(r.graph,t.id)??"",c=cte({requirements:t.requirements,element:i}),u=[];t.additionalElements&&(u=t.additionalElements.map(({id:m,requirements:p})=>{let f=r.graph.idToElement.get(m);if(!f)return;let h=WA(r.graph,m);return h?{xPath:h,requirements:cte({requirements:p,element:f})}:void 0}).filter(m=>!!m));let d;if(Uy(i)&&t.inWebview!==false?d={type:"WEBVIEW",resolvedDescription:e,xPath:s}:d={type:"NATIVE",bounds:a,resolvedDescription:e,xPath:s,elementOnlySerializedXml:l,requirements:c,requiredRelatedElements:u},o)if(t.updatedMemory){let m={type:"GCS_TRACES",traces:t.updatedMemory};d.memory=m;}else n&&(d.memory=n);return {target:d,resolvedNode:i}}function mte(t){return t?.type==="WEBVIEW"?t.browserCache?.memory:void 0}function Nze(t,e){let r=e.x2-e.x1,n=(e.x1+e.x2)/2,o=(t[0]+t[2])/2;if(!ws(e.tolerance,n,o,Math.min(1,r)))return false;let i=e.y2-e.y1,a=(e.y1+e.y2)/2,s=(t[1]+t[3])/2;return ws(e.tolerance,a,s,Math.min(1,i))}function kze(t,e){return ws(e.tolerance,e.width,t[2]-t[0],Math.min(1,e.width))?ws(e.tolerance,e.height,t[3]-t[1],Math.min(1,e.height)):false}var ute=(t,e,r)=>{if(!e)return;let{requiredAttributes:n,requiredText:o,requiredBounds:i,position:a,shape:s}=e;if(o!==void 0&&o.length>0){let l=kp(t);if(l!==o)throw new Pe(`Resolved element text mismatch: expected ${o}, got ${l}`)}if(n)for(let[l,c]of Object.entries(n)){let u=t.getAttribute(l)??void 0;if(u!==c)throw new Pe(`Attribute ${l} mismatch: expected ${c}, got ${u}`)}if(i&&r&&!r.targetBounds.every((c,u)=>c===r.newElementBounds[u]))throw new Pe(`Bounds changed from [${r.targetBounds.join(",")} ] to [${r.newElementBounds.join(",")} ]`);if(a&&r&&!Nze(r.newElementBounds,a))throw new Pe(`Position mismatch: expected ${JSON.stringify(a)}, got ${JSON.stringify(r.newElementBounds)}`);if(s&&r&&!kze(r.newElementBounds,s))throw new Pe(`Shape mismatch: expected ${JSON.stringify(s)}, got ${JSON.stringify(r.newElementBounds)}`)};async function yf(t){let{target:e,domState:r}=t,{graph:n}=r,{document:o}=n,i=ae();if(e.type==="WEBVIEW")return Fze(e,t);if(!e.xPath)throw new M("ActionFailureError","Native element cache has no XPath");let a=lte.evaluateXPathToFirstNode(e.xPath,o,null,null);if(!a)throw new Pe(`Could not resolve cached target via XPath: ${e.xPath}`);if(e.requiredRelatedElements){let m=e.requiredRelatedElements;i.startSection("Validate related elements are similar enough to past runs",()=>{for(let p of m){let f=lte.evaluateXPathToFirstNode(p.xPath,o);if(!f)throw new Pe(`Required related element not found for XPath: ${p.xPath}`);ute(f,p.requirements);}});}let s=Tl(a);if(!s)throw new Pe("Resolved native element has no bounding box");if(!e.bounds)throw new Pe("Native element cache has no bounds");ute(a,e.requirements,{targetBounds:e.bounds,newElementBounds:s});let l;for(let[m,p]of n.idToElement.entries())if(p===a){l=m;break}let c=e.elementOnlySerializedXml,u=e.xPath;return l!==void 0&&(c=tk(n,l)??c,u=WA(n,l)??u),{resolvedTarget:{...e,resolvedNode:a,bounds:s,elementOnlySerializedXml:c,xPath:u}}}async function Fze(t,e){let{stateManager:r,logger:n,signal:o}=e,i=ae(),a=await r.getActiveWebview();if(!a||!a.browserController)throw n.error({webview:a?{...a,browserController:!!a.browserController}:void 0},"resolveTargetCacheInWebView: No browser controller attached"),new Pe("No browser controller is attached to the requested webview");let s=a.browserController;if(!t.browserCache)throw n.error({target:t},"resolveTargetCacheInWebView: No browser target available on cache"),new Pe("No browser target available on cache");let l=t.browserCache,{finalTarget:c}=await i.startAsyncSection("Resolve target in webview",()=>s.resolveCachedTargetForAction({cache:l,options:{resolveTargetOptions:{logger:n,signal:o,skipWaitForPageLoad:true,skipSavingVisualAttributes:true}},logger:n}));return {resolvedTarget:{...t,controller:a.browserController,browserTarget:c}}}function Pd(t){let{command:e,cacheKey:r="cache",targetName:n="target",updatedCache:o}=t;Cm(e)&&(e[r]={...e[r],[n]:cm.parse(o)},t.updatedWithAI&&(e[r].updatedAt=new Date,e[r].updatedAtLoggerTags=De(t.logger)));}function Yc(t){if(t.type==="WEBVIEW")return {type:"WEBVIEW",resolvedDescription:t.resolvedDescription,xPath:t.xPath,browserCache:t.browserCache,memory:t.memory};let{resolvedNode:e,...r}=t;return {...r}}var Yo=.15,Uze=500,Cr=class{driver;generator;stateManager;logger;fixtures;aborter;orgId;aiSettings;options;constructor(e){this.stateManager=e.stateManager,this.generator=e.generator,this.driver=e.driver,this.logger=e.logger,this.fixtures=e.fixtures,this.aborter=e.aborter,this.orgId=e.orgId,this.aiSettings=e.aiSettings,this.options=e.options;}shouldUseMemoryForCommand(e){return this.aiSettings?.useMemory&&!e?.disableCache}async findElement({description:e,tracer:r,skipFetchingFullWebviewContent:n=false,removeWebviewContent:o=false,useMemory:i=false,memory:a,webviewMemory:s,metadata:l,cacheBustReason:c,knownState:u}){let d=this.logger.child({...l}),m=u??await r.startAsyncSection("Get emulator state",async()=>{let S=await this.stateManager.getCurrentScreenshotPngString();return {emulatorState:await this.stateManager.getDomState({skipFetchingFullWebviewContent:n,removeWebviewContent:o}),screenshot:S}}),p;try{p=await r.startAsyncSpan("AI_LOCATOR_CALL",async S=>{c&&(S.attributes.cacheBustReason=c);let E=await this.generator.getAndroidElementLocation({description:e,screenXml:m.emulatorState.graph.xml,screenshot:m.screenshot,source:l?.source==="SCROLL_TO"?"SCROLL_TO":void 0,memory:i?a:void 0},{logger:d,loggerTags:De(d),abortSignal:this.aborter.controller?.signal,useMemory:i,agentConfigVersion:this.aiSettings.agentConfig?.["android-locator"]});return S.result=E,E});}catch(S){throw this.throwIfAborted(),d.error({err:S},"Failed to locate element"),new M("InternalWebAgentError",`Failed to locate element: ${S instanceof Error?S.message:S}`,{errOptions:{cause:S}})}if(p.id===-1){let S=p.updatedMemory?{type:"GCS_TRACES",traces:p.updatedMemory}:void 0;return {success:false,thoughts:p.thoughts??"No matching element found",updatedLocatorMemory:S}}let{target:f,resolvedNode:h}=dte({aiResponse:p,description:e,emulatorState:m.emulatorState,memory:a,useMemory:i});if(f.type==="NATIVE")return r.addSpan({type:"TARGET_RESOLUTION",startTime:Date.now(),endTime:Date.now(),result:{serializedElement:f.elementOnlySerializedXml??"Unknown element"},attributes:{},subSpans:[]}),{success:true,resolvedTarget:{...f,resolvedNode:h},thoughts:p.thoughts};let{browserLocateResult:g,browserController:y}=await r.startWebviewTrace(async()=>{let S=await this.stateManager.getActiveWebview();if(!S||!S.browserController)throw new M("InternalWebAgentError","No browser controller is attached to the requested webview");return {browserLocateResult:await S.browserController.locateElement({description:e,disableCache:false,useMemory:i,memory:i?s:void 0,logger:this.logger,skipWait:true,skipSavingVisualAttributes:true}),browserController:S.browserController}});return r.addSpan({type:"TARGET_RESOLUTION",startTime:Date.now(),endTime:Date.now(),result:{serializedElement:g.target.nodeOnlySerializedHtml??"Unknown HTML element in webview"},attributes:{},subSpans:[]}),{success:true,resolvedTarget:{...f,controller:y,browserTarget:{...g.resolution,serverSideBoundingBox:await g.resolution.locator.boundingBox({timeout:5e3})},browserCache:g.target},thoughts:g.thoughts}}async targetingActionWithAILocator(e){let{action:r,command:n,description:o,tracer:i,cacheKey:a,targetName:s,cache:l,skipFetchingFullWebviewContent:c,removeWebviewContent:u,metadata:d,cacheBustReason:m}=e,p=await this.findElement({description:o,tracer:i,skipFetchingFullWebviewContent:c,removeWebviewContent:u,useMemory:this.shouldUseMemoryForCommand(n),memory:l?.memory,webviewMemory:mte(l),metadata:d,cacheBustReason:m});if(!p.success){if(p.updatedLocatorMemory&&l){let y={...l,memory:p.updatedLocatorMemory};Pd({command:n,cacheKey:a,targetName:s,updatedCache:y,updatedWithAI:true,logger:this.logger});}throw new M("NoMatchingElementError",p.thoughts??"No matching element found")}let f=p.thoughts,{result:h,resolvedTarget:g}=await this.executeActionWithWebviewReconstructRetry({action:r,resolvedTarget:p.resolvedTarget,reason:"webview target closed during AI-located action"});return Pd({command:n,cacheKey:a,targetName:s,updatedCache:Yc(g),updatedWithAI:true,logger:this.logger}),{result:h,thoughts:f}}async wrapTargetingAction(e){let{action:r,description:n,command:o,cacheKey:i="cache",targetName:a="target",cacheIsInvalidAfterResolution:s,tracer:l,skipFetchingFullWebviewContent:c=false,removeWebviewContent:u=false}=e,d,m={commandId:o.id};if(i==="cache"&&"cache"in o&&o.cache){let E=o.cache;a==="target"&&"target"in E?d=E.target:a==="fromTarget"&&"fromTarget"in E?d=E.fromTarget:a==="toTarget"&&"toTarget"in E&&(d=E.toTarget);}let p=false,f,h=cloneDeep(d);if(o.disableCache&&(this.logger.debug({command:o},"Cache explicitly disabled for command"),p=true,f="Cache explicitly disabled",h=void 0),s&&(p=true,f=f??"Cache invalidated after resolution",h=void 0),h&&!Dc(h?.resolvedDescription??"",n)&&(this.logger.info({description:n,cacheDescription:h?.resolvedDescription},"Cache description mismatch, clearing it automatically"),p=true,f="Description mismatch",h=void 0),!h)return this.logger.info({description:n,cacheBustedBeforeAction:p},"Prompting AI for a new element location"),this.targetingActionWithAILocator({action:r,command:o,description:n,tracer:l,cacheKey:i,targetName:a,cache:d,skipFetchingFullWebviewContent:c,removeWebviewContent:u,metadata:m,cacheBustReason:f});let g=h.type==="NATIVE"?!!h.requirements:!!h.browserCache?.requirements,y=h.type==="NATIVE"?!!h.requiredRelatedElements?.length:!!h.browserCache?.additionalElements?.length,S;try{this.options?.emulator?.waitForStability&&await this.stateManager.waitForPageSourceStability({timeoutMs:3e3,signal:this.aborter.controller?.signal,reason:"Waiting for stability before cache resolution"});let{resolvedTarget:E}=await l.startAsyncSpan("CACHE_RESOLUTION",async _=>{let L=Date.now(),I;for(;Date.now()-L<3e3;){S=await this.stateManager.getDomState({skipFetchingFullWebviewContent:h?.type==="NATIVE"});let R;try{R=(await yf({target:h,domState:S,stateManager:this.stateManager,logger:this.logger})).resolvedTarget;}catch(V){if(I=V,V instanceof Pe){this.logger.warn({err:V},"Failed to resolve target cache, retrying"),await ms(100,this.aborter.controller?.signal);continue}throw this.logger.error({err:V},"Failed to resolve target cache"),V}let k=Yc(R),D=diff(h,k);return D&&Object.keys(D).length>0&&this.logger.info({cacheDiffs:D},"Successfully resolved target with cache"),_.attributes.serializedElement=R.type==="WEBVIEW"?R.browserCache?.nodeOnlySerializedHtml??"Unknown HTML element in webview":R.elementOnlySerializedXml??"Unknown element",{resolvedTarget:R,updatedCache:k}}throw I}),{result:v,resolvedTarget:w}=await this.executeActionWithWebviewReconstructRetry({action:r,resolvedTarget:E,reason:"webview target closed during cached action"});return Pd({command:o,cacheKey:i,targetName:a,updatedCache:Yc(w),updatedWithAI:!1,logger:this.logger}),Ge.increment("cache_target_resolution_v2",1,["outcome:hit",`platform:mobile-${h.type.toLowerCase()}`,`hasRequirements:${g}`,`hasAdditionalElements:${y}`,`orgId:${this.orgId}`,"cliVersion:1.0.2"]),{result:v,thoughts:"Successfully executed preset action with cache"}}catch(E){if(this.throwIfAborted(),E instanceof M&&E.reason!=="InternalWebAgentError")throw this.logger.error({err:E},"Failed to execute action with target cache (fatal)"),E;return Ge.increment("cache_target_resolution_v2",1,["outcome:miss",`platform:mobile-${h.type.toLowerCase()}`,`hasRequirements:${g}`,`hasAdditionalElements:${y}`,`orgId:${this.orgId}`,"cliVersion:1.0.2"]),this.logger.warn({err:E},"Failed to execute action with target cache, retrying with AI"),this.targetingActionWithAILocator({action:r,command:o,description:n,tracer:l,cacheKey:i,targetName:a,cache:h,skipFetchingFullWebviewContent:c,removeWebviewContent:u,metadata:m})}}async executeActionWithWebviewReconstructRetry(e){let{action:r,resolvedTarget:n,reason:o}=e;try{return {result:await r(n),resolvedTarget:n}}catch(i){if(this.throwIfAborted(),n.type!=="WEBVIEW"||!this.errorLooksLikeClosedWebviewTarget(i)||(this.logger.warn({err:i},"Webview target appears closed or crashed during action, reconstructing browser and retrying once"),!(await this.stateManager.reconstructActiveWebviewBrowser(o))?.browserController))throw i;let s=await this.stateManager.getDomState({skipFetchingFullWebviewContent:true}),{resolvedTarget:l}=await yf({target:Yc(n),domState:s,stateManager:this.stateManager,logger:this.logger,signal:this.abortSignal});return {result:await r(l),resolvedTarget:l}}}errorLooksLikeClosedWebviewTarget(e){let r=W(e);return ["Target closed","Target crashed","Page crashed","Target page, context or browser has been closed","Session closed. Most likely the page has been closed"].some(n=>r.includes(n))}constructPerformerParams(){return {stateManager:this.stateManager,generator:this.generator,driver:this.driver,logger:this.logger,fixtures:this.fixtures,aborter:this.aborter,orgId:this.orgId,aiSettings:this.aiSettings,options:this.options}}getBoundsFromNativeCache(e){if(!e.bounds)throw new M("ActionFailureError","Native element cache has no bounds");let[r,n,o,i]=e.bounds;if(r===void 0||n===void 0||o===void 0||i===void 0)throw new M("ActionFailureError",`Native element cache has incomplete bounds: [${e.bounds.join(", ")}]`);return {left:r,top:n,width:o-r,height:i-n}}calculateSwipeCoordinates({containerBounds:e,direction:r,desiredDelta:n}){let o=e.left+e.width/2,i=e.top+e.height/2;if(r==="up"||r==="down"){let a=e.height*Yo,s=e.top+a,l=e.top+e.height-a,c=l-s,u=Math.min(Math.abs(n),c),d=c-u,m=r==="down"?l-d/2:s+d/2;return {startX:o,startY:m,actualDelta:u}}else {let a=e.width*Yo,s=e.left+a,l=e.left+e.width-a,c=l-s,u=Math.min(Math.abs(n),c),d=c-u;return {startX:r==="right"?l-d/2:s+d/2,startY:i,actualDelta:u}}}invertDirection(e){if(e==="up")return "down";if(e==="down")return "up";if(e==="left")return "right";if(e==="right")return "left";throw new Error(`Unreachable code: ${e}`)}async performRawSwipe({startX:e,startY:r,deltaPixels:n,direction:o,durationMs:i=300}){let a=Math.abs(n),s=e,l=r;o==="up"||o==="down"?l=o==="up"?r-a:r+a:s=o==="left"?e-a:e+a,await this.driver.executeInNativeContext(this.logger,async c=>{await c.performActions([{type:"pointer",id:"finger1",parameters:{pointerType:"touch"},actions:[{type:"pointerMove",duration:0,x:e,y:r},{type:"pointerDown",button:0},{type:"pause",duration:250},{type:"pointerMove",duration:i,x:s,y:l},{type:"pause",duration:500},{type:"pointerUp",button:0}]}]),await c.releaseActions();},{operationName:"performRawSwipe"}),await pe(Uze,this.abortSignal);}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}get abortSignal(){return this.aborter.controller?.signal}get aiSettingsCopy(){return cloneDeep(this.aiSettings)}get optionsCopy(){return cloneDeep(this.options)}};function Xc(t){if(t.type==="WEBVIEW"){let a=t.browserTarget.serverSideBoundingBox;return a?{left:a.x,top:a.y,width:a.width,height:a.height}:void 0}let{bounds:e}=t;if(!e)return;let[r,n,o,i]=e;if(!(r===void 0||n===void 0||o===void 0||i===void 0))return {left:r,top:n,width:o-r,height:i-n}}function fte(t){return "iterations"in t}function Vze(t){let e={relativePosition:t.relativePosition?er(t.relativePosition):void 0};if(t.iterations!==void 0&&(!Number.isInteger(t.iterations)||t.iterations<1))throw new Error("UserConfigurationError: iterations must be a positive integer");if(t.tapDelayMs!==void 0&&(!Number.isInteger(t.tapDelayMs)||t.tapDelayMs<0))throw new Error("UserConfigurationError: tapDelayMs must be >= 0");if(t.iterations&&t.iterations>1&&t.longPress)throw new Error("UserConfigurationError: Cannot specify both more than one tap iteration and long press at the same time");if(t.tapDelayMs!==void 0&&(!t.iterations||t.iterations<2))throw new Error("UserConfigurationError: tapDelayMs requires iterations >= 2");if(t.longPress){if(t.tapDelayMs!==void 0)throw new Error("UserConfigurationError: tapDelayMs cannot be used with longPress");return {...e,longPress:true,longPressDurationMs:t.longPressDurationMs}}return t.iterations!==void 0?{...e,iterations:t.iterations,tapDelayMs:t.tapDelayMs}:e}var Sf=class extends Cr{async tapOnNativeCoordinates(e){let r=e.x,n=e.y;if(this.logger.info({x:r,y:n},"Tap at coordinates"),"longPress"in e&&e.longPress)return await this.driver.executeInNativeContext(this.logger,o=>o.executeScript("mobile: longClickGesture",[{x:r,y:n,duration:e.longPressDurationMs??2e3}]),{operationName:"longPress"});if(fte(e)){let o=e.tapDelayMs??100;for(let i=0;i<e.iterations;i++)await this.driver.executeInNativeContext(this.logger,a=>a.tap({x:r,y:n}),{operationName:"tap"}),i<e.iterations-1&&await new Promise(a=>setTimeout(a,o));return}await this.driver.executeInNativeContext(this.logger,o=>o.tap({x:r,y:n}),{operationName:"tap"});}async tapOnNativeTarget(e,r){let[n,o,i,a]=e.bounds,s=i-n,l=a-o,c=r?.relativePosition?.x??s/2,u=r?.relativePosition?.y??l/2;c=Math.max(0,Math.min(c,s)),u=Math.max(0,Math.min(u,l));let d=n+c,m=o+u;return await this.tapOnNativeCoordinates({x:d,y:m,...r}),{x:d,y:m}}async tapOnWebviewTarget(e,r){let{controller:n}=e,o,i=1;return r&&fte(r)?(o=r.tapDelayMs,i=r.iterations):r&&"longPress"in r&&(o=r.longPressDurationMs),(await n.browser.click(e.browserTarget,{createIsolatedFolder:()=>{let s=Math.random().toString(36).substring(4),l=fr__default.join(tmpdir(),"momentic","downloads"),c=fr__default.join(l,this.orgId,s);return mkdirSync(c,{recursive:true}),c}},{delayMs:o,relativePosition:r?.relativePosition,iterations:i})).coordinates}async tapOnTarget({target:e,options:r}){return await ae().startAsyncSpan("EMULATOR_INTERACTION",async o=>{if(o.attributes.options=r,"type"in e&&e.type==="NATIVE"){let i=await this.tapOnNativeTarget(e,r);o.attributes.point=i,o.targetBounds=Xc(e);}else {o.withinWebview=true;let i=await this.tapOnWebviewTarget(e,r);o.attributes.point=i,o.targetBounds=Xc(e);}},{name:"Tap on target"})}async executeTap({command:e}){let r=ae(),n=Vze(e);if(e.target.type==="coordinates"||e.target.type==="absolute_percent"){let a=await this.driver.executeInNativeContext(this.logger,c=>c.getWindowSize(),{operationName:"getTapWindowSize"}),s,l;return e.target.type==="coordinates"?(s=e.target.xPercent*a.width,l=e.target.yPercent*a.height):(s=e.target.x/100*a.width,l=e.target.y/100*a.height),await r.startAsyncSpan("EMULATOR_INTERACTION",async c=>{await this.tapOnNativeCoordinates({...n,x:s,y:l}),c.attributes.point={x:s,y:l};},{name:`Tap at coordinates ${s}, ${l}`}),{success:true,message:`Tapped at ${s}, ${l}`}}let o=e.target.description,{thoughts:i}=await this.wrapTargetingAction({command:e,tracer:r,action:a=>this.tapOnTarget({target:a,options:n}),description:o});return {success:true,message:i}}};var Jc=class extends Cr{async doPress({keycode:e,repeat:r=1,keyPressDelayMs:n=0}){await ae().startAsyncSpan("EMULATOR_INTERACTION",async()=>{let i=jze({keycode:e,repeat:r,keyPressDelayMs:n});return this.driver.executeInNativeContext(this.logger,a=>a.execute("mobile: shell",i),{operationName:"pressKey"})},{name:r>1?`Send ${r} key event(s) to emulator`:"Send key events to emulator"});}};function jze({keycode:t,repeat:e,keyPressDelayMs:r}){if(e<=1)return {command:"input",args:["keyevent",`${t}`]};if(r<=0)return {command:"input",args:["keyevent",...Array(e).fill(`${t}`)]};let n=r/1e3;return {command:"sh",args:["-c",Array(e).fill(`input keyevent ${t}`).join(`; sleep ${n}; `)]}}var Id=25,gte=150,bte=67,Wze=123,Gze=100,qze=24,Kze=4,yte=1e3,KA=class extends Cr{async doType(e){let r=ae();if(!e.target){if(e.clearContent)throw new M("UserConfigurationError","Clearing content is only supported when a target is provided to the Type step");return await this.stateManager.waitForPageSourceStability({timeoutMs:2e3,signal:this.aborter.controller?.signal,reason:"Waiting for page to stabilize before typing"}),await this.sendKeys(e),{success:true,message:"Successfully executed type action"}}if(e.target.type!=="description")throw new M("UserConfigurationError","x/y targets are not supported for the Type step");let{thoughts:n}=await this.wrapTargetingAction({command:e,tracer:r,action:async o=>{"type"in o&&o.type==="NATIVE"?await this.doNativeType(e,o):await this.doWebviewType(e,o);},description:e.target.description});return {success:true,message:n}}async doWebviewType(e,r){await ae().startAsyncSpan("EMULATOR_INTERACTION",async o=>{o.withinWebview=true;let i={clearContent:e.clearContent,forceClearContent:e.forceClearContent,delay:e.keyPressDelayMs??Id};o.attributes.options=i;let{controller:a,browserTarget:s}=r;await a.browser.typeIntoTarget(e.text,s,i);},{name:"Typing within web view"});}async doNativeType(e,r){e.clearContent?await this.clearNativeContent(e,r):await this.tapNativeTargetForType(r),await this.stateManager.waitForPageSourceStability({timeoutMs:2e3,signal:this.aborter.controller?.signal,reason:"Waiting for keyboard to appear before typing"}),await this.sendKeys(e);}async tapNativeTargetForType(e,r){let n=ae(),o=new Sf(this.constructPerformerParams());await n.startAsyncSpan("EMULATOR_INTERACTION",async i=>{i.attributes.options=r??{};let a=await o.tapOnNativeTarget(e,r);i.attributes.point=a,i.targetBounds=Xc(e);},{name:"Tap on target"});}async sendKeys(e){let r=ae(),n=e.keyPressDelayMs??Id;await r.startAsyncSection("Waiting for system keyboard to open",async(o,i)=>{let a=Date.now();for(;Date.now()-a<2e3;){this.throwIfAborted();let s=Date.now();if(await this.driver.executeInNativeContext(this.logger,c=>c.isKeyboardShown(),{operationName:"isKeyboardShown"}))return;let l=Date.now()-s;l<100&&await new Promise(c=>setTimeout(c,100-l));}i.attributes.timedOut=true;}),await r.startAsyncSpan("EMULATOR_INTERACTION",async()=>{try{n!==Id&&await this.driver.executeInNativeContext(this.logger,async i=>i.updateSettings({keyInjectionDelay:n}),{operationName:"updateKeyInjectionDelay"});let o=[];for(let i=0;i<e.text.length;i+=gte)o.push(e.text.slice(i,i+gte));for(let i of o)await this.driver.executeInNativeContext(this.logger,async a=>a.keys(i),{operationName:"typeWithCustomKeyDelay",attemptTimeoutMs:FC(n,i),maxAttempts:1});}finally{n!==Id&&await this.driver.executeInNativeContext(this.logger,async o=>o.updateSettings({keyInjectionDelay:Id}),{operationName:"updateKeyInjectionDelay"});}},{name:`Typing with a ${n}ms delay`});}async clearNativeContent(e,r){let n=e.replaceStrategy??"auto";switch(this.logger.info({strategy:n,command:{targetDescription:e.target?.type==="description"?e.target.description:e.target?.type,textLength:e.text.length,clearContent:e.clearContent,forceClearContent:e.forceClearContent,replaceStrategy:e.replaceStrategy},target:sa(r)},"Preparing to clear native input content"),n){case "auto":await this.clearNativeContentAutomatically(r);return;case "programmatic":await this.clearContentWithAppium(r,{verify:false});return;case "long-press":await this.clearContentWithSelectAll(r);return;case "backspace":await this.clearContentWithBackspace(r);return}}async clearNativeContentAutomatically(e){let r=Ste(e),n=Yze(e);if(r===""&&n){this.logger.info({target:sa(e)},"Skipping native clear because target text is already empty");return}n&&await this.clearContentWithAppium(e,{verify:true})||await this.clearContentWithSelectAll(e)||await this.clearContentWithBackspace(e);}async clearContentWithSelectAll(e){await this.tapNativeTargetForType(e,{longPress:true});let r=ae();try{return await r.startAsyncSection("Clearing any content from the focused field",()=>this.clearContentHelper()),!0}catch(n){return this.logger.warn({err:n},"Failed to find select all button, continuing..."),false}}async clearContentWithAppium(e,r){let n=e.xPath,o=ok(e);if(!n||o)return this.logger.info({rejectionReason:n?o:"missing_xpath",target:sa(e)},"Skipping Appium clear for native target"),false;let i=ae();try{await i.startAsyncSection("Clearing content programmatically",()=>this.driver.executeInNativeContext(this.logger,async s=>{await(await s.$(n)).clearValue();},{operationName:"clearNativeTextInput",maxAttempts:1}));let a=r.verify?await this.waitForNativeTargetTextToClear(n):!0;return this.logger.info({target:sa(e),verified:r.verify,cleared:a},"Finished Appium clear for native target"),a?(await this.focusNativeTargetAfterClear(e),!0):!1}catch(a){return this.logger.warn({err:a},"Failed to clear native input with Appium, falling back..."),false}}async focusNativeTargetAfterClear(e){let r=e.xPath;if(!r){await this.tapNativeTargetForType(e);return}let n=await this.resolveNativeTargetFocusAfterClear(r);if(n.resolved&&n.focused){this.logger.info({target:sa(e)},"Target already focused after clear, skipping focus tap");return}if(n.resolved){let i=n.bounds;this.logger.info({target:sa(e),bounds:i},"Tapping native target to focus after clear"),await this.tapNativeTargetForType(i?{...e,bounds:i}:e);return}if(await this.driver.executeInNativeContext(this.logger,i=>i.isKeyboardShown(),{operationName:"isKeyboardShown"})){this.logger.info({target:sa(e)},"Target xPath no longer resolves but keyboard is open, skipping focus tap");return}this.logger.info({target:sa(e)},"Target xPath no longer resolves and keyboard is closed, tapping cached bounds"),await this.tapNativeTargetForType(e);}async resolveNativeTargetFocusAfterClear(e){try{let r=await this.stateManager.getDomState({skipFetchingFullWebviewContent:!0,removeWebviewContent:!0}),n=lte.evaluateXPathToFirstNode(e,r.graph.document,null,null);return n instanceof Element?{resolved:!0,focused:n.getAttribute("focused")==="true",bounds:Tl(n)}:{resolved:!1}}catch(r){return this.logger.debug({err:r},"Failed to resolve native target focus state after clear"),{resolved:false}}}async clearContentWithBackspace(e){let r=await this.readNativeTargetText(e.xPath);if(r===void 0)return this.logger.debug({target:sa(e)},"Skipping native backspace clear because the target text is not readable"),false;if(r==="")return true;await this.tapNativeTargetForType(e);let o=await ae().startAsyncSection("Clearing content with bounded backspaces",async(i,a)=>{let s=r.length,l=1,c=0,u=0;for(let d=0;d<qze;d++){let m=Gze-c;if(m<=0)break;let f=d===0||u>0?1:Math.max(1,Math.min(Math.ceil(s/2),Math.floor(s/l),m));this.logger.info({target:sa(e),round:d,lengthBefore:s,keysToIssue:f,maxUnitsPerKey:l},"Issuing bounded backspaces"),await this.driver.executeInNativeContext(this.logger,y=>y.execute("mobile: shell",{command:"sh",args:["-c",`input keyevent ${Wze}; i=0; while [ $i -lt ${f} ]; do input keyevent ${bte}; i=$((i+1)); done`]}),{operationName:"backspaceClearNativeTextInput",maxAttempts:1}),c+=f;let h=await this.readRemainingNativeTextLength(e.xPath);if(h===void 0)return false;let g=s-h;if(this.logger.info({target:sa(e),round:d,lengthAfter:h,deleted:g,totalKeys:c},"Bounded backspace iteration result"),h===0)return a.attributes.totalKeys=c,true;if(g<=0){if(u+=1,u>=2)return false;s=h;continue}u=0,l=Math.max(l,Math.ceil(g/f)),s=h;}return a.attributes.totalKeys=c,false});return this.logger.info({target:sa(e),cleared:o},"Finished native backspace clear"),o}async readNativeTargetText(e){let r=await this.readNativeTargetTextResult(e);if(r.status==="readable")return r.text}async readRemainingNativeTextLength(e){for(let r=0;r<Kze;r++){let n=await this.readNativeTargetTextResult(e);if(n.status==="readable")return n.text?.length??0}}async readNativeTargetTextResult(e){if(!e)return {status:"unreadable"};try{return {status:"readable",text:await ee(this.readNativeTargetTextFromXml(e),{milliseconds:yte,signal:this.aborter.controller?.signal,message:`readNativeTextInputValueFromXml timed out after ${yte}ms`})}}catch(r){return this.logger.debug({err:r},"Failed to read native input text from XML for clear verification"),{status:"unreadable"}}}async readNativeTargetTextFromXml(e){let r=await this.stateManager.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true}),n=lte.evaluateXPathToFirstNode(e,r.graph.document,null,null);if(!n)throw new Error(`Could not resolve native input via XPath: ${e}`);return Tte({text:n.getAttribute("text"),hint:n.getAttribute("hint"),showingHint:n.getAttribute("showing-hint"),password:n.getAttribute("password")})}async waitForNativeTargetTextToClear(e){return await ae().startAsyncSection("Verifying programmatic clear result",async(n,o)=>{let i=[],a=Date.now(),s=false,l=0;for(;Date.now()-a<2e3;){this.throwIfAborted(),l+=1;let c=await this.readNativeTargetTextResult(e);if(c.status==="unreadable"){i.push({attempt:l,status:"unreadable"});break}if(c.text===void 0||c.text==="")return i.push({attempt:l,status:"cleared"}),o.attributes.observations=i,o.attributes.result="cleared",true;s=true,i.push({attempt:l,status:"non_empty",textLength:c.text.length}),await new Promise(u=>setTimeout(u,100));}return o.attributes.observations=i,s?(o.attributes.result="still_non_empty",false):(o.attributes.result="unverifiable",true)})}async clearContentHelper(){await this.driver.executeInNativeContext(this.logger,async r=>{let n=r.$('//android.widget.LinearLayout[@content-desc="Select all" and @clickable="true"]');await n.waitForExist({timeout:750}),await n.click();},{operationName:"selectAllText",maxAttempts:1}),await new Jc(this.constructPerformerParams()).doPress({keycode:bte});}};function Ste(t){return Tte({text:t.resolvedNode.getAttribute("text"),hint:t.resolvedNode.getAttribute("hint"),showingHint:t.resolvedNode.getAttribute("showing-hint"),password:t.resolvedNode.getAttribute("password")})}function Tte({text:t,hint:e,showingHint:r,password:n}){if(!(t===null||r==="true"||n==="true")&&!(e!==null&&t.trim()!==""&&t.trim()===e.trim()))return t}function Yze(t){return ok(t)===void 0}function ok(t){if(!t.xPath)return "missing_xpath";if(t.resolvedNode.getAttribute("enabled")==="false")return "disabled";let e=t.resolvedNode.tagName.toLowerCase(),r=t.resolvedNode.getAttribute("class")?.toLowerCase();if(e.endsWith("edittext")||r?.endsWith("edittext"))return;let n=t.resolvedNode.getAttribute("input-type");if(!n||n==="0")return "not_text_input"}function sa(t){let e=Ste(t);return {xPath:t.xPath,tagName:t.resolvedNode.tagName,className:t.resolvedNode.getAttribute("class"),resourceId:t.resolvedNode.getAttribute("resource-id"),contentDescription:t.resolvedNode.getAttribute("content-desc"),hint:t.resolvedNode.getAttribute("hint"),inputType:t.resolvedNode.getAttribute("input-type"),enabled:t.resolvedNode.getAttribute("enabled"),focused:t.resolvedNode.getAttribute("focused"),showingHint:t.resolvedNode.getAttribute("showing-hint"),password:t.resolvedNode.getAttribute("password"),readableText:e===void 0?"unreadable":{length:e.length},appiumClearRejectionReason:ok(t)}}var Ete=.8,Xze=C__default.object({navigationBar:C__default.object({visible:C__default.boolean(),x:C__default.number(),y:C__default.number(),width:C__default.number(),height:C__default.number()}),statusBar:C__default.object({visible:C__default.boolean(),x:C__default.number(),y:C__default.number(),width:C__default.number(),height:C__default.number()})});function ik(t,e){t.attributes.scrollableElementType=e.type,t.attributes.scrollableElementDisplay=Ks(e),e.type==="CUSTOM"&&(t.attributes.scrollableElementDescription=e.target.description);}var Tf=class extends Cr{async getHardcodedScrollableElementBounds(e,r){let n;switch(e.type){case "SCREEN":n=this.getContainerBoundsFromViewport(r);break;case "OPEN_APP":try{let o=Xze.parse(await this.driver.executeInNativeContext(this.logger,i=>i.executeScript("mobile: getSystemBars",[]),{operationName:"getSystemBars"}));n=this.getContainerBoundsFromViewport(r),o.navigationBar.visible&&(n.height=Math.max(1,n.height-o.navigationBar.height)),o.statusBar.visible&&(n.top+=o.statusBar.height,n.height=Math.max(1,n.height-o.statusBar.height));}catch(o){this.logger.warn({err:o},"Failed to get system bars, using hardcoded bounds"),n=this.getContainerBoundsFromViewport(r);}break;case "OPEN_WEBVIEW":{let o=await this.stateManager.getActiveWebviewNodes();if(o.length===0&&(await this.stateManager.refreshWebviewsManually("get active webview nodes"),o=await this.stateManager.getActiveWebviewNodes()),o.length===0)throw new Error("No active webviews found");if(o.length>1){let a=o.map(s=>({id:s.id,ele:s.originalElement.outerHTML,bounds:s.bounds}));throw new Error(`Multiple active webviews found. Momentic currently only supports a single active webview at a time. Discovered nodes: ${JSON.stringify(a)}`)}let i=o[0]?.bounds;if(!i)throw new Error("No bounds found for active webview");n=this.getContainerBoundsFromBounds(i);break}default:{throw new Error("If Typescript complains about the line above, you missed a switch case")}}return n}getContainerBoundsFromViewport(e){return {left:e.x,top:e.y,width:Math.max(1,e.width),height:Math.max(1,e.height)}}getContainerBoundsFromBounds(e){let r=e[0],n=e[1],o=e[2],i=e[3],a=o-r,s=i-n;return {left:r,top:n,width:Math.max(1,a),height:Math.max(1,s)}}async executeSwipe(e){let r=ae(),n=Ks(e.scrollableElement);if(e.scrollableElement.type==="CUSTOM_COORDINATES"){let{startX:i,startY:a,deltaPixels:s}=e.scrollableElement;return await r.startAsyncSpan("EMULATOR_INTERACTION",async l=>{ik(l,e.scrollableElement),l.attributes.startX=i,l.attributes.startY=a,l.attributes.deltaPixels=s,l.attributes.direction=e.direction,await this.performRawSwipe({startX:i,startY:a,deltaPixels:s,direction:e.direction,durationMs:e.durationMs});},{name:`Swipe ${e.direction} in ${n}`}),{success:true,message:"Successfully executed swipe action"}}if(e.scrollableElement.type!=="CUSTOM"){let i=await this.driver.executeInNativeContext(this.logger,s=>s.getWindowRect(),{operationName:"getSwipeViewportRect"}),a=await this.getHardcodedScrollableElementBounds(e.scrollableElement,i);return await r.startAsyncSpan("EMULATOR_INTERACTION",async s=>{ik(s,e.scrollableElement),await this.swipeByAbsoluteCoordinates({span:s,direction:e.direction,percent:e.viewportPercent,durationMs:e.durationMs,containerBounds:a,relativePosition:e.relativePosition?er(e.relativePosition):void 0});},{name:`Swipe ${e.direction} in ${n}`}),{success:true,message:"Successfully executed swipe action"}}let{thoughts:o}=await this.wrapTargetingAction({command:e,description:e.scrollableElement.target.description,action:async i=>ae().startAsyncSpan("EMULATOR_INTERACTION",async s=>(ik(s,e.scrollableElement),"type"in i&&i.type==="NATIVE"?this.scrollInNativeContainer({span:s,cmd:e,target:i}):(s.withinWebview=true,this.swipeInWebview({span:s,cmd:e,target:i}))),{name:`Swipe ${e.direction} in ${n}`}),tracer:r});return {success:true,message:o}}async scrollInNativeContainer({span:e,cmd:r,target:n}){if(!n.bounds||n.bounds.length<4)throw new M("ActionFailureError","Native container cache has no bounds");let o=n.bounds,i=o[2]-o[0],a=o[3]-o[1];await this.swipeByAbsoluteCoordinates({span:e,direction:r.direction,percent:r.viewportPercent,durationMs:r.durationMs,containerBounds:{left:o[0],top:o[1],width:Math.max(1,i),height:Math.max(1,a)},relativePosition:r.relativePosition?er(r.relativePosition):void 0});}async swipeInWebview({span:e,cmd:r,target:n}){let{controller:o,browserTarget:i}=n;if(!o.browser.getViewport())throw new Error("Failed to get viewport size from webview");let s=r.direction==="down"||r.direction==="up",l=await i.locator.boundingBox();if(!l)throw new Error("Failed to get bounds for webview container");let c=Math.floor(l.width*Yo),u=Math.floor(l.height*Yo),d=Math.max(1,l.width-c*2),m=Math.max(1,l.height-u*2),p,f;if(r.relativePosition){let y=er(r.relativePosition);p=l.x+y.x,f=l.y+y.y;}else p=l.x+l.width/2,f=l.y+l.height/2;let h={x:p,y:f},g=(s?m:d)*(r.viewportPercent??Ete)*(s?r.direction==="down"?1:-1:r.direction==="right"?1:-1);e.attributes.startPoint=h,e.attributes.scrollPixelAmount=g,await o.browser.mouseDragUsingVisualCoordinates({deltaX:s?0:g,deltaY:s?g:0,steps:10,dragDurationMs:r.durationMs,fromTarget:h});}async swipeByAbsoluteCoordinates({span:e,direction:r,percent:n=Ete,durationMs:o=500,containerBounds:i,relativePosition:a}){e.attributes.containerBounds=i;let s=i.width*Yo,l=i.height*Yo,c,u;if(r==="up"||r==="down"?(c=(i.height-2*l)*n,u=Math.floor(c/(o/1e3))):(c=(i.width-2*s)*n,u=Math.floor(c/(o/1e3))),e.attributes.pixelDelta=c,e.attributes.pixelsPerSecond=u,a){let d=i.left+a.x,m=i.top+a.y;await this.performRawSwipe({startX:d,startY:m,deltaPixels:c,direction:r,durationMs:o});}else {let d=i.width*Yo,m=i.height*Yo,p={left:i.left+d,top:i.top+m,width:Math.max(1,i.width-2*d),height:Math.max(1,i.height-2*m)};await this.driver.executeInNativeContext(this.logger,f=>f.executeScript("mobile: swipeGesture",[{...p,direction:r,percent:n,speed:u}]),{operationName:"swipeGesture"});}}};var vte=20,ak=.9,Jze=2,Ef=.5,sk=.2;var YA=class extends Tf{async executeScrollTo(e){let r=e.target.description,n=e.scrollStepPercent??ak,o=await this.tryUseCachedScrollPosition(e,r);return o||this.searchForElement({cmd:e,description:r,scrollStepPercent:n})}async resolveContainer({scrollableElement:e,containerCache:r,aiMetadata:n}){let o=await this.stateManager.getViewportBounds(),i={x:o.left,y:o.top,width:o.right-o.left,height:o.bottom-o.top};if(e.type==="CUSTOM_COORDINATES")return {bounds:{left:0,top:0,width:i.width,height:i.height},diffThresholdPercent:Ef};if(e.type!=="CUSTOM")return {bounds:await this.getHardcodedScrollableElementBounds(e,i),diffThresholdPercent:Ef};let a=ae(),s=e.target.description;if(r){let d=this.getBoundsFromNativeCache(r);return this.logger.info({bounds:d},"Got container bounds from native cache"),{bounds:d,cache:r,diffThresholdPercent:_p({containerBounds:d,viewport:i,defaultThresholdPercent:Ef})}}let l=await this.findElement({description:s,tracer:a,metadata:n});if(!l.success)throw new M("NoMatchingElementError",l.thoughts??"No matching element found");let{resolvedTarget:c}=l;if(c.type!=="NATIVE")throw new Error(`ActionFailureError: Custom scroll container "${s}" resolved to a webview element. Custom containers must be native elements.`);let u=this.getBoundsFromNativeCache(c);return this.logger.info({bounds:u},"Got container bounds from AI"),{bounds:u,cache:c,diffThresholdPercent:_p({containerBounds:u,viewport:i,defaultThresholdPercent:Ef})}}async tryUseCachedScrollPosition(e,r){let n=e.cache?.target;return n?n.type==="WEBVIEW"?this.tryUseWebviewCache(e,r):n.scrollDetails?this.tryUseNativeScrollCache(e,r,n):null:null}async tryUseWebviewCache(e,r){let n=ae();try{let{thoughts:o}=await this.wrapTargetingAction({command:e,tracer:n,description:r,action:async i=>{if(i.type==="NATIVE")throw new Error("Expected WEBVIEW target but got NATIVE");await this.scrollWebviewTargetIntoView(i);}});return {success:!0,message:o}}catch(o){return this.logger.warn({err:o},"Failed to use webview cache, falling back to search"),null}}async tryUseNativeScrollCache(e,r,n){let o=n.scrollDetails,i=ae(),a=e.scrollStepPercent??ak,s=o.scrollableElement.type==="CUSTOM"?o.scrollableElement.cache:void 0,l=await this.resolveContainer({scrollableElement:e.scrollableElement,containerCache:s,aiMetadata:{commandId:e.id}}),c=l.bounds,u=l.diffThresholdPercent,d=e.scrollableElement.type==="CUSTOM_COORDINATES"?e.scrollableElement:void 0,m=d?Math.abs(d.deltaPixels):this.calculateSwipeCoordinates({containerBounds:c,direction:e.direction,desiredDelta:Cs({containerBounds:c,containerInsetRatio:Yo})*a}).actualDelta,p=await this.stateManager.getLastObservedState();if(p){let v=await this.tryFindElement({cmd:e,description:r,tracer:i,scrollDetails:this.buildScrollDetails(e,0,l.cache),knownState:p,useAIIfCacheFails:false});if(v)return this.logger.info("Element resolved from last observed state without scrolling"),v}else this.logger.debug("Skipping scroll-to preflight because no last observed state is available");let f=Math.abs(o.pixelDelta),h=0,g=m*Jze,y=0;for(;y<f;){this.throwIfAborted();let v=f-y,w=Math.min(v,g),_=await this.scrollByPixelDelta({pixelDelta:w,scrollableElement:e.scrollableElement,containerCache:l.cache,direction:e.direction,scrollStepPercent:a,aiMetadata:{commandId:e.id},useVisualDiff:false});if(_===0)break;y+=_,h+=e.direction==="down"?_:-_;let L=await this.tryFindElement({cmd:e,description:r,tracer:i,scrollDetails:this.buildScrollDetails(e,h,l.cache),useAIIfCacheFails:false});if(L)return this.logger.info({cumulativePixelDelta:h},"Element resolved during cache replay"),L}let S=Math.max(0,Math.min(e.maxScrollAttempts??vte,2)),E=true;for(let v=0;v<S&&E;v++){this.throwIfAborted(),E=await this.scrollByPage({direction:e.direction,containerBounds:c,scrollStepPercent:a,diffThresholdPercent:u,rawCoordinates:d}),E&&(h+=e.direction==="down"?m:-m);let w=await this.tryFindElement({cmd:e,description:r,tracer:i,scrollDetails:this.buildScrollDetails(e,h,l.cache),useAIIfCacheFails:false});if(w)return this.logger.info({attempt:v,cumulativePixelDelta:h},"Element resolved during cache buffer scroll"),w}if(h!==0){let v=e.direction==="down"?"up":"down";this.logger.info({cumulativePixelDelta:h,originalDirection:e.direction,undoDirection:v,scrollableElementType:e.scrollableElement.type},"Cache replay did not resolve target; undoing scroll"),await this.scrollByPixelDelta({pixelDelta:Math.abs(h),scrollableElement:e.scrollableElement,containerCache:l.cache,direction:v,scrollStepPercent:a,aiMetadata:{commandId:e.id}});}return null}async tryFindElement({cmd:e,description:r,tracer:n,scrollDetails:o,useAIIfCacheFails:i=true,knownState:a}){let s,l,c=false,u=o,d=lk(e.cache?.target);if(d&&d.resolvedDescription!==void 0&&Dc(d.resolvedDescription,r)&&!e.disableCache){let f=a?.emulatorState??await this.stateManager.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true});try{let{resolvedTarget:h}=await yf({target:d,domState:f,stateManager:this.stateManager,logger:this.logger});s=h,c=!0,l="Successfully resolved scroll to target with cache.",this.logger.info("Successfully resolved scroll to target from cache");}catch(h){this.logger.warn({err:h},"Failed to resolve target from cache");}}if(s&&c&&s.type==="NATIVE"&&o){let f=await this.correctNativeTargetIntoView({cmd:e,resolvedTarget:s,scrollDetails:o});u=f.scrollDetails,f.resolvedTarget?s=f.resolvedTarget:(s=void 0,c=false);}if(!s&&!i)return null;if(!s)try{let f=cw(r),h=await this.findElement({description:f,tracer:n,knownState:a,metadata:{commandId:e.id,source:"SCROLL_TO"}});if(!h.success)return null;s=h.resolvedTarget,l=h.thoughts;}catch(f){if(f instanceof M&&f.reason==="NoMatchingElementError")return null;throw this.logger.warn({err:f},"Failed to find scroll-to target with AI"),f}if(s&&!c&&s.type==="NATIVE"&&o)try{let f=await this.correctNativeTargetIntoView({cmd:e,resolvedTarget:s,scrollDetails:o});u=f.scrollDetails,f.resolvedTarget&&(s=f.resolvedTarget);}catch(f){this.logger.warn({err:f},"Failed to reposition AI-resolved scroll-to target for stable cache generation");}if(s.type==="WEBVIEW"){await this.scrollWebviewTargetIntoView(s);let f=lk(Yc(s));return Pd({command:e,updatedCache:f,updatedWithAI:!c,logger:this.logger}),{success:true,message:l}}let p=Yc(s);if(p.type!=="NATIVE")throw new Error("Expected native target cache for scroll-to");return Pd({command:e,updatedCache:lk({...p,scrollDetails:u}),updatedWithAI:!c,logger:this.logger}),{success:true,message:l}}async correctNativeTargetIntoView({cmd:e,resolvedTarget:r,scrollDetails:n}){let o=await this.getCorrectiveScrollForTarget({resolvedTarget:r});if(!o)return {resolvedTarget:r,scrollDetails:n};this.logger.info({bounds:r.bounds,correction:o},"Repositioning scroll-to target to the preferred viewport anchor");let i=n.scrollableElement.type==="CUSTOM"?n.scrollableElement.cache:void 0,a=await this.scrollByPixelDelta({pixelDelta:o.pixelDelta,scrollableElement:n.scrollableElement,containerCache:i,direction:o.direction,scrollStepPercent:e.scrollStepPercent??ak,aiMetadata:{commandId:e.id},useVisualDiff:true});if(a===0)return this.logger.info({bounds:r.bounds,correction:o},"Skipping corrective scroll update because the viewport did not move"),{resolvedTarget:r,scrollDetails:n};let s=await this.stateManager.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true}),l;try{({resolvedTarget:l}=await yf({target:r,domState:s,stateManager:this.stateManager,logger:this.logger}));}catch(f){return this.logger.warn({err:f},"Failed to re-resolve scroll-to target after corrective scroll"),{resolvedTarget:r,scrollDetails:n}}if(l.type!=="NATIVE")return {resolvedTarget:r,scrollDetails:n};let c=r.bounds,u=l.bounds;if(c!==void 0&&u!==void 0&&c.length===u.length&&c.every((f,h)=>f===u[h]))return this.logger.info({bounds:r.bounds,correction:o,appliedCorrectionPixels:a},"Skipping corrective scroll update because the target did not move (viewport at scroll extent)"),{resolvedTarget:l,scrollDetails:n};let m={...n,pixelDelta:_C({currentPixelDelta:n.pixelDelta,baseDirection:n.direction,correctionDirection:o.direction,correctionPixels:a})},p=await this.getCorrectiveScrollForTarget({resolvedTarget:l});return p?(this.logger.warn({bounds:l.bounds,correction:p},"Corrective scroll still did not bring the scroll-to target into the preferred viewport anchor"),{resolvedTarget:l,scrollDetails:m}):{resolvedTarget:l,scrollDetails:m}}async searchForElement({cmd:e,description:r,scrollStepPercent:n}){let o=ae(),i=await this.resolveContainer({scrollableElement:e.scrollableElement,aiMetadata:{commandId:e.id}});return this.scrollAndSearch({cmd:e,description:r,tracer:o,scrollStepPercent:n,resolvedContainer:i})}async scrollAndSearch({cmd:e,description:r,tracer:n,scrollStepPercent:o,resolvedContainer:i}){let a=0,s=i.bounds,l=i.diffThresholdPercent,c=e.scrollableElement.type==="CUSTOM_COORDINATES"?e.scrollableElement:void 0,u;c?u=Math.abs(c.deltaPixels):u=this.calculateSwipeCoordinates({containerBounds:s,direction:e.direction,desiredDelta:Cs({containerBounds:s,containerInsetRatio:Yo})*o}).actualDelta;let d=true,m=e.maxScrollAttempts??vte;for(let h=0;h<m;h++){this.throwIfAborted();let g=this.buildScrollDetails(e,a,i.cache),y=await this.tryFindElement({cmd:e,description:r,tracer:n,scrollDetails:g});if(y)return y;if(!d)throw new Error(`ActionFailureError: Could not find element "${r}" after scrolling to the end`);this.logger.debug({attempt:h,cumulativePixelDelta:a},"Element not found, scrolling further"),d=await this.scrollByPage({direction:e.direction,containerBounds:s,scrollStepPercent:o,diffThresholdPercent:l,rawCoordinates:c}),a+=e.direction==="down"?u:-u;}let p=this.buildScrollDetails(e,a,i.cache),f=await this.tryFindElement({cmd:e,description:r,tracer:n,scrollDetails:p});if(f)return f;throw new Error(`ActionFailureError: Could not find element "${r}" after ${m} scroll attempts`)}buildScrollDetails(e,r,n){return e.scrollableElement.type==="CUSTOM"?{pixelDelta:r,scrollableElement:{type:"CUSTOM",target:e.scrollableElement.target,cache:n},direction:e.direction}:e.scrollableElement.type==="CUSTOM_COORDINATES"?{pixelDelta:r,scrollableElement:e.scrollableElement,direction:e.direction}:{pixelDelta:r,scrollableElement:e.scrollableElement,direction:e.direction}}async scrollWebviewTargetIntoView(e){let{controller:r,browserTarget:n}=e;await r.browser.hover(n);}async scrollByPage({direction:e,containerBounds:r,scrollStepPercent:n,diffThresholdPercent:o,rawCoordinates:i}){return ae().startAsyncSpan("EMULATOR_INTERACTION",async s=>(s.attributes.containerBounds=r,s.attributes.direction=e,(await this.executeScrollGesture({direction:e,containerBounds:r,scrollStepPercent:n,diffThresholdPercent:o,rawCoordinates:i})).canScrollMore),{name:`Scroll ${e} by one page`})}async scrollByPixelDelta({pixelDelta:e,scrollableElement:r,containerCache:n,direction:o,scrollStepPercent:i,aiMetadata:a,useVisualDiff:s=false}){if(e===0)return 0;let l=ae(),c,u=Ef,d,m,p;if(r.type==="CUSTOM_COORDINATES")d=r.startX,m=r.startY,p=r.deltaPixels;else {c=await this.resolveContainer({scrollableElement:r,containerCache:n,aiMetadata:a});let h=c.bounds;u=c.diffThresholdPercent;let g=Cs({containerBounds:h,containerInsetRatio:Yo})*i,y=this.calculateSwipeCoordinates({containerBounds:h,direction:o,desiredDelta:g});d=y.startX,m=y.startY,p=y.actualDelta;}let f=Math.ceil(Math.abs(e)/p);return this.logger.debug({pixelDelta:e,direction:o,scrollableElementType:r.type,startX:d,startY:m,maxScrollPerStep:p,numScrolls:f},"scrollByPixelDelta calculated parameters"),l.startAsyncSpan("EMULATOR_INTERACTION",async h=>{h.attributes.pixelDelta=e,h.attributes.numScrolls=f,h.attributes.maxScrollPerStep=p,h.attributes.startX=d,h.attributes.startY=m;let g=this.invertDirection(o),y=0;for(let S=0;S<f;S++){this.throwIfAborted();let E=Math.abs(e)-y,v=Math.min(p,E);if(s){let w=await this.executeScrollGesture({direction:o,containerBounds:c?.bounds,scrollStepPercent:i,diffThresholdPercent:u,rawCoordinates:{type:"CUSTOM_COORDINATES",startX:d,startY:m,deltaPixels:v}});if(w.didScroll&&(y+=v),!w.canScrollMore)break}else await this.performRawSwipe({startX:d,startY:m,deltaPixels:v,direction:g}),y+=v;}return h.attributes.appliedPixels=y,y},{name:`Scroll ${o} by ${Math.abs(e)}px`})}async executeScrollGesture({direction:e,containerBounds:r,scrollStepPercent:n,diffThresholdPercent:o=Ef,rawCoordinates:i}){let a=await this.stateManager.getRawScreenshotBase64(),s,l,c;if(i)s=i.startX,l=i.startY,c=i.deltaPixels;else {if(!r)throw new Error("Expected container bounds for scroll gesture");let f=Cs({containerBounds:r,containerInsetRatio:Yo})*n,h=this.calculateSwipeCoordinates({containerBounds:r,direction:e,desiredDelta:f});s=h.startX,l=h.startY,c=h.actualDelta;}await this.performRawSwipe({startX:s,startY:l,deltaPixels:c,direction:this.invertDirection(e)});let u=await this.stateManager.getRawScreenshotBase64(),d=wc(a,u),m=d>o,p=d>o;return this.logger.debug({diffPercent:d,didScroll:m,diffThresholdPercent:o,canScrollMore:p,direction:e,actualDelta:c,rawCoordinates:i},"Scroll gesture visual diff result"),{didScroll:m,canScrollMore:p}}async getCorrectiveScrollForTarget({resolvedTarget:e}){let r=e.bounds;if(!r||r.length<4)return;let n=await this.stateManager.getViewportBounds(),o=Math.max(1,n.bottom-n.top),i=r[1],a=r[3],s=OC({viewportTop:n.top,viewportBottom:n.bottom,elementHeight:a-r[1],targetTopRatio:sk}),l=n.top+o*sk,c=n.bottom-o*sk,u=i>=n.top&&a<=n.bottom,d=i<l||a>c,m=e.resolvedNode.getAttribute("displayed")!=="false"&&e.resolvedNode.getAttribute("visible")!=="false",p=s-i;if(!(u&&m&&!d)){if(p>0)return {direction:"up",pixelDelta:p};if(p<0)return {direction:"down",pixelDelta:Math.abs(p)}}}};function lk(t){return !t||t.type!=="NATIVE"?t:DC(t)}var XA=class extends Cr{async doInstallApk(e){return await this.installApkFromUri(e.uri),{success:true,message:"Installed APK."}}async installApkFromUri(e){let r=await this.resolveUriToLocalApk(e);try{await this.stateManager.executeRawADBCommand(`install -r ${fr__default.resolve(r.localPath)}`),this.logger.info({uri:e,localPath:r.localPath},"Installed APK on device");}finally{r.cleanup();}}async resolveUriToLocalApk(e){try{let r=new URL(e);if(r.protocol==="file:"){let n=r.href.slice(7),o;if(Sn.existsSync(n))o=n;else if(Sn.existsSync(fr__default.join("/",n)))o=fr__default.join("/",n);else throw new M("UserConfigurationError",`APK not found at path: ${n}`);return this.assertFileExists(o),{localPath:o,cleanup:()=>{}}}if(r.protocol==="http:"||r.protocol==="https:"){let n=await this.fetchWithTimeout(r);if(!n.ok)throw new M("UserInfrastructureError",`Failed to download APK from ${e} (status ${n.status})`);let o=await n.arrayBuffer(),i=Buffer.from(o),a=await this.writeBufferToTempFile(i,r.pathname);return {localPath:a,cleanup:()=>{try{Sn.unlinkSync(a);}catch(s){this.logger.warn({err:s,path:a},"Failed to remove temporary APK file");}}}}throw new M("UserConfigurationError",`Unsupported URI scheme for APK installation: ${r.protocol}`)}catch(r){if(r instanceof TypeError){let n=fr__default.resolve(e);return this.assertFileExists(n),{localPath:n,cleanup:()=>{}}}throw r}}assertFileExists(e){try{Sn.accessSync(e);}catch{throw new M("UserConfigurationError",`APK not found at path: ${e}`)}}async fetchWithTimeout(e){let r=AbortSignal.timeout(9e4);return await fetch(e,{signal:r})}async writeBufferToTempFile(e,r){let n=fr__default.extname(r)||".apk",o=fr__default.join(tmpdir(),`momentic-apk-${randomUUID()}${n}`);return Sn.writeFileSync(o,e),o}};async function Cte({command:t,logger:e,generator:r,aiSettings:n,getEmulatorDomState:o,getScreenshotBase64:i,abortSignal:a}){let s=ae();if(!t.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(t.schema){let u=Vm(t.schema);if(u)throw new M("UserConfigurationError",u)}let l="",c="";return await s.startAsyncSpan("EMULATOR_READ_STATE",async()=>{l=await o(),c=await i();},{name:"Get emulator state"}),await s.startAsyncSpan("AI_EXTRACTION_CALL",async u=>{try{let d=await r.getAndroidTextExtraction({goal:t.goal,emulatorState:l,returnSchema:t.schema,screenshot:`data:image/png;base64,${c}`},{disableCache:!!t.disableCache,abortSignal:a,loggerTags:De(e),agentConfigVersion:n.agentConfig?.["android-text-extraction"]});if(u.result=d,LC({tracer:s,span:u,screenshot:c,emulatorState:l,logger:e}),d.result==="NOT_FOUND")return {success:!1,message:"No relevant data found for extraction goal on this page"};if(d.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",d.thoughts);return {success:!0,output:d.result,message:d.thoughts}}catch(d){let m=W(d);throw m.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step instead."):m.includes("AIProviderError")&&m.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:d}}):d}})}var JA=class extends Cr{async dragNative(e,r,n){let{left:o,top:i,width:a,height:s}=this.getBoundsFromNativeCache(e),{left:l,top:c,width:u,height:d}=this.getBoundsFromNativeCache(r),m=o+a/2,p=i+s/2,f=l+u/2,h=c+d/2,g=n?.hoverDuration??500,y=n?.dragDuration??1e3;await this.driver.executeInNativeContext(this.logger,async S=>{await S.performActions([{type:"pointer",id:"finger1",parameters:{pointerType:"touch"},actions:[{type:"pointerMove",duration:0,x:m,y:p},{type:"pointerDown",button:0},{type:"pause",duration:g},{type:"pointerMove",duration:y,x:f,y:h},{type:"pointerUp",button:0}]}]),await S.releaseActions();},{operationName:"dragAndDrop"});}async dragWebview(e,r,n){let{controller:o}=e;if(e.controller!==r.controller)throw new M("UserConfigurationError","Cannot drag and drop between different webviews");let i=n?.dragDuration??1e3,a=n?.hoverDuration??1e3,s;n?.dragDuration&&(s=Math.max(1,Math.floor(i/200))),await o.browser.dragAndDrop(e.browserTarget,r.browserTarget,{hoverDurationMs:a,steps:s,dragDurationMs:i});}async executeDragAndDrop({command:e}){let r=ae();if(e.fromTarget.type!=="description"||e.toTarget.type!=="description")throw new M("UserConfigurationError","Drag and drop only supports description targets for now");let n=e.fromTarget.description,{result:o,thoughts:i}=await this.wrapTargetingAction({command:e,tracer:r,description:n,cacheKey:"cache",targetName:"fromTarget",action:async c=>c}),a=e.toTarget.description,{result:s,thoughts:l}=await this.wrapTargetingAction({command:e,tracer:r,description:a,cacheKey:"cache",targetName:"toTarget",action:async c=>c});if(o.type!==s.type)throw new M("UserConfigurationError",`Drag and drop targets must be in the same context (both native or both webview). Found: From=${o.type}, To=${s.type}`);return await r.startAsyncSpan("EMULATOR_INTERACTION",async c=>{o.type==="NATIVE"&&s.type==="NATIVE"?await this.dragNative(o,s,{hoverDuration:e.hoverDuration,dragDuration:e.dragDuration}):o.type==="WEBVIEW"&&s.type==="WEBVIEW"&&(c.withinWebview=true,await this.dragWebview(o,s,{hoverDuration:e.hoverDuration,dragDuration:e.dragDuration}));},{name:"Drag and drop"}),{success:true,message:`${i}
|
|
5864
5864
|
${l}`}}};var ZA=class{async getTextContent(e){return await e.textContent()??""}async getAttribute(e,r){return await e.getAttribute(r,{timeout:3e3})??""}async getTagName(e){return await e.evaluate(r=>r.tagName)}async isEditable(e){return await e.isEditable({timeout:un*1e3})}async isEnabled(e){return await e.isEnabled({timeout:un*1e3})}async isFocused(e){return await e.evaluate(r=>r===document.activeElement)}async getStyleProperty(e,r){return await e.evaluate((n,o)=>window.getComputedStyle(n).getPropertyValue(o),r)}},QA=class{async getTextContent(e){return kp(e)}async getAttribute(e,r){return e.getAttribute(r)??""}async getTagName(e){return e.tagName}async isEditable(e){throw new Error("Cannot perform editable check on native element")}async isEnabled(e){return e.getAttribute("enabled")==="true"}async isFocused(e){return e.getAttribute("focused")==="true"}async getStyleProperty(e,r){throw new Error("Cannot perform computed style checks on native element")}};var e$e=5e3,eR=class extends Cr{async executeElementCheck(e){let r=Date.now(),n=(e.timeout??un)*1e3,o=n+1e4,i,a=0,s=500,l=cloneDeep(e.cache);if(e.target.type!=="description")throw new M("UserConfigurationError","x/y targets are not supported for the Element check step");for(;a-r<n;){if(Date.now()-r>o){this.logger.warn("Exceeded max system timeout for element check, exiting...");break}if(this.throwIfAborted(),i=await this.executeElementCheckHelper(e),a=Date.now(),!i.success)e.cache=l,l=cloneDeep(l),await pe(s,this.abortSignal),s=Math.min(Math.floor(s*1.5),e$e);else return i}let c=await this.executeElementCheckHelper(e,{cacheIsInvalidAfterResolution:true});if(!c.success&&l&&e.cache){let u=zg({logger:this.logger,originalTarget:vm(l)?l.target:void 0,newTarget:e.cache.target});u&&il(l.target,u)&&(e.cache={target:u,updatedAt:e.cache.updatedAt});}return c}async executeElementCheckHelper(e,r){let n=ae();if(e.target.type!=="description")throw new M("UserConfigurationError","x/y targets are not supported for the Element check step");let o=ap(e.assertion);try{return (await this.wrapTargetingAction({...r??{},command:e,tracer:n,action:async a=>"type"in a&&a.type==="NATIVE"?await this.executeNativeElementCheck(e,a):await this.executeWebviewElementCheck(e,a),description:e.target.description,skipFetchingFullWebviewContent:!0,removeWebviewContent:!0})).result}catch(i){return o&&(i instanceof M&&i.reason==="NoMatchingElementError"||i instanceof Wa)?{success:true}:{success:false,message:`Failed to evaluate element content assertion: ${i instanceof Error?i.message:`${i}`}`}}}async executeNativeElementCheck(e,r){let n=ae(),{assertion:o}=e,i=r.resolvedNode;return await n.startAsyncSpan("ELEMENT_ASSERTION",async a=>{a.targetBounds=Xc(r);let s=await this.executeElementAssertion({assertion:o,element:i,elementPropertyAccessors:new QA,span:a});return a.result=s,s},{name:"Native element check"})}async executeWebviewElementCheck(e,r){let n=ae(),o=r.browserTarget.locator,i=e.assertion;return await n.startAsyncSpan("ELEMENT_ASSERTION",async a=>{a.withinWebview=true,a.targetBounds=Xc(r),await r.controller.browser.highlight(o);let s=await this.executeElementAssertion({assertion:i,element:o,elementPropertyAccessors:new ZA,span:a});return a.result=s,s},{name:"Webview element check"})}async executeElementAssertion({assertion:e,element:r,elementPropertyAccessors:n,span:o}){switch(e.type){case "ELEMENT_CONTENT":{let i=await n.getTextContent(r)??"";return o.attributes.elementTextContent=kr(i,500,true),Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})?{success:true}:{success:false,message:`The content ${wn(e)} '${e.value}': ${i}`}}case "ELEMENT_ATTRIBUTE":{"evaluate"in r&&(o.attributes.elementOuterHtml=kr(await r.evaluate(a=>a.cloneNode(false).outerHTML),500,true));let i;try{i=await n.getAttribute(r,e.attr);}catch{i=null;}if(!Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let a=wn(e);return {success:false,message:`The attribute ${e.attr} ${a}${e.operation==="EXISTS"?"":` '${e.value}': ${i}`}`}}return {success:true}}case "ELEMENT_EXISTENCE":{let i=false;switch(e.condition){case "EDITABLE":i=await n.isEditable(r);break;case "VISIBLE":case "EXISTS":i=true;break;case "ENABLED":{i=await n.isEnabled(r);break}case "FOCUSED":i=await n.isFocused(r);break;default:throw e.condition,new Error("Unrecognized element condition type")}return i=e.negated?!i:i,i?{success:true}:{success:false,message:`The element ${wn(e)}`}}case "ELEMENT_NAME":{let i=await n.getTagName(r);return Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:true})?{success:true}:{success:false,message:`The element tag name ${wn(e)} '${e.value}': ${i}`}}case "ELEMENT_STYLE":{let i=await n.getStyleProperty(r,e.property);if(!Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let a=wn(e);return {success:false,message:`The style property ${e.property} ${a}${e.operation==="EXISTS"?"":` '${e.value}': ${i}`}`}}return {success:true}}default:throw new Error("Unrecognized element assertion type")}}};var t$e=5e3,tR=class extends Cr{async executeScreenCheck(e){let{timeout:r}=e,n=Date.now(),o=(r??un)*1e3,i=o+1e4,a=0,s=500;for(;a-n<o;){if(Date.now()-n>i){this.logger.warn("Exceeded max system timeout for screen check, exiting...");break}this.throwIfAborted();let l=await this.executeScreenCheckHelper(e);if(a=Date.now(),!l.success)await pe(s,this.abortSignal),s=Math.min(Math.floor(s*1.5),t$e);else return l}return await this.executeScreenCheckHelper(e)}async executeScreenCheckHelper(e){return await ae().startAsyncSection("Execute screen check",async(n,o)=>{let[i,a]=await Promise.all([this.executeNativeScreenCheckHelper({span:o,command:e}),this.executeWebviewScreenCheckHelper(e)]);return a?e.assertion.negated?i.success&&a.success?i:i.success?a:i:i.success?i:a:i})}async executeNativeScreenCheckHelper({span:e,command:r}){let{assertion:n}=r;switch(n.type){case "CONTENT":try{let o=(await this.stateManager.getDomState({skipFetchingFullWebviewContent:!0,removeWebviewContent:!0})).graph.document.documentElement?.outerHTML;if(!o)throw new Error("Failed to get screen HTML");let i=o.includes(n.value)===!n.negated;return o.length>1e4&&(o=o.slice(0,1e4)+"...TRUNCATED"),i?{success:!0}:(e.attributes.screenContent=o,{success:!1,message:`The screen ${ip({...n,negated:!n.negated})}.`})}catch(o){return {success:false,message:`Failed to evaluate screen content assertion: ${o instanceof Error?o.message:`${o}`}`}}default:return n.type,{success:false,message:`Unsupported screen check assertion type: ${n.type}`}}}async executeWebviewScreenCheckHelper(e){let r=await this.stateManager.getActiveWebview();if(!r||!r.browserController)return;let n=r.browserController.browser,o=await iL({assertion:e.assertion,logger:this.logger,browser:n,autoExpandIframes:!!n.userBrowserSettings.autoExpandIframes});return {success:o.success,message:o.err?.message,output:o.data}}};var rR=class extends Cr{async doUninstallApk(e){return await this.uninstallApkPackage(e.packageName),{success:true,message:"Uninstalled APK."}}async uninstallApkPackage(e){let r=e.replace(/^package:/,""),n=await this.stateManager.executeRawADBCommand(`shell pm list packages | grep -E "^package:${r}$" || true`);if(!n||n.length===0)throw new M("UserConfigurationError",`Package ${r} not found`);if(n.split(`
|
|
5865
5865
|
`).filter(i=>!!i).length>1)throw new M("UserConfigurationError",`Multiple packages found for ${r}`);try{await this.stateManager.executeRawADBCommand(`uninstall ${r}`);}catch(i){throw new M("UserInfrastructureError",`Failed to uninstall package ${r}: ${i}`)}}};var nR=class extends Cr{async executeVisualDiff({command:e,updateGoldenFiles:r}){let n=this.fixtures.visualDiffGoldenStorage;await this.stateManager.waitForScreenshotStability({timeoutMs:1e4,reason:"visual diff",signal:this.abortSignal});let o=await this.stateManager.getRawScreenshotBase64();return kC({goldenStorage:n,command:e,currentScreenshotBase64:o,threshold:e.threshold??zh,updateGoldenFiles:r,tracer:ae(),logger:this.logger})}};var Ate=z.object({"Android-Package":z.string(),Browser:z.string(),"Protocol-Version":z.string(),"User-Agent":z.string(),"V8-Version":z.string(),"WebKit-Version":z.string(),webSocketDebuggerUrl:z.string()}),Rte=z.object({description:z.string(),devtoolsFrontendUrl:z.string(),id:z.string(),title:z.string(),type:z.string(),url:z.string(),webSocketDebuggerUrl:z.string()}),xte=z.object({proc:z.string(),webview:z.string(),webviewName:z.string()}),Mte=z.array(xte.extend({info:Ate.optional(),pages:z.array(Rte).optional()}));z.array(xte.extend({info:Ate,pages:z.array(Rte)}));var oR=class t{driver;limbarClient;device;logger;webviews=new Map;fixtures;orgId;options;lastDomState;lastRawPageSource;lastScreenshot;lastViewportBounds;aborter;constructor({driver:e,limbarClient:r,logger:n,device:o,fixtures:i,orgId:a,options:s,aborter:l}){this.driver=e,this.limbarClient=r,this.device=o,this.logger=n,this.fixtures=i,this.orgId=a,this.options=s,this.aborter=l;for(let c of ["SIGINT","SIGTERM"])process.on(c,async()=>{await this.cleanupWebviews();});}static async init({driver:e,logger:r,fixtures:n,limbarClient:o,orgId:i,adbPort:a,options:s,aborter:l,playwrightDevice:c}){let u;if(c)u=c;else {let m=(await _android.devices()).filter(p=>p._initializer?.serial?.endsWith(a.toString())||p._initializer?.serial?.endsWith((a-1).toString()));if(r.warn({devices:m.map(p=>({serial:p._initializer?.serial,model:p._initializer?.model}))},"No playwright device provided, using ADB to find device"),m.length===0)throw new M("UserInfrastructureError",`Momentic found no devices listening on port ${a} or ${a-1}. This can occur if Android Studio reuses existing emulators. Please run 'adb emu kill' and 'adb disconnect' and retry.`);if(m.length>1)throw new M("UserInfrastructureError",`Momentic found multiple devices on the ports ${a} or ${a-1}. This can occur if Android Studio reuses existing emulators. Please run 'adb emu kill' and 'adb disconnect' and retry.`);u=m[0];}return new t({driver:e,logger:r,device:u,fixtures:n,orgId:i,options:s,aborter:l,limbarClient:o})}async getContexts(){let e=await this.driver.executeInNativeContext(this.logger,n=>n.getContexts({}),{operationName:"getContexts"}),r=Array.from(this.webviews.values());return {contexts:e,webviews:r.map(n=>({contextId:n.contextId,packageName:n.packageName,active:n.active,hasPlaywright:!!n.browserController,lastSeen:n.lastSeen,socketName:n.socketName}))}}async getRawScreenshotBase64({maxAttempts:e=3,signal:r}={}){let n=ae(),o=r??this.aborter.controller?.signal,i={maxAttempts:e,signal:o,operationName:"takeScreenshot"},a=await n.startAsyncSpan("EMULATOR_READ_STATE",async()=>{if(this.limbarClient){let s=this.limbarClient,l=await Ip(this.logger,async()=>s.screenshot(),i);if(l.dataUri.startsWith("data:image/png;base64,"))return l.dataUri.slice(22);throw new M("InternalWebAgentError",`Emulator provider returned unexpected screenshot URI: ${l.dataUri}`)}return this.driver.executeInNativeContext(this.logger,s=>s.takeScreenshot(),i)},{name:"Take screenshot",signal:o,timeoutMs:3e4});return this.lastScreenshot={pngString:`data:image/png;base64,${a}`,observedAt:Date.now()},a}async getCurrentScreenshotPngString(){return `data:image/png;base64,${await this.getRawScreenshotBase64({maxAttempts:1})}`}async waitForScreenshotStability({timeoutMs:e,signal:r,reason:n,tolerancePercent:o=1}){let i=Km({signal:r,timeoutMs:e});await ae().startAsyncSpan("WAIT_FOR_SCREENSHOT_STABILITY",async a=>{a.attributes.reason=n;let s,l=false;for(;!i.aborted;){let c=Date.now();if(s)try{let d=await this.getRawScreenshotBase64({maxAttempts:1,signal:i});if(wc(s,d)<=o){l=!0;break}s=d;}catch(d){this.logger.warn({err:d},"Failed to get screenshot during stability wait");}else try{s=await this.getRawScreenshotBase64({maxAttempts:1,signal:i});}catch(d){this.logger.warn({err:d},"Failed to get initial screenshot during stability wait");}let u=Math.max(250,Date.now()-c);await ms(Math.min(1e4,u),i);}l||(a.attributes.timedOut=true,this.logger.warn({purpose:n},"Timed out waiting for screenshot stability"));});}async waitForPageSourceStability({timeoutMs:e,signal:r,reason:n}){await ae().startAsyncSpan("WAIT_FOR_PAGE_STABILITY",async o=>{o.attributes.reason=n;let i=Km({signal:r,timeoutMs:e}),a,s=false;for(;!i.aborted;){let l,c=Date.now();try{l=await this.getPageSource(i);let d=createHash("md5").update(l).digest("hex");if(a&&a===d){s=!0;break}a=d;}catch(d){this.logger.warn({err:d},"Failed to get page source during stability wait");}let u=Math.max(250,Date.now()-c);await ms(Math.min(1e4,u),i);}if(!s){o.attributes.timedOut=true,this.logger.warn({purpose:n},"Timed out waiting for page source stability");return}await this.recordLastDomStateFromRawPageSource({removeWebviewContent:true});});}async getLastObservedState(){if(this.lastRawPageSource&&this.lastViewportBounds&&(!this.lastDomState||this.lastRawPageSource.observedAt>this.lastDomState.observedAt)&&await this.recordLastDomStateFromRawPageSource({removeWebviewContent:true}),!this.lastDomState||!this.lastScreenshot)return;let e=Date.now(),r=3e4;if(!(e-this.lastDomState.observedAt>r||e-this.lastScreenshot.observedAt>r||Math.abs(this.lastDomState.observedAt-this.lastScreenshot.observedAt)>3e4))return {emulatorState:this.lastDomState.state,screenshot:this.lastScreenshot.pngString}}async recordLastDomStateFromRawPageSource({removeWebviewContent:e}){if(!this.lastRawPageSource||!this.lastViewportBounds)return;let r=await this.buildDomStateFromRawXml({rawXml:this.lastRawPageSource.xml,removeWebviewContent:e,viewportBounds:this.lastViewportBounds});this.lastDomState={state:r,observedAt:this.lastRawPageSource.observedAt};}async buildDomStateFromRawXml({rawXml:e,webviewContent:r,removeWebviewContent:n,viewportBounds:o}){return {graph:await ate(e,this.logger,{injectedWebviewContent:r,disableMomenticAccessibilityTree:this.options.disableMomenticAccessibilityTree,removeWebviewContent:n,viewportBounds:o})}}recordRawPageSource(e){this.lastRawPageSource={xml:e,observedAt:Date.now()};}recordDomState(e){this.lastDomState={state:e,observedAt:Date.now()};}async getCurrentPackage(){let e=await this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: getCurrentPackage"),{operationName:"getCurrentPackage"});return typeof e=="string"?e:void 0}async getActiveWebviewNodes(){let r=(await this.getDomState({skipFetchingFullWebviewContent:true,removeWebviewContent:true})).graph,n=[];for(let[o,i]of r.idToElement.entries())n.some(a=>a.id===o)||Uy(i)&&n.push({id:o,originalElement:i,bounds:Tl(i)});return n}async getActiveWebviewContent(){let e=await this.getActiveWebview();if(!e||!e.browserController)return;this.throwIfAborted();let r=e.browserController;return (await ae().startAsyncSpan("EMULATOR_READ_STATE",()=>r.getBrowserState({abortSignal:this.aborter.controller?.signal,skipWait:true,skipWaitForPageLoad:true,logger:this.logger,serializationOpts:{noId:true}}),{name:"Get webview content",signal:this.aborter.controller?.signal})).serializedTree}async getDomState(e){return await ae().startAsyncSection("Get emulator state XML",async()=>{let n;if(!e?.skipFetchingFullWebviewContent&&!this.options.disableMomenticAccessibilityTree)try{n=await this.getActiveWebviewContent();}catch(l){this.logger.error({err:l},"Could not get webview info to get the nested DOM state");}this.throwIfAborted();let i=e?.filterOffscreenElements??true?await this.getViewportBounds():void 0,a=await this.getPageSource(),s=await this.buildDomStateFromRawXml({rawXml:a,webviewContent:n,removeWebviewContent:e?.removeWebviewContent,viewportBounds:i});return this.recordDomState(s),s},{timeoutMs:3e4})}async getPageSource(e){let r=e??this.aborter.controller?.signal,o=await ae().startAsyncSpan("EMULATOR_READ_STATE",()=>this.driver.executeInNativeContext(this.logger,i=>i.getPageSource(),{signal:r,operationName:"getPageSource"}),{name:"Get Android page source",signal:r,timeoutMs:3e4});return this.recordRawPageSource(o),o}async getViewportBounds(){let e=await this.driver.executeInNativeContext(this.logger,n=>n.getWindowRect(),{operationName:"getViewportBounds"}),r={left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height};return this.lastViewportBounds=r,r}refreshPromise;refreshInterval;webviewConnectionPromises=new Map;async refreshWebviewsManually(e){if(!this.options.disableMomenticAccessibilityTree){if(this.refreshPromise){await this.refreshPromise;return}this.refreshInterval&&(clearInterval(this.refreshInterval),this.refreshInterval=void 0),this.refreshPromise=this.doRefreshWebview(e,{currentAppOnly:true}).catch(r=>{this.logger.warn({err:r},"Error refreshing webviews, continuing...");}).finally(()=>{this.refreshPromise=void 0;}),await this.refreshPromise;}}async doRefreshWebview(e,{currentAppOnly:r}){if(this.options.disableMomenticAccessibilityTree)return;this.logger.info({reason:e,currentAppOnly:r},"Refreshing webviews"),this.throwIfAborted();let n=await this.getCurrentPackage();if(r&&n==="com.android.permissioncontroller")return;let o=await this.getDetailedContexts();if(!o){this.logger.warn("No context details, not proceeding with refreshing webviews");return}let i=Date.now(),a=new Set;for(let s of o){if(this.throwIfAborted(),s.webview==="NATIVE_APP")continue;let l=s.info["Android-Package"];if(r&&n&&l!==n&&l!=="com.android.chrome"){this.logger.debug({packageName:l,currentPkgName:n},"Skipping webview outside the active package during manual refresh");continue}a.add(s.webview);let c=!this.webviews.has(s.webview),u=!this.webviews.get(s.webview)?.active;if(c||u){let d={contextId:s.webview,packageName:l,active:false,lastSeen:i,socketName:s.proc.startsWith("@")?s.proc.substring(1):s.proc};this.logger.info({contextId:d.contextId,packageName:d.packageName,socketName:d.socketName},c?"New webview detected":"Inactive webview detected"),this.webviews.set(s.webview,d),this.logger.info({webviewInfo:d},`Connecting Playwright to webview: ${s.webview}`);let m=await this.connectPlaywrightToAvailableWebview(d);if(!m)continue;d.browserController=m,d.active=true;}}for(let[s,l]of this.webviews.entries())r&&n&&l.packageName!==n||!a.has(s)&&l.active&&(this.logger.info(`Disconnecting dead webview ${s}`),this.disconnectPlaywrightFromWebview(l),l.active=false);this.logger.info("Refreshed webviews");}async getActiveWebview(){if(this.options.disableMomenticAccessibilityTree)return;await this.refreshPromise;let e=await this.driver.executeInNativeContext(this.logger,a=>a.execute("mobile: getCurrentPackage"),{operationName:"getActiveWebviewCurrentPackage"}),r=async()=>{e!==void 0&&typeof e!="string"&&this.logger.warn({currentPkg:e},"Unexpected getCurrentPackage result");let a=[];for(let s of this.webviews.values())s.packageName===e&&s.active&&a.push(s);return this.logger.info({currentPkg:e,allWebviews:Array.from(this.webviews.values()).map(s=>({contextId:s.contextId,packageName:s.packageName,active:s.active}))},`getActiveWebview: found ${a.length} matching webviews`),a},n=await r();if(n.length===0&&(await ae().startAsyncSection("Refresh webviews",async()=>{await this.refreshWebviewsManually("no matching webview during getActiveWebview");}),n=await r()),n.length>1)throw new M("UserInfrastructureError","Multiple active webviews in a single package is currently not supported");let o=n[0];if(!o)return;if(this.hasUsableWebviewBrowser(o)||(this.logger.warn({contextId:o.contextId,packageName:o.packageName},"Active webview browser is unhealthy, reconstructing"),await this.reconstructWebviewBrowser(o,"active webview page or target crashed"),this.hasUsableWebviewBrowser(o)))return o;if(await ae().startAsyncSection("Refresh webviews after browser reconstruction failed",async()=>{await this.refreshWebviewsManually("active webview browser reconstruction failed");}),n=await r(),n.length>1)throw new M("UserInfrastructureError","Multiple active webviews in a single package is currently not supported");let i=n[0];if(i){if(this.hasUsableWebviewBrowser(i))return i;this.logger.warn({contextId:i.contextId,packageName:i.packageName},"Refreshed active webview is still unhealthy after reconstruction");}}async reconstructActiveWebviewBrowser(e){if(this.options.disableMomenticAccessibilityTree)return;await this.refreshPromise;let r=await this.driver.executeInNativeContext(this.logger,i=>i.execute("mobile: getCurrentPackage"),{operationName:"reconstructActiveWebviewCurrentPackage"});if(r!==void 0&&typeof r!="string"){this.logger.warn({currentPkg:r},"Unexpected getCurrentPackage result");return}let n=[];for(let i of this.webviews.values())i.packageName===r&&i.active&&n.push(i);if(n.length>1)throw new M("UserInfrastructureError","Multiple active webviews in a single package is currently not supported");let o=n[0];if(o)return await this.reconstructWebviewBrowser(o,e),this.hasUsableWebviewBrowser(o)?o:void 0}hasUsableWebviewBrowser(e){let r=e.browserController;if(!r||!e.active)return false;let n=r.browser;if(n.closed)return false;let o;try{o=n.getActivePage();}catch(i){return this.logger.warn({err:i,contextId:e.contextId},"Failed to resolve active page for webview browser health check"),false}return !o.isClosed()}async reconstructWebviewBrowser(e,r){this.logger.info({contextId:e.contextId,packageName:e.packageName,reason:r},"Reconstructing webview browser"),await this.disconnectPlaywrightFromWebview(e),e.active=false;let n=await this.connectPlaywrightToAvailableWebview(e);n&&(e.browserController=n,e.active=true);}getDeviceSerial(){let e=this.driver.capabilities,r=n=>{if(!e||typeof e!="object")return;let o=e[n];return typeof o=="string"?o:void 0};return r("deviceUDID")||r("udid")||r("appium:udid")||r("appium:deviceUDID")}async executeRawADBCommandWithArgs(e){let r=this.getDeviceSerial();this.logger.info({serial:r,args:e},"Executing ADB command");let n=await qr(e,{serial:r,timeoutMs:15e3,throwOnError:true});return this.logger.info({result:n},"ADB command result"),n}async executeRawADBCommand(e){let r=this.getDeviceSerial(),n=e.trim().split(/\s+/).filter(i=>i.length>0);this.logger.info({serial:r,cmdArgs:n},"Executing ADB command");let o=await qr(n,{serial:r,timeoutMs:15e3,throwOnError:true});return this.logger.info({result:o},"ADB command result"),o}async cleanupWebviews(){this.refreshInterval&&(clearInterval(this.refreshInterval),this.refreshInterval=void 0);for(let[e,r]of this.webviews.entries())this.logger.info(`Disconnecting webview ${e}`),this.disconnectPlaywrightFromWebview(r),r.active=false;}async getDetailedContexts(){return await ae().startAsyncSpan("EMULATOR_READ_STATE",async()=>{let r=await this.driver.executeInNativeContext(this.logger,o=>o.execute("mobile: getContexts"),{operationName:"getDetailedContexts"});this.aborter.controller?.signal.throwIfAborted();let n;try{n=Mte.parse(r);}catch(o){throw new M("InternalWebAgentError",`Failed to parse contexts. Original error:
|
|
5866
5866
|
${o}
|
|
5867
5867
|
Raw: ${JSON.stringify(r)}`)}return n.filter(o=>o.webviewName?!o.info||!o.pages?false:o.pages.filter(a=>{if(!a.title)return false;let s=a.url;return !(!s||s===""||s.startsWith("about:blank")||s.startsWith("chrome-error:"))}).length?true:(this.logger.debug({context:o},"Webview has no qualified pages, skipping"),false):true)},{name:"Get available contexts",signal:this.aborter.controller?.signal})}async createBrowserController({context:e,page:r}){return await ae().startSection("Run remote Chrome initialization",async(o,i)=>{let a={};i.attributes.timings=a;let s=await _b.fromExistingContext({context:e,page:r,attachTimeoutMs:8e3,logger:this.logger,timingRecorder:a,userBrowserSettings:{...this.options.browserSettings,disableBrowserMonitoring:true},properties:{isNewHeadless:false,allowedA11yIgnoreReasonsOverride:[],isAndroid:true},storage:this.fixtures.storage,enricher:this.fixtures.browserEnricher});try{return new lw({browser:s,generator:this.fixtures.browserGenerator,logger:this.logger,orgId:this.orgId,storage:this.fixtures.storage,localCodeEvalTools:this.fixtures.localCodeEvalTools,visualDiffScreenshotStorage:new rE})}catch(l){throw await s.cleanup(),l}})}async connectPlaywrightToWebview(e,r){return ae().startAsyncSection("Connect headless browser client to webview",async()=>{for(let o=0;o<2;o++)try{let i=await this.connectPlaywrightToWebviewHelper(e,r);return i?{kind:"connected",browserController:i}:{kind:"failed"}}catch(i){if(i instanceof bh)return {kind:"not_found"};if(this.errorLooksLikeUnattachableWebview(i))return this.logger.info({err:i,packageName:e,socketName:r},"Skipping Playwright connection for webview because the target is not attachable"),{kind:"not_attachable"};this.logger.warn({err:i},"Failed to connect Playwright to webview, retrying...");}return {kind:"failed"}},{signal:this.aborter.controller?.signal})}errorLooksLikeUnattachableWebview(e){let r=W(e);return ["No page found in existing context","Target closed","Target crashed","Page crashed","Target page, context or browser has been closed","Session closed. Most likely the page has been closed"].some(n=>r.includes(n))}async connectPlaywrightToAvailableWebview(e){let r=this.webviewConnectionPromises.get(e.contextId);if(r)return this.logger.debug({contextId:e.contextId},"Waiting for existing webview connection attempt"),r;let n=ae().startAsyncSection("Connect Playwright to available webview",async()=>await this.connectPlaywrightToAvailableWebviewHelper(e),{signal:this.aborter.controller?.signal}).catch(o=>{this.logger.warn({err:o,contextId:e.contextId},"Failed to connect Playwright to webview, continuing...");});return this.webviewConnectionPromises.set(e.contextId,n),n.finally(()=>{this.webviewConnectionPromises.get(e.contextId)===n&&this.webviewConnectionPromises.delete(e.contextId);}),n}async connectPlaywrightToAvailableWebviewHelper(e){let{contextId:r,packageName:n}=e,o=await this.connectPlaywrightToWebview(n??"",e.socketName);if(o.kind==="connected")return this.logger.info(`Connected Playwright to webview ${r}`),o.browserController;if(n!=="com.android.chrome"||o.kind!=="not_found")return;this.logger.info({webviewInfo:e},`Connecting Playwright to Android Chrome: ${r}`);let i=await this.connectPlaywrightToChrome(e);return i&&this.logger.info(`Connected Playwright to Android Chrome: ${r}`),i}extractSocketNameFromWebview(e,r){if("_socketName"in e&&typeof e._socketName=="string")return e._socketName;if("_data"in e&&e._data?.socketName)return e._data.socketName;r.warn({pkg:e.pkg()},"Could not extract socket name from webview");}async connectPlaywrightToWebviewHelper(e,r){let n=this.device.webViews(),o=n.find(c=>!(c.pkg()!==e&&e!=="com.android.chrome"||this.extractSocketNameFromWebview(c,this.logger)!==r));if(!o)throw this.logger.warn({webviews:n.map(c=>({pkg:c.pkg,name:this.extractSocketNameFromWebview(c,this.logger)}))},"Could not find matching webview in Playwright device list"),new bh(e,r);let i=await o.page(),a=i.url();if(a===""||a.startsWith("about:blank")||a.startsWith("chrome-error:")){let c=`Webview ${e} with socket ${r} is not a valid webview`;this.logger.warn({pageUrl:a},c);return}let s=i.context();return await this.createBrowserController({context:s,page:i})}async connectPlaywrightToChrome(e){return await ae().startAsyncSpan("EMULATOR_READ_STATE",async()=>this.connectPlaywrightToChromeHelper(e),{name:"Connect headless browser client to Chrome",signal:this.aborter.controller?.signal})}async connectPlaywrightToChromeHelper(e){let{contextId:r,socketName:n}=e,o,i=e.forwardedPort;try{this.logger.info({contextId:r,socketName:n},"Connecting to Chrome webview");let a;if(e.forwardedPort)a=`http://127.0.0.1:${e.forwardedPort}`,this.logger.info({contextId:r,endpoint:a,socketName:n},"Using existing forwarded port");else {let c=await this.forwardDevToolsSocket(e.socketName);e.forwardedPort=c,i=c,a=`http://127.0.0.1:${c}`,this.logger.info({contextId:r,endpoint:a,socketName:n},`Forwarding DevTools socket for ${e.socketName}`);}this.logger.info({endpoint:a,socketName:n},"Connecting to CDP endpoint"),o=await chromium.connectOverCDP({endpointURL:a,timeout:8e3});let s=o.contexts()[0];if(!s){this.logger.warn("No browser context available after CDP connection"),await o.close(),o=void 0;return}let l=await this.createBrowserController({context:s});return i=void 0,o=void 0,l}catch(a){this.logger.warn({err:a},`Error connecting Playwright to webview ${e.contextId}, continuing...`);return}finally{if(o)try{await o.close();}catch(a){this.logger.warn({err:a,contextId:r},"Failed to close orphaned CDP browser after webview connection failure");}if(i)try{await this.removeDevToolsForwarding(i);}catch(a){this.logger.warn({err:a,contextId:r,forwardedPort:i},"Failed to remove forwarded port after webview connection failure");}finally{e.forwardedPort===i&&(e.forwardedPort=void 0);}}}async disconnectPlaywrightFromWebview(e){if(e.browserController)try{this.logger.info(`Disconnecting Playwright from webview: ${e.contextId}`),await e.browserController.browser.cleanup();}catch(r){this.logger.error({err:r},`Error disconnecting Playwright from webview ${e.contextId}:`);}finally{e.browserController=void 0;}if(e.forwardedPort)try{await this.removeDevToolsForwarding(e.forwardedPort);}catch(r){this.logger.error({err:r},`Error removing forwarded port for webview ${e.contextId}:`);}finally{e.forwardedPort=void 0;}}async forwardDevToolsSocket(e){this.logger.info("Setting up port forwarding for DevTools");let r=1e4+Math.floor(Math.random()*1e4),n=this.getDeviceSerial();this.logger.info({deviceId:n},`Device ID from capabilities: ${n||"not found"}`);let o=e&&e.trim().length>0?`localabstract:${e}`:"localabstract:chrome_devtools_remote";return await this.executeRawADBCommand(`forward tcp:${r} ${o}`),this.logger.info(`Successfully forwarded DevTools socket to port ${r}`),r}async removeDevToolsForwarding(e){await this.executeRawADBCommand(`forward --remove tcp:${e}`),this.logger.info("Successfully removed port forwarding");}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}};var Zc=class t extends Cr{appsWithGrantedPermissions=new Set;parseInstalledPackageLines(e){return e?.split(`
|
|
5868
5868
|
`).filter(r=>r.trim().startsWith("package:")).map(r=>r.replace("package:","").trim()).filter(r=>r.length>0&&!r.startsWith("io.appium"))??[]}constructor(e){super(e);}static async init({driver:e,generator:r,logger:n,fixtures:o,orgId:i,options:a,abortController:s,adbPort:l,limbarClient:c,playwrightDevice:u,aiSettings:d}){let m={controller:s},p=await oR.init({driver:e,logger:n,fixtures:o,orgId:i,limbarClient:c,options:a?.emulator??{},aborter:m,adbPort:l,playwrightDevice:u}),f=new t({driver:e,generator:r,stateManager:p,logger:n,fixtures:o,options:a,aborter:m,orgId:i,aiSettings:d,adbPort:l});return await f.initializeSettings(),f}get emulatorSettings(){return this.options?.emulator??{}}async installApp(e){await this.stateManager.executeRawADBCommand(`install ${fr__default.resolve(e)}`);}async isPackageInstalled(e){let r=await this.executeRawADBCommand(`shell pm list packages ${e}`);return this.parseInstalledPackageLines(r).includes(e)}async getInstalledApps(){let[e,r]=await Promise.all([this.executeRawADBCommand("shell pm list packages -3"),this.executeRawADBCommand("shell pm list packages")]),n=this.parseInstalledPackageLines(e).sort((a,s)=>a.localeCompare(s)),i=this.parseInstalledPackageLines(r).filter(a=>!n.includes(a)&&!pD(a)).sort((a,s)=>a.localeCompare(s));return {installedApps:n,prunedApps:i}}async executeCommand(e){let r=["type","a11yData","thoughts","cache","code"],n;try{n=await Fp({obj:e.command,context:this.fixtures.testContext,bannedKeys:r,orgId:this.orgId,logger:this.logger,signal:this.abortSignal,localTools:this.fixtures.localCodeEvalTools});}catch(o){throw this.throwIfAborted(),new M("UserConfigurationError",`Failed to substitute template strings in command: ${o.message}`,{errOptions:{cause:o}})}try{let o=await this.executeCommandHelper(e);return !o.success&&(e.command.type==="SCREEN_CHECK"||e.command.type==="ELEMENT_CHECK")?{...o,message:PS(o.message)}:o}catch(o){throw o.name!=="AbortError"&&this.logger.error({err:o},"Error thrown in action controller"),o}finally{Bp(e.command,n);}}async executeCommandHelper({command:e,updateGoldenFiles:r}){let n=ae();switch(e.type){case "TAP":return new Sf(this.constructPerformerParams()).executeTap({command:e});case "TYPE":return await new KA(this.constructPerformerParams()).doType(e);case "AI_CHECK":{let o=this.shouldUseMemoryForCommand(e),i=e.contextChoice==="VISION_ONLY",a=15,s=e.timeoutSecs?e.timeoutSecs*1e3:5e3,l=Pv(s),c=Date.now(),u=0,d,m=false,p;for(;u<a&&!m;){this.throwIfAborted(),m||d&&d-c>=s&&(m=true),u!==0&&await pe(l,this.abortSignal),d=Date.now();try{let f="",h="";await n.startAsyncSpan("EMULATOR_READ_STATE",async()=>{i||(f=await this.getEmulatorDomState()),h=await this.getScreenshotBase64();},{name:"Get emulator state"});let g=await n.startAsyncSpan("AI_ASSERTION_CALL",async y=>{let S=await this.generator.evaluateAndroidAssertion({assertion:e.assertion,screenXml:f,screenshot:h,contextChoice:e.contextChoice,memory:o?e.cache?.memory:void 0},{logger:this.logger,loggerTags:De(this.logger),agentConfigVersion:this.aiSettings.agentConfig?.["android-assertion"],useMemory:o});return y.result={thoughts:S.thoughts,result:S.result},S});if(o&&g.updatedMemory){let y={type:"GCS_TRACES",traces:g.updatedMemory};e.cache={...e.cache??{},memory:y};}if(g.result)return {success:g.result,message:g.thoughts};{let y=`AssertionFailureError: ${g.thoughts}`;p=new Error(y);}}catch(f){this.throwIfAborted(),this.logger.info({err:f},`AI check assert attempt ${u} failed, retrying...`),p=f instanceof Error?f:new Error(`${f}`);}finally{u++;}}return {success:false,message:p?.message}}case "AI_EXTRACT":return Cte({command:e,logger:this.logger,generator:this.generator,aiSettings:this.aiSettings,getEmulatorDomState:()=>this.getEmulatorDomState(),getScreenshotBase64:()=>this.getScreenshotBase64(),abortSignal:this.abortSignal});case "SWIPE":return new Tf(this.constructPerformerParams()).executeSwipe(e);case "SCREEN_CHECK":return new tR(this.constructPerformerParams()).executeScreenCheck(e);case "ELEMENT_CHECK":return await new eR(this.constructPerformerParams()).executeElementCheck(e);case "DRAG_AND_DROP":return await new JA(this.constructPerformerParams()).executeDragAndDrop({command:e});case "SCROLL_TO":{let o=new YA(this.constructPerformerParams());return await this.waitForPageSourceStability({reason:"Waiting for stability before scrolling to ensure correct momentum"}),o.executeScrollTo(e)}case "JAVASCRIPT":{let o;try{o=await Yi({orgId:this.orgId,code:e.code,fragment:!1,context:this.fixtures.testContext,timeoutMs:e.timeout?e.timeout*1e3:void 0,logger:this.logger,localTools:this.fixtures.localCodeEvalTools,signal:this.abortSignal});}catch(i){throw new M("ActionFailureError",i instanceof M?i.message:`${i}`,{errOptions:{cause:i}})}try{JSON.stringify(o);}catch(i){throw new M("UserConfigurationError",`Return value is not serializable: ${i instanceof Error?i.message:`${i}`}`)}return {success:true,output:o}}case "REQUEST":{let o;try{o=new URL(e.url).hostname;}catch(u){throw new M("UserConfigurationError",`Invalid URL: ${u instanceof Error?u.message:`${u}`}`)}let i=new CookieJar,a=eOe(fetch,i),s=Date.now(),l=await jp({command:e,baseUrl:void 0,logger:this.logger,fetchImplementation:a}),c=Tm(i,o);return {output:Wd.parse({...l,cookies:c}),success:true,message:`Successfully executed request in ${Date.now()-s}ms`}}case "OPEN_NOTIFICATION_DRAWER":return await new Jc(this.constructPerformerParams()).doPress({keycode:83}),{success:true};case "OPEN_APP":{let o=e.activityName,i=["-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER"];if(!o){let s=["resolve-activity","--brief",...i,e.packageName],l=await ee(this.driver.executeInNativeContext(this.logger,c=>c.execute("mobile: shell",{command:"pm",args:s}),{operationName:"resolveMainActivity"}),{signal:this.abortSignal,milliseconds:1e4});if(typeof l!="string")throw new M("UserConfigurationError",`Could not find main activity name for package ${e.packageName}. Unexpected output: ${l}`);if(l.includes("No activity found"))throw await this.isPackageInstalled(e.packageName)?new M("UserConfigurationError",`App ${e.packageName} is installed but has no launchable MAIN/LAUNCHER activity. Set an explicit "activityName" on the Open App step.`):new M("UserConfigurationError",`App ${e.packageName} isn't installed on the device. Add an "Install App" step (or configure an APK to install) before opening it, or install the app manually, then re-run.`);if(o=l.trim().split(`
|
|
5869
|
-
`).pop()?.replace(/^.*\//,""),!o)throw new M("UserConfigurationError",`Could not parse main activity name for package ${e.packageName}. Raw output: ${l}`)}if(this.options?.emulator?.autoGrantPermissions&&!this.appsWithGrantedPermissions.has(e.packageName)){let s={permissions:"all",appPackage:e.packageName,action:"grant"};await this.driver.executeInNativeContext(this.logger,l=>l.executeScript("mobile: changePermissions",[s]),{operationName:"changePermissions"}),this.appsWithGrantedPermissions.add(e.packageName);}let a=["start",...i,"-f","0x10200000"];if(e.intentExtras)try{let s=JSON.parse(e.intentExtras);for(let[l,c]of Object.entries(s))a.push("-e",l,typeof c=="string"?c:JSON.stringify(c));}catch(s){throw new M("UserConfigurationError",`Invalid intent extras does not parse as valid JSON: ${s instanceof Error?s.message:`${s}`}`)}return a.push("-n",`${e.packageName}/${o}`),await this.driver.executeInNativeContext(this.logger,s=>s.execute("mobile: shell",{command:"am",args:a}),{operationName:"startApp"}),await this.stateManager.waitForPageSourceStability({timeoutMs:3e3,signal:this.abortSignal,reason:"Waiting for stability after app launch"}),this.stateManager.refreshWebviewsManually("new app launch"),{success:true}}case "PRESS":{let o=new Jc(this.constructPerformerParams());switch(e.key){case "HOME":await o.doPress({keycode:3});break;case "BACK":await o.doPress({keycode:4});break;case "APP_SWITCHER":await o.doPress({keycode:187});break;case "POWER":await o.doPress({keycode:26});break;case "SEARCH":await o.doPress({keycode:84});break;case "VOLUME_UP":await o.doPress({keycode:24});break;case "VOLUME_DOWN":await o.doPress({keycode:25});break;case "VOLUME_MUTE":await o.doPress({keycode:164});break}return {success:true}}case "PRESS_KEYBOARD":{let o=new Jc(this.constructPerformerParams()),i=a=>o.doPress({keycode:a,repeat:e.repeat,keyPressDelayMs:e.keyPressDelayMs});switch(e.key){case "CLOSE_KEYBOARD":{let a=Date.now();for(;Date.now()-a<2e3&&(await this.driver.executeInNativeContext(this.logger,l=>l.hideKeyboard(),{operationName:"hideKeyboard"}),!!await this.driver.executeInNativeContext(this.logger,l=>l.isKeyboardShown(),{operationName:"isKeyboardShown"})););break}case "ENTER":await i(66);break;case "BACKSPACE":await i(67);break;}return {success:true}}case "WAIT":return await pe(e.timeoutSecs*1e3,this.aborter.controller?.signal),{success:true};case "VISUAL_DIFF":return new nR(this.constructPerformerParams()).executeVisualDiff({command:e,updateGoldenFiles:r});case "INSTALL_APP":return new XA(this.constructPerformerParams()).doInstallApk(e);case "UNINSTALL_APP":return new rR(this.constructPerformerParams()).doUninstallApk(e);case "ADD_FILE":{let o=await xC(e.file);return await this.driver.executeInNativeContext(this.logger,async i=>{await i.pushFile(e.storageLocation,o),await i.execute("mobile: shell",{command:"am",args:["broadcast","-a","android.intent.action.MEDIA_SCANNER_SCAN_FILE","-d",`file://${e.storageLocation}`]});},{operationName:"addFile",attemptTimeoutMs:12e4}),{success:true}}case "TOGGLE_SETTINGS":return await this.driver.executeInNativeContext(this.logger,async o=>{switch(e.settingsType){case "AIRPLANE_MODE":await o.appiumToggleAirplaneMode();break;case "DATA":await o.appiumToggleData();break;case "WIFI":await o.appiumToggleWiFi();break;case "LOCATION":await o.appiumToggleLocationServices();break;default:throw e.settingsType,new M("UserConfigurationError",`Unknown settings type: ${e.settingsType}`)}},{operationName:"toggleSettings"}),{success:true};case "ROTATE_ORIENTATION":return await this.driver.executeInNativeContext(this.logger,async o=>{await o.execute("mobile: shell",{command:"settings",args:["put","system","accelerometer_rotation","0"]}),await o.execute("mobile: shell",{command:"settings",args:["put","system","user_rotation",e.orientation==="LANDSCAPE"?"1":"0"]});},{operationName:"rotateOrientation"}),{success:true,output:{newViewportBounds:await this.getViewportBounds()}};case "ADB_COMMAND":{let o;try{o=JSON.parse(e.jsonArgs??"[]");}catch(s){throw new M("UserConfigurationError",`Invalid JSON for ADB command arguments: ${s instanceof Error?s.message:`${s}`}`)}let i=C__default.string().array().safeParse(o);if(!i.success)throw new M("UserConfigurationError",`Invalid ADB command arguments: ${i.error.message}`);let a=await this.executeRawADBCommandWithArgs([e.command,...i.data]);return this.logger.info({output:a},"ADB command executed successfully"),{success:true,output:a,message:"ADB command executed successfully"}}case "APPIUM_EXECUTE":{let o=JSON.parse(e.jsonArgs??"{}"),i=await this.driver.executeInNativeContext(this.logger,async a=>a.execute(e.command,o),{attemptTimeoutMs:6e4,maxAttempts:1,operationName:"userAppiumExecuteOperation"});return this.logger.info({output:i},"Appium command executed successfully"),{success:true,output:i,message:"Appium command executed successfully"}}case "KILL_APP":{let o=await this.stateManager.getCurrentPackage();if(!o)throw new M("UserConfigurationError","No package is currently active");await this.driver.executeInNativeContext(this.logger,async i=>{await i.execute("mobile: shell",{command:"input",args:["keyevent","KEYCODE_HOME"]}),await i.terminateApp(o);},{operationName:"killApp"});try{await N8({packageName:o,driver:this.driver,abortSignal:this.abortSignal,logger:this.logger});}catch(i){this.throwIfAborted(),this.logger.warn({err:i,packageName:o},"Failed to remove package from recents, continuing...");}return {success:true}}case "STATE":{await this.stateManager.refreshWebviewsManually("debug cmd");let o=await this.stateManager.getDomState(),i=await this.stateManager.getContexts(),a={xml:o.graph.xml,contexts:i};return this.logger.info({result:a},"State debug command output"),{output:a,success:true}}default:{return {success:true}}}}async initializeSettings(){let{latitude:e,longitude:r}=this.options?.emulator?.geolocation??em;await this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: setGeolocation",{latitude:e,longitude:r}),{operationName:"setGeolocation"}),await Promise.all([this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: shell",{command:"pm",args:["grant","io.appium.settings","android.permission.ACCESS_COARSE_LOCATION"]}),{operationName:"grantCoarseLocationPermission"}),this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: shell",{command:"pm",args:["grant","io.appium.settings","android.permission.ACCESS_FINE_LOCATION"]}),{operationName:"grantFineLocationPermission"}),this.driver.executeInNativeContext(this.logger,n=>n.updateSettings({keyInjectionDelay:Id}),{operationName:"initializeKeyInjectionDelay"})]);}async getScreenshotBase64(){return this.stateManager.getRawScreenshotBase64()}async getScreenshotPngString(){return this.stateManager.getCurrentScreenshotPngString()}async getEmulatorDomState(){return (await this.stateManager.getDomState({})).graph.xml}async executeRawADBCommandWithArgs(e){return this.stateManager.executeRawADBCommandWithArgs(e)}async executeRawADBCommand(e){return this.stateManager.executeRawADBCommand(e)}async softReset(){await F8(this,this.logger),this.fixtures.testContext.resetToInitial();}async getViewportBounds(){return this.stateManager.getViewportBounds()}async waitForScreenshotStability(e){return this.stateManager.waitForScreenshotStability({timeoutMs:e.timeoutMs??3e3,reason:e.reason,signal:this.aborter.controller?.signal})}async getMobileFailureRecoveryPlan(e){return this.generator.getAndroidFailureRecoveryPlan(e,{disableCache:true,abortSignal:this.abortSignal,loggerTags:De(this.logger)})}async waitForPageSourceStability(e){await this.stateManager.waitForPageSourceStability({timeoutMs:e.timeoutMs??3e3,reason:e.reason,signal:this.aborter.controller?.signal});}resetAbortController(e){this.aborter.controller=e??new AbortController;}isAborted(){return this.aborter.controller?.signal.aborted}abort(){this.aborter.controller?.abort();}async cleanup(){await this.stateManager.cleanupWebviews();}get abortSignal(){return this.aborter.controller?.signal}get context(){return this.fixtures.testContext}get localCodeEvalTools(){return this.fixtures.localCodeEvalTools}};var m$e=new pv(30,60*1e3),uk="https://api.momentic.ai",aR,Ite,Cf=t=>{uk=t;},Vy=()=>uk;var uR=t=>{Ite=t;},Ns=()=>Ite,Wt=()=>aR;var $y,ck,_te,Ote,Dte,sR,Lte,Nte=({authInfo:t,apiKey:e,apiClient:r})=>{aR=r,$y=t.orgId,ck=t.userId,_te=t.email,Ote=t.name,Dte=t.pylonEmailHash,sR=e,Lte=t.selfServe;},dk=async({apiClient:t,apiKey:e,skipPrompts:r})=>{let n=await gb({client:t});return Nte({authInfo:n,apiKey:e,apiClient:t}),n},kte=async t=>{if(aR&&$y&&sR)return $y;let e=new Tr({baseUrl:uk,apiKey:t,logger:P});aR=e;try{let r=await e.getAuthInfo();return Nte({authInfo:r,apiKey:t,apiClient:e}),r.orgId}catch(r){throw new Error(`Error checking API key against server: ${r}`,{cause:r})}},an=()=>{if(!$y)throw new Error("Your organization ID is invalid.");return $y},_d=()=>{if(!ck)throw new Error("Your user ID is invalid.");return ck};var dR=()=>_te,Fte=()=>Ote,Bte=()=>Dte,mR=()=>Lte,Ute=()=>{if(!sR)throw new Error("Your API key is invalid.");return sR},lR,cR,Qc=()=>{cR?.abort(),cR=void 0;},pR=(t,e)=>{lR=t,Qc(),cR=new AbortController;let r=cR.signal,n=[t.configFilePath];t.config.environments?.forEach(o=>{if(!o.envFile)return;let i=fr__default.resolve(t.rootDir,o.envFile);try{if(Sn.lstatSync(i).isSymbolicLink())return;Sn.existsSync(i)&&n.push(i);}catch(a){P.warn({err:a},`Failed to check if env file ${i} exists`);}});try{p$e({filesToWatch:n,revalidator:e,signal:r,project:t});}catch(o){P.error({err:o},"Failed to start config file watchers");}};var ht=()=>{if(!lR)throw new Xe("No Momentic project is currently loaded. Open or select a project before invoking this action.");return lR};function p$e({filesToWatch:t,revalidator:e,signal:r,project:n}){P.debug("Starting watch on the following files:"),t.forEach(o=>{P.debug(`- ${o}`);}),t.forEach(o=>{let i=async(s,l)=>{if(s.mtime.getTime()!==l.mtime.getTime()){m$e.increment("setLocalProject")&&P.warn(`A file change under the ${n.rootDir} directory has caused Momentic to reload its configuration more than 30 times in the last minute. Rapid changes to files may indicate your momentic.config.yaml 'include' glob is incorrect. Please ensure temporary, library, and auto-generated files are not included in Momentic's context.`);try{lR=await Promise.resolve(e(n.configFilePath));}catch(c){P.warn({err:c},`Failed to reload Momentic configuration after a change to ${o}; continuing with the previously loaded configuration`);}}};Sn.watchFile(o,{persistent:false},i);let a=()=>{Sn.unwatchFile(o,i),r.removeEventListener("abort",a);};r.addEventListener("abort",a);});}function je(t){return function(...e){let r=e[e.length-1],n=t(...e);Promise.resolve(n).catch(r);}}var h$e="1.0.1",Od=qm({app:"desktop-server",hostname:hostname(),disableConsoleLogs:true}).child({cliVersion:h$e});(async()=>{try{let t=await ib(Od);t.gitBranchName&&Od.addBinding("branch",t.gitBranchName);}catch{}})();var zte=Router();zte.get("/",async(t,e)=>{let r=ht(),n=Wt();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Sr(Od,n,r),i=o?.gitProtectedBranches&&o?.gitBranchName&&o.gitProtectedBranches.includes(o.gitBranchName),{noCache:a,alwaysSaveCache:s}=Ns(),l=!a&&(s||!i);e.status(200).json({saveCaches:l,checkedOutBranch:o?.gitBranchName});});var mk=zte;var y$e=5e3,S$e=[".js",".mjs",".cjs",".ts"];function pk(t={}){let e=Router();function r(){let d=ht();return fr__default.dirname(d.configFilePath)}function n(d){return fr__default.join(r(),...d)}function o(d){let m=fr__default.relative(r(),d);return m?m.split(fr__default.sep):[]}function i(d,m){let p=Sn.statSync(d),f=o(d);return OP.parse({name:m,absolutePath:d,relativePath:f.join(fr__default.sep),pathSegments:f,isDirectory:p.isDirectory(),size:p.size,createdAt:p.birthtime,modifiedAt:p.mtime,accessedAt:p.atime})}function a(d){let m=fr__default.relative(r(),d);return m===""||!m.startsWith("..")&&!fr__default.isAbsolute(m)}async function s(d){let m=ht();return Yu(["*"],{cwd:d,ignore:m.config.exclude??[],maxDepth:1,nodir:false,signal:AbortSignal.timeout(y$e)})}function l(d){let m=d.trimStart().replace(/^file:\/\//,"").replaceAll("\\","/"),p=m.lastIndexOf("/");return p===-1?{directoryText:"",filePrefix:m}:{directoryText:m.slice(0,p+1),filePrefix:m.slice(p+1)}}function c(d){return d.replaceAll("\\","/").split("/").filter(m=>m&&m!==".")}function u({sourceDirectoryPath:d,targetPath:m,isDirectory:p}){let f=fr__default.relative(d,m).split(fr__default.sep).join("/");return p?f?`${f}/`:"./":f}return e.post("/file-reference-suggestions",je(async(d,m,p)=>{let f=b$.safeParse(d.body);if(!f.success){m.status(400).json({error:`Failed to parse file-reference-suggestions body: ${f.error.message}`});return}let{sourceDirectoryPath:h="",value:g}=f.data,y=new Set((f.data.allowedExtensions??S$e).map(R=>R.toLowerCase())),S=l(g);if(S.directoryText.startsWith("/")){m.status(200).json({suggestions:[]});return}let E=fr__default.resolve(r(),...c(h)),v=fr__default.resolve(E,...c(S.directoryText));if(!a(E)||!a(v)){m.status(200).json({suggestions:[]});return}if(!Sn.existsSync(v)||!Sn.statSync(v).isDirectory()){m.status(200).json({suggestions:[]});return}let w;try{w=await s(v);}catch(R){if(R instanceof Error&&R.name==="TimeoutError"){m.status(408).json({error:"Folder listing timed out. This directory may contain too many files."});return}throw R}let _=w.map(R=>{let k=fr__default.join(v,R);return {entryName:R,targetPath:k,isDirectory:Sn.statSync(k).isDirectory()}}),L=S.filePrefix.toLowerCase(),I=_.filter(R=>R.entryName.startsWith(".")||!R.entryName.toLowerCase().startsWith(L)?false:R.isDirectory?true:y.has(fr__default.extname(R.entryName).toLowerCase())).sort((R,k)=>R.isDirectory!==k.isDirectory?R.isDirectory?-1:1:R.entryName.localeCompare(k.entryName)).map(R=>({name:R.entryName,isDirectory:R.isDirectory,value:u({sourceDirectoryPath:E,targetPath:R.targetPath,isDirectory:R.isDirectory})}));m.status(200).json({suggestions:I});})),e.post("/",je(async(d,m,p)=>{let f;try{f=g$.parse(d.body).pathSegments;}catch(v){m.status(400).json({error:`Failed to parse folder read body: ${v}`});return}let h=n(f);if(!Sn.existsSync(h)){m.status(404).json({error:`Path not found: ${f.join(fr__default.sep)}`});return}if(!Sn.statSync(h).isDirectory()){m.status(400).json({error:`Path is not a directory: ${f.join(fr__default.sep)}`});return}let y;try{y=await s(h);}catch(v){if(v instanceof Error&&v.name==="TimeoutError"){m.status(408).json({error:"Folder listing timed out. This directory may contain too many files."});return}throw v}let S=y.map(v=>{let w=fr__default.join(h,v);return i(w,v)});if(t.allowedFileTypes){let v=new Set(t.allowedFileTypes);S=(await Promise.all(S.map(async w=>{if(w.isDirectory||!(w.name.endsWith(".test.yaml")||w.name.endsWith(".module.yaml")))return w;let L=await T$e(w.absolutePath);return L!==void 0&&v.has(L)?w:null}))).filter(w=>w!==null);}let E={absolutePath:h,pathSegments:f,contents:S};m.status(200).json(E);})),e.put("/",je(async(d,m,p)=>{let f;try{f=y$.parse(d.body).pathSegments;}catch(y){m.status(400).json({error:`Failed to parse folder create body: ${y}`});return}let h=n(f);if(Sn.existsSync(h)){m.status(200).json({success:true,message:`Folder already exists: ${f.join(fr__default.sep)}`,pathSegments:f});return}Sn.mkdirSync(h,{recursive:true});let g={success:true,message:`Folder created: ${f.join(fr__default.sep)}`,pathSegments:f};m.status(201).json(g);})),e.patch("/",je(async(d,m,p)=>{let f,h;try{let v=S$.parse(d.body);f=v.pathSegments,h=v.newPathSegments;}catch(v){m.status(400).json({error:`Failed to parse folder update body: ${v}`});return}let g=n(f),y=n(h);if(!Sn.existsSync(g)){m.status(400).json({error:`Folder not found: ${f.join(fr__default.sep)}`});return}if(Sn.existsSync(y)){m.status(400).json({error:`Destination already exists: ${h.join(fr__default.sep)}`});return}let S=fr__default.dirname(y);Sn.existsSync(S)||Sn.mkdirSync(S,{recursive:true}),Sn.renameSync(g,y);let E={success:true,message:`Folder moved from ${f.join(fr__default.sep)} to ${h.join(fr__default.sep)}`,pathSegments:h};m.status(200).json(E);})),e.delete("/",je(async(d,m,p)=>{let f,h=true;try{let E=T$.parse(d.body);f=E.pathSegments,h=E.recursive??!0;}catch(E){m.status(400).json({error:`Failed to parse folder delete body: ${E}`});return}let g=n(f);if(!Sn.existsSync(g)){m.status(200).json({success:true,message:`Folder not found: ${f.join(fr__default.sep)}`,pathSegments:f});return}if(!Sn.statSync(g).isDirectory()){m.status(400).json({error:`Path is not a directory: ${f.join(fr__default.sep)}`});return}try{if(h)Sn.rmSync(g,{recursive:!0,force:!0});else {if(Sn.readdirSync(g).length>0){m.status(409).json({error:`Cannot delete non-empty directory without recursive flag: ${f.join("/")}`});return}Sn.rmdirSync(g);}}catch(E){let{status:v,body:w}=d9(E,`delete folder ${f.join("/")}`);m.status(v).json(w);return}let S={success:true,message:`Folder deleted: ${f.join("/")}`,pathSegments:f};m.status(200).json(S);})),e}async function T$e(t){try{let e=await Sn.promises.open(t,"r");try{let r=Buffer.alloc(4096),{bytesRead:n}=await e.read(r,0,r.length,0);return r.toString("utf-8",0,n).match(/^fileType:\s*(.+)$/m)?.[1]?.trim()}finally{await e.close();}}catch{}}var $te=Router();$te.get("/",async(t,e)=>{let r=ht(),n=Wt();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Sr(Od,n,r);e.status(200).json(o);});var fk=$te;var fR=class t extends Ac{static async init(e){let r=await Ac.connectAppium(e);return new t(r)}async executeWebViewScript(e,r,n,...o){let i=await this.executeInContext(e,r,async a=>{let s=new Function("...args",`${xb.safariUtilsLibJs};
|
|
5869
|
+
`).pop()?.replace(/^.*\//,""),!o)throw new M("UserConfigurationError",`Could not parse main activity name for package ${e.packageName}. Raw output: ${l}`)}if(this.options?.emulator?.autoGrantPermissions&&!this.appsWithGrantedPermissions.has(e.packageName)){let s={permissions:"all",appPackage:e.packageName,action:"grant"};await this.driver.executeInNativeContext(this.logger,l=>l.executeScript("mobile: changePermissions",[s]),{operationName:"changePermissions"}),this.appsWithGrantedPermissions.add(e.packageName);}let a=["start",...i,"-f","0x10200000"];if(e.intentExtras)try{let s=JSON.parse(e.intentExtras);for(let[l,c]of Object.entries(s))a.push("-e",l,typeof c=="string"?c:JSON.stringify(c));}catch(s){throw new M("UserConfigurationError",`Invalid intent extras does not parse as valid JSON: ${s instanceof Error?s.message:`${s}`}`)}return a.push("-n",`${e.packageName}/${o}`),await this.driver.executeInNativeContext(this.logger,s=>s.execute("mobile: shell",{command:"am",args:a}),{operationName:"startApp"}),await this.stateManager.waitForPageSourceStability({timeoutMs:3e3,signal:this.abortSignal,reason:"Waiting for stability after app launch"}),this.stateManager.refreshWebviewsManually("new app launch"),{success:true}}case "PRESS":{let o=new Jc(this.constructPerformerParams());switch(e.key){case "HOME":await o.doPress({keycode:3});break;case "BACK":await o.doPress({keycode:4});break;case "APP_SWITCHER":await o.doPress({keycode:187});break;case "POWER":await o.doPress({keycode:26});break;case "SEARCH":await o.doPress({keycode:84});break;case "VOLUME_UP":await o.doPress({keycode:24});break;case "VOLUME_DOWN":await o.doPress({keycode:25});break;case "VOLUME_MUTE":await o.doPress({keycode:164});break}return {success:true}}case "PRESS_KEYBOARD":{let o=new Jc(this.constructPerformerParams()),i=a=>o.doPress({keycode:a,repeat:e.repeat,keyPressDelayMs:e.keyPressDelayMs});switch(e.key){case "CLOSE_KEYBOARD":{let a=Date.now();for(;Date.now()-a<2e3&&(await this.driver.executeInNativeContext(this.logger,l=>l.hideKeyboard(),{operationName:"hideKeyboard"}),!!await this.driver.executeInNativeContext(this.logger,l=>l.isKeyboardShown(),{operationName:"isKeyboardShown"})););break}case "ENTER":await i(66);break;case "BACKSPACE":await i(67);break;}return {success:true}}case "WAIT":return await pe(e.timeoutSecs*1e3,this.aborter.controller?.signal),{success:true};case "VISUAL_DIFF":return new nR(this.constructPerformerParams()).executeVisualDiff({command:e,updateGoldenFiles:r});case "INSTALL_APP":return new XA(this.constructPerformerParams()).doInstallApk(e);case "UNINSTALL_APP":return new rR(this.constructPerformerParams()).doUninstallApk(e);case "ADD_FILE":{let o=await xC(e.file);return await this.driver.executeInNativeContext(this.logger,async i=>{await i.pushFile(e.storageLocation,o),await i.execute("mobile: shell",{command:"am",args:["broadcast","-a","android.intent.action.MEDIA_SCANNER_SCAN_FILE","-d",`file://${e.storageLocation}`]});},{operationName:"addFile",attemptTimeoutMs:12e4}),{success:true}}case "TOGGLE_SETTINGS":return await this.driver.executeInNativeContext(this.logger,async o=>{switch(e.settingsType){case "AIRPLANE_MODE":await o.appiumToggleAirplaneMode();break;case "DATA":await o.appiumToggleData();break;case "WIFI":await o.appiumToggleWiFi();break;case "LOCATION":await o.appiumToggleLocationServices();break;default:throw e.settingsType,new M("UserConfigurationError",`Unknown settings type: ${e.settingsType}`)}},{operationName:"toggleSettings"}),{success:true};case "ROTATE_ORIENTATION":return await this.driver.executeInNativeContext(this.logger,async o=>{await o.execute("mobile: shell",{command:"settings",args:["put","system","accelerometer_rotation","0"]}),await o.execute("mobile: shell",{command:"settings",args:["put","system","user_rotation",e.orientation==="LANDSCAPE"?"1":"0"]});},{operationName:"rotateOrientation"}),{success:true,output:{newViewportBounds:await this.getViewportBounds()}};case "ADB_COMMAND":{let o;try{o=JSON.parse(e.jsonArgs??"[]");}catch(s){throw new M("UserConfigurationError",`Invalid JSON for ADB command arguments: ${s instanceof Error?s.message:`${s}`}`)}let i=C__default.string().array().safeParse(o);if(!i.success)throw new M("UserConfigurationError",`Invalid ADB command arguments: ${i.error.message}`);let a=await this.executeRawADBCommandWithArgs([e.command,...i.data]);return this.logger.info({output:a},"ADB command executed successfully"),{success:true,output:a,message:"ADB command executed successfully"}}case "APPIUM_EXECUTE":{let o=JSON.parse(e.jsonArgs??"{}"),i=await this.driver.executeInNativeContext(this.logger,async a=>a.execute(e.command,o),{attemptTimeoutMs:6e4,maxAttempts:1,operationName:"userAppiumExecuteOperation"});return this.logger.info({output:i},"Appium command executed successfully"),{success:true,output:i,message:"Appium command executed successfully"}}case "KILL_APP":{let o=await this.stateManager.getCurrentPackage();if(!o)throw new M("UserConfigurationError","No package is currently active");await this.driver.executeInNativeContext(this.logger,async i=>{await i.execute("mobile: shell",{command:"input",args:["keyevent","KEYCODE_HOME"]}),await i.terminateApp(o);},{operationName:"killApp"});try{await N8({packageName:o,driver:this.driver,abortSignal:this.abortSignal,logger:this.logger});}catch(i){this.throwIfAborted(),this.logger.warn({err:i,packageName:o},"Failed to remove package from recents, continuing...");}return {success:true}}case "STATE":{await this.stateManager.refreshWebviewsManually("debug cmd");let o=await this.stateManager.getDomState(),i=await this.stateManager.getContexts(),a={xml:o.graph.xml,contexts:i};return this.logger.info({result:a},"State debug command output"),{output:a,success:true}}default:{return {success:true}}}}async initializeSettings(){let{latitude:e,longitude:r}=this.options?.emulator?.geolocation??em;await this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: setGeolocation",{latitude:e,longitude:r}),{operationName:"setGeolocation"}),await Promise.all([this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: shell",{command:"pm",args:["grant","io.appium.settings","android.permission.ACCESS_COARSE_LOCATION"]}),{operationName:"grantCoarseLocationPermission"}),this.driver.executeInNativeContext(this.logger,n=>n.execute("mobile: shell",{command:"pm",args:["grant","io.appium.settings","android.permission.ACCESS_FINE_LOCATION"]}),{operationName:"grantFineLocationPermission"}),this.driver.executeInNativeContext(this.logger,n=>n.updateSettings({keyInjectionDelay:Id}),{operationName:"initializeKeyInjectionDelay"})]);}async getScreenshotBase64(){return this.stateManager.getRawScreenshotBase64()}async getScreenshotPngString(){return this.stateManager.getCurrentScreenshotPngString()}async getEmulatorDomState(){return (await this.stateManager.getDomState({})).graph.xml}async executeRawADBCommandWithArgs(e){return this.stateManager.executeRawADBCommandWithArgs(e)}async executeRawADBCommand(e){return this.stateManager.executeRawADBCommand(e)}async softReset(){await F8(this,this.logger),this.fixtures.testContext.resetToInitial();}async getViewportBounds(){return this.stateManager.getViewportBounds()}async waitForScreenshotStability(e){return this.stateManager.waitForScreenshotStability({timeoutMs:e.timeoutMs??3e3,reason:e.reason,signal:this.aborter.controller?.signal})}async getMobileFailureRecoveryPlan(e){return this.generator.getAndroidFailureRecoveryPlan(e,{disableCache:true,abortSignal:this.abortSignal,loggerTags:De(this.logger)})}async waitForPageSourceStability(e){await this.stateManager.waitForPageSourceStability({timeoutMs:e.timeoutMs??3e3,reason:e.reason,signal:this.aborter.controller?.signal});}resetAbortController(e){this.aborter.controller=e??new AbortController;}isAborted(){return this.aborter.controller?.signal.aborted}abort(){this.aborter.controller?.abort();}async cleanup(){await this.stateManager.cleanupWebviews();}get abortSignal(){return this.aborter.controller?.signal}get context(){return this.fixtures.testContext}get localCodeEvalTools(){return this.fixtures.localCodeEvalTools}};var m$e=new pv(30,60*1e3),uk="https://api.momentic.ai",aR,Ite,Cf=t=>{uk=t;},Vy=()=>uk;var uR=t=>{Ite=t;},Ns=()=>Ite,Wt=()=>aR;var $y,ck,_te,Ote,Dte,sR,Lte,Nte=({authInfo:t,apiKey:e,apiClient:r})=>{aR=r,$y=t.orgId,ck=t.userId,_te=t.email,Ote=t.name,Dte=t.pylonEmailHash,sR=e,Lte=t.selfServe;},dk=async({apiClient:t,apiKey:e,skipPrompts:r})=>{let n=await gb({client:t});return Nte({authInfo:n,apiKey:e,apiClient:t}),n},kte=async t=>{if(aR&&$y&&sR)return $y;let e=new Tr({baseUrl:uk,apiKey:t,logger:P});aR=e;try{let r=await e.getAuthInfo();return Nte({authInfo:r,apiKey:t,apiClient:e}),r.orgId}catch(r){throw new Error(`Error checking API key against server: ${r}`,{cause:r})}},an=()=>{if(!$y)throw new Error("Your organization ID is invalid.");return $y},_d=()=>{if(!ck)throw new Error("Your user ID is invalid.");return ck};var dR=()=>_te,Fte=()=>Ote,Bte=()=>Dte,mR=()=>Lte,Ute=()=>{if(!sR)throw new Error("Your API key is invalid.");return sR},lR,cR,Qc=()=>{cR?.abort(),cR=void 0;},pR=(t,e)=>{lR=t,Qc(),cR=new AbortController;let r=cR.signal,n=[t.configFilePath];t.config.environments?.forEach(o=>{if(!o.envFile)return;let i=fr__default.resolve(t.rootDir,o.envFile);try{if(Sn.lstatSync(i).isSymbolicLink())return;Sn.existsSync(i)&&n.push(i);}catch(a){P.warn({err:a},`Failed to check if env file ${i} exists`);}});try{p$e({filesToWatch:n,revalidator:e,signal:r,project:t});}catch(o){P.error({err:o},"Failed to start config file watchers");}};var ht=()=>{if(!lR)throw new Xe("No Momentic project is currently loaded. Open or select a project before invoking this action.");return lR};function p$e({filesToWatch:t,revalidator:e,signal:r,project:n}){P.debug("Starting watch on the following files:"),t.forEach(o=>{P.debug(`- ${o}`);}),t.forEach(o=>{let i=async(s,l)=>{if(s.mtime.getTime()!==l.mtime.getTime()){m$e.increment("setLocalProject")&&P.warn(`A file change under the ${n.rootDir} directory has caused Momentic to reload its configuration more than 30 times in the last minute. Rapid changes to files may indicate your momentic.config.yaml 'include' glob is incorrect. Please ensure temporary, library, and auto-generated files are not included in Momentic's context.`);try{lR=await Promise.resolve(e(n.configFilePath));}catch(c){P.warn({err:c},`Failed to reload Momentic configuration after a change to ${o}; continuing with the previously loaded configuration`);}}};Sn.watchFile(o,{persistent:false},i);let a=()=>{Sn.unwatchFile(o,i),r.removeEventListener("abort",a);};r.addEventListener("abort",a);});}function je(t){return function(...e){let r=e[e.length-1],n=t(...e);Promise.resolve(n).catch(r);}}var h$e="1.0.2",Od=qm({app:"desktop-server",hostname:hostname(),disableConsoleLogs:true}).child({cliVersion:h$e});(async()=>{try{let t=await ib(Od);t.gitBranchName&&Od.addBinding("branch",t.gitBranchName);}catch{}})();var zte=Router();zte.get("/",async(t,e)=>{let r=ht(),n=Wt();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Sr(Od,n,r),i=o?.gitProtectedBranches&&o?.gitBranchName&&o.gitProtectedBranches.includes(o.gitBranchName),{noCache:a,alwaysSaveCache:s}=Ns(),l=!a&&(s||!i);e.status(200).json({saveCaches:l,checkedOutBranch:o?.gitBranchName});});var mk=zte;var y$e=5e3,S$e=[".js",".mjs",".cjs",".ts"];function pk(t={}){let e=Router();function r(){let d=ht();return fr__default.dirname(d.configFilePath)}function n(d){return fr__default.join(r(),...d)}function o(d){let m=fr__default.relative(r(),d);return m?m.split(fr__default.sep):[]}function i(d,m){let p=Sn.statSync(d),f=o(d);return OP.parse({name:m,absolutePath:d,relativePath:f.join(fr__default.sep),pathSegments:f,isDirectory:p.isDirectory(),size:p.size,createdAt:p.birthtime,modifiedAt:p.mtime,accessedAt:p.atime})}function a(d){let m=fr__default.relative(r(),d);return m===""||!m.startsWith("..")&&!fr__default.isAbsolute(m)}async function s(d){let m=ht();return Yu(["*"],{cwd:d,ignore:m.config.exclude??[],maxDepth:1,nodir:false,signal:AbortSignal.timeout(y$e)})}function l(d){let m=d.trimStart().replace(/^file:\/\//,"").replaceAll("\\","/"),p=m.lastIndexOf("/");return p===-1?{directoryText:"",filePrefix:m}:{directoryText:m.slice(0,p+1),filePrefix:m.slice(p+1)}}function c(d){return d.replaceAll("\\","/").split("/").filter(m=>m&&m!==".")}function u({sourceDirectoryPath:d,targetPath:m,isDirectory:p}){let f=fr__default.relative(d,m).split(fr__default.sep).join("/");return p?f?`${f}/`:"./":f}return e.post("/file-reference-suggestions",je(async(d,m,p)=>{let f=b$.safeParse(d.body);if(!f.success){m.status(400).json({error:`Failed to parse file-reference-suggestions body: ${f.error.message}`});return}let{sourceDirectoryPath:h="",value:g}=f.data,y=new Set((f.data.allowedExtensions??S$e).map(R=>R.toLowerCase())),S=l(g);if(S.directoryText.startsWith("/")){m.status(200).json({suggestions:[]});return}let E=fr__default.resolve(r(),...c(h)),v=fr__default.resolve(E,...c(S.directoryText));if(!a(E)||!a(v)){m.status(200).json({suggestions:[]});return}if(!Sn.existsSync(v)||!Sn.statSync(v).isDirectory()){m.status(200).json({suggestions:[]});return}let w;try{w=await s(v);}catch(R){if(R instanceof Error&&R.name==="TimeoutError"){m.status(408).json({error:"Folder listing timed out. This directory may contain too many files."});return}throw R}let _=w.map(R=>{let k=fr__default.join(v,R);return {entryName:R,targetPath:k,isDirectory:Sn.statSync(k).isDirectory()}}),L=S.filePrefix.toLowerCase(),I=_.filter(R=>R.entryName.startsWith(".")||!R.entryName.toLowerCase().startsWith(L)?false:R.isDirectory?true:y.has(fr__default.extname(R.entryName).toLowerCase())).sort((R,k)=>R.isDirectory!==k.isDirectory?R.isDirectory?-1:1:R.entryName.localeCompare(k.entryName)).map(R=>({name:R.entryName,isDirectory:R.isDirectory,value:u({sourceDirectoryPath:E,targetPath:R.targetPath,isDirectory:R.isDirectory})}));m.status(200).json({suggestions:I});})),e.post("/",je(async(d,m,p)=>{let f;try{f=g$.parse(d.body).pathSegments;}catch(v){m.status(400).json({error:`Failed to parse folder read body: ${v}`});return}let h=n(f);if(!Sn.existsSync(h)){m.status(404).json({error:`Path not found: ${f.join(fr__default.sep)}`});return}if(!Sn.statSync(h).isDirectory()){m.status(400).json({error:`Path is not a directory: ${f.join(fr__default.sep)}`});return}let y;try{y=await s(h);}catch(v){if(v instanceof Error&&v.name==="TimeoutError"){m.status(408).json({error:"Folder listing timed out. This directory may contain too many files."});return}throw v}let S=y.map(v=>{let w=fr__default.join(h,v);return i(w,v)});if(t.allowedFileTypes){let v=new Set(t.allowedFileTypes);S=(await Promise.all(S.map(async w=>{if(w.isDirectory||!(w.name.endsWith(".test.yaml")||w.name.endsWith(".module.yaml")))return w;let L=await T$e(w.absolutePath);return L!==void 0&&v.has(L)?w:null}))).filter(w=>w!==null);}let E={absolutePath:h,pathSegments:f,contents:S};m.status(200).json(E);})),e.put("/",je(async(d,m,p)=>{let f;try{f=y$.parse(d.body).pathSegments;}catch(y){m.status(400).json({error:`Failed to parse folder create body: ${y}`});return}let h=n(f);if(Sn.existsSync(h)){m.status(200).json({success:true,message:`Folder already exists: ${f.join(fr__default.sep)}`,pathSegments:f});return}Sn.mkdirSync(h,{recursive:true});let g={success:true,message:`Folder created: ${f.join(fr__default.sep)}`,pathSegments:f};m.status(201).json(g);})),e.patch("/",je(async(d,m,p)=>{let f,h;try{let v=S$.parse(d.body);f=v.pathSegments,h=v.newPathSegments;}catch(v){m.status(400).json({error:`Failed to parse folder update body: ${v}`});return}let g=n(f),y=n(h);if(!Sn.existsSync(g)){m.status(400).json({error:`Folder not found: ${f.join(fr__default.sep)}`});return}if(Sn.existsSync(y)){m.status(400).json({error:`Destination already exists: ${h.join(fr__default.sep)}`});return}let S=fr__default.dirname(y);Sn.existsSync(S)||Sn.mkdirSync(S,{recursive:true}),Sn.renameSync(g,y);let E={success:true,message:`Folder moved from ${f.join(fr__default.sep)} to ${h.join(fr__default.sep)}`,pathSegments:h};m.status(200).json(E);})),e.delete("/",je(async(d,m,p)=>{let f,h=true;try{let E=T$.parse(d.body);f=E.pathSegments,h=E.recursive??!0;}catch(E){m.status(400).json({error:`Failed to parse folder delete body: ${E}`});return}let g=n(f);if(!Sn.existsSync(g)){m.status(200).json({success:true,message:`Folder not found: ${f.join(fr__default.sep)}`,pathSegments:f});return}if(!Sn.statSync(g).isDirectory()){m.status(400).json({error:`Path is not a directory: ${f.join(fr__default.sep)}`});return}try{if(h)Sn.rmSync(g,{recursive:!0,force:!0});else {if(Sn.readdirSync(g).length>0){m.status(409).json({error:`Cannot delete non-empty directory without recursive flag: ${f.join("/")}`});return}Sn.rmdirSync(g);}}catch(E){let{status:v,body:w}=d9(E,`delete folder ${f.join("/")}`);m.status(v).json(w);return}let S={success:true,message:`Folder deleted: ${f.join("/")}`,pathSegments:f};m.status(200).json(S);})),e}async function T$e(t){try{let e=await Sn.promises.open(t,"r");try{let r=Buffer.alloc(4096),{bytesRead:n}=await e.read(r,0,r.length,0);return r.toString("utf-8",0,n).match(/^fileType:\s*(.+)$/m)?.[1]?.trim()}finally{await e.close();}}catch{}}var $te=Router();$te.get("/",async(t,e)=>{let r=ht(),n=Wt();if(!n){e.status(500).json({message:"API client not initialized"});return}let o=await Sr(Od,n,r);e.status(200).json(o);});var fk=$te;var fR=class t extends Ac{static async init(e){let r=await Ac.connectAppium(e);return new t(r)}async executeWebViewScript(e,r,n,...o){let i=await this.executeInContext(e,r,async a=>{let s=new Function("...args",`${xb.safariUtilsLibJs};
|
|
5870
5870
|
const userFn = ${n.toString()};
|
|
5871
5871
|
try {
|
|
5872
5872
|
return userFn(momenticFunctions, ...args);
|
|
5873
5873
|
} catch (e) {
|
|
5874
5874
|
return { _failed: true, _error: e.message }
|
|
5875
|
-
}`);return a.execute(s,...o)},{operationName:"executeWebViewScript"});if(i&&typeof i=="object"&&"_failed"in i)throw new Error(`Error executing script in webview: ${i._error||"Unknown error"}`);return i}async healthcheck(){await this.driver.getWindowHandle();}};async function Vte({logger:t,driverLogLevel:e="error",emulator:r,callbacks:n}){let{onStatusUpdate:o}=n,i=t.child({emulatorName:r.name}),a={platformName:"iOS","appium:noReset":true,"appium:fullReset":false,"appium:shouldTerminateApp":false,"appium:forceAppLaunch":false,"appium:autoLaunch":false,"appium:newCommandTimeout":3600,"appium:autoWebview":false,"appium:webviewConnectTimeout":500,"appium:webviewConnectRetries":5,"appium:includeSafariInWebviews":true,"appium:fullContextList":false,"appium:additionalWebviewBundleIds":["*"],"appium:waitForIdleTimeout":0,"appium:reduceMotion":true,"appium:settings":{customSnapshotTimeout:0,animationCoolOffTimeout:0},...r.extraCapabilities};o("Starting Appium session");let s={capabilities:a},l=await fR.init({logger:i,logLevel:e,callbacks:{...n,restartWda:r.restartWda?async c=>{await r.restartWda?.(c);}:void 0,onFailure:async({err:c,attempt:u})=>{let d=IC(c),m=u<3&&d;return m&&i.warn({err:c},"Appium driver manifest race detected on first attempt, restarting Appium and retrying"),{shouldRetry:m}}},wdioOpts:s});return i.info({capabilities:a,emulatorName:r.name},"Started Appium driver"),l}async function hk({wdaUrl:t,token:e}){try{let r=new AbortController;return setTimeout(()=>r.abort(),3e3),await fetch(t+"/status",{headers:{Authorization:`Bearer ${e}`},signal:r.signal}),!0}catch{return false}}var hR={"appium:waitForIdleTimeout":2,"appium:commandTimeouts":"30000","appium:skipLogCapture":true,"appium:disableAutomaticScreenshots":true,"appium:simpleIsVisibleCheck":true};var R$e=["[com.apple.","loadConfigurationForEnvironment"],x$e=["com.apple.Accessibility","com.apple.news","com.apple.locationd","NewsToday","NewsTodayIntents","apsd","APSConfiguration","APSOutgoingQueue","APSCourierConnection","APSNetworkMonitor","loadConfigurationForEnvironment"],M$e=new Set(["D","Df","Db"]),P$e=new Set(["I"]),I$e=/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+\s+(\S+)\s+/,_$e="https://storage.googleapis.com/mobile-drivers/WebDriverAgentRunner-Build-Sim-arm64-v10.4.5.zip",Hte=6e4,O$e=5e3,D$e=250;function L$e(t){let e=I$e.exec(t)?.[1];if(!e)return false;let r=R$e.some(o=>t.includes(o)),n=x$e.some(o=>t.includes(o));return M$e.has(e)?r||n:P$e.has(e)?n:false}async function Wte({wdaUrl:t,token:e,limbarClient:r,logger:n,onStatusUpdate:o}){if(await hk({wdaUrl:t,token:e}))return;o("Starting WebDriverAgent"),n.debug("WDA is not running on the iOS emulator"),await r.simctl(["launch","booted","com.facebook.WebDriverAgentRunner.xctrunner"]).wait();let i=Date.now()+O$e;do{if(await hk({wdaUrl:t,token:e})){n.debug("WDA launched");return}await pe(D$e);}while(Date.now()<i);throw new hh("WebDriverAgent did not become reachable after relaunch")}var jy=class t{apiClient;name;extraCapabilities;limbarToken;limbarWebRtcUrl;limbarApiUrl;limbarWdaUrl;limbarRegion;limbarTag;limbarClient;onStatusUpdate;logStream=void 0;constructor({apiClient:e,limbarToken:r,limbarWebRtcUrl:n,limbarApiUrl:o,limbarWdaUrl:i,limbarRegion:a,limbarTag:s,emulatorName:l,limbarClient:c,onStatusUpdate:u}){this.apiClient=e,this.name=l,this.limbarToken=r,this.limbarWebRtcUrl=n,this.limbarApiUrl=o,this.limbarWdaUrl=i,this.limbarRegion=a,this.limbarTag=s,this.limbarClient=c,this.extraCapabilities={...hR,"appium:automationName":"@limrun/xcuitest","appium:webDriverAgentUrl":this.limbarWdaUrl,"appium:wdaLocalPort":443,"appium:useNewWDA":false,"appium:usePreinstalledWDA":true,"appium:limInstanceApiUrl":o,"appium:limInstanceToken":r,"appium:wdaRequestHeaders":{Authorization:`Bearer ${r}`}},this.onStatusUpdate=u;}static async init(e){let{apiClient:r,logger:n,creationOpts:o,logLevel:i,orgId:a,sessionId:s,onStatusUpdate:l,onConnectionStateChange:c}=e,u=o.appToInstall?.channel,d=o.appToInstall?.tag;l("Creating iOS emulator");let{token:m,webRtcUrl:p,wdaUrl:f,apiUrl:h,id:g,region:y,appDownloadUrl:S,appMd5:E,resolvedTag:v}=await r.createIosEmulator({...o,hostname:hostname(),sessionId:s,installAppOnClient:true});n.info({emulatorName:g,region:y,sessionId:s},"ios instance creation ok"),l("Connecting to iOS emulator");let w;try{w=await Ge.recordDuration({fn:async()=>await createInstanceClient({apiUrl:h,token:m,logLevel:i}),name:"test_event_duration",tags:["name:limbar-client-creation","clientOs:ios",`orgId:${a}`],timeoutMs:Hte,timeoutMessage:`Timed out after ${Hte}ms creating Limbar iOS instance client for emulator ${g} after instance creation succeeded (region: ${y??"unknown"}, channel: ${u??"none"}, tag: ${d??"none"})`}),c&&w.onConnectionStateChange(c),l("Installing WebDriverAgent");let _=w;return await Ge.recordDuration({fn:async()=>{await Gte({limbarClient:_,url:_$e,md5:void 0,logger:n,emulatorName:g,assetLabel:"WebDriverAgent"});},name:"test_event_duration",tags:["name:limbar-wda-install","clientOs:ios",`orgId:${a}`]}),await Wte({wdaUrl:f,token:m,limbarClient:_,logger:n,onStatusUpdate:l}),S&&(l(`Installing iOS app${u?` with channel ${u}`:""}${d?` and tag ${d}`:""}`),await Ge.recordDuration({fn:async()=>{await Gte({limbarClient:_,url:S,md5:E,logger:n,emulatorName:g,assetLabel:"iOS app"});},name:"test_event_duration",tags:["name:limbar-app-install","clientOs:ios",`orgId:${a}`]})),(async()=>{try{let[L,I]=await Promise.allSettled([rp("limserver-1.limrun.net"),rp("125.253.92.199")]);n.info({limserver:L.status==="fulfilled"?L.value:L.reason,ip125:I.status==="fulfilled"?I.value:I.reason},"Limbar network diagnostics");}catch(L){n.warn({err:L},"Failed to run network diagnostics");}})(),new t({apiClient:r,limbarToken:m,limbarWebRtcUrl:p,limbarApiUrl:h,limbarWdaUrl:f,limbarRegion:y,limbarTag:v??d,emulatorName:g,limbarClient:_,onStatusUpdate:l})}catch(_){throw n.warn({err:_,emulatorName:g},"iOS emulator init failed after creation; cleaning up remote instance"),await N$e({apiClient:r,limbarClient:w,id:g,logger:n}),_}}tap(e,r){return this.limbarClient.tap(e,r)}nativeA11yTreeJson(){return this.limbarClient.elementTreeRaw()}async screenshotPngBase64(){let e=await this.limbarClient.screenshot(),r=Buffer.from(e.base64,"base64"),n=oL.decode(r),o=new PNG({width:n.width,height:n.height});return o.data=Buffer.from(n.data),PNG.sync.write(o).toString("base64")}listApps(){return this.limbarClient.listApps()}terminateApp(e){return this.limbarClient.terminateApp(e)}setOrientation(e){return this.limbarClient.setOrientation(e==="LANDSCAPE"?"Landscape":"Portrait")}pressKey(e){return this.limbarClient.pressKey(e)}async resetSettings(){let e=await this.limbarClient.simctl(["privacy","booted","reset","all"]).wait();if(e.code!==0)throw new Error(`simctl privacy reset returned non-zero exit code: ${e.code} stderr: ${e.stderr}`)}async startScreenRecording(){await this.limbarClient.startRecording({quality:RecordingQuality.Q5});}async stopScreenRecording(e){await this.limbarClient.stopRecording({localPath:e});}addSyslogListener(e){this.logStream||(this.logStream=this.limbarClient.streamSyslog());let r=n=>{L$e(n)||e(n);};return this.logStream.on("line",r),()=>{this.logStream?.off("line",r);}}async restartWda(e){await Wte({wdaUrl:this.limbarWdaUrl,token:this.limbarToken,limbarClient:this.limbarClient,logger:e,onStatusUpdate:this.onStatusUpdate});}async close(){try{this.logStream?.stop();}catch{}try{this.limbarClient.disconnect();}catch{}await this.apiClient.deleteIosEmulator(this.name);}};async function N$e(t){let{apiClient:e,limbarClient:r,id:n,logger:o}=t;if(r)try{r.disconnect();}catch(i){o.warn({err:i,emulatorName:n},"Failed to disconnect limbar client during init cleanup");}try{await e.deleteIosEmulator(n);}catch(i){o.warn({err:i,emulatorName:n},"Failed to delete iOS emulator during init cleanup");}}var gk=12e4,gR=6,k$e=1e3;async function Gte(t){let{limbarClient:e,url:r,md5:n,logger:o,emulatorName:i,assetLabel:a}=t,s;for(let l=1;l<=gR;l++)try{await ee(e.installApp(r,{md5:n,timeoutMs:gk}),{milliseconds:gk,message:`Timed out after ${gk}ms installing ${a} on emulator ${i}`});return}catch(c){if(s=c,l===gR)break;let u=k$e*2**(l-1);o.warn({url:r,err:c,emulatorName:i,assetLabel:a,attempt:l,maxAttempts:gR,backoffMs:u},`Failed to install ${a} on Limbar emulator; retrying after backoff`),await pe(u);}throw o.error({url:r,err:s,emulatorName:i,assetLabel:a,maxAttempts:gR},`Failed to install ${a} on Limbar emulator (no more retries)`),new M("UserConfigurationError",`Failed to install ${a} on emulator ${i}: ${s}`)}var F$e=C__default.array(C__default.object({bundle_id:C__default.string(),name:C__default.string()})),yR=class{constructor(e){this.udid=e;}async exec(e,r=[]){return new Promise((n,o)=>{execFile$1("idb",[...e,"--udid",this.udid,...r],(i,a)=>{i?o(i):n(a.trim());});})}async execBuffer(e,r=[]){return new Promise((n,o)=>{execFile$1("idb",[...e,"--udid",this.udid,...r],{encoding:"buffer",maxBuffer:10*1024*1024},(i,a)=>{i?o(i):n(a);});})}async describeDevice(){return this.exec(["describe"])}async tap({x:e,y:r}){await this.exec(["ui","tap"],[Math.round(e).toString(),Math.round(r).toString()]);}async elementTree(){return this.exec(["ui","describe-all"])}async listApps(){let e=await this.exec(["list-apps","--json"]),r=JSON.parse(e);return F$e.parse(r).map(n=>({bundleId:n.bundle_id,name:n.name}))}async terminate(e){await this.exec(["terminate"],[e]);}async pressKey(e){await this.exec(["ui","press"],[e]);}async screenshot(){let e=await this.execBuffer(["screenshot"],["-"]),r=Buffer.from([137,80,78,71,13,10,26,10]);if(e.length<r.length||!e.subarray(0,r.length).equals(r))throw new Error(`idb screenshot returned invalid PNG data (got ${e.length} bytes)`);return e.toString("base64")}async disconnect(){await this.exec(["disconnect"]);}};async function Hy(t){try{return (await new Simctl().getDeviceTypes()).filter(n=>n.includes("iPhone"))}catch(e){return t.warn({err:e},"Got error listing local iPhone device types, returning empty list"),[]}}var B$e=C__default.object({runtimes:C__default.array(C__default.object({version:C__default.string(),name:C__default.string(),isAvailable:C__default.boolean().optional()}))});async function U$e(t){try{let e=new Simctl,{stdout:r}=await e.exec("list",{args:["runtimes","-j"]}),{runtimes:n}=B$e.parse(JSON.parse(r)),o=n.filter(i=>i.isAvailable!==!1&&i.name.toLowerCase().startsWith("ios")).map(i=>i.version);return o.length===0?void 0:o.sort((i,a)=>z$e(a,i))[0]}catch(e){t.warn({err:e},"Failed to detect latest installed iOS runtime version");return}}function z$e(t,e){let r=t.split(".").map(Number),n=e.split(".").map(Number);for(let o=0;o<Math.max(r.length,n.length);o++){let i=(r[o]??0)-(n[o]??0);if(i!==0)return i}return 0}var SR=class t{name;extraCapabilities;simctl;idb;constructor({name:e,simctl:r,idb:n}){this.name=e,this.simctl=r,this.idb=n,this.extraCapabilities={...hR,"appium:automationName":"XCUITest","appium:udid":r.udid??void 0};}static async init(e,r){let n=new Simctl,o=r.emulatorName??`momentic-${Date.now()}`,i=await Hy(e);if(!i.includes(r.deviceType))throw new M("UserConfigurationError",`Invalid device type: ${r.deviceType}. Valid device types are: ${i.join(", ")}. If you are sure the device type is correct, please make sure it is installed and available in Xcode.`);let a=r.iosVersion??await U$e(e);if(!a)throw new M("UserConfigurationError","Could not determine an installed iOS runtime version. Make sure an iOS simulator runtime is installed in Xcode, or specify one with --local-ios-version.");let s;try{let l=await n.createDevice(o,r.deviceType,a);n.udid=l,s=async()=>{try{await n.shutdownDevice();}catch{}await n.deleteDevice();},await n.bootDevice(),await n.startBootMonitor({timeout:12e4}),r.appFilePath&&await n.installApp(r.appFilePath);let c=new yR(l);return new t({name:o,simctl:n,idb:c})}catch(l){throw await s?.(),l}}async tap(e,r){await this.idb.tap({x:e,y:r});}async nativeA11yTreeJson(){return this.idb.elementTree()}async screenshotPngBase64(){return this.idb.screenshot()}async listApps(){return this.idb.listApps()}async terminateApp(e){await this.idb.terminate(e);}async pressKey(e){await this.idb.pressKey(e);}async resetSettings(){}async close(){try{await this.idb.disconnect();}catch{}try{await this.simctl.shutdownDevice();}catch{}await this.simctl.deleteDevice();}};var $$e=5e3;async function Af({creationOpts:t,apiClient:e,logger:r,driverLogLevel:n,orgId:o,sessionId:i,callbacks:a}){let s=Date.now();r.info("Starting ios driver creation");let{onLimbarConnectionStateChange:l,onStatusUpdate:c}=a,u=[],d=async()=>{let p=u.toReversed();for(let f of p)try{await ee(f(),{milliseconds:$$e,fallback:()=>{}});}catch(h){if(ju(h))continue;r.warn({err:h},"Error running cleanup task");}},m;switch(t.type){case "remote":{m=await jy.init({apiClient:e,logger:r,creationOpts:t,orgId:o,sessionId:i,onStatusUpdate:c,onConnectionStateChange:l,logLevel:n});break}case "local":{m=await SR.init(r,t);break}}u.push(async()=>{await m.close();});try{let p=await Vte({logger:r,driverLogLevel:n,emulatorStart:s,emulator:m,apiClient:e,creationOpts:t,orgId:o,sessionId:i,callbacks:a});return u.push(()=>p.close()),p.executeInNativeContext(r,f=>f.getPageSource(),{operationName:"Warm up Appium cache"}).catch(()=>{}),{driver:p,emulator:m,limbarParams:m instanceof jy?{token:m.limbarToken,webRtcUrl:m.limbarWebRtcUrl,region:m.limbarRegion,tag:m.limbarTag,osVersion:t.type==="remote"?t.osVersion:void 0}:void 0,cleanup:d}}catch(p){throw await d(),new Error(`Failed to start Appium driver: ${p}`,{cause:p})}}var H$e=100,W$e=2500,Kte=4e3,G$e="...";async function TR({emulator:t,onLogs:e}){if(!t.addSyslogListener)return;let r=create({fetcher:async o=>{e(o);},resolver:()=>{},scheduler:windowedFiniteBatchScheduler({windowMs:W$e,maxBatchSize:H$e})}),n=o=>{let i=o.toString().trim();i.length!==0&&(i.length>Kte&&(i=i.slice(0,Kte)+G$e),r.fetch(i).catch(()=>{}));};return t.addSyslogListener(n)}var Yte="NATIVE_APP";var K$e=new Set(["id","processId","bundleId","type","accessible","index","x","y","width","height"]),Y$e=new Set([]),X$e=new Set(["name","label","traits"]),J$e=new Set(["live-region","drawing-order"]),Z$e=new Set(["visible","enabled"]);function Xte(t){let e={},r=t.tagName,n=reduce(t.attributes,(o,i)=>(o[i.name]=i.value,o),{});for(let[o,i]of Object.entries(n))K$e.has(o)||o==="class"&&r===i||o==="focusable"&&i==="true"&&n.clickable==="true"||Y$e.has(o)&&i==="false"||X$e.has(o)&&i===""||Z$e.has(o)&&i==="true"||J$e.has(o)&&i==="0"||(e[o]=i);return e.name&&e.label&&e.name===e.label&&delete e.label,e.name&&e.value&&e.name===e.value&&delete e.value,e}function El(t){let e=t.getAttribute("x"),r=t.getAttribute("y"),n=t.getAttribute("width"),o=t.getAttribute("height");if(e===null||r===null||n===null||o===null)return;let i=parseFloat(e),a=parseFloat(r),s=parseFloat(n),l=parseFloat(o);if(!(isNaN(i)||isNaN(a)||isNaN(s)||isNaN(l)))return {x1:i,y1:a,x2:i+s,y2:a+l}}function yk(t,e){let{x1:r,y1:n,x2:o,y2:i}=e;t.setAttribute("bounds",`[${r},${n},${o},${i}]`);}function Q$e(t){let e=t.match(/\[([-\d.]+),([-\d.]+),([-\d.]+),([-\d.]+)\]/);if(!e)return;let r=parseFloat(e[1]),n=parseFloat(e[2]),o=parseFloat(e[3]),i=parseFloat(e[4]);if(!(isNaN(r)||isNaN(n)||isNaN(o)||isNaN(i)||o<r||i<n))return {x1:r,y1:n,x2:o,y2:i}}function ER(t){let e=t.getAttribute("bounds");if(e)return Q$e(e)}function Jte(t,e){if(!e)return true;let r=El(t);return r?Sk(r,e):true}function Sk(t,e){if(!e)return true;let{x1:r,y1:n,x2:o,y2:i}=t;return !(o<e.left||r>e.right||i<e.top||n>e.bottom)}function vR(t){let e=t.cloneNode(true);for(let r of Array.from(e.children)){let n=r;for(let o of Array.from(n.children))n.removeChild(o);}return e.outerHTML}var Zte=new Set(["XCUIElementTypeWebView"]);function oVe(t){if(Zte.has(t.tagName))return true;let e=t.getAttribute("name");if(e&&(e.startsWith("TabDocument")||e.startsWith("BrowserView"))){let r=e.match(/UUID=([A-F0-9-]+)/),n=e.match(/WebViewProcessID=(\d+)/);if(r&&n)return true}return false}function iVe(t){return t.startsWith("XCUIElementType")?t.substring(15):t}function Qte({state:t,originalElement:e,prunedElement:r,isInWebview:n,idInWebview:o}){let{idCounter:i,idToPrunedElement:a,idToOriginalElement:s,idToIdInWebview:l}=t,c=i.value++;r.setAttribute("id",String(c)),a.set(c,r),n?l.set(c,o):s.set(c,e);}function ere(t){if(!Zte.has(t.tagName)&&t.tagName==="XCUIElementTypeOther"&&t.hasAttribute("name")&&t.hasAttribute("label"))return t;for(let e of Array.from(t.children)){let r=ere(e);if(r)return r}}function aVe({webviewNativeRootBounds:t,webviewDocumentRootBounds:e}){let r=t.x1-e.x,n=t.y1-e.y;if(!Number.isFinite(r)||!Number.isFinite(n))return t;let o=t.x2-t.x1,i=t.y2-t.y1;return {x1:r,y1:n,x2:r+o,y2:n+i}}function tre(t,e,r,n){let{document:o}=r,{parentFrameBounds:i,pruneElementsOutsideBounds:a}=n;if(e.type==="element"){let s=o.createElement(e.role||e.tag);if(e.name&&s.setAttribute("name",e.name),e.description&&s.setAttribute("description",e.description),e.classes&&e.classes.length>0&&s.setAttribute("classes",e.classes.join(" ")),e.attrs)for(let[u,d]of Object.entries(e.attrs))s.setAttribute(u,d);let l=e.boundingRect,c={x1:i.x1+l.x,y1:i.y1+l.y,x2:i.x1+l.x+l.width,y2:i.y1+l.y+l.height};if(!Sk(c,a))return;yk(s,c),Qte({state:r,prunedElement:s,isInWebview:true,idInWebview:e.momenticWebviewElementId}),t.appendChild(s);for(let u of e.children)tre(s,u,r,n);}else if(e.type==="text"){let s=o.createElement("text");t.appendChild(s);let l=o.createTextNode(e.text);s.appendChild(l);}}function rre(t,e,r,n){let{pruneElementsOutsideBounds:o}=n,{document:i}=r;Qte({state:r,originalElement:t,prunedElement:e,isInWebview:false});let a=Xte(t);for(let[c,u]of Object.entries(a))e.setAttribute(c,u);let s=El(t);if(s&&yk(e,s),oVe(t)){let{removeWebviewContent:c,injectedWebviewContent:u}=n;if(c)return;if(u&&El(t)){let m=ere(t),p=m?El(m):void 0;if(m&&p){r.webviewRootElement=m,r.webviewRootBounds=p,tre(e,u.root,r,{parentFrameBounds:aVe({webviewNativeRootBounds:p,webviewDocumentRootBounds:u.rootBoundingBox}),pruneElementsOutsideBounds:o});return}}}let l=Array.from(t.childNodes??[]);for(let c of l){let u=c.nodeType;if(u===3){let d=c.nodeValue;d&&d.trim().length>0&&e.appendChild(i.createTextNode(d));continue}if(u===1){let d=c;if(!Jte(d,o))continue;let m=i.createElement(iVe(d.tagName));rre(d,m,r,n),e.appendChild(m);}}}async function Tk(t,e,r){let n=t.parseFromString("<AppiumAUT/>","text/xml"),o=new Map,i=new Map,a=new Map,s={document:n,idToPrunedElement:o,idToOriginalElement:i,idToIdInWebview:a,idCounter:{value:0},webviewRootElement:void 0,webviewRootBounds:void 0},l=n.documentElement;rre(e,l,s,r);let c=new XMLSerializer().serializeToString(n),u=await Eze.format(c,{parser:"xml",plugins:[Tze],printWidth:120,tabWidth:1,singleAttributePerLine:false});return {prunedDocument:n,idToPrunedElement:o,idToOriginalElement:i,idToIdInWebview:a,webviewRootElement:s.webviewRootElement,webviewRootBounds:s.webviewRootBounds,prunedXml:u}}async function nre(t,e){let r=new DOMParser,n=r.parseFromString(t,"text/xml"),o=n.documentElement;if(!o)throw new Error("No root element found in XML");if(o.tagName!=="AppiumAUT")throw new Error("No AppiumAUT element found in XML");let{prunedXml:i,idToPrunedElement:a,idToOriginalElement:s,idToIdInWebview:l,webviewRootElement:c,webviewRootBounds:u}=await Tk(r,o,e);return {xml:i,idToPrunedElement:a,idToOriginalElement:s,idToIdInWebview:l,webviewRootElement:c,webviewRootBounds:u,originalDocument:n}}var ore=(A=>(A.GenericElement="GenericElement",A.Any="Any",A.Other="Other",A.Application="Application",A.Group="Group",A.Window="Window",A.Sheet="Sheet",A.Drawer="Drawer",A.Alert="Alert",A.Dialog="Dialog",A.Button="Button",A.RadioButton="RadioButton",A.RadioGroup="RadioGroup",A.CheckBox="CheckBox",A.DisclosureTriangle="DisclosureTriangle",A.PopUpButton="PopUpButton",A.ComboBox="ComboBox",A.MenuButton="MenuButton",A.ToolbarButton="ToolbarButton",A.Popover="Popover",A.Keyboard="Keyboard",A.Key="Key",A.NavigationBar="NavigationBar",A.TabBar="TabBar",A.TabGroup="TabGroup",A.Toolbar="Toolbar",A.StatusBar="StatusBar",A.Table="Table",A.TableRow="TableRow",A.TableColumn="TableColumn",A.Outline="Outline",A.OutlineRow="OutlineRow",A.Browser="Browser",A.CollectionView="CollectionView",A.Slider="Slider",A.PageIndicator="PageIndicator",A.ProgressIndicator="ProgressIndicator",A.ActivityIndicator="ActivityIndicator",A.SegmentedControl="SegmentedControl",A.Picker="Picker",A.PickerWheel="PickerWheel",A.Switch="Switch",A.Toggle="Toggle",A.Link="Link",A.Image="Image",A.Icon="Icon",A.SearchField="SearchField",A.ScrollView="ScrollView",A.ScrollBar="ScrollBar",A.StaticText="StaticText",A.TextField="TextField",A.SecureTextField="SecureTextField",A.DatePicker="DatePicker",A.TextView="TextView",A.Menu="Menu",A.MenuItem="MenuItem",A.MenuBar="MenuBar",A.MenuBarItem="MenuBarItem",A.Map="Map",A.WebView="WebView",A.IncrementArrow="IncrementArrow",A.DecrementArrow="DecrementArrow",A.Heading="Heading",A.Cell="Cell",A))(ore||{}),ire=C__default.lazy(()=>C__default.object({AXFrame:C__default.string(),AXUniqueId:C__default.string().nullable(),AXLabel:C__default.string().nullable(),AXValue:C__default.string().nullable(),frame:C__default.object({x:C__default.number(),y:C__default.number(),width:C__default.number(),height:C__default.number()}),role:C__default.string(),role_description:C__default.string(),subrole:C__default.string().nullable(),type:C__default.nativeEnum(ore),title:C__default.string().nullable(),help:C__default.string().nullable(),content_required:C__default.boolean(),custom_actions:C__default.array(C__default.string()),enabled:C__default.boolean(),children:C__default.array(ire).default([])}));function lVe(t){return C__default.array(ire).parse(JSON.parse(t))}async function CR(t,e){let r=new DOMParser,n=lVe(t),o=cVe(r,n),{prunedXml:i,idToPrunedElement:a,idToOriginalElement:s}=await Tk(r,o.documentElement,{removeWebviewContent:false,injectedWebviewContent:void 0,pruneElementsOutsideBounds:e.pruneElementsOutsideBounds});return {xml:i,idToPrunedElement:a,idToOriginalElement:s,originalDocument:o,webviewRootElement:void 0,idToIdInWebview:new Map,webviewRootBounds:void 0}}function cVe(t,e){let r=t.parseFromString("<hierarchy/>","text/xml"),n=r.documentElement;for(let o=0;o<e.length;o++){let i=e[o],a=are(i,r);n.appendChild(a);}return r}function are(t,e){let r=t.type,n=e.createElement(r);if(n.setAttribute("type",r),n.setAttribute("x",String(t.frame.x.toFixed(2))),n.setAttribute("y",String(t.frame.y.toFixed(2))),n.setAttribute("width",String(t.frame.width.toFixed(2))),n.setAttribute("height",String(t.frame.height.toFixed(2))),t.AXLabel!==null&&n.setAttribute("label",t.AXLabel),t.AXValue!==null&&n.setAttribute("value",t.AXValue),t.title!==null&&n.setAttribute("title",t.title),t.help!==null&&n.setAttribute("help",t.help),n.setAttribute("enabled",String(t.enabled)),t.children)for(let o=0;o<t.children.length;o++){let i=t.children[o],a=are(i,e);n.appendChild(a);}return n}function Dd(t){let e=[],r=t;for(;r;){let n=r.parentElement;if(!n||n.tagName==="AppiumAUT"){e.unshift(`${r.tagName}[1]`);break}let o=r.tagName,i=Array.from(n.children).filter(s=>s.tagName===o),a=1;for(let s=0;s<i.length;s++)if(i[s]===r){a=s+1;break}e.unshift(`${o}[${a}]`),r=n;}return `/${e.join("/")}`}var wR=class t{driver;emulator;options;lastDomState;lastScreenshot;aborter;constructor({driver:e,emulator:r,aborter:n,options:o}){this.driver=e,this.emulator=r,this.aborter=n,this.options=o;}static async init({driver:e,emulator:r,aborter:n,options:o}){return new t({driver:e,aborter:n,emulator:r,options:o})}async getContexts(e){let r=await this.driver.executeInNativeContext(e,async o=>await o.getContexts({}),{operationName:"getContexts"}),n=r.filter(o=>o!==Yte);return {contexts:r.map(o=>o),webviews:n}}async getRawScreenshotBase64({logger:e,totalAttempts:r=3,signal:n}){let o=ae(),i=n??this.aborter.controller?.signal,a=await o.startAsyncSpan("EMULATOR_READ_STATE",async()=>await Ip(e,()=>this.emulator.screenshotPngBase64(),{maxAttempts:r,signal:i,operationName:"takeScreenshot"}),{name:"Take screenshot",signal:i,timeoutMs:3e4});return this.lastScreenshot={pngString:`data:image/png;base64,${a}`,observedAt:Date.now()},a}async getCurrentScreenshotPngString(e){return `data:image/png;base64,${await this.getRawScreenshotBase64({logger:e,totalAttempts:1})}`}async waitForScreenshotStability({logger:e,timeoutMs:r,signal:n,reason:o,tolerancePercent:i=1}){await ae().startAsyncSpan("WAIT_FOR_SCREENSHOT_STABILITY",async a=>{a.attributes.reason=o;let s=Km({signal:n,timeoutMs:r}),l,c=false;for(;!s.aborted;){let u=Date.now();if(l)try{let m=await this.getRawScreenshotBase64({logger:e,totalAttempts:1,signal:s});if(wc(l,m)<=i){c=!0;break}l=m;}catch(m){e.warn({err:m},"Failed to get screenshot during stability wait");}else try{l=await this.getRawScreenshotBase64({logger:e,totalAttempts:1,signal:s});}catch(m){e.warn({err:m},"Failed to get initial screenshot during stability wait");}let d=Math.max(250,Date.now()-u);await ms(Math.min(1e4,d),s);}c||(a.attributes.timedOut=true,e.warn({purpose:o},"Timed out waiting for screenshot stability"));});}async waitForPageSourceStability({logger:e,timeoutMs:r,signal:n,reason:o}){await ae().startAsyncSpan("WAIT_FOR_PAGE_STABILITY",async i=>{i.attributes.reason=o;let a=Km({signal:n,timeoutMs:r}),s,l=false;for(;!a.aborted;){let c,u=Date.now();try{c=await ee(this.emulator.nativeA11yTreeJson(),{milliseconds:1e4,signal:a,message:"Getting the native accessibility tree timed out after 10s"});let m=createHash("md5").update(c).digest("hex");if(s&&s===m){l=!0;break}s=m;}catch(m){e.warn({err:m},"Failed to get page source during stability wait");}let d=Math.max(250,Date.now()-u);await ms(Math.min(1e4,d),a);}l||(i.attributes.timedOut=true,e.warn({purpose:o},"Timed out waiting for page source stability"));});}async getActiveWebview(e){let n=(await this.getContexts(e)).webviews;if(n.length>1)throw new M("UserInfrastructureError","Multiple active webviews in a single package is currently not supported");return n[0]}async getActiveWebviewContent(e){let r=await this.getActiveWebview(e);if(!r)return;this.throwIfAborted();let n=await this.driver.executeWebViewScript(e,r,o=>o.dumpA11yTree());return {context:r,...n}}async getDomState(e,r){let o=await ae().startAsyncSection("Get emulator state XML",async()=>{let a=r?.filterOffscreenElements??true?await this.getViewportBounds(e):void 0,s;if(!r?.skipFetchingFullWebviewContent)try{s=await this.getActiveWebviewContent(e);}catch(u){e.error({err:u},"Could not get webview info to get the nested DOM state");}if(this.throwIfAborted(),!s&&this.options?.disableMomenticAccessibilityTree){let u=await this.getNativePageSource();this.throwIfAborted();let d=await CR(u,{pruneElementsOutsideBounds:a});return {sourceTree:"native",graph:d,webviewContent:void 0}}let l=await this.getAppiumPageSource(e);return this.throwIfAborted(),{graph:await nre(l,{injectedWebviewContent:s,removeWebviewContent:r?.removeWebviewContent,pruneElementsOutsideBounds:a}),sourceTree:"appium",webviewContent:s}});return this.recordDomState(o),o}async getLastObservedState(){let e=this.lastDomState,r=this.lastScreenshot;if(!e||!r)return;let n=Date.now(),o=3e4;if(!(n-e.observedAt>o||n-r.observedAt>o||Math.abs(e.observedAt-r.observedAt)>5e3))return {emulatorState:e.state,screenshot:r.pngString}}recordDomState(e){this.lastDomState={state:e,observedAt:Date.now()};}async getNativePageSource(){return await ae().startAsyncSpan("EMULATOR_READ_STATE",async()=>this.emulator.nativeA11yTreeJson(),{name:"Get iOS page source",signal:this.aborter.controller?.signal,timeoutMs:3e4})}async getAppiumPageSource(e,r){let n=r??this.aborter.controller?.signal;return await ae().startAsyncSpan("EMULATOR_READ_STATE",()=>this.driver.executeInNativeContext(e,i=>i.getPageSource(),{signal:n,operationName:"getPageSource"}),{name:"Get page source",signal:n,timeoutMs:3e4})}async getViewportBounds(e){let r=await this.driver.executeInNativeContext(e,async n=>n.getWindowRect(),{operationName:"getViewportBounds"});return {left:r.x,top:r.y,right:r.x+r.width,bottom:r.y+r.height}}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}};async function lre({command:t,logger:e,generator:r,aiSettings:n,getEmulatorDomState:o,getScreenshotBase64:i,throwIfAborted:a,abortSignal:s}){let l=ae(),c=t.contextChoice==="VISION_ONLY",u=15,d=t.timeoutSecs?t.timeoutSecs*1e3:5e3,m=Pv(d),p=Date.now(),f=0,h,g=false,y;for(;f<u&&!g;){a(),g||h&&h-p>=d&&(g=true),f!==0&&await pe(m,s),h=Date.now();try{let S="",E="";await l.startAsyncSpan("EMULATOR_READ_STATE",async()=>{c||(S=await o()),E=await i();},{name:"Get emulator state"});let v=await r.evaluateIosAssertion({assertion:t.assertion,screenXml:S,screenshot:E,contextChoice:t.contextChoice},{logger:e,loggerTags:De(e),agentConfigVersion:n.agentConfig?.["ios-assertion"]});if(v.result)return {success:v.result,message:v.thoughts};{let w=`AssertionFailureError: ${v.thoughts}`;y=new Error(w);}}catch(S){if(a(),NS(S))throw S;e.info({err:S},`AI check assert attempt ${f} failed, retrying...`),y=S instanceof Error?S:new Error(`${S}`);}finally{f++;}}return {success:false,message:y?.message}}async function cre({command:t,logger:e,generator:r,aiSettings:n,getEmulatorDomState:o,getScreenshotBase64:i,abortSignal:a}){if(!t.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(t.schema){let u=Vm(t.schema);if(u)throw new M("UserConfigurationError",u)}let s=ae(),l="",c="";return await s.startAsyncSpan("EMULATOR_READ_STATE",async()=>{l=await o(),c=await i();},{name:"Get emulator state"}),await s.startAsyncSpan("AI_EXTRACTION_CALL",async u=>{try{let d=await r.getIosTextExtraction({goal:t.goal,emulatorState:l,returnSchema:t.schema,screenshot:`data:image/png;base64,${c}`},{disableCache:!!t.disableCache,abortSignal:a,loggerTags:De(e),agentConfigVersion:n.agentConfig?.["ios-text-extraction"]});if(u.result=d,LC({tracer:s,span:u,screenshot:c,emulatorState:l,logger:e}),d.result==="NOT_FOUND")return {success:!1,message:"No relevant data found for extraction goal on this page"};if(d.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",d.thoughts);return {success:!0,output:d.result,message:d.thoughts}}catch(d){let m=W(d);throw m.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step instead."):m.includes("AIProviderError")&&m.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:d}}):d}})}function Ld(t){let{x1:e,y1:r,x2:n,y2:o}=t.bounds;return {left:e,top:r,width:n-e,height:o-r}}var vi="element-6066-11e4-a52e-4f735466cecf";function ks(t,e){return Math.abs(t-e)<1}function Rf(t,e){let r=e.x2-e.x1,n=(e.x1+e.x2)/2,o=(t.x1+t.x2)/2;if(!ws(e.tolerance,n,o,Math.min(1,r)))return false;let i=e.y2-e.y1,a=(e.y1+e.y2)/2,s=(t.y1+t.y2)/2;return ws(e.tolerance,a,s,Math.min(1,i))}function xf(t,e){let r=t.x2-t.x1,n=t.y2-t.y1;return ws(e.tolerance,e.width,r,Math.min(1,e.width))?ws(e.tolerance,e.height,n,Math.min(1,e.height)):false}function Nd(t){return t.type==="WEBVIEW",t.cache}function kd(t){let{command:e,cacheKey:r="cache",targetName:n="target",updatedCache:o}=t;gP(e)&&(e[r]={...e[r],[n]:um.parse(o)},t.updatedWithAI&&(e[r].updatedAt=new Date,e[r].updatedAtLoggerTags=De(t.logger)));}var Wy="name";async function ure(t,e,r){return await e.executeInNativeContext(t,n=>n.isElementDisplayed(r),{operationName:"isElementRendered"})}async function Mf(t,e,r,n){return await e.executeInNativeContext(t,o=>o.getElementAttribute(r,n),{operationName:"getAttributeFromIosElement"})}async function Ek(t,e,r){return await e.executeInNativeContext(t,async n=>{try{let o=await n.findElement("xpath",r);if(!o)return null;let i=o[vi];if(!i)return null;let a=await n.getElementRect(i);return {elementId:i,rect:a}}catch{return null}},{operationName:"findElementByXPath"})}async function dre(t,e,r){let n=Dd(r),o=await Ek(t,e,n);if(o)return {xPath:n,...o}}async function vk({logger:t,emulatorState:e,driver:r,idInWebview:n,requirements:o}){let i=e.graph.webviewRootElement?Dd(e.graph.webviewRootElement):void 0;if(!i||!e.webviewContent||!e.graph.webviewRootBounds)throw new Error("Cannot build webview target cache without webview root information");let a=await mVe({logger:t,driver:r,webviewRootBounds:e.graph.webviewRootBounds,nodeIdInWebview:n,aiGeneratedRequirements:o,webviewContent:e.webviewContent});if(!a)throw new Error("Failed to build browser cache for webview element");return {xPath:i,bounds:[e.graph.webviewRootBounds.x1,e.graph.webviewRootBounds.y1,e.graph.webviewRootBounds.x2,e.graph.webviewRootBounds.y2],browserCache:a}}async function mVe({logger:t,driver:e,webviewRootBounds:r,nodeIdInWebview:n,aiGeneratedRequirements:o,webviewContent:i}){let a=await e.executeWebViewScript(t,i.context,(c,u,d,m)=>c.generateCacheFromWebviewElementId(u,d,m),i.generatedAt,n,{attributesToFetch:o?.attributesRequired??[]});if(!a)return;let s=a.textContent??void 0,l={x:r.x1-i.rootBoundingBox.x+a.boundingBox.x,y:r.y1-i.rootBoundingBox.y+a.boundingBox.y,width:a.boundingBox.width,height:a.boundingBox.height};return {id:a.id,generatedSelectors:a.selectors,boundingBox:l,requirements:{text:o?.textRequired?s:void 0,attributes:a.attributes,boundingBox:o?.boundsRequired?l:void 0,shape:o?.shapeSpecificity?{tolerance:o.shapeSpecificity,width:a.boundingBox.width,height:a.boundingBox.height}:void 0,position:o?.positionSpecificity?{tolerance:o.positionSpecificity,x1:l.x,y1:l.y,x2:l.x+l.width,y2:l.y+l.height}:void 0}}}async function pVe(t,e,r,n){if(!n||!n.length)return;let o={};for(let i of n){let a=await Mf(t,e,r,i);a!==null&&(o[i]=a);}return Object.keys(o).length?o:void 0}async function mre({logger:t,driver:e,node:r,requirements:n}){let o=await dre(t,e,r);if(!o){t.warn("Failed to generate valid xPath selector for element");return}let{xPath:i,rect:a,elementId:s}=o,l={x1:a.x,y1:a.y,x2:a.x+a.width,y2:a.y+a.height};return {xPath:i,bounds:[l.x1,l.y1,l.x2,l.y2],requirements:{requiredText:n?.textRequired?await Mf(t,e,s,Wy)??void 0:void 0,requiredAttributes:await pVe(t,e,s,n?.attributesRequired?.filter(c=>!(n.textRequired&&c===Wy))),requiredBounds:n?.boundsRequired,position:n?.positionSpecificity?{x1:l.x1,y1:l.y1,x2:l.x2,y2:l.y2,tolerance:n?.positionSpecificity}:void 0,shape:n?.shapeSpecificity?{width:l.x2-l.x1,height:l.y2-l.y1,tolerance:n?.shapeSpecificity}:void 0}}}async function pre({logger:t,driver:e,aiResponse:r,description:n,emulatorState:o}){let i=o.graph.idToPrunedElement.get(r.id);if(!i)throw new Error(`Could not find node with id: ${r.id}`);let a=ER(i);if(!a)throw new Error(`Could not determine bounds for element with id: ${r.id}, description: ${n}`);let s=[];for(let{id:d,requirements:m}of r.additionalElements??[]){let p=o.graph.idToIdInWebview.get(d);if(p!==void 0){try{let g=await vk({logger:t,driver:e,emulatorState:o,idInWebview:p,requirements:m});s.push(g);}catch(g){t.warn({err:g},`Failed to build webview cache for related element with id: ${d}`);}continue}let f=o.graph.idToOriginalElement.get(d);if(!f){t.warn(`Could not find original element for additional element with id: ${d}`);continue}let h=await mre({logger:t,driver:e,node:f,requirements:m});h&&s.push(h);}let l=o.graph.idToIdInWebview.get(r.id);if(l!==void 0){let d={type:"WEBVIEW",bounds:a,cache:{type:"WEBVIEW"}};try{let m=await vk({logger:t,driver:e,emulatorState:o,idInWebview:l,requirements:r.requirements});return {...d,cache:{type:"WEBVIEW",resolvedDescription:n,requiredRelatedElements:s,...m}}}catch(m){return t.warn({err:m},"Failed to build webview target cache"),d}}let c=o.graph.idToOriginalElement.get(r.id);if(!c)throw new Error(`Node isn't in a webview but couldn't find original node for id: ${r.id}, description: ${n}`);let u=await mre({logger:t,driver:e,node:c,requirements:r.requirements});return u?{type:"NATIVE",bounds:a,cache:{type:"NATIVE",...u,resolvedDescription:n,sourceTree:"appium",requiredRelatedElements:s,elementOnlySerializedXml:vR(c)}}:(t.warn("Failed to generate valid cache for element"),{type:"NATIVE",cache:{type:"NATIVE"},bounds:a})}async function Ck({logger:t,driver:e,stateManager:r,parentWebviewBounds:n,cache:o}){if(!o||!o.generatedSelectors)throw new Pe("Cache is missing required attributes");let i=await r.getActiveWebview(t);if(!i)throw new Pe("No active webview context found");let a=await e.executeWebViewScript(t,i,(u,d)=>u.resolveWebviewTargetCache(d),{selectors:o.generatedSelectors,attributesToFetch:Object.keys(o.requirements?.attributes??{})});if(!a)throw new Pe("Failed to resolve webview target using cache");let s=n.x1-a.rootBoundingBox.x+a.boundingBox.x,l=n.y1-a.rootBoundingBox.y+a.boundingBox.y,c={x1:s,y1:l,x2:s+a.boundingBox.width,y2:l+a.boundingBox.height};return o.requirements&&fVe(t,c,a,o.requirements),c}function fVe(t,e,r,n){if(!n)return;let{attributes:o,text:i,position:a,shape:s}=n;if(i!==void 0&&i.length>0&&r.textContent!==i)throw new Pe(`Text content mismatch: expected "${i}", got "${r.textContent}"`);if(o)for(let[l,c]of Object.entries(o)){let u=r.attributes[l];if(u!==c)throw new Pe(`Attribute ${l} mismatch: expected "${c}", got "${u}"`)}if(a&&!Rf(e,a))throw new Pe(`Position mismatch: expected ${JSON.stringify(a)}, got ${JSON.stringify(e)}`);if(s&&!xf(e,s))throw new Pe(`Shape mismatch: expected ${JSON.stringify(s)}, got ${JSON.stringify(e)}`)}async function fre(t,e,r,n,o){if(!n)return;let{requiredAttributes:i,requiredText:a,requiredBounds:s,position:l,shape:c}=n;if(a!==void 0&&a.length>0){let u=await Mf(t,e,r,Wy);if(u!==a)throw new Pe(`Resolved element text mismatch: expected ${a}, got ${u}`)}if(i)for(let[u,d]of Object.entries(i)){let m=await Mf(t,e,r,u)??void 0;if(m!==d)throw new Pe(`Attribute ${u} mismatch: expected ${d}, got ${m}`)}if(s&&o){let{originalBounds:u,newBounds:d}=o;if(!u)throw new Pe("Cannot validate bounds requirements without original bounds in cache");if(!(ks(u.x1,d.x1)&&ks(u.y1,d.y1)&&ks(u.x2,d.x2)&&ks(u.y2,d.y2))){let p=f=>`[${f.x1},${f.y1},${f.x2},${f.y2}]`;throw new Pe(`Bounds changed from ${p(u)} to ${p(d)}`)}}if(l&&o&&!Rf(o.newBounds,l))throw new Pe(`Position mismatch: expected ${JSON.stringify(l)}, got ${JSON.stringify(o.newBounds)}`);if(c&&o&&!xf(o.newBounds,c))throw new Pe(`Shape mismatch: expected ${JSON.stringify(c)}, got ${JSON.stringify(o.newBounds)}`)}async function hre({logger:t,driver:e,xPath:r,elementType:n,skipVisibilityCheck:o=false}){let i=await Ek(t,e,r);if(!i)throw new Pe(`Could not resolve ${n} via XPath: ${r}`);let{elementId:a}=i;if(!o&&!await ure(t,e,a))throw new Pe(`${n} resolved via XPath is not rendered: ${r}`);return i}async function gre({target:t,driver:e,stateManager:r,logger:n}){if(!t.xPath)throw new Pe(`Could not resolve cached target via XPath: ${t.xPath}`);if(t.requiredRelatedElements){let s=t.requiredRelatedElements;for(let l of s){let{elementId:c,rect:u}=await hre({logger:n,driver:e,xPath:l.xPath,elementType:"related element",skipVisibilityCheck:!!l.browserCache});if(l.browserCache){let d={x1:u.x,y1:u.y,x2:u.x+u.width,y2:u.y+u.height};await Ck({logger:n,driver:e,stateManager:r,parentWebviewBounds:d,cache:l.browserCache});}else await fre(n,e,c,l.requirements);}}let{elementId:o,rect:i}=await hre({logger:n,driver:e,xPath:t.xPath,elementType:"element",skipVisibilityCheck:t.type==="WEBVIEW"}),a={x1:i.x,y1:i.y,x2:i.x+i.width,y2:i.y+i.height};if(t.type==="WEBVIEW"){let s=await Ck({logger:n,driver:e,stateManager:r,parentWebviewBounds:a,cache:t.browserCache});return {type:"WEBVIEW",bounds:s,cache:t}}return await fre(n,e,o,t.requirements,{originalBounds:t.bounds?{x1:t.bounds[0],y1:t.bounds[1],x2:t.bounds[2],y2:t.bounds[3]}:void 0,newBounds:a}),{type:"NATIVE",bounds:a,cache:{...t,bounds:[a.x1,a.y1,a.x2,a.y2]}}}function yre({aiResponse:t,description:e,emulatorState:r}){let n=r.graph.idToPrunedElement.get(t.id);if(!n)throw new Error(`Could not find node with id: ${t.id}`);let o=ER(n);if(!o)throw new Error(`Could not determine bounds for element with id: ${t.id}, description: ${e}`);let i=r.graph.idToOriginalElement.get(t.id);if(!i)throw new Error(`Node isn't in a webview but couldn't find original node for id: ${t.id}, description: ${e}`);let a=Dd(i),s=vR(i),l=bre({requirements:t.requirements,element:i}),c=(t.additionalElements??[]).map(({id:u,requirements:d})=>{let m=r.graph.idToOriginalElement.get(u);return m?{xPath:Dd(m),requirements:bre({requirements:d,element:m})}:void 0}).filter(u=>!!u);return {type:"NATIVE",bounds:o,cache:{type:"NATIVE",bounds:[o.x1,o.y1,o.x2,o.y2],resolvedDescription:e,sourceTree:r.sourceTree,xPath:a,elementOnlySerializedXml:s,requirements:l,requiredRelatedElements:c}}}function bre({requirements:t,element:e}){let r;if((t?.positionSpecificity||t?.shapeSpecificity)&&(r=El(e),!r))throw new M("ActionFailureError","Element to cache has no bounds or unexpected bounds format");return {requiredText:t?.textRequired?e.textContent??void 0:void 0,requiredAttributes:hVe(e,t?.attributesRequired),requiredBounds:t?.boundsRequired,position:t?.positionSpecificity?{x1:r.x1,y1:r.y1,x2:r.x2,y2:r.y2,tolerance:t?.positionSpecificity}:void 0,shape:t?.shapeSpecificity?{width:r.x2-r.x1,height:r.y2-r.y1,tolerance:t?.shapeSpecificity}:void 0}}function hVe(t,e){if(t&&!(!e||e.length===0))return Object.fromEntries(e.map(r=>[r,t.getAttribute(r)]).filter(([,r])=>r!==null))}async function Tre(t,e,r,n){if(!r)return;let{requiredAttributes:o,requiredText:i,requiredBounds:a,position:s,shape:l}=r;if(i!==void 0&&i.length>0){let c=e.textContent;if(c!==i)throw new Pe(`Resolved element text mismatch: expected ${i}, got ${c}`)}if(o)for(let[c,u]of Object.entries(o)){let d=e.getAttribute(c)??void 0;if(d!==u)throw new Pe(`Attribute ${c} mismatch: expected ${u}, got ${d}`)}if(a&&n){let{originalBounds:c,newBounds:u}=n;if(!c)throw new Pe("Cannot validate bounds requirements without original bounds in cache");if(!(ks(c.x1,u.x1)&&ks(c.y1,u.y1)&&ks(c.x2,u.x2)&&ks(c.y2,u.y2))){let m=p=>`[${p.x1},${p.y1},${p.x2},${p.y2}]`;throw new Pe(`Bounds changed from ${m(c)} to ${m(u)}`)}}if(s&&n&&!Rf(n.newBounds,s))throw new Pe(`Position mismatch: expected ${JSON.stringify(s)}, got ${JSON.stringify(n.newBounds)}`);if(l&&n&&!xf(n.newBounds,l))throw new Pe(`Shape mismatch: expected ${JSON.stringify(l)}, got ${JSON.stringify(n.newBounds)}`)}async function Ere({target:t,logger:e,emulator:r}){if(!t.xPath)throw new Pe(`Could not resolve cached target via XPath: ${t.xPath}`);let n=await r.nativeA11yTreeJson(),o=await CR(n,{pruneElementsOutsideBounds:void 0});return await wk({target:t,logger:e,document:o.originalDocument})}async function wk({target:t,logger:e,document:r}){if(!t.xPath)throw new Pe(`Could not resolve cached target via XPath: ${t.xPath}`);let n=t.xPath;if(t.requiredRelatedElements){let a=t.requiredRelatedElements;for(let s of a){let l=lte.evaluateXPathToFirstNode(s.xPath,r);if(!l)throw new Pe(`Required related element not found for XPath: ${s.xPath}`);await Tre(e,l,s.requirements);}}let o=lte.evaluateXPathToFirstNode(n,r);if(!o)throw new Pe(`Could not resolve cached target via XPath: ${n}`);let i=El(o);if(!i)throw new Pe(`Could not determine bounds for cached target via XPath: ${n}`);return await Tre(e,o,t.requirements,{originalBounds:t.bounds?{x1:t.bounds[0],y1:t.bounds[1],x2:t.bounds[2],y2:t.bounds[3]}:void 0,newBounds:i}),{type:"NATIVE",bounds:i,cache:{...t,bounds:[i.x1,i.y1,i.x2,i.y2]}}}async function vre({logger:t,driver:e,aiResponse:r,description:n,emulatorState:o}){switch(o.sourceTree){case "appium":return await pre({logger:t,driver:e,aiResponse:r,description:n,emulatorState:o});case "native":return await yre({aiResponse:r,description:n,emulatorState:o});default:{let i=o.sourceTree;throw new Error(`Unsupported source tree type for building iOS target cache: ${i}`)}}}async function Cre({target:t,driver:e,stateManager:r,logger:n,emulator:o}){if(t.type==="WEBVIEW"||!t.sourceTree||t.sourceTree=="appium")return await gre({target:t,driver:e,stateManager:r,logger:n});switch(t.sourceTree){case "native":return await Ere({target:t,logger:n,emulator:o});default:{let i=t.sourceTree;throw new Error(`Unsupported source tree type for resolving iOS target cache: ${i}`)}}}var Ur=class{emulator;driver;stateManager;generator;fixtures;orgId;aiSettings;emulatorSettings;aborter;constructor(e){this.stateManager=e.stateManager,this.driver=e.driver,this.emulator=e.emulator,this.aborter=e.aborter,this.fixtures=e.fixtures,this.orgId=e.orgId,this.generator=e.generator,this.aiSettings=e.aiSettings,this.emulatorSettings=e.emulatorSettings;}async findElement({logger:e,tracer:r,description:n,skipFetchingFullWebviewContent:o=false,removeWebviewContent:i=false,filterOffscreenElements:a=true,useMemory:s=false,metadata:l,cacheBustReason:c,knownState:u}){let d=e.child({...l});u||await this.stateManager.waitForScreenshotStability({logger:e,timeoutMs:5e3,signal:this.aborter.controller?.signal,reason:"Waiting for stability before locating an element with AI"});let{emulatorState:m,screenshot:p}=u??await r.startAsyncSection("Get emulator state",async()=>{let g=await this.stateManager.getCurrentScreenshotPngString(e);return {emulatorState:await this.stateManager.getDomState(e,{skipFetchingFullWebviewContent:o,removeWebviewContent:i,filterOffscreenElements:a}),screenshot:g}}),f;try{f=await r.startAsyncSpan("AI_LOCATOR_CALL",async g=>{c&&(g.attributes.cacheBustReason=c);let y=await this.generator.getIosElementLocation({description:n,screenXml:m.graph.xml,screenshot:p,source:l?.source==="SCROLL_TO"?"SCROLL_TO":void 0},{logger:d,loggerTags:De(d),abortSignal:this.aborter.controller?.signal,useMemory:s,agentConfigVersion:this.aiSettings.agentConfig?.["ios-locator"]});return g.result=y,y});}catch(g){throw this.throwIfAborted(),d.error({err:g},"Failed to locate element"),new Error(`ActionFailureError: Failed to locate element: ${g instanceof Error?g.message:g}`,{cause:g})}if(f.id===-1)throw new M("NoMatchingElementError",f.thoughts??"No matching element found");let h=await vre({logger:e,driver:this.driver,aiResponse:f,description:n,emulatorState:m});return r.addSpan({type:"TARGET_RESOLUTION",startTime:Date.now(),endTime:Date.now(),result:{serializedElement:(h.type==="NATIVE"?h.cache.elementOnlySerializedXml:void 0)??"Unknown element"},attributes:{},subSpans:[]}),{resolvedTarget:h,thoughts:f.thoughts}}async targetingActionWithAILocator(e){let{tracer:r,action:n,command:o,description:i,cacheKey:a,targetName:s,skipFetchingFullWebviewContent:l,removeWebviewContent:c,metadata:u,logger:d,cacheBustReason:m}=e,p=await this.findElement({logger:d,tracer:r,description:i,skipFetchingFullWebviewContent:l,removeWebviewContent:c,metadata:u,cacheBustReason:m}),f=p.thoughts,h=await n(p.resolvedTarget);return kd({command:o,cacheKey:a,targetName:s,updatedCache:Nd(p.resolvedTarget),updatedWithAI:true,logger:d}),{result:h,thoughts:f}}async targetingActionWithCache({logger:e,tracer:r,action:n,command:o,cacheKey:i,targetName:a,cacheCopyForAttempt:s}){this.emulatorSettings?.waitForStability!==false&&await this.stateManager.waitForScreenshotStability({logger:e,timeoutMs:5e3,signal:this.aborter.controller?.signal,reason:"Waiting for stability before cache resolution"});let l=await this.resolveTargetCacheWithTracing({logger:e,tracer:r,cache:s}),c=await n(l);return kd({command:o,cacheKey:i,targetName:a,updatedCache:Nd(l),updatedWithAI:false,logger:e}),{result:c,thoughts:"Successfully executed preset action with cache"}}async resolveTargetCacheWithTracing({logger:e,tracer:r,cache:n,retryWithinSmartWaiting:o=true}){let{resolvedTarget:i}=await r.startAsyncSpan("CACHE_RESOLUTION",async a=>{let s=Date.now(),l;for(;!o||Date.now()-s<3e3;)try{let c=await Cre({target:n,driver:this.driver,stateManager:this.stateManager,logger:e,emulator:this.emulator});return a.attributes.serializedElement=(c.type==="NATIVE"?c.cache.elementOnlySerializedXml:void 0)??"Unknown element",{resolvedTarget:c}}catch(c){if(l=c,c instanceof Pe){if(!o)throw c;e.warn({err:c},"Failed to resolve target cache, retrying"),await ms(100,this.aborter.controller?.signal);continue}throw e.error({err:c},"Failed to resolve target cache"),c}throw l});return i}async wrapTargetingAction(e){let{tracer:r,logger:n,action:o,description:i,command:a,cacheKey:s="cache",targetName:l="target",cacheIsInvalidAfterResolution:c,skipFetchingFullWebviewContent:u=false,removeWebviewContent:d=false}=e,m={commandId:a.id},p=false,f,h;if(s==="cache"&&"cache"in a&&a.cache){let g=a.cache;l==="target"&&"target"in g?h=cloneDeep(g.target):l==="fromTarget"&&"fromTarget"in g?h=cloneDeep(g.fromTarget):l==="toTarget"&&"toTarget"in g&&(h=cloneDeep(g.toTarget));}if(a.disableCache&&(n.debug({command:a},"Cache explicitly disabled for command"),p=true,f="Cache explicitly disabled",h=void 0),c&&(p=true,f=f??"Cache invalidated after resolution",h=void 0),h&&!Dc(h.resolvedDescription??"",i)&&(n.info({description:i,cacheDescription:h.resolvedDescription},"Cache description mismatch, clearing it automatically"),p=true,f="Description mismatch",h=void 0),h){let g=h.type==="NATIVE"?!!h.requirements:!!h.browserCache?.requirements;try{let y=await this.targetingActionWithCache({logger:n,tracer:r,action:o,command:a,cacheKey:s,targetName:l,cacheCopyForAttempt:h});return Ge.increment("cache_target_resolution_v2",1,["outcome:hit","platform:mobile-native",`hasRequirements:${g}`,`orgId:${this.orgId}`,"cliVersion:1.0.1"]),y}catch(y){if(this.throwIfAborted(),y instanceof M&&y.reason!=="InternalWebAgentError")throw n.error({err:y},"Failed to execute action with target cache (fatal)"),y;Ge.increment("cache_target_resolution_v2",1,["outcome:miss","platform:mobile-native",`hasRequirements:${g}`,`orgId:${this.orgId}`,"cliVersion:1.0.1"]),n.warn({err:y},"Failed to execute action with target cache, retrying with AI");}}return n.info({description:i,cacheBustedBeforeAction:p},"Prompting AI for a new element location"),await this.targetingActionWithAILocator({tracer:r,action:o,command:a,description:i,cacheKey:s,targetName:l,skipFetchingFullWebviewContent:u,removeWebviewContent:d,metadata:m,logger:n,cacheBustReason:f})}constructPerformerParams(){return {emulator:this.emulator,stateManager:this.stateManager,driver:this.driver,fixtures:this.fixtures,emulatorSettings:this.emulatorSettings,aborter:this.aborter,orgId:this.orgId,generator:this.generator,aiSettings:this.aiSettings}}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}get abortSignal(){return this.aborter.controller?.signal}};var RR=class extends Ur{async doDrag(e,r,n,o,i){let{x1:a,y1:s,x2:l,y2:c}=n.bounds,u=a+(l-a)/2,d=s+(c-s)/2;r.attributes.startPoint={x:u,y:d};let{x1:m,y1:p,x2:f,y2:h}=o.bounds,g=m+(f-m)/2,y=p+(h-p)/2;r.attributes.endPoint={x:g,y};let S=i?.hoverDuration??500,E=i?.dragDuration??1e3;E===0&&(E=1);let w=Math.sqrt(Math.pow(g-u,2)+Math.pow(y-d,2))/E*1e3;await this.driver.executeInNativeContext(e,async _=>{await _.execute("mobile: dragFromToWithVelocity",{fromX:u,fromY:d,toX:g,toY:y,pressDuration:S/1e3,velocity:w,holdDuration:.5});},{operationName:"dragAndDrop"});}async executeDragAndDrop({logger:e,command:r}){let n=ae();if(r.fromTarget.type!=="description"||r.toTarget.type!=="description")throw new M("UserConfigurationError","Drag and drop only supports description targets for now");let o=r.fromTarget.description,{result:i,thoughts:a}=await this.wrapTargetingAction({command:r,tracer:n,description:o,cacheKey:"cache",targetName:"fromTarget",action:async u=>u,logger:e}),s=r.toTarget.description,{result:l,thoughts:c}=await this.wrapTargetingAction({command:r,tracer:n,description:s,cacheKey:"cache",targetName:"toTarget",action:async u=>u,logger:e});return await n.startAsyncSpan("EMULATOR_INTERACTION",async u=>{await this.doDrag(e,u,i,l,{hoverDuration:r.hoverDuration,dragDuration:r.dragDuration});},{name:"Drag and drop"}),{success:true,message:`${a}
|
|
5875
|
+
}`);return a.execute(s,...o)},{operationName:"executeWebViewScript"});if(i&&typeof i=="object"&&"_failed"in i)throw new Error(`Error executing script in webview: ${i._error||"Unknown error"}`);return i}async healthcheck(){await this.driver.getWindowHandle();}};async function Vte({logger:t,driverLogLevel:e="error",emulator:r,callbacks:n}){let{onStatusUpdate:o}=n,i=t.child({emulatorName:r.name}),a={platformName:"iOS","appium:noReset":true,"appium:fullReset":false,"appium:shouldTerminateApp":false,"appium:forceAppLaunch":false,"appium:autoLaunch":false,"appium:newCommandTimeout":3600,"appium:autoWebview":false,"appium:webviewConnectTimeout":500,"appium:webviewConnectRetries":5,"appium:includeSafariInWebviews":true,"appium:fullContextList":false,"appium:additionalWebviewBundleIds":["*"],"appium:waitForIdleTimeout":0,"appium:reduceMotion":true,"appium:settings":{customSnapshotTimeout:0,animationCoolOffTimeout:0},...r.extraCapabilities};o("Starting Appium session");let s={capabilities:a},l=await fR.init({logger:i,logLevel:e,callbacks:{...n,restartWda:r.restartWda?async c=>{await r.restartWda?.(c);}:void 0,onFailure:async({err:c,attempt:u})=>{let d=IC(c),m=u<3&&d;return m&&i.warn({err:c},"Appium driver manifest race detected on first attempt, restarting Appium and retrying"),{shouldRetry:m}}},wdioOpts:s});return i.info({capabilities:a,emulatorName:r.name},"Started Appium driver"),l}async function hk({wdaUrl:t,token:e}){try{let r=new AbortController;return setTimeout(()=>r.abort(),3e3),await fetch(t+"/status",{headers:{Authorization:`Bearer ${e}`},signal:r.signal}),!0}catch{return false}}var hR={"appium:waitForIdleTimeout":2,"appium:commandTimeouts":"30000","appium:skipLogCapture":true,"appium:disableAutomaticScreenshots":true,"appium:simpleIsVisibleCheck":true};var R$e=["[com.apple.","loadConfigurationForEnvironment"],x$e=["com.apple.Accessibility","com.apple.news","com.apple.locationd","NewsToday","NewsTodayIntents","apsd","APSConfiguration","APSOutgoingQueue","APSCourierConnection","APSNetworkMonitor","loadConfigurationForEnvironment"],M$e=new Set(["D","Df","Db"]),P$e=new Set(["I"]),I$e=/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+\s+(\S+)\s+/,_$e="https://storage.googleapis.com/mobile-drivers/WebDriverAgentRunner-Build-Sim-arm64-v10.4.5.zip",Hte=6e4,O$e=5e3,D$e=250;function L$e(t){let e=I$e.exec(t)?.[1];if(!e)return false;let r=R$e.some(o=>t.includes(o)),n=x$e.some(o=>t.includes(o));return M$e.has(e)?r||n:P$e.has(e)?n:false}async function Wte({wdaUrl:t,token:e,limbarClient:r,logger:n,onStatusUpdate:o}){if(await hk({wdaUrl:t,token:e}))return;o("Starting WebDriverAgent"),n.debug("WDA is not running on the iOS emulator"),await r.simctl(["launch","booted","com.facebook.WebDriverAgentRunner.xctrunner"]).wait();let i=Date.now()+O$e;do{if(await hk({wdaUrl:t,token:e})){n.debug("WDA launched");return}await pe(D$e);}while(Date.now()<i);throw new hh("WebDriverAgent did not become reachable after relaunch")}var jy=class t{apiClient;name;extraCapabilities;limbarToken;limbarWebRtcUrl;limbarApiUrl;limbarWdaUrl;limbarRegion;limbarTag;limbarClient;onStatusUpdate;logStream=void 0;constructor({apiClient:e,limbarToken:r,limbarWebRtcUrl:n,limbarApiUrl:o,limbarWdaUrl:i,limbarRegion:a,limbarTag:s,emulatorName:l,limbarClient:c,onStatusUpdate:u}){this.apiClient=e,this.name=l,this.limbarToken=r,this.limbarWebRtcUrl=n,this.limbarApiUrl=o,this.limbarWdaUrl=i,this.limbarRegion=a,this.limbarTag=s,this.limbarClient=c,this.extraCapabilities={...hR,"appium:automationName":"@limrun/xcuitest","appium:webDriverAgentUrl":this.limbarWdaUrl,"appium:wdaLocalPort":443,"appium:useNewWDA":false,"appium:usePreinstalledWDA":true,"appium:limInstanceApiUrl":o,"appium:limInstanceToken":r,"appium:wdaRequestHeaders":{Authorization:`Bearer ${r}`}},this.onStatusUpdate=u;}static async init(e){let{apiClient:r,logger:n,creationOpts:o,logLevel:i,orgId:a,sessionId:s,onStatusUpdate:l,onConnectionStateChange:c}=e,u=o.appToInstall?.channel,d=o.appToInstall?.tag;l("Creating iOS emulator");let{token:m,webRtcUrl:p,wdaUrl:f,apiUrl:h,id:g,region:y,appDownloadUrl:S,appMd5:E,resolvedTag:v}=await r.createIosEmulator({...o,hostname:hostname(),sessionId:s,installAppOnClient:true});n.info({emulatorName:g,region:y,sessionId:s},"ios instance creation ok"),l("Connecting to iOS emulator");let w;try{w=await Ge.recordDuration({fn:async()=>await createInstanceClient({apiUrl:h,token:m,logLevel:i}),name:"test_event_duration",tags:["name:limbar-client-creation","clientOs:ios",`orgId:${a}`],timeoutMs:Hte,timeoutMessage:`Timed out after ${Hte}ms creating Limbar iOS instance client for emulator ${g} after instance creation succeeded (region: ${y??"unknown"}, channel: ${u??"none"}, tag: ${d??"none"})`}),c&&w.onConnectionStateChange(c),l("Installing WebDriverAgent");let _=w;return await Ge.recordDuration({fn:async()=>{await Gte({limbarClient:_,url:_$e,md5:void 0,logger:n,emulatorName:g,assetLabel:"WebDriverAgent"});},name:"test_event_duration",tags:["name:limbar-wda-install","clientOs:ios",`orgId:${a}`]}),await Wte({wdaUrl:f,token:m,limbarClient:_,logger:n,onStatusUpdate:l}),S&&(l(`Installing iOS app${u?` with channel ${u}`:""}${d?` and tag ${d}`:""}`),await Ge.recordDuration({fn:async()=>{await Gte({limbarClient:_,url:S,md5:E,logger:n,emulatorName:g,assetLabel:"iOS app"});},name:"test_event_duration",tags:["name:limbar-app-install","clientOs:ios",`orgId:${a}`]})),(async()=>{try{let[L,I]=await Promise.allSettled([rp("limserver-1.limrun.net"),rp("125.253.92.199")]);n.info({limserver:L.status==="fulfilled"?L.value:L.reason,ip125:I.status==="fulfilled"?I.value:I.reason},"Limbar network diagnostics");}catch(L){n.warn({err:L},"Failed to run network diagnostics");}})(),new t({apiClient:r,limbarToken:m,limbarWebRtcUrl:p,limbarApiUrl:h,limbarWdaUrl:f,limbarRegion:y,limbarTag:v??d,emulatorName:g,limbarClient:_,onStatusUpdate:l})}catch(_){throw n.warn({err:_,emulatorName:g},"iOS emulator init failed after creation; cleaning up remote instance"),await N$e({apiClient:r,limbarClient:w,id:g,logger:n}),_}}tap(e,r){return this.limbarClient.tap(e,r)}nativeA11yTreeJson(){return this.limbarClient.elementTreeRaw()}async screenshotPngBase64(){let e=await this.limbarClient.screenshot(),r=Buffer.from(e.base64,"base64"),n=oL.decode(r),o=new PNG({width:n.width,height:n.height});return o.data=Buffer.from(n.data),PNG.sync.write(o).toString("base64")}listApps(){return this.limbarClient.listApps()}terminateApp(e){return this.limbarClient.terminateApp(e)}setOrientation(e){return this.limbarClient.setOrientation(e==="LANDSCAPE"?"Landscape":"Portrait")}pressKey(e){return this.limbarClient.pressKey(e)}async resetSettings(){let e=await this.limbarClient.simctl(["privacy","booted","reset","all"]).wait();if(e.code!==0)throw new Error(`simctl privacy reset returned non-zero exit code: ${e.code} stderr: ${e.stderr}`)}async startScreenRecording(){await this.limbarClient.startRecording({quality:RecordingQuality.Q5});}async stopScreenRecording(e){await this.limbarClient.stopRecording({localPath:e});}addSyslogListener(e){this.logStream||(this.logStream=this.limbarClient.streamSyslog());let r=n=>{L$e(n)||e(n);};return this.logStream.on("line",r),()=>{this.logStream?.off("line",r);}}async restartWda(e){await Wte({wdaUrl:this.limbarWdaUrl,token:this.limbarToken,limbarClient:this.limbarClient,logger:e,onStatusUpdate:this.onStatusUpdate});}async close(){try{this.logStream?.stop();}catch{}try{this.limbarClient.disconnect();}catch{}await this.apiClient.deleteIosEmulator(this.name);}};async function N$e(t){let{apiClient:e,limbarClient:r,id:n,logger:o}=t;if(r)try{r.disconnect();}catch(i){o.warn({err:i,emulatorName:n},"Failed to disconnect limbar client during init cleanup");}try{await e.deleteIosEmulator(n);}catch(i){o.warn({err:i,emulatorName:n},"Failed to delete iOS emulator during init cleanup");}}var gk=12e4,gR=6,k$e=1e3;async function Gte(t){let{limbarClient:e,url:r,md5:n,logger:o,emulatorName:i,assetLabel:a}=t,s;for(let l=1;l<=gR;l++)try{await ee(e.installApp(r,{md5:n,timeoutMs:gk}),{milliseconds:gk,message:`Timed out after ${gk}ms installing ${a} on emulator ${i}`});return}catch(c){if(s=c,l===gR)break;let u=k$e*2**(l-1);o.warn({url:r,err:c,emulatorName:i,assetLabel:a,attempt:l,maxAttempts:gR,backoffMs:u},`Failed to install ${a} on Limbar emulator; retrying after backoff`),await pe(u);}throw o.error({url:r,err:s,emulatorName:i,assetLabel:a,maxAttempts:gR},`Failed to install ${a} on Limbar emulator (no more retries)`),new M("UserConfigurationError",`Failed to install ${a} on emulator ${i}: ${s}`)}var F$e=C__default.array(C__default.object({bundle_id:C__default.string(),name:C__default.string()})),yR=class{constructor(e){this.udid=e;}async exec(e,r=[]){return new Promise((n,o)=>{execFile$1("idb",[...e,"--udid",this.udid,...r],(i,a)=>{i?o(i):n(a.trim());});})}async execBuffer(e,r=[]){return new Promise((n,o)=>{execFile$1("idb",[...e,"--udid",this.udid,...r],{encoding:"buffer",maxBuffer:10*1024*1024},(i,a)=>{i?o(i):n(a);});})}async describeDevice(){return this.exec(["describe"])}async tap({x:e,y:r}){await this.exec(["ui","tap"],[Math.round(e).toString(),Math.round(r).toString()]);}async elementTree(){return this.exec(["ui","describe-all"])}async listApps(){let e=await this.exec(["list-apps","--json"]),r=JSON.parse(e);return F$e.parse(r).map(n=>({bundleId:n.bundle_id,name:n.name}))}async terminate(e){await this.exec(["terminate"],[e]);}async pressKey(e){await this.exec(["ui","press"],[e]);}async screenshot(){let e=await this.execBuffer(["screenshot"],["-"]),r=Buffer.from([137,80,78,71,13,10,26,10]);if(e.length<r.length||!e.subarray(0,r.length).equals(r))throw new Error(`idb screenshot returned invalid PNG data (got ${e.length} bytes)`);return e.toString("base64")}async disconnect(){await this.exec(["disconnect"]);}};async function Hy(t){try{return (await new Simctl().getDeviceTypes()).filter(n=>n.includes("iPhone"))}catch(e){return t.warn({err:e},"Got error listing local iPhone device types, returning empty list"),[]}}var B$e=C__default.object({runtimes:C__default.array(C__default.object({version:C__default.string(),name:C__default.string(),isAvailable:C__default.boolean().optional()}))});async function U$e(t){try{let e=new Simctl,{stdout:r}=await e.exec("list",{args:["runtimes","-j"]}),{runtimes:n}=B$e.parse(JSON.parse(r)),o=n.filter(i=>i.isAvailable!==!1&&i.name.toLowerCase().startsWith("ios")).map(i=>i.version);return o.length===0?void 0:o.sort((i,a)=>z$e(a,i))[0]}catch(e){t.warn({err:e},"Failed to detect latest installed iOS runtime version");return}}function z$e(t,e){let r=t.split(".").map(Number),n=e.split(".").map(Number);for(let o=0;o<Math.max(r.length,n.length);o++){let i=(r[o]??0)-(n[o]??0);if(i!==0)return i}return 0}var SR=class t{name;extraCapabilities;simctl;idb;constructor({name:e,simctl:r,idb:n}){this.name=e,this.simctl=r,this.idb=n,this.extraCapabilities={...hR,"appium:automationName":"XCUITest","appium:udid":r.udid??void 0};}static async init(e,r){let n=new Simctl,o=r.emulatorName??`momentic-${Date.now()}`,i=await Hy(e);if(!i.includes(r.deviceType))throw new M("UserConfigurationError",`Invalid device type: ${r.deviceType}. Valid device types are: ${i.join(", ")}. If you are sure the device type is correct, please make sure it is installed and available in Xcode.`);let a=r.iosVersion??await U$e(e);if(!a)throw new M("UserConfigurationError","Could not determine an installed iOS runtime version. Make sure an iOS simulator runtime is installed in Xcode, or specify one with --local-ios-version.");let s;try{let l=await n.createDevice(o,r.deviceType,a);n.udid=l,s=async()=>{try{await n.shutdownDevice();}catch{}await n.deleteDevice();},await n.bootDevice(),await n.startBootMonitor({timeout:12e4}),r.appFilePath&&await n.installApp(r.appFilePath);let c=new yR(l);return new t({name:o,simctl:n,idb:c})}catch(l){throw await s?.(),l}}async tap(e,r){await this.idb.tap({x:e,y:r});}async nativeA11yTreeJson(){return this.idb.elementTree()}async screenshotPngBase64(){return this.idb.screenshot()}async listApps(){return this.idb.listApps()}async terminateApp(e){await this.idb.terminate(e);}async pressKey(e){await this.idb.pressKey(e);}async resetSettings(){}async close(){try{await this.idb.disconnect();}catch{}try{await this.simctl.shutdownDevice();}catch{}await this.simctl.deleteDevice();}};var $$e=5e3;async function Af({creationOpts:t,apiClient:e,logger:r,driverLogLevel:n,orgId:o,sessionId:i,callbacks:a}){let s=Date.now();r.info("Starting ios driver creation");let{onLimbarConnectionStateChange:l,onStatusUpdate:c}=a,u=[],d=async()=>{let p=u.toReversed();for(let f of p)try{await ee(f(),{milliseconds:$$e,fallback:()=>{}});}catch(h){if(ju(h))continue;r.warn({err:h},"Error running cleanup task");}},m;switch(t.type){case "remote":{m=await jy.init({apiClient:e,logger:r,creationOpts:t,orgId:o,sessionId:i,onStatusUpdate:c,onConnectionStateChange:l,logLevel:n});break}case "local":{m=await SR.init(r,t);break}}u.push(async()=>{await m.close();});try{let p=await Vte({logger:r,driverLogLevel:n,emulatorStart:s,emulator:m,apiClient:e,creationOpts:t,orgId:o,sessionId:i,callbacks:a});return u.push(()=>p.close()),p.executeInNativeContext(r,f=>f.getPageSource(),{operationName:"Warm up Appium cache"}).catch(()=>{}),{driver:p,emulator:m,limbarParams:m instanceof jy?{token:m.limbarToken,webRtcUrl:m.limbarWebRtcUrl,region:m.limbarRegion,tag:m.limbarTag,osVersion:t.type==="remote"?t.osVersion:void 0}:void 0,cleanup:d}}catch(p){throw await d(),new Error(`Failed to start Appium driver: ${p}`,{cause:p})}}var H$e=100,W$e=2500,Kte=4e3,G$e="...";async function TR({emulator:t,onLogs:e}){if(!t.addSyslogListener)return;let r=create({fetcher:async o=>{e(o);},resolver:()=>{},scheduler:windowedFiniteBatchScheduler({windowMs:W$e,maxBatchSize:H$e})}),n=o=>{let i=o.toString().trim();i.length!==0&&(i.length>Kte&&(i=i.slice(0,Kte)+G$e),r.fetch(i).catch(()=>{}));};return t.addSyslogListener(n)}var Yte="NATIVE_APP";var K$e=new Set(["id","processId","bundleId","type","accessible","index","x","y","width","height"]),Y$e=new Set([]),X$e=new Set(["name","label","traits"]),J$e=new Set(["live-region","drawing-order"]),Z$e=new Set(["visible","enabled"]);function Xte(t){let e={},r=t.tagName,n=reduce(t.attributes,(o,i)=>(o[i.name]=i.value,o),{});for(let[o,i]of Object.entries(n))K$e.has(o)||o==="class"&&r===i||o==="focusable"&&i==="true"&&n.clickable==="true"||Y$e.has(o)&&i==="false"||X$e.has(o)&&i===""||Z$e.has(o)&&i==="true"||J$e.has(o)&&i==="0"||(e[o]=i);return e.name&&e.label&&e.name===e.label&&delete e.label,e.name&&e.value&&e.name===e.value&&delete e.value,e}function El(t){let e=t.getAttribute("x"),r=t.getAttribute("y"),n=t.getAttribute("width"),o=t.getAttribute("height");if(e===null||r===null||n===null||o===null)return;let i=parseFloat(e),a=parseFloat(r),s=parseFloat(n),l=parseFloat(o);if(!(isNaN(i)||isNaN(a)||isNaN(s)||isNaN(l)))return {x1:i,y1:a,x2:i+s,y2:a+l}}function yk(t,e){let{x1:r,y1:n,x2:o,y2:i}=e;t.setAttribute("bounds",`[${r},${n},${o},${i}]`);}function Q$e(t){let e=t.match(/\[([-\d.]+),([-\d.]+),([-\d.]+),([-\d.]+)\]/);if(!e)return;let r=parseFloat(e[1]),n=parseFloat(e[2]),o=parseFloat(e[3]),i=parseFloat(e[4]);if(!(isNaN(r)||isNaN(n)||isNaN(o)||isNaN(i)||o<r||i<n))return {x1:r,y1:n,x2:o,y2:i}}function ER(t){let e=t.getAttribute("bounds");if(e)return Q$e(e)}function Jte(t,e){if(!e)return true;let r=El(t);return r?Sk(r,e):true}function Sk(t,e){if(!e)return true;let{x1:r,y1:n,x2:o,y2:i}=t;return !(o<e.left||r>e.right||i<e.top||n>e.bottom)}function vR(t){let e=t.cloneNode(true);for(let r of Array.from(e.children)){let n=r;for(let o of Array.from(n.children))n.removeChild(o);}return e.outerHTML}var Zte=new Set(["XCUIElementTypeWebView"]);function oVe(t){if(Zte.has(t.tagName))return true;let e=t.getAttribute("name");if(e&&(e.startsWith("TabDocument")||e.startsWith("BrowserView"))){let r=e.match(/UUID=([A-F0-9-]+)/),n=e.match(/WebViewProcessID=(\d+)/);if(r&&n)return true}return false}function iVe(t){return t.startsWith("XCUIElementType")?t.substring(15):t}function Qte({state:t,originalElement:e,prunedElement:r,isInWebview:n,idInWebview:o}){let{idCounter:i,idToPrunedElement:a,idToOriginalElement:s,idToIdInWebview:l}=t,c=i.value++;r.setAttribute("id",String(c)),a.set(c,r),n?l.set(c,o):s.set(c,e);}function ere(t){if(!Zte.has(t.tagName)&&t.tagName==="XCUIElementTypeOther"&&t.hasAttribute("name")&&t.hasAttribute("label"))return t;for(let e of Array.from(t.children)){let r=ere(e);if(r)return r}}function aVe({webviewNativeRootBounds:t,webviewDocumentRootBounds:e}){let r=t.x1-e.x,n=t.y1-e.y;if(!Number.isFinite(r)||!Number.isFinite(n))return t;let o=t.x2-t.x1,i=t.y2-t.y1;return {x1:r,y1:n,x2:r+o,y2:n+i}}function tre(t,e,r,n){let{document:o}=r,{parentFrameBounds:i,pruneElementsOutsideBounds:a}=n;if(e.type==="element"){let s=o.createElement(e.role||e.tag);if(e.name&&s.setAttribute("name",e.name),e.description&&s.setAttribute("description",e.description),e.classes&&e.classes.length>0&&s.setAttribute("classes",e.classes.join(" ")),e.attrs)for(let[u,d]of Object.entries(e.attrs))s.setAttribute(u,d);let l=e.boundingRect,c={x1:i.x1+l.x,y1:i.y1+l.y,x2:i.x1+l.x+l.width,y2:i.y1+l.y+l.height};if(!Sk(c,a))return;yk(s,c),Qte({state:r,prunedElement:s,isInWebview:true,idInWebview:e.momenticWebviewElementId}),t.appendChild(s);for(let u of e.children)tre(s,u,r,n);}else if(e.type==="text"){let s=o.createElement("text");t.appendChild(s);let l=o.createTextNode(e.text);s.appendChild(l);}}function rre(t,e,r,n){let{pruneElementsOutsideBounds:o}=n,{document:i}=r;Qte({state:r,originalElement:t,prunedElement:e,isInWebview:false});let a=Xte(t);for(let[c,u]of Object.entries(a))e.setAttribute(c,u);let s=El(t);if(s&&yk(e,s),oVe(t)){let{removeWebviewContent:c,injectedWebviewContent:u}=n;if(c)return;if(u&&El(t)){let m=ere(t),p=m?El(m):void 0;if(m&&p){r.webviewRootElement=m,r.webviewRootBounds=p,tre(e,u.root,r,{parentFrameBounds:aVe({webviewNativeRootBounds:p,webviewDocumentRootBounds:u.rootBoundingBox}),pruneElementsOutsideBounds:o});return}}}let l=Array.from(t.childNodes??[]);for(let c of l){let u=c.nodeType;if(u===3){let d=c.nodeValue;d&&d.trim().length>0&&e.appendChild(i.createTextNode(d));continue}if(u===1){let d=c;if(!Jte(d,o))continue;let m=i.createElement(iVe(d.tagName));rre(d,m,r,n),e.appendChild(m);}}}async function Tk(t,e,r){let n=t.parseFromString("<AppiumAUT/>","text/xml"),o=new Map,i=new Map,a=new Map,s={document:n,idToPrunedElement:o,idToOriginalElement:i,idToIdInWebview:a,idCounter:{value:0},webviewRootElement:void 0,webviewRootBounds:void 0},l=n.documentElement;rre(e,l,s,r);let c=new XMLSerializer().serializeToString(n),u=await Eze.format(c,{parser:"xml",plugins:[Tze],printWidth:120,tabWidth:1,singleAttributePerLine:false});return {prunedDocument:n,idToPrunedElement:o,idToOriginalElement:i,idToIdInWebview:a,webviewRootElement:s.webviewRootElement,webviewRootBounds:s.webviewRootBounds,prunedXml:u}}async function nre(t,e){let r=new DOMParser,n=r.parseFromString(t,"text/xml"),o=n.documentElement;if(!o)throw new Error("No root element found in XML");if(o.tagName!=="AppiumAUT")throw new Error("No AppiumAUT element found in XML");let{prunedXml:i,idToPrunedElement:a,idToOriginalElement:s,idToIdInWebview:l,webviewRootElement:c,webviewRootBounds:u}=await Tk(r,o,e);return {xml:i,idToPrunedElement:a,idToOriginalElement:s,idToIdInWebview:l,webviewRootElement:c,webviewRootBounds:u,originalDocument:n}}var ore=(A=>(A.GenericElement="GenericElement",A.Any="Any",A.Other="Other",A.Application="Application",A.Group="Group",A.Window="Window",A.Sheet="Sheet",A.Drawer="Drawer",A.Alert="Alert",A.Dialog="Dialog",A.Button="Button",A.RadioButton="RadioButton",A.RadioGroup="RadioGroup",A.CheckBox="CheckBox",A.DisclosureTriangle="DisclosureTriangle",A.PopUpButton="PopUpButton",A.ComboBox="ComboBox",A.MenuButton="MenuButton",A.ToolbarButton="ToolbarButton",A.Popover="Popover",A.Keyboard="Keyboard",A.Key="Key",A.NavigationBar="NavigationBar",A.TabBar="TabBar",A.TabGroup="TabGroup",A.Toolbar="Toolbar",A.StatusBar="StatusBar",A.Table="Table",A.TableRow="TableRow",A.TableColumn="TableColumn",A.Outline="Outline",A.OutlineRow="OutlineRow",A.Browser="Browser",A.CollectionView="CollectionView",A.Slider="Slider",A.PageIndicator="PageIndicator",A.ProgressIndicator="ProgressIndicator",A.ActivityIndicator="ActivityIndicator",A.SegmentedControl="SegmentedControl",A.Picker="Picker",A.PickerWheel="PickerWheel",A.Switch="Switch",A.Toggle="Toggle",A.Link="Link",A.Image="Image",A.Icon="Icon",A.SearchField="SearchField",A.ScrollView="ScrollView",A.ScrollBar="ScrollBar",A.StaticText="StaticText",A.TextField="TextField",A.SecureTextField="SecureTextField",A.DatePicker="DatePicker",A.TextView="TextView",A.Menu="Menu",A.MenuItem="MenuItem",A.MenuBar="MenuBar",A.MenuBarItem="MenuBarItem",A.Map="Map",A.WebView="WebView",A.IncrementArrow="IncrementArrow",A.DecrementArrow="DecrementArrow",A.Heading="Heading",A.Cell="Cell",A))(ore||{}),ire=C__default.lazy(()=>C__default.object({AXFrame:C__default.string(),AXUniqueId:C__default.string().nullable(),AXLabel:C__default.string().nullable(),AXValue:C__default.string().nullable(),frame:C__default.object({x:C__default.number(),y:C__default.number(),width:C__default.number(),height:C__default.number()}),role:C__default.string(),role_description:C__default.string(),subrole:C__default.string().nullable(),type:C__default.nativeEnum(ore),title:C__default.string().nullable(),help:C__default.string().nullable(),content_required:C__default.boolean(),custom_actions:C__default.array(C__default.string()),enabled:C__default.boolean(),children:C__default.array(ire).default([])}));function lVe(t){return C__default.array(ire).parse(JSON.parse(t))}async function CR(t,e){let r=new DOMParser,n=lVe(t),o=cVe(r,n),{prunedXml:i,idToPrunedElement:a,idToOriginalElement:s}=await Tk(r,o.documentElement,{removeWebviewContent:false,injectedWebviewContent:void 0,pruneElementsOutsideBounds:e.pruneElementsOutsideBounds});return {xml:i,idToPrunedElement:a,idToOriginalElement:s,originalDocument:o,webviewRootElement:void 0,idToIdInWebview:new Map,webviewRootBounds:void 0}}function cVe(t,e){let r=t.parseFromString("<hierarchy/>","text/xml"),n=r.documentElement;for(let o=0;o<e.length;o++){let i=e[o],a=are(i,r);n.appendChild(a);}return r}function are(t,e){let r=t.type,n=e.createElement(r);if(n.setAttribute("type",r),n.setAttribute("x",String(t.frame.x.toFixed(2))),n.setAttribute("y",String(t.frame.y.toFixed(2))),n.setAttribute("width",String(t.frame.width.toFixed(2))),n.setAttribute("height",String(t.frame.height.toFixed(2))),t.AXLabel!==null&&n.setAttribute("label",t.AXLabel),t.AXValue!==null&&n.setAttribute("value",t.AXValue),t.title!==null&&n.setAttribute("title",t.title),t.help!==null&&n.setAttribute("help",t.help),n.setAttribute("enabled",String(t.enabled)),t.children)for(let o=0;o<t.children.length;o++){let i=t.children[o],a=are(i,e);n.appendChild(a);}return n}function Dd(t){let e=[],r=t;for(;r;){let n=r.parentElement;if(!n||n.tagName==="AppiumAUT"){e.unshift(`${r.tagName}[1]`);break}let o=r.tagName,i=Array.from(n.children).filter(s=>s.tagName===o),a=1;for(let s=0;s<i.length;s++)if(i[s]===r){a=s+1;break}e.unshift(`${o}[${a}]`),r=n;}return `/${e.join("/")}`}var wR=class t{driver;emulator;options;lastDomState;lastScreenshot;aborter;constructor({driver:e,emulator:r,aborter:n,options:o}){this.driver=e,this.emulator=r,this.aborter=n,this.options=o;}static async init({driver:e,emulator:r,aborter:n,options:o}){return new t({driver:e,aborter:n,emulator:r,options:o})}async getContexts(e){let r=await this.driver.executeInNativeContext(e,async o=>await o.getContexts({}),{operationName:"getContexts"}),n=r.filter(o=>o!==Yte);return {contexts:r.map(o=>o),webviews:n}}async getRawScreenshotBase64({logger:e,totalAttempts:r=3,signal:n}){let o=ae(),i=n??this.aborter.controller?.signal,a=await o.startAsyncSpan("EMULATOR_READ_STATE",async()=>await Ip(e,()=>this.emulator.screenshotPngBase64(),{maxAttempts:r,signal:i,operationName:"takeScreenshot"}),{name:"Take screenshot",signal:i,timeoutMs:3e4});return this.lastScreenshot={pngString:`data:image/png;base64,${a}`,observedAt:Date.now()},a}async getCurrentScreenshotPngString(e){return `data:image/png;base64,${await this.getRawScreenshotBase64({logger:e,totalAttempts:1})}`}async waitForScreenshotStability({logger:e,timeoutMs:r,signal:n,reason:o,tolerancePercent:i=1}){await ae().startAsyncSpan("WAIT_FOR_SCREENSHOT_STABILITY",async a=>{a.attributes.reason=o;let s=Km({signal:n,timeoutMs:r}),l,c=false;for(;!s.aborted;){let u=Date.now();if(l)try{let m=await this.getRawScreenshotBase64({logger:e,totalAttempts:1,signal:s});if(wc(l,m)<=i){c=!0;break}l=m;}catch(m){e.warn({err:m},"Failed to get screenshot during stability wait");}else try{l=await this.getRawScreenshotBase64({logger:e,totalAttempts:1,signal:s});}catch(m){e.warn({err:m},"Failed to get initial screenshot during stability wait");}let d=Math.max(250,Date.now()-u);await ms(Math.min(1e4,d),s);}c||(a.attributes.timedOut=true,e.warn({purpose:o},"Timed out waiting for screenshot stability"));});}async waitForPageSourceStability({logger:e,timeoutMs:r,signal:n,reason:o}){await ae().startAsyncSpan("WAIT_FOR_PAGE_STABILITY",async i=>{i.attributes.reason=o;let a=Km({signal:n,timeoutMs:r}),s,l=false;for(;!a.aborted;){let c,u=Date.now();try{c=await ee(this.emulator.nativeA11yTreeJson(),{milliseconds:1e4,signal:a,message:"Getting the native accessibility tree timed out after 10s"});let m=createHash("md5").update(c).digest("hex");if(s&&s===m){l=!0;break}s=m;}catch(m){e.warn({err:m},"Failed to get page source during stability wait");}let d=Math.max(250,Date.now()-u);await ms(Math.min(1e4,d),a);}l||(i.attributes.timedOut=true,e.warn({purpose:o},"Timed out waiting for page source stability"));});}async getActiveWebview(e){let n=(await this.getContexts(e)).webviews;if(n.length>1)throw new M("UserInfrastructureError","Multiple active webviews in a single package is currently not supported");return n[0]}async getActiveWebviewContent(e){let r=await this.getActiveWebview(e);if(!r)return;this.throwIfAborted();let n=await this.driver.executeWebViewScript(e,r,o=>o.dumpA11yTree());return {context:r,...n}}async getDomState(e,r){let o=await ae().startAsyncSection("Get emulator state XML",async()=>{let a=r?.filterOffscreenElements??true?await this.getViewportBounds(e):void 0,s;if(!r?.skipFetchingFullWebviewContent)try{s=await this.getActiveWebviewContent(e);}catch(u){e.error({err:u},"Could not get webview info to get the nested DOM state");}if(this.throwIfAborted(),!s&&this.options?.disableMomenticAccessibilityTree){let u=await this.getNativePageSource();this.throwIfAborted();let d=await CR(u,{pruneElementsOutsideBounds:a});return {sourceTree:"native",graph:d,webviewContent:void 0}}let l=await this.getAppiumPageSource(e);return this.throwIfAborted(),{graph:await nre(l,{injectedWebviewContent:s,removeWebviewContent:r?.removeWebviewContent,pruneElementsOutsideBounds:a}),sourceTree:"appium",webviewContent:s}});return this.recordDomState(o),o}async getLastObservedState(){let e=this.lastDomState,r=this.lastScreenshot;if(!e||!r)return;let n=Date.now(),o=3e4;if(!(n-e.observedAt>o||n-r.observedAt>o||Math.abs(e.observedAt-r.observedAt)>5e3))return {emulatorState:e.state,screenshot:r.pngString}}recordDomState(e){this.lastDomState={state:e,observedAt:Date.now()};}async getNativePageSource(){return await ae().startAsyncSpan("EMULATOR_READ_STATE",async()=>this.emulator.nativeA11yTreeJson(),{name:"Get iOS page source",signal:this.aborter.controller?.signal,timeoutMs:3e4})}async getAppiumPageSource(e,r){let n=r??this.aborter.controller?.signal;return await ae().startAsyncSpan("EMULATOR_READ_STATE",()=>this.driver.executeInNativeContext(e,i=>i.getPageSource(),{signal:n,operationName:"getPageSource"}),{name:"Get page source",signal:n,timeoutMs:3e4})}async getViewportBounds(e){let r=await this.driver.executeInNativeContext(e,async n=>n.getWindowRect(),{operationName:"getViewportBounds"});return {left:r.x,top:r.y,right:r.x+r.width,bottom:r.y+r.height}}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}};async function lre({command:t,logger:e,generator:r,aiSettings:n,getEmulatorDomState:o,getScreenshotBase64:i,throwIfAborted:a,abortSignal:s}){let l=ae(),c=t.contextChoice==="VISION_ONLY",u=15,d=t.timeoutSecs?t.timeoutSecs*1e3:5e3,m=Pv(d),p=Date.now(),f=0,h,g=false,y;for(;f<u&&!g;){a(),g||h&&h-p>=d&&(g=true),f!==0&&await pe(m,s),h=Date.now();try{let S="",E="";await l.startAsyncSpan("EMULATOR_READ_STATE",async()=>{c||(S=await o()),E=await i();},{name:"Get emulator state"});let v=await r.evaluateIosAssertion({assertion:t.assertion,screenXml:S,screenshot:E,contextChoice:t.contextChoice},{logger:e,loggerTags:De(e),agentConfigVersion:n.agentConfig?.["ios-assertion"]});if(v.result)return {success:v.result,message:v.thoughts};{let w=`AssertionFailureError: ${v.thoughts}`;y=new Error(w);}}catch(S){if(a(),NS(S))throw S;e.info({err:S},`AI check assert attempt ${f} failed, retrying...`),y=S instanceof Error?S:new Error(`${S}`);}finally{f++;}}return {success:false,message:y?.message}}async function cre({command:t,logger:e,generator:r,aiSettings:n,getEmulatorDomState:o,getScreenshotBase64:i,abortSignal:a}){if(!t.goal.trim())throw new M("ActionFailureError","Cannot perform AI extraction without goal");if(t.schema){let u=Vm(t.schema);if(u)throw new M("UserConfigurationError",u)}let s=ae(),l="",c="";return await s.startAsyncSpan("EMULATOR_READ_STATE",async()=>{l=await o(),c=await i();},{name:"Get emulator state"}),await s.startAsyncSpan("AI_EXTRACTION_CALL",async u=>{try{let d=await r.getIosTextExtraction({goal:t.goal,emulatorState:l,returnSchema:t.schema,screenshot:`data:image/png;base64,${c}`},{disableCache:!!t.disableCache,abortSignal:a,loggerTags:De(e),agentConfigVersion:n.agentConfig?.["ios-text-extraction"]});if(u.result=d,LC({tracer:s,span:u,screenshot:c,emulatorState:l,logger:e}),d.result==="NOT_FOUND")return {success:!1,message:"No relevant data found for extraction goal on this page"};if(d.thoughts?.includes("MaxGenerationLengthExceededError"))throw new M("UserConfigurationError",d.thoughts);return {success:!0,output:d.result,message:d.thoughts}}catch(d){let m=W(d);throw m.includes("MaxGenerationLengthExceededError")?new M("UserConfigurationError","You tried to extract too much data. Please rephrase your query to limit the results returned or use a JavaScript step instead."):m.includes("AIProviderError")&&m.includes("time")?new M("AIProviderError","The AI provider responded with an error. This may be because you tried to extract too much data. Please limit extraction results to 2000 characters.",{errOptions:{cause:d}}):d}})}function Ld(t){let{x1:e,y1:r,x2:n,y2:o}=t.bounds;return {left:e,top:r,width:n-e,height:o-r}}var vi="element-6066-11e4-a52e-4f735466cecf";function ks(t,e){return Math.abs(t-e)<1}function Rf(t,e){let r=e.x2-e.x1,n=(e.x1+e.x2)/2,o=(t.x1+t.x2)/2;if(!ws(e.tolerance,n,o,Math.min(1,r)))return false;let i=e.y2-e.y1,a=(e.y1+e.y2)/2,s=(t.y1+t.y2)/2;return ws(e.tolerance,a,s,Math.min(1,i))}function xf(t,e){let r=t.x2-t.x1,n=t.y2-t.y1;return ws(e.tolerance,e.width,r,Math.min(1,e.width))?ws(e.tolerance,e.height,n,Math.min(1,e.height)):false}function Nd(t){return t.type==="WEBVIEW",t.cache}function kd(t){let{command:e,cacheKey:r="cache",targetName:n="target",updatedCache:o}=t;gP(e)&&(e[r]={...e[r],[n]:um.parse(o)},t.updatedWithAI&&(e[r].updatedAt=new Date,e[r].updatedAtLoggerTags=De(t.logger)));}var Wy="name";async function ure(t,e,r){return await e.executeInNativeContext(t,n=>n.isElementDisplayed(r),{operationName:"isElementRendered"})}async function Mf(t,e,r,n){return await e.executeInNativeContext(t,o=>o.getElementAttribute(r,n),{operationName:"getAttributeFromIosElement"})}async function Ek(t,e,r){return await e.executeInNativeContext(t,async n=>{try{let o=await n.findElement("xpath",r);if(!o)return null;let i=o[vi];if(!i)return null;let a=await n.getElementRect(i);return {elementId:i,rect:a}}catch{return null}},{operationName:"findElementByXPath"})}async function dre(t,e,r){let n=Dd(r),o=await Ek(t,e,n);if(o)return {xPath:n,...o}}async function vk({logger:t,emulatorState:e,driver:r,idInWebview:n,requirements:o}){let i=e.graph.webviewRootElement?Dd(e.graph.webviewRootElement):void 0;if(!i||!e.webviewContent||!e.graph.webviewRootBounds)throw new Error("Cannot build webview target cache without webview root information");let a=await mVe({logger:t,driver:r,webviewRootBounds:e.graph.webviewRootBounds,nodeIdInWebview:n,aiGeneratedRequirements:o,webviewContent:e.webviewContent});if(!a)throw new Error("Failed to build browser cache for webview element");return {xPath:i,bounds:[e.graph.webviewRootBounds.x1,e.graph.webviewRootBounds.y1,e.graph.webviewRootBounds.x2,e.graph.webviewRootBounds.y2],browserCache:a}}async function mVe({logger:t,driver:e,webviewRootBounds:r,nodeIdInWebview:n,aiGeneratedRequirements:o,webviewContent:i}){let a=await e.executeWebViewScript(t,i.context,(c,u,d,m)=>c.generateCacheFromWebviewElementId(u,d,m),i.generatedAt,n,{attributesToFetch:o?.attributesRequired??[]});if(!a)return;let s=a.textContent??void 0,l={x:r.x1-i.rootBoundingBox.x+a.boundingBox.x,y:r.y1-i.rootBoundingBox.y+a.boundingBox.y,width:a.boundingBox.width,height:a.boundingBox.height};return {id:a.id,generatedSelectors:a.selectors,boundingBox:l,requirements:{text:o?.textRequired?s:void 0,attributes:a.attributes,boundingBox:o?.boundsRequired?l:void 0,shape:o?.shapeSpecificity?{tolerance:o.shapeSpecificity,width:a.boundingBox.width,height:a.boundingBox.height}:void 0,position:o?.positionSpecificity?{tolerance:o.positionSpecificity,x1:l.x,y1:l.y,x2:l.x+l.width,y2:l.y+l.height}:void 0}}}async function pVe(t,e,r,n){if(!n||!n.length)return;let o={};for(let i of n){let a=await Mf(t,e,r,i);a!==null&&(o[i]=a);}return Object.keys(o).length?o:void 0}async function mre({logger:t,driver:e,node:r,requirements:n}){let o=await dre(t,e,r);if(!o){t.warn("Failed to generate valid xPath selector for element");return}let{xPath:i,rect:a,elementId:s}=o,l={x1:a.x,y1:a.y,x2:a.x+a.width,y2:a.y+a.height};return {xPath:i,bounds:[l.x1,l.y1,l.x2,l.y2],requirements:{requiredText:n?.textRequired?await Mf(t,e,s,Wy)??void 0:void 0,requiredAttributes:await pVe(t,e,s,n?.attributesRequired?.filter(c=>!(n.textRequired&&c===Wy))),requiredBounds:n?.boundsRequired,position:n?.positionSpecificity?{x1:l.x1,y1:l.y1,x2:l.x2,y2:l.y2,tolerance:n?.positionSpecificity}:void 0,shape:n?.shapeSpecificity?{width:l.x2-l.x1,height:l.y2-l.y1,tolerance:n?.shapeSpecificity}:void 0}}}async function pre({logger:t,driver:e,aiResponse:r,description:n,emulatorState:o}){let i=o.graph.idToPrunedElement.get(r.id);if(!i)throw new Error(`Could not find node with id: ${r.id}`);let a=ER(i);if(!a)throw new Error(`Could not determine bounds for element with id: ${r.id}, description: ${n}`);let s=[];for(let{id:d,requirements:m}of r.additionalElements??[]){let p=o.graph.idToIdInWebview.get(d);if(p!==void 0){try{let g=await vk({logger:t,driver:e,emulatorState:o,idInWebview:p,requirements:m});s.push(g);}catch(g){t.warn({err:g},`Failed to build webview cache for related element with id: ${d}`);}continue}let f=o.graph.idToOriginalElement.get(d);if(!f){t.warn(`Could not find original element for additional element with id: ${d}`);continue}let h=await mre({logger:t,driver:e,node:f,requirements:m});h&&s.push(h);}let l=o.graph.idToIdInWebview.get(r.id);if(l!==void 0){let d={type:"WEBVIEW",bounds:a,cache:{type:"WEBVIEW"}};try{let m=await vk({logger:t,driver:e,emulatorState:o,idInWebview:l,requirements:r.requirements});return {...d,cache:{type:"WEBVIEW",resolvedDescription:n,requiredRelatedElements:s,...m}}}catch(m){return t.warn({err:m},"Failed to build webview target cache"),d}}let c=o.graph.idToOriginalElement.get(r.id);if(!c)throw new Error(`Node isn't in a webview but couldn't find original node for id: ${r.id}, description: ${n}`);let u=await mre({logger:t,driver:e,node:c,requirements:r.requirements});return u?{type:"NATIVE",bounds:a,cache:{type:"NATIVE",...u,resolvedDescription:n,sourceTree:"appium",requiredRelatedElements:s,elementOnlySerializedXml:vR(c)}}:(t.warn("Failed to generate valid cache for element"),{type:"NATIVE",cache:{type:"NATIVE"},bounds:a})}async function Ck({logger:t,driver:e,stateManager:r,parentWebviewBounds:n,cache:o}){if(!o||!o.generatedSelectors)throw new Pe("Cache is missing required attributes");let i=await r.getActiveWebview(t);if(!i)throw new Pe("No active webview context found");let a=await e.executeWebViewScript(t,i,(u,d)=>u.resolveWebviewTargetCache(d),{selectors:o.generatedSelectors,attributesToFetch:Object.keys(o.requirements?.attributes??{})});if(!a)throw new Pe("Failed to resolve webview target using cache");let s=n.x1-a.rootBoundingBox.x+a.boundingBox.x,l=n.y1-a.rootBoundingBox.y+a.boundingBox.y,c={x1:s,y1:l,x2:s+a.boundingBox.width,y2:l+a.boundingBox.height};return o.requirements&&fVe(t,c,a,o.requirements),c}function fVe(t,e,r,n){if(!n)return;let{attributes:o,text:i,position:a,shape:s}=n;if(i!==void 0&&i.length>0&&r.textContent!==i)throw new Pe(`Text content mismatch: expected "${i}", got "${r.textContent}"`);if(o)for(let[l,c]of Object.entries(o)){let u=r.attributes[l];if(u!==c)throw new Pe(`Attribute ${l} mismatch: expected "${c}", got "${u}"`)}if(a&&!Rf(e,a))throw new Pe(`Position mismatch: expected ${JSON.stringify(a)}, got ${JSON.stringify(e)}`);if(s&&!xf(e,s))throw new Pe(`Shape mismatch: expected ${JSON.stringify(s)}, got ${JSON.stringify(e)}`)}async function fre(t,e,r,n,o){if(!n)return;let{requiredAttributes:i,requiredText:a,requiredBounds:s,position:l,shape:c}=n;if(a!==void 0&&a.length>0){let u=await Mf(t,e,r,Wy);if(u!==a)throw new Pe(`Resolved element text mismatch: expected ${a}, got ${u}`)}if(i)for(let[u,d]of Object.entries(i)){let m=await Mf(t,e,r,u)??void 0;if(m!==d)throw new Pe(`Attribute ${u} mismatch: expected ${d}, got ${m}`)}if(s&&o){let{originalBounds:u,newBounds:d}=o;if(!u)throw new Pe("Cannot validate bounds requirements without original bounds in cache");if(!(ks(u.x1,d.x1)&&ks(u.y1,d.y1)&&ks(u.x2,d.x2)&&ks(u.y2,d.y2))){let p=f=>`[${f.x1},${f.y1},${f.x2},${f.y2}]`;throw new Pe(`Bounds changed from ${p(u)} to ${p(d)}`)}}if(l&&o&&!Rf(o.newBounds,l))throw new Pe(`Position mismatch: expected ${JSON.stringify(l)}, got ${JSON.stringify(o.newBounds)}`);if(c&&o&&!xf(o.newBounds,c))throw new Pe(`Shape mismatch: expected ${JSON.stringify(c)}, got ${JSON.stringify(o.newBounds)}`)}async function hre({logger:t,driver:e,xPath:r,elementType:n,skipVisibilityCheck:o=false}){let i=await Ek(t,e,r);if(!i)throw new Pe(`Could not resolve ${n} via XPath: ${r}`);let{elementId:a}=i;if(!o&&!await ure(t,e,a))throw new Pe(`${n} resolved via XPath is not rendered: ${r}`);return i}async function gre({target:t,driver:e,stateManager:r,logger:n}){if(!t.xPath)throw new Pe(`Could not resolve cached target via XPath: ${t.xPath}`);if(t.requiredRelatedElements){let s=t.requiredRelatedElements;for(let l of s){let{elementId:c,rect:u}=await hre({logger:n,driver:e,xPath:l.xPath,elementType:"related element",skipVisibilityCheck:!!l.browserCache});if(l.browserCache){let d={x1:u.x,y1:u.y,x2:u.x+u.width,y2:u.y+u.height};await Ck({logger:n,driver:e,stateManager:r,parentWebviewBounds:d,cache:l.browserCache});}else await fre(n,e,c,l.requirements);}}let{elementId:o,rect:i}=await hre({logger:n,driver:e,xPath:t.xPath,elementType:"element",skipVisibilityCheck:t.type==="WEBVIEW"}),a={x1:i.x,y1:i.y,x2:i.x+i.width,y2:i.y+i.height};if(t.type==="WEBVIEW"){let s=await Ck({logger:n,driver:e,stateManager:r,parentWebviewBounds:a,cache:t.browserCache});return {type:"WEBVIEW",bounds:s,cache:t}}return await fre(n,e,o,t.requirements,{originalBounds:t.bounds?{x1:t.bounds[0],y1:t.bounds[1],x2:t.bounds[2],y2:t.bounds[3]}:void 0,newBounds:a}),{type:"NATIVE",bounds:a,cache:{...t,bounds:[a.x1,a.y1,a.x2,a.y2]}}}function yre({aiResponse:t,description:e,emulatorState:r}){let n=r.graph.idToPrunedElement.get(t.id);if(!n)throw new Error(`Could not find node with id: ${t.id}`);let o=ER(n);if(!o)throw new Error(`Could not determine bounds for element with id: ${t.id}, description: ${e}`);let i=r.graph.idToOriginalElement.get(t.id);if(!i)throw new Error(`Node isn't in a webview but couldn't find original node for id: ${t.id}, description: ${e}`);let a=Dd(i),s=vR(i),l=bre({requirements:t.requirements,element:i}),c=(t.additionalElements??[]).map(({id:u,requirements:d})=>{let m=r.graph.idToOriginalElement.get(u);return m?{xPath:Dd(m),requirements:bre({requirements:d,element:m})}:void 0}).filter(u=>!!u);return {type:"NATIVE",bounds:o,cache:{type:"NATIVE",bounds:[o.x1,o.y1,o.x2,o.y2],resolvedDescription:e,sourceTree:r.sourceTree,xPath:a,elementOnlySerializedXml:s,requirements:l,requiredRelatedElements:c}}}function bre({requirements:t,element:e}){let r;if((t?.positionSpecificity||t?.shapeSpecificity)&&(r=El(e),!r))throw new M("ActionFailureError","Element to cache has no bounds or unexpected bounds format");return {requiredText:t?.textRequired?e.textContent??void 0:void 0,requiredAttributes:hVe(e,t?.attributesRequired),requiredBounds:t?.boundsRequired,position:t?.positionSpecificity?{x1:r.x1,y1:r.y1,x2:r.x2,y2:r.y2,tolerance:t?.positionSpecificity}:void 0,shape:t?.shapeSpecificity?{width:r.x2-r.x1,height:r.y2-r.y1,tolerance:t?.shapeSpecificity}:void 0}}function hVe(t,e){if(t&&!(!e||e.length===0))return Object.fromEntries(e.map(r=>[r,t.getAttribute(r)]).filter(([,r])=>r!==null))}async function Tre(t,e,r,n){if(!r)return;let{requiredAttributes:o,requiredText:i,requiredBounds:a,position:s,shape:l}=r;if(i!==void 0&&i.length>0){let c=e.textContent;if(c!==i)throw new Pe(`Resolved element text mismatch: expected ${i}, got ${c}`)}if(o)for(let[c,u]of Object.entries(o)){let d=e.getAttribute(c)??void 0;if(d!==u)throw new Pe(`Attribute ${c} mismatch: expected ${u}, got ${d}`)}if(a&&n){let{originalBounds:c,newBounds:u}=n;if(!c)throw new Pe("Cannot validate bounds requirements without original bounds in cache");if(!(ks(c.x1,u.x1)&&ks(c.y1,u.y1)&&ks(c.x2,u.x2)&&ks(c.y2,u.y2))){let m=p=>`[${p.x1},${p.y1},${p.x2},${p.y2}]`;throw new Pe(`Bounds changed from ${m(c)} to ${m(u)}`)}}if(s&&n&&!Rf(n.newBounds,s))throw new Pe(`Position mismatch: expected ${JSON.stringify(s)}, got ${JSON.stringify(n.newBounds)}`);if(l&&n&&!xf(n.newBounds,l))throw new Pe(`Shape mismatch: expected ${JSON.stringify(l)}, got ${JSON.stringify(n.newBounds)}`)}async function Ere({target:t,logger:e,emulator:r}){if(!t.xPath)throw new Pe(`Could not resolve cached target via XPath: ${t.xPath}`);let n=await r.nativeA11yTreeJson(),o=await CR(n,{pruneElementsOutsideBounds:void 0});return await wk({target:t,logger:e,document:o.originalDocument})}async function wk({target:t,logger:e,document:r}){if(!t.xPath)throw new Pe(`Could not resolve cached target via XPath: ${t.xPath}`);let n=t.xPath;if(t.requiredRelatedElements){let a=t.requiredRelatedElements;for(let s of a){let l=lte.evaluateXPathToFirstNode(s.xPath,r);if(!l)throw new Pe(`Required related element not found for XPath: ${s.xPath}`);await Tre(e,l,s.requirements);}}let o=lte.evaluateXPathToFirstNode(n,r);if(!o)throw new Pe(`Could not resolve cached target via XPath: ${n}`);let i=El(o);if(!i)throw new Pe(`Could not determine bounds for cached target via XPath: ${n}`);return await Tre(e,o,t.requirements,{originalBounds:t.bounds?{x1:t.bounds[0],y1:t.bounds[1],x2:t.bounds[2],y2:t.bounds[3]}:void 0,newBounds:i}),{type:"NATIVE",bounds:i,cache:{...t,bounds:[i.x1,i.y1,i.x2,i.y2]}}}async function vre({logger:t,driver:e,aiResponse:r,description:n,emulatorState:o}){switch(o.sourceTree){case "appium":return await pre({logger:t,driver:e,aiResponse:r,description:n,emulatorState:o});case "native":return await yre({aiResponse:r,description:n,emulatorState:o});default:{let i=o.sourceTree;throw new Error(`Unsupported source tree type for building iOS target cache: ${i}`)}}}async function Cre({target:t,driver:e,stateManager:r,logger:n,emulator:o}){if(t.type==="WEBVIEW"||!t.sourceTree||t.sourceTree=="appium")return await gre({target:t,driver:e,stateManager:r,logger:n});switch(t.sourceTree){case "native":return await Ere({target:t,logger:n,emulator:o});default:{let i=t.sourceTree;throw new Error(`Unsupported source tree type for resolving iOS target cache: ${i}`)}}}var Ur=class{emulator;driver;stateManager;generator;fixtures;orgId;aiSettings;emulatorSettings;aborter;constructor(e){this.stateManager=e.stateManager,this.driver=e.driver,this.emulator=e.emulator,this.aborter=e.aborter,this.fixtures=e.fixtures,this.orgId=e.orgId,this.generator=e.generator,this.aiSettings=e.aiSettings,this.emulatorSettings=e.emulatorSettings;}async findElement({logger:e,tracer:r,description:n,skipFetchingFullWebviewContent:o=false,removeWebviewContent:i=false,filterOffscreenElements:a=true,useMemory:s=false,metadata:l,cacheBustReason:c,knownState:u}){let d=e.child({...l});u||await this.stateManager.waitForScreenshotStability({logger:e,timeoutMs:5e3,signal:this.aborter.controller?.signal,reason:"Waiting for stability before locating an element with AI"});let{emulatorState:m,screenshot:p}=u??await r.startAsyncSection("Get emulator state",async()=>{let g=await this.stateManager.getCurrentScreenshotPngString(e);return {emulatorState:await this.stateManager.getDomState(e,{skipFetchingFullWebviewContent:o,removeWebviewContent:i,filterOffscreenElements:a}),screenshot:g}}),f;try{f=await r.startAsyncSpan("AI_LOCATOR_CALL",async g=>{c&&(g.attributes.cacheBustReason=c);let y=await this.generator.getIosElementLocation({description:n,screenXml:m.graph.xml,screenshot:p,source:l?.source==="SCROLL_TO"?"SCROLL_TO":void 0},{logger:d,loggerTags:De(d),abortSignal:this.aborter.controller?.signal,useMemory:s,agentConfigVersion:this.aiSettings.agentConfig?.["ios-locator"]});return g.result=y,y});}catch(g){throw this.throwIfAborted(),d.error({err:g},"Failed to locate element"),new Error(`ActionFailureError: Failed to locate element: ${g instanceof Error?g.message:g}`,{cause:g})}if(f.id===-1)throw new M("NoMatchingElementError",f.thoughts??"No matching element found");let h=await vre({logger:e,driver:this.driver,aiResponse:f,description:n,emulatorState:m});return r.addSpan({type:"TARGET_RESOLUTION",startTime:Date.now(),endTime:Date.now(),result:{serializedElement:(h.type==="NATIVE"?h.cache.elementOnlySerializedXml:void 0)??"Unknown element"},attributes:{},subSpans:[]}),{resolvedTarget:h,thoughts:f.thoughts}}async targetingActionWithAILocator(e){let{tracer:r,action:n,command:o,description:i,cacheKey:a,targetName:s,skipFetchingFullWebviewContent:l,removeWebviewContent:c,metadata:u,logger:d,cacheBustReason:m}=e,p=await this.findElement({logger:d,tracer:r,description:i,skipFetchingFullWebviewContent:l,removeWebviewContent:c,metadata:u,cacheBustReason:m}),f=p.thoughts,h=await n(p.resolvedTarget);return kd({command:o,cacheKey:a,targetName:s,updatedCache:Nd(p.resolvedTarget),updatedWithAI:true,logger:d}),{result:h,thoughts:f}}async targetingActionWithCache({logger:e,tracer:r,action:n,command:o,cacheKey:i,targetName:a,cacheCopyForAttempt:s}){this.emulatorSettings?.waitForStability!==false&&await this.stateManager.waitForScreenshotStability({logger:e,timeoutMs:5e3,signal:this.aborter.controller?.signal,reason:"Waiting for stability before cache resolution"});let l=await this.resolveTargetCacheWithTracing({logger:e,tracer:r,cache:s}),c=await n(l);return kd({command:o,cacheKey:i,targetName:a,updatedCache:Nd(l),updatedWithAI:false,logger:e}),{result:c,thoughts:"Successfully executed preset action with cache"}}async resolveTargetCacheWithTracing({logger:e,tracer:r,cache:n,retryWithinSmartWaiting:o=true}){let{resolvedTarget:i}=await r.startAsyncSpan("CACHE_RESOLUTION",async a=>{let s=Date.now(),l;for(;!o||Date.now()-s<3e3;)try{let c=await Cre({target:n,driver:this.driver,stateManager:this.stateManager,logger:e,emulator:this.emulator});return a.attributes.serializedElement=(c.type==="NATIVE"?c.cache.elementOnlySerializedXml:void 0)??"Unknown element",{resolvedTarget:c}}catch(c){if(l=c,c instanceof Pe){if(!o)throw c;e.warn({err:c},"Failed to resolve target cache, retrying"),await ms(100,this.aborter.controller?.signal);continue}throw e.error({err:c},"Failed to resolve target cache"),c}throw l});return i}async wrapTargetingAction(e){let{tracer:r,logger:n,action:o,description:i,command:a,cacheKey:s="cache",targetName:l="target",cacheIsInvalidAfterResolution:c,skipFetchingFullWebviewContent:u=false,removeWebviewContent:d=false}=e,m={commandId:a.id},p=false,f,h;if(s==="cache"&&"cache"in a&&a.cache){let g=a.cache;l==="target"&&"target"in g?h=cloneDeep(g.target):l==="fromTarget"&&"fromTarget"in g?h=cloneDeep(g.fromTarget):l==="toTarget"&&"toTarget"in g&&(h=cloneDeep(g.toTarget));}if(a.disableCache&&(n.debug({command:a},"Cache explicitly disabled for command"),p=true,f="Cache explicitly disabled",h=void 0),c&&(p=true,f=f??"Cache invalidated after resolution",h=void 0),h&&!Dc(h.resolvedDescription??"",i)&&(n.info({description:i,cacheDescription:h.resolvedDescription},"Cache description mismatch, clearing it automatically"),p=true,f="Description mismatch",h=void 0),h){let g=h.type==="NATIVE"?!!h.requirements:!!h.browserCache?.requirements;try{let y=await this.targetingActionWithCache({logger:n,tracer:r,action:o,command:a,cacheKey:s,targetName:l,cacheCopyForAttempt:h});return Ge.increment("cache_target_resolution_v2",1,["outcome:hit","platform:mobile-native",`hasRequirements:${g}`,`orgId:${this.orgId}`,"cliVersion:1.0.2"]),y}catch(y){if(this.throwIfAborted(),y instanceof M&&y.reason!=="InternalWebAgentError")throw n.error({err:y},"Failed to execute action with target cache (fatal)"),y;Ge.increment("cache_target_resolution_v2",1,["outcome:miss","platform:mobile-native",`hasRequirements:${g}`,`orgId:${this.orgId}`,"cliVersion:1.0.2"]),n.warn({err:y},"Failed to execute action with target cache, retrying with AI");}}return n.info({description:i,cacheBustedBeforeAction:p},"Prompting AI for a new element location"),await this.targetingActionWithAILocator({tracer:r,action:o,command:a,description:i,cacheKey:s,targetName:l,skipFetchingFullWebviewContent:u,removeWebviewContent:d,metadata:m,logger:n,cacheBustReason:f})}constructPerformerParams(){return {emulator:this.emulator,stateManager:this.stateManager,driver:this.driver,fixtures:this.fixtures,emulatorSettings:this.emulatorSettings,aborter:this.aborter,orgId:this.orgId,generator:this.generator,aiSettings:this.aiSettings}}throwIfAborted(){this.aborter.controller?.signal.throwIfAborted();}get abortSignal(){return this.aborter.controller?.signal}};var RR=class extends Ur{async doDrag(e,r,n,o,i){let{x1:a,y1:s,x2:l,y2:c}=n.bounds,u=a+(l-a)/2,d=s+(c-s)/2;r.attributes.startPoint={x:u,y:d};let{x1:m,y1:p,x2:f,y2:h}=o.bounds,g=m+(f-m)/2,y=p+(h-p)/2;r.attributes.endPoint={x:g,y};let S=i?.hoverDuration??500,E=i?.dragDuration??1e3;E===0&&(E=1);let w=Math.sqrt(Math.pow(g-u,2)+Math.pow(y-d,2))/E*1e3;await this.driver.executeInNativeContext(e,async _=>{await _.execute("mobile: dragFromToWithVelocity",{fromX:u,fromY:d,toX:g,toY:y,pressDuration:S/1e3,velocity:w,holdDuration:.5});},{operationName:"dragAndDrop"});}async executeDragAndDrop({logger:e,command:r}){let n=ae();if(r.fromTarget.type!=="description"||r.toTarget.type!=="description")throw new M("UserConfigurationError","Drag and drop only supports description targets for now");let o=r.fromTarget.description,{result:i,thoughts:a}=await this.wrapTargetingAction({command:r,tracer:n,description:o,cacheKey:"cache",targetName:"fromTarget",action:async u=>u,logger:e}),s=r.toTarget.description,{result:l,thoughts:c}=await this.wrapTargetingAction({command:r,tracer:n,description:s,cacheKey:"cache",targetName:"toTarget",action:async u=>u,logger:e});return await n.startAsyncSpan("EMULATOR_INTERACTION",async u=>{await this.doDrag(e,u,i,l,{hoverDuration:r.hoverDuration,dragDuration:r.dragDuration});},{name:"Drag and drop"}),{success:true,message:`${a}
|
|
5876
5876
|
${c}`}}};var xR=class{driver;logger;constructor(e,r){this.driver=e,this.logger=r;}async getTextContent(e){let r=e.cache.xPath;return r?await this.driver.executeInNativeContext(this.logger,async o=>{try{let a=(await o.findElement("xpath",r))[vi];if(!a)return "";let s=await o.getElementAttribute(a,"label"),l=await o.getElementAttribute(a,"value");return [s,l].filter(u=>!!u&&u.trim().length>0).join(" ").trim()}catch{return ""}},{operationName:"getNativeElementTextContent"})??"":""}async getAttribute(e,r){let n=e.cache.xPath;return n?await this.driver.executeInNativeContext(this.logger,async i=>{try{let s=(await i.findElement("xpath",n))[vi];return s?await i.getElementAttribute(s,r)??"":""}catch{return ""}},{operationName:"getNativeElementAttribute"})??"":""}async getTagName(e){let r=e.cache.xPath;return r?await this.driver.executeInNativeContext(this.logger,async o=>{try{let a=(await o.findElement("xpath",r))[vi];return a?await o.getElementTagName(a)??"":""}catch{return ""}},{operationName:"getNativeElementTagName"})??"":""}async isEditable(e){throw new M("UserConfigurationError","Editable checks are not supported on iOS native elements")}async isEnabled(e){let r=e.cache.xPath;return r?await this.driver.executeInNativeContext(this.logger,async n=>{try{let i=(await n.findElement("xpath",r))[vi];return i?await n.isElementEnabled(i):!1}catch{return false}},{operationName:"isNativeElementEnabled"}):false}async isFocused(e){let r=await this.getAttribute(e,"focused");return r==="true"||r==="1"}async getStyleProperty(e,r){throw new M("UserConfigurationError","Computed style checks are not supported on iOS native elements")}},MR=class{driver;webviewContext;logger;constructor(e,r,n){this.driver=e,this.webviewContext=r,this.logger=n;}getCenter(e){let{x1:r,y1:n,x2:o,y2:i}=e.bounds;return {x:(r+o)/2,y:(n+i)/2}}async getTextContent(e){let{x:r,y:n}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(i,a,s)=>{let l=document.elementFromPoint(a,s);return l?l.innerText??l.textContent??"":""},r,n)??""}async getAttribute(e,r){let{x:n,y:o}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(a,s,l,c)=>{let u=document.elementFromPoint(s,l);return u?u.getAttribute(c)??"":""},n,o,r)??""}async getTagName(e){let{x:r,y:n}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(i,a,s)=>{let l=document.elementFromPoint(a,s);return l?l.tagName:""},r,n)??""}async isEditable(e){let{x:r,y:n}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(i,a,s)=>{let l=document.elementFromPoint(a,s);if(!l)return false;let c=l.tagName;return c==="INPUT"||c==="TEXTAREA"||c==="SELECT"||l.isContentEditable},r,n)}async isEnabled(e){let{x:r,y:n}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(i,a,s)=>{let l=document.elementFromPoint(a,s);return l?!l.disabled:false},r,n)}async isFocused(e){let{x:r,y:n}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(i,a,s)=>{let l=document.elementFromPoint(a,s);return l?document.activeElement===l:false},r,n)}async getStyleProperty(e,r){let{x:n,y:o}=this.getCenter(e);return await this.driver.executeWebViewScript(this.logger,this.webviewContext,(a,s,l,c)=>{let u=document.elementFromPoint(s,l);return u?window.getComputedStyle(u).getPropertyValue(c):""},n,o,r)??""}};var gVe=5e3,PR=class extends Ur{async executeElementCheck({logger:e,command:r}){let n=Date.now(),o=(r.timeout??un)*1e3,i=o+1e4,a,s=0,l=500,c=cloneDeep(r.cache);if(r.target.type!=="description")throw new M("UserConfigurationError","x/y targets are not supported for the Element check step");for(;s-n<o;){if(Date.now()-n>i){e.warn("Exceeded max system timeout for element check, exiting...");break}if(this.throwIfAborted(),a=await this.executeElementCheckHelper({logger:e,command:r}),s=Date.now(),!a.success)r.cache=c,c=cloneDeep(c),await pe(l,this.abortSignal),l=Math.min(Math.floor(l*1.5),gVe);else return a}let u=await this.executeElementCheckHelper({logger:e,command:r,cacheIsInvalidAfterResolution:true});if(!u.success&&c&&r.cache){let d=x3({logger:e,originalTarget:fP(c)?c.target:void 0,newTarget:r.cache.target});d&&il(c.target,d)&&(r.cache={target:d,updatedAt:r.cache.updatedAt});}return u}async executeElementCheckHelper({logger:e,command:r,cacheIsInvalidAfterResolution:n}){let o=ae();if(r.target.type!=="description")throw new M("UserConfigurationError","x/y targets are not supported for the Element check step");let i=ap(r.assertion);try{return (await this.wrapTargetingAction({...n?{cacheIsInvalidAfterResolution:n}:{},command:r,tracer:o,action:async s=>s.type==="NATIVE"?await this.executeNativeElementCheck(e,r,s):await this.executeWebviewElementCheck(e,r,s),description:r.target.description,logger:e})).result}catch(a){return i&&(a instanceof M&&a.reason==="NoMatchingElementError"||a instanceof Wa)?{success:true}:{success:false,message:`Failed to evaluate element content assertion: ${a instanceof Error?a.message:`${a}`}`}}}async executeNativeElementCheck(e,r,n){let o=ae(),{assertion:i}=r;return await o.startAsyncSpan("ELEMENT_ASSERTION",async a=>{a.targetBounds=Ld(n);let s=await this.executeElementAssertion({assertion:i,element:n,elementPropertyAccessors:new xR(this.driver,e),span:a});return a.result=s,s},{name:"Native element check"})}async executeWebviewElementCheck(e,r,n){let o=ae(),{assertion:i}=r,s=(await this.stateManager.getContexts(e)).webviews[0];if(!s)throw new M("UserConfigurationError","No active webview context found for element check");return await o.startAsyncSpan("ELEMENT_ASSERTION",async l=>{l.targetBounds=Ld(n);let c=await this.executeElementAssertion({assertion:i,element:n,elementPropertyAccessors:new MR(this.driver,s,e),span:l});return l.result=c,c},{name:"Webview element check"})}async executeElementAssertion({assertion:e,element:r,elementPropertyAccessors:n,span:o}){switch(e.type){case "ELEMENT_CONTENT":{let i=await n.getTextContent(r)??"";return o.attributes.elementTextContent=kr(i,500,true),Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})?{success:true}:{success:false,message:`The content ${wn(e)} '${e.value}': ${i}`}}case "ELEMENT_ATTRIBUTE":{let i=null;try{i=await n.getAttribute(r,e.attr);}catch{i=null;}if(!Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let a=wn(e);return {success:false,message:`The attribute ${e.attr} ${a}${e.operation==="EXISTS"?"":` '${e.value}': ${i}`}`}}return {success:true}}case "ELEMENT_EXISTENCE":{let i=false;switch(e.condition){case "EDITABLE":i=await n.isEditable(r);break;case "VISIBLE":case "EXISTS":i=true;break;case "ENABLED":{i=await n.isEnabled(r);break}case "FOCUSED":i=await n.isFocused(r);break;default:throw e.condition,new Error("Unrecognized element condition type")}return i=e.negated?!i:i,i?{success:true}:{success:false,message:`The element ${wn(e)}`}}case "ELEMENT_NAME":{let i=await n.getTagName(r);return Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:true})?{success:true}:{success:false,message:`The element tag name ${wn(e)} '${e.value}': ${i}`}}case "ELEMENT_STYLE":{let i=await n.getStyleProperty(r,e.property);if(!Co(i,e.value,e.operation,{negated:!!e.negated,ignoreCase:false})){let a=wn(e);return {success:false,message:`The style property ${e.property} ${a}${e.operation==="EXISTS"?"":` '${e.value}': ${i}`}`}}return {success:true}}default:throw new Error("Unrecognized element assertion type")}}};async function Are({command:t,orgId:e,logger:r,fixtures:n,abortSignal:o}){let i;try{i=await Yi({orgId:e,code:t.code,fragment:!1,context:n.testContext,timeoutMs:t.timeout?t.timeout*1e3:void 0,logger:r,localTools:n.localCodeEvalTools,signal:o});}catch(a){throw new M("ActionFailureError",a instanceof M?a.message:`${a}`,{errOptions:{cause:a}})}try{JSON.stringify(i);}catch(a){throw new M("UserConfigurationError",`Return value is not serializable: ${a instanceof Error?a.message:`${a}`}`)}return {success:true,output:i}}async function Rre({command:t,emulator:e,abortSignal:r}){let n;switch(t.key){case "ENTER":n="enter";break;case "BACKSPACE":n="backspace";break;default:{t.key;return {success:true}}}let o=t.repeat??1,i=t.keyPressDelayMs??0;for(let a=0;a<o;a++)a>0&&i>0&&await pe(i,r),await e.pressKey(n);return {success:true}}var xre=C__default.object({name:C__default.string(),pid:C__default.number(),bundleId:C__default.string()});var Pf=class extends Ur{async doPress(e,{name:r,longPress:n}){return this.driver.executeInNativeContext(e,o=>o.executeScript("mobile: pressButton",[{name:r,isLongPress:n}]),{operationName:"pressButton"})}};var bVe="com.apple.springboard",Mre=5,_R=class extends Ur{async execute(e){let r;for(let n=0;n<Mre;n++){this.throwIfAborted();try{let i=await this.driver.executeInNativeContext(e,s=>s.executeScript("mobile: activeAppInfo",[]),{operationName:"getActiveAppInfo"});r=xre.parse(i).bundleId;}catch(i){throw new M("UserConfigurationError",`Failed to get active app info: ${i.message}`)}if(!r)return {success:true,message:"No active app found"};if(await new Pf(this.constructPerformerParams()).doPress(e,{name:"home"}),r!==bVe)return await this.emulator.terminateApp(r),{success:true};await pe(500,this.abortSignal);}throw new M("ActionFailureError",`Failed to dismiss notification after ${Mre} attempts, cannot kill the underlying app`)}};var yVe="FBSApplicationLibrary) returned nil";function Pre(t){return W(t).includes(yVe)}async function Ire({driver:t,logger:e,bundleId:r,launchArguments:n}){try{await t.executeInNativeContext(e,o=>o.execute("mobile: launchApp",{bundleId:r,arguments:n}),{operationName:"launchApp"});}catch(o){throw Pre(o)?new Ha(`App "${r}" is not installed on the device. Install the app on the device before running this step, or update the step to reference a bundle ID that is installed.`,{cause:o}):o}}async function _re({command:t,logger:e}){let r;try{r=new URL(t.url).hostname;}catch(l){throw new M("UserConfigurationError",`Invalid URL: ${l instanceof Error?l.message:`${l}`}`)}let n=new CookieJar,o=eOe(fetch,n),i=Date.now(),a=await jp({command:t,baseUrl:void 0,logger:e,fetchImplementation:o}),s=Tm(n,r);return {output:Wd.parse({...a,cookies:s}),success:true,message:`Successfully executed request in ${Date.now()-i}ms`}}async function Ore({command:t,emulator:e,driver:r,logger:n,getViewportBounds:o}){return e.setOrientation?await e.setOrientation(t.orientation):await r.executeInNativeContext(n,async i=>{await i.setOrientation(t.orientation==="LANDSCAPE"?"landscape":"portrait");},{operationName:"setOrientation"}),{success:true,output:{newViewportBounds:await o()}}}var EVe=5e3,OR=class extends Ur{async executeScreenCheck(e,r){let{timeout:n}=r,o=Date.now(),i=(n??un)*1e3,a=i+1e4,s=0,l=500;for(;s-o<i;){if(Date.now()-o>a){e.warn("Exceeded max system timeout for screen check, exiting...");break}this.throwIfAborted();let c=await this.executeScreenCheckHelper(e,r);if(s=Date.now(),!c.success)await pe(l,this.abortSignal),l=Math.min(Math.floor(l*1.5),EVe);else return c}return await this.executeScreenCheckHelper(e,r)}async executeScreenCheckHelper(e,r){let n=await this.executeNativeScreenCheckHelper(e,r);if(!r.assertion.negated&&n.success)return n;let o=await this.executeWebviewScreenCheckHelper(e,r);return o?r.assertion.negated?n.success&&o.success?n:n.success?o:n:n.success?n:o:n}async executeNativeScreenCheckHelper(e,r){let{assertion:n}=r;switch(n.type){case "CONTENT":try{let i=(await this.stateManager.getDomState(e,{skipFetchingFullWebviewContent:!0,removeWebviewContent:!0,filterOffscreenElements:!1})).graph.xml;if(!i)throw new Error("Failed to get screen XML");let a=i.includes(n.value)===!n.negated;return i.length>1e4&&(i=i.slice(0,1e4)+"...TRUNCATED"),a?{success:!0}:{success:!1,message:`The screen ${ip({...n,negated:!n.negated})}.`}}catch(o){if(NS(o))throw o;return {success:false,message:`Failed to evaluate screen content assertion: ${o instanceof Error?o.message:`${o}`}`}}default:return n.type,{success:false,message:`Unsupported screen check assertion type: ${n.type}`}}}async executeWebviewScreenCheckHelper(e,r){let n;try{if(n=await this.stateManager.getActiveWebview(e),!n)return}catch(i){e.warn({err:i},"Failed to get active webview context during screen check");return}let{assertion:o}=r;switch(o.type){case "CONTENT":try{return await this.driver.executeWebViewScript(e,n,(a,s,l)=>document.body.innerHTML.includes(s)===!l,o.value,!!o.negated)?{success:!0}:{success:!1,message:`The webview ${ip({...o,negated:!o.negated})}.`}}catch(i){e.warn({err:i},"Failed to check webview content during screen check");return}default:return}}};var vVe=.9,vl=.2,CVe=500;function Rk(t,e){t.attributes.scrollableElementType=e.type,t.attributes.scrollableElementDisplay=Ks(e),e.type==="CUSTOM"&&(t.attributes.scrollableElementDescription=e.target.description);}var If=class extends Ur{async getHardcodedScrollableElementBounds(e,r){let n;switch(e.type){case "SCREEN":n=this.getContainerBoundsFromViewport(r);break;case "OPEN_APP":n=this.getContainerBoundsFromViewport(r);break;case "OPEN_WEBVIEW":{n=this.getContainerBoundsFromViewport(r);break}default:{throw new Error("If Typescript complains about the line above, you missed a switch case")}}return n}getContainerBoundsFromViewport(e){return {left:e.x,top:e.y,width:e.width,height:e.height}}getContainerBoundsFromBounds(e){let r=e.x1,n=e.y1,o=e.x2,i=e.y2,a=o-r,s=i-n;return {left:r,top:n,width:a,height:s}}async executeSwipe({logger:e,command:r}){let n=ae(),o=Ks(r.scrollableElement);if(r.scrollableElement.type==="CUSTOM_COORDINATES"){let{startX:a,startY:s,deltaPixels:l}=r.scrollableElement;return await n.startAsyncSpan("EMULATOR_INTERACTION",async c=>{Rk(c,r.scrollableElement),await this.performRawSwipe({logger:e,span:c,startX:a,startY:s,deltaPixels:l,direction:r.direction,durationMs:r.durationMs});},{name:`Swipe ${r.direction} in ${o}`}),{success:true,message:"Successfully executed swipe action"}}if(r.scrollableElement.type!=="CUSTOM"){let a=await this.driver.executeInNativeContext(e,async l=>l.getWindowRect(),{operationName:"getSwipeViewportRect"}),s=await this.getHardcodedScrollableElementBounds(r.scrollableElement,a);return await n.startAsyncSpan("EMULATOR_INTERACTION",async l=>{Rk(l,r.scrollableElement),await this.swipeByAbsoluteCoordinates({logger:e,span:l,direction:r.direction,percent:r.viewportPercent,durationMs:r.durationMs,containerBounds:s,relativePosition:r.relativePosition?er(r.relativePosition):void 0});},{name:`Swipe ${r.direction} in ${o}`}),{success:true,message:"Successfully executed swipe action"}}let{thoughts:i}=await this.wrapTargetingAction({command:r,description:r.scrollableElement.target.description,action:async a=>ae().startAsyncSpan("EMULATOR_INTERACTION",async l=>(Rk(l,r.scrollableElement),this.scrollInNativeContainer({logger:e,span:l,cmd:r,target:a})),{name:`Swipe ${r.direction} in ${o}`}),tracer:n,logger:e});return {success:true,message:i}}async scrollInNativeContainer({logger:e,span:r,cmd:n,target:o}){let i=o.bounds,a=this.getContainerBoundsFromBounds(i);await this.swipeByAbsoluteCoordinates({logger:e,span:r,direction:n.direction,percent:n.viewportPercent,durationMs:n.durationMs,containerBounds:a,relativePosition:n.relativePosition?er(n.relativePosition):void 0});}async swipeByAbsoluteCoordinates({logger:e,span:r,direction:n,percent:o=vVe,durationMs:i,containerBounds:a,relativePosition:s}){r.attributes.containerBounds=a;let l=n==="up"||n==="down",c=a.width*vl,u=a.height*vl,d=l?(a.height-2*u)*o:(a.width-2*c)*o,m,p,f;if(s)m=a.left+s.x,p=a.top+s.y,f=d;else {let h=this.calculateSwipeCoordinates({containerBounds:a,direction:this.invertDirection(n),desiredDelta:d});m=h.startX,p=h.startY,f=h.actualDelta;}await this.performRawSwipe({logger:e,span:r,startX:m,startY:p,deltaPixels:f,direction:n,durationMs:i});}calculateSwipeCoordinates({containerBounds:e,direction:r,desiredDelta:n}){let o=e.left+e.width/2,i=e.top+e.height/2;if(r==="up"||r==="down"){let a=e.height*vl,s=e.top+a,l=e.top+e.height-a,c=l-s,u=Math.min(Math.abs(n),c),d=c-u,m=r==="down"?l-d/2:s+d/2;return {startX:o,startY:m,actualDelta:u}}else {let a=e.width*vl,s=e.left+a,l=e.left+e.width-a,c=l-s,u=Math.min(Math.abs(n),c),d=c-u;return {startX:r==="right"?l-d/2:s+d/2,startY:i,actualDelta:u}}}invertDirection(e){if(e==="up")return "down";if(e==="down")return "up";if(e==="left")return "right";if(e==="right")return "left";throw new Error(`Unreachable code: ${e}`)}async performRawSwipe({logger:e,span:r,startX:n,startY:o,deltaPixels:i,direction:a,durationMs:s=300}){let l=Math.abs(i),c=Math.max(2,Math.round(s)),u=Math.max(1,Math.min(120,Math.floor(c*.25))),d=Math.max(1,c-u),m=Math.min(l/2,Math.min(12,Math.max(l*.05,1))),p=n,f=o,h=n,g=o;a==="up"||a==="down"?(f=a==="up"?o-l:o+l,h=p,g=a==="up"?f+m:f-m):(p=a==="left"?n-l:n+l,h=a==="left"?p+m:p-m,g=f),r.attributes.pixelDelta=l,r.attributes.startPoint={x:n,y:o},r.attributes.endPoint={x:p,y:f},r.attributes.durationMs=c,await this.driver.executeInNativeContext(e,async y=>{let S={type:"pointer",id:"finger1",parameters:{pointerType:"touch"},actions:[{type:"pointerMove",duration:0,x:n,y:o},{type:"pointerDown",button:0},{type:"pause",duration:300},{type:"pointerMove",duration:d,x:h,y:g},{type:"pointerMove",duration:u,x:p,y:f},{type:"pause",duration:300},{type:"pointerUp",button:0}]};await y.performActions([S]),await y.releaseActions();},{operationName:"performRawSwipe"}),await pe(CVe,this.abortSignal);}};var Dre=20,xk=.9,AVe=2,_f=.5,Mk=.2;function RVe(t){return t.type==="NATIVE"&&t.scrollDetails!==void 0}var DR=class extends If{async executeScrollTo({logger:e,command:r}){let n=r.target.description,o=r.scrollStepPercent??xk,i=await this.tryUseCachedScrollPosition(e,r,n);return i||this.searchForElement({logger:e,cmd:r,description:n,scrollStepPercent:o})}async resolveContainer({logger:e,scrollableElement:r,containerCache:n}){let o=await this.driver.executeInNativeContext(e,async c=>c.getWindowRect(),{operationName:"getScrollContainerViewportRect"});if(r.type==="CUSTOM_COORDINATES")return {bounds:{left:0,top:0,width:o.width,height:o.height},diffThresholdPercent:_f};if(r.type!=="CUSTOM")return {bounds:await this.getHardcodedScrollableElementBounds(r,o),diffThresholdPercent:_f};let i=ae(),a=r.target.description;if(n){let c=this.getBoundsFromNativeCache(n);return e.info({bounds:c},"Got container bounds from native cache"),{bounds:c,cache:n,diffThresholdPercent:_p({containerBounds:c,viewport:o,defaultThresholdPercent:_f})}}let{resolvedTarget:s}=await this.findElement({logger:e,description:a,tracer:i});if(s.type!=="NATIVE")throw new Error(`ActionFailureError: Custom scroll container "${a}" resolved to a webview element. Custom containers must be native elements.`);let l=this.getBoundsFromNativeCache(s.cache);return e.info({bounds:l},"Got container bounds from AI"),{bounds:l,cache:s.cache,diffThresholdPercent:_p({containerBounds:l,viewport:o,defaultThresholdPercent:_f})}}getBoundsFromNativeCache(e){if(!e.bounds||e.bounds.length<4)throw new M("ActionFailureError","Native target cache has no bounds");let[r,n,o,i]=e.bounds;return {left:r,top:n,width:o-r,height:i-n}}async tryUseCachedScrollPosition(e,r,n){let o=r.cache?.target;if(o){if(o.type==="WEBVIEW")return await this.tryUseWebviewCache(e,r,n);if(RVe(o))return this.tryUseNativeScrollCacheHelper(e,r,n,o)}}async tryUseWebviewCache(e,r,n){let o=ae();try{let{thoughts:i}=await this.wrapTargetingAction({logger:e,command:r,tracer:o,description:n,action:async a=>{if(a.type!=="WEBVIEW")throw new Error("Expected WEBVIEW target but got NATIVE");await this.scrollWebviewTargetIntoView({logger:e,target:a});}});return {success:!0,message:i}}catch(i){e.warn({err:i},"Failed to use webview scroll-to cache, falling back to search");return}}async tryUseNativeScrollCacheHelper(e,r,n,o){let i=o.scrollDetails,a=ae(),s=r.scrollStepPercent??xk,l=i.scrollableElement.type==="CUSTOM"&&i.scrollableElement.cache?.type==="NATIVE"?i.scrollableElement.cache:void 0,c=await this.resolveContainer({logger:e,scrollableElement:r.scrollableElement,containerCache:l}),u=c.bounds,d=c.diffThresholdPercent,m=Nre(r.scrollableElement),p=m?Math.abs(m.deltaPixels):this.calculateSwipeCoordinates({containerBounds:u,direction:r.direction,desiredDelta:Cs({containerBounds:u,containerInsetRatio:vl})*s}).actualDelta,f=await this.stateManager.getLastObservedState();if(f){let w=await this.tryFindElement({logger:e,cmd:r,description:n,tracer:a,scrollDetails:this.buildScrollDetails(r,0,c.cache),knownState:f,useAIIfCacheFails:false});if(w)return e.info("Element resolved from last observed state without scrolling"),w}else e.debug("Skipping scroll-to preflight because no last observed state is available");let h=Math.abs(i.pixelDelta),g=0,y=p*AVe,S=0;for(;S<h;){this.throwIfAborted();let w=h-S,_=Math.min(w,y),L=await this.scrollByPixelDelta({logger:e,pixelDelta:_,scrollableElement:r.scrollableElement,containerCache:c.cache,direction:r.direction,scrollStepPercent:s,useVisualDiff:false});if(L===0)break;S+=L,g+=r.direction==="down"?L:-L;let I=await this.tryFindElement({logger:e,cmd:r,description:n,tracer:a,scrollDetails:this.buildScrollDetails(r,g,c.cache),useAIIfCacheFails:false});if(I)return e.info({cumulativePixelDelta:g},"Element resolved during cache replay"),I}let E=Math.max(0,Math.min(r.maxScrollAttempts??Dre,2)),v=true;for(let w=0;w<E&&v;w++){this.throwIfAborted(),v=await this.scrollByPage({logger:e,direction:r.direction,containerBounds:u,scrollStepPercent:s,diffThresholdPercent:d,rawCoordinates:m}),v&&(g+=r.direction==="down"?p:-p);let _=await this.tryFindElement({logger:e,cmd:r,description:n,tracer:a,scrollDetails:this.buildScrollDetails(r,g,c.cache),useAIIfCacheFails:false});if(_)return e.info({attempt:w,cumulativePixelDelta:g},"Element resolved during cache buffer scroll"),_}if(g!==0){let w=r.direction==="down"?"up":"down";e.info({cumulativePixelDelta:g,originalDirection:r.direction,undoDirection:w,scrollableElementType:r.scrollableElement.type},"Cache replay did not resolve target; undoing scroll"),await this.scrollByPixelDelta({logger:e,pixelDelta:Math.abs(g),scrollableElement:r.scrollableElement,containerCache:c.cache,direction:w,scrollStepPercent:s});}}async tryFindElement({logger:e,cmd:r,description:n,tracer:o,scrollDetails:i,useAIIfCacheFails:a=true,knownState:s}){let l,c,u=false,d=i,m=Lre(r.cache?.target);if(m&&m.type==="NATIVE"&&m.resolvedDescription!==void 0&&Dc(m.resolvedDescription,n)&&!r.disableCache)try{l=s?await o.startAsyncSpan("CACHE_RESOLUTION",async h=>{let g=await wk({target:m,logger:e,document:s.emulatorState.graph.originalDocument});return h.attributes.serializedElement=g.cache.elementOnlySerializedXml??"Unknown element",{resolvedTarget:g}}).then(({resolvedTarget:h})=>h):await this.resolveTargetCacheWithTracing({logger:e,tracer:o,cache:m,retryWithinSmartWaiting:!1}),u=!0,c="Successfully resolved scroll to target with cache.",e.info("Successfully resolved scroll to target from cache");}catch(f){e.warn({err:f},"Failed to resolve target from cache");}if(l&&u&&i){let f=await this.correctNativeTargetIntoView({logger:e,tracer:o,cmd:r,resolvedTarget:l,scrollDetails:i});d=f.scrollDetails,f.resolvedTarget?l=f.resolvedTarget:(l=void 0,u=false);}if(!l&&!a)return null;if(!l)try{let f=cw(n),h=await this.findElement({logger:e,description:f,tracer:o,knownState:s,metadata:{commandId:r.id,source:"SCROLL_TO"}});if(h.resolvedTarget.type==="WEBVIEW")return await this.scrollWebviewTargetIntoView({logger:e,target:h.resolvedTarget}),kd({command:r,updatedCache:Nd(h.resolvedTarget),updatedWithAI:!0,logger:e}),{success:!0,message:h.thoughts};if(h.resolvedTarget.type!=="NATIVE")return null;l=h.resolvedTarget,c=h.thoughts;}catch(f){if(f instanceof M&&f.reason==="NoMatchingElementError")return null;throw e.warn({err:f},"Failed to find scroll-to target with AI"),f}if(l&&!u&&i)try{let f=await this.correctNativeTargetIntoView({logger:e,tracer:o,cmd:r,resolvedTarget:l,scrollDetails:i});d=f.scrollDetails,f.resolvedTarget&&(l=f.resolvedTarget);}catch(f){e.warn({err:f},"Failed to reposition AI-resolved scroll-to target for stable cache generation");}return kd({command:r,updatedCache:Lre({...Nd(l),...d?{scrollDetails:d}:{}}),updatedWithAI:!u,logger:e}),{success:true,message:c}}async scrollWebviewTargetIntoView({logger:e,target:r}){let n=await this.stateManager.getActiveWebview(e);if(!n)throw new Error("ActionFailureError: Found webview element for scroll_to, but no active webview context is available.");let o=r.cache.browserCache?.generatedSelectors;if(!o?.length)throw new Error("ActionFailureError: Found webview element for scroll_to, but the element has no webview selector cache.");let i=Object.keys(r.cache.browserCache?.requirements?.attributes??{});if(!await this.driver.executeWebViewScript(e,n,(s,l,c)=>{let u=s.resolveWebviewTargetCache({selectors:l,attributesToFetch:c});if(!u)return false;for(let d of u.workingSelectors){let m=document.querySelector(d);if(m)return m.scrollIntoView({block:"center",inline:"nearest"}),true}return false},o,i))throw new Error("ActionFailureError: Found webview element for scroll_to, but could not resolve the element using its webview selector cache.")}async correctNativeTargetIntoView({logger:e,tracer:r,cmd:n,resolvedTarget:o,scrollDetails:i}){let a=await this.getCorrectiveScrollForTarget({logger:e,resolvedTarget:o});if(!a)return {resolvedTarget:o,scrollDetails:i};e.info({bounds:o.bounds,correction:a},"Repositioning scroll-to target to the preferred viewport anchor");let s=i.scrollableElement.type==="CUSTOM"&&i.scrollableElement.cache?.type==="NATIVE"?i.scrollableElement.cache:void 0,l=await this.scrollByPixelDelta({logger:e,pixelDelta:a.pixelDelta,scrollableElement:i.scrollableElement,containerCache:s,direction:a.direction,scrollStepPercent:n.scrollStepPercent??xk,useVisualDiff:true});if(l===0)return e.info({bounds:o.bounds,correction:a},"Skipping corrective scroll update because the viewport did not move"),{resolvedTarget:o,scrollDetails:i};let c;try{c=await this.resolveTargetCacheWithTracing({logger:e,tracer:r,cache:o.cache,retryWithinSmartWaiting:!1});}catch(h){return e.warn({err:h},"Failed to re-resolve scroll-to target after corrective scroll"),{resolvedTarget:o,scrollDetails:i}}let u=o.bounds,d=c.bounds;if(u.x1===d.x1&&u.y1===d.y1&&u.x2===d.x2&&u.y2===d.y2)return e.info({bounds:o.bounds,correction:a,appliedCorrectionPixels:l},"Skipping corrective scroll update because the target did not move (viewport at scroll extent)"),{resolvedTarget:c,scrollDetails:i};let p={...i,pixelDelta:_C({currentPixelDelta:i.pixelDelta,baseDirection:i.direction,correctionDirection:a.direction,correctionPixels:l})},f=await this.getCorrectiveScrollForTarget({logger:e,resolvedTarget:c});return f?(e.warn({bounds:c.bounds,correction:f},"Corrective scroll did not bring the scroll-to target into the preferred viewport anchor"),{resolvedTarget:c,scrollDetails:p}):{resolvedTarget:c,scrollDetails:p}}async searchForElement({logger:e,cmd:r,description:n,scrollStepPercent:o}){let i=ae(),a=await this.resolveContainer({logger:e,scrollableElement:r.scrollableElement});return this.scrollAndSearch({logger:e,cmd:r,description:n,tracer:i,scrollStepPercent:o,resolvedContainer:a})}async scrollAndSearch({logger:e,cmd:r,description:n,tracer:o,scrollStepPercent:i,resolvedContainer:a}){let s=0,l=a.bounds,c=a.diffThresholdPercent,u=Nre(r.scrollableElement),d=u?Math.abs(u.deltaPixels):this.calculateSwipeCoordinates({containerBounds:l,direction:r.direction,desiredDelta:Cs({containerBounds:l,containerInsetRatio:vl})*i}).actualDelta,m=true,p=r.maxScrollAttempts??Dre;for(let g=0;g<p;g++){this.throwIfAborted();let y=this.buildScrollDetails(r,s,a.cache),S=await this.tryFindElement({logger:e,cmd:r,description:n,tracer:o,scrollDetails:y});if(S)return S;if(!m)throw new Error(`ActionFailureError: Could not find element "${n}" after scrolling to the end`);e.debug({attempt:g,cumulativePixelDelta:s},"Element not found, scrolling further"),m=await this.scrollByPage({logger:e,direction:r.direction,containerBounds:l,scrollStepPercent:i,diffThresholdPercent:c,rawCoordinates:u}),s+=r.direction==="down"?d:-d;}let f=this.buildScrollDetails(r,s,a.cache),h=await this.tryFindElement({logger:e,cmd:r,description:n,tracer:o,scrollDetails:f});if(h)return h;throw new Error(`ActionFailureError: Could not find element "${n}" after ${p} scroll attempts`)}buildScrollDetails(e,r,n){return e.scrollableElement.type==="CUSTOM"?{pixelDelta:r,scrollableElement:{type:"CUSTOM",target:e.scrollableElement.target,cache:n},direction:e.direction}:e.scrollableElement.type==="CUSTOM_COORDINATES"?{pixelDelta:r,scrollableElement:e.scrollableElement,direction:e.direction}:{pixelDelta:r,scrollableElement:e.scrollableElement,direction:e.direction}}async scrollByPage({logger:e,direction:r,containerBounds:n,scrollStepPercent:o,diffThresholdPercent:i,rawCoordinates:a}){return ae().startAsyncSpan("EMULATOR_INTERACTION",async l=>(l.attributes.containerBounds=n,l.attributes.direction=r,(await this.executeScrollGesture({logger:e,span:l,direction:r,containerBounds:n,scrollStepPercent:o,diffThresholdPercent:i,rawCoordinates:a})).canScrollMore),{name:`Scroll ${r} by one page`})}async scrollByPixelDelta({logger:e,pixelDelta:r,scrollableElement:n,containerCache:o,direction:i,scrollStepPercent:a,useVisualDiff:s=false}){if(r===0)return 0;let l=ae(),c,u=_f,d,m,p;if(n.type==="CUSTOM_COORDINATES")d=n.startX,m=n.startY,p=n.deltaPixels;else {c=await this.resolveContainer({logger:e,scrollableElement:n,containerCache:o});let g=c.bounds;u=c.diffThresholdPercent;let y=Cs({containerBounds:g,containerInsetRatio:vl})*a,S=this.calculateSwipeCoordinates({containerBounds:g,direction:i,desiredDelta:y});d=S.startX,m=S.startY,p=S.actualDelta;}let f=Math.ceil(Math.abs(r)/p),h=this.invertDirection(i);return e.debug({pixelDelta:r,swipeDirection:h,scrollableElementType:n.type,startX:d,startY:m,maxScrollPerStep:p,numScrolls:f},"scrollByPixelDelta calculated parameters"),l.startAsyncSpan("EMULATOR_INTERACTION",async g=>{g.attributes.pixelDelta=r,g.attributes.numScrolls=f,g.attributes.maxScrollPerStep=p,g.attributes.startX=d,g.attributes.startY=m;let y=0;for(let S=0;S<f;S++){this.throwIfAborted();let E=Math.abs(r)-y,v=Math.min(p,E);if(s){let w=await this.executeScrollGesture({logger:e,span:g,direction:i,containerBounds:c?.bounds,scrollStepPercent:a,diffThresholdPercent:u,rawCoordinates:{type:"CUSTOM_COORDINATES",startX:d,startY:m,deltaPixels:v}});if(w.didScroll&&(y+=v),!w.canScrollMore)break}else await this.performRawSwipe({logger:e,span:g,startX:d,startY:m,deltaPixels:v,direction:h}),y+=v;}return g.attributes.appliedPixels=y,y},{name:`Scroll ${i} by ${Math.abs(r)}px`})}async getCorrectiveScrollForTarget({logger:e,resolvedTarget:r}){let n=r.bounds,o=await this.stateManager.getViewportBounds(e),i=Math.max(1,o.bottom-o.top),a=o.top+i*Mk,s=o.bottom-i*Mk,l=OC({viewportTop:o.top,viewportBottom:o.bottom,elementHeight:n.y2-n.y1,targetTopRatio:Mk}),c=n.y1>=o.top&&n.y2<=o.bottom,u=n.y1<a||n.y2>s,d=await this.isResolvedTargetVisible({logger:e,resolvedTarget:r}),m=l-n.y1;if(!(c&&d!==false&&!u)){if(m>0)return {direction:"up",pixelDelta:m};if(m<0)return {direction:"down",pixelDelta:Math.abs(m)}}}async isResolvedTargetVisible({logger:e,resolvedTarget:r}){if(r.type==="WEBVIEW")return null;let n=r.cache.xPath;if(!n)return kre(r.cache.elementOnlySerializedXml);let o=await this.getTargetVisibilityFromDriver({logger:e,xPath:n});return o!==null?o:kre(r.cache.elementOnlySerializedXml)}async getTargetVisibilityFromDriver({logger:e,xPath:r}){try{return await this.driver.executeInNativeContext(e,async n=>{let i=(await n.findElement("xpath",r))?.[vi];if(!i)return null;let a=await n.getElementAttribute(i,"visible");return a?a!=="false":null},{operationName:"getScrollToTargetVisibility"})}catch{return null}}async executeScrollGesture({logger:e,span:r,direction:n,containerBounds:o,scrollStepPercent:i,diffThresholdPercent:a=_f,rawCoordinates:s}){let l=await this.stateManager.getRawScreenshotBase64({logger:e}),c,u,d;if(s)c=s.startX,u=s.startY,d=s.deltaPixels;else {if(!o)throw new Error("Expected container bounds for scroll gesture");let g=Cs({containerBounds:o,containerInsetRatio:vl})*i,y=this.calculateSwipeCoordinates({containerBounds:o,direction:n,desiredDelta:g});c=y.startX,u=y.startY,d=y.actualDelta;}await this.performRawSwipe({logger:e,span:r,startX:c,startY:u,deltaPixels:d,direction:this.invertDirection(n)});let m=await this.stateManager.getRawScreenshotBase64({logger:e}),p=wc(l,m),f=p>a,h=p>a;return e.debug({diffPercent:p,didScroll:f,diffThresholdPercent:a,canScrollMore:h,direction:n,actualDelta:d,rawCoordinates:s},"Scroll gesture visual diff result"),{didScroll:f,canScrollMore:h}}};function Lre(t){return !t||t.type!=="NATIVE"?t:DC(t)}function Nre(t){if(t.type==="CUSTOM_COORDINATES")return t}function kre(t){if(!t)return null;let e=t.match(/\bvisible="(true|false)"/);return e?e[1]==="true":null}function xVe(t){return "iterations"in t}function MVe(t){let e={relativePosition:t.relativePosition?er(t.relativePosition):void 0},r=t.iterations??(t.doubleTap?2:void 0),n=t.tapDelayMs??t.doubleTapDelayMs;if(r!==void 0&&(!Number.isInteger(r)||r<1))throw new M("UserConfigurationError","iterations must be a positive integer");if(n!==void 0&&(!Number.isInteger(n)||n<0))throw new M("UserConfigurationError","tapDelayMs must be >= 0");if(r&&r>1&&t.longPress)throw new M("UserConfigurationError","Cannot specify both more than one tap iteration and long press at the same time");if(n!==void 0&&(!r||r<2))throw new M("UserConfigurationError","tapDelayMs requires iterations >= 2");if(t.longPress){if(n!==void 0)throw new M("UserConfigurationError","tapDelayMs cannot be used with longPress");return {...e,longPress:true,longPressDurationMs:t.longPressDurationMs}}return r!==void 0?{...e,iterations:r,tapDelayMs:n}:e}var Of=class extends Ur{async tapOnAbsoluteCoordinates(e,r){let n=r.x,o=r.y;if(e.info({x:n,y:o},"Tap at coordinates"),"longPress"in r&&r.longPress){let i=(r.longPressDurationMs??2e3)/1e3;await this.driver.executeInNativeContext(e,a=>a.executeScript("mobile: touchAndHold",[{x:n,y:o,duration:i}]),{operationName:"touchAndHold"});return}if(xVe(r)){let i=r.tapDelayMs??100;for(let a=0;a<r.iterations;a++)await this.emulator.tap(n,o),a<r.iterations-1&&await pe(i);return}await this.emulator.tap(n,o);}async tapOnTarget({logger:e,target:r,options:n,targetBounds:o=Ld(r)}){return await ae().startAsyncSpan("EMULATOR_INTERACTION",async a=>{a.attributes.options=n;let{x1:s,y1:l,x2:c,y2:u}=r.bounds,d=c-s,m=u-l,p=n?.relativePosition?.x??d/2,f=n?.relativePosition?.y??m/2;p=Math.max(0,Math.min(p,d)),f=Math.max(0,Math.min(f,m));let h=s+p,g=l+f;await this.tapOnAbsoluteCoordinates(e,{x:h,y:g,...n}),a.attributes.point={x:h,y:g},a.targetBounds=o;},{name:"Tap on target"})}async executeTap({logger:e,command:r}){let n=MVe(r),o=ae();if(r.target.type==="coordinates"||r.target.type==="absolute_percent"){let s=await this.driver.executeInNativeContext(e,async u=>u.getWindowSize(),{operationName:"getTapWindowSize"}),l,c;return r.target.type==="coordinates"?(l=r.target.xPercent*s.width,c=r.target.yPercent*s.height):(l=r.target.x/100*s.width,c=r.target.y/100*s.height),await o.startAsyncSpan("EMULATOR_INTERACTION",async u=>{await this.tapOnAbsoluteCoordinates(e,{...n,x:l,y:c}),u.attributes.point={x:l,y:c};},{name:`Tap at coordinates ${l}, ${c}`}),{success:true,message:`Tapped at ${l}, ${c}`}}let i=r.target.description,{thoughts:a}=await this.wrapTargetingAction({logger:e,tracer:o,command:r,action:s=>this.tapOnTarget({logger:e,target:s,options:n}),description:i});return {success:true,message:a}}};function Fre(t,e,r){let n=t.resolveWebviewTargetCache({selectors:e,attributesToFetch:r});if(!n)return {cleared:false,reason:"target_not_found"};let o=a(n.workingSelectors);if(!o)return {cleared:false,reason:"editable_not_found"};c(o,"");let i=l(o);return {cleared:i==="",reason:i===""?void 0:"still_non_empty",textLength:i.length};function a(u){for(let d of u){let m=document.querySelector(d);if(!m)continue;let p=s(m);if(p)return p;m instanceof HTMLElement&&(m.click(),m.focus());let f=s(document.activeElement);if(f)return f}}function s(u){if(u instanceof HTMLInputElement||u instanceof HTMLTextAreaElement||u instanceof HTMLElement&&u.isContentEditable)return u}function l(u){return u instanceof HTMLInputElement||u instanceof HTMLTextAreaElement?u.value:u.textContent??""}function c(u,d){if(u instanceof HTMLInputElement||u instanceof HTMLTextAreaElement){let m=u instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,p=Object.getOwnPropertyDescriptor(m,"value")?.set;p?p.call(u,d):u.value=d;}else u.textContent=d;u.dispatchEvent(new InputEvent("input",{bubbles:true,inputType:"deleteContentBackward"})),u.dispatchEvent(new Event("change",{bubbles:true}));}}var Fd=25,Bre=150,IVe=2,_Ve=100,OVe=24,DVe=4,Ure="\uE003",LVe=new Set(["XCUIElementTypeTextField","XCUIElementTypeSecureTextField","XCUIElementTypeTextView","TextField","SecureTextField","TextView"]),LR=class extends Ur{async doType(e,r){let n=ae();if(!r.target){if(r.clearContent)throw new Error("UserConfigurationError: clearing content is only supported when a target is provided to the Type step");return await this.stateManager.waitForScreenshotStability({logger:e,timeoutMs:3e3,signal:this.aborter.controller?.signal,reason:"Waiting for page to stabilize before typing"}),await this.sendKeys(e,r),{success:true,message:"Successfully executed type action"}}if(r.target.type!=="description")throw new Error("UserConfigurationError: x/y targets are not supported for the Type step");let{thoughts:o}=await this.wrapTargetingAction({logger:e,tracer:n,command:r,action:async i=>{await this.doTypeHelper(e,r,i);},description:r.target.description});return {success:true,message:o}}async doTypeHelper(e,r,n){let o=new Of(this.constructPerformerParams()),i=Ld(n);r.clearContent&&await this.clearContent(e,r,n,o,i),await this.shouldTapToFocusTarget(e,n)&&await o.tapOnTarget({logger:e,target:n,options:{},targetBounds:i}),await this.ensureKeyboardOpen(e,n,o,i),await this.injectKeys(e,r);}async shouldTapToFocusTarget(e,r){return r.type==="WEBVIEW"?await this.shouldTapWebviewTarget(e,r):await this.shouldTapNativeTarget(e,r)}async shouldTapWebviewTarget(e,r){let n=await this.releaseCompetingWebviewFocus(e,r);return !(n.targetFocused||!n.targetResolved&&await this.isKeyboardOpen(e))}async shouldTapNativeTarget(e,r){let n=await this.resolveNativeTargetFocus(e,r);return !(n.resolved&&n.focused||!n.resolved&&await this.isKeyboardOpen(e))}async ensureKeyboardOpen(e,r,n,o){if(!await this.waitForKeyboard(e)){for(let i=0;i<IVe;i++)if(this.throwIfAborted(),e.info({attempt:i+1},"Keyboard did not open after tapping the target, re-tapping to recover"),await n.tapOnTarget({logger:e,target:r,options:{},targetBounds:o}),await this.waitForKeyboard(e))return;throw new Error("The system keyboard never opened after tapping the target, so the typed text would not be entered")}}async sendKeys(e,r){await this.waitForKeyboard(e),await this.injectKeys(e,r);}async waitForKeyboard(e){return await ae().startAsyncSection("Waiting for system keyboard to open",async(n,o)=>{let i=Date.now();for(;Date.now()-i<3e3;){if(this.throwIfAborted(),await this.isKeyboardOpen(e))return true;await new Promise(a=>setTimeout(a,500));}return o.attributes.timedOut=true,false})}async isKeyboardOpen(e){return await this.driver.executeInNativeContext(e,r=>r.isKeyboardShown(),{operationName:"isKeyboardShown"})}async injectKeys(e,r){let n=ae(),o=r.keyPressDelayMs??Fd;o<=0&&(o=Fd),await n.startAsyncSpan("EMULATOR_INTERACTION",async()=>{try{o!==Fd&&await this.driver.executeInNativeContext(e,async a=>a.updateSettings({maxTypingFrequency:1e3/o}),{operationName:"updateKeyInjectionDelay"});let i=[];for(let a=0;a<r.text.length;a+=Bre)i.push(r.text.slice(a,a+Bre));for(let a of i)await this.driver.executeInNativeContext(e,async s=>{await s.performActions(NVe(a)),await s.releaseActions();},{operationName:"typeText",maxAttempts:1,attemptTimeoutMs:FC(o,a)});}finally{o!==Fd&&await this.driver.executeInNativeContext(e,async i=>i.updateSettings({maxTypingFrequency:1e3/Fd}),{operationName:"resetKeyInjectionDelay"});}},{name:`Typing "${r.text}"${o?` with a ${o}ms delay`:""}`});}async clearContent(e,r,n,o,i){if(n.type==="WEBVIEW"){await this.clearWebviewContent(e,r,n,o,i);return}switch(r.replaceStrategy??"auto"){case "auto":await this.clearContentAutomatically(e,n,o,i);return;case "programmatic":await this.clearContentWithProgrammatic(n,e,{verify:false});return;case "long-press":await this.clearContentWithSelectAll(e,n,o,i);return;case "backspace":await this.clearContentWithBackspace(n,e,o,i);return}}async clearWebviewContent(e,r,n,o,i){switch(r.replaceStrategy??"auto"){case "long-press":await this.clearWebviewWithLongPress(e,n,o,i);return;case "programmatic":await this.clearWebviewProgrammatically(e,n);return;case "backspace":await this.clearWebviewWithBackspaceOnly(e,n,o,i);return;case "auto":await this.clearWebviewAutomatically(e,n,o,i);return}}async clearWebviewWithLongPress(e,r,n,o){if(!await this.clearContentWithSelectAll(e,r,n,o))throw new Error("ActionFailureError: Could not clear the iOS webview input with long-press Select All.")}async clearWebviewProgrammatically(e,r){if(!await this.clearWebviewContentWithDom(e,r))throw new Error("ActionFailureError: Could not clear the iOS webview input programmatically.")}async clearWebviewWithBackspaceOnly(e,r,n,o){if(!await this.clearWebviewContentWithBackspace(e,r,n,o))throw new Error("ActionFailureError: Could not clear the iOS webview input before typing.")}async clearWebviewAutomatically(e,r,n,o){if(!await this.clearWebviewContentWithDom(e,r)&&!await this.clearContentWithSelectAll(e,r,n,o)&&!await this.clearWebviewContentWithBackspace(e,r,n,o))throw new Error("ActionFailureError: Could not clear the iOS webview input before typing.")}async clearWebviewContentWithDom(e,r){let n=await this.stateManager.getActiveWebview(e);if(!n)throw new Error("ActionFailureError: Found webview element for type, but no active webview context is available.");let o=r.cache.browserCache?.generatedSelectors;if(!o?.length)throw new Error("ActionFailureError: Found webview element for type, but the element has no webview selector cache.");let i=Object.keys(r.cache.browserCache?.requirements?.attributes??{});return await ae().startAsyncSection("Clearing webview content programmatically",async(s,l)=>{let c=await this.driver.executeWebViewScript(e,n,Fre,o,i);return l.attributes.result=c,c.cleared})}async releaseCompetingWebviewFocus(e,r){let n=await this.stateManager.getActiveWebview(e);if(!n)return {targetResolved:false,targetFocused:false};let o=r.cache.browserCache?.generatedSelectors;if(!o?.length)return {targetResolved:false,targetFocused:false};let i=Object.keys(r.cache.browserCache?.requirements?.attributes??{});return await ae().startAsyncSection("Releasing focus from the competing webview element before typing",async(s,l)=>{let c=await this.driver.executeWebViewScript(e,n,(u,d,m)=>{let p=u.resolveWebviewTargetCache({selectors:d,attributesToFetch:m}),f=p?g(p.workingSelectors):void 0;if(!f)return {targetResolved:false,targetFocused:false,blurred:false};let h=document.activeElement;if(h===f)return {targetResolved:true,targetFocused:true,blurred:false};if(h instanceof HTMLElement)return h.blur(),{targetResolved:true,targetFocused:false,blurred:true};return {targetResolved:true,targetFocused:false,blurred:false};function g(S){for(let E of S){let v=y(document.querySelector(E));if(v)return v}}function y(S){if(S instanceof HTMLInputElement||S instanceof HTMLTextAreaElement||S instanceof HTMLElement&&S.isContentEditable)return S}},o,i);return l.attributes.result=c,{targetResolved:c.targetResolved,targetFocused:c.targetFocused}})}async resolveNativeTargetFocus(e,r){if(r.type!=="NATIVE")return {resolved:false};let n=r.cache.xPath;if(!Pk(r)||!n)return {resolved:false};try{return await this.driver.executeInNativeContext(e,async o=>{let a=(await o.findElement("xpath",n))[vi];if(!a)return {resolved:!1};let s=await o.getElementAttribute(a,"focused");return {resolved:!0,focused:s==="true"||s==="1"}},{operationName:"readNativeTargetFocusState",maxAttempts:1})}catch(o){return e.debug({err:o},"Failed to read native target focus state before typing"),{resolved:false}}}async clearWebviewContentWithBackspace(e,r,n,o){let i=await this.readWebviewTargetText(r,e);return i===void 0?(e.debug("Skipping webview backspace clear because the target text is not readable"),false):i===""?true:(await n.tapOnTarget({logger:e,target:r,options:{},targetBounds:o}),await this.waitForKeyboard(e)?this.clearTextWithAdaptiveBackspace({logger:e,initialLength:i.length,readText:()=>this.readWebviewTargetText(r,e),spanName:"Clearing webview content with bounded backspaces",operationName:"backspaceClearWebviewTextInput"}):false)}async clearContentAutomatically(e,r,n,o){let i=await this.readNativeTargetText(r,e);i===""||(i!==void 0||zre(r))&&await this.clearContentWithProgrammatic(r,e,{verify:true})||await this.clearContentWithSelectAll(e,r,n,o)||await this.clearContentWithBackspace(r,e,n,o);}async clearContentWithSelectAll(e,r,n,o){await n.tapOnTarget({logger:e,target:r,options:{longPress:true},targetBounds:o});let i=ae();try{return await i.startAsyncSection("Clearing any content from the focused field",()=>this.clearContentHelper(e)),!0}catch(a){return e.warn({err:a},"Failed to find select all button, continuing..."),false}}async clearContentHelper(e){await this.driver.executeInNativeContext(e,async r=>{let n=r.$('-ios predicate string:label == "Select All"');await n.waitForExist({timeout:750}),await n.click();},{operationName:"selectAllText",maxAttempts:1}),await this.driver.executeInNativeContext(e,async r=>{await r.keys([Ure]);},{operationName:"deleteSelectedText"});}async clearContentWithProgrammatic(e,r,n){if(!zre(e))return false;let o=e.cache.xPath;if(!o)return false;let i=ae();try{if(await i.startAsyncSection("Clearing content programmatically",()=>this.driver.executeInNativeContext(r,async s=>{await(await s.$(o)).clearValue();},{operationName:"clearNativeTextInput",maxAttempts:1})),!n.verify)return !0;let a=await this.readNativeTargetText(e,r);return a===void 0||a===""}catch(a){return r.warn({err:a},"Failed to clear native input programmatically, falling back..."),false}}async clearContentWithBackspace(e,r,n,o){let i=await this.readNativeTargetText(e,r);return i===void 0?(r.debug("Skipping native backspace clear because the target text is not readable"),false):i===""?true:(await n.tapOnTarget({logger:r,target:e,options:{},targetBounds:o}),this.clearTextWithAdaptiveBackspace({logger:r,initialLength:i.length,readText:()=>this.readNativeTargetText(e,r),spanName:"Clearing content with bounded backspaces",operationName:"backspaceClearNativeTextInput"}))}async clearTextWithAdaptiveBackspace({logger:e,initialLength:r,readText:n,spanName:o,operationName:i}){return await ae().startAsyncSection(o,async(s,l)=>{let c=r,u=1,d=0,m=0;for(let p=0;p<OVe;p++){let f=_Ve-d;if(f<=0)break;let g=p===0||m>0?1:Math.max(1,Math.min(Math.ceil(c/2),Math.floor(c/u),f));e.info({round:p,lengthBefore:c,keysToIssue:g,maxUnitsPerKey:u},"Issuing bounded backspaces"),await this.driver.executeInNativeContext(e,async E=>{await E.keys(Array.from({length:g},()=>Ure));},{operationName:i,maxAttempts:1}),d+=g;let y;for(let E=0;E<DVe&&(y=await n(),y===void 0);E++);if(y===void 0)return false;let S=c-y.length;if(e.info({round:p,lengthAfter:y.length,deleted:S,totalKeys:d},"Bounded backspace iteration result"),y.length===0)return l.attributes.totalKeys=d,true;if(S<=0){if(m+=1,m>=2)return false;c=y.length;continue}m=0,u=Math.max(u,Math.ceil(S/g)),c=y.length;}return l.attributes.totalKeys=d,false})}async readNativeTargetText(e,r){if(e.type!=="NATIVE")return;let n=e.cache.xPath;if(!(!Pk(e)||!n))try{return await this.driver.executeInNativeContext(r,async o=>{let a=(await o.findElement("xpath",n))[vi];return !a||await o.getElementTagName(a)==="XCUIElementTypeSecureTextField"?void 0:await o.getElementAttribute(a,"value")??""},{operationName:"readNativeTextInputValue",maxAttempts:1})}catch(o){r.debug({err:o},"Failed to read native input text for clear verification");return}}async readWebviewTargetText(e,r){let n=await this.stateManager.getActiveWebview(r);if(!n)return;let o=e.cache.browserCache?.generatedSelectors;if(!o?.length)return;let i=Object.keys(e.cache.browserCache?.requirements?.attributes??{});try{return await this.driver.executeWebViewScript(r,n,(s,l,c)=>{let u=s.resolveWebviewTargetCache({selectors:l,attributesToFetch:c});if(u)for(let d of u.workingSelectors){let m=document.querySelector(d);if(m instanceof HTMLInputElement||m instanceof HTMLTextAreaElement)return m.value;if(m instanceof HTMLElement&&m.isContentEditable)return m.textContent??""}},o,i)}catch(a){r.debug({err:a},"Failed to read webview input text for clear verification");return}}};function zre(t){if(t.type!=="NATIVE"||!Pk(t)||!t.cache.xPath)return false;let e=t.cache.elementOnlySerializedXml;if(!e)return false;for(let r of LVe)if(e.includes(`<${r}`))return true;return false}function Pk(t){return t.cache.sourceTree!=="native"}function NVe(t){let e={type:"key",id:"pressKeys",actions:[]};for(let r of [...t])e.actions.push({type:"keyDown",value:r},{type:"keyUp",value:r});return [e]}var NR=class extends Ur{async executeVisualDiff({logger:e,command:r,updateGoldenFiles:n}){let o=this.fixtures.visualDiffGoldenStorage;await this.stateManager.waitForScreenshotStability({logger:e,timeoutMs:1e4,reason:"visual diff",signal:this.abortSignal});let i=await this.stateManager.getRawScreenshotBase64({logger:e});return kC({goldenStorage:o,command:r,currentScreenshotBase64:i,threshold:r.threshold??zh,updateGoldenFiles:n,tracer:ae(),logger:e})}};async function $re({command:t,abortSignal:e}){return await pe(t.timeoutSecs*1e3,e),{success:true}}async function kVe(t,e){try{await t.executeInNativeContext(e,r=>r.executeScript("mobile: pressButton",[{name:"home"}]),{operationName:"pressHomeButton"}),e.info("Navigated to home screen");}catch(r){e.warn({err:r},"Failed to press home button");}}var Ik=["io.appium."],_k=["com.facebook.WebDriverAgentRunner.xctrunner"];async function FVe(t,e){let r;try{r=await t.listApps();}catch(a){e.warn({err:a},"Failed to list installed apps");return}let n=r.filter(({bundleId:a})=>!_k.includes(a)&&!Ik.some(s=>a.startsWith(s)));e.info({count:n.length},"Terminating all apps");let i=(await Promise.allSettled(n.map(async a=>{try{return await t.terminateApp(a.bundleId),a.bundleId}catch(s){return e.debug({err:s,bundleId:a.bundleId},"Failed to terminate app (may not be running)"),null}}))).filter(a=>a.status==="fulfilled"&&a.value!==null).length;i>0&&e.info({count:i},"Terminated apps");}async function BVe(t,e){e.info("Resetting privacy settings for all apps");try{await t.resetSettings();}catch(r){e.warn({err:r},"Failed to reset privacy settings");}}async function Vre(t){let{emulator:e,driver:r,logger:n}=t;await kVe(r,n),await FVe(e,n),await BVe(e,n);}var eu=class t extends Ur{emulatorSettings;logger;splitInstalledApps(e){let r=[],n=[];for(let{bundleId:o}of e)if(!(_k.includes(o)||Ik.some(i=>o.startsWith(i)))){if(o.startsWith("com.apple.")){n.push(o);continue}r.push(o);}return {installedApps:r,prunedApps:n}}constructor(e){super(e),this.logger=e.logger,this.emulatorSettings=e.emulatorSettings;}static async init({driver:e,logger:r,fixtures:n,orgId:o,options:i,abortController:a,emulator:s,generator:l,aiSettings:c}){let u={controller:a},d=i?.emulator??{},m=await wR.init({driver:e,orgId:o,emulator:s,options:d,aborter:u}),p=new t({generator:l,aiSettings:c,emulator:s,driver:e,stateManager:m,logger:r,fixtures:n,aborter:u,orgId:o,emulatorSettings:d});return await p.initializeSettings(),p}async executeCommand(e){let r=["type","a11yData","thoughts","cache","code"],n;try{n=await Fp({obj:e.command,context:this.fixtures.testContext,bannedKeys:r,orgId:this.orgId,logger:this.logger,signal:this.abortSignal,localTools:this.fixtures.localCodeEvalTools});}catch(o){throw this.throwIfAborted(),new Error(`ActionFailureError: Failed to substitute template strings in command: ${o.message}`,{cause:o})}try{let o=await this.executeCommandHelper(e);return !o.success&&(e.command.type==="SCREEN_CHECK"||e.command.type==="ELEMENT_CHECK")?{...o,message:PS(o.message)}:o}catch(o){throw o.name!=="AbortError"&&this.logger.error({err:o},"Error thrown in action controller"),o}finally{Bp(e.command,n);}}async executeCommandHelper({command:e,updateGoldenFiles:r}){switch(e.type){case "TAP":return new Of(this.constructPerformerParams()).executeTap({logger:this.logger,command:e});case "SWIPE":return new If(this.constructPerformerParams()).executeSwipe({logger:this.logger,command:e});case "DRAG_AND_DROP":return new RR(this.constructPerformerParams()).executeDragAndDrop({logger:this.logger,command:e});case "SCROLL_TO":return new DR(this.constructPerformerParams()).executeScrollTo({logger:this.logger,command:e});case "TYPE":return new LR(this.constructPerformerParams()).doType(this.logger,e);case "STATE":{let n=await this.stateManager.getDomState(this.logger),o=await this.stateManager.getContexts(this.logger);return {output:{xml:n.graph.xml,contexts:o},success:true}}case "OPEN_APP":{let n=[];if(e.intentExtras)try{let o=JSON.parse(e.intentExtras);n=C__default.string().array().parse(o);}catch(o){throw new Ha(`Invalid launch arguments: expected a JSON array of strings. ${W(o)}`)}return await Ire({driver:this.driver,logger:this.logger,bundleId:e.packageName,launchArguments:n}),{success:true}}case "KILL_APP":return new _R(this.constructPerformerParams()).execute(this.logger);case "PRESS":{let n=new Pf(this.constructPerformerParams());switch(e.key){case "HOME":await n.doPress(this.logger,{name:"home"});break;case "POWER":await this.driver.executeInNativeContext(this.logger,o=>o.isLocked(),{operationName:"isLocked"})?await this.driver.executeInNativeContext(this.logger,o=>o.unlock(),{operationName:"unlockDevice"}):await this.driver.executeInNativeContext(this.logger,o=>o.lock(),{operationName:"lockDevice"});break}return {success:true}}case "PRESS_KEYBOARD":return Rre({command:e,emulator:this.emulator,abortSignal:this.abortSignal});case "AI_CHECK":return lre({command:e,logger:this.logger,generator:this.generator,aiSettings:this.aiSettings,getEmulatorDomState:()=>this.getEmulatorDomState(),getScreenshotBase64:()=>this.getScreenshotBase64(),throwIfAborted:()=>this.throwIfAborted(),abortSignal:this.abortSignal});case "AI_EXTRACT":return cre({command:e,logger:this.logger,generator:this.generator,aiSettings:this.aiSettings,getEmulatorDomState:()=>this.getEmulatorDomState(),getScreenshotBase64:()=>this.getScreenshotBase64(),abortSignal:this.abortSignal});case "JAVASCRIPT":return Are({command:e,orgId:this.orgId,logger:this.logger,fixtures:this.fixtures,abortSignal:this.abortSignal});case "WAIT":return $re({command:e,abortSignal:this.aborter.controller?.signal});case "VISUAL_DIFF":return new NR(this.constructPerformerParams()).executeVisualDiff({logger:this.logger,command:e,updateGoldenFiles:r});case "REQUEST":return _re({command:e,logger:this.logger});case "ROTATE_ORIENTATION":return Ore({command:e,emulator:this.emulator,driver:this.driver,logger:this.logger,getViewportBounds:()=>this.getViewportBounds()});case "ADD_FILE":{let n=await xC(e.file);return await this.driver.executeInNativeContext(this.logger,o=>o.pushFile(e.storageLocation,n),{attemptTimeoutMs:12e4,operationName:"pushFile"}),{success:true}}case "SCREEN_CHECK":return new OR(this.constructPerformerParams()).executeScreenCheck(this.logger,e);case "ELEMENT_CHECK":return new PR(this.constructPerformerParams()).executeElementCheck({logger:this.logger,command:e});case "APPIUM_EXECUTE":{let n=JSON.parse(e.jsonArgs??"{}"),o=await this.driver.executeInNativeContext(this.logger,async i=>i.execute(e.command,n),{attemptTimeoutMs:6e4,maxAttempts:1,operationName:"userAppiumExecuteOperation"});return this.logger.info({output:o},"Appium command executed successfully"),{success:true,output:o,message:"Appium command executed successfully"}}default:{let n=e;throw new Error(`Unsupported mobile command type: ${n}`)}}}async getMobileFailureRecoveryPlan(){return {thoughts:"Failure recovery is not yet supported for iOS.",scenario:"INELIGIBLE",instructions:void 0}}async waitForPageSourceStability(e){await this.stateManager.waitForPageSourceStability({logger:this.logger,timeoutMs:e.timeoutMs??5e3,reason:e.reason,signal:this.aborter.controller?.signal});}async getInstalledApps(){let e=await this.emulator.listApps();return this.splitInstalledApps(e)}async initializeSettings(){let{latitude:e,longitude:r}=this.emulatorSettings?.geolocation??em;await this.driver.executeInNativeContext(this.logger,async n=>{await n.setGeoLocation({latitude:e,longitude:r}),await n.updateSettings({pageSourceExcludedAttributes:"visible,accessible",maxTypingFrequency:1e3/Fd,reduceMotion:true});},{operationName:"initializeDeviceSettings"});}async getScreenshotBase64(){return this.stateManager.getRawScreenshotBase64({logger:this.logger})}async getScreenshotPngString(){return this.stateManager.getCurrentScreenshotPngString(this.logger)}async getEmulatorDomState(){return (await this.stateManager.getDomState(this.logger)).graph.xml}async getViewportBounds(){return this.stateManager.getViewportBounds(this.logger)}async waitForScreenshotStability(e){return this.stateManager.waitForScreenshotStability({logger:this.logger,timeoutMs:e.timeoutMs??5e3,reason:e.reason,signal:this.aborter.controller?.signal})}resetAbortController(e){this.aborter.controller=e??new AbortController;}isAborted(){return this.aborter.controller?.signal.aborted}abort(){this.aborter.controller?.abort();}async softReset(){await Vre({emulator:this.emulator,driver:this.driver,logger:this.logger}),this.fixtures.testContext.resetToInitial();}async cleanup(){}get abortSignal(){return this.aborter.controller?.signal}get context(){return this.fixtures.testContext}get localCodeEvalTools(){return this.fixtures.localCodeEvalTools}};function Df({appFolderPath:t,source:e,overrideBaseDir:r}){let n=t?.trim();if(!n)return;if(e==="default")return n;let o=e==="override"&&r&&!fr__default.isAbsolute(n)?fr__default.resolve(r,n):fr__default.resolve(n);if(e==="override"&&(!Sn.existsSync(o)||!Sn.statSync(o).isDirectory()))throw new Error(`Local iOS app path "${o}" does not exist. Provide a valid directory path.`);return o}var $Ve=3;async function Hre(t){let{results:e,fixtures:r,work:n}=t,{logger:o}=r,i=e[e.length-1],a=jVe(i,n);if(a)return o.info({failedResult:i,isNotEligible:a},"Skipping failure recovery because of ineligible failure"),{type:"NOT_ELIGIBLE",message:`The failed step is not eligible for failure recovery: ${a}`,shortMessage:a};o.info({failedResult:i},"Attempting failure recovery"),n.state.failureRecoveryAttempts=(n.state.failureRecoveryAttempts??0)+1;try{return await VVe(t)}catch(s){return o.warn({err:s},"Error during failure recovery attempt, continuing..."),null}}async function VVe(t){let{fixtures:e,results:r,failedStep:n,nextSteps:o,stepTracer:i,work:a,containerParentChain:s}=t,{controller:l,logger:c}=e,u=i.parentTracer,{testMetadata:d}=t.inputs;if(!r.length)throw new Error("Attempted failure recovery with no failed results");let m=s.length>0,p=m&&a.topLevelResults?[...a.topLevelResults,...r]:r,f=m&&a.fullTestSteps?Wre(a.fullTestSteps,s):[],h=[...o,...f],g=await l.getScreenshotPngString(),y=await l.getEmulatorDomState(),{results:S}=await Mv(c,u,p,{numStepsWithScreenshots:5,addIndices:true,includeBeforeScreenshots:false,screenshotMediaType:"image/png"}),E=h.map(U=>ps(U)),v=d.description.trim(),w=d?.settings?.ai?.failureRecoveryInstructions?.trim()||void 0,{scenario:_,thoughts:L,instructions:I,reasonSummary:R}=await l.getMobileFailureRecoveryPlan({currentScreenshot:g,failedResults:S,currentScreenXml:y,nextStepsSerialized:E,testDescription:v,customInstructions:w});if(_!=="RECOVERABLE")return c.info({scenario:_,thoughts:L,instructions:I},"Failure recovery is not applicable"),{type:"NOT_ELIGIBLE",message:`Momentic's failure recovery agent determined that this failure is not eligible for recovery: ${L}`,shortMessage:R?.trim()||void 0};if(!I)throw new Error("Momentic's failure recovery agent did not provide any instructions for recovery");let k={id:randomUUID(),type:"MOBILE_AI_ACTION_STEP",text:I},D,V=a.state.failureRecoveryDisabled;V||(a.state.failureRecoveryDisabled=true),c.info("executing mobile step list");try{D=await t.executeMobileStepList({...t,fixtures:{...t.fixtures},listParams:{steps:[k,n],containerName:"AI-recovered step list",tracer:u}});}finally{V||(a.state.failureRecoveryDisabled=V);}let $=D.results[0];if($&&$.type==="MOBILE_AI_ACTION_STEP")if($g({results:D.results,onPresetAction:U=>{U.aiSuggested=true;},onModule:U=>{U.aiSuggested=true;},onAiAction:U=>{U.aiSuggested=true;}}),D.status==="SUCCESS"){let U=`The following steps were automatically executed by the failure recovery agent. Analysis: ${L}`;return $.message=U,$.failureRecoveryReason=L,Ge.increment("test_event",1,["name:failure_recovery_success","platform:native",`orgId:${t.inputs.orgId}`]),c.info({thoughts:L},"Failure recovery succeeded"),{type:"ATTEMPTED",status:"SUCCESS",result:D,message:U}}else {Ge.increment("test_event",1,["name:failure_recovery_failure","platform:native",`orgId:${t.inputs.orgId}`]);let U=`The following steps were unsuccessfully attempted by the failure recovery agent. Analysis: ${L}`;return $.message=U,$.failureRecoveryReason=L,$.status="FAILED",c.info({thoughts:L},"Failure recovery failed"),{type:"ATTEMPTED",status:"FAILED",result:D,message:U}}return null}function Wre(t,e){if(e.length===0)return [];let r=e[0],n=t.findIndex(a=>a.id===r);if(n===-1)return [];let o=t.slice(n+1);if(e.length===1)return o;let i=t[n];return i.type!=="RESOLVED_MOBILE_MODULE"?o:[...Wre(i.steps,e.slice(1)),...o]}function jVe(t,e){if(!t)return "There is no failed result";if(t.type!=="MOBILE_PRESET_STEP")return "The failed step is not a preset action";let r=t.message;return r?r.includes("AbortError:")?"The user aborted the test":HB.some(n=>r.includes(n))?"The failed step is an irrecoverable configuration error":(e.state.failureRecoveryAttempts??0)>$Ve?"Too many failure recovery attempts":"":"There is no error message available on the failed step"}async function kR({fixtures:t,step:e,inputs:r,stepTracer:n,work:o}){let i=Date.now(),{logger:a,controller:s}=t,l,c="",u,d=s.emulatorSettings?.disableXmlSnapshots??true;if(!r.interactive){if(o.lastScreenshot&&Date.now()-o.lastScreenshot.capturedAtMs<500)l=o.lastScreenshot.screenshot,c=o.lastScreenshot.snapshotId;else {c=randomUUID();try{l=Buffer.from(await s.getScreenshotBase64(),"base64");}catch(h){a.warn({err:h},"Failed to take before screenshot");}}if(!d)if(o.lastScreenXml)u=o.lastScreenXml.screenXml;else try{u=await s.getEmulatorDomState();}catch(h){a.debug({err:h},"Failed to capture before XML snapshot");}}let m=U_(e.command,a),p=cloneDeep(m?.cache??{}),f={...e,status:"SUCCESS",startTime:i,endTime:Date.now()};try{let h=await s.executeCommand({command:e.command,updateGoldenFiles:r.updateGoldenFiles});f={...e,status:h.success?"SUCCESS":"FAILED",message:h.message,startTime:i,endTime:Date.now(),data:h.output};}catch(h){s.isAborted()?f={...e,status:"CANCELLED",message:"Step cancelled.",startTime:i,endTime:Date.now()}:(a.error({err:h},"Failed to execute preset step"),f={...e,status:"FAILED",message:W(h),startTime:i,endTime:Date.now()});}finally{if(!r.interactive){l&&(f.beforeSnapshot=c,n.attachBeforeScreenshot({snapshotId:c,screenshot:l}),!d&&u&&n.attachBeforeXmlSnapshot({snapshotId:c,xml:u}));let y=randomUUID();try{let S=await s.getScreenshotBase64();f.afterSnapshot=y;let E=Buffer.from(S,"base64");n.attachAfterScreenshot({snapshotId:y,screenshot:E}),o.lastScreenshot={capturedAtMs:Date.now(),snapshotId:y,screenshot:E};}catch(S){a.warn({err:S},"Failed to take after screenshot"),o.lastScreenshot=void 0;}if(!d)try{let S=await s.getEmulatorDomState();n.attachAfterXmlSnapshot({snapshotId:y,xml:S}),o.lastScreenXml={snapshotId:y,screenXml:S};}catch(S){a.debug({err:S},"Failed to capture after XML snapshot"),o.lastScreenXml=void 0;}}let h="cache"in e.command?e.command.cache??{}:{};f.status==="FAILED"&&R3({logger:a,step:e,originalAndroidCommandCache:m});let g=diff(p,h);g&&Object.keys(g).length>0&&a.info({diffs:sm(g)},"Updated cache");}return f}async function GVe(t,e,r){let{logger:n,controller:o}=t.fixtures,{stepTracer:i}=t.conditionalParams,a=e.assertion.command;try{let s=await kR({...t,step:e.assertion,stepTracer:i}),l=a.type;switch(l){case "AI_CHECK":case "SCREEN_CHECK":case "ELEMENT_CHECK":return s.status==="SUCCESS"?{type:"passed",conditionResult:s,steps:e.steps}:(n.info(s.message,`${a.type} mobile condition ${r} resolved to false`),{type:"failed",conditionResult:s});case "JAVASCRIPT":{if(s.status!=="SUCCESS")return {type:"execution_error",conditionResult:s};let c=!!s.data;return s.status=c?"SUCCESS":"FAILED",s.message=c?`JavaScript condition evaluated to true (${JSON.stringify(s.data)})`:`JavaScript condition evaluated to false (${JSON.stringify(s.data)})`,n.info({returnValue:s.data,conditionPassed:c},`JavaScript mobile condition ${r} evaluated`),c?{type:"passed",conditionResult:s,steps:e.steps}:{type:"failed",conditionResult:s}}default:return (u=>{throw new Error(`Unsupported mobile conditional command type: ${u}`)})(l)}}catch(s){n.error({err:s},`Mobile condition ${r} failed with error`);let l=s instanceof Error?s.message:"Unknown error during mobile condition evaluation";return {type:"execution_error",conditionResult:{...e.assertion,status:"FAILED",message:l,startTime:Date.now(),endTime:Date.now()}}}finally{o.throwIfAborted();}}function qVe({step:t,fromStepId:e,conditionalChain:r,fromStepParentChain:n}){let o=n.slice(r.length+1);for(let i=0;i<t.blocks.length;i++){let a=t.blocks[i],{result:s}=ac(a.steps,e,o);if(s)return i}return -1}async function qre(t){let e=Date.now(),{logger:r}=t.fixtures,{fromStep:n}=t.inputs,{step:o,stepTracer:i,executeMobileStepList:a}=t.conditionalParams,s=i.getParentStepIdChain(),l=!!n&&d3(s,n.parentStepIdChain),c=o.elseSteps,u=true,d=[],m,p=false;if(l&&n){let S=qVe({step:o,fromStepId:n.fromStepId,conditionalChain:s,fromStepParentChain:n.parentStepIdChain});S>=0&&(c=o.blocks[S].steps,u=false,p=true,r.info(`Skipping mobile conditional assertion (execution starts from block ${S}), running ${c.length} steps`));}if(!p)for(let S=0;S<o.blocks.length;S++){r.info(`Evaluating mobile condition ${S} in conditional step`);let E=o.blocks[S],v=await GVe(t,E,S);if(d.push(v.conditionResult),m=v.conditionResult,v.type==="execution_error"){let w=v.conditionResult.status==="CANCELLED"?"CANCELLED":"FAILED",_={...o,assertionResult:v.conditionResult,steps:[],startTime:e,endTime:Date.now(),status:w,message:v.conditionResult.message};return fi({result:_,...pi(d)}),_}if(v.type==="passed"){r.info(`Mobile condition ${S} resolved to true, executing ${v.steps.length} steps`),u=false,c=v.steps;break}}if(!c){r.warn("No mobile conditions resolved to true and no else block was provided, skipping conditional step body");let S={...o,assertionResult:m,steps:[],status:"SUCCESS",startTime:e,endTime:Date.now(),data:d[d.length-1]?.data,message:d[d.length-1]?.message};return fi({result:S,...pi(d)}),S}u&&r.info("No mobile conditions resolved to true, executing the else block steps"),r.info(`Executing ${c.length} steps in selected mobile conditional block`);let f=await i.startSubSteps(),{results:h,status:g}=await a({...t,listParams:{steps:c,containerName:"mobile conditional block",tracer:f}}),y={...o,assertionResult:m,steps:h,status:g,startTime:e,endTime:Date.now()};return fi({result:y,...pi([...d,...h])}),y}async function Kre(t){let e=Date.now(),r=t.fixtures.controller;try{return await KVe(t)}catch(n){let o=r.isAborted();return {...t.moduleParams.step,steps:[],type:"MOBILE_MODULE_STEP",startTime:e,endTime:Date.now(),status:o?"CANCELLED":"FAILED",message:o?"Step cancelled.":W(n)}}}async function KVe({moduleParams:t,...e}){let r=Date.now(),{step:n,stepTracer:o,executeMobileStepList:i}=t,{controller:a,logger:s}=e.fixtures,l=await YVe({step:n,params:e});Object.keys(l).length>0&&(a.context.setInputs(l),s.info(sc({json:{inputs:l,moduleId:n.moduleId},maxJsonStringSize:1e3}),"Set mobile module inputs"));let c={};Object.entries(l).forEach(([f,h])=>{c[f]=JSON.stringify(h);});let u={...n,type:"MOBILE_MODULE_STEP",inputs:c,startTime:r,steps:[],endTime:Date.now(),status:"SUCCESS"},d=await o.startSubSteps(),{status:m,results:p}=await i({...e,listParams:{steps:n.steps,containerName:`module ('${n.name}')`,tracer:d}});return u.steps=p,u.status=m,u.endTime=Date.now(),fi({result:u,...pi(p)}),u}async function YVe({step:t,params:e}){let r={},{logger:n,controller:o}=e.fixtures;for(let i of t.parameters?.parameterNames??[]){let a=t.inputs?.[i]??t.parameters?.defaultParameters?.[i];if(!a){n.warn({k:i},"No value found for parameter in module");continue}r[i]=await Yi({orgId:e.inputs.orgId,code:a,fragment:true,logger:n,context:o.context,localTools:o.localCodeEvalTools});}return r}var Fs="finish",Lk=C__default.object({message:C__default.string(),success:C__default.boolean()}),Gy=3,Yre=`You forgot to call ${Fs}. Review the prior conversation and return only the JSON object that should have been passed as the ${Fs} input. The object must include exactly the fields: "message" (a string describing what was accomplished or why you stopped) and "success" (a boolean indicating whether the goal was achieved).`,qy=t=>{let e=tool({description:"Signal that the AI action has reached a terminal state (either success or failure).",inputSchema:Lk,toModelOutput:({output:r})=>r,execute:async({message:r,success:n})=>{let{contextManager:o,logger:i}=t;return i.info({finishMessage:r,success:n},"AI action tool called (finish)"),o.finalState={message:r,status:n?"SUCCESS":"FAILED"},{type:"content",value:[{type:"text",text:"Done"}]}}});return {name:Fs,tool:e}};var Xre=["TAP","TYPE","PRESS","PRESS_KEYBOARD","SWIPE","SCROLL_TO","AI_CHECK","AI_EXTRACT","ELEMENT_CHECK","SCREEN_CHECK","WAIT","OPEN_APP","KILL_APP","DRAG_AND_DROP","ROTATE_ORIENTATION","JAVASCRIPT"],JVe=[...Xre,"OPEN_NOTIFICATION_DRAWER"],ZVe=Xre,FR={ANDROID:JVe,IOS:ZVe};function QVe(t,e){return e!==void 0&&FR[t].includes(e)}function BR({platform:t,input:e,logger:r,tempCaches:n}){let o=By(e);if(!QVe(t,o.stepType))throw new Error(`Unsupported AI Action V3 step type: ${o.stepType}. Supported types: ${FR[t].join(", ")}`);let i=jA(o,t);if(i.type!=="MOBILE_PRESET_STEP")throw new Error(`AI Action V3 only supports preset steps, got: ${i.type}`);if(o.disableCache&&o.cacheId&&r.warn({cacheId:o.cacheId},"--disable-cache was provided with --cache-id; disable cache flag is taking precedent and the cache id will be ignored."),o.cacheId&&!o.disableCache&&Bi(t,i.command)){let a=n[o.cacheId];a?i.command.cache=a.cache:r.warn({cacheId:o.cacheId,commandType:i.command.type},"Temp mobile cache not found for AI action V3 step");}return i}function Lf(t){let{id:e,cache:r,...n}=t;return JSON.stringify(n)}function tu(t){if(t.length===0)return "Generated cached steps: (none)";let e=t.map((r,n)=>` ${n}: ${Lf(r.command)}`).join(`
|
|
5877
5877
|
`);return `Generated cached steps (${t.length}):
|
|
5878
5878
|
${e}`}async function UR({storage:t,controller:e,onEvent:r,rootStep:n,stepIndex:o,logger:i}){if(!(!t||!r))try{let a=await e.getScreenshotBase64(),s=randomUUID();await t.createOnDemandScreenshot(s,Buffer.from(a,"base64"),"image/png"),r({type:"SCREENSHOT",stepIndex:o,screenshotId:s,rootStep:n});}catch(a){i.error({err:a,stepId:n.stepId,stepIndex:o},"Failed to capture AI action V3 trajectory screenshot");}}var zR=class{platform;controller;logger;rootStep;subStepIndex=0;callbacks;storage;results=[];generatedSteps=[];tempCaches={};finalState=void 0;postconditionAttempts=0;autoGeneratedPostcondition=void 0;postcondition;postconditionStep;constructor(e){this.platform=e.platform,this.controller=e.controller,this.logger=e.logger,this.rootStep=e.rootStep,this.callbacks=e.callbacks,this.storage=e.storage,this.subStepIndex=0,this.generatedSteps=[...e.initialGeneratedSteps??[]],this.postcondition=e.postcondition,this.postconditionStep=e.postconditionStep;}recordPostconditionRejected(e){this.postconditionAttempts+=1,this.logger.info({postconditionAttempts:this.postconditionAttempts,failureMessage:e},"AI action V3 postcondition rejected the finish call");}emitPhase(e,r){this.callbacks.onAiActionEvent?.({type:"PHASE",rootStep:this.rootStep,phase:e,failureMessage:r});}recordToolCall(e){this.callbacks.onAiActionEvent?.({type:"TOOL_CALL",rootStep:this.rootStep,toolName:e});}recordAutoGeneratedPostcondition(e){this.autoGeneratedPostcondition!==e&&(this.autoGeneratedPostcondition=e,this.callbacks.onAiActionEvent?.({type:"POSTCONDITION_AUTOGENERATED",rootStep:this.rootStep,postcondition:e}));}buildPostconditionStep(e){return eg({platform:this.platform,step:{cache:void 0,precondition:void 0,postcondition:e}}).postconditionStep}async executeSteps(e,r){r&&this.emitPhase(r);let n=[];for(let o of e){let i=this.subStepIndex++;this.callbacks.onAiActionEvent?.({type:"STEP_UPDATE",rootStep:this.rootStep,stepIndex:i,step:o,status:"running"});let a=await this.callbacks.executeStep(o,i);if(this.callbacks.onAiActionEvent?.({type:"STEP_UPDATE",rootStep:this.rootStep,stepIndex:i,step:o,status:a.status==="SUCCESS"?"success":"failed",message:a.message}),await UR({storage:this.storage,controller:this.controller,onEvent:this.callbacks.onAiActionEvent,rootStep:this.rootStep,stepIndex:i,logger:this.logger}),n.push(a),a.status!=="SUCCESS")break}return this.results.push(...n),n}spliceGeneratedSteps(e,r,...n){return this.generatedSteps.splice(e,r,...n)}saveTempCacheForCommand(e,r){if(!Bi(this.platform,e)||!e.cache)return;let n=r??crypto.randomUUID();return this.tempCaches[n]=PT[this.platform]({type:e.type,cache:cloneDeep(e.cache)}),n}};var Zre="get_emulator_screenshot";function Qre(t){let e=tool({description:"Get the current device state. Returns the viewport size and a screenshot by default, and can optionally include the UI hierarchy XML.",inputSchema:C__default.object({includeEmulatorXml:C__default.boolean().optional()}),toModelOutput:({output:r})=>r,execute:async r=>{let{controller:n,contextManager:o,logger:i}=t,a={includeEmulatorXml:r.includeEmulatorXml??false};return i.info(a,"AI action V3 tool called (get_emulator_screenshot)"),o.recordToolCall(Zre),Nf({controller:n,...a})}});return {name:Zre,tool:e}}async function Nf(t){let{controller:e,includeEmulatorXml:r=false}=t,n=await e.getScreenshotBase64(),o=await e.getViewportBounds(),i=o.right-o.left,a=o.bottom-o.top,s=[{type:"text",text:`<viewportSize width="${i}" height="${a}" />`}];if(r){let l=await e.getEmulatorDomState();s.push({type:"text",text:`<emulatorXml>
|
|
@@ -6235,7 +6235,7 @@ Choose the SCROLL_TO container based on which region will actually move:
|
|
|
6235
6235
|
- If an OPEN_APP scroll fails while a nested scrollable region is visible on screen, assume the container was probably wrong and retry with CUSTOM before giving up.
|
|
6236
6236
|
</rule>
|
|
6237
6237
|
</rules>
|
|
6238
|
-
`;function Pne(t){return VR(t,Rne,Mne())}var wl={initializeAIActionConfig:Pne,stepSchema:Jr,resultSchema:Do};var nje=5e3,jk=2;async function _ne({socket:t,logger:e,orgId:r,testMetadata:n,globalOrgSettings:o,androidDriverFactory:i,mobileGeneratorFactory:a,browserGeneratorFactory:s,browserEnricherFactory:l,storageFactory:c,visualDiffGoldenStorageFactory:u,cacheStorageFactory:d,localToolsFactory:m,onRemoteEmulatorCreated:p,onRemoteEmulatorDeleted:f,billingReporterFactory:h,globalStateManager:g,getGitMetadata:y,region:S,localApkPath:E,localAvdId:v}){let w=t.id,_=t.handshake.query?.fileName,L=_?fr__default.basename(_,".test.yaml"):"",I=n.id;e=e.child({sessionId:w,testId:I,orgId:r});let R=await y(e);e=e.child({branch:R.gitBranchName});let k=await c(r),D=n.settings?.defaultEnv,V={};D&&(V=(await k.fetchEnvironment(D,e))?.variables??{});let $={...o.emulator,...n.settings?.emulator},U={...o.ai,useMemory:o.ai?.useMemory!==false,...n.settings?.ai},fe=g.getSession(w);if(fe){if(e.info("Reconnecting to existing Android session"),fe.local)return t.emit("session",fe.metadata),fe.softDeleted=false,fe.metadata;throw new Error("Restoring existing remote emulator sessions is not supported. Please reconnect to a new emulator.")}let q=await d(r,R,e),N=Hl.optional().parse(S??$.region),F=N==="local",B,te,j;if(F){if(await g.clearSoftDeletedLocalSessions(e),g.hasActiveLocalSession())throw new Error("Another local emulator session is already active. Please close the existing session before creating a new one.");let{avdId:Tn,apkFilePath:co,apkFilePathSource:Na}=Dm({overrideAvdId:v,overrideApkFilePath:E,emulatorSettings:$,defaultApkFilePath:n.settings?.defaultApkFilePath,envVariables:V}),Ml=Np({apkFilePath:co,source:Na});if(!Tn)throw new Error(`An AVD ID is required when using a local region. Provide --local-avd-id, configure a default local AVD ID on the test's settings, or set the ${Dl} key on the environment.`);j={avdId:Tn,apkFilePath:Ml};}else B=n.settings?.defaultChannel,te=n.settings?.defaultTag,j={region:N===li?void 0:N,apkToInstall:B?{channel:B,tag:te}:void 0,osVersion:$.remoteEmulatorSettings?.androidVersion??Am};e.info({platform:"ANDROID",isLocalRegion:F,resolvedRegion:N,envName:D,emulatorSettings:$,aiSettings:U},"Starting mobile session with resolved configuration");let z=Date.now(),se,be;for(let Tn=1;Tn<=jk;Tn++)try{se=await i({socket:t,logger:e,creationOpts:j});break}catch(co){if(be=co,Tn===jk)break;e.warn({err:co,attempt:Tn,maxAttempts:jk},"Mobile session bootstrap failed; retrying bootstrap");}if(!se)throw be||new Error("Mobile session bootstrap failed without an error");let{driver:rt,cleanup:gt,emulatorName:it,adbPort:or}=se,Je,J,Me,Gt,at,Se;"limbarClient"in se&&(Je=se.limbarClient,J=se.limbarToken,Me=se.limbarUrl,Gt=se.limbarRegion,at=se.limbarOsVersion,Se=se.playwrightDevice);let Zo=fr__default.join(tmpdir(),`logcat-logs-${r}-${I}-${w}.txt`);F||await p?.({emulatorName:it,platform:"ANDROID"}),e.info({adbPort:or,apkChannel:B,apkTag:te,duration:Date.now()-z,emulatorName:it},"Android emulator session initiated"),e=e.child({emulator:it});let Qo=false,Ai=false,Dr,Zt,sn,On,La=async()=>{if(Qo)return;Qo=true,Ai=true,clearInterval(sn),sn=void 0;let co=[async()=>{await Zt?.cleanup();},async()=>{await Dr?.();},async()=>{await gt(),F||await f?.({emulatorName:it,platform:"ANDROID"});},async()=>{await On?.dispose();}].map(Na=>Na().catch(Ml=>{e.warn({err:Ml},"Failed to clean up socket server resource");}));await ee(Promise.allSettled(co),{milliseconds:nje,fallback:()=>{}});};g.registerPendingSession(w,{platform:"ANDROID",cleanup:La,emulatorName:it,local:F});let ou=async()=>{Dr=await rt.executeInNativeContext(e,cS=>$C({driver:cS,onLogs:sae=>{t.emit("logcatLogs",sae);},logFilePath:Zo}),{operationName:"startLogcatListener"});let Tn=await a(r,e),co=await s(r,e),Na=await l(r,e);On=m?await m(r):void 0;let Ml=new fs({logger:e,reporter:await h(r),runType:"mobile-test-run",runId:w,testMetadata:{id:n.id,name:L},isInteractive:true,runner:"editor"}),A=new Ui({variablesFromEnvironment:V,envName:D,testName:L});if(Zt=await Zc.init({driver:rt,generator:Tn,logger:e,limbarClient:Je,playwrightDevice:Se,aiSettings:U,options:{emulator:{...$,browserSettings:o.browser}},fixtures:{storage:k,browserEnricher:Na,browserGenerator:co,localCodeEvalTools:On,testContext:A,visualDiffGoldenStorage:u()},orgId:r,adbPort:or,abortController:new AbortController}),!Zt)throw new Error("Failed to initialize Android controller");let ne=Zt;if(Ai||!t.connected)throw new Error("Socket not connected anymore, not proceeding with Android session setup");let Yt=await ne.getViewportBounds();if(Ai||!t.connected)throw new Error("Socket not connected anymore, not proceeding with Android session setup");sn=oje({socket:t,testContext:A});let Ar={sessionId:w,testId:I,orgId:r,emulatorName:it,testName:L,limbarUrl:Me,limbarToken:J,limbarRegion:Gt,limbarOsVersion:at,viewportBounds:Yt,envName:D};return g.registerSession(w,{platform:"ANDROID",controller:ne,cacheStorage:q,cleanup:La,emulatorName:it,local:F,metadata:Ar,logFilePath:Zo,helpers:Cl,usageTracker:Ml}),t.emit("session",Ar),Ar};try{return await ou()}catch(Tn){throw await g.removeSession(w,e),Tn}}function oje({socket:t,testContext:e}){return setInterval(()=>{let r=e.toEditorDisplayCopy();t.emit("emulatorState",{context:r});},3e3)}async function One({socket:t,logger:e,globalStateManager:r,authorization:n}){let o=t.id,i=r.getSession(o);i&&i.platform==="ANDROID"&&n&&i.logFilePath&&ije({testId:i.metadata.testId,sessionId:o,logFilePath:i.logFilePath,authorization:n,logger:e}),await r.removeSession(o,e);}async function ije({testId:t,sessionId:e,logFilePath:r,authorization:n,logger:o}){try{let i;try{i=await jR.stat(r);}catch{o.debug({logFilePath:r},"No logcat file found to upload");return}if(i.size===0){o.debug({logFilePath:r},"Logcat file is empty, skipping upload"),await jR.unlink(r);return}let a=new Tr(n),{uploadUrl:s}=await a.generateMobileLogcatUploadUrl({testId:t,sessionId:e}),l=await jR.readFile(r),c=await fetch(s,{headers:{"Content-Length":l.length.toString(),"Content-Type":"text/plain"},method:"PUT",body:l});if(c.status!==200)throw new Error(`Failed to upload logcat: ${c.status} ${await c.text()}`);o.info({testId:t,sessionId:e,objectUrl:gv(s)},"Logcat file uploaded successfully");}catch(i){o.warn({err:i,testId:t,sessionId:e},"Failed to upload logcat file");}finally{try{await jR.unlink(r);}catch(i){o.warn({err:i,logFilePath:r},"Failed to delete temp logcat file");}}}var aje=({socket:t,globalStateManager:e})=>async()=>{let r=e.getSession(t.id);if(!r)throw new Error("No active Mobile session found");r.controller.abort();},Dne={event:"cancel",createHandler:aje};var sje=({logger:t,globalStateManager:e,socket:r})=>async(n,o)=>{let i=e.getSession(r.id);if(!i){o({err:"No active Mobile session found"});return}let a=i.controller;a.resetAbortController();let s=Date.now();try{let l=await a.getEmulatorDomState();t.info({durationMs:Date.now()-s},"Fetched screen XML"),o({screenXml:l});}catch(l){t.error({err:l},"Error fetching screen XML from the session controller"),o({err:l.message});}},Lne={event:"fetchScreenXml",createHandler:sje};var Hk=class{parentTracer;socket;step;orgId;interactionTracer;platform;constructor({step:e,socket:r,parentTracer:n,orgId:o,platform:i}){this.socket=r,this.parentTracer=n,this.step=e,this.orgId=o,this.platform=i,this.interactionTracer=new Xi,ro.initializeRootTracerContext(this.interactionTracer);}attachBeforeScreenshot(){}attachAfterScreenshot(){}attachBeforeXmlSnapshot(){}attachAfterXmlSnapshot(){}recordStepDuration(e){let{durationMs:r,step:n}=e;if(!iE(n))return;let o=oE(n);Ge.distribution("test_mobile_step_duration",r,[`type:${o}`,`platform:${this.platform.toLowerCase()}`,"executor:editor",`orgId:${this.orgId}`]);}async finish(e){this.interactionTracer.finish();let r=this.interactionTracer.getRootSpan(),n={result:e.result,parentStepIdChain:e.parentStepIdChain,trace:RP.parse(r)};switch(n.result.status){case "SUCCESS":this.socket.emit("success",n);break;case "FAILED":this.socket.emit("failure",n);break;case "CANCELLED":this.socket.emit("cancelled",n);break}return {trace:r}}getParentStepIdChain(){return this.parentTracer?this.parentTracer?.getParentStepIdChain()??[]:[]}async startSubSteps(){return new Bf({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId,platform:this.platform})}},Bf=class{parentTracer;parentStep;socket;orgId;platform;constructor({parentStep:e,socket:r,parentTracer:n,orgId:o,platform:i}){this.parentTracer=n,this.parentStep=e,this.socket=r,this.orgId=o,this.platform=i;}getParentStepIdChain(){return this.parentStep?[...this.parentTracer?.getParentStepIdChain()??[],this.parentStep.id]:[]}async startStep(e){return this.socket.emit("started",{stepId:e.step.id,parentStepIdChain:e.parentStepIdChain,attempt:e.attempt}),new Hk({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId,platform:this.platform})}async getScreenshot(e){}},HR=class{constructor(e,r,n){this.socket=e;this.orgId=r;this.platform=n;}appendLogs(){}setActiveVideo(){}async finish(){this.socket.emit("finished");}async startBeforeStepList(){return new Bf({parentStep:null,parentTracer:null,socket:this.socket,orgId:this.orgId,platform:this.platform})}async startMainStepList(){return new Bf({parentStep:null,parentTracer:null,socket:this.socket,orgId:this.orgId,platform:this.platform})}async startAfterStepList(){return new Bf({parentStep:null,parentTracer:null,socket:this.socket,orgId:this.orgId,platform:this.platform})}};var lje=({metadata:t,logger:e,globalStateManager:r,socket:n,useSnapshotIdentityCache:o,storageFactory:i})=>async(a,s)=>{let l=r.getSession(n.id);if(!l)throw new Error("No active Mobile session found");let c=await i(t.orgId),u=e.child({testId:a.testMetadata.id});u.info({sessionId:t.sessionId,platform:l.platform,testName:t.testName,stepCount:a.steps.length,beforeStepCount:a.beforeSteps?.length??0,afterStepCount:a.afterSteps?.length??0,fromStep:a.fromStep,toStep:a.toStep,typeCommands:uje(a.steps)},"Received mobile socket execute request"),l.controller.resetAbortController();let d=l.usageTracker,m;try{m=await cje({session:l,params:a,metadata:t,testLogger:u,usageTracker:d,socket:n,useSnapshotIdentityCache:o,storage:c});}finally{await d.flush(u);}let p={results:l.helpers.resultSchema.array().parse(m.results),status:m.status};s?.(p);};async function cje({session:t,...e}){switch(t.platform){case "ANDROID":return Nne({session:t,...e});case "IOS":return Nne({session:t,...e});default:return (n=>{throw new Error(`Unsupported platform: ${n}`)})(t)}}async function Nne({session:t,params:e,metadata:r,testLogger:n,usageTracker:o,socket:i,useSnapshotIdentityCache:a,storage:s}){let l=new HR(i,r.orgId,t.platform);try{return await Ff({platform:t.platform,work:{fastForwardingToStep:!!e.fromStep,state:{failureRecoveryDisabled:!0,failureRecoveryAttempts:0}},fixtures:{controller:t.controller,logger:n,cacheStorage:t.cacheStorage,usageTracker:o,storage:s},containerName:"entire test",inputs:{steps:t.helpers.stepSchema.array().parse(e.steps),beforeSteps:e.beforeSteps?t.helpers.stepSchema.array().parse(e.beforeSteps):void 0,afterSteps:e.afterSteps?t.helpers.stepSchema.array().parse(e.afterSteps):void 0,fromStep:e.fromStep,toStep:e.toStep,orgId:r.orgId,testName:r.testName,testMetadata:e.testMetadata,interactive:!0,useSnapshotIdentityCache:a,updateGoldenFiles:e.updateGoldenFiles},envName:r.envName,tracer:l,callbacks:{step:{onAiActionEvent:c=>{i.emit("aiActionEvent",c);}}},helpers:t.helpers})}finally{await l.finish();}}var kne={event:"execute",createHandler:lje};function uje(t){return t.flatMap((e,r)=>!("command"in e)||e.command.type!=="TYPE"?[]:[{index:r,stepId:e.id,target:e.command.target?.type==="description"?e.command.target.description:e.command.target?.type,textLength:e.command.text.length,clearContent:e.command.clearContent,forceClearContent:e.command.forceClearContent,replaceStrategy:e.command.replaceStrategy,hasCache:e.command.cache!==void 0}])}var mje=({socket:t,globalStateManager:e,keepSessionAlive:r})=>{let n=debounce(r,3e4,{maxWait:6e4});return async()=>{let o=e.getSession(t.id);if(!o)throw new Error("No active Mobile session found");o.emulatorName&&(o.local||n(o.platform,o.emulatorName));}},Fne={event:"keepalive",createHandler:mje};var pje=({socket:t,globalStateManager:e,logger:r})=>async(n,o)=>{let i=e.getSession(t.id);if(!i){let s="No active session found";r.error(s),o?.({success:false,err:s});return}let a=i.controller;a.abort(),a.resetAbortController(),r.info({platform:i.platform},"Resetting emulator state");try{await a.softReset(),r.info({platform:i.platform},"Emulator reset completed"),o?.({success:!0,message:"Emulator reset successfully"});}catch(s){let l=W(s);r.error({err:s,platform:i.platform},"Failed to reset emulator"),o?.({success:false,err:`Failed to reset emulator: ${l}`});}},Bne={event:"reset",createHandler:pje};var Une=[kne,Dne,Bne,Fne,Lne];var hje=5e3,Wk=2;async function zne({socket:t,logger:e,orgId:r,testMetadata:n,globalOrgSettings:o,localIosDeviceType:i,localIosVersion:a,iosDriverFactory:s,mobileGeneratorFactory:l,browserGeneratorFactory:c,browserEnricherFactory:u,billingReporterFactory:d,storageFactory:m,visualDiffGoldenStorageFactory:p,cacheStorageFactory:f,localToolsFactory:h,onRemoteEmulatorCreated:g,onRemoteEmulatorDeleted:y,globalStateManager:S,getGitMetadata:E,region:v,localAppPath:w}){let _=t.id,L=t.handshake.query?.fileName,I=L?fr__default.basename(L,".test.yaml"):"",R=n.id,k=n.settings?.defaultChannel,D=n.settings?.defaultTag;e=e.child({sessionId:_,testId:R,orgId:r});let V=await E(e);e=e.child({branch:V.gitBranchName});let $=await m(r),U=n.settings?.defaultEnv,fe={};U&&(fe=(await $.fetchEnvironment(U,e))?.variables??{});let q={...o.emulator,...n.settings?.emulator},N={...o.ai,useMemory:o.ai?.useMemory!==false,...n.settings?.ai},F=S.getSession(_);if(F){if(e.info("Reconnecting to existing iOS session"),F.local)return t.emit("session",F.metadata),F.softDeleted=false,F.metadata;throw new Error("Restoring existing remote emulator sessions is not supported. Please reconnect to a new emulator.")}let B=await f(r,V,e),te=Hl.optional().parse(v??q.region),j=te==="local",z;if(j){if(await S.clearSoftDeletedLocalSessions(e),S.hasActiveLocalSession())throw new Error("Another local emulator session is already active. Please close the existing session before creating a new one.");let{deviceType:Dr,iosVersion:Zt,appFilePath:sn,appFilePathSource:On}=Lm({overrideDeviceType:i,overrideIosVersion:a,overrideAppFilePath:w,emulatorSettings:q,defaultAppFilePath:n.settings?.defaultAppFilePath,envVariables:fe});if(!Dr)throw new Error(`A device type is required when using a local region. Provide --local-ios-device-type, configure a default local iOS device type on the test's settings, or set the ${Ll} key on the environment.`);let La=Df({appFolderPath:sn,source:On});z={type:"local",deviceType:Dr,iosVersion:Zt,appFilePath:La};}else z={type:"remote",region:te===li?void 0:te,appToInstall:k?{channel:k,tag:D}:void 0,osVersion:Rm};e.info({platform:"IOS",isLocalRegion:j,resolvedRegion:te,envName:U,emulatorSettings:q,aiSettings:N},"Starting mobile session with resolved configuration");let se=Date.now(),be,rt;for(let Dr=1;Dr<=Wk;Dr++)try{be=await s({socket:t,logger:e,creationOpts:z});break}catch(Zt){if(rt=Zt,Dr===Wk)break;e.warn({err:Zt,attempt:Dr,maxAttempts:Wk},"Mobile session bootstrap failed; retrying bootstrap");}if(!be)throw rt||new Error("Mobile session bootstrap failed without an error");let{driver:gt,cleanup:it,emulator:or,limbarParams:Je}=be;e=e.child({emulator:or.name}),e.info({duration:Date.now()-se},"iOS emulator session initiated"),j||await g?.({emulatorName:or.name,platform:"IOS"});let J=false,Me=false,Gt,at,Se,Zo,Qo=async()=>{if(J)return;J=true,Me=true,Se&&(clearInterval(Se),Se=void 0);let Zt=[async()=>{await at?.cleanup();},async()=>{Gt?.();},async()=>{await it(),j||await y?.({emulatorName:or.name,platform:"IOS"});},async()=>{await Zo?.dispose();}].map(sn=>sn().catch(On=>{e.warn({err:On},"Failed to clean up socket server resource");}));await ee(Promise.allSettled(Zt),{milliseconds:hje,fallback:()=>{}});};S.registerPendingSession(_,{platform:"IOS",cleanup:Qo,emulatorName:or.name,local:j});let Ai=async()=>{Gt=await TR({emulator:or,onLogs:Na=>{t.emit("syslogLogs",Na);}});let Dr=await l(r,e),Zt=await c(r,e),sn=await u(r,e);Zo=h?await h(r):void 0;let On=new fs({logger:e,reporter:await d(r),runType:"mobile-test-run",runId:_,runner:"editor",testMetadata:{id:n.id,name:I},isInteractive:true}),La=new Ui({variablesFromEnvironment:fe,envName:U,testName:I});if(at=await eu.init({driver:gt,generator:Dr,logger:e,emulator:or,aiSettings:N,options:{emulator:{...q,browserSettings:o.browser}},fixtures:{storage:$,browserEnricher:sn,browserGenerator:Zt,localCodeEvalTools:Zo,testContext:La,visualDiffGoldenStorage:p()},orgId:r,abortController:new AbortController}),!at)throw new Error("Failed to initialize iOS controller");let ou=at;if(Me||!t.connected)throw new Error("Socket not connected anymore, not proceeding with iOS session setup");let Tn=await ou.getViewportBounds();if(Me||!t.connected)throw new Error("Socket not connected anymore, not proceeding with iOS session setup");Se=gje({socket:t,testContext:La});let co={sessionId:_,testId:R,orgId:r,emulatorName:or.name,testName:I,limbarUrl:Je?.webRtcUrl,limbarToken:Je?.token,limbarRegion:Je?.region,limbarOsVersion:Je?.osVersion,viewportBounds:Tn,envName:U};return S.registerSession(_,{platform:"IOS",controller:ou,cacheStorage:B,cleanup:Qo,emulatorName:or.name,local:j,metadata:co,helpers:wl,usageTracker:On}),t.emit("session",co),co};try{return await Ai()}catch(Dr){throw await S.removeSession(_,e),Dr}}function gje({socket:t,testContext:e}){return setInterval(()=>{let r=e.toEditorDisplayCopy();t.emit("emulatorState",{context:r});},3e3)}var WR=class{sessions=new Map;pendingSessions=new Map;registerPendingSession(e,r){this.pendingSessions.set(e,r);}registerSession(e,r){this.pendingSessions.delete(e),this.sessions.set(e,r);}getSession(e){return this.sessions.get(e)}getSessionForTest(e){for(let r of this.sessions.values())if(r.metadata.testId===e)return r}async clearSoftDeletedLocalSessions(e){for(let r of this.sessions.values())r.softDeleted===true&&r.local===true&&await this.removeSession(r.metadata.sessionId,e);}hasActiveLocalSession(){for(let e of [...this.sessions.values(),...this.pendingSessions.values()])if(e.local===true)return true;return false}async removeSession(e,r){let n=this.sessions.get(e)??this.pendingSessions.get(e);if(!n)return;let o=r.child({sessionId:e,emulatorName:n.emulatorName,platform:n.platform});try{await this.sessions.get(e)?.usageTracker.flush(o);}catch(i){o.error({err:i},"Error flushing usage tracker before cleanup");}try{await n.cleanup?.(),o.info("Emulator cleaned up by removeSession");}catch(i){o.error({err:i},"Error during emulator cleanup");}finally{this.sessions.delete(e),this.pendingSessions.delete(e);}}async removeAllSessions(e){let r=Array.from(new Set([...this.sessions.keys(),...this.pendingSessions.keys()]));await Promise.all(r.map(n=>this.removeSession(n,e)));}};function $ne(t){let{logger:e,baseServer:r,globalStateManager:n,settingsFactory:o,getOrgId:i}=t,a=new Server(r,{cors:{origin:"*",methods:["GET","POST"]},pingTimeout:15*60*1e3,pingInterval:15*60*1e3,maxHttpBufferSize:1e7,perMessageDeflate:true,connectionStateRecovery:{maxDisconnectionDuration:60*60*1e3,skipMiddlewares:true}}),s=async()=>{await n.removeAllSessions(e);};a.on("connection",async c=>{let u=c.id,d=e.child({sessionId:u});d.info({event:"connection",transport:c.conn.transport.name},"Mobile websocket connection initiated"),c.on("disconnect",async f=>{if(e.info({reason:f},"Disconnect received"),f.includes("namespace disconnect")){await One({socket:c,globalStateManager:n,logger:d,authorization:t.authorization});return}let h=n.getSession(u);h&&(h.softDeleted=true);});let m,p;try{let f=c.handshake.query?.testMetadata,h=Gl.parse(JSON.parse(f??"")),g=h.id,y=await i({testId:g});switch(p=await o(y,d),h.platform){case "ANDROID":m=await _ne({...t,orgId:y,socket:c,globalStateManager:n,logger:d,globalOrgSettings:p,testMetadata:h});break;case "IOS":m=await zne({...t,orgId:y,socket:c,globalStateManager:n,logger:d,globalOrgSettings:p,testMetadata:h});break;default:throw new Error("Unsupported platform")}}catch(f){d.error({err:f},"Failed to setup mobile connection"),c.emit("error",{message:f instanceof Error?f.message:JSON.stringify(f)}),c.disconnect(true);return}Une.forEach(f=>l(f,{...t,socket:c,metadata:m,globalOrgSettings:p,logger:d}));});let l=(c,u)=>{let d=c.createHandler(u),m=(...p)=>{c.event!=="keepalive"&&u.logger.debug({event:c.event},`Websocket event (${c.event})`);let f=h=>{u.logger.error({event:c.event,err:h instanceof Error?h:new Error(`${h}`)},"Unhandled exception in socket handler"),u.socket.emit("error",{message:h instanceof Error?h.message:typeof h=="string"?h:JSON.stringify(h)});};try{let h=d.apply(this,p);h&&typeof h.catch=="function"&&h.catch(f);}catch(h){f(h);}};u.socket.on(c.event,m);};return {server:a,dispose:s}}async function vje(t,e){switch(t){case "ANDROID":return {uploadPath:e,cleanup:async()=>{}};case "IOS":{let r=await Sn.promises.mkdtemp(fr__default.join(el.tmpdir(),"momentic-mobile-asset-")),n=fr__default.join(r,"app.zip");return await Cje(e,n),{uploadPath:n,cleanup:()=>Sn.promises.rm(r,{recursive:true,force:true})}}}}function Cje(t,e){return new Promise((r,n)=>{let o=yje("zip",{zlib:{level:9}}),i=Sn.createWriteStream(e);i.on("close",()=>r()),i.on("error",n),o.on("error",n),o.on("warning",a=>{a.code!=="ENOENT"&&n(a);}),o.pipe(i),o.directory(t,false,a=>fr__default.basename(a.name)===".DS_Store"?false:(a.mode=a.stats?.isDirectory()?493:420,a)),o.finalize().catch(n);})}async function wje(t){let e=Sje.createHash("md5");await new Promise((n,o)=>{Sn.createReadStream(t).on("data",i=>e.update(i)).on("end",()=>n()).on("error",o);});let r=e.digest();return {md5Base64:r.toString("base64"),md5Hex:r.toString("hex")}}async function GR({tag:t,channel:e,filePath:r,apiClient:n,logger:o,platform:i}){o.info({channel:e,tag:t,platform:i,filePath:r},"starting asset upload");let a=Date.now(),{uploadPath:s,cleanup:l}=await vje(i,r);try{let{md5Base64:c,md5Hex:u}=await wje(s),{size:d}=await Sn.promises.stat(s),m=await n.generateAssetUploadUrl({channel:e,tag:t??"latest",md5:c,platform:i});if(m.md5&&(m.md5===c||m.md5===u))return o.info({channel:e,tag:t,platform:i,filePath:r,size:d,durationMs:Date.now()-a,skipped:!0},"skipped asset upload (md5 match)"),{skipped:!0};if(!m.uploadUrl)throw new M("InternalPlatformError",`No upload URL was given for asset ${r}`);try{let p=await fetch$1(m.uploadUrl,{headers:{"Content-Length":d.toString(),"Content-Type":"application/octet-stream"},method:"PUT",body:Sn.createReadStream(s),duplex:"half"});if(p.status!==200)throw new M("InternalPlatformError",`Got error response from emulator platform: ${p.status} ${await p.text()}`);return o.info({channel:e,tag:t,platform:i,filePath:r,size:d,durationMs:Date.now()-a},"finished asset upload"),{skipped:!1}}catch(p){try{await n.deleteAsset(e,t??"latest",i);}catch(f){o.warn({err:f,tag:t,channel:e},"Failed to clean up asset after failed upload");}throw p}}finally{await l();}}async function qR({channel:t,tag:e,platform:r,apiClient:n,logger:o}){let i=e??"latest";o.info({channel:t,tag:i,platform:r},`Deleting asset ${t}:${i} (${r})...`),await n.deleteAsset(t,i,r),o.info({channel:t,tag:i,platform:r},`Asset ${t}:${i} (${r}) deleted successfully!`);}var Aje=z.object({emulatorName:z.string(),platform:z.enum(Ze)});z.object({runId:z.string(),emulators:z.array(Aje)});var Vne;async function KR(t){await Vne?.registerEmulator(t);}async function YR(t){await Vne?.unregisterEmulator(t);}var $f=new WR;var qk="1.0.1",Tt=qm({app:"mobile-desktop-server",hostname:hostname(),disableConsoleLogs:true}).child({cliVersion:qk});(async()=>{try{let t=await ib(Tt);t.gitBranchName&&Tt.addBinding("branch",t.gitBranchName);}catch{}})();var XR=Router();XR.get("/",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({message:"API client not initialized"});return}let n=await r.getMobileAssets();e.status(200).json(n);}));XR.post("/upload-url",je(async(t,e)=>{let r;try{r=P$.parse(t.body);}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}let n=Wt();if(!n){e.status(500).json({error:"API client not initialized"});return}let o=fr__default.resolve(r.filePath);if(!existsSync(o)){e.status(400).json({error:`File not found: ${o}`});return}let i=/\.apk$/i.test(o),a=o.endsWith(".app")&&statSync(o).isDirectory();if(!i&&!a){e.status(400).json({error:"Unsupported file type. Only .apk files and .app directories are supported."});return}await GR({tag:r.tag,channel:r.channel,filePath:o,apiClient:n,logger:Tt,platform:i?"ANDROID":"IOS"}),e.sendStatus(204);}));XR.delete("/:channel/:tag/:platform",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({error:"API client not initialized"});return}let{channel:n,tag:o,platform:i}=t.params;if(!n||!o||!i){e.status(400).json({error:"Missing channel, tag, or platform."});return}let a=Ph.safeParse(i.toUpperCase());if(!a.success){e.status(400).json({error:`Invalid platform "${i}". Expected "android" or "ios".`});return}let s=a.data;await qR({channel:n,tag:o,platform:s,apiClient:r,logger:Tt}),e.sendStatus(204);}));var jne=XR;var Vf=Router();async function JR(t){return (await qK(t,Tt)).map(n=>{let o=t.mobileModules[n.moduleId];if(!o){P.warn(`Found a dangling mobile module with ID ${n.moduleId} that could not be found on disk.`);return}return {...o,content:n}}).filter(n=>n!==void 0)}Vf.get("/",je(async(t,e)=>{let r=ht(),n=await vt(r),o=await JR(n);e.status(200).json(o);}));Vf.get("/tests-join",je(async(t,e)=>{let r=ht(),n=await vt(r),o=await JR(n),i={};for(let s of o)i[s.id]={...s,tests:[]};let a=await Promise.all(Object.values(n.mobileTests).map(async s=>({id:s.id,name:s.name,relativePath:s.relativePath,test:await dr(s.fullFilePath,Tt,n)})));for(let{id:s,name:l,relativePath:c,test:u}of a){let d=new Set;Bo({steps:u.steps,onPreset:()=>false,onModule:m=>(d.add(m.moduleId),false)});for(let m of d){let p=i[m];p&&p.tests.push({id:s,name:l,relativePath:c});}}e.status(200).json(i);}));Vf.get("/:moduleId",je(async(t,e)=>{if(!t.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let r=await vt(ht()),n=r.mobileModules[t.params.moduleId];if(!n){e.status(404).json({error:"Mobile module not found."});return}try{let o=await nd(n,r,P);e.json(o);}catch(o){e.status(400).json({err:o});}}));Vf.patch("/:moduleId/metadata",je(async(t,e)=>{if(!t.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let r;try{r=_$.parse(t.body);}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=ht(),o=await vt(n);GK({moduleId:t.params.moduleId,patch:r,momenticFiles:o,logger:P,project:n}),e.status(201).json({message:"ok"});}));Vf.post("/",je(async(t,e)=>{let r;try{r=D$.parse(t.body);}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{_i(r.name);}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=ht(),o=await vt(n),i=o.mobileModules;if(Object.values(i).find(s=>s.name===r.name)){e.status(400).json({error:`A mobile module with the name "${r.name}" already exists. Please choose a different name.`});return}let a=fr__default.join(n.rootDir,r.folderPath??fr__default.dirname(r.testFilePath));if(!Sn.existsSync(a)||!Sn.statSync(a).isDirectory()){e.status(400).json({error:`The folder configured for mobile module creation does not exist: ${a}`});return}switch(r.platform){case "ANDROID":{let s=await sb({...r,folder:a,project:n,momenticFiles:o});e.status(201).json(s);return}case "IOS":{let s=await sb({...r,folder:a,project:n,momenticFiles:o});e.status(201).json(s);return}}}));var Gne=Vf;var Kk=Router();Kk.get("/",je(async(t,e)=>{let r=ht(),n=await vt(r),o=await JR(n),i=new Set;n?.mobileTests&&Object.values(n.mobileTests).forEach(c=>{c.labels?.forEach(u=>i.add(u));});let a=Array.from(i).sort(),s=Object.values(n.mobileTests),l={labels:a,modules:o,tests:s};e.status(200).json(l);}));Kk.get("/folders",je(async(t,e)=>{let r=ht(),n=await _K(r);e.status(200).json(n);}));var qne=Kk;var ZR=Router();ZR.get("/",je((t,e)=>{let r=eC(ht(),Tt);e.status(200).json(r);}));ZR.get("/names",je((t,e)=>{let n=ht().config.environments?.map(o=>o.name)??[];e.status(200).json(n);}));ZR.post("/",je((t,e)=>{let r;try{r=I$.parse(t.body);}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{_i(r.name);}catch(s){e.status(400).json({error:`Invalid environment name: ${s}`});return}let n=ht();if(n.config.environments?.find(s=>s.name===r.name)){e.status(400).json({error:`An environment with the name "${r.name}" already exists. Please choose a different name.`});return}let i={...n.config,environments:[...n.config.environments??[],{name:r.name}]};n.config=i,rd(i,n.configFilePath);let a=ed(r.name,n,Tt);e.status(201).json(a);}));var Kne=ZR;var Yne=Router();Yne.get("/",je((t,e)=>{let r={userId:_d(),orgId:an(),email:dR(),name:Fte(),pylonEmailHash:Bte(),cliVersion:qk};e.status(200).json(r);}));var Xne=Yne;var Jne=Router();Jne.get("/",je(async(t,e)=>{let r=t.query.sessionId;if(!r){e.status(400).json({packages:[]});return}let n=$f.getSession(r);if(!n?.controller){e.status(200).json({packages:[]});return}try{let o=n.controller,{installedApps:i}=await o.getInstalledApps();e.status(200).json({packages:i});}catch(o){Tt.error({err:o},"Error fetching installed packages from the session controller"),e.status(200).json({packages:[]});}}));var Zne=Jne;var Qne=Router();Qne.get("/",je(async(t,e)=>{let r=await Hy(Tt);e.status(200).json(r);}));var eoe=Qne;var QR=Router(),toe=async({platform:t,steps:e,cacheStorage:r,stepId:n,parentStepIdChain:o,testId:i,environment:a})=>{let{result:s,parentChain:l}=ac(e,n,o);if(!s)return;let c=l.filter(u=>u.type==="RESOLVED_MOBILE_MODULE").map(u=>u.id);return await r.getCacheKeyForStep({platform:t,logger:Tt,testId:i,environment:a,parentStepIdChain:c,step:s})};QR.patch("/",je(async(t,e)=>{let r=ht(),n=an(),o=Wt(),i=r.config?.advanced?.isolateCachesByEnvironment;if(!o){e.status(500).json({error:"API client not initialized"});return}let a;try{a=k$.parse(t.body);}catch(u){e.status(400).json({error:`Invalid request body: ${u}`});return}let s=await Sr(Tt,o,r),l=rn({logger:Tt,orgId:n,client:o,gitMetadata:s,regenerateCache:false,noCache:false,alwaysSaveCache:false,isolateCachesByEnvironment:i}),c=await toe({cacheStorage:l,platform:a.platform,steps:a.steps,stepId:a.stepId,parentStepIdChain:a.parentStepIdChain,testId:a.testId,environment:i?a.environment:void 0});if(!c){e.status(400).json({error:"Cache-supporting step not found"});return}await o.updateMobileStepCaches({platform:a.platform,body:{entries:[{key:c,organizationId:n,value:a.value,testId:a.testId,environment:i?a.environment:void 0}]},headers:_u(s)}),e.status(204).send();}));QR.delete("/entry",je(async(t,e)=>{let r=ht(),n=an(),o=Wt(),i=r.config?.advanced?.isolateCachesByEnvironment;if(!o){e.status(500).json({error:"API client not initialized"});return}let a;try{a=B$.parse(t.body);}catch(u){e.status(400).json({error:`Invalid request body: ${u}`});return}let s=await Sr(Tt,o,r),l=rn({logger:Tt,orgId:n,client:o,gitMetadata:s,regenerateCache:false,noCache:false,alwaysSaveCache:false,isolateCachesByEnvironment:i}),c=await toe({cacheStorage:l,platform:a.platform,steps:a.steps,stepId:a.stepId,parentStepIdChain:a.parentStepIdChain,testId:a.testId,environment:i?a.environment:void 0});if(!c){e.status(400).json({error:"Cache-supporting step not found"});return}await o.deleteMobileStepCacheEntry({platform:a.platform,body:{testId:a.testId,key:c,environment:i?a.environment:void 0},headers:_u(s)}),e.status(204).send();}));QR.post("/traces",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({error:"API client not initialized"});return}let n;try{n=U$.parse(t.body);}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let o=await r.getMobileStepCacheMemoryTraces(n.platform,n);e.status(200).json(o);}));var roe=QR;PMe("phc_WRWd8LYIv6rolgDsyCdrPpxtZhsu6qXAkEwPicl44bI","POSTHOG_WEB_WRITE_KEY is not set");var{captureEvent:Ci,setAnalyticsIdentity:ex,shutdownAnalytics:tx}=sE({writeKey:"phc_WRWd8LYIv6rolgDsyCdrPpxtZhsu6qXAkEwPicl44bI",host:"https://p.momentic.ai",platform:"local_mobile_app",identity:"stashed",flushImmediately:true});var Bd=Router();Bd.patch("/:testPath",je(async(t,e)=>{let r=t.params.testPath;if(!r){e.status(400).json({error:"Missing testPath in path"});return}let n;try{n=x$.parse(t.body);}catch(l){e.status(400).json({error:`Invalid request body: ${l}`});return}if(n.steps===void 0&&n.beforeSteps===void 0&&n.afterSteps===void 0&&n.settings===void 0&&n.labels===void 0){e.status(400).json({error:"At least one of steps, beforeSteps, afterSteps, settings, or labels is required"});return}let o=ht(),i=r.endsWith(".test.yaml")?r:`${r}.test.yaml`,a=await vt(o);await cl({platform:n.platform,filePath:i,steps:n.steps,beforeSteps:n.beforeSteps,afterSteps:n.afterSteps,settings:n.settings,labels:n.labels,folder:o.rootDir,project:o,momenticFiles:a,schemaVersion:dn});let s={message:"ok"};e.status(200).json(s);}));Bd.post("/",je(async(t,e)=>{let r;try{r=A$.parse(t.body);}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}let{name:n,description:o,settings:i,pathSegments:a,platform:s}=r;if(!n||typeof n!="string"){e.status(400).json({error:"Missing or invalid 'name' in body"});return}try{_i(n);}catch(g){e.status(400).json({error:W(g)});return}let l=ht(),c=await vt(l),u=fr__default.join(l.rootDir,...a??[]),{fullPath:d,testId:m}=rC({name:n,description:o,settings:i,folder:u,platform:s,project:l,momenticFiles:c});Ci({type:"test_editor:test_create",test_platform:Fi(s)});let p=fr__default.basename(d),f=fr__default.relative(l.rootDir,d),h={id:m,fileName:p,fullPath:d,relativeFilePath:f};e.status(201).json(h);}));Bd.get("/:fileName",je(async(t,e)=>{let r=Wt(),n=an(),o=t.params.fileName;if(!o){e.status(400).json({error:"Missing fileName in path"});return}if(!r){e.status(500).json({error:"API client not initialized"});return}let i=o.endsWith(".test.yaml")?o:`${o}.test.yaml`,a=fr__default.basename(i).replace(".test.yaml",""),s=ht(),l=fr__default.isAbsolute(i)?i:fr__default.join(s.rootDir,i);if(!Sn.existsSync(l)){e.status(404).json({error:"Test not found."});return}let c=await vt(s),u=await dr(l,Tt,c),d=$f.getSessionForTest(u.id),m=d?Tt.child({sessionId:d.metadata.sessionId,testId:u.id,testName:d.metadata.testName}):Tt,p=await Sr(m,r,s,{includeHostingUsername:false});await rn({logger:m,orgId:n,client:r,gitMetadata:p,regenerateCache:false,noCache:false,alwaysSaveCache:false,isolateCachesByEnvironment:s.config?.advanced?.isolateCachesByEnvironment}).resolveEntries({logger:m,platform:u.platform,testId:u.id,environment:u.settings?.defaultEnv,stepLists:{steps:u.steps,...u.beforeSteps&&{beforeSteps:u.beforeSteps},...u.afterSteps&&{afterSteps:u.afterSteps}},useSnapshotIdentityCache:s.config.fileFormat==="v2"});let h={...u,name:a,absoluteFilePath:l};e.status(200).json(h);}));Bd.patch("/:testPath/metadata",je(async(t,e)=>{let r=t.params.testPath;if(!r){e.status(400).json({error:"Missing testPath in path"});return}let n;try{n=M$.parse(t.body);}catch(l){e.status(400).json({error:`Invalid request body: ${l}`});return}let o=ht(),i=r.endsWith(".test.yaml")?r:`${r}.test.yaml`,s={message:"ok",newRelativeTestPath:KK(i,n,o).newRelativeTestPath};e.status(200).json(s);}));Bd.delete("/:testPath",je((t,e)=>{let r=t.params.testPath;if(!r){e.status(400).json({error:"Missing testPath in path"});return}let n=ht(),o=r.endsWith(".test.yaml")?r:`${r}.test.yaml`,i=fr__default.join(n.rootDir,o);if(!Sn.existsSync(i)){e.status(404).json({error:"Test not found."});return}Sn.unlinkSync(i),e.status(200).json({message:"ok"});}));Bd.post("/:testPath/duplicate",je(async(t,e)=>{let{testPath:r}=t.params;if(!r){e.status(400).json({error:"Missing testPath in url path."});return}let n;try{n=L$.parse(t.body);}catch(h){e.status(400).json({error:`Invalid request body: ${h}`});return}try{_i(n.name);}catch(h){e.status(400).json({error:W(h)});return}let o=ht(),i=fr__default.join(o.rootDir,r);if(!Sn.existsSync(i)){e.status(404).json({error:"Test not found."});return}let a=await vt(o),s;try{s=await dr(i,Tt,a);}catch(h){e.status(400).json({error:W(h)});return}let l=bp({projectConfig:o.config,momenticFiles:a,entityType:"mobile-test"}),{stepsToSave:c}=await An({platform:s.platform,stepLists:{steps:s.steps,beforeSteps:s.beforeSteps,afterSteps:s.afterSteps},createNewCacheIds:true}),u=hn({fileType:Ce.MOBILE_TEST,id:l,schemaVersion:dn,description:s.description,platform:s.platform,settings:s.settings,labels:s.labels,...c});LT.parse(u);let d=fr__default.dirname(i),m=fr__default.join(d,`${n.name}.test.yaml`);if(Sn.existsSync(m)){e.status(409).send("A test with this name already exists");return}let p=_g.stringify(u);Sn.writeFileSync(m,p,"utf-8");let f={relativeFilePath:fr__default.relative(o.rootDir,m)};e.status(201).json(f);}));var noe=Bd;var ooe=Router();ooe.get("/:id",je(async(t,e)=>{let{id:r}=t.params;if(!r){e.status(400).json({error:"Missing ID"});return}let n=Wt();if(!n){e.status(500).json({error:"API client not initialized"});return}try{let{data:o,contentType:i}=await n.fetchOnDemandScreenshot(r);e.setHeader("Content-Type",i),e.status(200).send(o);}catch(o){Tt.error({err:o,screenshotId:r},"Failed to proxy on-demand screenshot"),e.status(404).json({error:"Screenshot not found"});}}));var ioe=ooe;var aoe=Router();aoe.get("/",je((t,e)=>{let r=ht(),n={ai:r.config.ai,displayRoot:r.config.displayRoot};e.status(200).json(n);}));var soe=aoe;var loe=Router();loe.post("/traces",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({error:"API client not initialized"});return}let n;try{n=z$.parse(t.body);}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let o=await r.getWebStepCacheMemoryTraces(n);e.status(200).json(o);}));var coe=loe;var Hf=class extends vp{constructor(r,n){super(r,n);this.client=r;this.orgId=n;}async fetchEnvironment(r,n){let o=ht();return ed(r,o,P)}};var Gje=promisify$1(execFile$1);async function uoe({managedState:t,project:e,testEntity:r,resolvedTest:n,envName:o}){let{logger:i,sessionId:a}=t,s=Ute(),l=an(),c=Vy(),u=new Tr({apiKey:s,baseUrl:c,logger:i}),d=new Hf(u,l),m=o??n.settings?.defaultEnv,p={};m&&(p=(await d.fetchEnvironment(m,i))?.variables??{});let f={...e.config.emulator,...n.settings?.emulator},h=new Ts({baseUrl:c,apiKey:s,logger:i,mode:"interactive",runner:"mcp"}),g=new dl(e.config.ai?.agentConfig,{baseUrl:c,apiKey:s,logger:i,mode:"interactive",runner:"mcp"}),y=new Ec({baseUrl:c,apiKey:s,logger:i,mode:"interactive"},g),S=new vc({httpClient:u,fakerSeed:e.config.advanced?.fakerConstantSeed?Nm:void 0}),E=new Ui({variablesFromEnvironment:p,envName:m,testName:r.name}),v=new fs({logger:i,reporter:new Tc(u),runType:"mobile-test-run",runId:a,testMetadata:r,isInteractive:true,runner:"mcp"});return {logger:i,sessionId:a,orgId:l,apiClient:u,resolvedEnvName:m,variablesFromEnvironment:p,emulatorSettings:f,mobileGenerator:h,fixtures:{storage:d,browserEnricher:y,browserGenerator:g,localCodeEvalTools:S,testContext:E,visualDiffGoldenStorage:new vs({baseDir:e.rootDir,updateGoldenFiles:false})},aiSettings:{useMemory:true,...e.config.ai,...n.settings?.ai},usageTracker:v}}function qje(t){return {steps:t.steps,beforeSteps:t.beforeSteps,afterSteps:t.afterSteps}}async function rx({platform:t,project:e,logger:r,orgId:n,apiClient:o,resolvedTest:i,envName:a}){let s=qje(i);if(e.config.fileFormat!=="v2")return s;let l=await Sr(r,o,e),{alwaysSaveCache:c,noCache:u}=Ns();return await rn({logger:r,orgId:n,client:o,gitMetadata:l,regenerateCache:false,alwaysSaveCache:c,noCache:u,isolateCachesByEnvironment:e.config?.advanced?.isolateCachesByEnvironment}).resolveEntries({logger:r,platform:t,testId:i.id,environment:a,stepLists:s,useSnapshotIdentityCache:true}),s}async function doe({provider:t,platform:e,emulatorName:r,cleanupDriver:n}){let o=t==="remote";return o&&await KR({emulatorName:r,platform:e}),async()=>{await n(),o&&await YR({emulatorName:r,platform:e});}}async function moe({managedState:t,project:e,testEntity:r,resolvedTest:n,provider:o,envName:i,localAvdId:a,localApkPath:s}){let{logger:l,sessionId:c,orgId:u,apiClient:d,resolvedEnvName:m,variablesFromEnvironment:p,emulatorSettings:f,mobileGenerator:h,fixtures:g,aiSettings:y,usageTracker:S}=await uoe({managedState:t,project:e,testEntity:r,resolvedTest:n,envName:i}),E=n.settings?.defaultChannel,v=n.settings?.defaultTag,w=await rx({platform:"ANDROID",project:e,logger:l,orgId:u,apiClient:d,resolvedTest:n,envName:m}),_=await Kje({provider:o,projectRoot:e.rootDir,emulatorSettings:f,resolvedTest:n,localAvdId:a,localApkPath:s,variablesFromEnvironment:p});l.info({platform:"ANDROID",provider:o,envName:m,emulatorSettings:f,aiSettings:y},"Starting mobile session with resolved configuration");let L=o==="local"?"local":"region"in _?_.region:void 0,I=await Lp({apiClient:d,logger:l,creationOpts:o==="remote"?{..._,apkToInstall:E?{channel:E,tag:v}:void 0}:_,orgId:u,sessionId:c,callbacks:{onStatusUpdate:D=>{l.info({status:D},"Android session status update");}}}),R=await doe({provider:o,emulatorName:I.emulatorName,platform:"ANDROID",cleanupDriver:async()=>{await I.cleanup();}}),k;try{let D="limbarClient"in I?{limbarClient:I.limbarClient,limbarToken:I.limbarToken,limbarUrl:I.limbarUrl,limbarRegion:I.limbarRegion,playwrightDevice:I.playwrightDevice}:void 0;k=await Zc.init({driver:I.driver,generator:h,logger:l,limbarClient:D?.limbarClient,playwrightDevice:D?.playwrightDevice,aiSettings:y,options:{emulator:{...f,region:L,browserSettings:e.config.browser}},fixtures:g,orgId:u,adbPort:I.adbPort,abortController:new AbortController});let V=await k.getViewportBounds(),$=k;return {...t,platform:"ANDROID",provider:o,controller:$,cleanup:[async()=>{await Promise.allSettled([$.cleanup(),R(),g.localCodeEvalTools.dispose()]);}],testName:r.name,relativeTestPath:r.relativePath,testFileAbsolutePath:fr__default.join(e.rootDir,r.relativePath),envName:m,orgId:u,emulatorName:I.emulatorName,viewportBounds:V,adbPort:I.adbPort,tempCaches:{},limbarUrl:D?.limbarUrl,limbarToken:D?.limbarToken,limbarRegion:D?.limbarRegion,usageTracker:S,mutableStepState:{platform:"ANDROID",testId:n.id,stepLists:w}}}catch(D){let V=k?[k.cleanup(),R()]:[R()];throw await Promise.allSettled(V),D}}async function poe({managedState:t,project:e,testEntity:r,resolvedTest:n,provider:o,envName:i,localDeviceId:a,localIosVersion:s,localAppPath:l}){let{logger:c,sessionId:u,orgId:d,apiClient:m,resolvedEnvName:p,variablesFromEnvironment:f,emulatorSettings:h,mobileGenerator:g,fixtures:y,aiSettings:S,usageTracker:E}=await uoe({managedState:t,project:e,testEntity:r,resolvedTest:n,envName:i}),v=n.settings?.defaultChannel,w=n.settings?.defaultTag,_=await rx({platform:"IOS",project:e,logger:c,orgId:d,apiClient:m,resolvedTest:n,envName:p}),L=Yje({provider:o,projectRoot:e.rootDir,emulatorSettings:h,resolvedTest:n,appChannel:v,appTag:w,localDeviceId:a,localIosVersion:s,localAppPath:l,variablesFromEnvironment:f});c.info({platform:"IOS",provider:o,envName:p,emulatorSettings:h,aiSettings:S},"Starting mobile session with resolved configuration");let I=o==="local"?"local":L.type==="remote"?L.region:void 0,R=await Af({apiClient:m,logger:c,creationOpts:L,orgId:d,sessionId:u,callbacks:{onStatusUpdate:V=>{c.info({status:V},"iOS session status update");}}}),k=await doe({provider:o,emulatorName:R.emulator.name,platform:"IOS",cleanupDriver:async()=>{await R.cleanup();}}),D;try{D=await eu.init({driver:R.driver,generator:g,logger:c,emulator:R.emulator,aiSettings:S,options:{emulator:{...h,region:I,browserSettings:e.config.browser}},fixtures:y,orgId:d,abortController:new AbortController});let V=await D.getViewportBounds(),$=D;return {...t,platform:"IOS",provider:o,controller:$,cleanup:[async()=>{await Promise.allSettled([$.cleanup(),k(),y.localCodeEvalTools.dispose()]);}],testName:r.name,relativeTestPath:r.relativePath,testFileAbsolutePath:fr__default.join(e.rootDir,r.relativePath),envName:p,orgId:d,emulatorName:R.emulator.name,viewportBounds:V,tempCaches:{},limbarUrl:R.limbarParams?.webRtcUrl,limbarToken:R.limbarParams?.token,limbarRegion:R.limbarParams?.region,usageTracker:E,mutableStepState:{platform:"IOS",testId:n.id,stepLists:_}}}catch(V){let $=D?[D.cleanup(),k()]:[k()];throw await Promise.allSettled($),V}}async function Kje({provider:t,projectRoot:e,emulatorSettings:r,resolvedTest:n,localAvdId:o,localApkPath:i,variablesFromEnvironment:a}){if(t==="remote")return {region:r?.region==="local"?void 0:r?.region,osVersion:r?.remoteEmulatorSettings?.androidVersion??Am};let s=await Xk(),{avdId:l,apkFilePath:c,apkFilePathSource:u}=Dm({overrideAvdId:o,overrideApkFilePath:i,emulatorSettings:r,defaultApkFilePath:n.settings?.defaultApkFilePath,envVariables:a});if(!l){let d=s.availableAvdIds.length>0?` Known Available AVDs on this machine: ${s.availableAvdIds.join(", ")}.`:"",m=s.avdDiscoveryError?` Failed to list local AVDs: ${s.avdDiscoveryError}.`:"";throw new Error(`AVD ID is required when using a local emulator. Set it on the test (Options -> Emulator -> Local AVD ID), set ${Dl} on the environment, or pass localDeviceId directly.${d}${m}`)}if(s.availableAvdIds.length>0&&!s.availableAvdIds.includes(l))throw new Error(`AVD '${l}' is not available on this machine. Available AVDs: ${s.availableAvdIds.join(", ")}.`);return {avdId:l,apkFilePath:Np({apkFilePath:c,source:u,overrideBaseDir:e})}}function Yje({provider:t,projectRoot:e,emulatorSettings:r,resolvedTest:n,appChannel:o,appTag:i,localDeviceId:a,localIosVersion:s,localAppPath:l,variablesFromEnvironment:c}){if(t==="remote")return {type:"remote",region:r?.region==="local"?void 0:r?.region,appToInstall:o?{channel:o,tag:i}:void 0,osVersion:Rm};let{deviceType:u,iosVersion:d,appFilePath:m,appFilePathSource:p}=Lm({overrideDeviceType:a,overrideIosVersion:s,overrideAppFilePath:l,emulatorSettings:r,defaultAppFilePath:n.settings?.defaultAppFilePath,envVariables:c});if(!u)throw new Error(`A device type is required when using a local region. Pass localDeviceId, configure a default local iOS device type on the test's settings, or set the ${Ll} key on the environment.`);return {type:"local",deviceType:u,iosVersion:d,appFilePath:Df({appFolderPath:m,source:p,overrideBaseDir:e})}}async function Xk(){try{let{stdout:t}=await Gje(Xje(),["-list-avds"],{encoding:"utf8",timeout:5e3});return {availableAvdIds:t.split(/\r?\n/).map(r=>r.trim()).filter(Boolean)}}catch(t){return {availableAvdIds:[],avdDiscoveryError:W(t)}}}function Xje(){let t=process.platform==="win32"?"emulator.exe":"emulator";return process.env.ANDROID_HOME?fr__default.join(process.env.ANDROID_HOME,"emulator",t):t}var foe=5,Jk=class extends $A{isStartingSession=false;constructor(){super({sessionTypeLabel:"mobile MCP session"});}async kill(e,r){try{let n;for(let i of e.cleanup)try{await i();}catch(a){n??=a;}if(n)throw n;await e.usageTracker.flush(e.logger);let o=Lee(e);return await ete({apiClient:Wt(),logger:e.logger,orgId:e.orgId,testId:e.testId,sessionId:e.sessionId,reason:r,report:o}),e.logger.info({sessionId:e.sessionId,reason:r,emulatorName:e.emulatorName},"MCP session cleaned up"),{killed:!0,sessionId:e.sessionId,reason:r,report:o}}catch(n){return e.logger.error({err:n,sessionId:e.sessionId,reason:r},"Failed to clean up mobile MCP session"),{killed:false,sessionId:e.sessionId,reason:r}}}touchSession(e){let r=super.touchSession(e);return r?.provider==="remote"&&Wt()?.extendEmulatorTtl(r.platform,r.emulatorName).catch(()=>{}),r}async createSession({logger:e,testId:r,idleTimeoutMs:n,provider:o,envName:i,localDeviceId:a,localIosVersion:s,localAppPath:l,project:c}){let u=this.listSessionIds();if(this.isStartingSession||u.length>0)throw new Error(JSON.stringify({message:"Another mobile MCP session is already active or starting. Please terminate the existing session before creating a new one.",activeSessionIds:u},null,2));this.isStartingSession=true;let d;try{let{entity:m,momenticFiles:p}=await Es(c,{id:r},"mobileTests"),f=await dr(m.fullFilePath,e,p),y=(f.settings?.emulator?.region??c.config.emulator?.region)==="local"?"local":"remote",S=o??y,E,{platform:v}=f,w=e.child({testId:f.id});switch(v){case "ANDROID":d=this.buildManagedSessionState({logger:w,idleTimeoutMs:n,testId:m.id}),E=await moe({managedState:d,project:c,testEntity:m,resolvedTest:f,provider:S,envName:i,localAvdId:a,localApkPath:l});break;case "IOS":d=this.buildManagedSessionState({logger:w,idleTimeoutMs:n,testId:m.id}),E=await poe({managedState:d,project:c,testEntity:m,resolvedTest:f,provider:S,envName:i,localDeviceId:a,localIosVersion:s,localAppPath:l});break;default:return _t(v)}return w.info({sessionId:E.sessionId,testId:f.id},"Started MCP session for test"),E}catch(m){throw d&&clearTimeout(d.timeoutHandle),m}finally{this.isStartingSession=false;}}},so=new Jk,ru=({response:t,sessionId:e,toolName:r})=>{let n=so.touchSession(e);if(n)return t.addCleanupCallback(()=>{Qee({session:n,toolCallId:t.toolCallId});}),Zee({session:n,toolCallId:t.toolCallId,toolName:r}),n;t.addError(JSON.stringify({message:`No active session found for id '${e}'.`,availableSessionIds:so.listSessionIds()},null,2));};var Zje=4e4,Qje=1e4,Qk,goe=({staticDir:t})=>{Qk=t;},nx=class t{url;server;constructor({url:e,server:r}){this.url=e,this.server=r;}static async init({logger:e,testId:r,testName:n,sessionId:o,platform:i,limbarUrl:a,limbarToken:s,limbarRegion:l,tabLabel:c}){let u=await nHe({logger:e,assets:eHe()}),d=new URL(`http://localhost:${u.port}/`);return d.searchParams.set("testId",r),n&&d.searchParams.set("testName",n),d.searchParams.set("sessionId",o),d.searchParams.set("platform",i),d.searchParams.set("url",a),d.searchParams.set("token",s),l&&d.searchParams.set("region",l),c&&d.searchParams.set("tabLabel",c),new t({url:d.toString(),server:u})}async shutdown(){this.server?.server.listening&&(await new Promise(e=>{this.server?.server.close(()=>{e();});}),this.server=void 0);}};function eHe(){if(!Qk)throw new Error("Remote control viewer static directory is not configured. Pass remoteControlStaticDir when starting the mobile MCP server.");let t=fr__default.resolve(Qk),e=fr__default.join(t,"index.html");if(!Sn.existsSync(e))throw new Error(`Remote control viewer index file not found at '${e}'. Ensure mobile-remote-control-frontend is built and copied into npm/mobile-cli/remote-control-static.`);return {staticDir:t,indexHtmlBuffer:Sn.readFileSync(e)}}function Zk({response:t,statusCode:e,body:r,allow:n}){let o={"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-store"};n&&(o.Allow=n),t.writeHead(e,o),t.end(r);}function hoe({request:t,response:e,buffer:r,contentType:n}){if(e.writeHead(200,{"Content-Type":n,"Cache-Control":"no-store"}),t.method==="HEAD"){e.end();return}e.end(r);}function tHe({staticDir:t,pathname:e}){let r;try{r=decodeURIComponent(e);}catch{return}let n=r==="/"?"index.html":r.replace(/^\/+/,""),o=fr__default.resolve(t,n),i=fr__default.relative(t,o);if(!(i.startsWith("..")||fr__default.isAbsolute(i)))return o}function rHe({request:t,response:e,assets:r}){if(t.method!=="GET"&&t.method!=="HEAD"){Zk({response:e,statusCode:405,body:"Method Not Allowed",allow:"GET, HEAD"});return}let n=new URL(t.url??"/","http://localhost").pathname;if(n==="/"||n==="/index.html"){hoe({request:t,response:e,buffer:r.indexHtmlBuffer,contentType:"text/html; charset=utf-8"});return}let o=tHe({staticDir:r.staticDir,pathname:n});if(!o){Zk({response:e,statusCode:403,body:"Forbidden"});return}if(!Sn.existsSync(o)||!Sn.statSync(o).isFile()){Zk({response:e,statusCode:404,body:"Not Found"});return}let i=fr__default.extname(o).toLowerCase(),a=Mu[i]??"application/octet-stream";hoe({request:t,response:e,buffer:Sn.readFileSync(o),contentType:a});}async function nHe({logger:t,assets:e}){let r=createServer((i,a)=>rHe({request:i,response:a,assets:e})),n=Math.floor(Math.random()*Qje)+Zje,o=await ic(n,"mobile-mcp-remote-control-viewer");return await new Promise((i,a)=>{let s=l=>{a(l);};r.once("error",s),r.listen(o,()=>{r.off("error",s),i();});}),t.info({port:o,staticDir:e.staticDir},"Started mobile MCP remote control viewer server"),{port:o,server:r}}function eF({logger:t,applicationName:e,cliVersion:r,serverId:n=randomUUID()}){let o={serverId:n,applicationName:e,cliVersion:r},i=an(),a=t.child({orgId:i,userId:_d(),...o});return {info:o,mcpLogger:a,orgId:i}}function tF({sessionIdleTimeoutMinutes:t}){return (t&&t>=1?t:foe)*60*1e3}async function ox({project:t,serverUrl:e,alwaysSaveCache:r,noCache:n,remoteControlStaticDir:o}){goe({staticDir:o}),Cf(e),uR({alwaysSaveCache:r,noCache:n}),ex({userId:_d(),orgId:an(),selfServe:mR()}),pR(t,i=>hi({configFilePath:i}));}function ix({project:t,logger:e,apiKey:r,serverUrl:n,supportsFileOutput:o,headfulDefault:i,sessionIdleTimeoutMinutes:a,applicationName:s,cliVersion:l,serverId:c}){let{info:u,mcpLogger:d,orgId:m}=eF({logger:e,applicationName:s,cliVersion:l,serverId:c}),p=new Ts({baseUrl:n,apiKey:r,logger:d,mode:"interactive",runner:"mcp"});return {context:{project:t,orgId:m,logger:d,generator:p,serverId:u.serverId,saveChangesToDisk:true,sessionIdleTimeoutMs:tF({sessionIdleTimeoutMinutes:a}),supportsFileOutput:o,headfulDefault:i},info:u}}async function sHe({moduleId:t,name:e,description:r,enabled:n,platform:o,parameters:i,steps:a,project:s}){let l=await vt(s),{stepsToSave:{steps:c}}=await An({platform:o,stepLists:{steps:a}});bs({content:{platform:o,moduleId:t,name:e,description:r,enabled:n,parameters:i,steps:c},schemaVersion:dn,momenticFiles:l,project:s});}function lHe({module:t,inputs:e}){return {...t,id:randomUUID(),type:"RESOLVED_MOBILE_MODULE",inputs:e}}async function boe({project:t,logger:e,testPath:r,saveChangesToDisk:n,mutableStepState:o,params:i,initialMomenticFiles:a,platform:s,availableSteps:l,cacheContext:c}){let{stepsToExtract:u,startIndex:d,endIndex:m}=nte({moduleName:i.name,existingModuleNames:Object.values(a.mobileModules).map(h=>h.name),parameterNames:i.parameters?.parameterNames,defaultParameters:i.parameters?.defaultParameters,parameterEnums:i.parameters?.parameterEnums,moduleInputs:i.moduleInputs,testPath:r,startIndex:i.startIndex,endIndex:i.endIndex,availableSteps:l,containsNestedModuleStep:P3}),p=fr__default.join(t.rootDir,i.folderPath??"");i.folderPath&&Sn.mkdirSync(p,{recursive:true});let f=await sb({name:i.name,platform:s,description:i.description??"",enabled:i.enabled??true,steps:u,folder:p,project:t,momenticFiles:a});if(i.parameters!==void 0&&(await sHe({moduleId:f.moduleId,name:i.name,description:i.description??"",enabled:i.enabled??true,platform:s,parameters:i.parameters,steps:u,project:t}),f={...f,name:i.name,description:i.description??"",parameters:i.parameters}),n&&i.startIndex!==void 0&&r!==void 0){let h=await vt(t);if(!l)throw new Error("Mobile module was created successfully, but the source test steps were not available for replacement.");let g=lHe({module:f,inputs:i.moduleInputs}),y=[...l];if(y.splice(d,m-d,g),await cl({platform:s,filePath:r,steps:y,folder:t.rootDir,project:t,momenticFiles:h,schemaVersion:dn}),o&&(o.stepLists={...o.stepLists,steps:y}),c){let{cachesToSave:S,snapshotCachesToSave:E}=await An({platform:s,stepLists:{steps:y},cacheCreationParams:{orgId:c.orgId,testId:c.testId,environment:c.envName},useSnapshotIdentityCache:c.useSnapshotIdentityCache});try{await c.cacheStorage.saveEntries({platform:s,logger:e,entries:S});}catch(v){e.warn({err:v},"Failed to save mobile step caches after module create, future runs may be slower");}if(c.useSnapshotIdentityCache)try{await c.cacheStorage.saveSnapshotCacheEntries({platform:s,logger:e,entries:E});}catch(v){e.warn({err:v},"Failed to save mobile snapshot identity cache after module create, future runs may regenerate step ids");}}}return f}function yoe(t,e,r){if(!t)return {availableSteps:void 0,mutableStepState:void 0};if(t.platform!==e)throw new Error(`Internal error: test platform ${t.platform} does not match resolved platform ${e}`);return r&&r.testId===t.id&&r.platform===e?{availableSteps:r.stepLists.steps,mutableStepState:r}:{availableSteps:t.steps,mutableStepState:void 0}}async function Toe({project:t,logger:e,testPath:r,saveChangesToDisk:n,mutableStepState:o,params:i}){_i(i.name);let a=await vt(t),s=r!==void 0?await dr(fr__default.join(t.rootDir,r),e,a):void 0,l=s?.platform??i.platform??"ANDROID";if(i.platform&&l!==i.platform)throw new Error(`Error: Requested module platform ${i.platform} does not match source test platform ${s?.platform}.`);let c;if(s!==void 0){let d=Wt();if(d){let m=await Sr(e,d,t),{alwaysSaveCache:p,noCache:f}=Ns();c={cacheStorage:rn({logger:e,orgId:an(),client:d,gitMetadata:m,regenerateCache:false,alwaysSaveCache:p,noCache:f,isolateCachesByEnvironment:t.config?.advanced?.isolateCachesByEnvironment}),testId:s.id,orgId:an(),envName:s.settings?.defaultEnv,useSnapshotIdentityCache:t.config.fileFormat==="v2"};}}let u={project:t,logger:e,testPath:r,saveChangesToDisk:n,params:i,initialMomenticFiles:a,cacheContext:c};switch(l){case "ANDROID":return {module:await boe({...u,platform:"ANDROID",...yoe(s,"ANDROID",o)})};case "IOS":return {module:await boe({...u,platform:"IOS",...yoe(s,"IOS",o)})};default:return _t(l)}}var Eoe=Un({schema:{name:$S,description:"Get a single fully loaded mobile module by id, exact name, or file path. This returns complete module details including parameters, description, and the full step list. Exactly one selector must be provided.",inputSchema:z.object({selector:nU})},handle:async(t,e,r)=>{let{project:n,logger:o}=t;try{let i=await Es(n,e.selector,"mobileModules"),a=await nd(i.entity,i.momenticFiles,o);r.addPartFromText(JSON.stringify({module:a},null,2));}catch(i){r.addError(W(i));}}}),voe=Un({schema:{name:eU,description:"Create a mobile module. If startIndex is provided, testPath is required and the specified mobile test range is extracted into a module for that test's platform, then replaced with a module invocation in that test. For empty modules, platform defaults to Android unless platform or testPath identifies iOS.",inputSchema:DP},handle:async(t,e,r)=>{try{let n=DP.parse(e),{testPath:o,...i}=n,a=fX({projectRoot:t.project.rootDir,filePath:o,pathLabel:"testPath"}),s;if(a!==void 0){let c=fr__default.join(t.project.rootDir,a);for(let u of so.listSessionIds()){let d=so.getSession(u);if(d!==void 0&&d.testFileAbsolutePath===c){s=d.mutableStepState;break}}}let l=await Toe({project:t.project,logger:t.logger,testPath:a,saveChangesToDisk:t.saveChangesToDisk,mutableStepState:s,params:i});r.addPartFromText(JSON.stringify(l.module,null,2));}catch(n){r.addError(W(n));}}});function ax({step:t,parentChain:e}){let r=t;r.parentStepIdChain=e.map(n=>n.id),delete r.retries,delete r.skipped;}function pHe(t){let e=cloneDeep(t);return Bo({steps:e,earlyStop:false,onPreset:(r,n)=>{if(ax({step:r,parentChain:n.parentChain}),r.type==="MOBILE_PRESET_STEP"){let o=r.command;delete o.cache,delete o.id,delete o.thoughts;}return false},onModule:(r,n)=>{ax({step:r,parentChain:n.parentChain});let o=r;return delete o.enabled,delete o.schemaVersion,false},onConditional:(r,n)=>(ax({step:r,parentChain:n.parentChain}),false),onAiAction:(r,n)=>{ax({step:r,parentChain:n.parentChain});let o=r;return delete o.cache,false}}),e.map((r,n)=>{let o=r;return o.index=n,o})}function rF(t,e){if(t.length===0)return `${e}: (no steps)`;let r=["```json",JSON.stringify(pHe(t),null,2),"```"].join(`
|
|
6238
|
+
`;function Pne(t){return VR(t,Rne,Mne())}var wl={initializeAIActionConfig:Pne,stepSchema:Jr,resultSchema:Do};var nje=5e3,jk=2;async function _ne({socket:t,logger:e,orgId:r,testMetadata:n,globalOrgSettings:o,androidDriverFactory:i,mobileGeneratorFactory:a,browserGeneratorFactory:s,browserEnricherFactory:l,storageFactory:c,visualDiffGoldenStorageFactory:u,cacheStorageFactory:d,localToolsFactory:m,onRemoteEmulatorCreated:p,onRemoteEmulatorDeleted:f,billingReporterFactory:h,globalStateManager:g,getGitMetadata:y,region:S,localApkPath:E,localAvdId:v}){let w=t.id,_=t.handshake.query?.fileName,L=_?fr__default.basename(_,".test.yaml"):"",I=n.id;e=e.child({sessionId:w,testId:I,orgId:r});let R=await y(e);e=e.child({branch:R.gitBranchName});let k=await c(r),D=n.settings?.defaultEnv,V={};D&&(V=(await k.fetchEnvironment(D,e))?.variables??{});let $={...o.emulator,...n.settings?.emulator},U={...o.ai,useMemory:o.ai?.useMemory!==false,...n.settings?.ai},fe=g.getSession(w);if(fe){if(e.info("Reconnecting to existing Android session"),fe.local)return t.emit("session",fe.metadata),fe.softDeleted=false,fe.metadata;throw new Error("Restoring existing remote emulator sessions is not supported. Please reconnect to a new emulator.")}let q=await d(r,R,e),N=Hl.optional().parse(S??$.region),F=N==="local",B,te,j;if(F){if(await g.clearSoftDeletedLocalSessions(e),g.hasActiveLocalSession())throw new Error("Another local emulator session is already active. Please close the existing session before creating a new one.");let{avdId:Tn,apkFilePath:co,apkFilePathSource:Na}=Dm({overrideAvdId:v,overrideApkFilePath:E,emulatorSettings:$,defaultApkFilePath:n.settings?.defaultApkFilePath,envVariables:V}),Ml=Np({apkFilePath:co,source:Na});if(!Tn)throw new Error(`An AVD ID is required when using a local region. Provide --local-avd-id, configure a default local AVD ID on the test's settings, or set the ${Dl} key on the environment.`);j={avdId:Tn,apkFilePath:Ml};}else B=n.settings?.defaultChannel,te=n.settings?.defaultTag,j={region:N===li?void 0:N,apkToInstall:B?{channel:B,tag:te}:void 0,osVersion:$.remoteEmulatorSettings?.androidVersion??Am};e.info({platform:"ANDROID",isLocalRegion:F,resolvedRegion:N,envName:D,emulatorSettings:$,aiSettings:U},"Starting mobile session with resolved configuration");let z=Date.now(),se,be;for(let Tn=1;Tn<=jk;Tn++)try{se=await i({socket:t,logger:e,creationOpts:j});break}catch(co){if(be=co,Tn===jk)break;e.warn({err:co,attempt:Tn,maxAttempts:jk},"Mobile session bootstrap failed; retrying bootstrap");}if(!se)throw be||new Error("Mobile session bootstrap failed without an error");let{driver:rt,cleanup:gt,emulatorName:it,adbPort:or}=se,Je,J,Me,Gt,at,Se;"limbarClient"in se&&(Je=se.limbarClient,J=se.limbarToken,Me=se.limbarUrl,Gt=se.limbarRegion,at=se.limbarOsVersion,Se=se.playwrightDevice);let Zo=fr__default.join(tmpdir(),`logcat-logs-${r}-${I}-${w}.txt`);F||await p?.({emulatorName:it,platform:"ANDROID"}),e.info({adbPort:or,apkChannel:B,apkTag:te,duration:Date.now()-z,emulatorName:it},"Android emulator session initiated"),e=e.child({emulator:it});let Qo=false,Ai=false,Dr,Zt,sn,On,La=async()=>{if(Qo)return;Qo=true,Ai=true,clearInterval(sn),sn=void 0;let co=[async()=>{await Zt?.cleanup();},async()=>{await Dr?.();},async()=>{await gt(),F||await f?.({emulatorName:it,platform:"ANDROID"});},async()=>{await On?.dispose();}].map(Na=>Na().catch(Ml=>{e.warn({err:Ml},"Failed to clean up socket server resource");}));await ee(Promise.allSettled(co),{milliseconds:nje,fallback:()=>{}});};g.registerPendingSession(w,{platform:"ANDROID",cleanup:La,emulatorName:it,local:F});let ou=async()=>{Dr=await rt.executeInNativeContext(e,cS=>$C({driver:cS,onLogs:sae=>{t.emit("logcatLogs",sae);},logFilePath:Zo}),{operationName:"startLogcatListener"});let Tn=await a(r,e),co=await s(r,e),Na=await l(r,e);On=m?await m(r):void 0;let Ml=new fs({logger:e,reporter:await h(r),runType:"mobile-test-run",runId:w,testMetadata:{id:n.id,name:L},isInteractive:true,runner:"editor"}),A=new Ui({variablesFromEnvironment:V,envName:D,testName:L});if(Zt=await Zc.init({driver:rt,generator:Tn,logger:e,limbarClient:Je,playwrightDevice:Se,aiSettings:U,options:{emulator:{...$,browserSettings:o.browser}},fixtures:{storage:k,browserEnricher:Na,browserGenerator:co,localCodeEvalTools:On,testContext:A,visualDiffGoldenStorage:u()},orgId:r,adbPort:or,abortController:new AbortController}),!Zt)throw new Error("Failed to initialize Android controller");let ne=Zt;if(Ai||!t.connected)throw new Error("Socket not connected anymore, not proceeding with Android session setup");let Yt=await ne.getViewportBounds();if(Ai||!t.connected)throw new Error("Socket not connected anymore, not proceeding with Android session setup");sn=oje({socket:t,testContext:A});let Ar={sessionId:w,testId:I,orgId:r,emulatorName:it,testName:L,limbarUrl:Me,limbarToken:J,limbarRegion:Gt,limbarOsVersion:at,viewportBounds:Yt,envName:D};return g.registerSession(w,{platform:"ANDROID",controller:ne,cacheStorage:q,cleanup:La,emulatorName:it,local:F,metadata:Ar,logFilePath:Zo,helpers:Cl,usageTracker:Ml}),t.emit("session",Ar),Ar};try{return await ou()}catch(Tn){throw await g.removeSession(w,e),Tn}}function oje({socket:t,testContext:e}){return setInterval(()=>{let r=e.toEditorDisplayCopy();t.emit("emulatorState",{context:r});},3e3)}async function One({socket:t,logger:e,globalStateManager:r,authorization:n}){let o=t.id,i=r.getSession(o);i&&i.platform==="ANDROID"&&n&&i.logFilePath&&ije({testId:i.metadata.testId,sessionId:o,logFilePath:i.logFilePath,authorization:n,logger:e}),await r.removeSession(o,e);}async function ije({testId:t,sessionId:e,logFilePath:r,authorization:n,logger:o}){try{let i;try{i=await jR.stat(r);}catch{o.debug({logFilePath:r},"No logcat file found to upload");return}if(i.size===0){o.debug({logFilePath:r},"Logcat file is empty, skipping upload"),await jR.unlink(r);return}let a=new Tr(n),{uploadUrl:s}=await a.generateMobileLogcatUploadUrl({testId:t,sessionId:e}),l=await jR.readFile(r),c=await fetch(s,{headers:{"Content-Length":l.length.toString(),"Content-Type":"text/plain"},method:"PUT",body:l});if(c.status!==200)throw new Error(`Failed to upload logcat: ${c.status} ${await c.text()}`);o.info({testId:t,sessionId:e,objectUrl:gv(s)},"Logcat file uploaded successfully");}catch(i){o.warn({err:i,testId:t,sessionId:e},"Failed to upload logcat file");}finally{try{await jR.unlink(r);}catch(i){o.warn({err:i,logFilePath:r},"Failed to delete temp logcat file");}}}var aje=({socket:t,globalStateManager:e})=>async()=>{let r=e.getSession(t.id);if(!r)throw new Error("No active Mobile session found");r.controller.abort();},Dne={event:"cancel",createHandler:aje};var sje=({logger:t,globalStateManager:e,socket:r})=>async(n,o)=>{let i=e.getSession(r.id);if(!i){o({err:"No active Mobile session found"});return}let a=i.controller;a.resetAbortController();let s=Date.now();try{let l=await a.getEmulatorDomState();t.info({durationMs:Date.now()-s},"Fetched screen XML"),o({screenXml:l});}catch(l){t.error({err:l},"Error fetching screen XML from the session controller"),o({err:l.message});}},Lne={event:"fetchScreenXml",createHandler:sje};var Hk=class{parentTracer;socket;step;orgId;interactionTracer;platform;constructor({step:e,socket:r,parentTracer:n,orgId:o,platform:i}){this.socket=r,this.parentTracer=n,this.step=e,this.orgId=o,this.platform=i,this.interactionTracer=new Xi,ro.initializeRootTracerContext(this.interactionTracer);}attachBeforeScreenshot(){}attachAfterScreenshot(){}attachBeforeXmlSnapshot(){}attachAfterXmlSnapshot(){}recordStepDuration(e){let{durationMs:r,step:n}=e;if(!iE(n))return;let o=oE(n);Ge.distribution("test_mobile_step_duration",r,[`type:${o}`,`platform:${this.platform.toLowerCase()}`,"executor:editor",`orgId:${this.orgId}`]);}async finish(e){this.interactionTracer.finish();let r=this.interactionTracer.getRootSpan(),n={result:e.result,parentStepIdChain:e.parentStepIdChain,trace:RP.parse(r)};switch(n.result.status){case "SUCCESS":this.socket.emit("success",n);break;case "FAILED":this.socket.emit("failure",n);break;case "CANCELLED":this.socket.emit("cancelled",n);break}return {trace:r}}getParentStepIdChain(){return this.parentTracer?this.parentTracer?.getParentStepIdChain()??[]:[]}async startSubSteps(){return new Bf({parentStep:this.step,socket:this.socket,parentTracer:this,orgId:this.orgId,platform:this.platform})}},Bf=class{parentTracer;parentStep;socket;orgId;platform;constructor({parentStep:e,socket:r,parentTracer:n,orgId:o,platform:i}){this.parentTracer=n,this.parentStep=e,this.socket=r,this.orgId=o,this.platform=i;}getParentStepIdChain(){return this.parentStep?[...this.parentTracer?.getParentStepIdChain()??[],this.parentStep.id]:[]}async startStep(e){return this.socket.emit("started",{stepId:e.step.id,parentStepIdChain:e.parentStepIdChain,attempt:e.attempt}),new Hk({step:e.step,parentTracer:this,socket:this.socket,orgId:this.orgId,platform:this.platform})}async getScreenshot(e){}},HR=class{constructor(e,r,n){this.socket=e;this.orgId=r;this.platform=n;}appendLogs(){}setActiveVideo(){}async finish(){this.socket.emit("finished");}async startBeforeStepList(){return new Bf({parentStep:null,parentTracer:null,socket:this.socket,orgId:this.orgId,platform:this.platform})}async startMainStepList(){return new Bf({parentStep:null,parentTracer:null,socket:this.socket,orgId:this.orgId,platform:this.platform})}async startAfterStepList(){return new Bf({parentStep:null,parentTracer:null,socket:this.socket,orgId:this.orgId,platform:this.platform})}};var lje=({metadata:t,logger:e,globalStateManager:r,socket:n,useSnapshotIdentityCache:o,storageFactory:i})=>async(a,s)=>{let l=r.getSession(n.id);if(!l)throw new Error("No active Mobile session found");let c=await i(t.orgId),u=e.child({testId:a.testMetadata.id});u.info({sessionId:t.sessionId,platform:l.platform,testName:t.testName,stepCount:a.steps.length,beforeStepCount:a.beforeSteps?.length??0,afterStepCount:a.afterSteps?.length??0,fromStep:a.fromStep,toStep:a.toStep,typeCommands:uje(a.steps)},"Received mobile socket execute request"),l.controller.resetAbortController();let d=l.usageTracker,m;try{m=await cje({session:l,params:a,metadata:t,testLogger:u,usageTracker:d,socket:n,useSnapshotIdentityCache:o,storage:c});}finally{await d.flush(u);}let p={results:l.helpers.resultSchema.array().parse(m.results),status:m.status};s?.(p);};async function cje({session:t,...e}){switch(t.platform){case "ANDROID":return Nne({session:t,...e});case "IOS":return Nne({session:t,...e});default:return (n=>{throw new Error(`Unsupported platform: ${n}`)})(t)}}async function Nne({session:t,params:e,metadata:r,testLogger:n,usageTracker:o,socket:i,useSnapshotIdentityCache:a,storage:s}){let l=new HR(i,r.orgId,t.platform);try{return await Ff({platform:t.platform,work:{fastForwardingToStep:!!e.fromStep,state:{failureRecoveryDisabled:!0,failureRecoveryAttempts:0}},fixtures:{controller:t.controller,logger:n,cacheStorage:t.cacheStorage,usageTracker:o,storage:s},containerName:"entire test",inputs:{steps:t.helpers.stepSchema.array().parse(e.steps),beforeSteps:e.beforeSteps?t.helpers.stepSchema.array().parse(e.beforeSteps):void 0,afterSteps:e.afterSteps?t.helpers.stepSchema.array().parse(e.afterSteps):void 0,fromStep:e.fromStep,toStep:e.toStep,orgId:r.orgId,testName:r.testName,testMetadata:e.testMetadata,interactive:!0,useSnapshotIdentityCache:a,updateGoldenFiles:e.updateGoldenFiles},envName:r.envName,tracer:l,callbacks:{step:{onAiActionEvent:c=>{i.emit("aiActionEvent",c);}}},helpers:t.helpers})}finally{await l.finish();}}var kne={event:"execute",createHandler:lje};function uje(t){return t.flatMap((e,r)=>!("command"in e)||e.command.type!=="TYPE"?[]:[{index:r,stepId:e.id,target:e.command.target?.type==="description"?e.command.target.description:e.command.target?.type,textLength:e.command.text.length,clearContent:e.command.clearContent,forceClearContent:e.command.forceClearContent,replaceStrategy:e.command.replaceStrategy,hasCache:e.command.cache!==void 0}])}var mje=({socket:t,globalStateManager:e,keepSessionAlive:r})=>{let n=debounce(r,3e4,{maxWait:6e4});return async()=>{let o=e.getSession(t.id);if(!o)throw new Error("No active Mobile session found");o.emulatorName&&(o.local||n(o.platform,o.emulatorName));}},Fne={event:"keepalive",createHandler:mje};var pje=({socket:t,globalStateManager:e,logger:r})=>async(n,o)=>{let i=e.getSession(t.id);if(!i){let s="No active session found";r.error(s),o?.({success:false,err:s});return}let a=i.controller;a.abort(),a.resetAbortController(),r.info({platform:i.platform},"Resetting emulator state");try{await a.softReset(),r.info({platform:i.platform},"Emulator reset completed"),o?.({success:!0,message:"Emulator reset successfully"});}catch(s){let l=W(s);r.error({err:s,platform:i.platform},"Failed to reset emulator"),o?.({success:false,err:`Failed to reset emulator: ${l}`});}},Bne={event:"reset",createHandler:pje};var Une=[kne,Dne,Bne,Fne,Lne];var hje=5e3,Wk=2;async function zne({socket:t,logger:e,orgId:r,testMetadata:n,globalOrgSettings:o,localIosDeviceType:i,localIosVersion:a,iosDriverFactory:s,mobileGeneratorFactory:l,browserGeneratorFactory:c,browserEnricherFactory:u,billingReporterFactory:d,storageFactory:m,visualDiffGoldenStorageFactory:p,cacheStorageFactory:f,localToolsFactory:h,onRemoteEmulatorCreated:g,onRemoteEmulatorDeleted:y,globalStateManager:S,getGitMetadata:E,region:v,localAppPath:w}){let _=t.id,L=t.handshake.query?.fileName,I=L?fr__default.basename(L,".test.yaml"):"",R=n.id,k=n.settings?.defaultChannel,D=n.settings?.defaultTag;e=e.child({sessionId:_,testId:R,orgId:r});let V=await E(e);e=e.child({branch:V.gitBranchName});let $=await m(r),U=n.settings?.defaultEnv,fe={};U&&(fe=(await $.fetchEnvironment(U,e))?.variables??{});let q={...o.emulator,...n.settings?.emulator},N={...o.ai,useMemory:o.ai?.useMemory!==false,...n.settings?.ai},F=S.getSession(_);if(F){if(e.info("Reconnecting to existing iOS session"),F.local)return t.emit("session",F.metadata),F.softDeleted=false,F.metadata;throw new Error("Restoring existing remote emulator sessions is not supported. Please reconnect to a new emulator.")}let B=await f(r,V,e),te=Hl.optional().parse(v??q.region),j=te==="local",z;if(j){if(await S.clearSoftDeletedLocalSessions(e),S.hasActiveLocalSession())throw new Error("Another local emulator session is already active. Please close the existing session before creating a new one.");let{deviceType:Dr,iosVersion:Zt,appFilePath:sn,appFilePathSource:On}=Lm({overrideDeviceType:i,overrideIosVersion:a,overrideAppFilePath:w,emulatorSettings:q,defaultAppFilePath:n.settings?.defaultAppFilePath,envVariables:fe});if(!Dr)throw new Error(`A device type is required when using a local region. Provide --local-ios-device-type, configure a default local iOS device type on the test's settings, or set the ${Ll} key on the environment.`);let La=Df({appFolderPath:sn,source:On});z={type:"local",deviceType:Dr,iosVersion:Zt,appFilePath:La};}else z={type:"remote",region:te===li?void 0:te,appToInstall:k?{channel:k,tag:D}:void 0,osVersion:Rm};e.info({platform:"IOS",isLocalRegion:j,resolvedRegion:te,envName:U,emulatorSettings:q,aiSettings:N},"Starting mobile session with resolved configuration");let se=Date.now(),be,rt;for(let Dr=1;Dr<=Wk;Dr++)try{be=await s({socket:t,logger:e,creationOpts:z});break}catch(Zt){if(rt=Zt,Dr===Wk)break;e.warn({err:Zt,attempt:Dr,maxAttempts:Wk},"Mobile session bootstrap failed; retrying bootstrap");}if(!be)throw rt||new Error("Mobile session bootstrap failed without an error");let{driver:gt,cleanup:it,emulator:or,limbarParams:Je}=be;e=e.child({emulator:or.name}),e.info({duration:Date.now()-se},"iOS emulator session initiated"),j||await g?.({emulatorName:or.name,platform:"IOS"});let J=false,Me=false,Gt,at,Se,Zo,Qo=async()=>{if(J)return;J=true,Me=true,Se&&(clearInterval(Se),Se=void 0);let Zt=[async()=>{await at?.cleanup();},async()=>{Gt?.();},async()=>{await it(),j||await y?.({emulatorName:or.name,platform:"IOS"});},async()=>{await Zo?.dispose();}].map(sn=>sn().catch(On=>{e.warn({err:On},"Failed to clean up socket server resource");}));await ee(Promise.allSettled(Zt),{milliseconds:hje,fallback:()=>{}});};S.registerPendingSession(_,{platform:"IOS",cleanup:Qo,emulatorName:or.name,local:j});let Ai=async()=>{Gt=await TR({emulator:or,onLogs:Na=>{t.emit("syslogLogs",Na);}});let Dr=await l(r,e),Zt=await c(r,e),sn=await u(r,e);Zo=h?await h(r):void 0;let On=new fs({logger:e,reporter:await d(r),runType:"mobile-test-run",runId:_,runner:"editor",testMetadata:{id:n.id,name:I},isInteractive:true}),La=new Ui({variablesFromEnvironment:fe,envName:U,testName:I});if(at=await eu.init({driver:gt,generator:Dr,logger:e,emulator:or,aiSettings:N,options:{emulator:{...q,browserSettings:o.browser}},fixtures:{storage:$,browserEnricher:sn,browserGenerator:Zt,localCodeEvalTools:Zo,testContext:La,visualDiffGoldenStorage:p()},orgId:r,abortController:new AbortController}),!at)throw new Error("Failed to initialize iOS controller");let ou=at;if(Me||!t.connected)throw new Error("Socket not connected anymore, not proceeding with iOS session setup");let Tn=await ou.getViewportBounds();if(Me||!t.connected)throw new Error("Socket not connected anymore, not proceeding with iOS session setup");Se=gje({socket:t,testContext:La});let co={sessionId:_,testId:R,orgId:r,emulatorName:or.name,testName:I,limbarUrl:Je?.webRtcUrl,limbarToken:Je?.token,limbarRegion:Je?.region,limbarOsVersion:Je?.osVersion,viewportBounds:Tn,envName:U};return S.registerSession(_,{platform:"IOS",controller:ou,cacheStorage:B,cleanup:Qo,emulatorName:or.name,local:j,metadata:co,helpers:wl,usageTracker:On}),t.emit("session",co),co};try{return await Ai()}catch(Dr){throw await S.removeSession(_,e),Dr}}function gje({socket:t,testContext:e}){return setInterval(()=>{let r=e.toEditorDisplayCopy();t.emit("emulatorState",{context:r});},3e3)}var WR=class{sessions=new Map;pendingSessions=new Map;registerPendingSession(e,r){this.pendingSessions.set(e,r);}registerSession(e,r){this.pendingSessions.delete(e),this.sessions.set(e,r);}getSession(e){return this.sessions.get(e)}getSessionForTest(e){for(let r of this.sessions.values())if(r.metadata.testId===e)return r}async clearSoftDeletedLocalSessions(e){for(let r of this.sessions.values())r.softDeleted===true&&r.local===true&&await this.removeSession(r.metadata.sessionId,e);}hasActiveLocalSession(){for(let e of [...this.sessions.values(),...this.pendingSessions.values()])if(e.local===true)return true;return false}async removeSession(e,r){let n=this.sessions.get(e)??this.pendingSessions.get(e);if(!n)return;let o=r.child({sessionId:e,emulatorName:n.emulatorName,platform:n.platform});try{await this.sessions.get(e)?.usageTracker.flush(o);}catch(i){o.error({err:i},"Error flushing usage tracker before cleanup");}try{await n.cleanup?.(),o.info("Emulator cleaned up by removeSession");}catch(i){o.error({err:i},"Error during emulator cleanup");}finally{this.sessions.delete(e),this.pendingSessions.delete(e);}}async removeAllSessions(e){let r=Array.from(new Set([...this.sessions.keys(),...this.pendingSessions.keys()]));await Promise.all(r.map(n=>this.removeSession(n,e)));}};function $ne(t){let{logger:e,baseServer:r,globalStateManager:n,settingsFactory:o,getOrgId:i}=t,a=new Server(r,{cors:{origin:"*",methods:["GET","POST"]},pingTimeout:15*60*1e3,pingInterval:15*60*1e3,maxHttpBufferSize:1e7,perMessageDeflate:true,connectionStateRecovery:{maxDisconnectionDuration:60*60*1e3,skipMiddlewares:true}}),s=async()=>{await n.removeAllSessions(e);};a.on("connection",async c=>{let u=c.id,d=e.child({sessionId:u});d.info({event:"connection",transport:c.conn.transport.name},"Mobile websocket connection initiated"),c.on("disconnect",async f=>{if(e.info({reason:f},"Disconnect received"),f.includes("namespace disconnect")){await One({socket:c,globalStateManager:n,logger:d,authorization:t.authorization});return}let h=n.getSession(u);h&&(h.softDeleted=true);});let m,p;try{let f=c.handshake.query?.testMetadata,h=Gl.parse(JSON.parse(f??"")),g=h.id,y=await i({testId:g});switch(p=await o(y,d),h.platform){case "ANDROID":m=await _ne({...t,orgId:y,socket:c,globalStateManager:n,logger:d,globalOrgSettings:p,testMetadata:h});break;case "IOS":m=await zne({...t,orgId:y,socket:c,globalStateManager:n,logger:d,globalOrgSettings:p,testMetadata:h});break;default:throw new Error("Unsupported platform")}}catch(f){d.error({err:f},"Failed to setup mobile connection"),c.emit("error",{message:f instanceof Error?f.message:JSON.stringify(f)}),c.disconnect(true);return}Une.forEach(f=>l(f,{...t,socket:c,metadata:m,globalOrgSettings:p,logger:d}));});let l=(c,u)=>{let d=c.createHandler(u),m=(...p)=>{c.event!=="keepalive"&&u.logger.debug({event:c.event},`Websocket event (${c.event})`);let f=h=>{u.logger.error({event:c.event,err:h instanceof Error?h:new Error(`${h}`)},"Unhandled exception in socket handler"),u.socket.emit("error",{message:h instanceof Error?h.message:typeof h=="string"?h:JSON.stringify(h)});};try{let h=d.apply(this,p);h&&typeof h.catch=="function"&&h.catch(f);}catch(h){f(h);}};u.socket.on(c.event,m);};return {server:a,dispose:s}}async function vje(t,e){switch(t){case "ANDROID":return {uploadPath:e,cleanup:async()=>{}};case "IOS":{let r=await Sn.promises.mkdtemp(fr__default.join(el.tmpdir(),"momentic-mobile-asset-")),n=fr__default.join(r,"app.zip");return await Cje(e,n),{uploadPath:n,cleanup:()=>Sn.promises.rm(r,{recursive:true,force:true})}}}}function Cje(t,e){return new Promise((r,n)=>{let o=yje("zip",{zlib:{level:9}}),i=Sn.createWriteStream(e);i.on("close",()=>r()),i.on("error",n),o.on("error",n),o.on("warning",a=>{a.code!=="ENOENT"&&n(a);}),o.pipe(i),o.directory(t,false,a=>fr__default.basename(a.name)===".DS_Store"?false:(a.mode=a.stats?.isDirectory()?493:420,a)),o.finalize().catch(n);})}async function wje(t){let e=Sje.createHash("md5");await new Promise((n,o)=>{Sn.createReadStream(t).on("data",i=>e.update(i)).on("end",()=>n()).on("error",o);});let r=e.digest();return {md5Base64:r.toString("base64"),md5Hex:r.toString("hex")}}async function GR({tag:t,channel:e,filePath:r,apiClient:n,logger:o,platform:i}){o.info({channel:e,tag:t,platform:i,filePath:r},"starting asset upload");let a=Date.now(),{uploadPath:s,cleanup:l}=await vje(i,r);try{let{md5Base64:c,md5Hex:u}=await wje(s),{size:d}=await Sn.promises.stat(s),m=await n.generateAssetUploadUrl({channel:e,tag:t??"latest",md5:c,platform:i});if(m.md5&&(m.md5===c||m.md5===u))return o.info({channel:e,tag:t,platform:i,filePath:r,size:d,durationMs:Date.now()-a,skipped:!0},"skipped asset upload (md5 match)"),{skipped:!0};if(!m.uploadUrl)throw new M("InternalPlatformError",`No upload URL was given for asset ${r}`);try{let p=await fetch$1(m.uploadUrl,{headers:{"Content-Length":d.toString(),"Content-Type":"application/octet-stream"},method:"PUT",body:Sn.createReadStream(s),duplex:"half"});if(p.status!==200)throw new M("InternalPlatformError",`Got error response from emulator platform: ${p.status} ${await p.text()}`);return o.info({channel:e,tag:t,platform:i,filePath:r,size:d,durationMs:Date.now()-a},"finished asset upload"),{skipped:!1}}catch(p){try{await n.deleteAsset(e,t??"latest",i);}catch(f){o.warn({err:f,tag:t,channel:e},"Failed to clean up asset after failed upload");}throw p}}finally{await l();}}async function qR({channel:t,tag:e,platform:r,apiClient:n,logger:o}){let i=e??"latest";o.info({channel:t,tag:i,platform:r},`Deleting asset ${t}:${i} (${r})...`),await n.deleteAsset(t,i,r),o.info({channel:t,tag:i,platform:r},`Asset ${t}:${i} (${r}) deleted successfully!`);}var Aje=z.object({emulatorName:z.string(),platform:z.enum(Ze)});z.object({runId:z.string(),emulators:z.array(Aje)});var Vne;async function KR(t){await Vne?.registerEmulator(t);}async function YR(t){await Vne?.unregisterEmulator(t);}var $f=new WR;var qk="1.0.2",Tt=qm({app:"mobile-desktop-server",hostname:hostname(),disableConsoleLogs:true}).child({cliVersion:qk});(async()=>{try{let t=await ib(Tt);t.gitBranchName&&Tt.addBinding("branch",t.gitBranchName);}catch{}})();var XR=Router();XR.get("/",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({message:"API client not initialized"});return}let n=await r.getMobileAssets();e.status(200).json(n);}));XR.post("/upload-url",je(async(t,e)=>{let r;try{r=P$.parse(t.body);}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}let n=Wt();if(!n){e.status(500).json({error:"API client not initialized"});return}let o=fr__default.resolve(r.filePath);if(!existsSync(o)){e.status(400).json({error:`File not found: ${o}`});return}let i=/\.apk$/i.test(o),a=o.endsWith(".app")&&statSync(o).isDirectory();if(!i&&!a){e.status(400).json({error:"Unsupported file type. Only .apk files and .app directories are supported."});return}await GR({tag:r.tag,channel:r.channel,filePath:o,apiClient:n,logger:Tt,platform:i?"ANDROID":"IOS"}),e.sendStatus(204);}));XR.delete("/:channel/:tag/:platform",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({error:"API client not initialized"});return}let{channel:n,tag:o,platform:i}=t.params;if(!n||!o||!i){e.status(400).json({error:"Missing channel, tag, or platform."});return}let a=Ph.safeParse(i.toUpperCase());if(!a.success){e.status(400).json({error:`Invalid platform "${i}". Expected "android" or "ios".`});return}let s=a.data;await qR({channel:n,tag:o,platform:s,apiClient:r,logger:Tt}),e.sendStatus(204);}));var jne=XR;var Vf=Router();async function JR(t){return (await qK(t,Tt)).map(n=>{let o=t.mobileModules[n.moduleId];if(!o){P.warn(`Found a dangling mobile module with ID ${n.moduleId} that could not be found on disk.`);return}return {...o,content:n}}).filter(n=>n!==void 0)}Vf.get("/",je(async(t,e)=>{let r=ht(),n=await vt(r),o=await JR(n);e.status(200).json(o);}));Vf.get("/tests-join",je(async(t,e)=>{let r=ht(),n=await vt(r),o=await JR(n),i={};for(let s of o)i[s.id]={...s,tests:[]};let a=await Promise.all(Object.values(n.mobileTests).map(async s=>({id:s.id,name:s.name,relativePath:s.relativePath,test:await dr(s.fullFilePath,Tt,n)})));for(let{id:s,name:l,relativePath:c,test:u}of a){let d=new Set;Bo({steps:u.steps,onPreset:()=>false,onModule:m=>(d.add(m.moduleId),false)});for(let m of d){let p=i[m];p&&p.tests.push({id:s,name:l,relativePath:c});}}e.status(200).json(i);}));Vf.get("/:moduleId",je(async(t,e)=>{if(!t.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let r=await vt(ht()),n=r.mobileModules[t.params.moduleId];if(!n){e.status(404).json({error:"Mobile module not found."});return}try{let o=await nd(n,r,P);e.json(o);}catch(o){e.status(400).json({err:o});}}));Vf.patch("/:moduleId/metadata",je(async(t,e)=>{if(!t.params.moduleId){e.status(400).json({error:"Missing moduleId in url path."});return}let r;try{r=_$.parse(t.body);}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let n=ht(),o=await vt(n);GK({moduleId:t.params.moduleId,patch:r,momenticFiles:o,logger:P,project:n}),e.status(201).json({message:"ok"});}));Vf.post("/",je(async(t,e)=>{let r;try{r=D$.parse(t.body);}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{_i(r.name);}catch(s){e.status(400).json({error:`Invalid module name: ${s}`});return}let n=ht(),o=await vt(n),i=o.mobileModules;if(Object.values(i).find(s=>s.name===r.name)){e.status(400).json({error:`A mobile module with the name "${r.name}" already exists. Please choose a different name.`});return}let a=fr__default.join(n.rootDir,r.folderPath??fr__default.dirname(r.testFilePath));if(!Sn.existsSync(a)||!Sn.statSync(a).isDirectory()){e.status(400).json({error:`The folder configured for mobile module creation does not exist: ${a}`});return}switch(r.platform){case "ANDROID":{let s=await sb({...r,folder:a,project:n,momenticFiles:o});e.status(201).json(s);return}case "IOS":{let s=await sb({...r,folder:a,project:n,momenticFiles:o});e.status(201).json(s);return}}}));var Gne=Vf;var Kk=Router();Kk.get("/",je(async(t,e)=>{let r=ht(),n=await vt(r),o=await JR(n),i=new Set;n?.mobileTests&&Object.values(n.mobileTests).forEach(c=>{c.labels?.forEach(u=>i.add(u));});let a=Array.from(i).sort(),s=Object.values(n.mobileTests),l={labels:a,modules:o,tests:s};e.status(200).json(l);}));Kk.get("/folders",je(async(t,e)=>{let r=ht(),n=await _K(r);e.status(200).json(n);}));var qne=Kk;var ZR=Router();ZR.get("/",je((t,e)=>{let r=eC(ht(),Tt);e.status(200).json(r);}));ZR.get("/names",je((t,e)=>{let n=ht().config.environments?.map(o=>o.name)??[];e.status(200).json(n);}));ZR.post("/",je((t,e)=>{let r;try{r=I$.parse(t.body);}catch(s){e.status(400).json({error:`Invalid request body: ${s}`});return}try{_i(r.name);}catch(s){e.status(400).json({error:`Invalid environment name: ${s}`});return}let n=ht();if(n.config.environments?.find(s=>s.name===r.name)){e.status(400).json({error:`An environment with the name "${r.name}" already exists. Please choose a different name.`});return}let i={...n.config,environments:[...n.config.environments??[],{name:r.name}]};n.config=i,rd(i,n.configFilePath);let a=ed(r.name,n,Tt);e.status(201).json(a);}));var Kne=ZR;var Yne=Router();Yne.get("/",je((t,e)=>{let r={userId:_d(),orgId:an(),email:dR(),name:Fte(),pylonEmailHash:Bte(),cliVersion:qk};e.status(200).json(r);}));var Xne=Yne;var Jne=Router();Jne.get("/",je(async(t,e)=>{let r=t.query.sessionId;if(!r){e.status(400).json({packages:[]});return}let n=$f.getSession(r);if(!n?.controller){e.status(200).json({packages:[]});return}try{let o=n.controller,{installedApps:i}=await o.getInstalledApps();e.status(200).json({packages:i});}catch(o){Tt.error({err:o},"Error fetching installed packages from the session controller"),e.status(200).json({packages:[]});}}));var Zne=Jne;var Qne=Router();Qne.get("/",je(async(t,e)=>{let r=await Hy(Tt);e.status(200).json(r);}));var eoe=Qne;var QR=Router(),toe=async({platform:t,steps:e,cacheStorage:r,stepId:n,parentStepIdChain:o,testId:i,environment:a})=>{let{result:s,parentChain:l}=ac(e,n,o);if(!s)return;let c=l.filter(u=>u.type==="RESOLVED_MOBILE_MODULE").map(u=>u.id);return await r.getCacheKeyForStep({platform:t,logger:Tt,testId:i,environment:a,parentStepIdChain:c,step:s})};QR.patch("/",je(async(t,e)=>{let r=ht(),n=an(),o=Wt(),i=r.config?.advanced?.isolateCachesByEnvironment;if(!o){e.status(500).json({error:"API client not initialized"});return}let a;try{a=k$.parse(t.body);}catch(u){e.status(400).json({error:`Invalid request body: ${u}`});return}let s=await Sr(Tt,o,r),l=rn({logger:Tt,orgId:n,client:o,gitMetadata:s,regenerateCache:false,noCache:false,alwaysSaveCache:false,isolateCachesByEnvironment:i}),c=await toe({cacheStorage:l,platform:a.platform,steps:a.steps,stepId:a.stepId,parentStepIdChain:a.parentStepIdChain,testId:a.testId,environment:i?a.environment:void 0});if(!c){e.status(400).json({error:"Cache-supporting step not found"});return}await o.updateMobileStepCaches({platform:a.platform,body:{entries:[{key:c,organizationId:n,value:a.value,testId:a.testId,environment:i?a.environment:void 0}]},headers:_u(s)}),e.status(204).send();}));QR.delete("/entry",je(async(t,e)=>{let r=ht(),n=an(),o=Wt(),i=r.config?.advanced?.isolateCachesByEnvironment;if(!o){e.status(500).json({error:"API client not initialized"});return}let a;try{a=B$.parse(t.body);}catch(u){e.status(400).json({error:`Invalid request body: ${u}`});return}let s=await Sr(Tt,o,r),l=rn({logger:Tt,orgId:n,client:o,gitMetadata:s,regenerateCache:false,noCache:false,alwaysSaveCache:false,isolateCachesByEnvironment:i}),c=await toe({cacheStorage:l,platform:a.platform,steps:a.steps,stepId:a.stepId,parentStepIdChain:a.parentStepIdChain,testId:a.testId,environment:i?a.environment:void 0});if(!c){e.status(400).json({error:"Cache-supporting step not found"});return}await o.deleteMobileStepCacheEntry({platform:a.platform,body:{testId:a.testId,key:c,environment:i?a.environment:void 0},headers:_u(s)}),e.status(204).send();}));QR.post("/traces",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({error:"API client not initialized"});return}let n;try{n=U$.parse(t.body);}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let o=await r.getMobileStepCacheMemoryTraces(n.platform,n);e.status(200).json(o);}));var roe=QR;PMe("phc_WRWd8LYIv6rolgDsyCdrPpxtZhsu6qXAkEwPicl44bI","POSTHOG_WEB_WRITE_KEY is not set");var{captureEvent:Ci,setAnalyticsIdentity:ex,shutdownAnalytics:tx}=sE({writeKey:"phc_WRWd8LYIv6rolgDsyCdrPpxtZhsu6qXAkEwPicl44bI",host:"https://p.momentic.ai",platform:"local_mobile_app",identity:"stashed",flushImmediately:true});var Bd=Router();Bd.patch("/:testPath",je(async(t,e)=>{let r=t.params.testPath;if(!r){e.status(400).json({error:"Missing testPath in path"});return}let n;try{n=x$.parse(t.body);}catch(l){e.status(400).json({error:`Invalid request body: ${l}`});return}if(n.steps===void 0&&n.beforeSteps===void 0&&n.afterSteps===void 0&&n.settings===void 0&&n.labels===void 0){e.status(400).json({error:"At least one of steps, beforeSteps, afterSteps, settings, or labels is required"});return}let o=ht(),i=r.endsWith(".test.yaml")?r:`${r}.test.yaml`,a=await vt(o);await cl({platform:n.platform,filePath:i,steps:n.steps,beforeSteps:n.beforeSteps,afterSteps:n.afterSteps,settings:n.settings,labels:n.labels,folder:o.rootDir,project:o,momenticFiles:a,schemaVersion:dn});let s={message:"ok"};e.status(200).json(s);}));Bd.post("/",je(async(t,e)=>{let r;try{r=A$.parse(t.body);}catch(g){e.status(400).json({error:`Invalid request body: ${g}`});return}let{name:n,description:o,settings:i,pathSegments:a,platform:s}=r;if(!n||typeof n!="string"){e.status(400).json({error:"Missing or invalid 'name' in body"});return}try{_i(n);}catch(g){e.status(400).json({error:W(g)});return}let l=ht(),c=await vt(l),u=fr__default.join(l.rootDir,...a??[]),{fullPath:d,testId:m}=rC({name:n,description:o,settings:i,folder:u,platform:s,project:l,momenticFiles:c});Ci({type:"test_editor:test_create",test_platform:Fi(s)});let p=fr__default.basename(d),f=fr__default.relative(l.rootDir,d),h={id:m,fileName:p,fullPath:d,relativeFilePath:f};e.status(201).json(h);}));Bd.get("/:fileName",je(async(t,e)=>{let r=Wt(),n=an(),o=t.params.fileName;if(!o){e.status(400).json({error:"Missing fileName in path"});return}if(!r){e.status(500).json({error:"API client not initialized"});return}let i=o.endsWith(".test.yaml")?o:`${o}.test.yaml`,a=fr__default.basename(i).replace(".test.yaml",""),s=ht(),l=fr__default.isAbsolute(i)?i:fr__default.join(s.rootDir,i);if(!Sn.existsSync(l)){e.status(404).json({error:"Test not found."});return}let c=await vt(s),u=await dr(l,Tt,c),d=$f.getSessionForTest(u.id),m=d?Tt.child({sessionId:d.metadata.sessionId,testId:u.id,testName:d.metadata.testName}):Tt,p=await Sr(m,r,s,{includeHostingUsername:false});await rn({logger:m,orgId:n,client:r,gitMetadata:p,regenerateCache:false,noCache:false,alwaysSaveCache:false,isolateCachesByEnvironment:s.config?.advanced?.isolateCachesByEnvironment}).resolveEntries({logger:m,platform:u.platform,testId:u.id,environment:u.settings?.defaultEnv,stepLists:{steps:u.steps,...u.beforeSteps&&{beforeSteps:u.beforeSteps},...u.afterSteps&&{afterSteps:u.afterSteps}},useSnapshotIdentityCache:s.config.fileFormat==="v2"});let h={...u,name:a,absoluteFilePath:l};e.status(200).json(h);}));Bd.patch("/:testPath/metadata",je(async(t,e)=>{let r=t.params.testPath;if(!r){e.status(400).json({error:"Missing testPath in path"});return}let n;try{n=M$.parse(t.body);}catch(l){e.status(400).json({error:`Invalid request body: ${l}`});return}let o=ht(),i=r.endsWith(".test.yaml")?r:`${r}.test.yaml`,s={message:"ok",newRelativeTestPath:KK(i,n,o).newRelativeTestPath};e.status(200).json(s);}));Bd.delete("/:testPath",je((t,e)=>{let r=t.params.testPath;if(!r){e.status(400).json({error:"Missing testPath in path"});return}let n=ht(),o=r.endsWith(".test.yaml")?r:`${r}.test.yaml`,i=fr__default.join(n.rootDir,o);if(!Sn.existsSync(i)){e.status(404).json({error:"Test not found."});return}Sn.unlinkSync(i),e.status(200).json({message:"ok"});}));Bd.post("/:testPath/duplicate",je(async(t,e)=>{let{testPath:r}=t.params;if(!r){e.status(400).json({error:"Missing testPath in url path."});return}let n;try{n=L$.parse(t.body);}catch(h){e.status(400).json({error:`Invalid request body: ${h}`});return}try{_i(n.name);}catch(h){e.status(400).json({error:W(h)});return}let o=ht(),i=fr__default.join(o.rootDir,r);if(!Sn.existsSync(i)){e.status(404).json({error:"Test not found."});return}let a=await vt(o),s;try{s=await dr(i,Tt,a);}catch(h){e.status(400).json({error:W(h)});return}let l=bp({projectConfig:o.config,momenticFiles:a,entityType:"mobile-test"}),{stepsToSave:c}=await An({platform:s.platform,stepLists:{steps:s.steps,beforeSteps:s.beforeSteps,afterSteps:s.afterSteps},createNewCacheIds:true}),u=hn({fileType:Ce.MOBILE_TEST,id:l,schemaVersion:dn,description:s.description,platform:s.platform,settings:s.settings,labels:s.labels,...c});LT.parse(u);let d=fr__default.dirname(i),m=fr__default.join(d,`${n.name}.test.yaml`);if(Sn.existsSync(m)){e.status(409).send("A test with this name already exists");return}let p=_g.stringify(u);Sn.writeFileSync(m,p,"utf-8");let f={relativeFilePath:fr__default.relative(o.rootDir,m)};e.status(201).json(f);}));var noe=Bd;var ooe=Router();ooe.get("/:id",je(async(t,e)=>{let{id:r}=t.params;if(!r){e.status(400).json({error:"Missing ID"});return}let n=Wt();if(!n){e.status(500).json({error:"API client not initialized"});return}try{let{data:o,contentType:i}=await n.fetchOnDemandScreenshot(r);e.setHeader("Content-Type",i),e.status(200).send(o);}catch(o){Tt.error({err:o,screenshotId:r},"Failed to proxy on-demand screenshot"),e.status(404).json({error:"Screenshot not found"});}}));var ioe=ooe;var aoe=Router();aoe.get("/",je((t,e)=>{let r=ht(),n={ai:r.config.ai,displayRoot:r.config.displayRoot};e.status(200).json(n);}));var soe=aoe;var loe=Router();loe.post("/traces",je(async(t,e)=>{let r=Wt();if(!r){e.status(500).json({error:"API client not initialized"});return}let n;try{n=z$.parse(t.body);}catch(i){e.status(400).json({error:`Invalid request body: ${i}`});return}let o=await r.getWebStepCacheMemoryTraces(n);e.status(200).json(o);}));var coe=loe;var Hf=class extends vp{constructor(r,n){super(r,n);this.client=r;this.orgId=n;}async fetchEnvironment(r,n){let o=ht();return ed(r,o,P)}};var Gje=promisify$1(execFile$1);async function uoe({managedState:t,project:e,testEntity:r,resolvedTest:n,envName:o}){let{logger:i,sessionId:a}=t,s=Ute(),l=an(),c=Vy(),u=new Tr({apiKey:s,baseUrl:c,logger:i}),d=new Hf(u,l),m=o??n.settings?.defaultEnv,p={};m&&(p=(await d.fetchEnvironment(m,i))?.variables??{});let f={...e.config.emulator,...n.settings?.emulator},h=new Ts({baseUrl:c,apiKey:s,logger:i,mode:"interactive",runner:"mcp"}),g=new dl(e.config.ai?.agentConfig,{baseUrl:c,apiKey:s,logger:i,mode:"interactive",runner:"mcp"}),y=new Ec({baseUrl:c,apiKey:s,logger:i,mode:"interactive"},g),S=new vc({httpClient:u,fakerSeed:e.config.advanced?.fakerConstantSeed?Nm:void 0}),E=new Ui({variablesFromEnvironment:p,envName:m,testName:r.name}),v=new fs({logger:i,reporter:new Tc(u),runType:"mobile-test-run",runId:a,testMetadata:r,isInteractive:true,runner:"mcp"});return {logger:i,sessionId:a,orgId:l,apiClient:u,resolvedEnvName:m,variablesFromEnvironment:p,emulatorSettings:f,mobileGenerator:h,fixtures:{storage:d,browserEnricher:y,browserGenerator:g,localCodeEvalTools:S,testContext:E,visualDiffGoldenStorage:new vs({baseDir:e.rootDir,updateGoldenFiles:false})},aiSettings:{useMemory:true,...e.config.ai,...n.settings?.ai},usageTracker:v}}function qje(t){return {steps:t.steps,beforeSteps:t.beforeSteps,afterSteps:t.afterSteps}}async function rx({platform:t,project:e,logger:r,orgId:n,apiClient:o,resolvedTest:i,envName:a}){let s=qje(i);if(e.config.fileFormat!=="v2")return s;let l=await Sr(r,o,e),{alwaysSaveCache:c,noCache:u}=Ns();return await rn({logger:r,orgId:n,client:o,gitMetadata:l,regenerateCache:false,alwaysSaveCache:c,noCache:u,isolateCachesByEnvironment:e.config?.advanced?.isolateCachesByEnvironment}).resolveEntries({logger:r,platform:t,testId:i.id,environment:a,stepLists:s,useSnapshotIdentityCache:true}),s}async function doe({provider:t,platform:e,emulatorName:r,cleanupDriver:n}){let o=t==="remote";return o&&await KR({emulatorName:r,platform:e}),async()=>{await n(),o&&await YR({emulatorName:r,platform:e});}}async function moe({managedState:t,project:e,testEntity:r,resolvedTest:n,provider:o,envName:i,localAvdId:a,localApkPath:s}){let{logger:l,sessionId:c,orgId:u,apiClient:d,resolvedEnvName:m,variablesFromEnvironment:p,emulatorSettings:f,mobileGenerator:h,fixtures:g,aiSettings:y,usageTracker:S}=await uoe({managedState:t,project:e,testEntity:r,resolvedTest:n,envName:i}),E=n.settings?.defaultChannel,v=n.settings?.defaultTag,w=await rx({platform:"ANDROID",project:e,logger:l,orgId:u,apiClient:d,resolvedTest:n,envName:m}),_=await Kje({provider:o,projectRoot:e.rootDir,emulatorSettings:f,resolvedTest:n,localAvdId:a,localApkPath:s,variablesFromEnvironment:p});l.info({platform:"ANDROID",provider:o,envName:m,emulatorSettings:f,aiSettings:y},"Starting mobile session with resolved configuration");let L=o==="local"?"local":"region"in _?_.region:void 0,I=await Lp({apiClient:d,logger:l,creationOpts:o==="remote"?{..._,apkToInstall:E?{channel:E,tag:v}:void 0}:_,orgId:u,sessionId:c,callbacks:{onStatusUpdate:D=>{l.info({status:D},"Android session status update");}}}),R=await doe({provider:o,emulatorName:I.emulatorName,platform:"ANDROID",cleanupDriver:async()=>{await I.cleanup();}}),k;try{let D="limbarClient"in I?{limbarClient:I.limbarClient,limbarToken:I.limbarToken,limbarUrl:I.limbarUrl,limbarRegion:I.limbarRegion,playwrightDevice:I.playwrightDevice}:void 0;k=await Zc.init({driver:I.driver,generator:h,logger:l,limbarClient:D?.limbarClient,playwrightDevice:D?.playwrightDevice,aiSettings:y,options:{emulator:{...f,region:L,browserSettings:e.config.browser}},fixtures:g,orgId:u,adbPort:I.adbPort,abortController:new AbortController});let V=await k.getViewportBounds(),$=k;return {...t,platform:"ANDROID",provider:o,controller:$,cleanup:[async()=>{await Promise.allSettled([$.cleanup(),R(),g.localCodeEvalTools.dispose()]);}],testName:r.name,relativeTestPath:r.relativePath,testFileAbsolutePath:fr__default.join(e.rootDir,r.relativePath),envName:m,orgId:u,emulatorName:I.emulatorName,viewportBounds:V,adbPort:I.adbPort,tempCaches:{},limbarUrl:D?.limbarUrl,limbarToken:D?.limbarToken,limbarRegion:D?.limbarRegion,usageTracker:S,mutableStepState:{platform:"ANDROID",testId:n.id,stepLists:w}}}catch(D){let V=k?[k.cleanup(),R()]:[R()];throw await Promise.allSettled(V),D}}async function poe({managedState:t,project:e,testEntity:r,resolvedTest:n,provider:o,envName:i,localDeviceId:a,localIosVersion:s,localAppPath:l}){let{logger:c,sessionId:u,orgId:d,apiClient:m,resolvedEnvName:p,variablesFromEnvironment:f,emulatorSettings:h,mobileGenerator:g,fixtures:y,aiSettings:S,usageTracker:E}=await uoe({managedState:t,project:e,testEntity:r,resolvedTest:n,envName:i}),v=n.settings?.defaultChannel,w=n.settings?.defaultTag,_=await rx({platform:"IOS",project:e,logger:c,orgId:d,apiClient:m,resolvedTest:n,envName:p}),L=Yje({provider:o,projectRoot:e.rootDir,emulatorSettings:h,resolvedTest:n,appChannel:v,appTag:w,localDeviceId:a,localIosVersion:s,localAppPath:l,variablesFromEnvironment:f});c.info({platform:"IOS",provider:o,envName:p,emulatorSettings:h,aiSettings:S},"Starting mobile session with resolved configuration");let I=o==="local"?"local":L.type==="remote"?L.region:void 0,R=await Af({apiClient:m,logger:c,creationOpts:L,orgId:d,sessionId:u,callbacks:{onStatusUpdate:V=>{c.info({status:V},"iOS session status update");}}}),k=await doe({provider:o,emulatorName:R.emulator.name,platform:"IOS",cleanupDriver:async()=>{await R.cleanup();}}),D;try{D=await eu.init({driver:R.driver,generator:g,logger:c,emulator:R.emulator,aiSettings:S,options:{emulator:{...h,region:I,browserSettings:e.config.browser}},fixtures:y,orgId:d,abortController:new AbortController});let V=await D.getViewportBounds(),$=D;return {...t,platform:"IOS",provider:o,controller:$,cleanup:[async()=>{await Promise.allSettled([$.cleanup(),k(),y.localCodeEvalTools.dispose()]);}],testName:r.name,relativeTestPath:r.relativePath,testFileAbsolutePath:fr__default.join(e.rootDir,r.relativePath),envName:p,orgId:d,emulatorName:R.emulator.name,viewportBounds:V,tempCaches:{},limbarUrl:R.limbarParams?.webRtcUrl,limbarToken:R.limbarParams?.token,limbarRegion:R.limbarParams?.region,usageTracker:E,mutableStepState:{platform:"IOS",testId:n.id,stepLists:_}}}catch(V){let $=D?[D.cleanup(),k()]:[k()];throw await Promise.allSettled($),V}}async function Kje({provider:t,projectRoot:e,emulatorSettings:r,resolvedTest:n,localAvdId:o,localApkPath:i,variablesFromEnvironment:a}){if(t==="remote")return {region:r?.region==="local"?void 0:r?.region,osVersion:r?.remoteEmulatorSettings?.androidVersion??Am};let s=await Xk(),{avdId:l,apkFilePath:c,apkFilePathSource:u}=Dm({overrideAvdId:o,overrideApkFilePath:i,emulatorSettings:r,defaultApkFilePath:n.settings?.defaultApkFilePath,envVariables:a});if(!l){let d=s.availableAvdIds.length>0?` Known Available AVDs on this machine: ${s.availableAvdIds.join(", ")}.`:"",m=s.avdDiscoveryError?` Failed to list local AVDs: ${s.avdDiscoveryError}.`:"";throw new Error(`AVD ID is required when using a local emulator. Set it on the test (Options -> Emulator -> Local AVD ID), set ${Dl} on the environment, or pass localDeviceId directly.${d}${m}`)}if(s.availableAvdIds.length>0&&!s.availableAvdIds.includes(l))throw new Error(`AVD '${l}' is not available on this machine. Available AVDs: ${s.availableAvdIds.join(", ")}.`);return {avdId:l,apkFilePath:Np({apkFilePath:c,source:u,overrideBaseDir:e})}}function Yje({provider:t,projectRoot:e,emulatorSettings:r,resolvedTest:n,appChannel:o,appTag:i,localDeviceId:a,localIosVersion:s,localAppPath:l,variablesFromEnvironment:c}){if(t==="remote")return {type:"remote",region:r?.region==="local"?void 0:r?.region,appToInstall:o?{channel:o,tag:i}:void 0,osVersion:Rm};let{deviceType:u,iosVersion:d,appFilePath:m,appFilePathSource:p}=Lm({overrideDeviceType:a,overrideIosVersion:s,overrideAppFilePath:l,emulatorSettings:r,defaultAppFilePath:n.settings?.defaultAppFilePath,envVariables:c});if(!u)throw new Error(`A device type is required when using a local region. Pass localDeviceId, configure a default local iOS device type on the test's settings, or set the ${Ll} key on the environment.`);return {type:"local",deviceType:u,iosVersion:d,appFilePath:Df({appFolderPath:m,source:p,overrideBaseDir:e})}}async function Xk(){try{let{stdout:t}=await Gje(Xje(),["-list-avds"],{encoding:"utf8",timeout:5e3});return {availableAvdIds:t.split(/\r?\n/).map(r=>r.trim()).filter(Boolean)}}catch(t){return {availableAvdIds:[],avdDiscoveryError:W(t)}}}function Xje(){let t=process.platform==="win32"?"emulator.exe":"emulator";return process.env.ANDROID_HOME?fr__default.join(process.env.ANDROID_HOME,"emulator",t):t}var foe=5,Jk=class extends $A{isStartingSession=false;constructor(){super({sessionTypeLabel:"mobile MCP session"});}async kill(e,r){try{let n;for(let i of e.cleanup)try{await i();}catch(a){n??=a;}if(n)throw n;await e.usageTracker.flush(e.logger);let o=Lee(e);return await ete({apiClient:Wt(),logger:e.logger,orgId:e.orgId,testId:e.testId,sessionId:e.sessionId,reason:r,report:o}),e.logger.info({sessionId:e.sessionId,reason:r,emulatorName:e.emulatorName},"MCP session cleaned up"),{killed:!0,sessionId:e.sessionId,reason:r,report:o}}catch(n){return e.logger.error({err:n,sessionId:e.sessionId,reason:r},"Failed to clean up mobile MCP session"),{killed:false,sessionId:e.sessionId,reason:r}}}touchSession(e){let r=super.touchSession(e);return r?.provider==="remote"&&Wt()?.extendEmulatorTtl(r.platform,r.emulatorName).catch(()=>{}),r}async createSession({logger:e,testId:r,idleTimeoutMs:n,provider:o,envName:i,localDeviceId:a,localIosVersion:s,localAppPath:l,project:c}){let u=this.listSessionIds();if(this.isStartingSession||u.length>0)throw new Error(JSON.stringify({message:"Another mobile MCP session is already active or starting. Please terminate the existing session before creating a new one.",activeSessionIds:u},null,2));this.isStartingSession=true;let d;try{let{entity:m,momenticFiles:p}=await Es(c,{id:r},"mobileTests"),f=await dr(m.fullFilePath,e,p),y=(f.settings?.emulator?.region??c.config.emulator?.region)==="local"?"local":"remote",S=o??y,E,{platform:v}=f,w=e.child({testId:f.id});switch(v){case "ANDROID":d=this.buildManagedSessionState({logger:w,idleTimeoutMs:n,testId:m.id}),E=await moe({managedState:d,project:c,testEntity:m,resolvedTest:f,provider:S,envName:i,localAvdId:a,localApkPath:l});break;case "IOS":d=this.buildManagedSessionState({logger:w,idleTimeoutMs:n,testId:m.id}),E=await poe({managedState:d,project:c,testEntity:m,resolvedTest:f,provider:S,envName:i,localDeviceId:a,localIosVersion:s,localAppPath:l});break;default:return _t(v)}return w.info({sessionId:E.sessionId,testId:f.id},"Started MCP session for test"),E}catch(m){throw d&&clearTimeout(d.timeoutHandle),m}finally{this.isStartingSession=false;}}},so=new Jk,ru=({response:t,sessionId:e,toolName:r})=>{let n=so.touchSession(e);if(n)return t.addCleanupCallback(()=>{Qee({session:n,toolCallId:t.toolCallId});}),Zee({session:n,toolCallId:t.toolCallId,toolName:r}),n;t.addError(JSON.stringify({message:`No active session found for id '${e}'.`,availableSessionIds:so.listSessionIds()},null,2));};var Zje=4e4,Qje=1e4,Qk,goe=({staticDir:t})=>{Qk=t;},nx=class t{url;server;constructor({url:e,server:r}){this.url=e,this.server=r;}static async init({logger:e,testId:r,testName:n,sessionId:o,platform:i,limbarUrl:a,limbarToken:s,limbarRegion:l,tabLabel:c}){let u=await nHe({logger:e,assets:eHe()}),d=new URL(`http://localhost:${u.port}/`);return d.searchParams.set("testId",r),n&&d.searchParams.set("testName",n),d.searchParams.set("sessionId",o),d.searchParams.set("platform",i),d.searchParams.set("url",a),d.searchParams.set("token",s),l&&d.searchParams.set("region",l),c&&d.searchParams.set("tabLabel",c),new t({url:d.toString(),server:u})}async shutdown(){this.server?.server.listening&&(await new Promise(e=>{this.server?.server.close(()=>{e();});}),this.server=void 0);}};function eHe(){if(!Qk)throw new Error("Remote control viewer static directory is not configured. Pass remoteControlStaticDir when starting the mobile MCP server.");let t=fr__default.resolve(Qk),e=fr__default.join(t,"index.html");if(!Sn.existsSync(e))throw new Error(`Remote control viewer index file not found at '${e}'. Ensure mobile-remote-control-frontend is built and copied into npm/mobile-cli/remote-control-static.`);return {staticDir:t,indexHtmlBuffer:Sn.readFileSync(e)}}function Zk({response:t,statusCode:e,body:r,allow:n}){let o={"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-store"};n&&(o.Allow=n),t.writeHead(e,o),t.end(r);}function hoe({request:t,response:e,buffer:r,contentType:n}){if(e.writeHead(200,{"Content-Type":n,"Cache-Control":"no-store"}),t.method==="HEAD"){e.end();return}e.end(r);}function tHe({staticDir:t,pathname:e}){let r;try{r=decodeURIComponent(e);}catch{return}let n=r==="/"?"index.html":r.replace(/^\/+/,""),o=fr__default.resolve(t,n),i=fr__default.relative(t,o);if(!(i.startsWith("..")||fr__default.isAbsolute(i)))return o}function rHe({request:t,response:e,assets:r}){if(t.method!=="GET"&&t.method!=="HEAD"){Zk({response:e,statusCode:405,body:"Method Not Allowed",allow:"GET, HEAD"});return}let n=new URL(t.url??"/","http://localhost").pathname;if(n==="/"||n==="/index.html"){hoe({request:t,response:e,buffer:r.indexHtmlBuffer,contentType:"text/html; charset=utf-8"});return}let o=tHe({staticDir:r.staticDir,pathname:n});if(!o){Zk({response:e,statusCode:403,body:"Forbidden"});return}if(!Sn.existsSync(o)||!Sn.statSync(o).isFile()){Zk({response:e,statusCode:404,body:"Not Found"});return}let i=fr__default.extname(o).toLowerCase(),a=Mu[i]??"application/octet-stream";hoe({request:t,response:e,buffer:Sn.readFileSync(o),contentType:a});}async function nHe({logger:t,assets:e}){let r=createServer((i,a)=>rHe({request:i,response:a,assets:e})),n=Math.floor(Math.random()*Qje)+Zje,o=await ic(n,"mobile-mcp-remote-control-viewer");return await new Promise((i,a)=>{let s=l=>{a(l);};r.once("error",s),r.listen(o,()=>{r.off("error",s),i();});}),t.info({port:o,staticDir:e.staticDir},"Started mobile MCP remote control viewer server"),{port:o,server:r}}function eF({logger:t,applicationName:e,cliVersion:r,serverId:n=randomUUID()}){let o={serverId:n,applicationName:e,cliVersion:r},i=an(),a=t.child({orgId:i,userId:_d(),...o});return {info:o,mcpLogger:a,orgId:i}}function tF({sessionIdleTimeoutMinutes:t}){return (t&&t>=1?t:foe)*60*1e3}async function ox({project:t,serverUrl:e,alwaysSaveCache:r,noCache:n,remoteControlStaticDir:o}){goe({staticDir:o}),Cf(e),uR({alwaysSaveCache:r,noCache:n}),ex({userId:_d(),orgId:an(),selfServe:mR()}),pR(t,i=>hi({configFilePath:i}));}function ix({project:t,logger:e,apiKey:r,serverUrl:n,supportsFileOutput:o,headfulDefault:i,sessionIdleTimeoutMinutes:a,applicationName:s,cliVersion:l,serverId:c}){let{info:u,mcpLogger:d,orgId:m}=eF({logger:e,applicationName:s,cliVersion:l,serverId:c}),p=new Ts({baseUrl:n,apiKey:r,logger:d,mode:"interactive",runner:"mcp"});return {context:{project:t,orgId:m,logger:d,generator:p,serverId:u.serverId,saveChangesToDisk:true,sessionIdleTimeoutMs:tF({sessionIdleTimeoutMinutes:a}),supportsFileOutput:o,headfulDefault:i},info:u}}async function sHe({moduleId:t,name:e,description:r,enabled:n,platform:o,parameters:i,steps:a,project:s}){let l=await vt(s),{stepsToSave:{steps:c}}=await An({platform:o,stepLists:{steps:a}});bs({content:{platform:o,moduleId:t,name:e,description:r,enabled:n,parameters:i,steps:c},schemaVersion:dn,momenticFiles:l,project:s});}function lHe({module:t,inputs:e}){return {...t,id:randomUUID(),type:"RESOLVED_MOBILE_MODULE",inputs:e}}async function boe({project:t,logger:e,testPath:r,saveChangesToDisk:n,mutableStepState:o,params:i,initialMomenticFiles:a,platform:s,availableSteps:l,cacheContext:c}){let{stepsToExtract:u,startIndex:d,endIndex:m}=nte({moduleName:i.name,existingModuleNames:Object.values(a.mobileModules).map(h=>h.name),parameterNames:i.parameters?.parameterNames,defaultParameters:i.parameters?.defaultParameters,parameterEnums:i.parameters?.parameterEnums,moduleInputs:i.moduleInputs,testPath:r,startIndex:i.startIndex,endIndex:i.endIndex,availableSteps:l,containsNestedModuleStep:P3}),p=fr__default.join(t.rootDir,i.folderPath??"");i.folderPath&&Sn.mkdirSync(p,{recursive:true});let f=await sb({name:i.name,platform:s,description:i.description??"",enabled:i.enabled??true,steps:u,folder:p,project:t,momenticFiles:a});if(i.parameters!==void 0&&(await sHe({moduleId:f.moduleId,name:i.name,description:i.description??"",enabled:i.enabled??true,platform:s,parameters:i.parameters,steps:u,project:t}),f={...f,name:i.name,description:i.description??"",parameters:i.parameters}),n&&i.startIndex!==void 0&&r!==void 0){let h=await vt(t);if(!l)throw new Error("Mobile module was created successfully, but the source test steps were not available for replacement.");let g=lHe({module:f,inputs:i.moduleInputs}),y=[...l];if(y.splice(d,m-d,g),await cl({platform:s,filePath:r,steps:y,folder:t.rootDir,project:t,momenticFiles:h,schemaVersion:dn}),o&&(o.stepLists={...o.stepLists,steps:y}),c){let{cachesToSave:S,snapshotCachesToSave:E}=await An({platform:s,stepLists:{steps:y},cacheCreationParams:{orgId:c.orgId,testId:c.testId,environment:c.envName},useSnapshotIdentityCache:c.useSnapshotIdentityCache});try{await c.cacheStorage.saveEntries({platform:s,logger:e,entries:S});}catch(v){e.warn({err:v},"Failed to save mobile step caches after module create, future runs may be slower");}if(c.useSnapshotIdentityCache)try{await c.cacheStorage.saveSnapshotCacheEntries({platform:s,logger:e,entries:E});}catch(v){e.warn({err:v},"Failed to save mobile snapshot identity cache after module create, future runs may regenerate step ids");}}}return f}function yoe(t,e,r){if(!t)return {availableSteps:void 0,mutableStepState:void 0};if(t.platform!==e)throw new Error(`Internal error: test platform ${t.platform} does not match resolved platform ${e}`);return r&&r.testId===t.id&&r.platform===e?{availableSteps:r.stepLists.steps,mutableStepState:r}:{availableSteps:t.steps,mutableStepState:void 0}}async function Toe({project:t,logger:e,testPath:r,saveChangesToDisk:n,mutableStepState:o,params:i}){_i(i.name);let a=await vt(t),s=r!==void 0?await dr(fr__default.join(t.rootDir,r),e,a):void 0,l=s?.platform??i.platform??"ANDROID";if(i.platform&&l!==i.platform)throw new Error(`Error: Requested module platform ${i.platform} does not match source test platform ${s?.platform}.`);let c;if(s!==void 0){let d=Wt();if(d){let m=await Sr(e,d,t),{alwaysSaveCache:p,noCache:f}=Ns();c={cacheStorage:rn({logger:e,orgId:an(),client:d,gitMetadata:m,regenerateCache:false,alwaysSaveCache:p,noCache:f,isolateCachesByEnvironment:t.config?.advanced?.isolateCachesByEnvironment}),testId:s.id,orgId:an(),envName:s.settings?.defaultEnv,useSnapshotIdentityCache:t.config.fileFormat==="v2"};}}let u={project:t,logger:e,testPath:r,saveChangesToDisk:n,params:i,initialMomenticFiles:a,cacheContext:c};switch(l){case "ANDROID":return {module:await boe({...u,platform:"ANDROID",...yoe(s,"ANDROID",o)})};case "IOS":return {module:await boe({...u,platform:"IOS",...yoe(s,"IOS",o)})};default:return _t(l)}}var Eoe=Un({schema:{name:$S,description:"Get a single fully loaded mobile module by id, exact name, or file path. This returns complete module details including parameters, description, and the full step list. Exactly one selector must be provided.",inputSchema:z.object({selector:nU})},handle:async(t,e,r)=>{let{project:n,logger:o}=t;try{let i=await Es(n,e.selector,"mobileModules"),a=await nd(i.entity,i.momenticFiles,o);r.addPartFromText(JSON.stringify({module:a},null,2));}catch(i){r.addError(W(i));}}}),voe=Un({schema:{name:eU,description:"Create a mobile module. If startIndex is provided, testPath is required and the specified mobile test range is extracted into a module for that test's platform, then replaced with a module invocation in that test. For empty modules, platform defaults to Android unless platform or testPath identifies iOS.",inputSchema:DP},handle:async(t,e,r)=>{try{let n=DP.parse(e),{testPath:o,...i}=n,a=fX({projectRoot:t.project.rootDir,filePath:o,pathLabel:"testPath"}),s;if(a!==void 0){let c=fr__default.join(t.project.rootDir,a);for(let u of so.listSessionIds()){let d=so.getSession(u);if(d!==void 0&&d.testFileAbsolutePath===c){s=d.mutableStepState;break}}}let l=await Toe({project:t.project,logger:t.logger,testPath:a,saveChangesToDisk:t.saveChangesToDisk,mutableStepState:s,params:i});r.addPartFromText(JSON.stringify(l.module,null,2));}catch(n){r.addError(W(n));}}});function ax({step:t,parentChain:e}){let r=t;r.parentStepIdChain=e.map(n=>n.id),delete r.retries,delete r.skipped;}function pHe(t){let e=cloneDeep(t);return Bo({steps:e,earlyStop:false,onPreset:(r,n)=>{if(ax({step:r,parentChain:n.parentChain}),r.type==="MOBILE_PRESET_STEP"){let o=r.command;delete o.cache,delete o.id,delete o.thoughts;}return false},onModule:(r,n)=>{ax({step:r,parentChain:n.parentChain});let o=r;return delete o.enabled,delete o.schemaVersion,false},onConditional:(r,n)=>(ax({step:r,parentChain:n.parentChain}),false),onAiAction:(r,n)=>{ax({step:r,parentChain:n.parentChain});let o=r;return delete o.cache,false}}),e.map((r,n)=>{let o=r;return o.index=n,o})}function rF(t,e){if(t.length===0)return `${e}: (no steps)`;let r=["```json",JSON.stringify(pHe(t),null,2),"```"].join(`
|
|
6239
6239
|
`);return `${e}:
|
|
6240
6240
|
${r}`}var fHe=`## Note
|
|
6241
6241
|
The "Installed apps" list may still include default or system packages; it is a best-effort view, not a guarantee of user-installed apps only. `;async function hHe({project:t,testFileAbsolutePath:e,supportsFileOutput:r,platform:n,description:o,activeStepLists:i}){let a=[];a.push(`Name: ${fr__default.basename(e,".test.yaml")}`),a.push(`Platform: ${n}`),o&&a.push(`Description: ${o}`),a.push("");let s=i.beforeSteps??[],l=i.afterSteps??[];s.length>0&&(a.push(rF(s,"Setup Steps")),a.push("")),a.push(rF(i.steps,"Main Steps")),l.length>0&&(a.push(""),a.push(rF(l,"Teardown Steps")));let c=a.join(`
|
|
@@ -6253,7 +6253,7 @@ The "Installed apps" list may still include default or system packages; it is a
|
|
|
6253
6253
|
for /f "tokens=5" %a in ('netstat -ano ^| findstr :${t}') do taskkill /PID %a /F
|
|
6254
6254
|
`);}PMe("phc_WRWd8LYIv6rolgDsyCdrPpxtZhsu6qXAkEwPicl44bI","POSTHOG_WEB_WRITE_KEY is not set");var{captureEvent:oS,setAnalyticsIdentity:rie,shutdownAnalytics:nie}=sE({writeKey:"phc_WRWd8LYIv6rolgDsyCdrPpxtZhsu6qXAkEwPicl44bI",host:"https://p.momentic.ai",platform:"mobile_cli",identity:"stashed",flushImmediately:true,onIdentify:h8});async function oie({project:t,logger:e}){let r=await vt(t),n=Object.values(r.mobileTests),o=0,i=new Set,a=[];for(let s of n)try{await dr(s.fullFilePath,e,r);}catch(l){e.error(`Failed to parse mobile test ${s.name} (${s.relativePath})`),dv(l,s.relativePath,a),o++,i.add(s.relativePath);}return {parsingErrors:o,parsingErrorDetails:a,failedTestFilePaths:i}}async function iie({project:t,filePath:e}){let r={totalErrors:0,parsingErrors:0,parsingErrorDetails:[],failedTestFilePaths:new Set,failedModuleFilePaths:new Set},n=await vt(t);if(e!==void 0)return await WHe({project:t,momenticFiles:n,filePath:e,state:r}),r;for(let o of Object.values(n.mobileModules))await sie({momenticFiles:n,module:o,state:r});for(let o of Object.values(n.mobileTests))await aie({momenticFiles:n,test:o,state:r});for(let o of n.metadataParseFailures)uie({failure:o,state:r});return GHe({momenticFiles:n,state:r}),qHe({momenticFiles:n,state:r}),r}function cF(t,e,r){t.totalErrors++,e==="test"?t.failedTestFilePaths.add(r):t.failedModuleFilePaths.add(r);}async function WHe({project:t,momenticFiles:e,filePath:r,state:n}){let o=fr__default.isAbsolute(r)?r:fr__default.resolve(t.rootDir,r),i=fr__default.relative(t.rootDir,o);if(i.startsWith("..")||fr__default.isAbsolute(i)){P.error(`File '${r}' is outside the resolved project at '${t.rootDir}'. Lint a file inside the project, or run without an argument to lint the whole project.`),n.totalErrors++;return}let a=Object.values(e.mobileTests).find(c=>c.fullFilePath===o);if(a){await aie({momenticFiles:e,test:a,state:n});return}let s=Object.values(e.mobileModules).find(c=>c.fullFilePath===o);if(s){await sie({momenticFiles:e,module:s,state:n});return}let l=e.metadataParseFailures.find(c=>c.fullPath===o);if(l){uie({failure:l,state:n});return}P.error(`File '${r}' is not a recognized Momentic mobile test or module. Check the 'include' globs in your momentic.config.yaml.`),n.totalErrors++;}async function aie({momenticFiles:t,test:e,state:r}){if(e.type!==Ce.MOBILE_TEST_V2)return;lie({kind:"test",name:e.name,relativePath:e.relativePath,id:e.id,state:r});let{parsed:n}=Gi(e.fullFilePath);try{let o=Xl.parse(n),i=$m(o.platform);await Yv({testV2:o,platform:i,fileResolver:Qu({sourceFilePath:e.fullFilePath,momenticFiles:{mobileModules:t.mobileModules}})});}catch(o){cie({err:o,kind:"test",relativePath:e.relativePath,state:r});}}async function sie({momenticFiles:t,module:e,state:r}){if(e.type!==Ce.MOBILE_MODULE_V2)return;lie({kind:"module",name:e.name,relativePath:e.relativePath,id:e.id,state:r});let{parsed:n}=Gi(e.fullFilePath);try{Xv({moduleV2:n,moduleName:e.name,fileResolver:Qu({sourceFilePath:e.fullFilePath,momenticFiles:{mobileModules:t.mobileModules}})});}catch(o){cie({err:o,kind:"module",relativePath:e.relativePath,state:r});}}function lie({kind:t,name:e,relativePath:r,id:n,state:o}){if(Vr.safeParse(n).success)return;let i=t==="test"?"Mobile test":"Mobile module";P.error(`${i} '${e}' (${r}) has an invalid ID: '${n}'. IDs must be kebab-case or a UUID, up to 36 characters.`),cF(o,t,r);}function cie({err:t,kind:e,relativePath:r,state:n}){if(cF(n,e,r),n.parsingErrors++,!dv(t,r,n.parsingErrorDetails)){if(t instanceof z.ZodError){uv(t.issues,r,n.parsingErrorDetails);return}n.parsingErrorDetails.push({file:r,field:"",issue:W(t)});}}function uie({failure:t,state:e}){cF(e,t.kind,t.relativePath),e.parsingErrors++,uv(t.issues,t.relativePath,e.parsingErrorDetails);}function GHe({momenticFiles:t,state:e}){let r=new Set(Object.values(t.mobileModules).map(o=>o.fullFilePath)),n=new Set(Object.values(t.mobileTests).map(o=>o.fullFilePath));for(let[o,i]of Object.entries(t.duplicateEntities)){let a=i.filter(s=>r.has(s)||n.has(s));if(!(a.length<2)){P.error(`Duplicate ID '${o}' found in the following mobile files:
|
|
6255
6255
|
${a.map(s=>` - ${s}`).join(`
|
|
6256
|
-
`)}`),e.totalErrors++;for(let s of a){let l=fr__default.relative(t.project.rootDir,s);r.has(s)?e.failedModuleFilePaths.add(l):e.failedTestFilePaths.add(l);}}}}function qHe({momenticFiles:t,state:e}){for(let[r,n]of Object.entries(t.mobileTests)){let o=t.mobileModules[r];o&&(P.error(`ID '${r}' is shared between mobile test '${n.relativePath}' and mobile module '${o.relativePath}'. Test and module IDs must be unique across the entire project.`),e.totalErrors++,e.failedTestFilePaths.add(n.relativePath),e.failedModuleFilePaths.add(o.relativePath));}}async function die({project:t,filePath:e}){let{totalErrors:r,parsingErrors:n,parsingErrorDetails:o,failedTestFilePaths:i,failedModuleFilePaths:a}=await iie({project:t,filePath:e});if(r===0){P.success("Mobile lint passed. No issues found.");return}o.length>0&&mv({parsingErrors:n,parsingErrorDetails:o,failedTestFilePaths:i,failedModuleFilePaths:a,rootDir:t.rootDir}),P.error(`Found ${r} mobile lint error${r===1?"":"s"} in project.`),process.exit(1);}async function uF({project:t}){if(t.config.fileFormat==="v2"){let{totalErrors:o,parsingErrors:i,parsingErrorDetails:a,failedTestFilePaths:s,failedModuleFilePaths:l}=await iie({project:t});i>0&&(mv({parsingErrors:i,parsingErrorDetails:a,failedTestFilePaths:s,failedModuleFilePaths:l,rootDir:t.rootDir}),process.exit(1)),o>0&&(P.error(`Found ${o} lint errors`),P.warn("Run 'npx momentic-mobile lint' for details"),process.exit(1));return}let{parsingErrors:e,parsingErrorDetails:r,failedTestFilePaths:n}=await oie({project:t,logger:P});e>0&&(mv({parsingErrors:e,parsingErrorDetails:r,failedTestFilePaths:n,rootDir:t.rootDir}),process.exit(1));}async function mF({tests:t,momenticFiles:e,project:r,yes:n,include:o,exclude:i,labels:a,logger:s,quarantinedTestsMetadata:l}){let c=new Set;if(t&&t.length>0){let d=t.some(p=>Sn.existsSync(p)),m=cwd();d?(m!==r.rootDir&&s.warn(`Test paths resolve against the current directory ('${m}'), not the project root ('${r.rootDir}'). Run from the project root or use substring filters to avoid surprises.`),t.forEach(p=>{if(!Sn.existsSync(p))throw new Error(`Path '${p}' does not exist.`);let f,h;try{f=Sn.statSync(p),h=f.isDirectory();}catch(y){s.warn({err:y},`Skipping path ${p} because it cannot be read`);return}let g=fr__default.resolve(p);Object.values(e.mobileTests).filter(y=>h?y.fullFilePath.startsWith(g):y.fullFilePath===g).forEach(y=>{c.add(y.fullFilePath);});})):Object.values(e.mobileTests).forEach(p=>{t.some(f=>p.relativePath.includes(f))&&c.add(p.fullFilePath);});}else !n&&!await Jl("No test paths or substrings were provided. Do you want to run all tests?")&&(s.error("Cancelled by user."),process.exit(1)),Object.values(e.mobileTests).forEach(m=>{c.add(m.fullFilePath);});for(let d of Array.from(c)){let m=fr__default.relative(r.rootDir,d);o&&!o.some(p=>new RegExp(p).test(m))&&c.delete(d),i&&i.some(p=>new RegExp(p).test(m))&&c.delete(d);}return (await Promise.all(Array.from(c).map(async d=>{try{let m=fr__default.relative(r.rootDir,d),p=await dr(d,s,e),f=fr__default.basename(d,".test.yaml");if(p.disabled)return null;if(a&&a.length>0){let g=p.labels||[];if(!a.some(S=>g.includes(S)))return null}let h={id:p.id,name:f,description:p.description,schemaVersion:p.schemaVersion,settings:p.settings,fullFilePath:d,relativeFilePath:m,quarantined:!!l[p.id],quarantinedMetadata:l[p.id],labels:p.labels};switch(p.platform){case "ANDROID":return {...h,platform:"ANDROID",steps:p.steps,beforeSteps:p.beforeSteps,afterSteps:p.afterSteps};case "IOS":return {...h,platform:"IOS",steps:p.steps,beforeSteps:p.beforeSteps,afterSteps:p.afterSteps};default:return (y=>{throw new Error("You missed a case in the switch above")})(p)}}catch(m){s.error(`Failed to read and resolve mobile test at '${d}': ${m}`),process.exit(1);}}))).filter(d=>!!d)}function mie({testDefinitions:t,quarantinedTestsMetadata:e,onlyQuarantined:r=false,skipQuarantined:n=false}){let[o,i]=partition(t,a=>a.id in e);return {quarantinedTestsToSkip:n?o:[],testsToRun:r?[]:i,quarantinedTestsToRun:n?[]:o}}var pie=()=>process.exit(130),fie=()=>process.exit(143);process.on("SIGINT",pie);process.on("SIGTERM",fie);function hie(){process.off("SIGINT",pie),process.off("SIGTERM",fie);}async function pF({project:t,apiClient:e,gitMetadata:r,orgId:n,dryRun:o=false}){let i=await vt(t),a=Object.values(i.mobileTests).filter(g=>g.type===Ce.MOBILE_TEST),s=Object.values(i.mobileModules).filter(g=>g.type===Ce.MOBILE_MODULE),l=Object.values(i.mobileTests).filter(g=>g.type===Ce.MOBILE_TEST_V2).length,c=Object.values(i.mobileModules).filter(g=>g.type===Ce.MOBILE_MODULE_V2).length,u={...tD(),alreadyV2TestCount:l,alreadyV2ModuleCount:c},d=t.config.fileFormat!=="v2",{v2ProjectConfig:m,migratedFilePaths:p}=W9(t);!o&&a.length>0&&await JHe({legacyMobileTests:a,momenticFiles:i,project:t,apiClient:e,gitMetadata:r,orgId:n}),await ZHe({legacyMobileModules:s,momenticFiles:i,project:t,v2ProjectConfig:m,migratedFilePaths:p,summary:u,dryRun:o}),await tWe({legacyMobileTests:a,momenticFiles:i,project:t,v2ProjectConfig:m,migratedFilePaths:p,summary:u,dryRun:o});let f=u.migratedTestPaths.length>0||u.migratedModulePaths.length>0;return !o&&(d||f)&&QO({project:t,newProjectConfig:m,fileFormatLabel:"v2",migratedFilePaths:p}),u}async function gie({project:t,apiClient:e,gitMetadata:r}){let{legacyProjectConfig:n,migratedFilePaths:o}=G9(t),i=await vt(t),a=Object.values(i.mobileTests).filter(c=>c.type===Ce.MOBILE_TEST_V2),s=Object.values(i.mobileModules).filter(c=>c.type===Ce.MOBILE_MODULE_V2);P.info(`Migrating ${a.length} simplified format mobile tests and ${s.length} simplified format mobile modules to legacy YAML`);let l=new Set;await QHe({v2MobileTests:a,momenticFiles:i,project:t,legacyProjectConfig:n,migratedFilePaths:o,apiClient:e,gitMetadata:r,modulesCoveredByTests:l}),await eWe({v2MobileModules:s,momenticFiles:i,project:t,legacyProjectConfig:n,migratedFilePaths:o,modulesCoveredByTests:l}),QO({project:t,newProjectConfig:n,fileFormatLabel:"legacy",migratedFilePaths:o});}async function JHe({legacyMobileTests:t,momenticFiles:e,project:r,apiClient:n,gitMetadata:o,orgId:i}){if(t.length===0)return;let a={logger:P,orgId:i,client:n,regenerateCache:false,alwaysSaveCache:true,noCache:false,isolateCachesByEnvironment:r.config.advanced?.isolateCachesByEnvironment??false,bustOldestCachePercentage:void 0},s=[rn({...a,gitMetadata:o})];o.gitMainBranch&&o.gitBranchName!==o.gitMainBranch&&s.push(rn({...a,gitMetadata:{...o,gitBranchName:o.gitMainBranch,gitCommitTimestamp:o.lastCommitOnMainTimestamp??o.gitCommitTimestamp}})),P.info(`Pushing mobile test snapshots for ${t.length} legacy mobile tests so existing step caches survive the simplified format conversion`),await Mp(t,xp,async l=>{let c=await dr(l.fullFilePath,P,e),{snapshotCachesToSave:u}=await An({platform:c.platform,stepLists:{steps:c.steps,beforeSteps:c.beforeSteps,afterSteps:c.afterSteps},useSnapshotIdentityCache:true,cacheCreationParams:{orgId:i,testId:c.id,environment:void 0}});for(let d of s)await d.saveSnapshotCacheEntries({logger:P,platform:c.platform,entries:u});P.dimmed(`Pushed mobile test snapshot for: ${l.relativePath}`);});}async function ZHe({legacyMobileModules:t,momenticFiles:e,project:r,v2ProjectConfig:n,migratedFilePaths:o,summary:i,dryRun:a}){await Mp(t,xp,async s=>{let l=pc(s.fullFilePath,P);if(Qg(l))throw new Error(`Expected a legacy mobile module while migrating '${s.relativePath}', but found the simplified format`);let c=fc({module:l,moduleFilePath:s.fullFilePath,momenticFiles:e}),u=rs.parse(c),d={...u,name:c.name??s.name,steps:ha(u.platform).array().parse(c.steps)};a||bs({content:d,schemaVersion:dn,momenticFiles:e,project:{...r,config:n},forceSaveOnNoDiffs:true}),o.push(s.fullFilePath),i.migratedModulePaths.push(s.fullFilePath),P.dimmed(` + ${s.relativePath}`);});}async function QHe({v2MobileTests:t,momenticFiles:e,project:r,legacyProjectConfig:n,migratedFilePaths:o,apiClient:i,gitMetadata:a,modulesCoveredByTests:s}){await Mp(t,xp,async l=>{let c=await dr(l.fullFilePath,P,e),u=await nWe({platform:c.platform,stepLists:{steps:c.steps,beforeSteps:c.beforeSteps,afterSteps:c.afterSteps},apiClient:i,gitMetadata:a,testId:c.id,environment:void 0,missingSnapshotMessage:`Could not restore legacy step ids for '${l.fullFilePath}' because no mobile snapshot cache was found for test '${c.id}'. Run the simplified format migration before undoing it.`}),{moduleUpdates:d}=await An({platform:c.platform,stepLists:u});for(let m of d)s.add(m.moduleId);await cl({platform:c.platform,filePath:l.fullFilePath,steps:u.steps,beforeSteps:u.beforeSteps,afterSteps:u.afterSteps,settings:c.settings,labels:c.labels,folder:r.rootDir,project:{...r,config:n},momenticFiles:e,schemaVersion:dn,forceFileFormat:"v1"}),o.push(l.fullFilePath),P.dimmed(`Migrated simplified format mobile test to legacy: ${l.relativePath}`);});}async function eWe({v2MobileModules:t,momenticFiles:e,project:r,legacyProjectConfig:n,migratedFilePaths:o,modulesCoveredByTests:i}){await Mp(t,xp,async a=>{if(i.has(a.id)){o.push(a.fullFilePath);return}let s=pc(a.fullFilePath,P),l=fc({module:s,moduleFilePath:a.fullFilePath,momenticFiles:e}),c=rs.parse(l),u={...c,name:l.name??a.name,steps:ha(c.platform).array().parse(l.steps)};bs({content:u,schemaVersion:dn,momenticFiles:e,project:{...r,config:n},forceSaveOnNoDiffs:true,forceFileFormat:"v1"}),o.push(a.fullFilePath),P.dimmed(`Migrated unreferenced simplified format mobile module to legacy: ${a.relativePath}`);});}async function tWe({legacyMobileTests:t,momenticFiles:e,project:r,v2ProjectConfig:n,migratedFilePaths:o,summary:i,dryRun:a}){await Mp(t,xp,async s=>{let l=await dr(s.fullFilePath,P,e);a||await cl({platform:l.platform,filePath:s.fullFilePath,steps:l.steps,beforeSteps:l.beforeSteps,afterSteps:l.afterSteps,settings:l.settings,labels:l.labels,folder:r.rootDir,project:{...r,config:n},momenticFiles:e,schemaVersion:dn}),o.push(s.fullFilePath),i.migratedTestPaths.push(s.fullFilePath),P.dimmed(` + ${s.relativePath}`);});}async function rWe({apiClient:t,gitMetadata:e,testId:r,platform:n,environment:o}){let i=await t.getSnapshotCacheForTest({testId:r,environment:o,platform:n==="ANDROID"?"android":"ios"},_u(e));return Uv({entries:i,logger:P})}async function nWe({platform:t,stepLists:e,apiClient:r,gitMetadata:n,testId:o,environment:i,missingSnapshotMessage:a}){let s=await rWe({apiClient:r,gitMetadata:n,testId:o,platform:t,environment:i});s.testStepLists||P.warn(`${a} Minting fresh legacy ids.`);let l=zv({currentStepLists:e,previousSnapshots:s,generateUuid:randomUUID});return l.stats.mintedSteps>0&&P.warn(`Restored legacy mobile YAML with ${l.stats.mintedSteps} newly generated step ids because some steps did not match the snapshot cache.`),l.stepLists}var bie=58890;function zd(t){let e=parseInt(t,10);if(isNaN(e))throw new InvalidArgumentError("Not a number.");return e}function aWe(t){if(t.toUpperCase()==="AUTO")return "AUTO";let e=Number(t);if(isNaN(e))throw new InvalidArgumentError("Not a number or AUTO.");if(!Number.isInteger(e))throw new InvalidArgumentError("Not a number or AUTO.");if(e<=0)throw new InvalidArgumentError("Not a number or AUTO.");return e}var yie=new Option("--port <port>",`Port to run the local app on. Defaults to ${bie}.`).env("PORT").default(bie).argParser(zd),wi=new Option("--api-key <key>","Momentic API key").env("MOMENTIC_API_KEY").default(TC(),"value from ~/.momentic/auth.json").argParser(t=>{if(!t)throw new InvalidArgumentError("API key is required. Run `npx @momentic/wizard@latest login` or set MOMENTIC_API_KEY.");return t}).makeOptionMandatory(),Rl=new Option("-c, --config <configPath>","Absolute or relative path to a Momentic configuration file."),px=new Option("-f, --filter <filter>","Run tests within the project that has a name equal to the filter provided. This option cannot be used together with file path or directory arguments, but substring matches are allowed."),Xo=new Option("--server <server>","Momentic server to use.").env("MOMENTIC_SERVER").default(EC()??"https://api.momentic.ai").argParser(t=>{try{return z.url().parse(t),t}catch{throw new InvalidArgumentError("Not a valid URL.")}}),aS=new Option("-y, --yes","Skip all confirmation prompts.").env("CI"),fF=new Option("--regenerate-cache","Regenerate all caches by starting from an empty cache state. This flag is useful for completely regenerating caches after changing configuration options. Warning: using this option will cause all steps to run without any cached data, resulting in significantly longer execution times."),fx=new Option("--save-cache","Always save updated step caches after successful test runs. By default, caches are not saved when running on protected branches.").env("CI"),hx=new Option("--disable-cache","Disable using step caches completely. Using this option may lead to non-deterministic behavior and significantly longer runtimes.").implies({saveCache:false});function gx(t){return e=>{let r=e.trim();if(r==="")throw new InvalidArgumentError(`${t} must be a non-empty string (whitespace is not allowed).`);return r}}var hF=new Option("--tag <tag>","Tag identifier for the asset.").argParser(gx("--tag")),gF=new Option("--channel <channel>","Channel name for the asset.").argParser(gx("--channel")),bx=new Option("--channel <channel>","Channel name for the asset.").argParser(gx("--channel")).makeOptionMandatory(),bF=new Option("--tag <tag>","Tag identifier for the asset.").argParser(gx("--tag")).makeOptionMandatory(),yF=new Option("--platform <platform>","Mobile platform for the asset."),Sie=new Option("--platform <platform>","Mobile platform for the asset.").makeOptionMandatory(),Tie=new Option("--tag-filter <tagFilter>","Case-insensitive substring filter applied to tags when listing a channel."),Eie=new Option("--json","Emit machine-readable JSON output instead of a human-readable table.");function yx(t){if(!t)return "ANDROID";switch(t.toLowerCase()){case "android":return "ANDROID";case "ios":return "IOS";default:throw new InvalidArgumentError('Invalid platform. Valid options are "android" and "ios".')}}var vie=new Option("--env <env>","Environment to run all tests in (overrides test-level configuration)."),Cie=new Option("--android-home <androidHome>","Path to the Android SDK root. Sets ANDROID_HOME for this command."),wie=new Option("--java-home <javaHome>","Path to the Java home directory. Sets JAVA_HOME for this command."),SF=new Option("--region <region>",`Region to run all tests in (overrides all other configuration). Valid values: ${Object.values(ig).join(", ")}, ${Object.values(og).join(", ")}, ${li}, ${Object.values(os).join(", ")}.`),TF=new Option("--local-avd-id <localAvdId>","Force tests to use a specific local Android Virtual Device (AVD) instead of remote emulators."),EF=new Option("--local-apk-path <localApkPath>","Path to a local APK file to install when running tests with a local emulator. Overrides remote asset configuration."),vF=new Option("--local-ios-device-type <localIosDeviceType>","Force tests to use a specific local iOS device type instead of remote emulators."),CF=new Option("--local-ios-version <localIosVersion>","Target a specific local iOS runtime version (e.g. 26.4). Defaults to the latest installed runtime."),wF=new Option("--local-app-path <localAppPath>","Path to a local app file to install when running tests with a local emulator. Overrides remote asset configuration."),Aie=new Option("-p, --parallel <parallel>",['The number of tests to run in parallel. Defaults to 1. Pass "AUTO" to use the number of tests in the current shard.',"Remote (Limbar) runs: each test gets an independent emulator session; parallelism is safe and any org quota is enforced server-side.","Local Android runs: each parallel test must target a distinct AVD. Running parallel > 1 against the same --local-avd-id will conflict.","Local iOS runs: concurrent Appium instances share a driver manifest and may race on startup; prefer parallel=1 for local iOS."].join(" ")).argParser(aWe),Rie=new Option("--shard-index <shardIndex>","The index of the shard to run tests for. Defaults to 1.").default(1).argParser(t=>{let e=zd(t);if(e<1)throw new InvalidArgumentError("Shard index must be greater than 0.");return e}),xie=new Option("--shard-count <shardCount>","The number of shards that tests are being run on. Defaults to 1.").default(1).argParser(zd),AF=new Option("--output-dir <outputDir>","Output directory to store run artifacts such as screenshots, results, and logs."),RF=new Option("--include <includePatterns...>","Only include tests that match the provided regex patterns. Multiple patterns can be provided. The patterns will be matched against the test file paths and the pattern only needs to match a part of the path for the test to be included."),xF=new Option("--exclude <excludePatterns...>","The inverted version of --include: a test that matches any of the provided exclusion patterns will be excluded from running."),Mie=new Option("--upload-results","Upload test results to the Momentic dashboard.").default(false),Pie=new Option("--share-diagnostics","Share local run diagnostics (OpenTelemetry traces) with Momentic to help diagnose performance issues.").env("MOMENTIC_SHARE_DIAGNOSTICS"),sWe=["true","false","on-fail"],Iie=new Option("--video [value]","Record video of mobile test runs. By default, video is recorded but kept only for failing tests (on-fail). Use the bare flag or pass true, false, or on-fail.").choices(sWe),MF=new Option("--log-level <logLevel>","Log level for Momentic and dependent services.").choices(["error","warn","info","debug"]),_ie=new Option("--skip-quarantined","Skip quarantined tests entirely.").implies({onlyQuarantined:false,ignoreQuarantine:false}),Oie=new Option("--only-quarantined","Run only tests that are currently quarantined. When running with this option, any test failures will cause the pipeline to fail, even though the tests are quarantined.").implies({skipQuarantined:false,ignoreQuarantine:false}),Die=new Option("--ignore-quarantine","Run all tests even if they are quarantined. This is useful for validating that quarantined tests are fixed before moving them out of quarantine.").implies({skipQuarantined:false,onlyQuarantined:false}),Lie=new Option("--timeout-minutes <timeoutMinutes>","Maximum number of minutes to run tests before stopping. When the timeout is reached, tests will stop and current results will be printed.").argParser(zd),Nie=new Option("--reporter <reporter>","Output reporter. Live: list (default). File: "+AC.join(", ")+". File reporters write to --reporter-dir. Pass --reporter multiple times to combine reporters.").default([]).argParser(L9),kie=new Option("--reporter-dir <reporterDir>","Output directory to store report files. Relative paths are resolved relative to the project root, which is defined by the detected momentic.config.yaml.").default("reports"),Fie=new Option("--name <name>","A name to associate with this run for easier identification in the Momentic dashboard."),Bie=new Option("--session-idle-timeout-minutes <timeoutMinutes>","Session idle timeout in minutes. When set, MCP sessions that remain idle for this duration will be automatically terminated. Defaults to 5 minutes.").env("MOMENTIC_SESSION_IDLE_TIMEOUT_MINUTES").argParser(zd),Uie=new Option("--headful [headful]","Launch mobile MCP remote control browsers headfully by default.").argParser(xP),zie=new Option("--supports-file-output [supportsFileOutput]","Allow MCP tool responses to include file output references.").argParser(xP),$ie=new Option("--daemon","Keep session tools alive across MCP stdio calls by routing through a local daemon. Sets the daemon cwd to the directory of the config file, allowing multiple MCP servers to share the same project home."),Vie=new Argument("[results]",`Path to the results archive. Defaults to "${nb}".`).default(nb);var qf="screen-recording.mp4";var jie={...Cl,prepareRunParams:async({runTracer:t,metadata:{orgId:e},fixtures:{logger:r,apiClient:n,mobileGenerator:o,storage:i,cacheStorage:a,usageTracker:s,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u},inputs:{channel:d,tag:m,project:p,testDefinition:f},env:{envName:h,envVariables:g},settings:{emulatorSettings:y,aiSettings:S},options:{logLevel:E,localAvdId:v,localApkPath:w,region:_,updateGoldenFiles:L},registerCleanup:I})=>{let R=false,k=[()=>u.dispose()],D=async()=>{R=true;for(let j of k.toReversed())try{await j();}catch(z){q.warn({err:z},"Failed to run cleanup function");}await s.flush(r);};I?.(async()=>D());let V=Hl.optional().parse(_??y.region),$=V==="local",U;if($){let{avdId:j,apkFilePath:z,apkFilePathSource:se}=Dm({overrideAvdId:v,overrideApkFilePath:w,emulatorSettings:y,defaultApkFilePath:f.settings?.defaultApkFilePath,envVariables:g}),be=Np({apkFilePath:z,source:se});if(!j)throw new Error(`An AVD ID is required when using a local region. Provide --local-avd-id, configure a default local AVD ID on the test's settings, or set the ${Dl} key on the environment.`);U={avdId:j,apkFilePath:be};}else U={region:V===li?void 0:V,apkToInstall:d?{channel:d,tag:m}:void 0,osVersion:y.remoteEmulatorSettings?.androidVersion??Am};let fe=randomUUID(),q=r.child({runAttemptId:fe}),N=await Ne({name:"mobile-cli.driver_setup",attributes:{"momentic.platform":"ANDROID","momentic.test_id":f.id},fn:async()=>Lp({apiClient:n,logger:r,driverLogLevel:E,creationOpts:U,callbacks:{onStatusUpdate:j=>{r.debug({status:j},"Emulator status update");},onHeartbeatFailure:()=>{R||P.warn("Appium heartbeat connection lost. Possible ADB tunnel/emulator failure.");},onHeartbeatRestored:()=>{P.info("Appium heartbeat connection restored.");},onLimbarConnectionStateChange:j=>{j==="disconnected"?R||P.warn("Emulator websocket connection lost. Emulator may be unavailable."):(j==="reconnecting"||j==="connecting")&&P.info("Emulator websocket is reconnecting.");}},orgId:e,sessionId:fe})});k.push(()=>N.cleanup());let F="limbarRegion"in N?N.limbarRegion:void 0,B="limbarTag"in N?N.limbarTag:void 0,te="limbarOsVersion"in N?N.limbarOsVersion:void 0;try{let j=await t.startAttempt({emulatorName:N.emulatorName,runAttemptId:fe,assetDetails:{avdId:xu in U?U.avdId:void 0,osVersion:te,tag:B??("apkToInstall"in U?U.apkToInstall?.tag:void 0),channel:"apkToInstall"in U?U.apkToInstall?.channel:void 0,region:F??V??li}});q=q.child(j.loggerBindings||{});let z=await N.driver.executeInNativeContext(q,async it=>$C({driver:it,onLogs:or=>{j.appendLogs(or);}}),{operationName:"startLogcatListener"});k.push(()=>z());let se=new Ui({variablesFromEnvironment:g,envName:h,testName:f.name}),be="limbarClient"in N?N.limbarClient:void 0,rt="playwrightDevice"in N?N.playwrightDevice:void 0,gt=await Zc.init({driver:N.driver,generator:o,logger:q,limbarClient:be,playwrightDevice:rt,orgId:e,adbPort:N.adbPort,options:{emulator:{...y,browserSettings:p.config.browser}},aiSettings:S,fixtures:{storage:i,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u,testContext:se,visualDiffGoldenStorage:new vs({baseDir:p.rootDir,updateGoldenFiles:L})}});if(k.push(()=>gt.cleanup()),j.videoOutputPath&&be)try{await be.startRecording({quality:RecordingQuality$1.Q5}),j.setActiveVideo(qf,new Date),q.info("Started Android video recording"),k.push(async()=>{if(!j.videoOutputPath)return;let it=fr__default.join(j.videoOutputPath,qf);await be.stopRecording({localPath:it}),q.info({videoPath:it},"Saved Android video recording");});}catch(it){q.warn({err:it},"Failed to start Android video recording");}return {platform:"ANDROID",envName:h,tracer:j,fixtures:{controller:gt,logger:q,cacheStorage:a,usageTracker:s},work:{state:{failureRecoveryDisabled:S.failureRecovery===!1,failureRecoveryAttempts:0}},inputs:{testName:f.name,steps:f.steps,beforeSteps:f.beforeSteps,afterSteps:f.afterSteps,orgId:e,testMetadata:f,useSnapshotIdentityCache:!1},callbacks:{},cleanup:D}}catch(j){throw await D(),j}}};var Hie={...wl,prepareRunParams:async({runTracer:t,metadata:{orgId:e},fixtures:{logger:r,apiClient:n,mobileGenerator:o,storage:i,cacheStorage:a,usageTracker:s,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u},inputs:{channel:d,tag:m,project:p,testDefinition:f},env:{envName:h,envVariables:g},settings:{emulatorSettings:y,aiSettings:S},options:{logLevel:E,region:v,localIosDeviceType:w,localIosVersion:_,localAppPath:L,updateGoldenFiles:I},registerCleanup:R})=>{let k=false,D=[()=>u.dispose()],V=async()=>{k=true;for(let j of D.toReversed())try{await j();}catch(z){N.warn({err:z},"Failed to run cleanup function");}await s.flush(r);};R?.(async()=>V());let $=Hl.optional().parse(v??y.region),U;if($==="local"){let{deviceType:j,iosVersion:z,appFilePath:se,appFilePathSource:be}=Lm({overrideDeviceType:w,overrideIosVersion:_,overrideAppFilePath:L,emulatorSettings:y,defaultAppFilePath:f.settings?.defaultAppFilePath,envVariables:g});if(!j)throw new Error(`A device type is required when using a local region. Provide --local-ios-device-type, configure a default local iOS device type on the test's settings, or set the ${Ll} key on the environment.`);let rt=Df({appFolderPath:se,source:be});U={type:"local",deviceType:j,iosVersion:z,appFilePath:rt};}else U={type:"remote",region:$===li?void 0:$,appToInstall:d?{channel:d,tag:m}:void 0,osVersion:Rm};let q=randomUUID(),N=r.child({runAttemptId:q}),F=await Ne({name:"mobile-cli.driver_setup",attributes:{"momentic.platform":"IOS","momentic.test_id":f.id},fn:async()=>Af({apiClient:n,logger:r,driverLogLevel:E,creationOpts:U,callbacks:{onStatusUpdate:j=>{r.debug({status:j},"Emulator status update");},onHeartbeatFailure:()=>{k||P.warn("Appium heartbeat connection lost. Possible emulator failure.");},onHeartbeatRestored:()=>{P.info("Appium heartbeat connection restored.");},onLimbarConnectionStateChange:j=>{j==="disconnected"?k||P.warn("Emulator websocket connection lost. Emulator may be unavailable."):(j==="reconnecting"||j==="connecting")&&P.info("Emulator websocket is reconnecting.");}},orgId:e,sessionId:q})});D.push(()=>F.cleanup());let B=F.limbarParams?.region,te=F.limbarParams?.tag;try{let j=await t.startAttempt({emulatorName:F.emulator.name,runAttemptId:q,assetDetails:{region:B??$??li,osVersion:F.limbarParams?.osVersion,tag:te??(U.type==="remote"?U.appToInstall?.tag:void 0),channel:U.type==="remote"?U.appToInstall?.channel:void 0}});N=N.child(j.loggerBindings||{});let z=await TR({emulator:F.emulator,onLogs:gt=>{j.appendLogs(gt);}});z&&D.push(async()=>z());let se=new Ui({variablesFromEnvironment:g,envName:h,testName:f.name}),be=await eu.init({driver:F.driver,generator:o,logger:N,emulator:F.emulator,orgId:e,options:{emulator:{...y,browserSettings:p.config.browser}},aiSettings:S,fixtures:{storage:i,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u,testContext:se,visualDiffGoldenStorage:new vs({baseDir:p.rootDir,updateGoldenFiles:I})}});D.push(()=>be?.cleanup());let rt=F.emulator;if(j.videoOutputPath&&rt.startScreenRecording&&rt.stopScreenRecording)try{await rt.startScreenRecording(),j.setActiveVideo(qf,new Date),N.info("Started iOS video recording"),D.push(async()=>{if(!j.videoOutputPath||!rt.stopScreenRecording)return;let gt=fr__default.join(j.videoOutputPath,qf);await rt.stopScreenRecording(gt),N.info({videoPath:gt},"Saved iOS video recording");});}catch(gt){N.warn({err:gt},"Failed to start iOS video recording");}return {platform:"IOS",envName:h,tracer:j,fixtures:{controller:be,logger:N,cacheStorage:a,usageTracker:s},work:{state:{failureRecoveryDisabled:S.failureRecovery===!1,failureRecoveryAttempts:0}},inputs:{testName:f.name,steps:f.steps,beforeSteps:f.beforeSteps,afterSteps:f.afterSteps,orgId:e,testMetadata:f,useSnapshotIdentityCache:!1},callbacks:{},cleanup:V}}catch(j){throw await V(),j}}};var lo="1.0.1",{checkCLIVersion:Sx}=H9({packageName:"momentic-mobile",currentVersion:lo,changelogUrl:"https://github.com/momentic-ai/mobile-cli/blob/main/CHANGELOG.md",updateCommand:"npx momentic-mobile@latest upgrade"});var IF=class{constructor(e,r,n,o,i,a,s){this.keepalive=e;this.testId=r;this.testName=n;this.platform=o;this.diskStorage=i;this.parentTracer=a;this.orgId=s;this.interactionTracer=new Xi(void 0,l=>this.storeTraceAsset(l)),ro.initializeRootTracerContext(this.interactionTracer);}children=[];finished=false;interactionTracer;getParentStepIdChain(){return []}recordStepDuration(e){let{durationMs:r,step:n}=e;if(!iE(n))return;let o=oE(n);Ge.distribution("test_mobile_step_duration",r,[`type:${o}`,`platform:${this.platform.toLowerCase()}`,"executor:cli",`orgId:${this.orgId}`]);}attachBeforeScreenshot(e){let{snapshotId:r,screenshot:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.png`,contents:n});}attachAfterScreenshot(e){let{snapshotId:r,screenshot:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.png`,contents:n});}storeTraceAsset(e){let{snapshotId:r,data:n,extension:o}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.${o??"png"}`,contents:n});}attachBeforeXmlSnapshot(e){let{snapshotId:r,xml:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.xml`,contents:n});}attachAfterXmlSnapshot(e){let{snapshotId:r,xml:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.xml`,contents:n});}async finishInternal(e){this.finished||(this.finished=true,this.interactionTracer.finish(),await Promise.all(this.children.map(r=>r.finish({status:Oh(e.status),finishedAt:e.finishedAt}))));}async finish(e){return await this.finishInternal({status:e.result.status,finishedAt:new Date(e.result.endTime)}),{trace:this.interactionTracer.getRootSpan()}}async startSubSteps(){let e=new Kf(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this.orgId);return this.children.push(e),e}},Kf=class{constructor(e,r,n,o,i,a){this.keepalive=e;this.testId=r;this.testName=n;this.platform=o;this.diskStorage=i;this.orgId=a;}children=[];finished=false;async getScreenshot(e){return this.diskStorage.readFile(`${Vi}/${e}.png`)??this.diskStorage.readFile(`${Vi}/${e}.jpeg`)}getParentStepIdChain(){return []}async startStep(e){this.keepalive();let r=new IF(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this,this.orgId);return this.children.push(r),r}async finish(e){this.finished||(this.finished=true,await Promise.all(this.children.map(r=>r.finishInternal({status:n1(e.status),finishedAt:e.finishedAt}))));}},_F=class{constructor(e,r,n,o,i,a,s,l,c,u,d){this.keepalive=e;this.testId=r;this.testName=n;this.platform=o;this.runAttemptId=i;this.metadata=a;this.diskStorage=s;this.orgId=l;this.resultSchema=c;this.recordVideo=u;this.assetDetails=d;this.diskStorage.mkdir("assets");let m=o==="IOS"?"assets/logs.syslog":"assets/logs.logcat";this.logStream=this.diskStorage.createFileStream(m),this.resourceUsageStream=this.diskStorage.createFileStream(`${Vi}/resource-usage.ndjson`),this.resourceUsageSampler=CH({keepSamples:false,onSample:p=>{this.resourceUsageStream.write(`${JSON.stringify(p)}
|
|
6256
|
+
`)}`),e.totalErrors++;for(let s of a){let l=fr__default.relative(t.project.rootDir,s);r.has(s)?e.failedModuleFilePaths.add(l):e.failedTestFilePaths.add(l);}}}}function qHe({momenticFiles:t,state:e}){for(let[r,n]of Object.entries(t.mobileTests)){let o=t.mobileModules[r];o&&(P.error(`ID '${r}' is shared between mobile test '${n.relativePath}' and mobile module '${o.relativePath}'. Test and module IDs must be unique across the entire project.`),e.totalErrors++,e.failedTestFilePaths.add(n.relativePath),e.failedModuleFilePaths.add(o.relativePath));}}async function die({project:t,filePath:e}){let{totalErrors:r,parsingErrors:n,parsingErrorDetails:o,failedTestFilePaths:i,failedModuleFilePaths:a}=await iie({project:t,filePath:e});if(r===0){P.success("Mobile lint passed. No issues found.");return}o.length>0&&mv({parsingErrors:n,parsingErrorDetails:o,failedTestFilePaths:i,failedModuleFilePaths:a,rootDir:t.rootDir}),P.error(`Found ${r} mobile lint error${r===1?"":"s"} in project.`),process.exit(1);}async function uF({project:t}){if(t.config.fileFormat==="v2"){let{totalErrors:o,parsingErrors:i,parsingErrorDetails:a,failedTestFilePaths:s,failedModuleFilePaths:l}=await iie({project:t});i>0&&(mv({parsingErrors:i,parsingErrorDetails:a,failedTestFilePaths:s,failedModuleFilePaths:l,rootDir:t.rootDir}),process.exit(1)),o>0&&(P.error(`Found ${o} lint errors`),P.warn("Run 'npx momentic-mobile lint' for details"),process.exit(1));return}let{parsingErrors:e,parsingErrorDetails:r,failedTestFilePaths:n}=await oie({project:t,logger:P});e>0&&(mv({parsingErrors:e,parsingErrorDetails:r,failedTestFilePaths:n,rootDir:t.rootDir}),process.exit(1));}async function mF({tests:t,momenticFiles:e,project:r,yes:n,include:o,exclude:i,labels:a,logger:s,quarantinedTestsMetadata:l}){let c=new Set;if(t&&t.length>0){let d=t.some(p=>Sn.existsSync(p)),m=cwd();d?(m!==r.rootDir&&s.warn(`Test paths resolve against the current directory ('${m}'), not the project root ('${r.rootDir}'). Run from the project root or use substring filters to avoid surprises.`),t.forEach(p=>{if(!Sn.existsSync(p))throw new Error(`Path '${p}' does not exist.`);let f,h;try{f=Sn.statSync(p),h=f.isDirectory();}catch(y){s.warn({err:y},`Skipping path ${p} because it cannot be read`);return}let g=fr__default.resolve(p);Object.values(e.mobileTests).filter(y=>h?y.fullFilePath.startsWith(g):y.fullFilePath===g).forEach(y=>{c.add(y.fullFilePath);});})):Object.values(e.mobileTests).forEach(p=>{t.some(f=>p.relativePath.includes(f))&&c.add(p.fullFilePath);});}else !n&&!await Jl("No test paths or substrings were provided. Do you want to run all tests?")&&(s.error("Cancelled by user."),process.exit(1)),Object.values(e.mobileTests).forEach(m=>{c.add(m.fullFilePath);});for(let d of Array.from(c)){let m=fr__default.relative(r.rootDir,d);o&&!o.some(p=>new RegExp(p).test(m))&&c.delete(d),i&&i.some(p=>new RegExp(p).test(m))&&c.delete(d);}return (await Promise.all(Array.from(c).map(async d=>{try{let m=fr__default.relative(r.rootDir,d),p=await dr(d,s,e),f=fr__default.basename(d,".test.yaml");if(p.disabled)return null;if(a&&a.length>0){let g=p.labels||[];if(!a.some(S=>g.includes(S)))return null}let h={id:p.id,name:f,description:p.description,schemaVersion:p.schemaVersion,settings:p.settings,fullFilePath:d,relativeFilePath:m,quarantined:!!l[p.id],quarantinedMetadata:l[p.id],labels:p.labels};switch(p.platform){case "ANDROID":return {...h,platform:"ANDROID",steps:p.steps,beforeSteps:p.beforeSteps,afterSteps:p.afterSteps};case "IOS":return {...h,platform:"IOS",steps:p.steps,beforeSteps:p.beforeSteps,afterSteps:p.afterSteps};default:return (y=>{throw new Error("You missed a case in the switch above")})(p)}}catch(m){s.error(`Failed to read and resolve mobile test at '${d}': ${m}`),process.exit(1);}}))).filter(d=>!!d)}function mie({testDefinitions:t,quarantinedTestsMetadata:e,onlyQuarantined:r=false,skipQuarantined:n=false}){let[o,i]=partition(t,a=>a.id in e);return {quarantinedTestsToSkip:n?o:[],testsToRun:r?[]:i,quarantinedTestsToRun:n?[]:o}}var pie=()=>process.exit(130),fie=()=>process.exit(143);process.on("SIGINT",pie);process.on("SIGTERM",fie);function hie(){process.off("SIGINT",pie),process.off("SIGTERM",fie);}async function pF({project:t,apiClient:e,gitMetadata:r,orgId:n,dryRun:o=false}){let i=await vt(t),a=Object.values(i.mobileTests).filter(g=>g.type===Ce.MOBILE_TEST),s=Object.values(i.mobileModules).filter(g=>g.type===Ce.MOBILE_MODULE),l=Object.values(i.mobileTests).filter(g=>g.type===Ce.MOBILE_TEST_V2).length,c=Object.values(i.mobileModules).filter(g=>g.type===Ce.MOBILE_MODULE_V2).length,u={...tD(),alreadyV2TestCount:l,alreadyV2ModuleCount:c},d=t.config.fileFormat!=="v2",{v2ProjectConfig:m,migratedFilePaths:p}=W9(t);!o&&a.length>0&&await JHe({legacyMobileTests:a,momenticFiles:i,project:t,apiClient:e,gitMetadata:r,orgId:n}),await ZHe({legacyMobileModules:s,momenticFiles:i,project:t,v2ProjectConfig:m,migratedFilePaths:p,summary:u,dryRun:o}),await tWe({legacyMobileTests:a,momenticFiles:i,project:t,v2ProjectConfig:m,migratedFilePaths:p,summary:u,dryRun:o});let f=u.migratedTestPaths.length>0||u.migratedModulePaths.length>0;return !o&&(d||f)&&QO({project:t,newProjectConfig:m,fileFormatLabel:"v2",migratedFilePaths:p}),u}async function gie({project:t,apiClient:e,gitMetadata:r}){let{legacyProjectConfig:n,migratedFilePaths:o}=G9(t),i=await vt(t),a=Object.values(i.mobileTests).filter(c=>c.type===Ce.MOBILE_TEST_V2),s=Object.values(i.mobileModules).filter(c=>c.type===Ce.MOBILE_MODULE_V2);P.info(`Migrating ${a.length} simplified format mobile tests and ${s.length} simplified format mobile modules to legacy YAML`);let l=new Set;await QHe({v2MobileTests:a,momenticFiles:i,project:t,legacyProjectConfig:n,migratedFilePaths:o,apiClient:e,gitMetadata:r,modulesCoveredByTests:l}),await eWe({v2MobileModules:s,momenticFiles:i,project:t,legacyProjectConfig:n,migratedFilePaths:o,modulesCoveredByTests:l}),QO({project:t,newProjectConfig:n,fileFormatLabel:"legacy",migratedFilePaths:o});}async function JHe({legacyMobileTests:t,momenticFiles:e,project:r,apiClient:n,gitMetadata:o,orgId:i}){if(t.length===0)return;let a={logger:P,orgId:i,client:n,regenerateCache:false,alwaysSaveCache:true,noCache:false,isolateCachesByEnvironment:r.config.advanced?.isolateCachesByEnvironment??false,bustOldestCachePercentage:void 0},s=[rn({...a,gitMetadata:o})];o.gitMainBranch&&o.gitBranchName!==o.gitMainBranch&&s.push(rn({...a,gitMetadata:{...o,gitBranchName:o.gitMainBranch,gitCommitTimestamp:o.lastCommitOnMainTimestamp??o.gitCommitTimestamp}})),P.info(`Pushing mobile test snapshots for ${t.length} legacy mobile tests so existing step caches survive the simplified format conversion`),await Mp(t,xp,async l=>{let c=await dr(l.fullFilePath,P,e),{snapshotCachesToSave:u}=await An({platform:c.platform,stepLists:{steps:c.steps,beforeSteps:c.beforeSteps,afterSteps:c.afterSteps},useSnapshotIdentityCache:true,cacheCreationParams:{orgId:i,testId:c.id,environment:void 0}});for(let d of s)await d.saveSnapshotCacheEntries({logger:P,platform:c.platform,entries:u});P.dimmed(`Pushed mobile test snapshot for: ${l.relativePath}`);});}async function ZHe({legacyMobileModules:t,momenticFiles:e,project:r,v2ProjectConfig:n,migratedFilePaths:o,summary:i,dryRun:a}){await Mp(t,xp,async s=>{let l=pc(s.fullFilePath,P);if(Qg(l))throw new Error(`Expected a legacy mobile module while migrating '${s.relativePath}', but found the simplified format`);let c=fc({module:l,moduleFilePath:s.fullFilePath,momenticFiles:e}),u=rs.parse(c),d={...u,name:c.name??s.name,steps:ha(u.platform).array().parse(c.steps)};a||bs({content:d,schemaVersion:dn,momenticFiles:e,project:{...r,config:n},forceSaveOnNoDiffs:true}),o.push(s.fullFilePath),i.migratedModulePaths.push(s.fullFilePath),P.dimmed(` + ${s.relativePath}`);});}async function QHe({v2MobileTests:t,momenticFiles:e,project:r,legacyProjectConfig:n,migratedFilePaths:o,apiClient:i,gitMetadata:a,modulesCoveredByTests:s}){await Mp(t,xp,async l=>{let c=await dr(l.fullFilePath,P,e),u=await nWe({platform:c.platform,stepLists:{steps:c.steps,beforeSteps:c.beforeSteps,afterSteps:c.afterSteps},apiClient:i,gitMetadata:a,testId:c.id,environment:void 0,missingSnapshotMessage:`Could not restore legacy step ids for '${l.fullFilePath}' because no mobile snapshot cache was found for test '${c.id}'. Run the simplified format migration before undoing it.`}),{moduleUpdates:d}=await An({platform:c.platform,stepLists:u});for(let m of d)s.add(m.moduleId);await cl({platform:c.platform,filePath:l.fullFilePath,steps:u.steps,beforeSteps:u.beforeSteps,afterSteps:u.afterSteps,settings:c.settings,labels:c.labels,folder:r.rootDir,project:{...r,config:n},momenticFiles:e,schemaVersion:dn,forceFileFormat:"v1"}),o.push(l.fullFilePath),P.dimmed(`Migrated simplified format mobile test to legacy: ${l.relativePath}`);});}async function eWe({v2MobileModules:t,momenticFiles:e,project:r,legacyProjectConfig:n,migratedFilePaths:o,modulesCoveredByTests:i}){await Mp(t,xp,async a=>{if(i.has(a.id)){o.push(a.fullFilePath);return}let s=pc(a.fullFilePath,P),l=fc({module:s,moduleFilePath:a.fullFilePath,momenticFiles:e}),c=rs.parse(l),u={...c,name:l.name??a.name,steps:ha(c.platform).array().parse(l.steps)};bs({content:u,schemaVersion:dn,momenticFiles:e,project:{...r,config:n},forceSaveOnNoDiffs:true,forceFileFormat:"v1"}),o.push(a.fullFilePath),P.dimmed(`Migrated unreferenced simplified format mobile module to legacy: ${a.relativePath}`);});}async function tWe({legacyMobileTests:t,momenticFiles:e,project:r,v2ProjectConfig:n,migratedFilePaths:o,summary:i,dryRun:a}){await Mp(t,xp,async s=>{let l=await dr(s.fullFilePath,P,e);a||await cl({platform:l.platform,filePath:s.fullFilePath,steps:l.steps,beforeSteps:l.beforeSteps,afterSteps:l.afterSteps,settings:l.settings,labels:l.labels,folder:r.rootDir,project:{...r,config:n},momenticFiles:e,schemaVersion:dn}),o.push(s.fullFilePath),i.migratedTestPaths.push(s.fullFilePath),P.dimmed(` + ${s.relativePath}`);});}async function rWe({apiClient:t,gitMetadata:e,testId:r,platform:n,environment:o}){let i=await t.getSnapshotCacheForTest({testId:r,environment:o,platform:n==="ANDROID"?"android":"ios"},_u(e));return Uv({entries:i,logger:P})}async function nWe({platform:t,stepLists:e,apiClient:r,gitMetadata:n,testId:o,environment:i,missingSnapshotMessage:a}){let s=await rWe({apiClient:r,gitMetadata:n,testId:o,platform:t,environment:i});s.testStepLists||P.warn(`${a} Minting fresh legacy ids.`);let l=zv({currentStepLists:e,previousSnapshots:s,generateUuid:randomUUID});return l.stats.mintedSteps>0&&P.warn(`Restored legacy mobile YAML with ${l.stats.mintedSteps} newly generated step ids because some steps did not match the snapshot cache.`),l.stepLists}var bie=58890;function zd(t){let e=parseInt(t,10);if(isNaN(e))throw new InvalidArgumentError("Not a number.");return e}function aWe(t){if(t.toUpperCase()==="AUTO")return "AUTO";let e=Number(t);if(isNaN(e))throw new InvalidArgumentError("Not a number or AUTO.");if(!Number.isInteger(e))throw new InvalidArgumentError("Not a number or AUTO.");if(e<=0)throw new InvalidArgumentError("Not a number or AUTO.");return e}var yie=new Option("--port <port>",`Port to run the local app on. Defaults to ${bie}.`).env("PORT").default(bie).argParser(zd),wi=new Option("--api-key <key>","Momentic API key").env("MOMENTIC_API_KEY").default(TC(),"value from ~/.momentic/auth.json").argParser(t=>{if(!t)throw new InvalidArgumentError("API key is required. Run `npx @momentic/wizard@latest login` or set MOMENTIC_API_KEY.");return t}).makeOptionMandatory(),Rl=new Option("-c, --config <configPath>","Absolute or relative path to a Momentic configuration file."),px=new Option("-f, --filter <filter>","Run tests within the project that has a name equal to the filter provided. This option cannot be used together with file path or directory arguments, but substring matches are allowed."),Xo=new Option("--server <server>","Momentic server to use.").env("MOMENTIC_SERVER").default(EC()??"https://api.momentic.ai").argParser(t=>{try{return z.url().parse(t),t}catch{throw new InvalidArgumentError("Not a valid URL.")}}),aS=new Option("-y, --yes","Skip all confirmation prompts.").env("CI"),fF=new Option("--regenerate-cache","Regenerate all caches by starting from an empty cache state. This flag is useful for completely regenerating caches after changing configuration options. Warning: using this option will cause all steps to run without any cached data, resulting in significantly longer execution times."),fx=new Option("--save-cache","Always save updated step caches after successful test runs. By default, caches are not saved when running on protected branches.").env("CI"),hx=new Option("--disable-cache","Disable using step caches completely. Using this option may lead to non-deterministic behavior and significantly longer runtimes.").implies({saveCache:false});function gx(t){return e=>{let r=e.trim();if(r==="")throw new InvalidArgumentError(`${t} must be a non-empty string (whitespace is not allowed).`);return r}}var hF=new Option("--tag <tag>","Tag identifier for the asset.").argParser(gx("--tag")),gF=new Option("--channel <channel>","Channel name for the asset.").argParser(gx("--channel")),bx=new Option("--channel <channel>","Channel name for the asset.").argParser(gx("--channel")).makeOptionMandatory(),bF=new Option("--tag <tag>","Tag identifier for the asset.").argParser(gx("--tag")).makeOptionMandatory(),yF=new Option("--platform <platform>","Mobile platform for the asset."),Sie=new Option("--platform <platform>","Mobile platform for the asset.").makeOptionMandatory(),Tie=new Option("--tag-filter <tagFilter>","Case-insensitive substring filter applied to tags when listing a channel."),Eie=new Option("--json","Emit machine-readable JSON output instead of a human-readable table.");function yx(t){if(!t)return "ANDROID";switch(t.toLowerCase()){case "android":return "ANDROID";case "ios":return "IOS";default:throw new InvalidArgumentError('Invalid platform. Valid options are "android" and "ios".')}}var vie=new Option("--env <env>","Environment to run all tests in (overrides test-level configuration)."),Cie=new Option("--android-home <androidHome>","Path to the Android SDK root. Sets ANDROID_HOME for this command."),wie=new Option("--java-home <javaHome>","Path to the Java home directory. Sets JAVA_HOME for this command."),SF=new Option("--region <region>",`Region to run all tests in (overrides all other configuration). Valid values: ${Object.values(ig).join(", ")}, ${Object.values(og).join(", ")}, ${li}, ${Object.values(os).join(", ")}.`),TF=new Option("--local-avd-id <localAvdId>","Force tests to use a specific local Android Virtual Device (AVD) instead of remote emulators."),EF=new Option("--local-apk-path <localApkPath>","Path to a local APK file to install when running tests with a local emulator. Overrides remote asset configuration."),vF=new Option("--local-ios-device-type <localIosDeviceType>","Force tests to use a specific local iOS device type instead of remote emulators."),CF=new Option("--local-ios-version <localIosVersion>","Target a specific local iOS runtime version (e.g. 26.4). Defaults to the latest installed runtime."),wF=new Option("--local-app-path <localAppPath>","Path to a local app file to install when running tests with a local emulator. Overrides remote asset configuration."),Aie=new Option("-p, --parallel <parallel>",['The number of tests to run in parallel. Defaults to 1. Pass "AUTO" to use the number of tests in the current shard.',"Remote (Limbar) runs: each test gets an independent emulator session; parallelism is safe and any org quota is enforced server-side.","Local Android runs: each parallel test must target a distinct AVD. Running parallel > 1 against the same --local-avd-id will conflict.","Local iOS runs: concurrent Appium instances share a driver manifest and may race on startup; prefer parallel=1 for local iOS."].join(" ")).argParser(aWe),Rie=new Option("--shard-index <shardIndex>","The index of the shard to run tests for. Defaults to 1.").default(1).argParser(t=>{let e=zd(t);if(e<1)throw new InvalidArgumentError("Shard index must be greater than 0.");return e}),xie=new Option("--shard-count <shardCount>","The number of shards that tests are being run on. Defaults to 1.").default(1).argParser(zd),AF=new Option("--output-dir <outputDir>","Output directory to store run artifacts such as screenshots, results, and logs."),RF=new Option("--include <includePatterns...>","Only include tests that match the provided regex patterns. Multiple patterns can be provided. The patterns will be matched against the test file paths and the pattern only needs to match a part of the path for the test to be included."),xF=new Option("--exclude <excludePatterns...>","The inverted version of --include: a test that matches any of the provided exclusion patterns will be excluded from running."),Mie=new Option("--upload-results","Upload test results to the Momentic dashboard.").default(false),Pie=new Option("--share-diagnostics","Share local run diagnostics (OpenTelemetry traces) with Momentic to help diagnose performance issues.").env("MOMENTIC_SHARE_DIAGNOSTICS"),sWe=["true","false","on-fail"],Iie=new Option("--video [value]","Record video of mobile test runs. By default, video is recorded but kept only for failing tests (on-fail). Use the bare flag or pass true, false, or on-fail.").choices(sWe),MF=new Option("--log-level <logLevel>","Log level for Momentic and dependent services.").choices(["error","warn","info","debug"]),_ie=new Option("--skip-quarantined","Skip quarantined tests entirely.").implies({onlyQuarantined:false,ignoreQuarantine:false}),Oie=new Option("--only-quarantined","Run only tests that are currently quarantined. When running with this option, any test failures will cause the pipeline to fail, even though the tests are quarantined.").implies({skipQuarantined:false,ignoreQuarantine:false}),Die=new Option("--ignore-quarantine","Run all tests even if they are quarantined. This is useful for validating that quarantined tests are fixed before moving them out of quarantine.").implies({skipQuarantined:false,onlyQuarantined:false}),Lie=new Option("--timeout-minutes <timeoutMinutes>","Maximum number of minutes to run tests before stopping. When the timeout is reached, tests will stop and current results will be printed.").argParser(zd),Nie=new Option("--reporter <reporter>","Output reporter. Live: list (default). File: "+AC.join(", ")+". File reporters write to --reporter-dir. Pass --reporter multiple times to combine reporters.").default([]).argParser(L9),kie=new Option("--reporter-dir <reporterDir>","Output directory to store report files. Relative paths are resolved relative to the project root, which is defined by the detected momentic.config.yaml.").default("reports"),Fie=new Option("--name <name>","A name to associate with this run for easier identification in the Momentic dashboard."),Bie=new Option("--session-idle-timeout-minutes <timeoutMinutes>","Session idle timeout in minutes. When set, MCP sessions that remain idle for this duration will be automatically terminated. Defaults to 5 minutes.").env("MOMENTIC_SESSION_IDLE_TIMEOUT_MINUTES").argParser(zd),Uie=new Option("--headful [headful]","Launch mobile MCP remote control browsers headfully by default.").argParser(xP),zie=new Option("--supports-file-output [supportsFileOutput]","Allow MCP tool responses to include file output references.").argParser(xP),$ie=new Option("--daemon","Keep session tools alive across MCP stdio calls by routing through a local daemon. Sets the daemon cwd to the directory of the config file, allowing multiple MCP servers to share the same project home."),Vie=new Argument("[results]",`Path to the results archive. Defaults to "${nb}".`).default(nb);var qf="screen-recording.mp4";var jie={...Cl,prepareRunParams:async({runTracer:t,metadata:{orgId:e},fixtures:{logger:r,apiClient:n,mobileGenerator:o,storage:i,cacheStorage:a,usageTracker:s,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u},inputs:{channel:d,tag:m,project:p,testDefinition:f},env:{envName:h,envVariables:g},settings:{emulatorSettings:y,aiSettings:S},options:{logLevel:E,localAvdId:v,localApkPath:w,region:_,updateGoldenFiles:L},registerCleanup:I})=>{let R=false,k=[()=>u.dispose()],D=async()=>{R=true;for(let j of k.toReversed())try{await j();}catch(z){q.warn({err:z},"Failed to run cleanup function");}await s.flush(r);};I?.(async()=>D());let V=Hl.optional().parse(_??y.region),$=V==="local",U;if($){let{avdId:j,apkFilePath:z,apkFilePathSource:se}=Dm({overrideAvdId:v,overrideApkFilePath:w,emulatorSettings:y,defaultApkFilePath:f.settings?.defaultApkFilePath,envVariables:g}),be=Np({apkFilePath:z,source:se});if(!j)throw new Error(`An AVD ID is required when using a local region. Provide --local-avd-id, configure a default local AVD ID on the test's settings, or set the ${Dl} key on the environment.`);U={avdId:j,apkFilePath:be};}else U={region:V===li?void 0:V,apkToInstall:d?{channel:d,tag:m}:void 0,osVersion:y.remoteEmulatorSettings?.androidVersion??Am};let fe=randomUUID(),q=r.child({runAttemptId:fe}),N=await Ne({name:"mobile-cli.driver_setup",attributes:{"momentic.platform":"ANDROID","momentic.test_id":f.id},fn:async()=>Lp({apiClient:n,logger:r,driverLogLevel:E,creationOpts:U,callbacks:{onStatusUpdate:j=>{r.debug({status:j},"Emulator status update");},onHeartbeatFailure:()=>{R||P.warn("Appium heartbeat connection lost. Possible ADB tunnel/emulator failure.");},onHeartbeatRestored:()=>{P.info("Appium heartbeat connection restored.");},onLimbarConnectionStateChange:j=>{j==="disconnected"?R||P.warn("Emulator websocket connection lost. Emulator may be unavailable."):(j==="reconnecting"||j==="connecting")&&P.info("Emulator websocket is reconnecting.");}},orgId:e,sessionId:fe})});k.push(()=>N.cleanup());let F="limbarRegion"in N?N.limbarRegion:void 0,B="limbarTag"in N?N.limbarTag:void 0,te="limbarOsVersion"in N?N.limbarOsVersion:void 0;try{let j=await t.startAttempt({emulatorName:N.emulatorName,runAttemptId:fe,assetDetails:{avdId:xu in U?U.avdId:void 0,osVersion:te,tag:B??("apkToInstall"in U?U.apkToInstall?.tag:void 0),channel:"apkToInstall"in U?U.apkToInstall?.channel:void 0,region:F??V??li}});q=q.child(j.loggerBindings||{});let z=await N.driver.executeInNativeContext(q,async it=>$C({driver:it,onLogs:or=>{j.appendLogs(or);}}),{operationName:"startLogcatListener"});k.push(()=>z());let se=new Ui({variablesFromEnvironment:g,envName:h,testName:f.name}),be="limbarClient"in N?N.limbarClient:void 0,rt="playwrightDevice"in N?N.playwrightDevice:void 0,gt=await Zc.init({driver:N.driver,generator:o,logger:q,limbarClient:be,playwrightDevice:rt,orgId:e,adbPort:N.adbPort,options:{emulator:{...y,browserSettings:p.config.browser}},aiSettings:S,fixtures:{storage:i,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u,testContext:se,visualDiffGoldenStorage:new vs({baseDir:p.rootDir,updateGoldenFiles:L})}});if(k.push(()=>gt.cleanup()),j.videoOutputPath&&be)try{await be.startRecording({quality:RecordingQuality$1.Q5}),j.setActiveVideo(qf,new Date),q.info("Started Android video recording"),k.push(async()=>{if(!j.videoOutputPath)return;let it=fr__default.join(j.videoOutputPath,qf);await be.stopRecording({localPath:it}),q.info({videoPath:it},"Saved Android video recording");});}catch(it){q.warn({err:it},"Failed to start Android video recording");}return {platform:"ANDROID",envName:h,tracer:j,fixtures:{controller:gt,logger:q,cacheStorage:a,usageTracker:s},work:{state:{failureRecoveryDisabled:S.failureRecovery===!1,failureRecoveryAttempts:0}},inputs:{testName:f.name,steps:f.steps,beforeSteps:f.beforeSteps,afterSteps:f.afterSteps,orgId:e,testMetadata:f,useSnapshotIdentityCache:!1},callbacks:{},cleanup:D}}catch(j){throw await D(),j}}};var Hie={...wl,prepareRunParams:async({runTracer:t,metadata:{orgId:e},fixtures:{logger:r,apiClient:n,mobileGenerator:o,storage:i,cacheStorage:a,usageTracker:s,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u},inputs:{channel:d,tag:m,project:p,testDefinition:f},env:{envName:h,envVariables:g},settings:{emulatorSettings:y,aiSettings:S},options:{logLevel:E,region:v,localIosDeviceType:w,localIosVersion:_,localAppPath:L,updateGoldenFiles:I},registerCleanup:R})=>{let k=false,D=[()=>u.dispose()],V=async()=>{k=true;for(let j of D.toReversed())try{await j();}catch(z){N.warn({err:z},"Failed to run cleanup function");}await s.flush(r);};R?.(async()=>V());let $=Hl.optional().parse(v??y.region),U;if($==="local"){let{deviceType:j,iosVersion:z,appFilePath:se,appFilePathSource:be}=Lm({overrideDeviceType:w,overrideIosVersion:_,overrideAppFilePath:L,emulatorSettings:y,defaultAppFilePath:f.settings?.defaultAppFilePath,envVariables:g});if(!j)throw new Error(`A device type is required when using a local region. Provide --local-ios-device-type, configure a default local iOS device type on the test's settings, or set the ${Ll} key on the environment.`);let rt=Df({appFolderPath:se,source:be});U={type:"local",deviceType:j,iosVersion:z,appFilePath:rt};}else U={type:"remote",region:$===li?void 0:$,appToInstall:d?{channel:d,tag:m}:void 0,osVersion:Rm};let q=randomUUID(),N=r.child({runAttemptId:q}),F=await Ne({name:"mobile-cli.driver_setup",attributes:{"momentic.platform":"IOS","momentic.test_id":f.id},fn:async()=>Af({apiClient:n,logger:r,driverLogLevel:E,creationOpts:U,callbacks:{onStatusUpdate:j=>{r.debug({status:j},"Emulator status update");},onHeartbeatFailure:()=>{k||P.warn("Appium heartbeat connection lost. Possible emulator failure.");},onHeartbeatRestored:()=>{P.info("Appium heartbeat connection restored.");},onLimbarConnectionStateChange:j=>{j==="disconnected"?k||P.warn("Emulator websocket connection lost. Emulator may be unavailable."):(j==="reconnecting"||j==="connecting")&&P.info("Emulator websocket is reconnecting.");}},orgId:e,sessionId:q})});D.push(()=>F.cleanup());let B=F.limbarParams?.region,te=F.limbarParams?.tag;try{let j=await t.startAttempt({emulatorName:F.emulator.name,runAttemptId:q,assetDetails:{region:B??$??li,osVersion:F.limbarParams?.osVersion,tag:te??(U.type==="remote"?U.appToInstall?.tag:void 0),channel:U.type==="remote"?U.appToInstall?.channel:void 0}});N=N.child(j.loggerBindings||{});let z=await TR({emulator:F.emulator,onLogs:gt=>{j.appendLogs(gt);}});z&&D.push(async()=>z());let se=new Ui({variablesFromEnvironment:g,envName:h,testName:f.name}),be=await eu.init({driver:F.driver,generator:o,logger:N,emulator:F.emulator,orgId:e,options:{emulator:{...y,browserSettings:p.config.browser}},aiSettings:S,fixtures:{storage:i,browserEnricher:l,browserGenerator:c,localCodeEvalTools:u,testContext:se,visualDiffGoldenStorage:new vs({baseDir:p.rootDir,updateGoldenFiles:I})}});D.push(()=>be?.cleanup());let rt=F.emulator;if(j.videoOutputPath&&rt.startScreenRecording&&rt.stopScreenRecording)try{await rt.startScreenRecording(),j.setActiveVideo(qf,new Date),N.info("Started iOS video recording"),D.push(async()=>{if(!j.videoOutputPath||!rt.stopScreenRecording)return;let gt=fr__default.join(j.videoOutputPath,qf);await rt.stopScreenRecording(gt),N.info({videoPath:gt},"Saved iOS video recording");});}catch(gt){N.warn({err:gt},"Failed to start iOS video recording");}return {platform:"IOS",envName:h,tracer:j,fixtures:{controller:be,logger:N,cacheStorage:a,usageTracker:s},work:{state:{failureRecoveryDisabled:S.failureRecovery===!1,failureRecoveryAttempts:0}},inputs:{testName:f.name,steps:f.steps,beforeSteps:f.beforeSteps,afterSteps:f.afterSteps,orgId:e,testMetadata:f,useSnapshotIdentityCache:!1},callbacks:{},cleanup:V}}catch(j){throw await V(),j}}};var lo="1.0.2",{checkCLIVersion:Sx}=H9({packageName:"momentic-mobile",currentVersion:lo,changelogUrl:"https://github.com/momentic-ai/mobile-cli/blob/main/CHANGELOG.md",updateCommand:"npx momentic-mobile@latest upgrade"});var IF=class{constructor(e,r,n,o,i,a,s){this.keepalive=e;this.testId=r;this.testName=n;this.platform=o;this.diskStorage=i;this.parentTracer=a;this.orgId=s;this.interactionTracer=new Xi(void 0,l=>this.storeTraceAsset(l)),ro.initializeRootTracerContext(this.interactionTracer);}children=[];finished=false;interactionTracer;getParentStepIdChain(){return []}recordStepDuration(e){let{durationMs:r,step:n}=e;if(!iE(n))return;let o=oE(n);Ge.distribution("test_mobile_step_duration",r,[`type:${o}`,`platform:${this.platform.toLowerCase()}`,"executor:cli",`orgId:${this.orgId}`]);}attachBeforeScreenshot(e){let{snapshotId:r,screenshot:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.png`,contents:n});}attachAfterScreenshot(e){let{snapshotId:r,screenshot:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.png`,contents:n});}storeTraceAsset(e){let{snapshotId:r,data:n,extension:o}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.${o??"png"}`,contents:n});}attachBeforeXmlSnapshot(e){let{snapshotId:r,xml:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.xml`,contents:n});}attachAfterXmlSnapshot(e){let{snapshotId:r,xml:n}=e;this.diskStorage.storeFile({name:`${Vi}/${r}.xml`,contents:n});}async finishInternal(e){this.finished||(this.finished=true,this.interactionTracer.finish(),await Promise.all(this.children.map(r=>r.finish({status:Oh(e.status),finishedAt:e.finishedAt}))));}async finish(e){return await this.finishInternal({status:e.result.status,finishedAt:new Date(e.result.endTime)}),{trace:this.interactionTracer.getRootSpan()}}async startSubSteps(){let e=new Kf(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this.orgId);return this.children.push(e),e}},Kf=class{constructor(e,r,n,o,i,a){this.keepalive=e;this.testId=r;this.testName=n;this.platform=o;this.diskStorage=i;this.orgId=a;}children=[];finished=false;async getScreenshot(e){return this.diskStorage.readFile(`${Vi}/${e}.png`)??this.diskStorage.readFile(`${Vi}/${e}.jpeg`)}getParentStepIdChain(){return []}async startStep(e){this.keepalive();let r=new IF(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this,this.orgId);return this.children.push(r),r}async finish(e){this.finished||(this.finished=true,await Promise.all(this.children.map(r=>r.finishInternal({status:n1(e.status),finishedAt:e.finishedAt}))));}},_F=class{constructor(e,r,n,o,i,a,s,l,c,u,d){this.keepalive=e;this.testId=r;this.testName=n;this.platform=o;this.runAttemptId=i;this.metadata=a;this.diskStorage=s;this.orgId=l;this.resultSchema=c;this.recordVideo=u;this.assetDetails=d;this.diskStorage.mkdir("assets");let m=o==="IOS"?"assets/logs.syslog":"assets/logs.logcat";this.logStream=this.diskStorage.createFileStream(m),this.resourceUsageStream=this.diskStorage.createFileStream(`${Vi}/resource-usage.ndjson`),this.resourceUsageSampler=CH({keepSamples:false,onSample:p=>{this.resourceUsageStream.write(`${JSON.stringify(p)}
|
|
6257
6257
|
`);}});}finished=false;children=[];logStream;resourceUsageStream;resourceUsageSampler;get loggerBindings(){return {runAttemptId:this.runAttemptId}}get videoOutputPath(){if(this.recordVideo)return fr.resolve(this.diskStorage.cwd(),Vi)}appendLogs(e){let r=e.join(`
|
|
6258
6258
|
`);this.logStream.write(r+`
|
|
6259
6259
|
`);}setActiveVideo(e,r){this.recordVideo&&(this.metadata.activeVideos=this.metadata.activeVideos||[],this.metadata.activeVideos.push({videoName:e,timestamp:r}));}async finish(e){if(this.finished)return;this.finished=true;let{logger:r,status:n,results:o,beforeResults:i,afterResults:a}=e,s={...this.metadata,status:n,assetDetails:this.assetDetails,finishedAt:new Date,results:MC(o,this.resultSchema,r),beforeResults:i?MC(i,this.resultSchema,r):void 0,afterResults:a?MC(a,this.resultSchema,r):void 0};await Promise.all(this.children.map(l=>l.finish({status:s.status,finishedAt:s.finishedAt})));try{this.logStream.end();}catch{}try{this.resourceUsageSampler.stop(),this.resourceUsageStream.end();}catch{}this.recordVideo==="on-fail"&&n==="PASSED"&&(Wq(r,this.videoOutputPath),s.activeVideos=void 0),this.diskStorage.storeFile({name:fn,contents:JSON.stringify(s,null,2)});}async startBeforeStepList(){let e=new Kf(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this.orgId);return this.children.push(e),e}async startMainStepList(){let e=new Kf(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this.orgId);return this.children.push(e),e}async startAfterStepList(){let e=new Kf(this.keepalive,this.testId,this.testName,this.platform,this.diskStorage,this.orgId);return this.children.push(e),e}async getScreenshot(e,r){return this.diskStorage.readFile(`${Vi}/${r}.png`)??this.diskStorage.readFile(`${Vi}/${r}.jpeg`)}},OF=class{constructor(e,r,n,o,i,a,s,l,c,u){this.client=e;this.testId=r;this.testName=n;this.platform=o;this.runId=i;this.metadata=a;this.diskStorage=s;this.orgId=l;this.resultSchema=c;this.recordVideo=u;}children=[];finished=false;get loggerBindings(){return {runId:this.runId}}async finish(e){if(this.finished)return;this.finished=true;let r={...this.metadata,finishedAt:e.finishedAt||new Date,status:e.status,failureDetails:e.failureDetails,failureReason:e.failureReason,flake:e.isFlake||false,failureRecoveryDetails:e.failureRecoveryDetails};await Promise.all(this.children.map(n=>n.finish({logger:e.logger,status:r.status,results:[],beforeResults:[],afterResults:[]}))),this.diskStorage.storeFile({name:fn,contents:JSON.stringify(r,null,2)}),this.diskStorage.close();}async startAttempt(e){let{runAttemptId:r}=e;this.metadata.attempts=this.metadata.attempts+1,this.metadata.status="RUNNING",this.diskStorage.storeFile({name:fn,contents:JSON.stringify(this.metadata,null,2)});let n=this.diskStorage.cd(`attempts/${this.metadata.attempts}`),o={id:r,schemaVersion:US,runAttemptSchemaVersion:iH,startedAt:new Date,status:"RUNNING"};n.storeFile({name:fn,contents:JSON.stringify(o,null,2)});let i=debounce(async()=>{await this.client.extendEmulatorTtl(this.platform,e.emulatorName);},3e4,{maxWait:6e4}),a=new _F(()=>void i(),this.testId,this.testName,this.platform,r,o,n,this.orgId,this.resultSchema,this.recordVideo,e.assetDetails);return this.children.push(a),a}},Tx=class t{constructor(e,r,n,o,i,a){this.orgId=e;this.runGroupId=r;this.metadata=n;this.client=o;this.diskStorage=i;this.recordVideo=a;}children=[];finished=false;get loggerBindings(){return {orgId:this.orgId,runGroupId:this.runGroupId,branch:this.metadata.gitBranchName}}static async start({orgId:e,runGroupId:r,outputDir:n,client:o,gitMetadata:i,labels:a,suiteName:s,recordVideo:l}){let c={...i,suiteName:s&&ua(s),id:r,trigger:ri.CLI,startedAt:new Date,status:"RUNNING",cliVersion:lo,labels:a??[]},u=new bb(n);return u.storeFile({name:fn,contents:JSON.stringify(c,null,2)}),new t(e,r,c,o,u,l??false)}async finish(e){if(this.finished)return;this.finished=true;let{status:r}=e,n={...this.metadata,status:r,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:fn,contents:JSON.stringify(n,null,2)});}async startRun(e){let r=this.diskStorage.createRunArchive(e.runId,e.logger),n={stepsSnapshot:e.originalSteps.steps,beforeStepsSnapshot:e.originalSteps.beforeSteps??void 0,afterStepsSnapshot:e.originalSteps.afterSteps??void 0,runGroupId:this.runGroupId,testId:e.testId,testName:e.testName?ua(e.testName):e.testName,testDescription:e.testDescription,directory:e.directory,labels:e.testLabels,trigger:"CLI",status:"RUNNING",healStatus:"NOT_ATTEMPTED",environmentName:e.environmentName,cliVersion:lo,schemaVersion:e.schemaVersion,startedAt:new Date,attempts:0,quarantined:e.quarantined,quarantinedReason:e.quarantinedReason,executionType:e.platform,aiSettings:e.aiSettings};r.storeFile({name:fn,contents:JSON.stringify(n,null,2)});let o=new OF(this.client,e.testId,e.testName,e.platform,e.runId,n,r,this.orgId,e.resultSchema,this.recordVideo);return this.children.push(o),o}};function Gie(t){return {platform:t.platform,originalSteps:{steps:cloneDeep(t.steps),beforeSteps:t.beforeSteps?cloneDeep(t.beforeSteps):void 0,afterSteps:t.afterSteps?cloneDeep(t.afterSteps):void 0}}}var sS=2;async function DF(t){let{inputs:e,fixtures:r,metadata:n,helpers:o}=t,{tracer:i,logger:a}=r,{runId:s}=n,{platform:l,testDefinition:c,project:u}=e,d=new Date,m=await i.startRun({...Gie(c),logger:a,testId:c.id,testName:c.name,directory:dirname(c.relativeFilePath),runId:s,testDescription:c.description,testLabels:c.labels,schemaVersion:c.schemaVersion,quarantined:c.quarantined,quarantinedReason:c.quarantinedMetadata?.quarantinedReason,aiSettings:u.config.ai,resultSchema:o.resultSchema}),p=a.child(m.loggerBindings||{}),f=1+(c.settings?.retries??u.config.retries??rT),h=false;for(let g=0;g<f;g++){let y=new Date,S=await gWe({...t,runTracer:m,fixtures:{...r,logger:p},constants:{attemptNumber:g+1,totalAttempts:f}}),E=new Date;if(h||=S.results.length>0||(S.beforeResults?.length??0)>0||(S.afterResults?.length??0)>0,S.status!=="FAILED")return await m.finish({logger:p,status:S.status,failureRecoveryDetails:S.failureRecoveryDetails,finishedAt:E}),{...S,testMetadata:c,platformType:l,steps:c.steps,startedAt:d,lastAttemptStartedAt:y,finishedAt:E,runId:s,attempts:g+1,filePath:c.relativeFilePath,quarantined:c.quarantined,quarantinedMetadata:c.quarantinedMetadata,status:S.status};if(g!==f-1){p.warn("Retrying failed mobile run");continue}p.error("Mobile test failed after all exhausting attempts"),h||p.error({err:S.error,failureReason:S.error?.reason,testId:c.id,testName:c.name,attempts:f},`Mobile test ran ZERO steps across all ${f} attempt(s) - likely an emulator/driver startup failure`);let v={failureReason:S.error?.reason,failureDetails:S.error?{errorMessage:S.error.message,errorStack:S.error.stack}:void 0};return await m.finish({logger:p,status:S.status,...v,failureRecoveryDetails:S.failureRecoveryDetails,finishedAt:E}),{...S,testMetadata:c,platformType:l,steps:c.steps,startedAt:d,lastAttemptStartedAt:y,finishedAt:E,runId:s,...v,attempts:g+1,filePath:c.relativeFilePath,quarantined:c.quarantined,quarantinedMetadata:c.quarantinedMetadata,status:S.status}}throw new Error("This code should not be reachable")}async function gWe(t){let{metadata:e,constants:r,fixtures:n,inputs:o,options:i}=t,{attemptNumber:a,totalAttempts:s}=r,{orgId:l,gitMetadata:c}=e,{apiClient:u,logger:d}=n,{testDefinition:m,logUpdate:p,project:f,envOverride:h}=o,{regenerateCache:g,alwaysSaveCache:y,noCache:S}=i;a!==1&&p("RETRY",`attempt ${a}/${s}`);let E={...o.project.config.emulator,...m.settings?.emulator},v={...f.config.ai,useMemory:f.config.ai?.useMemory!==false,...m.settings?.ai},w=h||m.settings?.defaultEnv,L=(w?ed(w,f,d):void 0)?.variables??{},I=rn({logger:d,orgId:l,client:u,gitMetadata:c,regenerateCache:g,alwaysSaveCache:y,noCache:S,isolateCachesByEnvironment:f.config?.advanced?.isolateCachesByEnvironment}),R=new vp(u,l),k={type:"API_KEY",baseUrl:u.baseUrl,apiKey:u.apiKey,logger:d,mode:"runner",runner:"test-runner"},D=new Ts(k),V=new dl(v.agentConfig,k),$=new Ec(k,V),U=new vc({httpClient:u,fakerSeed:f.config.advanced?.fakerConstantSeed?Nm:void 0});return await bWe({...t,fixtures:{...t.fixtures,mobileGenerator:D,storage:R,cacheStorage:I,browserEnricher:$,browserGenerator:V,localCodeEvalTools:U},env:{envName:w,envVariables:L},settings:{aiSettings:v,emulatorSettings:E}})}async function bWe(t){let{inputs:{testDefinition:e,logUpdate:r},env:{envName:n},fixtures:{logger:o},helpers:i}=t,a=t.inputs.platform,s,l;for(let m=1;m<=sS;m++)try{s=await Ne({name:"mobile-cli.session_setup",attributes:{"momentic.platform":a,"momentic.test_id":e.id},fn:async()=>i.prepareRunParams(t)});break}catch(p){if(l=p,m===sS)break;r("RETRY",`emulator setup failed, retrying on a fresh emulator (${m+1}/${sS})`),o.warn({err:p,attempt:m,maxAttempts:sS},"Mobile emulator bootstrap failed; retrying bootstrap");}if(!s){let m=l instanceof M?l.reason:"InternalPlatformError",p=W(l);return {status:"FAILED",results:[],error:new M(m,`Mobile driver setup failed before any test steps ran after ${sS} bootstrap attempt(s). This usually means the emulator or Appium driver failed to start, not that the test file is empty or that its steps were skipped. Last setup error: ${p}`)}}let c=t.inputs.project.config.fileFormat==="v2",u;try{u=await Ne({name:"mobile-cli.execute_test",attributes:{"momentic.platform":a,"momentic.test_id":e.id},fn:async()=>Ff({...s,containerName:`mobile test ${e.name}`,envName:n,helpers:i,inputs:{...s.inputs,useSnapshotIdentityCache:c}})});}finally{await Ne({name:"mobile-cli.teardown",attributes:{"momentic.platform":a,"momentic.test_id":e.id},fn:async()=>s.cleanup()});}await s.tracer.finish({logger:s.fixtures.logger,results:u.results,beforeResults:u.beforeResults,afterResults:u.afterResults,status:u.status});let d;if(u.status==="FAILED"&&u.terminalResult){let m=u.terminalResult.message;d=m?M.fromMessage(m):new M("UnknownError","Unknown failure");}return {...u,error:d}}function Ex(t){if(t.status!=="FAILED")return "none";switch(t.failureReason){case "SetupFailureError":return "setup";case "TeardownFailureError":return "teardown";default:return "main"}}function SWe(t){switch(t){case "PASSED":return "passed";case "FAILED":return "failed";case "CANCELLED":return "skipped";case "RETRYING":case "WAITING_FOR_USER":case "PENDING":case "RUNNING":return "unknown";default:return _t(t)}}function Xie(t){let e=fr__default.relative(".",t);return e===""?t:e}function qie(t,e){return Math.max(0,(t.getTime()-e.getTime())/1e3)}function TWe(t,e,r){let n=qie(e,t),o=qie(r,t);return {start_at:n,end_at:o,duration:Math.max(0,o-n)}}function Jie(t){let e=t.reduce((r,[n,o])=>(!o||Object.keys(r).length>=10||(r[n]=o),r),{});return Object.keys(e).length>0?e:void 0}function EWe(t){if(t.status!=="FAILED"||!t.failureReason)return;let e=_l({failureReason:t.failureReason,classification:t.failureDetails?.classification,manualClassification:t.failureDetails?.manualClassification,errorMessage:t.failureDetails?.errorMessage});if(!(e.title==null||e.description==null))return `${e.title}: ${e.description}`}function vWe(t){if(t.status!=="FAILED")return;let e=[t.failureDetails?.classification?.summary,t.failureDetails?.classification?.rootCause,t.failureDetails?.errorMessage].filter(n=>!!n),r=t.failureDetails?.errorStack?.split(`
|