agent-device 0.7.15 → 0.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/daemon.js +18 -18
- package/package.json +1 -1
package/dist/src/daemon.js
CHANGED
|
@@ -15,27 +15,27 @@ ${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await p("adb",t4(e,["shell","
|
|
|
15
15
|
${t}`,i=r.indexOf("<?xml"),n=i>=0?i:r.indexOf("<hierarchy");if(n<0)return null;let a=r.lastIndexOf("</hierarchy>");if(a<0||a<n)return null;let o=r.slice(n,a+12).trim();return o.length>0?o:null}function r0(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}async function r1(e,t,r){await p("adb",t4(e,["shell","input","tap",String(t),String(r)]))}async function r2(e,t,r,i,n,a=250){await p("adb",t4(e,["shell","input","swipe",String(t),String(r),String(i),String(n),String(a)]))}async function r3(e){await p("adb",t4(e,["shell","input","keyevent","4"]))}async function r4(e){await p("adb",t4(e,["shell","input","keyevent","3"]))}async function r8(e){await p("adb",t4(e,["shell","input","keyevent","187"]))}async function r5(e,t,r,i=800){await p("adb",t4(e,["shell","input","swipe",String(t),String(r),String(t),String(r),String(i)]))}async function r6(e,t){let r=ia(t);if(!r||"ok"!==await io(e,t))try{let r=t.replace(/ /g,"%s");await p("adb",t4(e,["shell","input","text",r]))}catch(e){if(r&&function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return!!(t.includes("exception occurred while executing 'text'")||t.includes("nullpointerexception")&&t.includes("inputshellcommand.sendtext"))}(e))throw new I("COMMAND_FAILED","Non-ASCII text input is not supported on this Android shell. Install an ADB keyboard IME or use ASCII input.",{textPreview:t.slice(0,32)},e instanceof Error?e:void 0);throw e}}async function r9(e,t,r){await r1(e,t,r)}async function r7(e,t,r,i){let n=Array.from(i).length,a=ia(i),o=[{strategy:"input_text",clearPadding:12,minClear:8,maxClear:48}];a||(o.push({strategy:"clipboard_paste",clearPadding:12,minClear:8,maxClear:48}),o.push({strategy:"chunked_input",clearPadding:24,minClear:16,maxClear:96}));let s=null;for(let a of o){var l,d;await r9(e,t,r);let o=(l=n+a.clearPadding,d=a.minClear,Math.max(d,Math.min(a.maxClear,l)));if(await is(e,o),"input_text"===a.strategy)await r6(e,i);else if("clipboard_paste"===a.strategy){if("ok"!==await io(e,i))continue}else await ii(e,i,1,15);if((s=await il(e,t,r))===i)return}throw new I("COMMAND_FAILED","Android fill verification failed",{expected:i,actual:s??null})}async function ie(e,t,r=.6){let{width:i,height:n}=await ir(e),a=Math.floor(i*r),o=Math.floor(n*r),s=Math.floor(i/2),l=Math.floor(n/2),d=s,u=l,c=s,f=l;switch(t){case"up":u=l-Math.floor(o/2),f=l+Math.floor(o/2);break;case"down":u=l+Math.floor(o/2),f=l-Math.floor(o/2);break;case"left":d=s-Math.floor(a/2),c=s+Math.floor(a/2);break;case"right":d=s+Math.floor(a/2),c=s-Math.floor(a/2);break;default:throw new I("INVALID_ARGS",`Unknown direction: ${t}`)}await p("adb",t4(e,["shell","input","swipe",String(d),String(u),String(c),String(f),"300"]))}async function it(e,t){for(let r=0;r<8;r+=1){let r="";try{r=await rY(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new I("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let r=t.toLowerCase(),i=/<node[^>]+>/g,n=i.exec(e);for(;n;){let t=rj(n[0]),a=(rq(t,"text")??"").toLowerCase(),o=(rq(t,"content-desc")??"").toLowerCase();if(a.includes(r)||o.includes(r)){let e=rH(rq(t,"bounds"));if(e)return{x:Math.floor(e.x+e.width/2),y:Math.floor(e.y+e.height/2)};return{x:0,y:0}}n=i.exec(e)}return null}(r,t))return;await ie(e,"down",.5)}throw new I("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function ir(e){let t=(await p("adb",t4(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new I("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function ii(e,t,r,i){let n=Math.max(1,Math.floor(r)),a=Array.from(t);for(let t=0;t<a.length;t+=n){let r=a.slice(t,t+n).join("");await r6(e,r),i>0&&t+n<a.length&&await t6(i)}}function ia(e){for(let t of e){let e=t.codePointAt(0);if(void 0!==e&&(e<32||e>126))return!0}return!1}async function io(e,t){let r=await p("adb",t4(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":t5(r.stdout,r.stderr)?"unsupported":0===(await p("adb",t4(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await p("adb",t4(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}async function is(e,t){let r=Math.max(0,t);await p("adb",t4(e,["shell","input","keyevent","KEYCODE_MOVE_END"]),{allowFailure:!0});for(let t=0;t<r;t+=24){let i=Math.min(24,r-t);await p("adb",t4(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function il(e,t,r){let i,n=await rY(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(i=a.exec(n));){let e=rB(i[0]),n=rH(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!d)continue;let c=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&r>=n.y&&r<=n.y+n.height;if(u&&id(a)){(!o||c<=o.area)&&(o={text:d,area:c});continue}if(p&&id(a)){(!s||c<=s.area)&&(s={text:d,area:c});continue}p&&(!l||c<=l.area)&&(l={text:d,area:c})}return o?.text??s?.text??l?.text??null}function id(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function iu(e){let t=await p("adb",t4(e,["shell","dumpsys","input_method"]),{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t=function(e){let t=new Map;for(let r of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=r[1],i=r[2]?.toLowerCase();e&&("true"===i||"false"===i)&&t.set(e,"true"===i)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),r=t??!1;if(null===t){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(r=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),n=i.length>0?i[i.length-1]?.[1]:void 0,a=n?`0x${n.toLowerCase()}`:void 0;return{visible:r,inputType:a,type:a?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let r=15&t;if(2===r)return"number";if(3===r)return"phone";if(4===r)return"datetime";if(1!==r)return"unknown";let i=4080&t;return 32===i||208===i?"email":128===i||224===i||144===i?"password":"text"}(a):void 0}}(t.stdout)}async function ic(e){let t=await iu(e),r=t,i=0;for(;r.visible&&i<2;)await r3(e),i+=1,await t6(120),r=await iu(e);return{attempts:i,wasVisible:t.visible,dismissed:t.visible&&!r.visible,visible:r.visible,inputType:r.inputType,type:r.type}}async function ip(e){let t,r;return(r=(t=(await ih(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?r[1]??"":"null"===t.trim().toLowerCase()?"":t}async function im(e,t){await ih(e,["shell","cmd","clipboard","set","text",t],"write")}async function ih(e,t,r){let i=await p("adb",t4(e,t),{allowFailure:!0});if(t5(i.stdout,i.stderr))throw new I("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new I("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}let iw=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function ig(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new I("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function iI(e){let t=e?.trim().toLowerCase();if("camera"===t||"microphone"===t||"photos"===t||"contacts"===t||"contacts-limited"===t||"notifications"===t||"calendar"===t||"location"===t||"location-always"===t||"media-library"===t||"motion"===t||"reminders"===t||"siri"===t)return t;throw new I("INVALID_ARGS",`permission setting requires a target: ${iw.join("|")}`)}function iv(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new I("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}async function iA(e,t,r,i,n){switch(t.toLowerCase()){case"wifi":{let t=ib(r);await p("adb",t4(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=ib(r);await p("adb",t4(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await p("adb",t4(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=ib(r);await p("adb",t4(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"appearance":{let t=await iN(e,r);await p("adb",t4(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]));return}case"fingerprint":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";throw new I("INVALID_ARGS",`Invalid fingerprint state: ${e}. Use match|nonmatch.`)}(r);await iy(e,t);return}case"permission":{if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t=ig(r),a=function(e,t){let r=iI(e);if(t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return{kind:"pm",value:"android.permission.CAMERA",type:"camera"};if("microphone"===r)return{kind:"pm",value:"android.permission.RECORD_AUDIO",type:"microphone"};if("photos"===r)return{kind:"pm",value:"android.permission.READ_MEDIA_IMAGES",type:"photos"};if("contacts"===r)return{kind:"pm",value:"android.permission.READ_CONTACTS",type:"contacts"};if("notifications"===r)return{kind:"notifications",appOps:"POST_NOTIFICATION",permission:"android.permission.POST_NOTIFICATIONS"};throw new I("INVALID_ARGS",`Unsupported permission target on Android: ${e}. Use camera|microphone|photos|contacts|notifications.`)}(n?.permissionTarget,n?.permissionMode);if("notifications"===a.kind)return void await i_(e,i,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await iS(e,i,o);await p("adb",t4(e,["shell","pm",o,i,a.value]));return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function iy(e,t){var r;let i,n,a=(r=e,n=[["shell","cmd","fingerprint","touch",i="match"===t?"1":"9999"],["shell","cmd","fingerprint","finger",i]],"emulator"===r.kind&&n.push(["emu","finger","touch",i]),n),o=[];for(let t of a){let r=await p("adb",t4(e,t),{allowFailure:!0});if(0===r.exitCode)return;o.push({args:t,stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}let s=o.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(o.length>0&&o.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
16
16
|
${r}`.toLowerCase()).includes("unknown command")||i.includes("can't find service: fingerprint")||i.includes("service fingerprint was not found")||i.includes("fingerprint cmd unavailable")||i.includes("emu command is not supported")||i.includes("emulator console is not running")||i.includes("fingerprint")&&i.includes("not found")}))throw new I("UNSUPPORTED_OPERATION","Android fingerprint simulation is not supported on this target/runtime.",{deviceId:e.id,action:t,hint:"Use an Android emulator with biometric support, or a device/runtime that exposes cmd fingerprint.",attempts:s});throw new I("COMMAND_FAILED","Failed to simulate Android fingerprint.",{deviceId:e.id,action:t,attempts:s})}function ib(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function iN(e,t){let r=iv(t);if("toggle"!==r)return r;let i=await p("adb",t4(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current Android appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/night mode:\s*(yes|no|auto)\b/i.exec(`${e}
|
|
17
17
|
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"yes"===i?"dark":"no"===i?"light":"auto"===i?"auto":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current Android appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"auto"===n?"dark":"dark"===n?"light":"dark"}async function iS(e,t,r){let i=await iD(e),n=[];for(let a of null!==i&&i>=33?["android.permission.READ_MEDIA_IMAGES","android.permission.READ_EXTERNAL_STORAGE"]:["android.permission.READ_EXTERNAL_STORAGE","android.permission.READ_MEDIA_IMAGES"]){let i=await p("adb",t4(e,["shell","pm",r,t,a]),{allowFailure:!0});if(0===i.exitCode)return;n.push({permission:a,stderr:i.stderr,exitCode:i.exitCode})}throw new I("COMMAND_FAILED",`Failed to ${r} Android photos permission`,{appPackage:t,sdkInt:i,attempts:n})}async function i_(e,t,r,i){"grant"===r?await p("adb",t4(e,["shell","pm","grant",t,i.permission]),{allowFailure:!0}):(await p("adb",t4(e,["shell","pm","revoke",t,i.permission]),{allowFailure:!0}),"reset"===r&&(await p("adb",t4(e,["shell","pm","clear-permission-flags",t,i.permission,"user-set"]),{allowFailure:!0}),await p("adb",t4(e,["shell","pm","clear-permission-flags",t,i.permission,"user-fixed"]),{allowFailure:!0}))),await p("adb",t4(e,["shell","appops","set",t,i.appOps,"grant"===r?"allow":"deny"===r?"deny":"default"]))}async function iD(e){let t=await p("adb",t4(e,["shell","getprop","ro.build.version.sdk"]),{allowFailure:!0});if(0!==t.exitCode)return null;let r=Number.parseInt(t.stdout.trim(),10);return!Number.isFinite(r)||r<=0?null:r}async function iE(e,t,r){let i="string"==typeof r.action&&r.action.trim()?r.action.trim():`${t}.TEST_PUSH`,n=["shell","am","broadcast","-a",i,"-p",t],a="string"==typeof r.receiver?r.receiver.trim():"";a&&n.push("-n",a);let o=r.extras;if(void 0!==o&&("object"!=typeof o||null===o||Array.isArray(o)))throw new I("INVALID_ARGS","Android push payload extras must be an object");let s=0;for(let[e,t]of Object.entries(o??{}))e&&(function(e,t,r){if("string"==typeof r)return e.push("--es",t,r);if("boolean"==typeof r)return e.push("--ez",t,r?"true":"false");if("number"==typeof r&&Number.isFinite(r))return Number.isInteger(r)?e.push("--ei",t,String(r)):e.push("--ef",t,String(r));throw new I("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(n,e,t),s+=1);return await p("adb",t4(e,n)),{action:i,extrasCount:s}}let ik=ew(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,J,5e3),iO=ew(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,W,1e3),iL=ew(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),iM=ew(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3),ix=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_SCREENSHOT_TIMEOUT_MS,2e4,1e3),iC=ew(process.env.AGENT_DEVICE_IOS_RUNNER_SCREENSHOT_COPY_TIMEOUT_MS,2e4,1e3);async function iR(e,t){let r=["devicectl",...e],i=await p("xcrun",r,{allowFailure:!0,timeoutMs:iM});if(0===i.exitCode)return;let n=String(i.stdout??""),a=String(i.stderr??"");throw new I("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:r,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:i$(n,a)??iP})}async function iT(e,t){let r=n.join(V.tmpdir(),`agent-device-ios-apps-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),i=["devicectl","device","info","apps","--device",e.id,"--include-all-apps","--json-output",r],a=await p("xcrun",i,{allowFailure:!0,timeoutMs:iM});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),r=String(a.stderr??"");throw new I("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:i,exitCode:a.exitCode,stdout:t,stderr:r,deviceId:e.id,hint:i$(t,r)??iP})}let n=await x.readFile(r,"utf8");return o=function(e){let t=e?.result?.apps;if(!Array.isArray(t))return[];let r=[];for(let e of t){if(!e||"object"!=typeof e)continue;let t="string"==typeof e.bundleIdentifier?e.bundleIdentifier.trim():"";if(!t)continue;let i="string"==typeof e.name&&e.name.trim().length>0?e.name.trim():t;r.push({bundleId:t,name:i})}return r}(JSON.parse(n)),s=t,"user-installed"===s?o.filter(e=>!e.bundleId.startsWith("com.apple.")):o}catch(t){if(t instanceof I)throw t;throw new I("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await x.unlink(r).catch(()=>{})}}let iP="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function i$(e,t){let r=`${e}
|
|
18
|
-
${t}`.toLowerCase();return r.includes("device is busy")&&r.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":r.includes("coredeviceservice")&&r.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}function iF(e,t){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function
|
|
19
|
-
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",e_(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await
|
|
18
|
+
${t}`.toLowerCase();return r.includes("device is busy")&&r.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":r.includes("coredeviceservice")&&r.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}function iF(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function iV(e,t){let r=await p("xcrun",e_(e,["get_app_container",e.id,t]),{allowFailure:!0});if(0!==r.exitCode)return{installed:!1};let i=r.stdout.trim();if(!i)return{installed:!1};let n=await p("plutil",["-extract","CFBundleExecutable","raw","-o","-",`${i}/Info.plist`],{allowFailure:!0});if(0!==n.exitCode||!n.stdout.trim())return{installed:!0};let a=n.stdout.trim(),o=`${i}/${a}`,s=await p("otool",["-l",o],{allowFailure:!0});if(0!==s.exitCode)return{installed:!0};let l=s.stdout.toLowerCase();return{installed:!0,simulatorCompatible:l.includes("iossimulator")||l.includes("platform 7")}}function iU(e,t){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function iG(){await p("open",["-a","Simulator"],{allowFailure:!0})}async function iB(e){let t,r;if("simulator"!==e.kind||"Booted"===await iq(e))return;let i=K.fromTimeoutMs(ik);try{await X(async({deadline:i})=>{if(i?.isExpired())throw new I("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:ik});let n=Math.max(1e3,i?.remainingMs()??ik),a=await p("xcrun",e_(e,["boot",e.id]),{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
|
|
19
|
+
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",e_(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await iq(e);if("Booted"!==d)throw new I("COMMAND_FAILED","Simulator is still booting",{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let i=eu({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});return"IOS_BOOT_TIMEOUT"!==i&&"CI_RESOURCE_STARVATION_SUSPECTED"!==i}},{deadline:i,phase:"boot",classifyReason:e=>eu({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=eu({error:a,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new I("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:ik,elapsedMs:i.elapsedMs(),reason:n,hint:ec(n),boot:t,bootstatus:r})}}async function ij(e){let t=e_(e,["shutdown",e.id]),r=await p("xcrun",t,{allowFailure:!0,timeoutMs:15e3});return{success:0===r.exitCode,exitCode:r.exitCode,stdout:String(r.stdout??""),stderr:String(r.stderr??"")}}async function iq(e){let t="string"==typeof e?e:e.id,r="string"==typeof e?eS(["list","devices","-j"]):e_(e,["list","devices","-j"]),i=await p("xcrun",r,{allowFailure:!0,timeoutMs:iO});if(0!==i.exitCode)return null;try{let e=JSON.parse(String(i.stdout??""));for(let r of Object.values(e.devices??{})){let e=r.find(e=>e.udid===t);if(e)return e.state}return null}catch{return null}}function iH(e,t,r){return p("xcrun",e_(e,t),r)}let iW={ensureBooted:iB,captureWithRetry:iK,captureWithRunner:iX,shouldFallbackToRunner:i1};async function iJ(e,t,r){if("simulator"===e.kind)return void await iz(e,t,r);try{await iR(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(t){if(!function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=`${e.message}
|
|
20
20
|
${r}
|
|
21
|
-
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(t))throw t;
|
|
21
|
+
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(t))throw t;i0(e,"devicectl_screenshot",t)}await iX(e,t,r)}async function iz(e,t,r,i=iW){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");await i.ensureBooted(e);try{await i.captureWithRetry(e,t);return}catch(t){if(!i.shouldFallbackToRunner(t))throw t;i0(e,"simctl_screenshot",t)}await i.captureWithRunner(e,t,r)}async function iK(e,t){let r=K.fromTimeoutMs(ix);await iG(),await X(async({attempt:r,deadline:i})=>{r>1&&await iG(),await iH(e,["io",e.id,"screenshot",t],{timeoutMs:Math.max(1e3,i?.remainingMs()??ix)})},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>i1(e)},{deadline:r,phase:"ios_simulator_screenshot"})}async function iX(e,t,r){let i=(await ta(e,{command:"screenshot",appBundleId:r})).message;if(!i)throw new I("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");"simulator"===e.kind?await iZ(e,i,t):await iY(e,i,t)}async function iY(e,t,r){let i=K.fromTimeoutMs(iC),n={exitCode:1,stdout:"",stderr:""};for(let a of eY)if(0===(n=await p("xcrun",["devicectl","device","copy","from","--device",e.id,"--source",t,"--destination",r,"--domain-type","appDataContainer","--domain-identifier",a],{allowFailure:!0,timeoutMs:iQ(i,iC,"runner screenshot copy")})).exitCode)return;let a=n.stderr.trim()||n.stdout.trim()||`devicectl exited with code ${n.exitCode}`;throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${a}`)}async function iZ(e,t,r){let i=K.fromTimeoutMs(iC),a="Unable to locate runner container for simulator screenshot";for(let o of eY){let s=await iH(e,["get_app_container",e.id,o,"data"],{allowFailure:!0,timeoutMs:iQ(i,iC,"runner screenshot container lookup")});if(0!==s.exitCode){let e=s.stderr.trim();e&&(a=e);continue}let l=s.stdout.trim();if(!l){a="simctl get_app_container returned empty output";continue}for(let e of function(e,t){let r=n.resolve(e),i=t.trim();if(!i)return[];let a=[],o=new Set,s=e=>{let t=n.normalize(e);o.has(t)||(o.add(t),a.push(t))},l=i.replace(/^\/+/,""),d=l.replace(/\\/g,"/");if(l&&s(n.join(r,l)),n.isAbsolute(i)&&s(n.normalize(i)),d.startsWith("tmp/"))s(n.join(r,d));else{let e=d.lastIndexOf("/tmp/");if(e>=0){let t=d.slice(e+1);s(n.join(r,t))}}let u=n.basename(i);return u&&s(n.join(r,"tmp",u)),a}(l,t))try{await x.copyFile(e,r);return}catch(e){a=e instanceof Error?e.message:String(e)}}throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${a}`)}function iQ(e,t,r){let i=e.remainingMs();if(i>0)return i;throw new I("COMMAND_FAILED",`iOS ${r} timed out after ${t}ms`,{timeoutMs:t,step:r})}function i0(e,t,r){let i=function(e){if(!(e instanceof I))return{reason:e instanceof Error?e.message:String(e)};let t=e.details??{},r=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):void 0;return{errorCode:e.code,reason:e.message,timeoutMs:"number"==typeof t.timeoutMs?t.timeoutMs:void 0,exitCode:"number"==typeof t.exitCode?t.exitCode:void 0,stderr:"string"==typeof t.stderr&&t.stderr.trim()?t.stderr:void 0,stdout:"string"==typeof t.stdout&&t.stdout.trim()?t.stdout:void 0,commandArgs:r}}(r);M({level:"warn",phase:"ios_screenshot_fallback",data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:"runner",...i}})}function i1(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):"",a=`${e.message}
|
|
22
22
|
${r}
|
|
23
23
|
${i}
|
|
24
|
-
${n}`.toLowerCase();return a.includes("timeout waiting for screen surfaces")||a.includes("nsposixerrordomain")&&a.includes("code=60")&&a.includes("screenshot")||a.includes("timed out")&&a.includes("screenshot")}let
|
|
25
|
-
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:i$(n,a)??iP})}return{bundleId:r}}await
|
|
26
|
-
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function
|
|
27
|
-
`,"utf8"),await
|
|
28
|
-
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let
|
|
29
|
-
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return
|
|
30
|
-
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}function nI(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function nv(e,t){await iU(e),await iV();let r=K.fromTimeoutMs(iL);await X(async({deadline:r})=>{if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:iL});let i=e_(e,["launch",e.id,t]),n=await p("xcrun",i,{allowFailure:!0});if(0!==n.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${n.exitCode}`,{cmd:"xcrun",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:nI},{deadline:r})}async function nA(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await iR(i,{action:"launch iOS app",deviceId:e.id})}let ny=/^[A-Za-z0-9_.:-]{1,64}$/,nb=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function nN(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function nS(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await n_(t)}async function n_(e){await new Promise(t=>setTimeout(t,e))}function nD(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!$.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function nE(e){let t=nD(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await nk(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function nk(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}let nO=ew(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),nL=/^(iphone|ipad|ipod|appletv)/i,nM=/^appletv/i,nx=["apple tv","appletv","tvos"];function nC(e){return(e??"").trim().toLowerCase()}function nR(e){return nC(e.hardwareProperties?.platform)}function nT(e){return e.includes("tvos")}function nP(e){let t=nC(e);return nx.some(e=>t.includes(e))}function n$(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function nF(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function nV(e={}){if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await A("xcrun"))throw new I("TOOL_MISSING","xcrun not found in PATH");let t=[],r=ey(e.simulatorSetPath),i=await p("xcrun",eS(["list","devices","-j"],{simulatorSetPath:r}));try{let e=JSON.parse(i.stdout);for(let[i,n]of Object.entries(e.devices))if(function(e){let t=nC(e);return t.includes("ios")||t.includes("tvos")}(i))for(let e of n){var a;e.isAvailable&&t.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:(a=i,nT(nC(a))?"tv":"mobile"),booted:"Booted"===e.state,...r?{simulatorSetPath:r}:{}})}}catch(e){throw new I("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(r)return t;let o=null;try{o=n.join(V.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let e=await p("xcrun",["devicectl","list","devices","--json-output",o],{allowFailure:!0,timeoutMs:nO});if(0!==e.exitCode)return t;let r=await x.readFile(o,"utf8"),i=JSON.parse(r);for(let e of i.result?.devices??[])if(function(e){var t;let r=nR(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=nF(e),!!nL.test(t.trim())||n$(e).some(nP))}(e)){let r=e.hardwareProperties?.udid??e.identifier??"",i=e.name??e.deviceProperties?.name??r;if(!r)continue;t.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return nT(nR(e))?"tv":(t=nF(e),nM.test(t.trim())||n$(e).some(nP))?"tv":"mobile"}(e),booted:!0})}}catch{}finally{o&&await x.rm(o,{force:!0}).catch(()=>{})}return t}async function nU(e){let t=ej(e.platform),r=ey(e.iosSimulatorDeviceSet),i=eN(e.androidDeviceAllowlist);return await L("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await t8();let e=await rc({serialAllowlist:i});return await eq(e,n)}if("ios"===n.platform){let e=await nV({simulatorSetPath:r});return await eq(e,n,{simulatorSetPath:r})}let a=[];try{a.push(...await rc({serialAllowlist:i}))}catch{}try{a.push(...await nV({simulatorSetPath:r}))}catch{}return await eq(a,n,{simulatorSetPath:r})},{platform:t,target:e.target})}async function nG(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>rL(e,t,r?.activity),openDevice:()=>rx(e),close:t=>rC(e,t),tap:(t,r)=>r1(e,t,r),doubleTap:async(t,r)=>{await r1(e,t,r),await r1(e,t,r)},swipe:(t,r,i,n,a)=>r2(e,t,r,i,n,a),longPress:(t,r,i)=>r5(e,t,r,i),focus:(t,r)=>r9(e,t,r),type:t=>r6(e,t),fill:(t,r,i)=>r7(e,t,r,i),scroll:(t,r)=>ie(e,t,r),scrollIntoView:t=>it(e,t),screenshot:(t,r)=>rX(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>i7(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>ne(e),close:t=>nt(e,t),screenshot:(t,r)=>iH(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(es(i.requestId))throw el()},{tap:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await ta(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await ta(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await ta(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await ta(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await ta(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await ta(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await ta(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await L("platform_command",async()=>{switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(t9(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!t9(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=nN(a?.count??1,"count",1,200),s=nN(a?.intervalMs??0,"interval-ms",0,1e4),l=nN(a?.holdMs??0,"hold-ms",0,1e4),d=nN(a?.jitterPx??0,"jitter-px",0,100),u=a?.doubleTap===!0;if(u&&l>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(u&&d>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if("ios"===e.platform&&n>1&&0===l&&0===d)return await ta(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:s,doubleTap:u,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u,timingMode:"runner-series"};return await nS(n,s,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=nb[e%nb.length];return[r*t,i*t]}(e,d),a=t+r,s=i+n;u?await o.doubleTap(a,s):l>0?await o.longPress(a,s,l):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=nN(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=nN(a?.count??1,"count",1,200),c=nN(a?.pauseMs??0,"pause-ms",0,1e4),p=a?.pattern??"one-way";if("one-way"!==p&&"ping-pong"!==p)throw new I("INVALID_ARGS",`Invalid pattern: ${p}`);if("ios"===e.platform&&u>1)return await ta(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:c,pattern:p,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:c,pattern:p};return await nS(u,c,async e=>{"ping-pong"===p&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:c,pattern:p}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await ta(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!ny.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await ta(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await r3(e),{action:"back"};case"home":if("ios"===e.platform)return await ta(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await r4(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await ta(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await r8(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await na(e):await ip(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await no(e,i):await im(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await ic(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await iu(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await nl(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await iA(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await nE(i);if("ios"===e.platform)return await ns(e,t,n),{platform:"ios",bundleId:t};let a=await iE(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await L("snapshot_capture",async()=>await ta(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await L("snapshot_capture",async()=>await rz(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let nB={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},install:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function nj(e,t){let r=nB[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function nq(e,t,r,i,n){return{requestId:n??O().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let nH=ew(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function nW(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:iU}));await t(e);return}if("device"===e.kind)return void await nJ(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:rI}));await t(e.id)}}async function nJ(e){let t=n.join(V.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(nH/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:nH+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await nz(t);if(0===i.exitCode){if(!o.parsed)throw new I("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:nK(n,a)})}catch(t){if(t instanceof I&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??nH),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?nK(i,n):o},t)}throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await x.rm(t,{force:!0}).catch(()=>{})}}async function nz(e){try{let t=await x.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function nK(e,t){let r=i$(e,t);return r||(`${e}
|
|
31
|
-
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":iP)}function nX(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function nY(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function nZ(e,t){return e.find(e=>e.ref===t)??null}function nQ(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function n0(e,t){let r=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),i=(e.value??"").toLowerCase(),n=(e.identifier??"").toLowerCase();return t.includes(r)||i.includes(r)||n.includes(r)})??null}function n1(e,t){let r=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);return r&&n2(r)?r:function(e,t){if(!e.rect)return;let r=e.rect.y+e.rect.height/2,i=null;for(let e of t){if(!e.rect)continue;let t=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);if(!t||!n2(t))continue;let n=Math.abs(e.rect.y+e.rect.height/2-r);(!i||n<i.distance)&&(i={label:t,distance:n})}return i?.label}(e,t)??(r&&n2(r)?r:void 0)}function n2(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function n3(e){let t=[],r=[];for(let i of e){let e=i.depth??0;for(;t.length>0&&e<=t[t.length-1];)t.pop();let n=n4(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&n2(a);if(("group"===n||"ioscontentgroup"===n)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);r.push({...i,depth:s})}return r}function n4(e){let t=e.trim().replace(/XCUIElementType/gi,"").toLowerCase(),r=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==r&&(t=t.slice(r+1)),t}function n8(e,t){let r=n4(e);return!r||("android"===t?r.includes("edittext")||r.includes("autocompletetextview"):r.includes("textfield")||r.includes("securetextfield")||r.includes("searchfield")||r.includes("textview")||r.includes("textarea")||"search"===r)}function n5(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let n6=new Set(["id","role","text","label","value"]),n9=new Set(["visible","hidden","editable","selected","enabled","hittable"]),n7=new Set([...n6,...n9]);function ae(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!aI(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&"|"===a&&"|"===e[n+1]){let i=r.trim();if(!i)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new I("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!aI(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&/\s/.test(a)){r.trim().length>0&&t.push(r.trim()),r="";continue}r+=a}if(i)throw new I("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new I("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(au)}})(e))}}function at(e){try{return ae(e)}catch{return null}}function ar(e,t,r){let i=r.requireRect??!1,n=r.requireUnique??!0,a=r.disambiguateAmbiguous??!1,o=[];for(let s=0;s<t.selectors.length;s+=1){let l=t.selectors[s],d=function(e,t,r){let i=0,n=null,a=null,o=!1;for(let s of e){if(r.requireRect&&!s.rect||!ac(s,t,r.platform))continue;if(i+=1,n||(n=s),!a){a=s;continue}let e=function(e,t){let r=e.depth??0,i=t.depth??0;if(r!==i)return r>i?1:-1;let n=ag(e),a=ag(t);return n!==a?n<a?1:-1:0}(s,a);if(e>0){a=s,o=!1;continue}0===e&&(o=!0)}return{count:i,firstNode:n,disambiguated:o?null:a}}(e,l,{platform:r.platform,requireRect:i});if(o.push({selector:l.raw,matches:d.count}),0!==d.count&&d.firstNode){if(n&&1!==d.count){if(!a)continue;let e=d.disambiguated;if(!e)continue;return{node:e,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}return{node:d.firstNode,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}}return null}function ai(e,t,r){let i=r.requireRect??!1,n=[];for(let a=0;a<t.selectors.length;a+=1){let o=t.selectors[a],s=function(e,t,r){let i=0;for(let n of e)(!r.requireRect||n.rect)&&ac(n,t,r.platform)&&(i+=1);return i}(e,o,{platform:r.platform,requireRect:i});if(n.push({selector:o.raw,matches:s}),s>0)return{selectorIndex:a,selector:o,matches:s,diagnostics:n}}return null}function an(e,t,r){let i=r.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let n=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return i?`Selector did not resolve uniquely (${n})`:`Selector did not match (${n})`}function aa(e,t={}){if(0===e.length)return null;let r=t.preferTrailingValue??!1,i=0,n=[];for(;i<e.length&&function(e){let t=e.trim();if(!t)return!1;if("||"===t)return!0;let r=t.indexOf("=");if(-1!==r){let e=t.slice(0,r).trim().toLowerCase();return n7.has(e)}return n7.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&at(t)&&n.push(i)}if(0===n.length)return null;let a=n[n.length-1];if(r){for(let t=n.length-1;t>=0;t-=1)if(n[t]<e.length){a=n[t];break}}let o=e.slice(0,a).join(" ").trim();return o?{selectorExpression:o,rest:e.slice(a)}:null}function ao(e){let t=e[0]??"",r=aa(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function as(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function al(e,t){return n8(e.type??"",t)&&!1!==e.enabled}function ad(e,t,r={}){let i=[],n=n4(e.type??""),a=aw(e.identifier),o=aw(e.label),s=aw(e.value),l=aw(n5(e)),d="fill"===r.action;a&&i.push(`id=${ah(a)}`),n&&o&&i.push(d?`role=${ah(n)} label=${ah(o)} editable=true`:`role=${ah(n)} label=${ah(o)}`),o&&i.push(d?`label=${ah(o)} editable=true`:`label=${ah(o)}`),s&&i.push(d?`value=${ah(s)} editable=true`:`value=${ah(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${ah(l)} editable=true`:`text=${ah(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${ah(n)} editable=true`);let u=tl(i);return 0===u.length&&n&&u.push(d?`role=${ah(n)} editable=true`:`role=${ah(n)}`),0===u.length&&as(e)&&u.push("visible=true"),u}function au(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!n9.has(r))throw new I("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let i=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!n7.has(i))throw new I("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new I("INVALID_ARGS",`Missing selector value for key: ${i}`);if(n9.has(i)){let e,t="true"===(e=ap(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new I("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:ap(n)}}function ac(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return af(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return n4(e)}(i??"")===function(e){return n4(e)}(n);case"label":return af(e.label,String(t.value));case"value":return af(e.value,String(t.value));case"text":{let r=am(String(t.value));return am(n5(e))===r}case"visible":return as(e)===!!t.value;case"hidden":return!as(e)==!!t.value;case"editable":return al(e,r)===!!t.value;case"selected":return!0===e.selected==!!t.value;case"enabled":return!1!==e.enabled==!!t.value;case"hittable":return!0===e.hittable==!!t.value;default:return!1}})(e,t,r))}function ap(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function af(e,t){return am(e??"")===am(t)}function am(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function ah(e){return JSON.stringify(e)}function aw(e){if(!e)return null;let t=e.trim();return t||null}function ag(e){return e.rect?e.rect.width*e.rect.height:1/0}function aI(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}let av=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),aA=/https?:\/\/[^\s"'<>\])]+/i,ay=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function ab(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function aN(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return aS(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function aS(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function a_(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function aD(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let aE="shared_prefs/ReactNativeDevPrefs.xml",ak="debug_http_host",aO="dev_server_https",aL="RCT_jsLocation",aM="RCT_packager_scheme",ax="React Native runtime hints require adb run-as access to the app sandbox. Verify the app is debuggable and the selected package/device are correct.",aC='<?xml version="1.0" encoding="utf-8" standalone="yes" ?>\n<map>\n</map>\n';function aR(e){return void 0!==aT(e)}function aT(e){if(!e)return;let t=aJ(e.metroHost),r=az(e.metroPort),i="http",n=aJ(e.bundleUrl);if(n){var a;let e;try{e=new v(n)}catch(e){throw new I("INVALID_ARGS",`Invalid runtime bundle URL: ${n}`,{},e)}("http:"===e.protocol||"https:"===e.protocol)&&(t??=aJ(e.hostname),r??=az(e.port.length>0?Number(e.port):"https:"===(a=e.protocol)?443:"http:"===a?80:void 0),i="https:"===e.protocol?"https":"http")}if(t&&r)return{host:t,port:r,scheme:i}}async function aP(e){let{device:t,appId:r,runtime:i}=e;if(!r)return;let n=aT(i);if(n){if("android"===t.platform)return void await aF(t,r,n);"ios"===t.platform&&"simulator"===t.kind&&await aB(t,r,n)}}async function a$(e){let{device:t,appId:r}=e;if(r){if("android"===t.platform)return void await aV(t,r);"ios"===t.platform&&"simulator"===t.kind&&await aj(t,r)}}async function aF(e,t,r){var i,n,a,o,s,l;let d,u,c=(i=await aU(e,t),n=ak,a=`${r.host}:${r.port}`,d=` <string name="${aK(n)}">${aK(a)}</string>`,aH(aW(i,n),d));o=c,s=aO,l="https"===r.scheme,u=` <boolean name="${aK(s)}" value="${l?"true":"false"}" />`,c=aH(aW(o,s),u),await aG(e,t,c)}async function aV(e,t){let r=await aU(e,t),i=aW(r,ak),n=aW(i,aO);n!==r&&await aG(e,t,n)}async function aU(e,t){let r=await p("adb",t4(e,["shell","run-as",t,"cat",aE]),{allowFailure:!0});return 0!==r.exitCode?aC:aq(r.stdout)}async function aG(e,t,r){let i=t4(e,["shell","run-as",t,"id"]),n=await p("adb",i,{allowFailure:!0});if(0!==n.exitCode){let e=aX(n.stdout,n.stderr);throw new I("COMMAND_FAILED",e?`Failed to access Android app sandbox for ${t}`:`Failed to probe Android app sandbox for ${t}`,{package:t,cmd:"adb",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:e?ax:"adb shell run-as probe failed. Check adb connectivity and that the device is reachable. Inspect stderr/details for more information."})}let a=t4(e,["shell","run-as",t,"sh","-c",`mkdir -p shared_prefs && cat > ${aE}`]);try{await p("adb",a,{stdin:r.trimEnd()})}catch(i){let e=w(i);if("TOOL_MISSING"===e.code)throw e;let r=aX("string"==typeof e.details?.stdout?e.details.stdout:"","string"==typeof e.details?.stderr?e.details.stderr:"");throw new I("COMMAND_FAILED",r?`Failed to access Android app sandbox for ${t}`:`Failed to write Android runtime hints for ${t}`,{...e.details??{},package:t,cmd:"adb",args:a,phase:"write-runtime-hints",hint:r?ax:"adb run-as succeeded, but writing ReactNativeDevPrefs.xml failed. Inspect stderr/details for the failing shell command."},e)}}async function aB(e,t,r){await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aL,"-string",`${r.host}:${r.port}`])),await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aM,"-string",r.scheme]))}async function aj(e,t){await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aL]),{allowFailure:!0}),await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aM]),{allowFailure:!0})}function aq(e){let t=e.trim();return t.includes("<map")&&t.includes("</map>")?`${t}
|
|
32
|
-
`:
|
|
33
|
-
</map>`)}function
|
|
34
|
-
${t}`.toLowerCase();return["run-as: package not debuggable","run-as: permission denied","run-as: package is unknown","run-as: unknown package","is unknown","is not an application","could not set capabilities"].some(e=>r.includes(e))}function aY(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=aa(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function aZ(e){return!!e&&!Number.isNaN(Number(e))}async function aQ(e){let t,r,i,{deviceName:n,runtime:a,simulatorSetPath:o,reuseExisting:s,boot:l,ensureReady:d}=e;if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","ensure-simulator is only available on macOS");let u={simulatorSetPath:o??void 0};if(s){let e=await a0({deviceName:n,runtime:a,simctlOpts:u});e?(t=e.udid,r=e.runtime,i=!1):(t=(await a1({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await a2(t,u),i=!0)}else t=(await a1({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await a2(t,u),i=!0;let c=!1;if(l){let e={platform:"ios",id:t,name:n,kind:"simulator",target:"mobile",...o?{simulatorSetPath:o}:{}};await d(e),c=!0}return{udid:t,device:n,runtime:r,created:i,booted:c}}async function a0(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=await p("xcrun",eS(["list","devices","-j"],i),{allowFailure:!0,timeoutMs:iO});if(0!==n.exitCode)return null;try{let e=JSON.parse(String(n.stdout??""));for(let[i,n]of Object.entries(e.devices??{}))if(!r||a3(i).includes(a3(r))){for(let e of n)if(e.isAvailable&&e.name.toLowerCase()===t.toLowerCase())return{udid:e.udid,runtime:i}}return null}catch{return null}}async function a1(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=r?["create",t,t,r]:["create",t,t],a=await p("xcrun",eS(n,i),{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED","Failed to create iOS simulator",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode,hint:"Ensure the device type and runtime identifiers are valid. Run `xcrun simctl list devicetypes` and `xcrun simctl list runtimes` to see available options."});let o=String(a.stdout??"").trim();if(!o)throw new I("COMMAND_FAILED","simctl create returned no UDID",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??"")});return{udid:o}}async function a2(e,t){let r=await p("xcrun",eS(["list","devices","-j"],t),{allowFailure:!0,timeoutMs:iO});if(0!==r.exitCode)return"";try{let t=JSON.parse(String(r.stdout??""));for(let[r,i]of Object.entries(t.devices??{}))if(i.some(t=>t.udid===e))return r;return""}catch{return""}}function a3(e){return e.toLowerCase().replace(/[._-]/g,"")}let a4='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',a8=["platform","target","device","udid","serial","verbose","out"],a5=["platform","target","device","udid","serial","verbose","out"],a6=["path","start","stop","doctor","mark","clear"],a9=`logs requires ${a6.slice(0,-1).join(", ")}, or ${a6.at(-1)}`,a7="Not implemented for this platform in this release.",oe="open-command-roundtrip",ot=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_CLOSE_SETTLE_MS,300,0),or=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_OPEN_SETTLE_MS,300,0);function oi(e){let{sessionName:t,appName:r,appBundleId:i,startup:n,device:a,runtime:o}=e,s={session:t};return r&&(s.appName=r),i&&(s.appBundleId=i),n&&(s.startup=n),o&&on(o)>0&&(s.runtime=o),a?.platform==="ios"&&(s.device_udid=a.id,s.ios_simulator_device_set=a.simulatorSetPath??null),s}function on(e){return e?[e.metroHost,e.metroPort,e.bundleUrl,e.launchUrl].filter(e=>void 0!==e&&""!==e).length:0}function oa(e){let t=e?.trim();return t&&t.length>0?t:void 0}function oo(e,t,r){let i=e.getRuntimeHints(t);if(i){if(i.platform&&r&&i.platform!==r.platform)throw new I("INVALID_ARGS",`Session runtime hints target ${i.platform}, but session "${t}" is bound to ${r.platform}. Clear the runtime hints or use a different session.`);return r?.platform&&i.platform!==r.platform?{...i,platform:r.platform}:i}}async function os(e){let{runtime:t,device:r,dispatch:i,req:n,logPath:a,appBundleId:o,traceLogPath:s,openPositionals:l}=e,d=t?.launchUrl;if(!d||0===l.length||l.length>1)return;let u=l[0]?.trim();!u||t9(u)||await i(r,"open",[d],n.flags?.out,{...nq(a,n.flags,o,s)})}function ol(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:oe,appTarget:t,appBundleId:r}}let od=["dump","log"],ou=`network requires ${od.join(" or ")}`,oc=["summary","headers","body","all"],op=`network include mode must be one of: ${oc.join(", ")}`;function of(e,t,r){return t||om(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function om(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}function oh(e){return"ios"===e.platform&&"simulator"===e.kind}async function ow(e,t){oh(e)&&!(t<=0)&&await new Promise(e=>setTimeout(e,t))}async function og(e){let{device:t,closeTarget:r,stopIosRunner:i,dispatch:n,outFlag:a,context:o,settleSimulator:s}=e;"ios"===t.platform&&await i(t.id),await n(t,"close",[r],a,o),await s(t,ot)}async function oI(e){let t=om(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function ov(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let oA=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:rg}));return await i({avdName:e,serial:t,headless:r})};async function oy(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=of(l,p,f);if(m)return m;let h=await oI({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nj(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...nq(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let ob={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:nn}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:rG}));return await i(e,t,r)}},oN={ios:async(e,t,r)=>{let{installIosApp:i}=await Promise.resolve().then(()=>({installIosApp:ni}));await i(e,r,{appIdentifierHint:t});let{bundleId:n}=await ok(e,t);return n?{bundleId:n}:{}},android:async(e,t,r)=>{let{installAndroidApp:i}=await Promise.resolve().then(()=>({installAndroidApp:rU}));await i(e,r);let{package:n}=await ok(e,t);return n?{package:n}:{}}};async function oS(e){let{req:t,command:r,sessionName:i,sessionStore:n,ensureReady:a,resolveDevice:o,deployOps:s}=e,l=n.get(i),d=t.flags??{},u=of(r,l,d);if(u)return u;let c=t.positionals?.[0]?.trim(),p=t.positionals?.[1]?.trim();if(!c||!p)return{ok:!1,error:{code:"INVALID_ARGS",message:`${r} requires: ${r} <app> <path-to-app-binary>`}};let f=t.meta?.uploadedArtifactId;try{let e,i=f?function(e,t){let r=tT.get(e);if(!r)throw new I("INVALID_ARGS",`Uploaded artifact not found: ${e}`);if(r.tenantId&&r.tenantId!==t)throw new I("UNAUTHORIZED","Uploaded artifact belongs to a different tenant");return clearTimeout(r.timer),r.artifactPath}(f,t.meta?.tenantId):tw.expandHome(p);if(!$.existsSync(i))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${i}`}};let u=await oI({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!1});if(!nj(r,u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}};if("ios"===u.platform){let t=(await s.ios(u,c,i)).bundleId;e=t?{app:c,appPath:i,platform:"ios",appId:t,bundleId:t}:{app:c,appPath:i,platform:"ios"}}else{let t=(await s.android(u,c,i)).package;e=t?{app:c,appPath:i,platform:"android",appId:t,package:t}:{app:c,appPath:i,platform:"android"}}return l&&n.recordAction(l,{command:r,positionals:t.positionals??[],flags:t.flags??{},result:e}),{ok:!0,data:e}}finally{f&&tP(f)}}async function o_(e,t,r){if("ios"===e.platform&&t)return t9(t)?"device"===e.kind?t7(r,t):void 0:await oD(e,t)}async function oD(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:i9}));return await r(e,t)}catch{return}}async function oE(e,t){if(!("android"!==e.platform||!t||t9(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:rN})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function ok(e,t){return"ios"===e.platform?{bundleId:await oD(e,t)}:{package:await oE(e,t)}}async function oO(e,t,r,i){return await o_(e,t,r)??await i(e,t)??("android"===e.platform&&t&&t9(t)?r:void 0)}async function oL(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=ej(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=of("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!om(e))return!0;let r=ej(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:a4}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session",device_udid:o.device.id,ios_simulator_device_set:o.device.simulatorSetPath??null}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await oI({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:a4}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:rk})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function oM(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=of("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await oI({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nj("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...nq(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function ox(e){var t,r;let{req:i,sessionName:n,logPath:a,sessionStore:o,invoke:s,dispatch:l,ensureReady:d,resolveTargetDevice:u,installOps:c=oN,reinstallOps:p=ob,stopIosRunner:f,appLogOps:m={start:tO,stop:tL},ensureAndroidEmulatorBoot:h=oA,resolveAndroidPackageForOpen:g=oE,applyRuntimeHints:v=aP,clearRuntimeHints:A=a$,settleSimulator:y,shutdownSimulator:b}=e,N=l??nG,S=d??nW,D=u??nU,E=f??e9,k=y??ow,O=i.command;if("session_list"===O)return{ok:!0,data:{sessions:o.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.id,ios_simulator_device_set:e.device.simulatorSetPath??null}}))}};if("runtime"===O){let e,a=(i.positionals?.[0]??"show").toLowerCase(),s=o.get(n),l=o.getRuntimeHints(n);if(!["set","show","clear"].includes(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime requires set, show, or clear"}};if("clear"===a){aR(l)&&s?.appBundleId&&await A({device:s.device,appId:s.appBundleId});let e=o.clearRuntimeHints(n);return{ok:!0,data:{session:n,cleared:e}}}if("show"===a)return{ok:!0,data:{session:n,configured:!!l,runtime:l}};let d=ej(i.flags?.platform)??l?.platform??s?.device.platform;if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires --platform when the session has not been opened yet."}};if(s&&s.device.platform!==d)return{ok:!1,error:{code:"INVALID_ARGS",message:`runtime set targets ${d}, but session "${n}" is already bound to ${s.device.platform}.`}};let u={platform:(t=i.flags,e=t?.metroPort,r={platform:d,metroHost:oa(t?.metroHost),metroPort:Number.isInteger(e)?e:void 0,bundleUrl:oa(t?.bundleUrl),launchUrl:oa(t?.launchUrl)}).platform??l?.platform,metroHost:r.metroHost??l?.metroHost,metroPort:r.metroPort??l?.metroPort,bundleUrl:r.bundleUrl??l?.bundleUrl,launchUrl:r.launchUrl??l?.launchUrl};return 0===on(u)?{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires at least one hint such as --metro-host, --metro-port, --bundle-url, or --launch-url."}}:(o.setRuntimeHints(n,u),{ok:!0,data:{session:n,configured:!0,runtime:u}})}if("ensure-simulator"===O)try{let e=i.flags??{},t=e.device,r=e.runtime,n=ey(e.iosSimulatorDeviceSet);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"ensure-simulator requires --device <name>"}};let a=!0===e.boot,o=!1!==e.reuseExisting,s=await aQ({deviceName:t,runtime:r,simulatorSetPath:n,reuseExisting:o,boot:a,ensureReady:S});return{ok:!0,data:{udid:s.udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:n??null,created:s.created,booted:s.booted}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("devices"===O)try{let e=[],t=ey(i.flags?.iosSimulatorDeviceSet),r=eN(i.flags?.androidDeviceAllowlist),n=ej(i.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:rc}));e.push(...await t({serialAllowlist:r}))}else if("ios"===n){let{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:nV}));e.push(...await r({simulatorSetPath:t}))}else{let{listAndroidDevices:i}=await Promise.resolve().then(()=>({listAndroidDevices:rc})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:nV}));try{e.push(...await i({serialAllowlist:r}))}catch{}try{e.push(...await n({simulatorSetPath:t}))}catch{}}let a=(i.flags?.target?e.filter(e=>(e.target??"mobile")===i.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===O){let e=o.get(n),t=i.flags??{},r=of(O,e,t);if(r)return r;let a=await oI({session:e,flags:t,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!0});if(!nj("apps",a))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=i.flags?.appsFilter??"all";if("ios"===a.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:nd}));return{ok:!0,data:{apps:(await e(a,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:rS}));return{ok:!0,data:{apps:(await l(a,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===O){let e,t=o.get(n),r=i.flags??{},a=of(O,t,r);if(a)return a;let s="android"===(ej(r.platform)??t?.device.platform),l=!0===r.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=ov({flags:r,sessionDevice:t?.device}),u=s&&!!d,c=!1;try{e=await oI({session:t,flags:r,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!1})}catch(i){let t=w(i);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw i;e=await h({avdName:d,serial:r.serial,headless:l}),c=!0}if(r.target&&(e.target??"mobile")!==r.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${r.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let i=ov({flags:r,sessionDevice:t?.device,resolvedDevice:e});if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await h({avdName:i,serial:r.serial,headless:!0})}await S(e)}else("android"!==e.platform||!0!==e.booted)&&await S(e);return nj("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===O)return await oL({req:i,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D});if("clipboard"===O)return await oM({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N});if("keyboard"===O)return await oy({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"keyboard",positionals:i.positionals??[]});if("perf"===O){let e,t,r,i=o.get(n);return i?{ok:!0,data:(r=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===oe&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:oe,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(i.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:oe,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:oe},{session:i.name,platform:i.device.platform,device:i.device.name,deviceId:i.device.id,metrics:{startup:r,fps:{available:!1,reason:a7},memory:{available:!1,reason:a7},cpu:{available:!1,reason:a7}},sampling:{startup:{method:oe,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("install"===O||"reinstall"===O)return await oS({req:i,command:O,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D,deployOps:"install"===O?c:p});if("push"===O){let e,t=i.positionals?.[0]?.trim(),r=i.positionals?.[1]?.trim();if(!t||!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=nD(r,{subject:"Push payload",cwd:i.meta?.cwd,expandPath:(e,t)=>tw.expandHome(e,t)})).kind?e.path:e.text;return await oy({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"push",positionals:[t,s],recordPositionals:[t,r]})}if("trigger-app-event"===O)return await oy({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"trigger-app-event",positionals:i.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await oO(e.device,r,e.appBundleId,g)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===O){let e=i.flags?.relaunch===!0;if(o.has(n)){let t=o.get(n),r=i.positionals?.[0],s=r??(e?t?.appName:void 0);if(!t||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&t9(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await S(t.device);let l=oo(o,n,t?.device),d=await oO(t.device,s,t.appBundleId,g),u=r?i.positionals??[]:[s];if(e){let e=d??s;await og({device:t.device,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nq(a,i.flags,d??t.appBundleId,t.trace?.outPath)},settleSimulator:k})}await v({device:t.device,appId:d,runtime:l});let c=Date.now();await N(t.device,"open",u,i.flags?.out,{...nq(a,i.flags,d)}),await os({runtime:l,device:t.device,dispatch:N,req:i,logPath:a,appBundleId:d,traceLogPath:t.trace?.outPath,openPositionals:u});let p=ol(c,s,d);await k(t.device,or);let f={...t,appBundleId:d,appName:s,recordSession:t.recordSession||!!i.flags?.saveScript,snapshot:void 0},m=oi({sessionName:n,appName:s,appBundleId:d,startup:p,device:t.device,runtime:l});return o.recordAction(f,{command:O,positionals:u,flags:i.flags??{},result:m}),o.set(n,f),{ok:!0,data:m}}let t=i.positionals?.[0];if(e&&!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&t&&t9(t))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let r=await D(i.flags??{}),s=o.toArray().find(e=>e.device.id===r.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:r.id,deviceName:r.name}}};await S(r);let l=oo(o,n,r),d=await oO(r,t,void 0,g);if(e&&t){let e=d??t;await og({device:r,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nq(a,i.flags,d)},settleSimulator:k})}await v({device:r,appId:d,runtime:l});let u=Date.now();await N(r,"open",i.positionals??[],i.flags?.out,{...nq(a,i.flags,d)}),await os({runtime:l,device:r,dispatch:N,req:i,logPath:a,appBundleId:d,openPositionals:i.positionals??[]});let c=t?ol(u,t,d):void 0;await k(r,or);let p={name:n,device:r,createdAt:Date.now(),appBundleId:d,appName:t,recordSession:!!i.flags?.saveScript,actions:[]},f=oi({sessionName:n,appName:t,appBundleId:d,startup:c,device:r,runtime:l});return o.recordAction(p,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:f}),o.set(n,p),{ok:!0,data:f}}if("replay"===O){let e=i.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=tw.expandHome(e,i.meta?.cwd),r=$.readFileSync(t,"utf8"),l=r.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(tp(i)){let e=th(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return aZ(r)&&aZ(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=th(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(r),u=i.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let r=d[e];if(!r||"replay"===r.command)continue;let l=await s({token:i.token,session:n,command:r.command,positionals:r.positionals??[],flags:oP(i.flags,r.flags),meta:i.meta});if(l.ok)continue;if(!u)return oT(l,r,e,t);let p=await o$({action:r,sessionName:n,logPath:a,sessionStore:o,dispatch:N});if(!p)return oT(l,r,e,t);if(d[e]=p,!(l=await s({token:i.token,session:n,command:p.command,positionals:p.positionals??[],flags:oP(i.flags,p.flags),meta:i.meta})).ok)return oT(l,p,e,t);c+=1}if(u&&c>0){let e=o.get(n);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",tf(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(tf(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(tf(r));return tm(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
35
|
-
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;$.writeFileSync(a,n),$.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:n}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(i.positionals?.[0]??"path").toLowerCase(),r=!!i.flags?.restart;if(!
|
|
36
|
-
`,$.appendFileSync(r,e,"utf8"),{ok:!0,data:{path:r,marked:!0}}}if("clear"===t){if(e.appLog&&!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(r){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!nj("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=o.resolveAppLogPath(n);if(r){e.appLog&&await m.stop(e.appLog);let r=tx(t),i=o.resolveAppLogPidPath(n);try{let a=await m.start(e.device,e.appBundleId,t,i),s={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return o.set(n,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=_(r);return o.set(n,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:tx(t)}}if("start"===t){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!nj("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=o.resolveAppLogPath(n),r=o.resolveAppLogPidPath(n);try{let i=await m.start(e.device,e.appBundleId,t,r),a={...e,appLog:{platform:e.device.platform,backend:i.backend,outPath:t,startedAt:i.startedAt,getState:i.getState,stop:i.stop,wait:i.wait}};return o.set(n,a),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:_(e)}}}if("stop"===t){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await m.stop(e.appLog),o.set(n,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(i.positionals?.[0]??"dump").toLowerCase();if(!od.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:ou}};let r=i.positionals?.[1],a=r?Number.parseInt(r,10):25;if(!Number.isInteger(a)||a<1||a>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(i.positionals?.[2]??"summary").toLowerCase();if(!oc.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:op}};let l=function(e,t){let r=aD(t?.maxEntries,25,1,200),i=t?.include??"summary",n=aD(t?.maxPayloadChars,2048,64,16384),a=aD(t?.maxScanLines,4e3,100,2e4);if(!$.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=$.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=ab(n,["method","httpMethod"]),o=ab(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=av.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=aA.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of ay){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:a_(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return aS(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=a_(t,i))}if("body"===r||"all"===r){let t=aN(e,n,["requestBody","body","payload","request"]),r=aN(e,n,["responseBody","response"]);t&&(f.requestBody=a_(t,i)),r&&(f.responseBody=a_(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(o.resolveAppLogPath(n),{maxEntries:a,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===O)return await oC(i,n,s);if("close"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await m.stop(e.appLog),i.positionals&&i.positionals.length>0&&("ios"===e.device.platform&&await E(e.device.id),await N(e.device,"close",i.positionals,i.flags?.out,{...nq(a,i.flags,e.appBundleId,e.trace?.outPath)}),await k(e.device,ot)),"ios"===e.device.platform&&await E(e.device.id),aR(o.getRuntimeHints(n))&&e.appBundleId&&await A({device:e.device,appId:e.appBundleId}).catch(()=>{}),o.recordAction(e,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:{session:n}}),i.flags?.saveScript&&(e.recordSession=!0),o.writeSessionLog(e),o.delete(n),i.flags?.shutdown&&oh(e.device)){let t;try{t=await (b??iG)(e.device)}catch(r){let e=_(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:n,shutdown:t}}}return{ok:!0,data:{session:n}}}return null}async function oC(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??C;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=c(e.flags?.batchSteps,n),a=Date.now(),o=[];for(let n=0;n<i.length;n+=1){let a=i[n],s=await oR(e,t,a,r,n+1);if(!s.ok)return{ok:!1,error:{code:s.error.code,message:`Batch failed at step ${s.step} (${a.command}): ${s.error.message}`,hint:s.error.hint,diagnosticId:s.error.diagnosticId,logPath:s.error.logPath,details:{...s.error.details??{},step:s.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:o}}};o.push(s.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:o}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function oR(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of a8)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function oT(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>tf(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function oP(e,t){let r={...t??{}},i=e??{};for(let e of a5)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function o$(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(tp(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=tp(t.command)||"fill"===t.command,l=tp(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await oF(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),tp(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=ao(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=aY(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return tl(t).filter(e=>e.trim().length>0)}(t)){let r=at(e);if(!r)continue;let i=ar(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=ad(i.node,o.device.platform,{action:tp(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(tp(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ts(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=ao(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=aY(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=at(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(n4(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=n5(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(n4(e.type??"")))});if(0===s.length||1!==tl(s.map(e=>n5(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=ad(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function oF(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...nq(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:nX(t.flags?.snapshotRaw?s:n3(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function oV(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function oU(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function oG(e,t){return t.flatten?e.map(e=>({text:i(e,0,!1),comparable:oU(e,0)})):y(e).map(e=>({text:e.text,comparable:oU(e.node,e.depth)}))}function oB(e,t){return e.get(t)??0}async function oj(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??nG,o=e.runnerCommand??ta,s=t.command;if("snapshot"===s){let{session:e,device:o}=await oW(n,r,t.flags);if(!nj("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=oH(t.flags?.snapshotScope,e);return s.ok?await oJ(e,o,async()=>{let l=e?.appBundleId,d=await oq({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return oz(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===s){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await oW(n,r,t.flags);if(!nj("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=oH(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await oJ(e,o,async()=>{let d=e?.appBundleId,u=(await oq({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return oG(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return oz(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&oB(a,n-1)<oB(a,n+1)?oB(a,n+1):oB(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&oB(n,l-1)<oB(n,l+1)?l+1:l-1,u=oB(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(oG(e,r),oG(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return oz(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===s){let{session:e,device:o}=await oW(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=oV(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=oV(e[e.length-1]);return{kind:"text",text:(null!==t?e.slice(1,-1).join(" "):e.slice(1).join(" ")).trim(),timeoutMs:t}}if(e[0].startsWith("@")){let t=oV(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=oV(e[e.length-1]),i=aa(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=at(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),oz(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):nj("wait",o)?await oJ(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...nq(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=nX(t.flags?.snapshotRaw?u:n3(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=ai(c,s.selector,{platform:o.platform});if(p)return oz(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=nY(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=nZ(e.snapshot.nodes,t),i=r?n1(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await ta(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return oz(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&n0(nX((await rz(o,{scope:l})).nodes??[]),l))return oz(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===s){let{session:e,device:a}=await oW(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return nj("alert",a)?await oJ(e,a,async()=>{if("wait"===s){let r=oV(t.positionals?.[1])??1e4,s=Date.now();for(;Date.now()-s<r;){try{let r=await o(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return oz(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r="accept"===s||"dismiss"===s?s:"get",l={verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId};if("accept"===r||"dismiss"===r){let i,s=Date.now();for(;Date.now()-s<2e3;){try{let i=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return oz(n,e,t,i),{ok:!0,data:i}}catch(t){i=t;let e=String(t?.message??"").toLowerCase();if(!e.includes("alert not found")&&!e.includes("no alert"))break}await new Promise(e=>setTimeout(e,300))}throw i}let d=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return oz(n,e,t,d),{ok:!0,data:d}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===s){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:f}};let{session:s,device:l}=await oW(n,r,t.flags);return nj("settings",l)?await oJ(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await nG(l,"settings",d,t.flags?.out,{...nq(i,t.flags,r,s?.trace?.outPath)});return oz(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function oq(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...nq(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:nX(n.flags?.snapshotRaw?l:n3(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function oH(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=nY(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=nZ(t.snapshot.nodes,r),n=i?n1(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function oW(e,t,r){let i=e.get(t),n=i?.device??await nU(r??{});return i||await nW(n),{session:i,device:n}}async function oJ(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await e9(t.id)}}function oz(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function oK(e,t,r,i={}){let n=oY(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return oX(e.label,r);case"value":return oX(e.value,r);case"id":return oX(e.identifier,r);default:return Math.max(oX(e.label,r),oX(e.value,r),oX(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function oX(e,t){let r=oY(e??"");return r?r===t?2:+!!r.includes(t):0}function oY(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function oZ(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??nG,s=t.command;if("find"!==s)return null;let l=t.positionals??[];if(0===l.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:d,query:u,action:c,value:p,timeoutMs:f}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:oV(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(l);if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=n.get(r);if(!m&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await nU(t.flags??{});m||await nW(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,b=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...nq(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=nX(t.flags?.snapshotRaw?s:n3(s));return A=e,y=l,m&&(m.snapshot={nodes:l,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,m)),{nodes:l,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=f??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await b();if(oK(e,d,u,{requireRect:!1}).matches[0])return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await b(),S=oK(N,d,u,{requireRect:v});if(v&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=n5(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:S.matches.length,candidates:e}}}}let _=S.matches[0]??null;if(!_)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let D="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,_)??_:_,E=`@${D.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=n5(_);return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get text",text:e}}),{ok:!0,data:{ref:E,text:e,node:_}}}if("get_attrs"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get attrs"}}),{ok:!0,data:{ref:E,node:_}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[E],flags:k});if(!e.ok)return e;let i=D.rect?nQ(D.rect):null,o={ref:E,locator:d,query:u};return i&&(o.x=i.x,o.y=i.y),m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"click",locator:d,query:u}}),{ok:!0,data:o}}if("fill"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[E,p],flags:k});return e.ok&&m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"fill"}}),e}if("focus"===c){let e=_.rect?nQ(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nq(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"focus"}}),{ok:!0,data:r??{ref:E}}}if("type"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=_.rect?nQ(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nq(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...nq(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"type"}}),{ok:!0,data:r??{ref:E}}}return null}function oQ(e){return e instanceof Error?e.message:String(e)}function o0(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function o1(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function o2(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:ta},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await nU(t.flags??{});d||await nW(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!nj("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?o0(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=tw.expandHome(d,t.meta?.cwd),h=t.meta?.clientArtifactPaths?.outPath;$.mkdirSync(n.dirname(m),{recursive:!0});let w=o1(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},w)};try{await n()}catch(e){if(!oQ(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${oQ(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:oQ(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},w)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${oQ(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,clientOutPath:h,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",e_(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,clientOutPath:h,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,clientOutPath:h,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:h??d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=o0(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},o1(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:oQ(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of eY)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}});let m=[{field:"outPath",path:f.outPath,localPath:f.clientOutPath,fileName:n.basename(f.clientOutPath??f.outPath)}];return{ok:!0,data:{recording:"stopped",outPath:f.outPath,artifacts:m}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=tw.expandHome(e);return $.mkdirSync(n.dirname(r),{recursive:!0}),$.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=tw.expandHome(t.positionals[1]);$.mkdirSync(n.dirname(e),{recursive:!0}),$.existsSync(o)?$.renameSync(o,e):$.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function o3(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function o4(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function o8(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function o5(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??nG,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nj("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=o7("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=se({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=st(p.rect);if(!m){let r=await o6(e,t.flags,i,n,{interactiveOnly:!0},a),o=nZ(r.nodes,c),l=s.length>0?n0(r.nodes,s):null,d=st(l?.rect),u=st(o?.rect)?o:d?l:o??l,h=st(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=n1(p,f),w=ad(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=ae(u),p=await o6(e,t.flags,i,n,{interactiveOnly:!0},a),f=await L("selector_resolve",()=>ar(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:an(c,f?.diagnostics??[],{unique:!0})}};let m=st(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=ad(f.node,e.device.platform,{action:l}),v=n1(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!nj("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=o7("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=se({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!n8(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=n1(c,p),w=ad(c,e.device.platform,{action:"fill"}),{x:g,y:I}=nQ(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=aa(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=ae(s.selectorExpression),d=await o6(e,t.flags,i,n,{interactiveOnly:!0},a),u=await L("selector_resolve",()=>ar(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:an(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!n8(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=nQ(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=ad(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:n1(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nj("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=o7("get",t.flags);if(r)return r;let n=se({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=ad(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=n5(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=ae(d),c=await o6(s,t.flags,i,n,{interactiveOnly:!1},a),p=await L("selector_resolve",()=>ar(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:an(u,[],{unique:!0})}};let f=p.node,m=ad(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=n5(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nj("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=ao(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=ae(l.selectorExpression),c=await o6(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=ai(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:an(u,[],{unique:!1})}}}let p=await L("selector_resolve",()=>ar(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:an(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=n5(r),o=!1;switch(t){case"visible":o=as(r);break;case"hidden":o=!as(r);break;case"editable":o=al(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:as(r),editable:al(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nj("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=o7("scrollintoview",t.flags);if(l)return l;let d=se({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=nQ(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=o4(n.map(e=>e.rect).filter(e=>o3(e,r.x,r.y)));if(a)return a;let o=o4(n.map(e=>e.rect));if(o)return o;let s=o4(i.map(e=>e.rect).filter(e=>o3(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:o8(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:o8(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=n1(c,p),w=ad(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function o6(e,t,r,i,n,a=nG){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:nX(t?.snapshotRaw?s:n3(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let o9=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function o7(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of o9)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function se(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=nY(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=nZ(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=n0(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function st(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=nQ(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function sr(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function si(e){let{req:t,leaseRegistry:r}=e,i=sr(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let sn=new Set(["session_list","devices","ensure-simulator"]),sa=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]);function so(e,t,r,i){let n=O().requestId;return{...nq(e,t,r,i,n),requestId:n}}function ss(e){$.existsSync(e)&&$.unlinkSync(e)}function sl(e){if(!$.existsSync(e))return null;try{let t=JSON.parse($.readFileSync(e,"utf8"));if(!Number.isInteger(t.pid)||t.pid<=0)return null;return t}catch{return null}}function sd(e){let t=sl(e);if(!t||t.pid===process.pid)try{$.existsSync(e)&&$.unlinkSync(e)}catch{}}function su(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}let{baseDir:sc,infoPath:sp,lockPath:sf,logPath:sm,sessionsDir:sh}=B(process.env.AGENT_DEVICE_STATE_DIR),sw=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var sg=sh;if($.existsSync(sg))for(let e of $.readdirSync(sg,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(sg,e.name,"app-log.pid");if($.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}($.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{tI(t)}}let sI=new tw(sh),sv=new t3({maxActiveSimulatorLeases:su(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:su(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:su(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:su(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),sA=E(),sy=u.randomBytes(24).toString("hex"),sb=T(process.pid)??void 0,sN=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=$.statSync(e),r=k(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}(),sS=function(e){let{logPath:t,token:r,sessionStore:i,leaseRegistry:a,trackDownloadableArtifact:s}=e;async function l(e){let d="click"===e.command?{...e,command:"press"}:e,u=!!(d.meta?.debug||d.flags?.verbose);return await P({session:d.session,requestId:d.meta?.requestId,command:d.command,debug:u,logPath:t},async()=>{if(d.token!==r)return{ok:!1,error:_(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=D(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=o(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(d);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let r=e.command,u=t=>(function(e,t,r){let i=O();if(!t.ok){M({level:"error",phase:"request_failed",data:{code:t.error.code,message:t.error.message}});let e=F({force:!0})??void 0;return{ok:!1,error:_(new I(t.error.code,t.error.message,{...t.error.details??{},hint:t.error.hint,diagnosticId:t.error.diagnosticId,logPath:t.error.logPath}),{diagnosticId:i.diagnosticId,logPath:e})}}return M({level:"info",phase:"request_success"}),F(),{ok:!0,data:function(e,t,r){var i,a;let o;if(!t)return t;let s=(i=e,a=t,o=Array.isArray(a.artifacts)?[...a.artifacts]:[],"screenshot"!==i.command||o.some(e=>e?.field==="path")||"string"!=typeof a.path||o.push({field:"path",path:a.path,localPath:i.meta?.clientArtifactPaths?.path,fileName:n.basename(i.meta?.clientArtifactPaths?.path??a.path)}),o.filter(e=>!!(e&&"string"==typeof e.field&&"string"==typeof e.path&&"string"==typeof e.localPath&&e.localPath.length>0)));return 0===s.length?t:{...t,artifacts:s.map(t=>{let i=t.path;return{field:t.field,artifactId:r({artifactPath:i,tenantId:e.meta?.tenantId,fileName:t.fileName}),fileName:t.fileName,localPath:t.localPath}})}}(e,t.data,r)}})(e,t,s),c=sr(e);sa.has(r)||e.meta?.sessionIsolation!=="tenant"||a.assertLeaseAdmission({tenantId:c.tenantId,runId:c.runId,leaseId:c.leaseId,backend:c.leaseBackend});let p=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,i),f=i.get(p);f&&!sn.has(r)&&function(e,t){if(!t)return;let r=[],i=e.device,n=ej(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=eb(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(f,e.flags);let m=await si({req:e,leaseRegistry:a});if(m)return u(m);let h=await ox({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(h)return u(h);let w=await oj({req:e,sessionName:p,logPath:t,sessionStore:i});if(w)return u(w);let g=await o2({req:e,sessionName:p,sessionStore:i,logPath:t});if(g)return u(g);let v=await oZ({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(v)return u(v);let A=await o5({req:e,sessionName:p,sessionStore:i,contextFromFlags:(e,r,i)=>so(t,e,r,i)});if(A)return u(A);let y=i.get(p);if(!y)return u({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!nj(r,y.device))return u({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}});let b=await nG(y.device,r,e.positionals??[],e.flags?.out,{...so(t,e.flags,y.appBundleId,y.trace?.outPath)});return i.recordAction(y,{command:r,positionals:e.positionals??[],flags:e.flags??{},result:b??{}}),u({ok:!0,data:b??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=O(),t=F({force:!0})??void 0;return{ok:!1,error:_(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}return l}({logPath:sm,token:sy,sessionStore:sI,leaseRegistry:sv,trackDownloadableArtifact:function(e){let t=u.randomUUID(),r=setTimeout(()=>{tR(t)},9e5);return tC.set(t,{artifactPath:e.artifactPath,tenantId:e.tenantId,fileName:e.fileName,deleteAfterDownload:!1!==e.deleteAfterDownload,timer:r}),t}});!async function(){let e,t;if(!function(e,t,r){$.existsSync(e)||$.mkdirSync(e,{recursive:!0});let i=JSON.stringify(r,null,2),n=()=>{try{return $.writeFileSync(t,i,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(n())return!0;let a=sl(t);if(a?.pid&&a.pid!==process.pid&&s(a.pid,a.processStartTime))return!1;try{$.unlinkSync(t)}catch{}return n()}(sc,sf,{pid:process.pid,version:sA,startedAt:Date.now(),processStartTime:sb})){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===sw||"dual"===sw){let t=U.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))ea(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await e7(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,o,s=t.slice(0,a).trim();if(t=t.slice(a+1),0===s.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(s);if(o=ei(e.meta?.requestId,"socket"),e.meta={...e.meta,requestId:o},i.add(o),en(o),es(o))throw el();n=await sS(e)}catch(e){n={ok:!1,error:_(e)}}finally{r-=1,o&&(i.delete(o),eo(o))}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
37
|
-
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===
|
|
24
|
+
${n}`.toLowerCase();return a.includes("timeout waiting for screen surfaces")||a.includes("nsposixerrordomain")&&a.includes("code=60")&&a.includes("screenshot")||a.includes("timed out")&&a.includes("screenshot")}let i2={settings:"com.apple.Preferences"},i3=null;function i4(e,t,r){return p("xcrun",e_(e,t),r)}function i8(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function i5(e){let t=n.join(e,"Info.plist");try{let e=await p("plutil",["-extract","CFBundleIdentifier","raw","-o","-",t],{allowFailure:!0});if(0!==e.exitCode)return;let r=String(e.stdout??"").trim();return r.length>0?r:void 0}catch{return}}function i6(e){return e.bundleId?`${e.bundleName}.app (${e.bundleId})`:`${e.bundleName}.app`}async function i9(e){await Promise.all(e.map(async e=>{void 0===e.bundleId&&(e.bundleId=await i5(e.installPath))}))}async function i7(e,t){if(".ipa"!==n.extname(e).toLowerCase())return{installPath:e,cleanup:async()=>{}};let r=await x.mkdtemp(n.join(V.tmpdir(),"agent-device-ios-ipa-")),i=async()=>{await x.rm(r,{recursive:!0,force:!0})};try{await p("ditto",["-x","-k",e,r]);let a=n.join(r,"Payload"),o=(await x.readdir(a,{withFileTypes:!0}).catch(()=>{throw new I("INVALID_ARGS","Invalid IPA: missing Payload directory")})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(".app")).map(e=>({installPath:n.join(a,e.name),bundleName:e.name.replace(/\.app$/i,"")}));if(1===o.length)return{installPath:o[0].installPath,cleanup:i};if(0===o.length)throw new I("INVALID_ARGS","Invalid IPA: expected at least one .app under Payload, found 0");await i9(o);let s=t?.appIdentifierHint?.trim();if(s){let e=s.toLowerCase(),t=o.filter(t=>t.bundleName.toLowerCase()===e);if(1===t.length)return{installPath:t[0].installPath,cleanup:i};if(t.length>1)throw new I("INVALID_ARGS",`Invalid IPA: multiple app bundles matched "${s}" by name. Use a bundle id hint instead.`);if(s.includes(".")){let t=o.filter(t=>t.bundleId?.toLowerCase()===e);if(1===t.length)return{installPath:t[0].installPath,cleanup:i}}throw new I("INVALID_ARGS",`Invalid IPA: found ${o.length} .app bundles under Payload and none matched "${s}". Available bundles: ${o.map(i6).join(", ")}`)}throw new I("INVALID_ARGS",`Invalid IPA: found ${o.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${o.map(i6).join(", ")}`)}catch(e){throw await i(),e}}async function ne(e,t){let r=t.trim();if(r.includes("."))return r;let i=i2[r.toLowerCase()];if(i)return i;let n=("simulator"===e.kind?await np(e):await iT(e,"all")).filter(e=>e.name.toLowerCase()===r.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new I("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function nt(e,t,r){let i=r?.url?.trim();if(i){if(!t9(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await iB(e),await iG(),await i4(e,["openurl",e.id,i]);return}let n=t7(r?.appBundleId??await ne(e,t),i);if(!n)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await ny(e,n,{payloadUrl:i});return}let n=t.trim();if(t9(n)){if("simulator"===e.kind){await iB(e),await iG(),await i4(e,["openurl",e.id,n]);return}let t=t7(r?.appBundleId,n);if(!t)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await ny(e,t,{payloadUrl:n});return}let a=r?.appBundleId??await ne(e,t);"simulator"===e.kind?await nA(e,a):await ny(e,a)}async function nr(e){"simulator"!==e.kind||"Booted"!==await iq(e)&&(await iB(e),await iG())}async function ni(e,t){let r=await ne(e,t);if("simulator"===e.kind){await iB(e);let t=e_(e,["terminate",e.id,r]),i=await p("xcrun",t,{allowFailure:!0});if(0!==i.exitCode){if(i.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new I("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:t,stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return}await iR(["device","process","terminate","--device",e.id,r],{action:"terminate iOS app",deviceId:e.id})}async function nn(e,t){let r=await ne(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,r],i=await p("xcrun",t,{allowFailure:!0,timeoutMs:iM});if(0!==i.exitCode){let n=String(i.stdout??""),a=String(i.stderr??"");if(!i8(`${n}
|
|
25
|
+
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:i$(n,a)??iP})}return{bundleId:r}}await iB(e);let i=await i4(e,["uninstall",e.id,r],{allowFailure:!0});if(0!==i.exitCode&&!i8(`${i.stdout}
|
|
26
|
+
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function na(e,t,r){let{installPath:i,cleanup:n}=await i7(t,r);try{if("simulator"!==e.kind)return void await iR(["device","install","app","--device",e.id,i],{action:"install iOS app",deviceId:e.id});await iB(e),await i4(e,["install",e.id,i])}finally{await n()}}async function no(e,t,r){let{bundleId:i}=await nn(e,t);return await na(e,r,{appIdentifierHint:t}),{bundleId:i}}async function ns(e){iU(e,"clipboard"),await iB(e);let t=await i4(e,["pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to read iOS simulator clipboard",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return t.stdout.replace(/\r\n/g,"\n").replace(/\n$/,"")}async function nl(e,t){iU(e,"clipboard"),await iB(e);let r=await i4(e,["pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==r.exitCode)throw new I("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}async function nd(e,t,r){iU(e,"push"),await iB(e);let i=await x.mkdtemp(n.join(V.tmpdir(),"agent-device-ios-push-")),a=n.join(i,"payload.apns");try{await x.writeFile(a,`${JSON.stringify(r)}
|
|
27
|
+
`,"utf8"),await i4(e,["push",e.id,t,a])}finally{await x.rm(i,{recursive:!0,force:!0})}}async function nu(e,t,r,i,n){iU(e,"settings"),await iB(e);let a=t.toLowerCase();switch(a){case"wifi":{let t=nf(r);await i4(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(nf(r)?await i4(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await i4(e,["status_bar",e.id,"clear"]));case"location":{let t=nf(r);if(!i)throw new I("INVALID_ARGS","location setting requires an active app in session");await i4(e,["privacy",e.id,t?"grant":"revoke","location",i]);return}case"faceid":case"touchid":{let t=nh[a],i=function(e,t){let r=e.trim().toLowerCase();if("match"===r)return"match";if("nonmatch"===r)return"nonmatch";if("enroll"===r)return"enroll";if("unenroll"===r)return"unenroll";throw new I("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(r,a);await nv(e,i,{settingName:a,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await nm(e,r);await i4(e,["ui",e.id,"appearance",t]);return}case"permission":{var o;if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(o=ig(r))?"revoke":o,a=function(e,t){let r=iI(e);if("photos"!==r&&t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return"camera";if("microphone"===r)return"microphone";if("contacts"===r)return"contacts";if("contacts-limited"===r)return"contacts-limited";if("notifications"===r)return"notifications";if("calendar"===r)return"calendar";if("location"===r)return"location";if("location-always"===r)return"location-always";if("media-library"===r)return"media-library";if("motion"===r)return"motion";if("reminders"===r)return"reminders";if("siri"===r)return"siri";if("photos"===r){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new I("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new I("INVALID_ARGS",`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}(n?.permissionTarget,n?.permissionMode);await nw(e,t,a,i);return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function nc(e,t="all"){var r;return"simulator"===e.kind?(r=await np(e),"user-installed"===t?r.filter(e=>!e.bundleId.startsWith("com.apple.")):r):await iT(e,t)}async function np(e){let t=(await i4(e,["listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let r=null;if(t.startsWith("{"))try{r=JSON.parse(t)}catch{r=null}if(!r&&t.startsWith("{"))try{let e=await p("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(r=JSON.parse(e.stdout))}catch{r=null}return r?Object.entries(r).map(([e,t])=>({bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e})):[]}function nf(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function nm(e,t){let r=iv(t);if("toggle"!==r)return r;let i=await i4(e,["ui",e.id,"appearance"],{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current iOS appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}
|
|
28
|
+
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let nh={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function nw(e,t,r,i){let n=await nI(e);if(!n.has(r))throw new I("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["privacy",e.id,t,r,i],o="notifications"===r;if(!("reset"===t&&o))try{await i4(e,a);return}catch(t){if(!(o&&ng(t)))throw t;throw new I("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e.id,appBundleId:i,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await i4(e,a);return}catch(e){if(!ng(e))throw e}try{await i4(e,["privacy",e.id,"reset","all",i])}catch(t){throw new I("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e.id,appBundleId:i,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function ng(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return(t.includes("failed to grant access")||t.includes("failed to revoke access")||t.includes("failed to reset access"))&&t.includes("operation not permitted")}async function nI(t){let r=ey(t.simulatorSetPath),i=`${process.env.PATH??""}::${r??""}`;if(i3&&e===i)return i3;let n=await i4(t,["privacy","help"],{allowFailure:!0}),a=function(e){let t=new Set,r=!1;for(let i of e.split("\n")){let e=i.trim();if(!e)continue;if("service"===e){r=!0;continue}if(!r)continue;if(e.startsWith("bundle identifier"))break;let n=/^([a-z-]+)\s+-\s+/.exec(e);n&&t.add(n[1])}return t}(`${n.stdout}
|
|
29
|
+
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return i3=a,e=i,a}async function nv(e,t,r){let i=function(e,t,r){let i=r.length>0?r:["face"];switch(t){case"match":return i.flatMap(t=>[["biometric",e,"match",t],["biometric","match",e,t]]);case"nonmatch":return i.flatMap(t=>[["biometric",e,"nonmatch",t],["biometric",e,"nomatch",t],["biometric","nonmatch",e,t],["biometric","nomatch",e,t]]);case"enroll":return[["biometric",e,"enroll","yes"],["biometric",e,"enroll","1"],["biometric","enroll",e,"yes"],["biometric","enroll",e,"1"]];case"unenroll":return[["biometric",e,"enroll","no"],["biometric",e,"enroll","0"],["biometric","enroll",e,"no"],["biometric","enroll",e,"0"]]}}(e.id,t,r.modalityAliases),n=[];for(let t of i){let r=e_(e,t),i=await p("xcrun",r,{allowFailure:!0});if(0===i.exitCode)return;n.push({args:r,stderr:i.stderr,stdout:i.stdout,exitCode:i.exitCode})}let a=n.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(n.length>0&&n.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
30
|
+
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}async function nA(e,t){await iB(e),await iG();let r=0,i=K.fromTimeoutMs(iL);try{await X(async({deadline:r})=>{var i;if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:iL});let n=(i=["launch",e.id,t],e_(e,i)),a=await p("xcrun",n,{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${a.exitCode}`,{cmd:"xcrun",args:n,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode})},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>!!iF(e)&&(r+=1)<3},{deadline:i})}catch(r){if(iF(r)){var n;let i=(n=await iV(e,t)).installed?!1===n.simulatorCompatible?"ARCH_MISMATCH":"PERSISTENT_LAUNCH_FAIL":"APP_NOT_INSTALLED";r.details={...r.details,hint:function(e){switch(e){case"ARCH_MISMATCH":return"The app binary was not built for the simulator platform. Rebuild with a simulator destination or use a physical device.";case"APP_NOT_INSTALLED":return"The app bundle is not installed on this simulator. Run install before open.";case"PERSISTENT_LAUNCH_FAIL":return"The simulator repeatedly refused to launch the app. Inspect crash logs in Console.app or ~/Library/Logs/DiagnosticReports/ and consider reinstalling the app.";default:return"The simulator failed to launch the app. Retry with --debug and inspect diagnostics log for details."}}(i)}}throw r}}async function ny(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await iR(i,{action:"launch iOS app",deviceId:e.id})}let nb=/^[A-Za-z0-9_.:-]{1,64}$/,nN=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function nS(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function n_(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await nD(t)}async function nD(e){await new Promise(t=>setTimeout(t,e))}function nE(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!$.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function nk(e){let t=nE(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await nO(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function nO(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}let nL=ew(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),nM=/^(iphone|ipad|ipod|appletv)/i,nx=/^appletv/i,nC=["apple tv","appletv","tvos"];function nR(e){return(e??"").trim().toLowerCase()}function nT(e){return nR(e.hardwareProperties?.platform)}function nP(e){return e.includes("tvos")}function n$(e){let t=nR(e);return nC.some(e=>t.includes(e))}function nF(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function nV(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function nU(e={}){if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await A("xcrun"))throw new I("TOOL_MISSING","xcrun not found in PATH");let t=[],r=ey(e.simulatorSetPath),i=await p("xcrun",eS(["list","devices","-j"],{simulatorSetPath:r}));try{let e=JSON.parse(i.stdout);for(let[i,n]of Object.entries(e.devices))if(function(e){let t=nR(e);return t.includes("ios")||t.includes("tvos")}(i))for(let e of n){var a;e.isAvailable&&t.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:(a=i,nP(nR(a))?"tv":"mobile"),booted:"Booted"===e.state,...r?{simulatorSetPath:r}:{}})}}catch(e){throw new I("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(r)return t;let o=null;try{o=n.join(V.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let e=await p("xcrun",["devicectl","list","devices","--json-output",o],{allowFailure:!0,timeoutMs:nL});if(0!==e.exitCode)return t;let r=await x.readFile(o,"utf8"),i=JSON.parse(r);for(let e of i.result?.devices??[])if(function(e){var t;let r=nT(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=nV(e),!!nM.test(t.trim())||nF(e).some(n$))}(e)){let r=e.hardwareProperties?.udid??e.identifier??"",i=e.name??e.deviceProperties?.name??r;if(!r)continue;t.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return nP(nT(e))?"tv":(t=nV(e),nx.test(t.trim())||nF(e).some(n$))?"tv":"mobile"}(e),booted:!0})}}catch{}finally{o&&await x.rm(o,{force:!0}).catch(()=>{})}return t}async function nG(e){let t=ej(e.platform),r=ey(e.iosSimulatorDeviceSet),i=eN(e.androidDeviceAllowlist);return await L("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await t8();let e=await rc({serialAllowlist:i});return await eq(e,n)}if("ios"===n.platform){let e=await nU({simulatorSetPath:r});return await eq(e,n,{simulatorSetPath:r})}let a=[];try{a.push(...await rc({serialAllowlist:i}))}catch{}try{a.push(...await nU({simulatorSetPath:r}))}catch{}return await eq(a,n,{simulatorSetPath:r})},{platform:t,target:e.target})}async function nB(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>rL(e,t,r?.activity),openDevice:()=>rx(e),close:t=>rC(e,t),tap:(t,r)=>r1(e,t,r),doubleTap:async(t,r)=>{await r1(e,t,r),await r1(e,t,r)},swipe:(t,r,i,n,a)=>r2(e,t,r,i,n,a),longPress:(t,r,i)=>r5(e,t,r,i),focus:(t,r)=>r9(e,t,r),type:t=>r6(e,t),fill:(t,r,i)=>r7(e,t,r,i),scroll:(t,r)=>ie(e,t,r),scrollIntoView:t=>it(e,t),screenshot:(t,r)=>rX(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>nt(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>nr(e),close:t=>ni(e,t),screenshot:(t,r)=>iJ(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(es(i.requestId))throw el()},{tap:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await ta(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await ta(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await ta(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await ta(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await ta(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await ta(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await ta(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await L("platform_command",async()=>{switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(t9(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!t9(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=nS(a?.count??1,"count",1,200),s=nS(a?.intervalMs??0,"interval-ms",0,1e4),l=nS(a?.holdMs??0,"hold-ms",0,1e4),d=nS(a?.jitterPx??0,"jitter-px",0,100),u=a?.doubleTap===!0;if(u&&l>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(u&&d>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if("ios"===e.platform&&n>1&&0===l&&0===d)return await ta(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:s,doubleTap:u,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u,timingMode:"runner-series"};return await n_(n,s,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=nN[e%nN.length];return[r*t,i*t]}(e,d),a=t+r,s=i+n;u?await o.doubleTap(a,s):l>0?await o.longPress(a,s,l):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=nS(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=nS(a?.count??1,"count",1,200),c=nS(a?.pauseMs??0,"pause-ms",0,1e4),p=a?.pattern??"one-way";if("one-way"!==p&&"ping-pong"!==p)throw new I("INVALID_ARGS",`Invalid pattern: ${p}`);if("ios"===e.platform&&u>1)return await ta(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:c,pattern:p,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:c,pattern:p};return await n_(u,c,async e=>{"ping-pong"===p&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:c,pattern:p}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await ta(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!nb.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await ta(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await r3(e),{action:"back"};case"home":if("ios"===e.platform)return await ta(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await r4(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await ta(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await r8(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await ns(e):await ip(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await nl(e,i):await im(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await ic(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await iu(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await nu(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await iA(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await nk(i);if("ios"===e.platform)return await nd(e,t,n),{platform:"ios",bundleId:t};let a=await iE(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await L("snapshot_capture",async()=>await ta(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await L("snapshot_capture",async()=>await rz(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let nj={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},install:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function nq(e,t){let r=nj[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function nH(e,t,r,i,n){return{requestId:n??O().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let nW=ew(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function nJ(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:iB}));await t(e);return}if("device"===e.kind)return void await nz(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:rI}));await t(e.id)}}async function nz(e){let t=n.join(V.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(nW/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:nW+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await nK(t);if(0===i.exitCode){if(!o.parsed)throw new I("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:nX(n,a)})}catch(t){if(t instanceof I&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??nW),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?nX(i,n):o},t)}throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await x.rm(t,{force:!0}).catch(()=>{})}}async function nK(e){try{let t=await x.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function nX(e,t){let r=i$(e,t);return r||(`${e}
|
|
31
|
+
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":iP)}function nY(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function nZ(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function nQ(e,t){return e.find(e=>e.ref===t)??null}function n0(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function n1(e,t){let r=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),i=(e.value??"").toLowerCase(),n=(e.identifier??"").toLowerCase();return t.includes(r)||i.includes(r)||n.includes(r)})??null}function n2(e,t){let r=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);return r&&n3(r)?r:function(e,t){if(!e.rect)return;let r=e.rect.y+e.rect.height/2,i=null;for(let e of t){if(!e.rect)continue;let t=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);if(!t||!n3(t))continue;let n=Math.abs(e.rect.y+e.rect.height/2-r);(!i||n<i.distance)&&(i={label:t,distance:n})}return i?.label}(e,t)??(r&&n3(r)?r:void 0)}function n3(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function n4(e){let t=[],r=[];for(let i of e){let e=i.depth??0;for(;t.length>0&&e<=t[t.length-1];)t.pop();let n=n8(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&n3(a);if(("group"===n||"ioscontentgroup"===n)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);r.push({...i,depth:s})}return r}function n8(e){let t=e.trim().replace(/XCUIElementType/gi,"").toLowerCase(),r=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==r&&(t=t.slice(r+1)),t}function n5(e,t){let r=n8(e);return!r||("android"===t?r.includes("edittext")||r.includes("autocompletetextview"):r.includes("textfield")||r.includes("securetextfield")||r.includes("searchfield")||r.includes("textview")||r.includes("textarea")||"search"===r)}function n6(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let n9=new Set(["id","role","text","label","value"]),n7=new Set(["visible","hidden","editable","selected","enabled","hittable"]),ae=new Set([...n9,...n7]);function at(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!av(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&"|"===a&&"|"===e[n+1]){let i=r.trim();if(!i)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new I("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!av(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&/\s/.test(a)){r.trim().length>0&&t.push(r.trim()),r="";continue}r+=a}if(i)throw new I("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new I("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(ac)}})(e))}}function ar(e){try{return at(e)}catch{return null}}function ai(e,t,r){let i=r.requireRect??!1,n=r.requireUnique??!0,a=r.disambiguateAmbiguous??!1,o=[];for(let s=0;s<t.selectors.length;s+=1){let l=t.selectors[s],d=function(e,t,r){let i=0,n=null,a=null,o=!1;for(let s of e){if(r.requireRect&&!s.rect||!ap(s,t,r.platform))continue;if(i+=1,n||(n=s),!a){a=s;continue}let e=function(e,t){let r=e.depth??0,i=t.depth??0;if(r!==i)return r>i?1:-1;let n=aI(e),a=aI(t);return n!==a?n<a?1:-1:0}(s,a);if(e>0){a=s,o=!1;continue}0===e&&(o=!0)}return{count:i,firstNode:n,disambiguated:o?null:a}}(e,l,{platform:r.platform,requireRect:i});if(o.push({selector:l.raw,matches:d.count}),0!==d.count&&d.firstNode){if(n&&1!==d.count){if(!a)continue;let e=d.disambiguated;if(!e)continue;return{node:e,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}return{node:d.firstNode,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}}return null}function an(e,t,r){let i=r.requireRect??!1,n=[];for(let a=0;a<t.selectors.length;a+=1){let o=t.selectors[a],s=function(e,t,r){let i=0;for(let n of e)(!r.requireRect||n.rect)&&ap(n,t,r.platform)&&(i+=1);return i}(e,o,{platform:r.platform,requireRect:i});if(n.push({selector:o.raw,matches:s}),s>0)return{selectorIndex:a,selector:o,matches:s,diagnostics:n}}return null}function aa(e,t,r){let i=r.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let n=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return i?`Selector did not resolve uniquely (${n})`:`Selector did not match (${n})`}function ao(e,t={}){if(0===e.length)return null;let r=t.preferTrailingValue??!1,i=0,n=[];for(;i<e.length&&function(e){let t=e.trim();if(!t)return!1;if("||"===t)return!0;let r=t.indexOf("=");if(-1!==r){let e=t.slice(0,r).trim().toLowerCase();return ae.has(e)}return ae.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&ar(t)&&n.push(i)}if(0===n.length)return null;let a=n[n.length-1];if(r){for(let t=n.length-1;t>=0;t-=1)if(n[t]<e.length){a=n[t];break}}let o=e.slice(0,a).join(" ").trim();return o?{selectorExpression:o,rest:e.slice(a)}:null}function as(e){let t=e[0]??"",r=ao(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function al(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function ad(e,t){return n5(e.type??"",t)&&!1!==e.enabled}function au(e,t,r={}){let i=[],n=n8(e.type??""),a=ag(e.identifier),o=ag(e.label),s=ag(e.value),l=ag(n6(e)),d="fill"===r.action;a&&i.push(`id=${aw(a)}`),n&&o&&i.push(d?`role=${aw(n)} label=${aw(o)} editable=true`:`role=${aw(n)} label=${aw(o)}`),o&&i.push(d?`label=${aw(o)} editable=true`:`label=${aw(o)}`),s&&i.push(d?`value=${aw(s)} editable=true`:`value=${aw(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${aw(l)} editable=true`:`text=${aw(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${aw(n)} editable=true`);let u=tl(i);return 0===u.length&&n&&u.push(d?`role=${aw(n)} editable=true`:`role=${aw(n)}`),0===u.length&&al(e)&&u.push("visible=true"),u}function ac(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!n7.has(r))throw new I("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let i=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!ae.has(i))throw new I("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new I("INVALID_ARGS",`Missing selector value for key: ${i}`);if(n7.has(i)){let e,t="true"===(e=af(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new I("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:af(n)}}function ap(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return am(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return n8(e)}(i??"")===function(e){return n8(e)}(n);case"label":return am(e.label,String(t.value));case"value":return am(e.value,String(t.value));case"text":{let r=ah(String(t.value));return ah(n6(e))===r}case"visible":return al(e)===!!t.value;case"hidden":return!al(e)==!!t.value;case"editable":return ad(e,r)===!!t.value;case"selected":return!0===e.selected==!!t.value;case"enabled":return!1!==e.enabled==!!t.value;case"hittable":return!0===e.hittable==!!t.value;default:return!1}})(e,t,r))}function af(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function am(e,t){return ah(e??"")===ah(t)}function ah(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function aw(e){return JSON.stringify(e)}function ag(e){if(!e)return null;let t=e.trim();return t||null}function aI(e){return e.rect?e.rect.width*e.rect.height:1/0}function av(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}let aA=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),ay=/https?:\/\/[^\s"'<>\])]+/i,ab=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function aN(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function aS(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return a_(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function a_(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function aD(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function aE(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let ak="shared_prefs/ReactNativeDevPrefs.xml",aO="debug_http_host",aL="dev_server_https",aM="RCT_jsLocation",ax="RCT_packager_scheme",aC="React Native runtime hints require adb run-as access to the app sandbox. Verify the app is debuggable and the selected package/device are correct.",aR='<?xml version="1.0" encoding="utf-8" standalone="yes" ?>\n<map>\n</map>\n';function aT(e){return void 0!==aP(e)}function aP(e){if(!e)return;let t=az(e.metroHost),r=aK(e.metroPort),i="http",n=az(e.bundleUrl);if(n){var a;let e;try{e=new v(n)}catch(e){throw new I("INVALID_ARGS",`Invalid runtime bundle URL: ${n}`,{},e)}("http:"===e.protocol||"https:"===e.protocol)&&(t??=az(e.hostname),r??=aK(e.port.length>0?Number(e.port):"https:"===(a=e.protocol)?443:"http:"===a?80:void 0),i="https:"===e.protocol?"https":"http")}if(t&&r)return{host:t,port:r,scheme:i}}async function a$(e){let{device:t,appId:r,runtime:i}=e;if(!r)return;let n=aP(i);if(n){if("android"===t.platform)return void await aV(t,r,n);"ios"===t.platform&&"simulator"===t.kind&&await aj(t,r,n)}}async function aF(e){let{device:t,appId:r}=e;if(r){if("android"===t.platform)return void await aU(t,r);"ios"===t.platform&&"simulator"===t.kind&&await aq(t,r)}}async function aV(e,t,r){var i,n,a,o,s,l;let d,u,c=(i=await aG(e,t),n=aO,a=`${r.host}:${r.port}`,d=` <string name="${aX(n)}">${aX(a)}</string>`,aW(aJ(i,n),d));o=c,s=aL,l="https"===r.scheme,u=` <boolean name="${aX(s)}" value="${l?"true":"false"}" />`,c=aW(aJ(o,s),u),await aB(e,t,c)}async function aU(e,t){let r=await aG(e,t),i=aJ(r,aO),n=aJ(i,aL);n!==r&&await aB(e,t,n)}async function aG(e,t){let r=await p("adb",t4(e,["shell","run-as",t,"cat",ak]),{allowFailure:!0});return 0!==r.exitCode?aR:aH(r.stdout)}async function aB(e,t,r){let i=t4(e,["shell","run-as",t,"id"]),n=await p("adb",i,{allowFailure:!0});if(0!==n.exitCode){let e=aY(n.stdout,n.stderr);throw new I("COMMAND_FAILED",e?`Failed to access Android app sandbox for ${t}`:`Failed to probe Android app sandbox for ${t}`,{package:t,cmd:"adb",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:e?aC:"adb shell run-as probe failed. Check adb connectivity and that the device is reachable. Inspect stderr/details for more information."})}let a=`mkdir -p shared_prefs && cat > ${ak}`,o=t4(e,["shell","run-as",t,"sh","-c",`'${a}'`]);try{await p("adb",o,{stdin:r.trimEnd()})}catch(i){let e=w(i);if("TOOL_MISSING"===e.code)throw e;let r=aY("string"==typeof e.details?.stdout?e.details.stdout:"","string"==typeof e.details?.stderr?e.details.stderr:"");throw new I("COMMAND_FAILED",r?`Failed to access Android app sandbox for ${t}`:`Failed to write Android runtime hints for ${t}`,{...e.details??{},package:t,cmd:"adb",args:o,phase:"write-runtime-hints",hint:r?aC:"adb run-as succeeded, but writing ReactNativeDevPrefs.xml failed. Inspect stderr/details for the failing shell command."},e)}}async function aj(e,t,r){await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aM,"-string",`${r.host}:${r.port}`])),await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,ax,"-string",r.scheme]))}async function aq(e,t){await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aM]),{allowFailure:!0}),await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,ax]),{allowFailure:!0})}function aH(e){let t=e.trim();return t.includes("<map")&&t.includes("</map>")?`${t}
|
|
32
|
+
`:aR}function aW(e,t){return aH(e).replace("</map>",`${t}
|
|
33
|
+
</map>`)}function aJ(e,t){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return aH(e).replace(RegExp(`^\\s*<string name="${r}">[\\s\\S]*?<\\/string>\\n?`,"m"),"").replace(RegExp(`^\\s*<boolean name="${r}" value="(?:true|false)"\\s*\\/?>\\n?`,"m"),"")}function az(e){let t=e?.trim();return t&&t.length>0?t:void 0}function aK(e){if(Number.isInteger(e)&&!(e<=0)&&!(e>65535))return e}function aX(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function aY(e,t){let r=`${e}
|
|
34
|
+
${t}`.toLowerCase();return["run-as: package not debuggable","run-as: permission denied","run-as: package is unknown","run-as: unknown package","is unknown","is not an application","could not set capabilities"].some(e=>r.includes(e))}function aZ(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=ao(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function aQ(e){return!!e&&!Number.isNaN(Number(e))}async function a0(e){let t,r,i,{deviceName:n,runtime:a,simulatorSetPath:o,reuseExisting:s,boot:l,ensureReady:d}=e;if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","ensure-simulator is only available on macOS");let u={simulatorSetPath:o??void 0};if(s){let e=await a1({deviceName:n,runtime:a,simctlOpts:u});e?(t=e.udid,r=e.runtime,i=!1):(t=(await a2({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await a3(t,u),i=!0)}else t=(await a2({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await a3(t,u),i=!0;let c=!1;if(l){let e={platform:"ios",id:t,name:n,kind:"simulator",target:"mobile",...o?{simulatorSetPath:o}:{}};await d(e),c=!0}return{udid:t,device:n,runtime:r,created:i,booted:c}}async function a1(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=await p("xcrun",eS(["list","devices","-j"],i),{allowFailure:!0,timeoutMs:iO});if(0!==n.exitCode)return null;try{let e=JSON.parse(String(n.stdout??""));for(let[i,n]of Object.entries(e.devices??{}))if(!r||a4(i).includes(a4(r))){for(let e of n)if(e.isAvailable&&e.name.toLowerCase()===t.toLowerCase())return{udid:e.udid,runtime:i}}return null}catch{return null}}async function a2(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=r?["create",t,t,r]:["create",t,t],a=await p("xcrun",eS(n,i),{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED","Failed to create iOS simulator",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode,hint:"Ensure the device type and runtime identifiers are valid. Run `xcrun simctl list devicetypes` and `xcrun simctl list runtimes` to see available options."});let o=String(a.stdout??"").trim();if(!o)throw new I("COMMAND_FAILED","simctl create returned no UDID",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??"")});return{udid:o}}async function a3(e,t){let r=await p("xcrun",eS(["list","devices","-j"],t),{allowFailure:!0,timeoutMs:iO});if(0!==r.exitCode)return"";try{let t=JSON.parse(String(r.stdout??""));for(let[r,i]of Object.entries(t.devices??{}))if(i.some(t=>t.udid===e))return r;return""}catch{return""}}function a4(e){return e.toLowerCase().replace(/[._-]/g,"")}let a8='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',a5=["platform","target","device","udid","serial","verbose","out"],a6=["platform","target","device","udid","serial","verbose","out"],a9=["path","start","stop","doctor","mark","clear"],a7=`logs requires ${a9.slice(0,-1).join(", ")}, or ${a9.at(-1)}`,oe="Not implemented for this platform in this release.",ot="open-command-roundtrip",or=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_CLOSE_SETTLE_MS,300,0),oi=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_OPEN_SETTLE_MS,300,0);function on(e){let{sessionName:t,appName:r,appBundleId:i,startup:n,device:a,runtime:o}=e,s={session:t};return r&&(s.appName=r),i&&(s.appBundleId=i),n&&(s.startup=n),o&&oa(o)>0&&(s.runtime=o),a?.platform==="ios"&&(s.device_udid=a.id,s.ios_simulator_device_set=a.simulatorSetPath??null),s}function oa(e){return e?[e.metroHost,e.metroPort,e.bundleUrl,e.launchUrl].filter(e=>void 0!==e&&""!==e).length:0}function oo(e){let t=e?.trim();return t&&t.length>0?t:void 0}function os(e,t,r){let i=e.getRuntimeHints(t);if(i){if(i.platform&&r&&i.platform!==r.platform)throw new I("INVALID_ARGS",`Session runtime hints target ${i.platform}, but session "${t}" is bound to ${r.platform}. Clear the runtime hints or use a different session.`);return r?.platform&&i.platform!==r.platform?{...i,platform:r.platform}:i}}async function ol(e){let{runtime:t,device:r,dispatch:i,req:n,logPath:a,appBundleId:o,traceLogPath:s,openPositionals:l}=e,d=t?.launchUrl;if(!d||0===l.length||l.length>1)return;let u=l[0]?.trim();!u||t9(u)||await i(r,"open",[d],n.flags?.out,{...nH(a,n.flags,o,s)})}function od(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:ot,appTarget:t,appBundleId:r}}let ou=["dump","log"],oc=`network requires ${ou.join(" or ")}`,op=["summary","headers","body","all"],of=`network include mode must be one of: ${op.join(", ")}`;function om(e,t,r){return t||oh(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function oh(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}function ow(e){return"ios"===e.platform&&"simulator"===e.kind}async function og(e,t){ow(e)&&!(t<=0)&&await new Promise(e=>setTimeout(e,t))}async function oI(e){let{device:t,closeTarget:r,stopIosRunner:i,dispatch:n,outFlag:a,context:o,settleSimulator:s}=e;"ios"===t.platform&&await i(t.id),await n(t,"close",[r],a,o),await s(t,or)}async function ov(e){let t=oh(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function oA(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let oy=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:rg}));return await i({avdName:e,serial:t,headless:r})};async function ob(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=om(l,p,f);if(m)return m;let h=await ov({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nq(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...nH(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let oN={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:no}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:rG}));return await i(e,t,r)}},oS={ios:async(e,t,r)=>{let{installIosApp:i}=await Promise.resolve().then(()=>({installIosApp:na}));await i(e,r,{appIdentifierHint:t});let{bundleId:n}=await oO(e,t);return n?{bundleId:n}:{}},android:async(e,t,r)=>{let{installAndroidApp:i}=await Promise.resolve().then(()=>({installAndroidApp:rU}));await i(e,r);let{package:n}=await oO(e,t);return n?{package:n}:{}}};async function o_(e){let{req:t,command:r,sessionName:i,sessionStore:n,ensureReady:a,resolveDevice:o,deployOps:s}=e,l=n.get(i),d=t.flags??{},u=om(r,l,d);if(u)return u;let c=t.positionals?.[0]?.trim(),p=t.positionals?.[1]?.trim();if(!c||!p)return{ok:!1,error:{code:"INVALID_ARGS",message:`${r} requires: ${r} <app> <path-to-app-binary>`}};let f=t.meta?.uploadedArtifactId;try{let e,i=f?function(e,t){let r=tT.get(e);if(!r)throw new I("INVALID_ARGS",`Uploaded artifact not found: ${e}`);if(r.tenantId&&r.tenantId!==t)throw new I("UNAUTHORIZED","Uploaded artifact belongs to a different tenant");return clearTimeout(r.timer),r.artifactPath}(f,t.meta?.tenantId):tw.expandHome(p);if(!$.existsSync(i))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${i}`}};let u=await ov({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!1});if(!nq(r,u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}};if("ios"===u.platform){let t=(await s.ios(u,c,i)).bundleId;e=t?{app:c,appPath:i,platform:"ios",appId:t,bundleId:t}:{app:c,appPath:i,platform:"ios"}}else{let t=(await s.android(u,c,i)).package;e=t?{app:c,appPath:i,platform:"android",appId:t,package:t}:{app:c,appPath:i,platform:"android"}}return l&&n.recordAction(l,{command:r,positionals:t.positionals??[],flags:t.flags??{},result:e}),{ok:!0,data:e}}finally{f&&tP(f)}}async function oD(e,t,r){if("ios"===e.platform&&t)return t9(t)?"device"===e.kind?t7(r,t):void 0:await oE(e,t)}async function oE(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:ne}));return await r(e,t)}catch{return}}async function ok(e,t){if(!("android"!==e.platform||!t||t9(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:rN})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function oO(e,t){return"ios"===e.platform?{bundleId:await oE(e,t)}:{package:await ok(e,t)}}async function oL(e,t,r,i){return await oD(e,t,r)??await i(e,t)??("android"===e.platform&&t&&t9(t)?r:void 0)}async function oM(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=ej(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=om("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!oh(e))return!0;let r=ej(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:a8}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session",device_udid:o.device.id,ios_simulator_device_set:o.device.simulatorSetPath??null}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await ov({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:a8}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:rk})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function ox(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=om("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await ov({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nq("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...nH(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function oC(e){var t,r;let{req:i,sessionName:n,logPath:a,sessionStore:o,invoke:s,dispatch:l,ensureReady:d,resolveTargetDevice:u,installOps:c=oS,reinstallOps:p=oN,stopIosRunner:f,appLogOps:m={start:tO,stop:tL},ensureAndroidEmulatorBoot:h=oy,resolveAndroidPackageForOpen:g=ok,applyRuntimeHints:v=a$,clearRuntimeHints:A=aF,settleSimulator:y,shutdownSimulator:b}=e,N=l??nB,S=d??nJ,D=u??nG,E=f??e9,k=y??og,O=i.command;if("session_list"===O)return{ok:!0,data:{sessions:o.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.id,ios_simulator_device_set:e.device.simulatorSetPath??null}}))}};if("runtime"===O){let e,a=(i.positionals?.[0]??"show").toLowerCase(),s=o.get(n),l=o.getRuntimeHints(n);if(!["set","show","clear"].includes(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime requires set, show, or clear"}};if("clear"===a){aT(l)&&s?.appBundleId&&await A({device:s.device,appId:s.appBundleId});let e=o.clearRuntimeHints(n);return{ok:!0,data:{session:n,cleared:e}}}if("show"===a)return{ok:!0,data:{session:n,configured:!!l,runtime:l}};let d=ej(i.flags?.platform)??l?.platform??s?.device.platform;if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires --platform when the session has not been opened yet."}};if(s&&s.device.platform!==d)return{ok:!1,error:{code:"INVALID_ARGS",message:`runtime set targets ${d}, but session "${n}" is already bound to ${s.device.platform}.`}};let u={platform:(t=i.flags,e=t?.metroPort,r={platform:d,metroHost:oo(t?.metroHost),metroPort:Number.isInteger(e)?e:void 0,bundleUrl:oo(t?.bundleUrl),launchUrl:oo(t?.launchUrl)}).platform??l?.platform,metroHost:r.metroHost??l?.metroHost,metroPort:r.metroPort??l?.metroPort,bundleUrl:r.bundleUrl??l?.bundleUrl,launchUrl:r.launchUrl??l?.launchUrl};return 0===oa(u)?{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires at least one hint such as --metro-host, --metro-port, --bundle-url, or --launch-url."}}:(o.setRuntimeHints(n,u),{ok:!0,data:{session:n,configured:!0,runtime:u}})}if("ensure-simulator"===O)try{let e=i.flags??{},t=e.device,r=e.runtime,n=ey(e.iosSimulatorDeviceSet);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"ensure-simulator requires --device <name>"}};let a=!0===e.boot,o=!1!==e.reuseExisting,s=await a0({deviceName:t,runtime:r,simulatorSetPath:n,reuseExisting:o,boot:a,ensureReady:S});return{ok:!0,data:{udid:s.udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:n??null,created:s.created,booted:s.booted}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("devices"===O)try{let e=[],t=ey(i.flags?.iosSimulatorDeviceSet),r=eN(i.flags?.androidDeviceAllowlist),n=ej(i.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:rc}));e.push(...await t({serialAllowlist:r}))}else if("ios"===n){let{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:nU}));e.push(...await r({simulatorSetPath:t}))}else{let{listAndroidDevices:i}=await Promise.resolve().then(()=>({listAndroidDevices:rc})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:nU}));try{e.push(...await i({serialAllowlist:r}))}catch{}try{e.push(...await n({simulatorSetPath:t}))}catch{}}let a=(i.flags?.target?e.filter(e=>(e.target??"mobile")===i.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===O){let e=o.get(n),t=i.flags??{},r=om(O,e,t);if(r)return r;let a=await ov({session:e,flags:t,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!0});if(!nq("apps",a))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=i.flags?.appsFilter??"all";if("ios"===a.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:nc}));return{ok:!0,data:{apps:(await e(a,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:rS}));return{ok:!0,data:{apps:(await l(a,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===O){let e,t=o.get(n),r=i.flags??{},a=om(O,t,r);if(a)return a;let s="android"===(ej(r.platform)??t?.device.platform),l=!0===r.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=oA({flags:r,sessionDevice:t?.device}),u=s&&!!d,c=!1;try{e=await ov({session:t,flags:r,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!1})}catch(i){let t=w(i);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw i;e=await h({avdName:d,serial:r.serial,headless:l}),c=!0}if(r.target&&(e.target??"mobile")!==r.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${r.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let i=oA({flags:r,sessionDevice:t?.device,resolvedDevice:e});if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await h({avdName:i,serial:r.serial,headless:!0})}await S(e)}else("android"!==e.platform||!0!==e.booted)&&await S(e);return nq("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===O)return await oM({req:i,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D});if("clipboard"===O)return await ox({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N});if("keyboard"===O)return await ob({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"keyboard",positionals:i.positionals??[]});if("perf"===O){let e,t,r,i=o.get(n);return i?{ok:!0,data:(r=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===ot&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:ot,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(i.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:ot,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:ot},{session:i.name,platform:i.device.platform,device:i.device.name,deviceId:i.device.id,metrics:{startup:r,fps:{available:!1,reason:oe},memory:{available:!1,reason:oe},cpu:{available:!1,reason:oe}},sampling:{startup:{method:ot,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("install"===O||"reinstall"===O)return await o_({req:i,command:O,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D,deployOps:"install"===O?c:p});if("push"===O){let e,t=i.positionals?.[0]?.trim(),r=i.positionals?.[1]?.trim();if(!t||!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=nE(r,{subject:"Push payload",cwd:i.meta?.cwd,expandPath:(e,t)=>tw.expandHome(e,t)})).kind?e.path:e.text;return await ob({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"push",positionals:[t,s],recordPositionals:[t,r]})}if("trigger-app-event"===O)return await ob({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"trigger-app-event",positionals:i.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await oL(e.device,r,e.appBundleId,g)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===O){let e=i.flags?.relaunch===!0;if(o.has(n)){let t=o.get(n),r=i.positionals?.[0],s=r??(e?t?.appName:void 0);if(!t||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&t9(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await S(t.device);let l=os(o,n,t?.device),d=await oL(t.device,s,t.appBundleId,g),u=r?i.positionals??[]:[s];if(e){let e=d??s;await oI({device:t.device,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nH(a,i.flags,d??t.appBundleId,t.trace?.outPath)},settleSimulator:k})}await v({device:t.device,appId:d,runtime:l});let c=Date.now();await N(t.device,"open",u,i.flags?.out,{...nH(a,i.flags,d)}),await ol({runtime:l,device:t.device,dispatch:N,req:i,logPath:a,appBundleId:d,traceLogPath:t.trace?.outPath,openPositionals:u});let p=od(c,s,d);await k(t.device,oi);let f={...t,appBundleId:d,appName:s,recordSession:t.recordSession||!!i.flags?.saveScript,snapshot:void 0},m=on({sessionName:n,appName:s,appBundleId:d,startup:p,device:t.device,runtime:l});return o.recordAction(f,{command:O,positionals:u,flags:i.flags??{},result:m}),o.set(n,f),{ok:!0,data:m}}let t=i.positionals?.[0];if(e&&!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&t&&t9(t))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let r=await D(i.flags??{}),s=o.toArray().find(e=>e.device.id===r.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:r.id,deviceName:r.name}}};await S(r);let l=os(o,n,r),d=await oL(r,t,void 0,g);if(e&&t){let e=d??t;await oI({device:r,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nH(a,i.flags,d)},settleSimulator:k})}await v({device:r,appId:d,runtime:l});let u=Date.now();await N(r,"open",i.positionals??[],i.flags?.out,{...nH(a,i.flags,d)}),await ol({runtime:l,device:r,dispatch:N,req:i,logPath:a,appBundleId:d,openPositionals:i.positionals??[]});let c=t?od(u,t,d):void 0;await k(r,oi);let p={name:n,device:r,createdAt:Date.now(),appBundleId:d,appName:t,recordSession:!!i.flags?.saveScript,actions:[]},f=on({sessionName:n,appName:t,appBundleId:d,startup:c,device:r,runtime:l});return o.recordAction(p,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:f}),o.set(n,p),{ok:!0,data:f}}if("replay"===O){let e=i.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=tw.expandHome(e,i.meta?.cwd),r=$.readFileSync(t,"utf8"),l=r.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(tp(i)){let e=th(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return aQ(r)&&aQ(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=th(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(r),u=i.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let r=d[e];if(!r||"replay"===r.command)continue;let l=await s({token:i.token,session:n,command:r.command,positionals:r.positionals??[],flags:o$(i.flags,r.flags),meta:i.meta});if(l.ok)continue;if(!u)return oP(l,r,e,t);let p=await oF({action:r,sessionName:n,logPath:a,sessionStore:o,dispatch:N});if(!p)return oP(l,r,e,t);if(d[e]=p,!(l=await s({token:i.token,session:n,command:p.command,positionals:p.positionals??[],flags:o$(i.flags,p.flags),meta:i.meta})).ok)return oP(l,p,e,t);c+=1}if(u&&c>0){let e=o.get(n);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",tf(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(tf(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(tf(r));return tm(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
35
|
+
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;$.writeFileSync(a,n),$.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:n}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(i.positionals?.[0]??"path").toLowerCase(),r=!!i.flags?.restart;if(!a9.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:a7}};if(r&&"clear"!==t)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===t){let t=o.resolveAppLogPath(n),r=function(e){if(!$.existsSync(e))return{exists:!1,sizeBytes:0};let t=$.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),i=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:i,sizeBytes:r.sizeBytes,modifiedAt:r.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===t){let t=o.resolveAppLogPath(n),r=await tM(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:r.checks,notes:r.notes}}}if("mark"===t){let e,t=i.positionals?.slice(1).join(" ")??"",r=o.resolveAppLogPath(n);return tk(r),e=`[agent-device][mark][${new Date().toISOString()}] ${t.trim()||"marker"}
|
|
36
|
+
`,$.appendFileSync(r,e,"utf8"),{ok:!0,data:{path:r,marked:!0}}}if("clear"===t){if(e.appLog&&!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(r){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!nq("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=o.resolveAppLogPath(n);if(r){e.appLog&&await m.stop(e.appLog);let r=tx(t),i=o.resolveAppLogPidPath(n);try{let a=await m.start(e.device,e.appBundleId,t,i),s={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return o.set(n,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=_(r);return o.set(n,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:tx(t)}}if("start"===t){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!nq("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=o.resolveAppLogPath(n),r=o.resolveAppLogPidPath(n);try{let i=await m.start(e.device,e.appBundleId,t,r),a={...e,appLog:{platform:e.device.platform,backend:i.backend,outPath:t,startedAt:i.startedAt,getState:i.getState,stop:i.stop,wait:i.wait}};return o.set(n,a),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:_(e)}}}if("stop"===t){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await m.stop(e.appLog),o.set(n,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(i.positionals?.[0]??"dump").toLowerCase();if(!ou.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:oc}};let r=i.positionals?.[1],a=r?Number.parseInt(r,10):25;if(!Number.isInteger(a)||a<1||a>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(i.positionals?.[2]??"summary").toLowerCase();if(!op.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:of}};let l=function(e,t){let r=aE(t?.maxEntries,25,1,200),i=t?.include??"summary",n=aE(t?.maxPayloadChars,2048,64,16384),a=aE(t?.maxScanLines,4e3,100,2e4);if(!$.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=$.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=aN(n,["method","httpMethod"]),o=aN(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=aA.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=ay.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of ab){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:aD(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return a_(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=aD(t,i))}if("body"===r||"all"===r){let t=aS(e,n,["requestBody","body","payload","request"]),r=aS(e,n,["responseBody","response"]);t&&(f.requestBody=aD(t,i)),r&&(f.responseBody=aD(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(o.resolveAppLogPath(n),{maxEntries:a,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===O)return await oR(i,n,s);if("close"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await m.stop(e.appLog),i.positionals&&i.positionals.length>0&&("ios"===e.device.platform&&await E(e.device.id),await N(e.device,"close",i.positionals,i.flags?.out,{...nH(a,i.flags,e.appBundleId,e.trace?.outPath)}),await k(e.device,or)),"ios"===e.device.platform&&await E(e.device.id),aT(o.getRuntimeHints(n))&&e.appBundleId&&await A({device:e.device,appId:e.appBundleId}).catch(()=>{}),o.recordAction(e,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:{session:n}}),i.flags?.saveScript&&(e.recordSession=!0),o.writeSessionLog(e),o.delete(n),i.flags?.shutdown&&ow(e.device)){let t;try{t=await (b??ij)(e.device)}catch(r){let e=_(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:n,shutdown:t}}}return{ok:!0,data:{session:n}}}return null}async function oR(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??C;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=c(e.flags?.batchSteps,n),a=Date.now(),o=[];for(let n=0;n<i.length;n+=1){let a=i[n],s=await oT(e,t,a,r,n+1);if(!s.ok)return{ok:!1,error:{code:s.error.code,message:`Batch failed at step ${s.step} (${a.command}): ${s.error.message}`,hint:s.error.hint,diagnosticId:s.error.diagnosticId,logPath:s.error.logPath,details:{...s.error.details??{},step:s.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:o}}};o.push(s.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:o}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function oT(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of a5)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function oP(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>tf(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function o$(e,t){let r={...t??{}},i=e??{};for(let e of a6)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function oF(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(tp(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=tp(t.command)||"fill"===t.command,l=tp(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await oV(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),tp(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=as(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=aZ(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return tl(t).filter(e=>e.trim().length>0)}(t)){let r=ar(e);if(!r)continue;let i=ai(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=au(i.node,o.device.platform,{action:tp(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(tp(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ts(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=as(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=aZ(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=ar(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(n8(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=n6(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(n8(e.type??"")))});if(0===s.length||1!==tl(s.map(e=>n6(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=au(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function oV(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...nH(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:nY(t.flags?.snapshotRaw?s:n4(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function oU(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function oG(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function oB(e,t){return t.flatten?e.map(e=>({text:i(e,0,!1),comparable:oG(e,0)})):y(e).map(e=>({text:e.text,comparable:oG(e.node,e.depth)}))}function oj(e,t){return e.get(t)??0}async function oq(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??nB,o=e.runnerCommand??ta,s=t.command;if("snapshot"===s){let{session:e,device:o}=await oJ(n,r,t.flags);if(!nq("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=oW(t.flags?.snapshotScope,e);return s.ok?await oz(e,o,async()=>{let l=e?.appBundleId,d=await oH({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return oK(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===s){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await oJ(n,r,t.flags);if(!nq("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=oW(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await oz(e,o,async()=>{let d=e?.appBundleId,u=(await oH({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return oB(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return oK(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&oj(a,n-1)<oj(a,n+1)?oj(a,n+1):oj(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&oj(n,l-1)<oj(n,l+1)?l+1:l-1,u=oj(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(oB(e,r),oB(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return oK(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===s){let{session:e,device:o}=await oJ(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=oU(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=oU(e[e.length-1]);return{kind:"text",text:(null!==t?e.slice(1,-1).join(" "):e.slice(1).join(" ")).trim(),timeoutMs:t}}if(e[0].startsWith("@")){let t=oU(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=oU(e[e.length-1]),i=ao(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=ar(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),oK(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):nq("wait",o)?await oz(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...nH(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=nY(t.flags?.snapshotRaw?u:n4(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=an(c,s.selector,{platform:o.platform});if(p)return oK(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=nZ(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=nQ(e.snapshot.nodes,t),i=r?n2(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await ta(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return oK(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&n1(nY((await rz(o,{scope:l})).nodes??[]),l))return oK(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===s){let{session:e,device:a}=await oJ(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return nq("alert",a)?await oz(e,a,async()=>{if("wait"===s){let r=oU(t.positionals?.[1])??1e4,s=Date.now();for(;Date.now()-s<r;){try{let r=await o(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return oK(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r="accept"===s||"dismiss"===s?s:"get",l={verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId};if("accept"===r||"dismiss"===r){let i,s=Date.now();for(;Date.now()-s<2e3;){try{let i=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return oK(n,e,t,i),{ok:!0,data:i}}catch(t){i=t;let e=String(t?.message??"").toLowerCase();if(!e.includes("alert not found")&&!e.includes("no alert"))break}await new Promise(e=>setTimeout(e,300))}throw i}let d=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return oK(n,e,t,d),{ok:!0,data:d}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===s){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:f}};let{session:s,device:l}=await oJ(n,r,t.flags);return nq("settings",l)?await oz(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await nB(l,"settings",d,t.flags?.out,{...nH(i,t.flags,r,s?.trace?.outPath)});return oK(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function oH(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...nH(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:nY(n.flags?.snapshotRaw?l:n4(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function oW(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=nZ(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=nQ(t.snapshot.nodes,r),n=i?n2(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function oJ(e,t,r){let i=e.get(t),n=i?.device??await nG(r??{});return i||await nJ(n),{session:i,device:n}}async function oz(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await e9(t.id)}}function oK(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function oX(e,t,r,i={}){let n=oZ(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return oY(e.label,r);case"value":return oY(e.value,r);case"id":return oY(e.identifier,r);default:return Math.max(oY(e.label,r),oY(e.value,r),oY(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function oY(e,t){let r=oZ(e??"");return r?r===t?2:+!!r.includes(t):0}function oZ(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function oQ(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??nB,s=t.command;if("find"!==s)return null;let l=t.positionals??[];if(0===l.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:d,query:u,action:c,value:p,timeoutMs:f}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:oU(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(l);if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=n.get(r);if(!m&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await nG(t.flags??{});m||await nJ(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,b=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...nH(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=nY(t.flags?.snapshotRaw?s:n4(s));return A=e,y=l,m&&(m.snapshot={nodes:l,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,m)),{nodes:l,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=f??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await b();if(oX(e,d,u,{requireRect:!1}).matches[0])return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await b(),S=oX(N,d,u,{requireRect:v});if(v&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=n6(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:S.matches.length,candidates:e}}}}let _=S.matches[0]??null;if(!_)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let D="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,_)??_:_,E=`@${D.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=n6(_);return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get text",text:e}}),{ok:!0,data:{ref:E,text:e,node:_}}}if("get_attrs"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get attrs"}}),{ok:!0,data:{ref:E,node:_}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[E],flags:k});if(!e.ok)return e;let i=D.rect?n0(D.rect):null,o={ref:E,locator:d,query:u};return i&&(o.x=i.x,o.y=i.y),m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"click",locator:d,query:u}}),{ok:!0,data:o}}if("fill"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[E,p],flags:k});return e.ok&&m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"fill"}}),e}if("focus"===c){let e=_.rect?n0(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nH(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"focus"}}),{ok:!0,data:r??{ref:E}}}if("type"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=_.rect?n0(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nH(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...nH(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"type"}}),{ok:!0,data:r??{ref:E}}}return null}function o0(e){return e instanceof Error?e.message:String(e)}function o1(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function o2(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function o3(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:ta},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await nG(t.flags??{});d||await nJ(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!nq("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?o1(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=tw.expandHome(d,t.meta?.cwd),h=t.meta?.clientArtifactPaths?.outPath;$.mkdirSync(n.dirname(m),{recursive:!0});let w=o2(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},w)};try{await n()}catch(e){if(!o0(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${o0(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:o0(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},w)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${o0(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,clientOutPath:h,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",e_(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,clientOutPath:h,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,clientOutPath:h,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:h??d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=o1(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},o2(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:o0(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of eY)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}});let m=[{field:"outPath",path:f.outPath,localPath:f.clientOutPath,fileName:n.basename(f.clientOutPath??f.outPath)}];return{ok:!0,data:{recording:"stopped",outPath:f.outPath,artifacts:m}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=tw.expandHome(e);return $.mkdirSync(n.dirname(r),{recursive:!0}),$.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=tw.expandHome(t.positionals[1]);$.mkdirSync(n.dirname(e),{recursive:!0}),$.existsSync(o)?$.renameSync(o,e):$.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function o4(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function o8(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function o5(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function o6(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??nB,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nq("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=se("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=st({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=sr(p.rect);if(!m){let r=await o9(e,t.flags,i,n,{interactiveOnly:!0},a),o=nQ(r.nodes,c),l=s.length>0?n1(r.nodes,s):null,d=sr(l?.rect),u=sr(o?.rect)?o:d?l:o??l,h=sr(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=n2(p,f),w=au(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=at(u),p=await o9(e,t.flags,i,n,{interactiveOnly:!0},a),f=await L("selector_resolve",()=>ai(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:aa(c,f?.diagnostics??[],{unique:!0})}};let m=sr(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=au(f.node,e.device.platform,{action:l}),v=n2(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!nq("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=se("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=st({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!n5(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=n2(c,p),w=au(c,e.device.platform,{action:"fill"}),{x:g,y:I}=n0(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=ao(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=at(s.selectorExpression),d=await o9(e,t.flags,i,n,{interactiveOnly:!0},a),u=await L("selector_resolve",()=>ai(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:aa(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!n5(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=n0(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=au(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:n2(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nq("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=se("get",t.flags);if(r)return r;let n=st({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=au(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=n6(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=at(d),c=await o9(s,t.flags,i,n,{interactiveOnly:!1},a),p=await L("selector_resolve",()=>ai(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:aa(u,[],{unique:!0})}};let f=p.node,m=au(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=n6(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nq("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=as(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=at(l.selectorExpression),c=await o9(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=an(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:aa(u,[],{unique:!1})}}}let p=await L("selector_resolve",()=>ai(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:aa(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=n6(r),o=!1;switch(t){case"visible":o=al(r);break;case"hidden":o=!al(r);break;case"editable":o=ad(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:al(r),editable:ad(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nq("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=se("scrollintoview",t.flags);if(l)return l;let d=st({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=n0(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=o8(n.map(e=>e.rect).filter(e=>o4(e,r.x,r.y)));if(a)return a;let o=o8(n.map(e=>e.rect));if(o)return o;let s=o8(i.map(e=>e.rect).filter(e=>o4(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:o5(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:o5(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=n2(c,p),w=au(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function o9(e,t,r,i,n,a=nB){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:nY(t?.snapshotRaw?s:n4(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let o7=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function se(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of o7)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function st(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=nZ(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=nQ(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=n1(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function sr(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=n0(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function si(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function sn(e){let{req:t,leaseRegistry:r}=e,i=si(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let sa=new Set(["session_list","devices","ensure-simulator"]),so=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]);function ss(e,t,r,i){let n=O().requestId;return{...nH(e,t,r,i,n),requestId:n}}function sl(e){$.existsSync(e)&&$.unlinkSync(e)}function sd(e){if(!$.existsSync(e))return null;try{let t=JSON.parse($.readFileSync(e,"utf8"));if(!Number.isInteger(t.pid)||t.pid<=0)return null;return t}catch{return null}}function su(e){let t=sd(e);if(!t||t.pid===process.pid)try{$.existsSync(e)&&$.unlinkSync(e)}catch{}}function sc(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}let{baseDir:sp,infoPath:sf,lockPath:sm,logPath:sh,sessionsDir:sw}=B(process.env.AGENT_DEVICE_STATE_DIR),sg=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var sI=sw;if($.existsSync(sI))for(let e of $.readdirSync(sI,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(sI,e.name,"app-log.pid");if($.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}($.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{tI(t)}}let sv=new tw(sw),sA=new t3({maxActiveSimulatorLeases:sc(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:sc(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:sc(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:sc(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),sy=E(),sb=u.randomBytes(24).toString("hex"),sN=T(process.pid)??void 0,sS=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=$.statSync(e),r=k(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}(),s_=function(e){let{logPath:t,token:r,sessionStore:i,leaseRegistry:a,trackDownloadableArtifact:s}=e;async function l(e){let d="click"===e.command?{...e,command:"press"}:e,u=!!(d.meta?.debug||d.flags?.verbose);return await P({session:d.session,requestId:d.meta?.requestId,command:d.command,debug:u,logPath:t},async()=>{if(d.token!==r)return{ok:!1,error:_(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=D(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=o(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(d);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let r=e.command,u=t=>(function(e,t,r){let i=O();if(!t.ok){M({level:"error",phase:"request_failed",data:{code:t.error.code,message:t.error.message}});let e=F({force:!0})??void 0;return{ok:!1,error:_(new I(t.error.code,t.error.message,{...t.error.details??{},hint:t.error.hint,diagnosticId:t.error.diagnosticId,logPath:t.error.logPath}),{diagnosticId:i.diagnosticId,logPath:e})}}return M({level:"info",phase:"request_success"}),F(),{ok:!0,data:function(e,t,r){var i,a;let o;if(!t)return t;let s=(i=e,a=t,o=Array.isArray(a.artifacts)?[...a.artifacts]:[],"screenshot"!==i.command||o.some(e=>e?.field==="path")||"string"!=typeof a.path||o.push({field:"path",path:a.path,localPath:i.meta?.clientArtifactPaths?.path,fileName:n.basename(i.meta?.clientArtifactPaths?.path??a.path)}),o.filter(e=>!!(e&&"string"==typeof e.field&&"string"==typeof e.path&&"string"==typeof e.localPath&&e.localPath.length>0)));return 0===s.length?t:{...t,artifacts:s.map(t=>{let i=t.path;return{field:t.field,artifactId:r({artifactPath:i,tenantId:e.meta?.tenantId,fileName:t.fileName}),fileName:t.fileName,localPath:t.localPath}})}}(e,t.data,r)}})(e,t,s),c=si(e);so.has(r)||e.meta?.sessionIsolation!=="tenant"||a.assertLeaseAdmission({tenantId:c.tenantId,runId:c.runId,leaseId:c.leaseId,backend:c.leaseBackend});let p=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,i),f=i.get(p);f&&!sa.has(r)&&function(e,t){if(!t)return;let r=[],i=e.device,n=ej(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=eb(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(f,e.flags);let m=await sn({req:e,leaseRegistry:a});if(m)return u(m);let h=await oC({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(h)return u(h);let w=await oq({req:e,sessionName:p,logPath:t,sessionStore:i});if(w)return u(w);let g=await o3({req:e,sessionName:p,sessionStore:i,logPath:t});if(g)return u(g);let v=await oQ({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(v)return u(v);let A=await o6({req:e,sessionName:p,sessionStore:i,contextFromFlags:(e,r,i)=>ss(t,e,r,i)});if(A)return u(A);let y=i.get(p);if(!y)return u({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!nq(r,y.device))return u({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}});let b=await nB(y.device,r,e.positionals??[],e.flags?.out,{...ss(t,e.flags,y.appBundleId,y.trace?.outPath)});return i.recordAction(y,{command:r,positionals:e.positionals??[],flags:e.flags??{},result:b??{}}),u({ok:!0,data:b??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=O(),t=F({force:!0})??void 0;return{ok:!1,error:_(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}return l}({logPath:sh,token:sb,sessionStore:sv,leaseRegistry:sA,trackDownloadableArtifact:function(e){let t=u.randomUUID(),r=setTimeout(()=>{tR(t)},9e5);return tC.set(t,{artifactPath:e.artifactPath,tenantId:e.tenantId,fileName:e.fileName,deleteAfterDownload:!1!==e.deleteAfterDownload,timer:r}),t}});!async function(){let e,t;if(!function(e,t,r){$.existsSync(e)||$.mkdirSync(e,{recursive:!0});let i=JSON.stringify(r,null,2),n=()=>{try{return $.writeFileSync(t,i,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(n())return!0;let a=sd(t);if(a?.pid&&a.pid!==process.pid&&s(a.pid,a.processStartTime))return!1;try{$.unlinkSync(t)}catch{}return n()}(sp,sm,{pid:process.pid,version:sy,startedAt:Date.now(),processStartTime:sN})){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===sg||"dual"===sg){let t=U.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))ea(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await e7(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,o,s=t.slice(0,a).trim();if(t=t.slice(a+1),0===s.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(s);if(o=ei(e.meta?.requestId,"socket"),e.meta={...e.meta,requestId:o},i.add(o),en(o),es(o))throw el();n=await s_(e)}catch(e){n={ok:!1,error:_(e)}}finally{r-=1,o&&(i.delete(o),eo(o))}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
37
|
+
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===sg||"dual"===sg){let e=await tX({handleRequest:s_,token:sb});r.push(e),t=await new Promise((t,r)=>{e.once("error",r),e.listen(0,"127.0.0.1",()=>{e.off("error",r);let i=e.address();"object"==typeof i&&i?.port?t(i.port):r(new I("COMMAND_FAILED","Failed to bind HTTP server"))})})}i={socketPort:e,httpPort:t,token:sb,version:sy,codeSignature:sS,processStartTime:sN},$.existsSync(sp)||$.mkdirSync(sp,{recursive:!0}),$.writeFileSync(sh,""),n=i.socketPort&&i.httpPort?"dual":i.httpPort?"http":"socket",$.writeFileSync(sf,JSON.stringify({port:i.socketPort,httpPort:i.httpPort,transport:n,token:i.token,pid:process.pid,version:i.version,codeSignature:i.codeSignature,processStartTime:i.processStartTime,stateDir:sp},null,2),{mode:384}),e&&process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${e}
|
|
38
38
|
`),t&&process.stdout.write(`AGENT_DEVICE_DAEMON_HTTP_PORT=${t}
|
|
39
39
|
`)}catch(t){let e=w(t);for(let t of(process.stderr.write(`Daemon error: ${e.message}
|
|
40
|
-
`),r))try{t.close(()=>{})}catch{}
|
|
40
|
+
`),r))try{t.close(()=>{})}catch{}sl(sf),su(sm),process.exit(1);return}let n=!1,a=async()=>{await Promise.all(r.map(async e=>{await new Promise(t=>{try{e.close(()=>t())}catch{t()}})}))},o=async()=>{if(!n){for(let e of(n=!0,await a(),sv.toArray()))sv.writeSessionLog(e);await te(),sl(sf),su(sm),process.exit(0)}};process.on("SIGINT",()=>{o()}),process.on("SIGTERM",()=>{o()}),process.on("SIGHUP",()=>{o()}),process.on("uncaughtException",e=>{let t=e instanceof I?e:w(e);process.stderr.write(`Daemon error: ${t.message}
|
|
41
41
|
`),o()})}();
|