prompttest 1.3.1 → 1.3.3

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.
@@ -1,62 +1,62 @@
1
1
  #!/usr/bin/env node
2
- var Kn=Object.defineProperty;var oe=(p,t,e)=>()=>{if(e)throw e[0];try{return p&&(t=p(p=0)),t}catch(s){throw e=[s],s}};var xt=(p,t)=>{for(var e in t)Kn(p,e,{get:t[e],enumerable:!0})};var ue,tn=oe(()=>{"use strict";ue={DEVICES:["devices","-l"],SCREENCAP:["exec-out","screencap","-p"],FOREGROUND_APP:["shell","dumpsys","window"],CURRENT_FOCUS:["shell","dumpsys","activity","activities"],FORCE_STOP:p=>["shell","am","force-stop",p],CLEAR_APP:p=>["shell","pm","clear",p],LAUNCH_APP:p=>["shell","am","start","-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER",p],UIAUTOMATOR_DUMP:["exec-out","uiautomator","dump","--compressed","/dev/tty"],INPUT_TAP:(p,t)=>["shell","input","tap",p.toString(),t.toString()],INPUT_TEXT:p=>["shell","input","text",p],INPUT_KEY:p=>["shell","input","keyevent",p.toString()],INPUT_SWIPE:(p,t,e,s,n=300)=>["shell","input","swipe",p.toString(),t.toString(),e.toString(),s.toString(),n.toString()],LOGCAT_CRASH:p=>["shell","logcat","-d","-b","crash","-s","AndroidRuntime:E"],CLEAR_CRASH_LOGS:()=>["shell","logcat","-b","crash","-c"],GRANT_PERMISSION:(p,t)=>["shell","pm","grant",p,t.startsWith("android.permission.")?t:`android.permission.${t}`],INSTALL_APK:p=>["install","-r",p],UNINSTALL_APP:p=>["uninstall",p],DEEP_LINK:p=>["shell","am","start","-a","android.intent.action.VIEW","-d",p],TCPIP:(p=5555)=>["tcpip",p.toString()],CONNECT:p=>["connect",p],DISCONNECT:p=>p?["disconnect",p]:["disconnect"],GET_WLAN_IP:["shell","ip","-f","inet","addr","show","wlan0"]}});function zn(){let p=process.env.PROMPTTEST_SETTLE_FACTOR;if(!p)return 1;let t=parseFloat(p);return isNaN(t)||t<=0?1:t}function Ee(p,t=50){return Math.max(t,Math.round(p*zn()))}function sn(p=E.polling.intervalMs,t=E.polling.jitterMs){return Math.round(p+(Math.random()*2-1)*(t/2))}var E,Pe=oe(()=>{"use strict";E={adb:{commandTimeoutMs:2e4,binaryTimeoutMs:45e3,retryCount:2,retryBaseDelayMs:200},polling:{intervalMs:200,jitterMs:80,defaultTimeoutMs:3e3,extendedTimeoutMs:3500,hierarchyCacheTtlMs:3500,verifyCacheTtlMs:2e3},settle:{get tapMs(){return Ee(500)},get backMs(){return Ee(700)},get launchMs(){return Ee(2500)},get stopMs(){return Ee(600)},get keyboardDismissMs(){return Ee(500)},get scrollMs(){return Ee(350)},get toggleMs(){return Ee(350)},get selectMs(){return Ee(600)},get inputFocusMs(){return Ee(250)},get inputClearMs(){return Ee(150)},get inputDoneMs(){return Ee(350)},get submitWaitMs(){return Ee(1800)}},gestures:{swipeDurationMs:300,longPressDurationMs:1e3,bottomNavThresholdRatio:.88,tapTargetYRatio:.96},recorder:{staleTapTimeoutMs:3e3,asyncRefreshDelayMs:80,heartbeatIntervalMs:1500},screen:{fallbackWidth:1080,fallbackHeight:2400},visual:{overlapRatio:.2},device:{maxDeviceRetries:2,autoReconnect:!0},flow:{maxLoopIterations:50,waitUntilTimeoutMs:1e4,defaultRetryCount:3},ai:{provider:"heuristic",model:"gpt-4o-mini",selfHealing:!0,confidenceThreshold:.75,maxHealingAttempts:2,endpoint:""},memory:{staleThresholdDays:parseInt(process.env.PROMPTTEST_STALE_DAYS||"14",10),staleDecayAmount:.2,minConfidenceFloor:.2,maxHealedConfidence:.65},parser:{mode:process.env.PROMPTTEST_XML_PARSER||"regex"},safety:{mode:process.env.PROMPTTEST_SAFETY_MODE||"strict",customBlacklist:process.env.PROMPTTEST_SAFETY_BLACKLIST?process.env.PROMPTTEST_SAFETY_BLACKLIST.split(",").map(p=>p.trim()).filter(Boolean):[]},explorer:{strategy:process.env.PROMPTTEST_STRATEGY||"heuristic",maxTabs:parseInt(process.env.PROMPTTEST_MAX_TABS||"15",10),maxScreens:parseInt(process.env.PROMPTTEST_MAX_SCREENS||"30",10),maxDepth:parseInt(process.env.PROMPTTEST_MAX_DEPTH||"5",10),stepBudget:parseInt(process.env.PROMPTTEST_STEP_BUDGET||"100",10),screenshots:process.env.PROMPTTEST_SCREENSHOTS||"state-change"},locale:"en"}});var Tt,Et,Pt,At=oe(()=>{"use strict";Tt=class extends Error{exitCode;phase;constructor(t,e=1,s){super(t),this.name="PromptTestError",this.exitCode=e,this.phase=s,Object.setPrototypeOf(this,new.target.prototype)}},Et=class extends Tt{constructor(t,e="Device"){super(t,2,e),this.name="DeviceError"}},Pt=class extends Tt{cycle;constructor(t,e,s="SpecLoader"){super(t,3,s),this.name="SpecRecursionError",this.cycle=e}}});import{spawn as ht}from"child_process";import ts from"readline";var tt,Q,Ae=oe(()=>{"use strict";tn();Pe();At();tt=class{defaultSerial=null;cachedDimensions=new Map;inFlightHierarchies=new Map;constructor(t){t&&(this.defaultSerial=t)}setDefaultDevice(t){this.defaultSerial=t}getDefaultDevice(){return this.defaultSerial}async getScreenDimensions(t){let e=t||this.defaultSerial||"default";if(this.cachedDimensions.has(e))return this.cachedDimensions.get(e);try{let{stdout:n}=await this.execAdb(["shell","wm","size"],t),r=n.match(/(?:Physical|Override)\s*size:\s*(\d+)x(\d+)/i);if(r){let i={width:parseInt(r[1],10),height:parseInt(r[2],10)};return this.cachedDimensions.set(e,i),i}}catch{}let s={width:E.screen.fallbackWidth,height:E.screen.fallbackHeight};return this.cachedDimensions.set(e,s),s}clearScreenDimensionsCache(t){t?this.cachedDimensions.delete(t):this.cachedDimensions.clear()}async getNavigationBarHeight(t){try{let{stdout:e}=await this.execAdb(["shell","dumpsys","window","displays"],t).catch(()=>({stdout:""})),s=e.match(/(?:navigationBarHeight|navBarHeight|navigationBarFrame)[=:\s]+(\d+)/i);if(s&&parseInt(s[1],10)>0)return parseInt(s[1],10)}catch{}return 0}isGlobalAdbCommand(t){return t?["devices","connect","disconnect","version","kill-server","start-server","help"].includes(t.toLowerCase()):!0}async execAdbInternal(t,e,s=2e4){let n=e||this.defaultSerial;!n&&!this.isGlobalAdbCommand(t[0])&&(await this.ensureDefaultDevice(),n=this.defaultSerial);let r=n&&!this.isGlobalAdbCommand(t[0])?["-s",n,...t]:[...t];return new Promise((i,o)=>{let a=ht("adb",r),l="",c="",u=!1,h=setTimeout(()=>{u=!0;try{a.kill("SIGKILL")}catch{}o(new Error(`ADB command timed out after ${s}ms: adb ${r.join(" ")}`))},s);a.stdout.on("data",d=>{l+=d.toString("utf-8")}),a.stderr.on("data",d=>{c+=d.toString("utf-8")}),a.on("close",d=>{clearTimeout(h),!u&&(d===0?i({stdout:l,stderr:c}):o(new Error(`ADB command failed (code ${d}): adb ${r.join(" ")}
3
- Error: ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async execAdb(t,e,s=E.adb.commandTimeoutMs,n=E.device.maxDeviceRetries){let r;for(let i=0;i<=n;i++)try{return await this.execAdbInternal(t,e,s)}catch(o){r=o;let a=o instanceof Error?o.message:String(o),l=a.toLowerCase(),c=l.includes("device offline")||l.includes("device not found"),u=c||l.includes("error: closed")||l.includes("timed out");if(i>=n||!u||this.isGlobalAdbCommand(t[0]))throw c?new Et(`Target Android device ${e||this.defaultSerial||""} is offline or disconnected: ${a}`):o;if(E.device.autoReconnect&&c)try{await this.execAdbInternal(["reconnect"],e,5e3).catch(()=>{})}catch{}await new Promise(h=>setTimeout(h,E.adb.retryBaseDelayMs*Math.pow(2,i+1)))}throw r||new Error(`ADB command failed after ${n} retries: ${t.join(" ")}`)}async execAdbBinary(t,e,s=45e3){let n=e||this.defaultSerial;!n&&!this.isGlobalAdbCommand(t[0])&&(await this.ensureDefaultDevice(),n=this.defaultSerial);let r=n&&!this.isGlobalAdbCommand(t[0])?["-s",n,...t]:[...t];return new Promise((i,o)=>{let a=ht("adb",r),l=[],c="",u=!1,h=setTimeout(()=>{u=!0;try{a.kill("SIGKILL")}catch{}o(new Error(`ADB binary command timed out after ${s}ms: adb ${r.join(" ")}`))},s);a.stdout.on("data",d=>l.push(Buffer.from(d))),a.stderr.on("data",d=>{c+=d.toString("utf-8")}),a.on("close",d=>{clearTimeout(h),!u&&(d===0?i(Buffer.concat(l)):o(new Error(`ADB binary command failed (code ${d}): adb ${r.join(" ")}
4
- ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async getConnectedDevices(){let{stdout:t}=await this.execAdb(ue.DEVICES),e=t.split(`
5
- `).map(o=>o.trim()).filter(Boolean),s=e.findIndex(o=>o.toLowerCase().includes("list of devices attached")),n=s!==-1?e.slice(s+1):e,r=[];return r=(o=>{let a=[];for(let l of o){if(!l||l.startsWith("*")||l.toLowerCase().includes("list of devices"))continue;let c=l.split(/\s+/);if(c.length>=2){let u=c[0],h=c[1],d,g;for(let m of c.slice(2))m.startsWith("model:")&&(d=m.replace("model:","")),m.startsWith("product:")&&(g=m.replace("product:",""));a.push({serial:u,state:h,model:d,product:g})}}return a})(n),r}async wakeDevice(t){try{await this.execAdb(["shell","input","keyevent","224"],t),await this.execAdb(["shell","wm","dismiss-keyguard"],t)}catch{}}async ensureDefaultDevice(t){if(t)return await this.wakeDevice(t),t;if(this.defaultSerial)return await this.wakeDevice(this.defaultSerial),this.defaultSerial;let s=(await this.getConnectedDevices()).find(n=>n.state==="device");return s&&(this.defaultSerial=s.serial,await this.wakeDevice(this.defaultSerial)),this.defaultSerial||void 0}async getDeviceModel(t){try{let{stdout:r}=await this.execAdb(["shell","getprop","ro.product.model"],t),i=r.trim();if(i)return i}catch{}let e=await this.getConnectedDevices(),s=t||this.defaultSerial;return e.find(r=>r.serial===s)?.model||s||"Android Device"}async captureScreenshot(t){return this.execAdbBinary(ue.SCREENCAP,t)}async getUiHierarchy(t){let e=t||this.defaultSerial||"default",s=this.inFlightHierarchies.get(e);if(s)return s;let n=(async()=>{try{let{stdout:r}=await this.execAdb(ue.UIAUTOMATOR_DUMP,t,1e4,0),i=r.indexOf("<hierarchy");return i>=0?r.slice(i):r}finally{this.inFlightHierarchies.delete(e)}})();return this.inFlightHierarchies.set(e,n),n}clearInFlightHierarchies(t){t?this.inFlightHierarchies.delete(t):this.inFlightHierarchies.clear()}async getForegroundPackage(t){let e=s=>{let n=s.toLowerCase();return n==="android"||n.includes("systemui")||n.includes("inputmethod")||n.includes("latin")||n.includes("gboard")||n.includes("swiftkey")||n.includes("ime")};try{let{stdout:s}=await this.execAdb(["shell","dumpsys","activity","activities"],t).catch(()=>({stdout:""})),n=s.match(/(?:topResumedActivity|mResumedActivity)=.+?\s+([a-zA-Z0-9._]+)\//);if(n&&n[1]&&!e(n[1]))return n[1];let{stdout:r}=await this.execAdb(ue.FOREGROUND_APP,t),i=r.matchAll(/(?:mCurrentFocus|mFocusedWindow|mFocusedApp|topResumedActivity|mResumedActivity|mFocusedActivity)=.+?\s+([a-zA-Z0-9._]+)\/([a-zA-Z0-9._]+)/g);for(let o of i)if(o&&o[1]&&!e(o[1]))return o[1]}catch{}return null}async tap(t,e,s){await this.execAdb(ue.INPUT_TAP(t,e),s)}async inputText(t,e){let s=t.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/'/g,"\\'").replace(/%/g,"\\%").replace(/ /g,"%s").replace(/&/g,"\\&").replace(/</g,"\\<").replace(/>/g,"\\>").replace(/\(/g,"\\(").replace(/\)/g,"\\)").replace(/;/g,"\\;").replace(/\|/g,"\\|").replace(/\$/g,"\\$").replace(/#/g,"\\#").replace(/\*/g,"\\*").replace(/\?/g,"\\?").replace(/~/g,"\\~").replace(/`/g,"\\`");try{await this.execAdb(ue.INPUT_TEXT(s),e)}catch{for(let n of t)if(n===" ")await this.pressKey(62,e);else if(n==="@")await this.pressKey(77,e);else{let r=n.replace(/([\\"'&<>()|$;#*?~`%])/g,"\\$1");await this.execAdb(["shell","input","text",r],e).catch(()=>{})}}}async pressKey(t,e){await this.execAdb(ue.INPUT_KEY(t),e)}async pressEnter(t){await this.pressKey(66,t)}async pressTab(t){await this.pressKey(61,t)}async pressHome(t){await this.pressKey(3,t)}async pressBack(t){await this.pressKey(4,t)}async setWifiEnabled(t,e){await this.execAdb(["shell","svc","wifi",t?"enable":"disable"],e)}async setAirplaneMode(t,e){await this.execAdb(["shell","cmd","connectivity","airplane-mode",t?"enable":"disable"],e)}async setOrientation(t,e){await this.execAdb(["shell","content","insert","--uri","content://settings/system","--bind","name:s:accelerometer_rotation","--bind","value:i:0"],e).catch(()=>{});let s=t==="landscape"?"1":"0";await this.execAdb(["shell","settings","put","system","user_rotation",s],e)}async openNotificationShade(t){await this.execAdb(["shell","cmd","statusbar","expand-notifications"],t)}async collapseNotificationShade(t){await this.execAdb(["shell","cmd","statusbar","collapse"],t)}async clearInput(t=45,e){let s=Array(t).fill("67");await this.execAdb(["shell","input","keyevent",...s],e)}async clearField(t,e=80){await this.pressKey(123,t);let s=Math.max(50,e+10),n=Array(s).fill("67");await this.execAdb(["shell","input","keyevent",...n],t).catch(()=>{}),await this.pressKey(122,t);let r=Array(Math.max(30,Math.floor(e/2))).fill("112");await this.execAdb(["shell","input","keyevent",...r],t).catch(()=>{})}async swipe(t,e,s,n,r=300,i){await this.execAdb(ue.INPUT_SWIPE(t,e,s,n,r),i)}async launchApp(t,e){try{let{stdout:s}=await this.execAdb(["shell","cmd","package","resolve-activity","--brief",t],e),r=(s||"").split(`
6
- `).map(i=>i.trim()).find(i=>i.includes("/")&&!i.includes(" "));if(r){await this.execAdb(["shell","am","start","-n",r],e);return}}catch{}await this.execAdb(ue.LAUNCH_APP(t),e)}async forceStop(t,e){await this.execAdb(ue.FORCE_STOP(t),e)}async clearAppData(t,e){await this.execAdb(ue.CLEAR_APP(t),e)}async restartApp(t,e){await this.forceStop(t,e),await new Promise(s=>setTimeout(s,600)),await this.launchApp(t,e)}async grantPermission(t,e,s){await this.execAdb(ue.GRANT_PERMISSION(t,e),s)}async isAppInstalled(t,e){try{let{stdout:s}=await this.execAdb(["shell","pm","list","packages",t],e);return s.toLowerCase().includes(`package:${t.toLowerCase()}`)||s.includes(t)}catch{return!1}}async installApk(t,e){await this.execAdb(ue.INSTALL_APK(t),e)}async uninstallApp(t,e){await this.execAdb(ue.UNINSTALL_APP(t),e)}async openDeepLink(t,e){await this.execAdb(ue.DEEP_LINK(t),e)}async checkCrashes(t,e){try{let{stdout:s}=await this.execAdb(ue.LOGCAT_CRASH(t),e);if(s&&s.includes("FATAL EXCEPTION")&&s.includes(t))return s}catch{}return null}async clearCrashLogs(t){try{await this.execAdb(ue.CLEAR_CRASH_LOGS(),t)}catch{}}async getDeviceIp(t){try{let{stdout:e}=await this.execAdb(ue.GET_WLAN_IP,t),s=e.match(/inet\s+(\d+\.\d+\.\d+\.\d+)/);if(s&&s[1])return s[1]}catch{}try{let{stdout:e}=await this.execAdb(["shell","ip","route"],t),s=e.match(/src\s+(\d+\.\d+\.\d+\.\d+)/);if(s&&s[1])return s[1]}catch{}return null}async connectWifi(t,e=5555,s){let n=t,r=e;if(t&&t.includes(":")){let u=t.split(":");n=u[0],r=parseInt(u[1],10)||e}if(!n){let u=await this.getDeviceIp(s);if(!u)throw new Error("Could not auto-detect phone Wi-Fi IP. Make sure the phone is on Wi-Fi, or pass IP manually: npx prompttest wifi <ip>");n=u}let i=`${n}:${r}`;if(t)try{let{stdout:u,stderr:h}=await this.execAdb(ue.CONNECT(i)),d=`${u} ${h}`.trim();if(d.toLowerCase().includes("connected")||d.toLowerCase().includes("already"))return this.defaultSerial=i,{success:!0,target:i,message:d}}catch{}try{await this.execAdb(ue.TCPIP(r),s),await new Promise(u=>setTimeout(u,1e3))}catch{}let{stdout:o,stderr:a}=await this.execAdb(ue.CONNECT(i)),l=`${o} ${a}`.trim(),c=l.toLowerCase().includes("connected")||l.toLowerCase().includes("already");return c&&(this.defaultSerial=i),{success:c,target:i,message:l}}async disconnectWifi(t){let{stdout:e,stderr:s}=await this.execAdb(ue.DISCONNECT(t));return`${e} ${s}`.trim()}streamLogcatEvents(t,e){let n=ht("adb",["-s",t,"shell","logcat","-b","events","-v","time"]),r=ts.createInterface({input:n.stdout});return r.on("line",e),n.on("close",()=>{try{r.close()}catch{}}),n.on("error",()=>{}),n}streamLogcatCrashes(t,e){let n=ht("adb",["-s",t,"shell","logcat","-T","1","-s","AndroidRuntime:E","ANRManager:E","-v","time"]),r=ts.createInterface({input:n.stdout});return r.on("line",e),n.on("close",()=>{try{r.close()}catch{}}),n.on("error",()=>{}),n}streamLogcatToasts(t,e){let n=ht("adb",["-s",t,"shell","logcat","-s","Toast:D","Snackbar:D","-v","time"]),r=ts.createInterface({input:n.stdout});return r.on("line",e),n.on("close",()=>{try{r.close()}catch{}}),n.on("error",()=>{}),n}async getLogcatTail(t=150,e){try{let{stdout:s}=await this.execAdb(["logcat","-d","-t",String(t),"-v","time"],e);return s}catch(s){return`Failed to capture logcat: ${s instanceof Error?s.message:String(s)}`}}async startScreenRecording(t="/sdcard/prompttest_temp.mp4",e){let s=e||this.defaultSerial,r=ht("adb",s?["-s",s,"shell","screenrecord",t]:["shell","screenrecord",t]);return r.on("error",()=>{}),{remotePath:t,process:r}}async stopScreenRecording(t,e,s){try{try{t.process.kill("SIGINT")}catch{}return await this.execAdb(["shell","pkill","-2","screenrecord"],s).catch(()=>{}),await new Promise(n=>setTimeout(n,1500)),await this.execAdb(["pull",t.remotePath,e],s),await this.execAdb(["shell","rm","-f",t.remotePath],s).catch(()=>{}),e}catch{return""}}async isKeyboardVisible(t){try{let{stdout:e}=await this.execAdb(["shell","dumpsys","input_method"],t,4e3,0);return e.includes("mInputShown=true")||e.includes("isInputViewShown=true")||e.includes("mHasSurface=true")}catch{return!1}}async ensureAccessibilityServices(t){try{await this.execAdb(["shell","settings","put","secure","accessibility_enabled","1"],t,4e3,0)}catch{}}},Q=new tt});function on(p){let t=p.trim(),e=t.match(/^"([^"]+)"$/);if(e)return e[1].trim();let s=t.match(/^'([^']+)'$/);return s?s[1].trim():t.replace(/^['"]+|['"]+$/g,"").trim()}function ee(p){for(let t of p)if(t!=null&&t.trim().length>0)return t.trim();return""}function st(p,t){let e=p;if(t)for(let[s,n]of Object.entries(t))e=e.replace(new RegExp(`\\$${s}\\b`,"g"),()=>n);return e=e.replace(/\$ENV\{([A-Z0-9_]+)\}/gi,(s,n)=>process.env[n]||""),e=e.replace(/\$RANDOM_EMAIL\b/g,()=>`test_${Date.now().toString().slice(-6)}@prompttest.io`),e=e.replace(/\$RANDOM_NAME\b/g,()=>`User_${Math.floor(1e3+Math.random()*9e3)}`),e=e.replace(/\$RANDOM_PHONE\b/g,()=>`98${Math.floor(1e7+Math.random()*9e7)}`),e=e.replace(/\$TIMESTAMP\b/g,()=>Date.now().toString()),e=e.replace(/\$UUID\b/g,()=>`${Date.now().toString(16)}-${Math.random().toString(16).substring(2,8)}`),e=e.replace(/\$RANDOM_UUID\b/g,()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let n=Math.random()*16|0;return(s==="x"?n:n&3|8).toString(16)})),e=e.replace(/\$RANDOM_CARD\b/g,()=>{let s="4532";for(let n=0;n<12;n++)s+=Math.floor(Math.random()*10);return s}),e=e.replace(/\$DATE_OFFSET\((-?\d+)\)/g,(s,n)=>{let r=parseInt(n,10)||0;return new Date(Date.now()+r*864e5).toISOString().slice(0,10)}),e=e.replace(/\$RANDOM_INT\((\d+),\s*(\d+)\)/g,(s,n,r)=>{let i=parseInt(n,10),o=parseInt(r,10);return String(Math.floor(i+Math.random()*(o-i+1)))}),e}function gt(p){return(p||"").replace(/&#(\d+);/g,(t,e)=>{try{return String.fromCodePoint(parseInt(e,10))}catch{return""}}).replace(/&#x([0-9a-fA-F]+);/g,(t,e)=>{try{return String.fromCodePoint(parseInt(e,16))}catch{return""}}).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'")}function Z(p){return gt(p||"").trim().toLowerCase().replace(/[\u2018\u2019]/g,"'").replace(/[\u201C\u201D]/g,'"').replace(/\uFFFD/g,"").replace(new RegExp("\\p{Extended_Pictographic}","gu"),"").replace(/[\uE000-\uF8FF\uFFF0-\uFFFF]/g,"").replace(/\s+/g," ").trim()}function ne(p,t){if(!p||!t)return!1;let e=Z(p),s=Z(t);if(e.length<=3){let n=nn.get(e);if(!n){let r=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");n=new RegExp(`(?:^|\\b)${r}(?:\\b|$)`,"i"),nn.set(e,n)}return n.test(s)}return s.includes(e)}function Jn(p,t){let e=Z(p),s=Z(t),n=e.length,r=s.length;if(n===0)return r;if(r===0)return n;let i=Array.from({length:r+1},(a,l)=>l),o=new Array(r+1);for(let a=1;a<=n;a++){o[0]=a;for(let c=1;c<=r;c++){let u=e[a-1]===s[c-1]?0:1;o[c]=Math.min(i[c]+1,o[c-1]+1,i[c-1]+u)}let l=i;i=o,o=l}return i[r]}function Qn(p,t){let e=Z(p),s=Z(t);if(e===s)return 1;if(!e||!s)return 0;let n=Math.max(e.length,s.length);return 1-Jn(e,s)/n}function nt(p,t,e=3,s=.35){return Array.from(new Set(t.map(i=>i.trim()).filter(i=>i.length>0))).map(i=>({text:i,score:Qn(p,i)})).filter(i=>i.score>=s).sort((i,o)=>o.score-i.score).slice(0,e)}var rn,q,W,kt,nn,an,cn,Oe=oe(()=>{"use strict";rn=/^(\d+(?:\.\d+)*\.?|\-|\*)\s*/;q=`(?:"([^"]+)"|'([^']+)'|([^'"\\s][^'"]*?[^'"\\s]|\\S))`;W={TAP:new RegExp(`^(?:tap|click|press)(?:\\s+on)?\\s+(?:button\\s+|item\\s+)?${q}$`,"i"),ORDINAL_TAP:new RegExp(`^(?:tap|click|press)(?:\\s+on)?\\s+(?:the\\s+)?(1st|2nd|3rd|4th|5th|last|first)\\s+(?:button\\s+|item\\s+)?${q}$`,"i"),PROXIMITY_TAP:new RegExp(`^(?:tap|click|press)(?:\\s+on)?\\s+${q}\\s+(?:next\\s+to|near|beside|inside|for)\\s+${q}$`,"i"),CLEAR:new RegExp(`^(?:clear|empty)(?:\\s+(?:text\\s+(?:in|of)|field|input))?\\s+${q}$`,"i"),LONG_PRESS:new RegExp(`^(?:long\\s+press|press\\s+and\\s+hold)\\s+(?:button\\s+|item\\s+)?${q}$`,"i"),TYPE:new RegExp(`^(?:type|enter|input)\\s+${q}\\s+(?:in|into)\\s+${q}$`,"i"),VERIFY:new RegExp(`^(?:verify|veryfy|check|assert|ensure)\\s+(?:that\\s+)?(?:error\\s+message\\s+|message\\s+|text\\s+|element\\s+|button\\s+|toast\\s+|my\\s+)?${q}\\s*(?:is\\s+(visible|exists|appears|enabled|disabled|not\\s+visible|hidden|absent|not\\s+present|gone))?$`,"i"),BACK:/^(?:press\s+back|go\s+back|navigate\s+back|back)$/i,SCROLL_TO:new RegExp(`^(?:scroll|swipe)(?:\\s+(down|up))?\\s+(?:to|until)\\s+${q}$`,"i"),SCROLL:/^(?:scroll|swipe)\s+(down|up)$/i,DIRECTIONAL_SWIPE:new RegExp(`^(?:swipe|scroll)\\s+(left|right|up|down)(?:\\s+on\\s+${q})?$`,"i"),TOGGLE:new RegExp(`^(?:toggle|turn\\s+(on|off)|check|uncheck)\\s+(?:checkbox\\s+|switch\\s+)?${q}$`,"i"),SELECT_DROPDOWN:new RegExp(`^(?:select|choose)\\s+${q}\\s+from\\s+${q}$`,"i"),LAUNCH_APP:new RegExp(`^(?:launch|open)\\s+(?:app\\s+)?${q}$`,"i"),RESTART_APP:new RegExp(`^(?:restart|relaunch)\\s+(?:app\\s+)?${q}$`,"i"),TERMINATE_APP:new RegExp(`^(?:terminate|close|force\\s*stop)\\s+(?:app\\s+)?(?:${q})?$`,"i"),CLEAR_DATA:new RegExp(`^(?:clear\\s+(?:app\\s+)?data\\s+(?:for\\s+)?|reset\\s+app\\s+)${q}$`,"i"),GRANT_PERMISSION:new RegExp(`^grant\\s+permissions?\\s+${q}(?:\\s+(?:to|for)\\s+${q})?$`,"i"),DEEP_LINK:new RegExp(`^(?:open\\s+deep\\s*link|navigate\\s+to\\s+url)\\s+${q}$`,"i"),WAIT:/^wait\s+(\d+)\s*(?:s|sec|seconds|ms)?$/i,WAIT_UNTIL:new RegExp(`^(?:wait\\s+until|wait\\s+for)\\s+${q}\\s+(?:(?:is\\s+)?(visible|appears?|enabled|exists))?(?:\\s+(?:up\\s+to|for)\\s+(\\d+)\\s*(s|sec|seconds|ms)?)?$`,"i"),IF_VISIBLE:new RegExp(`^if\\s+(?:(?:that\\s+)?${q}\\s+(?:is\\s+)?(visible|present|exists|appears?)|element\\s+${q}\\s+(?:is\\s+)?visible)$`,"i"),ELSE:/^else$/i,END:/^(?:end|end\s*if|end\s*loop|fi|done)$/i,LOOP:/^(?:loop|repeat)\s+(\d+)\s*(?:times)?$/i,FOR_EACH:new RegExp(`^for\\s+each\\s+(?:item\\s+)?(?:in\\s+)?${q}$`,"i"),SET_VARIABLE:/^set\s+\$([a-zA-Z0-9_]+)\s*=\s*(.+)$/i,DEVICE_WIFI:/^(?:turn\s+|set\s+)?wifi\s+(on|off|enable|disable)$/i,DEVICE_AIRPLANE:/^(?:turn\s+|set\\s+)?airplane\s*(?:mode)?\s+(on|off|enable|disable)$/i,DEVICE_ORIENTATION:/^(?:set\s+)?orientation\s+(?:to\s+)?(portrait|landscape)$/i,DEVICE_NOTIFICATIONS:/^(open|expand|pull\s+down|collapse|close)\s+notification(?:s|\s+shade)?$/i,INCLUDE_SPEC:new RegExp(`^(?:include|run_spec|subflow)\\s+${q}$`,"i"),RUN_JS:/^(?:run\s+js|eval\s+js|js)(?::|\s+)(.+)$/i,ENTER_OTP:new RegExp(`^(?:enter|input|type)\\s+(?:the\\s+)?(?:verification\\s+code|otp|2fa\\s+code|sms\\s+code)(?:\\s+just\\s+sent)?(?:\\s+(?:in|into)\\s+${q})?$`,"i"),API_REQUEST:new RegExp(`^(?:api|call\\s+api)\\s+(GET|POST|PUT|DELETE|PATCH)\\s+${q}(?:\\s+with\\s+body\\s+${q})?(?:\\s+store\\s+${q}\\s+as\\s+\\$([a-zA-Z0-9_]+))?(?:\\s+assert\\s+status\\s+(\\d+))?$`,"i"),EMAIL_ASSERT:new RegExp(`^(?:assert|verify)\\s+email\\s+to\\s+${q}\\s+with\\s+subject\\s+${q}(?:\\s+contains\\s+${q})?$`,"i"),OPTIONAL_SUFFIX:/\s*\((?:optional|if\s+present|maybe)\)\s*$/i,FALLBACK_QUOTED_TAP:/^(?:tap|click)\s+.*?['"]([^'"]+)['"]/i},kt={HIERARCHY_ROOT:/<hierarchy[^>]*>([\s\S]*?)<\/hierarchy>/i,NODE_TAG:/<node\b([^>]*?)(\/?)>|<\/node>/gi,ATTR_KEY_VALUE:/([a-zA-Z0-9_-]+)="([^"]*)"/g,BOUNDS_RECT:/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/};nn=new Map;an=["sign in","signin","login","log in","submit","save","continue","next","done","send","confirm","proceed","post","rate","enter","join","apply","update"],cn=["sign in","signin","login","log in","submit","save","next","continue","done","like","fav","favorite","star","bookmark","add","post","confirm","apply","explore","search","filter"]});function ln(p){let t=p.match(kt.BOUNDS_RECT);if(!t)return{x1:0,y1:0,x2:0,y2:0,width:0,height:0,centerX:0,centerY:0};let e=parseInt(t[1],10),s=parseInt(t[2],10),n=parseInt(t[3],10),r=parseInt(t[4],10);return{x1:e,y1:s,x2:n,y2:r,width:n-e,height:r-s,centerX:Math.round((e+n)/2),centerY:Math.round((s+r)/2)}}function qn(p){let t=p.match(kt.HIERARCHY_ROOT);if(!t)return{root:[],flat:[]};let e=t[1],s=new RegExp(kt.NODE_TAG.source,"gi"),n=new RegExp(kt.ATTR_KEY_VALUE.source,"g"),r=[],i=[],o=[],a;for(;(a=s.exec(e))!==null;){let l=a[0],c=a[1],u=a[2]==="/";if(l.startsWith("</node>")){o.pop();continue}let h={};n.lastIndex=0;let d;for(;(d=n.exec(c))!==null;)h[d[1]]=d[2];let g={index:parseInt(h.index||"0",10),text:gt(h.text||""),resourceId:h["resource-id"]||"",className:h.class||"",packageName:h.package||"",contentDesc:gt(h["content-desc"]||""),bounds:ln(h.bounds||""),clickable:h.clickable==="true",enabled:h.enabled==="true",focused:h.focused==="true",scrollable:h.scrollable==="true",password:h.password==="true",selected:h.selected==="true",checked:h.checked!==void 0?h.checked==="true":void 0,checkable:h.checkable!==void 0?h.checkable==="true":void 0,children:[]};i.push(g),o.length===0?r.push(g):o[o.length-1].children.push(g),u||o.push(g)}return{root:r,flat:i}}function Zn(p){let t=[],e=[],s=[],n=p.length,r=0;for(;r<n;){let i=p.indexOf("<",r);if(i===-1)break;if(p.startsWith("<!--",i)){let S=p.indexOf("-->",i+4);r=S===-1?n:S+3;continue}if(p.startsWith("<?",i)){let S=p.indexOf("?>",i+2);r=S===-1?n:S+2;continue}if(p.startsWith("</",i)){let S=p.indexOf(">",i+2);if(S===-1)break;p.slice(i+2,S).trim()==="node"&&s.pop(),r=S+1;continue}let o=-1,a=null,l=!1;for(let S=i+1;S<n;S++){let b=p[S];if(a)b===a&&(a=null);else if(b==='"'||b==="'")a=b;else if(b===">"){o=S,p[S-1]==="/"&&(l=!0);break}}if(o===-1)break;let c=p.slice(i+1,l?o-1:o).trim();r=o+1;let u=0;for(;u<c.length&&!/\s/.test(c[u]);)u++;if(c.slice(0,u)!=="node")continue;let d={},g=u,m=c.length;for(;g<m;){for(;g<m&&/\s/.test(c[g]);)g++;if(g>=m)break;let S=g;for(;g<m&&c[g]!=="="&&!/\s/.test(c[g]);)g++;let b=c.slice(S,g);for(;g<m&&/\s/.test(c[g]);)g++;if(g>=m||c[g]!=="=")break;for(g++;g<m&&/\s/.test(c[g]);)g++;if(g>=m)break;let f=c[g];if(f==='"'||f==="'"){g++;let T=g;for(;g<m&&c[g]!==f;)g++;d[b]=c.slice(T,g),g<m&&g++}else{let T=g;for(;g<m&&!/\s/.test(c[g]);)g++;d[b]=c.slice(T,g)}}let y={index:parseInt(d.index||"0",10),text:gt(d.text||""),resourceId:d["resource-id"]||"",className:d.class||"",packageName:d.package||"",contentDesc:gt(d["content-desc"]||""),bounds:ln(d.bounds||""),clickable:d.clickable==="true",enabled:d.enabled==="true",focused:d.focused==="true",scrollable:d.scrollable==="true",password:d.password==="true",selected:d.selected==="true",checked:d.checked!==void 0?d.checked==="true":void 0,checkable:d.checkable!==void 0?d.checkable==="true":void 0,children:[]};e.push(y),s.length===0?t.push(y):s[s.length-1].children.push(y),l||s.push(y)}return{root:t,flat:e}}function pe(p,t){if((t||E.parser?.mode||"regex")==="streaming")try{return Zn(p)}catch{}return qn(p)}function ke(p){if(p.resourceId&&/logbox/i.test(p.resourceId)||p.className&&/logbox/i.test(p.className))return!0;let t=`${p.text} ${p.contentDesc}`.trim();return!!ei.some(e=>e.test(t))}function _e(p){return p.filter(t=>ke(t)?!1:(t.className.includes("EditText")||t.className.includes("TextInputEditText")||t.focused&&t.clickable)&&t.bounds.width>0&&t.bounds.height>0)}function ss(p){return p.className.includes("EditText")||p.className.includes("TextInputEditText")?!0:(p.children||[]).some(ss)}function it(p,t){let e=t?.width||E.screen.fallbackWidth,s=t?.height||E.screen.fallbackHeight,n=s*.08,r=s*.88,i=p.filter(a=>!ke(a)&&(a.className.includes("RecyclerView")||a.className.includes("ListView")||a.className.includes("ScrollView"))),o=[];for(let a of i)for(let l of a.children){if(ke(l)||l.bounds.centerY<n||l.bounds.centerY>r)continue;(l.clickable||l.children.some(u=>!ke(u)&&u.clickable&&u.bounds.width>e*.1))&&l.bounds.width>e*.08&&l.bounds.height>s*.02&&!ss(l)&&o.push(l)}return o.length===0?p.filter(a=>{if(ke(a))return!1;let l=(a.text||a.contentDesc||"").trim();return l.length<=1||/^(remember me|forgot password|sign in|sign up|login|submit|cancel)$/i.test(l)?!1:a.clickable&&a.bounds.width>e*.14&&a.bounds.height>s*.033&&a.bounds.centerY>n&&a.bounds.centerY<r&&!a.className.includes("Button")&&!a.className.includes("EditText")&&!ss(a)}):o}function Ue(p){return p.filter(t=>{if(ke(t)||!t.clickable||t.bounds.width===0||t.className.includes("EditText"))return!1;let e=t.className.includes("Button")||t.className.includes("ImageButton"),s=cn.some(n=>ne(n,t.text)||ne(n,t.contentDesc)||ne(n,t.resourceId));return e||s})}function Dt(p,t=E.screen.fallbackHeight,e){if(!p||p.length===0)return[];let s=p.find(d=>d.bounds.height>=t*.6&&d.bounds.y1<=t*.15),n=s?.bounds?.y1!==void 0&&s.bounds.y1>=0?s.bounds.y1:0,r=s?.bounds?.y2&&s.bounds.y2>n?s.bounds.y2:t,i=r-n,o=s?.bounds?.x2&&s.bounds.x2>0?s.bounds.x2-(s.bounds.x1||0):E.screen.fallbackWidth,a=n+i*.78,l=p.filter(d=>ke(d)||e&&d.packageName&&!d.packageName.includes(e)||!d.clickable||d.bounds.width<=0||d.bounds.height<=0||!(d.bounds.centerY>=a||d.bounds.y2>=r-20)?!1:d.bounds.width>=o*.12&&d.bounds.width<=o*.55);if(l.length<=1)return l;let c=[];for(let d of l){let g=c.find(m=>Math.abs(m[0].bounds.centerY-d.bounds.centerY)<=30||Math.abs(m[0].bounds.y2-d.bounds.y2)<=20);g||(g=[],c.push(g)),g.push(d)}let u=c.map(d=>{d.sort((m,y)=>m.bounds.centerX-y.bounds.centerX);let g=[];for(let m of d)g.some(y=>Math.abs(y.bounds.centerX-m.bounds.centerX)<o*.08)||g.push(m);return g}).filter(d=>d.length<2||d.length>6?!1:d[d.length-1].bounds.x2-d[0].bounds.x1>=o*.6);return u.length===0?l.slice(0,5):(u.sort((d,g)=>g[0].bounds.centerY-d[0].bounds.centerY),u[0].slice(0,5))}function dn(p){let t=[/fatal\s+exception/i,/unfortunately.*stopped/i,/(?:app|system|process).*(?:isn't|is not|not)\s+responding/i,/(?:isn't|is not|not)\s+responding/i,/force\s+close/i,/network\s+connection\s+(?:failed|lost|error)/i,/something went wrong/i,/(?:failed|unable)\s+to\s+(?:connect|load|fetch)/i];return p.filter(e=>{let s=`${e.text} ${e.contentDesc}`;return t.some(n=>n.test(s))})}function Ie(p,t,e=E.safety?.mode||"strict"){if(e==="disabled")return!1;let s=`${p.text} ${p.contentDesc} ${p.resourceId}`.trim();if((e==="moderate"?si:ti).some(i=>i.test(s)))return!0;let r=t||E.safety?.customBlacklist||[];for(let i of r)if(typeof i=="string"&&i.length>0){if(s.toLowerCase().includes(i.toLowerCase()))return!0}else if(i instanceof RegExp&&i.test(s))return!0;return!1}function Re(p){let t=`${p.text} ${p.contentDesc} ${p.resourceId}`.trim();return ni.some(e=>e.test(t))}function $t(p){for(let t of p){let e=`${t.text} ${t.contentDesc} ${t.resourceId}`;if(t.resourceId.toLowerCase().includes("logbox")||e.includes("Unhandled Promise Rejection")||e.includes("SyntaxError")||e.includes("Encountered two children with the same key")||e.includes("Warning:")||e.includes("Console Error")||e.includes("Console Warning")||e.includes("Console Info")||e.includes("TypeError:")||e.includes("ReferenceError:")||/Log \d+ of \d+/i.test(e)||e.includes("LogBox")&&(t.className.includes("Modal")||t.className.includes("ViewGroup"))){let n="error";/warning/i.test(e)?n="warning":/info/i.test(e)&&(n="info");let r=t.resourceId.includes("notification")||t.bounds.height>0&&t.bounds.height<250,i,o=[];for(let c of p){let u=`${c.text} ${c.contentDesc}`.trim();if(!i){let h=u.match(/\b([a-zA-Z0-9_.-]+\.(?:tsx?|jsx?|js|ts):\d+:\d+)\b/);h&&(i=h[1])}/\b(?:at\s+|\()?[a-zA-Z0-9_.-]+\.(?:tsx?|jsx?|js|ts):\d+/i.test(u)&&!o.includes(u)&&u.length<200&&o.push(u)}let a=p.find(c=>c.clickable&&c.bounds.width>0&&(/^(?:dismiss|close)$/i.test((c.text||"").trim())||/^(?:dismiss|close)$/i.test((c.contentDesc||"").trim())));if(!a&&!r){let u=p.filter(h=>h.clickable&&h.bounds.width>0&&h.bounds.height>0&&!/minimize|copy/i.test(`${h.text} ${h.contentDesc}`)).filter(h=>h.bounds.centerY>E.screen.fallbackHeight*.8);u.length>0&&(u.sort((h,d)=>h.bounds.x1-d.bounds.x1),a=u[0])}!a&&r&&(a=p.find(c=>c.clickable&&c.bounds.y1>=t.bounds.y1-20&&c.bounds.y2<=t.bounds.y2+20&&c.bounds.x1>=t.bounds.x2-120));let l=t.text||t.contentDesc||"React Native LogBox Console Overlay";return{type:"logbox",severity:n,node:t,errorText:l,sourceLocation:i,stackTrace:o.length>0?o:void 0,dismissButton:a,isToast:r}}if(t.resourceId.includes("alertTitle")&&(e.includes("isn't responding")||e.includes("has stopped"))){let n=p.find(r=>r.text.toLowerCase().includes("close app")||r.text.toLowerCase().includes("ok"));return{type:"anr",severity:"error",node:t,errorText:t.text||"Application Not Responding (ANR)",dismissButton:n}}}return null}function mt(p){return p.filter(t=>ke(t)?!1:(t.checkable||t.className.includes("CheckBox")||t.className.includes("Switch")||t.className.includes("RadioButton")||t.className.includes("SwitchCompat"))&&t.bounds.width>0&&t.bounds.height>0)}function Ke(p,t=E.screen.fallbackHeight,e=E.screen.fallbackWidth){let s=t*.22,n=/(?:menu|hamburger|drawer|navigation|\u2630|open[_\s-]*drawer)/i,r=p.find(i=>{if(!i.clickable||i.bounds.width===0||i.bounds.centerY>s)return!1;let o=`${i.contentDesc} ${i.text} ${i.resourceId}`;return n.test(o)});return r||p.find(i=>{if(!i.clickable||i.bounds.width===0||i.bounds.height===0||i.bounds.centerY>s||(i.text||i.contentDesc||"").trim().length>0)return!1;let a=i.bounds.x1<=e*.25,l=i.bounds.width<=250&&i.bounds.height<=250;return a&&l})||null}function un(p,t=E.screen.fallbackHeight,e=E.screen.fallbackWidth){let s=t*.22;return p.filter(n=>{if(!n.clickable||n.bounds.width===0||n.bounds.height===0||n.bounds.centerY>s)return!1;let r=n.bounds.x2>=e*.75,i=n.bounds.width<=250&&n.bounds.height<=250;return r&&i})}function pn(p){return p.filter(t=>{if(t.bounds.width===0||t.bounds.height===0)return!1;let e=t.className.includes("ScrollView")||t.className.includes("RecyclerView")||t.className.includes("ListView")||t.className.includes("NestedScrollView");return t.scrollable||e})}function hn(p,t=E.screen.fallbackWidth,e=E.screen.fallbackHeight,s=E.visual.overlapRatio){let n=[];for(let h of p)(h.text||h.clickable)&&h.bounds.width>0&&(h.bounds.x2>t+10&&h.bounds.x1<t&&n.push({type:"OVERFLOW",severity:"WARN",description:`Element "${h.text||h.contentDesc||h.className}" overflows right screen boundary by ${h.bounds.x2-t}px`,elements:[h.text||h.contentDesc||h.className]}),h.bounds.y2>e+20&&h.bounds.y1<e&&n.push({type:"OVERFLOW",severity:"WARN",description:`Element "${h.text||h.contentDesc||h.className}" overflows bottom screen boundary by ${h.bounds.y2-e}px`,elements:[h.text||h.contentDesc||h.className]}));let r=p.filter(h=>h.text&&h.text.trim().length>1&&h.bounds.width>0&&h.bounds.height>0),i=200,o=new Map;for(let h of r){let d=Math.floor(h.bounds.y1/i),g=Math.floor(h.bounds.y2/i);for(let m=d;m<=g;m++)o.has(m)||o.set(m,[]),o.get(m).push(h)}let a=new Set;for(let[,h]of o)for(let d=0;d<h.length;d++)for(let g=d+1;g<h.length;g++){let m=h[d],y=h[g];if(m===y||m.text===y.text)continue;let S=m.bounds.x1<y.bounds.x1?`${m.bounds.x1},${m.bounds.y1}:${y.bounds.x1},${y.bounds.y1}`:`${y.bounds.x1},${y.bounds.y1}:${m.bounds.x1},${m.bounds.y1}`;if(a.has(S))continue;a.add(S);let b=m.bounds,f=y.bounds;if(Math.abs(b.centerY-f.centerY)>(b.height+f.height)/2)continue;let T=Math.max(0,Math.min(b.x2,f.x2)-Math.max(b.x1,f.x1)),P=Math.max(0,Math.min(b.y2,f.y2)-Math.max(b.y1,f.y1)),I=T*P;if(I>0){let v=b.width*b.height,$=f.width*f.height,j=Math.min(v,$);j>0&&I/j>s&&n.push({type:"OVERLAP",severity:"WARN",description:`Visual text collision: "${m.text}" overlaps with "${y.text}" (${Math.round(I)}px\xB2 collision)`,elements:[m.text,y.text]})}}let l=p.filter(h=>(h.className.includes("ProgressBar")||h.className.includes("ActivityIndicator"))&&h.bounds.width>0);l.length>0&&n.push({type:"STALLED_LOADER",severity:"WARN",description:`Active loading indicator (${l[0].className}) detected on screen`,elements:l.map(h=>h.className)});let c=[],u=new Set;for(let h of n){let d=`${h.type}::${[...h.elements].sort().join("::")}`;u.has(d)||(u.add(d),c.push(h))}return c}function ns(p,t,e){let s=t?.height||E.screen.fallbackHeight,n=t?.width||E.screen.fallbackWidth,r=Dt(p,s,e);if(r.length>1&&r[0].bounds.centerY>=s*.75)return{paradigm:"bottom_tabs",roots:r};let i=s*.05,o=s*.22,a=p.filter(c=>{if(ke(c)||e&&c.packageName&&!c.packageName.includes(e))return!1;let u=c.className.includes("Tab")||c.resourceId.toLowerCase().includes("tab")||c.resourceId.toLowerCase().includes("header_tab")||/(?:tab\s*\d|\bphotos\b|\bvideos\b|\baudios\b)/i.test(`${c.text} ${c.contentDesc}`),h=c.bounds.centerY>=i&&c.bounds.centerY<=o,d=c.bounds.height>25&&c.bounds.height<=220;return(u||h)&&c.clickable&&c.bounds.width>50&&d});if(a.length>=2){let c=[];for(let h of a){let d=c.find(g=>Math.abs(g[0].bounds.centerY-h.bounds.centerY)<=20);d||(d=[],c.push(d)),d.push(h)}let u=c.find(h=>h.length>=2);if(u){u.sort((g,m)=>g.bounds.centerX-m.bounds.centerX);let h=[];for(let g of u)h.some(m=>Math.abs(m.bounds.centerX-g.bounds.centerX)<40)||h.push(g);if(!(h.length===2&&h[0].bounds.x1<=n*.25&&h[1].bounds.x2>=n*.75&&!h.some(g=>g.className.includes("Tab")||g.resourceId.toLowerCase().includes("tab")))&&h.length>=2)return{paradigm:"top_tabs",roots:h.slice(0,5)}}}let l=Ke(p,s,n);return l?{paradigm:"drawer",roots:[l]}:{paradigm:"single_hub",roots:[]}}function gn(p,t=2){if(p.length<=t)return p;let e=[];for(let n of p){let r=e.find(i=>{let o=i[0],a=o.className===n.className,l=Math.abs(o.bounds.width-n.bounds.width)<=30,c=Math.abs(o.bounds.height-n.bounds.height)<=30,u=Math.abs(o.bounds.x1-n.bounds.x1)<=30;return a&&l&&c&&u});r||(r=[],e.push(r)),r.push(n)}let s=[];for(let n of e)s.push(...n.slice(0,t));return s}function De(p,t=E.screen.fallbackHeight,e=E.screen.fallbackWidth,s=!1){let n=t*.22,r=e*.28,i=/(?:navigate[_\s-]*up|go[_\s-]*back|^back$|\bback\b|arrow_back|ic_arrow_back|chevron[_\s-]*left|ic_back|btn_back|action_bar_up|header[_\s-]*left|prev(?:ious)?|^close$|\bclose\b|^cancel$|^dismiss$|^done$|^exit$|[<←«‹❮⟨◁◀✕✖×]|\u2190|\u2196|\u2039|\u27E8|\u276E|\u25C1|\u25C0|\u00AB|\u2715|\u2716|\u00D7|[\uF060\uF104\uF053\uF2EA\uF00D\uE5C4\uE5CD])/i,o=a=>a.bounds.width>0&&a.bounds.height>0&&a.bounds.centerY<=n;for(let a of p){if(ke(a)||!o(a))continue;let l=`${a.text||""} ${a.contentDesc||""} ${a.resourceId||""}`.trim();if(i.test(l)||l.length<=2&&/^[<‹«←x✕×\-]$/i.test(l))return a.clickable?a:p.find(u=>u.clickable&&u.bounds.x1<=a.bounds.x1&&u.bounds.x2>=a.bounds.x2&&u.bounds.y1<=a.bounds.y1&&u.bounds.y2>=a.bounds.y2&&u.bounds.width<=300&&u.bounds.height<=300)||a}for(let a of p){if(ke(a)||!o(a)||a.bounds.x1>r)continue;if(a.className.includes("ImageButton")||a.className.includes("ImageView")||a.className.includes("ViewGroup")&&a.bounds.width<=250&&a.bounds.height<=250){let c=`${a.text||""} ${a.contentDesc||""} ${a.resourceId||""}`.toLowerCase();if(c.includes("back")||c.includes("up")||c.includes("arrow")||c.includes("chevron")||c.includes("nav")||c.includes("close")||c.includes("cancel"))return a.clickable?a:p.find(h=>h.clickable&&h.bounds.x1<=a.bounds.x1&&h.bounds.x2>=a.bounds.x2&&h.bounds.y1<=a.bounds.y1&&h.bounds.y2>=a.bounds.y2)||a}}if(s){let a=p.find(l=>{if(ke(l)||!o(l)||!l.clickable)return!1;let c=l.bounds.x1<=r,u=l.bounds.width<=250&&l.bounds.height<=250;return c&&u&&l.bounds.width<e*.4});if(a)return a}return null}var ei,ti,si,ni,je=oe(()=>{"use strict";Pe();Oe();ei=[/logbox/i,/^Log \d+ of \d+/i,/Console (?:Error|Warning|Log|Info)/i,/^Call Stack$/i,/^Source Map$/i,/^(?:Dismiss|Minimize|Copy|View error log)$/i,/\b[\w-]+\.(?:tsx?|jsx?|js|ts):\d+:\d+\b/i,/Unhandled Promise Rejection/i,/SyntaxError/i,/TypeError:/i,/ReferenceError:/i,/Warning:/i,/LogBoxNotificationOverlay/i];ti=[/(?:\b|[_\s-])(?:log[_\s-]*out|sign[_\s-]*out)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:delete|remove)(?:[_\s-]+(?:account|profile|all|data|item|cart|user))?(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:clear[_\s-]+data|wipe|force[_\s-]+stop|factory[_\s-]+reset|uninstall)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:pay|purchase|checkout|buy[_\s-]+now|order[_\s-]+now)(?:\b|[_\s-])/i],si=[/(?:\b|[_\s-])(?:log[_\s-]*out|sign[_\s-]*out)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:delete|remove)[_\s-]+(?:account|profile|user)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:clear[_\s-]+data|wipe|force[_\s-]+stop|factory[_\s-]+reset|uninstall)(?:\b|[_\s-])/i],ni=[/(?:\b|[_\s-])(?:rate[_\s-]*us|review[_\s-]*(?:on|in)[_\s-]*(?:play|store)|play[_\s-]*store)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:visit[_\s-]*(?:our)?[_\s-]*website|privacy[_\s-]*policy|terms[_\s-]*of[_\s-]*service|terms[_\s-]*&[_\s-]*conditions)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:follow[_\s-]*us|share[_\s-]*via|share[_\s-]*app|open[_\s-]*in[_\s-]*browser)(?:\b|[_\s-])/i,/^https?:\/\//i,/(?:www\.[a-z0-9-]+\.[a-z]{2,})/i]});import is from"chalk";var rs,Bt,Be,ft=oe(()=>{"use strict";rs={DEBUG:0,INFO:1,WARN:2,ERROR:3,SILENT:4},Bt=class{currentLevel="INFO";constructor(t){let e=(process.env.LOG_LEVEL||"").toUpperCase();t?this.currentLevel=t:rs[e]!==void 0?this.currentLevel=e:this.currentLevel="INFO"}setLevel(t){this.currentLevel=t}getLevel(){return this.currentLevel}isLevelEnabled(t){return rs[this.currentLevel]<=rs[t]}isJsonMode(){return(process.env.LOG_FORMAT||"").toLowerCase()==="json"}emitJson(t,...e){let s=e.map(r=>typeof r=="object"?JSON.stringify(r):String(r)).join(" "),n={ts:new Date().toISOString(),level:t,msg:s};t==="ERROR"||t==="WARN"?console.error(JSON.stringify(n)):console.log(JSON.stringify(n))}debug(...t){this.isLevelEnabled("DEBUG")&&(this.isJsonMode()?this.emitJson("DEBUG",...t):console.log(is.gray("[DEBUG]"),...t))}info(...t){this.isLevelEnabled("INFO")&&(this.isJsonMode()?this.emitJson("INFO",...t):console.log(...t))}warn(...t){this.isLevelEnabled("WARN")&&(this.isJsonMode()?this.emitJson("WARN",...t):console.warn(is.yellow("[WARN]"),...t))}error(...t){this.isLevelEnabled("ERROR")&&(this.isJsonMode()?this.emitJson("ERROR",...t):console.error(is.red("[ERROR]"),...t))}},Be=new Bt});import mn from"fs";import Ht from"path";import ae from"chalk";function os(p,t=new Set){let e=Ht.resolve(p);if(!mn.existsSync(e))throw new Error(`Included spec file not found: ${e}`);if(t.has(e)){let i=Array.from(t).concat(e);throw new Pt(`Circular spec inclusion detected: ${i.join(" -> ")}`,i)}t.add(e);let n=mn.readFileSync(e,"utf-8").split(`
7
- `),r=[];for(let i of n){let o=i.trim(),a=o.match(W.INCLUDE_SPEC);if(a&&!o.startsWith("#")){let l=ee([a[1],a[2],a[3]]),c=Ht.isAbsolute(l)?l:Ht.resolve(Ht.dirname(e),l),u=os(c,new Set(t));r.push(u)}else r.push(i)}return r.join(`
8
- `)}function ii(p){let t=[],e=[];for(let s of p){if(s._isControl==="END"){e.length>0&&e.pop();continue}if(s._isControl==="ELSE"){e.length>0&&e[e.length-1].step.type==="IF_VISIBLE"&&(e[e.length-1].inElse=!0);continue}let n=t;if(e.length>0){let r=e[e.length-1];r.step.type==="IF_VISIBLE"?r.inElse?(r.step.elseSteps=r.step.elseSteps||[],n=r.step.elseSteps):(r.step.thenSteps=r.step.thenSteps||[],n=r.step.thenSteps):r.step.type==="LOOP"&&(r.step.childSteps=r.step.childSteps||[],n=r.step.childSteps)}n.push(s),(s.type==="IF_VISIBLE"||s.type==="LOOP")&&e.push({step:s,inElse:!1})}return t}function Ut(p,t){let e=p.split(`
9
- `).map(n=>n.trim()).filter(n=>n.length>0&&!n.startsWith("#")),s=[];for(let n of e){let r=st(n,t),i=r.replace(rn,"").trim(),o=W.OPTIONAL_SUFFIX.test(i)||/^[(\[]\s*optional\s*[)\]]/i.test(i)||/^optional\s*:/i.test(i),a=i.replace(W.OPTIONAL_SUFFIX,"").replace(/^[(\[]\s*optional\s*[)\]]\s*/i,"").replace(/^optional\s*:\s*/i,"").trim();if(W.BACK.test(a)){s.push({originalText:r,type:"BACK",optional:o});continue}let l=a.match(W.WAIT);if(l){let x=parseInt(l[1],10),w=a.toLowerCase().includes("ms")?x:x*1e3;s.push({originalText:r,type:"WAIT",durationMs:w,optional:o});continue}let c=a.match(W.WAIT_UNTIL);if(c){let x=ee([c[1],c[2],c[3]]),N=(c[4]||"visible").toLowerCase().includes("enable")?"enabled":"visible",L=c[5]?parseInt(c[5],10):void 0,le=(c[6]||"s").toLowerCase(),U=L?le.includes("ms")?L:L*1e3:void 0;s.push({originalText:r,type:"WAIT_UNTIL",target:x,expectedState:N,durationMs:U,optional:o});continue}let u=a.match(W.IF_VISIBLE);if(u){let x=ee([u[1],u[2],u[3],u[5],u[6],u[7]]);s.push({originalText:r,type:"IF_VISIBLE",conditionTarget:x,thenSteps:[],elseSteps:[],optional:o});continue}if(W.ELSE.test(a)){s.push({originalText:r,type:"IF_VISIBLE",_isControl:"ELSE"});continue}if(W.END.test(a)){s.push({originalText:r,type:"IF_VISIBLE",_isControl:"END"});continue}let h=a.match(W.LOOP);if(h){let x=parseInt(h[1],10);s.push({originalText:r,type:"LOOP",loopCount:x,childSteps:[],optional:o});continue}let d=a.match(W.FOR_EACH);if(d){let x=ee([d[1],d[2],d[3]]);s.push({originalText:r,type:"LOOP",target:x,loopVariable:"item",childSteps:[],optional:o});continue}let g=a.match(W.SET_VARIABLE);if(g){let x=g[1].trim(),w=g[2].trim();s.push({originalText:r,type:"SET_VARIABLE",variableName:x,variableExpression:w,optional:o});continue}let m=a.match(W.DEVICE_WIFI);if(m){let x=m[1].toLowerCase();s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"wifi",deviceStateValue:x==="on"||x==="enable",optional:o});continue}let y=a.match(W.DEVICE_AIRPLANE);if(y){let x=y[1].toLowerCase();s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"airplane",deviceStateValue:x==="on"||x==="enable",optional:o});continue}let S=a.match(W.DEVICE_ORIENTATION);if(S){let x=S[1].toLowerCase();s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"orientation",deviceStateValue:x,optional:o});continue}let b=a.match(W.DEVICE_NOTIFICATIONS);if(b){let x=b[1].toLowerCase(),w=x.startsWith("open")||x.startsWith("expand")||x.startsWith("pull");s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"notifications",deviceStateValue:w?"open":"collapse",optional:o});continue}let f=a.match(W.RUN_JS);if(f){let x=f[1].trim();s.push({originalText:r,type:"RUN_JS",jsCode:x,optional:o});continue}let T=a.match(W.ENTER_OTP);if(T){let x=ee([T[1],T[2],T[3]])||void 0;s.push({originalText:r,type:"ENTER_OTP",target:x,optional:o});continue}let P=a.match(W.API_REQUEST);if(P){let x=P[1].toUpperCase(),w=ee([P[2],P[3],P[4]]),N=ee([P[5],P[6],P[7]])||void 0,L=ee([P[8],P[9],P[10]])||void 0,le=P[11]||void 0,U=P[12]?parseInt(P[12],10):void 0;s.push({originalText:r,type:"API_REQUEST",apiMethod:x,apiUrl:w,apiBody:N,apiStorePath:L,apiStoreVariable:le,apiExpectedStatus:U,optional:o});continue}let I=a.match(W.EMAIL_ASSERT);if(I){let x=ee([I[1],I[2],I[3]]),w=ee([I[4],I[5],I[6]]),N=ee([I[7],I[8],I[9]])||void 0;s.push({originalText:r,type:"EMAIL_ASSERT",emailRecipient:x,emailSubject:w,emailBodyContains:N,optional:o});continue}let v=a.match(W.LAUNCH_APP);if(v){let x=ee([v[1],v[2],v[3]]);s.push({originalText:r,type:"LAUNCH_APP",target:x,optional:o});continue}let $=a.match(W.RESTART_APP);if($){let x=ee([$[1],$[2],$[3]]);s.push({originalText:r,type:"RESTART_APP",target:x,optional:o});continue}let j=a.match(W.TERMINATE_APP);if(j){let x=ee([j[1],j[2],j[3]])||void 0;s.push({originalText:r,type:"TERMINATE_APP",target:x,optional:o});continue}let G=a.match(W.CLEAR_DATA);if(G){let x=ee([G[1],G[2],G[3]]);s.push({originalText:r,type:"CLEAR_DATA",target:x,optional:o});continue}let H=a.match(W.GRANT_PERMISSION);if(H){let x=ee([H[1],H[2],H[3]]),w=ee([H[4],H[5],H[6]])||void 0;s.push({originalText:r,type:"GRANT_PERMISSION",value:x,target:w,optional:o});continue}let be=a.match(W.DEEP_LINK);if(be){let x=ee([be[1],be[2],be[3]]);s.push({originalText:r,type:"DEEP_LINK",target:x,optional:o});continue}let J=a.match(W.DIRECTIONAL_SWIPE);if(J){let x=J[1].toLowerCase(),w=ee([J[2],J[3],J[4]])||void 0;s.push({originalText:r,type:"SWIPE",direction:x,target:w,optional:o});continue}let re=a.match(W.TOGGLE);if(re){let x=(re[1]||"").toLowerCase(),w=ee([re[2],re[3],re[4]]),N=a.toLowerCase().startsWith("uncheck")||x==="off"?!1:x==="on"||a.toLowerCase().startsWith("check")?!0:void 0;s.push({originalText:r,type:"TOGGLE",target:w,desiredState:N,optional:o});continue}let _=a.match(W.SELECT_DROPDOWN);if(_){let x=ee([_[1],_[2],_[3]]),w=ee([_[4],_[5],_[6]]);s.push({originalText:r,type:"SELECT",value:x,target:w,optional:o});continue}let me=a.match(W.SCROLL_TO);if(me){let x=(me[1]||"down").toLowerCase(),w=ee([me[2],me[3],me[4]]);s.push({originalText:r,type:"SCROLL",target:w,direction:x,optional:o});continue}let se=a.match(W.SCROLL);if(se){let x=se[1].toLowerCase();s.push({originalText:r,type:"SCROLL",target:x,direction:x,optional:o});continue}let X=a.match(W.LONG_PRESS);if(X){let x=ee([X[1],X[2],X[3]]);s.push({originalText:r,type:"LONG_PRESS",target:x,optional:o});continue}let O=a.match(W.ORDINAL_TAP);if(O){let x=O[1].toLowerCase(),w=ee([O[2],O[3],O[4]]);s.push({originalText:r,type:"TAP",target:w,ordinal:x,optional:o});continue}let Y=a.match(W.PROXIMITY_TAP);if(Y){let x=ee([Y[1],Y[2],Y[3]]),w=ee([Y[4],Y[5],Y[6]]);s.push({originalText:r,type:"TAP",target:x,relativeTo:w,optional:o});continue}let A=a.match(W.TYPE);if(A){let x=ee([A[1],A[2],A[3]]),w=ee([A[4],A[5],A[6]]);s.push({originalText:r,type:"TYPE",value:x,target:w,optional:o});continue}let M=a.match(W.CLEAR);if(M){let x=ee([M[1],M[2],M[3]]);s.push({originalText:r,type:"CLEAR",target:x,optional:o});continue}let R=a.match(W.VERIFY);if(R){let x=ee([R[1],R[2],R[3]]),w=(R[4]||"visible").toLowerCase(),N=w.includes("not visible")||w.includes("not present")||w.includes("absent")||w.includes("hidden")||w.includes("gone"),L=N?"absent":w==="exists"||w==="enabled"||w==="disabled"?w:"visible";s.push({originalText:r,type:"VERIFY",target:x,expectedState:L,negative:N,optional:o});continue}let F=a.match(W.TAP);if(F&&!a.toLowerCase().includes("back")){let x=ee([F[1],F[2],F[3]]);s.push({originalText:r,type:"TAP",target:x,optional:o});continue}let V=a.match(W.FALLBACK_QUOTED_TAP);if(V&&(a.toLowerCase().startsWith("tap")||a.toLowerCase().startsWith("click"))){s.push({originalText:r,type:"TAP",target:V[1],optional:o});continue}Be.warn(`Unrecognized prompt step: "${n}". Skipping.`)}return ii(s)}function bn(p,t,e){let s=t.map(i=>(i.text||i.contentDesc||"").trim()).filter(i=>i.length>1),n=nt(p,s,3),r=n.length>0?`
2
+ var Ki=Object.defineProperty;var oe=(p,t,e)=>()=>{if(e)throw e[0];try{return p&&(t=p(p=0)),t}catch(s){throw e=[s],s}};var xt=(p,t)=>{for(var e in t)Ki(p,e,{get:t[e],enumerable:!0})};var ue,ti=oe(()=>{"use strict";ue={DEVICES:["devices","-l"],SCREENCAP:["exec-out","screencap","-p"],FOREGROUND_APP:["shell","dumpsys","window"],CURRENT_FOCUS:["shell","dumpsys","activity","activities"],FORCE_STOP:p=>["shell","am","force-stop",p],CLEAR_APP:p=>["shell","pm","clear",p],LAUNCH_APP:p=>["shell","am","start","-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER",p],UIAUTOMATOR_DUMP:["exec-out","uiautomator","dump","--compressed","/dev/tty"],INPUT_TAP:(p,t)=>["shell","input","tap",p.toString(),t.toString()],INPUT_TEXT:p=>["shell","input","text",p],INPUT_KEY:p=>["shell","input","keyevent",p.toString()],INPUT_SWIPE:(p,t,e,s,i=300)=>["shell","input","swipe",p.toString(),t.toString(),e.toString(),s.toString(),i.toString()],LOGCAT_CRASH:p=>["shell","logcat","-d","-b","crash","-s","AndroidRuntime:E"],CLEAR_CRASH_LOGS:()=>["shell","logcat","-b","crash","-c"],GRANT_PERMISSION:(p,t)=>["shell","pm","grant",p,t.startsWith("android.permission.")?t:`android.permission.${t}`],INSTALL_APK:p=>["install","-r",p],UNINSTALL_APP:p=>["uninstall",p],DEEP_LINK:p=>["shell","am","start","-a","android.intent.action.VIEW","-d",p],TCPIP:(p=5555)=>["tcpip",p.toString()],CONNECT:p=>["connect",p],DISCONNECT:p=>p?["disconnect",p]:["disconnect"],GET_WLAN_IP:["shell","ip","-f","inet","addr","show","wlan0"]}});function zi(){let p=process.env.PROMPTTEST_SETTLE_FACTOR;if(!p)return 1;let t=parseFloat(p);return isNaN(t)||t<=0?1:t}function Ee(p,t=50){return Math.max(t,Math.round(p*zi()))}function si(p=P.polling.intervalMs,t=P.polling.jitterMs){return Math.round(p+(Math.random()*2-1)*(t/2))}var P,Pe=oe(()=>{"use strict";P={adb:{commandTimeoutMs:2e4,binaryTimeoutMs:45e3,retryCount:2,retryBaseDelayMs:200},polling:{intervalMs:200,jitterMs:80,defaultTimeoutMs:3e3,extendedTimeoutMs:3500,hierarchyCacheTtlMs:3500,verifyCacheTtlMs:2e3},settle:{get tapMs(){return Ee(500)},get backMs(){return Ee(700)},get launchMs(){return Ee(2500)},get stopMs(){return Ee(600)},get keyboardDismissMs(){return Ee(500)},get scrollMs(){return Ee(350)},get toggleMs(){return Ee(350)},get selectMs(){return Ee(600)},get inputFocusMs(){return Ee(250)},get inputClearMs(){return Ee(150)},get inputDoneMs(){return Ee(350)},get submitWaitMs(){return Ee(1800)}},gestures:{swipeDurationMs:300,longPressDurationMs:1e3,bottomNavThresholdRatio:.88,tapTargetYRatio:.96},recorder:{staleTapTimeoutMs:3e3,asyncRefreshDelayMs:80,heartbeatIntervalMs:1500},screen:{fallbackWidth:1080,fallbackHeight:2400},visual:{overlapRatio:.2},device:{maxDeviceRetries:2,autoReconnect:!0},flow:{maxLoopIterations:50,waitUntilTimeoutMs:1e4,defaultRetryCount:3},ai:{provider:"heuristic",model:"gpt-4o-mini",selfHealing:!0,confidenceThreshold:.75,maxHealingAttempts:2,endpoint:""},memory:{staleThresholdDays:parseInt(process.env.PROMPTTEST_STALE_DAYS||"14",10),staleDecayAmount:.2,minConfidenceFloor:.2,maxHealedConfidence:.65},parser:{mode:process.env.PROMPTTEST_XML_PARSER||"regex"},safety:{mode:process.env.PROMPTTEST_SAFETY_MODE||"strict",customBlacklist:process.env.PROMPTTEST_SAFETY_BLACKLIST?process.env.PROMPTTEST_SAFETY_BLACKLIST.split(",").map(p=>p.trim()).filter(Boolean):[]},explorer:{strategy:process.env.PROMPTTEST_STRATEGY||"heuristic",maxTabs:parseInt(process.env.PROMPTTEST_MAX_TABS||"15",10),maxScreens:parseInt(process.env.PROMPTTEST_MAX_SCREENS||"30",10),maxDepth:parseInt(process.env.PROMPTTEST_MAX_DEPTH||"5",10),stepBudget:parseInt(process.env.PROMPTTEST_STEP_BUDGET||"100",10),screenshots:process.env.PROMPTTEST_SCREENSHOTS||"state-change"},locale:"en"}});var Tt,Et,Pt,At=oe(()=>{"use strict";Tt=class extends Error{exitCode;phase;constructor(t,e=1,s){super(t),this.name="PromptTestError",this.exitCode=e,this.phase=s,Object.setPrototypeOf(this,new.target.prototype)}},Et=class extends Tt{constructor(t,e="Device"){super(t,2,e),this.name="DeviceError"}},Pt=class extends Tt{cycle;constructor(t,e,s="SpecLoader"){super(t,3,s),this.name="SpecRecursionError",this.cycle=e}}});import{spawn as ht}from"child_process";import ts from"readline";var tt,Q,Ae=oe(()=>{"use strict";ti();Pe();At();tt=class{defaultSerial=null;cachedDimensions=new Map;inFlightHierarchies=new Map;constructor(t){t&&(this.defaultSerial=t)}setDefaultDevice(t){this.defaultSerial=t}getDefaultDevice(){return this.defaultSerial}async getScreenDimensions(t){let e=t||this.defaultSerial||"default";if(this.cachedDimensions.has(e))return this.cachedDimensions.get(e);try{let{stdout:i}=await this.execAdb(["shell","wm","size"],t),r=i.match(/(?:Physical|Override)\s*size:\s*(\d+)x(\d+)/i);if(r){let n={width:parseInt(r[1],10),height:parseInt(r[2],10)};return this.cachedDimensions.set(e,n),n}}catch{}let s={width:P.screen.fallbackWidth,height:P.screen.fallbackHeight};return this.cachedDimensions.set(e,s),s}clearScreenDimensionsCache(t){t?this.cachedDimensions.delete(t):this.cachedDimensions.clear()}async getNavigationBarHeight(t){try{let{stdout:e}=await this.execAdb(["shell","dumpsys","window","displays"],t).catch(()=>({stdout:""})),s=e.match(/(?:navigationBarHeight|navBarHeight|navigationBarFrame)[=:\s]+(\d+)/i);if(s&&parseInt(s[1],10)>0)return parseInt(s[1],10)}catch{}return 0}isGlobalAdbCommand(t){return t?["devices","connect","disconnect","version","kill-server","start-server","help"].includes(t.toLowerCase()):!0}async execAdbInternal(t,e,s=2e4){let i=e||this.defaultSerial;!i&&!this.isGlobalAdbCommand(t[0])&&(await this.ensureDefaultDevice(),i=this.defaultSerial);let r=i&&!this.isGlobalAdbCommand(t[0])?["-s",i,...t]:[...t];return new Promise((n,o)=>{let a=ht("adb",r),d="",c="",l=!1,h=setTimeout(()=>{l=!0;try{a.kill("SIGKILL")}catch{}o(new Error(`ADB command timed out after ${s}ms: adb ${r.join(" ")}`))},s);a.stdout.on("data",u=>{d+=u.toString("utf-8")}),a.stderr.on("data",u=>{c+=u.toString("utf-8")}),a.on("close",u=>{clearTimeout(h),!l&&(u===0?n({stdout:d,stderr:c}):o(new Error(`ADB command failed (code ${u}): adb ${r.join(" ")}
3
+ Error: ${c}`)))}),a.on("error",u=>{clearTimeout(h),!l&&o(u)})})}async execAdb(t,e,s=P.adb.commandTimeoutMs,i=P.device.maxDeviceRetries){let r;for(let n=0;n<=i;n++)try{return await this.execAdbInternal(t,e,s)}catch(o){r=o;let a=o instanceof Error?o.message:String(o),d=a.toLowerCase(),c=d.includes("device offline")||d.includes("device not found"),l=c||d.includes("error: closed")||d.includes("timed out");if(n>=i||!l||this.isGlobalAdbCommand(t[0]))throw c?new Et(`Target Android device ${e||this.defaultSerial||""} is offline or disconnected: ${a}`):o;if(P.device.autoReconnect&&c)try{await this.execAdbInternal(["reconnect"],e,5e3).catch(()=>{})}catch{}await new Promise(h=>setTimeout(h,P.adb.retryBaseDelayMs*Math.pow(2,n+1)))}throw r||new Error(`ADB command failed after ${i} retries: ${t.join(" ")}`)}async execAdbBinary(t,e,s=45e3){let i=e||this.defaultSerial;!i&&!this.isGlobalAdbCommand(t[0])&&(await this.ensureDefaultDevice(),i=this.defaultSerial);let r=i&&!this.isGlobalAdbCommand(t[0])?["-s",i,...t]:[...t];return new Promise((n,o)=>{let a=ht("adb",r),d=[],c="",l=!1,h=setTimeout(()=>{l=!0;try{a.kill("SIGKILL")}catch{}o(new Error(`ADB binary command timed out after ${s}ms: adb ${r.join(" ")}`))},s);a.stdout.on("data",u=>d.push(Buffer.from(u))),a.stderr.on("data",u=>{c+=u.toString("utf-8")}),a.on("close",u=>{clearTimeout(h),!l&&(u===0?n(Buffer.concat(d)):o(new Error(`ADB binary command failed (code ${u}): adb ${r.join(" ")}
4
+ ${c}`)))}),a.on("error",u=>{clearTimeout(h),!l&&o(u)})})}async getConnectedDevices(){let{stdout:t}=await this.execAdb(ue.DEVICES),e=t.split(`
5
+ `).map(o=>o.trim()).filter(Boolean),s=e.findIndex(o=>o.toLowerCase().includes("list of devices attached")),i=s!==-1?e.slice(s+1):e,r=[];return r=(o=>{let a=[];for(let d of o){if(!d||d.startsWith("*")||d.toLowerCase().includes("list of devices"))continue;let c=d.split(/\s+/);if(c.length>=2){let l=c[0],h=c[1],u,g;for(let m of c.slice(2))m.startsWith("model:")&&(u=m.replace("model:","")),m.startsWith("product:")&&(g=m.replace("product:",""));a.push({serial:l,state:h,model:u,product:g})}}return a})(i),r}async wakeDevice(t){try{await this.execAdb(["shell","input","keyevent","224"],t),await this.execAdb(["shell","wm","dismiss-keyguard"],t)}catch{}}async ensureDefaultDevice(t){if(t)return await this.wakeDevice(t),t;if(this.defaultSerial)return await this.wakeDevice(this.defaultSerial),this.defaultSerial;let s=(await this.getConnectedDevices()).find(i=>i.state==="device");return s&&(this.defaultSerial=s.serial,await this.wakeDevice(this.defaultSerial)),this.defaultSerial||void 0}async getDeviceModel(t){try{let{stdout:r}=await this.execAdb(["shell","getprop","ro.product.model"],t),n=r.trim();if(n)return n}catch{}let e=await this.getConnectedDevices(),s=t||this.defaultSerial;return e.find(r=>r.serial===s)?.model||s||"Android Device"}async captureScreenshot(t){return this.execAdbBinary(ue.SCREENCAP,t)}async getUiHierarchy(t){let e=t||this.defaultSerial||"default",s=this.inFlightHierarchies.get(e);if(s)return s;let i=(async()=>{try{let{stdout:r}=await this.execAdb(ue.UIAUTOMATOR_DUMP,t,1e4,0),n=r.indexOf("<hierarchy");return n>=0?r.slice(n):r}finally{this.inFlightHierarchies.delete(e)}})();return this.inFlightHierarchies.set(e,i),i}clearInFlightHierarchies(t){t?this.inFlightHierarchies.delete(t):this.inFlightHierarchies.clear()}async getForegroundPackage(t){let e=s=>{let i=s.toLowerCase();return i==="android"||i.includes("systemui")||i.includes("inputmethod")||i.includes("latin")||i.includes("gboard")||i.includes("swiftkey")||i.includes("ime")};try{let{stdout:s}=await this.execAdb(["shell","dumpsys","activity","activities"],t).catch(()=>({stdout:""})),i=s.match(/(?:topResumedActivity|mResumedActivity)=.+?\s+([a-zA-Z0-9._]+)\//);if(i&&i[1]&&!e(i[1]))return i[1];let{stdout:r}=await this.execAdb(ue.FOREGROUND_APP,t),n=r.matchAll(/(?:mCurrentFocus|mFocusedWindow|mFocusedApp|topResumedActivity|mResumedActivity|mFocusedActivity)=.+?\s+([a-zA-Z0-9._]+)\/([a-zA-Z0-9._]+)/g);for(let o of n)if(o&&o[1]&&!e(o[1]))return o[1]}catch{}return null}async tap(t,e,s){await this.execAdb(ue.INPUT_TAP(t,e),s)}async inputText(t,e){let s=t.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/'/g,"\\'").replace(/%/g,"\\%").replace(/ /g,"%s").replace(/&/g,"\\&").replace(/</g,"\\<").replace(/>/g,"\\>").replace(/\(/g,"\\(").replace(/\)/g,"\\)").replace(/;/g,"\\;").replace(/\|/g,"\\|").replace(/\$/g,"\\$").replace(/#/g,"\\#").replace(/\*/g,"\\*").replace(/\?/g,"\\?").replace(/~/g,"\\~").replace(/`/g,"\\`");try{await this.execAdb(ue.INPUT_TEXT(s),e)}catch{for(let i of t)if(i===" ")await this.pressKey(62,e);else if(i==="@")await this.pressKey(77,e);else{let r=i.replace(/([\\"'&<>()|$;#*?~`%])/g,"\\$1");await this.execAdb(["shell","input","text",r],e).catch(()=>{})}}}async pressKey(t,e){await this.execAdb(ue.INPUT_KEY(t),e)}async pressEnter(t){await this.pressKey(66,t)}async pressTab(t){await this.pressKey(61,t)}async pressHome(t){await this.pressKey(3,t)}async pressBack(t){await this.pressKey(4,t)}async setWifiEnabled(t,e){await this.execAdb(["shell","svc","wifi",t?"enable":"disable"],e)}async setAirplaneMode(t,e){await this.execAdb(["shell","cmd","connectivity","airplane-mode",t?"enable":"disable"],e)}async setOrientation(t,e){await this.execAdb(["shell","content","insert","--uri","content://settings/system","--bind","name:s:accelerometer_rotation","--bind","value:i:0"],e).catch(()=>{});let s=t==="landscape"?"1":"0";await this.execAdb(["shell","settings","put","system","user_rotation",s],e)}async openNotificationShade(t){await this.execAdb(["shell","cmd","statusbar","expand-notifications"],t)}async collapseNotificationShade(t){await this.execAdb(["shell","cmd","statusbar","collapse"],t)}async clearInput(t=45,e){let s=Array(t).fill("67");await this.execAdb(["shell","input","keyevent",...s],e)}async clearField(t,e=80){await this.pressKey(123,t);let s=Math.max(50,e+10),i=Array(s).fill("67");await this.execAdb(["shell","input","keyevent",...i],t).catch(()=>{}),await this.pressKey(122,t);let r=Array(Math.max(30,Math.floor(e/2))).fill("112");await this.execAdb(["shell","input","keyevent",...r],t).catch(()=>{})}async swipe(t,e,s,i,r=300,n){await this.execAdb(ue.INPUT_SWIPE(t,e,s,i,r),n)}async launchApp(t,e){try{let{stdout:s}=await this.execAdb(["shell","cmd","package","resolve-activity","--brief",t],e),r=(s||"").split(`
6
+ `).map(n=>n.trim()).find(n=>n.includes("/")&&!n.includes(" "));if(r){await this.execAdb(["shell","am","start","-n",r],e);return}}catch{}await this.execAdb(ue.LAUNCH_APP(t),e)}async forceStop(t,e){await this.execAdb(ue.FORCE_STOP(t),e)}async clearAppData(t,e){await this.execAdb(ue.CLEAR_APP(t),e)}async restartApp(t,e){await this.forceStop(t,e),await new Promise(s=>setTimeout(s,600)),await this.launchApp(t,e)}async grantPermission(t,e,s){await this.execAdb(ue.GRANT_PERMISSION(t,e),s)}async isAppInstalled(t,e){try{let{stdout:s}=await this.execAdb(["shell","pm","list","packages",t],e);return s.toLowerCase().includes(`package:${t.toLowerCase()}`)||s.includes(t)}catch{return!1}}async installApk(t,e){await this.execAdb(ue.INSTALL_APK(t),e)}async uninstallApp(t,e){await this.execAdb(ue.UNINSTALL_APP(t),e)}async openDeepLink(t,e){await this.execAdb(ue.DEEP_LINK(t),e)}async checkCrashes(t,e){try{let{stdout:s}=await this.execAdb(ue.LOGCAT_CRASH(t),e);if(s&&s.includes("FATAL EXCEPTION")&&s.includes(t))return s}catch{}return null}async clearCrashLogs(t){try{await this.execAdb(ue.CLEAR_CRASH_LOGS(),t)}catch{}}async getDeviceIp(t){try{let{stdout:e}=await this.execAdb(ue.GET_WLAN_IP,t),s=e.match(/inet\s+(\d+\.\d+\.\d+\.\d+)/);if(s&&s[1])return s[1]}catch{}try{let{stdout:e}=await this.execAdb(["shell","ip","route"],t),s=e.match(/src\s+(\d+\.\d+\.\d+\.\d+)/);if(s&&s[1])return s[1]}catch{}return null}async connectWifi(t,e=5555,s){let i=t,r=e;if(t&&t.includes(":")){let l=t.split(":");i=l[0],r=parseInt(l[1],10)||e}if(!i){let l=await this.getDeviceIp(s);if(!l)throw new Error("Could not auto-detect phone Wi-Fi IP. Make sure the phone is on Wi-Fi, or pass IP manually: npx prompttest wifi <ip>");i=l}let n=`${i}:${r}`;if(t)try{let{stdout:l,stderr:h}=await this.execAdb(ue.CONNECT(n)),u=`${l} ${h}`.trim();if(u.toLowerCase().includes("connected")||u.toLowerCase().includes("already"))return this.defaultSerial=n,{success:!0,target:n,message:u}}catch{}try{await this.execAdb(ue.TCPIP(r),s),await new Promise(l=>setTimeout(l,1e3))}catch{}let{stdout:o,stderr:a}=await this.execAdb(ue.CONNECT(n)),d=`${o} ${a}`.trim(),c=d.toLowerCase().includes("connected")||d.toLowerCase().includes("already");return c&&(this.defaultSerial=n),{success:c,target:n,message:d}}async disconnectWifi(t){let{stdout:e,stderr:s}=await this.execAdb(ue.DISCONNECT(t));return`${e} ${s}`.trim()}streamLogcatEvents(t,e){let i=ht("adb",["-s",t,"shell","logcat","-b","events","-v","time"]),r=ts.createInterface({input:i.stdout});return r.on("line",e),i.on("close",()=>{try{r.close()}catch{}}),i.on("error",()=>{}),i}streamLogcatCrashes(t,e){let i=ht("adb",["-s",t,"shell","logcat","-T","1","-s","AndroidRuntime:E","ANRManager:E","-v","time"]),r=ts.createInterface({input:i.stdout});return r.on("line",e),i.on("close",()=>{try{r.close()}catch{}}),i.on("error",()=>{}),i}streamLogcatToasts(t,e){let i=ht("adb",["-s",t,"shell","logcat","-s","Toast:D","Snackbar:D","-v","time"]),r=ts.createInterface({input:i.stdout});return r.on("line",e),i.on("close",()=>{try{r.close()}catch{}}),i.on("error",()=>{}),i}async getLogcatTail(t=150,e){try{let{stdout:s}=await this.execAdb(["logcat","-d","-t",String(t),"-v","time"],e);return s}catch(s){return`Failed to capture logcat: ${s instanceof Error?s.message:String(s)}`}}async startScreenRecording(t="/sdcard/prompttest_temp.mp4",e){let s=e||this.defaultSerial,r=ht("adb",s?["-s",s,"shell","screenrecord",t]:["shell","screenrecord",t]);return r.on("error",()=>{}),{remotePath:t,process:r}}async stopScreenRecording(t,e,s){try{try{t.process.kill("SIGINT")}catch{}return await this.execAdb(["shell","pkill","-2","screenrecord"],s).catch(()=>{}),await new Promise(i=>setTimeout(i,1500)),await this.execAdb(["pull",t.remotePath,e],s),await this.execAdb(["shell","rm","-f",t.remotePath],s).catch(()=>{}),e}catch{return""}}async isKeyboardVisible(t){try{let{stdout:e}=await this.execAdb(["shell","dumpsys","input_method"],t,4e3,0);return e.includes("mInputShown=true")||e.includes("isInputViewShown=true")||e.includes("mHasSurface=true")}catch{return!1}}async ensureAccessibilityServices(t){try{await this.execAdb(["shell","settings","put","secure","accessibility_enabled","1"],t,4e3,0)}catch{}}},Q=new tt});function ri(p){let t=p.trim(),e=t.match(/^"([^"]+)"$/);if(e)return e[1].trim();let s=t.match(/^'([^']+)'$/);return s?s[1].trim():t.replace(/^['"]+|['"]+$/g,"").trim()}function ee(p){for(let t of p)if(t!=null&&t.trim().length>0)return t.trim();return""}function st(p,t){let e=p;if(t)for(let[s,i]of Object.entries(t))e=e.replace(new RegExp(`\\$${s}\\b`,"g"),()=>i);return e=e.replace(/\$ENV\{([A-Z0-9_]+)\}/gi,(s,i)=>process.env[i]||""),e=e.replace(/\$RANDOM_EMAIL\b/g,()=>`test_${Date.now().toString().slice(-6)}@prompttest.io`),e=e.replace(/\$RANDOM_NAME\b/g,()=>`User_${Math.floor(1e3+Math.random()*9e3)}`),e=e.replace(/\$RANDOM_PHONE\b/g,()=>`98${Math.floor(1e7+Math.random()*9e7)}`),e=e.replace(/\$TIMESTAMP\b/g,()=>Date.now().toString()),e=e.replace(/\$UUID\b/g,()=>`${Date.now().toString(16)}-${Math.random().toString(16).substring(2,8)}`),e=e.replace(/\$RANDOM_UUID\b/g,()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let i=Math.random()*16|0;return(s==="x"?i:i&3|8).toString(16)})),e=e.replace(/\$RANDOM_CARD\b/g,()=>{let s="4532";for(let i=0;i<12;i++)s+=Math.floor(Math.random()*10);return s}),e=e.replace(/\$DATE_OFFSET\((-?\d+)\)/g,(s,i)=>{let r=parseInt(i,10)||0;return new Date(Date.now()+r*864e5).toISOString().slice(0,10)}),e=e.replace(/\$RANDOM_INT\((\d+),\s*(\d+)\)/g,(s,i,r)=>{let n=parseInt(i,10),o=parseInt(r,10);return String(Math.floor(n+Math.random()*(o-n+1)))}),e}function gt(p){return(p||"").replace(/&#(\d+);/g,(t,e)=>{try{return String.fromCodePoint(parseInt(e,10))}catch{return""}}).replace(/&#x([0-9a-fA-F]+);/g,(t,e)=>{try{return String.fromCodePoint(parseInt(e,16))}catch{return""}}).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'")}function Z(p){return gt(p||"").trim().toLowerCase().replace(/[\u2018\u2019]/g,"'").replace(/[\u201C\u201D]/g,'"').replace(/\uFFFD/g,"").replace(new RegExp("\\p{Extended_Pictographic}","gu"),"").replace(/[\uE000-\uF8FF\uFFF0-\uFFFF]/g,"").replace(/\s+/g," ").trim()}function ie(p,t){if(!p||!t)return!1;let e=Z(p),s=Z(t);if(e.length<=3){let i=ii.get(e);if(!i){let r=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");i=new RegExp(`(?:^|\\b)${r}(?:\\b|$)`,"i"),ii.set(e,i)}return i.test(s)}return s.includes(e)}function Ji(p,t){let e=Z(p),s=Z(t),i=e.length,r=s.length;if(i===0)return r;if(r===0)return i;let n=Array.from({length:r+1},(a,d)=>d),o=new Array(r+1);for(let a=1;a<=i;a++){o[0]=a;for(let c=1;c<=r;c++){let l=e[a-1]===s[c-1]?0:1;o[c]=Math.min(n[c]+1,o[c-1]+1,n[c-1]+l)}let d=n;n=o,o=d}return n[r]}function Qi(p,t){let e=Z(p),s=Z(t);if(e===s)return 1;if(!e||!s)return 0;let i=Math.max(e.length,s.length);return 1-Ji(e,s)/i}function it(p,t,e=3,s=.35){return Array.from(new Set(t.map(n=>n.trim()).filter(n=>n.length>0))).map(n=>({text:n,score:Qi(p,n)})).filter(n=>n.score>=s).sort((n,o)=>o.score-n.score).slice(0,e)}var ni,q,W,kt,ii,oi,ai,Oe=oe(()=>{"use strict";ni=/^(\d+(?:\.\d+)*\.?|\-|\*)\s*/;q=`(?:"([^"]+)"|'([^']+)'|([^'"\\s][^'"]*?[^'"\\s]|\\S))`;W={TAP:new RegExp(`^(?:tap|click|press)(?:\\s+on)?\\s+(?:button\\s+|item\\s+)?${q}$`,"i"),ORDINAL_TAP:new RegExp(`^(?:tap|click|press)(?:\\s+on)?\\s+(?:the\\s+)?(1st|2nd|3rd|4th|5th|last|first)\\s+(?:button\\s+|item\\s+)?${q}$`,"i"),PROXIMITY_TAP:new RegExp(`^(?:tap|click|press)(?:\\s+on)?\\s+${q}\\s+(?:next\\s+to|near|beside|inside|for)\\s+${q}$`,"i"),CLEAR:new RegExp(`^(?:clear|empty)(?:\\s+(?:text\\s+(?:in|of)|field|input))?\\s+${q}$`,"i"),LONG_PRESS:new RegExp(`^(?:long\\s+press|press\\s+and\\s+hold)\\s+(?:button\\s+|item\\s+)?${q}$`,"i"),TYPE:new RegExp(`^(?:type|enter|input)\\s+${q}\\s+(?:in|into)\\s+${q}$`,"i"),VERIFY:new RegExp(`^(?:verify|veryfy|check|assert|ensure)\\s+(?:that\\s+)?(?:error\\s+message\\s+|message\\s+|text\\s+|element\\s+|button\\s+|toast\\s+|my\\s+)?${q}\\s*(?:is\\s+(visible|exists|appears|enabled|disabled|not\\s+visible|hidden|absent|not\\s+present|gone))?$`,"i"),BACK:/^(?:press\s+back|go\s+back|navigate\s+back|back)$/i,SCROLL_TO:new RegExp(`^(?:scroll|swipe)(?:\\s+(down|up))?\\s+(?:to|until)\\s+${q}$`,"i"),SCROLL:/^(?:scroll|swipe)\s+(down|up)$/i,DIRECTIONAL_SWIPE:new RegExp(`^(?:swipe|scroll)\\s+(left|right|up|down)(?:\\s+on\\s+${q})?$`,"i"),TOGGLE:new RegExp(`^(?:toggle|turn\\s+(on|off)|check|uncheck)\\s+(?:checkbox\\s+|switch\\s+)?${q}$`,"i"),SELECT_DROPDOWN:new RegExp(`^(?:select|choose)\\s+${q}\\s+from\\s+${q}$`,"i"),LAUNCH_APP:new RegExp(`^(?:launch|open)\\s+(?:app\\s+)?${q}$`,"i"),RESTART_APP:new RegExp(`^(?:restart|relaunch)\\s+(?:app\\s+)?${q}$`,"i"),TERMINATE_APP:new RegExp(`^(?:terminate|close|force\\s*stop)\\s+(?:app\\s+)?(?:${q})?$`,"i"),CLEAR_DATA:new RegExp(`^(?:clear\\s+(?:app\\s+)?data\\s+(?:for\\s+)?|reset\\s+app\\s+)${q}$`,"i"),GRANT_PERMISSION:new RegExp(`^grant\\s+permissions?\\s+${q}(?:\\s+(?:to|for)\\s+${q})?$`,"i"),DEEP_LINK:new RegExp(`^(?:open\\s+deep\\s*link|navigate\\s+to\\s+url)\\s+${q}$`,"i"),WAIT:/^wait\s+(\d+)\s*(?:s|sec|seconds|ms)?$/i,WAIT_UNTIL:new RegExp(`^(?:wait\\s+until|wait\\s+for)\\s+${q}\\s+(?:(?:is\\s+)?(visible|appears?|enabled|exists))?(?:\\s+(?:up\\s+to|for)\\s+(\\d+)\\s*(s|sec|seconds|ms)?)?$`,"i"),IF_VISIBLE:new RegExp(`^if\\s+(?:(?:that\\s+)?${q}\\s+(?:is\\s+)?(visible|present|exists|appears?)|element\\s+${q}\\s+(?:is\\s+)?visible)$`,"i"),ELSE:/^else$/i,END:/^(?:end|end\s*if|end\s*loop|fi|done)$/i,LOOP:/^(?:loop|repeat)\s+(\d+)\s*(?:times)?$/i,FOR_EACH:new RegExp(`^for\\s+each\\s+(?:item\\s+)?(?:in\\s+)?${q}$`,"i"),SET_VARIABLE:/^set\s+\$([a-zA-Z0-9_]+)\s*=\s*(.+)$/i,DEVICE_WIFI:/^(?:turn\s+|set\s+)?wifi\s+(on|off|enable|disable)$/i,DEVICE_AIRPLANE:/^(?:turn\s+|set\\s+)?airplane\s*(?:mode)?\s+(on|off|enable|disable)$/i,DEVICE_ORIENTATION:/^(?:set\s+)?orientation\s+(?:to\s+)?(portrait|landscape)$/i,DEVICE_NOTIFICATIONS:/^(open|expand|pull\s+down|collapse|close)\s+notification(?:s|\s+shade)?$/i,INCLUDE_SPEC:new RegExp(`^(?:include|run_spec|subflow)\\s+${q}$`,"i"),RUN_JS:/^(?:run\s+js|eval\s+js|js)(?::|\s+)(.+)$/i,ENTER_OTP:new RegExp(`^(?:enter|input|type)\\s+(?:the\\s+)?(?:verification\\s+code|otp|2fa\\s+code|sms\\s+code)(?:\\s+just\\s+sent)?(?:\\s+(?:in|into)\\s+${q})?$`,"i"),API_REQUEST:new RegExp(`^(?:api|call\\s+api)\\s+(GET|POST|PUT|DELETE|PATCH)\\s+${q}(?:\\s+with\\s+body\\s+${q})?(?:\\s+store\\s+${q}\\s+as\\s+\\$([a-zA-Z0-9_]+))?(?:\\s+assert\\s+status\\s+(\\d+))?$`,"i"),EMAIL_ASSERT:new RegExp(`^(?:assert|verify)\\s+email\\s+to\\s+${q}\\s+with\\s+subject\\s+${q}(?:\\s+contains\\s+${q})?$`,"i"),OPTIONAL_SUFFIX:/\s*\((?:optional|if\s+present|maybe)\)\s*$/i,FALLBACK_QUOTED_TAP:/^(?:tap|click)\s+.*?['"]([^'"]+)['"]/i},kt={HIERARCHY_ROOT:/<hierarchy[^>]*>([\s\S]*?)<\/hierarchy>/i,NODE_TAG:/<node\b([^>]*?)(\/?)>|<\/node>/gi,ATTR_KEY_VALUE:/([a-zA-Z0-9_-]+)="([^"]*)"/g,BOUNDS_RECT:/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/};ii=new Map;oi=["sign in","signin","login","log in","submit","save","continue","next","done","send","confirm","proceed","post","rate","enter","join","apply","update"],ai=["sign in","signin","login","log in","submit","save","next","continue","done","like","fav","favorite","star","bookmark","add","post","confirm","apply","explore","search","filter"]});function ci(p){let t=p.match(kt.BOUNDS_RECT);if(!t)return{x1:0,y1:0,x2:0,y2:0,width:0,height:0,centerX:0,centerY:0};let e=parseInt(t[1],10),s=parseInt(t[2],10),i=parseInt(t[3],10),r=parseInt(t[4],10);return{x1:e,y1:s,x2:i,y2:r,width:i-e,height:r-s,centerX:Math.round((e+i)/2),centerY:Math.round((s+r)/2)}}function qi(p){let t=p.match(kt.HIERARCHY_ROOT);if(!t)return{root:[],flat:[]};let e=t[1],s=new RegExp(kt.NODE_TAG.source,"gi"),i=new RegExp(kt.ATTR_KEY_VALUE.source,"g"),r=[],n=[],o=[],a;for(;(a=s.exec(e))!==null;){let d=a[0],c=a[1],l=a[2]==="/";if(d.startsWith("</node>")){o.pop();continue}let h={};i.lastIndex=0;let u;for(;(u=i.exec(c))!==null;)h[u[1]]=u[2];let g={index:parseInt(h.index||"0",10),text:gt(h.text||""),resourceId:h["resource-id"]||"",className:h.class||"",packageName:h.package||"",contentDesc:gt(h["content-desc"]||""),bounds:ci(h.bounds||""),clickable:h.clickable==="true",enabled:h.enabled==="true",focused:h.focused==="true",scrollable:h.scrollable==="true",password:h.password==="true",selected:h.selected==="true",checked:h.checked!==void 0?h.checked==="true":void 0,checkable:h.checkable!==void 0?h.checkable==="true":void 0,children:[]};n.push(g),o.length===0?r.push(g):o[o.length-1].children.push(g),l||o.push(g)}return{root:r,flat:n}}function Zi(p){let t=[],e=[],s=[],i=p.length,r=0;for(;r<i;){let n=p.indexOf("<",r);if(n===-1)break;if(p.startsWith("<!--",n)){let S=p.indexOf("-->",n+4);r=S===-1?i:S+3;continue}if(p.startsWith("<?",n)){let S=p.indexOf("?>",n+2);r=S===-1?i:S+2;continue}if(p.startsWith("</",n)){let S=p.indexOf(">",n+2);if(S===-1)break;p.slice(n+2,S).trim()==="node"&&s.pop(),r=S+1;continue}let o=-1,a=null,d=!1;for(let S=n+1;S<i;S++){let b=p[S];if(a)b===a&&(a=null);else if(b==='"'||b==="'")a=b;else if(b===">"){o=S,p[S-1]==="/"&&(d=!0);break}}if(o===-1)break;let c=p.slice(n+1,d?o-1:o).trim();r=o+1;let l=0;for(;l<c.length&&!/\s/.test(c[l]);)l++;if(c.slice(0,l)!=="node")continue;let u={},g=l,m=c.length;for(;g<m;){for(;g<m&&/\s/.test(c[g]);)g++;if(g>=m)break;let S=g;for(;g<m&&c[g]!=="="&&!/\s/.test(c[g]);)g++;let b=c.slice(S,g);for(;g<m&&/\s/.test(c[g]);)g++;if(g>=m||c[g]!=="=")break;for(g++;g<m&&/\s/.test(c[g]);)g++;if(g>=m)break;let f=c[g];if(f==='"'||f==="'"){g++;let x=g;for(;g<m&&c[g]!==f;)g++;u[b]=c.slice(x,g),g<m&&g++}else{let x=g;for(;g<m&&!/\s/.test(c[g]);)g++;u[b]=c.slice(x,g)}}let y={index:parseInt(u.index||"0",10),text:gt(u.text||""),resourceId:u["resource-id"]||"",className:u.class||"",packageName:u.package||"",contentDesc:gt(u["content-desc"]||""),bounds:ci(u.bounds||""),clickable:u.clickable==="true",enabled:u.enabled==="true",focused:u.focused==="true",scrollable:u.scrollable==="true",password:u.password==="true",selected:u.selected==="true",checked:u.checked!==void 0?u.checked==="true":void 0,checkable:u.checkable!==void 0?u.checkable==="true":void 0,children:[]};e.push(y),s.length===0?t.push(y):s[s.length-1].children.push(y),d||s.push(y)}return{root:t,flat:e}}function pe(p,t){if((t||P.parser?.mode||"regex")==="streaming")try{return Zi(p)}catch{}return qi(p)}function ke(p){if(p.resourceId&&/logbox/i.test(p.resourceId)||p.className&&/logbox/i.test(p.className))return!0;let t=`${p.text} ${p.contentDesc}`.trim();return!!en.some(e=>e.test(t))}function _e(p){return p.filter(t=>ke(t)?!1:(t.className.includes("EditText")||t.className.includes("TextInputEditText")||t.focused&&t.clickable)&&t.bounds.width>0&&t.bounds.height>0)}function ss(p){return p.className.includes("EditText")||p.className.includes("TextInputEditText")?!0:(p.children||[]).some(ss)}function nt(p,t){let e=t?.width||P.screen.fallbackWidth,s=t?.height||P.screen.fallbackHeight,i=s*.08,r=s*.88,n=p.filter(a=>!ke(a)&&(a.className.includes("RecyclerView")||a.className.includes("ListView")||a.className.includes("ScrollView"))),o=[];for(let a of n)for(let d of a.children){if(ke(d)||d.bounds.centerY<i||d.bounds.centerY>r)continue;(d.clickable||d.children.some(l=>!ke(l)&&l.clickable&&l.bounds.width>e*.1))&&d.bounds.width>e*.08&&d.bounds.height>s*.02&&!ss(d)&&o.push(d)}return o.length===0?p.filter(a=>{if(ke(a))return!1;let d=(a.text||a.contentDesc||"").trim();return d.length<=1||/^(remember me|forgot password|sign in|sign up|login|submit|cancel)$/i.test(d)?!1:a.clickable&&a.bounds.width>e*.14&&a.bounds.height>s*.033&&a.bounds.centerY>i&&a.bounds.centerY<r&&!a.className.includes("Button")&&!a.className.includes("EditText")&&!ss(a)}):o}function Ue(p){return p.filter(t=>{if(ke(t)||!t.clickable||t.bounds.width===0||t.className.includes("EditText"))return!1;let e=t.className.includes("Button")||t.className.includes("ImageButton"),s=ai.some(i=>ie(i,t.text)||ie(i,t.contentDesc)||ie(i,t.resourceId));return e||s})}function Dt(p,t=P.screen.fallbackHeight,e){if(!p||p.length===0)return[];let s=p.find(u=>u.bounds.height>=t*.6&&u.bounds.y1<=t*.15),i=s?.bounds?.y1!==void 0&&s.bounds.y1>=0?s.bounds.y1:0,r=s?.bounds?.y2&&s.bounds.y2>i?s.bounds.y2:t,n=r-i,o=s?.bounds?.x2&&s.bounds.x2>0?s.bounds.x2-(s.bounds.x1||0):P.screen.fallbackWidth,a=i+n*.78,d=p.filter(u=>ke(u)||e&&u.packageName&&!u.packageName.includes(e)||!u.clickable||u.bounds.width<=0||u.bounds.height<=0||!(u.bounds.centerY>=a||u.bounds.y2>=r-20)?!1:u.bounds.width>=o*.12&&u.bounds.width<=o*.55);if(d.length<=1)return d;let c=[];for(let u of d){let g=c.find(m=>Math.abs(m[0].bounds.centerY-u.bounds.centerY)<=30||Math.abs(m[0].bounds.y2-u.bounds.y2)<=20);g||(g=[],c.push(g)),g.push(u)}let l=c.map(u=>{u.sort((m,y)=>m.bounds.centerX-y.bounds.centerX);let g=[];for(let m of u)g.some(y=>Math.abs(y.bounds.centerX-m.bounds.centerX)<o*.08)||g.push(m);return g}).filter(u=>u.length<2||u.length>6?!1:u[u.length-1].bounds.x2-u[0].bounds.x1>=o*.6);return l.length===0?d.slice(0,5):(l.sort((u,g)=>g[0].bounds.centerY-u[0].bounds.centerY),l[0].slice(0,5))}function li(p){let t=[/fatal\s+exception/i,/unfortunately.*stopped/i,/(?:app|system|process).*(?:isn't|is not|not)\s+responding/i,/(?:isn't|is not|not)\s+responding/i,/force\s+close/i,/network\s+connection\s+(?:failed|lost|error)/i,/something went wrong/i,/(?:failed|unable)\s+to\s+(?:connect|load|fetch)/i];return p.filter(e=>{let s=`${e.text} ${e.contentDesc}`;return t.some(i=>i.test(s))})}function Ie(p,t,e=P.safety?.mode||"strict"){if(e==="disabled")return!1;let s=`${p.text} ${p.contentDesc} ${p.resourceId}`.trim();if((e==="moderate"?sn:tn).some(n=>n.test(s)))return!0;let r=t||P.safety?.customBlacklist||[];for(let n of r)if(typeof n=="string"&&n.length>0){if(s.toLowerCase().includes(n.toLowerCase()))return!0}else if(n instanceof RegExp&&n.test(s))return!0;return!1}function Re(p){let t=`${p.text} ${p.contentDesc} ${p.resourceId}`.trim();return nn.some(e=>e.test(t))}function $t(p){for(let t of p){let e=`${t.text} ${t.contentDesc} ${t.resourceId}`;if(t.resourceId.toLowerCase().includes("logbox")||e.includes("Unhandled Promise Rejection")||e.includes("SyntaxError")||e.includes("Encountered two children with the same key")||e.includes("Warning:")||e.includes("Console Error")||e.includes("Console Warning")||e.includes("Console Info")||e.includes("TypeError:")||e.includes("ReferenceError:")||/Log \d+ of \d+/i.test(e)||e.includes("LogBox")&&(t.className.includes("Modal")||t.className.includes("ViewGroup"))){let i="error";/warning/i.test(e)?i="warning":/info/i.test(e)&&(i="info");let r=t.resourceId.includes("notification")||t.bounds.height>0&&t.bounds.height<250,n,o=[];for(let c of p){let l=`${c.text} ${c.contentDesc}`.trim();if(!n){let h=l.match(/\b([a-zA-Z0-9_.-]+\.(?:tsx?|jsx?|js|ts):\d+:\d+)\b/);h&&(n=h[1])}/\b(?:at\s+|\()?[a-zA-Z0-9_.-]+\.(?:tsx?|jsx?|js|ts):\d+/i.test(l)&&!o.includes(l)&&l.length<200&&o.push(l)}let a=p.find(c=>c.clickable&&c.bounds.width>0&&(/^(?:dismiss|close)$/i.test((c.text||"").trim())||/^(?:dismiss|close)$/i.test((c.contentDesc||"").trim())));if(!a&&!r){let l=p.filter(h=>h.clickable&&h.bounds.width>0&&h.bounds.height>0&&!/minimize|copy/i.test(`${h.text} ${h.contentDesc}`)).filter(h=>h.bounds.centerY>P.screen.fallbackHeight*.8);l.length>0&&(l.sort((h,u)=>h.bounds.x1-u.bounds.x1),a=l[0])}!a&&r&&(a=p.find(c=>c.clickable&&c.bounds.y1>=t.bounds.y1-20&&c.bounds.y2<=t.bounds.y2+20&&c.bounds.x1>=t.bounds.x2-120));let d=t.text||t.contentDesc||"React Native LogBox Console Overlay";return{type:"logbox",severity:i,node:t,errorText:d,sourceLocation:n,stackTrace:o.length>0?o:void 0,dismissButton:a,isToast:r}}if(t.resourceId.includes("alertTitle")&&(e.includes("isn't responding")||e.includes("has stopped"))){let i=p.find(r=>r.text.toLowerCase().includes("close app")||r.text.toLowerCase().includes("ok"));return{type:"anr",severity:"error",node:t,errorText:t.text||"Application Not Responding (ANR)",dismissButton:i}}}return null}function mt(p){return p.filter(t=>ke(t)?!1:(t.checkable||t.className.includes("CheckBox")||t.className.includes("Switch")||t.className.includes("RadioButton")||t.className.includes("SwitchCompat"))&&t.bounds.width>0&&t.bounds.height>0)}function Ke(p,t=P.screen.fallbackHeight,e=P.screen.fallbackWidth){let s=t*.22,i=/(?:menu|hamburger|drawer|navigation|\u2630|open[_\s-]*drawer)/i,r=p.find(n=>{if(!n.clickable||n.bounds.width===0||n.bounds.centerY>s)return!1;let o=`${n.contentDesc} ${n.text} ${n.resourceId}`;return i.test(o)});return r||p.find(n=>{if(!n.clickable||n.bounds.width===0||n.bounds.height===0||n.bounds.centerY>s||(n.text||n.contentDesc||"").trim().length>0)return!1;let a=n.bounds.x1<=e*.25,d=n.bounds.width<=250&&n.bounds.height<=250;return a&&d})||null}function di(p,t=P.screen.fallbackHeight,e=P.screen.fallbackWidth){let s=t*.22;return p.filter(i=>{if(!i.clickable||i.bounds.width===0||i.bounds.height===0||i.bounds.centerY>s)return!1;let r=i.bounds.x2>=e*.75,n=i.bounds.width<=250&&i.bounds.height<=250;return r&&n})}function ui(p){return p.filter(t=>{if(t.bounds.width===0||t.bounds.height===0)return!1;let e=t.className.includes("ScrollView")||t.className.includes("RecyclerView")||t.className.includes("ListView")||t.className.includes("NestedScrollView");return t.scrollable||e})}function pi(p,t=P.screen.fallbackWidth,e=P.screen.fallbackHeight,s=P.visual.overlapRatio){let i=[];for(let h of p)(h.text||h.clickable)&&h.bounds.width>0&&(h.bounds.x2>t+10&&h.bounds.x1<t&&i.push({type:"OVERFLOW",severity:"WARN",description:`Element "${h.text||h.contentDesc||h.className}" overflows right screen boundary by ${h.bounds.x2-t}px`,elements:[h.text||h.contentDesc||h.className]}),h.bounds.y2>e+20&&h.bounds.y1<e&&i.push({type:"OVERFLOW",severity:"WARN",description:`Element "${h.text||h.contentDesc||h.className}" overflows bottom screen boundary by ${h.bounds.y2-e}px`,elements:[h.text||h.contentDesc||h.className]}));let r=p.filter(h=>h.text&&h.text.trim().length>1&&h.bounds.width>0&&h.bounds.height>0),n=200,o=new Map;for(let h of r){let u=Math.floor(h.bounds.y1/n),g=Math.floor(h.bounds.y2/n);for(let m=u;m<=g;m++)o.has(m)||o.set(m,[]),o.get(m).push(h)}let a=new Set;for(let[,h]of o)for(let u=0;u<h.length;u++)for(let g=u+1;g<h.length;g++){let m=h[u],y=h[g];if(m===y||m.text===y.text)continue;let S=m.bounds.x1<y.bounds.x1?`${m.bounds.x1},${m.bounds.y1}:${y.bounds.x1},${y.bounds.y1}`:`${y.bounds.x1},${y.bounds.y1}:${m.bounds.x1},${m.bounds.y1}`;if(a.has(S))continue;a.add(S);let b=m.bounds,f=y.bounds;if(Math.abs(b.centerY-f.centerY)>(b.height+f.height)/2)continue;let x=Math.max(0,Math.min(b.x2,f.x2)-Math.max(b.x1,f.x1)),T=Math.max(0,Math.min(b.y2,f.y2)-Math.max(b.y1,f.y1)),$=x*T;if($>0){let v=b.width*b.height,C=f.width*f.height,U=Math.min(v,C);U>0&&$/U>s&&i.push({type:"OVERLAP",severity:"WARN",description:`Visual text collision: "${m.text}" overlaps with "${y.text}" (${Math.round($)}px\xB2 collision)`,elements:[m.text,y.text]})}}let d=p.filter(h=>(h.className.includes("ProgressBar")||h.className.includes("ActivityIndicator"))&&h.bounds.width>0);d.length>0&&i.push({type:"STALLED_LOADER",severity:"WARN",description:`Active loading indicator (${d[0].className}) detected on screen`,elements:d.map(h=>h.className)});let c=[],l=new Set;for(let h of i){let u=`${h.type}::${[...h.elements].sort().join("::")}`;l.has(u)||(l.add(u),c.push(h))}return c}function is(p,t,e){let s=t?.height||P.screen.fallbackHeight,i=t?.width||P.screen.fallbackWidth,r=Dt(p,s,e);if(r.length>1&&r[0].bounds.centerY>=s*.75)return{paradigm:"bottom_tabs",roots:r};let n=s*.05,o=s*.22,a=p.filter(c=>{if(ke(c)||e&&c.packageName&&!c.packageName.includes(e))return!1;let l=c.className.includes("Tab")||c.resourceId.toLowerCase().includes("tab")||c.resourceId.toLowerCase().includes("header_tab")||/(?:tab\s*\d|\bphotos\b|\bvideos\b|\baudios\b)/i.test(`${c.text} ${c.contentDesc}`),h=c.bounds.centerY>=n&&c.bounds.centerY<=o,u=c.bounds.height>25&&c.bounds.height<=220;return(l||h)&&c.clickable&&c.bounds.width>50&&u});if(a.length>=2){let c=[];for(let h of a){let u=c.find(g=>Math.abs(g[0].bounds.centerY-h.bounds.centerY)<=20);u||(u=[],c.push(u)),u.push(h)}let l=c.find(h=>h.length>=2);if(l){l.sort((g,m)=>g.bounds.centerX-m.bounds.centerX);let h=[];for(let g of l)h.some(m=>Math.abs(m.bounds.centerX-g.bounds.centerX)<40)||h.push(g);if(!(h.length===2&&h[0].bounds.x1<=i*.25&&h[1].bounds.x2>=i*.75&&!h.some(g=>g.className.includes("Tab")||g.resourceId.toLowerCase().includes("tab")))&&h.length>=2)return{paradigm:"top_tabs",roots:h.slice(0,5)}}}let d=Ke(p,s,i);return d?{paradigm:"drawer",roots:[d]}:{paradigm:"single_hub",roots:[]}}function hi(p,t=2){if(p.length<=t)return p;let e=[];for(let i of p){let r=e.find(n=>{let o=n[0],a=o.className===i.className,d=Math.abs(o.bounds.width-i.bounds.width)<=30,c=Math.abs(o.bounds.height-i.bounds.height)<=30,l=Math.abs(o.bounds.x1-i.bounds.x1)<=30;return a&&d&&c&&l});r||(r=[],e.push(r)),r.push(i)}let s=[];for(let i of e)s.push(...i.slice(0,t));return s}function De(p,t=P.screen.fallbackHeight,e=P.screen.fallbackWidth,s=!1){let i=t*.22,r=e*.28,n=/(?:navigate[_\s-]*up|go[_\s-]*back|^back$|\bback\b|arrow_back|ic_arrow_back|chevron[_\s-]*left|ic_back|btn_back|action_bar_up|header[_\s-]*left|prev(?:ious)?|^close$|\bclose\b|^cancel$|^dismiss$|^done$|^exit$|[<←«‹❮⟨◁◀✕✖×]|\u2190|\u2196|\u2039|\u27E8|\u276E|\u25C1|\u25C0|\u00AB|\u2715|\u2716|\u00D7|[\uF060\uF104\uF053\uF2EA\uF00D\uE5C4\uE5CD])/i,o=a=>a.bounds.width>0&&a.bounds.height>0&&a.bounds.centerY<=i;for(let a of p){if(ke(a)||!o(a))continue;let d=`${a.text||""} ${a.contentDesc||""} ${a.resourceId||""}`.trim();if(n.test(d)||d.length<=2&&/^[<‹«←x✕×\-]$/i.test(d))return a.clickable?a:p.find(l=>l.clickable&&l.bounds.x1<=a.bounds.x1&&l.bounds.x2>=a.bounds.x2&&l.bounds.y1<=a.bounds.y1&&l.bounds.y2>=a.bounds.y2&&l.bounds.width<=300&&l.bounds.height<=300)||a}for(let a of p){if(ke(a)||!o(a)||a.bounds.x1>r)continue;if(a.className.includes("ImageButton")||a.className.includes("ImageView")||a.className.includes("ViewGroup")&&a.bounds.width<=250&&a.bounds.height<=250){let c=`${a.text||""} ${a.contentDesc||""} ${a.resourceId||""}`.toLowerCase();if(c.includes("back")||c.includes("up")||c.includes("arrow")||c.includes("chevron")||c.includes("nav")||c.includes("close")||c.includes("cancel"))return a.clickable?a:p.find(h=>h.clickable&&h.bounds.x1<=a.bounds.x1&&h.bounds.x2>=a.bounds.x2&&h.bounds.y1<=a.bounds.y1&&h.bounds.y2>=a.bounds.y2)||a}}if(s){let a=p.find(d=>{if(ke(d)||!o(d)||!d.clickable)return!1;let c=d.bounds.x1<=r,l=d.bounds.width<=250&&d.bounds.height<=250;return c&&l&&d.bounds.width<e*.4});if(a)return a}return null}var en,tn,sn,nn,je=oe(()=>{"use strict";Pe();Oe();en=[/logbox/i,/^Log \d+ of \d+/i,/Console (?:Error|Warning|Log|Info)/i,/^Call Stack$/i,/^Source Map$/i,/^(?:Dismiss|Minimize|Copy|View error log)$/i,/\b[\w-]+\.(?:tsx?|jsx?|js|ts):\d+:\d+\b/i,/Unhandled Promise Rejection/i,/SyntaxError/i,/TypeError:/i,/ReferenceError:/i,/Warning:/i,/LogBoxNotificationOverlay/i];tn=[/(?:\b|[_\s-])(?:log[_\s-]*out|sign[_\s-]*out)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:delete|remove)(?:[_\s-]+(?:account|profile|all|data|item|cart|user))?(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:clear[_\s-]+data|wipe|force[_\s-]+stop|factory[_\s-]+reset|uninstall)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:pay|purchase|checkout|buy[_\s-]+now|order[_\s-]+now)(?:\b|[_\s-])/i],sn=[/(?:\b|[_\s-])(?:log[_\s-]*out|sign[_\s-]*out)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:delete|remove)[_\s-]+(?:account|profile|user)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:clear[_\s-]+data|wipe|force[_\s-]+stop|factory[_\s-]+reset|uninstall)(?:\b|[_\s-])/i],nn=[/(?:\b|[_\s-])(?:rate[_\s-]*us|review[_\s-]*(?:on|in)[_\s-]*(?:play|store)|play[_\s-]*store)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:visit[_\s-]*(?:our)?[_\s-]*website|privacy[_\s-]*policy|terms[_\s-]*of[_\s-]*service|terms[_\s-]*&[_\s-]*conditions)(?:\b|[_\s-])/i,/(?:\b|[_\s-])(?:follow[_\s-]*us|share[_\s-]*via|share[_\s-]*app|open[_\s-]*in[_\s-]*browser)(?:\b|[_\s-])/i,/^https?:\/\//i,/(?:www\.[a-z0-9-]+\.[a-z]{2,})/i]});import ns from"chalk";var rs,Bt,Be,ft=oe(()=>{"use strict";rs={DEBUG:0,INFO:1,WARN:2,ERROR:3,SILENT:4},Bt=class{currentLevel="INFO";constructor(t){let e=(process.env.LOG_LEVEL||"").toUpperCase();t?this.currentLevel=t:rs[e]!==void 0?this.currentLevel=e:this.currentLevel="INFO"}setLevel(t){this.currentLevel=t}getLevel(){return this.currentLevel}isLevelEnabled(t){return rs[this.currentLevel]<=rs[t]}isJsonMode(){return(process.env.LOG_FORMAT||"").toLowerCase()==="json"}emitJson(t,...e){let s=e.map(r=>typeof r=="object"?JSON.stringify(r):String(r)).join(" "),i={ts:new Date().toISOString(),level:t,msg:s};t==="ERROR"||t==="WARN"?console.error(JSON.stringify(i)):console.log(JSON.stringify(i))}debug(...t){this.isLevelEnabled("DEBUG")&&(this.isJsonMode()?this.emitJson("DEBUG",...t):console.log(ns.gray("[DEBUG]"),...t))}info(...t){this.isLevelEnabled("INFO")&&(this.isJsonMode()?this.emitJson("INFO",...t):console.log(...t))}warn(...t){this.isLevelEnabled("WARN")&&(this.isJsonMode()?this.emitJson("WARN",...t):console.warn(ns.yellow("[WARN]"),...t))}error(...t){this.isLevelEnabled("ERROR")&&(this.isJsonMode()?this.emitJson("ERROR",...t):console.error(ns.red("[ERROR]"),...t))}},Be=new Bt});import gi from"fs";import Ht from"path";import ae from"chalk";function os(p,t=new Set){let e=Ht.resolve(p);if(!gi.existsSync(e))throw new Error(`Included spec file not found: ${e}`);if(t.has(e)){let n=Array.from(t).concat(e);throw new Pt(`Circular spec inclusion detected: ${n.join(" -> ")}`,n)}t.add(e);let i=gi.readFileSync(e,"utf-8").split(`
7
+ `),r=[];for(let n of i){let o=n.trim(),a=o.match(W.INCLUDE_SPEC);if(a&&!o.startsWith("#")){let d=ee([a[1],a[2],a[3]]),c=Ht.isAbsolute(d)?d:Ht.resolve(Ht.dirname(e),d),l=os(c,new Set(t));r.push(l)}else r.push(n)}return r.join(`
8
+ `)}function rn(p){let t=[],e=[];for(let s of p){if(s._isControl==="END"){e.length>0&&e.pop();continue}if(s._isControl==="ELSE"){e.length>0&&e[e.length-1].step.type==="IF_VISIBLE"&&(e[e.length-1].inElse=!0);continue}let i=t;if(e.length>0){let r=e[e.length-1];r.step.type==="IF_VISIBLE"?r.inElse?(r.step.elseSteps=r.step.elseSteps||[],i=r.step.elseSteps):(r.step.thenSteps=r.step.thenSteps||[],i=r.step.thenSteps):r.step.type==="LOOP"&&(r.step.childSteps=r.step.childSteps||[],i=r.step.childSteps)}i.push(s),(s.type==="IF_VISIBLE"||s.type==="LOOP")&&e.push({step:s,inElse:!1})}return t}function Ut(p,t){let e=p.split(`
9
+ `).map(i=>i.trim()).filter(i=>i.length>0&&!i.startsWith("#")),s=[];for(let i of e){let r=st(i,t),n=r.replace(ni,"").trim(),o=W.OPTIONAL_SUFFIX.test(n)||/^[(\[]\s*optional\s*[)\]]/i.test(n)||/^optional\s*:/i.test(n),a=n.replace(W.OPTIONAL_SUFFIX,"").replace(/^[(\[]\s*optional\s*[)\]]\s*/i,"").replace(/^optional\s*:\s*/i,"").trim();if(W.BACK.test(a)){s.push({originalText:r,type:"BACK",optional:o});continue}let d=a.match(W.WAIT);if(d){let E=parseInt(d[1],10),w=a.toLowerCase().includes("ms")?E:E*1e3;s.push({originalText:r,type:"WAIT",durationMs:w,optional:o});continue}let c=a.match(W.WAIT_UNTIL);if(c){let E=ee([c[1],c[2],c[3]]),N=(c[4]||"visible").toLowerCase().includes("enable")?"enabled":"visible",L=c[5]?parseInt(c[5],10):void 0,le=(c[6]||"s").toLowerCase(),j=L?le.includes("ms")?L:L*1e3:void 0;s.push({originalText:r,type:"WAIT_UNTIL",target:E,expectedState:N,durationMs:j,optional:o});continue}let l=a.match(W.IF_VISIBLE);if(l){let E=ee([l[1],l[2],l[3],l[5],l[6],l[7]]);s.push({originalText:r,type:"IF_VISIBLE",conditionTarget:E,thenSteps:[],elseSteps:[],optional:o});continue}if(W.ELSE.test(a)){s.push({originalText:r,type:"IF_VISIBLE",_isControl:"ELSE"});continue}if(W.END.test(a)){s.push({originalText:r,type:"IF_VISIBLE",_isControl:"END"});continue}let h=a.match(W.LOOP);if(h){let E=parseInt(h[1],10);s.push({originalText:r,type:"LOOP",loopCount:E,childSteps:[],optional:o});continue}let u=a.match(W.FOR_EACH);if(u){let E=ee([u[1],u[2],u[3]]);s.push({originalText:r,type:"LOOP",target:E,loopVariable:"item",childSteps:[],optional:o});continue}let g=a.match(W.SET_VARIABLE);if(g){let E=g[1].trim(),w=g[2].trim();s.push({originalText:r,type:"SET_VARIABLE",variableName:E,variableExpression:w,optional:o});continue}let m=a.match(W.DEVICE_WIFI);if(m){let E=m[1].toLowerCase();s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"wifi",deviceStateValue:E==="on"||E==="enable",optional:o});continue}let y=a.match(W.DEVICE_AIRPLANE);if(y){let E=y[1].toLowerCase();s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"airplane",deviceStateValue:E==="on"||E==="enable",optional:o});continue}let S=a.match(W.DEVICE_ORIENTATION);if(S){let E=S[1].toLowerCase();s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"orientation",deviceStateValue:E,optional:o});continue}let b=a.match(W.DEVICE_NOTIFICATIONS);if(b){let E=b[1].toLowerCase(),w=E.startsWith("open")||E.startsWith("expand")||E.startsWith("pull");s.push({originalText:r,type:"DEVICE_STATE",deviceAction:"notifications",deviceStateValue:w?"open":"collapse",optional:o});continue}let f=a.match(W.RUN_JS);if(f){let E=f[1].trim();s.push({originalText:r,type:"RUN_JS",jsCode:E,optional:o});continue}let x=a.match(W.ENTER_OTP);if(x){let E=ee([x[1],x[2],x[3]])||void 0;s.push({originalText:r,type:"ENTER_OTP",target:E,optional:o});continue}let T=a.match(W.API_REQUEST);if(T){let E=T[1].toUpperCase(),w=ee([T[2],T[3],T[4]]),N=ee([T[5],T[6],T[7]])||void 0,L=ee([T[8],T[9],T[10]])||void 0,le=T[11]||void 0,j=T[12]?parseInt(T[12],10):void 0;s.push({originalText:r,type:"API_REQUEST",apiMethod:E,apiUrl:w,apiBody:N,apiStorePath:L,apiStoreVariable:le,apiExpectedStatus:j,optional:o});continue}let $=a.match(W.EMAIL_ASSERT);if($){let E=ee([$[1],$[2],$[3]]),w=ee([$[4],$[5],$[6]]),N=ee([$[7],$[8],$[9]])||void 0;s.push({originalText:r,type:"EMAIL_ASSERT",emailRecipient:E,emailSubject:w,emailBodyContains:N,optional:o});continue}let v=a.match(W.LAUNCH_APP);if(v){let E=ee([v[1],v[2],v[3]]);s.push({originalText:r,type:"LAUNCH_APP",target:E,optional:o});continue}let C=a.match(W.RESTART_APP);if(C){let E=ee([C[1],C[2],C[3]]);s.push({originalText:r,type:"RESTART_APP",target:E,optional:o});continue}let U=a.match(W.TERMINATE_APP);if(U){let E=ee([U[1],U[2],U[3]])||void 0;s.push({originalText:r,type:"TERMINATE_APP",target:E,optional:o});continue}let G=a.match(W.CLEAR_DATA);if(G){let E=ee([G[1],G[2],G[3]]);s.push({originalText:r,type:"CLEAR_DATA",target:E,optional:o});continue}let H=a.match(W.GRANT_PERMISSION);if(H){let E=ee([H[1],H[2],H[3]]),w=ee([H[4],H[5],H[6]])||void 0;s.push({originalText:r,type:"GRANT_PERMISSION",value:E,target:w,optional:o});continue}let be=a.match(W.DEEP_LINK);if(be){let E=ee([be[1],be[2],be[3]]);s.push({originalText:r,type:"DEEP_LINK",target:E,optional:o});continue}let J=a.match(W.DIRECTIONAL_SWIPE);if(J){let E=J[1].toLowerCase(),w=ee([J[2],J[3],J[4]])||void 0;s.push({originalText:r,type:"SWIPE",direction:E,target:w,optional:o});continue}let re=a.match(W.TOGGLE);if(re){let E=(re[1]||"").toLowerCase(),w=ee([re[2],re[3],re[4]]),N=a.toLowerCase().startsWith("uncheck")||E==="off"?!1:E==="on"||a.toLowerCase().startsWith("check")?!0:void 0;s.push({originalText:r,type:"TOGGLE",target:w,desiredState:N,optional:o});continue}let _=a.match(W.SELECT_DROPDOWN);if(_){let E=ee([_[1],_[2],_[3]]),w=ee([_[4],_[5],_[6]]);s.push({originalText:r,type:"SELECT",value:E,target:w,optional:o});continue}let me=a.match(W.SCROLL_TO);if(me){let E=(me[1]||"down").toLowerCase(),w=ee([me[2],me[3],me[4]]);s.push({originalText:r,type:"SCROLL",target:w,direction:E,optional:o});continue}let se=a.match(W.SCROLL);if(se){let E=se[1].toLowerCase();s.push({originalText:r,type:"SCROLL",target:E,direction:E,optional:o});continue}let X=a.match(W.LONG_PRESS);if(X){let E=ee([X[1],X[2],X[3]]);s.push({originalText:r,type:"LONG_PRESS",target:E,optional:o});continue}let O=a.match(W.ORDINAL_TAP);if(O){let E=O[1].toLowerCase(),w=ee([O[2],O[3],O[4]]);s.push({originalText:r,type:"TAP",target:w,ordinal:E,optional:o});continue}let Y=a.match(W.PROXIMITY_TAP);if(Y){let E=ee([Y[1],Y[2],Y[3]]),w=ee([Y[4],Y[5],Y[6]]);s.push({originalText:r,type:"TAP",target:E,relativeTo:w,optional:o});continue}let A=a.match(W.TYPE);if(A){let E=ee([A[1],A[2],A[3]]),w=ee([A[4],A[5],A[6]]);s.push({originalText:r,type:"TYPE",value:E,target:w,optional:o});continue}let M=a.match(W.CLEAR);if(M){let E=ee([M[1],M[2],M[3]]);s.push({originalText:r,type:"CLEAR",target:E,optional:o});continue}let R=a.match(W.VERIFY);if(R){let E=ee([R[1],R[2],R[3]]),w=(R[4]||"visible").toLowerCase(),N=w.includes("not visible")||w.includes("not present")||w.includes("absent")||w.includes("hidden")||w.includes("gone"),L=N?"absent":w==="exists"||w==="enabled"||w==="disabled"?w:"visible";s.push({originalText:r,type:"VERIFY",target:E,expectedState:L,negative:N,optional:o});continue}let F=a.match(W.TAP);if(F&&!a.toLowerCase().includes("back")){let E=ee([F[1],F[2],F[3]]);s.push({originalText:r,type:"TAP",target:E,optional:o});continue}let V=a.match(W.FALLBACK_QUOTED_TAP);if(V&&(a.toLowerCase().startsWith("tap")||a.toLowerCase().startsWith("click"))){s.push({originalText:r,type:"TAP",target:V[1],optional:o});continue}Be.warn(`Unrecognized prompt step: "${i}". Skipping.`)}return rn(s)}function fi(p,t,e){let s=t.map(n=>(n.text||n.contentDesc||"").trim()).filter(n=>n.length>1),i=it(p,s,3),r=i.length>0?`
10
10
  \u{1F4A1} Did you mean one of these visible items?
11
- `+n.map(i=>` \u2022 "${i.text}" (${Math.round(i.score*100)}% match)`).join(`
11
+ `+i.map(n=>` \u2022 "${n.text}" (${Math.round(n.score*100)}% match)`).join(`
12
12
  `):`
13
- \u{1F4A1} No similar text found on current screen.`;return new Error(`${e}${r}`)}function yn(p,t,e,s){let n=Z(t),r=n.includes("password")||n.includes("passcode")||n.includes("pin")||n.includes("pwd")||n.includes("secret"),i=n.includes("email")||n.includes("mail")||n.includes("user")||n.includes("login")||n.includes("username")||e&&e.includes("@"),o=p.filter(c=>c.className.includes("EditText")&&c.bounds.width>0);if(o.length===0)return null;let a=o.find(c=>ne(t,c.contentDesc)||ne(t,c.resourceId)||ne(t,c.text));if(a)return a;let l=p.filter(c=>!c.className.includes("EditText")&&(ne(t,c.text)||ne(t,c.contentDesc)||ne(t,c.resourceId))&&c.bounds.width>0);for(let c of l){let u=o.filter(h=>h.bounds.centerY>=c.bounds.centerY&&h.bounds.centerY-c.bounds.centerY<300&&Math.abs(h.bounds.centerX-c.bounds.centerX)<450);if(u.length>0)return u.sort((h,d)=>h.bounds.centerY-d.bounds.centerY),u[0]}if(s){let c=s.getAllCandidates("TYPE",t);for(let u of c){let h=o.find(d=>ne(u,d.contentDesc)||ne(u,d.resourceId)||ne(u,d.text));if(h)return h}}if(r){let c=o.find(u=>u.password);if(c)return c;if(o.length>1){let u=o.find(h=>h.text?.toLowerCase().includes("email")||h.contentDesc?.toLowerCase().includes("email"));if(u){let h=o.filter(d=>d.bounds.centerY>u.bounds.centerY);if(h.length>0)return h.sort((d,g)=>d.bounds.centerY-g.bounds.centerY),h[0]}}if(o.length>=2)return o[1]}if(i){let c=o.find(u=>!u.password);if(c)return c;if(o.length>0)return o[0]}return o.length===1?o[0]:null}function jt(p,t,e,s="en",n,r){let i=n?.type||"TAP",o=Z(t),l=p.filter(d=>(Z(d.text)===o||Z(d.contentDesc)===o)&&d.bounds.width>0&&d.bounds.height>0).find(d=>d.clickable);if(l)return[l];let c=e.getAllCandidates(i,t,s,r),u=[];for(let d of c){let g=p.filter(m=>{let y=ne(d,m.text),S=ne(d,m.contentDesc),b=ne(d,m.resourceId);return(y||S||b)&&m.bounds.width>0&&m.bounds.height>0});if(g.length>0){u=g;break}}if(u.length===0){let d=[];for(let m of p)m.text&&m.text.trim().length>1&&d.push(m.text.trim()),m.contentDesc&&m.contentDesc.trim().length>1&&d.push(m.contentDesc.trim());let g=nt(t,d,1);if(g.length>0&&g[0].score>=.8){let m=g[0].text,y=p.filter(S=>(ne(m,S.text)||ne(m,S.contentDesc))&&S.bounds.width>0&&S.bounds.height>0);y.length>0&&(console.log(ae.yellow(` \u{1F4A1} [Self-Healing] Auto-resolved "${t}" \u2192 "${m}" (${Math.round(g[0].score*100)}% match)`)),u=y)}}if(u.length===0)return[];let h=u.filter(d=>{let g=Z(d.text),m=Z(d.contentDesc);return g===o||m===o});if(h.length>0)u=h;else{let d=u.filter(g=>{let m=Z(g.contentDesc);return m.endsWith(o)||m.includes(`, ${o}`)});d.length>0&&(u=d)}if(n?.relativeTo){let d=p.find(g=>ne(n.relativeTo,g.text)||ne(n.relativeTo,g.contentDesc));if(d){let g=u.filter(m=>Math.abs(m.bounds.centerY-d.bounds.centerY)<140).sort((m,y)=>{let S=Math.hypot(m.bounds.centerX-d.bounds.centerX,m.bounds.centerY-d.bounds.centerY),b=Math.hypot(y.bounds.centerX-d.bounds.centerX,y.bounds.centerY-d.bounds.centerY);return S-b});if(g.length>0)return g}}if(n?.ordinal){let d=n.ordinal.toLowerCase();if(d==="1st"||d==="first")return[u[0]];if(d==="2nd"&&u.length>1)return[u[1]];if(d==="3rd"&&u.length>2)return[u[2]];if(d==="4th"&&u.length>3)return[u[3]];if(d==="5th"&&u.length>4)return[u[4]];if(d==="last"&&u.length>0)return[u[u.length-1]]}return u}function ge(p){if(!p||p.length===0)return"0";let t=2166136261;for(let e=0;e<p.length;e++){let s=p[e],n=`${s.text||""}|${s.contentDesc||""}|${s.resourceId||""}|${s.bounds?.x1||0},${s.bounds?.y1||0},${s.bounds?.width||0},${s.bounds?.height||0}`;for(let r=0;r<n.length;r++)t^=n.charCodeAt(r),t=Math.imul(t,16777619)}return(t>>>0).toString(16)}function fn(p){if(!p)return"";let t=p;for(let e of ri)t=t.replace(e,"<VAL>");return t.trim()}function We(p,t){if(!p||p.length===0)return"0";let s=(t?.height||2400)*.04,n=2166136261;for(let r=0;r<p.length;r++){let i=p[r];if(i.bounds&&i.bounds.centerY<s)continue;let o=fn(i.text||""),a=fn(i.contentDesc||""),l=i.resourceId||"",c=i.className||"",u=i.clickable?"1":"0",h=i.checkable?"1":"0",d=Math.round((i.bounds?.x1||0)/50),g=Math.round((i.bounds?.y1||0)/50),m=Math.round((i.bounds?.width||0)/50),y=Math.round((i.bounds?.height||0)/50),S=`${c}|${l}|${o}|${a}|${u}|${h}|${d},${g},${m},${y}`;for(let b=0;b<S.length;b++)n^=S.charCodeAt(b),n=Math.imul(n,16777619)}return(n>>>0).toString(16)}function Sn(p){let t=new Set;if(!p)return t;let e=p.split(",").map(s=>s.trim()).filter(Boolean);for(let s of e)if(s.includes("-")){let[n,r]=s.split("-").map(a=>a.trim()),i=parseInt(n,10),o=parseInt(r,10);if(!isNaN(i)&&!isNaN(o)){let[a,l]=i<=o?[i,o]:[o,i];for(let c=a;c<=l;c++)t.add(c)}}else{let n=parseInt(s,10);isNaN(n)||t.add(n)}return t}function vn(p){let t=new Set,e=p.split(`
14
- `);for(let s of e){let n=s.trim();if(!n.startsWith("#"))continue;let r=n.match(/#\s*@tags?:\s*(.+)/i);if(r){r[1].split(",").map(o=>o.trim().toLowerCase()).filter(Boolean).forEach(o=>t.add(o));continue}let i=n.match(/#\s*@([a-zA-Z0-9_-]+)/);i&&i[1].toLowerCase()!=="tags"&&i[1].toLowerCase()!=="tag"&&t.add(i[1].toLowerCase())}return Array.from(t)}function wn(p){let t=["",ae.bold.cyan(`\u{1F4CB} Parsed Test Steps (${p.length} total):`),ae.gray("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),ae.gray("\u2502")+` ${ae.bold("#".padEnd(3))} `+ae.gray("\u2502")+` ${ae.bold("Type".padEnd(14))} `+ae.gray("\u2502")+` ${ae.bold("Target".padEnd(28))} `+ae.gray("\u2502")+` ${ae.bold("Value / Detail".padEnd(30))} `+ae.gray("\u2502")+` ${ae.bold("Optional".padEnd(8))} `+ae.gray("\u2502"),ae.gray("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524")];return p.forEach((e,s)=>{let n=`${s+1}`.padEnd(3),r=e.type.padEnd(14),i=(e.target||e.conditionTarget||"\u2014").slice(0,28).padEnd(28),o=(e.value||(e.durationMs?`${e.durationMs}ms`:e.expectedState)||"\u2014").slice(0,30).padEnd(30),a=(e.optional?"Yes":"No").padEnd(8);t.push(ae.gray("\u2502")+` ${ae.white(n)} `+ae.gray("\u2502")+` ${ae.cyan(r)} `+ae.gray("\u2502")+` ${ae.yellow(i)} `+ae.gray("\u2502")+` ${ae.white(o)} `+ae.gray("\u2502")+` ${ae.gray(a)} `+ae.gray("\u2502"))}),t.push(ae.gray(`\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
13
+ \u{1F4A1} No similar text found on current screen.`;return new Error(`${e}${r}`)}function bi(p,t,e,s){let i=Z(t),r=i.includes("password")||i.includes("passcode")||i.includes("pin")||i.includes("pwd")||i.includes("secret"),n=i.includes("email")||i.includes("mail")||i.includes("user")||i.includes("login")||i.includes("username")||e&&e.includes("@"),o=p.filter(c=>c.className.includes("EditText")&&c.bounds.width>0);if(o.length===0)return null;let a=o.find(c=>ie(t,c.contentDesc)||ie(t,c.resourceId)||ie(t,c.text));if(a)return a;let d=p.filter(c=>!c.className.includes("EditText")&&(ie(t,c.text)||ie(t,c.contentDesc)||ie(t,c.resourceId))&&c.bounds.width>0);for(let c of d){let l=o.filter(h=>h.bounds.centerY>=c.bounds.centerY&&h.bounds.centerY-c.bounds.centerY<300&&Math.abs(h.bounds.centerX-c.bounds.centerX)<450);if(l.length>0)return l.sort((h,u)=>h.bounds.centerY-u.bounds.centerY),l[0]}if(s){let c=s.getAllCandidates("TYPE",t);for(let l of c){let h=o.find(u=>ie(l,u.contentDesc)||ie(l,u.resourceId)||ie(l,u.text));if(h)return h}}if(r){let c=o.find(l=>l.password);if(c)return c;if(o.length>1){let l=o.find(h=>h.text?.toLowerCase().includes("email")||h.contentDesc?.toLowerCase().includes("email"));if(l){let h=o.filter(u=>u.bounds.centerY>l.bounds.centerY);if(h.length>0)return h.sort((u,g)=>u.bounds.centerY-g.bounds.centerY),h[0]}}if(o.length>=2)return o[1]}if(n){let c=o.find(l=>!l.password);if(c)return c;if(o.length>0)return o[0]}return o.length===1?o[0]:null}function jt(p,t,e,s="en",i,r){let n=i?.type||"TAP",o=Z(t),d=p.filter(u=>(Z(u.text)===o||Z(u.contentDesc)===o)&&u.bounds.width>0&&u.bounds.height>0).find(u=>u.clickable);if(d)return[d];let c=e.getAllCandidates(n,t,s,r),l=[];for(let u of c){let g=p.filter(m=>{let y=ie(u,m.text),S=ie(u,m.contentDesc),b=ie(u,m.resourceId);return(y||S||b)&&m.bounds.width>0&&m.bounds.height>0});if(g.length>0){l=g;break}}if(l.length===0){let u=[];for(let m of p)m.text&&m.text.trim().length>1&&u.push(m.text.trim()),m.contentDesc&&m.contentDesc.trim().length>1&&u.push(m.contentDesc.trim());let g=it(t,u,1);if(g.length>0&&g[0].score>=.8){let m=g[0].text,y=p.filter(S=>(ie(m,S.text)||ie(m,S.contentDesc))&&S.bounds.width>0&&S.bounds.height>0);y.length>0&&(console.log(ae.yellow(` \u{1F4A1} [Self-Healing] Auto-resolved "${t}" \u2192 "${m}" (${Math.round(g[0].score*100)}% match)`)),l=y)}}if(l.length===0)return[];let h=l.filter(u=>{let g=Z(u.text),m=Z(u.contentDesc);return g===o||m===o});if(h.length>0)l=h;else{let u=l.filter(g=>{let m=Z(g.contentDesc);return m.endsWith(o)||m.includes(`, ${o}`)});u.length>0&&(l=u)}if(i?.relativeTo){let u=p.find(g=>ie(i.relativeTo,g.text)||ie(i.relativeTo,g.contentDesc));if(u){let g=l.filter(m=>Math.abs(m.bounds.centerY-u.bounds.centerY)<140).sort((m,y)=>{let S=Math.hypot(m.bounds.centerX-u.bounds.centerX,m.bounds.centerY-u.bounds.centerY),b=Math.hypot(y.bounds.centerX-u.bounds.centerX,y.bounds.centerY-u.bounds.centerY);return S-b});if(g.length>0)return g}}if(i?.ordinal){let u=i.ordinal.toLowerCase();if(u==="1st"||u==="first")return[l[0]];if(u==="2nd"&&l.length>1)return[l[1]];if(u==="3rd"&&l.length>2)return[l[2]];if(u==="4th"&&l.length>3)return[l[3]];if(u==="5th"&&l.length>4)return[l[4]];if(u==="last"&&l.length>0)return[l[l.length-1]]}return l}function ge(p){if(!p||p.length===0)return"0";let t=2166136261;for(let e=0;e<p.length;e++){let s=p[e],i=`${s.text||""}|${s.contentDesc||""}|${s.resourceId||""}|${s.bounds?.x1||0},${s.bounds?.y1||0},${s.bounds?.width||0},${s.bounds?.height||0}`;for(let r=0;r<i.length;r++)t^=i.charCodeAt(r),t=Math.imul(t,16777619)}return(t>>>0).toString(16)}function mi(p){if(!p)return"";let t=p;for(let e of on)t=t.replace(e,"<VAL>");return t.trim()}function We(p,t){if(!p||p.length===0)return"0";let s=(t?.height||2400)*.04,i=2166136261;for(let r=0;r<p.length;r++){let n=p[r];if(n.bounds&&n.bounds.centerY<s)continue;let o=mi(n.text||""),a=mi(n.contentDesc||""),d=n.resourceId||"",c=n.className||"",l=n.clickable?"1":"0",h=n.checkable?"1":"0",u=Math.round((n.bounds?.x1||0)/50),g=Math.round((n.bounds?.y1||0)/50),m=Math.round((n.bounds?.width||0)/50),y=Math.round((n.bounds?.height||0)/50),S=`${c}|${d}|${o}|${a}|${l}|${h}|${u},${g},${m},${y}`;for(let b=0;b<S.length;b++)i^=S.charCodeAt(b),i=Math.imul(i,16777619)}return(i>>>0).toString(16)}function yi(p){let t=new Set;if(!p)return t;let e=p.split(",").map(s=>s.trim()).filter(Boolean);for(let s of e)if(s.includes("-")){let[i,r]=s.split("-").map(a=>a.trim()),n=parseInt(i,10),o=parseInt(r,10);if(!isNaN(n)&&!isNaN(o)){let[a,d]=n<=o?[n,o]:[o,n];for(let c=a;c<=d;c++)t.add(c)}}else{let i=parseInt(s,10);isNaN(i)||t.add(i)}return t}function Si(p){let t=new Set,e=p.split(`
14
+ `);for(let s of e){let i=s.trim();if(!i.startsWith("#"))continue;let r=i.match(/#\s*@tags?:\s*(.+)/i);if(r){r[1].split(",").map(o=>o.trim().toLowerCase()).filter(Boolean).forEach(o=>t.add(o));continue}let n=i.match(/#\s*@([a-zA-Z0-9_-]+)/);n&&n[1].toLowerCase()!=="tags"&&n[1].toLowerCase()!=="tag"&&t.add(n[1].toLowerCase())}return Array.from(t)}function vi(p){let t=["",ae.bold.cyan(`\u{1F4CB} Parsed Test Steps (${p.length} total):`),ae.gray("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),ae.gray("\u2502")+` ${ae.bold("#".padEnd(3))} `+ae.gray("\u2502")+` ${ae.bold("Type".padEnd(14))} `+ae.gray("\u2502")+` ${ae.bold("Target".padEnd(28))} `+ae.gray("\u2502")+` ${ae.bold("Value / Detail".padEnd(30))} `+ae.gray("\u2502")+` ${ae.bold("Optional".padEnd(8))} `+ae.gray("\u2502"),ae.gray("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524")];return p.forEach((e,s)=>{let i=`${s+1}`.padEnd(3),r=e.type.padEnd(14),n=(e.target||e.conditionTarget||"\u2014").slice(0,28).padEnd(28),o=(e.value||(e.durationMs?`${e.durationMs}ms`:e.expectedState)||"\u2014").slice(0,30).padEnd(30),a=(e.optional?"Yes":"No").padEnd(8);t.push(ae.gray("\u2502")+` ${ae.white(i)} `+ae.gray("\u2502")+` ${ae.cyan(r)} `+ae.gray("\u2502")+` ${ae.yellow(n)} `+ae.gray("\u2502")+` ${ae.white(o)} `+ae.gray("\u2502")+` ${ae.gray(a)} `+ae.gray("\u2502"))}),t.push(ae.gray(`\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
15
15
  `)),t.join(`
16
- `)}function Wt(p,t,e=[],s="SKIPPED",n="Validation"){let r=new Date().toISOString(),i=s==="PASS";return{packageName:p||"none",deviceId:t||"none",startTime:r,endTime:r,durationSeconds:0,totalSteps:e.length,passedSteps:i?e.length:0,failedSteps:0,skippedSteps:i?0:e.length,warnSteps:0,errorsDetected:[],steps:e.map((o,a)=>({stepIndex:a+1,timestamp:r,phase:n,description:o.originalText,action:o.type,target:o.target,status:s,durationMs:0}))}}var ri,rt=oe(()=>{"use strict";At();ft();Oe();ri=[/\b\d{1,2}:\d{2}(?::\d{2})?\s*(?:AM|PM|am|pm)?\b/g,/\b\d+\s*(?:sec|min|hr|hour|day|week|month|year)s?\s*ago\b/gi,/\b(?:just now|yesterday|today)\b/gi,/[\$€£₹]\s*\d+(?:\.\d{1,2})?/g,/(?:#|(?:\b(?:ID|No)[\s:-]*))[A-Z0-9_-]{3,}\b/gi,/\b\d{1,3}%\b/g]});import Ye from"fs";import ze from"path";function as(p,t){let e=t?.suiteName||"PromptTest Suite",s=p.failedSteps===0&&p.errorsDetected.length===0,n=s?"ALL PASSED":"ISSUES DETECTED",r=s?"#10b981":"#ef4444",i=p.totalSteps,o=i>0?Math.round(p.passedSteps/i*100):100,a=d=>(d||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"),l=[],c=p.steps.map(d=>{let g=d.status.toLowerCase(),m=d.durationMs!==void 0?`${d.durationMs}ms`:"\u2014",y=t?.screenshotResolver?t.screenshotResolver(d):d.screenshotPath?`./${d.screenshotPath}`:void 0;y&&l.push({stepIndex:d.stepIndex,action:d.action,description:d.description,status:d.status,src:y,durationMs:d.durationMs});let S="\u2014";if(d.triageBundle){let P=a(d.triageBundle);S=`
16
+ `)}function Wt(p,t,e=[],s="SKIPPED",i="Validation"){let r=new Date().toISOString(),n=s==="PASS";return{packageName:p||"none",deviceId:t||"none",startTime:r,endTime:r,durationSeconds:0,totalSteps:e.length,passedSteps:n?e.length:0,failedSteps:0,skippedSteps:n?0:e.length,warnSteps:0,errorsDetected:[],steps:e.map((o,a)=>({stepIndex:a+1,timestamp:r,phase:i,description:o.originalText,action:o.type,target:o.target,status:s,durationMs:0}))}}var on,rt=oe(()=>{"use strict";At();ft();Oe();on=[/\b\d{1,2}:\d{2}(?::\d{2})?\s*(?:AM|PM|am|pm)?\b/g,/\b\d+\s*(?:sec|min|hr|hour|day|week|month|year)s?\s*ago\b/gi,/\b(?:just now|yesterday|today)\b/gi,/[\$€£₹]\s*\d+(?:\.\d{1,2})?/g,/(?:#|(?:\b(?:ID|No)[\s:-]*))[A-Z0-9_-]{3,}\b/gi,/\b\d{1,3}%\b/g]});import Ye from"fs";import ze from"path";function as(p,t){let e=t?.suiteName||"PromptTest Suite",s=p.failedSteps===0&&p.errorsDetected.length===0,i=s?"ALL PASSED":"ISSUES DETECTED",r=s?"#10b981":"#ef4444",n=p.totalSteps,o=n>0?Math.round(p.passedSteps/n*100):100,a=u=>(u||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"),d=[],c=p.steps.map(u=>{let g=u.status.toLowerCase(),m=u.durationMs!==void 0?`${u.durationMs}ms`:"\u2014",y=t?.screenshotResolver?t.screenshotResolver(u):u.screenshotPath?`./${u.screenshotPath}`:void 0;y&&d.push({stepIndex:u.stepIndex,action:u.action,description:u.description,status:u.status,src:y,durationMs:u.durationMs});let S="\u2014";if(u.triageBundle){let T=a(u.triageBundle);S=`
17
17
  <div class="triage-bundle-links">
18
- <a class="btn-triage" href="./${P}" target="_blank" title="Open Failure Triage Directory">\u{1F50D} Triage Bundle</a>
18
+ <a class="btn-triage" href="./${T}" target="_blank" title="Open Failure Triage Directory">\u{1F50D} Triage Bundle</a>
19
19
  <div class="triage-files">
20
- <a href="./${P}/screenshot.png" target="_blank" class="mini-link">\u{1F4F8} Shot</a>
21
- <a href="./${P}/hierarchy.xml" target="_blank" class="mini-link">\u{1F4C4} XML</a>
22
- <a href="./${P}/logcat_tail.log" target="_blank" class="mini-link">\u{1F4DC} Logcat</a>
23
- <a href="./${P}/match_scores.json" target="_blank" class="mini-link">\u{1F3AF} Scores</a>
20
+ <a href="./${T}/screenshot.png" target="_blank" class="mini-link">\u{1F4F8} Shot</a>
21
+ <a href="./${T}/hierarchy.xml" target="_blank" class="mini-link">\u{1F4C4} XML</a>
22
+ <a href="./${T}/logcat_tail.log" target="_blank" class="mini-link">\u{1F4DC} Logcat</a>
23
+ <a href="./${T}/match_scores.json" target="_blank" class="mini-link">\u{1F3AF} Scores</a>
24
24
  </div>
25
25
  </div>`}else y&&(S=`
26
26
  <div class="screenshot-cell">
27
- <img src="${y}" class="thumb" alt="Step ${d.stepIndex}" onclick="openLightboxByStep(${d.stepIndex})" title="Click to view in full-screen Lightbox"/>
28
- <button class="btn-zoom" onclick="openLightboxByStep(${d.stepIndex})" title="Enlarge Screenshot">\u{1F50D}</button>
29
- </div>`);let b="";if(d.details&&(typeof d.details.diffPercent=="number"||d.details.diffPath||d.details.baselinePath)){let P=typeof d.details.diffPercent=="number"?`${(d.details.diffPercent*100).toFixed(2)}%`:"N/A",I=typeof d.details.threshold=="number"?`${(d.details.threshold*100).toFixed(2)}%`:"2.00%";b=`
27
+ <img src="${y}" class="thumb" alt="Step ${u.stepIndex}" onclick="openLightboxByStep(${u.stepIndex})" title="Click to view in full-screen Lightbox"/>
28
+ <button class="btn-zoom" onclick="openLightboxByStep(${u.stepIndex})" title="Enlarge Screenshot">\u{1F50D}</button>
29
+ </div>`);let b="";if(u.details&&(typeof u.details.diffPercent=="number"||u.details.diffPath||u.details.baselinePath)){let T=typeof u.details.diffPercent=="number"?`${(u.details.diffPercent*100).toFixed(2)}%`:"N/A",$=typeof u.details.threshold=="number"?`${(u.details.threshold*100).toFixed(2)}%`:"2.00%";b=`
30
30
  <div class="diff-viewer-card">
31
31
  <div class="diff-header">
32
- <span class="badge diff-badge">Visual Diff: ${a(P)}</span>
33
- <span class="diff-meta">Threshold: ${a(I)}</span>
32
+ <span class="badge diff-badge">Visual Diff: ${a(T)}</span>
33
+ <span class="diff-meta">Threshold: ${a($)}</span>
34
34
  </div>
35
35
  <div class="diff-grid">
36
- ${d.details.baselinePath?`<div class="diff-pane"><div class="pane-label">Baseline</div><img src="./${a(String(d.details.baselinePath))}" class="diff-thumb" onclick="openLightboxCustom('./${a(String(d.details.baselinePath))}', 'Baseline Screenshot')"/></div>`:""}
36
+ ${u.details.baselinePath?`<div class="diff-pane"><div class="pane-label">Baseline</div><img src="./${a(String(u.details.baselinePath))}" class="diff-thumb" onclick="openLightboxCustom('./${a(String(u.details.baselinePath))}', 'Baseline Screenshot')"/></div>`:""}
37
37
  ${y?`<div class="diff-pane"><div class="pane-label">Actual Screen</div><img src="${y}" class="diff-thumb" onclick="openLightboxCustom('${y}', 'Actual Screenshot')"/></div>`:""}
38
- ${d.details.diffPath?`<div class="diff-pane"><div class="pane-label">Pixel Diff Overlay</div><img src="./${a(String(d.details.diffPath))}" class="diff-thumb" onclick="openLightboxCustom('./${a(String(d.details.diffPath))}', 'Visual Difference Overlay')"/></div>`:""}
38
+ ${u.details.diffPath?`<div class="diff-pane"><div class="pane-label">Pixel Diff Overlay</div><img src="./${a(String(u.details.diffPath))}" class="diff-thumb" onclick="openLightboxCustom('./${a(String(u.details.diffPath))}', 'Visual Difference Overlay')"/></div>`:""}
39
39
  </div>
40
- </div>`}let f="";d.details&&Object.keys(d.details).length>0&&(f=`
40
+ </div>`}let f="";u.details&&Object.keys(u.details).length>0&&(f=`
41
41
  <details class="step-details">
42
42
  <summary>Diagnostics &amp; Context</summary>
43
- <pre>${a(JSON.stringify(d.details,null,2))}</pre>
44
- </details>`);let T=`${d.stepIndex} ${d.phase} ${d.action} ${d.description} ${d.target||""}`.toLowerCase();return`
45
- <tr class="step-row status-${g}" data-status="${g}" data-search="${a(T)}">
46
- <td class="col-num">${d.stepIndex}</td>
47
- <td><span class="badge phase-badge">${a(d.phase)}</span></td>
48
- <td><span class="badge action-badge">${a(d.action)}</span></td>
43
+ <pre>${a(JSON.stringify(u.details,null,2))}</pre>
44
+ </details>`);let x=`${u.stepIndex} ${u.phase} ${u.action} ${u.description} ${u.target||""}`.toLowerCase();return`
45
+ <tr class="step-row status-${g}" data-status="${g}" data-search="${a(x)}">
46
+ <td class="col-num">${u.stepIndex}</td>
47
+ <td><span class="badge phase-badge">${a(u.phase)}</span></td>
48
+ <td><span class="badge action-badge">${a(u.action)}</span></td>
49
49
  <td>
50
- <div class="desc-text">${a(d.description)}</div>
50
+ <div class="desc-text">${a(u.description)}</div>
51
51
  ${b}
52
52
  ${f}
53
53
  </td>
54
- <td><code>${a(d.target||"\u2014")}</code></td>
55
- <td><span class="badge status-badge status-${g}">${d.status}</span></td>
54
+ <td><code>${a(u.target||"\u2014")}</code></td>
55
+ <td><span class="badge status-badge status-${g}">${u.status}</span></td>
56
56
  <td class="col-duration">${m}</td>
57
57
  <td class="col-artifact">${S}</td>
58
58
  </tr>`}).join(`
59
- `),u=p.videoPath?`
59
+ `),l=p.videoPath?`
60
60
  <section class="card video-card">
61
61
  <h3>\u{1F3AC} Session Screen Recording</h3>
62
62
  <video controls preload="metadata" class="recording-player" src="./${a(p.videoPath)}"></video>
@@ -64,7 +64,7 @@ ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async getConnectedDevic
64
64
  <section class="card error-card">
65
65
  <h3>\u26A0\uFE0F Critical Flagged Errors (${p.errorsDetected.length})</h3>
66
66
  <ul class="error-list">
67
- ${p.errorsDetected.map(d=>`<li>\u{1F534} <code>${a(d)}</code></li>`).join(`
67
+ ${p.errorsDetected.map(u=>`<li>\u{1F534} <code>${a(u)}</code></li>`).join(`
68
68
  `)}
69
69
  </ul>
70
70
  </section>`:"";return`<!DOCTYPE html>
@@ -473,7 +473,7 @@ ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async getConnectedDevic
473
473
  <strong>Duration:</strong> ${p.durationSeconds}s (${p.startTime.substring(11,19)} to ${p.endTime.substring(11,19)})
474
474
  </div>
475
475
  </div>
476
- <div class="status-pill">${n}</div>
476
+ <div class="status-pill">${i}</div>
477
477
  </header>
478
478
 
479
479
  <div class="dashboard-grid">
@@ -507,7 +507,7 @@ ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async getConnectedDevic
507
507
  </div>
508
508
  </div>
509
509
 
510
- ${u}
510
+ ${l}
511
511
  ${h}
512
512
 
513
513
  <section class="card">
@@ -572,7 +572,7 @@ ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async getConnectedDevic
572
572
  </div>
573
573
 
574
574
  <script>
575
- const SCREENSHOTS = ${JSON.stringify(l)};
575
+ const SCREENSHOTS = ${JSON.stringify(d)};
576
576
  let currentLightboxIdx = -1;
577
577
  let currentFilter = 'all';
578
578
 
@@ -685,12 +685,12 @@ ${c}`)))}),a.on("error",d=>{clearTimeout(h),!u&&o(d)})})}async getConnectedDevic
685
685
  }
686
686
  </script>
687
687
  </body>
688
- </html>`}var at,bt,Je=oe(()=>{"use strict";at=class{outputDir;steps=[];errorsDetected=[];startTime=new Date;packageName="Unknown";deviceId="Unknown";pendingWrites=[];formats=["json","md","junit","html"];videoPath;embedScreenshots=!1;screenshotBuffers=new Map;stepListeners=[];completeListeners=[];errorListeners=[];constructor(t,e){typeof t=="object"&&t!==null?(this.outputDir=t.outputDir||ze.resolve(process.cwd(),"output"),t.formats&&t.formats.length>0&&(this.formats=t.formats),this.embedScreenshots=!!t.embedScreenshots):(this.outputDir=t||ze.resolve(process.cwd(),"output"),e&&e.length>0&&(this.formats=e)),Ye.existsSync(this.outputDir)||Ye.mkdirSync(this.outputDir,{recursive:!0})}setEmbedScreenshots(t){this.embedScreenshots=t}onStep(t){return this.stepListeners.push(t),()=>{let e=this.stepListeners.indexOf(t);e!==-1&&this.stepListeners.splice(e,1)}}onComplete(t){return this.completeListeners.push(t),()=>{let e=this.completeListeners.indexOf(t);e!==-1&&this.completeListeners.splice(e,1)}}onError(t){return this.errorListeners.push(t),()=>{let e=this.errorListeners.indexOf(t);e!==-1&&this.errorListeners.splice(e,1)}}setFormats(t){this.formats=t}setVideoPath(t){this.videoPath=t}init(t,e){this.packageName=t,this.deviceId=e,this.startTime=new Date,this.steps=[],this.errorsDetected=[],this.pendingWrites=[],this.videoPath=void 0,this.screenshotBuffers.clear()}clearScreenshotBuffers(){this.screenshotBuffers.clear()}logStep(t,e,s,n,r,i,o,a,l){let c=this.steps.length+1,u;if(i){this.embedScreenshots&&this.screenshotBuffers.set(c,i);let d=`step_${c}_${t.toLowerCase().replace(/[^a-z0-9]/g,"_")}.png`,g=ze.join(this.outputDir,d),m=Ye.promises.writeFile(g,i).catch(y=>{console.error(`Warning: Failed to write screenshot ${d}:`,y)}).finally(()=>{let y=this.pendingWrites.indexOf(m);y!==-1&&this.pendingWrites.splice(y,1)});this.pendingWrites.push(m),u=d}let h={stepIndex:c,timestamp:new Date().toISOString(),phase:t,description:e,action:s,target:r,status:n,screenshotPath:u,durationMs:a,triageBundle:l,details:o};this.steps.push(h);for(let d of this.stepListeners)try{d(h)}catch{}return h}logError(t){this.errorsDetected.push(t);for(let e of this.errorListeners)try{e(t)}catch{}}async generateReport(t){this.pendingWrites.length>0&&await Promise.all(this.pendingWrites);let e=new Date,s=Math.round((e.getTime()-this.startTime.getTime())/1e3),n={packageName:this.packageName,deviceId:this.deviceId,startTime:this.startTime.toISOString(),endTime:e.toISOString(),durationSeconds:s,totalSteps:this.steps.length,passedSteps:this.steps.filter(i=>i.status==="PASS").length,failedSteps:this.steps.filter(i=>i.status==="FAIL").length,skippedSteps:this.steps.filter(i=>i.status==="SKIPPED").length,warnSteps:this.steps.filter(i=>i.status==="WARN").length,errorsDetected:this.errorsDetected,videoPath:this.videoPath,steps:this.steps},r=t||"prompttest";if(this.formats.includes("json")){let i=ze.join(this.outputDir,`${r}-results.json`);await Ye.promises.writeFile(i,JSON.stringify(n,null,2),"utf-8")}if(this.formats.includes("md")){let i=ze.join(this.outputDir,`${r}-report.md`),o=this.formatMarkdownReport(n);await Ye.promises.writeFile(i,o,"utf-8")}if(this.formats.includes("junit")){let i=ze.join(this.outputDir,`${r}-junit.xml`),o=this.formatJunitXml(n,r);await Ye.promises.writeFile(i,o,"utf-8")}if(this.formats.includes("html")){let i=ze.join(this.outputDir,`${r}-report.html`),o=this.formatHtmlReport(n,r);await Ye.promises.writeFile(i,o,"utf-8")}for(let i of this.completeListeners)try{i(n)}catch{}return this.clearScreenshotBuffers(),n}escapeXml(t){return(t||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeHtml(t){return(t||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}formatJunitXml(t,e){let s=t.durationSeconds,n=t.failedSteps+(t.errorsDetected.length>0&&t.failedSteps===0?1:0),r=['<?xml version="1.0" encoding="UTF-8"?>',`<testsuites name="PromptTest" tests="${t.totalSteps}" failures="${n}" skipped="${t.skippedSteps}" time="${s}">`,` <testsuite name="${this.escapeXml(e)}" tests="${t.totalSteps}" failures="${n}" skipped="${t.skippedSteps}" time="${s}">`];for(let i of t.steps){let o=`Step ${i.stepIndex}: ${this.escapeXml(i.action)} - ${this.escapeXml(i.description)}`,a=i.durationMs!==void 0?(i.durationMs/1e3).toFixed(3):"1.000";r.push(` <testcase classname="${this.escapeXml(e)}" name="${o}" time="${a}">`),i.status==="FAIL"?r.push(` <failure message="${this.escapeXml(i.description)}">${this.escapeXml(i.description)}</failure>`):i.status==="SKIPPED"&&r.push(` <skipped message="${this.escapeXml(i.description)}"/>`),r.push(" </testcase>")}return t.failedSteps===0&&t.errorsDetected.length>0&&r.push(` <testcase classname="${this.escapeXml(e)}" name="Error Sentinel Crash Detection" time="0.000">`,` <failure message="${this.escapeXml(t.errorsDetected[0])}">${this.escapeXml(t.errorsDetected.join(`
688
+ </html>`}var at,bt,Je=oe(()=>{"use strict";at=class{outputDir;steps=[];errorsDetected=[];startTime=new Date;packageName="Unknown";deviceId="Unknown";pendingWrites=[];formats=["json","md","junit","html"];videoPath;embedScreenshots=!1;screenshotBuffers=new Map;stepListeners=[];completeListeners=[];errorListeners=[];constructor(t,e){typeof t=="object"&&t!==null?(this.outputDir=t.outputDir||ze.resolve(process.cwd(),"output"),t.formats&&t.formats.length>0&&(this.formats=t.formats),this.embedScreenshots=!!t.embedScreenshots):(this.outputDir=t||ze.resolve(process.cwd(),"output"),e&&e.length>0&&(this.formats=e)),Ye.existsSync(this.outputDir)||Ye.mkdirSync(this.outputDir,{recursive:!0})}setEmbedScreenshots(t){this.embedScreenshots=t}onStep(t){return this.stepListeners.push(t),()=>{let e=this.stepListeners.indexOf(t);e!==-1&&this.stepListeners.splice(e,1)}}onComplete(t){return this.completeListeners.push(t),()=>{let e=this.completeListeners.indexOf(t);e!==-1&&this.completeListeners.splice(e,1)}}onError(t){return this.errorListeners.push(t),()=>{let e=this.errorListeners.indexOf(t);e!==-1&&this.errorListeners.splice(e,1)}}setFormats(t){this.formats=t}setVideoPath(t){this.videoPath=t}init(t,e){this.packageName=t,this.deviceId=e,this.startTime=new Date,this.steps=[],this.errorsDetected=[],this.pendingWrites=[],this.videoPath=void 0,this.screenshotBuffers.clear()}clearScreenshotBuffers(){this.screenshotBuffers.clear()}logStep(t,e,s,i,r,n,o,a,d){let c=this.steps.length+1,l;if(n){this.embedScreenshots&&this.screenshotBuffers.set(c,n);let u=`step_${c}_${t.toLowerCase().replace(/[^a-z0-9]/g,"_")}.png`,g=ze.join(this.outputDir,u),m=Ye.promises.writeFile(g,n).catch(y=>{console.error(`Warning: Failed to write screenshot ${u}:`,y)}).finally(()=>{let y=this.pendingWrites.indexOf(m);y!==-1&&this.pendingWrites.splice(y,1)});this.pendingWrites.push(m),l=u}let h={stepIndex:c,timestamp:new Date().toISOString(),phase:t,description:e,action:s,target:r,status:i,screenshotPath:l,durationMs:a,triageBundle:d,details:o};this.steps.push(h);for(let u of this.stepListeners)try{u(h)}catch{}return h}logError(t){this.errorsDetected.push(t);for(let e of this.errorListeners)try{e(t)}catch{}}async generateReport(t){this.pendingWrites.length>0&&await Promise.all(this.pendingWrites);let e=new Date,s=Math.round((e.getTime()-this.startTime.getTime())/1e3),i={packageName:this.packageName,deviceId:this.deviceId,startTime:this.startTime.toISOString(),endTime:e.toISOString(),durationSeconds:s,totalSteps:this.steps.length,passedSteps:this.steps.filter(n=>n.status==="PASS").length,failedSteps:this.steps.filter(n=>n.status==="FAIL").length,skippedSteps:this.steps.filter(n=>n.status==="SKIPPED").length,warnSteps:this.steps.filter(n=>n.status==="WARN").length,errorsDetected:this.errorsDetected,videoPath:this.videoPath,steps:this.steps},r=t||"prompttest";if(this.formats.includes("json")){let n=ze.join(this.outputDir,`${r}-results.json`);await Ye.promises.writeFile(n,JSON.stringify(i,null,2),"utf-8")}if(this.formats.includes("md")){let n=ze.join(this.outputDir,`${r}-report.md`),o=this.formatMarkdownReport(i);await Ye.promises.writeFile(n,o,"utf-8")}if(this.formats.includes("junit")){let n=ze.join(this.outputDir,`${r}-junit.xml`),o=this.formatJunitXml(i,r);await Ye.promises.writeFile(n,o,"utf-8")}if(this.formats.includes("html")){let n=ze.join(this.outputDir,`${r}-report.html`),o=this.formatHtmlReport(i,r);await Ye.promises.writeFile(n,o,"utf-8")}for(let n of this.completeListeners)try{n(i)}catch{}return this.clearScreenshotBuffers(),i}escapeXml(t){return(t||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeHtml(t){return(t||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}formatJunitXml(t,e){let s=t.durationSeconds,i=t.failedSteps+(t.errorsDetected.length>0&&t.failedSteps===0?1:0),r=['<?xml version="1.0" encoding="UTF-8"?>',`<testsuites name="PromptTest" tests="${t.totalSteps}" failures="${i}" skipped="${t.skippedSteps}" time="${s}">`,` <testsuite name="${this.escapeXml(e)}" tests="${t.totalSteps}" failures="${i}" skipped="${t.skippedSteps}" time="${s}">`];for(let n of t.steps){let o=`Step ${n.stepIndex}: ${this.escapeXml(n.action)} - ${this.escapeXml(n.description)}`,a=n.durationMs!==void 0?(n.durationMs/1e3).toFixed(3):"1.000";r.push(` <testcase classname="${this.escapeXml(e)}" name="${o}" time="${a}">`),n.status==="FAIL"?r.push(` <failure message="${this.escapeXml(n.description)}">${this.escapeXml(n.description)}</failure>`):n.status==="SKIPPED"&&r.push(` <skipped message="${this.escapeXml(n.description)}"/>`),r.push(" </testcase>")}return t.failedSteps===0&&t.errorsDetected.length>0&&r.push(` <testcase classname="${this.escapeXml(e)}" name="Error Sentinel Crash Detection" time="0.000">`,` <failure message="${this.escapeXml(t.errorsDetected[0])}">${this.escapeXml(t.errorsDetected.join(`
689
689
  `))}</failure>`," </testcase>"),r.push(" </testsuite>"),r.push("</testsuites>"),r.join(`
690
- `)}formatMarkdownReport(t){let n=["# \u{1F9EA} PromptTest Autonomous Mobile QA Audit Report","",`**Status:** ${t.failedSteps===0&&t.errorsDetected.length===0?"\u2705 ALL PASSED":"\u26A0\uFE0F ISSUES DETECTED"} `,`**Target Package:** \`${t.packageName}\` `,`**Device:** \`${t.deviceId}\` `,`**Execution Time:** ${t.durationSeconds}s (${t.startTime} to ${t.endTime}) `];if(t.videoPath&&n.push(`**Screen Recording:** [Download Video](./${t.videoPath}) `),n.push("","---","","## \u{1F4CA} Executive Summary","","| Metric | Count |","|---|---|",`| **Total Steps** | ${t.totalSteps} |`,`| **Passed** | \u{1F7E2} ${t.passedSteps} |`,`| **Warnings** | \u{1F7E1} ${t.warnSteps} |`,`| **Failures** | \u{1F534} ${t.failedSteps} |`,`| **Skipped** | \u26AA ${t.skippedSteps} |`,`| **Errors Detected** | ${t.errorsDetected.length} |`,""),t.errorsDetected.length>0){n.push("## \u26A0\uFE0F Errors & Sentinels Flagged");for(let i of t.errorsDetected)n.push(`- \u{1F534} \`${i}\``);n.push("")}n.push("## \u{1F50D} Detailed Execution Timeline"),n.push(""),n.push("| Step | Phase | Action | Target / Details | Status | Duration | Screenshot / Triage |"),n.push("|---|---|---|---|---|---|---|");let r=i=>(i||"").replace(/\|/g,"\\|").replace(/\r?\n/g," ");for(let i of t.steps){let o="\u2014";i.triageBundle?o=`[\u{1F50D} Triage Bundle](./${i.triageBundle})`:i.screenshotPath&&(o=`[\u{1F4F8} Screenshot](./${i.screenshotPath})`);let a=i.durationMs!==void 0?`${i.durationMs}ms`:"\u2014",l=i.status==="PASS"?"\u{1F7E2} PASS":i.status==="WARN"?"\u{1F7E1} WARN":i.status==="SKIPPED"?"\u26AA SKIPPED":"\u{1F534} FAIL";n.push(`| ${i.stepIndex} | ${r(i.phase)} | ${r(i.action)} | ${r(i.description)} | ${l} | ${a} | ${o} |`)}return n.push(""),n.push("---"),n.push("*Generated autonomously by PromptTest Mobile QA Brain.*"),n.join(`
691
- `)}resolveScreenshotData(t){if(t.screenshotPath){if(this.embedScreenshots){if(this.screenshotBuffers.has(t.stepIndex))return`data:image/png;base64,${this.screenshotBuffers.get(t.stepIndex).toString("base64")}`;let e=ze.join(this.outputDir,t.screenshotPath);if(Ye.existsSync(e))try{return`data:image/png;base64,${Ye.readFileSync(e).toString("base64")}`}catch{}}return`./${t.screenshotPath}`}}formatHtmlReport(t,e){return as(t,{suiteName:e,embedScreenshots:this.embedScreenshots,screenshotResolver:s=>this.resolveScreenshotData(s)})}};bt=new at});function ai(p){let t=new Map;for(let[e,s]of Object.entries(p)){let r=[Z(e),...s.map(i=>Z(i))];for(let i of r){t.has(i)||t.set(i,[]);let o=t.get(i);for(let a of r)o.includes(a)||o.push(a)}}return t}function Ct(p,t="en"){let e=Z(p),s=(t||"en").toLowerCase(),n=cs.get(s);if(n){let r=n.get(e);if(r&&r.length>0)return r}if(s!=="en"){let r=cs.get("en");if(r){let i=r.get(e);if(i&&i.length>0)return i}}return[e]}var En,gr,cs,Pn,Yt=oe(()=>{"use strict";Oe();En={en:{bell:["bell","notification","notifications","alert","alerts","reminders","notice","badge"],notification:["notification","notifications","bell","alert","alerts","reminders","badge"],close:["close","dismiss","cancel","clear","cross","exit","\u2715","\xD7","x"],like:["like","favorite","heart","thumbs up","thumbs-up","fav","upvote"],dislike:["dislike","thumbs down","thumbs-down","downvote"],search:["search","find","query","magnifier","explore","lookup"],settings:["settings","preferences","gear","options","setup","config"],profile:["profile","account","user","my profile","avatar","me","personal"],trash:["trash","delete","remove","bin","discard"],delete:["delete","trash","remove","bin","discard"],share:["share","export","send to","forward"],back:["back","navigate up","previous","arrow back","chevron left","return"],menu:["menu","hamburger","drawer","sidebar","options","navigation","\u2630"],add:["add","new","create","plus","+","insert"],edit:["edit","pencil","modify","update","rename","change"],calendar:["calendar","schedule","date","events","timetable"],refresh:["refresh","reload","sync","update"],info:["info","information","details","help","about"],filter:["filter","filters","sort","refine","funnel"],check:["check","done","tick","mark","select","\u2713","\u2714"],lock:["lock","security","privacy","padlock"],camera:["camera","photo","picture","capture","snapshot"],cart:["cart","shopping cart","bag","basket","checkout"],email:["email","username","user name","e-mail","mail","login ID","user id"],username:["username","user name","email","user id","handle"],password:["password","passcode","pin","pwd","secret"],phone:["phone","mobile","contact","telephone","cell","phone number"],name:["name","full name","first name","last name"],otp:["otp","verification code","code","pin"],submit:["submit","save","continue","confirm","proceed","done","apply","ok"],save:["save","submit","done","apply","store","update"],cancel:["cancel","abort","discard","close","dismiss"],confirm:["confirm","yes","proceed","ok","agree","accept"],login:["sign in","signin","log in","login","enter"],signin:["sign in","signin","log in","login","enter"],logout:["sign out","signout","log out","logout","exit"],signout:["sign out","signout","log out","logout","exit"]},es:{bell:["campana","notificaci\xF3n","notificaciones","alerta","alertas","aviso","avisos"],notification:["notificaci\xF3n","notificaciones","campana","alerta","alertas","aviso","avisos","notification","notifications"],close:["cerrar","cancelar","quitar","salir","descartar","\u2715","\xD7","x","close"],like:["me gusta","favorito","favoritos","coraz\xF3n","like"],dislike:["no me gusta","desaprobar"],search:["buscar","b\xFAsqueda","lupa","explorar","encontrar","search"],settings:["ajustes","configuraci\xF3n","preferencias","opciones","settings"],profile:["perfil","cuenta","usuario","mi perfil","avatar","profile"],trash:["papelera","eliminar","borrar","descartar","quitar"],delete:["eliminar","borrar","quitar","papelera","descartar","delete"],share:["compartir","enviar","difundir","share"],back:["atr\xE1s","volver","regresar","anterior","flecha atr\xE1s","back"],menu:["men\xFA","opciones","navegaci\xF3n","\u2630","menu"],add:["a\xF1adir","agregar","nuevo","crear","m\xE1s","+","add"],edit:["editar","modificar","cambiar","actualizar","edit"],calendar:["calendario","fecha","eventos","horario","calendar"],refresh:["actualizar","recargar","sincronizar","refresh"],info:["informaci\xF3n","detalles","ayuda","acerca de","info"],filter:["filtrar","filtros","ordenar","filter"],check:["listo","hecho","marcar","seleccionar","\u2713","\u2714","check"],lock:["bloqueo","seguridad","privacidad","candado","lock"],camera:["c\xE1mara","foto","captura","imagen","camera"],cart:["carrito","cesta","bolsa","comprar","cart","checkout"],email:["correo","correo electr\xF3nico","email","usuario","mail"],username:["usuario","nombre de usuario","correo","username"],password:["contrase\xF1a","clave","pin","c\xF3digo","password"],phone:["tel\xE9fono","m\xF3vil","celular","contacto","n\xFAmero","phone"],name:["nombre","nombre completo","apellidos","name"],otp:["c\xF3digo de verificaci\xF3n","c\xF3digo","otp","pin"],submit:["enviar","guardar","confirmar","continuar","proceder","listo","aceptar","submit"],save:["guardar","salvar","almacenar","actualizar","save"],cancel:["cancelar","descartar","anular","abortar","cancel"],confirm:["confirmar","aceptar","s\xED","continuar","de acuerdo","confirm"],login:["iniciar sesi\xF3n","entrar","acceder","identificarse","ingresar","login","sign in"],signin:["iniciar sesi\xF3n","entrar","acceder","identificarse","ingresar","login","sign in"],logout:["cerrar sesi\xF3n","salir","desconectar","logout","sign out"],signout:["cerrar sesi\xF3n","salir","desconectar","logout","sign out"]},hi:{bell:["\u0918\u0902\u091F\u0940","\u0928\u094B\u091F\u093F\u092B\u093F\u0915\u0947\u0936\u0928","\u0938\u0942\u091A\u0928\u093E\u090F\u0902","alert","reminders"],notification:["\u0928\u094B\u091F\u093F\u092B\u093F\u0915\u0947\u0936\u0928","\u0938\u0942\u091A\u0928\u093E\u090F\u0902","alert","reminders","notification"],close:["\u092C\u0902\u0926 \u0915\u0930\u0947\u0902","\u0939\u091F\u093E\u090F\u0902","\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902","\u2715","\xD7","x","close"],like:["\u092A\u0938\u0902\u0926","\u0932\u093E\u0907\u0915","\u092A\u0938\u0902\u0926\u0940\u0926\u093E"],dislike:["\u0928\u093E\u092A\u0938\u0902\u0926"],search:["\u0916\u094B\u091C\u0947\u0902","\u0922\u0942\u0902\u0922\u0947\u0902","\u0938\u0930\u094D\u091A","explore","search"],settings:["\u0938\u0947\u091F\u093F\u0902\u0917\u094D\u0938","\u0935\u093F\u0915\u0932\u094D\u092A","\u092A\u094D\u0930\u093E\u0925\u092E\u093F\u0915\u0924\u093E\u090F\u0902","settings"],profile:["\u092A\u094D\u0930\u094B\u092B\u093C\u093E\u0907\u0932","\u0916\u093E\u0924\u093E","\u0909\u092A\u092F\u094B\u0917\u0915\u0930\u094D\u0924\u093E","\u0905\u0915\u093E\u0909\u0902\u091F","profile"],trash:["\u0939\u091F\u093E\u090F\u0902","\u0921\u093F\u0932\u0940\u091F","\u0915\u091A\u0930\u093E"],delete:["\u0939\u091F\u093E\u090F\u0902","\u0921\u093F\u0932\u0940\u091F","\u092E\u093F\u091F\u093E\u090F\u0902","delete"],share:["\u0936\u0947\u092F\u0930 \u0915\u0930\u0947\u0902","\u092D\u0947\u091C\u0947\u0902","share"],back:["\u0935\u093E\u092A\u0938","\u092A\u0940\u091B\u0947","\u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0902","back"],menu:["\u092E\u0947\u0928\u0942","\u0935\u093F\u0915\u0932\u094D\u092A","\u2630","menu"],add:["\u091C\u094B\u0921\u093C\u0947\u0902","\u0928\u092F\u093E","\u092C\u0928\u093E\u090F\u0902","+","add"],edit:["\u0938\u0902\u092A\u093E\u0926\u093F\u0924 \u0915\u0930\u0947\u0902","\u092C\u0926\u0932\u0947\u0902","\u090F\u0921\u093F\u091F","edit"],calendar:["\u0915\u0948\u0932\u0947\u0902\u0921\u0930","\u0924\u093E\u0930\u0940\u0916","\u0938\u092E\u092F \u0938\u093E\u0930\u093F\u0923\u0940"],refresh:["\u0930\u093F\u092B\u094D\u0930\u0947\u0936","\u0924\u093E\u091C\u093C\u093E \u0915\u0930\u0947\u0902","\u0905\u092A\u0921\u0947\u091F \u0915\u0930\u0947\u0902"],info:["\u091C\u093E\u0928\u0915\u093E\u0930\u0940","\u0935\u093F\u0935\u0930\u0923","\u092E\u0926\u0926","info"],filter:["\u092B\u093C\u093F\u0932\u094D\u091F\u0930","\u091B\u093E\u0902\u091F\u0947\u0902","filter"],check:["\u0939\u094B \u0917\u092F\u093E","\u091A\u0941\u0928\u0947\u0902","\u0938\u0939\u0940","\u2713","\u2714"],cart:["\u0915\u093E\u0930\u094D\u091F","\u0925\u0948\u0932\u093E","\u091F\u094B\u0915\u0930\u0940","cart"],email:["\u0908\u092E\u0947\u0932","\u0908-\u092E\u0947\u0932","\u092F\u0942\u091C\u0930\u0928\u0947\u092E","email"],username:["\u0909\u092A\u092F\u094B\u0917\u0915\u0930\u094D\u0924\u093E \u0928\u093E\u092E","\u092F\u0942\u091C\u0930\u0928\u0947\u092E","\u0908\u092E\u0947\u0932","username"],password:["\u092A\u093E\u0938\u0935\u0930\u094D\u0921","\u092A\u093F\u0928","\u092A\u093E\u0938\u0915\u094B\u0921","password"],phone:["\u092B\u093C\u094B\u0928","\u092E\u094B\u092C\u093E\u0907\u0932","\u0928\u0902\u092C\u0930","\u0938\u0902\u092A\u0930\u094D\u0915","phone"],name:["\u0928\u093E\u092E","\u092A\u0942\u0930\u093E \u0928\u093E\u092E","name"],otp:["\u0913\u091F\u0940\u092A\u0940","\u0938\u0924\u094D\u092F\u093E\u092A\u0928 \u0915\u094B\u0921","\u092A\u093F\u0928","otp"],submit:["\u091C\u092E\u093E \u0915\u0930\u0947\u0902","\u0938\u092C\u092E\u093F\u091F","\u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902","\u0906\u0917\u0947 \u092C\u0922\u093C\u0947\u0902","submit"],save:["\u0938\u0939\u0947\u091C\u0947\u0902","\u0938\u0947\u0935 \u0915\u0930\u0947\u0902","\u0938\u0941\u0930\u0915\u094D\u0937\u093F\u0924 \u0915\u0930\u0947\u0902","save"],cancel:["\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902","\u0915\u0948\u0902\u0938\u093F\u0932","cancel"],confirm:["\u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902","\u0938\u094D\u0935\u0940\u0915\u093E\u0930 \u0915\u0930\u0947\u0902","\u0939\u093E\u0901","\u0920\u0940\u0915 \u0939\u0948","confirm"],login:["\u0932\u0949\u0917 \u0907\u0928","\u0932\u0949\u0917\u093F\u0928","\u092A\u094D\u0930\u0935\u0947\u0936 \u0915\u0930\u0947\u0902","\u0938\u093E\u0907\u0928 \u0907\u0928","login","sign in"],signin:["\u0932\u0949\u0917 \u0907\u0928","\u0932\u0949\u0917\u093F\u0928","\u0938\u093E\u0907\u0928 \u0907\u0928","\u092A\u094D\u0930\u0935\u0947\u0936 \u0915\u0930\u0947\u0902","login","sign in"],logout:["\u0932\u0949\u0917 \u0906\u0909\u091F","\u0938\u093E\u0907\u0928 \u0906\u0909\u091F","\u092C\u093E\u0939\u0930 \u0928\u093F\u0915\u0932\u0947\u0902","logout"],signout:["\u0932\u0949\u0917 \u0906\u0909\u091F","\u0938\u093E\u0907\u0928 \u0906\u0909\u091F","\u092C\u093E\u0939\u0930 \u0928\u093F\u0915\u0932\u0947\u0902","logout"]}},gr=En.en,cs=new Map;for(let[p,t]of Object.entries(En))cs.set(p.toLowerCase(),ai(t));Pn=Ct});import we from"fs";import Ve from"path";import{fileURLToPath as ci}from"url";var Xe,ve,Qe=oe(()=>{"use strict";Oe();Yt();Pe();Xe=class p{memoryDir;currentPackage="global";mappings=new Map;screens=new Map;intents=new Map;dirty=!1;locale="en";setLocale(t){this.locale=(t||"en").toLowerCase()}getLocale(){return this.locale}constructor(t){if(t)this.memoryDir=t;else{let e=Ve.dirname(ci(import.meta.url));this.memoryDir=Ve.resolve(e,"..","memory")}we.existsSync(this.memoryDir)||we.mkdirSync(this.memoryDir,{recursive:!0})}cleanPackageName(t){return(t||"global").replace(/[^a-zA-Z0-9._-]/g,"_")}static SCHEMA_VERSION=2;async init(t){this.currentPackage=this.cleanPackageName(t),this.mappings.clear(),this.screens.clear(),this.intents.clear(),this.dirty=!1;let e=Ve.join(this.memoryDir,`${this.currentPackage}.json`);if(we.existsSync(e))try{let s=await we.promises.readFile(e,"utf-8"),n=JSON.parse(s);if(n&&n.mappings){let r=!n.version||n.version<2;for(let[i,o]of Object.entries(n.mappings))r&&(o.totalSuccesses=o.totalSuccesses??o.successCount??1,o.recentOutcomes=o.recentOutcomes??(o.failCount>0?["FAIL"]:["PASS"]),o.lastSeenTs=o.lastSeenTs??o.lastUpdated??new Date().toISOString(),this.dirty=!0),this.mappings.set(i,o);if(n.screens)for(let[i,o]of Object.entries(n.screens))this.screens.set(i,o);if(n.intents)for(let[i,o]of Object.entries(n.intents))this.intents.set(i,o);this.decayStaleMappings()}else this.mappings.clear(),this.screens.clear(),this.intents.clear()}catch{this.mappings.clear(),this.screens.clear(),this.intents.clear()}}getCanonicalQuery(t){let e=Z(t),s=Ct(e,this.locale);return s&&s.length>0?s[0]:e}buildKey(t,e){return`${t.toUpperCase()}:${this.getCanonicalQuery(e)}`}resolve(t,e){let s=this.buildKey(t,e),n=this.mappings.get(s);if(n)return n;let r=`${t.toUpperCase()}:${Z(e)}`,i=this.mappings.get(r);if(i)return i;let o=Ct(e,this.locale);for(let a of o){let l=`${t.toUpperCase()}:${a}`,c=this.mappings.get(l);if(c)return c}}getAllCandidates(t,e,s,n){let r=(s||this.locale||"en").toLowerCase(),i=new Set;if(n){let l=this.getScreenElements(n),c=this.getCanonicalQuery(e);for(let u of l)u.action===t.toUpperCase()&&(u.canonicalIntent===c||u.canonicalIntent===Z(e))&&u.confidence>=.7&&i.add(u.matchedIdentifier)}let o=this.resolve(t,e);o&&o.confidence>=.8&&i.add(o.matchedIdentifier),i.add(e);let a=Ct(e,r);for(let l of a)i.add(l);return Array.from(i)}recordSuccess(t,e,s,n,r=1,i,o){if(s.length>35||s.includes("?")||s.includes(`
692
- `))return;let a=this.buildKey(t,e),l=this.mappings.get(a),c=new Date().toISOString(),u=i||l?.healedFrom?E.memory?.maxHealedConfidence??.65:1,h=i||l?.healedFrom?Math.min(r,u):r;l&&l.matchedIdentifier===s?(l.successCount+=1,l.totalSuccesses=(l.totalSuccesses||0)+1,l.failCount=0,l.recentOutcomes||(l.recentOutcomes=[]),l.recentOutcomes.push("PASS"),l.recentOutcomes.length>5&&l.recentOutcomes.shift(),l.confidence=Math.min(u,Number((l.confidence+.05).toFixed(2))),l.lastUpdated=c,l.lastSeenTs=c,i&&(l.healedFrom=i)):this.mappings.set(a,{canonicalIntent:this.getCanonicalQuery(e),action:t.toUpperCase(),matchedIdentifier:s,matchType:n,confidence:h,successCount:1,failCount:0,totalSuccesses:1,recentOutcomes:["PASS"],lastUpdated:c,lastSeenTs:c,healedFrom:i}),o&&this.associateScreenElement(o,a),this.dirty=!0}associateScreenElement(t,e){if(!t||!e)return;let s=new Date().toISOString(),n=this.screens.get(t);n?(n.elements.includes(e)||n.elements.push(e),n.lastSeenTs=s):this.screens.set(t,{lastSeenTs:s,elements:[e]}),this.dirty=!0}getScreenElements(t){let e=this.screens.get(t);return e?e.elements.map(s=>this.mappings.get(s)).filter(s=>s!==void 0):[]}getScreenIndex(){return Object.fromEntries(this.screens.entries())}markScreenCrawled(t,e){if(!t)return;let s=new Date().toISOString(),n=this.screens.get(t);if(n){if(n.crawled=!0,n.crawledAt=s,n.lastSeenTs=s,e&&e.length>0){n.safeActions||(n.safeActions=[]);for(let r of e)n.safeActions.includes(r)||n.safeActions.push(r)}}else this.screens.set(t,{lastSeenTs:s,elements:[],crawled:!0,crawledAt:s,safeActions:e?[...e]:[]});this.dirty=!0}isScreenCrawled(t){return t?!!this.screens.get(t)?.crawled:!1}getScreenMemory(t){return this.screens.get(t)}getCrawledScreensCount(){let t=0;for(let e of this.screens.values())e.crawled&&t++;return t}recordIntentExpansion(t,e){if(!t||!e||e.length===0)return;let s=Z(t),n=new Date().toISOString(),r=this.intents.get(s);r?(r.steps=[...e],r.usageCount=(r.usageCount||1)+1,r.learnedAt=n):this.intents.set(s,{intent:t,steps:[...e],learnedAt:n,usageCount:1}),this.dirty=!0}getIntentExpansion(t){if(!t)return;let e=Z(t),s=this.intents.get(e);if(s)return s.usageCount=(s.usageCount||0)+1,this.dirty=!0,[...s.steps]}hasIntentExpansion(t){return t?this.intents.has(Z(t)):!1}getIntentExpansionsCount(){return this.intents.size}recordFailure(t,e){let s=this.buildKey(t,e),n=this.mappings.get(s);n&&(n.failCount+=1,n.recentOutcomes||(n.recentOutcomes=[]),n.recentOutcomes.push("FAIL"),n.recentOutcomes.length>5&&n.recentOutcomes.shift(),n.confidence=Math.max(.1,Number((n.confidence-.25).toFixed(2))),n.lastUpdated=new Date().toISOString(),(n.recentOutcomes.filter(i=>i==="FAIL").length>=3||n.confidence<.2)&&this.mappings.delete(s),this.dirty=!0)}decayStaleMappings(t){let s=(t??E.memory?.staleThresholdDays??14)*24*60*60*1e3,n=Date.now(),r=0;for(let i of this.mappings.values()){let o=i.lastSeenTs?new Date(i.lastSeenTs).getTime():0;if(o>0&&n-o>s){let a=E.memory?.staleDecayAmount??.2,l=E.memory?.minConfidenceFloor??.2,c=Math.max(l,Number((i.confidence-a).toFixed(2)));c<i.confidence&&(i.confidence=c,r++,this.dirty=!0)}}return r}async save(){if(!this.dirty)return;let t={packageName:this.currentPackage,version:p.SCHEMA_VERSION,lastUpdated:new Date().toISOString(),mappings:Object.fromEntries(this.mappings.entries()),screens:Object.fromEntries(this.screens.entries()),intents:Object.fromEntries(this.intents.entries())},e=Ve.join(this.memoryDir,`${this.currentPackage}.json`),s=`${e}.tmp.${Date.now()}`;await we.promises.writeFile(s,JSON.stringify(t,null,2),"utf-8");try{await we.promises.rename(s,e)}catch{await we.promises.copyFile(s,e),await we.promises.unlink(s).catch(()=>{})}this.dirty=!1}async exportMemory(t){let e=t?Ve.resolve(t):Ve.join(this.memoryDir,`${this.currentPackage}-export.json`),s=Ve.dirname(e);we.existsSync(s)||we.mkdirSync(s,{recursive:!0});let n={packageName:this.currentPackage,version:p.SCHEMA_VERSION,lastUpdated:new Date().toISOString(),mappings:Object.fromEntries(this.mappings.entries()),screens:Object.fromEntries(this.screens.entries()),intents:Object.fromEntries(this.intents.entries())};return await we.promises.writeFile(e,JSON.stringify(n,null,2),"utf-8"),e}async importMemory(t){let e=Ve.resolve(t);if(!we.existsSync(e))throw new Error(`Memory import source file not found: ${e}`);let s=await we.promises.readFile(e,"utf-8"),n=JSON.parse(s);if(!n||!n.mappings)throw new Error("Invalid memory file format: missing mappings object.");let r=0,i=new Date().toISOString();for(let[o,a]of Object.entries(n.mappings)){let l=this.mappings.get(o);(!l||a.confidence>=l.confidence)&&(this.mappings.set(o,{...a,totalSuccesses:a.totalSuccesses??a.successCount??1,recentOutcomes:a.recentOutcomes??["PASS"],lastSeenTs:a.lastSeenTs??a.lastUpdated??i,lastUpdated:i}),r++)}if(n.screens)for(let[o,a]of Object.entries(n.screens)){let l=this.screens.get(o);if(!l)this.screens.set(o,a);else{let c=new Set([...l.elements,...a.elements]),u=new Set([...l.safeActions||[],...a.safeActions||[]]);this.screens.set(o,{lastSeenTs:a.lastSeenTs||l.lastSeenTs,elements:Array.from(c),crawled:l.crawled||a.crawled,crawledAt:a.crawledAt||l.crawledAt,safeActions:Array.from(u)})}}if(n.intents)for(let[o,a]of Object.entries(n.intents)){let l=this.intents.get(o);(!l||(a.usageCount||0)>=(l.usageCount||0))&&this.intents.set(o,a)}return r>0&&(this.dirty=!0,await this.save()),r}getMappingsList(){return Array.from(this.mappings.values())}getStats(){let t=Array.from(this.mappings.values()),e=t.reduce((r,i)=>r+(i.totalSuccesses||i.successCount||0),0),s=t.length>0?Number((t.reduce((r,i)=>r+i.confidence,0)/t.length).toFixed(2)):0,n=0;for(let r of this.screens.values())r.crawled&&n++;return{totalMappings:this.mappings.size,totalScreens:this.screens.size,crawledScreens:n,totalIntents:this.intents.size,package:this.currentPackage,totalSuccesses:e,averageConfidence:s}}async clear(t){let e=this.cleanPackageName(t||this.currentPackage),s=Ve.join(this.memoryDir,`${e}.json`);return we.existsSync(s)?(await we.promises.unlink(s),e===this.currentPackage&&(this.mappings.clear(),this.screens.clear(),this.intents.clear(),this.dirty=!1),!0):!1}},ve=new Xe});import Le from"fs";import li from"path";import di from"os";function ct(p){let t=(p||"default").replace(/[^a-zA-Z0-9._-]/g,"_"),e=li.join(di.tmpdir(),`prompttest-${t}.lock`);if(Le.existsSync(e))try{let n=Le.readFileSync(e,"utf-8").trim(),r=parseInt(n,10);if(!isNaN(r)){if(r===process.pid)return{serial:p,lockFilePath:e,acquired:!0,pid:process.pid};try{throw process.kill(r,0),new Error(`Device "${p}" is locked by another PromptTest process (PID ${r}).
693
- Wait for the other run to complete, or remove the lock file if it is stale: ${e}`)}catch(i){if(i.code==="ESRCH")try{Le.unlinkSync(e)}catch{}else throw i}}}catch(n){let r=n;if(r.message&&r.message.includes("locked by another"))throw r;try{Le.unlinkSync(e)}catch{}}try{Le.writeFileSync(e,process.pid.toString(),{flag:"wx"})}catch(n){throw n.code==="EEXIST"?new Error(`Device "${p}" was just acquired by a concurrent PromptTest process.`):n}let s=()=>{try{Le.existsSync(e)&&Le.readFileSync(e,"utf-8").trim()===process.pid.toString()&&Le.unlinkSync(e)}catch{}};return ls.set(e,s),process.once("exit",s),{serial:p,lockFilePath:e,acquired:!0,pid:process.pid}}function lt(p){if(p)try{let t=ls.get(p.lockFilePath);if(t)process.removeListener("exit",t),ls.delete(p.lockFilePath),t();else if(Le.existsSync(p.lockFilePath))try{Le.readFileSync(p.lockFilePath,"utf-8").trim()===process.pid.toString()&&Le.unlinkSync(p.lockFilePath)}catch{}}catch{}}var ls,It=oe(()=>{"use strict";ls=new Map});import qe from"fs";import kn from"path";var ds,Dn,$n=oe(()=>{"use strict";ds=class{checkpointDir;constructor(t){this.checkpointDir=t||kn.resolve(process.cwd(),"output","checkpoints"),qe.existsSync(this.checkpointDir)||qe.mkdirSync(this.checkpointDir,{recursive:!0})}filePath(t){let e=t.replace(/[^a-zA-Z0-9._-]/g,"_");return kn.join(this.checkpointDir,`${e}.checkpoint.json`)}async save(t,e,s,n){let r={specFile:t,packageName:e,lastPassedStep:s,totalSteps:n,savedAt:new Date().toISOString()},i=this.filePath(t)+`.tmp.${Date.now()}`;await qe.promises.writeFile(i,JSON.stringify(r,null,2),"utf-8"),await qe.promises.rename(i,this.filePath(t))}async load(t){let e=this.filePath(t);if(!qe.existsSync(e))return null;try{let s=await qe.promises.readFile(e,"utf-8");return JSON.parse(s)}catch{return null}}async clear(t){let e=this.filePath(t);qe.existsSync(e)&&await qe.promises.unlink(e)}async getResumeIndex(t){let e=await this.load(t);return e?e.lastPassedStep+1:0}},Dn=new ds});import $e from"fs";import Lt from"path";import{PNG as dt}from"pngjs";import ui from"pixelmatch";var Nt,us,Xt=oe(()=>{"use strict";Nt=class{baselineDir;defaultThreshold;constructor(t,e=.02){this.baselineDir=t||Lt.resolve(process.cwd(),"output","baselines"),this.defaultThreshold=e,$e.existsSync(this.baselineDir)||$e.mkdirSync(this.baselineDir,{recursive:!0})}filePath(t,e){let s=t.replace(/[^a-zA-Z0-9._-]/g,"_");return Lt.join(this.baselineDir,`${s}_step${String(e).padStart(3,"0")}.png`)}diffFilePath(t,e){let s=t.replace(/[^a-zA-Z0-9._-]/g,"_");return Lt.join(this.baselineDir,`${s}_step${String(e).padStart(3,"0")}_diff.png`)}async saveBaseline(t,e,s){let n=this.filePath(t,e),r=n+`.tmp.${Date.now()}`;return await $e.promises.writeFile(r,s),await $e.promises.rename(r,n),n}hasBaseline(t,e){return $e.existsSync(this.filePath(t,e))}async compare(t,e,s,n){let r=typeof n=="number"?{threshold:n}:n||{},i=this.filePath(t,e),o=Lt.join(this.baselineDir,`${t.replace(/[^a-zA-Z0-9._-]/g,"_")}_step${String(e).padStart(3,"0")}_current.png`);await $e.promises.writeFile(o,s);let a=r.threshold??this.defaultThreshold;if(!$e.existsSync(i)){await this.saveBaseline(t,e,s);let v=dt.sync.read(s),$=v.width*v.height;return{stepName:`Step ${e}`,baselineFile:i,currentFile:o,diffRatio:0,diffPixels:0,totalPixels:$,passed:!0,threshold:a}}let l=await $e.promises.readFile(i),c=dt.sync.read(l),u=dt.sync.read(s),h=Math.max(c.width,u.width),d=Math.max(c.height,u.height),g=h*d,m=this.fitToCanvas(c,h,d),y=this.fitToCanvas(u,h,d);r.maskRegions&&r.maskRegions.length>0&&(this.applyMasks(m,r.maskRegions),this.applyMasks(y,r.maskRegions));let S=new dt({width:h,height:d}),b=r.pixelmatchThreshold??.1,f=ui(m.data,y.data,S.data,h,d,{threshold:b,includeAA:!1}),T=g>0?f/g:0,P=T<=a,I;if(f>0){I=this.diffFilePath(t,e);let v=dt.sync.write(S);await $e.promises.writeFile(I,v)}return{stepName:`Step ${e}`,baselineFile:i,currentFile:o,diffRatio:T,diffPixels:f,totalPixels:g,passed:P,threshold:a,diffImagePath:I}}fitToCanvas(t,e,s){if(t.width===e&&t.height===s)return t;let n=new dt({width:e,height:s});return n.data.fill(0),dt.bitblt(t,n,0,0,t.width,t.height,0,0),n}applyMasks(t,e){for(let s of e){let n=Math.min(t.width,s.x+s.width),r=Math.min(t.height,s.y+s.height);for(let i=Math.max(0,s.y);i<r;i++)for(let o=Math.max(0,s.x);o<n;o++){let a=t.width*i+o<<2;t.data[a]=0,t.data[a+1]=0,t.data[a+2]=0,t.data[a+3]=0}}}async clearBaselines(t){let e=t.replace(/[^a-zA-Z0-9._-]/g,"_");if(!$e.existsSync(this.baselineDir))return;let s=await $e.promises.readdir(this.baselineDir);await Promise.all(s.filter(n=>n.startsWith(e+"_step")).map(n=>$e.promises.unlink(Lt.join(this.baselineDir,n)).catch(()=>{})))}},us=new Nt});import ce from"chalk";import Cn from"vm";function z(p){return new Promise(t=>setTimeout(t,p))}function pi(p){let t=p.screenDimensions.height,e=p.navBarHeight>0?t-p.navBarHeight:t,s=p.navBarHeight>0?e*.94:t*E.gestures.bottomNavThresholdRatio;return{effectiveHeight:e,bottomThreshold:s}}var ps,hs,Gt,gs,ms,fs,bs,ys,Ss,vs,ws,xs,Ts,Es,Ps,As,ks,Ds,$s,Cs,Is,Rs,Ls,Ns,Ms,Fs,hi,In,Os=oe(()=>{"use strict";Pe();ft();Oe();ps=class{type="TAP";async execute(t,e){let s=t.target,{width:n,height:r}=e.screenDimensions,i=Math.round(n*.5),{flat:o,matched:a}=await e.waitForTarget(s,e.serial,E.polling.defaultTimeoutMs,t);if(a.length===0&&e.upcomingSteps&&e.upcomingSteps.length>0&&!o.some(S=>S.password===!0||S.className.includes("EditText")&&o.some(b=>b.text?.toLowerCase().includes("password")))){let S=e.upcomingSteps.findIndex(f=>f.type==="VERIFY"&&f.target&&e.matchNodes(o,f.target,f).length>0);if(S!==-1)return{fastForwarded:!0,reason:`Screen already displays "${e.upcomingSteps[S].target}"`,skipCount:S};let b=e.upcomingSteps.findIndex(f=>f.type==="TAP"&&f.target&&e.matchNodes(o,f.target,f).length>0);if(b!==-1)return{fastForwarded:!0,reason:`Upcoming action "${e.upcomingSteps[b].target}" is directly actionable`,skipCount:b}}if(a.length===0){await e.driver.swipe(i,Math.round(r*.75),i,Math.round(r*.35),300,e.serial),await z(350),e.setLastHierarchy(null);let y=await e.waitForTarget(s,e.serial,2e3,t);o=y.flat,a=y.matched}if(a.length===0)throw e.buildDiagnosticError(s,o,`Element matching "${s}" not found on current screen.`);let l=a.find(y=>y.clickable)||a[0];if(await e.ensureInViewport(l,e.serial)){let y=await e.waitForTarget(s,e.serial,1500,t);y.matched.length>0&&(o=y.flat,a=y.matched,l=a.find(S=>S.clickable)||a[0])}let u=l.bounds.centerX,{effectiveHeight:h}=pi(e),d=l.bounds.centerY;if(l.bounds.y2>h&&(d=Math.min(Math.round((l.bounds.y1+h)/2),h-15)),d=Math.min(d,l.bounds.y2-2),d=Math.max(d,l.bounds.y1+2),d>r*.6&&typeof e.driver.isKeyboardVisible=="function")try{await e.driver.isKeyboardVisible(e.serial)&&(console.log(ce.gray(` [Keyboard] Target occluded by soft keyboard (Y=${d} > ${Math.round(r*.6)}). Dismissing...`)),await e.driver.pressBack(e.serial),await z(300),e.setLastHierarchy(null))}catch{}let g=l.contentDesc||l.text||l.resourceId;console.log(ce.gray(` [Tap Target] (${u}, ${d}) for "${g||s}"`));let m=e.lastHierarchy?.hash;await e.driver.tap(u,d,e.serial),await z(E.settle.tapMs),e.setLastHierarchy(null),g&&Z(g)!==Z(s)&&e.memory.recordSuccess("TAP",s,g,l.contentDesc?"contentDesc":l.text?"text":"resourceId",1,void 0,m)}},hs=class{type="LONG_PRESS";async execute(t,e){let s=t.target,{flat:n,matched:r}=await e.waitForTarget(s,e.serial,E.polling.defaultTimeoutMs,t);if(r.length===0)throw e.buildDiagnosticError(s,n,`Element matching "${s}" not found for long-press.`);let i=r[0];if(await e.ensureInViewport(i,e.serial)){let a=await e.waitForTarget(s,e.serial,1500,t);a.matched.length>0&&(i=a.matched[0])}await e.driver.swipe(i.bounds.centerX,i.bounds.centerY,i.bounds.centerX,i.bounds.centerY,E.gestures.longPressDurationMs,e.serial),await z(300),e.setLastHierarchy(null)}},Gt=class{type="TYPE";async execute(t,e){let s=t.target,n=t.value??"",r=[],i=null;if(e.lastHierarchy&&Date.now()-e.lastHierarchy.timestamp<E.polling.hierarchyCacheTtlMs){let u=e.findTargetInputField(e.lastHierarchy.flat,s,n);u&&(r=e.lastHierarchy.flat,i=u)}if(i||(r=(await e.getCleanHierarchy(e.serial)).flat,i=e.findTargetInputField(r,s,n)),!i){let u=Date.now();for(;Date.now()-u<2e3&&(await z(200),r=(await e.getCleanHierarchy(e.serial)).flat,i=e.findTargetInputField(r,s,n),!i););}if(!i&&e.upcomingSteps&&e.upcomingSteps.length>0&&!r.some(h=>h.className.includes("EditText"))){let h=e.upcomingSteps.findIndex(d=>d.type==="VERIFY"&&d.target&&e.matchNodes(r,d.target,d).length>0);if(h!==-1)return{fastForwarded:!0,reason:`Screen already displays "${e.upcomingSteps[h].target}" and form is completed`,skipCount:h}}if(!i)throw e.buildDiagnosticError(s,r,`Input field matching "${s}" not found.`);if(i.text&&i.text===n){console.log(ce.gray(` [Input Field] Already contains desired value "${n}". Skipping typing.`));return}if(await e.ensureInViewport(i,e.serial)){r=(await e.getCleanHierarchy(e.serial)).flat;let h=e.findTargetInputField(r,s,n);h&&(i=h)}let{height:a}=e.screenDimensions;if(i.bounds.centerY>a*.6&&typeof e.driver.isKeyboardVisible=="function")try{await e.driver.isKeyboardVisible(e.serial)&&(console.log(ce.gray(" [Keyboard] Input field occluded by soft keyboard. Dismissing before focus...")),await e.driver.pressBack(e.serial),await z(300),e.setLastHierarchy(null))}catch{}let l=e.lastHierarchy?.hash;await e.driver.tap(i.bounds.centerX,i.bounds.centerY,e.serial),await z(E.settle.inputFocusMs),await e.driver.clearField(e.serial),await z(E.settle.inputClearMs),await e.driver.inputText(n,e.serial),await z(E.settle.inputDoneMs),e.setLastHierarchy(null);let c=i.contentDesc||i.resourceId;c&&Z(c)!==Z(s)&&e.memory.recordSuccess("TYPE",s,c,i.contentDesc?"contentDesc":"resourceId",1,void 0,l)}},gs=class{type="CLEAR";async execute(t,e){let s=t.target,n=[],r=null;if(e.lastHierarchy&&Date.now()-e.lastHierarchy.timestamp<E.polling.hierarchyCacheTtlMs&&(r=e.findTargetInputField(e.lastHierarchy.flat,s),r&&(n=e.lastHierarchy.flat)),r||(n=(await e.getCleanHierarchy(e.serial)).flat,r=e.findTargetInputField(n,s)),!r){let o=e.matchNodes(n,s,t);o.length>0&&(r=o[0])}if(!r)throw e.buildDiagnosticError(s,n,`Input field matching "${s}" not found to clear.`);await e.driver.tap(r.bounds.centerX,r.bounds.centerY,e.serial),await z(300);let i=e.driver;typeof i.clearField=="function"?await i.clearField(e.serial):typeof i.clearInput=="function"&&await i.clearInput(50,e.serial),await z(200),e.setLastHierarchy(null)}},ms=class{type="VERIFY";async execute(t,e){let s=t.target,n=t.expectedState||"visible";if(t.negative===!0||n==="absent"||n==="hidden"){let h=await e.getCleanHierarchy(e.serial);if(e.matchNodes(h.flat,s,t).length>0)throw new Error(`Negative assertion failed: "${s}" was expected to be NOT visible, but is present on screen.`);return}let{width:i,height:o}=e.screenDimensions,a=Math.round(i*.5),l=!1,c=[],u;if(e.lastHierarchy&&Date.now()-e.lastHierarchy.timestamp<E.polling.verifyCacheTtlMs&&(u=e.matchNodes(e.lastHierarchy.flat,s,t)[0],u&&(c=e.lastHierarchy.flat,l=!0,e.lastHierarchy.timestamp=Date.now())),!l){let h=Date.now();for(;Date.now()-h<E.polling.extendedTimeoutMs;){if(c=(await e.getCleanHierarchy(e.serial)).flat,u=e.matchNodes(c,s,t)[0],u){l=!0,e.lastHierarchy&&(e.lastHierarchy.timestamp=Date.now()),await z(400);break}await z(200)}}if(l||(await e.driver.swipe(a,Math.round(o*.75),a,Math.round(o*.35),300,e.serial),await z(400),c=(await e.getCleanHierarchy(e.serial)).flat,u=e.matchNodes(c,s,t)[0],u&&(l=!0)),!l){if(e.upcomingSteps&&e.upcomingSteps.length>0&&!c.some(d=>d.password===!0||d.className.includes("EditText")&&c.some(g=>g.text?.toLowerCase().includes("password")))){let d=e.upcomingSteps.findIndex(g=>g.type==="VERIFY"&&g.target&&e.matchNodes(c,g.target,g).length>0);if(d!==-1)return{fastForwarded:!0,reason:`Screen is already on "${e.upcomingSteps[d].target}"`,skipCount:d}}throw await e.driver.swipe(a,Math.round(o*.35),a,Math.round(o*.75),300,e.serial),await z(300),e.buildDiagnosticError(s,c,`Verification assertion failed: "${s}" is not visible on screen.`)}if(u&&n==="disabled"&&u.enabled)throw new Error(`State assertion failed: "${s}" was expected to be DISABLED, but is enabled.`);if(u&&n==="enabled"&&!u.enabled)throw new Error(`State assertion failed: "${s}" was expected to be ENABLED, but is disabled.`)}},fs=class{type="BACK";async execute(t,e){await e.driver.pressKey(4,e.serial),await z(E.settle.backMs),e.setLastHierarchy(null)}},bs=class{type="SCROLL";async execute(t,e){let{width:s,height:n}=e.screenDimensions,r=Math.round(s*.5);if(t.target&&t.target!=="up"&&t.target!=="down"){let o=t.target,a=t.direction||"down",l=!1;for(let c=0;c<5;c++){let{flat:u}=await e.getCleanHierarchy(e.serial),h=e.matchNodes(u,o,t);if(h.length>0){await e.ensureInViewport(h[0],e.serial),l=!0;break}a==="up"?await e.driver.swipe(r,Math.round(n*.35),r,Math.round(n*.75),300,e.serial):await e.driver.swipe(r,Math.round(n*.75),r,Math.round(n*.35),300,e.serial),await z(E.settle.scrollMs),e.setLastHierarchy(null)}if(!l){let{flat:c}=await e.getCleanHierarchy(e.serial);throw e.buildDiagnosticError(o,c,`Element "${o}" not found after scrolling ${t.direction||"down"}.`)}}else t.target==="up"||t.direction==="up"?await e.driver.swipe(r,Math.round(n*.35),r,Math.round(n*.75),300,e.serial):await e.driver.swipe(r,Math.round(n*.75),r,Math.round(n*.35),300,e.serial),await z(E.settle.scrollMs),e.setLastHierarchy(null)}},ys=class{type="SWIPE";async execute(t,e){let{width:s,height:n}=e.screenDimensions,r=Math.round(s*.5),i=t.direction||"left";if(t.target){let{matched:u}=await e.waitForTarget(t.target,e.serial,2500,t);if(u.length>0){let h=u[0],d=i==="left"?h.bounds.x2-40:i==="right"?h.bounds.x1+40:h.bounds.centerX,g=i==="left"?h.bounds.x1+40:i==="right"?h.bounds.x2-40:h.bounds.centerX,m=i==="up"?h.bounds.y2-40:i==="down"?h.bounds.y1+40:h.bounds.centerY,y=i==="up"?h.bounds.y1+40:i==="down"?h.bounds.y2-40:h.bounds.centerY;await e.driver.swipe(d,m,g,y,E.gestures.swipeDurationMs,e.serial),await z(400),e.setLastHierarchy(null);return}}let o=i==="left"?Math.round(s*.8):i==="right"?Math.round(s*.2):r,a=i==="left"?Math.round(s*.2):i==="right"?Math.round(s*.8):r,l=Math.round(i==="up"?n*.75:i==="down"?n*.35:n*.5),c=Math.round(i==="up"?n*.35:i==="down"?n*.75:n*.5);await e.driver.swipe(o,l,a,c,E.gestures.swipeDurationMs,e.serial),await z(400),e.setLastHierarchy(null)}},Ss=class{type="TOGGLE";async execute(t,e){let s=t.target,{flat:n,matched:r}=await e.waitForTarget(s,e.serial,E.polling.defaultTimeoutMs,t);if(r.length===0)throw e.buildDiagnosticError(s,n,`Toggle element matching "${s}" not found.`);let i=r.find(a=>a.clickable)||r[0];if(await e.ensureInViewport(i,e.serial)){let a=await e.waitForTarget(s,e.serial,1500,t);a.matched.length>0&&(i=a.matched.find(l=>l.clickable)||a.matched[0])}if(t.desiredState!==void 0&&i.checked!==void 0&&i.checked===t.desiredState){console.log(ce.gray(` [Toggle] "${s}" is already in desired state (${t.desiredState?"ON":"OFF"}).`));return}await e.driver.tap(i.bounds.centerX,i.bounds.centerY,e.serial),await z(E.settle.toggleMs),e.setLastHierarchy(null)}},vs=class{type="SELECT";async execute(t,e){let s=t.target,n=t.value,{flat:r,matched:i}=await e.waitForTarget(s,e.serial,E.polling.defaultTimeoutMs,t);if(i.length===0)throw e.buildDiagnosticError(s,r,`Dropdown / picker element matching "${s}" not found.`);let o=i.find(c=>c.clickable)||i[0];await e.driver.tap(o.bounds.centerX,o.bounds.centerY,e.serial),await z(E.settle.selectMs),e.setLastHierarchy(null);let a=await e.waitForTarget(n,e.serial,E.polling.defaultTimeoutMs);if(a.matched.length===0)throw e.buildDiagnosticError(n,a.flat,`Dropdown option "${n}" not found.`);let l=a.matched[0];await e.driver.tap(l.bounds.centerX,l.bounds.centerY,e.serial),await z(400),e.setLastHierarchy(null)}},ws=class{type="LAUNCH_APP";async execute(t,e){let s=t.target;if(!s)throw new Error("Target package name required to launch app.");await e.driver.launchApp(s,e.serial),await z(E.settle.launchMs),e.setLastHierarchy(null)}},xs=class{type="RESTART_APP";async execute(t,e){let s=t.target;if(!s)throw new Error("Target package name required to restart app.");await e.driver.restartApp(s,e.serial),await z(E.settle.launchMs),e.setLastHierarchy(null)}},Ts=class{type="TERMINATE_APP";async execute(t,e){let s=t.target||await e.driver.getForegroundPackage(e.serial);s&&await e.driver.forceStop(s,e.serial),await z(E.settle.stopMs),e.setLastHierarchy(null)}},Es=class{type="CLEAR_DATA";async execute(t,e){let s=t.target;if(!s)throw new Error("Target package name required to clear data.");await e.driver.clearAppData(s,e.serial),await z(1e3),e.setLastHierarchy(null)}},Ps=class{type="GRANT_PERMISSION";async execute(t,e){let s=t.value,n=t.target||await e.driver.getForegroundPackage(e.serial);if(!n)throw new Error("Foreground package not detected for grant permission.");await e.driver.grantPermission(n,s,e.serial),await z(400)}},As=class{type="DEEP_LINK";async execute(t,e){let s=t.target;await e.driver.openDeepLink(s,e.serial),await z(E.settle.launchMs),e.setLastHierarchy(null)}},ks=class{type="WAIT";async execute(t,e){await z(t.durationMs||1e3)}},Ds=class{type="IF_VISIBLE";async execute(t,e){let s=t.conditionTarget||t.target;if(!s)return;let n=!1;try{let{matched:r}=await e.waitForTarget(s,e.serial,1500,t);n=r.length>0}catch{n=!1}n?(console.log(ce.cyan(` [Conditional] Condition met: "${s}" is visible.`)),t.thenSteps&&t.thenSteps.length>0&&e.executeChildSteps&&await e.executeChildSteps(t.thenSteps,e)):(console.log(ce.gray(` [Conditional] Condition not met: "${s}" is not visible.`)),t.elseSteps&&t.elseSteps.length>0&&e.executeChildSteps&&await e.executeChildSteps(t.elseSteps,e))}},$s=class{type="LOOP";async execute(t,e){let s=E.flow?.maxLoopIterations||50,n=Math.min(t.loopCount||1,s),r=t.childSteps||[];if(!(r.length===0||!e.executeChildSteps)){console.log(ce.cyan(` [Loop] Starting loop iteration (1 to ${n})...`));for(let i=1;i<=n;i++){t.loopVariable&&e.variables.set(t.loopVariable,String(i)),e.loopStack.push({current:i,total:n,variable:t.loopVariable});try{await e.executeChildSteps(r,e)}finally{e.loopStack.pop()}}}}},Cs=class{type="WAIT_UNTIL";async execute(t,e){let s=t.target,n=t.durationMs||E.flow?.waitUntilTimeoutMs||1e4,r=t.expectedState||"visible";console.log(ce.gray(` [Wait Until] Waiting for "${s}" to be ${r} (up to ${n}ms)...`));let i=Date.now(),o=!1;for(;Date.now()-i<n;){try{let{matched:a}=await e.waitForTarget(s,e.serial,1e3,t);if(a.length>0){let l=a[0];if(r==="enabled"&&!l.enabled){await z(250);continue}o=!0;break}}catch{}await z(250)}if(!o){let{flat:a}=await e.getCleanHierarchy(e.serial);throw e.buildDiagnosticError(s,a,`WaitUntil assertion failed: "${s}" did not become ${r} within ${n}ms.`)}}},Is=class{type="SET_VARIABLE";async execute(t,e){let s=t.variableName,n=t.variableExpression||"";n=st(n,Object.fromEntries(e.variables));let r=on(n);e.variables.set(s,r),console.log(ce.cyan(` [Variable] $${s} = "${r}"`))}},Rs=class{type="DEVICE_STATE";async execute(t,e){let s=t.deviceAction,n=t.deviceStateValue;switch(s){case"wifi":{let r=n===!0||n==="on"||n==="enable";console.log(ce.cyan(` [Device] Setting Wi-Fi: ${r?"ENABLED":"DISABLED"}`)),await e.driver.setWifiEnabled(r,e.serial);break}case"airplane":{let r=n===!0||n==="on"||n==="enable";console.log(ce.cyan(` [Device] Setting Airplane Mode: ${r?"ENABLED":"DISABLED"}`)),await e.driver.setAirplaneMode(r,e.serial);break}case"orientation":{let r=n==="landscape"?"landscape":"portrait";console.log(ce.cyan(` [Device] Setting Orientation: ${r.toUpperCase()}`)),await e.driver.setOrientation(r,e.serial);break}case"notifications":{let r=n==="open"||n==="expand"||n===!0;console.log(ce.cyan(` [Device] ${r?"Expanding":"Collapsing"} Notification Shade`)),r?await e.driver.openNotificationShade(e.serial):await e.driver.collapseNotificationShade(e.serial);break}default:throw new Error(`Unsupported device action: ${s}`)}await z(400),e.setLastHierarchy(null)}},Ls=class{type="RUN_JS";async execute(t,e){let s=t.jsCode||t.value||"";if(!s)return;console.log(ce.cyan(" [JS Hook] Executing sandboxed JavaScript snippet..."));let n={vars:Object.fromEntries(e.variables),setVar:(i,o)=>{e.variables.set(i,String(o))},getVar:i=>e.variables.get(i),console:{log:(...i)=>console.log(ce.gray(" [JS Output]",...i)),error:(...i)=>console.error(ce.red(" [JS Error]",...i))}},r=Cn.createContext(n);Cn.runInContext(s,r,{timeout:3e3});for(let[i,o]of Object.entries(n.vars))e.variables.set(i,String(o))}},Ns=class{type="ENTER_OTP";async execute(t,e){console.log(ce.cyan(" [OTP Capture] Detecting verification code..."));let s=null;if(process.env.PROMPTTEST_MOCK_OTP)s=process.env.PROMPTTEST_MOCK_OTP.trim(),console.log(ce.gray(` [OTP Capture] Captured code from environment: ${s}`));else try{let{stdout:n}=await e.driver.execAdb(["shell","logcat","-d","-t","200","-s","SMSDispatcher:V","SmsMessage:V","NotificationService:V","ActivityManager:I"],e.serial),r=n.match(/(?:code|otp|pin|verification)[^0-9\r\n]{0,35}(\d{4,8})\b/i)||n.match(/\b(\d{4,8})\s*(?:is your verification|is your otp)/i);r&&(s=r[1],console.log(ce.gray(` [OTP Capture] Captured code from logcat: ${s}`)))}catch{}if(s||(s="123456",console.log(ce.yellow(` [OTP Capture] No live code detected; using simulated OTP: ${s}`))),t.target){let n={originalText:`Type '${s}' into '${t.target}'`,type:"TYPE",target:t.target,value:s};return new Gt().execute(n,e)}else{let{flat:n}=await e.getCleanHierarchy(e.serial),r=e.findTargetInputField(n,"code",s)||n.find(i=>i.className.includes("EditText"));r?(await e.driver.tap(r.bounds.centerX,r.bounds.centerY,e.serial),await z(250),await e.driver.inputText(s,e.serial)):await e.driver.inputText(s,e.serial)}}},Ms=class{type="API_REQUEST";async execute(t,e){let s=t.apiMethod||"GET",n=t.apiUrl||"";if(!n)throw new Error("API_REQUEST requires a valid target URL.");console.log(ce.cyan(` [API Request] ${s} ${n}...`));let r={method:s,headers:{"Content-Type":"application/json",Accept:"application/json"}};t.apiBody&&(s==="POST"||s==="PUT"||s==="PATCH")&&(r.body=t.apiBody);let i=await fetch(n,r);if(t.apiExpectedStatus!==void 0){if(i.status!==t.apiExpectedStatus)throw new Error(`API status assertion failed for ${n}: expected HTTP ${t.apiExpectedStatus}, but received HTTP ${i.status}`);console.log(ce.green(` \u2714 API Status HTTP ${i.status} matched expectation.`))}if(t.apiStorePath&&t.apiStoreVariable)try{let o=await i.text(),a=JSON.parse(o),l=this.resolveJsonPath(a,t.apiStorePath);l!==void 0&&(e.variables.set(t.apiStoreVariable,String(l)),console.log(ce.cyan(` [Variable] $${t.apiStoreVariable} = "${l}" (from ${t.apiStorePath})`)))}catch(o){Be.warn(`Failed to parse JSON response for path extraction: ${o.message}`)}}resolveJsonPath(t,e){let s=e.replace(/^\$\.?/,"").split("."),n=t;for(let r of s){if(n==null||typeof n!="object")return;n=n[r]}return n}},Fs=class{type="EMAIL_ASSERT";async execute(t,e){let s=t.emailRecipient||"",n=t.emailSubject||"";console.log(ce.cyan(` [Email Assertion] Checking email to "${s}" with subject "${n}"...`));let r=[];if(process.env.PROMPTTEST_MOCK_EMAILS)try{r=JSON.parse(process.env.PROMPTTEST_MOCK_EMAILS)}catch{r=[]}let i=r.find(o=>o.to.toLowerCase()===s.toLowerCase()&&o.subject.toLowerCase().includes(n.toLowerCase()));if(!i){if(r.length===0){if(!s.includes("@"))throw new Error(`Invalid email recipient address: "${s}"`);console.log(ce.yellow(" \u26A0 No mock inbox configured (PROMPTTEST_MOCK_EMAILS); simulated email check passed."));return}throw new Error(`Email assertion failed: No email to "${s}" with subject "${n}" found.`)}if(t.emailBodyContains&&i.body&&!i.body.includes(t.emailBodyContains))throw new Error(`Email body assertion failed: Expected email to contain "${t.emailBodyContains}", but content did not match.`);console.log(ce.green(" \u2714 Email verified successfully."))}},hi=[new ps,new hs,new Gt,new gs,new ms,new fs,new bs,new ys,new Ss,new vs,new ws,new xs,new Ts,new Es,new Ps,new As,new ks,new Ds,new $s,new Cs,new Is,new Rs,new Ls,new Ns,new Ms,new Fs],In=new Map(hi.map(p=>[p.type,p]))});var ut,Kt=oe(()=>{"use strict";Oe();Yt();ut=class{providerName="heuristic";async resolveIntent(t,e){let s=Z(t);return(s.includes("login")||s.includes("log in")||s.includes("sign in")||s.includes("signin"))&&(s.includes("test user")||s.includes("default credentials")||s.includes("credentials"))?[{originalText:"Type 'user@example.com' into 'Email'",type:"TYPE",target:"Email",value:"user@example.com"},{originalText:"Type 'Password123!' into 'Password'",type:"TYPE",target:"Password",value:"Password123!"},{originalText:"Tap 'Sign In'",type:"TAP",target:"Sign In"}]:s.includes("sign up with random user")||s.includes("register new user")?[{originalText:"Type $RANDOM_NAME into 'Name'",type:"TYPE",target:"Name",value:"$RANDOM_NAME"},{originalText:"Type $RANDOM_EMAIL into 'Email'",type:"TYPE",target:"Email",value:"$RANDOM_EMAIL"},{originalText:"Type 'Password123!' into 'Password'",type:"TYPE",target:"Password",value:"Password123!"},{originalText:"Tap 'Create Account'",type:"TAP",target:"Create Account"}]:s.includes("dismiss dialog")||s.includes("close modal")||s.includes("dismiss popup")?[{originalText:"Tap 'Close'",type:"TAP",target:"Close",optional:!0},{originalText:"Tap 'Dismiss'",type:"TAP",target:"Dismiss",optional:!0},{originalText:"Press back",type:"BACK",optional:!0}]:null}async findSuggestions(t,e,s){let n=[],r=Z(t),i=new Set,o=Pn(t,s?.locale);for(let u of o){let h=e.find(d=>d.bounds.width>0&&d.bounds.height>0&&(ne(u,d.text)||ne(u,d.contentDesc)));if(h){let d=(h.text||h.contentDesc||u).trim();i.has(d)||(i.add(d),n.push({text:d,score:.9,node:h,strategy:"synonym",reason:`Direct synonym match for "${t}" via semantic dictionary`}))}}for(let u of e)if(u.resourceId&&u.bounds.width>0&&u.bounds.height>0&&u.resourceId.toLowerCase().split(/[:/_]/).some(g=>g===r||r.includes(g))){let g=(u.text||u.contentDesc||u.resourceId).trim();i.has(g)||(i.add(g),n.push({text:g,score:.85,node:u,strategy:"exact",reason:`Resource-ID segment matches target "${t}"`}))}let a=[];for(let u of e)u.bounds.width>0&&u.bounds.height>0&&(u.text&&u.text.trim().length>1&&a.push({text:u.text.trim(),node:u}),u.contentDesc&&u.contentDesc.trim().length>1&&a.push({text:u.contentDesc.trim(),node:u}));let l=Array.from(new Set(a.map(u=>u.text))),c=nt(t,l,5);for(let u of c)if(u.score>=.7&&!i.has(u.text)){i.add(u.text);let h=a.find(d=>d.text===u.text)?.node;n.push({text:u.text,score:u.score,node:h,strategy:"fuzzy",reason:`String similarity match (${Math.round(u.score*100)}%)`})}return n.sort((u,h)=>h.score-u.score)}}});var yt,zt,_s=oe(()=>{"use strict";Kt();ft();yt=class{providerName="mock";mockIntents=new Map;mockSuggestions=new Map;constructor(){this.mockIntents.set("log in to account",[{originalText:"Type 'test@example.com' into 'Email'",type:"TYPE",target:"Email",value:"test@example.com"},{originalText:"Type 'Password123' into 'Password'",type:"TYPE",target:"Password",value:"Password123"},{originalText:"Tap 'Sign In'",type:"TAP",target:"Sign In"}])}setMockIntent(t,e){this.mockIntents.set(t.toLowerCase().trim(),e)}setMockSuggestion(t,e){this.mockSuggestions.set(t.toLowerCase().trim(),e)}async resolveIntent(t,e){let s=t.toLowerCase().trim();return this.mockIntents.has(s)?this.mockIntents.get(s):null}async findSuggestions(t,e,s){let n=t.toLowerCase().trim();return this.mockSuggestions.has(n)?this.mockSuggestions.get(n):new ut().findSuggestions(t,e)}},zt=class{providerName;config;heuristicFallback;constructor(t){this.config=t,this.providerName=t.provider,this.heuristicFallback=new ut}async resolveIntent(t,e){if(this.config.provider==="mock")return new yt().resolveIntent(t,e);try{let s=`You are a test automation engineer generating steps for PromptTest.
690
+ `)}formatMarkdownReport(t){let i=["# \u{1F9EA} PromptTest Autonomous Mobile QA Audit Report","",`**Status:** ${t.failedSteps===0&&t.errorsDetected.length===0?"\u2705 ALL PASSED":"\u26A0\uFE0F ISSUES DETECTED"} `,`**Target Package:** \`${t.packageName}\` `,`**Device:** \`${t.deviceId}\` `,`**Execution Time:** ${t.durationSeconds}s (${t.startTime} to ${t.endTime}) `];if(t.videoPath&&i.push(`**Screen Recording:** [Download Video](./${t.videoPath}) `),i.push("","---","","## \u{1F4CA} Executive Summary","","| Metric | Count |","|---|---|",`| **Total Steps** | ${t.totalSteps} |`,`| **Passed** | \u{1F7E2} ${t.passedSteps} |`,`| **Warnings** | \u{1F7E1} ${t.warnSteps} |`,`| **Failures** | \u{1F534} ${t.failedSteps} |`,`| **Skipped** | \u26AA ${t.skippedSteps} |`,`| **Errors Detected** | ${t.errorsDetected.length} |`,""),t.errorsDetected.length>0){i.push("## \u26A0\uFE0F Errors & Sentinels Flagged");for(let n of t.errorsDetected)i.push(`- \u{1F534} \`${n}\``);i.push("")}i.push("## \u{1F50D} Detailed Execution Timeline"),i.push(""),i.push("| Step | Phase | Action | Target / Details | Status | Duration | Screenshot / Triage |"),i.push("|---|---|---|---|---|---|---|");let r=n=>(n||"").replace(/\|/g,"\\|").replace(/\r?\n/g," ");for(let n of t.steps){let o="\u2014";n.triageBundle?o=`[\u{1F50D} Triage Bundle](./${n.triageBundle})`:n.screenshotPath&&(o=`[\u{1F4F8} Screenshot](./${n.screenshotPath})`);let a=n.durationMs!==void 0?`${n.durationMs}ms`:"\u2014",d=n.status==="PASS"?"\u{1F7E2} PASS":n.status==="WARN"?"\u{1F7E1} WARN":n.status==="SKIPPED"?"\u26AA SKIPPED":"\u{1F534} FAIL";i.push(`| ${n.stepIndex} | ${r(n.phase)} | ${r(n.action)} | ${r(n.description)} | ${d} | ${a} | ${o} |`)}return i.push(""),i.push("---"),i.push("*Generated autonomously by PromptTest Mobile QA Brain.*"),i.join(`
691
+ `)}resolveScreenshotData(t){if(t.screenshotPath){if(this.embedScreenshots){if(this.screenshotBuffers.has(t.stepIndex))return`data:image/png;base64,${this.screenshotBuffers.get(t.stepIndex).toString("base64")}`;let e=ze.join(this.outputDir,t.screenshotPath);if(Ye.existsSync(e))try{return`data:image/png;base64,${Ye.readFileSync(e).toString("base64")}`}catch{}}return`./${t.screenshotPath}`}}formatHtmlReport(t,e){return as(t,{suiteName:e,embedScreenshots:this.embedScreenshots,screenshotResolver:s=>this.resolveScreenshotData(s)})}};bt=new at});function cn(p){let t=new Map;for(let[e,s]of Object.entries(p)){let r=[Z(e),...s.map(n=>Z(n))];for(let n of r){t.has(n)||t.set(n,[]);let o=t.get(n);for(let a of r)o.includes(a)||o.push(a)}}return t}function Ct(p,t="en"){let e=Z(p),s=(t||"en").toLowerCase(),i=cs.get(s);if(i){let r=i.get(e);if(r&&r.length>0)return r}if(s!=="en"){let r=cs.get("en");if(r){let n=r.get(e);if(n&&n.length>0)return n}}return[e]}var Ti,gr,cs,Ei,Yt=oe(()=>{"use strict";Oe();Ti={en:{bell:["bell","notification","notifications","alert","alerts","reminders","notice","badge"],notification:["notification","notifications","bell","alert","alerts","reminders","badge"],close:["close","dismiss","cancel","clear","cross","exit","\u2715","\xD7","x"],like:["like","favorite","heart","thumbs up","thumbs-up","fav","upvote"],dislike:["dislike","thumbs down","thumbs-down","downvote"],search:["search","find","query","magnifier","explore","lookup"],settings:["settings","preferences","gear","options","setup","config"],profile:["profile","account","user","my profile","avatar","me","personal"],trash:["trash","delete","remove","bin","discard"],delete:["delete","trash","remove","bin","discard"],share:["share","export","send to","forward"],back:["back","navigate up","previous","arrow back","chevron left","return"],menu:["menu","hamburger","drawer","sidebar","options","navigation","\u2630"],add:["add","new","create","plus","+","insert"],edit:["edit","pencil","modify","update","rename","change"],calendar:["calendar","schedule","date","events","timetable"],refresh:["refresh","reload","sync","update"],info:["info","information","details","help","about"],filter:["filter","filters","sort","refine","funnel"],check:["check","done","tick","mark","select","\u2713","\u2714"],lock:["lock","security","privacy","padlock"],camera:["camera","photo","picture","capture","snapshot"],cart:["cart","shopping cart","bag","basket","checkout"],email:["email","username","user name","e-mail","mail","login ID","user id"],username:["username","user name","email","user id","handle"],password:["password","passcode","pin","pwd","secret"],phone:["phone","mobile","contact","telephone","cell","phone number"],name:["name","full name","first name","last name"],otp:["otp","verification code","code","pin"],submit:["submit","save","continue","confirm","proceed","done","apply","ok"],save:["save","submit","done","apply","store","update"],cancel:["cancel","abort","discard","close","dismiss"],confirm:["confirm","yes","proceed","ok","agree","accept"],login:["sign in","signin","log in","login","enter"],signin:["sign in","signin","log in","login","enter"],logout:["sign out","signout","log out","logout","exit"],signout:["sign out","signout","log out","logout","exit"]},es:{bell:["campana","notificaci\xF3n","notificaciones","alerta","alertas","aviso","avisos"],notification:["notificaci\xF3n","notificaciones","campana","alerta","alertas","aviso","avisos","notification","notifications"],close:["cerrar","cancelar","quitar","salir","descartar","\u2715","\xD7","x","close"],like:["me gusta","favorito","favoritos","coraz\xF3n","like"],dislike:["no me gusta","desaprobar"],search:["buscar","b\xFAsqueda","lupa","explorar","encontrar","search"],settings:["ajustes","configuraci\xF3n","preferencias","opciones","settings"],profile:["perfil","cuenta","usuario","mi perfil","avatar","profile"],trash:["papelera","eliminar","borrar","descartar","quitar"],delete:["eliminar","borrar","quitar","papelera","descartar","delete"],share:["compartir","enviar","difundir","share"],back:["atr\xE1s","volver","regresar","anterior","flecha atr\xE1s","back"],menu:["men\xFA","opciones","navegaci\xF3n","\u2630","menu"],add:["a\xF1adir","agregar","nuevo","crear","m\xE1s","+","add"],edit:["editar","modificar","cambiar","actualizar","edit"],calendar:["calendario","fecha","eventos","horario","calendar"],refresh:["actualizar","recargar","sincronizar","refresh"],info:["informaci\xF3n","detalles","ayuda","acerca de","info"],filter:["filtrar","filtros","ordenar","filter"],check:["listo","hecho","marcar","seleccionar","\u2713","\u2714","check"],lock:["bloqueo","seguridad","privacidad","candado","lock"],camera:["c\xE1mara","foto","captura","imagen","camera"],cart:["carrito","cesta","bolsa","comprar","cart","checkout"],email:["correo","correo electr\xF3nico","email","usuario","mail"],username:["usuario","nombre de usuario","correo","username"],password:["contrase\xF1a","clave","pin","c\xF3digo","password"],phone:["tel\xE9fono","m\xF3vil","celular","contacto","n\xFAmero","phone"],name:["nombre","nombre completo","apellidos","name"],otp:["c\xF3digo de verificaci\xF3n","c\xF3digo","otp","pin"],submit:["enviar","guardar","confirmar","continuar","proceder","listo","aceptar","submit"],save:["guardar","salvar","almacenar","actualizar","save"],cancel:["cancelar","descartar","anular","abortar","cancel"],confirm:["confirmar","aceptar","s\xED","continuar","de acuerdo","confirm"],login:["iniciar sesi\xF3n","entrar","acceder","identificarse","ingresar","login","sign in"],signin:["iniciar sesi\xF3n","entrar","acceder","identificarse","ingresar","login","sign in"],logout:["cerrar sesi\xF3n","salir","desconectar","logout","sign out"],signout:["cerrar sesi\xF3n","salir","desconectar","logout","sign out"]},hi:{bell:["\u0918\u0902\u091F\u0940","\u0928\u094B\u091F\u093F\u092B\u093F\u0915\u0947\u0936\u0928","\u0938\u0942\u091A\u0928\u093E\u090F\u0902","alert","reminders"],notification:["\u0928\u094B\u091F\u093F\u092B\u093F\u0915\u0947\u0936\u0928","\u0938\u0942\u091A\u0928\u093E\u090F\u0902","alert","reminders","notification"],close:["\u092C\u0902\u0926 \u0915\u0930\u0947\u0902","\u0939\u091F\u093E\u090F\u0902","\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902","\u2715","\xD7","x","close"],like:["\u092A\u0938\u0902\u0926","\u0932\u093E\u0907\u0915","\u092A\u0938\u0902\u0926\u0940\u0926\u093E"],dislike:["\u0928\u093E\u092A\u0938\u0902\u0926"],search:["\u0916\u094B\u091C\u0947\u0902","\u0922\u0942\u0902\u0922\u0947\u0902","\u0938\u0930\u094D\u091A","explore","search"],settings:["\u0938\u0947\u091F\u093F\u0902\u0917\u094D\u0938","\u0935\u093F\u0915\u0932\u094D\u092A","\u092A\u094D\u0930\u093E\u0925\u092E\u093F\u0915\u0924\u093E\u090F\u0902","settings"],profile:["\u092A\u094D\u0930\u094B\u092B\u093C\u093E\u0907\u0932","\u0916\u093E\u0924\u093E","\u0909\u092A\u092F\u094B\u0917\u0915\u0930\u094D\u0924\u093E","\u0905\u0915\u093E\u0909\u0902\u091F","profile"],trash:["\u0939\u091F\u093E\u090F\u0902","\u0921\u093F\u0932\u0940\u091F","\u0915\u091A\u0930\u093E"],delete:["\u0939\u091F\u093E\u090F\u0902","\u0921\u093F\u0932\u0940\u091F","\u092E\u093F\u091F\u093E\u090F\u0902","delete"],share:["\u0936\u0947\u092F\u0930 \u0915\u0930\u0947\u0902","\u092D\u0947\u091C\u0947\u0902","share"],back:["\u0935\u093E\u092A\u0938","\u092A\u0940\u091B\u0947","\u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0902","back"],menu:["\u092E\u0947\u0928\u0942","\u0935\u093F\u0915\u0932\u094D\u092A","\u2630","menu"],add:["\u091C\u094B\u0921\u093C\u0947\u0902","\u0928\u092F\u093E","\u092C\u0928\u093E\u090F\u0902","+","add"],edit:["\u0938\u0902\u092A\u093E\u0926\u093F\u0924 \u0915\u0930\u0947\u0902","\u092C\u0926\u0932\u0947\u0902","\u090F\u0921\u093F\u091F","edit"],calendar:["\u0915\u0948\u0932\u0947\u0902\u0921\u0930","\u0924\u093E\u0930\u0940\u0916","\u0938\u092E\u092F \u0938\u093E\u0930\u093F\u0923\u0940"],refresh:["\u0930\u093F\u092B\u094D\u0930\u0947\u0936","\u0924\u093E\u091C\u093C\u093E \u0915\u0930\u0947\u0902","\u0905\u092A\u0921\u0947\u091F \u0915\u0930\u0947\u0902"],info:["\u091C\u093E\u0928\u0915\u093E\u0930\u0940","\u0935\u093F\u0935\u0930\u0923","\u092E\u0926\u0926","info"],filter:["\u092B\u093C\u093F\u0932\u094D\u091F\u0930","\u091B\u093E\u0902\u091F\u0947\u0902","filter"],check:["\u0939\u094B \u0917\u092F\u093E","\u091A\u0941\u0928\u0947\u0902","\u0938\u0939\u0940","\u2713","\u2714"],cart:["\u0915\u093E\u0930\u094D\u091F","\u0925\u0948\u0932\u093E","\u091F\u094B\u0915\u0930\u0940","cart"],email:["\u0908\u092E\u0947\u0932","\u0908-\u092E\u0947\u0932","\u092F\u0942\u091C\u0930\u0928\u0947\u092E","email"],username:["\u0909\u092A\u092F\u094B\u0917\u0915\u0930\u094D\u0924\u093E \u0928\u093E\u092E","\u092F\u0942\u091C\u0930\u0928\u0947\u092E","\u0908\u092E\u0947\u0932","username"],password:["\u092A\u093E\u0938\u0935\u0930\u094D\u0921","\u092A\u093F\u0928","\u092A\u093E\u0938\u0915\u094B\u0921","password"],phone:["\u092B\u093C\u094B\u0928","\u092E\u094B\u092C\u093E\u0907\u0932","\u0928\u0902\u092C\u0930","\u0938\u0902\u092A\u0930\u094D\u0915","phone"],name:["\u0928\u093E\u092E","\u092A\u0942\u0930\u093E \u0928\u093E\u092E","name"],otp:["\u0913\u091F\u0940\u092A\u0940","\u0938\u0924\u094D\u092F\u093E\u092A\u0928 \u0915\u094B\u0921","\u092A\u093F\u0928","otp"],submit:["\u091C\u092E\u093E \u0915\u0930\u0947\u0902","\u0938\u092C\u092E\u093F\u091F","\u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902","\u0906\u0917\u0947 \u092C\u0922\u093C\u0947\u0902","submit"],save:["\u0938\u0939\u0947\u091C\u0947\u0902","\u0938\u0947\u0935 \u0915\u0930\u0947\u0902","\u0938\u0941\u0930\u0915\u094D\u0937\u093F\u0924 \u0915\u0930\u0947\u0902","save"],cancel:["\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902","\u0915\u0948\u0902\u0938\u093F\u0932","cancel"],confirm:["\u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902","\u0938\u094D\u0935\u0940\u0915\u093E\u0930 \u0915\u0930\u0947\u0902","\u0939\u093E\u0901","\u0920\u0940\u0915 \u0939\u0948","confirm"],login:["\u0932\u0949\u0917 \u0907\u0928","\u0932\u0949\u0917\u093F\u0928","\u092A\u094D\u0930\u0935\u0947\u0936 \u0915\u0930\u0947\u0902","\u0938\u093E\u0907\u0928 \u0907\u0928","login","sign in"],signin:["\u0932\u0949\u0917 \u0907\u0928","\u0932\u0949\u0917\u093F\u0928","\u0938\u093E\u0907\u0928 \u0907\u0928","\u092A\u094D\u0930\u0935\u0947\u0936 \u0915\u0930\u0947\u0902","login","sign in"],logout:["\u0932\u0949\u0917 \u0906\u0909\u091F","\u0938\u093E\u0907\u0928 \u0906\u0909\u091F","\u092C\u093E\u0939\u0930 \u0928\u093F\u0915\u0932\u0947\u0902","logout"],signout:["\u0932\u0949\u0917 \u0906\u0909\u091F","\u0938\u093E\u0907\u0928 \u0906\u0909\u091F","\u092C\u093E\u0939\u0930 \u0928\u093F\u0915\u0932\u0947\u0902","logout"]}},gr=Ti.en,cs=new Map;for(let[p,t]of Object.entries(Ti))cs.set(p.toLowerCase(),cn(t));Ei=Ct});import we from"fs";import Ve from"path";import{fileURLToPath as ln}from"url";var Xe,ve,Qe=oe(()=>{"use strict";Oe();Yt();Pe();Xe=class p{memoryDir;currentPackage="global";mappings=new Map;screens=new Map;intents=new Map;dirty=!1;locale="en";setLocale(t){this.locale=(t||"en").toLowerCase()}getLocale(){return this.locale}constructor(t){if(t)this.memoryDir=t;else{let e=Ve.dirname(ln(import.meta.url));this.memoryDir=Ve.resolve(e,"..","memory")}we.existsSync(this.memoryDir)||we.mkdirSync(this.memoryDir,{recursive:!0})}cleanPackageName(t){return(t||"global").replace(/[^a-zA-Z0-9._-]/g,"_")}static SCHEMA_VERSION=2;async init(t){this.currentPackage=this.cleanPackageName(t),this.mappings.clear(),this.screens.clear(),this.intents.clear(),this.dirty=!1;let e=Ve.join(this.memoryDir,`${this.currentPackage}.json`);if(we.existsSync(e))try{let s=await we.promises.readFile(e,"utf-8"),i=JSON.parse(s);if(i&&i.mappings){let r=!i.version||i.version<2;for(let[n,o]of Object.entries(i.mappings))r&&(o.totalSuccesses=o.totalSuccesses??o.successCount??1,o.recentOutcomes=o.recentOutcomes??(o.failCount>0?["FAIL"]:["PASS"]),o.lastSeenTs=o.lastSeenTs??o.lastUpdated??new Date().toISOString(),this.dirty=!0),this.mappings.set(n,o);if(i.screens)for(let[n,o]of Object.entries(i.screens))this.screens.set(n,o);if(i.intents)for(let[n,o]of Object.entries(i.intents))this.intents.set(n,o);this.decayStaleMappings()}else this.mappings.clear(),this.screens.clear(),this.intents.clear()}catch{this.mappings.clear(),this.screens.clear(),this.intents.clear()}}getCanonicalQuery(t){let e=Z(t),s=Ct(e,this.locale);return s&&s.length>0?s[0]:e}buildKey(t,e){return`${t.toUpperCase()}:${this.getCanonicalQuery(e)}`}resolve(t,e){let s=this.buildKey(t,e),i=this.mappings.get(s);if(i)return i;let r=`${t.toUpperCase()}:${Z(e)}`,n=this.mappings.get(r);if(n)return n;let o=Ct(e,this.locale);for(let a of o){let d=`${t.toUpperCase()}:${a}`,c=this.mappings.get(d);if(c)return c}}getAllCandidates(t,e,s,i){let r=(s||this.locale||"en").toLowerCase(),n=new Set;if(i){let d=this.getScreenElements(i),c=this.getCanonicalQuery(e);for(let l of d)l.action===t.toUpperCase()&&(l.canonicalIntent===c||l.canonicalIntent===Z(e))&&l.confidence>=.7&&n.add(l.matchedIdentifier)}let o=this.resolve(t,e);o&&o.confidence>=.8&&n.add(o.matchedIdentifier),n.add(e);let a=Ct(e,r);for(let d of a)n.add(d);return Array.from(n)}recordSuccess(t,e,s,i,r=1,n,o){if(s.length>35||s.includes("?")||s.includes(`
692
+ `))return;let a=this.buildKey(t,e),d=this.mappings.get(a),c=new Date().toISOString(),l=n||d?.healedFrom?P.memory?.maxHealedConfidence??.65:1,h=n||d?.healedFrom?Math.min(r,l):r;d&&d.matchedIdentifier===s?(d.successCount+=1,d.totalSuccesses=(d.totalSuccesses||0)+1,d.failCount=0,d.recentOutcomes||(d.recentOutcomes=[]),d.recentOutcomes.push("PASS"),d.recentOutcomes.length>5&&d.recentOutcomes.shift(),d.confidence=Math.min(l,Number((d.confidence+.05).toFixed(2))),d.lastUpdated=c,d.lastSeenTs=c,n&&(d.healedFrom=n)):this.mappings.set(a,{canonicalIntent:this.getCanonicalQuery(e),action:t.toUpperCase(),matchedIdentifier:s,matchType:i,confidence:h,successCount:1,failCount:0,totalSuccesses:1,recentOutcomes:["PASS"],lastUpdated:c,lastSeenTs:c,healedFrom:n}),o&&this.associateScreenElement(o,a),this.dirty=!0}associateScreenElement(t,e){if(!t||!e)return;let s=new Date().toISOString(),i=this.screens.get(t);i?(i.elements.includes(e)||i.elements.push(e),i.lastSeenTs=s):this.screens.set(t,{lastSeenTs:s,elements:[e]}),this.dirty=!0}getScreenElements(t){let e=this.screens.get(t);return e?e.elements.map(s=>this.mappings.get(s)).filter(s=>s!==void 0):[]}getScreenIndex(){return Object.fromEntries(this.screens.entries())}markScreenCrawled(t,e){if(!t)return;let s=new Date().toISOString(),i=this.screens.get(t);if(i){if(i.crawled=!0,i.crawledAt=s,i.lastSeenTs=s,e&&e.length>0){i.safeActions||(i.safeActions=[]);for(let r of e)i.safeActions.includes(r)||i.safeActions.push(r)}}else this.screens.set(t,{lastSeenTs:s,elements:[],crawled:!0,crawledAt:s,safeActions:e?[...e]:[]});this.dirty=!0}isScreenCrawled(t){return t?!!this.screens.get(t)?.crawled:!1}getScreenMemory(t){return this.screens.get(t)}getCrawledScreensCount(){let t=0;for(let e of this.screens.values())e.crawled&&t++;return t}recordIntentExpansion(t,e){if(!t||!e||e.length===0)return;let s=Z(t),i=new Date().toISOString(),r=this.intents.get(s);r?(r.steps=[...e],r.usageCount=(r.usageCount||1)+1,r.learnedAt=i):this.intents.set(s,{intent:t,steps:[...e],learnedAt:i,usageCount:1}),this.dirty=!0}getIntentExpansion(t){if(!t)return;let e=Z(t),s=this.intents.get(e);if(s)return s.usageCount=(s.usageCount||0)+1,this.dirty=!0,[...s.steps]}hasIntentExpansion(t){return t?this.intents.has(Z(t)):!1}getIntentExpansionsCount(){return this.intents.size}recordFailure(t,e){let s=this.buildKey(t,e),i=this.mappings.get(s);i&&(i.failCount+=1,i.recentOutcomes||(i.recentOutcomes=[]),i.recentOutcomes.push("FAIL"),i.recentOutcomes.length>5&&i.recentOutcomes.shift(),i.confidence=Math.max(.1,Number((i.confidence-.25).toFixed(2))),i.lastUpdated=new Date().toISOString(),(i.recentOutcomes.filter(n=>n==="FAIL").length>=3||i.confidence<.2)&&this.mappings.delete(s),this.dirty=!0)}decayStaleMappings(t){let s=(t??P.memory?.staleThresholdDays??14)*24*60*60*1e3,i=Date.now(),r=0;for(let n of this.mappings.values()){let o=n.lastSeenTs?new Date(n.lastSeenTs).getTime():0;if(o>0&&i-o>s){let a=P.memory?.staleDecayAmount??.2,d=P.memory?.minConfidenceFloor??.2,c=Math.max(d,Number((n.confidence-a).toFixed(2)));c<n.confidence&&(n.confidence=c,r++,this.dirty=!0)}}return r}async save(){if(!this.dirty)return;let t={packageName:this.currentPackage,version:p.SCHEMA_VERSION,lastUpdated:new Date().toISOString(),mappings:Object.fromEntries(this.mappings.entries()),screens:Object.fromEntries(this.screens.entries()),intents:Object.fromEntries(this.intents.entries())},e=Ve.join(this.memoryDir,`${this.currentPackage}.json`),s=`${e}.tmp.${Date.now()}`;await we.promises.writeFile(s,JSON.stringify(t,null,2),"utf-8");try{await we.promises.rename(s,e)}catch{await we.promises.copyFile(s,e),await we.promises.unlink(s).catch(()=>{})}this.dirty=!1}async exportMemory(t){let e=t?Ve.resolve(t):Ve.join(this.memoryDir,`${this.currentPackage}-export.json`),s=Ve.dirname(e);we.existsSync(s)||we.mkdirSync(s,{recursive:!0});let i={packageName:this.currentPackage,version:p.SCHEMA_VERSION,lastUpdated:new Date().toISOString(),mappings:Object.fromEntries(this.mappings.entries()),screens:Object.fromEntries(this.screens.entries()),intents:Object.fromEntries(this.intents.entries())};return await we.promises.writeFile(e,JSON.stringify(i,null,2),"utf-8"),e}async importMemory(t){let e=Ve.resolve(t);if(!we.existsSync(e))throw new Error(`Memory import source file not found: ${e}`);let s=await we.promises.readFile(e,"utf-8"),i=JSON.parse(s);if(!i||!i.mappings)throw new Error("Invalid memory file format: missing mappings object.");let r=0,n=new Date().toISOString();for(let[o,a]of Object.entries(i.mappings)){let d=this.mappings.get(o);(!d||a.confidence>=d.confidence)&&(this.mappings.set(o,{...a,totalSuccesses:a.totalSuccesses??a.successCount??1,recentOutcomes:a.recentOutcomes??["PASS"],lastSeenTs:a.lastSeenTs??a.lastUpdated??n,lastUpdated:n}),r++)}if(i.screens)for(let[o,a]of Object.entries(i.screens)){let d=this.screens.get(o);if(!d)this.screens.set(o,a);else{let c=new Set([...d.elements,...a.elements]),l=new Set([...d.safeActions||[],...a.safeActions||[]]);this.screens.set(o,{lastSeenTs:a.lastSeenTs||d.lastSeenTs,elements:Array.from(c),crawled:d.crawled||a.crawled,crawledAt:a.crawledAt||d.crawledAt,safeActions:Array.from(l)})}}if(i.intents)for(let[o,a]of Object.entries(i.intents)){let d=this.intents.get(o);(!d||(a.usageCount||0)>=(d.usageCount||0))&&this.intents.set(o,a)}return r>0&&(this.dirty=!0,await this.save()),r}getMappingsList(){return Array.from(this.mappings.values())}getStats(){let t=Array.from(this.mappings.values()),e=t.reduce((r,n)=>r+(n.totalSuccesses||n.successCount||0),0),s=t.length>0?Number((t.reduce((r,n)=>r+n.confidence,0)/t.length).toFixed(2)):0,i=0;for(let r of this.screens.values())r.crawled&&i++;return{totalMappings:this.mappings.size,totalScreens:this.screens.size,crawledScreens:i,totalIntents:this.intents.size,package:this.currentPackage,totalSuccesses:e,averageConfidence:s}}async clear(t){let e=this.cleanPackageName(t||this.currentPackage),s=Ve.join(this.memoryDir,`${e}.json`);return we.existsSync(s)?(await we.promises.unlink(s),e===this.currentPackage&&(this.mappings.clear(),this.screens.clear(),this.intents.clear(),this.dirty=!1),!0):!1}},ve=new Xe});import Le from"fs";import dn from"path";import un from"os";function ct(p){let t=(p||"default").replace(/[^a-zA-Z0-9._-]/g,"_"),e=dn.join(un.tmpdir(),`prompttest-${t}.lock`);if(Le.existsSync(e))try{let i=Le.readFileSync(e,"utf-8").trim(),r=parseInt(i,10);if(!isNaN(r)){if(r===process.pid)return{serial:p,lockFilePath:e,acquired:!0,pid:process.pid};try{throw process.kill(r,0),new Error(`Device "${p}" is locked by another PromptTest process (PID ${r}).
693
+ Wait for the other run to complete, or remove the lock file if it is stale: ${e}`)}catch(n){if(n.code==="ESRCH")try{Le.unlinkSync(e)}catch{}else throw n}}}catch(i){let r=i;if(r.message&&r.message.includes("locked by another"))throw r;try{Le.unlinkSync(e)}catch{}}try{Le.writeFileSync(e,process.pid.toString(),{flag:"wx"})}catch(i){throw i.code==="EEXIST"?new Error(`Device "${p}" was just acquired by a concurrent PromptTest process.`):i}let s=()=>{try{Le.existsSync(e)&&Le.readFileSync(e,"utf-8").trim()===process.pid.toString()&&Le.unlinkSync(e)}catch{}};return ls.set(e,s),process.once("exit",s),{serial:p,lockFilePath:e,acquired:!0,pid:process.pid}}function lt(p){if(p)try{let t=ls.get(p.lockFilePath);if(t)process.removeListener("exit",t),ls.delete(p.lockFilePath),t();else if(Le.existsSync(p.lockFilePath))try{Le.readFileSync(p.lockFilePath,"utf-8").trim()===process.pid.toString()&&Le.unlinkSync(p.lockFilePath)}catch{}}catch{}}var ls,It=oe(()=>{"use strict";ls=new Map});import qe from"fs";import Ai from"path";var ds,ki,Di=oe(()=>{"use strict";ds=class{checkpointDir;constructor(t){this.checkpointDir=t||Ai.resolve(process.cwd(),"output","checkpoints"),qe.existsSync(this.checkpointDir)||qe.mkdirSync(this.checkpointDir,{recursive:!0})}filePath(t){let e=t.replace(/[^a-zA-Z0-9._-]/g,"_");return Ai.join(this.checkpointDir,`${e}.checkpoint.json`)}async save(t,e,s,i){let r={specFile:t,packageName:e,lastPassedStep:s,totalSteps:i,savedAt:new Date().toISOString()},n=this.filePath(t)+`.tmp.${Date.now()}`;await qe.promises.writeFile(n,JSON.stringify(r,null,2),"utf-8"),await qe.promises.rename(n,this.filePath(t))}async load(t){let e=this.filePath(t);if(!qe.existsSync(e))return null;try{let s=await qe.promises.readFile(e,"utf-8");return JSON.parse(s)}catch{return null}}async clear(t){let e=this.filePath(t);qe.existsSync(e)&&await qe.promises.unlink(e)}async getResumeIndex(t){let e=await this.load(t);return e?e.lastPassedStep+1:0}},ki=new ds});import $e from"fs";import Lt from"path";import{PNG as dt}from"pngjs";import pn from"pixelmatch";var Nt,us,Xt=oe(()=>{"use strict";Nt=class{baselineDir;defaultThreshold;constructor(t,e=.02){this.baselineDir=t||Lt.resolve(process.cwd(),"output","baselines"),this.defaultThreshold=e,$e.existsSync(this.baselineDir)||$e.mkdirSync(this.baselineDir,{recursive:!0})}filePath(t,e){let s=t.replace(/[^a-zA-Z0-9._-]/g,"_");return Lt.join(this.baselineDir,`${s}_step${String(e).padStart(3,"0")}.png`)}diffFilePath(t,e){let s=t.replace(/[^a-zA-Z0-9._-]/g,"_");return Lt.join(this.baselineDir,`${s}_step${String(e).padStart(3,"0")}_diff.png`)}async saveBaseline(t,e,s){let i=this.filePath(t,e),r=i+`.tmp.${Date.now()}`;return await $e.promises.writeFile(r,s),await $e.promises.rename(r,i),i}hasBaseline(t,e){return $e.existsSync(this.filePath(t,e))}async compare(t,e,s,i){let r=typeof i=="number"?{threshold:i}:i||{},n=this.filePath(t,e),o=Lt.join(this.baselineDir,`${t.replace(/[^a-zA-Z0-9._-]/g,"_")}_step${String(e).padStart(3,"0")}_current.png`);await $e.promises.writeFile(o,s);let a=r.threshold??this.defaultThreshold;if(!$e.existsSync(n)){await this.saveBaseline(t,e,s);let v=dt.sync.read(s),C=v.width*v.height;return{stepName:`Step ${e}`,baselineFile:n,currentFile:o,diffRatio:0,diffPixels:0,totalPixels:C,passed:!0,threshold:a}}let d=await $e.promises.readFile(n),c=dt.sync.read(d),l=dt.sync.read(s),h=Math.max(c.width,l.width),u=Math.max(c.height,l.height),g=h*u,m=this.fitToCanvas(c,h,u),y=this.fitToCanvas(l,h,u);r.maskRegions&&r.maskRegions.length>0&&(this.applyMasks(m,r.maskRegions),this.applyMasks(y,r.maskRegions));let S=new dt({width:h,height:u}),b=r.pixelmatchThreshold??.1,f=pn(m.data,y.data,S.data,h,u,{threshold:b,includeAA:!1}),x=g>0?f/g:0,T=x<=a,$;if(f>0){$=this.diffFilePath(t,e);let v=dt.sync.write(S);await $e.promises.writeFile($,v)}return{stepName:`Step ${e}`,baselineFile:n,currentFile:o,diffRatio:x,diffPixels:f,totalPixels:g,passed:T,threshold:a,diffImagePath:$}}fitToCanvas(t,e,s){if(t.width===e&&t.height===s)return t;let i=new dt({width:e,height:s});return i.data.fill(0),dt.bitblt(t,i,0,0,t.width,t.height,0,0),i}applyMasks(t,e){for(let s of e){let i=Math.min(t.width,s.x+s.width),r=Math.min(t.height,s.y+s.height);for(let n=Math.max(0,s.y);n<r;n++)for(let o=Math.max(0,s.x);o<i;o++){let a=t.width*n+o<<2;t.data[a]=0,t.data[a+1]=0,t.data[a+2]=0,t.data[a+3]=0}}}async clearBaselines(t){let e=t.replace(/[^a-zA-Z0-9._-]/g,"_");if(!$e.existsSync(this.baselineDir))return;let s=await $e.promises.readdir(this.baselineDir);await Promise.all(s.filter(i=>i.startsWith(e+"_step")).map(i=>$e.promises.unlink(Lt.join(this.baselineDir,i)).catch(()=>{})))}},us=new Nt});import ce from"chalk";import $i from"vm";function z(p){return new Promise(t=>setTimeout(t,p))}function hn(p){let t=p.screenDimensions.height,e=p.navBarHeight>0?t-p.navBarHeight:t,s=p.navBarHeight>0?e*.94:t*P.gestures.bottomNavThresholdRatio;return{effectiveHeight:e,bottomThreshold:s}}var ps,hs,Gt,gs,ms,fs,bs,ys,Ss,vs,ws,xs,Ts,Es,Ps,As,ks,Ds,$s,Cs,Is,Rs,Ls,Ns,Ms,Fs,gn,Ci,Os=oe(()=>{"use strict";Pe();ft();Oe();ps=class{type="TAP";async execute(t,e){let s=t.target,{width:i,height:r}=e.screenDimensions,n=Math.round(i*.5),{flat:o,matched:a}=await e.waitForTarget(s,e.serial,P.polling.defaultTimeoutMs,t);if(a.length===0&&e.upcomingSteps&&e.upcomingSteps.length>0&&!o.some(S=>S.password===!0||S.className.includes("EditText")&&o.some(b=>b.text?.toLowerCase().includes("password")))){let S=e.upcomingSteps.findIndex(f=>f.type==="VERIFY"&&f.target&&e.matchNodes(o,f.target,f).length>0);if(S!==-1)return{fastForwarded:!0,reason:`Screen already displays "${e.upcomingSteps[S].target}"`,skipCount:S};let b=e.upcomingSteps.findIndex(f=>f.type==="TAP"&&f.target&&e.matchNodes(o,f.target,f).length>0);if(b!==-1)return{fastForwarded:!0,reason:`Upcoming action "${e.upcomingSteps[b].target}" is directly actionable`,skipCount:b}}if(a.length===0){await e.driver.swipe(n,Math.round(r*.75),n,Math.round(r*.35),300,e.serial),await z(350),e.setLastHierarchy(null);let y=await e.waitForTarget(s,e.serial,2e3,t);o=y.flat,a=y.matched}if(a.length===0)throw e.buildDiagnosticError(s,o,`Element matching "${s}" not found on current screen.`);let d=a.find(y=>y.clickable)||a[0];if(await e.ensureInViewport(d,e.serial)){let y=await e.waitForTarget(s,e.serial,1500,t);y.matched.length>0&&(o=y.flat,a=y.matched,d=a.find(S=>S.clickable)||a[0])}let l=d.bounds.centerX,{effectiveHeight:h}=hn(e),u=d.bounds.centerY;if(d.bounds.y2>h&&(u=Math.min(Math.round((d.bounds.y1+h)/2),h-15)),u=Math.min(u,d.bounds.y2-2),u=Math.max(u,d.bounds.y1+2),u>r*.6&&typeof e.driver.isKeyboardVisible=="function")try{await e.driver.isKeyboardVisible(e.serial)&&(console.log(ce.gray(` [Keyboard] Target occluded by soft keyboard (Y=${u} > ${Math.round(r*.6)}). Dismissing...`)),await e.driver.pressBack(e.serial),await z(300),e.setLastHierarchy(null))}catch{}let g=d.contentDesc||d.text||d.resourceId;console.log(ce.gray(` [Tap Target] (${l}, ${u}) for "${g||s}"`));let m=e.lastHierarchy?.hash;await e.driver.tap(l,u,e.serial),await z(P.settle.tapMs),e.setLastHierarchy(null),g&&Z(g)!==Z(s)&&e.memory.recordSuccess("TAP",s,g,d.contentDesc?"contentDesc":d.text?"text":"resourceId",1,void 0,m)}},hs=class{type="LONG_PRESS";async execute(t,e){let s=t.target,{flat:i,matched:r}=await e.waitForTarget(s,e.serial,P.polling.defaultTimeoutMs,t);if(r.length===0)throw e.buildDiagnosticError(s,i,`Element matching "${s}" not found for long-press.`);let n=r[0];if(await e.ensureInViewport(n,e.serial)){let a=await e.waitForTarget(s,e.serial,1500,t);a.matched.length>0&&(n=a.matched[0])}await e.driver.swipe(n.bounds.centerX,n.bounds.centerY,n.bounds.centerX,n.bounds.centerY,P.gestures.longPressDurationMs,e.serial),await z(300),e.setLastHierarchy(null)}},Gt=class{type="TYPE";async execute(t,e){let s=t.target,i=t.value??"",r=[],n=null;if(e.lastHierarchy&&Date.now()-e.lastHierarchy.timestamp<P.polling.hierarchyCacheTtlMs){let l=e.findTargetInputField(e.lastHierarchy.flat,s,i);l&&(r=e.lastHierarchy.flat,n=l)}if(n||(r=(await e.getCleanHierarchy(e.serial)).flat,n=e.findTargetInputField(r,s,i)),!n){let l=Date.now();for(;Date.now()-l<2e3&&(await z(200),r=(await e.getCleanHierarchy(e.serial)).flat,n=e.findTargetInputField(r,s,i),!n););}if(!n&&e.upcomingSteps&&e.upcomingSteps.length>0&&!r.some(h=>h.className.includes("EditText"))){let h=e.upcomingSteps.findIndex(u=>u.type==="VERIFY"&&u.target&&e.matchNodes(r,u.target,u).length>0);if(h!==-1)return{fastForwarded:!0,reason:`Screen already displays "${e.upcomingSteps[h].target}" and form is completed`,skipCount:h}}if(!n)throw e.buildDiagnosticError(s,r,`Input field matching "${s}" not found.`);if(n.text&&n.text===i){console.log(ce.gray(` [Input Field] Already contains desired value "${i}". Skipping typing.`));return}if(await e.ensureInViewport(n,e.serial)){r=(await e.getCleanHierarchy(e.serial)).flat;let h=e.findTargetInputField(r,s,i);h&&(n=h)}let{height:a}=e.screenDimensions;if(n.bounds.centerY>a*.6&&typeof e.driver.isKeyboardVisible=="function")try{await e.driver.isKeyboardVisible(e.serial)&&(console.log(ce.gray(" [Keyboard] Input field occluded by soft keyboard. Dismissing before focus...")),await e.driver.pressBack(e.serial),await z(300),e.setLastHierarchy(null))}catch{}let d=e.lastHierarchy?.hash;await e.driver.tap(n.bounds.centerX,n.bounds.centerY,e.serial),await z(P.settle.inputFocusMs),await e.driver.clearField(e.serial),await z(P.settle.inputClearMs),await e.driver.inputText(i,e.serial),await z(P.settle.inputDoneMs),e.setLastHierarchy(null);let c=n.contentDesc||n.resourceId;c&&Z(c)!==Z(s)&&e.memory.recordSuccess("TYPE",s,c,n.contentDesc?"contentDesc":"resourceId",1,void 0,d)}},gs=class{type="CLEAR";async execute(t,e){let s=t.target,i=[],r=null;if(e.lastHierarchy&&Date.now()-e.lastHierarchy.timestamp<P.polling.hierarchyCacheTtlMs&&(r=e.findTargetInputField(e.lastHierarchy.flat,s),r&&(i=e.lastHierarchy.flat)),r||(i=(await e.getCleanHierarchy(e.serial)).flat,r=e.findTargetInputField(i,s)),!r){let o=e.matchNodes(i,s,t);o.length>0&&(r=o[0])}if(!r)throw e.buildDiagnosticError(s,i,`Input field matching "${s}" not found to clear.`);await e.driver.tap(r.bounds.centerX,r.bounds.centerY,e.serial),await z(300);let n=e.driver;typeof n.clearField=="function"?await n.clearField(e.serial):typeof n.clearInput=="function"&&await n.clearInput(50,e.serial),await z(200),e.setLastHierarchy(null)}},ms=class{type="VERIFY";async execute(t,e){let s=t.target,i=t.expectedState||"visible";if(t.negative===!0||i==="absent"||i==="hidden"){let h=await e.getCleanHierarchy(e.serial);if(e.matchNodes(h.flat,s,t).length>0)throw new Error(`Negative assertion failed: "${s}" was expected to be NOT visible, but is present on screen.`);return}let{width:n,height:o}=e.screenDimensions,a=Math.round(n*.5),d=!1,c=[],l;if(e.lastHierarchy&&Date.now()-e.lastHierarchy.timestamp<P.polling.verifyCacheTtlMs&&(l=e.matchNodes(e.lastHierarchy.flat,s,t)[0],l&&(c=e.lastHierarchy.flat,d=!0,e.lastHierarchy.timestamp=Date.now())),!d){let h=Date.now();for(;Date.now()-h<P.polling.extendedTimeoutMs;){if(c=(await e.getCleanHierarchy(e.serial)).flat,l=e.matchNodes(c,s,t)[0],l){d=!0,e.lastHierarchy&&(e.lastHierarchy.timestamp=Date.now()),await z(400);break}await z(200)}}if(d||(await e.driver.swipe(a,Math.round(o*.75),a,Math.round(o*.35),300,e.serial),await z(400),c=(await e.getCleanHierarchy(e.serial)).flat,l=e.matchNodes(c,s,t)[0],l&&(d=!0)),!d){if(e.upcomingSteps&&e.upcomingSteps.length>0&&!c.some(u=>u.password===!0||u.className.includes("EditText")&&c.some(g=>g.text?.toLowerCase().includes("password")))){let u=e.upcomingSteps.findIndex(g=>g.type==="VERIFY"&&g.target&&e.matchNodes(c,g.target,g).length>0);if(u!==-1)return{fastForwarded:!0,reason:`Screen is already on "${e.upcomingSteps[u].target}"`,skipCount:u}}throw await e.driver.swipe(a,Math.round(o*.35),a,Math.round(o*.75),300,e.serial),await z(300),e.buildDiagnosticError(s,c,`Verification assertion failed: "${s}" is not visible on screen.`)}if(l&&i==="disabled"&&l.enabled)throw new Error(`State assertion failed: "${s}" was expected to be DISABLED, but is enabled.`);if(l&&i==="enabled"&&!l.enabled)throw new Error(`State assertion failed: "${s}" was expected to be ENABLED, but is disabled.`)}},fs=class{type="BACK";async execute(t,e){await e.driver.pressKey(4,e.serial),await z(P.settle.backMs),e.setLastHierarchy(null)}},bs=class{type="SCROLL";async execute(t,e){let{width:s,height:i}=e.screenDimensions,r=Math.round(s*.5);if(t.target&&t.target!=="up"&&t.target!=="down"){let o=t.target,a=t.direction||"down",d=!1;for(let c=0;c<5;c++){let{flat:l}=await e.getCleanHierarchy(e.serial),h=e.matchNodes(l,o,t);if(h.length>0){await e.ensureInViewport(h[0],e.serial),d=!0;break}a==="up"?await e.driver.swipe(r,Math.round(i*.35),r,Math.round(i*.75),300,e.serial):await e.driver.swipe(r,Math.round(i*.75),r,Math.round(i*.35),300,e.serial),await z(P.settle.scrollMs),e.setLastHierarchy(null)}if(!d){let{flat:c}=await e.getCleanHierarchy(e.serial);throw e.buildDiagnosticError(o,c,`Element "${o}" not found after scrolling ${t.direction||"down"}.`)}}else t.target==="up"||t.direction==="up"?await e.driver.swipe(r,Math.round(i*.35),r,Math.round(i*.75),300,e.serial):await e.driver.swipe(r,Math.round(i*.75),r,Math.round(i*.35),300,e.serial),await z(P.settle.scrollMs),e.setLastHierarchy(null)}},ys=class{type="SWIPE";async execute(t,e){let{width:s,height:i}=e.screenDimensions,r=Math.round(s*.5),n=t.direction||"left";if(t.target){let{matched:l}=await e.waitForTarget(t.target,e.serial,2500,t);if(l.length>0){let h=l[0],u=n==="left"?h.bounds.x2-40:n==="right"?h.bounds.x1+40:h.bounds.centerX,g=n==="left"?h.bounds.x1+40:n==="right"?h.bounds.x2-40:h.bounds.centerX,m=n==="up"?h.bounds.y2-40:n==="down"?h.bounds.y1+40:h.bounds.centerY,y=n==="up"?h.bounds.y1+40:n==="down"?h.bounds.y2-40:h.bounds.centerY;await e.driver.swipe(u,m,g,y,P.gestures.swipeDurationMs,e.serial),await z(400),e.setLastHierarchy(null);return}}let o=n==="left"?Math.round(s*.8):n==="right"?Math.round(s*.2):r,a=n==="left"?Math.round(s*.2):n==="right"?Math.round(s*.8):r,d=Math.round(n==="up"?i*.75:n==="down"?i*.35:i*.5),c=Math.round(n==="up"?i*.35:n==="down"?i*.75:i*.5);await e.driver.swipe(o,d,a,c,P.gestures.swipeDurationMs,e.serial),await z(400),e.setLastHierarchy(null)}},Ss=class{type="TOGGLE";async execute(t,e){let s=t.target,{flat:i,matched:r}=await e.waitForTarget(s,e.serial,P.polling.defaultTimeoutMs,t);if(r.length===0)throw e.buildDiagnosticError(s,i,`Toggle element matching "${s}" not found.`);let n=r.find(a=>a.clickable)||r[0];if(await e.ensureInViewport(n,e.serial)){let a=await e.waitForTarget(s,e.serial,1500,t);a.matched.length>0&&(n=a.matched.find(d=>d.clickable)||a.matched[0])}if(t.desiredState!==void 0&&n.checked!==void 0&&n.checked===t.desiredState){console.log(ce.gray(` [Toggle] "${s}" is already in desired state (${t.desiredState?"ON":"OFF"}).`));return}await e.driver.tap(n.bounds.centerX,n.bounds.centerY,e.serial),await z(P.settle.toggleMs),e.setLastHierarchy(null)}},vs=class{type="SELECT";async execute(t,e){let s=t.target,i=t.value,{flat:r,matched:n}=await e.waitForTarget(s,e.serial,P.polling.defaultTimeoutMs,t);if(n.length===0)throw e.buildDiagnosticError(s,r,`Dropdown / picker element matching "${s}" not found.`);let o=n.find(c=>c.clickable)||n[0];await e.driver.tap(o.bounds.centerX,o.bounds.centerY,e.serial),await z(P.settle.selectMs),e.setLastHierarchy(null);let a=await e.waitForTarget(i,e.serial,P.polling.defaultTimeoutMs);if(a.matched.length===0)throw e.buildDiagnosticError(i,a.flat,`Dropdown option "${i}" not found.`);let d=a.matched[0];await e.driver.tap(d.bounds.centerX,d.bounds.centerY,e.serial),await z(400),e.setLastHierarchy(null)}},ws=class{type="LAUNCH_APP";async execute(t,e){let s=t.target;if(!s)throw new Error("Target package name required to launch app.");await e.driver.launchApp(s,e.serial),await z(P.settle.launchMs),e.setLastHierarchy(null)}},xs=class{type="RESTART_APP";async execute(t,e){let s=t.target;if(!s)throw new Error("Target package name required to restart app.");await e.driver.restartApp(s,e.serial),await z(P.settle.launchMs),e.setLastHierarchy(null)}},Ts=class{type="TERMINATE_APP";async execute(t,e){let s=t.target||await e.driver.getForegroundPackage(e.serial);s&&await e.driver.forceStop(s,e.serial),await z(P.settle.stopMs),e.setLastHierarchy(null)}},Es=class{type="CLEAR_DATA";async execute(t,e){let s=t.target;if(!s)throw new Error("Target package name required to clear data.");await e.driver.clearAppData(s,e.serial),await z(1e3),e.setLastHierarchy(null)}},Ps=class{type="GRANT_PERMISSION";async execute(t,e){let s=t.value,i=t.target||await e.driver.getForegroundPackage(e.serial);if(!i)throw new Error("Foreground package not detected for grant permission.");await e.driver.grantPermission(i,s,e.serial),await z(400)}},As=class{type="DEEP_LINK";async execute(t,e){let s=t.target;await e.driver.openDeepLink(s,e.serial),await z(P.settle.launchMs),e.setLastHierarchy(null)}},ks=class{type="WAIT";async execute(t,e){await z(t.durationMs||1e3)}},Ds=class{type="IF_VISIBLE";async execute(t,e){let s=t.conditionTarget||t.target;if(!s)return;let i=!1;try{let{matched:r}=await e.waitForTarget(s,e.serial,1500,t);i=r.length>0}catch{i=!1}i?(console.log(ce.cyan(` [Conditional] Condition met: "${s}" is visible.`)),t.thenSteps&&t.thenSteps.length>0&&e.executeChildSteps&&await e.executeChildSteps(t.thenSteps,e)):(console.log(ce.gray(` [Conditional] Condition not met: "${s}" is not visible.`)),t.elseSteps&&t.elseSteps.length>0&&e.executeChildSteps&&await e.executeChildSteps(t.elseSteps,e))}},$s=class{type="LOOP";async execute(t,e){let s=P.flow?.maxLoopIterations||50,i=Math.min(t.loopCount||1,s),r=t.childSteps||[];if(!(r.length===0||!e.executeChildSteps)){console.log(ce.cyan(` [Loop] Starting loop iteration (1 to ${i})...`));for(let n=1;n<=i;n++){t.loopVariable&&e.variables.set(t.loopVariable,String(n)),e.loopStack.push({current:n,total:i,variable:t.loopVariable});try{await e.executeChildSteps(r,e)}finally{e.loopStack.pop()}}}}},Cs=class{type="WAIT_UNTIL";async execute(t,e){let s=t.target,i=t.durationMs||P.flow?.waitUntilTimeoutMs||1e4,r=t.expectedState||"visible";console.log(ce.gray(` [Wait Until] Waiting for "${s}" to be ${r} (up to ${i}ms)...`));let n=Date.now(),o=!1;for(;Date.now()-n<i;){try{let{matched:a}=await e.waitForTarget(s,e.serial,1e3,t);if(a.length>0){let d=a[0];if(r==="enabled"&&!d.enabled){await z(250);continue}o=!0;break}}catch{}await z(250)}if(!o){let{flat:a}=await e.getCleanHierarchy(e.serial);throw e.buildDiagnosticError(s,a,`WaitUntil assertion failed: "${s}" did not become ${r} within ${i}ms.`)}}},Is=class{type="SET_VARIABLE";async execute(t,e){let s=t.variableName,i=t.variableExpression||"";i=st(i,Object.fromEntries(e.variables));let r=ri(i);e.variables.set(s,r),console.log(ce.cyan(` [Variable] $${s} = "${r}"`))}},Rs=class{type="DEVICE_STATE";async execute(t,e){let s=t.deviceAction,i=t.deviceStateValue;switch(s){case"wifi":{let r=i===!0||i==="on"||i==="enable";console.log(ce.cyan(` [Device] Setting Wi-Fi: ${r?"ENABLED":"DISABLED"}`)),await e.driver.setWifiEnabled(r,e.serial);break}case"airplane":{let r=i===!0||i==="on"||i==="enable";console.log(ce.cyan(` [Device] Setting Airplane Mode: ${r?"ENABLED":"DISABLED"}`)),await e.driver.setAirplaneMode(r,e.serial);break}case"orientation":{let r=i==="landscape"?"landscape":"portrait";console.log(ce.cyan(` [Device] Setting Orientation: ${r.toUpperCase()}`)),await e.driver.setOrientation(r,e.serial);break}case"notifications":{let r=i==="open"||i==="expand"||i===!0;console.log(ce.cyan(` [Device] ${r?"Expanding":"Collapsing"} Notification Shade`)),r?await e.driver.openNotificationShade(e.serial):await e.driver.collapseNotificationShade(e.serial);break}default:throw new Error(`Unsupported device action: ${s}`)}await z(400),e.setLastHierarchy(null)}},Ls=class{type="RUN_JS";async execute(t,e){let s=t.jsCode||t.value||"";if(!s)return;console.log(ce.cyan(" [JS Hook] Executing sandboxed JavaScript snippet..."));let i={vars:Object.fromEntries(e.variables),setVar:(n,o)=>{e.variables.set(n,String(o))},getVar:n=>e.variables.get(n),console:{log:(...n)=>console.log(ce.gray(" [JS Output]",...n)),error:(...n)=>console.error(ce.red(" [JS Error]",...n))}},r=$i.createContext(i);$i.runInContext(s,r,{timeout:3e3});for(let[n,o]of Object.entries(i.vars))e.variables.set(n,String(o))}},Ns=class{type="ENTER_OTP";async execute(t,e){console.log(ce.cyan(" [OTP Capture] Detecting verification code..."));let s=null;if(process.env.PROMPTTEST_MOCK_OTP)s=process.env.PROMPTTEST_MOCK_OTP.trim(),console.log(ce.gray(` [OTP Capture] Captured code from environment: ${s}`));else try{let{stdout:i}=await e.driver.execAdb(["shell","logcat","-d","-t","200","-s","SMSDispatcher:V","SmsMessage:V","NotificationService:V","ActivityManager:I"],e.serial),r=i.match(/(?:code|otp|pin|verification)[^0-9\r\n]{0,35}(\d{4,8})\b/i)||i.match(/\b(\d{4,8})\s*(?:is your verification|is your otp)/i);r&&(s=r[1],console.log(ce.gray(` [OTP Capture] Captured code from logcat: ${s}`)))}catch{}if(s||(s="123456",console.log(ce.yellow(` [OTP Capture] No live code detected; using simulated OTP: ${s}`))),t.target){let i={originalText:`Type '${s}' into '${t.target}'`,type:"TYPE",target:t.target,value:s};return new Gt().execute(i,e)}else{let{flat:i}=await e.getCleanHierarchy(e.serial),r=e.findTargetInputField(i,"code",s)||i.find(n=>n.className.includes("EditText"));r?(await e.driver.tap(r.bounds.centerX,r.bounds.centerY,e.serial),await z(250),await e.driver.inputText(s,e.serial)):await e.driver.inputText(s,e.serial)}}},Ms=class{type="API_REQUEST";async execute(t,e){let s=t.apiMethod||"GET",i=t.apiUrl||"";if(!i)throw new Error("API_REQUEST requires a valid target URL.");console.log(ce.cyan(` [API Request] ${s} ${i}...`));let r={method:s,headers:{"Content-Type":"application/json",Accept:"application/json"}};t.apiBody&&(s==="POST"||s==="PUT"||s==="PATCH")&&(r.body=t.apiBody);let n=await fetch(i,r);if(t.apiExpectedStatus!==void 0){if(n.status!==t.apiExpectedStatus)throw new Error(`API status assertion failed for ${i}: expected HTTP ${t.apiExpectedStatus}, but received HTTP ${n.status}`);console.log(ce.green(` \u2714 API Status HTTP ${n.status} matched expectation.`))}if(t.apiStorePath&&t.apiStoreVariable)try{let o=await n.text(),a=JSON.parse(o),d=this.resolveJsonPath(a,t.apiStorePath);d!==void 0&&(e.variables.set(t.apiStoreVariable,String(d)),console.log(ce.cyan(` [Variable] $${t.apiStoreVariable} = "${d}" (from ${t.apiStorePath})`)))}catch(o){Be.warn(`Failed to parse JSON response for path extraction: ${o.message}`)}}resolveJsonPath(t,e){let s=e.replace(/^\$\.?/,"").split("."),i=t;for(let r of s){if(i==null||typeof i!="object")return;i=i[r]}return i}},Fs=class{type="EMAIL_ASSERT";async execute(t,e){let s=t.emailRecipient||"",i=t.emailSubject||"";console.log(ce.cyan(` [Email Assertion] Checking email to "${s}" with subject "${i}"...`));let r=[];if(process.env.PROMPTTEST_MOCK_EMAILS)try{r=JSON.parse(process.env.PROMPTTEST_MOCK_EMAILS)}catch{r=[]}let n=r.find(o=>o.to.toLowerCase()===s.toLowerCase()&&o.subject.toLowerCase().includes(i.toLowerCase()));if(!n){if(r.length===0){if(!s.includes("@"))throw new Error(`Invalid email recipient address: "${s}"`);console.log(ce.yellow(" \u26A0 No mock inbox configured (PROMPTTEST_MOCK_EMAILS); simulated email check passed."));return}throw new Error(`Email assertion failed: No email to "${s}" with subject "${i}" found.`)}if(t.emailBodyContains&&n.body&&!n.body.includes(t.emailBodyContains))throw new Error(`Email body assertion failed: Expected email to contain "${t.emailBodyContains}", but content did not match.`);console.log(ce.green(" \u2714 Email verified successfully."))}},gn=[new ps,new hs,new Gt,new gs,new ms,new fs,new bs,new ys,new Ss,new vs,new ws,new xs,new Ts,new Es,new Ps,new As,new ks,new Ds,new $s,new Cs,new Is,new Rs,new Ls,new Ns,new Ms,new Fs],Ci=new Map(gn.map(p=>[p.type,p]))});var ut,Kt=oe(()=>{"use strict";Oe();Yt();ut=class{providerName="heuristic";async resolveIntent(t,e){let s=Z(t);return(s.includes("login")||s.includes("log in")||s.includes("sign in")||s.includes("signin"))&&(s.includes("test user")||s.includes("default credentials")||s.includes("credentials"))?[{originalText:"Type 'user@example.com' into 'Email'",type:"TYPE",target:"Email",value:"user@example.com"},{originalText:"Type 'Password123!' into 'Password'",type:"TYPE",target:"Password",value:"Password123!"},{originalText:"Tap 'Sign In'",type:"TAP",target:"Sign In"}]:s.includes("sign up with random user")||s.includes("register new user")?[{originalText:"Type $RANDOM_NAME into 'Name'",type:"TYPE",target:"Name",value:"$RANDOM_NAME"},{originalText:"Type $RANDOM_EMAIL into 'Email'",type:"TYPE",target:"Email",value:"$RANDOM_EMAIL"},{originalText:"Type 'Password123!' into 'Password'",type:"TYPE",target:"Password",value:"Password123!"},{originalText:"Tap 'Create Account'",type:"TAP",target:"Create Account"}]:s.includes("dismiss dialog")||s.includes("close modal")||s.includes("dismiss popup")?[{originalText:"Tap 'Close'",type:"TAP",target:"Close",optional:!0},{originalText:"Tap 'Dismiss'",type:"TAP",target:"Dismiss",optional:!0},{originalText:"Press back",type:"BACK",optional:!0}]:null}async findSuggestions(t,e,s){let i=[],r=Z(t),n=new Set,o=Ei(t,s?.locale);for(let l of o){let h=e.find(u=>u.bounds.width>0&&u.bounds.height>0&&(ie(l,u.text)||ie(l,u.contentDesc)));if(h){let u=(h.text||h.contentDesc||l).trim();n.has(u)||(n.add(u),i.push({text:u,score:.9,node:h,strategy:"synonym",reason:`Direct synonym match for "${t}" via semantic dictionary`}))}}for(let l of e)if(l.resourceId&&l.bounds.width>0&&l.bounds.height>0&&l.resourceId.toLowerCase().split(/[:/_]/).some(g=>g===r||r.includes(g))){let g=(l.text||l.contentDesc||l.resourceId).trim();n.has(g)||(n.add(g),i.push({text:g,score:.85,node:l,strategy:"exact",reason:`Resource-ID segment matches target "${t}"`}))}let a=[];for(let l of e)l.bounds.width>0&&l.bounds.height>0&&(l.text&&l.text.trim().length>1&&a.push({text:l.text.trim(),node:l}),l.contentDesc&&l.contentDesc.trim().length>1&&a.push({text:l.contentDesc.trim(),node:l}));let d=Array.from(new Set(a.map(l=>l.text))),c=it(t,d,5);for(let l of c)if(l.score>=.7&&!n.has(l.text)){n.add(l.text);let h=a.find(u=>u.text===l.text)?.node;i.push({text:l.text,score:l.score,node:h,strategy:"fuzzy",reason:`String similarity match (${Math.round(l.score*100)}%)`})}return i.sort((l,h)=>h.score-l.score)}}});var yt,zt,_s=oe(()=>{"use strict";Kt();ft();yt=class{providerName="mock";mockIntents=new Map;mockSuggestions=new Map;constructor(){this.mockIntents.set("log in to account",[{originalText:"Type 'test@example.com' into 'Email'",type:"TYPE",target:"Email",value:"test@example.com"},{originalText:"Type 'Password123' into 'Password'",type:"TYPE",target:"Password",value:"Password123"},{originalText:"Tap 'Sign In'",type:"TAP",target:"Sign In"}])}setMockIntent(t,e){this.mockIntents.set(t.toLowerCase().trim(),e)}setMockSuggestion(t,e){this.mockSuggestions.set(t.toLowerCase().trim(),e)}async resolveIntent(t,e){let s=t.toLowerCase().trim();return this.mockIntents.has(s)?this.mockIntents.get(s):null}async findSuggestions(t,e,s){let i=t.toLowerCase().trim();return this.mockSuggestions.has(i)?this.mockSuggestions.get(i):new ut().findSuggestions(t,e)}},zt=class{providerName;config;heuristicFallback;constructor(t){this.config=t,this.providerName=t.provider,this.heuristicFallback=new ut}async resolveIntent(t,e){if(this.config.provider==="mock")return new yt().resolveIntent(t,e);try{let s=`You are a test automation engineer generating steps for PromptTest.
694
694
  Convert the following high-level user intent into a concrete sequence of plain-English test steps.
695
695
  Valid syntax examples:
696
696
  - Tap 'Button Label'
@@ -703,80 +703,80 @@ Valid syntax examples:
703
703
  User Intent: "${t}"
704
704
 
705
705
  Return ONLY a JSON array of plain strings representing each step, e.g.:
706
- ["Type 'user@test.com' into 'Email'", "Tap 'Next'"]`,n=await this.callLlm(s);if(!n)return this.heuristicFallback.resolveIntent(t,e);let r=n.match(/\[[\s\S]*\]/);return r?JSON.parse(r[0]).map(a=>({originalText:a,type:a.startsWith("Tap")?"TAP":a.startsWith("Type")?"TYPE":"VERIFY"})):this.heuristicFallback.resolveIntent(t,e)}catch(s){return Be.warn(`LLM intent resolution failed (${s.message}), falling back to heuristic engine.`),this.heuristicFallback.resolveIntent(t,e)}}async findSuggestions(t,e,s){if(this.config.provider==="mock")return new yt().findSuggestions(t,e,s);try{let n=e.filter(l=>l.bounds.width>0&&l.bounds.height>0&&(l.text||l.contentDesc)).map(l=>({text:l.text||l.contentDesc,id:l.resourceId||"",class:l.className.split(".").pop()})).slice(0,30),r=`A UI test failed because an element named "${t}" could not be found.
706
+ ["Type 'user@test.com' into 'Email'", "Tap 'Next'"]`,i=await this.callLlm(s);if(!i)return this.heuristicFallback.resolveIntent(t,e);let r=i.match(/\[[\s\S]*\]/);return r?JSON.parse(r[0]).map(a=>({originalText:a,type:a.startsWith("Tap")?"TAP":a.startsWith("Type")?"TYPE":"VERIFY"})):this.heuristicFallback.resolveIntent(t,e)}catch(s){return Be.warn(`LLM intent resolution failed (${s.message}), falling back to heuristic engine.`),this.heuristicFallback.resolveIntent(t,e)}}async findSuggestions(t,e,s){if(this.config.provider==="mock")return new yt().findSuggestions(t,e,s);try{let i=e.filter(d=>d.bounds.width>0&&d.bounds.height>0&&(d.text||d.contentDesc)).map(d=>({text:d.text||d.contentDesc,id:d.resourceId||"",class:d.className.split(".").pop()})).slice(0,30),r=`A UI test failed because an element named "${t}" could not be found.
707
707
  Here are the visible UI elements on the current Android screen:
708
- ${JSON.stringify(n,null,2)}
708
+ ${JSON.stringify(i,null,2)}
709
709
 
710
710
  Identify the best matching replacement element for "${t}".
711
711
  Respond ONLY with a JSON object in this format:
712
- {"bestMatch": "Exact Text of Best Element", "confidence": 0.85, "reason": "Reason for match"}`,i=await this.callLlm(r);if(!i)return this.heuristicFallback.findSuggestions(t,e,s);let o=i.match(/\{[\s\S]*\}/);if(!o)return this.heuristicFallback.findSuggestions(t,e,s);let a=JSON.parse(o[0]);if(a.bestMatch){let l=e.find(c=>c.text===a.bestMatch||c.contentDesc===a.bestMatch);return[{text:a.bestMatch,score:typeof a.confidence=="number"?a.confidence:.85,node:l,strategy:"llm",reason:a.reason||"LLM semantic match"},...await this.heuristicFallback.findSuggestions(t,e,s)]}}catch(n){Be.warn(`LLM self-healing failed (${n.message}), using heuristic suggestions.`)}return this.heuristicFallback.findSuggestions(t,e,s)}async callLlm(t){let e=this.config.timeoutMs||8e3,s=new AbortController,n=setTimeout(()=>s.abort(),e);try{if(this.config.provider==="openai"){let r=this.config.apiKey||process.env.OPENAI_API_KEY;if(!r)throw new Error("OPENAI_API_KEY is not set");let i=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:this.config.model||"gpt-4o-mini",messages:[{role:"user",content:t}],temperature:.1}),signal:s.signal});if(!i.ok)throw new Error(`OpenAI HTTP ${i.status}: ${await i.text()}`);return(await i.json()).choices?.[0]?.message?.content||null}if(this.config.provider==="anthropic"){let r=this.config.apiKey||process.env.ANTHROPIC_API_KEY;if(!r)throw new Error("ANTHROPIC_API_KEY is not set");let i=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":r,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:this.config.model||"claude-3-haiku-20240307",max_tokens:1024,messages:[{role:"user",content:t}]}),signal:s.signal});if(!i.ok)throw new Error(`Anthropic HTTP ${i.status}: ${await i.text()}`);return(await i.json()).content?.[0]?.text||null}if(this.config.provider==="ollama"){let r=this.config.endpoint||process.env.OLLAMA_BASE_URL||"http://localhost:11434",i=await fetch(`${r.replace(/\/$/,"")}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:this.config.model||"llama3.2",messages:[{role:"user",content:t}],stream:!1}),signal:s.signal});if(!i.ok)throw new Error(`Ollama HTTP ${i.status}: ${await i.text()}`);return(await i.json()).message?.content||null}return null}finally{clearTimeout(n)}}}});var Rn=oe(()=>{"use strict"});function Bs(p){let t=p?.provider||E.ai.provider;if(t==="heuristic")return new ut;if(t==="mock")return new yt;let e={provider:t,model:p?.model||E.ai.model,endpoint:p?.endpoint||E.ai.endpoint};return new zt(e)}var Hs=oe(()=>{"use strict";Kt();_s();Pe();Rn();Kt();_s()});import Ln from"fs";import Us from"path";var St,js=oe(()=>{"use strict";St=class{static extractDataDirective(t,e=process.cwd()){let s=t.split(`
713
- `),n="",r=-1;for(let c=0;c<s.length;c++){let u=s[c].trim();if(u.startsWith("#!data")||u.startsWith("#! data")){n=u,r=c;break}}if(r===-1)return null;let i=n.replace(/^#!\s*data\s*/,"").trim(),o=[],a="inline";if(i.startsWith("[")||i.startsWith("{"))try{let c=JSON.parse(i);o=Array.isArray(c)?c.map(u=>this.stringifyObject(u)):[this.stringifyObject(c)]}catch(c){throw new Error(`Failed to parse inline #!data JSON directive: ${c.message}`)}else{let c=i.replace(/^['"]+|['"]+$/g,"").trim(),u=Us.isAbsolute(c)?c:Us.resolve(e,c);a=u,o=this.loadFromFile(u)}let l=[...s];return l.splice(r,1),{directive:n,source:a,cleanedSpec:l.join(`
714
- `),rows:o}}static loadFromFile(t){if(!Ln.existsSync(t))throw new Error(`Data file not found: ${t}`);let e=Ln.readFileSync(t,"utf-8");return Us.extname(t).toLowerCase()===".json"?this.parseJson(e):this.parseCsv(e)}static parseJson(t){try{let e=JSON.parse(t);return Array.isArray(e)?e.map(s=>this.stringifyObject(s)):[this.stringifyObject(e)]}catch(e){throw new Error(`Invalid JSON data file format: ${e.message}`)}}static parseCsv(t){let e=this.splitCsvLines(t);if(e.length<2)return[];let s=this.parseCsvRow(e[0]).map(r=>r.trim().replace(/^['"]+|['"]+$/g,"")),n=[];for(let r=1;r<e.length;r++){if(!e[r].trim())continue;let o=this.parseCsvRow(e[r]),a={};for(let l=0;l<s.length;l++){let c=s[l];a[c]=o[l]!==void 0?o[l].trim():""}n.push(a)}return n}static filterRows(t,e){if(!e)return t;let s=[...t];if(e.onlyRow!==void 0&&e.onlyRow>0){let n=e.onlyRow-1;if(n<s.length)return[s[n]];throw new Error(`Requested --only-row=${e.onlyRow}, but dataset only contains ${s.length} row(s).`)}if(e.iterations!==void 0&&e.iterations>0){if(e.iterations<=s.length)return s.slice(0,e.iterations);let n=[];for(let r=0;r<e.iterations;r++)n.push(s[r%s.length]);return n}return s}static parseCsvRow(t){let e=[],s="",n=!1;for(let r=0;r<t.length;r++){let i=t[r];i==='"'?n&&t[r+1]==='"'?(s+='"',r++):n=!n:i===","&&!n?(e.push(s),s=""):s+=i}return e.push(s),e}static splitCsvLines(t){let e=[],s="",n=!1;for(let r=0;r<t.length;r++){let i=t[r];i==='"'?n&&t[r+1]==='"'?(s+='""',r++):(n=!n,s+=i):(i===`
715
- `||i==="\r")&&!n?(i==="\r"&&t[r+1]===`
716
- `&&r++,s.trim().length>0&&e.push(s),s=""):s+=i}return s.trim().length>0&&e.push(s),e}static stringifyObject(t){if(!t||typeof t!="object")return{};let e={};for(let[s,n]of Object.entries(t))e[s]=n!=null?String(n):"";return e}}});import gi from"http";import Ws from"fs";import Jt from"path";async function Nn(p={}){let t=p.port??4040,e=p.host||"127.0.0.1",s=p.outputDir?Jt.resolve(p.outputDir):Jt.resolve(process.cwd(),"output"),n=p.suiteName||"PromptTest Live Monitor",r=p.initialReport||{packageName:"PromptTest Execution",deviceId:"Live Device",startTime:new Date().toISOString(),endTime:new Date().toISOString(),durationSeconds:0,totalSteps:0,passedSteps:0,failedSteps:0,skippedSteps:0,warnSteps:0,errorsDetected:[],steps:[]},i=new Set,o=setInterval(()=>{for(let d of i)try{d.write(`: heartbeat
712
+ {"bestMatch": "Exact Text of Best Element", "confidence": 0.85, "reason": "Reason for match"}`,n=await this.callLlm(r);if(!n)return this.heuristicFallback.findSuggestions(t,e,s);let o=n.match(/\{[\s\S]*\}/);if(!o)return this.heuristicFallback.findSuggestions(t,e,s);let a=JSON.parse(o[0]);if(a.bestMatch){let d=e.find(c=>c.text===a.bestMatch||c.contentDesc===a.bestMatch);return[{text:a.bestMatch,score:typeof a.confidence=="number"?a.confidence:.85,node:d,strategy:"llm",reason:a.reason||"LLM semantic match"},...await this.heuristicFallback.findSuggestions(t,e,s)]}}catch(i){Be.warn(`LLM self-healing failed (${i.message}), using heuristic suggestions.`)}return this.heuristicFallback.findSuggestions(t,e,s)}async callLlm(t){let e=this.config.timeoutMs||8e3,s=new AbortController,i=setTimeout(()=>s.abort(),e);try{if(this.config.provider==="openai"){let r=this.config.apiKey||process.env.OPENAI_API_KEY;if(!r)throw new Error("OPENAI_API_KEY is not set");let n=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:this.config.model||"gpt-4o-mini",messages:[{role:"user",content:t}],temperature:.1}),signal:s.signal});if(!n.ok)throw new Error(`OpenAI HTTP ${n.status}: ${await n.text()}`);return(await n.json()).choices?.[0]?.message?.content||null}if(this.config.provider==="anthropic"){let r=this.config.apiKey||process.env.ANTHROPIC_API_KEY;if(!r)throw new Error("ANTHROPIC_API_KEY is not set");let n=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":r,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:this.config.model||"claude-3-haiku-20240307",max_tokens:1024,messages:[{role:"user",content:t}]}),signal:s.signal});if(!n.ok)throw new Error(`Anthropic HTTP ${n.status}: ${await n.text()}`);return(await n.json()).content?.[0]?.text||null}if(this.config.provider==="ollama"){let r=this.config.endpoint||process.env.OLLAMA_BASE_URL||"http://localhost:11434",n=await fetch(`${r.replace(/\/$/,"")}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:this.config.model||"llama3.2",messages:[{role:"user",content:t}],stream:!1}),signal:s.signal});if(!n.ok)throw new Error(`Ollama HTTP ${n.status}: ${await n.text()}`);return(await n.json()).message?.content||null}return null}finally{clearTimeout(i)}}}});var Ii=oe(()=>{"use strict"});function Bs(p){let t=p?.provider||P.ai.provider;if(t==="heuristic")return new ut;if(t==="mock")return new yt;let e={provider:t,model:p?.model||P.ai.model,endpoint:p?.endpoint||P.ai.endpoint};return new zt(e)}var Hs=oe(()=>{"use strict";Kt();_s();Pe();Ii();Kt();_s()});import Ri from"fs";import Us from"path";var St,js=oe(()=>{"use strict";St=class{static extractDataDirective(t,e=process.cwd()){let s=t.split(`
713
+ `),i="",r=-1;for(let c=0;c<s.length;c++){let l=s[c].trim();if(l.startsWith("#!data")||l.startsWith("#! data")){i=l,r=c;break}}if(r===-1)return null;let n=i.replace(/^#!\s*data\s*/,"").trim(),o=[],a="inline";if(n.startsWith("[")||n.startsWith("{"))try{let c=JSON.parse(n);o=Array.isArray(c)?c.map(l=>this.stringifyObject(l)):[this.stringifyObject(c)]}catch(c){throw new Error(`Failed to parse inline #!data JSON directive: ${c.message}`)}else{let c=n.replace(/^['"]+|['"]+$/g,"").trim(),l=Us.isAbsolute(c)?c:Us.resolve(e,c);a=l,o=this.loadFromFile(l)}let d=[...s];return d.splice(r,1),{directive:i,source:a,cleanedSpec:d.join(`
714
+ `),rows:o}}static loadFromFile(t){if(!Ri.existsSync(t))throw new Error(`Data file not found: ${t}`);let e=Ri.readFileSync(t,"utf-8");return Us.extname(t).toLowerCase()===".json"?this.parseJson(e):this.parseCsv(e)}static parseJson(t){try{let e=JSON.parse(t);return Array.isArray(e)?e.map(s=>this.stringifyObject(s)):[this.stringifyObject(e)]}catch(e){throw new Error(`Invalid JSON data file format: ${e.message}`)}}static parseCsv(t){let e=this.splitCsvLines(t);if(e.length<2)return[];let s=this.parseCsvRow(e[0]).map(r=>r.trim().replace(/^['"]+|['"]+$/g,"")),i=[];for(let r=1;r<e.length;r++){if(!e[r].trim())continue;let o=this.parseCsvRow(e[r]),a={};for(let d=0;d<s.length;d++){let c=s[d];a[c]=o[d]!==void 0?o[d].trim():""}i.push(a)}return i}static filterRows(t,e){if(!e)return t;let s=[...t];if(e.onlyRow!==void 0&&e.onlyRow>0){let i=e.onlyRow-1;if(i<s.length)return[s[i]];throw new Error(`Requested --only-row=${e.onlyRow}, but dataset only contains ${s.length} row(s).`)}if(e.iterations!==void 0&&e.iterations>0){if(e.iterations<=s.length)return s.slice(0,e.iterations);let i=[];for(let r=0;r<e.iterations;r++)i.push(s[r%s.length]);return i}return s}static parseCsvRow(t){let e=[],s="",i=!1;for(let r=0;r<t.length;r++){let n=t[r];n==='"'?i&&t[r+1]==='"'?(s+='"',r++):i=!i:n===","&&!i?(e.push(s),s=""):s+=n}return e.push(s),e}static splitCsvLines(t){let e=[],s="",i=!1;for(let r=0;r<t.length;r++){let n=t[r];n==='"'?i&&t[r+1]==='"'?(s+='""',r++):(i=!i,s+=n):(n===`
715
+ `||n==="\r")&&!i?(n==="\r"&&t[r+1]===`
716
+ `&&r++,s.trim().length>0&&e.push(s),s=""):s+=n}return s.trim().length>0&&e.push(s),e}static stringifyObject(t){if(!t||typeof t!="object")return{};let e={};for(let[s,i]of Object.entries(t))e[s]=i!=null?String(i):"";return e}}});import mn from"http";import Ws from"fs";import Jt from"path";async function Li(p={}){let t=p.port??4040,e=p.host||"127.0.0.1",s=p.outputDir?Jt.resolve(p.outputDir):Jt.resolve(process.cwd(),"output"),i=p.suiteName||"PromptTest Live Monitor",r=p.initialReport||{packageName:"PromptTest Execution",deviceId:"Live Device",startTime:new Date().toISOString(),endTime:new Date().toISOString(),durationSeconds:0,totalSteps:0,passedSteps:0,failedSteps:0,skippedSteps:0,warnSteps:0,errorsDetected:[],steps:[]},n=new Set,o=setInterval(()=>{for(let u of n)try{u.write(`: heartbeat
717
717
 
718
- `)}catch{i.delete(d)}},15e3),a=gi.createServer((d,g)=>{let m=new URL(d.url||"/",`http://${e}:${t}`),y=decodeURIComponent(m.pathname);if(y==="/events"){g.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),g.write(`event: connected
718
+ `)}catch{n.delete(u)}},15e3),a=mn.createServer((u,g)=>{let m=new URL(u.url||"/",`http://${e}:${t}`),y=decodeURIComponent(m.pathname);if(y==="/events"){g.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),g.write(`event: connected
719
719
  data: ${JSON.stringify({status:"connected",time:Date.now()})}
720
720
 
721
- `),i.add(g),d.on("close",()=>{i.delete(g)});return}if(y==="/"||y==="/report"||y==="/index.html"){let f=as(r,{suiteName:n});g.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-cache"}),g.end(f);return}if(y==="/api/report"||y==="/results.json"){g.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),g.end(JSON.stringify(r,null,2));return}let S=y.replace(/^\/+/,""),b=Jt.join(s,S);if(!b.startsWith(s)){g.writeHead(403,{"Content-Type":"text/plain"}),g.end("Access Denied");return}if(Ws.existsSync(b)&&Ws.statSync(b).isFile()){let f=Jt.extname(b).toLowerCase(),T=mi[f]||"application/octet-stream";g.writeHead(200,{"Content-Type":T,"Cache-Control":"no-cache"}),Ws.createReadStream(b).pipe(g);return}g.writeHead(404,{"Content-Type":"text/plain"}),g.end("Not Found")});await new Promise((d,g)=>{a.once("error",g),a.listen(t,e,()=>{d()})});let l=a.address(),c=typeof l=="object"&&l?l.port:t,u=`http://${e}:${c}`;function h(d,g){let m=`event: ${d}
721
+ `),n.add(g),u.on("close",()=>{n.delete(g)});return}if(y==="/"||y==="/report"||y==="/index.html"){let f=as(r,{suiteName:i});g.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-cache"}),g.end(f);return}if(y==="/api/report"||y==="/results.json"){g.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}),g.end(JSON.stringify(r,null,2));return}let S=y.replace(/^\/+/,""),b=Jt.join(s,S);if(!b.startsWith(s)){g.writeHead(403,{"Content-Type":"text/plain"}),g.end("Access Denied");return}if(Ws.existsSync(b)&&Ws.statSync(b).isFile()){let f=Jt.extname(b).toLowerCase(),x=fn[f]||"application/octet-stream";g.writeHead(200,{"Content-Type":x,"Cache-Control":"no-cache"}),Ws.createReadStream(b).pipe(g);return}g.writeHead(404,{"Content-Type":"text/plain"}),g.end("Not Found")});await new Promise((u,g)=>{a.once("error",g),a.listen(t,e,()=>{u()})});let d=a.address(),c=typeof d=="object"&&d?d.port:t,l=`http://${e}:${c}`;function h(u,g){let m=`event: ${u}
722
722
  data: ${JSON.stringify(g)}
723
723
 
724
- `;for(let y of i)try{y.write(m)}catch{i.delete(y)}}return{server:a,port:c,url:u,broadcastStep(d){r.steps.push(d),r.totalSteps=r.steps.length,d.status==="PASS"?r.passedSteps++:d.status==="FAIL"?r.failedSteps++:d.status==="WARN"?r.warnSteps++:d.status==="SKIPPED"&&r.skippedSteps++,h("step",d)},broadcastComplete(d){r=d,h("complete",d)},broadcastError(d){r.errorsDetected.push(d),h("error",{error:d})},updateReport(d){r=d},async close(){clearInterval(o);for(let d of i)try{d.end()}catch{}i.clear(),await new Promise((d,g)=>{a.close(m=>{m?g(m):d()})})}}}var mi,Ys=oe(()=>{"use strict";Je();mi={".html":"text/html; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".svg":"image/svg+xml",".mp4":"video/mp4",".log":"text/plain; charset=utf-8",".txt":"text/plain; charset=utf-8",".xml":"application/xml; charset=utf-8"}});import He from"fs";import xe from"path";import B from"chalk";var Ze,Mt,Ft=oe(()=>{"use strict";Ae();je();Je();Qe();Pe();It();ft();$n();Xt();Os();Hs();js();Ys();rt();Oe();Ze=class{driver;memory;reporter;checkpoints;baselines;lastHierarchy=null;screenDimensions={width:E.screen.fallbackWidth,height:E.screen.fallbackHeight};navBarHeight=0;constructor(t,e,s,n,r,i){this.driver=t||Q,this.memory=e||ve,this.reporter=s||bt,this.checkpoints=n||Dn,this.baselines=r||us,this.semanticResolver=i||Bs()}semanticResolver;healEnabled=!1;activeLocale="en";runtimeVariables=new Map;loopStack=[];expandSpecIncludes(t,e=new Set){return os(t,e)}async expandSpec(t,e){let s=e||this.semanticResolver,n=t.split(`
725
- `),r=[],i=0;for(let o of n){let a=o.trim();if(!a||a.startsWith("#")||a.startsWith("//")){r.push(o);continue}let l=this.parsePrompt(a);if(l.length>0&&l[0].type!==void 0&&!a.toLowerCase().startsWith("intent:")){r.push(o);continue}let u=a.replace(/^intent:\s*/i,""),h=this.memory?.getIntentExpansion(u);if(h?.length){r.push(`# [Cached Intent] ${a}`,...h),i+=h.length;continue}let d=await s.resolveIntent(u);if(d?.length){r.push(`# [AI Expanded] ${a}`);let g=d.map(m=>m.originalText);r.push(...g),this.memory&&(this.memory.recordIntentExpansion(u,g),await this.memory.save().catch(()=>{})),i+=d.length}else r.push(o)}return{expanded:r.join(`
726
- `),stepsAdded:i}}parsePrompt(t,e){return Ut(t,e)}async runSpec(t,e,s){if(!He.existsSync(t))throw new Error(`Spec file not found: ${t}`);let n=typeof e=="string"?{packageName:e,serial:s,screenshotMode:"on-failure",continueOnError:!1}:{screenshotMode:"on-failure",continueOnError:!1,...e};n.heal!==void 0&&(this.healEnabled=n.heal),n.noAi&&(this.semanticResolver=Bs({provider:"heuristic"})),this.activeLocale=(n.locale||E.locale||"en").toLowerCase(),typeof this.memory.setLocale=="function"&&this.memory.setLocale(this.activeLocale);let r=this.expandSpecIncludes(t),i=r,o=[],a=St.extractDataDirective(r,xe.dirname(t));if(a)i=a.cleanedSpec,o=a.rows;else if(n.dataFile){let b=xe.isAbsolute(n.dataFile)?n.dataFile:xe.resolve(process.cwd(),n.dataFile);o=St.loadFromFile(b)}(n.onlyRow!==void 0||n.iterations!==void 0)&&(o.length>0?o=St.filterRows(o,{onlyRow:n.onlyRow,iterations:n.iterations}):n.iterations&&n.iterations>0&&(o=Array.from({length:n.iterations},()=>({}))));let l=o.length>0?o.map(b=>({...n.variables||{},...b})):[n.variables||{}],c=xe.basename(t,xe.extname(t)),u=i.match(/#\s*(?:Target\s*)?Package:\s*([a-zA-Z0-9._-]+)/i),h=u?u[1]:void 0;if(n.tags){let b=vn(r),f=n.tags.split(",").map(P=>P.trim().toLowerCase()).filter(Boolean);if(!f.some(P=>b.includes(P)))return console.log(B.yellow(`
727
- \u23E9 Skipping ${t}: tags [${b.join(", ")}] do not match filter [${f.join(", ")}]`)),Wt(h||n.packageName||"",n.serial||"",[],"SKIPPED")}if(n.listSteps){let b=this.parsePrompt(i,l[0]);return console.log(wn(b)),Wt(h||n.packageName||"",n.serial||"",b,"SKIPPED","Listing")}if(n.dryRun){let b=this.parsePrompt(i,l[0]);return console.log(B.bold.cyan(`
728
- \u{1F50D} [Dry Run] Validated ${b.length} test step(s) in ${t} successfully (no device interaction).`)),Wt(h||n.packageName||"",n.serial||"",b,"PASS","Validation")}if(l.length>1)console.log(B.cyan(`
729
- \u{1F4CB} Loaded spec with ${l.length} data iteration(s) from ${t}`));else{let b=this.parsePrompt(i,l[0]);console.log(B.cyan(`
730
- \u{1F4CB} Loaded ${b.length} test step(s) from ${t}`))}console.log(B.gray("Execution Policy: ")+B.bold.white(n.continueOnError?"Continue on Error (Modular Run)":"Fail-Fast (Default)")+B.gray(" | Screenshots: ")+B.bold.white(n.screenshotMode==="all"?"All Steps":"Failure-Only")),n.serial=await this.driver.ensureDefaultDevice(n.serial);let d=n.serial||this.driver.getDefaultDevice()||"Default Device",g=null;n.serial&&(g=ct(n.serial)),n.embedScreenshots&&typeof this.reporter.setEmbedScreenshots=="function"&&this.reporter.setEmbedScreenshots(!0);let m,y;if(n.serve){let b=typeof n.serve=="number"?n.serve:4040;try{m=await Nn({port:b,suiteName:c}),console.log(B.bold.magenta(`
724
+ `;for(let y of n)try{y.write(m)}catch{n.delete(y)}}return{server:a,port:c,url:l,broadcastStep(u){r.steps.push(u),r.totalSteps=r.steps.length,u.status==="PASS"?r.passedSteps++:u.status==="FAIL"?r.failedSteps++:u.status==="WARN"?r.warnSteps++:u.status==="SKIPPED"&&r.skippedSteps++,h("step",u)},broadcastComplete(u){r=u,h("complete",u)},broadcastError(u){r.errorsDetected.push(u),h("error",{error:u})},updateReport(u){r=u},async close(){clearInterval(o);for(let u of n)try{u.end()}catch{}n.clear(),await new Promise((u,g)=>{a.close(m=>{m?g(m):u()})})}}}var fn,Ys=oe(()=>{"use strict";Je();fn={".html":"text/html; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".svg":"image/svg+xml",".mp4":"video/mp4",".log":"text/plain; charset=utf-8",".txt":"text/plain; charset=utf-8",".xml":"application/xml; charset=utf-8"}});import He from"fs";import xe from"path";import B from"chalk";var Ze,Mt,Ft=oe(()=>{"use strict";Ae();je();Je();Qe();Pe();It();ft();Di();Xt();Os();Hs();js();Ys();rt();Oe();Ze=class{driver;memory;reporter;checkpoints;baselines;lastHierarchy=null;screenDimensions={width:P.screen.fallbackWidth,height:P.screen.fallbackHeight};navBarHeight=0;constructor(t,e,s,i,r,n){this.driver=t||Q,this.memory=e||ve,this.reporter=s||bt,this.checkpoints=i||ki,this.baselines=r||us,this.semanticResolver=n||Bs()}semanticResolver;healEnabled=!1;activeLocale="en";runtimeVariables=new Map;loopStack=[];expandSpecIncludes(t,e=new Set){return os(t,e)}async expandSpec(t,e){let s=e||this.semanticResolver,i=t.split(`
725
+ `),r=[],n=0;for(let o of i){let a=o.trim();if(!a||a.startsWith("#")||a.startsWith("//")){r.push(o);continue}let d=this.parsePrompt(a);if(d.length>0&&d[0].type!==void 0&&!a.toLowerCase().startsWith("intent:")){r.push(o);continue}let l=a.replace(/^intent:\s*/i,""),h=this.memory?.getIntentExpansion(l);if(h?.length){r.push(`# [Cached Intent] ${a}`,...h),n+=h.length;continue}let u=await s.resolveIntent(l);if(u?.length){r.push(`# [AI Expanded] ${a}`);let g=u.map(m=>m.originalText);r.push(...g),this.memory&&(this.memory.recordIntentExpansion(l,g),await this.memory.save().catch(()=>{})),n+=u.length}else r.push(o)}return{expanded:r.join(`
726
+ `),stepsAdded:n}}parsePrompt(t,e){return Ut(t,e)}async runSpec(t,e,s){if(!He.existsSync(t))throw new Error(`Spec file not found: ${t}`);let i=typeof e=="string"?{packageName:e,serial:s,screenshotMode:"on-failure",continueOnError:!1}:{screenshotMode:"on-failure",continueOnError:!1,...e};i.heal!==void 0&&(this.healEnabled=i.heal),i.noAi&&(this.semanticResolver=Bs({provider:"heuristic"})),this.activeLocale=(i.locale||P.locale||"en").toLowerCase(),typeof this.memory.setLocale=="function"&&this.memory.setLocale(this.activeLocale);let r=this.expandSpecIncludes(t),n=r,o=[],a=St.extractDataDirective(r,xe.dirname(t));if(a)n=a.cleanedSpec,o=a.rows;else if(i.dataFile){let b=xe.isAbsolute(i.dataFile)?i.dataFile:xe.resolve(process.cwd(),i.dataFile);o=St.loadFromFile(b)}(i.onlyRow!==void 0||i.iterations!==void 0)&&(o.length>0?o=St.filterRows(o,{onlyRow:i.onlyRow,iterations:i.iterations}):i.iterations&&i.iterations>0&&(o=Array.from({length:i.iterations},()=>({}))));let d=o.length>0?o.map(b=>({...i.variables||{},...b})):[i.variables||{}],c=xe.basename(t,xe.extname(t)),l=n.match(/#\s*(?:Target\s*)?Package:\s*([a-zA-Z0-9._-]+)/i),h=l?l[1]:void 0;if(i.tags){let b=Si(r),f=i.tags.split(",").map(T=>T.trim().toLowerCase()).filter(Boolean);if(!f.some(T=>b.includes(T)))return console.log(B.yellow(`
727
+ \u23E9 Skipping ${t}: tags [${b.join(", ")}] do not match filter [${f.join(", ")}]`)),Wt(h||i.packageName||"",i.serial||"",[],"SKIPPED")}if(i.listSteps){let b=this.parsePrompt(n,d[0]);return console.log(vi(b)),Wt(h||i.packageName||"",i.serial||"",b,"SKIPPED","Listing")}if(i.dryRun){let b=this.parsePrompt(n,d[0]);return console.log(B.bold.cyan(`
728
+ \u{1F50D} [Dry Run] Validated ${b.length} test step(s) in ${t} successfully (no device interaction).`)),Wt(h||i.packageName||"",i.serial||"",b,"PASS","Validation")}if(d.length>1)console.log(B.cyan(`
729
+ \u{1F4CB} Loaded spec with ${d.length} data iteration(s) from ${t}`));else{let b=this.parsePrompt(n,d[0]);console.log(B.cyan(`
730
+ \u{1F4CB} Loaded ${b.length} test step(s) from ${t}`))}console.log(B.gray("Execution Policy: ")+B.bold.white(i.continueOnError?"Continue on Error (Modular Run)":"Fail-Fast (Default)")+B.gray(" | Screenshots: ")+B.bold.white(i.screenshotMode==="all"?"All Steps":"Failure-Only")),i.serial=await this.driver.ensureDefaultDevice(i.serial);let u=i.serial||this.driver.getDefaultDevice()||"Default Device",g=null;i.serial&&(g=ct(i.serial)),i.embedScreenshots&&typeof this.reporter.setEmbedScreenshots=="function"&&this.reporter.setEmbedScreenshots(!0);let m,y;if(i.serve){let b=typeof i.serve=="number"?i.serve:4040;try{m=await Li({port:b,suiteName:c}),console.log(B.bold.magenta(`
731
731
  \u{1F4E1} Live Monitor streaming at: ${m.url}
732
- `)),typeof this.reporter.onStep=="function"&&(y=this.reporter.onStep(f=>{m?.broadcastStep(f)}))}catch(f){let T=f;console.warn(B.yellow(`Warning: Could not start live server: ${T.message}`))}}let S=null;n.video&&(console.log(B.cyan("\u{1F3AC} Starting ADB screen recording (--video enabled)...")),S=await this.driver.startScreenRecording("/sdcard/prompttest_temp.mp4",n.serial));try{this.screenDimensions=await this.driver.getScreenDimensions(n.serial),this.navBarHeight=typeof this.driver.getNavigationBarHeight=="function"?await this.driver.getNavigationBarHeight(n.serial):0,console.log(B.gray("Target Screen Geometry: ")+B.bold.cyan(`${this.screenDimensions.width}x${this.screenDimensions.height}`)+(this.navBarHeight>0?B.gray(` (Nav Bar: ${this.navBarHeight}px)`):"")),n.apkPath&&(He.existsSync(n.apkPath)?(console.log(B.cyan(`\u{1F4E6} Installing APK: ${n.apkPath}...`)),await this.driver.installApk(n.apkPath,n.serial),await new Promise(j=>setTimeout(j,2e3))):console.log(B.yellow(`Warning: Specified APK file not found at: ${n.apkPath}`)));let b=n.packageName||h||(typeof this.driver.getForegroundPackage=="function"?await this.driver.getForegroundPackage(n.serial):null)||"Foreground App";if(b&&!b.includes("Launcher")&&!b.includes("Foreground")){if(!(typeof this.driver.isAppInstalled=="function"?await this.driver.isAppInstalled(b,n.serial):!0))if(n.apkPath&&He.existsSync(n.apkPath))console.log(B.cyan(`\u{1F4E6} Target app not found. Auto-installing APK: ${n.apkPath}...`)),await this.driver.installApk(n.apkPath,n.serial),await new Promise(H=>setTimeout(H,2500));else throw new Error(`Target application "${b}" is not installed on device (${d}).
732
+ `)),typeof this.reporter.onStep=="function"&&(y=this.reporter.onStep(f=>{m?.broadcastStep(f)}))}catch(f){let x=f;console.warn(B.yellow(`Warning: Could not start live server: ${x.message}`))}}let S=null;i.video&&(console.log(B.cyan("\u{1F3AC} Starting ADB screen recording (--video enabled)...")),S=await this.driver.startScreenRecording("/sdcard/prompttest_temp.mp4",i.serial));try{this.screenDimensions=await this.driver.getScreenDimensions(i.serial),this.navBarHeight=typeof this.driver.getNavigationBarHeight=="function"?await this.driver.getNavigationBarHeight(i.serial):0,console.log(B.gray("Target Screen Geometry: ")+B.bold.cyan(`${this.screenDimensions.width}x${this.screenDimensions.height}`)+(this.navBarHeight>0?B.gray(` (Nav Bar: ${this.navBarHeight}px)`):"")),i.apkPath&&(He.existsSync(i.apkPath)?(console.log(B.cyan(`\u{1F4E6} Installing APK: ${i.apkPath}...`)),await this.driver.installApk(i.apkPath,i.serial),await new Promise(U=>setTimeout(U,2e3))):console.log(B.yellow(`Warning: Specified APK file not found at: ${i.apkPath}`)));let b=i.packageName||h||(typeof this.driver.getForegroundPackage=="function"?await this.driver.getForegroundPackage(i.serial):null)||"Foreground App";if(b&&!b.includes("Launcher")&&!b.includes("Foreground")){if(!(typeof this.driver.isAppInstalled=="function"?await this.driver.isAppInstalled(b,i.serial):!0))if(i.apkPath&&He.existsSync(i.apkPath))console.log(B.cyan(`\u{1F4E6} Target app not found. Auto-installing APK: ${i.apkPath}...`)),await this.driver.installApk(i.apkPath,i.serial),await new Promise(H=>setTimeout(H,2500));else throw new Error(`Target application "${b}" is not installed on device (${u}).
733
733
  \u{1F4A1} Suggestions:
734
734
  \u2022 Install the app manually or via: adb install <path-to-apk>
735
- \u2022 Or provide an APK path to auto-install before running: --apk=path/to/app.apk`);let G=await this.driver.getForegroundPackage(n.serial);(n.fresh||G&&G!==b)&&(console.log(B.cyan(`\u{1F680} Launching target application: ${B.bold(b)}...`)),n.fresh&&(await this.driver.forceStop(b,n.serial),await new Promise(H=>setTimeout(H,600))),await this.driver.launchApp(b,n.serial),await new Promise(H=>setTimeout(H,2500)))}n.reporter&&(this.reporter=n.reporter),n.reporters&&typeof this.reporter.setFormats=="function"&&this.reporter.setFormats(n.reporters),this.reporter.init(b,d),await this.memory.init(b),this.lastHierarchy=null;let f=Date.now(),T=0;for(let j=0;j<l.length;j++){let G=l[j],H=l.length>1,be=n.onlyRow?`Row ${n.onlyRow}`:H?`Row ${j+1}`:void 0,J=be?`${c} [${be}]`:c;H&&(console.log(B.bold.magenta(`
735
+ \u2022 Or provide an APK path to auto-install before running: --apk=path/to/app.apk`);let G=await this.driver.getForegroundPackage(i.serial);(i.fresh||G&&G!==b)&&(console.log(B.cyan(`\u{1F680} Launching target application: ${B.bold(b)}...`)),i.fresh&&(await this.driver.forceStop(b,i.serial),await new Promise(H=>setTimeout(H,600))),await this.driver.launchApp(b,i.serial),await new Promise(H=>setTimeout(H,2500)))}i.reporter&&(this.reporter=i.reporter),i.reporters&&typeof this.reporter.setFormats=="function"&&this.reporter.setFormats(i.reporters),this.reporter.init(b,u),await this.memory.init(b),this.lastHierarchy=null;let f=Date.now(),x=0;for(let U=0;U<d.length;U++){let G=d[U],H=d.length>1,be=i.onlyRow?`Row ${i.onlyRow}`:H?`Row ${U+1}`:void 0,J=be?`${c} [${be}]`:c;H&&(console.log(B.bold.magenta(`
736
736
  ======================================================
737
- \u{1F504} [Data-Driven Iteration ${j+1}/${l.length}] Row Data: ${JSON.stringify(G)}
738
- ======================================================`)),n.fresh&&j>0&&b&&(await this.driver.clearAppData(b,n.serial),await new Promise(X=>setTimeout(X,1e3)))),this.runtimeVariables.clear();for(let[X,O]of Object.entries(G))this.runtimeVariables.set(X,O);this.loopStack=[];let re=this.parsePrompt(i,G),_=1,me=n.resume&&j===0?await this.checkpoints.getResumeIndex(c):0;me>0&&console.log(B.cyan(`\u23ED Resuming from step ${me+1} (checkpoint found).`));let se=n.only?Sn(n.only):null;for(let X=0;X<re.length;X++){let O=re[X];if(_=X+1,se&&!se.has(_)){console.log(B.gray(`[Step ${_}/${re.length}] \u23E9 Skipped (not in --only range: ${n.only})`)),this.reporter.logStep(J,O.originalText,O.type,"SKIPPED",`Filtered out by --only="${n.only}"`,void 0,void 0,0);continue}if(X<me){this.reporter.logStep(J,O.originalText,O.type,"SKIPPED","Resumed \u2014 already passed",void 0,void 0,0);continue}let Y=re.slice(X+1);console.log(B.bold.blue(`
739
- [Step ${_}/${re.length}] ${O.originalText}`));let A=Date.now();try{let M=await this.executeStep(O,n.serial,Y),R=Date.now()-A;if(M&&M.fastForwarded){if(console.log(B.cyan(`\u23E9 Fast-Forward: ${M.reason}. Redundant step(s) bypassed.`)),this.reporter.logStep(J,O.originalText,O.type,"PASS",`Fast-Forward: ${M.reason}`,void 0,void 0,R),console.log(B.green(`\u2714 Step ${_} PASSED (Fast-Forward)`)),M?.skipCount&&M.skipCount>0){let F=M.skipCount;for(let V=0;V<F&&X+1<re.length;V++){X++;let x=re[X],w=X+1;this.reporter.logStep(J,x.originalText,x.type,"PASS",`Fast-Forward: ${M.reason}`,void 0,void 0,0),console.log(B.gray(` [Step ${w}/${re.length}] \u23E9 Fast-Forward: ${x.originalText}`))}}}else{let F;if((n.screenshotMode==="all"||n.saveBaseline||n.compareBaseline)&&(F=await this.driver.captureScreenshot(n.serial)),F&&n.compareBaseline){let V=await this.baselines.compare(J,_,F,n.baselineThreshold);V.passed||(console.log(B.yellow(` \u26A0\uFE0F [Baseline] Step ${_} visual diff ${(V.diffRatio*100).toFixed(1)}% exceeds threshold ${(V.threshold*100).toFixed(1)}%`)),this.reporter.logError(`Visual baseline diff at Step ${_}: ${(V.diffRatio*100).toFixed(1)}% changed`))}F&&n.saveBaseline&&await this.baselines.saveBaseline(J,_,F),this.reporter.logStep(J,O.originalText,O.type,"PASS",O.target||O.value,n.screenshotMode==="all"?F:void 0,void 0,R),console.log(B.green(`\u2714 Step ${_} PASSED`)),n.benchmark&&console.log(B.gray(` \u23F1 [Benchmark] Step ${_} latency: ${R}ms (${O.type}${O.target?` -> "${O.target}"`:""})`))}n.resume&&!H&&await this.checkpoints.save(c,b,X,re.length)}catch(M){let R=M,F=Date.now()-A;if(O.optional){console.log(B.yellow(`\u26AA Step ${_} OPTIONAL (Skipped: ${R.message})`)),this.reporter.logStep(J,O.originalText,O.type,"SKIPPED",`Optional step bypassed: ${R.message}`,void 0,void 0,F);continue}T++,console.log(B.red(`\u274C Step ${_} FAILED: ${R.message}`)),O.target&&this.memory.recordFailure(O.type,O.target);let V=await this.driver.captureScreenshot(n.serial).catch(()=>{}),x;try{let w=xe.resolve(process.cwd(),"output"),N=`${c}_step_${_}`,L=xe.join(w,"failures",N);He.existsSync(L)||He.mkdirSync(L,{recursive:!0}),V&&await He.promises.writeFile(xe.join(L,"screenshot.png"),V);let le=this.lastHierarchy?.xml||await this.driver.getUiHierarchy(n.serial).catch(()=>"");le&&await He.promises.writeFile(xe.join(L,"hierarchy.xml"),le,"utf-8");let U=await this.driver.getLogcatTail(150,n.serial);await He.promises.writeFile(xe.join(L,"logcat_tail.log"),U,"utf-8");let Se=this.lastHierarchy?.flat||[],Ne=O.target&&Se.length>0?nt(O.target,Se.map(ie=>ie.text||ie.contentDesc||"").filter(Boolean)):[];await He.promises.writeFile(xe.join(L,"match_scores.json"),JSON.stringify(Ne,null,2),"utf-8"),x=xe.join("failures",N).replace(/\\/g,"/"),console.log(B.red(` \u{1F4C1} Failure Triage Bundle generated at: output/${x}`))}catch{}if(this.reporter.logStep(J,O.originalText,O.type,"FAIL",R.message,V,void 0,F,x),this.reporter.logError(`Step ${_} failed: ${R.message}`),n.continueOnError)console.log(B.yellow("Continuing with next test step (--continue enabled)..."));else{let w=re.slice(X+1);if(w.length>0){console.log(B.yellow(`
740
- \u{1F6D1} Aborting dependent flow due to upstream failure at Step ${_}.`)),console.log(B.gray(`Cascading skip applied to ${w.length} downstream step(s):`));for(let N=0;N<w.length;N++){let L=w[N],le=_+1+N;this.reporter.logStep(J,L.originalText,L.type,"SKIPPED",`Cascading skip: Precondition failed at Step ${_} (${O.originalText})`,void 0,void 0,0),console.log(B.gray(` [Step ${le}/${re.length}] \u26AA SKIPPED: ${L.originalText}`))}}break}}}}try{let j=this.lastHierarchy;if(j?.flat){let G=hn(j.flat,this.screenDimensions.width,this.screenDimensions.height);if(G.length>0){console.log(B.bold.yellow(`
741
- \u{1F50D} Visual QA Sentinel Warnings (${G.length} detected):`));for(let H of G)console.log(B.yellow(` \u2022 [${H.type}] ${H.description}`)),this.reporter.logError(`Visual Defect (${H.type}): ${H.description}`)}}}catch{}await this.memory.save(),n.resume&&T===0&&await this.checkpoints.clear(c);let P=this.memory.getStats();if(P.totalMappings>0&&console.log(B.cyan(`\u{1F9E0} Knowledge Engine: ${P.totalMappings} active learned mapping(s) for ${P.package}`)),S){console.log(B.cyan("\u{1F3AC} Finalizing video recording..."));let j=xe.resolve(process.cwd(),"output"),G=xe.join(j,`${c}-recording.mp4`),H=await this.driver.stopScreenRecording(S,G,n.serial);H&&He.existsSync(H)&&(this.reporter.setVideoPath?.(`${c}-recording.mp4`),console.log(B.green(`\u2714 Screen recording saved to: output/${c}-recording.mp4`))),S=null}let I=((Date.now()-f)/1e3).toFixed(1),v=await this.reporter.generateReport(c);m&&(m.broadcastComplete(v),y&&y()),console.log(B.bold.green(`
742
- \u2728 PromptTest Script Execution Finished in ${I}s!`));let $=v.failedSteps===0?B.bold.green:B.bold.yellow;return console.log($(`Result: ${v.passedSteps}/${v.totalSteps} passed (${v.failedSteps} failed, ${v.skippedSteps} skipped).`)),console.log(B.cyan(`Report saved to output/${c}-report.html
743
- `)),n.json&&console.log(JSON.stringify(v,null,2)),v}finally{if(S)try{await this.driver.stopScreenRecording(S,xe.join("output",`${c}-recording.mp4`),n.serial)}catch{}g&&lt(g)}}async getCleanHierarchy(t){let e=await this.driver.getUiHierarchy(t),{flat:s}=pe(e),n=s.find(o=>(o.text==="Dismiss"||o.contentDesc==="Dismiss")&&o.bounds.width>0);n&&(await this.driver.tap(n.bounds.centerX,n.bounds.centerY,t),await new Promise(o=>setTimeout(o,400)),e=await this.driver.getUiHierarchy(t),s=pe(e).flat);let r=s.find(o=>o.contentDesc&&(o.contentDesc.startsWith("!, ")||o.contentDesc.includes("react.dev/link")));if(r){let o=r.bounds.x2-45,a=r.bounds.centerY;await this.driver.tap(o,a,t),await new Promise(l=>setTimeout(l,350)),e=await this.driver.getUiHierarchy(t),s=pe(e).flat}let i=ge(s);return this.lastHierarchy={xml:e,flat:s,timestamp:Date.now(),hash:i},{xml:e,flat:s}}async ensureInViewport(t,e){let s=this.screenDimensions.width,n=this.screenDimensions.height,r=Math.round(s*.5),i=this.navBarHeight>0?n-this.navBarHeight:n,o=this.navBarHeight>0?i*.94:n*E.gestures.bottomNavThresholdRatio;if(t.bounds.centerY>o||t.bounds.y1>o)return!1;let l=t.bounds.y2>i,c=t.bounds.y1<Math.round(n*.04)&&t.bounds.centerY<Math.round(n*.06);return l?(await this.driver.swipe(r,Math.round(n*.75),r,Math.round(n*.45),250,e),await new Promise(u=>setTimeout(u,200)),this.lastHierarchy=null,!0):c?(await this.driver.swipe(r,Math.round(n*.35),r,Math.round(n*.65),250,e),await new Promise(u=>setTimeout(u,200)),this.lastHierarchy=null,!0):!1}async waitForTarget(t,e,s=3e3,n){if(this.lastHierarchy&&Date.now()-this.lastHierarchy.timestamp<E.polling.hierarchyCacheTtlMs){let a=this.matchNodes(this.lastHierarchy.flat,t,n);if(a.length>0)return{flat:this.lastHierarchy.flat,matched:a}}let r=Date.now();for(;Date.now()-r<s;){let{flat:a}=await this.getCleanHierarchy(e),l=this.matchNodes(a,t,n);if(l.length>0)return{flat:a,matched:l};await new Promise(c=>setTimeout(c,sn()))}let{flat:i}=await this.getCleanHierarchy(e),o=this.matchNodes(i,t,n);if(o.length===0&&(this.healEnabled||E.ai.selfHealing))try{let a=await this.semanticResolver.findSuggestions(t,i,{locale:this.activeLocale}),l=E.ai.confidenceThreshold||.75,c=a.find(u=>u.score>=l);if(c){let u=c.node||i.find(h=>(ne(c.text,h.text)||ne(c.text,h.contentDesc))&&h.bounds.width>0);if(u){console.log(B.yellow(` \u{1F4A1} [Self-Healing] Auto-healed "${t}" \u2192 "${c.text}" (${Math.round(c.score*100)}% confidence, ${c.strategy})`)),n&&(n.healedFrom=t);let h=u.text?"text":u.contentDesc?"contentDesc":"resourceId",d=this.lastHierarchy?.hash,g=Math.min(E.memory?.maxHealedConfidence??.65,c.score);this.memory.recordSuccess(n?.type||"TAP",t,c.text,h,g,t,d),o=[u]}}}catch(a){Be.warn(`Self-healing resolution failed: ${a.message}`)}return{flat:i,matched:o}}buildDiagnosticError(t,e,s){return bn(t,e,s)}async executeStep(t,e,s){let n=In.get(t.type);if(!n)throw new Error(`No handler registered for step type: ${t.type}`);t.target&&t.target.includes("$")&&(t.target=st(t.target,Object.fromEntries(this.runtimeVariables))),t.value&&t.value.includes("$")&&(t.value=st(t.value,Object.fromEntries(this.runtimeVariables)));let r={driver:this.driver,memory:this.memory,serial:e,screenDimensions:this.screenDimensions,navBarHeight:this.navBarHeight,lastHierarchy:this.lastHierarchy,setLastHierarchy:i=>{this.lastHierarchy=i},getCleanHierarchy:i=>this.getCleanHierarchy(i),waitForTarget:(i,o,a,l)=>this.waitForTarget(i,o,a,l),matchNodes:(i,o,a)=>this.matchNodes(i,o,a),ensureInViewport:(i,o)=>this.ensureInViewport(i,o),buildDiagnosticError:(i,o,a)=>this.buildDiagnosticError(i,o,a),findTargetInputField:(i,o,a)=>this.findTargetInputField(i,o,a),upcomingSteps:s,variables:this.runtimeVariables,loopStack:this.loopStack,executeChildSteps:async(i,o)=>{for(let a=0;a<i.length;a++){let l=i[a];await this.executeStep(l,o.serial,i.slice(a+1))}}};return n.execute(t,r)}findTargetInputField(t,e,s){return yn(t,e,s,this.memory)}matchNodes(t,e,s){return jt(t,e,this.memory,this.activeLocale,s,this.lastHierarchy?.hash)}},Mt=new Ze});var Mn={};xt(Mn,{AutonomousRecorder:()=>vt,autonomousRecorder:()=>vi});import he from"fs";import de from"path";import C from"chalk";import{spawn as fi}from"child_process";import bi from"readline";import{createRequire as yi}from"module";var Si,Vs,vt,vi,Qt=oe(()=>{"use strict";Ae();It();je();Pe();Si=yi(import.meta.url),Vs="1.1.0";try{Vs=Si("../../package.json").version||"1.1.0"}catch{}vt=class{driver;deviceLock=null;isRecording=!1;recordedSteps=[];existingSteps=[];existingFileHeader=[];lastHierarchyFlat=[];lastScreenTitle="";visitedScreens=[];targetPackage=null;isAppendMode=!1;resolvedOutputPath="";activeInput=null;geteventProcess=null;isRefreshingHierarchy=!1;targetSerial="";touchMaxX=E.screen.fallbackWidth;touchMaxY=E.screen.fallbackHeight;displayWidth=E.screen.fallbackWidth;displayHeight=E.screen.fallbackHeight;lastTapTimestamp=0;lastRecordedTapTarget="";inFlightTapQueue=[];lastScrollTimestamp=0;lastScrollDirection="";inputDebounceTimer=null;logcatEventProcess=null;logcatCrashProcess=null;hierarchyStale=!0;hierarchyCacheTime=0;currentScreenName="";sessionScreenSections=[];sessionStartTime=0;screenshotDir="";screenshotCounter=0;crashDetected=!1;lastScreenTransitionTime=0;constructor(t){this.driver=t||Q}extractBrandSlug(t){if(!t)return"app";let e=new Set(["com","org","net","io","in","co","uk","de","fr","us","ai","dev","android","mobile","app","apps","client","release","debug","main","browser","ui","view","experience","portal","phone","tablet","service"]),s=t.split("."),n=s.filter(i=>!e.has(i.toLowerCase())&&!/^\d+$/.test(i));return((n.length>0?n[n.length-1]:s[s.length-1])||"app").toLowerCase().replace(/[^a-z0-9_]/g,"")}async startRecording(t,e,s){let n=await this.driver.ensureDefaultDevice(e);if(!n)throw new Error("No Android device connected for recording.");this.deviceLock=ct(n),this.targetSerial=n,this.isRecording=!0,this.recordedSteps=[],this.existingSteps=[],this.existingFileHeader=[],this.visitedScreens=[],this.targetPackage=null,this.activeInput=null,this.isAppendMode=!!s?.append;try{let f=await this.driver.getForegroundPackage(n);f&&(this.targetPackage=f)}catch{}let r=this.extractBrandSlug(this.targetPackage),i;if(t&&t!=="specs/recorded_suite.txt")i=de.resolve(t);else{let f=`${r}_flow`,T=de.resolve(`specs/${f}.txt`);if(!this.isAppendMode&&he.existsSync(T)){let P=1;for(T=de.resolve(`specs/${f}_${P}.txt`);he.existsSync(T);)P++,T=de.resolve(`specs/${f}_${P}.txt`)}i=T}if(this.resolvedOutputPath=i,he.existsSync(i))if(this.isAppendMode){let f=he.readFileSync(i,"utf-8"),T=f.split(`
744
- `);for(let I of T){let v=I.trim();if(/^\d+\.\s+/.test(v))this.existingSteps.push(v.replace(/^\d+\.\s+/,""));else if(v.startsWith("# Package:")){let $=v.match(/# Package:\s*([a-zA-Z0-9._]+)/);$&&(this.targetPackage=$[1])}}let P=`${i}.bak`;he.writeFileSync(P,f,"utf-8"),console.log(C.cyan(`\u{1F4E5} Loaded ${this.existingSteps.length} existing step(s) from: ${de.basename(i)}`)),console.log(C.gray(`\u{1F4E6} Safety backup preserved at: ${de.basename(P)}`))}else{let f=he.readFileSync(i,"utf-8"),T=`${i}.bak`;he.writeFileSync(T,f,"utf-8"),console.log(C.yellow(`\u26A0\uFE0F File "${de.basename(i)}" already exists.`)),console.log(C.gray(`\u{1F4E6} Safety backup preserved at: ${de.basename(T)}`))}await this.driver.wakeDevice(n).catch(()=>{});let a=await this.driver.getScreenDimensions(n);this.displayWidth=a.width||E.screen.fallbackWidth,this.displayHeight=a.height||E.screen.fallbackHeight,this.touchMaxX=this.displayWidth,this.touchMaxY=this.displayHeight;try{let{stdout:f}=await this.driver.execAdb(["shell","getevent","-p"],n),T=f.match(/0035\s*:\s*value\s*\d+,\s*min\s*\d+,\s*max\s*(\d+)/),P=f.match(/0036\s*:\s*value\s*\d+,\s*min\s*\d+,\s*max\s*(\d+)/);T&&parseInt(T[1])>0&&(this.touchMaxX=parseInt(T[1])),P&&parseInt(P[1])>0&&(this.touchMaxY=parseInt(P[1]))}catch{}this.sessionStartTime=Date.now(),this.sessionScreenSections=[],this.screenshotCounter=0,this.crashDetected=!1,this.hierarchyStale=!0,this.currentScreenName="";let l=de.basename(i,".txt"),c=de.resolve("output");this.screenshotDir=de.join(c,"screenshots",l),he.existsSync(this.screenshotDir)||he.mkdirSync(this.screenshotDir,{recursive:!0});let u=C.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),h=await this.driver.getDeviceModel(n).catch(()=>n);console.log(`
745
- ${u}`),console.log(C.bold.cyan(`\u26A1 PromptTest v${Vs}`)+C.gray(" | Recording Session")),console.log(u),console.log(` ${C.gray("\u{1F4F1} Device ")} ${C.white(h)} ${C.gray(`(${n})`)}`),console.log(` ${C.gray("\u{1F4E6} App ")} ${C.green(this.targetPackage||"Unknown")}`),console.log(` ${C.gray("\u{1F3AF} Spec ")} ${C.yellow(de.basename(i))}`);let d=de.join(c,`${l}_report.md`);console.log(` ${C.gray("\u{1F4CA} Report ")} ${C.yellow(de.basename(d))}`),console.log(` ${C.gray("\u{1F4F8} Photos ")} ${C.yellow(de.relative(process.cwd(),this.screenshotDir))}`),this.isAppendMode&&this.existingSteps.length>0&&console.log(` ${C.gray("\u{1F4CE} Mode ")} ${C.magenta(`Append \u2014 resuming from step #${this.existingSteps.length+1}`)}`),console.log(u),process.stdout.write(` ${C.gray("Checking device health...")} `),console.log(C.green("\u2714 Ready")),process.stdout.write(` ${C.gray("Loading initial screen...")} `);let g=Date.now();await this.refreshHierarchySync();let m=Date.now()-g,y=this.currentScreenName?C.bold.white(this.currentScreenName):C.gray("Unknown");console.log(`${C.green("\u2714")} ${y} ${C.gray(`[${m}ms]`)}`),process.stdout.write(` ${C.gray("Starting screen watcher...")} `),this.startLogcatScreenWatcher(n),this.startLogcatCrashWatcher(n),console.log(C.green("\u2714 Streaming")),console.log(u),console.log(` ${C.gray("Use the app naturally. Every action is captured.")}`),console.log(` ${C.gray("Press Ctrl+C to stop and save.")}`),console.log(`${u}
746
- `);let S=()=>{if(this.isRecording=!1,this.inputDebounceTimer&&(clearTimeout(this.inputDebounceTimer),this.inputDebounceTimer=null),this.deviceLock&&(lt(this.deviceLock),this.deviceLock=null),this.geteventProcess)try{this.geteventProcess.kill()}catch{}if(this.logcatEventProcess)try{this.logcatEventProcess.kill()}catch{}if(this.logcatCrashProcess)try{this.logcatCrashProcess.kill()}catch{}this.saveSpec(this.resolvedOutputPath),this.saveReport(d),this.printExitSummary(u),process.exit(0)};process.once("SIGINT",S),process.once("SIGTERM",S),this.startEventStream(n);let b=0;for(;this.isRecording;)if(await new Promise(f=>setTimeout(f,1500)),b++,b%20===0&&this.driver.wakeDevice(n).catch(()=>{}),!this.targetPackage){let f=await this.driver.getForegroundPackage(n).catch(()=>null);f&&(this.targetPackage=f)}}startEventStream(t){let s=fi("adb",t?["-s",t,"shell","getevent","-l"]:["shell","getevent","-l"]);this.geteventProcess=s;let n=null,r=null,i=null,o=null,a=0;bi.createInterface({input:s.stdout}).on("line",c=>{if(this.isRecording)if(c.includes("ABS_MT_POSITION_X")){let u=c.match(/ABS_MT_POSITION_X\s+([0-9a-fA-F]+)/);u&&(n=parseInt(u[1],16))}else if(c.includes("ABS_MT_POSITION_Y")){let u=c.match(/ABS_MT_POSITION_Y\s+([0-9a-fA-F]+)/);u&&(r=parseInt(u[1],16))}else if(c.includes("BTN_TOUCH")&&c.includes("DOWN"))i=n,o=r,a=Date.now();else if(c.includes("BTN_TOUCH")&&c.includes("UP")){let u=n!==null?n:i,h=r!==null?r:o,d=Date.now()-a;if(u!==null&&h!==null&&i!==null&&o!==null){let g=Math.round(i/this.touchMaxX*this.displayWidth),m=Math.round(o/this.touchMaxY*this.displayHeight),y=Math.round(u/this.touchMaxX*this.displayWidth),S=Math.round(h/this.touchMaxY*this.displayHeight),b=y-g,f=S-m,T=Math.abs(b),P=Math.abs(f),I=Math.hypot(T,P);if(this.activeInput&&m>this.displayHeight*.58&&S>this.displayHeight*.58){d>=20&&d<400&&I<45&&y>=this.displayWidth*.78&&S>=this.displayHeight*.84?this.flushActiveInput().then(()=>{this.handleKeyPress("Enter")}).catch(()=>{}):this.scheduleInputDebounce(),n=null,r=null,i=null,o=null;return}if(d>=20&&d<400&&I<45)this.isRefreshingHierarchy?this.inFlightTapQueue.push({x:y,y:S,timestamp:Date.now()}):this.handleTapAt(y,S);else if(d>=450&&I<45)this.handleLongPressAt(y,S);else if(P>=100&&P>1.4*T){let v=f<0?"down":"up";this.handleScroll(v)}else if(T>=100&&T>1.4*P){let v=b<0?"left":"right";this.handleSwipe(v)}}n=null,r=null,i=null,o=null}else c.includes("KEY_ENTER")&&c.includes("DOWN")?this.handleKeyPress("Enter"):c.includes("KEY_BACK")&&c.includes("DOWN")&&this.handleKeyPress("Back")}),s.on("close",c=>{this.isRecording&&(console.warn(C.yellow(`
747
- \u26A0\uFE0F [EventStream] ADB event listener stream closed (code ${c}). Auto-reconnecting in 800ms...`)),setTimeout(()=>{this.isRecording&&this.startEventStream(t)},800))}),s.on("error",c=>{this.isRecording&&console.warn(C.yellow(`
748
- \u26A0\uFE0F [EventStream] ADB stream error: ${c.message}.`))})}cleanLabel(t){return t?t.replace(/[\uE000-\uF8FF\uFFF0-\uFFFF\uFFFD]/gu,"").replace(/,\s*tab,\s*\d+\s*of\s*\d+/gi,"").replace(/,\s*button$/gi,"").replace(/^[\s,•\-_:;|/\\]+|[\s,•\-_:;|/\\]+$/g,"").trim():""}handleScroll(t){let e=Date.now();if(this.lastScrollDirection===t&&e-this.lastScrollTimestamp<850)return;this.lastScrollTimestamp=e,this.lastScrollDirection=t,this.activeInput&&this.flushActiveInput().catch(()=>{});let s=`Scroll ${t}`;this.recordedSteps[this.recordedSteps.length-1]!==s&&(this.recordedSteps.push(s),console.log(C.blue(` \u{1F4DC} Recorded Scroll [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(s)}`)),this.triggerAsyncHierarchyRefresh(400))}handleSwipe(t){let e=Date.now();if(e-this.lastScrollTimestamp<600)return;this.lastScrollTimestamp=e,this.activeInput&&this.flushActiveInput().catch(()=>{});let s=`Swipe ${t}`;this.recordedSteps.push(s),console.log(C.blue(` \u{1F449} Recorded Swipe [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(s)}`)),this.triggerAsyncHierarchyRefresh(500)}handleLongPressAt(t,e){let s=this.lastHierarchyFlat.filter(i=>t>=i.bounds.x1&&t<=i.bounds.x2&&e>=i.bounds.y1&&e<=i.bounds.y2);if(s.length===0)return;s.sort((i,o)=>{let a=(i.bounds.x2-i.bounds.x1)*(i.bounds.y2-i.bounds.y1),l=(o.bounds.x2-o.bounds.x1)*(o.bounds.y2-o.bounds.y1);return a-l});let n=s[0],r=this.resolveActionLabel(n,s,this.lastHierarchyFlat);if(r){let i=`Long press '${r}'`;this.recordedSteps.push(i),console.log(C.cyan(` \u23F1\uFE0F Recorded Long Press [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(i)}`)),this.triggerAsyncHierarchyRefresh()}}handleTapAt(t,e){let s=Date.now(),n=this.lastHierarchyFlat.filter(h=>t>=h.bounds.x1&&t<=h.bounds.x2&&e>=h.bounds.y1&&e<=h.bounds.y2),i=this.lastHierarchyFlat.filter(h=>{let d=h.bounds.height;return d>0&&d<320&&h.bounds.width>0&&(h.clickable||h.contentDesc||h.text)}).filter(h=>e>=h.bounds.y1-30&&e<=h.bounds.y2+40);if(i.length>=2){let h=i.find(d=>t>=d.bounds.x1-20&&t<=d.bounds.x2+20);h&&(n=[this.lastHierarchyFlat.find(g=>(this.cleanLabel(g.text).length>0||this.cleanLabel(g.contentDesc).length>0)&&Math.abs(g.bounds.centerX-h.bounds.centerX)<h.bounds.width*.48&&Math.abs(g.bounds.centerY-h.bounds.centerY)<h.bounds.height*.48&&!this.isIconGlyph(this.cleanLabel(g.text)))||h])}if(e>this.displayHeight*.82){let d=this.lastHierarchyFlat.filter(g=>{let m=g.bounds.y1>=this.displayHeight*.78||g.bounds.y2>=this.displayHeight*.82,y=g.bounds.width>0&&g.bounds.width<=this.displayWidth*.52;return m&&y}).find(g=>t>=g.bounds.x1-20&&t<=g.bounds.x2+20);if(d){let g=this.lastHierarchyFlat.find(m=>(this.cleanLabel(m.text).length>0||this.cleanLabel(m.contentDesc).length>0)&&t>=m.bounds.x1-25&&t<=m.bounds.x2+25&&m.bounds.y1>=this.displayHeight*.78&&!this.isIconGlyph(this.cleanLabel(m.text)));g?n=[g]:(this.cleanLabel(d.text)||this.cleanLabel(d.contentDesc))&&(n=[d])}}if(n.length===0){let h=this.lastHierarchyFlat.filter(m=>(this.cleanLabel(m.text).length>0||this.cleanLabel(m.contentDesc).length>0)&&(m.clickable||m.className.includes("Button")||m.className.includes("Text"))),d=null,g=70;for(let m of h){let y=Math.hypot(m.bounds.centerX-t,m.bounds.centerY-e);y<g&&(g=y,d=m)}if(d)n=[d];else{this.triggerAsyncHierarchyRefresh();return}}n.sort((h,d)=>{let g=(h.bounds.x2-h.bounds.x1)*(h.bounds.y2-h.bounds.y1),m=(d.bounds.x2-d.bounds.x1)*(d.bounds.y2-d.bounds.y1);return g-m});let o=n[0],a=n.find(h=>h.className.includes("EditText"))||(o.className.includes("EditText")?o:null);if(a){this.activeInput&&this.activeInput.node!==a&&this.flushActiveInput().catch(()=>{});let h=this.resolveFieldLabel(a,this.lastHierarchyFlat);this.activeInput={node:a,label:h,startText:a.text||""},this.triggerAsyncHierarchyRefresh();return}this.activeInput&&this.flushActiveInput().catch(()=>{});let l=this.resolveActionLabel(o,n,this.lastHierarchyFlat);if(!l||l.length===0){this.triggerAsyncHierarchyRefresh();return}if(!o.clickable&&!n.some(h=>h.clickable||h.className.includes("Button"))&&/^\d+%$|^\d+$/.test(l)){this.triggerAsyncHierarchyRefresh();return}if(l===this.lastRecordedTapTarget&&s-this.lastTapTimestamp<350)return;this.lastTapTimestamp=s,this.lastRecordedTapTarget=l;let c;if(o.checkable||o.className.includes("Switch")||o.className.includes("CheckBox")){let h=o.checked!==void 0?!o.checked:!0;c=`Toggle '${l}' to ${h?"on":"off"}`}else{c=`Tap '${l}'`;let h=this.lastHierarchyFlat.filter(g=>this.cleanLabel(g.text)===l||this.cleanLabel(g.contentDesc)===l),d=[];for(let g of h)d.some(y=>Math.hypot(y.bounds.centerX-g.bounds.centerX,y.bounds.centerY-g.bounds.centerY)<40)||d.push(g);if(d.length>1){let m=this.lastHierarchyFlat.filter(y=>y!==o&&Math.abs(y.bounds.centerY-o.bounds.centerY)<140&&Math.abs(y.bounds.centerX-o.bounds.centerX)<550).find(y=>{let S=this.cleanLabel(y.text)||this.cleanLabel(y.contentDesc);return S.length>2&&S!==l&&!/^\d+$/.test(S)&&!this.isIconGlyph(S)});if(m){let y=this.cleanLabel(m.text)||this.cleanLabel(m.contentDesc);y&&y!==l&&(c=`Tap '${l}' next to '${y}'`)}}}this.recordedSteps[this.recordedSteps.length-1]!==c&&(this.recordedSteps.push(c),console.log(C.cyan(` \u{1F446} Recorded Tap [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(c)}`))),this.triggerAsyncHierarchyRefresh()}handleKeyPress(t){if(this.activeInput&&this.flushActiveInput().catch(()=>{}),t==="Enter"){let e="Press 'Enter'";this.recordedSteps[this.recordedSteps.length-1]!==e&&(this.recordedSteps.push(e),console.log(C.magenta(` \u21B5 Recorded Key [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(e)}`)))}else if(t==="Back"){let e="Tap 'Back'";this.recordedSteps[this.recordedSteps.length-1]!==e&&(this.recordedSteps.push(e),console.log(C.magenta(` \u25C0 Recorded Key [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(e)}`)))}this.triggerAsyncHierarchyRefresh()}scheduleInputDebounce(){this.inputDebounceTimer&&clearTimeout(this.inputDebounceTimer),this.inputDebounceTimer=setTimeout(()=>{this.activeInput&&this.syncActiveInputText().catch(()=>{})},450)}async flushActiveInput(){if(this.inputDebounceTimer&&(clearTimeout(this.inputDebounceTimer),this.inputDebounceTimer=null),!this.activeInput)return;let t=this.activeInput;this.activeInput=null,await this.recordInputText(t)}async syncActiveInputText(){this.activeInput&&await this.recordInputText(this.activeInput)}async recordInputText(t){try{let e=await this.driver.getUiHierarchy(this.targetSerial).catch(()=>null);if(!e)return;let{flat:s}=pe(e);this.lastHierarchyFlat=s;let n=s.find(r=>r.className.includes("EditText")&&(r.focused||r.selected))||s.find(r=>r.className.includes("EditText")&&this.resolveFieldLabel(r,s).toLowerCase()===t.label.toLowerCase())||s.find(r=>r.className.includes("EditText")&&Math.abs(r.bounds.centerX-t.node.bounds.centerX)<80)||s.find(r=>r.className.includes("EditText"));if(n&&n.text&&n.text.trim().length>0){let r=n.text.trim(),i=/^[•*•\u2022\u25cf]+$/.test(r);if(!(r===t.startText)&&!i){if(t.startText===""&&this.isPlaceholderText(r))return;let a=t.label||this.resolveFieldLabel(n,s),l=`Type '${r}' into '${a}'`,c=this.recordedSteps.length-1,u=c>=0?this.recordedSteps[c]:"";u.startsWith("Type ")&&u.endsWith(`into '${a}'`)?u!==l&&(this.recordedSteps[c]=l,console.log(C.gray(` \u270D\uFE0F Updated Input [Step #${c+1+this.existingSteps.length}]: ${C.bold(l)}`))):(this.recordedSteps.push(l),console.log(C.green(` \u270D\uFE0F Recorded Input [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(l)}`)))}else if(i&&(n.password||t.label.toLowerCase().includes("password"))){let a=t.label||"Password",l=`Type '<password>' into '${a}'`,c=this.recordedSteps.length-1,u=c>=0?this.recordedSteps[c]:"";(!u.startsWith("Type ")||!u.endsWith(`into '${a}'`))&&(this.recordedSteps.push(l),console.log(C.green(` \u270D\uFE0F Recorded Password Input [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(l)}`)))}}}catch{}}startLogcatScreenWatcher(t){try{this.logcatEventProcess=this.driver.streamLogcatEvents(t,e=>{if(this.isRecording&&(e.includes("wm_on_resume_called")||e.includes("am_on_resume_called"))){let s=Date.now();if(s-this.lastScreenTransitionTime<500)return;this.lastScreenTransitionTime=s,this.hierarchyStale=!0,this.triggerAsyncHierarchyRefresh(50)}})}catch{}}startLogcatCrashWatcher(t){try{this.logcatCrashProcess=this.driver.streamLogcatCrashes(t,e=>{if(this.isRecording&&(e.includes("FATAL EXCEPTION")||e.includes("ANR in"))){if(this.targetPackage&&!e.includes(this.targetPackage))return;this.crashDetected=!0,console.log(C.red.bold(`
749
- \u26A0\uFE0F [Crash Alert] Fatal exception / ANR detected in ${this.targetPackage||"app"}!`))}})}catch{}}captureSessionScreenshot(t){if(!this.screenshotDir)return;let e=++this.screenshotCounter,s=t.toLowerCase().replace(/[^a-z0-9_]/g,"_").slice(0,30)||"screen",n=`screen_${String(e).padStart(2,"0")}_${s}.png`,r=de.join(this.screenshotDir,n);(async()=>{try{let i=await this.driver.captureScreenshot(this.targetSerial);if(i&&i.length>0){await he.promises.writeFile(r,i);let o=this.sessionScreenSections[this.sessionScreenSections.length-1];o&&!o.screenshotFile&&(o.screenshotFile=n)}}catch{}})()}triggerAsyncHierarchyRefresh(t=E.recorder.asyncRefreshDelayMs){this.isRefreshingHierarchy||(this.isRefreshingHierarchy=!0,setTimeout(()=>{this.doHierarchyRefresh().catch(()=>{this.isRefreshingHierarchy=!1})},t))}async doHierarchyRefresh(){try{let t=await this.driver.getUiHierarchy(this.targetSerial),{flat:e}=pe(t);this.lastHierarchyFlat=e,this.hierarchyStale=!1,this.hierarchyCacheTime=Date.now(),this.detectAndLogScreenHeader(e),this.detectAndLogTransientAlerts(e)}catch{}finally{for(this.isRefreshingHierarchy=!1;this.inFlightTapQueue.length>0;){let t=this.inFlightTapQueue.shift();if(!t)break;Date.now()-t.timestamp<E.recorder.staleTapTimeoutMs?this.handleTapAt(t.x,t.y):console.warn(C.yellow(`[Recorder] Dropped stale tap at (${t.x}, ${t.y}) \u2014 screen refresh took longer than ${E.recorder.staleTapTimeoutMs}ms`))}}}detectAndLogTransientAlerts(t){let e=t.find(s=>(s.className.includes("Toast")||s.className.includes("Snackbar")||s.resourceId&&s.resourceId.includes("snackbar")||s.contentDesc&&(s.contentDesc.includes("Alert")||s.contentDesc.includes("Success")))&&(s.text||s.contentDesc));if(e){let s=this.cleanLabel(e.text)||this.cleanLabel(e.contentDesc);if(s&&s.length>3&&s.length<80){let n=`Verify '${s}' is visible`;this.recordedSteps.slice(-3).includes(n)||(this.recordedSteps.push(n),console.log(C.green(` \u2714 Recorded Alert [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(n)}`)))}}}async refreshHierarchySync(){try{let t=await this.driver.getUiHierarchy(this.targetSerial),{flat:e}=pe(t);this.lastHierarchyFlat=e,this.hierarchyStale=!1,this.hierarchyCacheTime=Date.now(),this.detectAndLogScreenHeader(e)}catch{}}isIconGlyph(t){if(!t||t.trim().length===0)return!0;let e=t.trim();return!!(/[\uE000-\uF8FF\uFFF0-\uFFFF]/.test(e)||e.length===1&&e.charCodeAt(0)>255&&!new RegExp("\\p{Extended_Pictographic}","u").test(e))}cleanDialogOrCompoundLabel(t){if(!t)return"";let e=t.trim();if(e.includes(",")||e.includes(`
750
- `)){let s=e.split(/[\n,]+/).map(n=>this.cleanLabel(n)).filter(Boolean);if(s.length>1){let n=s.find(i=>i.includes("?")||/\b(are you sure|do you want|cannot be undone|would you like|please confirm)\b/i.test(i)||i.length>35);if(n){let i=s.find(o=>o!==n&&o.length<=30&&!o.includes("?"));if(i)return i}let r=s.filter(i=>/^[A-Z]{1,3}$/.test(i)||/^\d+%?$/.test(i)||this.isCardMetadataSubtitle(i)||/^(attend|present|absent|status|active|inactive)$/i.test(i)?!1:i.length>1);if(r.length>0)return r[0]}}return e}isCardMetadataSubtitle(t){if(!t||t.trim().length===0)return!1;let e=t.trim();return!!(/\+?\d{1,3}[\s-]?\d{4,}[\s-]?\d{4,}/.test(e)||/^(STD|ID|EMP|REF|ORD|USER|ACC|BATCH)[\-_:\s]?\d+/i.test(e)||/[•|·]/.test(e)&&/\d/.test(e)||/^\d+$/.test(e)||/^\d{1,2}:\d{2}/.test(e)||/^(teacher|roll\s*no|std\s*id|class|sec)[\s:]+/i.test(e))}findPrimaryCardTitle(t,e,s){if(t.bounds.y1>=this.displayHeight*.8||t.bounds.centerY>=this.displayHeight*.82||t.clickable&&(t.className.includes("Button")||t.className.includes("Check")))return null;let n=this.cleanLabel(t.text),r=this.isCardMetadataSubtitle(n),i=s.find(l=>l!==t&&l.clickable&&l.bounds.height>60&&l.bounds.height<600),o;i?o=e.filter(l=>l.className.includes("Text")&&l.bounds.x1>=i.bounds.x1-10&&l.bounds.x2<=i.bounds.x2+10&&l.bounds.y1>=i.bounds.y1-10&&l.bounds.y2<=i.bounds.y2+10):o=e.filter(l=>l!==t&&l.className.includes("Text")&&l.bounds.centerY<t.bounds.centerY&&t.bounds.centerY-l.bounds.centerY<160&&Math.abs(l.bounds.centerX-t.bounds.centerX)<500);let a=o.filter(l=>{let c=this.cleanLabel(l.text);return c.length>2&&!this.isCardMetadataSubtitle(c)&&!this.isIconGlyph(c)&&!/^\d+$/.test(c)&&!/^(active|inactive|present|absent|new|pending)$/i.test(c)}).sort((l,c)=>l.bounds.y1-c.bounds.y1);if(a.length>0){let l=this.cleanLabel(a[0].text);if(r||i&&l!==n&&!t.clickable)return l}return null}resolveActionLabel(t,e,s){if(t.bounds.y1>=this.displayHeight*.8||t.bounds.centerY>=this.displayHeight*.82){let l=this.cleanLabel(t.contentDesc)||this.cleanLabel(t.text);if(l&&l.length>0&&!this.isIconGlyph(l))return this.cleanDialogOrCompoundLabel(l);for(let c of e){let u=this.cleanLabel(c.contentDesc)||this.cleanLabel(c.text);if(u&&u.length>0&&!this.isIconGlyph(u))return this.cleanDialogOrCompoundLabel(u)}}let n=this.findPrimaryCardTitle(t,s,e);if(n)return this.cleanDialogOrCompoundLabel(n);let r=this.cleanLabel(t.text);if(r.length>0&&r.length<90){let l=r.split(/[\n\r]+/).map(u=>this.cleanLabel(u)).filter(Boolean),c=l.length>1?l.find(u=>u.length>2&&!/^\d+$/.test(u))||l[0]:r;return this.cleanDialogOrCompoundLabel(c)}let i=this.cleanLabel(t.contentDesc);if(i.length>0&&i.length<90)return this.cleanDialogOrCompoundLabel(i);let o=e.find(l=>(l.clickable||l.className.includes("Button"))&&(this.cleanLabel(l.text)||this.cleanLabel(l.contentDesc)));if(o){let l=this.cleanLabel(o.text)||this.cleanLabel(o.contentDesc);if(l.length>0&&l.length<90)return this.cleanDialogOrCompoundLabel(l)}for(let l of e){let c=this.cleanLabel(l.text);if(c.length>0&&c.length<90){let h=c.split(/[\n\r]+/).map(g=>this.cleanLabel(g)).filter(Boolean),d=h.length>1?h.find(g=>g.length>2&&!/^\d+$/.test(g))||h[0]:c;return this.cleanDialogOrCompoundLabel(d)}let u=this.cleanLabel(l.contentDesc);if(u.length>0&&u.length<90)return this.cleanDialogOrCompoundLabel(u)}let a=s.find(l=>l!==t&&(this.cleanLabel(l.text).length>0||this.cleanLabel(l.contentDesc).length>0)&&Math.abs(l.bounds.centerX-t.bounds.centerX)<80&&Math.abs(l.bounds.centerY-t.bounds.centerY)<100);if(a){let l=this.cleanLabel(a.text)||this.cleanLabel(a.contentDesc);if(l.length>0)return this.cleanDialogOrCompoundLabel(l)}if(t.resourceId){let l=t.resourceId.split("/"),c=l[l.length-1];if(c&&!/^\d+$/.test(c)){let u=c.replace(/_/g," ").replace(/btn|button|icon|view|action/gi,"").trim();if(u.length>1)return u.charAt(0).toUpperCase()+u.slice(1)}}return""}getCurrentStepNumber(){return this.existingSteps.length+this.recordedSteps.length+1}detectAndLogScreenHeader(t){let e=t.filter(s=>{if(!s.className.includes("TextView")||s.text.trim().length<2||s.packageName&&(s.packageName.includes("systemui")||s.packageName.includes("launcher"))||s.bounds.y1<60||s.bounds.y1>=450)return!1;let n=s.text.trim();return!(this.isCardMetadataSubtitle(n)||/\b(JIO|Airtel|Vodafone|No service|Emergency|VoLTE|4G|5G)\b/i.test(n)||/^\d+%?$|^\d+$/.test(n)||/^step\s*\d+\s*(of|\/)\s*\d+/i.test(n))}).sort((s,n)=>s.bounds.y1-n.bounds.y1);if(e.length>0){let s=e[0].text.trim();if(s&&s!==this.lastScreenTitle&&!s.includes(":")&&s.length<40){this.lastScreenTitle=s,this.currentScreenName=s,this.visitedScreens.includes(s)||this.visitedScreens.push(s),this.sessionScreenSections.push({name:s,stepStart:this.recordedSteps.length}),this.captureSessionScreenshot(s);let n=`Verify '${s}' is visible`;this.recordedSteps[this.recordedSteps.length-1]!==n&&!this.recordedSteps.slice(-3).includes(n)&&(this.recordedSteps.push(n),console.log(C.green(` \u2714 Recorded Header [Step #${this.getCurrentStepNumber()-1}]: ${C.bold(n)}`)))}}}resolveFieldLabel(t,e){if(t.contentDesc&&t.contentDesc.trim().length>0)return t.contentDesc.trim();if(t.password)return"Password";let s=e.filter(n=>n.className.includes("TextView")&&n.text&&n.text.trim().length>1&&n.bounds.centerY<t.bounds.centerY&&t.bounds.centerY-n.bounds.centerY<250&&Math.abs(n.bounds.centerX-t.bounds.centerX)<450);if(s.length>0){s.sort((r,i)=>i.bounds.centerY-r.bounds.centerY);let n=s[0].text.trim().replace(/[*:]/g,"").trim();if(n.length>0)return n}if(t.resourceId){let n=t.resourceId.split("/"),r=n[n.length-1];if(r&&!/^\d+$/.test(r)){let i=r.replace(/_/g," ").replace(/edit|text|input|field|et|txt/gi,"").trim();return i.length>1?i.charAt(0).toUpperCase()+i.slice(1):r}}if(t.text&&t.text.trim().length>0&&t.text.trim().length<40){let n=t.text.trim();if(n.toLowerCase().startsWith("search"))return n.length<=25?n:"Search";if(!this.isPlaceholderText(n))return n}return"Input Field"}isPlaceholderText(t){let e=t.trim().toLowerCase();return e.startsWith("search")||e.startsWith("e.g.")||e.startsWith("enter ")||e.startsWith("type ")||e.includes("optional")}saveSpec(t){let e=de.resolve(t);if(de.basename(e).startsWith("app_flow")&&this.targetPackage&&!this.isAppendMode){let a=this.extractBrandSlug(this.targetPackage);if(a!=="app"){let l=`${a}_flow`,c=de.resolve(`specs/${l}.txt`),u=1;for(;he.existsSync(c);)c=de.resolve(`specs/${l}_${u}.txt`),u++;e=c}}let n=de.dirname(e);he.existsSync(n)||he.mkdirSync(n,{recursive:!0});let r=[];if(this.isAppendMode&&this.existingSteps.length>0&&he.existsSync(e)){let a=he.readFileSync(e,"utf-8").trim();r.push(a),r.push(""),r.push(`# --- Appended Session (${new Date().toISOString().replace("T"," ").slice(0,19)}) ---`),this.recordedSteps.forEach((l,c)=>{r.push(`${this.existingSteps.length+c+1}. ${l}`)})}else{r.push("# ==========================================================",`# Autonomous Recorded Test Spec: ${de.basename(e)}`,...this.targetPackage?[`# Package: ${this.targetPackage}`]:[],`# Generated: ${new Date().toISOString()}`,`# PromptTest v${Vs}`,"# ==========================================================","");let a=0;this.recordedSteps.forEach((l,c)=>{if(a<this.sessionScreenSections.length&&c===this.sessionScreenSections[a].stepStart){let u=this.sessionScreenSections[a];r.push(""),r.push(`# Screen: ${u.name}`),a++}r.push(`${this.existingSteps.length+c+1}. ${l}`)})}r.push("");let i=r.join(`
751
- `),o=`${e}.tmp.${Date.now()}`;try{he.writeFileSync(o,i,"utf-8"),he.renameSync(o,e)}catch{try{he.unlinkSync(o)}catch{}he.writeFileSync(e,i,"utf-8")}}saveReport(t){let e=Math.round((Date.now()-this.sessionStartTime)/1e3),s=Math.floor(e/60),n=e%60,r=`${String(s).padStart(2,"0")}:${String(n).padStart(2,"0")}`,i=this.existingSteps.length+this.recordedSteps.length,o=["# PromptTest Recording Report","","| Property | Value |","|---|---|",`| **Target Package** | \`${this.targetPackage||"Unknown"}\` |`,`| **Device Serial** | \`${this.targetSerial}\` |`,`| **Session Started** | ${new Date(this.sessionStartTime).toISOString()} |`,`| **Session Duration** | ${r} |`,`| **Steps in Session** | ${this.recordedSteps.length} |`,`| **Total Suite Steps** | ${i} |`,`| **Screens Visited** | ${this.visitedScreens.length} |`,`| **Screenshots Saved** | ${this.screenshotCounter} |`,`| **Crash Signals** | ${this.crashDetected?"\u26A0\uFE0F Detected":"\u2705 None"} |`,"","---","","## Screen Journey","",this.visitedScreens.length>0?this.visitedScreens.map((a,l)=>`${l+1}. **${a}**`).join(`
752
- `):"*Single screen flow*","","---","","## Recorded Interactions",""];if(this.sessionScreenSections.length>0)for(let a=0;a<this.sessionScreenSections.length;a++){let l=this.sessionScreenSections[a],c=this.sessionScreenSections[a+1],u=c?c.stepStart:this.recordedSteps.length,h=this.recordedSteps.slice(l.stepStart,u);o.push(`### Screen: ${l.name}`),o.push(""),l.screenshotFile&&(o.push(`![${l.name}](screenshots/${de.basename(this.screenshotDir)}/${l.screenshotFile})`),o.push("")),h.length>0?h.forEach((d,g)=>{o.push(`${l.stepStart+g+1}. \`${d}\``)}):o.push("*(No interactions on this screen)*"),o.push("")}else o.push("### Steps"),o.push(""),this.recordedSteps.forEach((a,l)=>{o.push(`${l+1}. \`${a}\``)}),o.push("");try{let a=de.dirname(t);he.existsSync(a)||he.mkdirSync(a,{recursive:!0}),he.writeFileSync(t,o.join(`
753
- `),"utf-8")}catch{}}printExitSummary(t){let e=Math.round((Date.now()-this.sessionStartTime)/1e3),s=Math.floor(e/60),n=e%60,r=`${String(s).padStart(2,"0")}:${String(n).padStart(2,"0")}`,i=this.existingSteps.length+this.recordedSteps.length;console.log(`
754
- ${t}`),console.log(C.bold.green(" \u{1F4BE} Recording Session Saved Successfully!")),console.log(t),console.log(` ${C.gray("Steps Captured ")} ${C.bold.yellow(this.recordedSteps.length.toString())} ${this.isAppendMode?C.gray(`(Total Suite: ${i})`):""}`),console.log(` ${C.gray("Screens Visited")} ${C.bold.white(this.visitedScreens.length.toString())} ${this.visitedScreens.length>0?C.gray(`(${this.visitedScreens.join(" \u2192 ")})`):""}`),console.log(` ${C.gray("Screenshots ")} ${C.bold.white(this.screenshotCounter.toString())} saved`),console.log(` ${C.gray("Session Time ")} ${C.bold.white(r)}`),console.log(` ${C.gray("Crash Signals ")} ${this.crashDetected?C.red.bold("\u26A0\uFE0F Detected"):C.green("\u2714 0 detected")}`),console.log(t),console.log(` ${C.gray("\u{1F4C4} Spec ")} ${C.cyan(this.resolvedOutputPath)}`);let o=de.basename(this.resolvedOutputPath,".txt");console.log(` ${C.gray("\u{1F4CA} Report ")} ${C.cyan(de.resolve("output",`${o}_report.md`))}`),console.log(`${t}
755
- `)}},vi=new vt});var On={};xt(On,{calculatePercentile:()=>Xs,formatBenchmarkTable:()=>xi,generateSyntheticHierarchy:()=>Fn,runBenchmark:()=>wi,summarizeMetrics:()=>qt});import Ce from"chalk";function Xs(p,t){if(p.length===0)return 0;let e=[...p].sort((n,r)=>n-r),s=Math.min(e.length-1,Math.max(0,Math.floor(t/100*(e.length-1))));return Math.round(e[s]*100)/100}function qt(p){if(p.length===0)return{minMs:0,maxMs:0,avgMs:0,p50Ms:0,p95Ms:0,iterations:0,durations:[]};let t=Math.round(Math.min(...p)*100)/100,e=Math.round(Math.max(...p)*100)/100,s=p.reduce((o,a)=>o+a,0),n=Math.round(s/p.length*100)/100,r=Xs(p,50),i=Xs(p,95);return{minMs:t,maxMs:e,avgMs:n,p50Ms:r,p95Ms:i,iterations:p.length,durations:p}}function Fn(p=1e3){let t=[];t.push({index:0,className:"android.widget.FrameLayout",packageName:"com.app",text:"",resourceId:"android:id/content",contentDesc:"Main Screen Root",clickable:!1,enabled:!0,focused:!1,scrollable:!1,password:!1,selected:!1,children:[],bounds:{x1:0,y1:0,x2:1080,y2:2400,width:1080,height:2400,centerX:540,centerY:1200}}),t.push({index:1,className:"android.widget.TextView",packageName:"com.app",text:"Apex Coaching Academy - Dashboard",resourceId:"com.app:id/title_header",contentDesc:"Header Title",clickable:!1,enabled:!0,focused:!1,scrollable:!1,password:!1,selected:!1,children:[],bounds:{x1:40,y1:100,x2:1040,y2:220,width:1e3,height:120,centerX:540,centerY:160}});let e=["android.widget.TextView","android.widget.Button","android.widget.EditText","android.widget.ImageView","android.view.ViewGroup","android.widget.LinearLayout","android.widget.CheckBox","android.widget.Switch"],s=["Sign In","Email Address","Password","Submit","Save Changes","Settings","Profile","Notifications","Batch 10A","Mathematics","Physics","Attendance","Export PDF","Delete Record","Cancel","Next","Back","Search","Filter","Refresh"];for(let n=2;n<p;n++){let r=e[n%e.length],i=r.includes("Button")||r.includes("CheckBox")||r.includes("Switch"),o=s[n%s.length],a=`${o} #${n}`,l=Math.min(2400,250+n*20%2e3),c=50+n*30%900;t.push({index:n,className:r,packageName:"com.app",text:r.includes("ImageView")?"":a,resourceId:`com.app:id/element_${n}`,contentDesc:r.includes("ImageView")?`Icon of ${o}`:"",clickable:i,enabled:n%25!==0,focused:!1,scrollable:!1,password:o.toLowerCase().includes("password"),selected:!1,children:[],bounds:{x1:c,y1:l,x2:c+200,y2:l+80,width:200,height:80,centerX:c+100,centerY:l+40}})}return t}async function wi(p=Q,t={}){let e=t.iterations||5,s=Date.now(),n=t.serial,r="Synthetic Mock Android Environment",i=!1;if(!t.forceMock)try{n=await p.ensureDefaultDevice(t.serial),n&&(r=await p.getDeviceModel(n),i=!0)}catch{i=!1}let o=[];for(let g=0;g<e;g++){let m=performance.now();i?await p.captureScreenshot(n):(await new Promise(y=>setTimeout(y,15)),Buffer.alloc(1024*1024)),o.push(performance.now()-m)}let a=[];for(let g=0;g<e;g++){let m=performance.now();i?await p.getUiHierarchy(n):await new Promise(y=>setTimeout(y,25)),a.push(performance.now()-m)}let l=Fn(1e3),c=new Xe,u=["Submit","Email Address","Mathematics","Save Changes","NonExistent Query Fallback"],h=[];for(let g=0;g<e;g++){let m=u[g%u.length],y=performance.now();jt(l,m,c),h.push(performance.now()-y)}let d=Date.now()-s;return{timestamp:new Date().toISOString(),device:r,package:t.packageName,screencap:qt(o),uiHierarchy:qt(a),nodeMatching:qt(h),totalDurationMs:d}}function xi(p){let t=(r,i)=>{let o=`${i.minMs.toFixed(1)}ms`.padStart(9),a=`${i.avgMs.toFixed(1)}ms`.padStart(9),l=`${i.p50Ms.toFixed(1)}ms`.padStart(9),c=`${i.p95Ms.toFixed(1)}ms`.padStart(9),u=`${i.maxMs.toFixed(1)}ms`.padStart(9);return`\u2502 ${r.padEnd(28)} \u2502 ${o} \u2502 ${a} \u2502 ${l} \u2502 ${c} \u2502 ${u} \u2502`};return["",Ce.bold.cyan("\u26A1 PromptTest Performance Diagnostic Benchmark"),Ce.gray("Device: ")+Ce.bold.white(p.device)+Ce.gray(` | Samples: ${p.screencap.iterations} runs`),"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",`\u2502 ${Ce.bold("Operation".padEnd(28))} \u2502 ${Ce.bold("Min".padStart(9))} \u2502 ${Ce.bold("Avg".padStart(9))} \u2502 ${Ce.bold("p50".padStart(9))} \u2502 ${Ce.bold("p95".padStart(9))} \u2502 ${Ce.bold("Max".padStart(9))} \u2502`,"\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524",t("Device Screencap",p.screencap),t("UI Hierarchy Dump (XML)",p.uiHierarchy),t("Node Matching (1k nodes)",p.nodeMatching),"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",Ce.gray("Total Benchmark Wall-Time: ")+Ce.bold.green(`${p.totalDurationMs}ms
737
+ \u{1F504} [Data-Driven Iteration ${U+1}/${d.length}] Row Data: ${JSON.stringify(G)}
738
+ ======================================================`)),i.fresh&&U>0&&b&&(await this.driver.clearAppData(b,i.serial),await new Promise(X=>setTimeout(X,1e3)))),this.runtimeVariables.clear();for(let[X,O]of Object.entries(G))this.runtimeVariables.set(X,O);this.loopStack=[];let re=this.parsePrompt(n,G),_=1,me=i.resume&&U===0?await this.checkpoints.getResumeIndex(c):0;me>0&&console.log(B.cyan(`\u23ED Resuming from step ${me+1} (checkpoint found).`));let se=i.only?yi(i.only):null;for(let X=0;X<re.length;X++){let O=re[X];if(_=X+1,se&&!se.has(_)){console.log(B.gray(`[Step ${_}/${re.length}] \u23E9 Skipped (not in --only range: ${i.only})`)),this.reporter.logStep(J,O.originalText,O.type,"SKIPPED",`Filtered out by --only="${i.only}"`,void 0,void 0,0);continue}if(X<me){this.reporter.logStep(J,O.originalText,O.type,"SKIPPED","Resumed \u2014 already passed",void 0,void 0,0);continue}let Y=re.slice(X+1);console.log(B.bold.blue(`
739
+ [Step ${_}/${re.length}] ${O.originalText}`));let A=Date.now();try{let M=await this.executeStep(O,i.serial,Y),R=Date.now()-A;if(M&&M.fastForwarded){if(console.log(B.cyan(`\u23E9 Fast-Forward: ${M.reason}. Redundant step(s) bypassed.`)),this.reporter.logStep(J,O.originalText,O.type,"PASS",`Fast-Forward: ${M.reason}`,void 0,void 0,R),console.log(B.green(`\u2714 Step ${_} PASSED (Fast-Forward)`)),M?.skipCount&&M.skipCount>0){let F=M.skipCount;for(let V=0;V<F&&X+1<re.length;V++){X++;let E=re[X],w=X+1;this.reporter.logStep(J,E.originalText,E.type,"PASS",`Fast-Forward: ${M.reason}`,void 0,void 0,0),console.log(B.gray(` [Step ${w}/${re.length}] \u23E9 Fast-Forward: ${E.originalText}`))}}}else{let F;if((i.screenshotMode==="all"||i.saveBaseline||i.compareBaseline)&&(F=await this.driver.captureScreenshot(i.serial)),F&&i.compareBaseline){let V=await this.baselines.compare(J,_,F,i.baselineThreshold);V.passed||(console.log(B.yellow(` \u26A0\uFE0F [Baseline] Step ${_} visual diff ${(V.diffRatio*100).toFixed(1)}% exceeds threshold ${(V.threshold*100).toFixed(1)}%`)),this.reporter.logError(`Visual baseline diff at Step ${_}: ${(V.diffRatio*100).toFixed(1)}% changed`))}F&&i.saveBaseline&&await this.baselines.saveBaseline(J,_,F),this.reporter.logStep(J,O.originalText,O.type,"PASS",O.target||O.value,i.screenshotMode==="all"?F:void 0,void 0,R),console.log(B.green(`\u2714 Step ${_} PASSED`)),i.benchmark&&console.log(B.gray(` \u23F1 [Benchmark] Step ${_} latency: ${R}ms (${O.type}${O.target?` -> "${O.target}"`:""})`))}i.resume&&!H&&await this.checkpoints.save(c,b,X,re.length)}catch(M){let R=M,F=Date.now()-A;if(O.optional){console.log(B.yellow(`\u26AA Step ${_} OPTIONAL (Skipped: ${R.message})`)),this.reporter.logStep(J,O.originalText,O.type,"SKIPPED",`Optional step bypassed: ${R.message}`,void 0,void 0,F);continue}x++,console.log(B.red(`\u274C Step ${_} FAILED: ${R.message}`)),O.target&&this.memory.recordFailure(O.type,O.target);let V=await this.driver.captureScreenshot(i.serial).catch(()=>{}),E;try{let w=xe.resolve(process.cwd(),"output"),N=`${c}_step_${_}`,L=xe.join(w,"failures",N);He.existsSync(L)||He.mkdirSync(L,{recursive:!0}),V&&await He.promises.writeFile(xe.join(L,"screenshot.png"),V);let le=this.lastHierarchy?.xml||await this.driver.getUiHierarchy(i.serial).catch(()=>"");le&&await He.promises.writeFile(xe.join(L,"hierarchy.xml"),le,"utf-8");let j=await this.driver.getLogcatTail(150,i.serial);await He.promises.writeFile(xe.join(L,"logcat_tail.log"),j,"utf-8");let Se=this.lastHierarchy?.flat||[],Ne=O.target&&Se.length>0?it(O.target,Se.map(ne=>ne.text||ne.contentDesc||"").filter(Boolean)):[];await He.promises.writeFile(xe.join(L,"match_scores.json"),JSON.stringify(Ne,null,2),"utf-8"),E=xe.join("failures",N).replace(/\\/g,"/"),console.log(B.red(` \u{1F4C1} Failure Triage Bundle generated at: output/${E}`))}catch{}if(this.reporter.logStep(J,O.originalText,O.type,"FAIL",R.message,V,void 0,F,E),this.reporter.logError(`Step ${_} failed: ${R.message}`),i.continueOnError)console.log(B.yellow("Continuing with next test step (--continue enabled)..."));else{let w=re.slice(X+1);if(w.length>0){console.log(B.yellow(`
740
+ \u{1F6D1} Aborting dependent flow due to upstream failure at Step ${_}.`)),console.log(B.gray(`Cascading skip applied to ${w.length} downstream step(s):`));for(let N=0;N<w.length;N++){let L=w[N],le=_+1+N;this.reporter.logStep(J,L.originalText,L.type,"SKIPPED",`Cascading skip: Precondition failed at Step ${_} (${O.originalText})`,void 0,void 0,0),console.log(B.gray(` [Step ${le}/${re.length}] \u26AA SKIPPED: ${L.originalText}`))}}break}}}}try{let U=this.lastHierarchy;if(U?.flat){let G=pi(U.flat,this.screenDimensions.width,this.screenDimensions.height);if(G.length>0){console.log(B.bold.yellow(`
741
+ \u{1F50D} Visual QA Sentinel Warnings (${G.length} detected):`));for(let H of G)console.log(B.yellow(` \u2022 [${H.type}] ${H.description}`)),this.reporter.logError(`Visual Defect (${H.type}): ${H.description}`)}}}catch{}await this.memory.save(),i.resume&&x===0&&await this.checkpoints.clear(c);let T=this.memory.getStats();if(T.totalMappings>0&&console.log(B.cyan(`\u{1F9E0} Knowledge Engine: ${T.totalMappings} active learned mapping(s) for ${T.package}`)),S){console.log(B.cyan("\u{1F3AC} Finalizing video recording..."));let U=xe.resolve(process.cwd(),"output"),G=xe.join(U,`${c}-recording.mp4`),H=await this.driver.stopScreenRecording(S,G,i.serial);H&&He.existsSync(H)&&(this.reporter.setVideoPath?.(`${c}-recording.mp4`),console.log(B.green(`\u2714 Screen recording saved to: output/${c}-recording.mp4`))),S=null}let $=((Date.now()-f)/1e3).toFixed(1),v=await this.reporter.generateReport(c);m&&(m.broadcastComplete(v),y&&y()),console.log(B.bold.green(`
742
+ \u2728 PromptTest Script Execution Finished in ${$}s!`));let C=v.failedSteps===0?B.bold.green:B.bold.yellow;return console.log(C(`Result: ${v.passedSteps}/${v.totalSteps} passed (${v.failedSteps} failed, ${v.skippedSteps} skipped).`)),console.log(B.cyan(`Report saved to output/${c}-report.html
743
+ `)),i.json&&console.log(JSON.stringify(v,null,2)),v}finally{if(S)try{await this.driver.stopScreenRecording(S,xe.join("output",`${c}-recording.mp4`),i.serial)}catch{}g&&lt(g)}}async getCleanHierarchy(t){let e=await this.driver.getUiHierarchy(t),{flat:s}=pe(e),i=s.find(o=>(o.text==="Dismiss"||o.contentDesc==="Dismiss")&&o.bounds.width>0);i&&(await this.driver.tap(i.bounds.centerX,i.bounds.centerY,t),await new Promise(o=>setTimeout(o,400)),e=await this.driver.getUiHierarchy(t),s=pe(e).flat);let r=s.find(o=>o.contentDesc&&(o.contentDesc.startsWith("!, ")||o.contentDesc.includes("react.dev/link")));if(r){let o=r.bounds.x2-45,a=r.bounds.centerY;await this.driver.tap(o,a,t),await new Promise(d=>setTimeout(d,350)),e=await this.driver.getUiHierarchy(t),s=pe(e).flat}let n=ge(s);return this.lastHierarchy={xml:e,flat:s,timestamp:Date.now(),hash:n},{xml:e,flat:s}}async ensureInViewport(t,e){let s=this.screenDimensions.width,i=this.screenDimensions.height,r=Math.round(s*.5),n=this.navBarHeight>0?i-this.navBarHeight:i,o=this.navBarHeight>0?n*.94:i*P.gestures.bottomNavThresholdRatio;if(t.bounds.centerY>o||t.bounds.y1>o)return!1;let d=t.bounds.y2>n,c=t.bounds.y1<Math.round(i*.04)&&t.bounds.centerY<Math.round(i*.06);return d?(await this.driver.swipe(r,Math.round(i*.75),r,Math.round(i*.45),250,e),await new Promise(l=>setTimeout(l,200)),this.lastHierarchy=null,!0):c?(await this.driver.swipe(r,Math.round(i*.35),r,Math.round(i*.65),250,e),await new Promise(l=>setTimeout(l,200)),this.lastHierarchy=null,!0):!1}async waitForTarget(t,e,s=3e3,i){if(this.lastHierarchy&&Date.now()-this.lastHierarchy.timestamp<P.polling.hierarchyCacheTtlMs){let a=this.matchNodes(this.lastHierarchy.flat,t,i);if(a.length>0)return{flat:this.lastHierarchy.flat,matched:a}}let r=Date.now();for(;Date.now()-r<s;){let{flat:a}=await this.getCleanHierarchy(e),d=this.matchNodes(a,t,i);if(d.length>0)return{flat:a,matched:d};await new Promise(c=>setTimeout(c,si()))}let{flat:n}=await this.getCleanHierarchy(e),o=this.matchNodes(n,t,i);if(o.length===0&&(this.healEnabled||P.ai.selfHealing))try{let a=await this.semanticResolver.findSuggestions(t,n,{locale:this.activeLocale}),d=P.ai.confidenceThreshold||.75,c=a.find(l=>l.score>=d);if(c){let l=c.node||n.find(h=>(ie(c.text,h.text)||ie(c.text,h.contentDesc))&&h.bounds.width>0);if(l){console.log(B.yellow(` \u{1F4A1} [Self-Healing] Auto-healed "${t}" \u2192 "${c.text}" (${Math.round(c.score*100)}% confidence, ${c.strategy})`)),i&&(i.healedFrom=t);let h=l.text?"text":l.contentDesc?"contentDesc":"resourceId",u=this.lastHierarchy?.hash,g=Math.min(P.memory?.maxHealedConfidence??.65,c.score);this.memory.recordSuccess(i?.type||"TAP",t,c.text,h,g,t,u),o=[l]}}}catch(a){Be.warn(`Self-healing resolution failed: ${a.message}`)}return{flat:n,matched:o}}buildDiagnosticError(t,e,s){return fi(t,e,s)}async executeStep(t,e,s){let i=Ci.get(t.type);if(!i)throw new Error(`No handler registered for step type: ${t.type}`);t.target&&t.target.includes("$")&&(t.target=st(t.target,Object.fromEntries(this.runtimeVariables))),t.value&&t.value.includes("$")&&(t.value=st(t.value,Object.fromEntries(this.runtimeVariables)));let r={driver:this.driver,memory:this.memory,serial:e,screenDimensions:this.screenDimensions,navBarHeight:this.navBarHeight,lastHierarchy:this.lastHierarchy,setLastHierarchy:n=>{this.lastHierarchy=n},getCleanHierarchy:n=>this.getCleanHierarchy(n),waitForTarget:(n,o,a,d)=>this.waitForTarget(n,o,a,d),matchNodes:(n,o,a)=>this.matchNodes(n,o,a),ensureInViewport:(n,o)=>this.ensureInViewport(n,o),buildDiagnosticError:(n,o,a)=>this.buildDiagnosticError(n,o,a),findTargetInputField:(n,o,a)=>this.findTargetInputField(n,o,a),upcomingSteps:s,variables:this.runtimeVariables,loopStack:this.loopStack,executeChildSteps:async(n,o)=>{for(let a=0;a<n.length;a++){let d=n[a];await this.executeStep(d,o.serial,n.slice(a+1))}}};return i.execute(t,r)}findTargetInputField(t,e,s){return bi(t,e,s,this.memory)}matchNodes(t,e,s){return jt(t,e,this.memory,this.activeLocale,s,this.lastHierarchy?.hash)}},Mt=new Ze});var Mi={};xt(Mi,{AutonomousRecorder:()=>vt,autonomousRecorder:()=>vn});import he from"fs";import de from"path";import I from"chalk";import{spawn as bn}from"child_process";import Ni from"readline";import{createRequire as yn}from"module";var Sn,Vs,vt,vn,Qt=oe(()=>{"use strict";Ae();It();je();Pe();Sn=yn(import.meta.url),Vs="1.1.0";try{Vs=Sn("../../package.json").version||"1.1.0"}catch{}vt=class{driver;deviceLock=null;isRecording=!1;recordedSteps=[];existingSteps=[];existingFileHeader=[];lastHierarchyFlat=[];lastScreenTitle="";visitedScreens=[];targetPackage=null;isAppendMode=!1;resolvedOutputPath="";resolvedReportPath="";activeInput=null;geteventProcess=null;isRefreshingHierarchy=!1;targetSerial="";touchMaxX=P.screen.fallbackWidth;touchMaxY=P.screen.fallbackHeight;displayWidth=P.screen.fallbackWidth;displayHeight=P.screen.fallbackHeight;activeTouchX=-1;activeTouchY=-1;touchDownTime=0;isTouchActive=!1;isSwipeGesture=!1;lastHierarchyTimestamp=0;lastTapTimestamp=0;lastRecordedTapTarget="";inFlightTapQueue=[];inputDebounceTimer=null;logcatEventProcess=null;logcatCrashProcess=null;hierarchyCacheTime=0;hierarchyStale=!0;lastScrollTimestamp=0;lastScrollDirection="";currentScreenName="";sessionScreenSections=[];sessionStartTime=0;screenshotDir="";screenshotCounter=0;crashDetected=!1;lastScreenTransitionTime=0;constructor(t){this.driver=t||Q}flushToDisk(){if(this.resolvedOutputPath)try{this.saveSpec(this.resolvedOutputPath)}catch{}if(this.resolvedReportPath)try{this.saveReport(this.resolvedReportPath)}catch{}}appendStep(t,e){this.recordedSteps[this.recordedSteps.length-1]!==t&&(this.recordedSteps.push(t),this.flushToDisk(),e&&console.log(e))}extractBrandSlug(t){if(!t)return"app";let e=new Set(["com","org","net","io","in","co","uk","de","fr","us","ai","dev","android","mobile","app","apps","client","release","debug","main","browser","ui","view","experience","portal","phone","tablet","service"]),s=t.split("."),i=s.filter(n=>!e.has(n.toLowerCase())&&!/^\d+$/.test(n));return((i.length>0?i[i.length-1]:s[s.length-1])||"app").toLowerCase().replace(/[^a-z0-9_]/g,"")}async startRecording(t,e,s){let i=await this.driver.ensureDefaultDevice(e);if(!i)throw new Error("No Android device connected for recording.");this.deviceLock=ct(i),this.targetSerial=i,this.isRecording=!0,this.recordedSteps=[],this.existingSteps=[],this.existingFileHeader=[],this.visitedScreens=[],this.targetPackage=null,this.activeInput=null,this.isAppendMode=!!s?.append;try{let x=await this.driver.getForegroundPackage(i);x&&(this.targetPackage=x)}catch{}let r=this.extractBrandSlug(this.targetPackage),n;if(t&&t!=="specs/recorded_suite.txt")n=de.resolve(t);else{let x=`${r}_flow`,T=de.resolve(`specs/${x}.txt`);if(!this.isAppendMode&&he.existsSync(T)){let $=1;for(T=de.resolve(`specs/${x}_${$}.txt`);he.existsSync(T);)$++,T=de.resolve(`specs/${x}_${$}.txt`)}n=T}if(this.resolvedOutputPath=n,he.existsSync(n))if(this.isAppendMode){let x=he.readFileSync(n,"utf-8"),T=x.split(`
744
+ `);for(let v of T){let C=v.trim();if(/^\d+\.\s+/.test(C))this.existingSteps.push(C.replace(/^\d+\.\s+/,""));else if(C.startsWith("# Package:")){let U=C.match(/# Package:\s*([a-zA-Z0-9._]+)/);U&&(this.targetPackage=U[1])}}let $=`${n}.bak`;he.writeFileSync($,x,"utf-8"),console.log(I.cyan(`\u{1F4E5} Loaded ${this.existingSteps.length} existing step(s) from: ${de.basename(n)}`)),console.log(I.gray(`\u{1F4E6} Safety backup preserved at: ${de.basename($)}`))}else{let x=he.readFileSync(n,"utf-8"),T=`${n}.bak`;he.writeFileSync(T,x,"utf-8"),console.log(I.yellow(`\u26A0\uFE0F File "${de.basename(n)}" already exists.`)),console.log(I.gray(`\u{1F4E6} Safety backup preserved at: ${de.basename(T)}`))}await this.driver.wakeDevice(i).catch(()=>{});let a=await this.driver.getScreenDimensions(i);this.displayWidth=a.width||P.screen.fallbackWidth,this.displayHeight=a.height||P.screen.fallbackHeight,this.touchMaxX=this.displayWidth,this.touchMaxY=this.displayHeight;try{let{stdout:x}=await this.driver.execAdb(["shell","getevent","-p"],i),T=x.match(/0035\s*:\s*value\s*\d+,\s*min\s*\d+,\s*max\s*(\d+)/),$=x.match(/0036\s*:\s*value\s*\d+,\s*min\s*\d+,\s*max\s*(\d+)/);T&&parseInt(T[1])>0&&(this.touchMaxX=parseInt(T[1])),$&&parseInt($[1])>0&&(this.touchMaxY=parseInt($[1]))}catch{}this.sessionStartTime=Date.now(),this.sessionScreenSections=[],this.screenshotCounter=0,this.crashDetected=!1,this.hierarchyStale=!0,this.currentScreenName="";let d=de.basename(n,".txt"),c=de.resolve("output");this.screenshotDir=de.join(c,"screenshots",d),he.existsSync(this.screenshotDir)||he.mkdirSync(this.screenshotDir,{recursive:!0});let l=I.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),h=await this.driver.getDeviceModel(i).catch(()=>i);console.log(`
745
+ ${l}`),console.log(I.bold.cyan(`\u26A1 PromptTest v${Vs}`)+I.gray(" | Recording Session")),console.log(l),console.log(` ${I.gray("\u{1F4F1} Device ")} ${I.white(h)} ${I.gray(`(${i})`)}`),console.log(` ${I.gray("\u{1F4E6} App ")} ${I.green(this.targetPackage||"Unknown")}`),console.log(` ${I.gray("\u{1F3AF} Spec ")} ${I.yellow(de.basename(n))}`);let u=de.join(c,`${d}_report.md`);this.resolvedReportPath=u,console.log(` ${I.gray("\u{1F4CA} Report ")} ${I.yellow(de.basename(u))}`),console.log(` ${I.gray("\u{1F4F8} Photos ")} ${I.yellow(de.relative(process.cwd(),this.screenshotDir))}`),this.isAppendMode&&this.existingSteps.length>0&&console.log(` ${I.gray("\u{1F4CE} Mode ")} ${I.magenta(`Append \u2014 resuming from step #${this.existingSteps.length+1}`)}`),console.log(l),process.stdout.write(` ${I.gray("Checking device health...")} `),console.log(I.green("\u2714 Ready")),process.stdout.write(` ${I.gray("Loading initial screen...")} `);let g=Date.now();await this.refreshHierarchySync();let m=Date.now()-g,y=this.currentScreenName?I.bold.white(this.currentScreenName):I.gray("Unknown");console.log(`${I.green("\u2714")} ${y} ${I.gray(`[${m}ms]`)}`),process.stdout.write(` ${I.gray("Starting screen watcher...")} `),this.startLogcatScreenWatcher(i),this.startLogcatCrashWatcher(i),console.log(I.green("\u2714 Streaming")),console.log(l),console.log(` ${I.gray("Use the app naturally. Every action is captured.")}`),console.log(` ${I.gray('Press Ctrl+C or type "exit" / "q" + Enter to stop and save.')}`),console.log(`${l}
746
+ `),this.flushToDisk();let S=null,b=()=>{if(this.isRecording=!1,S)try{S.close()}catch{}if(this.inputDebounceTimer&&(clearTimeout(this.inputDebounceTimer),this.inputDebounceTimer=null),this.deviceLock&&(lt(this.deviceLock),this.deviceLock=null),this.geteventProcess)try{this.geteventProcess.kill()}catch{}if(this.logcatEventProcess)try{this.logcatEventProcess.kill()}catch{}if(this.logcatCrashProcess)try{this.logcatCrashProcess.kill()}catch{}this.flushToDisk(),this.printExitSummary(l),process.exit(0)};if(process.once("SIGINT",b),process.once("SIGTERM",b),process.stdin.isTTY)try{S=Ni.createInterface({input:process.stdin,output:process.stdout}),S.on("line",x=>{let T=x.trim().toLowerCase();(T==="exit"||T==="quit"||T==="q"||T==="stop")&&b()}),S.on("SIGINT",()=>{b()})}catch{}this.startEventStream(i);let f=0;for(;this.isRecording;)if(await new Promise(x=>setTimeout(x,1500)),f++,f%20===0&&this.driver.wakeDevice(i).catch(()=>{}),!this.targetPackage){let x=await this.driver.getForegroundPackage(i).catch(()=>null);x&&(this.targetPackage=x)}}startEventStream(t){let s=bn("adb",t?["-s",t,"shell","getevent","-l"]:["shell","getevent","-l"]);this.geteventProcess=s;let i=null,r=null,n=null,o=null,a=0;Ni.createInterface({input:s.stdout}).on("line",c=>{if(this.isRecording)if(c.includes("ABS_MT_POSITION_X")){let l=c.match(/ABS_MT_POSITION_X\s+([0-9a-fA-F]+)/);l&&(i=parseInt(l[1],16))}else if(c.includes("ABS_MT_POSITION_Y")){let l=c.match(/ABS_MT_POSITION_Y\s+([0-9a-fA-F]+)/);l&&(r=parseInt(l[1],16))}else if(c.includes("BTN_TOUCH")&&c.includes("DOWN"))n=i,o=r,a=Date.now();else if(c.includes("BTN_TOUCH")&&c.includes("UP")){let l=i!==null?i:n,h=r!==null?r:o,u=Date.now()-a;if(l!==null&&h!==null&&n!==null&&o!==null){let g=Math.round(n/this.touchMaxX*this.displayWidth),m=Math.round(o/this.touchMaxY*this.displayHeight),y=Math.round(l/this.touchMaxX*this.displayWidth),S=Math.round(h/this.touchMaxY*this.displayHeight),b=y-g,f=S-m,x=Math.abs(b),T=Math.abs(f),$=Math.hypot(x,T);if(this.activeInput&&m>this.displayHeight*.58&&S>this.displayHeight*.58){u>=20&&u<400&&$<45&&y>=this.displayWidth*.78&&S>=this.displayHeight*.84?this.flushActiveInput().then(()=>{this.handleKeyPress("Enter")}).catch(()=>{}):this.scheduleInputDebounce(),i=null,r=null,n=null,o=null;return}if(u>=20&&u<400&&$<45)this.isRefreshingHierarchy?this.inFlightTapQueue.push({x:y,y:S,timestamp:Date.now()}):this.handleTapAt(y,S);else if(u>=450&&$<45)this.handleLongPressAt(y,S);else if(T>=100&&T>1.4*x){let v=f<0?"down":"up";this.handleScroll(v)}else if(x>=100&&x>1.4*T){let v=b<0?"left":"right";this.handleSwipe(v)}}i=null,r=null,n=null,o=null}else c.includes("KEY_ENTER")&&c.includes("DOWN")?this.handleKeyPress("Enter"):c.includes("KEY_BACK")&&c.includes("DOWN")&&this.handleKeyPress("Back")}),s.on("close",c=>{this.isRecording&&(console.warn(I.yellow(`
747
+ \u26A0\uFE0F [EventStream] ADB event listener stream closed (code ${c}). Auto-reconnecting in 800ms...`)),setTimeout(()=>{this.isRecording&&this.startEventStream(t)},800))}),s.on("error",c=>{this.isRecording&&console.warn(I.yellow(`
748
+ \u26A0\uFE0F [EventStream] ADB stream error: ${c.message}.`))})}cleanLabel(t){return t?t.replace(/[\uE000-\uF8FF\uFFF0-\uFFFF\uFFFD]/gu,"").replace(/,\s*tab,\s*\d+\s*of\s*\d+/gi,"").replace(/,\s*button$/gi,"").replace(/^[\s,•\-_:;|/\\]+|[\s,•\-_:;|/\\]+$/g,"").trim():""}handleScroll(t){let e=Date.now();if(this.lastScrollDirection===t&&e-this.lastScrollTimestamp<850)return;this.lastScrollTimestamp=e,this.lastScrollDirection=t,this.activeInput&&this.flushActiveInput().catch(()=>{});let s=`Scroll ${t}`;this.recordedSteps[this.recordedSteps.length-1]!==s&&(this.appendStep(s,I.blue(` \u{1F4DC} Recorded Scroll [Step #${this.getCurrentStepNumber()}]: ${I.bold(s)}`)),this.triggerAsyncHierarchyRefresh(400))}handleSwipe(t){let e=Date.now();if(e-this.lastScrollTimestamp<600)return;this.lastScrollTimestamp=e,this.activeInput&&this.flushActiveInput().catch(()=>{});let s=`Swipe ${t}`;this.appendStep(s,I.blue(` \u{1F449} Recorded Swipe [Step #${this.getCurrentStepNumber()}]: ${I.bold(s)}`)),this.triggerAsyncHierarchyRefresh(500)}handleLongPressAt(t,e){let s=this.lastHierarchyFlat.filter(n=>t>=n.bounds.x1&&t<=n.bounds.x2&&e>=n.bounds.y1&&e<=n.bounds.y2);if(s.length===0)return;s.sort((n,o)=>{let a=(n.bounds.x2-n.bounds.x1)*(n.bounds.y2-n.bounds.y1),d=(o.bounds.x2-o.bounds.x1)*(o.bounds.y2-o.bounds.y1);return a-d});let i=s[0],r=this.resolveActionLabel(i,s,this.lastHierarchyFlat);if(r){let n=`Long press '${r}'`;this.appendStep(n,I.cyan(` \u23F1\uFE0F Recorded Long Press [Step #${this.getCurrentStepNumber()}]: ${I.bold(n)}`)),this.triggerAsyncHierarchyRefresh()}}handleTapAt(t,e){let s=Date.now(),i=this.lastHierarchyFlat.filter(l=>t>=l.bounds.x1&&t<=l.bounds.x2&&e>=l.bounds.y1&&e<=l.bounds.y2),n=this.lastHierarchyFlat.filter(l=>{let h=l.bounds.height;return h>0&&h<320&&l.bounds.width>0&&(l.clickable||l.contentDesc||l.text)}).filter(l=>e>=l.bounds.y1-30&&e<=l.bounds.y2+40);if(n.length>=2){let l=n.find(h=>t>=h.bounds.x1-20&&t<=h.bounds.x2+20);l&&(i=[this.lastHierarchyFlat.find(u=>(this.cleanLabel(u.text).length>0||this.cleanLabel(u.contentDesc).length>0)&&Math.abs(u.bounds.centerX-l.bounds.centerX)<l.bounds.width*.48&&Math.abs(u.bounds.centerY-l.bounds.centerY)<l.bounds.height*.48&&!this.isIconGlyph(this.cleanLabel(u.text)))||l])}if(e>this.displayHeight*.82){let h=this.lastHierarchyFlat.filter(u=>{let g=u.bounds.y1>=this.displayHeight*.78||u.bounds.y2>=this.displayHeight*.82,m=u.bounds.width>0&&u.bounds.width<=this.displayWidth*.52;return g&&m}).find(u=>t>=u.bounds.x1-20&&t<=u.bounds.x2+20);if(h){let u=this.lastHierarchyFlat.find(g=>(this.cleanLabel(g.text).length>0||this.cleanLabel(g.contentDesc).length>0)&&t>=g.bounds.x1-25&&t<=g.bounds.x2+25&&g.bounds.y1>=this.displayHeight*.78&&!this.isIconGlyph(this.cleanLabel(g.text)));u?i=[u]:(this.cleanLabel(h.text)||this.cleanLabel(h.contentDesc))&&(i=[h])}}if(i.length===0){let l=this.lastHierarchyFlat.filter(g=>(this.cleanLabel(g.text).length>0||this.cleanLabel(g.contentDesc).length>0)&&(g.clickable||g.className.includes("Button")||g.className.includes("Text"))),h=null,u=70;for(let g of l){let m=Math.hypot(g.bounds.centerX-t,g.bounds.centerY-e);m<u&&(u=m,h=g)}if(h)i=[h];else{this.triggerAsyncHierarchyRefresh();return}}i.sort((l,h)=>{let u=(l.bounds.x2-l.bounds.x1)*(l.bounds.y2-l.bounds.y1),g=(h.bounds.x2-h.bounds.x1)*(h.bounds.y2-h.bounds.y1);return u-g});let o=i[0],a=i.find(l=>l.className.includes("EditText"))||(o.className.includes("EditText")?o:null);if(a){this.activeInput&&this.activeInput.node!==a&&this.flushActiveInput().catch(()=>{});let l=this.resolveFieldLabel(a,this.lastHierarchyFlat);this.activeInput={node:a,label:l,startText:a.text||""},this.triggerAsyncHierarchyRefresh();return}this.activeInput&&this.flushActiveInput().catch(()=>{});let d=this.resolveActionLabel(o,i,this.lastHierarchyFlat);if(!d||d.length===0){this.triggerAsyncHierarchyRefresh();return}if(!o.clickable&&!i.some(l=>l.clickable||l.className.includes("Button"))&&/^\d+%$|^\d+$/.test(d)){this.triggerAsyncHierarchyRefresh();return}if(d===this.lastRecordedTapTarget&&s-this.lastTapTimestamp<350)return;this.lastTapTimestamp=s,this.lastRecordedTapTarget=d;let c;if(o.checkable||o.className.includes("Switch")||o.className.includes("CheckBox")){let l=o.checked!==void 0?!o.checked:!0;c=`Toggle '${d}' to ${l?"on":"off"}`}else{c=`Tap '${d}'`;let l=this.lastHierarchyFlat.filter(u=>this.cleanLabel(u.text)===d||this.cleanLabel(u.contentDesc)===d),h=[];for(let u of l)h.some(m=>Math.hypot(m.bounds.centerX-u.bounds.centerX,m.bounds.centerY-u.bounds.centerY)<40)||h.push(u);if(h.length>1){let g=this.lastHierarchyFlat.filter(m=>m!==o&&Math.abs(m.bounds.centerY-o.bounds.centerY)<140&&Math.abs(m.bounds.centerX-o.bounds.centerX)<550).find(m=>{let y=this.cleanLabel(m.text)||this.cleanLabel(m.contentDesc);return y.length>2&&y!==d&&!/^\d+$/.test(y)&&!this.isIconGlyph(y)});if(g){let m=this.cleanLabel(g.text)||this.cleanLabel(g.contentDesc);m&&m!==d&&(c=`Tap '${d}' next to '${m}'`)}}}this.appendStep(c,I.cyan(` \u{1F446} Recorded Tap [Step #${this.getCurrentStepNumber()}]: ${I.bold(c)}`)),this.triggerAsyncHierarchyRefresh()}handleKeyPress(t){if(this.activeInput&&this.flushActiveInput().catch(()=>{}),t==="Enter"){let e="Press 'Enter'";this.appendStep(e,I.magenta(` \u21B5 Recorded Key [Step #${this.getCurrentStepNumber()}]: ${I.bold(e)}`))}else if(t==="Back"){let e="Tap 'Back'";this.appendStep(e,I.magenta(` \u25C0 Recorded Key [Step #${this.getCurrentStepNumber()}]: ${I.bold(e)}`))}this.triggerAsyncHierarchyRefresh()}scheduleInputDebounce(){this.inputDebounceTimer&&clearTimeout(this.inputDebounceTimer),this.inputDebounceTimer=setTimeout(()=>{this.activeInput&&this.syncActiveInputText().catch(()=>{})},450)}async flushActiveInput(){if(this.inputDebounceTimer&&(clearTimeout(this.inputDebounceTimer),this.inputDebounceTimer=null),!this.activeInput)return;let t=this.activeInput;this.activeInput=null,await this.recordInputText(t)}async syncActiveInputText(){this.activeInput&&await this.recordInputText(this.activeInput)}async recordInputText(t){try{let e=await this.driver.getUiHierarchy(this.targetSerial).catch(()=>null);if(!e)return;let{flat:s}=pe(e);this.lastHierarchyFlat=s;let i=s.find(r=>r.className.includes("EditText")&&(r.focused||r.selected))||s.find(r=>r.className.includes("EditText")&&this.resolveFieldLabel(r,s).toLowerCase()===t.label.toLowerCase())||s.find(r=>r.className.includes("EditText")&&Math.abs(r.bounds.centerX-t.node.bounds.centerX)<80)||s.find(r=>r.className.includes("EditText"));if(i&&i.text&&i.text.trim().length>0){let r=i.text.trim(),n=/^[•*•\u2022\u25cf]+$/.test(r);if(!(r===t.startText)&&!n){if(t.startText===""&&this.isPlaceholderText(r))return;let a=t.label||this.resolveFieldLabel(i,s),d=`Type '${r}' into '${a}'`,c=this.recordedSteps.length-1,l=c>=0?this.recordedSteps[c]:"";l.startsWith("Type ")&&l.endsWith(`into '${a}'`)?l!==d&&(this.recordedSteps[c]=d,this.flushToDisk(),console.log(I.gray(` \u270D\uFE0F Updated Input [Step #${c+1+this.existingSteps.length}]: ${I.bold(d)}`))):this.appendStep(d,I.green(` \u270D\uFE0F Recorded Input [Step #${this.getCurrentStepNumber()}]: ${I.bold(d)}`))}else if(n&&(i.password||t.label.toLowerCase().includes("password"))){let a=t.label||"Password",d=`Type '<password>' into '${a}'`,c=this.recordedSteps.length-1,l=c>=0?this.recordedSteps[c]:"";(!l.startsWith("Type ")||!l.endsWith(`into '${a}'`))&&this.appendStep(d,I.green(` \u270D\uFE0F Recorded Password Input [Step #${this.getCurrentStepNumber()}]: ${I.bold(d)}`))}}}catch{}}startLogcatScreenWatcher(t){try{this.logcatEventProcess=this.driver.streamLogcatEvents(t,e=>{if(this.isRecording&&(e.includes("wm_on_resume_called")||e.includes("am_on_resume_called"))){let s=Date.now();if(s-this.lastScreenTransitionTime<500)return;this.lastScreenTransitionTime=s,this.hierarchyStale=!0,this.triggerAsyncHierarchyRefresh(50)}})}catch{}}startLogcatCrashWatcher(t){try{this.logcatCrashProcess=this.driver.streamLogcatCrashes(t,e=>{if(this.isRecording&&(e.includes("FATAL EXCEPTION")||e.includes("ANR in"))){if(this.targetPackage&&!e.includes(this.targetPackage))return;this.crashDetected=!0,console.log(I.red.bold(`
749
+ \u26A0\uFE0F [Crash Alert] Fatal exception / ANR detected in ${this.targetPackage||"app"}!`))}})}catch{}}captureSessionScreenshot(t){if(!this.screenshotDir)return;let e=++this.screenshotCounter,s=t.toLowerCase().replace(/[^a-z0-9_]/g,"_").slice(0,30)||"screen",i=`screen_${String(e).padStart(2,"0")}_${s}.png`,r=de.join(this.screenshotDir,i);(async()=>{try{let n=await this.driver.captureScreenshot(this.targetSerial);if(n&&n.length>0){await he.promises.writeFile(r,n);let o=this.sessionScreenSections[this.sessionScreenSections.length-1];o&&!o.screenshotFile&&(o.screenshotFile=i)}}catch{}})()}triggerAsyncHierarchyRefresh(t=P.recorder.asyncRefreshDelayMs){this.isRefreshingHierarchy||(this.isRefreshingHierarchy=!0,setTimeout(()=>{this.doHierarchyRefresh().catch(()=>{this.isRefreshingHierarchy=!1})},t))}async doHierarchyRefresh(){try{let t=await this.driver.getUiHierarchy(this.targetSerial),{flat:e}=pe(t);this.lastHierarchyFlat=e,this.hierarchyStale=!1,this.hierarchyCacheTime=Date.now(),this.detectAndLogScreenHeader(e),this.detectAndLogTransientAlerts(e)}catch{}finally{for(this.isRefreshingHierarchy=!1;this.inFlightTapQueue.length>0;){let t=this.inFlightTapQueue.shift();if(!t)break;Date.now()-t.timestamp<P.recorder.staleTapTimeoutMs?this.handleTapAt(t.x,t.y):console.warn(I.yellow(`[Recorder] Dropped stale tap at (${t.x}, ${t.y}) \u2014 screen refresh took longer than ${P.recorder.staleTapTimeoutMs}ms`))}}}detectAndLogTransientAlerts(t){let e=t.find(s=>(s.className.includes("Toast")||s.className.includes("Snackbar")||s.resourceId&&s.resourceId.includes("snackbar")||s.contentDesc&&(s.contentDesc.includes("Alert")||s.contentDesc.includes("Success")))&&(s.text||s.contentDesc));if(e){let s=this.cleanLabel(e.text)||this.cleanLabel(e.contentDesc);if(s&&s.length>3&&s.length<80){let i=`Verify '${s}' is visible`;this.recordedSteps.slice(-3).includes(i)||this.appendStep(i,I.green(` \u2714 Recorded Alert [Step #${this.getCurrentStepNumber()}]: ${I.bold(i)}`))}}}async refreshHierarchySync(){try{let t=await this.driver.getUiHierarchy(this.targetSerial),{flat:e}=pe(t);this.lastHierarchyFlat=e,this.hierarchyStale=!1,this.hierarchyCacheTime=Date.now(),this.detectAndLogScreenHeader(e)}catch{}}isIconGlyph(t){if(!t||t.trim().length===0)return!0;let e=t.trim();return!!(/[\uE000-\uF8FF\uFFF0-\uFFFF]/.test(e)||e.length===1&&e.charCodeAt(0)>255&&!new RegExp("\\p{Extended_Pictographic}","u").test(e))}cleanDialogOrCompoundLabel(t){if(!t)return"";let e=t.trim();if(e.includes(",")||e.includes(`
750
+ `)){let s=e.split(/[\n,]+/).map(i=>this.cleanLabel(i)).filter(Boolean);if(s.length>1){let i=s.find(n=>n.includes("?")||/\b(are you sure|do you want|cannot be undone|would you like|please confirm)\b/i.test(n)||n.length>35);if(i){let n=s.find(o=>o!==i&&o.length<=30&&!o.includes("?"));if(n)return n}let r=s.filter(n=>/^[A-Z]{1,3}$/.test(n)||/^\d+%?$/.test(n)||this.isCardMetadataSubtitle(n)||/^(attend|present|absent|status|active|inactive)$/i.test(n)?!1:n.length>1);if(r.length>0)return r[0]}}return e}isCardMetadataSubtitle(t){if(!t||t.trim().length===0)return!1;let e=t.trim();return!!(/\+?\d{1,3}[\s-]?\d{4,}[\s-]?\d{4,}/.test(e)||/^(STD|ID|EMP|REF|ORD|USER|ACC|BATCH)[\-_:\s]?\d+/i.test(e)||/[•|·]/.test(e)&&/\d/.test(e)||/^\d+$/.test(e)||/^\d{1,2}:\d{2}/.test(e)||/^(teacher|roll\s*no|std\s*id|class|sec)[\s:]+/i.test(e))}findPrimaryCardTitle(t,e,s){if(t.bounds.y1>=this.displayHeight*.8||t.bounds.centerY>=this.displayHeight*.82||t.clickable&&(t.className.includes("Button")||t.className.includes("Check")))return null;let i=this.cleanLabel(t.text),r=this.isCardMetadataSubtitle(i),n=s.find(d=>d!==t&&d.clickable&&d.bounds.height>60&&d.bounds.height<600),o;n?o=e.filter(d=>d.className.includes("Text")&&d.bounds.x1>=n.bounds.x1-10&&d.bounds.x2<=n.bounds.x2+10&&d.bounds.y1>=n.bounds.y1-10&&d.bounds.y2<=n.bounds.y2+10):o=e.filter(d=>d!==t&&d.className.includes("Text")&&d.bounds.centerY<t.bounds.centerY&&t.bounds.centerY-d.bounds.centerY<160&&Math.abs(d.bounds.centerX-t.bounds.centerX)<500);let a=o.filter(d=>{let c=this.cleanLabel(d.text);return c.length>2&&!this.isCardMetadataSubtitle(c)&&!this.isIconGlyph(c)&&!/^\d+$/.test(c)&&!/^(active|inactive|present|absent|new|pending)$/i.test(c)}).sort((d,c)=>d.bounds.y1-c.bounds.y1);if(a.length>0){let d=this.cleanLabel(a[0].text);if(r||n&&d!==i&&!t.clickable)return d}return null}resolveActionLabel(t,e,s){if(t.bounds.y1>=this.displayHeight*.8||t.bounds.centerY>=this.displayHeight*.82){let d=this.cleanLabel(t.contentDesc)||this.cleanLabel(t.text);if(d&&d.length>0&&!this.isIconGlyph(d))return this.cleanDialogOrCompoundLabel(d);for(let c of e){let l=this.cleanLabel(c.contentDesc)||this.cleanLabel(c.text);if(l&&l.length>0&&!this.isIconGlyph(l))return this.cleanDialogOrCompoundLabel(l)}}let i=this.findPrimaryCardTitle(t,s,e);if(i)return this.cleanDialogOrCompoundLabel(i);let r=this.cleanLabel(t.text);if(r.length>0&&r.length<90){let d=r.split(/[\n\r]+/).map(l=>this.cleanLabel(l)).filter(Boolean),c=d.length>1?d.find(l=>l.length>2&&!/^\d+$/.test(l))||d[0]:r;return this.cleanDialogOrCompoundLabel(c)}let n=this.cleanLabel(t.contentDesc);if(n.length>0&&n.length<90)return this.cleanDialogOrCompoundLabel(n);let o=e.find(d=>(d.clickable||d.className.includes("Button"))&&(this.cleanLabel(d.text)||this.cleanLabel(d.contentDesc)));if(o){let d=this.cleanLabel(o.text)||this.cleanLabel(o.contentDesc);if(d.length>0&&d.length<90)return this.cleanDialogOrCompoundLabel(d)}for(let d of e){let c=this.cleanLabel(d.text);if(c.length>0&&c.length<90){let h=c.split(/[\n\r]+/).map(g=>this.cleanLabel(g)).filter(Boolean),u=h.length>1?h.find(g=>g.length>2&&!/^\d+$/.test(g))||h[0]:c;return this.cleanDialogOrCompoundLabel(u)}let l=this.cleanLabel(d.contentDesc);if(l.length>0&&l.length<90)return this.cleanDialogOrCompoundLabel(l)}let a=s.find(d=>d!==t&&(this.cleanLabel(d.text).length>0||this.cleanLabel(d.contentDesc).length>0)&&Math.abs(d.bounds.centerX-t.bounds.centerX)<80&&Math.abs(d.bounds.centerY-t.bounds.centerY)<100);if(a){let d=this.cleanLabel(a.text)||this.cleanLabel(a.contentDesc);if(d.length>0)return this.cleanDialogOrCompoundLabel(d)}if(t.resourceId){let d=t.resourceId.split("/"),c=d[d.length-1];if(c&&!/^\d+$/.test(c)){let l=c.replace(/_/g," ").replace(/btn|button|icon|view|action/gi,"").trim();if(l.length>1)return l.charAt(0).toUpperCase()+l.slice(1)}}return""}getCurrentStepNumber(){return this.existingSteps.length+this.recordedSteps.length+1}detectAndLogScreenHeader(t){let e=t.filter(s=>{if(!s.className.includes("TextView")||s.text.trim().length<2||s.packageName&&(s.packageName.includes("systemui")||s.packageName.includes("launcher"))||s.bounds.y1<60||s.bounds.y1>=450)return!1;let i=s.text.trim();return!(this.isCardMetadataSubtitle(i)||/\b(JIO|Airtel|Vodafone|No service|Emergency|VoLTE|4G|5G)\b/i.test(i)||/^\d+%?$|^\d+$/.test(i)||/^step\s*\d+\s*(of|\/)\s*\d+/i.test(i))}).sort((s,i)=>s.bounds.y1-i.bounds.y1);if(e.length>0){let s=e[0].text.trim();if(s&&s!==this.lastScreenTitle&&!s.includes(":")&&s.length<40){this.lastScreenTitle=s,this.currentScreenName=s,this.visitedScreens.includes(s)||this.visitedScreens.push(s),this.sessionScreenSections.push({name:s,stepStart:this.recordedSteps.length}),this.captureSessionScreenshot(s);let i=`Verify '${s}' is visible`;this.recordedSteps[this.recordedSteps.length-1]!==i&&!this.recordedSteps.slice(-3).includes(i)&&this.appendStep(i,I.green(` \u2714 Recorded Header [Step #${this.getCurrentStepNumber()}]: ${I.bold(i)}`))}}}resolveFieldLabel(t,e){if(t.contentDesc&&t.contentDesc.trim().length>0)return t.contentDesc.trim();if(t.password)return"Password";let s=e.filter(i=>i.className.includes("TextView")&&i.text&&i.text.trim().length>1&&i.bounds.centerY<t.bounds.centerY&&t.bounds.centerY-i.bounds.centerY<250&&Math.abs(i.bounds.centerX-t.bounds.centerX)<450);if(s.length>0){s.sort((r,n)=>n.bounds.centerY-r.bounds.centerY);let i=s[0].text.trim().replace(/[*:]/g,"").trim();if(i.length>0)return i}if(t.resourceId){let i=t.resourceId.split("/"),r=i[i.length-1];if(r&&!/^\d+$/.test(r)){let n=r.replace(/_/g," ").replace(/edit|text|input|field|et|txt/gi,"").trim();return n.length>1?n.charAt(0).toUpperCase()+n.slice(1):r}}if(t.text&&t.text.trim().length>0&&t.text.trim().length<40){let i=t.text.trim();if(i.toLowerCase().startsWith("search"))return i.length<=25?i:"Search";if(!this.isPlaceholderText(i))return i}return"Input Field"}isPlaceholderText(t){let e=t.trim().toLowerCase();return e.startsWith("search")||e.startsWith("e.g.")||e.startsWith("enter ")||e.startsWith("type ")||e.includes("optional")}saveSpec(t){let e=de.resolve(t);if(de.basename(e).startsWith("app_flow")&&this.targetPackage&&!this.isAppendMode){let a=this.extractBrandSlug(this.targetPackage);if(a!=="app"){let d=`${a}_flow`,c=de.resolve(`specs/${d}.txt`),l=1;for(;he.existsSync(c);)c=de.resolve(`specs/${d}_${l}.txt`),l++;e=c}}let i=de.dirname(e);he.existsSync(i)||he.mkdirSync(i,{recursive:!0});let r=[];if(this.isAppendMode&&this.existingSteps.length>0&&he.existsSync(e)){let a=he.readFileSync(e,"utf-8").trim();r.push(a),r.push(""),r.push(`# --- Appended Session (${new Date().toISOString().replace("T"," ").slice(0,19)}) ---`),this.recordedSteps.forEach((d,c)=>{r.push(`${this.existingSteps.length+c+1}. ${d}`)})}else{r.push("# ==========================================================",`# Autonomous Recorded Test Spec: ${de.basename(e)}`,...this.targetPackage?[`# Package: ${this.targetPackage}`]:[],`# Generated: ${new Date().toISOString()}`,`# PromptTest v${Vs}`,"# ==========================================================","");let a=0;this.recordedSteps.forEach((d,c)=>{if(a<this.sessionScreenSections.length&&c===this.sessionScreenSections[a].stepStart){let l=this.sessionScreenSections[a];r.push(""),r.push(`# Screen: ${l.name}`),a++}r.push(`${this.existingSteps.length+c+1}. ${d}`)})}r.push("");let n=r.join(`
751
+ `),o=`${e}.tmp.${Date.now()}`;try{he.writeFileSync(o,n,"utf-8"),he.renameSync(o,e)}catch{try{he.unlinkSync(o)}catch{}he.writeFileSync(e,n,"utf-8")}}saveReport(t){let e=Math.round((Date.now()-this.sessionStartTime)/1e3),s=Math.floor(e/60),i=e%60,r=`${String(s).padStart(2,"0")}:${String(i).padStart(2,"0")}`,n=this.existingSteps.length+this.recordedSteps.length,o=["# PromptTest Recording Report","","| Property | Value |","|---|---|",`| **Target Package** | \`${this.targetPackage||"Unknown"}\` |`,`| **Device Serial** | \`${this.targetSerial}\` |`,`| **Session Started** | ${new Date(this.sessionStartTime).toISOString()} |`,`| **Session Duration** | ${r} |`,`| **Steps in Session** | ${this.recordedSteps.length} |`,`| **Total Suite Steps** | ${n} |`,`| **Screens Visited** | ${this.visitedScreens.length} |`,`| **Screenshots Saved** | ${this.screenshotCounter} |`,`| **Crash Signals** | ${this.crashDetected?"\u26A0\uFE0F Detected":"\u2705 None"} |`,"","---","","## Screen Journey","",this.visitedScreens.length>0?this.visitedScreens.map((a,d)=>`${d+1}. **${a}**`).join(`
752
+ `):"*Single screen flow*","","---","","## Recorded Interactions",""];if(this.sessionScreenSections.length>0)for(let a=0;a<this.sessionScreenSections.length;a++){let d=this.sessionScreenSections[a],c=this.sessionScreenSections[a+1],l=c?c.stepStart:this.recordedSteps.length,h=this.recordedSteps.slice(d.stepStart,l);o.push(`### Screen: ${d.name}`),o.push(""),d.screenshotFile&&(o.push(`![${d.name}](screenshots/${de.basename(this.screenshotDir)}/${d.screenshotFile})`),o.push("")),h.length>0?h.forEach((u,g)=>{o.push(`${d.stepStart+g+1}. \`${u}\``)}):o.push("*(No interactions on this screen)*"),o.push("")}else o.push("### Steps"),o.push(""),this.recordedSteps.forEach((a,d)=>{o.push(`${d+1}. \`${a}\``)}),o.push("");try{let a=de.dirname(t);he.existsSync(a)||he.mkdirSync(a,{recursive:!0}),he.writeFileSync(t,o.join(`
753
+ `),"utf-8")}catch{}}printExitSummary(t){let e=Math.round((Date.now()-this.sessionStartTime)/1e3),s=Math.floor(e/60),i=e%60,r=`${String(s).padStart(2,"0")}:${String(i).padStart(2,"0")}`,n=this.existingSteps.length+this.recordedSteps.length;console.log(`
754
+ ${t}`),console.log(I.bold.green(" \u{1F4BE} Recording Session Saved Successfully!")),console.log(t),console.log(` ${I.gray("Steps Captured ")} ${I.bold.yellow(this.recordedSteps.length.toString())} ${this.isAppendMode?I.gray(`(Total Suite: ${n})`):""}`),console.log(` ${I.gray("Screens Visited")} ${I.bold.white(this.visitedScreens.length.toString())} ${this.visitedScreens.length>0?I.gray(`(${this.visitedScreens.join(" \u2192 ")})`):""}`),console.log(` ${I.gray("Screenshots ")} ${I.bold.white(this.screenshotCounter.toString())} saved`),console.log(` ${I.gray("Session Time ")} ${I.bold.white(r)}`),console.log(` ${I.gray("Crash Signals ")} ${this.crashDetected?I.red.bold("\u26A0\uFE0F Detected"):I.green("\u2714 0 detected")}`),console.log(t),console.log(` ${I.gray("\u{1F4C4} Spec ")} ${I.cyan(this.resolvedOutputPath)}`);let o=de.basename(this.resolvedOutputPath,".txt");console.log(` ${I.gray("\u{1F4CA} Report ")} ${I.cyan(de.resolve("output",`${o}_report.md`))}`),console.log(`${t}
755
+ `)}},vn=new vt});var Oi={};xt(Oi,{calculatePercentile:()=>Xs,formatBenchmarkTable:()=>xn,generateSyntheticHierarchy:()=>Fi,runBenchmark:()=>wn,summarizeMetrics:()=>qt});import Ce from"chalk";function Xs(p,t){if(p.length===0)return 0;let e=[...p].sort((i,r)=>i-r),s=Math.min(e.length-1,Math.max(0,Math.floor(t/100*(e.length-1))));return Math.round(e[s]*100)/100}function qt(p){if(p.length===0)return{minMs:0,maxMs:0,avgMs:0,p50Ms:0,p95Ms:0,iterations:0,durations:[]};let t=Math.round(Math.min(...p)*100)/100,e=Math.round(Math.max(...p)*100)/100,s=p.reduce((o,a)=>o+a,0),i=Math.round(s/p.length*100)/100,r=Xs(p,50),n=Xs(p,95);return{minMs:t,maxMs:e,avgMs:i,p50Ms:r,p95Ms:n,iterations:p.length,durations:p}}function Fi(p=1e3){let t=[];t.push({index:0,className:"android.widget.FrameLayout",packageName:"com.app",text:"",resourceId:"android:id/content",contentDesc:"Main Screen Root",clickable:!1,enabled:!0,focused:!1,scrollable:!1,password:!1,selected:!1,children:[],bounds:{x1:0,y1:0,x2:1080,y2:2400,width:1080,height:2400,centerX:540,centerY:1200}}),t.push({index:1,className:"android.widget.TextView",packageName:"com.app",text:"Apex Coaching Academy - Dashboard",resourceId:"com.app:id/title_header",contentDesc:"Header Title",clickable:!1,enabled:!0,focused:!1,scrollable:!1,password:!1,selected:!1,children:[],bounds:{x1:40,y1:100,x2:1040,y2:220,width:1e3,height:120,centerX:540,centerY:160}});let e=["android.widget.TextView","android.widget.Button","android.widget.EditText","android.widget.ImageView","android.view.ViewGroup","android.widget.LinearLayout","android.widget.CheckBox","android.widget.Switch"],s=["Sign In","Email Address","Password","Submit","Save Changes","Settings","Profile","Notifications","Batch 10A","Mathematics","Physics","Attendance","Export PDF","Delete Record","Cancel","Next","Back","Search","Filter","Refresh"];for(let i=2;i<p;i++){let r=e[i%e.length],n=r.includes("Button")||r.includes("CheckBox")||r.includes("Switch"),o=s[i%s.length],a=`${o} #${i}`,d=Math.min(2400,250+i*20%2e3),c=50+i*30%900;t.push({index:i,className:r,packageName:"com.app",text:r.includes("ImageView")?"":a,resourceId:`com.app:id/element_${i}`,contentDesc:r.includes("ImageView")?`Icon of ${o}`:"",clickable:n,enabled:i%25!==0,focused:!1,scrollable:!1,password:o.toLowerCase().includes("password"),selected:!1,children:[],bounds:{x1:c,y1:d,x2:c+200,y2:d+80,width:200,height:80,centerX:c+100,centerY:d+40}})}return t}async function wn(p=Q,t={}){let e=t.iterations||5,s=Date.now(),i=t.serial,r="Synthetic Mock Android Environment",n=!1;if(!t.forceMock)try{i=await p.ensureDefaultDevice(t.serial),i&&(r=await p.getDeviceModel(i),n=!0)}catch{n=!1}let o=[];for(let g=0;g<e;g++){let m=performance.now();n?await p.captureScreenshot(i):(await new Promise(y=>setTimeout(y,15)),Buffer.alloc(1024*1024)),o.push(performance.now()-m)}let a=[];for(let g=0;g<e;g++){let m=performance.now();n?await p.getUiHierarchy(i):await new Promise(y=>setTimeout(y,25)),a.push(performance.now()-m)}let d=Fi(1e3),c=new Xe,l=["Submit","Email Address","Mathematics","Save Changes","NonExistent Query Fallback"],h=[];for(let g=0;g<e;g++){let m=l[g%l.length],y=performance.now();jt(d,m,c),h.push(performance.now()-y)}let u=Date.now()-s;return{timestamp:new Date().toISOString(),device:r,package:t.packageName,screencap:qt(o),uiHierarchy:qt(a),nodeMatching:qt(h),totalDurationMs:u}}function xn(p){let t=(r,n)=>{let o=`${n.minMs.toFixed(1)}ms`.padStart(9),a=`${n.avgMs.toFixed(1)}ms`.padStart(9),d=`${n.p50Ms.toFixed(1)}ms`.padStart(9),c=`${n.p95Ms.toFixed(1)}ms`.padStart(9),l=`${n.maxMs.toFixed(1)}ms`.padStart(9);return`\u2502 ${r.padEnd(28)} \u2502 ${o} \u2502 ${a} \u2502 ${d} \u2502 ${c} \u2502 ${l} \u2502`};return["",Ce.bold.cyan("\u26A1 PromptTest Performance Diagnostic Benchmark"),Ce.gray("Device: ")+Ce.bold.white(p.device)+Ce.gray(` | Samples: ${p.screencap.iterations} runs`),"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",`\u2502 ${Ce.bold("Operation".padEnd(28))} \u2502 ${Ce.bold("Min".padStart(9))} \u2502 ${Ce.bold("Avg".padStart(9))} \u2502 ${Ce.bold("p50".padStart(9))} \u2502 ${Ce.bold("p95".padStart(9))} \u2502 ${Ce.bold("Max".padStart(9))} \u2502`,"\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524",t("Device Screencap",p.screencap),t("UI Hierarchy Dump (XML)",p.uiHierarchy),t("Node Matching (1k nodes)",p.nodeMatching),"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",Ce.gray("Total Benchmark Wall-Time: ")+Ce.bold.green(`${p.totalDurationMs}ms
756
756
  `)].join(`
757
- `)}var Gs=oe(()=>{"use strict";Ae();rt();Qe()});var Bn={};xt(Bn,{formatDoctorReport:()=>Ei,runDoctor:()=>Ti});import Zt from"fs";import _n from"path";import et from"chalk";async function Ti(p=Q,t={}){let e=[],s=process.versions.node,r=parseInt(s.split(".")[0],10)>=18;e.push({name:"Node.js Runtime",passed:r,message:`Node.js v${s} (Required >= 18.0.0)`,hint:r?void 0:"Please upgrade Node.js to v18.0.0 or higher: https://nodejs.org"});let i=!1,o="ADB binary not found in PATH",a='Install Android SDK platform-tools and ensure "adb" is in your system PATH.';try{let{stdout:b}=await p.execAdb(["version"],void 0,5e3),f=b.match(/Android Debug Bridge version ([\d.]+)/i);f?(i=!0,o=`Android Debug Bridge version ${f[1]}`,a=void 0):(i=!0,o=b.split(`
758
- `)[0].trim(),a=void 0)}catch(b){o=`Failed to execute adb: ${b.message}`}e.push({name:"Android Debug Bridge (ADB)",passed:i,message:o,hint:a});let l=!1,c="No connected Android devices or emulators found",u="Connect an Android device via USB/Wi-Fi or launch an emulator with USB Debugging enabled.";try{let b=await p.getConnectedDevices(),f=b.filter(I=>I.state==="device"),T=b.filter(I=>I.state==="unauthorized"),P=b.filter(I=>I.state==="offline");if(f.length>0){l=!0;let I=f.map(v=>`${v.serial} (${v.model||"Unknown"})`).join(", ");c=`Found ${f.length} authorized device(s): ${I}`,u=void 0}else T.length>0?(c=`Device(s) found but unauthorized: ${T.map(I=>I.serial).join(", ")}`,u='Check the device screen and accept the "Allow USB debugging" RSA prompt.'):P.length>0&&(c=`Device(s) found in offline state: ${P.map(I=>I.serial).join(", ")}`,u='Try running "adb reconnect" or reconnect the USB cable.')}catch(b){c=`Failed to list devices: ${b.message}`}if(e.push({name:"Connected Android Device",passed:l,message:c,hint:u}),t.packageName){let b=t.packageName,f=!1,T=`Package "${b}" not found on target device`,P='Install the APK using "adb install <path.apk>" or check the package identifier.';if(l)try{let{stdout:I}=await p.execAdb(["shell","pm","list","packages",b],t.serial,5e3);I.includes(`package:${b}`)&&(f=!0,T=`Package "${b}" is installed on target device`,P=void 0)}catch(I){T=`Failed to query package status: ${I.message}`}else T="Skipped package verification (no authorized device available)",P=`Connect a device to verify package "${b}".`;e.push({name:`Target Package [${b}]`,passed:f,message:T,hint:P})}let h=!0,d="All required workspace directories are accessible",g,m=["output","memory",".prompttest"];for(let b of m)try{let f=_n.resolve(process.cwd(),b);Zt.existsSync(f)||Zt.mkdirSync(f,{recursive:!0});let T=_n.join(f,".doctor_perm_test");Zt.writeFileSync(T,"ok","utf-8"),Zt.unlinkSync(T)}catch(f){h=!1,d=`Filesystem permission error for "./${b}": ${f.message}`,g="Ensure the current user has write permissions to the workspace directory.";break}e.push({name:"Workspace Storage & Permissions",passed:h,message:d,hint:g});let y=e.filter(b=>b.passed).length,S=e.filter(b=>!b.passed).length;return{timestamp:new Date().toISOString(),allPassed:S===0,checks:e,summary:{passed:y,failed:S,warnings:0}}}function Ei(p){let t=["",et.bold.cyan("\u{1FA7A} PromptTest Doctor \u2014 Environment Health Diagnostic"),et.gray(`Scanned at ${p.timestamp}
759
- `)];for(let e of p.checks){let s=e.passed?et.green("\u2714"):et.red("\u2716"),n=et.bold(e.name);t.push(` ${s} ${n}: ${e.message}`),e.hint&&!e.passed&&t.push(et.yellow(` \u{1F4A1} Fix: ${e.hint}`))}return t.push(""),p.allPassed?t.push(et.bold.green("\u2728 All diagnostic checks passed! Your environment is ready to test.")):t.push(et.bold.red(`\u26A0\uFE0F ${p.summary.failed} diagnostic check(s) failed. Please review the remediation hints above.`)),t.push(""),t.join(`
760
- `)}var Ks=oe(()=>{"use strict";Ae()});var Un={};xt(Un,{startRepl:()=>Ai});import Pi from"readline";import wt from"fs";import Hn from"path";import te from"chalk";async function Ai(p=Q,t,e={}){let s=await p.ensureDefaultDevice(e.serial),n=t||new Ze(p),r={history:[],successfulSteps:[]},i=e.input||process.stdin,o=e.output||process.stdout,a=Pi.createInterface({input:i,output:o,prompt:te.bold.cyan("prompttest> ")}),l=!1,c=()=>{if(!l)try{a.prompt()}catch{}},u=h=>{o.write(h+`
761
- `)};return u(te.bold.cyan(`
762
- \u26A1 PromptTest Interactive Live REPL / Playground (v1.1.0)`)),u(te.gray("Device: ")+te.bold.white(s||"No device connected (offline mock)")+(e.packageName?te.gray(" | Package: ")+te.bold.white(e.packageName):"")),u(te.gray(`Type natural language instructions (e.g. Tap 'Sign In'), or REPL commands: "inspect", "screenshot", "history", "save <file.txt>", "exit".
763
- `)),new Promise(h=>{c(),a.on("line",async d=>{let g=d.trim();if(!g){c();return}r.history.push(g);let m=g.toLowerCase();if(m==="exit"||m==="quit"||m===":q"){l=!0,u(te.yellow("Exiting PromptTest REPL.")),a.close();return}if(m==="help"||m==="?"){u(te.bold.white(`
764
- \u{1F4D6} PromptTest REPL Commands:`)),u(` \u2022 ${te.cyan("Tap '...'")} / ${te.cyan("Type '...' into '...'")} : Execute action live on device`),u(` \u2022 ${te.cyan("Verify '...' is visible")} : Assert element visibility`),u(` \u2022 ${te.cyan("inspect")} / ${te.cyan("tree")} : List interactive elements and input fields on screen`),u(` \u2022 ${te.cyan("screenshot [path]")} : Capture current screen to image file`),u(` \u2022 ${te.cyan("history")} : Show executed commands in current session`),u(` \u2022 ${te.cyan("save <file.txt>")} : Save successful steps into a reusable spec file`),u(` \u2022 ${te.cyan("clear")} : Clear session history`),u(` \u2022 ${te.cyan("exit")} : Quit the REPL
765
- `),c();return}if(m==="history"){u(te.bold.white(`
766
- \u{1F4DC} Session History (${r.history.length} commands):`)),r.history.forEach((y,S)=>{u(` ${S+1}. ${y}`)}),u(""),c();return}if(m==="clear"){r.successfulSteps=[],r.history=[],u(te.green("Session history cleared.")),c();return}if(m.startsWith("save")){let S=g.split(/\s+/)[1]||"output/repl_spec.txt";try{let b=Hn.dirname(S);b&&!wt.existsSync(b)&&wt.mkdirSync(b,{recursive:!0});let f=r.successfulSteps.map((T,P)=>`${P+1}. ${T}`).join(`
767
- `);wt.writeFileSync(S,f,"utf-8"),u(te.bold.green(`\u2714 Saved ${r.successfulSteps.length} step(s) to ${S}`))}catch(b){let f=b;u(te.red(`Failed to save spec: ${f.message}`))}c();return}if(m.startsWith("screenshot")){let S=g.split(/\s+/)[1]||`output/repl_screenshot_${Date.now()}.png`;try{let b=Hn.dirname(S);b&&!wt.existsSync(b)&&wt.mkdirSync(b,{recursive:!0});let f=await p.captureScreenshot(s);wt.writeFileSync(S,f),u(te.bold.green(`\u2714 Screenshot saved to ${S}`))}catch(b){let f=b;u(te.red(`Failed to capture screenshot: ${f.message}`))}c();return}if(m==="inspect"||m==="tree"){try{u(te.gray("Dumping UI hierarchy..."));let y=await p.getUiHierarchy(s),{flat:S}=pe(y),b=S.filter(f=>f.clickable||f.className.includes("Button")||f.className.includes("EditText"));u(te.bold.white(`
768
- \u{1F50D} Visible Interactive Elements (${b.length} found):`)),b.slice(0,25).forEach((f,T)=>{let P=f.text||f.contentDesc||f.resourceId||`<Unnamed ${f.className}>`,I=f.className.split(".").pop()||f.className;u(` [${T+1}] (${I}) "${P}" at (${f.bounds.centerX}, ${f.bounds.centerY})`)}),b.length>25&&u(te.gray(` ... and ${b.length-25} more elements.`)),u("")}catch(y){let S=y;u(te.red(`Failed to inspect hierarchy: ${S.message}`))}c();return}try{let y=Ut(g);if(y.length===0){u(te.yellow(`Could not parse natural language step: "${g}"`)),c();return}let S=y[0],b=performance.now();await n.executeStep(S,s);let f=Math.round(performance.now()-b);r.successfulSteps.push(g),u(te.green(`\u2714 [${S.type}] Completed in ${f}ms: `)+te.white(S.originalText))}catch(y){let S=y;u(te.red(`\u2716 Step failed: ${S.message}`))}c()}),a.on("close",()=>{l=!0,h(r)})})}var zs=oe(()=>{"use strict";Ae();Ft();rt();je()});var jn={};xt(jn,{calculateReleaseConfidence:()=>Qs,generateAggregatedHtml:()=>Di,mergeReports:()=>ki});import Ot from"fs";import Js from"path";function Qs(p){let t=p.totalSteps||0,e=p.passedSteps||0,s=p.failedSteps||0,n=p.skippedSteps||0,r=p.errorsDetected?p.errorsDetected.length:0;if(t===0)return{score:0,grade:"F",verdict:"RELEASE_BLOCKER",rationale:"No test steps were executed.",metrics:{passRate:0,criticalFailures:0,visualDefects:0,totalSteps:0,skippedSteps:0}};let i=e/t,o=Math.min(30,r*10),a=s>0?35+Math.min(25,s*5):0,l=Math.round(i*80+20-o-a);l=Math.max(0,Math.min(100,l));let c="F",u="RELEASE_BLOCKER",h="";return l>=90?(c="A",u="READY_FOR_RELEASE",h="High quality gate confidence. All critical assertion paths verified."):l>=80?(c="B",u="READY_FOR_RELEASE",h="Acceptable release confidence. Minor non-critical or optional warnings observed."):l>=70?(c="C",u="PROCEED_WITH_CAUTION",h="Elevated risk. Visual QA warnings or multiple non-critical step failures detected."):(c="F",u="RELEASE_BLOCKER",h=`Critical test failures (${s}) or visual defects (${r}) block safe release.`),{score:l,grade:c,verdict:u,rationale:h,metrics:{passRate:Math.round(i*100)/100,criticalFailures:s,visualDefects:r,totalSteps:t,skippedSteps:n}}}function ki(p="output"){let t=[],e=d=>{if(!Ot.existsSync(d))return;let g=Ot.readdirSync(d,{withFileTypes:!0});for(let m of g){let y=Js.join(d,m.name);m.isDirectory()?e(y):m.isFile()&&(m.name.endsWith("-results.json")||m.name.endsWith("-report.json"))&&t.push(y)}};if(Array.isArray(p))for(let d of p)Ot.existsSync(d)&&(Ot.statSync(d).isDirectory()?e(d):t.push(d));else e(p);let s=[],n=new Set,r=0,i=0,o=0,a=0,l=[];for(let d of t)try{let g=Ot.readFileSync(d,"utf-8"),m=JSON.parse(g),y=Qs(m),S=m.deviceId||"unknown-device";n.add(S),r+=m.totalSteps||0,i+=m.passedSteps||0,o+=m.failedSteps||0,a+=m.skippedSteps||0,m.errorsDetected&&l.push(...m.errorsDetected),s.push({deviceId:S,suiteName:Js.basename(d,Js.extname(d)).replace(/-results|-report/,""),packageName:m.packageName||"unknown",totalSteps:m.totalSteps||0,passedSteps:m.passedSteps||0,failedSteps:m.failedSteps||0,skippedSteps:m.skippedSteps||0,durationSeconds:m.durationSeconds||0,confidenceScore:y.score,confidenceGrade:y.grade,sourceFile:d})}catch{}let c=r>0?Math.round(i/r*100)/100:0,u={packageName:s[0]?.packageName||"Enterprise Matrix",deviceId:`${n.size} devices`,startTime:new Date().toISOString(),endTime:new Date().toISOString(),durationSeconds:s.reduce((d,g)=>d+g.durationSeconds,0),totalSteps:r,passedSteps:i,failedSteps:o,skippedSteps:a,warnSteps:0,errorsDetected:l,steps:[]},h=Qs(u);return{timestamp:new Date().toISOString(),totalRuns:s.length,uniqueDevices:Array.from(n),totalSteps:r,passedSteps:i,failedSteps:o,skippedSteps:a,overallPassRate:c,overallConfidence:h,deviceSummaries:s}}function Di(p){let t=p.overallConfidence,e=t.grade==="A"?"#10B981":t.grade==="B"?"#3B82F6":t.grade==="C"?"#F59E0B":"#EF4444",s=p.deviceSummaries.map(n=>{let r=n.confidenceGrade==="A"?"#10B981":n.confidenceGrade==="B"?"#3B82F6":n.confidenceGrade==="C"?"#F59E0B":"#EF4444";return`
757
+ `)}var Gs=oe(()=>{"use strict";Ae();rt();Qe()});var Bi={};xt(Bi,{formatDoctorReport:()=>En,runDoctor:()=>Tn});import Zt from"fs";import _i from"path";import et from"chalk";async function Tn(p=Q,t={}){let e=[],s=process.versions.node,r=parseInt(s.split(".")[0],10)>=18;e.push({name:"Node.js Runtime",passed:r,message:`Node.js v${s} (Required >= 18.0.0)`,hint:r?void 0:"Please upgrade Node.js to v18.0.0 or higher: https://nodejs.org"});let n=!1,o="ADB binary not found in PATH",a='Install Android SDK platform-tools and ensure "adb" is in your system PATH.';try{let{stdout:b}=await p.execAdb(["version"],void 0,5e3),f=b.match(/Android Debug Bridge version ([\d.]+)/i);f?(n=!0,o=`Android Debug Bridge version ${f[1]}`,a=void 0):(n=!0,o=b.split(`
758
+ `)[0].trim(),a=void 0)}catch(b){o=`Failed to execute adb: ${b.message}`}e.push({name:"Android Debug Bridge (ADB)",passed:n,message:o,hint:a});let d=!1,c="No connected Android devices or emulators found",l="Connect an Android device via USB/Wi-Fi or launch an emulator with USB Debugging enabled.";try{let b=await p.getConnectedDevices(),f=b.filter($=>$.state==="device"),x=b.filter($=>$.state==="unauthorized"),T=b.filter($=>$.state==="offline");if(f.length>0){d=!0;let $=f.map(v=>`${v.serial} (${v.model||"Unknown"})`).join(", ");c=`Found ${f.length} authorized device(s): ${$}`,l=void 0}else x.length>0?(c=`Device(s) found but unauthorized: ${x.map($=>$.serial).join(", ")}`,l='Check the device screen and accept the "Allow USB debugging" RSA prompt.'):T.length>0&&(c=`Device(s) found in offline state: ${T.map($=>$.serial).join(", ")}`,l='Try running "adb reconnect" or reconnect the USB cable.')}catch(b){c=`Failed to list devices: ${b.message}`}if(e.push({name:"Connected Android Device",passed:d,message:c,hint:l}),t.packageName){let b=t.packageName,f=!1,x=`Package "${b}" not found on target device`,T='Install the APK using "adb install <path.apk>" or check the package identifier.';if(d)try{let{stdout:$}=await p.execAdb(["shell","pm","list","packages",b],t.serial,5e3);$.includes(`package:${b}`)&&(f=!0,x=`Package "${b}" is installed on target device`,T=void 0)}catch($){x=`Failed to query package status: ${$.message}`}else x="Skipped package verification (no authorized device available)",T=`Connect a device to verify package "${b}".`;e.push({name:`Target Package [${b}]`,passed:f,message:x,hint:T})}let h=!0,u="All required workspace directories are accessible",g,m=["output","memory",".prompttest"];for(let b of m)try{let f=_i.resolve(process.cwd(),b);Zt.existsSync(f)||Zt.mkdirSync(f,{recursive:!0});let x=_i.join(f,".doctor_perm_test");Zt.writeFileSync(x,"ok","utf-8"),Zt.unlinkSync(x)}catch(f){h=!1,u=`Filesystem permission error for "./${b}": ${f.message}`,g="Ensure the current user has write permissions to the workspace directory.";break}e.push({name:"Workspace Storage & Permissions",passed:h,message:u,hint:g});let y=e.filter(b=>b.passed).length,S=e.filter(b=>!b.passed).length;return{timestamp:new Date().toISOString(),allPassed:S===0,checks:e,summary:{passed:y,failed:S,warnings:0}}}function En(p){let t=["",et.bold.cyan("\u{1FA7A} PromptTest Doctor \u2014 Environment Health Diagnostic"),et.gray(`Scanned at ${p.timestamp}
759
+ `)];for(let e of p.checks){let s=e.passed?et.green("\u2714"):et.red("\u2716"),i=et.bold(e.name);t.push(` ${s} ${i}: ${e.message}`),e.hint&&!e.passed&&t.push(et.yellow(` \u{1F4A1} Fix: ${e.hint}`))}return t.push(""),p.allPassed?t.push(et.bold.green("\u2728 All diagnostic checks passed! Your environment is ready to test.")):t.push(et.bold.red(`\u26A0\uFE0F ${p.summary.failed} diagnostic check(s) failed. Please review the remediation hints above.`)),t.push(""),t.join(`
760
+ `)}var Ks=oe(()=>{"use strict";Ae()});var Ui={};xt(Ui,{startRepl:()=>An});import Pn from"readline";import wt from"fs";import Hi from"path";import te from"chalk";async function An(p=Q,t,e={}){let s=await p.ensureDefaultDevice(e.serial),i=t||new Ze(p),r={history:[],successfulSteps:[]},n=e.input||process.stdin,o=e.output||process.stdout,a=Pn.createInterface({input:n,output:o,prompt:te.bold.cyan("prompttest> ")}),d=!1,c=()=>{if(!d)try{a.prompt()}catch{}},l=h=>{o.write(h+`
761
+ `)};return l(te.bold.cyan(`
762
+ \u26A1 PromptTest Interactive Live REPL / Playground (v1.1.0)`)),l(te.gray("Device: ")+te.bold.white(s||"No device connected (offline mock)")+(e.packageName?te.gray(" | Package: ")+te.bold.white(e.packageName):"")),l(te.gray(`Type natural language instructions (e.g. Tap 'Sign In'), or REPL commands: "inspect", "screenshot", "history", "save <file.txt>", "exit".
763
+ `)),new Promise(h=>{c(),a.on("line",async u=>{let g=u.trim();if(!g){c();return}r.history.push(g);let m=g.toLowerCase();if(m==="exit"||m==="quit"||m===":q"){d=!0,l(te.yellow("Exiting PromptTest REPL.")),a.close();return}if(m==="help"||m==="?"){l(te.bold.white(`
764
+ \u{1F4D6} PromptTest REPL Commands:`)),l(` \u2022 ${te.cyan("Tap '...'")} / ${te.cyan("Type '...' into '...'")} : Execute action live on device`),l(` \u2022 ${te.cyan("Verify '...' is visible")} : Assert element visibility`),l(` \u2022 ${te.cyan("inspect")} / ${te.cyan("tree")} : List interactive elements and input fields on screen`),l(` \u2022 ${te.cyan("screenshot [path]")} : Capture current screen to image file`),l(` \u2022 ${te.cyan("history")} : Show executed commands in current session`),l(` \u2022 ${te.cyan("save <file.txt>")} : Save successful steps into a reusable spec file`),l(` \u2022 ${te.cyan("clear")} : Clear session history`),l(` \u2022 ${te.cyan("exit")} : Quit the REPL
765
+ `),c();return}if(m==="history"){l(te.bold.white(`
766
+ \u{1F4DC} Session History (${r.history.length} commands):`)),r.history.forEach((y,S)=>{l(` ${S+1}. ${y}`)}),l(""),c();return}if(m==="clear"){r.successfulSteps=[],r.history=[],l(te.green("Session history cleared.")),c();return}if(m.startsWith("save")){let S=g.split(/\s+/)[1]||"output/repl_spec.txt";try{let b=Hi.dirname(S);b&&!wt.existsSync(b)&&wt.mkdirSync(b,{recursive:!0});let f=r.successfulSteps.map((x,T)=>`${T+1}. ${x}`).join(`
767
+ `);wt.writeFileSync(S,f,"utf-8"),l(te.bold.green(`\u2714 Saved ${r.successfulSteps.length} step(s) to ${S}`))}catch(b){let f=b;l(te.red(`Failed to save spec: ${f.message}`))}c();return}if(m.startsWith("screenshot")){let S=g.split(/\s+/)[1]||`output/repl_screenshot_${Date.now()}.png`;try{let b=Hi.dirname(S);b&&!wt.existsSync(b)&&wt.mkdirSync(b,{recursive:!0});let f=await p.captureScreenshot(s);wt.writeFileSync(S,f),l(te.bold.green(`\u2714 Screenshot saved to ${S}`))}catch(b){let f=b;l(te.red(`Failed to capture screenshot: ${f.message}`))}c();return}if(m==="inspect"||m==="tree"){try{l(te.gray("Dumping UI hierarchy..."));let y=await p.getUiHierarchy(s),{flat:S}=pe(y),b=S.filter(f=>f.clickable||f.className.includes("Button")||f.className.includes("EditText"));l(te.bold.white(`
768
+ \u{1F50D} Visible Interactive Elements (${b.length} found):`)),b.slice(0,25).forEach((f,x)=>{let T=f.text||f.contentDesc||f.resourceId||`<Unnamed ${f.className}>`,$=f.className.split(".").pop()||f.className;l(` [${x+1}] (${$}) "${T}" at (${f.bounds.centerX}, ${f.bounds.centerY})`)}),b.length>25&&l(te.gray(` ... and ${b.length-25} more elements.`)),l("")}catch(y){let S=y;l(te.red(`Failed to inspect hierarchy: ${S.message}`))}c();return}try{let y=Ut(g);if(y.length===0){l(te.yellow(`Could not parse natural language step: "${g}"`)),c();return}let S=y[0],b=performance.now();await i.executeStep(S,s);let f=Math.round(performance.now()-b);r.successfulSteps.push(g),l(te.green(`\u2714 [${S.type}] Completed in ${f}ms: `)+te.white(S.originalText))}catch(y){let S=y;l(te.red(`\u2716 Step failed: ${S.message}`))}c()}),a.on("close",()=>{d=!0,h(r)})})}var zs=oe(()=>{"use strict";Ae();Ft();rt();je()});var ji={};xt(ji,{calculateReleaseConfidence:()=>Qs,generateAggregatedHtml:()=>Dn,mergeReports:()=>kn});import Ot from"fs";import Js from"path";function Qs(p){let t=p.totalSteps||0,e=p.passedSteps||0,s=p.failedSteps||0,i=p.skippedSteps||0,r=p.errorsDetected?p.errorsDetected.length:0;if(t===0)return{score:0,grade:"F",verdict:"RELEASE_BLOCKER",rationale:"No test steps were executed.",metrics:{passRate:0,criticalFailures:0,visualDefects:0,totalSteps:0,skippedSteps:0}};let n=e/t,o=Math.min(30,r*10),a=s>0?35+Math.min(25,s*5):0,d=Math.round(n*80+20-o-a);d=Math.max(0,Math.min(100,d));let c="F",l="RELEASE_BLOCKER",h="";return d>=90?(c="A",l="READY_FOR_RELEASE",h="High quality gate confidence. All critical assertion paths verified."):d>=80?(c="B",l="READY_FOR_RELEASE",h="Acceptable release confidence. Minor non-critical or optional warnings observed."):d>=70?(c="C",l="PROCEED_WITH_CAUTION",h="Elevated risk. Visual QA warnings or multiple non-critical step failures detected."):(c="F",l="RELEASE_BLOCKER",h=`Critical test failures (${s}) or visual defects (${r}) block safe release.`),{score:d,grade:c,verdict:l,rationale:h,metrics:{passRate:Math.round(n*100)/100,criticalFailures:s,visualDefects:r,totalSteps:t,skippedSteps:i}}}function kn(p="output"){let t=[],e=u=>{if(!Ot.existsSync(u))return;let g=Ot.readdirSync(u,{withFileTypes:!0});for(let m of g){let y=Js.join(u,m.name);m.isDirectory()?e(y):m.isFile()&&(m.name.endsWith("-results.json")||m.name.endsWith("-report.json"))&&t.push(y)}};if(Array.isArray(p))for(let u of p)Ot.existsSync(u)&&(Ot.statSync(u).isDirectory()?e(u):t.push(u));else e(p);let s=[],i=new Set,r=0,n=0,o=0,a=0,d=[];for(let u of t)try{let g=Ot.readFileSync(u,"utf-8"),m=JSON.parse(g),y=Qs(m),S=m.deviceId||"unknown-device";i.add(S),r+=m.totalSteps||0,n+=m.passedSteps||0,o+=m.failedSteps||0,a+=m.skippedSteps||0,m.errorsDetected&&d.push(...m.errorsDetected),s.push({deviceId:S,suiteName:Js.basename(u,Js.extname(u)).replace(/-results|-report/,""),packageName:m.packageName||"unknown",totalSteps:m.totalSteps||0,passedSteps:m.passedSteps||0,failedSteps:m.failedSteps||0,skippedSteps:m.skippedSteps||0,durationSeconds:m.durationSeconds||0,confidenceScore:y.score,confidenceGrade:y.grade,sourceFile:u})}catch{}let c=r>0?Math.round(n/r*100)/100:0,l={packageName:s[0]?.packageName||"Enterprise Matrix",deviceId:`${i.size} devices`,startTime:new Date().toISOString(),endTime:new Date().toISOString(),durationSeconds:s.reduce((u,g)=>u+g.durationSeconds,0),totalSteps:r,passedSteps:n,failedSteps:o,skippedSteps:a,warnSteps:0,errorsDetected:d,steps:[]},h=Qs(l);return{timestamp:new Date().toISOString(),totalRuns:s.length,uniqueDevices:Array.from(i),totalSteps:r,passedSteps:n,failedSteps:o,skippedSteps:a,overallPassRate:c,overallConfidence:h,deviceSummaries:s}}function Dn(p){let t=p.overallConfidence,e=t.grade==="A"?"#10B981":t.grade==="B"?"#3B82F6":t.grade==="C"?"#F59E0B":"#EF4444",s=p.deviceSummaries.map(i=>{let r=i.confidenceGrade==="A"?"#10B981":i.confidenceGrade==="B"?"#3B82F6":i.confidenceGrade==="C"?"#F59E0B":"#EF4444";return`
769
769
  <tr style="border-bottom: 1px solid #334155;">
770
- <td style="padding: 12px; font-weight: bold; color: #F8FAFC;">${n.deviceId}</td>
771
- <td style="padding: 12px; color: #94A3B8;">${n.suiteName}</td>
772
- <td style="padding: 12px; color: #94A3B8;">${n.packageName}</td>
773
- <td style="padding: 12px; text-align: center; color: #F8FAFC;">${n.totalSteps}</td>
774
- <td style="padding: 12px; text-align: center; color: #10B981; font-weight: bold;">${n.passedSteps}</td>
775
- <td style="padding: 12px; text-align: center; color: #EF4444; font-weight: bold;">${n.failedSteps}</td>
776
- <td style="padding: 12px; text-align: center; color: #64748B;">${n.skippedSteps}</td>
770
+ <td style="padding: 12px; font-weight: bold; color: #F8FAFC;">${i.deviceId}</td>
771
+ <td style="padding: 12px; color: #94A3B8;">${i.suiteName}</td>
772
+ <td style="padding: 12px; color: #94A3B8;">${i.packageName}</td>
773
+ <td style="padding: 12px; text-align: center; color: #F8FAFC;">${i.totalSteps}</td>
774
+ <td style="padding: 12px; text-align: center; color: #10B981; font-weight: bold;">${i.passedSteps}</td>
775
+ <td style="padding: 12px; text-align: center; color: #EF4444; font-weight: bold;">${i.failedSteps}</td>
776
+ <td style="padding: 12px; text-align: center; color: #64748B;">${i.skippedSteps}</td>
777
777
  <td style="padding: 12px; text-align: center;">
778
778
  <span style="background: ${r}22; color: ${r}; border: 1px solid ${r}; padding: 4px 10px; border-radius: 9999px; font-weight: bold; font-size: 12px;">
779
- Grade ${n.confidenceGrade} (${n.confidenceScore}%)
779
+ Grade ${i.confidenceGrade} (${i.confidenceScore}%)
780
780
  </span>
781
781
  </td>
782
782
  </tr>`}).join("");return`<!DOCTYPE html>
@@ -835,31 +835,31 @@ ${t}`),console.log(C.bold.green(" \u{1F4BE} Recording Session Saved Successful
835
835
  </table>
836
836
  </div>
837
837
  </body>
838
- </html>`}var qs=oe(()=>{"use strict"});Ae();import ye from"fs";import Te from"path";import k from"chalk";Ae();je();Pe();rt();import D from"chalk";Ae();je();Oe();Pe();import xn from"fs";import oi from"path";var ot=class{testData={};dataPath;isLoaded=!1;driver;constructor(t,e){this.dataPath=t||oi.resolve(process.cwd(),"test-data.json"),this.driver=e||Q}setTestData(t){this.testData=t,this.isLoaded=!0}async ensureDataLoaded(){if(!this.isLoaded){if(xn.existsSync(this.dataPath))try{let t=await xn.promises.readFile(this.dataPath,"utf-8");this.testData=JSON.parse(t)}catch{this.testData={}}this.isLoaded=!0}}async loadTestData(t){return t&&(this.dataPath=t),this.isLoaded=!1,await this.ensureDataLoaded(),this.testData}inferValueForNode(t,e){let s=[t.text,t.contentDesc,t.resourceId].join(" ").toLowerCase(),n="",r=e.filter(o=>o.text&&!o.clickable&&o.bounds.centerY<t.bounds.centerY&&t.bounds.centerY-o.bounds.centerY<250&&Math.abs(o.bounds.centerX-t.bounds.centerX)<400);r.length>0&&(n=r[r.length-1].text.toLowerCase());let i=`${s} ${n}`.toLowerCase();if(i.includes("review")||i.includes("feedback")||i.includes("comment")||i.includes("write a review")||i.includes("experience")){if(!this.testData.review?.text)throw new Error("Missing test-data.json field: review.text");return this.testData.review.text}if(i.includes("card")||i.includes("credit")||i.includes("debit")||i.includes("card number")){let o=this.testData.payment?.card;if(o)return String(o);let a="4532";for(let l=0;l<12;l++)a+=Math.floor(Math.random()*10);return a}if(i.includes("phone")||i.includes("mobile")||!i.includes("card")&&i.includes("number")||i.includes("contact")){let o=this.testData.auth?.phone||this.testData.profile?.phone;if(!o)throw new Error("Missing test-data.json field: auth.phone or profile.phone");return o}if(i.includes("email")||i.includes("e-mail")||i.includes("mail")){let o=this.testData.profile?.email||this.testData.auth?.email;if(!o)throw new Error("Missing test-data.json field: profile.email or auth.email");return o}if(i.includes("cvv")||i.includes("cvc")||i.includes("security code"))return"123";if(i.includes("expiry")||i.includes("exp date")||i.includes("expiration"))return"12/28";if(i.includes("pincode")||i.includes("zip")||i.includes("postal")){if(!this.testData.profile?.pincode)throw new Error("Missing test-data.json field: profile.pincode");return this.testData.profile.pincode}if(t.password||i.includes("password")||/\bpin\b/.test(i)&&!i.includes("pincode")||i.includes("passcode")){if(!this.testData.auth?.password)throw new Error("Missing test-data.json field: auth.password");return this.testData.auth.password}if(i.includes("otp")||i.includes("verification")||i.includes("code")&&!i.includes("postal")&&!i.includes("zip")){if(!this.testData.auth?.otp)throw new Error("Missing test-data.json field: auth.otp");return this.testData.auth.otp}if(i.includes("address")||i.includes("street")||i.includes("location")){if(!this.testData.profile?.address)throw new Error("Missing test-data.json field: profile.address");return this.testData.profile.address}if(i.includes("city")||i.includes("state")){if(!this.testData.profile?.city)throw new Error("Missing test-data.json field: profile.city");return this.testData.profile.city}if(i.includes("name")||i.includes("full name")||i.includes("first name")){if(!this.testData.profile?.name)throw new Error("Missing test-data.json field: profile.name");return this.testData.profile.name}if(i.includes("search")||i.includes("find")||i.includes("query")){if(!this.testData.search?.query)throw new Error("Missing test-data.json field: search.query");return this.testData.search.query}return this.testData.review?.text||"PromptTest Auto QA Test Data"}async fillAndSubmitForm(t,e,s=!0,n=!1){await this.ensureDataLoaded();let r=_e(t),i=[];if(r.length===0)return{filledFields:[],submitted:!1};let o=!1;for(let c of r){let u=c.resourceId||c.text||`input_${c.bounds.centerX}_${c.bounds.centerY}`,h=(c.text||"").trim(),d=!h||/^enter\s+/i.test(h)||/^type\s+/i.test(h)||/^e\.g\./i.test(h)||/^(email|email address|password|phone|name|search)$/i.test(h);if(!n&&!d){i.push({fieldId:u,fieldLabel:c.text||c.contentDesc||c.resourceId,valueEntered:h});continue}let g=this.inferValueForNode(c,t);await this.driver.tap(c.bounds.centerX,c.bounds.centerY,e),await new Promise(m=>setTimeout(m,400)),await this.driver.clearField(e,g.length+10),await new Promise(m=>setTimeout(m,200)),await this.driver.inputText(g,e),await new Promise(m=>setTimeout(m,300)),o=!0,i.push({fieldId:u,fieldLabel:c.text||c.contentDesc||c.resourceId,valueEntered:g})}o&&(await this.driver.pressKey(4,e),await new Promise(c=>setTimeout(c,500)));let a=!1,l;if(s){let c=t.filter(u=>!u.clickable||u.bounds.width===0?!1:an.some(h=>ne(h,u.text)||ne(h,u.contentDesc)||ne(h,u.resourceId)));if(c.length>0){let u=["submit","sign in","signin","login","save","confirm","proceed","continue"];c.sort((d,g)=>{let m=(d.text||d.contentDesc||d.resourceId||"").toLowerCase(),y=(g.text||g.contentDesc||g.resourceId||"").toLowerCase(),S=u.findIndex(P=>m.includes(P)),b=u.findIndex(P=>y.includes(P)),f=S>=0?S:99,T=b>=0?b:99;return f!==T?f-T:g.bounds.centerY-d.bounds.centerY});let h=c[0];l=h.text||h.contentDesc||h.resourceId,await this.driver.tap(h.bounds.centerX,h.bounds.centerY,e),await new Promise(d=>setTimeout(d,E.settle.submitWaitMs));try{let d=await this.driver.getUiHierarchy(e),{flat:g}=pe(d),m=_e(g);a=!(m.length>0&&r.every(S=>m.some(b=>b.resourceId&&b.resourceId===S.resourceId)))}catch{a=!0}}}return{filledFields:i,submitted:a,submitButtonText:l}}},Tn=new ot;Je();Qe();It();je();rt();Ae();Je();Qe();import K from"chalk";var Vt=class{driver;reporter;memory;formFiller;screenLedger=new Map;callStack=[];executedStepCount=0;visitedScreenHashes=new Set;devDefectsList=[];safetyHitList=[];externalSkippedList=[];constructor(t=Q,e=bt,s=ve){this.driver=t,this.reporter=e,this.memory=s,this.formFiller=new ot(void 0,t)}async getCleanUiHierarchy(t,e,s=5){let n=await this.driver.getUiHierarchy(e),{flat:r}=pe(n),i=0;for(;i<s;){let o=$t(r);if(!o)break;i++;let a=`[${(o.severity||"error").toUpperCase()} - ${o.type.toUpperCase()}]`,l=o.sourceLocation?` [${o.sourceLocation}]`:"";console.log(K.red(` \u{1F6A8} Global Dev Console Intercepted: ${a} "${o.errorText.slice(0,80)}"${l}`)),this.devDefectsList.push(o.sourceLocation?`${o.errorText} (${o.sourceLocation})`:o.errorText);let c=await this.driver.captureScreenshot(e);this.reporter.logStep("Dev Overlay Triage",`Intercepted and triaged ${a}: "${o.errorText}"${l}`,"Verify","FAIL",o.errorText,c,{errors:[o.sourceLocation?`${o.errorText} at ${o.sourceLocation}`:o.errorText]}),o.dismissButton&&o.dismissButton.bounds.width>0?(console.log(K.gray(" Dismissing overlay via dismiss button...")),await this.driver.tap(o.dismissButton.bounds.centerX,o.dismissButton.bounds.centerY,e)):o.isToast&&o.node&&o.node.bounds.width>0?(console.log(K.gray(" Expanding toast notification to access Dismiss button...")),await this.driver.tap(o.node.bounds.centerX,o.node.bounds.centerY,e)):(console.log(K.gray(" Pressing Back to dismiss overlay...")),await this.driver.pressBack(e)),await new Promise(u=>setTimeout(u,800)),n=await this.driver.getUiHierarchy(e),r=pe(n).flat}return{xml:n,flat:r}}async dismissSoftKeyboard(t){try{await this.driver.pressKey(111,t),await new Promise(e=>setTimeout(e,150))}catch{}}async packageJailGuard(t,e){let s=await this.driver.getForegroundPackage(e);if(!s||!s.includes(t)){console.log(K.yellow(` \u{1F6A8} External App Jailbreak Detected [${s||"Unknown"}]. Recovering...`)),await this.driver.pressBack(e),await new Promise(r=>setTimeout(r,800));let n=await this.driver.getForegroundPackage(e);return(!n||!n.includes(t))&&(console.log(K.red(` Force restoring ${t} foreground...`)),await this.driver.launchApp(t,e),await new Promise(r=>setTimeout(r,1500)),this.callStack=this.callStack.slice(0,1)),!0}return!1}async handleExternalMediaChooser(t,e){let s=await this.driver.getForegroundPackage(e);if(s==="android"||s?.includes("resolver")||s?.includes("intentresolver")||s&&!s.includes(t)){console.log(K.yellow(` \u{1F6E1}\uFE0F External Media Chooser / Third-Party App Intercepted [${s||"Unknown"}]. Dismissing to stay in-app...`)),await this.driver.pressBack(e),await new Promise(i=>setTimeout(i,800));let r=await this.driver.getForegroundPackage(e);return(!r||!r.includes(t))&&(await this.driver.launchApp(t,e),await new Promise(i=>setTimeout(i,1200)),this.callStack=this.callStack.slice(0,1)),!0}return!1}catalogScreen(t,e,s=[]){let n=[],r=e.height,i=r*.06,o=r*.88,a=f=>s.some(T=>Math.abs(T.bounds.centerX-f.bounds.centerX)<30&&Math.abs(T.bounds.centerY-f.bounds.centerY)<30),l=_e(t);for(let f of l){if(a(f))continue;let T=f.text||f.contentDesc||f.resourceId||"Text Input";n.push({node:f,type:"input",label:T,tested:!1})}let c=mt(t);for(let f of c){if(a(f))continue;let T=f.text||f.contentDesc||f.resourceId||"Toggle Control";n.push({node:f,type:"toggle",label:T,tested:!1})}let u=Ue(t);for(let f of u){if(a(f)||Ke([f],r,e.width)||De([f],r,e.width,!0))continue;let T=f.text||f.contentDesc||f.resourceId||"Action Button";if(Re(f)){this.externalSkippedList.push(T);continue}let P=f.selected!==void 0||f.checkable||/(?:tab|chip|pill|filter|segment|toggle)/i.test(`${f.resourceId} ${f.className} ${f.contentDesc}`)||/(?:today|yesterday|all|active|archived|pending|completed|present|absent)/i.test(T);n.push({node:f,type:P?"toggle":"transition",label:T,tested:!1})}let h=un(t,r,e.width);for(let f of h){if(a(f)||De([f],r,e.width,!0)||n.some(P=>Math.abs(P.node.bounds.centerX-f.bounds.centerX)<25&&Math.abs(P.node.bounds.centerY-f.bounds.centerY)<25))continue;let T=f.text||f.contentDesc||f.resourceId||"Notification / Header Action";if(Re(f)){this.externalSkippedList.push(T);continue}n.push({node:f,type:"transition",label:T,tested:!1})}let d=t.filter(f=>{if(!f.clickable||f.bounds.width===0)return!1;let T=`${f.text} ${f.contentDesc} ${f.resourceId}`.toLowerCase();return T.includes("now playing")||T.includes("play")||T.includes("pause")});for(let f of d){if(a(f)||n.some(P=>Math.abs(P.node.bounds.centerX-f.bounds.centerX)<25&&Math.abs(P.node.bounds.centerY-f.bounds.centerY)<25))continue;let T=f.text||f.contentDesc||f.resourceId||"Media Control";n.push({node:f,type:"toggle",label:T,tested:!1})}let g=it(t,e).filter(f=>!a(f)&&f.bounds.centerY>i&&f.bounds.centerY<o&&!De([f],r,e.width,!0)&&!Re(f)),m=gn(g,2);for(let f of m){let T=f.text||f.contentDesc||f.resourceId||`Item (${f.bounds.centerX},${f.bounds.centerY})`;n.push({node:f,type:"transition",label:T,tested:!1})}let y=0,S=0,b=[];for(let f of n){let T=/\.(?:mp4|mkv|mov|webm|flv|avi)\b/i.test(f.label),P=/\.(?:mp3|wav|m4a|aac|ogg)\b/i.test(f.label);if(T){if(y++,y>1)continue}else if(P&&(S++,S>1))continue;b.push(f)}return b}async safeBacktrack(t,e,s,n,r=!0){let{flat:i}=await this.getCleanUiHierarchy(e,s),{height:o,width:a}=await this.driver.getScreenDimensions(s),l=We(i,{width:a,height:o});if(l===t)return!0;let c=De(i,o,a,!0);if(c&&c.bounds.width>0){console.log(K.gray(` [Backtrack] Tapping in-app back/close button "${c.text||c.contentDesc||c.className}"...`)),await this.driver.tap(c.bounds.centerX,c.bounds.centerY,s),await new Promise(d=>setTimeout(d,1e3)),await this.packageJailGuard(e,s);let u=await this.getCleanUiHierarchy(e,s),h=We(u.flat,{width:a,height:o});if(h===t||h!==l)return!0}if(n&&n.bounds.width>0){console.log(K.gray(` [Backtrack] Restoring root domain via tab "${n.text||n.contentDesc||"Root Tab"}"...`)),await this.driver.tap(n.bounds.centerX,n.bounds.centerY,s),await new Promise(d=>setTimeout(d,1e3)),await this.packageJailGuard(e,s);let u=await this.getCleanUiHierarchy(e,s),h=We(u.flat,{width:a,height:o});if(h===t||h!==l)return!0}if(r){if(console.log(K.gray(" [Backtrack] Sending fallback KEYCODE_BACK...")),await this.driver.pressKey(4,s),await new Promise(g=>setTimeout(g,1e3)),await this.packageJailGuard(e,s))return console.log(K.yellow(" \u26A0\uFE0F Backtrack via KEYCODE_BACK caused app jailbreak. Aborting branch restoration.")),!1;let h=await this.getCleanUiHierarchy(e,s),d=We(h.flat,{width:a,height:o});if(d===t||d!==l)return!0}return!1}async explore(t){let{packageName:e,serial:s,maxScreens:n=30,maxDepth:r=3,stepBudget:i=100,maxInteractionsPerScreen:o=6,safetyMode:a="strict",safetyBlacklist:l=[]}=t;console.log(K.bold.cyan(`
839
- \u{1F916} PromptTest Universal State-Graph DFS Engine`)),console.log(K.gray(`Target Package: ${e}`)),console.log(K.gray(`Safety Policy: ${a.toUpperCase()}`)),console.log(K.gray(`Limits: Max Screens = ${n}, Step Budget = ${i}, Max Depth = ${r}`)),await this.driver.clearCrashLogs(s);let c=await this.driver.getScreenDimensions(s),u=await this.driver.getForegroundPackage(s);(!u||!u.includes(e))&&(console.log(K.gray(`Launching ${e}...`)),await this.driver.launchApp(e,s),await new Promise(S=>setTimeout(S,2500)));let{flat:h}=await this.getCleanUiHierarchy(e,s);await this.dismissSoftKeyboard(s);let d=ns(h,c,e);console.log(K.magenta(`\u26A1 Universal Paradigm Detected: [${d.paradigm.toUpperCase()}] with ${d.roots.length} root node(s).`));let g=[],m;if(d.paradigm==="drawer"&&d.roots.length>0){m=d.roots[0];let S={...h[0]||{},text:"Home Screen / Main Hub",contentDesc:"Home Screen / Main Hub",clickable:!0,bounds:{x1:0,y1:0,x2:c.width,y2:c.height,centerX:c.width/2,centerY:c.height/2,width:c.width,height:c.height}};g.push(S),console.log(K.gray(" Opening drawer to catalog root destinations...")),await this.driver.tap(m.bounds.centerX,m.bounds.centerY,s),await new Promise(v=>setTimeout(v,1200));let b=await this.getCleanUiHierarchy(e,s),f=b.flat.filter(v=>{if(!v.clickable||v.bounds.width===0||v.bounds.height===0||v.bounds.width>=c.width*.95&&v.bounds.height>=c.height*.95||De([v],c.height,c.width,!0))return!1;let $=`${v.contentDesc} ${v.text}`.trim(),j=v.bounds.width>c.width*.15&&v.bounds.height>c.height*.05;return $.toLowerCase().includes("developed by")||v.bounds.centerY>c.height*.85?!1:$.length>=2||j});for(let v of f)g.some($=>Math.abs($.bounds.centerX-v.bounds.centerX)<30&&Math.abs($.bounds.centerY-v.bounds.centerY)<30)||g.push(v);let T=De(b.flat,c.height,c.width,!0);T?await this.driver.tap(T.bounds.centerX,T.bounds.centerY,s):await this.driver.tap(m.bounds.centerX,m.bounds.centerY,s),await new Promise(v=>setTimeout(v,1200));let P=await this.getCleanUiHierarchy(e,s);if(P.flat.some(v=>`${v.contentDesc} ${v.text}`.includes("Gallery")&&`${v.contentDesc} ${v.text}`.includes("Planner"))){let v=De(P.flat,c.height,c.width,!0);v?await this.driver.tap(v.bounds.centerX,v.bounds.centerY,s):await this.driver.tap(c.width-50,c.height/2,s),await new Promise($=>setTimeout($,1e3))}console.log(K.magenta(` Discovered ${g.length} destinations (1 Main Hub + ${g.length-1} Drawer destinations).`))}else d.roots.length>0?g=d.roots:g=[h[0]||{text:"Main Hub",clickable:!0}];let y=1;for(let S of g){if(this.executedStepCount>=i||this.visitedScreenHashes.size>=n)break;let b=S.text||S.contentDesc||`Root #${y}`;if(console.log(K.yellow(`
840
- [Domain ${y}/${g.length}] Entering Root Tree: "${b}"...`)),d.paradigm==="bottom_tabs"||d.paradigm==="top_tabs"){let P=S.bounds.height<25?Math.max(S.bounds.y1-10,S.bounds.centerY):Math.min(S.bounds.centerY,S.bounds.y2-4);await this.driver.tap(S.bounds.centerX,P,s),this.executedStepCount++,await new Promise(I=>setTimeout(I,1200))}else d.paradigm==="drawer"&&y>1&&m&&(await this.dismissSoftKeyboard(s),console.log(K.gray(` Opening drawer to select "${b}"...`)),await this.driver.tap(m.bounds.centerX,m.bounds.centerY,s),await new Promise(P=>setTimeout(P,1e3)),await this.driver.tap(S.bounds.centerX,S.bounds.centerY,s),this.executedStepCount++,await new Promise(P=>setTimeout(P,1500)));h=(await this.getCleanUiHierarchy(e,s)).flat,await this.dismissSoftKeyboard(s);let T=y===1?Math.max(25,Math.ceil(i*.45)):Math.max(8,Math.ceil(i*.55/Math.max(1,g.length-1)));if(await this.exploreDfsNode({packageName:e,serial:s,screenDims:c,rootNodes:d.roots,activeRootNode:S,currentDepth:0,maxDepth:r,maxScreens:n,stepBudget:i,domainStepLimit:this.executedStepCount+T,maxInteractionsPerScreen:o,safetyMode:a,safetyBlacklist:l,domainLabel:b}),d.paradigm==="drawer"&&y>1){let P=0;for(;P<4;){let I=await this.getCleanUiHierarchy(e,s),v=Ke(I.flat,c.height,c.width),$=I.flat.some(G=>`${G.contentDesc} ${G.text}`.includes("Gallery")&&`${G.contentDesc} ${G.text}`.includes("Planner"));if(v&&!$)break;let j=De(I.flat,c.height,c.width,!0);if(j)console.log(K.gray(" [Domain Wrap-Up] Returning to Home Screen via in-app back...")),await this.driver.tap(j.bounds.centerX,j.bounds.centerY,s),await new Promise(G=>setTimeout(G,1e3)),P++;else break}}if(y===1&&g.length===1){let P=await this.getCleanUiHierarchy(e,s),I=ns(P.flat,c,e);if((I.paradigm==="bottom_tabs"||I.paradigm==="top_tabs")&&I.roots.length>1){console.log(K.magenta(`
841
- \u26A1 Post-Auth Navigation Discovered: [${I.paradigm.toUpperCase()}] with ${I.roots.length} root domain(s)!`)),d.paradigm=I.paradigm,d.roots=I.roots;let v=I.roots.slice(1);g.push(...v.length>0?v:I.roots)}}y++}for(let S of this.visitedScreenHashes)this.memory.markScreenCrawled(S);await this.memory.save(),console.log(K.green(`
842
- \u2714 Universal DFS Traversal Complete!`)),console.log(K.cyan(` Visited Screens: ${this.visitedScreenHashes.size}`)),console.log(K.cyan(` Total Steps Executed: ${this.executedStepCount}/${i}`)),console.log(K.cyan(` Defects Triaged: ${this.devDefectsList.length}`))}async exploreDfsNode(t){let{packageName:e,serial:s,screenDims:n,rootNodes:r,activeRootNode:i,currentDepth:o,maxDepth:a,maxScreens:l,stepBudget:c,domainStepLimit:u,maxInteractionsPerScreen:h,safetyMode:d,safetyBlacklist:g,domainLabel:m}=t;if(this.executedStepCount>=c||this.visitedScreenHashes.size>=l||u&&this.executedStepCount>=u)return;let{flat:y}=await this.getCleanUiHierarchy(e,s),S=ge(y),b=We(y,n);this.visitedScreenHashes.add(S);let f=this.screenLedger.get(b);if(f){if(f.status==="FULLY_EXPLORED"){console.log(K.gray(` \u26A1 Cycle Detected: Screen [${b.slice(0,8)}] already fully explored. Pruning branch.`));return}}else{let v=this.catalogScreen(y,n,r);f={hash:S,semanticHash:b,title:`${m} (depth ${o})`,elements:v,status:"IN_PROGRESS",depth:o,interactionCount:0},this.screenLedger.set(b,f),console.log(K.cyan(` \u{1F50E} Discovered Screen [${b.slice(0,8)}] at depth ${o} with ${v.length} candidate element(s).`))}this.callStack.push({screenHash:S,semanticHash:b,title:f.title,timestamp:Date.now()});let T=f.elements.filter(v=>v.type==="input"&&!v.tested);if(T.length>0&&f.interactionCount<h){console.log(K.magenta(` Filling in-place form fields (${T.length} inputs)...`));let v=await this.formFiller.fillAndSubmitForm(y,s,!0,!1);this.executedStepCount++,f.interactionCount++;for(let $ of T)$.tested=!0;await this.dismissSoftKeyboard(s),await this.packageJailGuard(e,s),this.reporter.logStep("In-Place Form Fill",`Populated ${v.filledFields.length} field(s) on [${b.slice(0,8)}]`,"FormSubmit","PASS",v.submitButtonText||"Auto")}let P=f.elements.filter(v=>v.type==="toggle"&&!v.tested);for(let v of P){if(this.executedStepCount>=c||f.interactionCount>=h)break;if(v.tested=!0,Ie(v.node,g,d)){this.safetyHitList.push(v.label);continue}console.log(K.gray(` Exercising toggle: "${v.label.slice(0,30)}"...`)),this.executedStepCount++,f.interactionCount++,await this.driver.tap(v.node.bounds.centerX,v.node.bounds.centerY,s),await new Promise($=>setTimeout($,600)),this.reporter.logStep("In-Place Toggle",`Toggled control "${v.label}"`,"Tap","PASS",v.label)}let I=f.elements.filter(v=>v.type==="transition"&&!v.tested);for(let v of I){if(this.executedStepCount>=c||this.visitedScreenHashes.size>=l||u&&this.executedStepCount>=u&&!(o===0&&m.includes("Home Screen"))||f.interactionCount>=h)break;if(v.tested=!0,Re(v.node)){this.externalSkippedList.push(v.label);continue}if(Ie(v.node,g,d)){this.safetyHitList.push(v.label);continue}console.log(K.magenta(` \u26A1 [DFS Depth ${o}] Testing transition: "${v.label.slice(0,40)}"...`)),this.executedStepCount++,f.interactionCount++,await this.driver.tap(v.node.bounds.centerX,v.node.bounds.centerY,s),await new Promise(H=>setTimeout(H,1500)),await this.dismissSoftKeyboard(s),await this.handleExternalMediaChooser(e,s),await this.packageJailGuard(e,s);let $=await this.getCleanUiHierarchy(e,s),G=We($.flat,n)!==b;if(this.reporter.logStep("DFS Transition",`Tapped "${v.label}" [${G?"Navigated":"In-Place"}]`,"Tap","PASS",v.label),G){if(o<a){let J=o===0&&m.includes("Home Screen")?Math.min(this.executedStepCount+3,u||this.executedStepCount+3):u;await this.exploreDfsNode({packageName:e,serial:s,screenDims:n,rootNodes:r,activeRootNode:i,domainStepLimit:J,currentDepth:o+1,maxDepth:a,maxScreens:l,stepBudget:c,maxInteractionsPerScreen:h,safetyMode:d,safetyBlacklist:g,domainLabel:`${m} > ${v.label.slice(0,20)}`})}console.log(K.gray(` [DFS Backtrack] Returning to [${b.slice(0,8)}]...`)),await this.safeBacktrack(b,e,s,o===0?i:void 0,o>0),await this.dismissSoftKeyboard(s);let H=await this.getCleanUiHierarchy(e,s);if(We(H.flat,n)!==b){let J=De(H.flat,n.height,n.width,!0);J&&(console.log(K.gray(" [Backtrack Verification] Re-tapping in-app back/close button...")),await this.driver.tap(J.bounds.centerX,J.bounds.centerY,s),await new Promise(me=>setTimeout(me,1e3)),await this.packageJailGuard(e,s));let re=await this.getCleanUiHierarchy(e,s);if(We(re.flat,n)!==b){console.log(K.yellow(` \u26A0\uFE0F Unable to restore parent screen [${b.slice(0,8)}]. Unwinding branch to prevent jailbreak loop.`));break}}}}f.status="FULLY_EXPLORED",this.callStack.pop()}};var Rt=class{driver;formFiller;reporter;memory;safetyHitList=[];externalSkippedList=[];devDefectsList=[];visitedScreenHashes=new Set;executedStepCount=0;constructor(t,e,s,n){this.driver=t||Q,this.formFiller=e||Tn,this.reporter=s||bt,this.memory=n||ve}getMemory(){return this.memory}getSafetyHitList(){return this.safetyHitList}getExternalSkippedList(){return this.externalSkippedList}getDevDefectsList(){return this.devDefectsList}getVisitedScreensCount(){return this.visitedScreenHashes.size}async packageJailGuard(t,e){let s=await this.driver.getForegroundPackage(e);if(s&&!s.includes(t)){console.log(D.yellow(` \u{1F6E1}\uFE0F Jail Containment: App escaped to "${s}". Executing containment recovery...`)),await this.driver.pressBack(e),await new Promise(r=>setTimeout(r,600));let n=await this.driver.getForegroundPackage(e);return(!n||!n.includes(t))&&(console.log(D.gray(` Force re-launching ${t} to restore foreground...`)),await this.driver.launchApp(t,e),await new Promise(r=>setTimeout(r,1200))),this.reporter.logStep("Jail Containment",`App escaped to "${s}"; successfully contained and restored "${t}"`,"Back","PASS"),!0}return!1}async getCleanUiHierarchy(t,e,s=5){let n=await this.driver.getUiHierarchy(e),{flat:r}=pe(n),i=0;for(;i<s;){let o=$t(r);if(!o)break;i++;let a=`[${(o.severity||"error").toUpperCase()} - ${o.type.toUpperCase()}]`,l=o.sourceLocation?` [${o.sourceLocation}]`:"";console.log(D.red(` \u{1F6A8} Global Dev Console Intercepted: ${a} "${o.errorText.slice(0,80)}"${l}`)),this.devDefectsList.push(o.sourceLocation?`${o.errorText} (${o.sourceLocation})`:o.errorText);let c=await this.driver.captureScreenshot(e);this.reporter.logStep("Dev Overlay Triage",`Intercepted and triaged ${a}: "${o.errorText}"${l}`,"Verify","FAIL",o.errorText,c,{errors:[o.sourceLocation?`${o.errorText} at ${o.sourceLocation}`:o.errorText]}),o.dismissButton&&o.dismissButton.bounds.width>0?(console.log(D.gray(" Dismissing overlay via dismiss button...")),await this.driver.tap(o.dismissButton.bounds.centerX,o.dismissButton.bounds.centerY,e)):o.isToast&&o.node&&o.node.bounds.width>0?(console.log(D.gray(" Expanding toast notification to access Dismiss button...")),await this.driver.tap(o.node.bounds.centerX,o.node.bounds.centerY,e)):(console.log(D.gray(" Pressing Back to dismiss overlay...")),await this.driver.pressBack(e)),await new Promise(u=>setTimeout(u,800)),n=await this.driver.getUiHierarchy(e),r=pe(n).flat}return{xml:n,flat:r}}async handleDevOverlays(t,e,s){let n=$t(t);if(!n)return!1;let r=`[${(n.severity||"error").toUpperCase()} - ${n.type.toUpperCase()}]`,i=n.sourceLocation?` [${n.sourceLocation}]`:"";console.log(D.red(` \u{1F6A8} Dev Overlay Detected: ${r} "${n.errorText.slice(0,80)}"${i}`)),this.devDefectsList.push(n.sourceLocation?`${n.errorText} (${n.sourceLocation})`:n.errorText);let o=await this.driver.captureScreenshot(s);return this.reporter.logStep("Dev Overlay Triage",`Detected and triaged ${r} error: "${n.errorText}"${i}`,"Verify","FAIL",n.errorText,o,{errors:[n.sourceLocation?`${n.errorText} (${n.sourceLocation})`:n.errorText]}),n.dismissButton&&n.dismissButton.bounds.width>0?(console.log(D.gray(" Dismissing error overlay via dismiss button...")),await this.driver.tap(n.dismissButton.bounds.centerX,n.dismissButton.bounds.centerY,s)):n.isToast&&n.node&&n.node.bounds.width>0?(console.log(D.gray(" Expanding toast notification to access Dismiss button...")),await this.driver.tap(n.node.bounds.centerX,n.node.bounds.centerY,s)):(console.log(D.gray(" Pressing Back to dismiss error overlay...")),await this.driver.pressBack(s)),await new Promise(a=>setTimeout(a,800)),!0}async dismissSoftKeyboard(t){try{await this.driver.pressKey(111,t),await new Promise(e=>setTimeout(e,200))}catch{}}async explore(t){let{packageName:e,serial:s,maxTabs:n=E.explorer?.maxTabs||15,exploreLists:r=!0,skipAlreadyCrawled:i=!1,safetyMode:o=E.safety?.mode||"strict",safetyBlacklist:a=E.safety?.customBlacklist?[...E.safety.customBlacklist]:[],maxScreens:l=E.explorer?.maxScreens||30,stepBudget:c=E.explorer?.stepBudget||100,screenshots:u=E.explorer?.screenshots||"state-change"}=t;console.log(D.cyan(`
843
- \u{1F916} PromptTest Autonomous Exploration Brain v3`)),console.log(D.gray("Target Package: ")+D.bold.white(e)),console.log(D.gray("Safety Policy: ")+D.bold.yellow(o.toUpperCase())+(a.length>0?D.gray(` (+${a.length} custom blacklist)`):"")),console.log(D.gray("Screenshots Policy: ")+D.bold.white(u));let h=async(y,S=!0)=>{if(!(u==="failure-only"&&y!=="FAIL")&&!(u==="state-change"&&!S&&y!=="FAIL"))try{return await this.driver.captureScreenshot(s)}catch{return}};await this.memory.init(e);let d=s||this.driver.getDefaultDevice(),g=d||"Default Device";this.reporter.init(e,g);let m=null;d&&(m=ct(d)),this.safetyHitList=[],this.externalSkippedList=[],this.devDefectsList=[],this.visitedScreenHashes.clear(),this.executedStepCount=0;try{if(await this.driver.clearCrashLogs(s),(t.strategy||E.explorer?.strategy||"heuristic")==="dfs"){let se=new Vt(this.driver,this.reporter,this.memory);await se.explore({packageName:e,serial:s,maxScreens:l,maxDepth:t.maxDepth||E.explorer?.maxDepth||5,stepBudget:c,safetyMode:o,safetyBlacklist:a,screenshotPolicy:u,skipAlreadyCrawled:i}),this.safetyHitList=se.safetyHitList,this.externalSkippedList=se.externalSkippedList,this.devDefectsList=se.devDefectsList,this.visitedScreenHashes=se.visitedScreenHashes,this.executedStepCount=se.executedStepCount;let X=this.memory.getStats();this.reporter.logStep("Coverage Audit",`State Graph Coverage: Visited ${this.visitedScreenHashes.size} unique screen state(s). Memory Engine cached ${X.totalScreens} crawled screen(s).`,"Verify","PASS"),await this.reporter.generateReport(),console.log(D.bold.green(`
838
+ </html>`}var qs=oe(()=>{"use strict"});Ae();import ye from"fs";import Te from"path";import k from"chalk";Ae();je();Pe();rt();import D from"chalk";Ae();je();Oe();Pe();import wi from"fs";import an from"path";var ot=class{testData={};dataPath;isLoaded=!1;driver;constructor(t,e){this.dataPath=t||an.resolve(process.cwd(),"test-data.json"),this.driver=e||Q}setTestData(t){this.testData=t,this.isLoaded=!0}async ensureDataLoaded(){if(!this.isLoaded){if(wi.existsSync(this.dataPath))try{let t=await wi.promises.readFile(this.dataPath,"utf-8");this.testData=JSON.parse(t)}catch{this.testData={}}this.isLoaded=!0}}async loadTestData(t){return t&&(this.dataPath=t),this.isLoaded=!1,await this.ensureDataLoaded(),this.testData}inferValueForNode(t,e){let s=[t.text,t.contentDesc,t.resourceId].join(" ").toLowerCase(),i="",r=e.filter(o=>o.text&&!o.clickable&&o.bounds.centerY<t.bounds.centerY&&t.bounds.centerY-o.bounds.centerY<250&&Math.abs(o.bounds.centerX-t.bounds.centerX)<400);r.length>0&&(i=r[r.length-1].text.toLowerCase());let n=`${s} ${i}`.toLowerCase();if(n.includes("review")||n.includes("feedback")||n.includes("comment")||n.includes("write a review")||n.includes("experience")){if(!this.testData.review?.text)throw new Error("Missing test-data.json field: review.text");return this.testData.review.text}if(n.includes("card")||n.includes("credit")||n.includes("debit")||n.includes("card number")){let o=this.testData.payment?.card;if(o)return String(o);let a="4532";for(let d=0;d<12;d++)a+=Math.floor(Math.random()*10);return a}if(n.includes("phone")||n.includes("mobile")||!n.includes("card")&&n.includes("number")||n.includes("contact")){let o=this.testData.auth?.phone||this.testData.profile?.phone;if(!o)throw new Error("Missing test-data.json field: auth.phone or profile.phone");return o}if(n.includes("email")||n.includes("e-mail")||n.includes("mail")){let o=this.testData.profile?.email||this.testData.auth?.email;if(!o)throw new Error("Missing test-data.json field: profile.email or auth.email");return o}if(n.includes("cvv")||n.includes("cvc")||n.includes("security code"))return"123";if(n.includes("expiry")||n.includes("exp date")||n.includes("expiration"))return"12/28";if(n.includes("pincode")||n.includes("zip")||n.includes("postal")){if(!this.testData.profile?.pincode)throw new Error("Missing test-data.json field: profile.pincode");return this.testData.profile.pincode}if(t.password||n.includes("password")||/\bpin\b/.test(n)&&!n.includes("pincode")||n.includes("passcode")){if(!this.testData.auth?.password)throw new Error("Missing test-data.json field: auth.password");return this.testData.auth.password}if(n.includes("otp")||n.includes("verification")||n.includes("code")&&!n.includes("postal")&&!n.includes("zip")){if(!this.testData.auth?.otp)throw new Error("Missing test-data.json field: auth.otp");return this.testData.auth.otp}if(n.includes("address")||n.includes("street")||n.includes("location")){if(!this.testData.profile?.address)throw new Error("Missing test-data.json field: profile.address");return this.testData.profile.address}if(n.includes("city")||n.includes("state")){if(!this.testData.profile?.city)throw new Error("Missing test-data.json field: profile.city");return this.testData.profile.city}if(n.includes("name")||n.includes("full name")||n.includes("first name")){if(!this.testData.profile?.name)throw new Error("Missing test-data.json field: profile.name");return this.testData.profile.name}if(n.includes("search")||n.includes("find")||n.includes("query")){if(!this.testData.search?.query)throw new Error("Missing test-data.json field: search.query");return this.testData.search.query}return this.testData.review?.text||"PromptTest Auto QA Test Data"}async fillAndSubmitForm(t,e,s=!0,i=!1){await this.ensureDataLoaded();let r=_e(t),n=[];if(r.length===0)return{filledFields:[],submitted:!1};let o=!1;for(let c of r){let l=c.resourceId||c.text||`input_${c.bounds.centerX}_${c.bounds.centerY}`,h=(c.text||"").trim(),u=!h||/^enter\s+/i.test(h)||/^type\s+/i.test(h)||/^e\.g\./i.test(h)||/^(email|email address|password|phone|name|search)$/i.test(h);if(!i&&!u){n.push({fieldId:l,fieldLabel:c.text||c.contentDesc||c.resourceId,valueEntered:h});continue}let g=this.inferValueForNode(c,t);await this.driver.tap(c.bounds.centerX,c.bounds.centerY,e),await new Promise(m=>setTimeout(m,400)),await this.driver.clearField(e,g.length+10),await new Promise(m=>setTimeout(m,200)),await this.driver.inputText(g,e),await new Promise(m=>setTimeout(m,300)),o=!0,n.push({fieldId:l,fieldLabel:c.text||c.contentDesc||c.resourceId,valueEntered:g})}o&&(await this.driver.pressKey(4,e),await new Promise(c=>setTimeout(c,500)));let a=!1,d;if(s){let c=t.filter(l=>!l.clickable||l.bounds.width===0?!1:oi.some(h=>ie(h,l.text)||ie(h,l.contentDesc)||ie(h,l.resourceId)));if(c.length>0){let l=["submit","sign in","signin","login","save","confirm","proceed","continue"];c.sort((u,g)=>{let m=(u.text||u.contentDesc||u.resourceId||"").toLowerCase(),y=(g.text||g.contentDesc||g.resourceId||"").toLowerCase(),S=l.findIndex(T=>m.includes(T)),b=l.findIndex(T=>y.includes(T)),f=S>=0?S:99,x=b>=0?b:99;return f!==x?f-x:g.bounds.centerY-u.bounds.centerY});let h=c[0];d=h.text||h.contentDesc||h.resourceId,await this.driver.tap(h.bounds.centerX,h.bounds.centerY,e),await new Promise(u=>setTimeout(u,P.settle.submitWaitMs));try{let u=await this.driver.getUiHierarchy(e),{flat:g}=pe(u),m=_e(g);a=!(m.length>0&&r.every(S=>m.some(b=>b.resourceId&&b.resourceId===S.resourceId)))}catch{a=!0}}}return{filledFields:n,submitted:a,submitButtonText:d}}},xi=new ot;Je();Qe();It();je();rt();Ae();Je();Qe();import K from"chalk";var Vt=class{driver;reporter;memory;formFiller;screenLedger=new Map;callStack=[];executedStepCount=0;visitedScreenHashes=new Set;devDefectsList=[];safetyHitList=[];externalSkippedList=[];constructor(t=Q,e=bt,s=ve){this.driver=t,this.reporter=e,this.memory=s,this.formFiller=new ot(void 0,t)}async getCleanUiHierarchy(t,e,s=5){let i=await this.driver.getUiHierarchy(e),{flat:r}=pe(i),n=0;for(;n<s;){let o=$t(r);if(!o)break;n++;let a=`[${(o.severity||"error").toUpperCase()} - ${o.type.toUpperCase()}]`,d=o.sourceLocation?` [${o.sourceLocation}]`:"";console.log(K.red(` \u{1F6A8} Global Dev Console Intercepted: ${a} "${o.errorText.slice(0,80)}"${d}`)),this.devDefectsList.push(o.sourceLocation?`${o.errorText} (${o.sourceLocation})`:o.errorText);let c=await this.driver.captureScreenshot(e);this.reporter.logStep("Dev Overlay Triage",`Intercepted and triaged ${a}: "${o.errorText}"${d}`,"Verify","FAIL",o.errorText,c,{errors:[o.sourceLocation?`${o.errorText} at ${o.sourceLocation}`:o.errorText]}),o.dismissButton&&o.dismissButton.bounds.width>0?(console.log(K.gray(" Dismissing overlay via dismiss button...")),await this.driver.tap(o.dismissButton.bounds.centerX,o.dismissButton.bounds.centerY,e)):o.isToast&&o.node&&o.node.bounds.width>0?(console.log(K.gray(" Expanding toast notification to access Dismiss button...")),await this.driver.tap(o.node.bounds.centerX,o.node.bounds.centerY,e)):(console.log(K.gray(" Pressing Back to dismiss overlay...")),await this.driver.pressBack(e)),await new Promise(l=>setTimeout(l,800)),i=await this.driver.getUiHierarchy(e),r=pe(i).flat}return{xml:i,flat:r}}async dismissSoftKeyboard(t){try{await this.driver.pressKey(111,t),await new Promise(e=>setTimeout(e,150))}catch{}}async packageJailGuard(t,e){let s=await this.driver.getForegroundPackage(e);if(!s||!s.includes(t)){console.log(K.yellow(` \u{1F6A8} External App Jailbreak Detected [${s||"Unknown"}]. Recovering...`)),await this.driver.pressBack(e),await new Promise(r=>setTimeout(r,800));let i=await this.driver.getForegroundPackage(e);return(!i||!i.includes(t))&&(console.log(K.red(` Force restoring ${t} foreground...`)),await this.driver.launchApp(t,e),await new Promise(r=>setTimeout(r,1500)),this.callStack=this.callStack.slice(0,1)),!0}return!1}async handleExternalMediaChooser(t,e){let s=await this.driver.getForegroundPackage(e);if(s==="android"||s?.includes("resolver")||s?.includes("intentresolver")||s&&!s.includes(t)){console.log(K.yellow(` \u{1F6E1}\uFE0F External Media Chooser / Third-Party App Intercepted [${s||"Unknown"}]. Dismissing to stay in-app...`)),await this.driver.pressBack(e),await new Promise(n=>setTimeout(n,800));let r=await this.driver.getForegroundPackage(e);return(!r||!r.includes(t))&&(await this.driver.launchApp(t,e),await new Promise(n=>setTimeout(n,1200)),this.callStack=this.callStack.slice(0,1)),!0}return!1}catalogScreen(t,e,s=[]){let i=[],r=e.height,n=r*.06,o=r*.88,a=f=>s.some(x=>Math.abs(x.bounds.centerX-f.bounds.centerX)<30&&Math.abs(x.bounds.centerY-f.bounds.centerY)<30),d=_e(t);for(let f of d){if(a(f))continue;let x=f.text||f.contentDesc||f.resourceId||"Text Input";i.push({node:f,type:"input",label:x,tested:!1})}let c=mt(t);for(let f of c){if(a(f))continue;let x=f.text||f.contentDesc||f.resourceId||"Toggle Control";i.push({node:f,type:"toggle",label:x,tested:!1})}let l=Ue(t);for(let f of l){if(a(f)||Ke([f],r,e.width)||De([f],r,e.width,!0))continue;let x=f.text||f.contentDesc||f.resourceId||"Action Button";if(Re(f)){this.externalSkippedList.push(x);continue}let T=f.selected!==void 0||f.checkable||/(?:tab|chip|pill|filter|segment|toggle)/i.test(`${f.resourceId} ${f.className} ${f.contentDesc}`)||/(?:today|yesterday|all|active|archived|pending|completed|present|absent)/i.test(x);i.push({node:f,type:T?"toggle":"transition",label:x,tested:!1})}let h=di(t,r,e.width);for(let f of h){if(a(f)||De([f],r,e.width,!0)||i.some(T=>Math.abs(T.node.bounds.centerX-f.bounds.centerX)<25&&Math.abs(T.node.bounds.centerY-f.bounds.centerY)<25))continue;let x=f.text||f.contentDesc||f.resourceId||"Notification / Header Action";if(Re(f)){this.externalSkippedList.push(x);continue}i.push({node:f,type:"transition",label:x,tested:!1})}let u=t.filter(f=>{if(!f.clickable||f.bounds.width===0)return!1;let x=`${f.text} ${f.contentDesc} ${f.resourceId}`.toLowerCase();return x.includes("now playing")||x.includes("play")||x.includes("pause")});for(let f of u){if(a(f)||i.some(T=>Math.abs(T.node.bounds.centerX-f.bounds.centerX)<25&&Math.abs(T.node.bounds.centerY-f.bounds.centerY)<25))continue;let x=f.text||f.contentDesc||f.resourceId||"Media Control";i.push({node:f,type:"toggle",label:x,tested:!1})}let g=nt(t,e).filter(f=>!a(f)&&f.bounds.centerY>n&&f.bounds.centerY<o&&!De([f],r,e.width,!0)&&!Re(f)),m=hi(g,2);for(let f of m){let x=f.text||f.contentDesc||f.resourceId||`Item (${f.bounds.centerX},${f.bounds.centerY})`;i.push({node:f,type:"transition",label:x,tested:!1})}let y=0,S=0,b=[];for(let f of i){let x=/\.(?:mp4|mkv|mov|webm|flv|avi)\b/i.test(f.label),T=/\.(?:mp3|wav|m4a|aac|ogg)\b/i.test(f.label);if(x){if(y++,y>1)continue}else if(T&&(S++,S>1))continue;b.push(f)}return b}async safeBacktrack(t,e,s,i,r=!0){let{flat:n}=await this.getCleanUiHierarchy(e,s),{height:o,width:a}=await this.driver.getScreenDimensions(s),d=We(n,{width:a,height:o});if(d===t)return!0;let c=De(n,o,a,!0);if(c&&c.bounds.width>0){console.log(K.gray(` [Backtrack] Tapping in-app back/close button "${c.text||c.contentDesc||c.className}"...`)),await this.driver.tap(c.bounds.centerX,c.bounds.centerY,s),await new Promise(u=>setTimeout(u,1e3)),await this.packageJailGuard(e,s);let l=await this.getCleanUiHierarchy(e,s),h=We(l.flat,{width:a,height:o});if(h===t||h!==d)return!0}if(i&&i.bounds.width>0){console.log(K.gray(` [Backtrack] Restoring root domain via tab "${i.text||i.contentDesc||"Root Tab"}"...`)),await this.driver.tap(i.bounds.centerX,i.bounds.centerY,s),await new Promise(u=>setTimeout(u,1e3)),await this.packageJailGuard(e,s);let l=await this.getCleanUiHierarchy(e,s),h=We(l.flat,{width:a,height:o});if(h===t||h!==d)return!0}if(r){if(console.log(K.gray(" [Backtrack] Sending fallback KEYCODE_BACK...")),await this.driver.pressKey(4,s),await new Promise(g=>setTimeout(g,1e3)),await this.packageJailGuard(e,s))return console.log(K.yellow(" \u26A0\uFE0F Backtrack via KEYCODE_BACK caused app jailbreak. Aborting branch restoration.")),!1;let h=await this.getCleanUiHierarchy(e,s),u=We(h.flat,{width:a,height:o});if(u===t||u!==d)return!0}return!1}async explore(t){let{packageName:e,serial:s,maxScreens:i=30,maxDepth:r=3,stepBudget:n=100,maxInteractionsPerScreen:o=6,safetyMode:a="strict",safetyBlacklist:d=[]}=t;console.log(K.bold.cyan(`
839
+ \u{1F916} PromptTest Universal State-Graph DFS Engine`)),console.log(K.gray(`Target Package: ${e}`)),console.log(K.gray(`Safety Policy: ${a.toUpperCase()}`)),console.log(K.gray(`Limits: Max Screens = ${i}, Step Budget = ${n}, Max Depth = ${r}`)),await this.driver.clearCrashLogs(s);let c=await this.driver.getScreenDimensions(s),l=await this.driver.getForegroundPackage(s);(!l||!l.includes(e))&&(console.log(K.gray(`Launching ${e}...`)),await this.driver.launchApp(e,s),await new Promise(S=>setTimeout(S,2500)));let{flat:h}=await this.getCleanUiHierarchy(e,s);await this.dismissSoftKeyboard(s);let u=is(h,c,e);console.log(K.magenta(`\u26A1 Universal Paradigm Detected: [${u.paradigm.toUpperCase()}] with ${u.roots.length} root node(s).`));let g=[],m;if(u.paradigm==="drawer"&&u.roots.length>0){m=u.roots[0];let S={...h[0]||{},text:"Home Screen / Main Hub",contentDesc:"Home Screen / Main Hub",clickable:!0,bounds:{x1:0,y1:0,x2:c.width,y2:c.height,centerX:c.width/2,centerY:c.height/2,width:c.width,height:c.height}};g.push(S),console.log(K.gray(" Opening drawer to catalog root destinations...")),await this.driver.tap(m.bounds.centerX,m.bounds.centerY,s),await new Promise(v=>setTimeout(v,1200));let b=await this.getCleanUiHierarchy(e,s),f=b.flat.filter(v=>{if(!v.clickable||v.bounds.width===0||v.bounds.height===0||v.bounds.width>=c.width*.95&&v.bounds.height>=c.height*.95||De([v],c.height,c.width,!0))return!1;let C=`${v.contentDesc} ${v.text}`.trim(),U=v.bounds.width>c.width*.15&&v.bounds.height>c.height*.05;return C.toLowerCase().includes("developed by")||v.bounds.centerY>c.height*.85?!1:C.length>=2||U});for(let v of f)g.some(C=>Math.abs(C.bounds.centerX-v.bounds.centerX)<30&&Math.abs(C.bounds.centerY-v.bounds.centerY)<30)||g.push(v);let x=De(b.flat,c.height,c.width,!0);x?await this.driver.tap(x.bounds.centerX,x.bounds.centerY,s):await this.driver.tap(m.bounds.centerX,m.bounds.centerY,s),await new Promise(v=>setTimeout(v,1200));let T=await this.getCleanUiHierarchy(e,s);if(T.flat.some(v=>`${v.contentDesc} ${v.text}`.includes("Gallery")&&`${v.contentDesc} ${v.text}`.includes("Planner"))){let v=De(T.flat,c.height,c.width,!0);v?await this.driver.tap(v.bounds.centerX,v.bounds.centerY,s):await this.driver.tap(c.width-50,c.height/2,s),await new Promise(C=>setTimeout(C,1e3))}console.log(K.magenta(` Discovered ${g.length} destinations (1 Main Hub + ${g.length-1} Drawer destinations).`))}else u.roots.length>0?g=u.roots:g=[h[0]||{text:"Main Hub",clickable:!0}];let y=1;for(let S of g){if(this.executedStepCount>=n||this.visitedScreenHashes.size>=i)break;let b=S.text||S.contentDesc||`Root #${y}`;if(console.log(K.yellow(`
840
+ [Domain ${y}/${g.length}] Entering Root Tree: "${b}"...`)),u.paradigm==="bottom_tabs"||u.paradigm==="top_tabs"){let T=S.bounds.height<25?Math.max(S.bounds.y1-10,S.bounds.centerY):Math.min(S.bounds.centerY,S.bounds.y2-4);await this.driver.tap(S.bounds.centerX,T,s),this.executedStepCount++,await new Promise($=>setTimeout($,1200))}else u.paradigm==="drawer"&&y>1&&m&&(await this.dismissSoftKeyboard(s),console.log(K.gray(` Opening drawer to select "${b}"...`)),await this.driver.tap(m.bounds.centerX,m.bounds.centerY,s),await new Promise(T=>setTimeout(T,1e3)),await this.driver.tap(S.bounds.centerX,S.bounds.centerY,s),this.executedStepCount++,await new Promise(T=>setTimeout(T,1500)));h=(await this.getCleanUiHierarchy(e,s)).flat,await this.dismissSoftKeyboard(s);let x=y===1?Math.max(25,Math.ceil(n*.45)):Math.max(8,Math.ceil(n*.55/Math.max(1,g.length-1)));if(await this.exploreDfsNode({packageName:e,serial:s,screenDims:c,rootNodes:u.roots,activeRootNode:S,currentDepth:0,maxDepth:r,maxScreens:i,stepBudget:n,domainStepLimit:this.executedStepCount+x,maxInteractionsPerScreen:o,safetyMode:a,safetyBlacklist:d,domainLabel:b}),u.paradigm==="drawer"&&y>1){let T=0;for(;T<4;){let $=await this.getCleanUiHierarchy(e,s),v=Ke($.flat,c.height,c.width),C=$.flat.some(G=>`${G.contentDesc} ${G.text}`.includes("Gallery")&&`${G.contentDesc} ${G.text}`.includes("Planner"));if(v&&!C)break;let U=De($.flat,c.height,c.width,!0);if(U)console.log(K.gray(" [Domain Wrap-Up] Returning to Home Screen via in-app back...")),await this.driver.tap(U.bounds.centerX,U.bounds.centerY,s),await new Promise(G=>setTimeout(G,1e3)),T++;else break}}if(y===1&&g.length===1){let T=await this.getCleanUiHierarchy(e,s),$=is(T.flat,c,e);if(($.paradigm==="bottom_tabs"||$.paradigm==="top_tabs")&&$.roots.length>1){console.log(K.magenta(`
841
+ \u26A1 Post-Auth Navigation Discovered: [${$.paradigm.toUpperCase()}] with ${$.roots.length} root domain(s)!`)),u.paradigm=$.paradigm,u.roots=$.roots;let v=$.roots.slice(1);g.push(...v.length>0?v:$.roots)}}y++}for(let S of this.visitedScreenHashes)this.memory.markScreenCrawled(S);await this.memory.save(),console.log(K.green(`
842
+ \u2714 Universal DFS Traversal Complete!`)),console.log(K.cyan(` Visited Screens: ${this.visitedScreenHashes.size}`)),console.log(K.cyan(` Total Steps Executed: ${this.executedStepCount}/${n}`)),console.log(K.cyan(` Defects Triaged: ${this.devDefectsList.length}`))}async exploreDfsNode(t){let{packageName:e,serial:s,screenDims:i,rootNodes:r,activeRootNode:n,currentDepth:o,maxDepth:a,maxScreens:d,stepBudget:c,domainStepLimit:l,maxInteractionsPerScreen:h,safetyMode:u,safetyBlacklist:g,domainLabel:m}=t;if(this.executedStepCount>=c||this.visitedScreenHashes.size>=d||l&&this.executedStepCount>=l)return;let{flat:y}=await this.getCleanUiHierarchy(e,s),S=ge(y),b=We(y,i);this.visitedScreenHashes.add(S);let f=this.screenLedger.get(b);if(f){if(f.status==="FULLY_EXPLORED"){console.log(K.gray(` \u26A1 Cycle Detected: Screen [${b.slice(0,8)}] already fully explored. Pruning branch.`));return}}else{let v=this.catalogScreen(y,i,r);f={hash:S,semanticHash:b,title:`${m} (depth ${o})`,elements:v,status:"IN_PROGRESS",depth:o,interactionCount:0},this.screenLedger.set(b,f),console.log(K.cyan(` \u{1F50E} Discovered Screen [${b.slice(0,8)}] at depth ${o} with ${v.length} candidate element(s).`))}this.callStack.push({screenHash:S,semanticHash:b,title:f.title,timestamp:Date.now()});let x=f.elements.filter(v=>v.type==="input"&&!v.tested);if(x.length>0&&f.interactionCount<h){console.log(K.magenta(` Filling in-place form fields (${x.length} inputs)...`));let v=await this.formFiller.fillAndSubmitForm(y,s,!0,!1);this.executedStepCount++,f.interactionCount++;for(let C of x)C.tested=!0;await this.dismissSoftKeyboard(s),await this.packageJailGuard(e,s),this.reporter.logStep("In-Place Form Fill",`Populated ${v.filledFields.length} field(s) on [${b.slice(0,8)}]`,"FormSubmit","PASS",v.submitButtonText||"Auto")}let T=f.elements.filter(v=>v.type==="toggle"&&!v.tested);for(let v of T){if(this.executedStepCount>=c||f.interactionCount>=h)break;if(v.tested=!0,Ie(v.node,g,u)){this.safetyHitList.push(v.label);continue}console.log(K.gray(` Exercising toggle: "${v.label.slice(0,30)}"...`)),this.executedStepCount++,f.interactionCount++,await this.driver.tap(v.node.bounds.centerX,v.node.bounds.centerY,s),await new Promise(C=>setTimeout(C,600)),this.reporter.logStep("In-Place Toggle",`Toggled control "${v.label}"`,"Tap","PASS",v.label)}let $=f.elements.filter(v=>v.type==="transition"&&!v.tested);for(let v of $){if(this.executedStepCount>=c||this.visitedScreenHashes.size>=d||l&&this.executedStepCount>=l&&!(o===0&&m.includes("Home Screen"))||f.interactionCount>=h)break;if(v.tested=!0,Re(v.node)){this.externalSkippedList.push(v.label);continue}if(Ie(v.node,g,u)){this.safetyHitList.push(v.label);continue}console.log(K.magenta(` \u26A1 [DFS Depth ${o}] Testing transition: "${v.label.slice(0,40)}"...`)),this.executedStepCount++,f.interactionCount++,await this.driver.tap(v.node.bounds.centerX,v.node.bounds.centerY,s),await new Promise(H=>setTimeout(H,1500)),await this.dismissSoftKeyboard(s),await this.handleExternalMediaChooser(e,s),await this.packageJailGuard(e,s);let C=await this.getCleanUiHierarchy(e,s),G=We(C.flat,i)!==b;if(this.reporter.logStep("DFS Transition",`Tapped "${v.label}" [${G?"Navigated":"In-Place"}]`,"Tap","PASS",v.label),G){if(o<a){let J=o===0&&m.includes("Home Screen")?Math.min(this.executedStepCount+3,l||this.executedStepCount+3):l;await this.exploreDfsNode({packageName:e,serial:s,screenDims:i,rootNodes:r,activeRootNode:n,domainStepLimit:J,currentDepth:o+1,maxDepth:a,maxScreens:d,stepBudget:c,maxInteractionsPerScreen:h,safetyMode:u,safetyBlacklist:g,domainLabel:`${m} > ${v.label.slice(0,20)}`})}console.log(K.gray(` [DFS Backtrack] Returning to [${b.slice(0,8)}]...`)),await this.safeBacktrack(b,e,s,o===0?n:void 0,o>0),await this.dismissSoftKeyboard(s);let H=await this.getCleanUiHierarchy(e,s);if(We(H.flat,i)!==b){let J=De(H.flat,i.height,i.width,!0);J&&(console.log(K.gray(" [Backtrack Verification] Re-tapping in-app back/close button...")),await this.driver.tap(J.bounds.centerX,J.bounds.centerY,s),await new Promise(me=>setTimeout(me,1e3)),await this.packageJailGuard(e,s));let re=await this.getCleanUiHierarchy(e,s);if(We(re.flat,i)!==b){console.log(K.yellow(` \u26A0\uFE0F Unable to restore parent screen [${b.slice(0,8)}]. Unwinding branch to prevent jailbreak loop.`));break}}}}f.status="FULLY_EXPLORED",this.callStack.pop()}};var Rt=class{driver;formFiller;reporter;memory;safetyHitList=[];externalSkippedList=[];devDefectsList=[];visitedScreenHashes=new Set;executedStepCount=0;constructor(t,e,s,i){this.driver=t||Q,this.formFiller=e||xi,this.reporter=s||bt,this.memory=i||ve}getMemory(){return this.memory}getSafetyHitList(){return this.safetyHitList}getExternalSkippedList(){return this.externalSkippedList}getDevDefectsList(){return this.devDefectsList}getVisitedScreensCount(){return this.visitedScreenHashes.size}async packageJailGuard(t,e){let s=await this.driver.getForegroundPackage(e);if(s&&!s.includes(t)){console.log(D.yellow(` \u{1F6E1}\uFE0F Jail Containment: App escaped to "${s}". Executing containment recovery...`)),await this.driver.pressBack(e),await new Promise(r=>setTimeout(r,600));let i=await this.driver.getForegroundPackage(e);return(!i||!i.includes(t))&&(console.log(D.gray(` Force re-launching ${t} to restore foreground...`)),await this.driver.launchApp(t,e),await new Promise(r=>setTimeout(r,1200))),this.reporter.logStep("Jail Containment",`App escaped to "${s}"; successfully contained and restored "${t}"`,"Back","PASS"),!0}return!1}async getCleanUiHierarchy(t,e,s=5){let i=await this.driver.getUiHierarchy(e),{flat:r}=pe(i),n=0;for(;n<s;){let o=$t(r);if(!o)break;n++;let a=`[${(o.severity||"error").toUpperCase()} - ${o.type.toUpperCase()}]`,d=o.sourceLocation?` [${o.sourceLocation}]`:"";console.log(D.red(` \u{1F6A8} Global Dev Console Intercepted: ${a} "${o.errorText.slice(0,80)}"${d}`)),this.devDefectsList.push(o.sourceLocation?`${o.errorText} (${o.sourceLocation})`:o.errorText);let c=await this.driver.captureScreenshot(e);this.reporter.logStep("Dev Overlay Triage",`Intercepted and triaged ${a}: "${o.errorText}"${d}`,"Verify","FAIL",o.errorText,c,{errors:[o.sourceLocation?`${o.errorText} at ${o.sourceLocation}`:o.errorText]}),o.dismissButton&&o.dismissButton.bounds.width>0?(console.log(D.gray(" Dismissing overlay via dismiss button...")),await this.driver.tap(o.dismissButton.bounds.centerX,o.dismissButton.bounds.centerY,e)):o.isToast&&o.node&&o.node.bounds.width>0?(console.log(D.gray(" Expanding toast notification to access Dismiss button...")),await this.driver.tap(o.node.bounds.centerX,o.node.bounds.centerY,e)):(console.log(D.gray(" Pressing Back to dismiss overlay...")),await this.driver.pressBack(e)),await new Promise(l=>setTimeout(l,800)),i=await this.driver.getUiHierarchy(e),r=pe(i).flat}return{xml:i,flat:r}}async handleDevOverlays(t,e,s){let i=$t(t);if(!i)return!1;let r=`[${(i.severity||"error").toUpperCase()} - ${i.type.toUpperCase()}]`,n=i.sourceLocation?` [${i.sourceLocation}]`:"";console.log(D.red(` \u{1F6A8} Dev Overlay Detected: ${r} "${i.errorText.slice(0,80)}"${n}`)),this.devDefectsList.push(i.sourceLocation?`${i.errorText} (${i.sourceLocation})`:i.errorText);let o=await this.driver.captureScreenshot(s);return this.reporter.logStep("Dev Overlay Triage",`Detected and triaged ${r} error: "${i.errorText}"${n}`,"Verify","FAIL",i.errorText,o,{errors:[i.sourceLocation?`${i.errorText} (${i.sourceLocation})`:i.errorText]}),i.dismissButton&&i.dismissButton.bounds.width>0?(console.log(D.gray(" Dismissing error overlay via dismiss button...")),await this.driver.tap(i.dismissButton.bounds.centerX,i.dismissButton.bounds.centerY,s)):i.isToast&&i.node&&i.node.bounds.width>0?(console.log(D.gray(" Expanding toast notification to access Dismiss button...")),await this.driver.tap(i.node.bounds.centerX,i.node.bounds.centerY,s)):(console.log(D.gray(" Pressing Back to dismiss error overlay...")),await this.driver.pressBack(s)),await new Promise(a=>setTimeout(a,800)),!0}async dismissSoftKeyboard(t){try{await this.driver.pressKey(111,t),await new Promise(e=>setTimeout(e,200))}catch{}}async explore(t){let{packageName:e,serial:s,maxTabs:i=P.explorer?.maxTabs||15,exploreLists:r=!0,skipAlreadyCrawled:n=!1,safetyMode:o=P.safety?.mode||"strict",safetyBlacklist:a=P.safety?.customBlacklist?[...P.safety.customBlacklist]:[],maxScreens:d=P.explorer?.maxScreens||30,stepBudget:c=P.explorer?.stepBudget||100,screenshots:l=P.explorer?.screenshots||"state-change"}=t;console.log(D.cyan(`
843
+ \u{1F916} PromptTest Autonomous Exploration Brain v3`)),console.log(D.gray("Target Package: ")+D.bold.white(e)),console.log(D.gray("Safety Policy: ")+D.bold.yellow(o.toUpperCase())+(a.length>0?D.gray(` (+${a.length} custom blacklist)`):"")),console.log(D.gray("Screenshots Policy: ")+D.bold.white(l));let h=async(y,S=!0)=>{if(!(l==="failure-only"&&y!=="FAIL")&&!(l==="state-change"&&!S&&y!=="FAIL"))try{return await this.driver.captureScreenshot(s)}catch{return}};await this.memory.init(e);let u=s||this.driver.getDefaultDevice(),g=u||"Default Device";this.reporter.init(e,g);let m=null;u&&(m=ct(u)),this.safetyHitList=[],this.externalSkippedList=[],this.devDefectsList=[],this.visitedScreenHashes.clear(),this.executedStepCount=0;try{if(await this.driver.clearCrashLogs(s),(t.strategy||P.explorer?.strategy||"heuristic")==="dfs"){let se=new Vt(this.driver,this.reporter,this.memory);await se.explore({packageName:e,serial:s,maxScreens:d,maxDepth:t.maxDepth||P.explorer?.maxDepth||5,stepBudget:c,safetyMode:o,safetyBlacklist:a,screenshotPolicy:l,skipAlreadyCrawled:n}),this.safetyHitList=se.safetyHitList,this.externalSkippedList=se.externalSkippedList,this.devDefectsList=se.devDefectsList,this.visitedScreenHashes=se.visitedScreenHashes,this.executedStepCount=se.executedStepCount;let X=this.memory.getStats();this.reporter.logStep("Coverage Audit",`State Graph Coverage: Visited ${this.visitedScreenHashes.size} unique screen state(s). Memory Engine cached ${X.totalScreens} crawled screen(s).`,"Verify","PASS"),await this.reporter.generateReport(),console.log(D.bold.green(`
844
844
  \u2728 Full Audit Report generated at: output/prompttest-report.md`));return}let{width:S,height:b}=await this.driver.getScreenDimensions(s);console.log(D.yellow(`
845
- [1/5] Verifying Foreground State...`));let f=await this.driver.getForegroundPackage(s);(!f||!f.includes(e))&&(console.log(D.gray(`Launching ${e}...`)),await this.driver.launchApp(e,s),await new Promise(se=>setTimeout(se,2500)));let T=await this.runErrorSentinel(e,s,"Post-Launch"),P=T.hasError?"FAIL":"PASS",I=await h(P,!0);this.reporter.logStep("Init",`Launched and verified foreground for ${e}`,"Launch",P,e,I,T.hasError?{errors:T.errors}:void 0),console.log(P==="PASS"?D.green("\u2714 App is active in foreground."):D.red(`\u2716 Issues detected during launch for ${e}.`)),console.log(D.yellow(`
846
- [2/5] Inspecting UI Hierarchy for Forms...`));let{xml:v,flat:$}=await this.getCleanUiHierarchy(e,s),j=ge($);if(this.visitedScreenHashes.add(j),this.memory.isScreenCrawled(j)&&i)console.log(D.cyan(` \u26A1 Fast-Forward: Screen [${j.slice(0,8)}] was previously crawled offline. Skipping redundant element interactions.`)),this.reporter.logStep("Fast Forward",`Fast-forwarded past previously crawled screen [${j.slice(0,8)}] (Memory Engine)`,"Skip","PASS");else{let se=_e($);if(se.length>0){console.log(D.magenta(`\u26A1 Detected ${se.length} form field(s)! Engaging Semantic Form Filler...`));for(let L of se)console.log(D.gray(` - Field: "${L.text||L.contentDesc||L.resourceId}"`));let A=await this.formFiller.fillAndSubmitForm($,s,!0,!1);this.executedStepCount++,await new Promise(L=>setTimeout(L,1500)),await this.dismissSoftKeyboard(s),await this.packageJailGuard(e,s);let M=await this.getCleanUiHierarchy(e,s);v=M.xml,$=M.flat,this.visitedScreenHashes.add(ge($));let R=await this.runErrorSentinel(e,s,"Post-Form-Submit"),F=_e($),x=R.hasError||F.length===se.length&&R.errors.length>0?"FAIL":"PASS",w=await h(x,!0),N=A.filledFields.map(L=>`${L.fieldLabel} -> "${L.valueEntered}"`).join(", ");this.reporter.logStep("Form Fill",`Filled ${A.filledFields.length} field(s) [${N}] and submitted via "${A.submitButtonText||"Auto"}"`,"FormSubmit",x,A.submitButtonText,w,R.hasError?{errors:R.errors}:void 0),console.log(x==="PASS"?D.green("\u2714 Form populated and submitted successfully!"):D.red("\u2716 Form submission triggered an error or remained unauthenticated."))}else console.log(D.gray("No form input fields detected on initial screen."));console.log(D.yellow(`
847
- [3/5] Inspecting Interactive Action Controls...`));let X=Ue($).filter(A=>{let M=(A.text+" "+A.contentDesc).toLowerCase();if(M.includes("submit")||M.includes("cancel")||Ke([A],b))return!1;if(Re(A)){let R=A.text||A.contentDesc||A.resourceId||"External Link";return console.log(D.gray(` \u{1F517} External Link Bypassed: "${R}"`)),this.externalSkippedList.push(R),!1}if(Ie(A,a,o)){let R=A.text||A.contentDesc||A.resourceId||"Action";return console.log(D.yellow(` \u{1F6E1}\uFE0F Safety Guard: Blocked destructive action "${R}"`)),this.safetyHitList.push(R),!1}return!0});if(X.length>0){let A=X[0],M=A.text||A.contentDesc||A.resourceId;console.log(D.magenta(`\u26A1 Found action button: "${M}". Testing interaction...`));let R=ge($);this.executedStepCount++,await this.driver.tap(A.bounds.centerX,A.bounds.centerY,s),await new Promise(U=>setTimeout(U,1200)),await this.packageJailGuard(e,s);let F=await this.getCleanUiHierarchy(e,s);v=F.xml,$=F.flat;let V=ge($);this.visitedScreenHashes.add(V);let x=await this.runErrorSentinel(e,s,"Post-Action-Tap"),w=R!==V,N="PASS",L="";x.hasError?(N="FAIL",L="Action triggered error or crash"):w?(N="PASS",L="Screen transitioned successfully"):(N="WARN",L="No visible screen transition or state change observed (No-Op)",console.log(D.yellow(` \u26A0\uFE0F Outcome Warning: Action "${M}" produced no UI state change.`)));let le=await h(N,w);this.reporter.logStep("Action Testing",`Tapped action button "${M}" [${L}]`,"Tap",N,M,le,x.hasError?{errors:x.errors}:void 0),console.log(N==="PASS"?D.green(`\u2714 Action interaction complete (${L}).`):N==="WARN"?D.yellow(`\u2714 Action interaction recorded with warning (${L}).`):D.red("\u2716 Action interaction triggered an error.")),N!=="FAIL"&&(this.memory.recordSuccess("TAP",M,A.resourceId||A.text||A.contentDesc||M,"text",1,void 0,R),this.memory.markScreenCrawled(R,[M]))}else console.log(D.gray("No standalone action buttons to test."));let O=mt($).filter(A=>!Ie(A,a,o));if(O.length>0){console.log(D.yellow(`
848
- [3b/5] Inspecting Toggle & Checkable Controls...`));let A=O[0],M=A.text||A.contentDesc||A.resourceId||"Switch/Checkbox",R=A.checked;console.log(D.magenta(`\u26A1 Found toggle: "${M}" (checked: ${R}). Testing toggle interaction...`)),this.executedStepCount++,await this.driver.tap(A.bounds.centerX,A.bounds.centerY,s),await new Promise(U=>setTimeout(U,1e3)),v=await this.driver.getUiHierarchy(s),$=pe(v).flat;let F=ge($);this.visitedScreenHashes.add(F);let x=mt($).find(U=>Math.abs(U.bounds.centerX-A.bounds.centerX)<25&&Math.abs(U.bounds.centerY-A.bounds.centerY)<25),w=x?x.checked!==R:!0,N=await this.runErrorSentinel(e,s,"Post-Toggle"),L=N.hasError?"FAIL":w?"PASS":"WARN",le=await h(L,w);this.reporter.logStep("Toggle Testing",`Toggled "${M}" (Checked: ${R} -> ${x?x.checked:"flipped"})`,"Toggle",L,M,le,N.hasError?{errors:N.errors}:void 0),console.log(L==="PASS"?D.green("\u2714 Toggle control flipped successfully!"):L==="WARN"?D.yellow("\u26A0\uFE0F Toggle tapped but checked state did not flip."):D.red("\u2716 Toggle control triggered an error.")),L!=="FAIL"&&this.memory.markScreenCrawled(F,[M])}let Y=Ke($,b);if(Y&&!Ie(Y,a,o)){let A=Y.contentDesc||Y.text||Y.resourceId||"Drawer Menu";console.log(D.yellow(`
849
- [3c/5] Inspecting Side Navigation Drawer...`)),console.log(D.magenta(`\u26A1 Found drawer trigger: "${A}". Opening side drawer...`));let M=ge($);this.executedStepCount++,await this.driver.tap(Y.bounds.centerX,Y.bounds.centerY,s),await new Promise(L=>setTimeout(L,1200)),await this.packageJailGuard(e,s);let R=await this.getCleanUiHierarchy(e,s);v=R.xml,$=R.flat;let F=ge($);this.visitedScreenHashes.add(F);let V=M!==F,x=await this.runErrorSentinel(e,s,"Drawer-Open"),w=x.hasError?"FAIL":V?"PASS":"WARN",N=await h(w,V);if(this.reporter.logStep("Drawer Navigation",`Opened side drawer via "${A}"`,"Tap",w,A,N,x.hasError?{errors:x.errors}:void 0),w==="PASS"){console.log(D.green("\u2714 Side drawer opened successfully!"));let L=Ue($).filter(U=>!Ie(U,a,o)&&!Re(U)&&U.bounds.centerY>Y.bounds.y2);if(L.length>0){let U=L[0],Se=U.text||U.contentDesc||U.resourceId||"Drawer Item";console.log(D.gray(` - Testing drawer item: "${Se}"...`)),this.executedStepCount++,await this.driver.tap(U.bounds.centerX,U.bounds.centerY,s),await new Promise(ie=>setTimeout(ie,1200)),await this.packageJailGuard(e,s);let Ne=await this.getCleanUiHierarchy(e,s);v=Ne.xml,$=Ne.flat,this.visitedScreenHashes.add(ge($))}console.log(D.gray(" Closing side drawer to restore main view...")),await this.driver.pressBack(s),await new Promise(U=>setTimeout(U,1e3));let le=await this.getCleanUiHierarchy(e,s);v=le.xml,$=le.flat,this.visitedScreenHashes.add(ge($)),console.log(D.green("\u2714 Main view restored from side drawer."))}else w==="WARN"&&console.log(D.yellow("\u26A0\uFE0F Drawer button tapped but no visible screen change occurred."));w!=="FAIL"&&this.memory.markScreenCrawled(M,[A])}if(r){console.log(D.yellow(`
850
- [4/5] Inspecting Lists & Master-Detail Flows...`));let A=pn($);if(A.length>0){console.log(D.magenta(`\u26A1 Found ${A.length} scrollable container(s). Performing vertical scroll exploration...`));let R=ge($),F=Math.round(S*.5);await this.driver.swipe(F,Math.round(b*.7),F,Math.round(b*.3),300,s),await new Promise(L=>setTimeout(L,1200));let V=await this.getCleanUiHierarchy(e,s);v=V.xml,$=V.flat;let x=ge($);this.visitedScreenHashes.add(x);let w=R!==x,N=await h("PASS",w);this.reporter.logStep("Scroll Exploration",w?"Scrolled vertically to discover off-screen elements":"Scrolled but content remained at edge","Swipe","PASS","SwipeUp",N),w&&console.log(D.green("\u2714 Vertical scroll succeeded; discovered off-screen content below fold."))}let M=it($).filter(R=>{if(Re(R)){let F=R.text||R.contentDesc||"External Link";return this.externalSkippedList.push(F),!1}if(Ie(R,a,o)){let F=R.text||R.contentDesc||"List Item";return console.log(D.yellow(` \u{1F6E1}\uFE0F Safety Guard: Blocked destructive list item "${F}"`)),this.safetyHitList.push(F),!1}return!0});if(M.length>0){let R=M[0],F=R.text||R.contentDesc||`Item at (${R.bounds.centerX}, ${R.bounds.centerY})`;console.log(D.magenta(`\u26A1 Found list item: "${F}". Diving into detail view...`));let V=ge($);await this.driver.tap(R.bounds.centerX,R.bounds.centerY,s),await new Promise(Me=>setTimeout(Me,1800));let x=await this.getCleanUiHierarchy(e,s);v=x.xml,$=x.flat;let w=ge($);this.visitedScreenHashes.add(w);let N=await this.runErrorSentinel(e,s,"Detail-View"),L=V!==w,le=N.hasError?"FAIL":L?"PASS":"WARN",U=await h(le,L);this.reporter.logStep("List Dive",`Dived into detail view for "${F}" [${L?"Navigated":"Unchanged"}]`,"Tap",le,F,U,N.hasError?{errors:N.errors}:void 0),console.log(le==="PASS"?D.green("\u2714 Detail screen loaded."):le==="WARN"?D.yellow("\u26A0\uFE0F Detail view tapped but no navigation detected."):D.red("\u2716 Detail view triggered an error."));let Se=De(x.flat,E.screen.fallbackHeight,E.screen.fallbackWidth,!0);Se&&Se.bounds.width>0?(console.log(D.gray(`Navigating back via in-app back button "${Se.text||Se.contentDesc||Se.className}"...`)),await this.driver.tap(Se.bounds.centerX,Se.bounds.centerY,s)):(console.log(D.gray("Navigating back to main view...")),await this.driver.pressKey(4,s)),await new Promise(Me=>setTimeout(Me,1200));let Ne=await this.driver.getForegroundPackage(s);(!Ne||!Ne.includes(e))&&(console.log(D.yellow(`Restoring ${e} foreground after back navigation...`)),await this.driver.launchApp(e,s),await new Promise(Me=>setTimeout(Me,2e3)));let ie=await this.getCleanUiHierarchy(e,s);v=ie.xml,$=ie.flat,this.visitedScreenHashes.add(ge($));let fe=await this.runErrorSentinel(e,s,"Post-Back-Restore"),Ge=fe.hasError?"FAIL":"PASS",_t=await h(Ge,!0);this.reporter.logStep("List Dive","Navigated back to master screen","Back",Ge,"KEYCODE_BACK",_t,fe.hasError?{errors:fe.errors}:void 0),Ge==="PASS"&&console.log(D.green("\u2714 Master view restored."))}else console.log(D.gray("No list items found for master-detail exploration."))}}console.log(D.yellow(`
851
- [5/5] Inspecting Navigation Tabs...`));let H=await this.driver.getForegroundPackage(s);(!H||!H.includes(e))&&(console.log(D.gray(`Restoring ${e} foreground for tab traversal...`)),await this.driver.launchApp(e,s),await new Promise(se=>setTimeout(se,2e3))),await this.dismissSoftKeyboard(s);let be=await this.getCleanUiHierarchy(e,s);v=be.xml,$=be.flat;let J=Dt($,void 0,e);if(J.length>1){console.log(D.magenta(`\u26A1 Found ${J.length} navigation tab(s). Traversal sequence initiated...`));let se=J.slice(0,n),X=1;for(let O of se){let Y=O.text||O.contentDesc||`Tab #${X}`;console.log(D.gray(` - Visiting ${Y}...`)),await this.dismissSoftKeyboard(s);let A=Math.min(O.bounds.centerY,O.bounds.y2-4);this.executedStepCount++,await this.driver.tap(O.bounds.centerX,A,s),await new Promise(w=>setTimeout(w,1500)),await this.packageJailGuard(e,s);let M=await this.getCleanUiHierarchy(e,s);v=M.xml,$=M.flat;let R=ge($);this.visitedScreenHashes.add(R),this.memory.markScreenCrawled(R,[Y]);let F=await this.runErrorSentinel(e,s,`Tab-${Y}`),V=F.hasError?"FAIL":"PASS",x=await h(V,!0);if(this.reporter.logStep("Tab Traversal",`Navigated to tab "${Y}"`,"Tap",V,Y,x,F.hasError?{errors:F.errors}:void 0),console.log(V==="PASS"?D.green(` \u2714 Tab "${Y}" loaded cleanly.`):D.red(` \u2716 Tab "${Y}" triggered errors.`)),this.executedStepCount<c&&this.visitedScreenHashes.size<l){let w=[],N=b*.08,L=b*.88,le=ie=>ie.bounds.centerY>N&&ie.bounds.centerY<L&&ie.clickable&&ie.bounds.width>30&&ie.bounds.height>20&&J.every(fe=>Math.abs(fe.bounds.centerX-ie.bounds.centerX)>40||Math.abs(fe.bounds.centerY-ie.bounds.centerY)>40),U=it($,{width:S,height:b}).filter(le);for(let ie of U.slice(0,3))w.push({node:ie,type:"list"});let Se=Ue($).filter(ie=>!(!le(ie)||Ke([ie],b)));for(let ie of Se.slice(0,4))w.push({node:ie,type:"button"});let Ne=mt($).filter(le);for(let ie of Ne.slice(0,2))w.push({node:ie,type:"toggle"});for(let ie of w){if(this.executedStepCount>=c||this.visitedScreenHashes.size>=l)break;let fe=ie.node;if(Re(fe)){this.externalSkippedList.push(fe.text||fe.contentDesc||"External Link");continue}if(Ie(fe,a,o)){let pt=fe.text||fe.contentDesc||"Destructive Action";this.safetyHitList.push(pt);continue}let Ge=fe.text||fe.contentDesc||fe.resourceId||`${ie.type} element`;console.log(D.gray(` Sub-crawl [${Y}]: Exercising ${ie.type} "${Ge.slice(0,40)}"...`)),this.executedStepCount++,await this.driver.tap(fe.bounds.centerX,fe.bounds.centerY,s),await new Promise(pt=>setTimeout(pt,1200)),await this.dismissSoftKeyboard(s),await this.packageJailGuard(e,s);let _t=await this.getCleanUiHierarchy(e,s);v=_t.xml,$=_t.flat;let Me=ge($),Yn=!this.visitedScreenHashes.has(Me);this.visitedScreenHashes.add(Me);let es=await this.runErrorSentinel(e,s,`Sub-${Ge.slice(0,30)}`),Zs=es.hasError?"FAIL":"PASS",Vn=await h(Zs,Yn);if(this.reporter.logStep("Tab Sub-Crawl",`Tested ${ie.type} "${Ge}" under tab "${Y}"`,"Tap",Zs,Ge,Vn,es.hasError?{errors:es.errors}:void 0),Me!==R){console.log(D.cyan(` \u{1F50E} Screen transitioned. Discovered new screen state [${Me.slice(0,8)}]`));let pt=Ue($).filter(Fe=>le(Fe)&&!Ie(Fe,a,o)&&!Re(Fe));if(pt.length>0&&this.executedStepCount<c){let Fe=pt[0],Xn=Fe.text||Fe.contentDesc||"Child Action";console.log(D.gray(` Exercising child action "${Xn.slice(0,30)}"...`)),this.executedStepCount++,await this.driver.tap(Fe.bounds.centerX,Fe.bounds.centerY,s),await new Promise(Gn=>setTimeout(Gn,1e3)),await this.dismissSoftKeyboard(s)}console.log(D.gray(` Restoring ${Y} master view via Back...`)),await this.driver.pressBack(s),await new Promise(Fe=>setTimeout(Fe,1e3)),await this.dismissSoftKeyboard(s);let en=await this.getCleanUiHierarchy(e,s);v=en.xml,$=en.flat}}}X++}console.log(D.green("\u2714 Navigation tabs traversed successfully!"))}else console.log(D.gray("Single-screen or tabs not detected at screen footer."));for(let se of this.visitedScreenHashes)this.memory.markScreenCrawled(se);await this.memory.save();let re=this.memory.getStats();this.reporter.logStep("Coverage Audit",`State Graph Coverage: Visited ${this.visitedScreenHashes.size} unique screen state(s). Memory Engine cached ${re.crawledScreens} crawled screen(s).`,"Verify","PASS"),await this.runErrorSentinel(e,s,"Final-State");let _=await this.reporter.generateReport(),me=_.failedSteps===0&&_.errorsDetected.length===0;console.log(me?D.bold.green(`
845
+ [1/5] Verifying Foreground State...`));let f=await this.driver.getForegroundPackage(s);(!f||!f.includes(e))&&(console.log(D.gray(`Launching ${e}...`)),await this.driver.launchApp(e,s),await new Promise(se=>setTimeout(se,2500)));let x=await this.runErrorSentinel(e,s,"Post-Launch"),T=x.hasError?"FAIL":"PASS",$=await h(T,!0);this.reporter.logStep("Init",`Launched and verified foreground for ${e}`,"Launch",T,e,$,x.hasError?{errors:x.errors}:void 0),console.log(T==="PASS"?D.green("\u2714 App is active in foreground."):D.red(`\u2716 Issues detected during launch for ${e}.`)),console.log(D.yellow(`
846
+ [2/5] Inspecting UI Hierarchy for Forms...`));let{xml:v,flat:C}=await this.getCleanUiHierarchy(e,s),U=ge(C);if(this.visitedScreenHashes.add(U),this.memory.isScreenCrawled(U)&&n)console.log(D.cyan(` \u26A1 Fast-Forward: Screen [${U.slice(0,8)}] was previously crawled offline. Skipping redundant element interactions.`)),this.reporter.logStep("Fast Forward",`Fast-forwarded past previously crawled screen [${U.slice(0,8)}] (Memory Engine)`,"Skip","PASS");else{let se=_e(C);if(se.length>0){console.log(D.magenta(`\u26A1 Detected ${se.length} form field(s)! Engaging Semantic Form Filler...`));for(let L of se)console.log(D.gray(` - Field: "${L.text||L.contentDesc||L.resourceId}"`));let A=await this.formFiller.fillAndSubmitForm(C,s,!0,!1);this.executedStepCount++,await new Promise(L=>setTimeout(L,1500)),await this.dismissSoftKeyboard(s),await this.packageJailGuard(e,s);let M=await this.getCleanUiHierarchy(e,s);v=M.xml,C=M.flat,this.visitedScreenHashes.add(ge(C));let R=await this.runErrorSentinel(e,s,"Post-Form-Submit"),F=_e(C),E=R.hasError||F.length===se.length&&R.errors.length>0?"FAIL":"PASS",w=await h(E,!0),N=A.filledFields.map(L=>`${L.fieldLabel} -> "${L.valueEntered}"`).join(", ");this.reporter.logStep("Form Fill",`Filled ${A.filledFields.length} field(s) [${N}] and submitted via "${A.submitButtonText||"Auto"}"`,"FormSubmit",E,A.submitButtonText,w,R.hasError?{errors:R.errors}:void 0),console.log(E==="PASS"?D.green("\u2714 Form populated and submitted successfully!"):D.red("\u2716 Form submission triggered an error or remained unauthenticated."))}else console.log(D.gray("No form input fields detected on initial screen."));console.log(D.yellow(`
847
+ [3/5] Inspecting Interactive Action Controls...`));let X=Ue(C).filter(A=>{let M=(A.text+" "+A.contentDesc).toLowerCase();if(M.includes("submit")||M.includes("cancel")||Ke([A],b))return!1;if(Re(A)){let R=A.text||A.contentDesc||A.resourceId||"External Link";return console.log(D.gray(` \u{1F517} External Link Bypassed: "${R}"`)),this.externalSkippedList.push(R),!1}if(Ie(A,a,o)){let R=A.text||A.contentDesc||A.resourceId||"Action";return console.log(D.yellow(` \u{1F6E1}\uFE0F Safety Guard: Blocked destructive action "${R}"`)),this.safetyHitList.push(R),!1}return!0});if(X.length>0){let A=X[0],M=A.text||A.contentDesc||A.resourceId;console.log(D.magenta(`\u26A1 Found action button: "${M}". Testing interaction...`));let R=ge(C);this.executedStepCount++,await this.driver.tap(A.bounds.centerX,A.bounds.centerY,s),await new Promise(j=>setTimeout(j,1200)),await this.packageJailGuard(e,s);let F=await this.getCleanUiHierarchy(e,s);v=F.xml,C=F.flat;let V=ge(C);this.visitedScreenHashes.add(V);let E=await this.runErrorSentinel(e,s,"Post-Action-Tap"),w=R!==V,N="PASS",L="";E.hasError?(N="FAIL",L="Action triggered error or crash"):w?(N="PASS",L="Screen transitioned successfully"):(N="WARN",L="No visible screen transition or state change observed (No-Op)",console.log(D.yellow(` \u26A0\uFE0F Outcome Warning: Action "${M}" produced no UI state change.`)));let le=await h(N,w);this.reporter.logStep("Action Testing",`Tapped action button "${M}" [${L}]`,"Tap",N,M,le,E.hasError?{errors:E.errors}:void 0),console.log(N==="PASS"?D.green(`\u2714 Action interaction complete (${L}).`):N==="WARN"?D.yellow(`\u2714 Action interaction recorded with warning (${L}).`):D.red("\u2716 Action interaction triggered an error.")),N!=="FAIL"&&(this.memory.recordSuccess("TAP",M,A.resourceId||A.text||A.contentDesc||M,"text",1,void 0,R),this.memory.markScreenCrawled(R,[M]))}else console.log(D.gray("No standalone action buttons to test."));let O=mt(C).filter(A=>!Ie(A,a,o));if(O.length>0){console.log(D.yellow(`
848
+ [3b/5] Inspecting Toggle & Checkable Controls...`));let A=O[0],M=A.text||A.contentDesc||A.resourceId||"Switch/Checkbox",R=A.checked;console.log(D.magenta(`\u26A1 Found toggle: "${M}" (checked: ${R}). Testing toggle interaction...`)),this.executedStepCount++,await this.driver.tap(A.bounds.centerX,A.bounds.centerY,s),await new Promise(j=>setTimeout(j,1e3)),v=await this.driver.getUiHierarchy(s),C=pe(v).flat;let F=ge(C);this.visitedScreenHashes.add(F);let E=mt(C).find(j=>Math.abs(j.bounds.centerX-A.bounds.centerX)<25&&Math.abs(j.bounds.centerY-A.bounds.centerY)<25),w=E?E.checked!==R:!0,N=await this.runErrorSentinel(e,s,"Post-Toggle"),L=N.hasError?"FAIL":w?"PASS":"WARN",le=await h(L,w);this.reporter.logStep("Toggle Testing",`Toggled "${M}" (Checked: ${R} -> ${E?E.checked:"flipped"})`,"Toggle",L,M,le,N.hasError?{errors:N.errors}:void 0),console.log(L==="PASS"?D.green("\u2714 Toggle control flipped successfully!"):L==="WARN"?D.yellow("\u26A0\uFE0F Toggle tapped but checked state did not flip."):D.red("\u2716 Toggle control triggered an error.")),L!=="FAIL"&&this.memory.markScreenCrawled(F,[M])}let Y=Ke(C,b);if(Y&&!Ie(Y,a,o)){let A=Y.contentDesc||Y.text||Y.resourceId||"Drawer Menu";console.log(D.yellow(`
849
+ [3c/5] Inspecting Side Navigation Drawer...`)),console.log(D.magenta(`\u26A1 Found drawer trigger: "${A}". Opening side drawer...`));let M=ge(C);this.executedStepCount++,await this.driver.tap(Y.bounds.centerX,Y.bounds.centerY,s),await new Promise(L=>setTimeout(L,1200)),await this.packageJailGuard(e,s);let R=await this.getCleanUiHierarchy(e,s);v=R.xml,C=R.flat;let F=ge(C);this.visitedScreenHashes.add(F);let V=M!==F,E=await this.runErrorSentinel(e,s,"Drawer-Open"),w=E.hasError?"FAIL":V?"PASS":"WARN",N=await h(w,V);if(this.reporter.logStep("Drawer Navigation",`Opened side drawer via "${A}"`,"Tap",w,A,N,E.hasError?{errors:E.errors}:void 0),w==="PASS"){console.log(D.green("\u2714 Side drawer opened successfully!"));let L=Ue(C).filter(j=>!Ie(j,a,o)&&!Re(j)&&j.bounds.centerY>Y.bounds.y2);if(L.length>0){let j=L[0],Se=j.text||j.contentDesc||j.resourceId||"Drawer Item";console.log(D.gray(` - Testing drawer item: "${Se}"...`)),this.executedStepCount++,await this.driver.tap(j.bounds.centerX,j.bounds.centerY,s),await new Promise(ne=>setTimeout(ne,1200)),await this.packageJailGuard(e,s);let Ne=await this.getCleanUiHierarchy(e,s);v=Ne.xml,C=Ne.flat,this.visitedScreenHashes.add(ge(C))}console.log(D.gray(" Closing side drawer to restore main view...")),await this.driver.pressBack(s),await new Promise(j=>setTimeout(j,1e3));let le=await this.getCleanUiHierarchy(e,s);v=le.xml,C=le.flat,this.visitedScreenHashes.add(ge(C)),console.log(D.green("\u2714 Main view restored from side drawer."))}else w==="WARN"&&console.log(D.yellow("\u26A0\uFE0F Drawer button tapped but no visible screen change occurred."));w!=="FAIL"&&this.memory.markScreenCrawled(M,[A])}if(r){console.log(D.yellow(`
850
+ [4/5] Inspecting Lists & Master-Detail Flows...`));let A=ui(C);if(A.length>0){console.log(D.magenta(`\u26A1 Found ${A.length} scrollable container(s). Performing vertical scroll exploration...`));let R=ge(C),F=Math.round(S*.5);await this.driver.swipe(F,Math.round(b*.7),F,Math.round(b*.3),300,s),await new Promise(L=>setTimeout(L,1200));let V=await this.getCleanUiHierarchy(e,s);v=V.xml,C=V.flat;let E=ge(C);this.visitedScreenHashes.add(E);let w=R!==E,N=await h("PASS",w);this.reporter.logStep("Scroll Exploration",w?"Scrolled vertically to discover off-screen elements":"Scrolled but content remained at edge","Swipe","PASS","SwipeUp",N),w&&console.log(D.green("\u2714 Vertical scroll succeeded; discovered off-screen content below fold."))}let M=nt(C).filter(R=>{if(Re(R)){let F=R.text||R.contentDesc||"External Link";return this.externalSkippedList.push(F),!1}if(Ie(R,a,o)){let F=R.text||R.contentDesc||"List Item";return console.log(D.yellow(` \u{1F6E1}\uFE0F Safety Guard: Blocked destructive list item "${F}"`)),this.safetyHitList.push(F),!1}return!0});if(M.length>0){let R=M[0],F=R.text||R.contentDesc||`Item at (${R.bounds.centerX}, ${R.bounds.centerY})`;console.log(D.magenta(`\u26A1 Found list item: "${F}". Diving into detail view...`));let V=ge(C);await this.driver.tap(R.bounds.centerX,R.bounds.centerY,s),await new Promise(Me=>setTimeout(Me,1800));let E=await this.getCleanUiHierarchy(e,s);v=E.xml,C=E.flat;let w=ge(C);this.visitedScreenHashes.add(w);let N=await this.runErrorSentinel(e,s,"Detail-View"),L=V!==w,le=N.hasError?"FAIL":L?"PASS":"WARN",j=await h(le,L);this.reporter.logStep("List Dive",`Dived into detail view for "${F}" [${L?"Navigated":"Unchanged"}]`,"Tap",le,F,j,N.hasError?{errors:N.errors}:void 0),console.log(le==="PASS"?D.green("\u2714 Detail screen loaded."):le==="WARN"?D.yellow("\u26A0\uFE0F Detail view tapped but no navigation detected."):D.red("\u2716 Detail view triggered an error."));let Se=De(E.flat,P.screen.fallbackHeight,P.screen.fallbackWidth,!0);Se&&Se.bounds.width>0?(console.log(D.gray(`Navigating back via in-app back button "${Se.text||Se.contentDesc||Se.className}"...`)),await this.driver.tap(Se.bounds.centerX,Se.bounds.centerY,s)):(console.log(D.gray("Navigating back to main view...")),await this.driver.pressKey(4,s)),await new Promise(Me=>setTimeout(Me,1200));let Ne=await this.driver.getForegroundPackage(s);(!Ne||!Ne.includes(e))&&(console.log(D.yellow(`Restoring ${e} foreground after back navigation...`)),await this.driver.launchApp(e,s),await new Promise(Me=>setTimeout(Me,2e3)));let ne=await this.getCleanUiHierarchy(e,s);v=ne.xml,C=ne.flat,this.visitedScreenHashes.add(ge(C));let fe=await this.runErrorSentinel(e,s,"Post-Back-Restore"),Ge=fe.hasError?"FAIL":"PASS",_t=await h(Ge,!0);this.reporter.logStep("List Dive","Navigated back to master screen","Back",Ge,"KEYCODE_BACK",_t,fe.hasError?{errors:fe.errors}:void 0),Ge==="PASS"&&console.log(D.green("\u2714 Master view restored."))}else console.log(D.gray("No list items found for master-detail exploration."))}}console.log(D.yellow(`
851
+ [5/5] Inspecting Navigation Tabs...`));let H=await this.driver.getForegroundPackage(s);(!H||!H.includes(e))&&(console.log(D.gray(`Restoring ${e} foreground for tab traversal...`)),await this.driver.launchApp(e,s),await new Promise(se=>setTimeout(se,2e3))),await this.dismissSoftKeyboard(s);let be=await this.getCleanUiHierarchy(e,s);v=be.xml,C=be.flat;let J=Dt(C,void 0,e);if(J.length>1){console.log(D.magenta(`\u26A1 Found ${J.length} navigation tab(s). Traversal sequence initiated...`));let se=J.slice(0,i),X=1;for(let O of se){let Y=O.text||O.contentDesc||`Tab #${X}`;console.log(D.gray(` - Visiting ${Y}...`)),await this.dismissSoftKeyboard(s);let A=Math.min(O.bounds.centerY,O.bounds.y2-4);this.executedStepCount++,await this.driver.tap(O.bounds.centerX,A,s),await new Promise(w=>setTimeout(w,1500)),await this.packageJailGuard(e,s);let M=await this.getCleanUiHierarchy(e,s);v=M.xml,C=M.flat;let R=ge(C);this.visitedScreenHashes.add(R),this.memory.markScreenCrawled(R,[Y]);let F=await this.runErrorSentinel(e,s,`Tab-${Y}`),V=F.hasError?"FAIL":"PASS",E=await h(V,!0);if(this.reporter.logStep("Tab Traversal",`Navigated to tab "${Y}"`,"Tap",V,Y,E,F.hasError?{errors:F.errors}:void 0),console.log(V==="PASS"?D.green(` \u2714 Tab "${Y}" loaded cleanly.`):D.red(` \u2716 Tab "${Y}" triggered errors.`)),this.executedStepCount<c&&this.visitedScreenHashes.size<d){let w=[],N=b*.08,L=b*.88,le=ne=>ne.bounds.centerY>N&&ne.bounds.centerY<L&&ne.clickable&&ne.bounds.width>30&&ne.bounds.height>20&&J.every(fe=>Math.abs(fe.bounds.centerX-ne.bounds.centerX)>40||Math.abs(fe.bounds.centerY-ne.bounds.centerY)>40),j=nt(C,{width:S,height:b}).filter(le);for(let ne of j.slice(0,3))w.push({node:ne,type:"list"});let Se=Ue(C).filter(ne=>!(!le(ne)||Ke([ne],b)));for(let ne of Se.slice(0,4))w.push({node:ne,type:"button"});let Ne=mt(C).filter(le);for(let ne of Ne.slice(0,2))w.push({node:ne,type:"toggle"});for(let ne of w){if(this.executedStepCount>=c||this.visitedScreenHashes.size>=d)break;let fe=ne.node;if(Re(fe)){this.externalSkippedList.push(fe.text||fe.contentDesc||"External Link");continue}if(Ie(fe,a,o)){let pt=fe.text||fe.contentDesc||"Destructive Action";this.safetyHitList.push(pt);continue}let Ge=fe.text||fe.contentDesc||fe.resourceId||`${ne.type} element`;console.log(D.gray(` Sub-crawl [${Y}]: Exercising ${ne.type} "${Ge.slice(0,40)}"...`)),this.executedStepCount++,await this.driver.tap(fe.bounds.centerX,fe.bounds.centerY,s),await new Promise(pt=>setTimeout(pt,1200)),await this.dismissSoftKeyboard(s),await this.packageJailGuard(e,s);let _t=await this.getCleanUiHierarchy(e,s);v=_t.xml,C=_t.flat;let Me=ge(C),Yi=!this.visitedScreenHashes.has(Me);this.visitedScreenHashes.add(Me);let es=await this.runErrorSentinel(e,s,`Sub-${Ge.slice(0,30)}`),Zs=es.hasError?"FAIL":"PASS",Vi=await h(Zs,Yi);if(this.reporter.logStep("Tab Sub-Crawl",`Tested ${ne.type} "${Ge}" under tab "${Y}"`,"Tap",Zs,Ge,Vi,es.hasError?{errors:es.errors}:void 0),Me!==R){console.log(D.cyan(` \u{1F50E} Screen transitioned. Discovered new screen state [${Me.slice(0,8)}]`));let pt=Ue(C).filter(Fe=>le(Fe)&&!Ie(Fe,a,o)&&!Re(Fe));if(pt.length>0&&this.executedStepCount<c){let Fe=pt[0],Xi=Fe.text||Fe.contentDesc||"Child Action";console.log(D.gray(` Exercising child action "${Xi.slice(0,30)}"...`)),this.executedStepCount++,await this.driver.tap(Fe.bounds.centerX,Fe.bounds.centerY,s),await new Promise(Gi=>setTimeout(Gi,1e3)),await this.dismissSoftKeyboard(s)}console.log(D.gray(` Restoring ${Y} master view via Back...`)),await this.driver.pressBack(s),await new Promise(Fe=>setTimeout(Fe,1e3)),await this.dismissSoftKeyboard(s);let ei=await this.getCleanUiHierarchy(e,s);v=ei.xml,C=ei.flat}}}X++}console.log(D.green("\u2714 Navigation tabs traversed successfully!"))}else console.log(D.gray("Single-screen or tabs not detected at screen footer."));for(let se of this.visitedScreenHashes)this.memory.markScreenCrawled(se);await this.memory.save();let re=this.memory.getStats();this.reporter.logStep("Coverage Audit",`State Graph Coverage: Visited ${this.visitedScreenHashes.size} unique screen state(s). Memory Engine cached ${re.crawledScreens} crawled screen(s).`,"Verify","PASS"),await this.runErrorSentinel(e,s,"Final-State");let _=await this.reporter.generateReport(),me=_.failedSteps===0&&_.errorsDetected.length===0;console.log(me?D.bold.green(`
852
852
  \u2728 PromptTest Exploration Complete \u2014 All Steps Passed!`):D.bold.red(`
853
853
  \u26A0\uFE0F PromptTest Exploration Complete \u2014 Issues Detected!`)),console.log(D.white(`Summary: ${_.passedSteps} passed, ${_.warnSteps} warnings, ${_.failedSteps} failed, ${_.errorsDetected.length} errors detected.`)),this.safetyHitList.length>0&&console.log(D.cyan(`\u{1F6E1}\uFE0F Safety Shield: Blocked ${this.safetyHitList.length} destructive action(s) [${this.safetyHitList.join(", ")}].`)),console.log(D.cyan(`\u{1F5FA}\uFE0F State Graph Coverage: Visited ${this.visitedScreenHashes.size} unique screen state(s).`)),console.log(D.cyan(`\u{1F9E0} Memory Engine Coverage: ${re.crawledScreens} crawled screen(s) indexed offline.`)),console.log(D.cyan(`Full Audit Report generated at: output/prompttest-report.md
854
- `))}finally{m&&lt(m)}}async runErrorSentinel(t,e,s){let n=[];try{let[r,i]=await Promise.all([this.driver.checkCrashes(t,e),this.driver.getUiHierarchy(e)]);if(r){let l=`Crash in ${s}: ${r.slice(0,300)}`;console.log(D.bold.red(`\u{1F6A8} FATAL EXCEPTION DETECTED in ${t} [${s}]!`)),this.reporter.logError(l),n.push(l)}let{flat:o}=pe(i),a=dn(o);if(a.length>0)for(let l of a){let c=l.text||l.contentDesc,u=`UI Error dialog in ${s}: "${c}"`;console.log(D.bold.yellow(`\u26A0\uFE0F Error Dialog/Banner on screen [${s}]: "${c}"`)),this.reporter.logError(u),n.push(u)}}catch{}return{hasError:n.length>0,errors:n}}},An=new Rt;Ft();je();Qe();Je();Ft();Ae();Qe();Je();Qt();Xt();Ft();Ae();Qe();Je();Qt();ft();It();Xt();At();je();Oe();Yt();Pe();Pe();Os();js();Ys();rt();Hs();Gs();Ks();zs();qs();function Wn(p,t,e){return new Ze(p,t,e)}At();function Ci(){try{let p=new URL(import.meta.url).pathname.replace(/^\/([a-zA-Z]:)/,"$1"),t=Te.dirname(p),e=[Te.resolve(t,"../package.json"),Te.resolve(t,"../../package.json"),Te.resolve(process.cwd(),"package.json")];for(let s of e)if(ye.existsSync(s)){let n=JSON.parse(ye.readFileSync(s,"utf-8"));if(n.name==="prompttest"&&n.version)return n.version}}catch{}return"1.1.0"}async function Ii(){let p=process.argv.slice(2),t=p[0]||"help";if(p.includes("--version")||p.includes("-v")||t==="version"){console.log(Ci());return}switch(t){case"devices":{console.log(k.cyan(`
855
- \u{1F4F1} Scanning for Android Devices...`));let e=await Q.getConnectedDevices();if(e.length===0){console.log(k.yellow("No Android devices found. Make sure USB debugging is enabled."));return}console.log(k.green(`Found ${e.length} device(s):`));for(let s of e){let n=s.state==="device"?k.green:k.red;console.log(`- ${k.bold(s.serial)} [${n(s.state)}] ${s.model?`Model: ${s.model}`:""}`)}console.log();break}case"status":{let e=p.slice(1),s=e.find(a=>a.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0);console.log(k.cyan(`
856
- \u{1F50D} Inspecting Foreground Application & UI Components...`));let n=await Q.getConnectedDevices(),r=s?n.find(a=>a.serial===s):n.find(a=>a.state==="device");if(!r||r.state!=="device"){console.log(s?k.red(`Device "${s}" is not connected or unauthorized. Check 'prompttest devices'.`):k.red("No authorized device online. Check 'prompttest devices'."));return}let i=r.serial,o=await Q.getForegroundPackage(i);s&&console.log(k.gray("Target Device: ")+k.bold.white(i)),console.log(k.gray("Foreground Package: ")+k.bold.green(o||"None / Launcher"));try{let a=await Q.getUiHierarchy(i),{flat:l}=pe(a),c=_e(l),u=Ue(l),h=it(l),d=Dt(l);console.log(k.white(`
857
- On-Screen Component Breakdown:`)),console.log(`- \u{1F4DD} Input / Form Fields: ${k.bold.magenta(c.length.toString())}`);for(let g of c)console.log(` \u2022 "${g.text||g.contentDesc||g.resourceId}"`);console.log(`- \u{1F518} Action Buttons: ${k.bold.blue(u.length.toString())}`);for(let g of u.slice(0,5))console.log(` \u2022 "${g.text||g.contentDesc||g.resourceId}"`);console.log(`- \u{1F4CB} List Items: ${k.bold.yellow(h.length.toString())}`),console.log(`- \u{1F4D1} Navigation Tabs: ${k.bold.cyan(d.length.toString())}`),console.log()}catch(a){let l=a instanceof Error?a.message:String(a);console.log(k.red(`Error reading UI tree: ${l}`))}break}case"explore":{let e=p.slice(1),s=e.find(m=>m.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),n=e.find(m=>m.startsWith("--safety-mode="))?.replace("--safety-mode=",""),r=e.find(m=>m.startsWith("--safety-blacklist="))?.replace("--safety-blacklist=","")||e.find(m=>m.startsWith("--blacklist="))?.replace("--blacklist=",""),i=r?r.split(",").map(m=>m.trim().replace(/^["']|["']$/g,"")).filter(Boolean):void 0,o=e.find(m=>m.startsWith("--max-tabs="))?parseInt(e.find(m=>m.startsWith("--max-tabs=")).replace("--max-tabs=",""),10):void 0,a=e.find(m=>m.startsWith("--max-screens="))?parseInt(e.find(m=>m.startsWith("--max-screens=")).replace("--max-screens=",""),10):void 0,l=e.find(m=>m.startsWith("--max-depth="))?parseInt(e.find(m=>m.startsWith("--max-depth=")).replace("--max-depth=",""),10):void 0,c=e.find(m=>m.startsWith("--step-budget="))?parseInt(e.find(m=>m.startsWith("--step-budget=")).replace("--step-budget=",""),10):void 0,u=e.find(m=>m.startsWith("--screenshots="))?.replace("--screenshots=",""),h=e.find(m=>m.startsWith("--strategy="))?.replace("--strategy=",""),g=e.filter((m,y,S)=>!m.startsWith("-")&&m!==s&&(y===0||S[y-1]!=="-s"))[0];if(!g){let m=await Q.getForegroundPackage(s);m&&!m.includes("launcher")?(g=m,console.log(k.gray("Auto-detected active package: ")+k.bold.green(g))):(console.log(k.red("Error: No package specified and no foreground application detected.")),console.log(k.yellow('Usage: npx prompttest explore <package_name> [--strategy=dfs|heuristic] [--serial=<id>] [--safety-mode=strict|moderate|interactive|disabled] [--safety-blacklist="kw1,kw2"] [--max-tabs=N] [--max-screens=N] [--step-budget=N] [--screenshots=state-change|failure-only|all]')),process.exit(1))}await An.explore({packageName:g,serial:s,strategy:h||"dfs",safetyMode:n,safetyBlacklist:i,maxTabs:o,maxScreens:a,maxDepth:l,stepBudget:c,screenshots:u});break}case"doctor":{let e=p.slice(1),s=e.includes("--json"),n=e.find(c=>c.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),i=e.filter((c,u,h)=>!c.startsWith("-")&&c!==n&&(u===0||h[u-1]!=="-s"))[0],{runDoctor:o,formatDoctorReport:a}=await Promise.resolve().then(()=>(Ks(),Bn)),l=await o(Q,{packageName:i,serial:n,json:s});console.log(s?JSON.stringify(l,null,2):a(l)),l.allPassed||(process.exitCode=1);break}case"repl":{let e=p.slice(1),s=e.find(o=>o.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),r=e.filter((o,a,l)=>!o.startsWith("-")&&o!==s&&(a===0||l[a-1]!=="-s"))[0],{startRepl:i}=await Promise.resolve().then(()=>(zs(),Un));await i(Q,Mt,{serial:s,packageName:r});break}case"report":case"merge-reports":{let e=p.slice(1),s=e.includes("--json"),r=e.filter(l=>!l.startsWith("-"))[0]||"output",{mergeReports:i,generateAggregatedHtml:o}=await Promise.resolve().then(()=>(qs(),jn)),a=i(r);if(s)console.log(JSON.stringify(a,null,2));else{let l=a.overallConfidence,c=l.grade==="A"?k.bold.green:l.grade==="B"?k.bold.blue:l.grade==="C"?k.bold.yellow:k.bold.red;if(console.log(k.bold.cyan(`
854
+ `))}finally{m&&lt(m)}}async runErrorSentinel(t,e,s){let i=[];try{let[r,n]=await Promise.all([this.driver.checkCrashes(t,e),this.driver.getUiHierarchy(e)]);if(r){let d=`Crash in ${s}: ${r.slice(0,300)}`;console.log(D.bold.red(`\u{1F6A8} FATAL EXCEPTION DETECTED in ${t} [${s}]!`)),this.reporter.logError(d),i.push(d)}let{flat:o}=pe(n),a=li(o);if(a.length>0)for(let d of a){let c=d.text||d.contentDesc,l=`UI Error dialog in ${s}: "${c}"`;console.log(D.bold.yellow(`\u26A0\uFE0F Error Dialog/Banner on screen [${s}]: "${c}"`)),this.reporter.logError(l),i.push(l)}}catch{}return{hasError:i.length>0,errors:i}}},Pi=new Rt;Ft();je();Qe();Je();Ft();Ae();Qe();Je();Qt();Xt();Ft();Ae();Qe();Je();Qt();ft();It();Xt();At();je();Oe();Yt();Pe();Pe();Os();js();Ys();rt();Hs();Gs();Ks();zs();qs();function Wi(p,t,e){return new Ze(p,t,e)}At();function Cn(){try{let p=new URL(import.meta.url).pathname.replace(/^\/([a-zA-Z]:)/,"$1"),t=Te.dirname(p),e=[Te.resolve(t,"../package.json"),Te.resolve(t,"../../package.json"),Te.resolve(process.cwd(),"package.json")];for(let s of e)if(ye.existsSync(s)){let i=JSON.parse(ye.readFileSync(s,"utf-8"));if(i.name==="prompttest"&&i.version)return i.version}}catch{}return"1.1.0"}async function In(){let p=process.argv.slice(2),t=p[0]||"help";if(p.includes("--version")||p.includes("-v")||t==="version"){console.log(Cn());return}switch(t){case"devices":{console.log(k.cyan(`
855
+ \u{1F4F1} Scanning for Android Devices...`));let e=await Q.getConnectedDevices();if(e.length===0){console.log(k.yellow("No Android devices found. Make sure USB debugging is enabled."));return}console.log(k.green(`Found ${e.length} device(s):`));for(let s of e){let i=s.state==="device"?k.green:k.red;console.log(`- ${k.bold(s.serial)} [${i(s.state)}] ${s.model?`Model: ${s.model}`:""}`)}console.log();break}case"status":{let e=p.slice(1),s=e.find(a=>a.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0);console.log(k.cyan(`
856
+ \u{1F50D} Inspecting Foreground Application & UI Components...`));let i=await Q.getConnectedDevices(),r=s?i.find(a=>a.serial===s):i.find(a=>a.state==="device");if(!r||r.state!=="device"){console.log(s?k.red(`Device "${s}" is not connected or unauthorized. Check 'prompttest devices'.`):k.red("No authorized device online. Check 'prompttest devices'."));return}let n=r.serial,o=await Q.getForegroundPackage(n);s&&console.log(k.gray("Target Device: ")+k.bold.white(n)),console.log(k.gray("Foreground Package: ")+k.bold.green(o||"None / Launcher"));try{let a=await Q.getUiHierarchy(n),{flat:d}=pe(a),c=_e(d),l=Ue(d),h=nt(d),u=Dt(d);console.log(k.white(`
857
+ On-Screen Component Breakdown:`)),console.log(`- \u{1F4DD} Input / Form Fields: ${k.bold.magenta(c.length.toString())}`);for(let g of c)console.log(` \u2022 "${g.text||g.contentDesc||g.resourceId}"`);console.log(`- \u{1F518} Action Buttons: ${k.bold.blue(l.length.toString())}`);for(let g of l.slice(0,5))console.log(` \u2022 "${g.text||g.contentDesc||g.resourceId}"`);console.log(`- \u{1F4CB} List Items: ${k.bold.yellow(h.length.toString())}`),console.log(`- \u{1F4D1} Navigation Tabs: ${k.bold.cyan(u.length.toString())}`),console.log()}catch(a){let d=a instanceof Error?a.message:String(a);console.log(k.red(`Error reading UI tree: ${d}`))}break}case"explore":{let e=p.slice(1),s=e.find(m=>m.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),i=e.find(m=>m.startsWith("--safety-mode="))?.replace("--safety-mode=",""),r=e.find(m=>m.startsWith("--safety-blacklist="))?.replace("--safety-blacklist=","")||e.find(m=>m.startsWith("--blacklist="))?.replace("--blacklist=",""),n=r?r.split(",").map(m=>m.trim().replace(/^["']|["']$/g,"")).filter(Boolean):void 0,o=e.find(m=>m.startsWith("--max-tabs="))?parseInt(e.find(m=>m.startsWith("--max-tabs=")).replace("--max-tabs=",""),10):void 0,a=e.find(m=>m.startsWith("--max-screens="))?parseInt(e.find(m=>m.startsWith("--max-screens=")).replace("--max-screens=",""),10):void 0,d=e.find(m=>m.startsWith("--max-depth="))?parseInt(e.find(m=>m.startsWith("--max-depth=")).replace("--max-depth=",""),10):void 0,c=e.find(m=>m.startsWith("--step-budget="))?parseInt(e.find(m=>m.startsWith("--step-budget=")).replace("--step-budget=",""),10):void 0,l=e.find(m=>m.startsWith("--screenshots="))?.replace("--screenshots=",""),h=e.find(m=>m.startsWith("--strategy="))?.replace("--strategy=",""),g=e.filter((m,y,S)=>!m.startsWith("-")&&m!==s&&(y===0||S[y-1]!=="-s"))[0];if(!g){let m=await Q.getForegroundPackage(s);m&&!m.includes("launcher")?(g=m,console.log(k.gray("Auto-detected active package: ")+k.bold.green(g))):(console.log(k.red("Error: No package specified and no foreground application detected.")),console.log(k.yellow('Usage: npx prompttest explore <package_name> [--strategy=dfs|heuristic] [--serial=<id>] [--safety-mode=strict|moderate|interactive|disabled] [--safety-blacklist="kw1,kw2"] [--max-tabs=N] [--max-screens=N] [--step-budget=N] [--screenshots=state-change|failure-only|all]')),process.exit(1))}await Pi.explore({packageName:g,serial:s,strategy:h||"dfs",safetyMode:i,safetyBlacklist:n,maxTabs:o,maxScreens:a,maxDepth:d,stepBudget:c,screenshots:l});break}case"doctor":{let e=p.slice(1),s=e.includes("--json"),i=e.find(c=>c.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),n=e.filter((c,l,h)=>!c.startsWith("-")&&c!==i&&(l===0||h[l-1]!=="-s"))[0],{runDoctor:o,formatDoctorReport:a}=await Promise.resolve().then(()=>(Ks(),Bi)),d=await o(Q,{packageName:n,serial:i,json:s});console.log(s?JSON.stringify(d,null,2):a(d)),d.allPassed||(process.exitCode=1);break}case"repl":{let e=p.slice(1),s=e.find(o=>o.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),r=e.filter((o,a,d)=>!o.startsWith("-")&&o!==s&&(a===0||d[a-1]!=="-s"))[0],{startRepl:n}=await Promise.resolve().then(()=>(zs(),Ui));await n(Q,Mt,{serial:s,packageName:r});break}case"report":case"merge-reports":{let e=p.slice(1),s=e.includes("--json"),r=e.filter(d=>!d.startsWith("-"))[0]||"output",{mergeReports:n,generateAggregatedHtml:o}=await Promise.resolve().then(()=>(qs(),ji)),a=n(r);if(s)console.log(JSON.stringify(a,null,2));else{let d=a.overallConfidence,c=d.grade==="A"?k.bold.green:d.grade==="B"?k.bold.blue:d.grade==="C"?k.bold.yellow:k.bold.red;if(console.log(k.bold.cyan(`
858
858
  \u{1F4CA} PromptTest Enterprise Matrix Aggregator`)),console.log(k.gray(`Aggregated ${a.totalRuns} run(s) across ${a.uniqueDevices.length} device(s) from "${r}":
859
- `)),console.log(` \u2022 Overall Pass Rate: ${k.bold.white(`${Math.round(a.overallPassRate*100)}%`)} (${a.passedSteps}/${a.totalSteps} steps)`),console.log(` \u2022 Failed Steps: ${k.bold.red(a.failedSteps.toString())}`),console.log(` \u2022 Release Confidence: ${c(`Grade ${l.grade} (${l.score}%) \u2014 ${l.verdict}`)}`),console.log(` \u2022 Assessment: ${k.gray(l.rationale)}
860
- `),a.deviceSummaries.length>0){console.log(k.white("Device Matrix Breakdown:"));for(let u of a.deviceSummaries)console.log(` - [${k.cyan(u.deviceId)}] ${k.bold(u.suiteName)}: ${u.passedSteps}/${u.totalSteps} passed (Grade ${u.confidenceGrade}, ${u.confidenceScore}%)`);console.log()}try{let u=Te.resolve(process.cwd(),"output");ye.existsSync(u)||ye.mkdirSync(u,{recursive:!0});let h=o(a),d=Te.join(u,"aggregated-dashboard.html"),g=Te.join(u,"aggregated-results.json");ye.writeFileSync(d,h,"utf-8"),ye.writeFileSync(g,JSON.stringify(a,null,2),"utf-8"),console.log(k.green("\u2714 Saved executive dashboard to: output/aggregated-dashboard.html")),console.log(k.green(`\u2714 Saved aggregated metrics to: output/aggregated-results.json
861
- `))}catch{}}a.overallConfidence.verdict==="RELEASE_BLOCKER"&&(process.exitCode=1);break}case"record":{let e=p.slice(1),s=e.includes("--append"),n=e.find(a=>a.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),i=e.filter((a,l,c)=>!a.startsWith("-")&&a!==n&&(l===0||c[l-1]!=="-s"))[0],{autonomousRecorder:o}=await Promise.resolve().then(()=>(Qt(),Mn));await o.startRecording(i,n,{append:s});break}case"init-ci":{console.log(k.cyan(`
862
- \u2699\uFE0F Setting up GitHub Actions CI Workflows for PromptTest...`));let e=Te.resolve(".github","workflows");ye.existsSync(e)||ye.mkdirSync(e,{recursive:!0});let s=Te.join(e,"unit.yml"),n=Te.join(e,"device.yml"),r=`name: PromptTest Unit & Quality CI
859
+ `)),console.log(` \u2022 Overall Pass Rate: ${k.bold.white(`${Math.round(a.overallPassRate*100)}%`)} (${a.passedSteps}/${a.totalSteps} steps)`),console.log(` \u2022 Failed Steps: ${k.bold.red(a.failedSteps.toString())}`),console.log(` \u2022 Release Confidence: ${c(`Grade ${d.grade} (${d.score}%) \u2014 ${d.verdict}`)}`),console.log(` \u2022 Assessment: ${k.gray(d.rationale)}
860
+ `),a.deviceSummaries.length>0){console.log(k.white("Device Matrix Breakdown:"));for(let l of a.deviceSummaries)console.log(` - [${k.cyan(l.deviceId)}] ${k.bold(l.suiteName)}: ${l.passedSteps}/${l.totalSteps} passed (Grade ${l.confidenceGrade}, ${l.confidenceScore}%)`);console.log()}try{let l=Te.resolve(process.cwd(),"output");ye.existsSync(l)||ye.mkdirSync(l,{recursive:!0});let h=o(a),u=Te.join(l,"aggregated-dashboard.html"),g=Te.join(l,"aggregated-results.json");ye.writeFileSync(u,h,"utf-8"),ye.writeFileSync(g,JSON.stringify(a,null,2),"utf-8"),console.log(k.green("\u2714 Saved executive dashboard to: output/aggregated-dashboard.html")),console.log(k.green(`\u2714 Saved aggregated metrics to: output/aggregated-results.json
861
+ `))}catch{}}a.overallConfidence.verdict==="RELEASE_BLOCKER"&&(process.exitCode=1);break}case"record":{let e=p.slice(1),s=e.includes("--append"),i=e.find(a=>a.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),n=e.filter((a,d,c)=>!a.startsWith("-")&&a!==i&&(d===0||c[d-1]!=="-s"))[0],{autonomousRecorder:o}=await Promise.resolve().then(()=>(Qt(),Mi));await o.startRecording(n,i,{append:s});break}case"init-ci":{console.log(k.cyan(`
862
+ \u2699\uFE0F Setting up GitHub Actions CI Workflows for PromptTest...`));let e=Te.resolve(".github","workflows");ye.existsSync(e)||ye.mkdirSync(e,{recursive:!0});let s=Te.join(e,"unit.yml"),i=Te.join(e,"device.yml"),r=`name: PromptTest Unit & Quality CI
863
863
 
864
864
  on:
865
865
  push:
@@ -914,7 +914,7 @@ jobs:
914
914
  name: coverage-report
915
915
  path: coverage/
916
916
  if-no-files-found: ignore
917
- `,i=`name: PromptTest Android Emulator CI
917
+ `,n=`name: PromptTest Android Emulator CI
918
918
 
919
919
  on:
920
920
  workflow_dispatch:
@@ -983,38 +983,38 @@ jobs:
983
983
  name: prompttest-device-artifacts
984
984
  path: output/
985
985
  if-no-files-found: ignore
986
- `;ye.writeFileSync(s,r,"utf-8"),ye.writeFileSync(n,i,"utf-8"),console.log(k.bold.green("\u2714 Created GitHub Actions workflows:")),console.log(k.cyan(` \u2022 ${s} (Headless Node 18 & 20 quality gates)`)),console.log(k.cyan(` \u2022 ${n} (Android Emulator API 33 live specs)
987
- `));break}case"benchmark":{let e=p.slice(1),s=e.includes("--json"),n=e.find(h=>h.startsWith("--iterations=")),r=n?parseInt(n.replace("--iterations=",""),10):5,i=e.find(h=>h.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),a=e.filter((h,d,g)=>!h.startsWith("-")&&h!==i&&(d===0||g[d-1]!=="-s"))[0];s||console.log(k.cyan(`
988
- \u26A1 Running PromptTest Performance Diagnostic Benchmark...`));let{runBenchmark:l,formatBenchmarkTable:c}=await Promise.resolve().then(()=>(Gs(),On)),u=await l(Q,{iterations:r,serial:i,packageName:a});console.log(s?JSON.stringify(u,null,2):c(u));break}case"run":{let e=[...p.slice(1)],s=e.includes("--screenshots")||e.includes("--all-screenshots")||e.includes("--screenshots=all"),n=e.indexOf("--screenshots");n!==-1&&e[n+1]==="all"&&(s=!0,e.splice(n+1,1));let r=e.includes("--continue")||e.includes("--continue-on-error"),i=e.includes("--fresh")||e.includes("--cold-start"),o=e.includes("--all-devices"),a=e.includes("--resume"),l=e.includes("--save-baseline"),c=e.includes("--compare-baseline"),u=e.find(w=>w.startsWith("--baseline-threshold=")),h=u?parseFloat(u.replace("--baseline-threshold=","")):void 0,d=e.find(w=>w.startsWith("--reporter="))?.replace("--reporter=",""),g=e.find(w=>w.startsWith("--apk="))?.replace("--apk=",""),m=e.includes("--video"),y=e.includes("--heal"),S=e.includes("--expand"),b=e.includes("--expand-apply"),f=e.includes("--no-ai"),T=e.includes("--benchmark"),P=e.find(w=>w.startsWith("--reporters=")),I=P?P.replace("--reporters=","").split(",").map(w=>w.trim()):void 0,v=e.find(w=>w.startsWith("--data="))?.replace("--data=",""),$=e.find(w=>w.startsWith("--iterations=")),j=$?parseInt($.replace("--iterations=",""),10):void 0,G=e.find(w=>w.startsWith("--only-row=")),H=G?parseInt(G.replace("--only-row=",""),10):void 0,be=e.find(w=>w.startsWith("--locale="))?.replace("--locale=",""),J=e.includes("--dry-run"),re=e.includes("--list-steps"),_=e.includes("--json"),me=e.find(w=>w.startsWith("--only="))?.replace("--only=",""),se=e.find(w=>w.startsWith("--tags="))?.replace("--tags=",""),X=e.includes("--embed-screenshots"),O=e.find(w=>w.startsWith("--serve=")||w==="--serve"),Y;if(O)if(O.startsWith("--serve=")){let w=parseInt(O.replace("--serve=",""),10);Y=isNaN(w)?4040:w}else{let w=e.indexOf("--serve"),N=e[w+1];N&&/^\d+$/.test(N)?(Y=parseInt(N,10),e.splice(w+1,1)):Y=4040}let A=e.find(w=>w.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),M={};for(let w of e)if(w.startsWith("--var:")){let[N,L]=w.replace("--var:","").split("=");N&&L&&(M[N]=L)}let R=e.filter((w,N,L)=>!(w.startsWith("-")||w===A||N>0&&L[N-1]==="-s")),F=R[0],V=R[1];if(F||(console.log(k.red("Error: Please specify a spec file path. E.g. prompttest run specs/coachconnect_flow.txt")),process.exit(3)),ye.existsSync(F)&&ye.statSync(F).isDirectory()&&V&&!V.startsWith("--")){let w=Te.join(F,V);ye.existsSync(w)&&(F=w,V=R[2])}if(S||b){console.log(k.cyan(`
986
+ `;ye.writeFileSync(s,r,"utf-8"),ye.writeFileSync(i,n,"utf-8"),console.log(k.bold.green("\u2714 Created GitHub Actions workflows:")),console.log(k.cyan(` \u2022 ${s} (Headless Node 18 & 20 quality gates)`)),console.log(k.cyan(` \u2022 ${i} (Android Emulator API 33 live specs)
987
+ `));break}case"benchmark":{let e=p.slice(1),s=e.includes("--json"),i=e.find(h=>h.startsWith("--iterations=")),r=i?parseInt(i.replace("--iterations=",""),10):5,n=e.find(h=>h.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),a=e.filter((h,u,g)=>!h.startsWith("-")&&h!==n&&(u===0||g[u-1]!=="-s"))[0];s||console.log(k.cyan(`
988
+ \u26A1 Running PromptTest Performance Diagnostic Benchmark...`));let{runBenchmark:d,formatBenchmarkTable:c}=await Promise.resolve().then(()=>(Gs(),Oi)),l=await d(Q,{iterations:r,serial:n,packageName:a});console.log(s?JSON.stringify(l,null,2):c(l));break}case"run":{let e=[...p.slice(1)],s=e.includes("--screenshots")||e.includes("--all-screenshots")||e.includes("--screenshots=all"),i=e.indexOf("--screenshots");i!==-1&&e[i+1]==="all"&&(s=!0,e.splice(i+1,1));let r=e.includes("--continue")||e.includes("--continue-on-error"),n=e.includes("--fresh")||e.includes("--cold-start"),o=e.includes("--all-devices"),a=e.includes("--resume"),d=e.includes("--save-baseline"),c=e.includes("--compare-baseline"),l=e.find(w=>w.startsWith("--baseline-threshold=")),h=l?parseFloat(l.replace("--baseline-threshold=","")):void 0,u=e.find(w=>w.startsWith("--reporter="))?.replace("--reporter=",""),g=e.find(w=>w.startsWith("--apk="))?.replace("--apk=",""),m=e.includes("--video"),y=e.includes("--heal"),S=e.includes("--expand"),b=e.includes("--expand-apply"),f=e.includes("--no-ai"),x=e.includes("--benchmark"),T=e.find(w=>w.startsWith("--reporters=")),$=T?T.replace("--reporters=","").split(",").map(w=>w.trim()):void 0,v=e.find(w=>w.startsWith("--data="))?.replace("--data=",""),C=e.find(w=>w.startsWith("--iterations=")),U=C?parseInt(C.replace("--iterations=",""),10):void 0,G=e.find(w=>w.startsWith("--only-row=")),H=G?parseInt(G.replace("--only-row=",""),10):void 0,be=e.find(w=>w.startsWith("--locale="))?.replace("--locale=",""),J=e.includes("--dry-run"),re=e.includes("--list-steps"),_=e.includes("--json"),me=e.find(w=>w.startsWith("--only="))?.replace("--only=",""),se=e.find(w=>w.startsWith("--tags="))?.replace("--tags=",""),X=e.includes("--embed-screenshots"),O=e.find(w=>w.startsWith("--serve=")||w==="--serve"),Y;if(O)if(O.startsWith("--serve=")){let w=parseInt(O.replace("--serve=",""),10);Y=isNaN(w)?4040:w}else{let w=e.indexOf("--serve"),N=e[w+1];N&&/^\d+$/.test(N)?(Y=parseInt(N,10),e.splice(w+1,1)):Y=4040}let A=e.find(w=>w.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),M={};for(let w of e)if(w.startsWith("--var:")){let[N,L]=w.replace("--var:","").split("=");N&&L&&(M[N]=L)}let R=e.filter((w,N,L)=>!(w.startsWith("-")||w===A||N>0&&L[N-1]==="-s")),F=R[0],V=R[1];if(F||(console.log(k.red("Error: Please specify a spec file path. E.g. prompttest run specs/coachconnect_flow.txt")),process.exit(3)),ye.existsSync(F)&&ye.statSync(F).isDirectory()&&V&&!V.startsWith("--")){let w=Te.join(F,V);ye.existsSync(w)&&(F=w,V=R[2])}if(S||b){console.log(k.cyan(`
989
989
  \u{1F916} Analyzing and expanding spec "${F}" using Semantic AI...`));let w=ye.readFileSync(F,"utf-8"),{expanded:N,stepsAdded:L}=await Mt.expandSpec(w);if(L>0?(console.log(k.green(`\u2714 Successfully expanded ${L} macro step(s)!`)),b?(ye.writeFileSync(F,N,"utf-8"),console.log(k.bold.green(`\u2714 Applied expanded steps directly to ${F}.
990
990
  `))):(console.log(k.yellow(`
991
991
  --- Preview of Expanded Spec (--expand-apply to overwrite) ---`)),console.log(k.gray(N)),console.log(k.yellow(`---------------------------------------------------------------
992
992
  `)))):console.log(k.gray(`No high-level macro steps detected for expansion.
993
- `)),!e.includes("--execute"))break}if(o){let N=(await Q.getConnectedDevices()).filter(U=>U.state==="device");N.length===0&&(console.log(k.red("No online devices found for multi-device run.")),process.exit(2)),console.log(k.bold.cyan(`
994
- \u{1F4F1} Multi-Device Matrix Execution across ${N.length} device(s):`));for(let U of N)console.log(`- ${U.serial} (${U.model||"Android"})`);let L=await Promise.allSettled(N.map(U=>{let Se=U.serial.replace(/[^a-zA-Z0-9._-]/g,"_");return Wn(new tt(U.serial),new Xe,new at(Te.join("output",Se))).runSpec(F,{packageName:V,serial:U.serial,screenshotMode:s?"all":"on-failure",continueOnError:r,fresh:i,resume:a,saveBaseline:l,compareBaseline:c,baselineThreshold:h,apkPath:g,variables:M,video:m,reporters:I,heal:y,noAi:f,dataFile:v,iterations:j,onlyRow:H,locale:be,benchmark:T,dryRun:J,listSteps:re,only:me,tags:se,json:_})}));console.log(k.bold.green(`
995
- \u2728 Multi-Device Execution Finished!`)),L.some(U=>U.status==="rejected"||U.status==="fulfilled"&&U.value&&U.value.failedSteps>0)&&process.exit(1);break}let x=await Mt.runSpec(F,{packageName:V,serial:A,screenshotMode:s?"all":"on-failure",continueOnError:r,fresh:i,resume:a,saveBaseline:l,compareBaseline:c,baselineThreshold:h,apkPath:g,variables:M,video:m,reporters:I,heal:y,noAi:f,dataFile:v,iterations:j,onlyRow:H,locale:be,embedScreenshots:X,serve:Y,benchmark:T,dryRun:J,listSteps:re,only:me,tags:se,json:_,reporter:d?(await import(Te.resolve(d))).default:void 0});x&&x.failedSteps>0&&process.exit(1);break}case"watch":{let e=[...p.slice(1)],s=e.includes("--screenshots")||e.includes("--all-screenshots")||e.includes("--screenshots=all"),n=e.indexOf("--screenshots");n!==-1&&e[n+1]==="all"&&(s=!0,e.splice(n+1,1));let r=e.includes("--continue")||e.includes("--continue-on-error"),i=e.includes("--fresh")||e.includes("--cold-start"),o=e.includes("--resume"),a=e.includes("--save-baseline"),l=e.includes("--compare-baseline"),c=e.find(A=>A.startsWith("--baseline-threshold=")),u=c?parseFloat(c.replace("--baseline-threshold=","")):void 0,h=e.find(A=>A.startsWith("--reporter="))?.replace("--reporter=",""),d=e.find(A=>A.startsWith("--apk="))?.replace("--apk=",""),g=e.includes("--video"),m=e.includes("--heal"),y=e.includes("--no-ai"),S=e.find(A=>A.startsWith("--reporters=")),b=S?S.replace("--reporters=","").split(",").map(A=>A.trim()):void 0,f=e.find(A=>A.startsWith("--data="))?.replace("--data=",""),T=e.find(A=>A.startsWith("--iterations=")),P=T?parseInt(T.replace("--iterations=",""),10):void 0,I=e.find(A=>A.startsWith("--only-row=")),v=I?parseInt(I.replace("--only-row=",""),10):void 0,$=e.find(A=>A.startsWith("--locale="))?.replace("--locale=",""),j=e.includes("--embed-screenshots"),G=e.find(A=>A.startsWith("--serve=")||A==="--serve"),H;if(G)if(G.startsWith("--serve=")){let A=parseInt(G.replace("--serve=",""),10);H=isNaN(A)?4040:A}else{let A=e.indexOf("--serve"),M=e[A+1];M&&/^\d+$/.test(M)?(H=parseInt(M,10),e.splice(A+1,1)):H=4040}let be=e.find(A=>A.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),J={};for(let A of e)if(A.startsWith("--var:")){let[M,R]=A.replace("--var:","").split("=");M&&R&&(J[M]=R)}let re=e.filter((A,M,R)=>!(A.startsWith("-")||A===be||M>0&&R[M-1]==="-s")),_=re[0],me=re[1];_||(console.log(k.red("Error: Please specify a spec file path to watch. E.g. prompttest watch specs/flow.txt")),process.exit(3)),ye.existsSync(_)||(console.log(k.red(`Error: Spec file not found: ${_}`)),process.exit(3)),console.log(k.bold.cyan(`
993
+ `)),!e.includes("--execute"))break}if(o){let N=(await Q.getConnectedDevices()).filter(j=>j.state==="device");N.length===0&&(console.log(k.red("No online devices found for multi-device run.")),process.exit(2)),console.log(k.bold.cyan(`
994
+ \u{1F4F1} Multi-Device Matrix Execution across ${N.length} device(s):`));for(let j of N)console.log(`- ${j.serial} (${j.model||"Android"})`);let L=await Promise.allSettled(N.map(j=>{let Se=j.serial.replace(/[^a-zA-Z0-9._-]/g,"_");return Wi(new tt(j.serial),new Xe,new at(Te.join("output",Se))).runSpec(F,{packageName:V,serial:j.serial,screenshotMode:s?"all":"on-failure",continueOnError:r,fresh:n,resume:a,saveBaseline:d,compareBaseline:c,baselineThreshold:h,apkPath:g,variables:M,video:m,reporters:$,heal:y,noAi:f,dataFile:v,iterations:U,onlyRow:H,locale:be,benchmark:x,dryRun:J,listSteps:re,only:me,tags:se,json:_})}));console.log(k.bold.green(`
995
+ \u2728 Multi-Device Execution Finished!`)),L.some(j=>j.status==="rejected"||j.status==="fulfilled"&&j.value&&j.value.failedSteps>0)&&process.exit(1);break}let E=await Mt.runSpec(F,{packageName:V,serial:A,screenshotMode:s?"all":"on-failure",continueOnError:r,fresh:n,resume:a,saveBaseline:d,compareBaseline:c,baselineThreshold:h,apkPath:g,variables:M,video:m,reporters:$,heal:y,noAi:f,dataFile:v,iterations:U,onlyRow:H,locale:be,embedScreenshots:X,serve:Y,benchmark:x,dryRun:J,listSteps:re,only:me,tags:se,json:_,reporter:u?(await import(Te.resolve(u))).default:void 0});E&&E.failedSteps>0&&process.exit(1);break}case"watch":{let e=[...p.slice(1)],s=e.includes("--screenshots")||e.includes("--all-screenshots")||e.includes("--screenshots=all"),i=e.indexOf("--screenshots");i!==-1&&e[i+1]==="all"&&(s=!0,e.splice(i+1,1));let r=e.includes("--continue")||e.includes("--continue-on-error"),n=e.includes("--fresh")||e.includes("--cold-start"),o=e.includes("--resume"),a=e.includes("--save-baseline"),d=e.includes("--compare-baseline"),c=e.find(A=>A.startsWith("--baseline-threshold=")),l=c?parseFloat(c.replace("--baseline-threshold=","")):void 0,h=e.find(A=>A.startsWith("--reporter="))?.replace("--reporter=",""),u=e.find(A=>A.startsWith("--apk="))?.replace("--apk=",""),g=e.includes("--video"),m=e.includes("--heal"),y=e.includes("--no-ai"),S=e.find(A=>A.startsWith("--reporters=")),b=S?S.replace("--reporters=","").split(",").map(A=>A.trim()):void 0,f=e.find(A=>A.startsWith("--data="))?.replace("--data=",""),x=e.find(A=>A.startsWith("--iterations=")),T=x?parseInt(x.replace("--iterations=",""),10):void 0,$=e.find(A=>A.startsWith("--only-row=")),v=$?parseInt($.replace("--only-row=",""),10):void 0,C=e.find(A=>A.startsWith("--locale="))?.replace("--locale=",""),U=e.includes("--embed-screenshots"),G=e.find(A=>A.startsWith("--serve=")||A==="--serve"),H;if(G)if(G.startsWith("--serve=")){let A=parseInt(G.replace("--serve=",""),10);H=isNaN(A)?4040:A}else{let A=e.indexOf("--serve"),M=e[A+1];M&&/^\d+$/.test(M)?(H=parseInt(M,10),e.splice(A+1,1)):H=4040}let be=e.find(A=>A.startsWith("--serial="))?.replace("--serial=","")||(e.includes("-s")?e[e.indexOf("-s")+1]:void 0),J={};for(let A of e)if(A.startsWith("--var:")){let[M,R]=A.replace("--var:","").split("=");M&&R&&(J[M]=R)}let re=e.filter((A,M,R)=>!(A.startsWith("-")||A===be||M>0&&R[M-1]==="-s")),_=re[0],me=re[1];_||(console.log(k.red("Error: Please specify a spec file path to watch. E.g. prompttest watch specs/flow.txt")),process.exit(3)),ye.existsSync(_)||(console.log(k.red(`Error: Spec file not found: ${_}`)),process.exit(3)),console.log(k.bold.cyan(`
996
996
  \u{1F440} PromptTest Watch Mode Active`)),console.log(k.gray("Watching: ")+k.white.bold(_)),H&&console.log(k.gray("Live Monitor: ")+k.magenta.bold(`http://localhost:${typeof H=="number"?H:4040}`)),console.log(k.gray(`Press Ctrl+C to exit.
997
997
  `));let se=!1,X=!1,O=async()=>{if(se){X=!0;return}se=!0,X=!1;try{console.log(k.cyan(`
998
- \u26A1 [${new Date().toLocaleTimeString()}] Running ${_}...`)),await Mt.runSpec(_,{packageName:me,serial:be,screenshotMode:s?"all":"on-failure",continueOnError:r,fresh:i,resume:o,saveBaseline:a,compareBaseline:l,baselineThreshold:u,apkPath:d,variables:J,video:g,reporters:b,heal:m,noAi:y,dataFile:f,iterations:P,onlyRow:v,locale:$,embedScreenshots:j,serve:H,reporter:h?(await import(Te.resolve(h))).default:void 0})}catch(A){let M=A instanceof Error?A.message:String(A);console.error(k.red(`Run error: ${M}`))}finally{se=!1,X&&(X=!1,setTimeout(O,100))}};await O();let Y=null;ye.watch(_,()=>{Y&&clearTimeout(Y),Y=setTimeout(()=>{console.log(k.yellow(`
998
+ \u26A1 [${new Date().toLocaleTimeString()}] Running ${_}...`)),await Mt.runSpec(_,{packageName:me,serial:be,screenshotMode:s?"all":"on-failure",continueOnError:r,fresh:n,resume:o,saveBaseline:a,compareBaseline:d,baselineThreshold:l,apkPath:u,variables:J,video:g,reporters:b,heal:m,noAi:y,dataFile:f,iterations:T,onlyRow:v,locale:C,embedScreenshots:U,serve:H,reporter:h?(await import(Te.resolve(h))).default:void 0})}catch(A){let M=A instanceof Error?A.message:String(A);console.error(k.red(`Run error: ${M}`))}finally{se=!1,X&&(X=!1,setTimeout(O,100))}};await O();let Y=null;ye.watch(_,()=>{Y&&clearTimeout(Y),Y=setTimeout(()=>{console.log(k.yellow(`
999
999
  \u{1F4DD} Change detected in ${_}`)),O()},300)}),await new Promise(()=>{});break}case"wifi":{let e=p[1];console.log(k.cyan(`
1000
1000
  \u{1F4F6} Establishing Wireless ADB Connection...`));try{let s=await Q.connectWifi(e);s.success?(console.log(k.bold.green(`\u2714 Connected to ${s.target} over Wi-Fi successfully!`)),console.log(k.yellow("\u{1F449} You can now safely UNPLUG the USB cable.")),console.log(k.gray(`PromptTest will execute all tests wirelessly over ${s.target}
1001
- `))):(console.log(k.yellow(`Connection response: ${s.message}`)),process.exitCode=1)}catch(s){let n=s instanceof Error?s.message:String(s);console.log(k.red(`\u274C Wireless connection failed: ${n}`)),process.exit(1)}break}case"disconnect":{let e=p[1];console.log(k.cyan(`
1001
+ `))):(console.log(k.yellow(`Connection response: ${s.message}`)),process.exitCode=1)}catch(s){let i=s instanceof Error?s.message:String(s);console.log(k.red(`\u274C Wireless connection failed: ${i}`)),process.exit(1)}break}case"disconnect":{let e=p[1];console.log(k.cyan(`
1002
1002
  \u{1F50C} Disconnecting Wireless ADB...`));let s=await Q.disconnectWifi(e);console.log(k.green(`\u2714 ${s||"Disconnected wireless devices."}
1003
- `));break}case"memory":{let e=p[1];if(e==="clear"){let r=p[2]||await Q.getForegroundPackage()||"host.exp.exponent",i=await ve.clear(r);console.log(i?k.green(`
1003
+ `));break}case"memory":{let e=p[1];if(e==="clear"){let r=p[2]||await Q.getForegroundPackage()||"host.exp.exponent",n=await ve.clear(r);console.log(n?k.green(`
1004
1004
  \u2714 Cleared learned memory for package: ${k.bold(r)}
1005
1005
  `):k.yellow(`
1006
1006
  No learned memory found for package: ${r}
1007
- `));break}if(e==="export"){let r=p[2]||await Q.getForegroundPackage()||"host.exp.exponent",i=p[3];await ve.init(r);let o=await ve.exportMemory(i);console.log(k.green(`
1007
+ `));break}if(e==="export"){let r=p[2]||await Q.getForegroundPackage()||"host.exp.exponent",n=p[3];await ve.init(r);let o=await ve.exportMemory(n);console.log(k.green(`
1008
1008
  \u2714 Exported memory for [${k.bold(r)}] to: ${k.bold(o)}
1009
1009
  `));break}if(e==="import"){let r=p[2];r||(console.log(k.red(`
1010
1010
  Error: Please provide a source JSON file to import: npx prompttest memory import <file.json> [pkg]
1011
- `)),process.exit(1));let i=p[3]||await Q.getForegroundPackage()||"host.exp.exponent";await ve.init(i);let o=await ve.importMemory(r);console.log(k.green(`
1012
- \u2714 Successfully imported/merged ${k.bold(o)} mappings into [${k.bold(i)}]
1013
- `));break}if(e==="stats"){let r=p[2]||await Q.getForegroundPackage()||"host.exp.exponent";await ve.init(r);let i=ve.getStats();console.log(k.bold.cyan(`
1014
- \u{1F4CA} PromptTest Knowledge Memory Stats [Package: ${i.package}]`)),console.log(` \u2022 Total Learned Mappings: ${k.bold.white(i.totalMappings)}`),console.log(` \u2022 Lifetime Success Hits: ${k.bold.green(i.totalSuccesses)}`),console.log(` \u2022 Average Confidence: ${k.bold.yellow(`${Math.round(i.averageConfidence*100)}%`)}
1015
- `);break}let s=e||await Q.getForegroundPackage()||"host.exp.exponent";await ve.init(s);let n=ve.getMappingsList();if(console.log(k.bold.cyan(`
1016
- \u{1F9E0} PromptTest Autonomous Knowledge Memory [Package: ${s}]`)),n.length===0)console.log(k.gray("No learned component mappings recorded yet for this app.")),console.log(k.gray(`Run tests or autonomous exploration to build knowledge automatically.
1017
- `));else{console.log(k.white(`Active Learned Mappings (${n.length}):
1018
- `));for(let r of n)console.log(` \u2022 [${k.magenta(r.action)}] "${k.bold.yellow(r.canonicalIntent)}" \u2794 "${k.green(r.matchedIdentifier)}" `+k.gray(`(${r.matchType}, ${Math.round(r.confidence*100)}% conf, ${r.totalSuccesses||r.successCount} hits)`));console.log()}break}default:{console.log(k.bold.cyan(`
1011
+ `)),process.exit(1));let n=p[3]||await Q.getForegroundPackage()||"host.exp.exponent";await ve.init(n);let o=await ve.importMemory(r);console.log(k.green(`
1012
+ \u2714 Successfully imported/merged ${k.bold(o)} mappings into [${k.bold(n)}]
1013
+ `));break}if(e==="stats"){let r=p[2]||await Q.getForegroundPackage()||"host.exp.exponent";await ve.init(r);let n=ve.getStats();console.log(k.bold.cyan(`
1014
+ \u{1F4CA} PromptTest Knowledge Memory Stats [Package: ${n.package}]`)),console.log(` \u2022 Total Learned Mappings: ${k.bold.white(n.totalMappings)}`),console.log(` \u2022 Lifetime Success Hits: ${k.bold.green(n.totalSuccesses)}`),console.log(` \u2022 Average Confidence: ${k.bold.yellow(`${Math.round(n.averageConfidence*100)}%`)}
1015
+ `);break}let s=e||await Q.getForegroundPackage()||"host.exp.exponent";await ve.init(s);let i=ve.getMappingsList();if(console.log(k.bold.cyan(`
1016
+ \u{1F9E0} PromptTest Autonomous Knowledge Memory [Package: ${s}]`)),i.length===0)console.log(k.gray("No learned component mappings recorded yet for this app.")),console.log(k.gray(`Run tests or autonomous exploration to build knowledge automatically.
1017
+ `));else{console.log(k.white(`Active Learned Mappings (${i.length}):
1018
+ `));for(let r of i)console.log(` \u2022 [${k.magenta(r.action)}] "${k.bold.yellow(r.canonicalIntent)}" \u2794 "${k.green(r.matchedIdentifier)}" `+k.gray(`(${r.matchType}, ${Math.round(r.confidence*100)}% conf, ${r.totalSuccesses||r.successCount} hits)`));console.log()}break}default:{console.log(k.bold.cyan(`
1019
1019
  \u{1F9EA} PromptTest \u2014 Autonomous Mobile Testing & Visual QA Brain`)),console.log(`
1020
- Usage:`),console.log(" npx prompttest doctor [--json] Run environment health diagnostic check"),console.log(" npx prompttest repl [-s serial] [pkg] Interactive live REPL playground"),console.log(" npx prompttest merge-reports [dir] Aggregate multi-device reports into executive dashboard"),console.log(" npx prompttest devices List connected Android devices"),console.log(" npx prompttest wifi [ip[:port]] Connect to device over Wi-Fi (auto-detects IP if omitted)"),console.log(" npx prompttest disconnect [ip[:port]] Disconnect wireless Wi-Fi device"),console.log(" npx prompttest status Inspect current screen components & forms"),console.log(" npx prompttest record [spec.txt] [--append] Interactive record-and-replay (auto-backup & append)"),console.log(" npx prompttest explore [package] Run autonomous exploration (forms -> lists -> tabs)"),console.log(" [--safety-mode=strict|moderate|interactive|disabled] Policy level (default: strict)"),console.log(' [--safety-blacklist="kw1,kw2"] Additional blacklist keywords'),console.log(" [--max-screens=N] [--max-depth=N] [--step-budget=N] Exploration bounds & budgets"),console.log(" [--screenshots=state-change|failure-only|all] Visual snapshot capture policy"),console.log(" npx prompttest run <spec.txt> [pkg] Run test (Fail-Fast with Cascading Skip)"),console.log(" npx prompttest run <spec.txt> --apk=<path> Auto-install APK if not installed on device"),console.log(" npx prompttest run <spec.txt> --all-devices Run concurrently across all connected devices"),console.log(" npx prompttest run <spec.txt> --fresh Cold-restart target app before test suite begins"),console.log(" npx prompttest run <spec.txt> --continue Run test continuing through all steps on failure"),console.log(" npx prompttest run <spec.txt> --screenshots Capture full visual screenshots on every step"),console.log(" npx prompttest run <spec.txt> --resume Resume from last checkpoint on failure"),console.log(" npx prompttest run <spec.txt> --save-baseline Save screenshots as visual baseline"),console.log(" npx prompttest run <spec.txt> --compare-baseline Compare screenshots against saved baseline"),console.log(" npx prompttest run <spec.txt> --baseline-threshold=N Diff threshold 0-1 (default 0.02)"),console.log(" npx prompttest run <spec.txt> --video Record test session to MP4 video"),console.log(" npx prompttest run <spec.txt> --heal Enable automatic locator self-healing"),console.log(" npx prompttest run <spec.txt> --expand Preview AI macro intent expansion"),console.log(" npx prompttest run <spec.txt> --expand-apply Apply expanded steps directly to spec"),console.log(" npx prompttest run <spec.txt> --no-ai Force offline heuristic resolver"),console.log(" npx prompttest run <spec.txt> --reporters=json,html Output specific report formats"),console.log(" npx prompttest run <spec.txt> --reporter=<path> Load custom reporter module"),console.log(" npx prompttest run <spec.txt> --data=<path.csv|json> Execute data-driven test across rows"),console.log(" npx prompttest run <spec.txt> --iterations=N Repeat spec across N iterations or rows"),console.log(" npx prompttest run <spec.txt> --only-row=N Execute only specific 1-indexed data row"),console.log(" npx prompttest run <spec.txt> --locale=<code> Set active taxonomy locale (e.g. 'en', 'es', 'hi')"),console.log(" npx prompttest run <spec.txt> --embed-screenshots Inline base64 screenshots into standalone HTML report"),console.log(" npx prompttest run <spec.txt> --dry-run Validate spec syntax without device interaction"),console.log(" npx prompttest run <spec.txt> --list-steps Print parsed test steps table and exit"),console.log(' npx prompttest run <spec.txt> --only="1-3,5" Execute only specified step range or indices'),console.log(' npx prompttest run <spec.txt> --tags="smoke" Execute only specs matching metadata tags'),console.log(" npx prompttest run <spec.txt> --json Output machine-readable execution report JSON"),console.log(" npx prompttest run <spec.txt> --serve [port] Stream live test events over HTTP/SSE dashboard (default: 4040)"),console.log(" npx prompttest watch <spec.txt> Auto-rerun test on spec file changes with live monitor"),console.log(" npx prompttest init-ci Generate GitHub Actions workflows (unit.yml & device.yml)"),console.log(" npx prompttest memory [package] View learned component knowledge & aliases"),console.log(" npx prompttest memory stats [package] View memory health & accuracy statistics"),console.log(" npx prompttest memory export [pkg] [dest] Export learned memory to JSON file"),console.log(" npx prompttest memory import <file> [pkg] Import/merge shared knowledge from JSON"),console.log(" npx prompttest memory clear [package] Clear learned memory for an app"),console.log();break}}}Ii().catch(p=>{console.error(k.red(`Fatal Error: ${p.message}`));let t=typeof p.exitCode=="number"?p.exitCode:1;process.exit(t)});
1020
+ Usage:`),console.log(" npx prompttest doctor [--json] Run environment health diagnostic check"),console.log(" npx prompttest repl [-s serial] [pkg] Interactive live REPL playground"),console.log(" npx prompttest merge-reports [dir] Aggregate multi-device reports into executive dashboard"),console.log(" npx prompttest devices List connected Android devices"),console.log(" npx prompttest wifi [ip[:port]] Connect to device over Wi-Fi (auto-detects IP if omitted)"),console.log(" npx prompttest disconnect [ip[:port]] Disconnect wireless Wi-Fi device"),console.log(" npx prompttest status Inspect current screen components & forms"),console.log(" npx prompttest record [spec.txt] [--append] Interactive record-and-replay (auto-backup & append)"),console.log(" npx prompttest explore [package] Run autonomous exploration (forms -> lists -> tabs)"),console.log(" [--safety-mode=strict|moderate|interactive|disabled] Policy level (default: strict)"),console.log(' [--safety-blacklist="kw1,kw2"] Additional blacklist keywords'),console.log(" [--max-screens=N] [--max-depth=N] [--step-budget=N] Exploration bounds & budgets"),console.log(" [--screenshots=state-change|failure-only|all] Visual snapshot capture policy"),console.log(" npx prompttest run <spec.txt> [pkg] Run test (Fail-Fast with Cascading Skip)"),console.log(" npx prompttest run <spec.txt> --apk=<path> Auto-install APK if not installed on device"),console.log(" npx prompttest run <spec.txt> --all-devices Run concurrently across all connected devices"),console.log(" npx prompttest run <spec.txt> --fresh Cold-restart target app before test suite begins"),console.log(" npx prompttest run <spec.txt> --continue Run test continuing through all steps on failure"),console.log(" npx prompttest run <spec.txt> --screenshots Capture full visual screenshots on every step"),console.log(" npx prompttest run <spec.txt> --resume Resume from last checkpoint on failure"),console.log(" npx prompttest run <spec.txt> --save-baseline Save screenshots as visual baseline"),console.log(" npx prompttest run <spec.txt> --compare-baseline Compare screenshots against saved baseline"),console.log(" npx prompttest run <spec.txt> --baseline-threshold=N Diff threshold 0-1 (default 0.02)"),console.log(" npx prompttest run <spec.txt> --video Record test session to MP4 video"),console.log(" npx prompttest run <spec.txt> --heal Enable automatic locator self-healing"),console.log(" npx prompttest run <spec.txt> --expand Preview AI macro intent expansion"),console.log(" npx prompttest run <spec.txt> --expand-apply Apply expanded steps directly to spec"),console.log(" npx prompttest run <spec.txt> --no-ai Force offline heuristic resolver"),console.log(" npx prompttest run <spec.txt> --reporters=json,html Output specific report formats"),console.log(" npx prompttest run <spec.txt> --reporter=<path> Load custom reporter module"),console.log(" npx prompttest run <spec.txt> --data=<path.csv|json> Execute data-driven test across rows"),console.log(" npx prompttest run <spec.txt> --iterations=N Repeat spec across N iterations or rows"),console.log(" npx prompttest run <spec.txt> --only-row=N Execute only specific 1-indexed data row"),console.log(" npx prompttest run <spec.txt> --locale=<code> Set active taxonomy locale (e.g. 'en', 'es', 'hi')"),console.log(" npx prompttest run <spec.txt> --embed-screenshots Inline base64 screenshots into standalone HTML report"),console.log(" npx prompttest run <spec.txt> --dry-run Validate spec syntax without device interaction"),console.log(" npx prompttest run <spec.txt> --list-steps Print parsed test steps table and exit"),console.log(' npx prompttest run <spec.txt> --only="1-3,5" Execute only specified step range or indices'),console.log(' npx prompttest run <spec.txt> --tags="smoke" Execute only specs matching metadata tags'),console.log(" npx prompttest run <spec.txt> --json Output machine-readable execution report JSON"),console.log(" npx prompttest run <spec.txt> --serve [port] Stream live test events over HTTP/SSE dashboard (default: 4040)"),console.log(" npx prompttest watch <spec.txt> Auto-rerun test on spec file changes with live monitor"),console.log(" npx prompttest init-ci Generate GitHub Actions workflows (unit.yml & device.yml)"),console.log(" npx prompttest memory [package] View learned component knowledge & aliases"),console.log(" npx prompttest memory stats [package] View memory health & accuracy statistics"),console.log(" npx prompttest memory export [pkg] [dest] Export learned memory to JSON file"),console.log(" npx prompttest memory import <file> [pkg] Import/merge shared knowledge from JSON"),console.log(" npx prompttest memory clear [package] Clear learned memory for an app"),console.log();break}}}In().catch(p=>{console.error(k.red(`Fatal Error: ${p.message}`));let t=typeof p.exitCode=="number"?p.exitCode:1;process.exit(t)});